diff options
author | davem <davem> | 2002-01-04 21:12:44 +0000 |
---|---|---|
committer | davem <davem> | 2002-01-04 21:12:44 +0000 |
commit | fe58c5e863f549493b9234d6461715440be63de5 (patch) | |
tree | 6b0a66eb8edbb11639e0bac1ace28203fdc7d681 | |
parent | b60ee3e6302370eb9bb1860ee9c0a0f02e899cc3 (diff) | |
download | netdev-vger-cvs-fe58c5e863f549493b9234d6461715440be63de5.tar.gz |
Use R3 for interrupt status reading instead
of R2. Change receive_chars to read the status byte with
each incomming character.
-rw-r--r-- | drivers/sbus/char/zs.c | 203 |
1 files changed, 79 insertions, 124 deletions
diff --git a/drivers/sbus/char/zs.c b/drivers/sbus/char/zs.c index 70c054018..8d714e1a6 100644 --- a/drivers/sbus/char/zs.c +++ b/drivers/sbus/char/zs.c @@ -1,4 +1,4 @@ -/* $Id: zs.c,v 1.68 2001-10-25 18:48:03 davem Exp $ +/* $Id: zs.c,v 1.69 2002-01-04 21:12:44 davem Exp $ * zs.c: Zilog serial port driver for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -486,10 +486,19 @@ extern void breakpoint(void); /* For the KGDB frame character */ static void receive_chars(struct sun_serial *info, struct pt_regs *regs) { struct tty_struct *tty = info->tty; - unsigned char ch, stat; - int do_queue_task = 1; + int do_queue_task = 0; + + while (1) { + unsigned char ch, r1; + + r1 = read_zsreg(info->zs_channel, R1); + if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) { + sbus_writeb(ERR_RES, &info->zs_channel->control); + ZSDELAY(); + ZS_WSYNC(info->zs_channel); + ZSLOG(REGCTRL, ERR_RES, 1); + } - do { ch = sbus_readb(&info->zs_channel->data); ZSLOG(REGDATA, ch, 0); ch &= info->parity_mask; @@ -498,17 +507,17 @@ static void receive_chars(struct sun_serial *info, struct pt_regs *regs) /* If this is the console keyboard, we need to handle * L1-A's here. */ - if(info->cons_keyb) { - if(ch == SUNKBD_RESET) { + if (info->cons_keyb) { + if (ch == SUNKBD_RESET) { l1a_state.kbd_id = 1; l1a_state.l1_down = 0; - } else if(l1a_state.kbd_id) { + } else if (l1a_state.kbd_id) { l1a_state.kbd_id = 0; - } else if(ch == SUNKBD_L1) { + } else if (ch == SUNKBD_L1) { l1a_state.l1_down = 1; - } else if(ch == (SUNKBD_L1|SUNKBD_UP)) { + } else if (ch == (SUNKBD_L1|SUNKBD_UP)) { l1a_state.l1_down = 0; - } else if(ch == SUNKBD_A && l1a_state.l1_down) { + } else if (ch == SUNKBD_A && l1a_state.l1_down) { /* whee... */ batten_down_hatches(); /* Continue execution... */ @@ -517,16 +526,14 @@ static void receive_chars(struct sun_serial *info, struct pt_regs *regs) return; } sunkbd_inchar(ch, regs); - do_queue_task = 0; goto next_char; } - if(info->cons_mouse) { + if (info->cons_mouse) { sun_mouse_inbyte(ch, 0); - do_queue_task = 0; goto next_char; } - if(info->is_cons) { - if(ch == 0) { + if (info->is_cons) { + if (ch == 0) { /* whee, break received */ batten_down_hatches(); /* Continue execution... */ @@ -540,32 +547,42 @@ static void receive_chars(struct sun_serial *info, struct pt_regs *regs) * documentation for remote target debugging and * arch/sparc/kernel/sparc-stub.c to see how all this works. */ - if((info->kgdb_channel) && (ch =='\003')) { + if (info->kgdb_channel && (ch =='\003')) { breakpoint(); return; } #endif - if(!tty) + if (!tty) return; + do_queue_task++; + if (tty->flip.count >= TTY_FLIPBUF_SIZE) break; tty->flip.count++; - *tty->flip.flag_buf_ptr++ = 0; + if (r1 & PAR_ERR) + *tty->flip.flag_buf_ptr++ = TTY_PARITY; + else if (r1 & Rx_OVR) + *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; + else if (r1 & CRC_ERR) + *tty->flip.flag_buf_ptr++ = TTY_FRAME; + else + *tty->flip.flag_buf_ptr++ = 0; *tty->flip.char_buf_ptr++ = ch; next_char: - /* Check if we have another character... */ - stat = sbus_readb(&info->zs_channel->control); - ZSDELAY(); - ZSLOG(REGCTRL, stat, 0); - if (!(stat & Rx_CH_AV)) - break; - - /* ... and see if it is clean. */ - stat = read_zsreg(info->zs_channel, R1); - } while (!(stat & (PAR_ERR | Rx_OVR | CRC_ERR))); + { + unsigned char stat; + + /* Check if we have another character... */ + stat = sbus_readb(&info->zs_channel->control); + ZSDELAY(); + ZSLOG(REGCTRL, stat, 0); + if (!(stat & Rx_CH_AV)) + break; + } + } if (do_queue_task != 0) queue_task(&tty->flip.tqueue, &tq_timer); @@ -582,7 +599,7 @@ static void transmit_chars(struct sun_serial *info) return; } - if((info->xmit_cnt <= 0) || (tty != 0 && tty->stopped)) { + if ((info->xmit_cnt <= 0) || (tty != 0 && tty->stopped)) { /* That's peculiar... */ sbus_writeb(RES_Tx_P, &info->zs_channel->control); ZSDELAY(); @@ -599,7 +616,7 @@ static void transmit_chars(struct sun_serial *info) if (info->xmit_cnt < WAKEUP_CHARS) zs_sched_event(info, RS_EVENT_WRITE_WAKEUP); - if(info->xmit_cnt <= 0) { + if (info->xmit_cnt <= 0) { sbus_writeb(RES_Tx_P, &info->zs_channel->control); ZSDELAY(); ZS_WSYNC(info->zs_channel); @@ -621,14 +638,14 @@ static void status_handle(struct sun_serial *info) ZS_WSYNC(info->zs_channel); ZSLOG(REGCTRL, RES_EXT_INT, 1); #if 0 - if(status & DCD) { - if((info->tty->termios->c_cflag & CRTSCTS) && - ((info->curregs[3] & AUTO_ENAB)==0)) { + if (status & DCD) { + if ((info->tty->termios->c_cflag & CRTSCTS) && + ((info->curregs[3] & AUTO_ENAB)==0)) { info->curregs[3] |= AUTO_ENAB; write_zsreg(info->zs_channel, 3, info->curregs[3]); } } else { - if((info->curregs[3] & AUTO_ENAB)) { + if ((info->curregs[3] & AUTO_ENAB)) { info->curregs[3] &= ~AUTO_ENAB; write_zsreg(info->zs_channel, 3, info->curregs[3]); } @@ -638,7 +655,7 @@ static void status_handle(struct sun_serial *info) * 'break asserted' status change interrupt, call * the boot prom. */ - if(status & BRK_ABRT) { + if (status & BRK_ABRT) { if (info->break_abort) batten_down_hatches(); if (info->cons_mouse) @@ -651,110 +668,49 @@ static void status_handle(struct sun_serial *info) return; } -static void special_receive(struct sun_serial *info) -{ - struct tty_struct *tty = info->tty; - unsigned char ch, stat; - - stat = read_zsreg(info->zs_channel, R1); - if (stat & (PAR_ERR | Rx_OVR | CRC_ERR)) { - ch = sbus_readb(&info->zs_channel->data); - ZSDELAY(); - ZSLOG(REGDATA, ch, 0); - } - - if (!tty) - goto clear; - - if (tty->flip.count >= TTY_FLIPBUF_SIZE) - goto done; - - tty->flip.count++; - if(stat & PAR_ERR) - *tty->flip.flag_buf_ptr++ = TTY_PARITY; - else if(stat & Rx_OVR) - *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; - else if(stat & CRC_ERR) - *tty->flip.flag_buf_ptr++ = TTY_FRAME; - -done: - queue_task(&tty->flip.tqueue, &tq_timer); -clear: - sbus_writeb(ERR_RES, &info->zs_channel->control); - ZSDELAY(); - ZS_WSYNC(info->zs_channel); - ZSLOG(REGCTRL, ERR_RES, 1); -} - - /* * This is the serial driver's generic interrupt routine */ void zs_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct sun_serial *info; - unsigned char zs_intreg; int i; info = (struct sun_serial *)dev_id; ZSLOG(REGIRQ, 0, 0); for (i = 0; i < NUM_SERIAL; i++) { - zs_intreg = read_zsreg(info->zs_next->zs_channel, 2); - zs_intreg &= STATUS_MASK; - - /* NOTE: The read register 2, which holds the irq status, - * does so for both channels on each chip. Although - * the status value itself must be read from the B - * channel and is only valid when read from channel B. - * When read from channel A, read register 2 contains - * the value written to write register 2. - */ + unsigned char r3 = read_zsreg(info->zs_channel, 3); /* Channel A -- /dev/ttya or /dev/kbd, could be the console */ - if (zs_intreg == CHA_Rx_AVAIL) { - receive_chars(info, regs); - return; - } - if(zs_intreg == CHA_Tx_EMPTY) { - transmit_chars(info); - return; - } - if (zs_intreg == CHA_EXT_STAT) { - status_handle(info); - return; - } - if (zs_intreg == CHA_SPECIAL) { - special_receive(info); - return; + if (r3 & (CHAEXT | CHATxIP | CHARxIP)) { + sbus_writeb(RES_H_IUS, &info->zs_channel->control); + ZSDELAY(); + ZS_WSYNC(info->zs_channel); + ZSLOG(REGCTRL, RES_H_IUS, 1); + if (r3 & CHARxIP) + receive_chars(info, regs); + if (r3 & CHAEXT) + status_handle(info); + if (r3 & CHATxIP) + transmit_chars(info); } /* Channel B -- /dev/ttyb or /dev/mouse, could be the console */ - if(zs_intreg == CHB_Rx_AVAIL) { - receive_chars(info->zs_next, regs); - return; + info = info->zs_next; + if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) { + sbus_writeb(RES_H_IUS, &info->zs_channel->control); + ZSDELAY(); + ZS_WSYNC(info->zs_channel); + ZSLOG(REGCTRL, RES_H_IUS, 1); + if (r3 & CHBRxIP) + receive_chars(info, regs); + if (r3 & CHBEXT) + status_handle(info); + if (r3 & CHBTxIP) + transmit_chars(info); } - if(zs_intreg == CHB_Tx_EMPTY) { - transmit_chars(info->zs_next); - return; - } - if (zs_intreg == CHB_EXT_STAT) { - status_handle(info->zs_next); - return; - } - - /* NOTE: The default value for the IRQ status in read register - * 2 in channel B is CHB_SPECIAL, so we need to look at - * read register 3 in channel A to check if this is a - * real interrupt, or just the default value. - * Yes... broken hardware... - */ - zs_intreg = read_zsreg(info->zs_channel, 3); - if (zs_intreg & CHBRxIP) { - special_receive(info->zs_next); - return; - } - info = info->zs_next->zs_next; + info = info->zs_next; } } @@ -1933,7 +1889,7 @@ int zs_open(struct tty_struct *tty, struct file * filp) static void show_serial_version(void) { - char *revision = "$Revision: 1.68 $"; + char *revision = "$Revision: 1.69 $"; char *version, *p; version = strchr(revision, ' '); @@ -2469,8 +2425,7 @@ int __init zs_init(void) /* Grab IRQ line before poking the chips so we do * not lose any interrupts. */ - if (request_irq(zilog_irq, zs_interrupt, - (SA_INTERRUPT | SA_STATIC_ALLOC), + if (request_irq(zilog_irq, zs_interrupt, SA_SHIRQ, "Zilog8530", zs_chain)) { prom_printf("Unable to attach zs intr\n"); prom_halt(); |