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