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