finally move buildroot-ng to trunk
[openwrt.git] / target / linux / sibyte-2.6 / patches / 000-DUART.patch
1 diff -Nur linux-2.6.17/drivers/char/Kconfig linux-2.6.17-owrt/drivers/char/Kconfig
2 --- linux-2.6.17/drivers/char/Kconfig   2006-06-18 03:49:35.000000000 +0200
3 +++ linux-2.6.17-owrt/drivers/char/Kconfig      2006-06-18 12:41:36.000000000 +0200
4 @@ -340,6 +340,14 @@
5           To compile this driver as a module, choose M here: the
6           module will be called istallion.
7  
8 +config SIBYTE_SB1250_DUART
9 +       bool "Support for BCM1xxx onchip DUART"
10 +       depends on MIPS && SIBYTE_SB1xxx_SOC=y
11 +
12 +config SIBYTE_SB1250_DUART_CONSOLE
13 +       bool "Console on BCM1xxx DUART"
14 +       depends on SIBYTE_SB1250_DUART
15 +
16  config AU1000_UART
17         bool "Enable Au1000 UART Support"
18         depends on SERIAL_NONSTANDARD && MIPS
19 diff -Nur linux-2.6.17/drivers/char/Makefile linux-2.6.17-owrt/drivers/char/Makefile
20 --- linux-2.6.17/drivers/char/Makefile  2006-06-18 03:49:35.000000000 +0200
21 +++ linux-2.6.17-owrt/drivers/char/Makefile     2006-06-18 12:42:57.000000000 +0200
22 @@ -31,6 +31,7 @@
23  obj-$(CONFIG_A2232)            += ser_a2232.o generic_serial.o
24  obj-$(CONFIG_ATARI_DSP56K)     += dsp56k.o
25  obj-$(CONFIG_MOXA_SMARTIO)     += mxser.o
26 +obj-$(CONFIG_SIBYTE_SB1250_DUART) += sb1250_duart.o
27  obj-$(CONFIG_COMPUTONE)                += ip2/
28  obj-$(CONFIG_RISCOM8)          += riscom8.o
29  obj-$(CONFIG_ISI)              += isicom.o
30 diff -Nur linux-2.6.17/drivers/char/sb1250_duart.c linux-2.6.17-owrt/drivers/char/sb1250_duart.c
31 --- linux-2.6.17/drivers/char/sb1250_duart.c    1970-01-01 01:00:00.000000000 +0100
32 +++ linux-2.6.17-owrt/drivers/char/sb1250_duart.c       2006-06-18 12:41:36.000000000 +0200
33 @@ -0,0 +1,911 @@
34 +/*
35 + * Copyright (C) 2000,2001,2002,2003,2004 Broadcom Corporation
36 + *
37 + * This program is free software; you can redistribute it and/or
38 + * modify it under the terms of the GNU General Public License
39 + * as published by the Free Software Foundation; either version 2
40 + * of the License, or (at your option) any later version.
41 + *
42 + * This program is distributed in the hope that it will be useful,
43 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
44 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
45 + * GNU General Public License for more details.
46 + * 
47 + * You should have received a copy of the GNU General Public License
48 + * along with this program; if not, write to the Free Software
49 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
50 + */
51 +
52 +/* 
53 + * Driver support for the on-chip sb1250 dual-channel serial port,
54 + * running in asynchronous mode.  Also, support for doing a serial console
55 + * on one of those ports 
56 + */
57 +#include <linux/config.h>
58 +#include <linux/types.h>
59 +#include <linux/kernel.h>
60 +#include <linux/serial.h>
61 +#include <linux/interrupt.h>
62 +#include <linux/module.h>
63 +#include <linux/console.h>
64 +#include <linux/kdev_t.h>
65 +#include <linux/major.h>
66 +#include <linux/termios.h>
67 +#include <linux/spinlock.h>
68 +#include <linux/irq.h>
69 +#include <linux/errno.h>
70 +#include <linux/tty.h>
71 +#include <linux/sched.h>
72 +#include <linux/tty_flip.h>
73 +#include <linux/timer.h>
74 +#include <linux/init.h>
75 +#include <linux/mm.h>
76 +#include <asm/delay.h>
77 +#include <asm/io.h>
78 +#include <asm/uaccess.h>
79 +#include <asm/sibyte/swarm.h>
80 +#include <asm/sibyte/sb1250.h>
81 +#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
82 +#include <asm/sibyte/bcm1480_regs.h>
83 +#include <asm/sibyte/bcm1480_int.h>
84 +#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
85 +#include <asm/sibyte/sb1250_regs.h>
86 +#include <asm/sibyte/sb1250_int.h>
87 +#else
88 +#error invalid SiByte UART configuation
89 +#endif
90 +#include <asm/sibyte/sb1250_uart.h>
91 +#include <asm/war.h>
92 +
93 +#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
94 +#define UNIT_CHANREG(n,reg)    A_BCM1480_DUART_CHANREG((n),(reg))
95 +#define UNIT_IMRREG(n)         A_BCM1480_DUART_IMRREG(n)
96 +#define UNIT_INT(n)            (K_BCM1480_INT_UART_0 + (n))
97 +#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
98 +#define UNIT_CHANREG(n,reg)    A_DUART_CHANREG((n),(reg))
99 +#define UNIT_IMRREG(n)         A_DUART_IMRREG(n)
100 +#define UNIT_INT(n)            (K_INT_UART_0 + (n))
101 +#else
102 +#error invalid SiByte UART configuation
103 +#endif
104 +
105 +/* Toggle spewing of debugging output */
106 +#undef DEBUG
107 +
108 +#define DEFAULT_CFLAGS          (CS8 | B115200)
109 +
110 +#define TX_INTEN          1
111 +#define DUART_INITIALIZED 2
112 +
113 +#define DUART_MAX_LINE 4
114 +char sb1250_duart_present[DUART_MAX_LINE];
115 +EXPORT_SYMBOL(sb1250_duart_present);
116 +
117 +/*
118 + * Still not sure what the termios structures set up here are for, 
119 + *  but we have to supply pointers to them to register the tty driver
120 + */
121 +static struct tty_driver *sb1250_duart_driver; //, sb1250_duart_callout_driver;
122 +
123 +/*
124 + * This lock protects both the open flags for all the uart states as 
125 + * well as the reference count for the module
126 + */
127 +static DEFINE_SPINLOCK(open_lock);
128 +
129 +typedef struct { 
130 +       unsigned char       outp_buf[SERIAL_XMIT_SIZE];
131 +       unsigned int        outp_head;
132 +       unsigned int        outp_tail;
133 +       unsigned int        outp_count;
134 +       spinlock_t          outp_lock;
135 +       unsigned int        open;
136 +       unsigned int        line;
137 +       unsigned int        last_cflags;
138 +       unsigned long       flags;
139 +       struct tty_struct   *tty;
140 +       /* CSR addresses */
141 +       volatile u32        *status;
142 +       volatile u32        *imr;
143 +       volatile u32        *tx_hold;
144 +       volatile u32        *rx_hold;
145 +       volatile u32        *mode_1;
146 +       volatile u32        *mode_2;
147 +       volatile u32        *clk_sel;
148 +       volatile u32        *cmd;
149 +} uart_state_t;
150 +
151 +static uart_state_t uart_states[DUART_MAX_LINE];
152 +
153 +/*
154 + * Inline functions local to this module 
155 + */
156 +
157 +/*
158 + * In bug 1956, we get glitches that can mess up uart registers.  This
159 + * "write-mode-1 after any register access" is the accepted
160 + * workaround.
161 + */
162 +#if SIBYTE_1956_WAR
163 +static unsigned int last_mode1[DUART_MAX_LINE];
164 +#endif
165 +
166 +static inline u32 READ_SERCSR(volatile u32 *addr, int line)
167 +{
168 +       u32 val = csr_in32(addr);
169 +#if SIBYTE_1956_WAR
170 +       csr_out32(last_mode1[line], uart_states[line].mode_1);
171 +#endif
172 +       return val;
173 +}
174 +
175 +static inline void WRITE_SERCSR(u32 val, volatile u32 *addr, int line)
176 +{
177 +       csr_out32(val, addr);
178 +#if SIBYTE_1956_WAR
179 +       csr_out32(last_mode1[line], uart_states[line].mode_1);
180 +#endif
181 +}
182 +
183 +static void init_duart_port(uart_state_t *port, int line)
184 +{
185 +       if (!(port->flags & DUART_INITIALIZED)) {
186 +               port->line = line;
187 +               port->status = IOADDR(UNIT_CHANREG(line, R_DUART_STATUS));
188 +               port->imr = IOADDR(UNIT_IMRREG(line));
189 +               port->tx_hold = IOADDR(UNIT_CHANREG(line, R_DUART_TX_HOLD));
190 +               port->rx_hold = IOADDR(UNIT_CHANREG(line, R_DUART_RX_HOLD));
191 +               port->mode_1 = IOADDR(UNIT_CHANREG(line, R_DUART_MODE_REG_1));
192 +               port->mode_2 = IOADDR(UNIT_CHANREG(line, R_DUART_MODE_REG_2));
193 +               port->clk_sel = IOADDR(UNIT_CHANREG(line, R_DUART_CLK_SEL));
194 +               port->cmd = IOADDR(UNIT_CHANREG(line, R_DUART_CMD));
195 +               port->flags |= DUART_INITIALIZED;
196 +       }
197 +}
198 +
199 +/*
200 + * Mask out the passed interrupt lines at the duart level.  This should be
201 + * called while holding the associated outp_lock.
202 + */
203 +static inline void duart_mask_ints(unsigned int line, unsigned int mask)
204 +{
205 +       uart_state_t *port = uart_states + line;
206 +       u64 tmp = READ_SERCSR(port->imr, line);
207 +       WRITE_SERCSR(tmp & ~mask, port->imr, line);
208 +}
209 +
210 +       
211 +/* Unmask the passed interrupt lines at the duart level */
212 +static inline void duart_unmask_ints(unsigned int line, unsigned int mask)
213 +{
214 +       uart_state_t *port = uart_states + line;
215 +       u64 tmp = READ_SERCSR(port->imr, line);
216 +       WRITE_SERCSR(tmp | mask, port->imr, line);
217 +}
218 +
219 +static inline void transmit_char_pio(uart_state_t *us)
220 +{
221 +       struct tty_struct *tty = us->tty;
222 +       int blocked = 0;
223 +
224 +       if (spin_trylock(&us->outp_lock)) {
225 +               for (;;) {
226 +                       if (!(READ_SERCSR(us->status, us->line) & M_DUART_TX_RDY))
227 +                               break;
228 +                       if (us->outp_count <= 0 || tty->stopped || tty->hw_stopped) {
229 +                               break;
230 +                       } else {
231 +                               WRITE_SERCSR(us->outp_buf[us->outp_head],
232 +                                            us->tx_hold, us->line);
233 +                               us->outp_head = (us->outp_head + 1) & (SERIAL_XMIT_SIZE-1);
234 +                               if (--us->outp_count <= 0)
235 +                                       break;
236 +                       }
237 +                       udelay(10);
238 +               }
239 +               spin_unlock(&us->outp_lock);
240 +       } else {
241 +               blocked = 1;
242 +       }
243 +
244 +       if (!us->outp_count || tty->stopped ||
245 +           tty->hw_stopped || blocked) {
246 +               us->flags &= ~TX_INTEN;
247 +               duart_mask_ints(us->line, M_DUART_IMR_TX);
248 +       }
249 +
250 +       if (us->open &&
251 +           (us->outp_count < (SERIAL_XMIT_SIZE/2))) {
252 +               /*
253 +                * We told the discipline at one point that we had no
254 +                * space, so it went to sleep.  Wake it up when we hit
255 +                * half empty
256 +                */
257 +               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
258 +                   tty->ldisc.write_wakeup)
259 +                       tty->ldisc.write_wakeup(tty);
260 +               wake_up_interruptible(&tty->write_wait);
261 +       }
262 +}
263 +
264 +/* 
265 + * Generic interrupt handler for both channels.  dev_id is a pointer
266 + * to the proper uart_states structure, so from that we can derive 
267 + * which port interrupted 
268 + */
269 +
270 +static irqreturn_t duart_int(int irq, void *dev_id, struct pt_regs *regs)
271 +{
272 +       uart_state_t *us = (uart_state_t *)dev_id;
273 +       struct tty_struct *tty = us->tty;
274 +       unsigned int status = READ_SERCSR(us->status, us->line);
275 +
276 +       pr_debug("DUART INT\n");
277 +
278 +       if (status & M_DUART_RX_RDY) {
279 +               int counter = 2048;
280 +               unsigned int ch;
281 +
282 +               if (status & M_DUART_OVRUN_ERR)
283 +                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
284 +               if (status & M_DUART_PARITY_ERR) {
285 +                       printk("Parity error!\n");
286 +               } else if (status & M_DUART_FRM_ERR) {
287 +                       printk("Frame error!\n");
288 +               }
289 +
290 +               while (counter > 0) {
291 +                       if (!(READ_SERCSR(us->status, us->line) & M_DUART_RX_RDY))
292 +                               break;
293 +                       ch = READ_SERCSR(us->rx_hold, us->line);
294 +                       tty_insert_flip_char(tty, ch, 0);
295 +                       udelay(1);
296 +                       counter--;
297 +               }
298 +               tty_flip_buffer_push(tty);
299 +       }
300 +
301 +       if (status & M_DUART_TX_RDY) {
302 +               transmit_char_pio(us);
303 +       }
304 +
305 +       return IRQ_HANDLED;
306 +}
307 +
308 +/*
309 + *  Actual driver functions
310 + */
311 +
312 +/* Return the number of characters we can accomodate in a write at this instant */
313 +static int duart_write_room(struct tty_struct *tty)
314 +{
315 +       uart_state_t *us = (uart_state_t *) tty->driver_data;
316 +       int retval;
317 +
318 +       retval = SERIAL_XMIT_SIZE - us->outp_count;
319 +
320 +       pr_debug("duart_write_room called, returning %i\n", retval);
321 +
322 +       return retval;
323 +}
324 +
325 +/* memcpy the data from src to destination, but take extra care if the
326 +   data is coming from user space */
327 +static inline int copy_buf(char *dest, const char *src, int size, int from_user) 
328 +{
329 +       if (from_user) {
330 +               (void) copy_from_user(dest, src, size); 
331 +       } else {
332 +               memcpy(dest, src, size);
333 +       }
334 +       return size;
335 +}
336 +
337 +/*
338 + * Buffer up to count characters from buf to be written.  If we don't have
339 + * other characters buffered, enable the tx interrupt to start sending
340 + */
341 +static int duart_write(struct tty_struct *tty, const unsigned char *buf,
342 +                      int count)
343 +{
344 +       uart_state_t *us;
345 +       int c, t, total = 0;
346 +       unsigned long flags;
347 +
348 +       if (!tty) return 0;
349 +
350 +       us = tty->driver_data;
351 +       if (!us) return 0;
352 +
353 +       pr_debug("duart_write called for %i chars by %i (%s)\n", count, current->pid, current->comm);
354 +
355 +       spin_lock_irqsave(&us->outp_lock, flags);
356 +
357 +       for (;;) {
358 +               c = count;
359 +
360 +               t = SERIAL_XMIT_SIZE - us->outp_tail;
361 +               if (t < c) c = t;
362 +
363 +               t = SERIAL_XMIT_SIZE - 1 - us->outp_count;
364 +               if (t < c) c = t;
365 +
366 +               if (c <= 0) break;
367 +
368 +               memcpy(us->outp_buf + us->outp_tail, buf, c);
369 +
370 +               us->outp_count += c;
371 +               us->outp_tail = (us->outp_tail + c) & (SERIAL_XMIT_SIZE - 1);
372 +               buf += c;
373 +               count -= c;
374 +               total += c;
375 +       }
376 +
377 +       spin_unlock_irqrestore(&us->outp_lock, flags);
378 +
379 +       if (us->outp_count && !tty->stopped && 
380 +           !tty->hw_stopped && !(us->flags & TX_INTEN)) {
381 +               us->flags |= TX_INTEN;
382 +               duart_unmask_ints(us->line, M_DUART_IMR_TX);
383 +       }
384 +
385 +       return total;
386 +}
387 +
388 +
389 +/* Buffer one character to be written.  If there's not room for it, just drop
390 +   it on the floor.  This is used for echo, among other things */
391 +static void duart_put_char(struct tty_struct *tty, u_char ch)
392 +{
393 +       uart_state_t *us = (uart_state_t *) tty->driver_data;
394 +       unsigned long flags;
395 +
396 +       pr_debug("duart_put_char called.  Char is %x (%c)\n", (int)ch, ch);
397 +
398 +       spin_lock_irqsave(&us->outp_lock, flags);
399 +
400 +       if (us->outp_count == SERIAL_XMIT_SIZE) {
401 +               spin_unlock_irqrestore(&us->outp_lock, flags);
402 +               return;
403 +       }
404 +
405 +       us->outp_buf[us->outp_tail] = ch;
406 +       us->outp_tail = (us->outp_tail + 1) &(SERIAL_XMIT_SIZE-1);
407 +       us->outp_count++;
408 +
409 +       spin_unlock_irqrestore(&us->outp_lock, flags);
410 +}
411 +
412 +static void duart_flush_chars(struct tty_struct * tty)
413 +{
414 +       uart_state_t *port;
415 +
416 +       if (!tty) return;
417 +
418 +       port = tty->driver_data;
419 +
420 +       if (!port) return;
421 +
422 +       if (port->outp_count <= 0 || tty->stopped || tty->hw_stopped) {
423 +               return;
424 +       }
425 +
426 +       port->flags |= TX_INTEN;
427 +       duart_unmask_ints(port->line, M_DUART_IMR_TX);
428 +}
429 +
430 +/* Return the number of characters in the output buffer that have yet to be 
431 +   written */
432 +static int duart_chars_in_buffer(struct tty_struct *tty)
433 +{
434 +       uart_state_t *us = (uart_state_t *) tty->driver_data;
435 +       int retval;
436 +
437 +       retval = us->outp_count;
438 +
439 +       pr_debug("duart_chars_in_buffer returning %i\n", retval);
440 +
441 +       return retval;
442 +}
443 +
444 +/* Kill everything we haven't yet shoved into the FIFO.  Turn off the
445 +   transmit interrupt since we've nothing more to transmit */
446 +static void duart_flush_buffer(struct tty_struct *tty)
447 +{
448 +       uart_state_t *us = (uart_state_t *) tty->driver_data;
449 +       unsigned long flags;
450 +
451 +       pr_debug("duart_flush_buffer called\n");
452 +       spin_lock_irqsave(&us->outp_lock, flags);
453 +       us->outp_head = us->outp_tail = us->outp_count = 0;
454 +       spin_unlock_irqrestore(&us->outp_lock, flags);
455 +
456 +       wake_up_interruptible(&us->tty->write_wait);
457 +       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
458 +           tty->ldisc.write_wakeup)
459 +               tty->ldisc.write_wakeup(tty);
460 +}
461 +
462 +
463 +/* See sb1250 user manual for details on these registers */
464 +static inline void duart_set_cflag(unsigned int line, unsigned int cflag)
465 +{
466 +       unsigned int mode_reg1 = 0, mode_reg2 = 0;
467 +       unsigned int clk_divisor;
468 +       uart_state_t *port = uart_states + line;
469 +
470 +       switch (cflag & CSIZE) {
471 +       case CS7:
472 +               mode_reg1 |= V_DUART_BITS_PER_CHAR_7;
473 +               
474 +       default:
475 +               /* We don't handle CS5 or CS6...is there a way we're supposed to flag this? 
476 +                  right now we just force them to CS8 */
477 +               mode_reg1 |= 0x0;
478 +               break;
479 +       }
480 +       if (cflag & CSTOPB) {
481 +               mode_reg2 |= M_DUART_STOP_BIT_LEN_2;
482 +       }
483 +       if (!(cflag & PARENB)) {
484 +               mode_reg1 |= V_DUART_PARITY_MODE_NONE;
485 +       }
486 +       if (cflag & PARODD) {
487 +               mode_reg1 |= M_DUART_PARITY_TYPE_ODD;
488 +       }
489 +       
490 +       /* Formula for this is (5000000/baud)-1, but we saturate
491 +          at 12 bits, which means we can't actually do anything less
492 +          that 1200 baud */
493 +       switch (cflag & CBAUD) {
494 +       case B200:      
495 +       case B300:      
496 +       case B1200:     clk_divisor = 4095;             break;
497 +       case B1800:     clk_divisor = 2776;             break;
498 +       case B2400:     clk_divisor = 2082;             break;
499 +       case B4800:     clk_divisor = 1040;             break;
500 +       default:
501 +       case B9600:     clk_divisor = 519;              break;
502 +       case B19200:    clk_divisor = 259;              break;
503 +       case B38400:    clk_divisor = 129;              break;
504 +       case B57600:    clk_divisor = 85;               break;
505 +       case B115200:   clk_divisor = 42;               break;
506 +       }
507 +       WRITE_SERCSR(mode_reg1, port->mode_1, port->line);
508 +       WRITE_SERCSR(mode_reg2, port->mode_2, port->line);
509 +       WRITE_SERCSR(clk_divisor, port->clk_sel, port->line);
510 +       port->last_cflags = cflag;
511 +}
512 +
513 +
514 +/* Handle notification of a termios change.  */
515 +static void duart_set_termios(struct tty_struct *tty, struct termios *old)
516 +{
517 +       uart_state_t *us = (uart_state_t *) tty->driver_data;
518 +
519 +       pr_debug("duart_set_termios called by %i (%s)\n", current->pid, current->comm);
520 +       if (old && tty->termios->c_cflag == old->c_cflag)
521 +               return;
522 +       duart_set_cflag(us->line, tty->termios->c_cflag);
523 +}
524 +
525 +static int get_serial_info(uart_state_t *us, struct serial_struct * retinfo) {
526 +
527 +       struct serial_struct tmp;
528 +
529 +       memset(&tmp, 0, sizeof(tmp));
530 +
531 +       tmp.type=PORT_SB1250;
532 +       tmp.line=us->line;
533 +       tmp.port=UNIT_CHANREG(tmp.line,0);
534 +       tmp.irq=UNIT_INT(tmp.line);
535 +       tmp.xmit_fifo_size=16; /* fixed by hw */
536 +       tmp.baud_base=5000000;
537 +       tmp.io_type=SERIAL_IO_MEM;
538 +
539 +       if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
540 +               return -EFAULT;
541 +
542 +       return 0;
543 +}
544 +
545 +static int duart_ioctl(struct tty_struct *tty, struct file * file,
546 +                      unsigned int cmd, unsigned long arg)
547 +{
548 +       uart_state_t *us = (uart_state_t *) tty->driver_data;
549 +
550 +/*     if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
551 +       return -ENODEV;*/
552 +       switch (cmd) {
553 +       case TIOCMGET:
554 +               printk("Ignoring TIOCMGET\n");
555 +               break;
556 +       case TIOCMBIS:
557 +               printk("Ignoring TIOCMBIS\n");
558 +               break;
559 +       case TIOCMBIC:
560 +               printk("Ignoring TIOCMBIC\n");
561 +               break;
562 +       case TIOCMSET:
563 +               printk("Ignoring TIOCMSET\n");
564 +               break;
565 +       case TIOCGSERIAL:
566 +               return get_serial_info(us,(struct serial_struct *) arg);
567 +       case TIOCSSERIAL:
568 +               printk("Ignoring TIOCSSERIAL\n");
569 +               break;
570 +       case TIOCSERCONFIG:
571 +               printk("Ignoring TIOCSERCONFIG\n");
572 +               break;
573 +       case TIOCSERGETLSR: /* Get line status register */
574 +               printk("Ignoring TIOCSERGETLSR\n");
575 +               break;
576 +       case TIOCSERGSTRUCT:
577 +               printk("Ignoring TIOCSERGSTRUCT\n");
578 +               break;
579 +       case TIOCMIWAIT:
580 +               printk("Ignoring TIOCMIWAIT\n");
581 +               break;
582 +       case TIOCGICOUNT:
583 +               printk("Ignoring TIOCGICOUNT\n");
584 +               break;
585 +       case TIOCSERGWILD:
586 +               printk("Ignoring TIOCSERGWILD\n");
587 +               break;
588 +       case TIOCSERSWILD:
589 +               printk("Ignoring TIOCSERSWILD\n");
590 +               break;
591 +       default:
592 +               break;
593 +       }
594 +//     printk("Ignoring IOCTL %x from pid %i (%s)\n", cmd, current->pid, current->comm);
595 +       return -ENOIOCTLCMD;
596 +}
597 +
598 +/* XXXKW locking? */
599 +static void duart_start(struct tty_struct *tty)
600 +{
601 +       uart_state_t *us = (uart_state_t *) tty->driver_data;
602 +
603 +       pr_debug("duart_start called\n");
604 +
605 +       if (us->outp_count && !(us->flags & TX_INTEN)) {
606 +               us->flags |= TX_INTEN;
607 +               duart_unmask_ints(us->line, M_DUART_IMR_TX);
608 +       }
609 +}
610 +
611 +/* XXXKW locking? */
612 +static void duart_stop(struct tty_struct *tty)
613 +{
614 +       uart_state_t *us = (uart_state_t *) tty->driver_data;
615 +
616 +       pr_debug("duart_stop called\n");
617 +
618 +       if (us->outp_count && (us->flags & TX_INTEN)) {
619 +               us->flags &= ~TX_INTEN;
620 +               duart_mask_ints(us->line, M_DUART_IMR_TX);
621 +       }
622 +}
623 +
624 +/* Not sure on the semantics of this; are we supposed to wait until the stuff
625 +   already in the hardware FIFO drains, or are we supposed to wait until 
626 +   we've drained the output buffer, too?  I'm assuming the former, 'cause thats
627 +   what the other drivers seem to assume 
628 +*/
629 +
630 +static void duart_wait_until_sent(struct tty_struct *tty, int timeout)
631 +{
632 +       uart_state_t *us = (uart_state_t *) tty->driver_data;
633 +       unsigned long orig_jiffies;
634 +
635 +       orig_jiffies = jiffies;
636 +       pr_debug("duart_wait_until_sent(%d)+\n", timeout);
637 +       while (!(READ_SERCSR(us->status, us->line) & M_DUART_TX_EMT)) {
638 +               set_current_state(TASK_INTERRUPTIBLE);
639 +               schedule_timeout(1);
640 +               if (signal_pending(current))
641 +                       break;
642 +               if (timeout && time_after(jiffies, orig_jiffies + timeout))
643 +                       break;
644 +       }
645 +       pr_debug("duart_wait_until_sent()-\n");
646 +}
647 +
648 +/*
649 + * duart_hangup() --- called by tty_hangup() when a hangup is signaled.
650 + */
651 +static void duart_hangup(struct tty_struct *tty)
652 +{
653 +       uart_state_t *us = (uart_state_t *) tty->driver_data;
654 +
655 +       duart_flush_buffer(tty);
656 +       us->open = 0;
657 +       us->tty = 0;
658 +}
659 +
660 +/*
661 + * Open a tty line.  Note that this can be called multiple times, so ->open can
662 + * be >1.  Only set up the tty struct if this is a "new" open, e.g. ->open was
663 + * zero
664 + */
665 +static int duart_open(struct tty_struct *tty, struct file *filp)
666 +{
667 +       uart_state_t *us;
668 +       unsigned int line = tty->index;
669 +       unsigned long flags;
670 +
671 +       if ((line >= tty->driver->num) || !sb1250_duart_present[line])
672 +               return -ENODEV;
673 +
674 +       pr_debug("duart_open called by %i (%s), tty is %p, rw is %p, ww is %p\n",
675 +              current->pid, current->comm, tty, tty->read_wait,
676 +              tty->write_wait);
677 +
678 +       us = uart_states + line;
679 +       tty->driver_data = us;
680 +
681 +       spin_lock_irqsave(&open_lock, flags);
682 +       if (!us->open) {
683 +               us->tty = tty;
684 +               us->tty->termios->c_cflag = us->last_cflags;
685 +       }
686 +       us->open++;
687 +       us->flags &= ~TX_INTEN;
688 +       duart_unmask_ints(line, M_DUART_IMR_RX);
689 +       spin_unlock_irqrestore(&open_lock, flags);
690 +
691 +       return 0;
692 +}
693 +
694 +
695 +/*
696 + * Close a reference count out.  If reference count hits zero, null the
697 + * tty, kill the interrupts.  The tty_io driver is responsible for making
698 + * sure we've cleared out our internal buffers before calling close()
699 + */
700 +static void duart_close(struct tty_struct *tty, struct file *filp)
701 +{
702 +       uart_state_t *us = (uart_state_t *) tty->driver_data;
703 +       unsigned long flags;
704 +
705 +       pr_debug("duart_close called by %i (%s)\n", current->pid, current->comm);
706 +
707 +       if (!us || !us->open)
708 +               return;
709 +
710 +       spin_lock_irqsave(&open_lock, flags);
711 +       if (tty_hung_up_p(filp)) {
712 +               spin_unlock_irqrestore(&open_lock, flags);
713 +               return;
714 +       }
715 +
716 +       if (--us->open < 0) {
717 +               us->open = 0;
718 +               printk(KERN_ERR "duart: bad open count: %d\n", us->open);
719 +       }
720 +       if (us->open) {
721 +               spin_unlock_irqrestore(&open_lock, flags);
722 +               return;
723 +       }
724 +
725 +       spin_unlock_irqrestore(&open_lock, flags);
726 +
727 +       tty->closing = 1;
728 +
729 +       /* Stop accepting input */
730 +       duart_mask_ints(us->line, M_DUART_IMR_RX);
731 +       /* Wait for FIFO to drain */
732 +       while (!(READ_SERCSR(us->status, us->line) & M_DUART_TX_EMT))
733 +               ;
734 +
735 +       if (tty->driver->flush_buffer)
736 +               tty->driver->flush_buffer(tty);
737 +       if (tty->ldisc.flush_buffer)
738 +               tty->ldisc.flush_buffer(tty);
739 +       tty->closing = 0;
740 +}
741 +
742 +
743 +static struct tty_operations duart_ops = {
744 +        .open   = duart_open,
745 +        .close = duart_close,
746 +        .write = duart_write,
747 +        .put_char = duart_put_char,
748 +        .flush_chars = duart_flush_chars,
749 +        .write_room = duart_write_room,
750 +        .chars_in_buffer = duart_chars_in_buffer,
751 +        .flush_buffer = duart_flush_buffer,
752 +        .ioctl = duart_ioctl,
753 +//        .throttle = duart_throttle,
754 +//        .unthrottle = duart_unthrottle,
755 +        .set_termios = duart_set_termios,
756 +        .stop = duart_stop,
757 +        .start = duart_start,
758 +        .hangup = duart_hangup,
759 +       .wait_until_sent = duart_wait_until_sent,
760 +};
761 +
762 +/* Initialize the sb1250_duart_present array based on SOC type.  */
763 +static void __init sb1250_duart_init_present_lines(void)
764 +{
765 +       int i, max_lines;
766 +
767 +       /* Set the number of available units based on the SOC type.  */
768 +       switch (soc_type) {
769 +       case K_SYS_SOC_TYPE_BCM1x55:
770 +       case K_SYS_SOC_TYPE_BCM1x80:
771 +               max_lines = 4;
772 +               break;
773 +       default:
774 +               /* Assume at least two serial ports at the normal address.  */
775 +               max_lines = 2;
776 +               break;
777 +       }
778 +       if (max_lines > DUART_MAX_LINE)
779 +               max_lines = DUART_MAX_LINE;
780 +
781 +       for (i = 0; i < max_lines; i++)
782 +               sb1250_duart_present[i] = 1;
783 +}
784 +
785 +/* Set up the driver and register it, register the UART interrupts.  This
786 +   is called from tty_init, or as a part of the module init */
787 +static int __init sb1250_duart_init(void) 
788 +{
789 +       int i;
790 +
791 +       sb1250_duart_init_present_lines();
792 +
793 +       sb1250_duart_driver = alloc_tty_driver(DUART_MAX_LINE);
794 +       if (!sb1250_duart_driver)
795 +               return -ENOMEM;
796 +
797 +       sb1250_duart_driver->owner = THIS_MODULE;
798 +       sb1250_duart_driver->name = "duart";
799 +       sb1250_duart_driver->devfs_name = "duart/";
800 +       sb1250_duart_driver->major = TTY_MAJOR;
801 +       sb1250_duart_driver->minor_start = SB1250_DUART_MINOR_BASE;
802 +       sb1250_duart_driver->type            = TTY_DRIVER_TYPE_SERIAL;
803 +       sb1250_duart_driver->subtype         = SERIAL_TYPE_NORMAL;
804 +       sb1250_duart_driver->init_termios    = tty_std_termios;
805 +       sb1250_duart_driver->flags           = TTY_DRIVER_REAL_RAW;
806 +       tty_set_operations(sb1250_duart_driver, &duart_ops);
807 +
808 +       for (i=0; i<DUART_MAX_LINE; i++) {
809 +               uart_state_t *port = uart_states + i;
810 +
811 +               if (!sb1250_duart_present[i])
812 +                       continue;
813 +
814 +               init_duart_port(port, i);
815 +               spin_lock_init(&port->outp_lock);
816 +               duart_mask_ints(i, M_DUART_IMR_ALL);
817 +               if (request_irq(UNIT_INT(i), duart_int, 0, "uart", port)) {
818 +                       panic("Couldn't get uart0 interrupt line");
819 +               }
820 +               __raw_writeq(M_DUART_RX_EN|M_DUART_TX_EN,
821 +                            IOADDR(UNIT_CHANREG(i, R_DUART_CMD)));
822 +               duart_set_cflag(i, DEFAULT_CFLAGS);
823 +       }
824 +
825 +       /* Interrupts are now active, our ISR can be called. */
826 +
827 +       if (tty_register_driver(sb1250_duart_driver)) {
828 +               printk(KERN_ERR "Couldn't register sb1250 duart serial driver\n");
829 +               put_tty_driver(sb1250_duart_driver);
830 +               return 1;
831 +       }
832 +       return 0;
833 +}
834 +
835 +/* Unload the driver.  Unregister stuff, get ready to go away */
836 +static void __exit sb1250_duart_fini(void)
837 +{
838 +       unsigned long flags;
839 +       int i;
840 +
841 +       local_irq_save(flags);
842 +       tty_unregister_driver(sb1250_duart_driver);
843 +       put_tty_driver(sb1250_duart_driver);
844 +
845 +       for (i=0; i<DUART_MAX_LINE; i++) {
846 +               if (!sb1250_duart_present[i])
847 +                       continue;
848 +               free_irq(UNIT_INT(i), &uart_states[i]);
849 +               disable_irq(UNIT_INT(i));
850 +       }
851 +       local_irq_restore(flags);
852 +}
853 +
854 +module_init(sb1250_duart_init);
855 +module_exit(sb1250_duart_fini);
856 +MODULE_DESCRIPTION("SB1250 Duart serial driver");
857 +MODULE_AUTHOR("Broadcom Corp.");
858 +
859 +#ifdef CONFIG_SIBYTE_SB1250_DUART_CONSOLE
860 +
861 +/*
862 + * Serial console stuff.  Very basic, polling driver for doing serial
863 + * console output.  The console_sem is held by the caller, so we
864 + * shouldn't be interrupted for more console activity.
865 + * XXXKW What about getting interrupted by uart driver activity?
866 + */
867 +
868 +void serial_outc(unsigned char c, int line)
869 +{
870 +       uart_state_t *port = uart_states + line;
871 +       while (!(READ_SERCSR(port->status, line) & M_DUART_TX_RDY)) ;
872 +       WRITE_SERCSR(c, port->tx_hold, line);
873 +       while (!(READ_SERCSR(port->status, port->line) & M_DUART_TX_EMT)) ;
874 +}
875 +
876 +static void ser_console_write(struct console *cons, const char *s,
877 +       unsigned int count)
878 +{
879 +       int line = cons->index;
880 +       uart_state_t *port = uart_states + line;
881 +       u32 imr;
882 +
883 +       imr = READ_SERCSR(port->imr, line);
884 +       WRITE_SERCSR(0, port->imr, line);
885 +       while (count--) {
886 +               if (*s == '\n')
887 +                       serial_outc('\r', line);
888 +               serial_outc(*s++, line);
889 +       }
890 +       WRITE_SERCSR(imr, port->imr, line);
891 +}
892 +
893 +static struct tty_driver *ser_console_device(struct console *c, int *index)
894 +{
895 +       *index = c->index;
896 +       return sb1250_duart_driver;
897 +}
898 +
899 +static int ser_console_setup(struct console *cons, char *str)
900 +{
901 +       int i;
902 +
903 +       sb1250_duart_init_present_lines();
904 +
905 +       for (i=0; i<DUART_MAX_LINE; i++) {
906 +               uart_state_t *port = uart_states + i;
907 +
908 +               if (!sb1250_duart_present[i])
909 +                       continue;
910 +
911 +               init_duart_port(port, i);
912 +#if SIBYTE_1956_WAR
913 +               last_mode1[i] = V_DUART_PARITY_MODE_NONE|V_DUART_BITS_PER_CHAR_8;
914 +#endif
915 +               WRITE_SERCSR(V_DUART_PARITY_MODE_NONE|V_DUART_BITS_PER_CHAR_8,
916 +                            port->mode_1, i);
917 +               WRITE_SERCSR(M_DUART_STOP_BIT_LEN_1,
918 +                            port->mode_2, i);
919 +               WRITE_SERCSR(V_DUART_BAUD_RATE(115200),
920 +                            port->clk_sel, i);
921 +               WRITE_SERCSR(M_DUART_RX_EN|M_DUART_TX_EN,
922 +                            port->cmd, i);
923 +       }
924 +       return 0;
925 +}
926 +
927 +static struct console sb1250_ser_cons = {
928 +       .name           = "duart",
929 +       .write          = ser_console_write,
930 +       .device         = ser_console_device,
931 +       .setup          = ser_console_setup,
932 +       .flags          = CON_PRINTBUFFER,
933 +       .index          = -1,
934 +};
935 +
936 +static int __init sb1250_serial_console_init(void)
937 +{
938 +       register_console(&sb1250_ser_cons);
939 +       return 0;
940 +}
941 +
942 +console_initcall(sb1250_serial_console_init);
943 +
944 +#endif /* CONFIG_SIBYTE_SB1250_DUART_CONSOLE */
945 diff -Nur linux-2.6.17/include/linux/serial.h linux-2.6.17-owrt/include/linux/serial.h
946 --- linux-2.6.17/include/linux/serial.h 2006-06-18 03:49:35.000000000 +0200
947 +++ linux-2.6.17-owrt/include/linux/serial.h    2006-06-18 12:41:36.000000000 +0200
948 @@ -76,7 +76,8 @@
949  #define PORT_16654     11
950  #define PORT_16850     12
951  #define PORT_RSA       13      /* RSA-DV II/S card */
952 -#define PORT_MAX       13
953 +#define PORT_SB1250    14
954 +#define PORT_MAX       14
955  
956  #define SERIAL_IO_PORT 0
957  #define SERIAL_IO_HUB6 1