00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00039 #include <ddi.h>
00040 #include <libarch/ddi.h>
00041 #include <devmap.h>
00042 #include <ipc/char.h>
00043 #include <async.h>
00044 #include <unistd.h>
00045 #include <stdio.h>
00046 #include <stdlib.h>
00047 #include <sysinfo.h>
00048 #include <errno.h>
00049 #include <inttypes.h>
00050
00051 #include "s3c24xx_uart.h"
00052
00053 #define NAME "s3c24ser"
00054 #define NAMESPACE "char"
00055
00056 static irq_cmd_t uart_irq_cmds[] = {
00057 {
00058 .cmd = CMD_ACCEPT
00059 }
00060 };
00061
00062 static irq_code_t uart_irq_code = {
00063 sizeof(uart_irq_cmds) / sizeof(irq_cmd_t),
00064 uart_irq_cmds
00065 };
00066
00068 static s3c24xx_uart_t *uart;
00069
00070 static void s3c24xx_uart_connection(ipc_callid_t iid, ipc_call_t *icall);
00071 static void s3c24xx_uart_irq_handler(ipc_callid_t iid, ipc_call_t *call);
00072 static int s3c24xx_uart_init(s3c24xx_uart_t *uart);
00073 static void s3c24xx_uart_sendb(s3c24xx_uart_t *uart, uint8_t byte);
00074
00075 int main(int argc, char *argv[])
00076 {
00077 int rc;
00078
00079 printf(NAME ": S3C24xx on-chip UART driver\n");
00080
00081 rc = devmap_driver_register(NAME, s3c24xx_uart_connection);
00082 if (rc < 0) {
00083 printf(NAME ": Unable to register driver.\n");
00084 return -1;
00085 }
00086
00087 uart = malloc(sizeof(s3c24xx_uart_t));
00088 if (uart == NULL)
00089 return -1;
00090
00091 if (s3c24xx_uart_init(uart) != EOK)
00092 return -1;
00093
00094 rc = devmap_device_register(NAMESPACE "/" NAME, &uart->devmap_handle);
00095 if (rc != EOK) {
00096 printf(NAME ": Unable to register device %s.\n",
00097 NAMESPACE "/" NAME);
00098 return -1;
00099 }
00100
00101 printf(NAME ": Registered device %s.\n", NAMESPACE "/" NAME);
00102
00103 printf(NAME ": Accepting connections\n");
00104 task_retval(0);
00105 async_manager();
00106
00107
00108 return 0;
00109 }
00110
00112 static void s3c24xx_uart_connection(ipc_callid_t iid, ipc_call_t *icall)
00113 {
00114 ipc_callid_t callid;
00115 ipc_call_t call;
00116 sysarg_t method;
00117 int retval;
00118
00119
00120 async_answer_0(iid, EOK);
00121
00122 while (1) {
00123 callid = async_get_call(&call);
00124 method = IPC_GET_IMETHOD(call);
00125 switch (method) {
00126 case IPC_M_PHONE_HUNGUP:
00127
00128 async_answer_0(callid, EOK);
00129 return;
00130 case IPC_M_CONNECT_TO_ME:
00131 printf(NAME ": creating callback connection\n");
00132 uart->client_phone = IPC_GET_ARG5(call);
00133 retval = 0;
00134 break;
00135 case CHAR_WRITE_BYTE:
00136 printf(NAME ": write %" PRIun " to device\n",
00137 IPC_GET_ARG1(call));
00138 s3c24xx_uart_sendb(uart, (uint8_t) IPC_GET_ARG1(call));
00139 retval = 0;
00140 break;
00141 default:
00142 retval = EINVAL;
00143 break;
00144 }
00145 async_answer_0(callid, retval);
00146 }
00147 }
00148
00149 static void s3c24xx_uart_irq_handler(ipc_callid_t iid, ipc_call_t *call)
00150 {
00151 (void) iid; (void) call;
00152
00153 while ((pio_read_32(&uart->io->ufstat) & S3C24XX_UFSTAT_RX_COUNT) != 0) {
00154 uint32_t data = pio_read_32(&uart->io->urxh) & 0xff;
00155 uint32_t status = pio_read_32(&uart->io->uerstat);
00156
00157 if (uart->client_phone != -1) {
00158 async_msg_1(uart->client_phone, CHAR_NOTIF_BYTE,
00159 data);
00160 }
00161
00162 if (status != 0)
00163 printf(NAME ": Error status 0x%x\n", status);
00164 }
00165 }
00166
00168 static int s3c24xx_uart_init(s3c24xx_uart_t *uart)
00169 {
00170 void *vaddr;
00171 sysarg_t inr;
00172
00173 if (sysinfo_get_value("s3c24xx_uart.address.physical",
00174 &uart->paddr) != EOK)
00175 return -1;
00176
00177 if (pio_enable((void *) uart->paddr, sizeof(s3c24xx_uart_io_t),
00178 &vaddr) != 0)
00179 return -1;
00180
00181 if (sysinfo_get_value("s3c24xx_uart.inr", &inr) != EOK)
00182 return -1;
00183
00184 uart->io = vaddr;
00185 uart->client_phone = -1;
00186
00187 printf(NAME ": device at physical address %p, inr %" PRIun ".\n",
00188 (void *) uart->paddr, inr);
00189
00190 async_set_interrupt_received(s3c24xx_uart_irq_handler);
00191
00192 register_irq(inr, device_assign_devno(), 0, &uart_irq_code);
00193
00194
00195 pio_write_32(&uart->io->ufcon, UFCON_FIFO_ENABLE |
00196 UFCON_TX_FIFO_TLEVEL_EMPTY | UFCON_RX_FIFO_TLEVEL_1B);
00197
00198
00199 pio_write_32(&uart->io->ucon,
00200 pio_read_32(&uart->io->ucon) & ~UCON_RX_INT_LEVEL);
00201
00202 return EOK;
00203 }
00204
00206 static void s3c24xx_uart_sendb(s3c24xx_uart_t *uart, uint8_t byte)
00207 {
00208
00209 while ((pio_read_32(&uart->io->ufstat) & S3C24XX_UFSTAT_TX_FULL) != 0)
00210 ;
00211
00212 pio_write_32(&uart->io->utxh, byte);
00213 }
00214