Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /* drivers/serial/serial_lh7a40x.c
  2  *
  3  *  Copyright (C) 2004 Coastal Environmental Systems
  4  *
  5  *  This program is free software; you can redistribute it and/or
  6  *  modify it under the terms of the GNU General Public License
  7  *  version 2 as published by the Free Software Foundation.
  8  *
  9  */
 10 
 11 /* Driver for Sharp LH7A40X embedded serial ports
 12  *
 13  *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
 14  *  Based on drivers/serial/amba.c, by Deep Blue Solutions Ltd.
 15  *
 16  *  ---
 17  *
 18  * This driver supports the embedded UARTs of the Sharp LH7A40X series
 19  * CPUs.  While similar to the 16550 and other UART chips, there is
 20  * nothing close to register compatibility.  Moreover, some of the
 21  * modem control lines are not available, either in the chip or they
 22  * are lacking in the board-level implementation.
 23  *
 24  * - Use of SIRDIS
 25  *   For simplicity, we disable the IR functions of any UART whenever
 26  *   we enable it.
 27  *
 28  */
 29 
 30 #include <linux/config.h>
 31 
 32 #if defined(CONFIG_SERIAL_LH7A40X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 33 #define SUPPORT_SYSRQ
 34 #endif
 35 
 36 #include <linux/module.h>
 37 #include <linux/ioport.h>
 38 #include <linux/init.h>
 39 #include <linux/console.h>
 40 #include <linux/sysrq.h>
 41 #include <linux/tty.h>
 42 #include <linux/tty_flip.h>
 43 #include <linux/serial_core.h>
 44 #include <linux/serial.h>
 45 
 46 #include <asm/io.h>
 47 #include <asm/irq.h>
 48 
 49 #define DEV_MAJOR       204
 50 #define DEV_MINOR       16
 51 #define DEV_NR          3
 52 
 53 #define ISR_LOOP_LIMIT  256
 54 
 55 #define UR(p,o) _UR ((p)->membase, o)
 56 #define _UR(b,o) (*((volatile unsigned int*)(((unsigned char*) b) + (o))))
 57 #define BIT_CLR(p,o,m)  UR(p,o) = UR(p,o) & (~(unsigned int)m)
 58 #define BIT_SET(p,o,m)  UR(p,o) = UR(p,o) | ( (unsigned int)m)
 59 
 60 #define UART_REG_SIZE   32
 61 
 62 #define UART_R_DATA     (0x00)
 63 #define UART_R_FCON     (0x04)
 64 #define UART_R_BRCON    (0x08)
 65 #define UART_R_CON      (0x0c)
 66 #define UART_R_STATUS   (0x10)
 67 #define UART_R_RAWISR   (0x14)
 68 #define UART_R_INTEN    (0x18)
 69 #define UART_R_ISR      (0x1c)
 70 
 71 #define UARTEN          (0x01)          /* UART enable */
 72 #define SIRDIS          (0x02)          /* Serial IR disable (UART1 only) */
 73 
 74 #define RxEmpty         (0x10)
 75 #define TxEmpty         (0x80)
 76 #define TxFull          (0x20)
 77 #define nRxRdy          RxEmpty
 78 #define nTxRdy          TxFull
 79 #define TxBusy          (0x08)
 80 
 81 #define RxBreak         (0x0800)
 82 #define RxOverrunError  (0x0400)
 83 #define RxParityError   (0x0200)
 84 #define RxFramingError  (0x0100)
 85 #define RxError     (RxBreak | RxOverrunError | RxParityError | RxFramingError)
 86 
 87 #define DCD             (0x04)
 88 #define DSR             (0x02)
 89 #define CTS             (0x01)
 90 
 91 #define RxInt           (0x01)
 92 #define TxInt           (0x02)
 93 #define ModemInt        (0x04)
 94 #define RxTimeoutInt    (0x08)
 95 
 96 #define MSEOI           (0x10)
 97 
 98 #define WLEN_8          (0x60)
 99 #define WLEN_7          (0x40)
100 #define WLEN_6          (0x20)
101 #define WLEN_5          (0x00)
102 #define WLEN            (0x60)  /* Mask for all word-length bits */
103 #define STP2            (0x08)
104 #define PEN             (0x02)  /* Parity Enable */
105 #define EPS             (0x04)  /* Even Parity Set */
106 #define FEN             (0x10)  /* FIFO Enable */
107 #define BRK             (0x01)  /* Send Break */
108 
109 
110 struct uart_port_lh7a40x {
111         struct uart_port port;
112         unsigned int statusPrev; /* Most recently read modem status */
113 };
114 
115 static void lh7a40xuart_stop_tx (struct uart_port* port, unsigned int tty_stop)
116 {
117         BIT_CLR (port, UART_R_INTEN, TxInt);
118 }
119 
120 static void lh7a40xuart_start_tx (struct uart_port* port,
121                                   unsigned int tty_start)
122 {
123         BIT_SET (port, UART_R_INTEN, TxInt);
124 
125         /* *** FIXME: do I need to check for startup of the
126                       transmitter?  The old driver did, but AMBA
127                       doesn't . */
128 }
129 
130 static void lh7a40xuart_stop_rx (struct uart_port* port)
131 {
132         BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt);
133 }
134 
135 static void lh7a40xuart_enable_ms (struct uart_port* port)
136 {
137         BIT_SET (port, UART_R_INTEN, ModemInt);
138 }
139 
140 static void
141 #ifdef SUPPORT_SYSRQ
142 lh7a40xuart_rx_chars (struct uart_port* port, struct pt_regs* regs)
143 #else
144 lh7a40xuart_rx_chars (struct uart_port* port)
145 #endif
146 {
147         struct tty_struct* tty = port->info->tty;
148         int cbRxMax = 256;      /* (Gross) limit on receive */
149         unsigned int data, flag;/* Received data and status */
150 
151         while (!(UR (port, UART_R_STATUS) & nRxRdy) && --cbRxMax) {
152                 if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
153                         if (tty->low_latency)
154                                 tty_flip_buffer_push(tty);
155                         /*
156                          * If this failed then we will throw away the
157                          * bytes but must do so to clear interrupts
158                          */
159                 }
160 
161                 data = UR (port, UART_R_DATA);
162                 flag = TTY_NORMAL;
163                 ++port->icount.rx;
164 
165                 if (data & RxError) {   /* Quick check, short-circuit */
166                         if (data & RxBreak) {
167                                 data &= ~(RxFramingError | RxParityError);
168                                 ++port->icount.brk;
169                                 if (uart_handle_break (port))
170                                         continue;
171                         }
172                         else if (data & RxParityError)
173                                 ++port->icount.parity;
174                         else if (data & RxFramingError)
175                                 ++port->icount.frame;
176                         if (data & RxOverrunError)
177                                 ++port->icount.overrun;
178 
179                                 /* Mask by termios, leave Rx'd byte */
180                         data &= port->read_status_mask | 0xff;
181 
182                         if (data & RxBreak)
183                                 flag = TTY_BREAK;
184                         else if (data & RxParityError)
185                                 flag = TTY_PARITY;
186                         else if (data & RxFramingError)
187                                 flag = TTY_FRAME;
188                 }
189 
190                 if (uart_handle_sysrq_char (port, (unsigned char) data, regs))
191                         continue;
192 
193                 if ((data & port->ignore_status_mask) == 0) {
194                         tty_insert_flip_char(tty, data, flag);
195                 }
196                 if ((data & RxOverrunError)
197                     && tty->flip.count < TTY_FLIPBUF_SIZE) {
198                         /*
199                          * Overrun is special, since it's reported
200                          * immediately, and doesn't affect the current
201                          * character
202                          */
203                         tty_insert_flip_char(tty, 0, TTY_OVERRUN);
204                 }
205         }
206         tty_flip_buffer_push (tty);
207         return;
208 }
209 
210 static void lh7a40xuart_tx_chars (struct uart_port* port)
211 {
212         struct circ_buf* xmit = &port->info->xmit;
213         int cbTxMax = port->fifosize;
214 
215         if (port->x_char) {
216                 UR (port, UART_R_DATA) = port->x_char;
217                 ++port->icount.tx;
218                 port->x_char = 0;
219                 return;
220         }
221         if (uart_circ_empty (xmit) || uart_tx_stopped (port)) {
222                 lh7a40xuart_stop_tx (port, 0);
223                 return;
224         }
225 
226         /* Unlike the AMBA UART, the lh7a40x UART does not guarantee
227            that at least half of the FIFO is empty.  Instead, we check
228            status for every character.  Using the AMBA method causes
229            the transmitter to drop characters. */
230 
231         do {
232                 UR (port, UART_R_DATA) = xmit->buf[xmit->tail];
233                 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
234                 ++port->icount.tx;
235                 if (uart_circ_empty(xmit))
236                         break;
237         } while (!(UR (port, UART_R_STATUS) & nTxRdy)
238                  && cbTxMax--);
239 
240         if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS)
241                 uart_write_wakeup (port);
242 
243         if (uart_circ_empty (xmit))
244                 lh7a40xuart_stop_tx (port, 0);
245 }
246 
247 static void lh7a40xuart_modem_status (struct uart_port* port)
248 {
249         unsigned int status = UR (port, UART_R_STATUS);
250         unsigned int delta
251                 = status ^ ((struct uart_port_lh7a40x*) port)->statusPrev;
252 
253         BIT_SET (port, UART_R_RAWISR, MSEOI); /* Clear modem status intr */
254 
255         if (!delta)             /* Only happens if we missed 2 transitions */
256                 return;
257 
258         ((struct uart_port_lh7a40x*) port)->statusPrev = status;
259 
260         if (delta & DCD)
261                 uart_handle_dcd_change (port, status & DCD);
262 
263         if (delta & DSR)
264                 ++port->icount.dsr;
265 
266         if (delta & CTS)
267                 uart_handle_cts_change (port, status & CTS);
268 
269         wake_up_interruptible (&port->info->delta_msr_wait);
270 }
271 
272 static irqreturn_t lh7a40xuart_int (int irq, void* dev_id,
273                                     struct pt_regs* regs)
274 {
275         struct uart_port* port = dev_id;
276         unsigned int cLoopLimit = ISR_LOOP_LIMIT;
277         unsigned int isr = UR (port, UART_R_ISR);
278 
279 
280         do {
281                 if (isr & (RxInt | RxTimeoutInt))
282 #ifdef SUPPORT_SYSRQ
283                         lh7a40xuart_rx_chars(port, regs);
284 #else
285                         lh7a40xuart_rx_chars(port);
286 #endif
287                 if (isr & ModemInt)
288                         lh7a40xuart_modem_status (port);
289                 if (isr & TxInt)
290                         lh7a40xuart_tx_chars (port);
291 
292                 if (--cLoopLimit == 0)
293                         break;
294 
295                 isr = UR (port, UART_R_ISR);
296         } while (isr & (RxInt | TxInt | RxTimeoutInt));
297 
298         return IRQ_HANDLED;
299 }
300 
301 static unsigned int lh7a40xuart_tx_empty (struct uart_port* port)
302 {
303         return (UR (port, UART_R_STATUS) & TxEmpty) ? TIOCSER_TEMT : 0;
304 }
305 
306 static unsigned int lh7a40xuart_get_mctrl (struct uart_port* port)
307 {
308         unsigned int result = 0;
309         unsigned int status = UR (port, UART_R_STATUS);
310 
311         if (status & DCD)
312                 result |= TIOCM_CAR;
313         if (status & DSR)
314                 result |= TIOCM_DSR;
315         if (status & CTS)
316                 result |= TIOCM_CTS;
317 
318         return result;
319 }
320 
321 static void lh7a40xuart_set_mctrl (struct uart_port* port, unsigned int mctrl)
322 {
323         /* None of the ports supports DTR. UART1 supports RTS through GPIO. */
324         /* Note, kernel appears to be setting DTR and RTS on console. */
325 
326         /* *** FIXME: this deserves more work.  There's some work in
327                tracing all of the IO pins. */
328 #if 0
329         if( port->mapbase == UART1_PHYS) {
330                 gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS);
331 
332                 if (mctrl & TIOCM_RTS)
333                         gpio->pbdr &= ~GPIOB_UART1_RTS;
334                 else
335                         gpio->pbdr |= GPIOB_UART1_RTS;
336         }
337 #endif
338 }
339 
340 static void lh7a40xuart_break_ctl (struct uart_port* port, int break_state)
341 {
342         unsigned long flags;
343 
344         spin_lock_irqsave(&port->lock, flags);
345         if (break_state == -1)
346                 BIT_SET (port, UART_R_FCON, BRK); /* Assert break */
347         else
348                 BIT_CLR (port, UART_R_FCON, BRK); /* Deassert break */
349         spin_unlock_irqrestore(&port->lock, flags);
350 }
351 
352 static int lh7a40xuart_startup (struct uart_port* port)
353 {
354         int retval;
355 
356         retval = request_irq (port->irq, lh7a40xuart_int, 0,
357                               "serial_lh7a40x", port);
358         if (retval)
359                 return retval;
360 
361                                 /* Initial modem control-line settings */
362         ((struct uart_port_lh7a40x*) port)->statusPrev
363                 = UR (port, UART_R_STATUS);
364 
365         /* There is presently no configuration option to enable IR.
366            Thus, we always disable it. */
367 
368         BIT_SET (port, UART_R_CON, UARTEN | SIRDIS);
369         BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt);
370 
371         return 0;
372 }
373 
374 static void lh7a40xuart_shutdown (struct uart_port* port)
375 {
376         free_irq (port->irq, port);
377         BIT_CLR (port, UART_R_FCON, BRK | FEN);
378         BIT_CLR (port, UART_R_CON, UARTEN);
379 }
380 
381 static void lh7a40xuart_set_termios (struct uart_port* port,
382                                      struct termios* termios,
383                                      struct termios* old)
384 {
385         unsigned int con;
386         unsigned int inten;
387         unsigned int fcon;
388         unsigned long flags;
389         unsigned int baud;
390         unsigned int quot;
391 
392         baud = uart_get_baud_rate (port, termios, old, 8, port->uartclk/16);
393         quot = uart_get_divisor (port, baud); /* -1 performed elsewhere */
394 
395         switch (termios->c_cflag & CSIZE) {
396         case CS5:
397                 fcon = WLEN_5;
398                 break;
399         case CS6:
400                 fcon = WLEN_6;
401                 break;
402         case CS7:
403                 fcon = WLEN_7;
404                 break;
405         case CS8:
406         default:
407                 fcon = WLEN_8;
408                 break;
409         }
410         if (termios->c_cflag & CSTOPB)
411                 fcon |= STP2;
412         if (termios->c_cflag & PARENB) {
413                 fcon |= PEN;
414                 if (!(termios->c_cflag & PARODD))
415                         fcon |= EPS;
416         }
417         if (port->fifosize > 1)
418                 fcon |= FEN;
419 
420         spin_lock_irqsave (&port->lock, flags);
421 
422         uart_update_timeout (port, termios->c_cflag, baud);
423 
424         port->read_status_mask = RxOverrunError;
425         if (termios->c_iflag & INPCK)
426                 port->read_status_mask |= RxFramingError | RxParityError;
427         if (termios->c_iflag & (BRKINT | PARMRK))
428                 port->read_status_mask |= RxBreak;
429 
430                 /* Figure mask for status we ignore */
431         port->ignore_status_mask = 0;
432         if (termios->c_iflag & IGNPAR)
433                 port->ignore_status_mask |= RxFramingError | RxParityError;
434         if (termios->c_iflag & IGNBRK) {
435                 port->ignore_status_mask |= RxBreak;
436                 /* Ignore overrun when ignorning parity */
437                 /* *** FIXME: is this in the right place? */
438                 if (termios->c_iflag & IGNPAR)
439                         port->ignore_status_mask |= RxOverrunError;
440         }
441 
442                 /* Ignore all receive errors when receive disabled */
443         if ((termios->c_cflag & CREAD) == 0)
444                 port->ignore_status_mask |= RxError;
445 
446         con   = UR (port, UART_R_CON);
447         inten = (UR (port, UART_R_INTEN) & ~ModemInt);
448 
449         if (UART_ENABLE_MS (port, termios->c_cflag))
450                 inten |= ModemInt;
451 
452         BIT_CLR (port, UART_R_CON, UARTEN);     /* Disable UART */
453         UR (port, UART_R_INTEN) = 0;            /* Disable interrupts */
454         UR (port, UART_R_BRCON) = quot - 1;     /* Set baud rate divisor */
455         UR (port, UART_R_FCON)  = fcon;         /* Set FIFO and frame ctrl */
456         UR (port, UART_R_INTEN) = inten;        /* Enable interrupts */
457         UR (port, UART_R_CON)   = con;          /* Restore UART mode */
458 
459         spin_unlock_irqrestore(&port->lock, flags);
460 }
461 
462 static const char* lh7a40xuart_type (struct uart_port* port)
463 {
464         return port->type == PORT_LH7A40X ? "LH7A40X" : NULL;
465 }
466 
467 static void lh7a40xuart_release_port (struct uart_port* port)
468 {
469         release_mem_region (port->mapbase, UART_REG_SIZE);
470 }
471 
472 static int lh7a40xuart_request_port (struct uart_port* port)
473 {
474         return request_mem_region (port->mapbase, UART_REG_SIZE,
475                                    "serial_lh7a40x") != NULL
476                 ? 0 : -EBUSY;
477 }
478 
479 static void lh7a40xuart_config_port (struct uart_port* port, int flags)
480 {
481         if (flags & UART_CONFIG_TYPE) {
482                 port->type = PORT_LH7A40X;
483                 lh7a40xuart_request_port (port);
484         }
485 }
486 
487 static int lh7a40xuart_verify_port (struct uart_port* port,
488                                     struct serial_struct* ser)
489 {
490         int ret = 0;
491 
492         if (ser->type != PORT_UNKNOWN && ser->type != PORT_LH7A40X)
493                 ret = -EINVAL;
494         if (ser->irq < 0 || ser->irq >= NR_IRQS)
495                 ret = -EINVAL;
496         if (ser->baud_base < 9600) /* *** FIXME: is this true? */
497                 ret = -EINVAL;
498         return ret;
499 }
500 
501 static struct uart_ops lh7a40x_uart_ops = {
502         .tx_empty       = lh7a40xuart_tx_empty,
503         .set_mctrl      = lh7a40xuart_set_mctrl,
504         .get_mctrl      = lh7a40xuart_get_mctrl,
505         .stop_tx        = lh7a40xuart_stop_tx,
506         .start_tx       = lh7a40xuart_start_tx,
507         .stop_rx        = lh7a40xuart_stop_rx,
508         .enable_ms      = lh7a40xuart_enable_ms,
509         .break_ctl      = lh7a40xuart_break_ctl,
510         .startup        = lh7a40xuart_startup,
511         .shutdown       = lh7a40xuart_shutdown,
512         .set_termios    = lh7a40xuart_set_termios,
513         .type           = lh7a40xuart_type,
514         .release_port   = lh7a40xuart_release_port,
515         .request_port   = lh7a40xuart_request_port,
516         .config_port    = lh7a40xuart_config_port,
517         .verify_port    = lh7a40xuart_verify_port,
518 };
519 
520 static struct uart_port_lh7a40x lh7a40x_ports[DEV_NR] = {
521         {
522                 .port = {
523                         .membase        = (void*) io_p2v (UART1_PHYS),
524                         .mapbase        = UART1_PHYS,
525                         .iotype         = SERIAL_IO_MEM,
526                         .irq            = IRQ_UART1INTR,
527                         .uartclk        = 14745600/2,
528                         .fifosize       = 16,
529                         .ops            = &lh7a40x_uart_ops,
530                         .flags          = ASYNC_BOOT_AUTOCONF,
531                         .line           = 0,
532                 },
533         },
534         {
535                 .port = {
536                         .membase        = (void*) io_p2v (UART2_PHYS),
537                         .mapbase        = UART2_PHYS,
538                         .iotype         = SERIAL_IO_MEM,
539                         .irq            = IRQ_UART2INTR,
540                         .uartclk        = 14745600/2,
541                         .fifosize       = 16,
542                         .ops            = &lh7a40x_uart_ops,
543                         .flags          = ASYNC_BOOT_AUTOCONF,
544                         .line           = 1,
545                 },
546         },
547         {
548                 .port = {
549                         .membase        = (void*) io_p2v (UART3_PHYS),
550                         .mapbase        = UART3_PHYS,
551                         .iotype         = SERIAL_IO_MEM,
552                         .irq            = IRQ_UART3INTR,
553                         .uartclk        = 14745600/2,
554                         .fifosize       = 16,
555                         .ops            = &lh7a40x_uart_ops,
556                         .flags          = ASYNC_BOOT_AUTOCONF,
557                         .line           = 2,
558                 },
559         },
560 };
561 
562 #ifndef CONFIG_SERIAL_LH7A40X_CONSOLE
563 # define LH7A40X_CONSOLE NULL
564 #else
565 # define LH7A40X_CONSOLE &lh7a40x_console
566 
567 
568 static void lh7a40xuart_console_write (struct console* co,
569                                        const char* s,
570                                        unsigned int count)
571 {
572         struct uart_port* port = &lh7a40x_ports[co->index].port;
573         unsigned int con = UR (port, UART_R_CON);
574         unsigned int inten = UR (port, UART_R_INTEN);
575 
576 
577         UR (port, UART_R_INTEN) = 0;            /* Disable all interrupts */
578         BIT_SET (port, UART_R_CON, UARTEN | SIRDIS); /* Enable UART */
579 
580         for (; count-- > 0; ++s) {
581                 while (UR (port, UART_R_STATUS) & nTxRdy)
582                         ;
583                 UR (port, UART_R_DATA) = *s;
584                 if (*s == '\n') {
585                         while ((UR (port, UART_R_STATUS) & TxBusy))
586                                 ;
587                         UR (port, UART_R_DATA) = '\r';
588                 }
589         }
590 
591                                 /* Wait until all characters are sent */
592         while (UR (port, UART_R_STATUS) & TxBusy)
593                 ;
594 
595                                 /* Restore control and interrupt mask */
596         UR (port, UART_R_CON) = con;
597         UR (port, UART_R_INTEN) = inten;
598 }
599 
600 static void __init lh7a40xuart_console_get_options (struct uart_port* port,
601                                                     int* baud,
602                                                     int* parity,
603                                                     int* bits)
604 {
605         if (UR (port, UART_R_CON) & UARTEN) {
606                 unsigned int fcon = UR (port, UART_R_FCON);
607                 unsigned int quot = UR (port, UART_R_BRCON) + 1;
608 
609                 switch (fcon & (PEN | EPS)) {
610                 default:        *parity = 'n'; break;
611                 case PEN:       *parity = 'o'; break;
612                 case PEN | EPS: *parity = 'e'; break;
613                 }
614 
615                 switch (fcon & WLEN) {
616                 default:
617                 case WLEN_8: *bits = 8; break;
618                 case WLEN_7: *bits = 7; break;
619                 case WLEN_6: *bits = 6; break;
620                 case WLEN_5: *bits = 5; break;
621                 }
622 
623                 *baud = port->uartclk/(16*quot);
624         }
625 }
626 
627 static int __init lh7a40xuart_console_setup (struct console* co, char* options)
628 {
629         struct uart_port* port;
630         int baud = 38400;
631         int bits = 8;
632         int parity = 'n';
633         int flow = 'n';
634 
635         if (co->index >= DEV_NR) /* Bounds check on device number */
636                 co->index = 0;
637         port = &lh7a40x_ports[co->index].port;
638 
639         if (options)
640                 uart_parse_options (options, &baud, &parity, &bits, &flow);
641         else
642                 lh7a40xuart_console_get_options (port, &baud, &parity, &bits);
643 
644         return uart_set_options (port, co, baud, parity, bits, flow);
645 }
646 
647 extern struct uart_driver lh7a40x_reg;
648 static struct console lh7a40x_console = {
649         .name           = "ttyAM",
650         .write          = lh7a40xuart_console_write,
651         .device         = uart_console_device,
652         .setup          = lh7a40xuart_console_setup,
653         .flags          = CON_PRINTBUFFER,
654         .index          = -1,
655         .data           = &lh7a40x_reg,
656 };
657 
658 static int __init lh7a40xuart_console_init(void)
659 {
660         register_console (&lh7a40x_console);
661         return 0;
662 }
663 
664 console_initcall (lh7a40xuart_console_init);
665 
666 #endif
667 
668 static struct uart_driver lh7a40x_reg = {
669         .owner                  = THIS_MODULE,
670         .driver_name            = "ttyAM",
671         .dev_name               = "ttyAM",
672         .major                  = DEV_MAJOR,
673         .minor                  = DEV_MINOR,
674         .nr                     = DEV_NR,
675         .cons                   = LH7A40X_CONSOLE,
676 };
677 
678 static int __init lh7a40xuart_init(void)
679 {
680         int ret;
681 
682         printk (KERN_INFO "serial: LH7A40X serial driver\n");
683 
684         ret = uart_register_driver (&lh7a40x_reg);
685 
686         if (ret == 0) {
687                 int i;
688 
689                 for (i = 0; i < DEV_NR; i++)
690                         uart_add_one_port (&lh7a40x_reg,
691                                            &lh7a40x_ports[i].port);
692         }
693         return ret;
694 }
695 
696 static void __exit lh7a40xuart_exit(void)
697 {
698         int i;
699 
700         for (i = 0; i < DEV_NR; i++)
701                 uart_remove_one_port (&lh7a40x_reg, &lh7a40x_ports[i].port);
702 
703         uart_unregister_driver (&lh7a40x_reg);
704 }
705 
706 module_init (lh7a40xuart_init);
707 module_exit (lh7a40xuart_exit);
708 
709 MODULE_AUTHOR ("Marc Singer");
710 MODULE_DESCRIPTION ("Sharp LH7A40X serial port driver");
711 MODULE_LICENSE ("GPL");
712 
  This page was automatically generated by the LXR engine.