diff options
Diffstat (limited to 'drivers/sbus/char/sab82532.c')
-rw-r--r-- | drivers/sbus/char/sab82532.c | 522 |
1 files changed, 422 insertions, 100 deletions
diff --git a/drivers/sbus/char/sab82532.c b/drivers/sbus/char/sab82532.c index 2134d3d75..9eed1d7f6 100644 --- a/drivers/sbus/char/sab82532.c +++ b/drivers/sbus/char/sab82532.c @@ -1,4 +1,4 @@ -/* $Id: sab82532.c,v 1.4 1997/09/03 17:04:21 ecd Exp $ +/* $Id: sab82532.c,v 1.13 1997/12/30 09:37:49 ecd Exp $ * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -16,6 +16,7 @@ #include <linux/tty_flip.h> #include <linux/serial.h> #include <linux/serial_reg.h> +#include <linux/console.h> #include <linux/major.h> #include <linux/string.h> #include <linux/fcntl.h> @@ -40,6 +41,9 @@ static int sab82532_refcount; /* number of characters left in xmit buffer before we ask for more */ #define WAKEUP_CHARS 256 +#define SERIAL_PARANOIA_CHECK +#define SERIAL_DO_RESTART + /* Set of debugging defines */ #undef SERIAL_DEBUG_OPEN #undef SERIAL_DEBUG_INTR @@ -59,10 +63,23 @@ static struct tty_struct *sab82532_table[NR_PORTS]; static struct termios *sab82532_termios[NR_PORTS]; static struct termios *sab82532_termios_locked[NR_PORTS]; +#ifdef CONFIG_SERIAL_CONSOLE +extern int serial_console; +static struct console sab82532_console; +static int sab82532_console_init(void); +#endif + #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif +static char *sab82532_version[16] = { + "V1.0", "V2.0", "V3.2", "V(0x03)", + "V(0x04)", "V(0x05)", "V(0x06)", "V(0x07)", + "V(0x08)", "V(0x09)", "V(0x0a)", "V(0x0b)", + "V(0x0c)", "V(0x0d)", "V(0x0e)", "V(0x0f)" +}; + /* * tmp_buf is used as a temporary buffer by sab82532_write. We need to * lock it in case the copy_from_user blocks while swapping in a page, @@ -178,8 +195,10 @@ static void sab82532_start(struct tty_struct *tty) restore_flags(flags); } -static void batten_down_hatches(void) +static void batten_down_hatches(struct sab82532 *info) { + unsigned char saved_rfc; + /* If we are doing kadb, we call the debugger * else we just drop into the boot monitor. * Note that we must flush the user windows @@ -187,6 +206,16 @@ static void batten_down_hatches(void) */ printk("\n"); flush_user_windows(); + + /* + * Set FIFO to single character mode. + */ + saved_rfc = info->regs->r.rfc; + info->regs->rw.rfc &= ~(SAB82532_RFC_RFDF); + if (info->regs->r.star & SAB82532_STAR_CEC) + udelay(1); + info->regs->w.cmdr = SAB82532_CMDR_RRES; + #ifndef __sparc_v9__ if ((((unsigned long)linux_dbvec) >= DEBUG_FIRSTVADDR) && (((unsigned long)linux_dbvec) <= DEBUG_LASTVADDR)) @@ -194,6 +223,14 @@ static void batten_down_hatches(void) else #endif prom_cmdline(); + + /* + * Reset FIFO to character + status mode. + */ + info->regs->w.rfc = saved_rfc; + if (info->regs->r.star & SAB82532_STAR_CEC) + udelay(1); + info->regs->w.cmdr = SAB82532_CMDR_RRES; } /* @@ -242,16 +279,11 @@ static inline void receive_chars(struct sab82532 *info, count = info->recv_fifo_size; free_fifo++; } + if (stat->sreg.isr0 & SAB82532_ISR0_TCD) { count = info->regs->r.rbcl & (info->recv_fifo_size - 1); free_fifo++; } - if (stat->sreg.isr0 & SAB82532_ISR0_RFO) { -#if 1 - printk("sab82532: receive_chars: RFO"); -#endif - free_fifo++; - } /* Issue a FIFO read command in case we where idle. */ if (stat->sreg.isr0 & SAB82532_ISR0_TIME) { @@ -260,8 +292,15 @@ static inline void receive_chars(struct sab82532 *info, info->regs->w.cmdr = SAB82532_CMDR_RFRD; } + if (stat->sreg.isr0 & SAB82532_ISR0_RFO) { +#if 1 + printk("sab82532: receive_chars: RFO"); +#endif + free_fifo++; + } + /* Read the FIFO. */ - for (i = 0; i < (count << 1); i++) + for (i = 0; i < count; i++) buf[i] = info->regs->r.rfifo[i]; /* Issue Receive Message Complete command. */ @@ -271,6 +310,11 @@ static inline void receive_chars(struct sab82532 *info, info->regs->w.cmdr = SAB82532_CMDR_RMC; } + if (info->is_console) + wake_up(&keypress_wait); + if (!tty) + return; + for (i = 0; i < count; ) { if (tty->flip.count >= TTY_FLIPBUF_SIZE) { #if 1 @@ -312,6 +356,12 @@ static inline void transmit_chars(struct sab82532 *info, { int i; + if (!info->tty) { + info->interrupt_mask1 |= SAB82532_IMR1_XPR; + info->regs->w.imr1 = info->interrupt_mask1; + return; + } + if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tty->hw_stopped) { if (stat->sreg.isr1 & SAB82532_ISR1_ALLS) @@ -356,7 +406,7 @@ static inline void check_status(struct sab82532 *info, if (stat->sreg.isr1 & SAB82532_ISR1_BRK) { if (info->is_console) { - batten_down_hatches(); + batten_down_hatches(info); return; } if (tty->flip.count >= TTY_FLIPBUF_SIZE) { @@ -369,6 +419,9 @@ static inline void check_status(struct sab82532 *info, info->icount.brk++; } + if (!tty) + return; + if (stat->sreg.isr0 & SAB82532_ISR0_RFO) { if (tty->flip.count >= TTY_FLIPBUF_SIZE) { info->icount.buf_overrun++; @@ -380,9 +433,6 @@ static inline void check_status(struct sab82532 *info, info->icount.overrun++; } - if (info->is_console) - return; - check_modem: if (stat->sreg.isr0 & SAB82532_ISR0_CDSC) { info->dcd = (info->regs->r.vstr & SAB82532_VSTR_CD) ? 0 : 1; @@ -581,38 +631,18 @@ static void do_serial_hangup(void *private_) tty_hangup(tty); } - -static int startup(struct sab82532 *info) +static void +sab82532_init_line(struct sab82532 *info) { - unsigned long flags; - unsigned long page; unsigned char stat; - page = get_free_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - - save_flags(flags); cli(); - - if (info->flags & ASYNC_INITIALIZED) { - free_page(page); - goto errout; - } - - if (!info->regs) { - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); - free_page(page); - goto errout; - } - if (info->xmit_buf) - free_page(page); - else - info->xmit_buf = (unsigned char *)page; - -#ifdef SERIAL_DEBUG_OPEN - printk("starting up serial port %d...", info->line); -#endif + /* + * Wait for any commands or immediate characters + */ + if (info->regs->r.star & SAB82532_STAR_CEC) + udelay(1); + while (info->regs->r.star & SAB82532_STAR_TEC) + udelay(1); /* * Clear the FIFO buffers. @@ -662,7 +692,46 @@ static int startup(struct sab82532 *info) break; } info->regs->rw.ccr0 |= SAB82532_CCR0_PU; /* power-up */ - +} + +static int startup(struct sab82532 *info) +{ + unsigned long flags; + unsigned long page; + int retval = 0; + + page = get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + save_flags(flags); cli(); + + if (info->flags & ASYNC_INITIALIZED) { + free_page(page); + goto errout; + } + + if (!info->regs) { + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + free_page(page); + retval = -ENODEV; + goto errout; + } + if (info->xmit_buf) + free_page(page); + else + info->xmit_buf = (unsigned char *)page; + +#ifdef SERIAL_DEBUG_OPEN + printk("starting up serial port %d...", info->line); +#endif + + /* + * Initialize the Hardware + */ + sab82532_init_line(info); + /* * Finally, enable interrupts */ @@ -689,7 +758,7 @@ static int startup(struct sab82532 *info) errout: restore_flags(flags); - return -ENODEV; + return retval; } /* @@ -720,6 +789,22 @@ static void shutdown(struct sab82532 *info) info->xmit_buf = 0; } + if (info->is_console) { + info->interrupt_mask0 = SAB82532_IMR0_PERR | SAB82532_IMR0_FERR | + SAB82532_IMR0_PLLA | SAB82532_IMR0_CDSC; + info->regs->w.imr0 = info->interrupt_mask0; + info->interrupt_mask1 = SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS | + SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN | + SAB82532_IMR1_CSC | SAB82532_IMR1_XON | + SAB82532_IMR1_XPR; + info->regs->w.imr1 = info->interrupt_mask1; + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + info->flags &= ~ASYNC_INITIALIZED; + restore_flags(flags); + return; + } + /* Disable Interrupts */ info->interrupt_mask0 = 0xff; info->regs->w.imr0 = info->interrupt_mask0; @@ -758,7 +843,7 @@ static void change_speed(struct sab82532 *info) unsigned int ebrg; tcflag_t cflag; unsigned char dafo; - int i; + int i, bits; if (!info->tty || !info->tty->termios) return; @@ -766,19 +851,23 @@ static void change_speed(struct sab82532 *info) /* Byte size and parity */ switch (cflag & CSIZE) { - case CS5: dafo = SAB82532_DAFO_CHL5; break; - case CS6: dafo = SAB82532_DAFO_CHL6; break; - case CS7: dafo = SAB82532_DAFO_CHL7; break; - case CS8: dafo = SAB82532_DAFO_CHL8; break; + case CS5: dafo = SAB82532_DAFO_CHL5; bits = 7; break; + case CS6: dafo = SAB82532_DAFO_CHL6; bits = 8; break; + case CS7: dafo = SAB82532_DAFO_CHL7; bits = 9; break; + case CS8: dafo = SAB82532_DAFO_CHL8; bits = 10; break; /* Never happens, but GCC is too dumb to figure it out */ - default: dafo = SAB82532_DAFO_CHL5; break; + default: dafo = SAB82532_DAFO_CHL5; bits = 7; break; } - if (cflag & CSTOPB) + if (cflag & CSTOPB) { dafo |= SAB82532_DAFO_STOP; + bits++; + } - if (cflag & PARENB) + if (cflag & PARENB) { dafo |= SAB82532_DAFO_PARE; + bits++; + } if (cflag & PARODD) { #ifdef CMSPAR @@ -808,6 +897,12 @@ static void change_speed(struct sab82532 *info) ebrg = ebrg_table[i].n; ebrg |= (ebrg_table[i].m << 6); + if (ebrg_table[i].baud) + info->timeout = (info->xmit_fifo_size * HZ * bits) / ebrg_table[i].baud; + else + info->timeout = 0; + info->timeout += HZ / 50; /* Add .02 seconds of slop */ + /* CTS flow control flags */ if (cflag & CRTSCTS) info->flags |= ASYNC_CTS_FLOW; @@ -842,6 +937,10 @@ static void change_speed(struct sab82532 *info) SAB82532_ISR0_TIME; save_flags(flags); cli(); + if (info->regs->r.star & SAB82532_STAR_CEC) + udelay(1); + while (info->regs->r.star & SAB82532_STAR_TEC) + udelay(1); info->regs->w.dafo = dafo; info->regs->w.bgr = ebrg & 0xff; info->regs->rw.ccr2 &= ~(0xc0); @@ -980,7 +1079,7 @@ static int sab82532_chars_in_buffer(struct tty_struct *tty) static void sab82532_flush_buffer(struct tty_struct *tty) { struct sab82532 *info = (struct sab82532 *)tty->driver_data; - + if (serial_paranoia_check(info, tty->device, "sab82532_flush_buffer")) return; cli(); @@ -1003,7 +1102,7 @@ static void sab82532_send_xchar(struct tty_struct *tty, char ch) if (serial_paranoia_check(info, tty->device, "sab82532_send_xchar")) return; - if (info->regs->r.star & SAB82532_STAR_TEC) + while (info->regs->r.star & SAB82532_STAR_TEC) udelay(1); info->regs->w.tic = ch; } @@ -1114,7 +1213,7 @@ static int get_lsr_info(struct sab82532 * info, unsigned int *value) { unsigned int result; - result = info->all_sent ? TIOCSER_TEMT : 0; + result = (!info->xmit_buf && info->all_sent) ? TIOCSER_TEMT : 0; return put_user(result, value); } @@ -1496,7 +1595,9 @@ static void sab82532_close(struct tty_struct *tty, struct file * filp) */ info->interrupt_mask0 |= SAB82532_IMR0_TCD; info->regs->w.imr0 = info->interrupt_mask0; +#if 0 info->regs->rw.mode &= ~(SAB82532_MODE_RAC); +#endif if (info->flags & ASYNC_INITIALIZED) { /* * Before we drop DTR, make sure the UART transmitter @@ -1554,16 +1655,23 @@ static void sab82532_wait_until_sent(struct tty_struct *tty, int timeout) char_time = 1; if (timeout) char_time = MIN(char_time, timeout); -#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT +#ifdef SERIAL_DEBUG_WAIT_UNTIL_SENT printk("In sab82532_wait_until_sent(%d) check=%lu...", timeout, char_time); printk("jiff=%lu...", jiffies); #endif - - /* XXX: Implement this... */ - + while (info->xmit_cnt || !info->all_sent) { + current->state = TASK_INTERRUPTIBLE; + current->counter = 0; + current->timeout = jiffies + char_time; + schedule(); + if (signal_pending(current)) + break; + if (timeout && (orig_jiffies + timeout) < jiffies) + break; + } current->state = TASK_RUNNING; -#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); +#ifdef SERIAL_DEBUG_WAIT_UNTIL_SENT + printk("xmit_cnt = %d, alls = %d (jiff=%lu)...done\n", info->xmit_cnt, info->all_sent, jiffies); #endif } @@ -1573,10 +1681,13 @@ static void sab82532_wait_until_sent(struct tty_struct *tty, int timeout) static void sab82532_hangup(struct tty_struct *tty) { struct sab82532 * info = (struct sab82532 *)tty->driver_data; - + if (serial_paranoia_check(info, tty->device, "sab82532_hangup")) return; + if (info->is_console) + return; + sab82532_flush_buffer(tty); shutdown(info); info->event = 0; @@ -1754,7 +1865,6 @@ static int sab82532_open(struct tty_struct *tty, struct file * filp) return -ENODEV; } - info->count++; if (serial_paranoia_check(info, tty->device, "sab82532_open")) return -ENODEV; @@ -1762,6 +1872,8 @@ static int sab82532_open(struct tty_struct *tty, struct file * filp) printk("sab82532_open %s%d, count = %d\n", tty->driver.name, info->line, info->count); #endif + + info->count++; tty->driver_data = info; info->tty = tty; @@ -1774,7 +1886,22 @@ static int sab82532_open(struct tty_struct *tty, struct file * filp) else tmp_buf = (unsigned char *) page; } - + + /* + * If the port is in the middle of closing, bail out now. + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + return -EAGAIN; +#endif + } + /* * Start up serial port */ @@ -1801,6 +1928,14 @@ static int sab82532_open(struct tty_struct *tty, struct file * filp) change_speed(info); } +#ifdef CONFIG_SERIAL_CONSOLE + if (sab82532_console.cflag && sab82532_console.index == line) { + tty->termios->c_cflag = sab82532_console.cflag; + sab82532_console.cflag = 0; + change_speed(info); + } +#endif + info->session = current->session; info->pgrp = current->pgrp; @@ -1856,7 +1991,7 @@ int sab82532_read_proc(char *page, char **start, off_t off, int count, int i, len = 0; off_t begin = 0; - len += sprintf(page, "serinfo:1.0 driver:%s\n", "$Revision: 1.4 $"); + len += sprintf(page, "serinfo:1.0 driver:%s\n", "$Revision: 1.13 $"); for (i = 0; i < NR_PORTS && len < 4000; i++) { len += line_info(page + len, sab82532_table[i]); if (len+begin > off+count) @@ -1881,7 +2016,7 @@ done: * sab82532_init() is called at boot-time to initialize the serial driver. * --------------------------------------------------------------------- */ -__initfunc(static int get_sab82532(void)) +__initfunc(static int get_sab82532(unsigned long *memory_start)) { struct linux_ebus *ebus; struct linux_ebus_device *edev; @@ -1895,23 +2030,29 @@ __initfunc(static int get_sab82532(void)) if (!edev) return -ENODEV; - printk("%s: SAB82532 at 0x%lx IRQ %x\n", __FUNCTION__, - edev->base_address[0], edev->irqs[0]); - regs = edev->base_address[0]; offset = sizeof(union sab82532_async_regs); for (i = 0; i < 2; i++) { - sab = (struct sab82532 *)kmalloc(sizeof(struct sab82532), - GFP_KERNEL); - if (!sab) { - printk("sab82532: can't alloc sab struct\n"); - break; + if (memory_start) { + *memory_start = (*memory_start + 7) & ~(7); + sab = (struct sab82532 *)*memory_start; + *memory_start += sizeof(struct sab82532); + } else { + sab = (struct sab82532 *)kmalloc(sizeof(struct sab82532), + GFP_KERNEL); + if (!sab) { + printk("sab82532: can't alloc sab struct\n"); + break; + } } memset(sab, 0, sizeof(struct sab82532)); sab->regs = (union sab82532_async_regs *)(regs + offset); sab->irq = edev->irqs[0]; + sab->line = 1 - i; + sab->xmit_fifo_size = 32; + sab->recv_fifo_size = 32; if (check_region((unsigned long)sab->regs, sizeof(union sab82532_async_regs))) { @@ -1932,20 +2073,8 @@ __initfunc(static int get_sab82532(void)) return 0; } -/* Hooks for running a serial console. con_init() calls this if the - * console is run over one of the ttya/ttyb serial ports. - * 'chip' should be zero, as for now we only have one chip on board. - * 'line' is decoded as 0=ttya, 1=ttyb. - */ -void -sab82532_cons_hook(int chip, int out, int line) -{ - prom_printf("sab82532: serial console is not implemented, yet\n"); - prom_halt(); -} - -void -sab82532_kgdb_hook(int line) +__initfunc(static void +sab82532_kgdb_hook(int line)) { prom_printf("sab82532: kgdb support is not implemented, yet\n"); prom_halt(); @@ -1953,7 +2082,7 @@ sab82532_kgdb_hook(int line) __initfunc(static inline void show_serial_version(void)) { - char *revision = "$Revision: 1.4 $"; + char *revision = "$Revision: 1.13 $"; char *version, *p; version = strchr(revision, ' '); @@ -1971,7 +2100,7 @@ __initfunc(int sab82532_init(void)) int i; if (!sab82532_chain) - get_sab82532(); + get_sab82532(0); if (!sab82532_chain) return -ENODEV; @@ -2035,9 +2164,6 @@ __initfunc(int sab82532_init(void)) for (info = sab82532_chain, i = 0; info; info = info->next, i++) { info->magic = SERIAL_MAGIC; - info->line = i; - info->tty = 0; - info->count = 0; info->type = info->regs->r.vstr & 0x0f; info->regs->w.pcr = ~((1 << 1) | (1 << 2) | (1 << 4)); @@ -2053,14 +2179,11 @@ __initfunc(int sab82532_init(void)) info->regs->rw.mode |= SAB82532_MODE_FRTS; info->regs->rw.mode |= SAB82532_MODE_RTS; - info->xmit_fifo_size = 32; - info->recv_fifo_size = 32; info->custom_divisor = 16; info->close_delay = 5*HZ/10; info->closing_wait = 30*HZ; info->x_char = 0; info->event = 0; - info->count = 0; info->blocked_open = 0; info->tqueue.routine = do_softint; info->tqueue.data = info; @@ -2086,9 +2209,9 @@ __initfunc(int sab82532_init(void)) } } - printk(KERN_INFO "ttyS%02d at 0x%lx (irq = %x) is a %s\n", + printk(KERN_INFO "ttyS%02d at 0x%lx (irq = %x) is a SAB82532 %s\n", info->line, (unsigned long)info->regs, info->irq, - "SAB82532"); + sab82532_version[info->type]); } return 0; } @@ -2125,8 +2248,10 @@ __initfunc(int sab82532_probe(unsigned long *memory_start)) return -ENODEV; found: +#ifdef CONFIG_SERIAL_CONSOLE + sunserial_setinitfunc(memory_start, sab82532_console_init); +#endif sunserial_setinitfunc(memory_start, sab82532_init); - rs_ops.rs_cons_hook = sab82532_cons_hook; rs_ops.rs_kgdb_hook = sab82532_kgdb_hook; return 0; } @@ -2134,7 +2259,7 @@ found: #ifdef MODULE int init_module(void) { - if (get_sab82532()) + if (get_sab82532(0)) return -ENODEV; return sab82532_init(); @@ -2171,3 +2296,200 @@ void cleanup_module(void) } } #endif /* MODULE */ + +#ifdef CONFIG_SERIAL_CONSOLE + +static void +sab82532_console_putchar(struct sab82532 *info, char c) +{ + while (info->regs->r.star & SAB82532_STAR_TEC) + udelay(1); + info->regs->w.tic = c; +} + +static void +sab82532_console_write(struct console *con, const char *s, unsigned n) +{ + struct sab82532 *info; + int i; + + info = sab82532_chain + con->index; + + for (i = 0; i < n; i++) { + if (*s == '\n') + sab82532_console_putchar(info, '\r'); + sab82532_console_putchar(info, *s++); + } + while (info->regs->r.star & SAB82532_STAR_TEC) + udelay(1); +} + +static int +sab82532_console_wait_key(struct console *con) +{ + sleep_on(&keypress_wait); + return 0; +} + +static kdev_t +sab82532_console_device(struct console *con) +{ + return MKDEV(TTY_MAJOR, 64 + con->index); +} + +static int +sab82532_console_setup(struct console *con, char *options) +{ + struct sab82532 *info; + unsigned int ebrg; + tcflag_t cflag; + unsigned char dafo; + int i, bits; + unsigned long flags; + + info = sab82532_chain + con->index; + info->is_console = 1; + + /* + * Initialize the hardware + */ + sab82532_init_line(info); + + /* + * Finally, enable interrupts + */ + info->interrupt_mask0 = SAB82532_IMR0_PERR | SAB82532_IMR0_FERR | + SAB82532_IMR0_PLLA | SAB82532_IMR0_CDSC; + info->regs->w.imr0 = info->interrupt_mask0; + info->interrupt_mask1 = SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS | + SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN | + SAB82532_IMR1_CSC | SAB82532_IMR1_XON | + SAB82532_IMR1_XPR; + info->regs->w.imr1 = info->interrupt_mask1; + + printk("Console: ttyS%d (SAB82532)\n", info->line); + + sunserial_console_termios(con); + cflag = con->cflag; + + /* Byte size and parity */ + switch (cflag & CSIZE) { + case CS5: dafo = SAB82532_DAFO_CHL5; bits = 7; break; + case CS6: dafo = SAB82532_DAFO_CHL6; bits = 8; break; + case CS7: dafo = SAB82532_DAFO_CHL7; bits = 9; break; + case CS8: dafo = SAB82532_DAFO_CHL8; bits = 10; break; + /* Never happens, but GCC is too dumb to figure it out */ + default: dafo = SAB82532_DAFO_CHL5; bits = 7; break; + } + + if (cflag & CSTOPB) { + dafo |= SAB82532_DAFO_STOP; + bits++; + } + + if (cflag & PARENB) { + dafo |= SAB82532_DAFO_PARE; + bits++; + } + + if (cflag & PARODD) { +#ifdef CMSPAR + if (cflag & CMSPAR) + dafo |= SAB82532_DAFO_PAR_MARK; + else +#endif + dafo |= SAB82532_DAFO_PAR_ODD; + } else { +#ifdef CMSPAR + if (cflag & CMSPAR) + dafo |= SAB82532_DAFO_PAR_SPACE; + else +#endif + dafo |= SAB82532_DAFO_PAR_EVEN; + } + + /* Determine EBRG values based on baud rate */ + i = cflag & CBAUD; + if (i & CBAUDEX) { + i &= ~(CBAUDEX); + if ((i < 1) || ((i + 15) >= NR_EBRG_VALUES)) + info->tty->termios->c_cflag &= ~CBAUDEX; + else + i += 15; + } + ebrg = ebrg_table[i].n; + ebrg |= (ebrg_table[i].m << 6); + + if (ebrg_table[i].baud) + info->timeout = (info->xmit_fifo_size * HZ * bits) / ebrg_table[i].baud; + else + info->timeout = 0; + info->timeout += HZ / 50; /* Add .02 seconds of slop */ + + /* CTS flow control flags */ + if (cflag & CRTSCTS) + info->flags |= ASYNC_CTS_FLOW; + else + info->flags &= ~(ASYNC_CTS_FLOW); + + if (cflag & CLOCAL) + info->flags &= ~(ASYNC_CHECK_CD); + else + info->flags |= ASYNC_CHECK_CD; + + save_flags(flags); cli(); + if (info->regs->r.star & SAB82532_STAR_CEC) + udelay(1); + while (info->regs->r.star & SAB82532_STAR_TEC) + udelay(1); + info->regs->w.dafo = dafo; + info->regs->w.bgr = ebrg & 0xff; + info->regs->rw.ccr2 &= ~(0xc0); + info->regs->rw.ccr2 |= (ebrg >> 2) & 0xc0; + if (info->flags & ASYNC_CTS_FLOW) { + info->regs->rw.mode &= ~(SAB82532_MODE_RTS); + info->regs->rw.mode |= SAB82532_MODE_FRTS; + info->regs->rw.mode &= ~(SAB82532_MODE_FCTS); + } else { + info->regs->rw.mode |= SAB82532_MODE_RTS; + info->regs->rw.mode &= ~(SAB82532_MODE_FRTS); + info->regs->rw.mode |= SAB82532_MODE_FCTS; + } + info->regs->rw.mode |= SAB82532_MODE_RAC; + restore_flags(flags); + + return 0; +} + +static struct console sab82532_console = { + "ttyS", + sab82532_console_write, + NULL, + sab82532_console_device, + sab82532_console_wait_key, + NULL, + sab82532_console_setup, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + +__initfunc(int sab82532_console_init(void)) +{ + extern int con_is_present(void); + + if (con_is_present()) + return 0; + + if (!sab82532_chain) { + prom_printf("sab82532_console_setup: can't get SAB82532 chain"); + prom_halt(); + } + + sab82532_console.index = serial_console - 1; + register_console(&sab82532_console); + return 0; +} + +#endif /* CONFIG_SERIAL_CONSOLE */ |