brcm63xx cleanups; add a watchdog driver, indent serial console driver, add support...
[openwrt.git] / target / linux / brcm63xx-2.6 / files / drivers / serial / bcm63xx_cons.c
1 /*
2 <:copyright-gpl 
3  Copyright 2002 Broadcom Corp. All Rights Reserved. 
4  
5  This program is free software; you can distribute it and/or modify it 
6  under the terms of the GNU General Public License (Version 2) as 
7  published by the Free Software Foundation. 
8  
9  This program is distributed in the hope it will be useful, but WITHOUT 
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
11  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License 
12  for more details. 
13  
14  You should have received a copy of the GNU General Public License along 
15  with this program; if not, write to the Free Software Foundation, Inc., 
16  59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 
17 :>
18 */
19
20 /* Description: Serial port driver for the BCM963XX. */
21
22 #define CARDNAME    "bcm963xx_serial driver"
23 #define VERSION     "2.0"
24 #define VER_STR     CARDNAME " v" VERSION "\n"
25
26
27 #include <linux/kernel.h>
28 #include <linux/module.h>
29 #include <linux/version.h>
30 #include <linux/init.h>
31 #include <linux/slab.h>
32 #include <linux/interrupt.h>
33 #include <linux/spinlock.h>
34
35 /* for definition of struct console */
36 #include <linux/console.h>
37 #include <linux/tty.h>
38 #include <linux/tty_flip.h>
39 #include <linux/serial.h>
40 #include <linux/serialP.h>
41 #include <asm/uaccess.h>
42
43 #include <bcmtypes.h>
44 #include <board.h>
45 #include <bcm_map_part.h>
46 #include <bcm_intr.h>
47 #include <6348_map_part.h>
48 #include <6348_intr.h>
49
50 static DEFINE_SPINLOCK(bcm963xx_serial_lock);
51
52 extern void _putc(char);
53 extern void _puts(const char *);
54
55 typedef struct bcm_serial {
56         volatile Uart *port;
57         int type;
58         int flags;
59         int irq;
60         int baud_base;
61         int blocked_open;
62         unsigned short close_delay;
63         unsigned short closing_wait;
64         unsigned short line;    /* port/line number */
65         unsigned short cflags;  /* line configuration flag */
66         unsigned short x_char;  /* xon/xoff character */
67         unsigned short read_status_mask;        /* mask for read condition */
68         unsigned short ignore_status_mask;      /* mask for ignore condition */
69         unsigned long event;    /* mask used in BH */
70         int xmit_head;          /* Position of the head */
71         int xmit_tail;          /* Position of the tail */
72         int xmit_cnt;           /* Count of the chars in the buffer */
73         int count;              /* indicates how many times it has been opened */
74         int magic;
75
76         struct async_icount icount;     /* keep track of things ... */
77         struct tty_struct *tty; /* tty associated */
78         struct termios normal_termios;
79
80         wait_queue_head_t open_wait;
81         wait_queue_head_t close_wait;
82
83         long session;           /* Session of opening process */
84         long pgrp;              /* pgrp of opening process */
85
86         unsigned char is_initialized;
87 } Context;
88
89
90 /*---------------------------------------------------------------------*/
91 /* Define bits in the Interrupt Enable register                        */
92 /*---------------------------------------------------------------------*/
93 /* Enable receive interrupt              */
94 #define RXINT   (RXFIFONE|RXOVFERR)
95
96 /* Enable transmit interrupt             */
97 #define TXINT    (TXFIFOEMT|TXUNDERR|TXOVFERR)
98
99 /* Enable receiver line status interrupt */
100 #define LSINT    (RXBRK|RXPARERR|RXFRAMERR)
101
102 #define BCM_NUM_UARTS                   1
103
104 #define BD_BCM63XX_TIMER_CLOCK_INPUT    (FPERIPH)
105
106
107 static struct bcm_serial multi[BCM_NUM_UARTS];
108 static struct bcm_serial *lines[BCM_NUM_UARTS];
109 static struct tty_driver *serial_driver;
110 static struct termios *serial_termios[BCM_NUM_UARTS];
111 static struct termios *serial_termios_locked[BCM_NUM_UARTS];
112
113
114 static void bcm_stop(struct tty_struct *tty);
115 static void bcm_start(struct tty_struct *tty);
116 static inline void receive_chars(struct bcm_serial *info);
117 static int startup(struct bcm_serial *info);
118 static void shutdown(struct bcm_serial *info);
119 static void change_speed(volatile Uart * pUart, tcflag_t cFlag);
120 static void bcm63xx_cons_flush_chars(struct tty_struct *tty);
121 static int bcm63xx_cons_write(struct tty_struct *tty,
122                               const unsigned char *buf, int count);
123 static int bcm63xx_cons_write_room(struct tty_struct *tty);
124 static int bcm_chars_in_buffer(struct tty_struct *tty);
125 static void bcm_flush_buffer(struct tty_struct *tty);
126 static void bcm_throttle(struct tty_struct *tty);
127 static void bcm_unthrottle(struct tty_struct *tty);
128 static void bcm_send_xchar(struct tty_struct *tty, char ch);
129 static int get_serial_info(struct bcm_serial *info,
130                            struct serial_struct *retinfo);
131 static int set_serial_info(struct bcm_serial *info,
132                            struct serial_struct *new_info);
133 static int get_lsr_info(struct bcm_serial *info, unsigned int *value);
134 static void send_break(struct bcm_serial *info, int duration);
135 static int bcm_ioctl(struct tty_struct *tty, struct file *file,
136                      unsigned int cmd, unsigned long arg);
137 static void bcm_set_termios(struct tty_struct *tty,
138                             struct termios *old_termios);
139 static void bcm63xx_cons_close(struct tty_struct *tty, struct file *filp);
140 static void bcm_hangup(struct tty_struct *tty);
141 static int block_til_ready(struct tty_struct *tty, struct file *filp,
142                            struct bcm_serial *info);
143 static int bcm63xx_cons_open(struct tty_struct *tty, struct file *filp);
144 static int __init bcm63xx_serialinit(void);
145
146
147 /*
148  * ------------------------------------------------------------
149  * rs_stop () and rs_start ()
150  *
151  * These routines are called before setting or resetting 
152  * tty->stopped. They enable or disable transmitter interrupts, 
153  * as necessary.
154  * ------------------------------------------------------------
155  */
156 static void bcm_stop(struct tty_struct *tty)
157 {
158 }
159
160 static void bcm_start(struct tty_struct *tty)
161 {
162         _puts(CARDNAME " Start\n");
163 }
164
165 /*
166  * ------------------------------------------------------------
167  * receive_char ()
168  *
169  * This routine deals with inputs from any lines.
170  * ------------------------------------------------------------
171  */
172 static inline void receive_chars(struct bcm_serial *info)
173 {
174         struct tty_struct *tty = 0;
175         struct async_icount *icount;
176         int ignore = 0;
177         unsigned short status, tmp;
178         UCHAR ch = 0;
179         while ((status = info->port->intStatus) & RXINT) {
180                 char flag_char = TTY_NORMAL;
181
182                 if (status & RXFIFONE)
183                         ch = info->port->Data;  // Read the character
184                 tty = info->tty;        /* now tty points to the proper dev */
185                 icount = &info->icount;
186                 if (!tty)
187                         break;
188                 if (!tty_buffer_request_room(tty, 1))
189                         break;
190                 icount->rx++;
191                 if (status & RXBRK) {
192                         flag_char = TTY_BREAK;
193                         icount->brk++;
194                 }
195                 // keep track of the statistics
196                 if (status & (RXFRAMERR | RXPARERR | RXOVFERR)) {
197                         if (status & RXPARERR)  /* parity error */
198                                 icount->parity++;
199                         else if (status & RXFRAMERR)    /* frame error */
200                                 icount->frame++;
201                         if (status & RXOVFERR) {
202                                 // Overflow. Reset the RX FIFO
203                                 info->port->fifoctl |= RSTRXFIFOS;
204                                 icount->overrun++;
205                         }
206                         // check to see if we should ignore the character
207                         // and mask off conditions that should be ignored
208                         if (status & info->ignore_status_mask) {
209                                 if (++ignore > 100)
210                                         break;
211                                 goto ignore_char;
212                         }
213                         // Mask off the error conditions we want to ignore
214                         tmp = status & info->read_status_mask;
215                         if (tmp & RXPARERR) {
216                                 flag_char = TTY_PARITY;
217                         } else if (tmp & RXFRAMERR) {
218                                 flag_char = TTY_FRAME;
219                         }
220                         if (tmp & RXOVFERR) {
221                                 tty_insert_flip_char(tty, ch, flag_char);
222                                 ch = 0;
223                                 flag_char = TTY_OVERRUN;
224                                 if (!tty_buffer_request_room(tty, 1))
225                                         break;
226                         }
227                 }
228                 tty_insert_flip_char(tty, ch, flag_char);
229         }
230       ignore_char:;
231         tty_flip_buffer_push(tty);
232         tty_schedule_flip(tty);
233
234 }
235
236
237 /*
238  * ------------------------------------------------------------
239  * bcm_interrupt ()
240  *
241  * this is the main interrupt routine for the chip.
242  * It deals with the multiple ports.
243  * ------------------------------------------------------------
244  */
245 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
246 static irqreturn_t bcm_interrupt(int irq, void *dev)
247 #else
248 static void bcm_interrupt(int irq, void *dev, struct pt_regs *regs)
249 #endif
250 {
251         struct bcm_serial *info = lines[0];
252         UINT16 intStat;
253
254         /* get pending interrupt flags from UART  */
255
256         /* Mask with only the serial interrupts that are enabled */
257         intStat = info->port->intStatus & info->port->intMask;
258         while (intStat) {
259                 if (intStat & RXINT)
260                         receive_chars(info);
261                 else if (intStat & TXINT)
262                         info->port->intStatus = TXINT;
263                 else            /* don't know what it was, so let's mask it */
264                         info->port->intMask &= ~intStat;
265
266                 intStat = info->port->intStatus & info->port->intMask;
267         }
268
269         // Clear the interrupt
270         enable_brcm_irq(INTERRUPT_ID_UART);
271 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
272         return IRQ_HANDLED;
273 #endif
274 }
275
276 /*
277  * -------------------------------------------------------------------
278  * startup ()
279  *
280  * various initialization tasks
281  * ------------------------------------------------------------------- 
282  */
283 static int startup(struct bcm_serial *info)
284 {
285         // Port is already started...
286         return 0;
287 }
288
289 /* 
290  * -------------------------------------------------------------------
291  * shutdown ()
292  *
293  * This routine will shutdown a serial port; interrupts are disabled, and
294  * DTR is dropped if the hangup on close termio flag is on.
295  * ------------------------------------------------------------------- 
296  */
297 static void shutdown(struct bcm_serial *info)
298 {
299         unsigned long flags;
300         if (!info->is_initialized)
301                 return;
302
303         spin_lock_irqsave(&bcm963xx_serial_lock, flags);
304
305         info->port->control &= ~(BRGEN | TXEN | RXEN);
306         if (info->tty)
307                 set_bit(TTY_IO_ERROR, &info->tty->flags);
308         info->is_initialized = 0;
309
310         spin_unlock_irqrestore(&bcm963xx_serial_lock, flags);
311 }
312
313 /* 
314  * -------------------------------------------------------------------
315  * change_speed ()
316  *
317  * Set the baud rate, character size, parity and stop bits.
318  * ------------------------------------------------------------------- 
319  */
320 static void change_speed(volatile Uart * pUart, tcflag_t cFlag)
321 {
322         unsigned long ulFlags, ulBaud, ulClockFreqHz, ulTmp;
323
324         spin_lock_irqsave(&bcm963xx_serial_lock, ulFlags);
325         switch (cFlag & (CBAUD | CBAUDEX)) {
326         case B115200:
327                 ulBaud = 115200;
328                 break;
329         case B57600:
330                 ulBaud = 57600;
331                 break;
332         case B38400:
333                 ulBaud = 38400;
334                 break;
335         case B19200:
336                 ulBaud = 19200;
337                 break;
338         case B9600:
339                 ulBaud = 9600;
340                 break;
341         case B4800:
342                 ulBaud = 4800;
343                 break;
344         case B2400:
345                 ulBaud = 2400;
346                 break;
347         case B1800:
348                 ulBaud = 1800;
349                 break;
350         case B1200:
351                 ulBaud = 1200;
352                 break;
353         case B600:
354                 ulBaud = 600;
355                 break;
356         case B300:
357                 ulBaud = 300;
358                 break;
359         case B200:
360                 ulBaud = 200;
361                 break;
362         case B150:
363                 ulBaud = 150;
364                 break;
365         case B134:
366                 ulBaud = 134;
367                 break;
368         case B110:
369                 ulBaud = 110;
370                 break;
371         case B75:
372                 ulBaud = 75;
373                 break;
374         case B50:
375                 ulBaud = 50;
376                 break;
377         default:
378                 ulBaud = 115200;
379                 break;
380         }
381
382         /* Calculate buad rate.  */
383         ulClockFreqHz = BD_BCM63XX_TIMER_CLOCK_INPUT;
384         ulTmp = (ulClockFreqHz / ulBaud) / 16;
385         if (ulTmp & 0x01)
386                 ulTmp /= 2;     /* Rounding up, so sub is already accounted for */
387         else
388                 ulTmp = (ulTmp / 2) - 1;        /* Rounding down so we must sub 1 */
389         pUart->baudword = ulTmp;
390
391         /* Set character size, stop bits and parity.  */
392         switch (cFlag & CSIZE) {
393         case CS5:
394                 ulTmp = BITS5SYM;       /* select transmit 5 bit data size */
395                 break;
396         case CS6:
397                 ulTmp = BITS6SYM;       /* select transmit 6 bit data size */
398                 break;
399         case CS7:
400                 ulTmp = BITS7SYM;       /* select transmit 7 bit data size */
401                 break;
402         default:
403                 ulTmp = BITS8SYM;       /* select transmit 8 bit data size */
404                 break;
405         }
406         if (cFlag & CSTOPB)
407                 ulTmp |= TWOSTOP;       /* select 2 stop bits */
408         else
409                 ulTmp |= ONESTOP;       /* select one stop bit */
410
411         /* Write these values into the config reg.  */
412         pUart->config = ulTmp;
413         pUart->control &=
414             ~(RXPARITYEN | TXPARITYEN | RXPARITYEVEN | TXPARITYEVEN);
415         switch (cFlag & (PARENB | PARODD)) {
416         case PARENB | PARODD:
417                 pUart->control |= RXPARITYEN | TXPARITYEN;
418                 break;
419         case PARENB:
420                 pUart->control |=
421                     RXPARITYEN | TXPARITYEN | RXPARITYEVEN | TXPARITYEVEN;
422                 break;
423         default:
424                 pUart->control |= 0;
425                 break;
426         }
427
428         /* Reset and flush uart */
429         pUart->fifoctl = RSTTXFIFOS | RSTRXFIFOS;
430         spin_unlock_irqrestore(&bcm963xx_serial_lock, ulFlags);
431 }
432
433
434 /* 
435  * -------------------------------------------------------------------
436  * bcm_flush_char ()
437  *
438  * Nothing to flush.  Polled I/O is used.
439  * ------------------------------------------------------------------- 
440  */
441 static void bcm63xx_cons_flush_chars(struct tty_struct *tty)
442 {
443 }
444
445
446 /* 
447  * -------------------------------------------------------------------
448  * bcm63xx_cons_write ()
449  *
450  * Main output routine using polled I/O.
451  * ------------------------------------------------------------------- 
452  */
453 static int bcm63xx_cons_write(struct tty_struct *tty,
454                               const unsigned char *buf, int count)
455 {
456         int c;
457
458         for (c = 0; c < count; c++)
459                 _putc(buf[c]);
460         return count;
461 }
462
463 /* 
464  * -------------------------------------------------------------------
465  * bcm63xx_cons_write_room ()
466  *
467  * Compute the amount of space available for writing.
468  * ------------------------------------------------------------------- 
469  */
470 static int bcm63xx_cons_write_room(struct tty_struct *tty)
471 {
472         /* Pick a number.  Any number.  Polled I/O is used. */
473         return 1024;
474 }
475
476 /* 
477  * -------------------------------------------------------------------
478  * bcm_chars_in_buffer ()
479  *
480  * compute the amount of char left to be transmitted
481  * ------------------------------------------------------------------- 
482  */
483 static int bcm_chars_in_buffer(struct tty_struct *tty)
484 {
485         return 0;
486 }
487
488 /* 
489  * -------------------------------------------------------------------
490  * bcm_flush_buffer ()
491  *
492  * Empty the output buffer
493  * ------------------------------------------------------------------- 
494  */
495 static void bcm_flush_buffer(struct tty_struct *tty)
496 {
497         tty_wakeup(tty);
498 }
499
500 /*
501  * ------------------------------------------------------------
502  * bcm_throttle () and bcm_unthrottle ()
503  * 
504  * This routine is called by the upper-layer tty layer to signal that
505  * incoming characters should be throttled (or not).
506  * ------------------------------------------------------------
507  */
508 static void bcm_throttle(struct tty_struct *tty)
509 {
510         struct bcm_serial *info = (struct bcm_serial *) tty->driver_data;
511         if (I_IXOFF(tty))
512                 info->x_char = STOP_CHAR(tty);
513 }
514
515 static void bcm_unthrottle(struct tty_struct *tty)
516 {
517         struct bcm_serial *info = (struct bcm_serial *) tty->driver_data;
518         if (I_IXOFF(tty)) {
519                 if (info->x_char)
520                         info->x_char = 0;
521                 else
522                         info->x_char = START_CHAR(tty);
523         }
524 }
525
526 static void bcm_send_xchar(struct tty_struct *tty, char ch)
527 {
528         struct bcm_serial *info = (struct bcm_serial *) tty->driver_data;
529         info->x_char = ch;
530         if (ch)
531                 bcm_start(info->tty);
532 }
533
534 /*
535  * ------------------------------------------------------------
536  * rs_ioctl () and friends
537  * ------------------------------------------------------------
538  */
539 static int get_serial_info(struct bcm_serial *info,
540                            struct serial_struct *retinfo)
541 {
542         struct serial_struct tmp;
543
544         if (!retinfo)
545                 return -EFAULT;
546
547         memset(&tmp, 0, sizeof(tmp));
548         tmp.type = info->type;
549         tmp.line = info->line;
550         tmp.port = (int) info->port;
551         tmp.irq = info->irq;
552         tmp.flags = 0;
553         tmp.baud_base = info->baud_base;
554         tmp.close_delay = info->close_delay;
555         tmp.closing_wait = info->closing_wait;
556
557         return copy_to_user(retinfo, &tmp, sizeof(*retinfo));
558 }
559
560 static int set_serial_info(struct bcm_serial *info,
561                            struct serial_struct *new_info)
562 {
563         struct serial_struct new_serial;
564         struct bcm_serial old_info;
565         int retval = 0;
566
567         if (!new_info)
568                 return -EFAULT;
569
570         copy_from_user(&new_serial, new_info, sizeof(new_serial));
571         old_info = *info;
572
573         if (!capable(CAP_SYS_ADMIN))
574                 return -EPERM;
575
576
577         if (info->count > 1)
578                 return -EBUSY;
579
580         /* OK, past this point, all the error checking has been done.
581          * At this point, we start making changes.....
582          */
583         info->baud_base = new_serial.baud_base;
584         info->type = new_serial.type;
585         info->close_delay = new_serial.close_delay;
586         info->closing_wait = new_serial.closing_wait;
587         retval = startup(info);
588         return retval;
589 }
590
591 /*
592  * get_lsr_info - get line status register info
593  *
594  * Purpose: Let user call ioctl() to get info when the UART physically
595  *          is emptied.  On bus types like RS485, the transmitter must
596  *          release the bus after transmitting. This must be done when
597  *          the transmit shift register is empty, not be done when the
598  *          transmit holding register is empty.  This functionality
599  *          allows an RS485 driver to be written in user space. 
600  */
601 static int get_lsr_info(struct bcm_serial *info, unsigned int *value)
602 {
603         return (0);
604 }
605
606 /*
607  * This routine sends a break character out the serial port.
608  */
609 static void send_break(struct bcm_serial *info, int duration)
610 {
611         unsigned long flags;
612
613         if (!info->port)
614                 return;
615
616         current->state = TASK_INTERRUPTIBLE;
617
618         /*save_flags (flags);
619            cli(); */
620         spin_lock_irqsave(&bcm963xx_serial_lock, flags);
621
622         info->port->control |= XMITBREAK;
623         schedule_timeout(duration);
624         info->port->control &= ~XMITBREAK;
625
626         spin_unlock_irqrestore(&bcm963xx_serial_lock, flags);
627         //restore_flags (flags);
628 }
629
630 static int bcm_ioctl(struct tty_struct *tty, struct file *file,
631                      unsigned int cmd, unsigned long arg)
632 {
633         int error;
634         struct bcm_serial *info = (struct bcm_serial *) tty->driver_data;
635         int retval;
636
637         if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
638             (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) &&
639             (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
640                 if (tty->flags & (1 << TTY_IO_ERROR))
641                         return -EIO;
642         }
643         switch (cmd) {
644
645         case TCSBRK:            /* SVID version: non-zero arg --> no break */
646                 retval = tty_check_change(tty);
647                 if (retval)
648                         return retval;
649                 tty_wait_until_sent(tty, 0);
650                 if (!arg)
651                         send_break(info, HZ / 4);       /* 1/4 second */
652                 return 0;
653
654         case TCSBRKP:           /* support for POSIX tcsendbreak() */
655                 retval = tty_check_change(tty);
656                 if (retval)
657                         return retval;
658                 tty_wait_until_sent(tty, 0);
659                 send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
660                 return 0;
661
662         case TIOCGSOFTCAR:
663                 error =
664                     access_ok(VERIFY_WRITE, (void *) arg, sizeof(long));
665                 if (!error)
666                         return -EFAULT;
667                 else {
668                         put_user(C_CLOCAL(tty) ? 1 : 0,
669                                  (unsigned long *) arg);
670                         return 0;
671                 }
672
673         case TIOCSSOFTCAR:
674                 error = get_user(arg, (unsigned long *) arg);
675                 if (error)
676                         return error;
677                 tty->termios->c_cflag =
678                     ((tty->termios->
679                       c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
680                 return 0;
681
682         case TIOCGSERIAL:
683                 error =
684                     access_ok(VERIFY_WRITE, (void *) arg,
685                               sizeof(struct serial_struct));
686                 if (!error)
687                         return -EFAULT;
688                 else
689                         return get_serial_info(info,
690                                                (struct serial_struct *)
691                                                arg);
692
693         case TIOCSSERIAL:
694                 return set_serial_info(info, (struct serial_struct *) arg);
695
696         case TIOCSERGETLSR:     /* Get line status register */
697                 error =
698                     access_ok(VERIFY_WRITE, (void *) arg,
699                               sizeof(unsigned int));
700                 if (!error)
701                         return -EFAULT;
702                 else
703                         return get_lsr_info(info, (unsigned int *) arg);
704
705         case TIOCSERGSTRUCT:
706                 error =
707                     access_ok(VERIFY_WRITE, (void *) arg,
708                               sizeof(struct bcm_serial));
709                 if (!error)
710                         return -EFAULT;
711                 else {
712                         copy_to_user((struct bcm_serial *) arg, info,
713                                      sizeof(struct bcm_serial));
714                         return 0;
715                 }
716
717         default:
718                 return -ENOIOCTLCMD;
719         }
720         return 0;
721 }
722
723 static void bcm_set_termios(struct tty_struct *tty,
724                             struct termios *old_termios)
725 {
726         struct bcm_serial *info = (struct bcm_serial *) tty->driver_data;
727
728         if (tty->termios->c_cflag != old_termios->c_cflag)
729                 change_speed(info->port, tty->termios->c_cflag);
730 }
731
732 /*
733  * ------------------------------------------------------------
734  * bcm63xx_cons_close()
735  * 
736  * This routine is called when the serial port gets closed.  First, we
737  * wait for the last remaining data to be sent.  Then, we turn off
738  * the transmit enable and receive enable flags.
739  * ------------------------------------------------------------
740  */
741 static void bcm63xx_cons_close(struct tty_struct *tty, struct file *filp)
742 {
743         struct bcm_serial *info = (struct bcm_serial *) tty->driver_data;
744         unsigned long flags;
745
746         if (!info)
747                 return;
748
749         /*save_flags (flags); 
750            cli(); */
751         spin_lock_irqsave(&bcm963xx_serial_lock, flags);
752
753         if (tty_hung_up_p(filp)) {
754                 spin_unlock_irqrestore(&bcm963xx_serial_lock, flags);
755                 //restore_flags (flags);
756                 return;
757         }
758
759         if ((tty->count == 1) && (info->count != 1)) {
760
761                 /* Uh, oh.  tty->count is 1, which means that the tty
762                  * structure will be freed.  Info->count should always
763                  * be one in these conditions.  If it's greater than
764                  * one, we've got real problems, since it means the
765                  * serial port won't be shutdown.
766                  */
767                 printk
768                     ("bcm63xx_cons_close: bad serial port count; tty->count is 1, "
769                      "info->count is %d\n", info->count);
770                 info->count = 1;
771         }
772
773         if (--info->count < 0) {
774                 printk("ds_close: bad serial port count for ttys%d: %d\n",
775                        info->line, info->count);
776                 info->count = 0;
777         }
778
779         if (info->count) {
780                 //restore_flags (flags);
781                 spin_unlock_irqrestore(&bcm963xx_serial_lock, flags);
782                 return;
783         }
784
785         /* Now we wait for the transmit buffer to clear; and we notify 
786          * the line discipline to only process XON/XOFF characters.
787          */
788         tty->closing = 1;
789
790         /* At this point we stop accepting input.  To do this, we
791          * disable the receive line status interrupts.
792          */
793         shutdown(info);
794 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
795         if (tty->driver->flush_buffer)
796                 tty->driver->flush_buffer(tty);
797 #else
798         if (tty->driver.flush_buffer)
799                 tty->driver.flush_buffer(tty);
800 #endif
801         if (tty->ldisc.flush_buffer)
802                 tty->ldisc.flush_buffer(tty);
803
804         tty->closing = 0;
805         info->event = 0;
806         info->tty = 0;
807         if (tty->ldisc.num != tty_ldisc_get(N_TTY)->num) {
808                 if (tty->ldisc.close)
809                         (tty->ldisc.close) (tty);
810                 tty->ldisc = *tty_ldisc_get(N_TTY);
811                 tty->termios->c_line = N_TTY;
812                 if (tty->ldisc.open)
813                         (tty->ldisc.open) (tty);
814         }
815         if (info->blocked_open) {
816                 if (info->close_delay) {
817                         current->state = TASK_INTERRUPTIBLE;
818                         schedule_timeout(info->close_delay);
819                 }
820                 wake_up_interruptible(&info->open_wait);
821         }
822         wake_up_interruptible(&info->close_wait);
823
824         //restore_flags (flags);
825         spin_unlock_irqrestore(&bcm963xx_serial_lock, flags);
826 }
827
828 /*
829  * bcm_hangup () --- called by tty_hangup() when a hangup is signaled.
830  */
831 static void bcm_hangup(struct tty_struct *tty)
832 {
833
834         struct bcm_serial *info = (struct bcm_serial *) tty->driver_data;
835
836         shutdown(info);
837         info->event = 0;
838         info->count = 0;
839         info->tty = 0;
840         wake_up_interruptible(&info->open_wait);
841 }
842
843 /*
844  * ------------------------------------------------------------
845  * rs_open() and friends
846  * ------------------------------------------------------------
847  */
848 static int block_til_ready(struct tty_struct *tty, struct file *filp,
849                            struct bcm_serial *info)
850 {
851         return 0;
852 }
853
854 /*
855  * This routine is called whenever a serial port is opened.  It
856  * enables interrupts for a serial port. It also performs the 
857  * serial-specific initialization for the tty structure.
858  */
859 static int bcm63xx_cons_open(struct tty_struct *tty, struct file *filp)
860 {
861         struct bcm_serial *info;
862         int retval, line;
863
864         // Make sure we're only opening on of the ports we support
865 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
866         line = MINOR(tty->driver->cdev.dev) - tty->driver->minor_start;
867 #else
868         line = MINOR(tty->device) - tty->driver.minor_start;
869 #endif
870
871         if ((line < 0) || (line >= BCM_NUM_UARTS))
872                 return -ENODEV;
873
874         info = lines[line];
875
876         tty->low_latency = 1;
877         info->port->intMask = 0;        /* Clear any pending interrupts */
878         info->port->intMask = RXINT;    /* Enable RX */
879
880         info->count++;
881         tty->driver_data = info;
882         info->tty = tty;
883         enable_brcm_irq(INTERRUPT_ID_UART);
884
885         // Start up serial port
886         retval = startup(info);
887         if (retval)
888                 return retval;
889
890         retval = block_til_ready(tty, filp, info);
891         if (retval)
892                 return retval;
893
894
895 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
896         info->pgrp = process_group(current);
897         info->session = current->signal->session;
898 #else
899         info->session = current->session;
900         info->pgrp = current->pgrp;
901 #endif
902
903         return 0;
904 }
905
906
907 static struct tty_operations rs_ops = {
908         .open = bcm63xx_cons_open,
909         .close = bcm63xx_cons_close,
910         .write = bcm63xx_cons_write,
911         .flush_chars = bcm63xx_cons_flush_chars,
912         .write_room = bcm63xx_cons_write_room,
913         .chars_in_buffer = bcm_chars_in_buffer,
914         .flush_buffer = bcm_flush_buffer,
915         .ioctl = bcm_ioctl,
916         .throttle = bcm_throttle,
917         .unthrottle = bcm_unthrottle,
918         .send_xchar = bcm_send_xchar,
919         .set_termios = bcm_set_termios,
920         .stop = bcm_stop,
921         .start = bcm_start,
922         .hangup = bcm_hangup,
923 };
924
925 /* --------------------------------------------------------------------------
926     Name: bcm63xx_serialinit
927  Purpose: Initialize our BCM63xx serial driver
928 -------------------------------------------------------------------------- */
929 static int __init bcm63xx_serialinit(void)
930 {
931         int i, flags;
932         struct bcm_serial *info;
933
934         // Print the driver version information
935         printk(VER_STR);
936         serial_driver = alloc_tty_driver(BCM_NUM_UARTS);
937         if (!serial_driver)
938                 return -ENOMEM;
939
940         serial_driver->owner = THIS_MODULE;
941         serial_driver->name = "ttyS";
942         serial_driver->major = TTY_MAJOR;
943         serial_driver->minor_start = 64;
944         serial_driver->num = 1;
945         serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
946         serial_driver->subtype = SERIAL_TYPE_NORMAL;
947         serial_driver->init_termios = tty_std_termios;
948         serial_driver->init_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
949         serial_driver->flags = TTY_DRIVER_REAL_RAW;
950
951         serial_driver->termios = serial_termios;
952         serial_driver->termios_locked = serial_termios_locked;
953
954         tty_set_operations(serial_driver, &rs_ops);
955
956         if (tty_register_driver(serial_driver))
957                 panic("Couldn't register serial driver\n");
958
959         //save_flags(flags); cli();
960         spin_lock_irqsave(&bcm963xx_serial_lock, flags);
961
962         for (i = 0; i < 1; i++) {
963                 info = &multi[i];
964                 lines[i] = info;
965                 info->magic = SERIAL_MAGIC;
966                 info->port = (Uart *) ((char *) UART_BASE + (i * 0x20));
967                 info->tty = 0;
968                 info->irq = (2 - i) + 8;
969                 info->line = i;
970                 info->close_delay = 50;
971                 info->closing_wait = 3000;
972                 info->x_char = 0;
973                 info->event = 0;
974                 info->count = 0;
975                 info->blocked_open = 0;
976                 info->normal_termios = serial_driver->init_termios;
977                 init_waitqueue_head(&info->open_wait);
978                 init_waitqueue_head(&info->close_wait);
979
980                 /* If we are pointing to address zero then punt - not correctly
981                  * set up in setup.c to handle this. 
982                  */
983                 if (!info->port)
984                         return 0;
985                 BcmHalMapInterrupt(bcm_interrupt, 0, INTERRUPT_ID_UART);
986         }
987
988         /* order matters here... the trick is that flags
989          * is updated... in request_irq - to immediatedly obliterate
990          * it is unwise. 
991          */
992         spin_unlock_irqrestore(&bcm963xx_serial_lock, flags);
993         return 0;
994 }
995
996 module_init(bcm63xx_serialinit);
997
998 /* --------------------------------------------------------------------------
999     Name: bcm_console_print
1000  Purpose: bcm_console_print is registered for printk.
1001           The console_lock must be held when we get here.
1002 -------------------------------------------------------------------------- */
1003 static void bcm_console_print(struct console *cons, const char *str,
1004                               unsigned int count)
1005 {
1006         unsigned int i;
1007         //_puts(str);
1008         for (i = 0; i < count; i++, str++) {
1009                 _putc(*str);
1010                 if (*str == 10) {
1011                         _putc(13);
1012                 }
1013         }
1014 }
1015
1016 static struct tty_driver *bcm_console_device(struct console *c, int *index)
1017 {
1018         *index = c->index;
1019         return serial_driver;
1020 }
1021
1022 static int __init bcm_console_setup(struct console *co, char *options)
1023 {
1024         return 0;
1025 }
1026
1027 static struct console bcm_sercons = {
1028         .name = "ttyS",
1029         .write = bcm_console_print,
1030         .device = bcm_console_device,
1031         .setup = bcm_console_setup,
1032         .flags = CON_PRINTBUFFER,
1033         .index = -1,
1034 };
1035
1036 static int __init bcm63xx_console_init(void)
1037 {
1038         register_console(&bcm_sercons);
1039         return 0;
1040 }
1041
1042 console_initcall(bcm63xx_console_init);