X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Ftc%2Fzs.c;h=0f0d879bd1bf09e1adfd0f5b61c2b5d9cd7140a2;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=c5befc9af125e518f4c1487d87e46e62cb2c7ff6;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c index c5befc9af..0f0d879bd 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 Maciej W. Rozycki * * For the rest of the code the original Copyright applies: * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au) @@ -55,7 +55,7 @@ #include #include #include -#ifdef CONFIG_SERIAL_CONSOLE +#ifdef CONFIG_SERIAL_DEC_CONSOLE #include #endif @@ -63,20 +63,16 @@ #include #include #include -#include #include -#include #include +#include + #ifdef CONFIG_MACH_DECSTATION #include #include #include #include #endif -#ifdef CONFIG_BAGET_MIPS -#include -unsigned long system_base; -#endif #ifdef CONFIG_KGDB #include #endif @@ -94,7 +90,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 +101,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 +110,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 +126,7 @@ 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 || BAGET_BUS_PRESENT) +#define BUS_PRESENT (DS_BUS_PRESENT) struct dec_zschannel zs_channels[NUM_CHANNELS]; struct dec_serial zs_soft[NUM_CHANNELS]; @@ -153,28 +135,28 @@ 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); @@ -190,7 +172,6 @@ static struct tty_driver *serial_driver; /* * Debugging. */ -#undef SERIAL_DEBUG_INTR #undef SERIAL_DEBUG_OPEN #undef SERIAL_DEBUG_FLOW #undef SERIAL_DEBUG_THROTTLE @@ -251,7 +232,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, @@ -261,7 +242,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; @@ -273,10 +254,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; } @@ -293,7 +274,7 @@ static inline void write_zsdata(struct dec_zschannel *channel, unsigned char value) { *channel->data = value; - wbflush(); RECOVERY_DELAY; + fast_iob(); RECOVERY_DELAY; return; } @@ -303,9 +284,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]); @@ -372,8 +353,6 @@ 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. @@ -397,23 +376,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; @@ -421,20 +395,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)) { + /* Ignore the null char got when BREAK is removed. */ + if (ch == 0) + continue; + if (time_before(jiffies, break_pressed + HZ * 5)) { handle_sysrq(ch, regs, NULL); break_pressed = 0; - goto ignore_char; + continue; } break_pressed = 0; } @@ -444,22 +420,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); @@ -501,18 +463,22 @@ static _INLINE_ void status_handle(struct dec_serial *info) /* 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 { @@ -563,7 +529,7 @@ 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; @@ -577,7 +543,7 @@ 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); } @@ -586,14 +552,14 @@ void rs_interrupt(int irq, void *dev_id, struct pt_regs * 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"); @@ -622,7 +588,7 @@ static void rs_stop(struct tty_struct *tty) if (serial_paranoia_check(info, tty->name, "rs_stop")) return; - + #if 1 save_flags(flags); cli(); if (info->zs_channel->curregs[5] & TxENAB) { @@ -637,10 +603,10 @@ 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(); #if 1 if (info->xmit_cnt && info->xmit_buf && !(info->zs_channel->curregs[5] & TxENAB)) { @@ -673,7 +639,7 @@ static void do_softint(void *private_) { struct dec_serial *info = (struct dec_serial *) private_; struct tty_struct *tty; - + tty = info->tty; if (!tty) return; @@ -711,8 +677,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. @@ -722,35 +693,30 @@ 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); return 0; @@ -771,9 +737,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 */ - + if (info->xmit_buf) { free_page((unsigned long) info->xmit_buf); info->xmit_buf = 0; @@ -833,13 +799,11 @@ static void change_speed(struct dec_serial *info) save_flags(flags); cli(); 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; @@ -927,7 +891,7 @@ static void rs_flush_chars(struct tty_struct *tty) restore_flags(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; @@ -942,17 +906,17 @@ static int rs_write(struct tty_struct * tty, int from_user, save_flags(flags); while (1) { - cli(); - c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); + cli(); + 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_t(int, c, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); + 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 @@ -976,7 +940,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; @@ -988,7 +952,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; @@ -997,7 +961,7 @@ 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(); @@ -1009,7 +973,7 @@ static void rs_flush_buffer(struct tty_struct *tty) /* * ------------------------------------------------------------ * rs_throttle() - * + * * This routine is called by the upper-layer tty layer to signal that * incoming characters should be throttled. * ------------------------------------------------------------ @@ -1021,14 +985,14 @@ 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(); info->x_char = STOP_CHAR(tty); @@ -1049,14 +1013,14 @@ 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(); if (info->x_char) @@ -1153,7 +1117,7 @@ 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) { @@ -1200,7 +1164,7 @@ 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; @@ -1218,6 +1182,7 @@ static int rs_tiocmset(struct tty_struct *tty, struct file *file, if (info->zs_channel == info->zs_chan_a) return 0; + get_user(arg, value); cli(); if (set & TIOCM_RTS) info->zs_chan_a->curregs[5] |= RTS; @@ -1272,38 +1237,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: + 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; + } return 0; } @@ -1325,7 +1290,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. * ------------------------------------------------------------ @@ -1337,14 +1302,14 @@ 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(); - + if (tty_hung_up_p(filp)) { restore_flags(flags); return; } - + #ifdef SERIAL_DEBUG_OPEN printk("rs_close ttyS%d, count = %d\n", info->line, info->count); #endif @@ -1371,7 +1336,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) } 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; @@ -1419,7 +1384,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; @@ -1435,7 +1401,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) if (char_time == 0) char_time = 1; if (timeout) - char_time = min_t(unsigned long, 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); @@ -1492,11 +1458,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. @@ -1524,7 +1485,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, info->line, info->count); #endif cli(); - if (!tty_hung_up_p(filp)) + if (!tty_hung_up_p(filp)) info->count--; sti(); info->blocked_open++; @@ -1540,7 +1501,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 @@ -1572,7 +1533,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, return retval; info->flags |= ZILOG_NORMAL_ACTIVE; return 0; -} +} /* * This routine is called whenever a serial port is opened. It @@ -1634,7 +1595,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; @@ -1653,7 +1614,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 @@ -1663,6 +1624,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? @@ -1671,7 +1633,7 @@ 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 @@ -1680,27 +1642,25 @@ static void __init probe_sccs(void) switch(mips_machtype) { #ifdef CONFIG_MACH_DECSTATION case MACH_DS5000_2X0: - system_base = 0xbf800000; + case MACH_DS5900: + system_base = KSEG1ADDR(0x1f800000); 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; + system_base = KSEG1ADDR(0x1c000000); 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; + system_base = KSEG1ADDR(0x1c000000); 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: @@ -1718,15 +1678,15 @@ 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_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].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. @@ -1737,20 +1697,24 @@ static void __init probe_sccs(void) panic("SCC I/O region is not free"); #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]; @@ -1768,16 +1732,17 @@ static void __init probe_sccs(void) } } -/* save_and_cli(flags); + save_and_cli(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); + } + restore_flags(flags); } static struct tty_operations serial_ops = { @@ -1805,7 +1770,6 @@ static struct tty_operations serial_ops = { int __init zs_init(void) { int channel, i; - unsigned long flags; struct dec_serial *info; if(!BUS_PRESENT) @@ -1817,7 +1781,6 @@ int __init zs_init(void) /* 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; @@ -1841,39 +1804,25 @@ int __init zs_init(void) tty_set_operations(serial_driver, &serial_ops); if (tty_register_driver(serial_driver)) - panic("Couldn't register serial driver\n"); - - save_flags(flags); cli(); - - 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]); + panic("Couldn't register serial driver"); - zs_soft[channel].clk_divisor = 16; - zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]); + for (info = zs_chain, i = 0; info; info = info->zs_next, i++) { - 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; @@ -1881,94 +1830,83 @@ int __init zs_init(void) info->tqueue.data = info; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); - printk("ttyS%d 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, SA_SHIRQ, + "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) +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; - - if (loops) { - ret = 0; - *(chan->data) = ch; - wbflush(); - RECOVERY_DELAY; - } else - ret = -EAGAIN; -// write_zsreg(chan, R9, nine); - wbflush(); - RECOVERY_DELAY; + while (loops && !(read_zsreg(chan, 0) & Tx_BUF_EMP)) + loops--; - 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) +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]; @@ -1978,22 +1916,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]; @@ -2012,7 +1943,7 @@ unsigned int unregister_zs_hook(unsigned int channel) * Serial console driver * ------------------------------------------------------------ */ -#ifdef CONFIG_SERIAL_CONSOLE +#ifdef CONFIG_SERIAL_DEC_CONSOLE /* @@ -2049,11 +1980,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) @@ -2105,6 +2038,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) { @@ -2125,43 +2062,64 @@ static int __init serial_console_setup(struct console *co, char *options) break; } co->cflag = cflag; -#if 1 + save_and_cli(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. */ 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 + return 0; } @@ -2181,7 +2139,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; @@ -2219,7 +2177,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 { @@ -2231,22 +2189,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 @@ -2272,11 +2231,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)