s3c24xx_uart.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2010 Jiri Svoboda
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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         /* Not reached */
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         /* Answer the IPC_M_CONNECT_ME_TO call. */
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                         /* The other side has hung up. */
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         /* Enable FIFO, Tx trigger level: empty, Rx trigger level: 1 byte. */
00195         pio_write_32(&uart->io->ufcon, UFCON_FIFO_ENABLE |
00196             UFCON_TX_FIFO_TLEVEL_EMPTY | UFCON_RX_FIFO_TLEVEL_1B);
00197 
00198         /* Set RX interrupt to pulse mode */
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         /* Wait for space becoming available in Tx FIFO. */
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 

Generated on Thu Jun 2 07:45:50 2011 for HelenOS/USB by  doxygen 1.4.7