diff options
-rw-r--r-- | drivers/char/serial167.c | 3322 |
1 files changed, 1645 insertions, 1677 deletions
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index af50d32ae2c..5fd314adc1f 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c @@ -111,12 +111,13 @@ u_char initial_console_speed; /* This is the per-port data structure */ struct cyclades_port cy_port[] = { - /* CARD# */ - {-1 }, /* ttyS0 */ - {-1 }, /* ttyS1 */ - {-1 }, /* ttyS2 */ - {-1 }, /* ttyS3 */ + /* CARD# */ + {-1}, /* ttyS0 */ + {-1}, /* ttyS1 */ + {-1}, /* ttyS2 */ + {-1}, /* ttyS3 */ }; + #define NR_PORTS ARRAY_SIZE(cy_port) /* @@ -128,42 +129,46 @@ struct cyclades_port cy_port[] = { * HI VHI */ static int baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, - 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800,115200,150000, - 0}; + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, + 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000, + 0 +}; #if 0 -static char baud_co[] = { /* 25 MHz clock option table */ - /* value => 00 01 02 03 04 */ - /* divide by 8 32 128 512 2048 */ - 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02, - 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static char baud_co[] = { /* 25 MHz clock option table */ + /* value => 00 01 02 03 04 */ + /* divide by 8 32 128 512 2048 */ + 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02, + 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; -static char baud_bpr[] = { /* 25 MHz baud rate period table */ - 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3, - 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15}; +static char baud_bpr[] = { /* 25 MHz baud rate period table */ + 0x00, 0xf5, 0xa3, 0x6f, 0x5c, 0x51, 0xf5, 0xa3, 0x51, 0xa3, + 0x6d, 0x51, 0xa3, 0x51, 0xa3, 0x51, 0x36, 0x29, 0x1b, 0x15 +}; #endif /* I think 166 brd clocks 2401 at 20MHz.... */ /* These values are written directly to tcor, and >> 5 for writing to rcor */ -static u_char baud_co[] = { /* 20 MHz clock option table */ - 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x60, 0x60, 0x40, - 0x40, 0x40, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static u_char baud_co[] = { /* 20 MHz clock option table */ + 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x60, 0x60, 0x40, + 0x40, 0x40, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; /* These values written directly to tbpr/rbpr */ -static u_char baud_bpr[] = { /* 20 MHz baud rate period table */ - 0x00, 0xc0, 0x80, 0x58, 0x6c, 0x40, 0xc0, 0x81, 0x40, 0x81, - 0x57, 0x40, 0x81, 0x40, 0x81, 0x40, 0x2b, 0x20, 0x15, 0x10}; - -static u_char baud_cor4[] = { /* receive threshold */ - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07}; - +static u_char baud_bpr[] = { /* 20 MHz baud rate period table */ + 0x00, 0xc0, 0x80, 0x58, 0x6c, 0x40, 0xc0, 0x81, 0x40, 0x81, + 0x57, 0x40, 0x81, 0x40, 0x81, 0x40, 0x2b, 0x20, 0x15, 0x10 +}; +static u_char baud_cor4[] = { /* receive threshold */ + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07 +}; static void shutdown(struct cyclades_port *); -static int startup (struct cyclades_port *); +static int startup(struct cyclades_port *); static void cy_throttle(struct tty_struct *); static void cy_unthrottle(struct tty_struct *); static void config_setup(struct cyclades_port *); @@ -174,16 +179,16 @@ static void show_status(int); #ifdef CONFIG_REMOTE_DEBUG static void debug_setup(void); -void queueDebugChar (int c); +void queueDebugChar(int c); int getDebugChar(void); #define DEBUG_PORT 1 #define DEBUG_LEN 256 typedef struct { - int in; - int out; - unsigned char buf[DEBUG_LEN]; + int in; + int out; + unsigned char buf[DEBUG_LEN]; } debugq; debugq debugiq; @@ -196,7 +201,7 @@ debugq debugiq; * delay, but this wild guess will do for now. */ -void my_udelay (long us) +void my_udelay(long us) { u_char x; volatile u_char *p = &x; @@ -207,62 +212,73 @@ void my_udelay (long us) x |= *p; } -static inline int -serial_paranoia_check(struct cyclades_port *info, char *name, - const char *routine) +static inline int serial_paranoia_check(struct cyclades_port *info, char *name, + const char *routine) { #ifdef SERIAL_PARANOIA_CHECK - static const char *badmagic = - "Warning: bad magic number for serial struct (%s) in %s\n"; - static const char *badinfo = - "Warning: null cyclades_port for (%s) in %s\n"; - static const char *badrange = - "Warning: cyclades_port out of range for (%s) in %s\n"; - - if (!info) { - printk(badinfo, name, routine); - return 1; - } - - if( (long)info < (long)(&cy_port[0]) - || (long)(&cy_port[NR_PORTS]) < (long)info ){ - printk(badrange, name, routine); - return 1; - } - - if (info->magic != CYCLADES_MAGIC) { - printk(badmagic, name, routine); - return 1; - } + if (!info) { + printk("Warning: null cyclades_port for (%s) in %s\n", name, + routine); + return 1; + } + + if ((long)info < (long)(&cy_port[0]) + || (long)(&cy_port[NR_PORTS]) < (long)info) { + printk("Warning: cyclades_port out of range for (%s) in %s\n", + name, routine); + return 1; + } + + if (info->magic != CYCLADES_MAGIC) { + printk("Warning: bad magic number for serial struct (%s) in " + "%s\n", name, routine); + return 1; + } #endif return 0; -} /* serial_paranoia_check */ +} /* serial_paranoia_check */ #if 0 /* The following diagnostic routines allow the driver to spew information on the screen, even (especially!) during interrupts. */ -void -SP(char *data){ - unsigned long flags; - local_irq_save(flags); - console_print(data); - local_irq_restore(flags); +void SP(char *data) +{ + unsigned long flags; + local_irq_save(flags); + console_print(data); + local_irq_restore(flags); } + char scrn[2]; -void -CP(char data){ - unsigned long flags; - local_irq_save(flags); - scrn[0] = data; - console_print(scrn); - local_irq_restore(flags); -}/* CP */ +void CP(char data) +{ + unsigned long flags; + local_irq_save(flags); + scrn[0] = data; + console_print(scrn); + local_irq_restore(flags); +} /* CP */ -void CP1(int data) { (data<10)? CP(data+'0'): CP(data+'A'-10); }/* CP1 */ -void CP2(int data) { CP1((data>>4) & 0x0f); CP1( data & 0x0f); }/* CP2 */ -void CP4(int data) { CP2((data>>8) & 0xff); CP2(data & 0xff); }/* CP4 */ -void CP8(long data) { CP4((data>>16) & 0xffff); CP4(data & 0xffff); }/* CP8 */ +void CP1(int data) +{ + (data < 10) ? CP(data + '0') : CP(data + 'A' - 10); +} /* CP1 */ +void CP2(int data) +{ + CP1((data >> 4) & 0x0f); + CP1(data & 0x0f); +} /* CP2 */ +void CP4(int data) +{ + CP2((data >> 8) & 0xff); + CP2(data & 0xff); +} /* CP4 */ +void CP8(long data) +{ + CP4((data >> 16) & 0xffff); + CP4(data & 0xffff); +} /* CP8 */ #endif /* This routine waits up to 1000 micro-seconds for the previous @@ -270,87 +286,78 @@ void CP8(long data) { CP4((data>>16) & 0xffff); CP4(data & 0xffff); }/* CP8 */ new command. An error is returned if the previous command didn't finish within the time limit. */ -u_short -write_cy_cmd(volatile u_char *base_addr, u_char cmd) +u_short write_cy_cmd(volatile u_char * base_addr, u_char cmd) { - unsigned long flags; - volatile int i; + unsigned long flags; + volatile int i; - local_irq_save(flags); + local_irq_save(flags); /* Check to see that the previous command has completed */ - for(i = 0 ; i < 100 ; i++){ - if (base_addr[CyCCR] == 0){ - break; - } - my_udelay(10L); + for (i = 0; i < 100; i++) { + if (base_addr[CyCCR] == 0) { + break; + } + my_udelay(10L); } /* if the CCR never cleared, the previous command - didn't finish within the "reasonable time" */ - if ( i == 10 ) { - local_irq_restore(flags); - return (-1); + didn't finish within the "reasonable time" */ + if (i == 10) { + local_irq_restore(flags); + return (-1); } /* Issue the new command */ base_addr[CyCCR] = cmd; - local_irq_restore(flags); - return(0); -} /* write_cy_cmd */ - + local_irq_restore(flags); + return (0); +} /* write_cy_cmd */ /* cy_start and cy_stop provide software output flow control as a function of XON/XOFF, software CTS, and other such stuff. */ -static void -cy_stop(struct tty_struct *tty) +static void cy_stop(struct tty_struct *tty) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; - volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; - int channel; - unsigned long flags; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; + int channel; + unsigned long flags; #ifdef SERIAL_DEBUG_OTHER - printk("cy_stop %s\n", tty->name); /* */ + printk("cy_stop %s\n", tty->name); /* */ #endif - if (serial_paranoia_check(info, tty->name, "cy_stop")) - return; - - channel = info->line; + if (serial_paranoia_check(info, tty->name, "cy_stop")) + return; - local_irq_save(flags); - base_addr[CyCAR] = (u_char)(channel); /* index channel */ - base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy); - local_irq_restore(flags); + channel = info->line; - return; -} /* cy_stop */ + local_irq_save(flags); + base_addr[CyCAR] = (u_char) (channel); /* index channel */ + base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy); + local_irq_restore(flags); +} /* cy_stop */ -static void -cy_start(struct tty_struct *tty) +static void cy_start(struct tty_struct *tty) { - struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; - volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; - int channel; - unsigned long flags; + struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; + volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; + int channel; + unsigned long flags; #ifdef SERIAL_DEBUG_OTHER - printk("cy_start %s\n", tty->name); /* */ + printk("cy_start %s\n", tty->name); /* */ #endif - if (serial_paranoia_check(info, tty->name, "cy_start")) - return; - - channel = info->line; + if (serial_paranoia_check(info, tty->name, "cy_start")) + return; - local_irq_save(flags); - base_addr[CyCAR] = (u_char)(channel); - base_addr[CyIER] |= CyTxMpty; - local_irq_restore(flags); - - return; -} /* cy_start */ + channel = info->line; + local_irq_save(flags); + base_addr[CyCAR] = (u_char) (channel); + base_addr[CyIER] |= CyTxMpty; + local_irq_restore(flags); +} /* cy_start */ /* * This routine is used by the interrupt handler to schedule @@ -358,332 +365,332 @@ cy_start(struct tty_struct *tty) * (also known as the "bottom half"). This can be called any * number of times for any channel without harm. */ -static inline void -cy_sched_event(struct cyclades_port *info, int event) +static inline void cy_sched_event(struct cyclades_port *info, int event) { - info->event |= 1 << event; /* remember what kind of event and who */ - schedule_work(&info->tqueue); -} /* cy_sched_event */ - + info->event |= 1 << event; /* remember what kind of event and who */ + schedule_work(&info->tqueue); +} /* cy_sched_event */ /* The real interrupt service routines are called whenever the card wants its hand held--chars received, out buffer empty, modem change, etc. */ -static irqreturn_t -cd2401_rxerr_interrupt(int irq, void *dev_id) +static irqreturn_t cd2401_rxerr_interrupt(int irq, void *dev_id) { - struct tty_struct *tty; - struct cyclades_port *info; - volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; - unsigned char err, rfoc; - int channel; - char data; - - /* determine the channel and change to that context */ - channel = (u_short ) (base_addr[CyLICR] >> 2); - info = &cy_port[channel]; - info->last_active = jiffies; - - if ((err = base_addr[CyRISR]) & CyTIMEOUT) { - /* This is a receive timeout interrupt, ignore it */ - base_addr[CyREOIR] = CyNOTRANS; - return IRQ_HANDLED; - } - - /* Read a byte of data if there is any - assume the error - * is associated with this character */ + struct tty_struct *tty; + struct cyclades_port *info; + volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; + unsigned char err, rfoc; + int channel; + char data; + + /* determine the channel and change to that context */ + channel = (u_short) (base_addr[CyLICR] >> 2); + info = &cy_port[channel]; + info->last_active = jiffies; + + if ((err = base_addr[CyRISR]) & CyTIMEOUT) { + /* This is a receive timeout interrupt, ignore it */ + base_addr[CyREOIR] = CyNOTRANS; + return IRQ_HANDLED; + } - if ((rfoc = base_addr[CyRFOC]) != 0) - data = base_addr[CyRDR]; - else - data = 0; + /* Read a byte of data if there is any - assume the error + * is associated with this character */ - /* if there is nowhere to put the data, discard it */ - if(info->tty == 0) { + if ((rfoc = base_addr[CyRFOC]) != 0) + data = base_addr[CyRDR]; + else + data = 0; + + /* if there is nowhere to put the data, discard it */ + if (info->tty == 0) { + base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS; + return IRQ_HANDLED; + } else { /* there is an open port for this data */ + tty = info->tty; + if (err & info->ignore_status_mask) { + base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS; + return IRQ_HANDLED; + } + if (tty_buffer_request_room(tty, 1) != 0) { + if (err & info->read_status_mask) { + if (err & CyBREAK) { + tty_insert_flip_char(tty, data, + TTY_BREAK); + if (info->flags & ASYNC_SAK) { + do_SAK(tty); + } + } else if (err & CyFRAME) { + tty_insert_flip_char(tty, data, + TTY_FRAME); + } else if (err & CyPARITY) { + tty_insert_flip_char(tty, data, + TTY_PARITY); + } else if (err & CyOVERRUN) { + tty_insert_flip_char(tty, 0, + TTY_OVERRUN); + /* + If the flip buffer itself is + overflowing, we still loose + the next incoming character. + */ + if (tty_buffer_request_room(tty, 1) != + 0) { + tty_insert_flip_char(tty, data, + TTY_FRAME); + } + /* These two conditions may imply */ + /* a normal read should be done. */ + /* else if(data & CyTIMEOUT) */ + /* else if(data & CySPECHAR) */ + } else { + tty_insert_flip_char(tty, 0, + TTY_NORMAL); + } + } else { + tty_insert_flip_char(tty, data, TTY_NORMAL); + } + } else { + /* there was a software buffer overrun + and nothing could be done about it!!! */ + } + } + tty_schedule_flip(tty); + /* end of service */ base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS; return IRQ_HANDLED; - } - else { /* there is an open port for this data */ - tty = info->tty; - if(err & info->ignore_status_mask){ - base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS; - return IRQ_HANDLED; - } - if (tty_buffer_request_room(tty, 1) != 0){ - if (err & info->read_status_mask){ - if(err & CyBREAK){ - tty_insert_flip_char(tty, data, TTY_BREAK); - if (info->flags & ASYNC_SAK){ - do_SAK(tty); - } - }else if(err & CyFRAME){ - tty_insert_flip_char(tty, data, TTY_FRAME); - }else if(err & CyPARITY){ - tty_insert_flip_char(tty, data, TTY_PARITY); - }else if(err & CyOVERRUN){ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - /* - If the flip buffer itself is - overflowing, we still loose - the next incoming character. - */ - if (tty_buffer_request_room(tty, 1) != 0){ - tty_insert_flip_char(tty, data, TTY_FRAME); - } - /* These two conditions may imply */ - /* a normal read should be done. */ - /* else if(data & CyTIMEOUT) */ - /* else if(data & CySPECHAR) */ - }else{ - tty_insert_flip_char(tty, 0, TTY_NORMAL); - } - }else{ - tty_insert_flip_char(tty, data, TTY_NORMAL); - } - }else{ - /* there was a software buffer overrun - and nothing could be done about it!!! */ - } - } - tty_schedule_flip(tty); - /* end of service */ - base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS; - return IRQ_HANDLED; -} /* cy_rxerr_interrupt */ - -static irqreturn_t -cd2401_modem_interrupt(int irq, void *dev_id) +} /* cy_rxerr_interrupt */ + +static irqreturn_t cd2401_modem_interrupt(int irq, void *dev_id) { - struct cyclades_port *info; - volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; - int channel; - int mdm_change; - int mdm_status; - - - /* determine the channel and change to that context */ - channel = (u_short ) (base_addr[CyLICR] >> 2); - info = &cy_port[channel]; - info->last_active = jiffies; - - mdm_change = base_addr[CyMISR]; - mdm_status = base_addr[CyMSVR1]; - - if(info->tty == 0){ /* nowhere to put the data, ignore it */ - ; - }else{ - if((mdm_change & CyDCD) - && (info->flags & ASYNC_CHECK_CD)){ - if(mdm_status & CyDCD){ + struct cyclades_port *info; + volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; + int channel; + int mdm_change; + int mdm_status; + + /* determine the channel and change to that context */ + channel = (u_short) (base_addr[CyLICR] >> 2); + info = &cy_port[channel]; + info->last_active = jiffies; + + mdm_change = base_addr[CyMISR]; + mdm_status = base_addr[CyMSVR1]; + + if (info->tty == 0) { /* nowhere to put the data, ignore it */ + ; + } else { + if ((mdm_change & CyDCD) + && (info->flags & ASYNC_CHECK_CD)) { + if (mdm_status & CyDCD) { /* CP('!'); */ - cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP); - } else { + cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP); + } else { /* CP('@'); */ - cy_sched_event(info, Cy_EVENT_HANGUP); - } - } - if((mdm_change & CyCTS) - && (info->flags & ASYNC_CTS_FLOW)){ - if(info->tty->stopped){ - if(mdm_status & CyCTS){ - /* !!! cy_start isn't used because... */ - info->tty->stopped = 0; - base_addr[CyIER] |= CyTxMpty; - cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP); + cy_sched_event(info, Cy_EVENT_HANGUP); + } } - }else{ - if(!(mdm_status & CyCTS)){ - /* !!! cy_stop isn't used because... */ - info->tty->stopped = 1; - base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy); + if ((mdm_change & CyCTS) + && (info->flags & ASYNC_CTS_FLOW)) { + if (info->tty->stopped) { + if (mdm_status & CyCTS) { + /* !!! cy_start isn't used because... */ + info->tty->stopped = 0; + base_addr[CyIER] |= CyTxMpty; + cy_sched_event(info, + Cy_EVENT_WRITE_WAKEUP); + } + } else { + if (!(mdm_status & CyCTS)) { + /* !!! cy_stop isn't used because... */ + info->tty->stopped = 1; + base_addr[CyIER] &= + ~(CyTxMpty | CyTxRdy); + } + } + } + if (mdm_status & CyDSR) { } - } - } - if(mdm_status & CyDSR){ } - } - base_addr[CyMEOIR] = 0; - return IRQ_HANDLED; -} /* cy_modem_interrupt */ + base_addr[CyMEOIR] = 0; + return IRQ_HANDLED; +} /* cy_modem_interrupt */ -static irqreturn_t -cd2401_tx_interrupt(int irq, void *dev_id) +static irqreturn_t cd2401_tx_interrupt(int irq, void *dev_id) { - struct cyclades_port *info; - volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; - int channel; - int char_count, saved_cnt; - int outch; + struct cyclades_port *info; + volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; + int channel; + int char_count, saved_cnt; + int outch; - /* determine the channel and change to that context */ - channel = (u_short ) (base_addr[CyLICR] >> 2); + /* determine the channel and change to that context */ + channel = (u_short) (base_addr[CyLICR] >> 2); #ifdef CONFIG_REMOTE_DEBUG - if (channel == DEBUG_PORT) { - panic ("TxInt on debug port!!!"); - } + if (channel == DEBUG_PORT) { + panic("TxInt on debug port!!!"); + } #endif - info = &cy_port[channel]; + info = &cy_port[channel]; - /* validate the port number (as configured and open) */ - if( (channel < 0) || (NR_PORTS <= channel) ){ - base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy); - base_addr[CyTEOIR] = CyNOTRANS; - return IRQ_HANDLED; - } - info->last_active = jiffies; - if(info->tty == 0){ - base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy); - if (info->xmit_cnt < WAKEUP_CHARS) { - cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP); - } - base_addr[CyTEOIR] = CyNOTRANS; - return IRQ_HANDLED; - } - - /* load the on-chip space available for outbound data */ - saved_cnt = char_count = base_addr[CyTFTC]; - - if(info->x_char) { /* send special char */ - outch = info->x_char; - base_addr[CyTDR] = outch; - char_count--; - info->x_char = 0; - } - - if (info->x_break){ - /* The Cirrus chip requires the "Embedded Transmit - Commands" of start break, delay, and end break - sequences to be sent. The duration of the - break is given in TICs, which runs at HZ - (typically 100) and the PPR runs at 200 Hz, - so the delay is duration * 200/HZ, and thus a - break can run from 1/100 sec to about 5/4 sec. - Need to check these values - RGH 141095. - */ - base_addr[CyTDR] = 0; /* start break */ - base_addr[CyTDR] = 0x81; - base_addr[CyTDR] = 0; /* delay a bit */ - base_addr[CyTDR] = 0x82; - base_addr[CyTDR] = info->x_break*200/HZ; - base_addr[CyTDR] = 0; /* terminate break */ - base_addr[CyTDR] = 0x83; - char_count -= 7; - info->x_break = 0; - } - - while (char_count > 0){ - if (!info->xmit_cnt){ - base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy); - break; - } - if (info->xmit_buf == 0){ - base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy); - break; - } - if (info->tty->stopped || info->tty->hw_stopped){ - base_addr[CyIER] &= ~(CyTxMpty|CyTxRdy); - break; - } - /* Because the Embedded Transmit Commands have been - enabled, we must check to see if the escape - character, NULL, is being sent. If it is, we - must ensure that there is room for it to be - doubled in the output stream. Therefore we - no longer advance the pointer when the character - is fetched, but rather wait until after the check - for a NULL output character. (This is necessary - because there may not be room for the two chars - needed to send a NULL. - */ - outch = info->xmit_buf[info->xmit_tail]; - if( outch ){ - info->xmit_cnt--; - info->xmit_tail = (info->xmit_tail + 1) - & (PAGE_SIZE - 1); - base_addr[CyTDR] = outch; - char_count--; - }else{ - if(char_count > 1){ - info->xmit_cnt--; - info->xmit_tail = (info->xmit_tail + 1) - & (PAGE_SIZE - 1); + /* validate the port number (as configured and open) */ + if ((channel < 0) || (NR_PORTS <= channel)) { + base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy); + base_addr[CyTEOIR] = CyNOTRANS; + return IRQ_HANDLED; + } + info->last_active = jiffies; + if (info->tty == 0) { + base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy); + if (info->xmit_cnt < WAKEUP_CHARS) { + cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP); + } + base_addr[CyTEOIR] = CyNOTRANS; + return IRQ_HANDLED; + } + + /* load the on-chip space available for outbound data */ + saved_cnt = char_count = base_addr[CyTFTC]; + + if (info->x_char) { /* send special char */ + outch = info->x_char; base_addr[CyTDR] = outch; - base_addr[CyTDR] = 0; char_count--; - char_count--; - }else{ - break; - } + info->x_char = 0; } - } - if (info->xmit_cnt < WAKEUP_CHARS) { - cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP); - } - base_addr[CyTEOIR] = (char_count != saved_cnt) ? 0 : CyNOTRANS; - return IRQ_HANDLED; -} /* cy_tx_interrupt */ + if (info->x_break) { + /* The Cirrus chip requires the "Embedded Transmit + Commands" of start break, delay, and end break + sequences to be sent. The duration of the + break is given in TICs, which runs at HZ + (typically 100) and the PPR runs at 200 Hz, + so the delay is duration * 200/HZ, and thus a + break can run from 1/100 sec to about 5/4 sec. + Need to check these values - RGH 141095. + */ + base_addr[CyTDR] = 0; /* start break */ + base_addr[CyTDR] = 0x81; + base_addr[CyTDR] = 0; /* delay a bit */ + base_addr[CyTDR] = 0x82; + base_addr[CyTDR] = info->x_break * 200 / HZ; + base_addr[CyTDR] = 0; /* terminate break */ + base_addr[CyTDR] = 0x83; + char_count -= 7; + info->x_break = 0; + } + + while (char_count > 0) { + if (!info->xmit_cnt) { + base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy); + break; + } + if (info->xmit_buf == 0) { + base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy); + break; + } + if (info->tty->stopped || info->tty->hw_stopped) { + base_addr[CyIER] &= ~(CyTxMpty | CyTxRdy); + break; + } + /* Because the Embedded Transmit Commands have been + enabled, we must check to see if the escape + character, NULL, is being sent. If it is, we + must ensure that there is room for it to be + doubled in the output stream. Therefore we + no longer advance the pointer when the character + is fetched, but rather wait until after the check + for a NULL output character. (This is necessary + because there may not be room for the two chars + needed to send a NULL. + */ + outch = info->xmit_buf[info->xmit_tail]; + if (outch) { + info->xmit_cnt--; + info->xmit_tail = (info->xmit_tail + 1) + & (PAGE_SIZE - 1); + base_addr[CyTDR] = outch; + char_count--; + } else { + if (char_count > 1) { + info->xmit_cnt--; + info->xmit_tail = (info->xmit_tail + 1) + & (PAGE_SIZE - 1); + base_addr[CyTDR] = outch; + base_addr[CyTDR] = 0; + char_count--; + char_count--; + } else { + break; + } + } + } + + if (info->xmit_cnt < WAKEUP_CHARS) { + cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP); + } + base_addr[CyTEOIR] = (char_count != saved_cnt) ? 0 : CyNOTRANS; + return IRQ_HANDLED; +} /* cy_tx_interrupt */ -static irqreturn_t -cd2401_rx_interrupt(int irq, void *dev_id) +static irqreturn_t cd2401_rx_interrupt(int irq, void *dev_id) { - struct tty_struct *tty; - struct cyclades_port *info; - volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; - int channel; - char data; - int char_count; - int save_cnt; - int len; - - /* determine the channel and change to that context */ - channel = (u_short ) (base_addr[CyLICR] >> 2); - info = &cy_port[channel]; - info->last_active = jiffies; - save_cnt = char_count = base_addr[CyRFOC]; + struct tty_struct *tty; + struct cyclades_port *info; + volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; + int channel; + char data; + int char_count; + int save_cnt; + int len; + + /* determine the channel and change to that context */ + channel = (u_short) (base_addr[CyLICR] >> 2); + info = &cy_port[channel]; + info->last_active = jiffies; + save_cnt = char_count = base_addr[CyRFOC]; #ifdef CONFIG_REMOTE_DEBUG - if (channel == DEBUG_PORT) { - while (char_count--) { - data = base_addr[CyRDR]; - queueDebugChar(data); - } - } - else + if (channel == DEBUG_PORT) { + while (char_count--) { + data = base_addr[CyRDR]; + queueDebugChar(data); + } + } else #endif - /* if there is nowhere to put the data, discard it */ - if(info->tty == 0){ - while(char_count--){ - data = base_addr[CyRDR]; - } - }else{ /* there is an open port for this data */ - tty = info->tty; - /* load # characters available from the chip */ + /* if there is nowhere to put the data, discard it */ + if (info->tty == 0) { + while (char_count--) { + data = base_addr[CyRDR]; + } + } else { /* there is an open port for this data */ + tty = info->tty; + /* load # characters available from the chip */ #ifdef CYCLOM_ENABLE_MONITORING - ++info->mon.int_count; - info->mon.char_count += char_count; - if (char_count > info->mon.char_max) - info->mon.char_max = char_count; - info->mon.char_last = char_count; -#endif - len = tty_buffer_request_room(tty, char_count); - while(len--){ - data = base_addr[CyRDR]; - tty_insert_flip_char(tty, data, TTY_NORMAL); + ++info->mon.int_count; + info->mon.char_count += char_count; + if (char_count > info->mon.char_max) + info->mon.char_max = char_count; + info->mon.char_last = char_count; +#endif + len = tty_buffer_request_room(tty, char_count); + while (len--) { + data = base_addr[CyRDR]; + tty_insert_flip_char(tty, data, TTY_NORMAL); #ifdef CYCLOM_16Y_HACK - udelay(10L); + udelay(10L); #endif - } - tty_schedule_flip(tty); - } - /* end of service */ - base_addr[CyREOIR] = save_cnt ? 0 : CyNOTRANS; - return IRQ_HANDLED; -} /* cy_rx_interrupt */ + } + tty_schedule_flip(tty); + } + /* end of service */ + base_addr[CyREOIR] = save_cnt ? 0 : CyNOTRANS; + return IRQ_HANDLED; +} /* cy_rx_interrupt */ /* * This routine is used to handle the "bottom half" processing for the @@ -705,192 +712,188 @@ cd2401_rx_interrupt(int irq, void *dev_id) * structure) to the bottom half of the driver. Previous kernels * had to poll every port to see if that port needed servicing. */ -static void -do_softint(struct work_struct *ugly_api) +static void do_softint(struct work_struct *ugly_api) { - struct cyclades_port *info = container_of(ugly_api, struct cyclades_port, tqueue); - struct tty_struct *tty; - - tty = info->tty; - if (!tty) - return; + struct cyclades_port *info = + container_of(ugly_api, struct cyclades_port, tqueue); + struct tty_struct *tty; - if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) { - tty_hangup(info->tty); - wake_up_interruptible(&info->open_wait); - info->flags &= ~ASYNC_NORMAL_ACTIVE; - } - if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) { - wake_up_interruptible(&info->open_wait); - } - if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) { - tty_wakeup(tty); - } -} /* do_softint */ + tty = info->tty; + if (!tty) + return; + if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) { + tty_hangup(info->tty); + wake_up_interruptible(&info->open_wait); + info->flags &= ~ASYNC_NORMAL_ACTIVE; + } + if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) { + wake_up_interruptible(&info->open_wait); + } + if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) { + tty_wakeup(tty); + } +} /* do_softint */ /* This is called whenever a port becomes active; interrupts are enabled and DTR & RTS are turned on. */ -static int -startup(struct cyclades_port * info) +static int startup(struct cyclades_port *info) { - unsigned long flags; - volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; - int channel; + unsigned long flags; + volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR; + int channel; - if (info->flags & ASYNC_INITIALIZED){ - return 0; - } + if (info->flags & ASYNC_INITIALIZED) { + return 0; + } - if (!info->type){ - if (info->tty){ - set_bit(TTY_IO_ERROR, &info->tty->flags); + if (!info->type) { + if (info->tty) { + set_bit(TTY_IO_ERROR, &info->tty->flags); + } + return 0; } - return 0; - } - if (!info->xmit_buf){ - info->xmit_buf = (unsigned char *) get_zeroed_page (GFP_KERNEL); - if (!info->xmit_buf){ - return -ENOMEM; + if (!info->xmit_buf) { + info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL); + if (!info->xmit_buf) { + return -ENOMEM; + } } - } - config_setup(info); + config_setup(info); - channel = info->line; + channel = info->line; #ifdef SERIAL_DEBUG_OPEN - printk("startup channel %d\n", channel); + printk("startup channel %d\n", channel); #endif - local_irq_save(flags); - base_addr[CyCAR] = (u_char)channel; - write_cy_cmd(base_addr,CyENB_RCVR|CyENB_XMTR); + local_irq_save(flags); + base_addr[CyCAR] = (u_char) channel; + write_cy_cmd(base_addr, CyENB_RCVR | CyENB_XMTR); - base_addr[CyCAR] = (u_char)channel; /* !!! Is this needed? */ + base_addr[CyCAR] = (u_char) channel; /* !!! Is this needed? */ base_addr[CyMSVR1] = CyRTS; /* CP('S');CP('1'); */ base_addr[CyMSVR2] = CyDTR; #ifdef SERIAL_DEBUG_DTR - printk("cyc: %d: raising DTR\n", __LINE__); - printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]); + printk("cyc: %d: raising DTR\n", __LINE__); + printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], + base_addr[CyMSVR2]); #endif base_addr[CyIER] |= CyRxData; info->flags |= ASYNC_INITIALIZED; - if (info->tty){ - clear_bit(TTY_IO_ERROR, &info->tty->flags); + if (info->tty) { + clear_bit(TTY_IO_ERROR, &info->tty->flags); } info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - local_irq_restore(flags); + local_irq_restore(flags); #ifdef SERIAL_DEBUG_OPEN - printk(" done\n"); + printk(" done\n"); #endif - return 0; -} /* startup */ + return 0; +} /* startup */ -void -start_xmit( struct cyclades_port *info ) +void start_xmit(struct cyclades_port *info) { - unsigned long flags; - volatile unsigned char *base_addr = (u_char *)BASE_ADDR; - int channel; + unsigned long flags; + volatile unsigned char *base_addr = (u_char *) BASE_ADDR; + int channel; - channel = info->line; - local_irq_save(flags); + channel = info->line; + local_irq_save(flags); base_addr[CyCAR] = channel; base_addr[CyIER] |= CyTxMpty; - local_irq_restore(flags); -} /* start_xmit */ + local_irq_restore(flags); +} /* start_xmit */ /* * This routine shuts down a serial port; interrupts are disabled, * and DTR is dropped if the hangup on close termio flag is on. */ -static void -shutdown(struct cyclades_port * info) |