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