diff options
Diffstat (limited to 'drivers/char/cyclades.c')
-rw-r--r-- | drivers/char/cyclades.c | 7804 |
1 files changed, 3943 insertions, 3861 deletions
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index c1c67281750..3ffa0807754 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -1,8 +1,6 @@ #undef BLOCKMOVE #define Z_WAKE #undef Z_EXT_CHARS_IN_BUFFER -static char rcsid[] = -"$Revision: 2.3.2.20 $$Date: 2004/02/25 18:14:16 $"; /* * linux/drivers/char/cyclades.c @@ -593,18 +591,20 @@ static char rcsid[] = * */ +#define CY_VERSION "2.4" + /* If you need to install more boards than NR_CARDS, change the constant in the definition below. No other change is necessary to support up to eight boards. Beyond that you'll have to extend cy_isa_addresses. */ -#define NR_CARDS 4 +#define NR_CARDS 4 /* If the total number of ports is larger than NR_PORTS, change this constant in the definition below. No other change is necessary to support more boards/ports. */ -#define NR_PORTS 256 +#define NR_PORTS 256 #define ZE_V1_NPORTS 64 #define ZO_V1 0 @@ -625,9 +625,9 @@ static char rcsid[] = #undef CY_PCI_DEBUG #if 0 -#define PAUSE __asm__("nop"); +#define PAUSE __asm__("nop") #else -#define PAUSE ; +#define PAUSE do {} while (0) #endif /* @@ -663,7 +663,7 @@ static char rcsid[] = do { \ spin_lock_irqsave(&cy_card[info->card].card_lock, flags); \ } while (0) - + #define CY_UNLOCK(info,flags) \ do { \ spin_unlock_irqrestore(&cy_card[info->card].card_lock, flags); \ @@ -676,14 +676,14 @@ static char rcsid[] = #include <linux/stat.h> #include <linux/proc_fs.h> -static void cy_throttle (struct tty_struct *tty); -static void cy_send_xchar (struct tty_struct *tty, char ch); +static void cy_throttle(struct tty_struct *tty); +static void cy_send_xchar(struct tty_struct *tty, char ch); #define IS_CYC_Z(card) ((card).num_chips == -1) #define Z_FPGA_CHECK(card) \ - ((cy_readl(&((struct RUNTIME_9060 __iomem *) \ - ((card).ctl_addr))->init_ctrl) & (1<<17)) != 0) + ((cy_readl(&((struct RUNTIME_9060 __iomem *) \ + ((card).ctl_addr))->init_ctrl) & (1<<17)) != 0) #define ISZLOADED(card) (((ZO_V1==cy_readl(&((struct RUNTIME_9060 __iomem *) \ ((card).ctl_addr))->mail_box_0)) || \ @@ -698,8 +698,6 @@ static void cy_send_xchar (struct tty_struct *tty, char ch); #define STD_COM_FLAGS (0) -#define JIFFIES_DIFF(n, j) ((j) - (n)) - static struct tty_driver *cy_serial_driver; #ifdef CONFIG_ISA @@ -713,27 +711,28 @@ static struct tty_driver *cy_serial_driver; */ static unsigned int cy_isa_addresses[] = { - 0xD0000, - 0xD2000, - 0xD4000, - 0xD6000, - 0xD8000, - 0xDA000, - 0xDC000, - 0xDE000, - 0,0,0,0,0,0,0,0 + 0xD0000, + 0xD2000, + 0xD4000, + 0xD6000, + 0xD8000, + 0xDA000, + 0xDC000, + 0xDE000, + 0, 0, 0, 0, 0, 0, 0, 0 }; + #define NR_ISA_ADDRS ARRAY_SIZE(cy_isa_addresses) #ifdef MODULE static long maddr[NR_CARDS] = { 0, }; -static int irq[NR_CARDS] = { 0, }; +static int irq[NR_CARDS] = { 0, }; module_param_array(maddr, long, NULL, 0); module_param_array(irq, int, NULL, 0); #endif -#endif /* CONFIG_ISA */ +#endif /* CONFIG_ISA */ /* This is the per-card data structure containing address, irq, number of channels, etc. This driver supports a maximum of NR_CARDS cards. @@ -745,19 +744,7 @@ static struct cyclades_card cy_card[NR_CARDS]; */ static struct cyclades_port cy_port[NR_PORTS]; -static int cy_next_channel; /* next minor available */ - -/* - * 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. This buffer is - * allocated when the first cy_open occurs. - */ -static unsigned char *tmp_buf; +static int cy_next_channel; /* next minor available */ /* * This is used to look up the divisor speeds and the timeouts @@ -769,36 +756,42 @@ static unsigned char *tmp_buf; * 20 */ static int baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, - 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800,115200,150000, - 230400, 0}; - -static char baud_co_25[] = { /* 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[] = { /* 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_co_60[] = { /* 60 MHz clock option table (CD1400 J) */ - /* value => 00 01 02 03 04 */ - /* divide by 8 32 128 512 2048 */ - 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, - 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00}; - -static char baud_bpr_60[] = { /* 60 MHz baud rate period table (CD1400 J) */ - 0x00, 0x82, 0x21, 0xff, 0xdb, 0xc3, 0x92, 0x62, 0xc3, 0x62, - 0x41, 0xc3, 0x62, 0xc3, 0x62, 0xc3, 0x82, 0x62, 0x41, 0x32, - 0x21}; - -static char baud_cor3[] = { /* receive threshold */ - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07, - 0x07}; + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, + 1800, 2400, 4800, 9600, 19200, 38400, 57600, 76800, 115200, 150000, + 230400, 0 +}; + +static char baud_co_25[] = { /* 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[] = { /* 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_co_60[] = { /* 60 MHz clock option table (CD1400 J) */ + /* value => 00 01 02 03 04 */ + /* divide by 8 32 128 512 2048 */ + 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, + 0x03, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00 +}; + +static char baud_bpr_60[] = { /* 60 MHz baud rate period table (CD1400 J) */ + 0x00, 0x82, 0x21, 0xff, 0xdb, 0xc3, 0x92, 0x62, 0xc3, 0x62, + 0x41, 0xc3, 0x62, 0xc3, 0x62, 0xc3, 0x82, 0x62, 0x41, 0x32, + 0x21 +}; + +static char baud_cor3[] = { /* receive threshold */ + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07, + 0x07 +}; /* * The Cyclades driver implements HW flow control as any serial driver. @@ -811,42 +804,42 @@ static char baud_cor3[] = { /* receive threshold */ * cables. */ -static char rflow_thr[] = { /* rflow threshold */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a}; +static char rflow_thr[] = { /* rflow threshold */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a +}; /* The Cyclom-Ye has placed the sequential chips in non-sequential * address order. This look-up table overcomes that problem. */ -static int cy_chip_offset [] = - { 0x0000, - 0x0400, - 0x0800, - 0x0C00, - 0x0200, - 0x0600, - 0x0A00, - 0x0E00 - }; +static int cy_chip_offset[] = { 0x0000, + 0x0400, + 0x0800, + 0x0C00, + 0x0200, + 0x0600, + 0x0A00, + 0x0E00 +}; /* PCI related definitions */ -static unsigned short cy_pci_nboard; -static unsigned short cy_isa_nboard; -static unsigned short cy_nboard; +static unsigned short cy_pci_nboard; +static unsigned short cy_isa_nboard; +static unsigned short cy_nboard; #ifdef CONFIG_PCI -static unsigned short cy_pci_dev_id[] = { - PCI_DEVICE_ID_CYCLOM_Y_Lo, /* PCI < 1Mb */ - PCI_DEVICE_ID_CYCLOM_Y_Hi, /* PCI > 1Mb */ - PCI_DEVICE_ID_CYCLOM_4Y_Lo, /* 4Y PCI < 1Mb */ - PCI_DEVICE_ID_CYCLOM_4Y_Hi, /* 4Y PCI > 1Mb */ - PCI_DEVICE_ID_CYCLOM_8Y_Lo, /* 8Y PCI < 1Mb */ - PCI_DEVICE_ID_CYCLOM_8Y_Hi, /* 8Y PCI > 1Mb */ - PCI_DEVICE_ID_CYCLOM_Z_Lo, /* Z PCI < 1Mb */ - PCI_DEVICE_ID_CYCLOM_Z_Hi, /* Z PCI > 1Mb */ - 0 /* end of table */ - }; +static unsigned short cy_pci_dev_id[] = { + PCI_DEVICE_ID_CYCLOM_Y_Lo, /* PCI < 1Mb */ + PCI_DEVICE_ID_CYCLOM_Y_Hi, /* PCI > 1Mb */ + PCI_DEVICE_ID_CYCLOM_4Y_Lo, /* 4Y PCI < 1Mb */ + PCI_DEVICE_ID_CYCLOM_4Y_Hi, /* 4Y PCI > 1Mb */ + PCI_DEVICE_ID_CYCLOM_8Y_Lo, /* 8Y PCI < 1Mb */ + PCI_DEVICE_ID_CYCLOM_8Y_Hi, /* 8Y PCI > 1Mb */ + PCI_DEVICE_ID_CYCLOM_Z_Lo, /* Z PCI < 1Mb */ + PCI_DEVICE_ID_CYCLOM_Z_Hi, /* Z PCI > 1Mb */ + 0 /* end of table */ +}; #endif static void cy_start(struct tty_struct *); @@ -854,9 +847,9 @@ static void set_line_char(struct cyclades_port *); static int cyz_issue_cmd(struct cyclades_card *, uclong, ucchar, uclong); #ifdef CONFIG_ISA static unsigned detect_isa_irq(void __iomem *); -#endif /* CONFIG_ISA */ +#endif /* CONFIG_ISA */ -static int cyclades_get_proc_info(char *, char **, off_t , int , int *, void *); +static int cyclades_get_proc_info(char *, char **, off_t, int, int *, void *); #ifndef CONFIG_CYZ_INTR static void cyz_poll(unsigned long); @@ -867,41 +860,36 @@ static long cyz_polling_cycle = CZ_DEF_POLL; static int cyz_timeron = 0; static DEFINE_TIMER(cyz_timerlist, cyz_poll, 0, 0); -#else /* CONFIG_CYZ_INTR */ +#else /* CONFIG_CYZ_INTR */ static void cyz_rx_restart(unsigned long); static struct timer_list cyz_rx_full_timer[NR_PORTS]; -#endif /* CONFIG_CYZ_INTR */ +#endif /* CONFIG_CYZ_INTR */ -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 = - "cyc Warning: bad magic number for serial struct (%s) in %s\n"; - static const char *badinfo = - "cyc Warning: null cyclades_port for (%s) in %s\n"; - static const char *badrange = - "cyc 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("cyc 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("cyc Warning: cyclades_port out of range for (%s) in " + "%s\n", name, routine); + return 1; + } + + if (info->magic != CYCLADES_MAGIC) { + printk("cyc Warning: bad magic number for serial struct (%s) " + "in %s\n", name, routine); + return 1; + } #endif - return 0; -} /* serial_paranoia_check */ + return 0; +} /* serial_paranoia_check */ /* * This routine is used by the interrupt handler to schedule @@ -909,13 +897,11 @@ serial_paranoia_check(struct cyclades_port *info, * (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 */ /* * This routine is used to handle the "bottom half" processing for the @@ -938,44 +924,40 @@ cy_sched_event(struct cyclades_port *info, int event) * had to poll every port to see if that port needed servicing. */ static void -do_softint(void *private_) +do_softint(struct work_struct *work) { - struct cyclades_port *info = (struct cyclades_port *) private_; - struct tty_struct *tty; - - 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); - } + struct cyclades_port *info = + container_of(work, struct cyclades_port, tqueue); + struct tty_struct *tty; + + 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); #ifdef CONFIG_CYZ_INTR - if (test_and_clear_bit(Cy_EVENT_Z_RX_FULL, &info->event)) { - if (cyz_rx_full_timer[info->line].function == NULL) { - cyz_rx_full_timer[info->line].expires = jiffies + 1; - cyz_rx_full_timer[info->line].function = cyz_rx_restart; - cyz_rx_full_timer[info->line].data = (unsigned long)info; - add_timer(&cyz_rx_full_timer[info->line]); + if (test_and_clear_bit(Cy_EVENT_Z_RX_FULL, &info->event)) { + if (cyz_rx_full_timer[info->line].function == NULL) { + cyz_rx_full_timer[info->line].expires = jiffies + 1; + cyz_rx_full_timer[info->line].function = cyz_rx_restart; + cyz_rx_full_timer[info->line].data = + (unsigned long)info; + add_timer(&cyz_rx_full_timer[info->line]); + } } - } #endif - if (test_and_clear_bit(Cy_EVENT_DELTA_WAKEUP, &info->event)) { - wake_up_interruptible(&info->delta_msr_wait); - } - if (test_and_clear_bit(Cy_EVENT_WRITE_WAKEUP, &info->event)) { - tty_wakeup(tty); - wake_up_interruptible(&tty->write_wait); - } + if (test_and_clear_bit(Cy_EVENT_DELTA_WAKEUP, &info->event)) + wake_up_interruptible(&info->delta_msr_wait); + tty_wakeup(tty); #ifdef Z_WAKE - if (test_and_clear_bit(Cy_EVENT_SHUTDOWN_WAKEUP, &info->event)) { - wake_up_interruptible(&info->shutdown_wait); - } + if (test_and_clear_bit(Cy_EVENT_SHUTDOWN_WAKEUP, &info->event)) + wake_up_interruptible(&info->shutdown_wait); #endif } /* do_softint */ @@ -990,341 +972,339 @@ do_softint(void *private_) This function is only called from inside spinlock-protected code. */ -static int -cyy_issue_cmd(void __iomem *base_addr, u_char cmd, int index) +static int cyy_issue_cmd(void __iomem * base_addr, u_char cmd, int index) { - volatile int i; + volatile int i; - /* Check to see that the previous command has completed */ - for(i = 0 ; i < 100 ; i++){ - if (cy_readb(base_addr+(CyCCR<<index)) == 0){ - break; + /* Check to see that the previous command has completed */ + for (i = 0; i < 100; i++) { + if (cy_readb(base_addr + (CyCCR << index)) == 0) { + break; + } + udelay(10L); } - udelay(10L); - } - /* if the CCR never cleared, the previous command - didn't finish within the "reasonable time" */ - if (i == 100) return (-1); + /* if the CCR never cleared, the previous command + didn't finish within the "reasonable time" */ + if (i == 100) + return -1; - /* Issue the new command */ - cy_writeb(base_addr+(CyCCR<<index), cmd); + /* Issue the new command */ + cy_writeb(base_addr + (CyCCR << index), cmd); - return(0); -} /* cyy_issue_cmd */ + return 0; +} /* cyy_issue_cmd */ #ifdef CONFIG_ISA /* ISA interrupt detection code */ -static unsigned -detect_isa_irq(void __iomem *address) +static unsigned detect_isa_irq(void __iomem * address) { - int irq; - unsigned long irqs, flags; - int save_xir, save_car; - int index = 0; /* IRQ probing is only for ISA */ - - /* forget possible initially masked and pending IRQ */ - irq = probe_irq_off(probe_irq_on()); - - /* Clear interrupts on the board first */ - cy_writeb(address + (Cy_ClrIntr<<index), 0); - /* Cy_ClrIntr is 0x1800 */ - - irqs = probe_irq_on(); - /* Wait ... */ - udelay(5000L); - - /* Enable the Tx interrupts on the CD1400 */ - local_irq_save(flags); - cy_writeb(address + (CyCAR<<index), 0); - cyy_issue_cmd(address, CyCHAN_CTL|CyENB_XMTR, index); - - cy_writeb(address + (CyCAR<<index), 0); - cy_writeb(address + (CySRER<<index), - cy_readb(address + (CySRER<<index)) | CyTxRdy); - local_irq_restore(flags); - - /* Wait ... */ - udelay(5000L); - - /* Check which interrupt is in use */ - irq = probe_irq_off(irqs); - - /* Clean up */ - save_xir = (u_char) cy_readb(address + (CyTIR<<index)); - save_car = cy_readb(address + (CyCAR<<index)); - cy_writeb(address + (CyCAR<<index), (save_xir & 0x3)); - cy_writeb(address + (CySRER<<index), - cy_readb(address + (CySRER<<index)) & ~CyTxRdy); - cy_writeb(address + (CyTIR<<index), (save_xir & 0x3f)); - cy_writeb(address + (CyCAR<<index), (save_car)); - cy_writeb(address + (Cy_ClrIntr<<index), 0); - /* Cy_ClrIntr is 0x1800 */ - - return (irq > 0)? irq : 0; + int irq; + unsigned long irqs, flags; + int save_xir, save_car; + int index = 0; /* IRQ probing is only for ISA */ + + /* forget possible initially masked and pending IRQ */ + irq = probe_irq_off(probe_irq_on()); + + /* Clear interrupts on the board first */ + cy_writeb(address + (Cy_ClrIntr << index), 0); + /* Cy_ClrIntr is 0x1800 */ + + irqs = probe_irq_on(); + /* Wait ... */ + udelay(5000L); + + /* Enable the Tx interrupts on the CD1400 */ + local_irq_save(flags); + cy_writeb(address + (CyCAR << index), 0); + cyy_issue_cmd(address, CyCHAN_CTL | CyENB_XMTR, index); + + cy_writeb(address + (CyCAR << index), 0); + cy_writeb(address + (CySRER << index), + cy_readb(address + (CySRER << index)) | CyTxRdy); + local_irq_restore(flags); + + /* Wait ... */ + udelay(5000L); + + /* Check which interrupt is in use */ + irq = probe_irq_off(irqs); + + /* Clean up */ + save_xir = (u_char) cy_readb(address + (CyTIR << index)); + save_car = cy_readb(address + (CyCAR << index)); + cy_writeb(address + (CyCAR << index), (save_xir & 0x3)); + cy_writeb(address + (CySRER << index), + cy_readb(address + (CySRER << index)) & ~CyTxRdy); + cy_writeb(address + (CyTIR << index), (save_xir & 0x3f)); + cy_writeb(address + (CyCAR << index), (save_car)); + cy_writeb(address + (Cy_ClrIntr << index), 0); + /* Cy_ClrIntr is 0x1800 */ + + return (irq > 0) ? irq : 0; } -#endif /* CONFIG_ISA */ +#endif /* CONFIG_ISA */ -/* The real interrupt service routine is called - whenever the card wants its hand held--chars - received, out buffer empty, modem change, etc. - */ -static irqreturn_t -cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, + void __iomem * base_addr, int status, int index) { - struct tty_struct *tty; - int status; - struct cyclades_card *cinfo; - struct cyclades_port *info; - void __iomem *base_addr, *card_base_addr; - int chip; - int save_xir, channel, save_car; - char data; - volatile int char_count; - int outch; - int i,j,index; - int too_many; - int had_work; - int mdm_change; - int mdm_status; - int len; - if((cinfo = (struct cyclades_card *)dev_id) == 0){ + struct cyclades_port *info; + struct tty_struct *tty; + volatile int char_count; + int i, j, len, mdm_change, mdm_status, outch; + int save_xir, channel, save_car; + char data; + + if (status & CySRReceive) { /* reception interrupt */ #ifdef CY_DEBUG_INTERRUPTS - printk("cyy_interrupt: spurious interrupt %d\n\r", irq); + printk("cyy_interrupt: rcvd intr, chip %d\n\r", chip); #endif - return IRQ_NONE; /* spurious interrupt */ - } - - card_base_addr = cinfo->base_addr; - index = cinfo->bus_index; - - - /* This loop checks all chips in the card. Make a note whenever - _any_ chip had some work to do, as this is considered an - indication that there will be more to do. Only when no chip - has any work does this outermost loop exit. - */ - do{ - had_work = 0; - for ( chip = 0 ; chip < cinfo->num_chips ; chip ++) { - base_addr = cinfo->base_addr + (cy_chip_offset[chip]<<index); - too_many = 0; - while ( (status = cy_readb(base_addr+(CySVRR<<index))) != 0x00) { - had_work++; - /* The purpose of the following test is to ensure that - no chip can monopolize the driver. This forces the - chips to be checked in a round-robin fashion (after - draining each of a bunch (1000) of characters). - */ - if(1000<too_many++){ - break; - } - if (status & CySRReceive) { /* reception interrupt */ -#ifdef CY_DEBUG_INTERRUPTS - printk("cyy_interrupt: rcvd intr, chip %d\n\r", chip); -#endif - /* determine the channel & change to that context */ - spin_lock(&cinfo->card_lock); - save_xir = (u_char) cy_readb(base_addr+(CyRIR<<index)); - channel = (u_short ) (save_xir & CyIRChannel); - i = channel + chip * 4 + cinfo->first_line; - info = &cy_port[i]; - info->last_active = jiffies; - save_car = cy_readb(base_addr+(CyCAR<<index)); - cy_writeb(base_addr+(CyCAR<<index), save_xir); - - /* if there is nowhere to put the data, discard it */ - if(info->tty == 0){ - j = (cy_readb(base_addr+(CyRIVR<<index)) & CyIVRMask); - if ( j == CyIVRRxEx ) { /* exception */ - data = cy_readb(base_addr+(CyRDSR<<index)); - } else { /* normal character reception */ - char_count = cy_readb(base_addr+(CyRDCR<<index)); - while(char_count--){ - data = cy_readb(base_addr+(CyRDSR<<index)); - } - } - }else{ /* there is an open port for this data */ - tty = info->tty; - j = (cy_readb(base_addr+(CyRIVR<<index)) & CyIVRMask); - if ( j == CyIVRRxEx ) { /* exception */ - data = cy_readb(base_addr+(CyRDSR<<index)); - - /* For statistics only */ - if (data & CyBREAK) - info->icount.brk++; - else if(data & CyFRAME) - info->icount.frame++; - else if(data & CyPARITY) - info->icount.parity++; - else if(data & CyOVERRUN) - info->icount.overrun++; - - if(data & info->ignore_status_mask){ - info->icount.rx++; - continue; - } - if (tty_buffer_request_room(tty, 1)) { - if (data & info->read_status_mask){ - if(data & CyBREAK){ - tty_insert_flip_char(tty, cy_readb(base_addr+(CyRDSR<<index)), TTY_BREAK); - info->icount.rx++; - if (info->flags & ASYNC_SAK){ - do_SAK(tty); - } - }else if(data & CyFRAME){ - tty_insert_flip_char(tty, cy_readb(base_addr+(CyRDSR<<index)), TTY_FRAME); - info->icount.rx++; - info->idle_stats.frame_errs++; - }else if(data & CyPARITY){ - /* Pieces of seven... */ - tty_insert_flip_char(tty, cy_readb(base_addr+(CyRDSR<<index)), TTY_PARITY); - info->icount.rx++; - info->idle_stats.parity_errs++; - }else if(data & CyOVERRUN){ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + /* determine the channel & change to that context */ + spin_lock(&cinfo->card_lock); + save_xir = (u_char) cy_readb(base_addr + (CyRIR << index)); + channel = (u_short) (save_xir & CyIRChannel); + i = channel + chip * 4 + cinfo->first_line; + info = &cy_port[i]; + info->last_active = jiffies; + save_car = cy_readb(base_addr + (CyCAR << index)); + cy_writeb(base_addr + (CyCAR << index), save_xir); + + /* if there is nowhere to put the data, discard it */ + if (info->tty == 0) { + j = (cy_readb(base_addr + (CyRIVR << index)) & + CyIVRMask); + if (j == CyIVRRxEx) { /* exception */ + data = cy_readb(base_addr + (CyRDSR << index)); + } else { /* normal character reception */ + char_count = cy_readb(base_addr + + (CyRDCR << index)); + while (char_count--) { + data = cy_readb(base_addr + + (CyRDSR << index)); + } + } + } else { /* there is an open port for this data */ + tty = info->tty; + j = (cy_readb(base_addr + (CyRIVR << index)) & + CyIVRMask); + if (j == CyIVRRxEx) { /* exception */ + data = cy_readb(base_addr + (CyRDSR << index)); + + /* For statistics only */ + if (data & CyBREAK) + info->icount.brk++; + else if (data & CyFRAME) + info->icount.frame++; + else if (data & CyPARITY) + info->icount.parity++; + else if (data & CyOVERRUN) + info->icount.overrun++; + + if (data & info->ignore_status_mask) { info->icount.rx++; - /* If the flip buffer itself is - overflowing, we still lose - the next incoming character. - */ - tty_insert_flip_char(tty, cy_readb(base_addr+(CyRDSR<<index)), TTY_FRAME); - info->icount.rx++; + return; + } + if (tty_buffer_request_room(tty, 1)) { + if (data & info->read_status_mask) { + if (data & CyBREAK) { + tty_insert_flip_char( + tty, + cy_readb( + base_addr + + (CyRDSR << + index)), + TTY_BREAK); + info->icount.rx++; + if (info->flags & + ASYNC_SAK) { + do_SAK(tty); + } + } else if (data & CyFRAME) { + tty_insert_flip_char( + tty, + cy_readb( + base_addr + + (CyRDSR << + index)), + TTY_FRAME); + info->icount.rx++; + info->idle_stats. + frame_errs++; + } else if (data & CyPARITY) { + /* Pieces of seven... */ + tty_insert_flip_char( + tty, + cy_readb( + base_addr + + (CyRDSR << + index)), + TTY_PARITY); + info->icount.rx++; + info->idle_stats. + parity_errs++; + } else if (data & CyOVERRUN) { + tty_insert_flip_char( + tty, 0, + TTY_OVERRUN); + info->icount.rx++; + /* If the flip buffer itself is + overflowing, we still lose + the next incoming character. + */ + tty_insert_flip_char( + tty, + cy_readb( + base_addr + + (CyRDSR << + index)), + TTY_FRAME); + info->icount.rx++; + info->idle_stats. + overruns++; + /* 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); + info->icount.rx++; + } + } else { + tty_insert_flip_char(tty, 0, + TTY_NORMAL); + info->icount.rx++; + } + } else { + /* there was a software buffer + overrun and nothing could be + done about it!!! */ + info->icount.buf_overrun++; info->idle_stats.overruns++; - /* 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); - info->icount.rx++; - } - }else{ - tty_insert_flip_char(tty, 0, TTY_NORMAL); - info->icount.rx++; - } - }else{ - /* there was a software buffer - overrun and nothing could be - done about it!!! */ - info->icount.buf_overrun++; - info->idle_stats.overruns++; - } - } else { /* normal character reception */ - /* load # chars available from the chip */ - char_count = cy_readb(base_addr+(CyRDCR<<index)); + } + } else { /* normal character reception */ + /* load # chars available from the chip */ + char_count = cy_readb(base_addr + + (CyRDCR << index)); #ifdef CY_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; + ++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 = cy_readb(base_addr+(CyRDSR<<index)); - tty_insert_flip_char(tty, data, TTY_NORMAL); - info->idle_stats.recv_bytes++; - info->icount.rx++; + len = tty_buffer_request_room(tty, char_count); + while (len--) { + data = cy_readb(base_addr + + (CyRDSR << index)); + tty_insert_flip_char(tty, data, + TTY_NORMAL); + info->idle_stats.recv_bytes++; + info->icount.rx++; #ifdef CY_16Y_HACK - udelay(10L); + udelay(10L); #endif - } - info->idle_stats.recv_idle = jiffies; - } + } + info->idle_stats.recv_idle = jiffies; + } tty_schedule_flip(tty); - } - /* end of service */ - cy_writeb(base_addr+(CyRIR<<index), (save_xir & 0x3f)); - cy_writeb(base_addr+(CyCAR<<index), (save_car)); - spin_unlock(&cinfo->card_lock); - } - - - if (status & CySRTransmit) { /* transmission interrupt */ - /* Since we only get here when the transmit buffer - is empty, we know we can always stuff a dozen - characters. */ + } + /* end of service */ + cy_writeb(base_addr + (CyRIR << index), (save_xir & 0x3f)); + cy_writeb(base_addr + (CyCAR << index), (save_car)); + spin_unlock(&cinfo->card_lock); + } + + if (status & CySRTransmit) { /* transmission interrupt */ + /* Since we only get here when the transmit buffer + is empty, we know we can always stuff a dozen + characters. */ #ifdef CY_DEBUG_INTERRUPTS - printk("cyy_interrupt: xmit intr, chip %d\n\r", chip); + printk("cyy_interrupt: xmit intr, chip %d\n\r", chip); #endif - /* determine the channel & change to that context */ - spin_lock(&cinfo->card_lock); - save_xir = (u_char) cy_readb(base_addr+(CyTIR<<index)); - channel = (u_short ) (save_xir & CyIRChannel); - i = channel + chip * 4 + cinfo->first_line; - save_car = cy_readb(base_addr+(CyCAR<<index)); - cy_writeb(base_addr+(CyCAR<<index), save_xir); - - /* validate the port# (as configured and open) */ - if( (i < 0) || (NR_PORTS <= i) ){ - cy_writeb(base_addr+(CySRER<<index), - cy_readb(base_addr+(CySRER<<index)) & ~CyTxRdy); - goto txend; - } - info = &cy_port[i]; - info->last_active = jiffies; - if(info->tty == 0){ - cy_writeb(base_addr+(CySRER<<index), - cy_readb(base_addr+(CySRER<<index)) & ~CyTxRdy); - goto txdone; - } - - /* load the on-chip space for outbound data */ - char_count = info->xmit_fifo_size; - - if(info->x_char) { /* send special char */ - outch = info->x_char; - cy_writeb(base_addr+(CyTDR<<index), outch); - char_count--; + /* determine the channel & change to that context */ + spin_lock(&cinfo->card_lock); + save_xir = (u_char) cy_readb(base_addr + (CyTIR << index)); + channel = (u_short) (save_xir & CyIRChannel); + i = channel + chip * 4 + cinfo->first_line; + save_car = cy_readb(base_addr + (CyCAR << index)); + cy_writeb(base_addr + (CyCAR << index), save_xir); + + /* validate the port# (as configured and open) */ + if ((i < 0) || (NR_PORTS <= i)) { + cy_writeb(base_addr + (CySRER << index), + cy_readb(base_addr + (CySRER << index)) & + ~CyTxRdy); + goto txend; + } + info = &cy_port[i]; + info->last_active = jiffies; + if (info->tty == 0) { + cy_writeb(base_addr + (CySRER << index), + cy_readb(base_addr + (CySRER << index)) & + ~CyTxRdy); + goto txdone; + } + + /* load the on-chip space for outbound data */ + char_count = info->xmit_fifo_size; + + if (info->x_char) { /* send special char */ + outch = info->x_char; + cy_writeb(base_addr + (CyTDR << index), outch); + char_count--; info->icount.tx++; - info->x_char = 0; - } + info->x_char = 0; + } - if (info->breakon || info->breakoff) { + if (info->breakon || info->breakoff) { if (info->breakon) { - cy_writeb(base_addr + (CyTDR<<index), 0); - cy_writeb(base_addr + (CyTDR<<index), 0x81); - info->breakon = 0; - char_count -= 2; + cy_writeb(base_addr + (CyTDR << index), 0); + cy_writeb(base_addr + (CyTDR << index), 0x81); + info->breakon = 0; + char_count -= 2; } if (info->breakoff) { - cy_writeb(base_addr + (CyTDR<<index), 0); - cy_writeb(base_addr + (CyTDR<<index), 0x83); - info->breakoff = 0; - char_count -= 2; + cy_writeb(base_addr + (CyTDR << index), 0); + cy_writeb(base_addr + (CyTDR << index), 0x83); + info->breakoff = 0; |