Prex Home / Browse Source - Prex Version: 0.9.0

root/bsp/drv/dev/serial/ns16550.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ns16550_xmt_char
  2. ns16550_rcv_char
  3. ns16550_set_poll
  4. ns16550_isr
  5. ns16550_start
  6. ns16550_stop
  7. ns16550_probe
  8. ns16550_init

   1 /*-
   2  * Copyright (c) 2009, Kohsuke Ohtani
   3  * All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 1. Redistributions of source code must retain the above copyright
   9  *    notice, this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright
  11  *    notice, this list of conditions and the following disclaimer in the
  12  *    documentation and/or other materials provided with the distribution.
  13  * 3. Neither the name of the author nor the names of any co-contributors
  14  *    may be used to endorse or promote products derived from this software
  15  *    without specific prior written permission.
  16  *
  17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27  * SUCH DAMAGE.
  28  */
  29 
  30 /*
  31  * ns16550.c - NS16550 serial driver
  32  */
  33 
  34 #include <driver.h>
  35 #include <tty.h>
  36 #include <serial.h>
  37 
  38 /* #define DEBUG_NS16550 1 */
  39 
  40 #ifdef DEBUG_NS16550
  41 #define DPRINTF(a) printf a
  42 #else
  43 #define DPRINTF(a)
  44 #endif
  45 
  46 #define COM_BASE        CONFIG_NS16550_BASE
  47 #define COM_IRQ         CONFIG_NS16550_IRQ
  48 
  49 /* Register offsets */
  50 #define COM_RBR         (COM_BASE + 0x00)       /* receive buffer register */
  51 #define COM_THR         (COM_BASE + 0x00)       /* transmit holding register */
  52 #define COM_IER         (COM_BASE + 0x01)       /* interrupt enable register */
  53 #define COM_FCR         (COM_BASE + 0x02)       /* FIFO control register */
  54 #define COM_IIR         (COM_BASE + 0x02)       /* interrupt identification register */
  55 #define COM_LCR         (COM_BASE + 0x03)       /* line control register */
  56 #define COM_MCR         (COM_BASE + 0x04)       /* modem control register */
  57 #define COM_LSR         (COM_BASE + 0x05)       /* line status register */
  58 #define COM_MSR         (COM_BASE + 0x06)       /* modem status register */
  59 #define COM_DLL         (COM_BASE + 0x00)       /* divisor latch LSB (LCR[7] = 1) */
  60 #define COM_DLM         (COM_BASE + 0x01)       /* divisor latch MSB (LCR[7] = 1) */
  61 
  62 /* Interrupt enable register */
  63 #define IER_RDA         0x01    /* enable receive data available */
  64 #define IER_THRE        0x02    /* enable transmitter holding register empty */
  65 #define IER_RLS         0x04    /* enable recieve line status */
  66 #define IER_RMS         0x08    /* enable receive modem status */
  67 
  68 /* Interrupt identification register */
  69 #define IIR_MSR         0x00    /* modem status change */
  70 #define IIR_IP          0x01    /* 0 when interrupt pending */
  71 #define IIR_TXB         0x02    /* transmitter holding register empty */
  72 #define IIR_RXB         0x04    /* received data available */
  73 #define IIR_LSR         0x06    /* line status change */
  74 #define IIR_MASK        0x07    /* mask off just the meaningful bits */
  75 
  76 /* line status register */
  77 #define LSR_RCV_FIFO    0x80
  78 #define LSR_TSRE        0x40    /* Transmitter empty: byte sent */
  79 #define LSR_TXRDY       0x20    /* Transmitter buffer empty */
  80 #define LSR_BI          0x10    /* Break detected */
  81 #define LSR_FE          0x08    /* Framing error: bad stop bit */
  82 #define LSR_PE          0x04    /* Parity error */
  83 #define LSR_OE          0x02    /* Overrun, lost incoming byte */
  84 #define LSR_RXRDY       0x01    /* Byte ready in Receive Buffer */
  85 #define LSR_RCV_MASK    0x1f    /* Mask for incoming data or error */
  86 
  87 /* Forward functions */
  88 static int      ns16550_probe(struct driver *);
  89 static int      ns16550_init(struct driver *);
  90 
  91 static void     ns16550_xmt_char(struct serial_port *, char);
  92 static char     ns16550_rcv_char(struct serial_port *);
  93 static void     ns16550_set_poll(struct serial_port *, int);
  94 static void     ns16550_start(struct serial_port *);
  95 static void     ns16550_stop(struct serial_port *);
  96 
  97 
  98 struct driver ns16550_driver = {
  99         /* name */      "ns16550",
 100         /* devops */    NULL,
 101         /* devsz */     0,
 102         /* flags */     0,
 103         /* probe */     ns16550_probe,
 104         /* init */      ns16550_init,
 105         /* unload */    NULL,
 106 };
 107 
 108 static struct serial_ops ns16550_ops = {
 109         /* xmt_char */  ns16550_xmt_char,
 110         /* rcv_char */  ns16550_rcv_char,
 111         /* set_poll */  ns16550_set_poll,
 112         /* start */     ns16550_start,
 113         /* stop */      ns16550_stop,
 114 };
 115 
 116 
 117 static struct serial_port ns16550_port;
 118 
 119 
 120 static void
 121 ns16550_xmt_char(struct serial_port *sp, char c)
 122 {
 123 
 124         while (!(bus_read_8(COM_LSR) & LSR_TXRDY))
 125                 ;
 126         bus_write_8(COM_THR, c);
 127 }
 128 
 129 static char
 130 ns16550_rcv_char(struct serial_port *sp)
 131 {
 132 
 133         while (!(bus_read_8(COM_LSR) & LSR_RXRDY))
 134                 ;
 135         return bus_read_8(COM_RBR);
 136 }
 137 
 138 static void
 139 ns16550_set_poll(struct serial_port *sp, int on)
 140 {
 141 
 142         if (on) {
 143                 /* Disable interrupt for polling mode. */
 144                 bus_write_8(COM_IER, 0x00);
 145         } else {
 146                 /* enable interrupt again */
 147                 bus_write_8(COM_IER, IER_RDA|IER_THRE|IER_RLS);
 148         }
 149 }
 150 
 151 static int
 152 ns16550_isr(void *arg)
 153 {
 154         struct serial_port *sp = arg;
 155 
 156         switch (bus_read_8(COM_IIR) & IIR_MASK) {
 157         case IIR_MSR:           /* Modem status change */
 158                 break;
 159         case IIR_LSR:           /* Line status change */
 160                 bus_read_8(COM_LSR);
 161                 break;
 162         case IIR_TXB:           /* Transmitter holding register empty */
 163                 serial_xmt_done(sp);
 164                 break;
 165         case IIR_RXB:           /* Received data available */
 166                 bus_read_8(COM_LSR);
 167                 serial_rcv_char(sp, bus_read_8(COM_RBR));
 168                 break;
 169         }
 170         return 0;
 171 }
 172 
 173 static void
 174 ns16550_start(struct serial_port *sp)
 175 {
 176         int s;
 177 
 178         bus_write_8(COM_IER, 0x00);     /* Disable interrupt */
 179         bus_write_8(COM_LCR, 0x80);     /* Access baud rate */
 180         bus_write_8(COM_DLL, 0x01);     /* 115200 baud */
 181         bus_write_8(COM_DLM, 0x00);
 182         bus_write_8(COM_LCR, 0x03);     /* N, 8, 1 */
 183         bus_write_8(COM_FCR, 0x06);     /* Disable & clear FIFO */
 184 
 185         sp->irq = irq_attach(COM_IRQ, IPL_COMM, 0, ns16550_isr,
 186                              IST_NONE, sp);
 187 
 188         s = splhigh();
 189         bus_write_8(COM_MCR, 0x0b);  /* Enable OUT2 interrupt */
 190         bus_write_8(COM_IER, IER_RDA|IER_THRE|IER_RLS);  /* Enable interrupt */
 191         bus_read_8(COM_IIR);
 192         splx(s);
 193 }
 194 
 195 static void
 196 ns16550_stop(struct serial_port *sp)
 197 {
 198 
 199         /* Disable all interrupts */
 200         bus_write_8(COM_IER, 0x00);
 201 }
 202 
 203 
 204 static int
 205 ns16550_probe(struct driver *self)
 206 {
 207 
 208         if (bus_read_8(COM_LSR) == 0xff)
 209                 return ENXIO;   /* Port is disabled */
 210         return 0;
 211 }
 212 
 213 static int
 214 ns16550_init(struct driver *self)
 215 {
 216 
 217         serial_attach(&ns16550_ops, &ns16550_port);
 218         return 0;
 219 }

/* [<][>][^][v][top][bottom][index][help] */