X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Ftc%2Fzs.c;h=fc3197273663e93c48f975cded7c748727ad0370;hb=refs%2Fheads%2Fvserver;hp=7391ae6490294d548e3cc3d4efe05e39c93aabc6;hpb=9bf4aaab3e101692164d49b7ca357651eb691cb6;p=linux-2.6.git diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c index 7391ae649..fc3197273 100644 --- a/drivers/tc/zs.c +++ b/drivers/tc/zs.c @@ -6,7 +6,7 @@ * * DECstation changes * Copyright (C) 1998-2000 Harald Koerfgen - * Copyright (C) 2000,2001 Maciej W. Rozycki + * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Maciej W. Rozycki * * For the rest of the code the original Copyright applies: * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au) @@ -39,7 +39,6 @@ * is shared with DSRS(DTE) at pin 23. */ -#include #include #include #include @@ -55,7 +54,8 @@ #include #include #include -#ifdef CONFIG_SERIAL_CONSOLE +#include +#ifdef CONFIG_SERIAL_DEC_CONSOLE #include #endif @@ -63,20 +63,15 @@ #include #include #include -#include -#include -#include #include -#ifdef CONFIG_MACH_DECSTATION + #include +#include #include +#include +#include #include -#include -#endif -#ifdef CONFIG_BAGET_MIPS -#include -unsigned long system_base; -#endif + #ifdef CONFIG_KGDB #include #endif @@ -94,7 +89,7 @@ unsigned long system_base; #define NUM_SERIAL 2 /* Max number of ZS chips supported */ #define NUM_CHANNELS (NUM_SERIAL * 2) /* 2 channels per chip */ #define CHANNEL_A_NR (zs_parms->channel_a_offset > zs_parms->channel_b_offset) - /* Number of channel A in the chip */ + /* Number of channel A in the chip */ #define ZS_CHAN_IO_SIZE 8 #define ZS_CLOCK 7372800 /* Z8530 RTxC input clock rate */ @@ -105,7 +100,8 @@ struct zs_parms { unsigned long scc1; int channel_a_offset; int channel_b_offset; - int irq; + int irq0; + int irq1; int clock; }; @@ -113,24 +109,15 @@ static struct zs_parms *zs_parms; #ifdef CONFIG_MACH_DECSTATION static struct zs_parms ds_parms = { - scc0 : SCC0, - scc1 : SCC1, + scc0 : IOASIC_SCC0, + scc1 : IOASIC_SCC1, channel_a_offset : 1, channel_b_offset : 9, - irq : SERIAL, + irq0 : -1, + irq1 : -1, clock : ZS_CLOCK }; #endif -#ifdef CONFIG_BAGET_MIPS -static struct zs_parms baget_parms = { - scc0 : UNI_SCC0, - scc1 : UNI_SCC1, - channel_a_offset : 9, - channel_b_offset : 1, - irq : BAGET_SCC_IRQ, - clock : 14745000 -}; -#endif #ifdef CONFIG_MACH_DECSTATION #define DS_BUS_PRESENT (IOASIC) @@ -138,13 +125,9 @@ static struct zs_parms baget_parms = { #define DS_BUS_PRESENT 0 #endif -#ifdef CONFIG_BAGET_MIPS -#define BAGET_BUS_PRESENT (mips_machtype == MACH_BAGET202) -#else -#define BAGET_BUS_PRESENT 0 -#endif +#define BUS_PRESENT (DS_BUS_PRESENT) -#define BUS_PRESENT (DS_BUS_PRESENT || BAGET_BUS_PRESENT) +DEFINE_SPINLOCK(zs_lock); struct dec_zschannel zs_channels[NUM_CHANNELS]; struct dec_serial zs_soft[NUM_CHANNELS]; @@ -153,32 +136,30 @@ struct dec_serial *zs_chain; /* list of all channels */ struct tty_struct zs_ttys[NUM_CHANNELS]; -#ifdef CONFIG_SERIAL_CONSOLE +#ifdef CONFIG_SERIAL_DEC_CONSOLE static struct console sercons; #endif -#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) \ - && !defined(MODULE) +#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \ + !defined(MODULE) static unsigned long break_pressed; /* break, really ... */ #endif static unsigned char zs_init_regs[16] __initdata = { - 0, /* write 0 */ - 0, /* write 1 */ - 0xf0, /* write 2 */ - (Rx8), /* write 3 */ - (X16CLK | SB1), /* write 4 */ - (Tx8), /* write 5 */ - 0, 0, 0, /* write 6, 7, 8 */ - (VIS), /* write 9 */ - (NRZ), /* write 10 */ - (TCBR | RCBR), /* write 11 */ - 0, 0, /* BRG time constant, write 12 + 13 */ - (BRSRC | BRENABL), /* write 14 */ - 0 /* write 15 */ + 0, /* write 0 */ + 0, /* write 1 */ + 0, /* write 2 */ + 0, /* write 3 */ + (X16CLK), /* write 4 */ + 0, /* write 5 */ + 0, 0, 0, /* write 6, 7, 8 */ + (MIE | DLC | NV), /* write 9 */ + (NRZ), /* write 10 */ + (TCBR | RCBR), /* write 11 */ + 0, 0, /* BRG time constant, write 12 + 13 */ + (BRSRC | BRENABL), /* write 14 */ + 0 /* write 15 */ }; -DECLARE_TASK_QUEUE(tq_zs_serial); - static struct tty_driver *serial_driver; /* serial subtype definitions */ @@ -190,7 +171,6 @@ static struct tty_driver *serial_driver; /* * Debugging. */ -#undef SERIAL_DEBUG_INTR #undef SERIAL_DEBUG_OPEN #undef SERIAL_DEBUG_FLOW #undef SERIAL_DEBUG_THROTTLE @@ -205,28 +185,10 @@ static struct tty_driver *serial_driver; #define RS_STROBE_TIME 10 #define RS_ISR_PASS_LIMIT 256 -#define _INLINE_ inline - static void probe_sccs(void); static void change_speed(struct dec_serial *info); static void rs_wait_until_sent(struct tty_struct *tty, int timeout); -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - -/* - * tmp_buf is used as a temporary buffer by serial_write. We need to - * lock it in case the copy_from_user blocks while swapping in a page, - * and some other program tries to do a serial write at the same time. - * Since the lock will only come under contention when the system is - * swapping and available memory is low, it makes sense to share one - * buffer across all the serial ports, since it significantly saves - * memory if large numbers of serial ports are open. - */ -static unsigned char tmp_buf[4096]; /* This is cheating */ -static DECLARE_MUTEX(tmp_buf_sem); - static inline int serial_paranoia_check(struct dec_serial *info, char *name, const char *routine) { @@ -255,7 +217,7 @@ static int baud_table[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 0 }; -/* +/* * Reading and writing Z8530 registers. */ static inline unsigned char read_zsreg(struct dec_zschannel *channel, @@ -265,7 +227,7 @@ static inline unsigned char read_zsreg(struct dec_zschannel *channel, if (reg != 0) { *channel->control = reg & 0xf; - wbflush(); RECOVERY_DELAY; + fast_iob(); RECOVERY_DELAY; } retval = *channel->control; RECOVERY_DELAY; @@ -277,10 +239,10 @@ static inline void write_zsreg(struct dec_zschannel *channel, { if (reg != 0) { *channel->control = reg & 0xf; - wbflush(); RECOVERY_DELAY; + fast_iob(); RECOVERY_DELAY; } *channel->control = value; - wbflush(); RECOVERY_DELAY; + fast_iob(); RECOVERY_DELAY; return; } @@ -297,7 +259,7 @@ static inline void write_zsdata(struct dec_zschannel *channel, unsigned char value) { *channel->data = value; - wbflush(); RECOVERY_DELAY; + fast_iob(); RECOVERY_DELAY; return; } @@ -307,9 +269,9 @@ static inline void load_zsregs(struct dec_zschannel *channel, /* ZS_CLEARERR(channel); ZS_CLEARFIFO(channel); */ /* Load 'em up */ - write_zsreg(channel, R4, regs[R4]); write_zsreg(channel, R3, regs[R3] & ~RxENABLE); write_zsreg(channel, R5, regs[R5] & ~TxENAB); + write_zsreg(channel, R4, regs[R4]); write_zsreg(channel, R9, regs[R9]); write_zsreg(channel, R1, regs[R1]); write_zsreg(channel, R2, regs[R2]); @@ -329,8 +291,7 @@ static inline void zs_rtsdtr(struct dec_serial *info, int which, int set) { unsigned long flags; - - save_flags(flags); cli(); + spin_lock_irqsave(&zs_lock, flags); if (info->zs_channel != info->zs_chan_a) { if (set) { info->zs_chan_a->curregs[5] |= (which & (RTS | DTR)); @@ -339,7 +300,7 @@ static inline void zs_rtsdtr(struct dec_serial *info, int which, int set) } write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]); } - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); } /* Utility routines for the Zilog */ @@ -376,22 +337,17 @@ static inline void rs_recv_clear(struct dec_zschannel *zsc) * ----------------------------------------------------------------------- */ -static int tty_break; /* Set whenever BREAK condition is detected. */ - /* * This routine is used by the interrupt handler to schedule * processing in the software interrupt portion of the driver. */ -static _INLINE_ void rs_sched_event(struct dec_serial *info, - int event) +static void rs_sched_event(struct dec_serial *info, int event) { info->event |= 1 << event; - queue_task(&info->tqueue, &tq_zs_serial); - mark_bh(SERIAL_BH); + tasklet_schedule(&info->tlet); } -static _INLINE_ void receive_chars(struct dec_serial *info, - struct pt_regs *regs) +static void receive_chars(struct dec_serial *info) { struct tty_struct *tty = info->tty; unsigned char ch, stat, flag; @@ -401,23 +357,18 @@ static _INLINE_ void receive_chars(struct dec_serial *info, stat = read_zsreg(info->zs_channel, R1); ch = read_zsdata(info->zs_channel); - if (!tty && !info->hook && !info->hook->rx_char) + if (!tty && (!info->hook || !info->hook->rx_char)) continue; - if (tty_break) { - tty_break = 0; -#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE) - if (info->line == sercons.index) { - if (!break_pressed) { - break_pressed = jiffies; - goto ignore_char; - } - break_pressed = 0; - } -#endif + flag = TTY_NORMAL; + if (info->tty_break) { + info->tty_break = 0; flag = TTY_BREAK; if (info->flags & ZILOG_SAK) do_SAK(tty); + /* Ignore the null char got when BREAK is removed. */ + if (ch == 0) + continue; } else { if (stat & Rx_OVR) { flag = TTY_OVERRUN; @@ -425,20 +376,22 @@ static _INLINE_ void receive_chars(struct dec_serial *info, flag = TTY_FRAME; } else if (stat & PAR_ERR) { flag = TTY_PARITY; - } else - flag = 0; - if (flag) + } + if (flag != TTY_NORMAL) /* reset the error indication */ write_zsreg(info->zs_channel, R0, ERR_RES); } -#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE) +#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \ + !defined(MODULE) if (break_pressed && info->line == sercons.index) { - if (ch != 0 && - time_before(jiffies, break_pressed + HZ*5)) { - handle_sysrq(ch, regs, NULL); + /* Ignore the null char got when BREAK is removed. */ + if (ch == 0) + continue; + if (time_before(jiffies, break_pressed + HZ * 5)) { + handle_sysrq(ch, NULL); break_pressed = 0; - goto ignore_char; + continue; } break_pressed = 0; } @@ -448,22 +401,8 @@ static _INLINE_ void receive_chars(struct dec_serial *info, (*info->hook->rx_char)(ch, flag); return; } - - if (tty->flip.count >= TTY_FLIPBUF_SIZE) { - static int flip_buf_ovf; - ++flip_buf_ovf; - continue; - } - tty->flip.count++; - { - static int flip_max_cnt; - if (flip_max_cnt < tty->flip.count) - flip_max_cnt = tty->flip.count; - } - *tty->flip.flag_buf_ptr++ = flag; - *tty->flip.char_buf_ptr++ = ch; - ignore_char: + tty_insert_flip_char(tty, ch, flag); } if (tty) tty_flip_buffer_push(tty); @@ -498,25 +437,29 @@ static void transmit_chars(struct dec_serial *info) rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); } -static _INLINE_ void status_handle(struct dec_serial *info) +static void status_handle(struct dec_serial *info) { unsigned char stat; /* Get status from Read Register 0 */ stat = read_zsreg(info->zs_channel, R0); - if (stat & BRK_ABRT) { -#ifdef SERIAL_DEBUG_INTR - printk("handling break...."); + if ((stat & BRK_ABRT) && !(info->read_reg_zero & BRK_ABRT)) { +#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \ + !defined(MODULE) + if (info->line == sercons.index) { + if (!break_pressed) + break_pressed = jiffies; + } else #endif - tty_break = 1; + info->tty_break = 1; } if (info->zs_channel != info->zs_chan_a) { - /* FIXEM: Check for DCD transitions */ - if (((stat ^ info->read_reg_zero) & DCD) != 0 - && info->tty && !C_CLOCAL(info->tty)) { + /* Check for DCD transitions */ + if (info->tty && !C_CLOCAL(info->tty) && + ((stat ^ info->read_reg_zero) & DCD) != 0 ) { if (stat & DCD) { wake_up_interruptible(&info->open_wait); } else { @@ -547,9 +490,10 @@ static _INLINE_ void status_handle(struct dec_serial *info) /* * This is the serial driver's generic interrupt routine */ -void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t rs_interrupt(int irq, void *dev_id) { struct dec_serial *info = (struct dec_serial *) dev_id; + irqreturn_t status = IRQ_NONE; unsigned char zs_intreg; int shift; @@ -567,12 +511,14 @@ void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) shift = 0; /* Channel B */ for (;;) { - zs_intreg = read_zsreg(info->zs_chan_a, R3) >> shift; + zs_intreg = read_zsreg(info->zs_chan_a, R3) >> shift; if ((zs_intreg & CHAN_IRQMASK) == 0) break; + status = IRQ_HANDLED; + if (zs_intreg & CHBRxIP) { - receive_chars(info, regs); + receive_chars(info); } if (zs_intreg & CHBTxIP) { transmit_chars(info); @@ -581,23 +527,25 @@ void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) status_handle(info); } } - + /* Why do we need this ? */ write_zsreg(info->zs_channel, 0, RES_H_IUS); + + return status; } #ifdef ZS_DEBUG_REGS void zs_dump (void) { int i, j; for (i = 0; i < zs_channels_found; i++) { - struct dec_zschannel *ch = &zs_channels[i]; + struct dec_zschannel *ch = &zs_channels[i]; if ((long)ch->control == UNI_IO_BASE+UNI_SCC1A_CTRL) { for (j = 0; j < 15; j++) { - printk("W%d = 0x%x\t", + printk("W%d = 0x%x\t", j, (int)ch->curregs[j]); } for (j = 0; j < 15; j++) { - printk("R%d = 0x%x\t", + printk("R%d = 0x%x\t", j, (int)read_zsreg(ch,j)); } printk("\n\n"); @@ -626,14 +574,14 @@ static void rs_stop(struct tty_struct *tty) if (serial_paranoia_check(info, tty->name, "rs_stop")) return; - + #if 1 - save_flags(flags); cli(); + spin_lock_irqsave(&zs_lock, flags); if (info->zs_channel->curregs[5] & TxENAB) { info->zs_channel->curregs[5] &= ~TxENAB; write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]); } - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); #endif } @@ -641,11 +589,11 @@ static void rs_start(struct tty_struct *tty) { struct dec_serial *info = (struct dec_serial *)tty->driver_data; unsigned long flags; - + if (serial_paranoia_check(info, tty->name, "rs_start")) return; - - save_flags(flags); cli(); + + spin_lock_irqsave(&zs_lock, flags); #if 1 if (info->xmit_cnt && info->xmit_buf && !(info->zs_channel->curregs[5] & TxENAB)) { info->zs_channel->curregs[5] |= TxENAB; @@ -656,7 +604,7 @@ static void rs_start(struct tty_struct *tty) transmit_chars(info); } #endif - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); } /* @@ -668,29 +616,23 @@ static void rs_start(struct tty_struct *tty) * interrupt driver proper are done; the interrupt driver schedules * them using rs_sched_event(), and they get done here. */ -static void do_serial_bh(void) -{ - run_task_queue(&tq_zs_serial); -} -static void do_softint(void *private_) +static void do_softint(unsigned long private_) { struct dec_serial *info = (struct dec_serial *) private_; struct tty_struct *tty; - + tty = info->tty; if (!tty) return; if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); } } -int zs_startup(struct dec_serial * info) +static int zs_startup(struct dec_serial * info) { unsigned long flags; @@ -703,10 +645,10 @@ int zs_startup(struct dec_serial * info) return -ENOMEM; } - save_flags(flags); cli(); + spin_lock_irqsave(&zs_lock, flags); #ifdef SERIAL_DEBUG_OPEN - printk("starting up ttyS%02d (irq %d)...", info->line, info->irq); + printk("starting up ttyS%d (irq %d)...", info->line, info->irq); #endif /* @@ -718,8 +660,13 @@ int zs_startup(struct dec_serial * info) /* * Clear the interrupt registers. */ - write_zsreg(info->zs_channel, 0, ERR_RES); - write_zsreg(info->zs_channel, 0, RES_H_IUS); + write_zsreg(info->zs_channel, R0, ERR_RES); + write_zsreg(info->zs_channel, R0, RES_H_IUS); + + /* + * Set the speed of the serial port + */ + change_speed(info); /* * Turn on RTS and DTR. @@ -729,37 +676,32 @@ int zs_startup(struct dec_serial * info) /* * Finally, enable sequencing and interrupts */ - info->zs_channel->curregs[1] = (info->zs_channel->curregs[1] & ~0x18) | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB); - info->zs_channel->curregs[3] |= (RxENABLE | Rx8); - info->zs_channel->curregs[5] |= (TxENAB | Tx8); - info->zs_channel->curregs[15] |= (DCDIE | CTSIE | TxUIE | BRKIE); - info->zs_channel->curregs[9] |= (VIS | MIE); - write_zsreg(info->zs_channel, 1, info->zs_channel->curregs[1]); - write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]); - write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]); - write_zsreg(info->zs_channel, 15, info->zs_channel->curregs[15]); - write_zsreg(info->zs_channel, 9, info->zs_channel->curregs[9]); + info->zs_channel->curregs[R1] &= ~RxINT_MASK; + info->zs_channel->curregs[R1] |= (RxINT_ALL | TxINT_ENAB | + EXT_INT_ENAB); + info->zs_channel->curregs[R3] |= RxENABLE; + info->zs_channel->curregs[R5] |= TxENAB; + info->zs_channel->curregs[R15] |= (DCDIE | CTSIE | TxUIE | BRKIE); + write_zsreg(info->zs_channel, R1, info->zs_channel->curregs[R1]); + write_zsreg(info->zs_channel, R3, info->zs_channel->curregs[R3]); + write_zsreg(info->zs_channel, R5, info->zs_channel->curregs[R5]); + write_zsreg(info->zs_channel, R15, info->zs_channel->curregs[R15]); /* * And clear the interrupt registers again for luck. */ - write_zsreg(info->zs_channel, 0, ERR_RES); - write_zsreg(info->zs_channel, 0, RES_H_IUS); + write_zsreg(info->zs_channel, R0, ERR_RES); + write_zsreg(info->zs_channel, R0, RES_H_IUS); + + /* Save the current value of RR0 */ + info->read_reg_zero = read_zsreg(info->zs_channel, R0); if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - /* - * Set the speed of the serial port - */ - change_speed(info); - - /* Save the current value of RR0 */ - info->read_reg_zero = read_zsreg(info->zs_channel, 0); - info->flags |= ZILOG_INITIALIZED; - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); return 0; } @@ -778,9 +720,9 @@ static void shutdown(struct dec_serial * info) printk("Shutting down serial port %d (irq %d)....", info->line, info->irq); #endif - - save_flags(flags); cli(); /* Disable interrupts */ - + + spin_lock_irqsave(&zs_lock, flags); + if (info->xmit_buf) { free_page((unsigned long) info->xmit_buf); info->xmit_buf = 0; @@ -802,7 +744,7 @@ static void shutdown(struct dec_serial * info) set_bit(TTY_IO_ERROR, &info->tty->flags); info->flags &= ~ZILOG_INITIALIZED; - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); } /* @@ -838,15 +780,13 @@ static void change_speed(struct dec_serial *info) i += 15; } - save_flags(flags); cli(); + spin_lock_irqsave(&zs_lock, flags); info->zs_baud = baud_table[i]; - info->clk_divisor = 16; if (info->zs_baud) { - info->zs_channel->curregs[4] = X16CLK; brg = BPS_TO_BRG(info->zs_baud, zs_parms->clock/info->clk_divisor); info->zs_channel->curregs[12] = (brg & 255); info->zs_channel->curregs[13] = ((brg >> 8) & 255); - zs_rtsdtr(info, DTR, 1); + zs_rtsdtr(info, DTR, 1); } else { zs_rtsdtr(info, RTS | DTR, 0); return; @@ -913,7 +853,7 @@ static void change_speed(struct dec_serial *info) /* Load up the new values */ load_zsregs(info->zs_channel, info->zs_channel->curregs); - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); } static void rs_flush_chars(struct tty_struct *tty) @@ -929,12 +869,12 @@ static void rs_flush_chars(struct tty_struct *tty) return; /* Enable transmitter */ - save_flags(flags); cli(); + spin_lock_irqsave(&zs_lock, flags); transmit_chars(info); - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); } -static int rs_write(struct tty_struct * tty, int from_user, +static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count) { int c, total = 0; @@ -947,26 +887,17 @@ static int rs_write(struct tty_struct * tty, int from_user, if (!tty || !info->xmit_buf) return 0; - save_flags(flags); while (1) { - cli(); - c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + spin_lock_irqsave(&zs_lock, flags); + c = min(count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); if (c <= 0) break; - if (from_user) { - down(&tmp_buf_sem); - copy_from_user(tmp_buf, buf, c); - c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); - memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); - up(&tmp_buf_sem); - } else - memcpy(info->xmit_buf + info->xmit_head, buf, c); + memcpy(info->xmit_buf + info->xmit_head, buf, c); info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); info->xmit_cnt += c; - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); buf += c; count -= c; total += c; @@ -975,7 +906,7 @@ static int rs_write(struct tty_struct * tty, int from_user, if (info->xmit_cnt && !tty->stopped && !info->tx_stopped && !info->tx_active) transmit_chars(info); - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); return total; } @@ -983,7 +914,7 @@ static int rs_write_room(struct tty_struct *tty) { struct dec_serial *info = (struct dec_serial *)tty->driver_data; int ret; - + if (serial_paranoia_check(info, tty->name, "rs_write_room")) return 0; ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; @@ -995,7 +926,7 @@ static int rs_write_room(struct tty_struct *tty) static int rs_chars_in_buffer(struct tty_struct *tty) { struct dec_serial *info = (struct dec_serial *)tty->driver_data; - + if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer")) return 0; return info->xmit_cnt; @@ -1004,22 +935,19 @@ static int rs_chars_in_buffer(struct tty_struct *tty) static void rs_flush_buffer(struct tty_struct *tty) { struct dec_serial *info = (struct dec_serial *)tty->driver_data; - + if (serial_paranoia_check(info, tty->name, "rs_flush_buffer")) return; - cli(); + spin_lock_irq(&zs_lock); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - sti(); - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + spin_unlock_irq(&zs_lock); + tty_wakeup(tty); } /* * ------------------------------------------------------------ * rs_throttle() - * + * * This routine is called by the upper-layer tty layer to signal that * incoming characters should be throttled. * ------------------------------------------------------------ @@ -1031,20 +959,20 @@ static void rs_throttle(struct tty_struct * tty) #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; - + printk("throttle %s: %d....\n", _tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty)); #endif if (serial_paranoia_check(info, tty->name, "rs_throttle")) return; - + if (I_IXOFF(tty)) { - save_flags(flags); cli(); + spin_lock_irqsave(&zs_lock, flags); info->x_char = STOP_CHAR(tty); if (!info->tx_active) transmit_chars(info); - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); } if (C_CRTSCTS(tty)) { @@ -1059,16 +987,16 @@ static void rs_unthrottle(struct tty_struct * tty) #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; - + printk("unthrottle %s: %d....\n", _tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty)); #endif if (serial_paranoia_check(info, tty->name, "rs_unthrottle")) return; - + if (I_IXOFF(tty)) { - save_flags(flags); cli(); + spin_lock_irqsave(&zs_lock, flags); if (info->x_char) info->x_char = 0; else { @@ -1076,7 +1004,7 @@ static void rs_unthrottle(struct tty_struct * tty) if (!info->tx_active) transmit_chars(info); } - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); } if (C_CRTSCTS(tty)) { @@ -1163,15 +1091,15 @@ check_and_exit: * release the bus after transmitting. This must be done when * the transmit shift register is empty, not be done when the * transmit holding register is empty. This functionality - * allows an RS485 driver to be written in user space. + * allows an RS485 driver to be written in user space. */ static int get_lsr_info(struct dec_serial * info, unsigned int *value) { unsigned char status; - cli(); + spin_lock(&zs_lock); status = read_zsreg(info->zs_channel, 0); - sti(); + spin_unlock_irq(&zs_lock); put_user(status,value); return 0; } @@ -1194,11 +1122,11 @@ static int rs_tiocmget(struct tty_struct *tty, struct file *file) if (info->zs_channel == info->zs_chan_a) result = 0; else { - cli(); + spin_lock(&zs_lock); control = info->zs_chan_a->curregs[5]; status_a = read_zsreg(info->zs_chan_a, 0); status_b = read_zsreg(info->zs_channel, 0); - sti(); + spin_unlock_irq(&zs_lock); result = ((control & RTS) ? TIOCM_RTS: 0) | ((control & DTR) ? TIOCM_DTR: 0) | ((status_b & DCD) ? TIOCM_CAR: 0) @@ -1210,11 +1138,9 @@ static int rs_tiocmget(struct tty_struct *tty, struct file *file) } static int rs_tiocmset(struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear) + unsigned int set, unsigned int clear) { struct dec_serial * info = (struct dec_serial *)tty->driver_data; - int error; - unsigned int arg, bits; if (info->hook) return -ENODEV; @@ -1228,7 +1154,7 @@ static int rs_tiocmset(struct tty_struct *tty, struct file *file, if (info->zs_channel == info->zs_chan_a) return 0; - cli(); + spin_lock(&zs_lock); if (set & TIOCM_RTS) info->zs_chan_a->curregs[5] |= RTS; if (set & TIOCM_DTR) @@ -1238,7 +1164,7 @@ static int rs_tiocmset(struct tty_struct *tty, struct file *file, if (clear & TIOCM_DTR) info->zs_chan_a->curregs[5] &= ~DTR; write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]); - sti(); + spin_unlock_irq(&zs_lock); return 0; } @@ -1255,19 +1181,18 @@ static void rs_break(struct tty_struct *tty, int break_state) if (!info->port) return; - save_flags(flags); cli(); + spin_lock_irqsave(&zs_lock, flags); if (break_state == -1) info->zs_channel->curregs[5] |= SND_BRK; else info->zs_channel->curregs[5] &= ~SND_BRK; write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]); - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); } static int rs_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { - int error; struct dec_serial * info = (struct dec_serial *)tty->driver_data; if (info->hook) @@ -1282,42 +1207,38 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; } - + switch (cmd) { - case TIOCGSERIAL: - error = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(struct serial_struct)); - if (error) - return error; - return get_serial_info(info, - (struct serial_struct *) arg); - case TIOCSSERIAL: - return set_serial_info(info, - (struct serial_struct *) arg); - case TIOCSERGETLSR: /* Get line status register */ - error = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(unsigned int)); - if (error) - return error; - else - return get_lsr_info(info, (unsigned int *) arg); - - case TIOCSERGSTRUCT: - error = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(struct dec_serial)); - if (error) - return error; - copy_from_user((struct dec_serial *) arg, - info, sizeof(struct dec_serial)); - return 0; - - default: - return -ENOIOCTLCMD; - } + case TIOCGSERIAL: + if (!access_ok(VERIFY_WRITE, (void *)arg, + sizeof(struct serial_struct))) + return -EFAULT; + return get_serial_info(info, (struct serial_struct *)arg); + + case TIOCSSERIAL: + return set_serial_info(info, (struct serial_struct *)arg); + + case TIOCSERGETLSR: /* Get line status register */ + if (!access_ok(VERIFY_WRITE, (void *)arg, + sizeof(unsigned int))) + return -EFAULT; + return get_lsr_info(info, (unsigned int *)arg); + + case TIOCSERGSTRUCT: + if (!access_ok(VERIFY_WRITE, (void *)arg, + sizeof(struct dec_serial))) + return -EFAULT; + copy_from_user((struct dec_serial *)arg, info, + sizeof(struct dec_serial)); + return 0; + + default: + return -ENOIOCTLCMD; + } return 0; } -static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) +static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct dec_serial *info = (struct dec_serial *)tty->driver_data; int was_stopped; @@ -1335,7 +1256,7 @@ static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) /* * ------------------------------------------------------------ * rs_close() - * + * * This routine is called when the serial port gets closed. * Wait for the last remaining data to be sent. * ------------------------------------------------------------ @@ -1347,16 +1268,16 @@ static void rs_close(struct tty_struct *tty, struct file * filp) if (!info || serial_paranoia_check(info, tty->name, "rs_close")) return; - - save_flags(flags); cli(); - + + spin_lock_irqsave(&zs_lock, flags); + if (tty_hung_up_p(filp)) { - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); return; } - + #ifdef SERIAL_DEBUG_OPEN - printk("rs_close ttyS%02d, count = %d\n", info->line, info->count); + printk("rs_close ttyS%d, count = %d\n", info->line, info->count); #endif if ((tty->count == 1) && (info->count != 1)) { /* @@ -1371,17 +1292,17 @@ static void rs_close(struct tty_struct *tty, struct file * filp) info->count = 1; } if (--info->count < 0) { - printk("rs_close: bad serial port count for ttyS%02d: %d\n", + printk("rs_close: bad serial port count for ttyS%d: %d\n", info->line, info->count); info->count = 0; } if (info->count) { - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); return; } info->flags |= ZILOG_CLOSING; /* - * Now we wait for the transmit buffer to clear; and we notify + * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. */ tty->closing = 1; @@ -1407,21 +1328,19 @@ static void rs_close(struct tty_struct *tty, struct file * filp) shutdown(info); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); tty->closing = 0; info->event = 0; info->tty = 0; if (info->blocked_open) { if (info->close_delay) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(info->close_delay); + msleep_interruptible(jiffies_to_msecs(info->close_delay)); } wake_up_interruptible(&info->open_wait); } info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CLOSING); wake_up_interruptible(&info->close_wait); - restore_flags(flags); + spin_unlock_irqrestore(&zs_lock, flags); } /* @@ -1430,7 +1349,8 @@ static void rs_close(struct tty_struct *tty, struct file * filp) static void rs_wait_until_sent(struct tty_struct *tty, int timeout) { struct dec_serial *info = (struct dec_serial *) tty->driver_data; - unsigned long orig_jiffies, char_time; + unsigned long orig_jiffies; + int char_time; if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent")) return; @@ -1446,10 +1366,9 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) if (char_time == 0) char_time = 1; if (timeout) - char_time = MIN(char_time, timeout); + char_time = min(char_time, timeout); while ((read_zsreg(info->zs_channel, 1) & Tx_BUF_EMP) == 0) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(char_time); + msleep_interruptible(jiffies_to_msecs(char_time)); if (signal_pending(current)) break; if (timeout && time_after(jiffies, orig_jiffies + timeout)) @@ -1461,7 +1380,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) /* * rs_hangup() --- called by tty_hangup() when a hangup is signaled. */ -void rs_hangup(struct tty_struct *tty) +static void rs_hangup(struct tty_struct *tty) { struct dec_serial * info = (struct dec_serial *)tty->driver_data; @@ -1503,11 +1422,6 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, #endif } - /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. @@ -1531,19 +1445,19 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, retval = 0; add_wait_queue(&info->open_wait, &wait); #ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready before block: ttyS%02d, count = %d\n", + printk("block_til_ready before block: ttyS%d, count = %d\n", info->line, info->count); #endif - cli(); - if (!tty_hung_up_p(filp)) + spin_lock(&zs_lock); + if (!tty_hung_up_p(filp)) info->count--; - sti(); + spin_unlock_irq(&zs_lock); info->blocked_open++; while (1) { - cli(); + spin_lock(&zs_lock); if (tty->termios->c_cflag & CBAUD) zs_rtsdtr(info, RTS | DTR, 1); - sti(); + spin_unlock_irq(&zs_lock); set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ZILOG_INITIALIZED)) { @@ -1551,7 +1465,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, if (info->flags & ZILOG_HUP_NOTIFY) retval = -EAGAIN; else - retval = -ERESTARTSYS; + retval = -ERESTARTSYS; #else retval = -EAGAIN; #endif @@ -1565,7 +1479,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, break; } #ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready blocking: ttyS%02d, count = %d\n", + printk("block_til_ready blocking: ttyS%d, count = %d\n", info->line, info->count); #endif schedule(); @@ -1576,14 +1490,14 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, info->count++; info->blocked_open--; #ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready after blocking: ttyS%02d, count = %d\n", + printk("block_til_ready after blocking: ttyS%d, count = %d\n", info->line, info->count); #endif if (retval) return retval; info->flags |= ZILOG_NORMAL_ACTIVE; return 0; -} +} /* * This routine is called whenever a serial port is opened. It @@ -1591,7 +1505,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, * the IRQ chain. It also performs the serial-specific * initialization for the tty structure. */ -int rs_open(struct tty_struct *tty, struct file * filp) +static int rs_open(struct tty_struct *tty, struct file * filp) { struct dec_serial *info; int retval, line; @@ -1645,7 +1559,7 @@ int rs_open(struct tty_struct *tty, struct file * filp) return retval; } -#ifdef CONFIG_SERIAL_CONSOLE +#ifdef CONFIG_SERIAL_DEC_CONSOLE if (sercons.cflag && sercons.index == line) { tty->termios->c_cflag = sercons.cflag; sercons.cflag = 0; @@ -1664,7 +1578,7 @@ int rs_open(struct tty_struct *tty, struct file * filp) static void __init show_serial_version(void) { - printk("DECstation Z8530 serial driver version 0.05\n"); + printk("DECstation Z8530 serial driver version 0.09\n"); } /* Initialize Z8530s zs_channels @@ -1674,6 +1588,7 @@ static void __init probe_sccs(void) { struct dec_serial **pp; int i, n, n_chips = 0, n_channels, chip, channel; + unsigned long flags; /* * did we get here by accident? @@ -1682,36 +1597,26 @@ static void __init probe_sccs(void) printk("Not on JUNKIO machine, skipping probe_sccs\n"); return; } - - /* - * When serial console is activated, tc_init has not been called yet - * and system_base is undefined. Unfortunately we have to hardcode - * system_base for this case :-(. HK - */ + switch(mips_machtype) { #ifdef CONFIG_MACH_DECSTATION case MACH_DS5000_2X0: - system_base = 0xbf800000; + case MACH_DS5900: n_chips = 2; zs_parms = &ds_parms; + zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0]; + zs_parms->irq1 = dec_interrupt[DEC_IRQ_SCC1]; break; case MACH_DS5000_1XX: - system_base = 0xbc000000; n_chips = 2; zs_parms = &ds_parms; + zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0]; + zs_parms->irq1 = dec_interrupt[DEC_IRQ_SCC1]; break; case MACH_DS5000_XX: - system_base = 0xbc000000; n_chips = 1; zs_parms = &ds_parms; - break; -#endif -#ifdef CONFIG_BAGET_MIPS - case MACH_BAGET202: - system_base = UNI_IO_BASE; - n_chips = 2; - zs_parms = &baget_parms; - zs_init_regs[2] = 0x8; + zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0]; break; #endif default: @@ -1729,43 +1634,43 @@ static void __init probe_sccs(void) /* * The sccs reside on the high byte of the 16 bit IOBUS */ - zs_channels[n_channels].control = - (volatile unsigned char *)system_base + - (0 == chip ? zs_parms->scc0 : zs_parms->scc1) + - (0 == channel ? zs_parms->channel_a_offset : - zs_parms->channel_b_offset); - zs_channels[n_channels].data = + zs_channels[n_channels].control = + (volatile void *)CKSEG1ADDR(dec_kn_slot_base + + (0 == chip ? zs_parms->scc0 : zs_parms->scc1) + + (0 == channel ? zs_parms->channel_a_offset : + zs_parms->channel_b_offset)); + zs_channels[n_channels].data = zs_channels[n_channels].control + 4; -#ifndef CONFIG_SERIAL_CONSOLE +#ifndef CONFIG_SERIAL_DEC_CONSOLE /* * We're called early and memory managment isn't up, yet. - * Thus check_region would fail. + * Thus request_region would fail. */ - if (check_region((unsigned long) + if (!request_region((unsigned long) zs_channels[n_channels].control, - ZS_CHAN_IO_SIZE) < 0) { + ZS_CHAN_IO_SIZE, "SCC")) panic("SCC I/O region is not free"); - } - request_region((unsigned long) - zs_channels[n_channels].control, - ZS_CHAN_IO_SIZE, "SCC"); #endif zs_soft[n_channels].zs_channel = &zs_channels[n_channels]; - zs_soft[n_channels].irq = zs_parms->irq; + /* HACK alert! */ + if (!(chip & 1)) + zs_soft[n_channels].irq = zs_parms->irq0; + else + zs_soft[n_channels].irq = zs_parms->irq1; - /* + /* * Identification of channel A. Location of channel A * inside chip depends on mapping of internal address * the chip decodes channels by. - * CHANNEL_A_NR returns either 0 (in case of + * CHANNEL_A_NR returns either 0 (in case of * DECstations) or 1 (in case of Baget). */ if (CHANNEL_A_NR == channel) - zs_soft[n_channels].zs_chan_a = + zs_soft[n_channels].zs_chan_a = &zs_channels[n_channels+1-2*CHANNEL_A_NR]; else - zs_soft[n_channels].zs_chan_a = + zs_soft[n_channels].zs_chan_a = &zs_channels[n_channels]; *pp = &zs_soft[n_channels]; @@ -1783,19 +1688,20 @@ static void __init probe_sccs(void) } } -/* save_and_cli(flags); + spin_lock_irqsave(&zs_lock, flags); for (n = 0; n < zs_channels_found; n++) { - if (((int)zs_channels[n].control & 0xf) == 1) { + if (n % 2 == 0) { write_zsreg(zs_soft[n].zs_chan_a, R9, FHWRES); - mdelay(10); + udelay(10); write_zsreg(zs_soft[n].zs_chan_a, R9, 0); } - load_zsregs(zs_soft[n].zs_channel, zs_soft[n].zs_channel->curregs); - } - restore_flags(flags); */ + load_zsregs(zs_soft[n].zs_channel, + zs_soft[n].zs_channel->curregs); + } + spin_unlock_irqrestore(&zs_lock, flags); } -static struct tty_operations serial_ops = { +static const struct tty_operations serial_ops = { .open = rs_open, .close = rs_close, .write = rs_write, @@ -1820,19 +1726,14 @@ static struct tty_operations serial_ops = { int __init zs_init(void) { int channel, i; - unsigned long flags; struct dec_serial *info; if(!BUS_PRESENT) return -ENODEV; - /* Setup base handler, and timer table. */ - init_bh(SERIAL_BH, do_serial_bh); - /* Find out how many Z8530 SCCs we have */ if (zs_chain == 0) probe_sccs(); - serial_driver = alloc_tty_driver(zs_channels_found); if (!serial_driver) return -ENOMEM; @@ -1843,7 +1744,6 @@ int __init zs_init(void) /* Not all of this is exactly right for us. */ serial_driver->owner = THIS_MODULE; - serial_driver->devfs_name = "tts/"; serial_driver->name = "ttyS"; serial_driver->major = TTY_MAJOR; serial_driver->minor_start = 64; @@ -1852,138 +1752,110 @@ int __init zs_init(void) serial_driver->init_termios = tty_std_termios; serial_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; + serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty_set_operations(serial_driver, &serial_ops); if (tty_register_driver(serial_driver)) - panic("Couldn't register serial driver\n"); - - save_flags(flags); cli(); + panic("Couldn't register serial driver"); - for (channel = 0; channel < zs_channels_found; ++channel) { - if (zs_soft[channel].hook && - zs_soft[channel].hook->init_channel) - (*zs_soft[channel].hook->init_channel) - (&zs_soft[channel]); + for (info = zs_chain, i = 0; info; info = info->zs_next, i++) { - zs_soft[channel].clk_divisor = 16; - zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]); - - if (request_irq(zs_parms->irq, rs_interrupt, SA_SHIRQ, - "SCC", &zs_soft[channel])) - printk(KERN_ERR "decserial: can't get irq %d\n", - zs_parms->irq); - } + /* Needed before interrupts are enabled. */ + info->tty = 0; + info->x_char = 0; - for (info = zs_chain, i = 0; info; info = info->zs_next, i++) - { if (info->hook && info->hook->init_info) { (*info->hook->init_info)(info); continue; } + info->magic = SERIAL_MAGIC; info->port = (int) info->zs_channel->control; info->line = i; - info->tty = 0; info->custom_divisor = 16; info->close_delay = 50; info->closing_wait = 3000; - info->x_char = 0; info->event = 0; info->count = 0; info->blocked_open = 0; - info->tqueue.routine = do_softint; - info->tqueue.data = info; + tasklet_init(&info->tlet, do_softint, (unsigned long)info); init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); - printk("ttyS%02d at 0x%08x (irq = %d)", info->line, - info->port, info->irq); - printk(" is a Z85C30 SCC\n"); + printk("ttyS%02d at 0x%08x (irq = %d) is a Z85C30 SCC\n", + info->line, info->port, info->irq); tty_register_device(serial_driver, info->line, NULL); + } - restore_flags(flags); + for (channel = 0; channel < zs_channels_found; ++channel) { + zs_soft[channel].clk_divisor = 16; + zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]); - return 0; -} + if (request_irq(zs_soft[channel].irq, rs_interrupt, IRQF_SHARED, + "scc", &zs_soft[channel])) + printk(KERN_ERR "decserial: can't get irq %d\n", + zs_soft[channel].irq); -/* - * register_serial and unregister_serial allows for serial ports to be - * configured at run-time, to support PCMCIA modems. - */ -/* PowerMac: Unused at this time, just here to make things link. */ -int register_serial(struct serial_struct *req) -{ - return -1; -} + if (zs_soft[channel].hook) { + zs_startup(&zs_soft[channel]); + if (zs_soft[channel].hook->init_channel) + (*zs_soft[channel].hook->init_channel) + (&zs_soft[channel]); + } + } -void unregister_serial(int line) -{ - return; + return 0; } /* * polling I/O routines */ -static int -zs_poll_tx_char(struct dec_serial *info, unsigned char ch) +static int zs_poll_tx_char(void *handle, unsigned char ch) { + struct dec_serial *info = handle; struct dec_zschannel *chan = info->zs_channel; int ret; if(chan) { int loops = 10000; -// int nine = read_zsreg(chan, R9); - - RECOVERY_DELAY; -// write_zsreg(chan, R9, nine & ~MIE); - wbflush(); - RECOVERY_DELAY; - while (!(*(chan->control) & Tx_BUF_EMP) && --loops) - RECOVERY_DELAY; + while (loops && !(read_zsreg(chan, 0) & Tx_BUF_EMP)) + loops--; - if (loops) { - ret = 0; - *(chan->data) = ch; - wbflush(); - RECOVERY_DELAY; - } else - ret = -EAGAIN; - -// write_zsreg(chan, R9, nine); - wbflush(); - RECOVERY_DELAY; - - return ret; - } + if (loops) { + write_zsdata(chan, ch); + ret = 0; + } else + ret = -EAGAIN; - return -ENODEV; + return ret; + } else + return -ENODEV; } -static int -zs_poll_rx_char(struct dec_serial *info) +static int zs_poll_rx_char(void *handle) { + struct dec_serial *info = handle; struct dec_zschannel *chan = info->zs_channel; int ret; if(chan) { int loops = 10000; - while((read_zsreg(chan, 0) & Rx_CH_AV) == 0) - loops--; + while (loops && !(read_zsreg(chan, 0) & Rx_CH_AV)) + loops--; if (loops) ret = read_zsdata(chan); else ret = -EAGAIN; - return ret; - } else - return -ENODEV; + return ret; + } else + return -ENODEV; } -unsigned int register_zs_hook(unsigned int channel, struct zs_hook *hook) +int register_zs_hook(unsigned int channel, struct dec_serial_hook *hook) { struct dec_serial *info = &zs_soft[channel]; @@ -1993,22 +1865,15 @@ unsigned int register_zs_hook(unsigned int channel, struct zs_hook *hook) return 0; } else { - info->hook = hook; - - if (zs_chain == 0) - probe_sccs(); - - if (!(info->flags & ZILOG_INITIALIZED)) - zs_startup(info); - hook->poll_rx_char = zs_poll_rx_char; hook->poll_tx_char = zs_poll_tx_char; + info->hook = hook; return 1; } } -unsigned int unregister_zs_hook(unsigned int channel) +int unregister_zs_hook(unsigned int channel) { struct dec_serial *info = &zs_soft[channel]; @@ -2027,7 +1892,7 @@ unsigned int unregister_zs_hook(unsigned int channel) * Serial console driver * ------------------------------------------------------------ */ -#ifdef CONFIG_SERIAL_CONSOLE +#ifdef CONFIG_SERIAL_DEC_CONSOLE /* @@ -2064,11 +1929,13 @@ static struct tty_driver *serial_console_device(struct console *c, int *index) static int __init serial_console_setup(struct console *co, char *options) { struct dec_serial *info; - int baud = 9600; - int bits = 8; - int parity = 'n'; - int cflag = CREAD | HUPCL | CLOCAL; - char *s; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int cflag = CREAD | HUPCL | CLOCAL; + int clk_divisor = 16; + int brg; + char *s; unsigned long flags; if(!BUS_PRESENT) @@ -2120,6 +1987,10 @@ static int __init serial_console_setup(struct console *co, char *options) case 9600: default: cflag |= B9600; + /* + * Set this to a sane value to prevent a divide error. + */ + baud = 9600; break; } switch(bits) { @@ -2140,8 +2011,33 @@ static int __init serial_console_setup(struct console *co, char *options) break; } co->cflag = cflag; -#if 1 - save_and_cli(flags); + + spin_lock_irqsave(&zs_lock, flags); + + /* + * Set up the baud rate generator. + */ + brg = BPS_TO_BRG(baud, zs_parms->clock / clk_divisor); + info->zs_channel->curregs[R12] = (brg & 255); + info->zs_channel->curregs[R13] = ((brg >> 8) & 255); + + /* + * Set byte size and parity. + */ + if (bits == 7) { + info->zs_channel->curregs[R3] |= Rx7; + info->zs_channel->curregs[R5] |= Tx7; + } else { + info->zs_channel->curregs[R3] |= Rx8; + info->zs_channel->curregs[R5] |= Tx8; + } + if (cflag & PARENB) { + info->zs_channel->curregs[R4] |= PAR_ENA; + } + if (!(cflag & PARODD)) { + info->zs_channel->curregs[R4] |= PAR_EVEN; + } + info->zs_channel->curregs[R4] |= SB1; /* * Turn on RTS and DTR. @@ -2149,34 +2045,30 @@ static int __init serial_console_setup(struct console *co, char *options) zs_rtsdtr(info, RTS | DTR, 1); /* - * Finally, enable sequencing + * Finally, enable sequencing. */ - info->zs_channel->curregs[3] |= (RxENABLE | Rx8); - info->zs_channel->curregs[5] |= (TxENAB | Tx8); - info->zs_channel->curregs[9] |= (VIS); - write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]); - write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]); - write_zsreg(info->zs_channel, 9, info->zs_channel->curregs[9]); + info->zs_channel->curregs[R3] |= RxENABLE; + info->zs_channel->curregs[R5] |= TxENAB; /* * Clear the interrupt registers. */ - write_zsreg(info->zs_channel, 0, ERR_RES); - write_zsreg(info->zs_channel, 0, RES_H_IUS); + write_zsreg(info->zs_channel, R0, ERR_RES); + write_zsreg(info->zs_channel, R0, RES_H_IUS); /* - * Set the speed of the serial port + * Load up the new values. */ - change_speed(info); + load_zsregs(info->zs_channel, info->zs_channel->curregs); /* Save the current value of RR0 */ - info->read_reg_zero = read_zsreg(info->zs_channel, 0); + info->read_reg_zero = read_zsreg(info->zs_channel, R0); - zs_soft[co->index].clk_divisor = 16; + zs_soft[co->index].clk_divisor = clk_divisor; zs_soft[co->index].zs_baud = get_zsbaud(&zs_soft[co->index]); - restore_flags(flags); -#endif + spin_unlock_irqrestore(&zs_lock, flags); + return 0; } @@ -2196,7 +2088,7 @@ void __init zs_serial_console_init(void) { register_console(&sercons); } -#endif /* ifdef CONFIG_SERIAL_CONSOLE */ +#endif /* ifdef CONFIG_SERIAL_DEC_CONSOLE */ #ifdef CONFIG_KGDB struct dec_zschannel *zs_kgdbchan; @@ -2234,7 +2126,7 @@ void kgdb_interruptible(int yes) int one, nine; nine = read_zsreg(chan, 9); if (yes == 1) { - one = EXT_INT_ENAB|INT_ALL_Rx; + one = EXT_INT_ENAB|RxINT_ALL; nine |= MIE; printk("turning serial ints on\n"); } else { @@ -2246,22 +2138,23 @@ void kgdb_interruptible(int yes) write_zsreg(chan, 9, nine); } -static int kgdbhook_init_channel(struct dec_serial* info) +static int kgdbhook_init_channel(void *handle) { return 0; } -static void kgdbhook_init_info(struct dec_serial* info) +static void kgdbhook_init_info(void *handle) { } -static void kgdbhook_rx_char(struct dec_serial* info, - unsigned char ch, unsigned char stat) +static void kgdbhook_rx_char(void *handle, unsigned char ch, unsigned char fl) { + struct dec_serial *info = handle; + + if (fl != TTY_NORMAL) + return; if (ch == 0x03 || ch == '$') breakpoint(); - if (stat & (Rx_OVR|FRM_ERR|PAR_ERR)) - write_zsreg(info->zs_channel, 0, ERR_RES); } /* This sets up the serial port we're using, and turns on @@ -2287,11 +2180,11 @@ static inline void kgdb_chaninit(struct dec_zschannel *ms, int intson, int bps) * for /dev/ttyb which is determined in setup_arch() from the * boot command line flags. */ -struct zs_hook zs_kgdbhook = { - init_channel : kgdbhook_init_channel, - init_info : kgdbhook_init_info, - cflags : B38400|CS8|CLOCAL, - rx_char : kgdbhook_rx_char, +struct dec_serial_hook zs_kgdbhook = { + .init_channel = kgdbhook_init_channel, + .init_info = kgdbhook_init_info, + .rx_char = kgdbhook_rx_char, + .cflags = B38400 | CS8 | CLOCAL, } void __init zs_kgdb_hook(int tty_num) @@ -2311,5 +2204,3 @@ void __init zs_kgdb_hook(int tty_num) set_debug_traps(); /* init stub */ } #endif /* ifdef CONFIG_KGDB */ - -