From c7fc24dc4420057f103afe8fc64524ebc25c5d37 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 25 Aug 1998 09:12:35 +0000 Subject: o Merge with Linux 2.1.116. o New Newport console code. o New G364 console code. --- drivers/char/cyclades.c | 994 +++++++++++++++++++++++------------------------- 1 file changed, 475 insertions(+), 519 deletions(-) (limited to 'drivers/char/cyclades.c') diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index 9f51607fe..976219825 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -1,9 +1,7 @@ #define BLOCKMOVE -#define NEW_INTR_FLOW #define Z_WAKE -#define NEW_PCI static char rcsid[] = -"$Revision: 2.2.1.1 $$Date: 1998/03/19 16:43:12 $"; +"$Revision: 2.2.1.5 $$Date: 1998/08/10 18:10:28 $"; /* * linux/drivers/char/cyclades.c @@ -33,6 +31,22 @@ static char rcsid[] = * void cleanup_module(void); * * $Log: cyclades.c,v $ + * Revision 2.2.1.5 1998/08/10 18:10:28 ivan + * Fixed Cyclom-4Yo hardware detection bug. + * + * Revision 2.2.1.4 1998/08/04 11:02:50 ivan + * /proc/cyclades implementation with great collaboration of + * Marc Lewis ; + * cyy_interrupt was changed to avoid occurence of kernel oopses + * during PPP operation. + * + * Revision 2.2.1.3 1998/06/01 12:09:10 ivan + * General code review in order to comply with 2.1 kernel standards; + * data loss prevention for slow devices revisited (cy_wait_until_sent + * was created); + * removed conditional compilation for new/old PCI structure support + * (now the driver only supports the new PCI structure). + * * Revision 2.2.1.1 1998/03/19 16:43:12 ivan * added conditional compilation for new/old PCI structure support; * removed kernel series (2.0.x / 2.1.x) conditional compilation. @@ -40,7 +54,7 @@ static char rcsid[] = * Revision 2.1.1.3 1998/03/16 18:01:12 ivan * cleaned up the data loss fix; * fixed XON/XOFF handling once more (Cyclades-Z); - * general revision in the driver routines; + * general review of the driver routines; * introduction of a mechanism to prevent data loss with slow * printers, by forcing a delay before closing the port. * @@ -138,7 +152,7 @@ static char rcsid[] = * Price for help on this) * * Revision 1.36.4.21 1996/09/10 17:00:10 bentson - * shift from cpu-bound to memcopy in cyz_polling operation + * shift from CPU-bound to memcopy in cyz_polling operation * * Revision 1.36.4.20 1996/09/09 18:30:32 Bentson * Added support to set and report higher speeds. @@ -482,14 +496,15 @@ static char rcsid[] = #define ZE_V1 2 #define SERIAL_PARANOIA_CHECK -#undef SERIAL_DEBUG_OPEN -#undef SERIAL_DEBUG_THROTTLE -#undef SERIAL_DEBUG_OTHER -#undef SERIAL_DEBUG_IO -#undef SERIAL_DEBUG_COUNT -#undef SERIAL_DEBUG_DTR -#undef CYCLOM_16Y_HACK -#undef CYCLOM_ENABLE_MONITORING +#undef CY_DEBUG_OPEN +#undef CY_DEBUG_THROTTLE +#undef CY_DEBUG_OTHER +#undef CY_DEBUG_IO +#undef CY_DEBUG_COUNT +#undef CY_DEBUG_DTR +#undef CY_DEBUG_WAIT_UNTIL_SENT +#undef CY_16Y_HACK +#undef CY_ENABLE_MONITORING #undef CY_PCI_DEBUG #if 0 @@ -519,40 +534,42 @@ static char rcsid[] = (cy_readl(&buf_ctrl->tx_bufsize) - 1)) #endif +/* + * Include section + */ +#include #include - #include #include #include #include +#include #include #include -#include +#include #include #include #include #include -#include -#include #include +#include +#include #include #include -#include +#include +#include #include -#include #include #include -#ifndef NEW_PCI -#include -#endif #include - #include -#include -#include +#ifdef CONFIG_PROC_FS +#include +#include +#endif #define cy_put_user put_user @@ -569,7 +586,7 @@ static unsigned long cy_get_user(unsigned long *addr) #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif -#define IS_CYC_Z(card) ((card).num_chips == 1) +#define IS_CYC_Z(card) ((card).num_chips == -1) #define Z_FPGA_CHECK(card) \ ((cy_readl(&((struct RUNTIME_9060 *) \ @@ -585,19 +602,18 @@ static unsigned long cy_get_user(unsigned long *addr) #define STD_COM_FLAGS (0) -#define SERIAL_TYPE_NORMAL 1 -#define SERIAL_TYPE_CALLOUT 2 +#define JIFFIES_DIFF(n, j) ((n) - (j)) static DECLARE_TASK_QUEUE(tq_cyclades); static struct tty_driver cy_serial_driver, cy_callout_driver; +static int serial_refcount; static volatile int cy_irq_triggered; static volatile int cy_triggered; static int cy_wild_int_mask; static volatile ucchar *intr_base_addr; - /* This is the address lookup table. The driver will probe for Cyclom-Y/ISA boards at all addresses in here. If you want the driver to probe addresses at a different address, add it to @@ -632,8 +648,6 @@ static struct cyclades_port cy_port[NR_PORTS]; static int cy_next_channel = 0; /* next minor available */ -static int serial_refcount; - static struct tty_struct *serial_table[NR_PORTS]; static struct termios *serial_termios[NR_PORTS]; static struct termios *serial_termios_locked[NR_PORTS]; @@ -641,8 +655,7 @@ static struct termios *serial_termios_locked[NR_PORTS]; /* This is the per-irq data structure, it maps an irq to the corresponding card */ -static struct cyclades_card *IRQ_cards[16]; - +static struct cyclades_card *IRQ_cards[NR_IRQS]; /* * tmp_buf is used as a temporary buffer by serial_write. We need to @@ -654,7 +667,7 @@ static struct cyclades_card *IRQ_cards[16]; * memory if large numbers of serial ports are open. This buffer is * allocated when the first cy_open occurs. */ -static unsigned char *tmp_buf = 0; +static unsigned char *tmp_buf; static struct semaphore tmp_buf_sem = MUTEX; /* @@ -750,6 +763,10 @@ static void cyz_poll(unsigned long); static void show_status(int); #endif +#ifdef CONFIG_PROC_FS +static int cyclades_get_proc_info(char *, char **, off_t , int , int *, void *); +#endif + /* The Cyclades-Z polling cycle is defined by this variable */ static long cyz_polling_cycle = CZ_DEF_POLL; @@ -799,41 +816,6 @@ serial_paranoia_check(struct cyclades_port *info, return 0; } /* serial_paranoia_check */ - -/* The following diagnostic routines allow the driver to spew - information on the screen, even (especially!) during interrupts. - */ -static void -SP(char *data){ - unsigned long flags; - save_flags(flags); cli(); - console_print(data); - restore_flags(flags); -}/* SP */ - -static void -CP(char data){ - unsigned long flags; - char scrn[2]; - save_flags(flags); cli(); - scrn[0] = data; - scrn[1] = '\0'; - console_print(scrn); - restore_flags(flags); -}/* CP */ - -static void CP4(int data) - { (data<10)? CP(data+'0'): CP(data+'A'-10); }/* CP4 */ -static void CP8(int data) - { CP4((data>>4) & 0x0f); CP4( data & 0x0f); }/* CP8 */ -#if 0 -static void CP16(int data) - { CP8((data>>8) & 0xff); CP8(data & 0xff); }/* CP16 */ -static void CP32(long data) - { CP16((data>>16) & 0xffff); CP16(data & 0xffff); }/* CP32 */ -#endif - - /* * This routine is used by the interrupt handler to schedule * processing in the software interrupt portion of the driver @@ -1125,11 +1107,6 @@ cy_probe(int irq, void *dev_id, struct pt_regs *regs) if(cy_readb(intr_base_addr+(CySVRR<flip.char_buf_ptr++ = cy_readb(base_addr+(CyRDSR<idle_stats.frame_errs++; }else if(data & CyPARITY){ *tty->flip.flag_buf_ptr++ = TTY_PARITY; *tty->flip.char_buf_ptr++ = cy_readb(base_addr+(CyRDSR<idle_stats.parity_errs++; }else if(data & CyOVERRUN){ *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; @@ -1265,6 +1244,7 @@ printk("cy_interrupt: rcvd intr, chip %d\n\r", chip); *tty->flip.char_buf_ptr++ = cy_readb(base_addr+(CyRDSR<idle_stats.overruns++; /* These two conditions may imply */ /* a normal read should be done. */ /* }else if(data & CyTIMEOUT){ */ @@ -1281,18 +1261,21 @@ printk("cy_interrupt: rcvd intr, chip %d\n\r", chip); /* there was a software buffer overrun and nothing could be done about it!!! */ + info->idle_stats.overruns++; } } else { /* normal character reception */ /* load # chars available from the chip */ char_count = cy_readb(base_addr+(CyRDCR<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 + info->idle_stats.recv_bytes += char_count; + info->idle_stats.recv_idle = jiffies; while(char_count--){ if (tty->flip.count >= TTY_FLIPBUF_SIZE){ break; @@ -1301,7 +1284,7 @@ printk("cy_interrupt: rcvd intr, chip %d\n\r", chip); data = cy_readb(base_addr+(CyRDSR<flip.flag_buf_ptr++ = TTY_NORMAL; *tty->flip.char_buf_ptr++ = data; -#ifdef CYCLOM_16Y_HACK +#ifdef CY_16Y_HACK udelay(10L); #endif } @@ -1387,45 +1370,25 @@ printk("cy_interrupt: xmit intr, chip %d\n\r", chip); info->x_break = 0; } -#ifdef NEW_INTR_FLOW - if (!info->xmit_cnt){ - cy_writeb((u_long)base_addr+(CySRER<xmit_buf == 0){ - cy_writeb((u_long)base_addr+(CySRER<tty->stopped || info->tty->hw_stopped){ - cy_writeb((u_long)base_addr+(CySRER< 0){ -#ifdef NEW_INTR_FLOW - if (!info->xmit_cnt){ - goto txdone; - } -#else - if (!info->xmit_cnt){ + if (!info->xmit_cnt){ cy_writeb((u_long)base_addr+(CySRER<xmit_buf == 0){ + cy_readb(base_addr+(CySRER<xmit_buf == 0){ cy_writeb((u_long)base_addr+(CySRER<tty->stopped || info->tty->hw_stopped){ + } + if (info->tty->stopped || info->tty->hw_stopped){ cy_writeb((u_long)base_addr+(CySRER< 241 ? ((u_long)param) : cy_readl(&ch_ctrl[channel].rs_status)) & C_RS_DCD) { - /* SP("Open Wakeup\n"); */ cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP); }else if(!((info->flags & ASYNC_CALLOUT_ACTIVE) &&(info->flags & ASYNC_CALLOUT_NOHUP))){ - /* SP("Hangup\n"); */ cy_sched_event(info, Cy_EVENT_HANGUP); } @@ -1744,7 +1705,6 @@ cyz_poll(unsigned long arg) if( cy_readl(&ch_ctrl[channel].rs_status) & C_RS_DCD){ /* cy_start isn't used because... HW flow is handled by the board */ - /* SP("Write Wakeup\n"); */ cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP); } @@ -1752,7 +1712,6 @@ cyz_poll(unsigned long arg) if(!(cy_readl(&ch_ctrl[channel].rs_status) & C_RS_CTS)){ /* cy_stop isn't used because HW flow is handled by the board */ - /* SP("Write stop\n"); */ } } } @@ -1796,17 +1755,18 @@ cyz_poll(unsigned long arg) info->last_active = jiffies; info->jiffies[1] = jiffies; -#ifdef CYCLOM_ENABLE_MONITORING +#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; #endif + info->idle_stats.recv_bytes += char_count; + info->idle_stats.recv_idle = jiffies; if( tty == 0){ /* flush received characters */ rx_get = (rx_get + char_count) & (rx_bufsize - 1); - /* SP("-"); */ info->rflush_count++; }else{ #ifdef BLOCKMOVE @@ -1986,7 +1946,7 @@ startup(struct cyclades_port * info) base_addr = (unsigned char*) (cy_card[card].base_addr + (cy_chip_offset[chip]<tty->flags); } info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats)); + info->idle_stats.in_use = + info->idle_stats.recv_idle = + info->idle_stats.xmit_idle = jiffies; restore_flags(flags); } else { struct FIRM_ID *firm_id; @@ -2040,7 +2004,7 @@ startup(struct cyclades_port * info) board_ctrl = &zfw_ctrl->board_ctrl; ch_ctrl = zfw_ctrl->ch_ctrl; -#ifdef SERIAL_DEBUG_OPEN +#ifdef CY_DEBUG_OPEN printk("cyc startup Z card %d, channel %d, base_addr %lx\n", card, channel, (long)base_addr);/**/ #endif @@ -2068,7 +2032,7 @@ startup(struct cyclades_port * info) if (retval != 0){ printk("cyc:startup(2) retval was %x\n", retval); } -#ifdef SERIAL_DEBUG_DTR +#ifdef CY_DEBUG_DTR printk("cyc:startup raising Z DTR\n"); #endif @@ -2080,9 +2044,13 @@ startup(struct cyclades_port * info) } info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats)); + info->idle_stats.in_use = + info->idle_stats.recv_idle = + info->idle_stats.xmit_idle = jiffies; } -#ifdef SERIAL_DEBUG_OPEN +#ifdef CY_DEBUG_OPEN printk(" cyc startup done\n"); #endif return 0; @@ -2142,7 +2110,7 @@ shutdown(struct cyclades_port * info) (cy_card[card].base_addr + (cy_chip_offset[chip]<tty || (info->tty->termios->c_cflag & HUPCL)) { cy_writeb((u_long)base_addr+(CyMSVR1<flags & ASYNC_CLOSING) { interruptible_sleep_on(&info->close_wait); } - if (info->flags & ASYNC_HUP_NOTIFY){ - return -EAGAIN; - }else{ - return -ERESTARTSYS; - } + return ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); } /* @@ -2313,7 +2277,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, */ retval = 0; add_wait_queue(&info->open_wait, &wait); -#ifdef SERIAL_DEBUG_OPEN +#ifdef CY_DEBUG_OPEN printk("cyc block_til_ready before block: ttyC%d, count = %d\n", info->line, info->count);/**/ #endif @@ -2321,7 +2285,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, if (!tty_hung_up_p(filp)) info->count--; restore_flags(flags); -#ifdef SERIAL_DEBUG_COUNT +#ifdef CY_DEBUG_COUNT printk("cyc block_til_ready: (%d): decrementing count to %d\n", current->pid, info->count); #endif @@ -2338,11 +2302,12 @@ block_til_ready(struct tty_struct *tty, struct file * filp, while (1) { save_flags(flags); cli(); - if (!(info->flags & ASYNC_CALLOUT_ACTIVE)){ + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + (tty->termios->c_cflag & CBAUD)){ cy_writeb((u_long)base_addr+(CyCAR<state = TASK_INTERRUPTIBLE; if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED) ){ - if (info->flags & ASYNC_HUP_NOTIFY) { - retval = -EAGAIN; - }else{ - retval = -ERESTARTSYS; - } + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); break; } save_flags(flags); cli(); @@ -2374,7 +2336,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, retval = -ERESTARTSYS; break; } -#ifdef SERIAL_DEBUG_OPEN +#ifdef CY_DEBUG_OPEN printk("cyc block_til_ready blocking: ttyC%d, count = %d\n", info->line, info->count);/**/ #endif @@ -2408,18 +2370,15 @@ block_til_ready(struct tty_struct *tty, struct file * filp, if (retval != 0){ printk("cyc:block_til_ready retval was %x\n", retval); } -#ifdef SERIAL_DEBUG_DTR +#ifdef CY_DEBUG_DTR printk("cyc:block_til_ready raising Z DTR\n"); #endif current->state = TASK_INTERRUPTIBLE; if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED) ){ - if (info->flags & ASYNC_HUP_NOTIFY) { - retval = -EAGAIN; - }else{ - retval = -ERESTARTSYS; - } + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); break; } if (!(info->flags & ASYNC_CALLOUT_ACTIVE) @@ -2432,7 +2391,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, retval = -ERESTARTSYS; break; } -#ifdef SERIAL_DEBUG_OPEN +#ifdef CY_DEBUG_OPEN printk("cyc block_til_ready blocking: ttyC%d, count = %d\n", info->line, info->count);/**/ #endif @@ -2443,13 +2402,13 @@ block_til_ready(struct tty_struct *tty, struct file * filp, remove_wait_queue(&info->open_wait, &wait); if (!tty_hung_up_p(filp)){ info->count++; -#ifdef SERIAL_DEBUG_COUNT +#ifdef CY_DEBUG_COUNT printk("cyc:block_til_ready (%d): incrementing count to %d\n", current->pid, info->count); #endif } info->blocked_open--; -#ifdef SERIAL_DEBUG_OPEN +#ifdef CY_DEBUG_OPEN printk("cyc:block_til_ready after blocking: ttyC%d, count = %d\n", info->line, info->count);/**/ #endif @@ -2464,11 +2423,12 @@ block_til_ready(struct tty_struct *tty, struct file * filp, * This routine is called whenever a serial port is opened. It * performs the serial-specific initialization for the tty structure. */ -int +static int cy_open(struct tty_struct *tty, struct file * filp) { struct cyclades_port *info; int retval, line; + unsigned long page; line = MINOR(tty->device) - tty->driver.minor_start; if ((line < 0) || (NR_PORTS <= line)){ @@ -2491,46 +2451,50 @@ cy_open(struct tty_struct *tty, struct file * filp) (ZFIRM_HLT==cy_readl(&((struct FIRM_ID *) ((cy_card[info->card]).base_addr+ID_ADDRESS))->signature))) { - printk ("Cyclades-Z Error: you need an external power supply for this number of ports.\n\rFirmware halted.\r\n"); + printk ("cyc:Cyclades-Z Error: you need an external power supply for this number of ports.\n\rFirmware halted.\r\n"); } else { - printk("Cyclades-Z firmware not yet loaded\n"); + printk("cyc:Cyclades-Z firmware not yet loaded\n"); } return -ENODEV; } } -#ifdef SERIAL_DEBUG_OTHER +#ifdef CY_DEBUG_OTHER printk("cyc:cy_open ttyC%d\n", info->line); /* */ #endif if (serial_paranoia_check(info, tty->device, "cy_open")){ return -ENODEV; } -#ifdef SERIAL_DEBUG_OPEN +#ifdef CY_DEBUG_OPEN printk("cyc:cy_open ttyC%d, count = %d\n", info->line, info->count);/**/ #endif info->count++; -#ifdef SERIAL_DEBUG_COUNT +#ifdef CY_DEBUG_COUNT printk("cyc:cy_open (%d): incrementing count to %d\n", current->pid, info->count); #endif tty->driver_data = info; info->tty = tty; - /* Some drivers have (incorrect/incomplete) code to test - against a race condition. Should add good code here!!! */ if (!tmp_buf) { - tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL); - if (!tmp_buf){ - return -ENOMEM; - } + page = get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + if (tmp_buf) + free_page(page); + else + tmp_buf = (unsigned char *) page; } - if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver.subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->normal_termios; - else - *tty->termios = info->callout_termios; + /* + * If the port is the middle of closing, bail out now + */ + if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); + return ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); } + /* * Start up serial port */ @@ -2543,17 +2507,24 @@ cy_open(struct tty_struct *tty, struct file * filp) retval = block_til_ready(tty, filp, info); if (retval) { -#ifdef SERIAL_DEBUG_OPEN +#ifdef CY_DEBUG_OPEN printk("cyc:cy_open returning after block_til_ready with %d\n", retval); #endif return retval; } + if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = info->normal_termios; + else + *tty->termios = info->callout_termios; + } + info->session = current->session; info->pgrp = current->pgrp; -#ifdef SERIAL_DEBUG_OPEN +#ifdef CY_DEBUG_OPEN printk(" cyc:cy_open done\n");/**/ #endif @@ -2561,6 +2532,76 @@ cy_open(struct tty_struct *tty, struct file * filp) } /* cy_open */ +/* + * cy_wait_until_sent() --- wait until the transmitter is empty + */ +static void cy_wait_until_sent(struct tty_struct *tty, int timeout) +{ + struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; + unsigned char *base_addr; + int card,chip,channel,index; + unsigned long orig_jiffies, char_time; + + if (serial_paranoia_check(info, tty->device, "cy_wait_until_sent")) + return; + + orig_jiffies = jiffies; + /* + * Set the check interval to be 1/5 of the estimated time to + * send a single character, and make it at least 1. The check + * interval should also be less than the timeout. + * + * Note: we have to use pretty tight timings here to satisfy + * the NIST-PCTS. + */ + char_time = (info->timeout - HZ/50) / info->xmit_fifo_size; + char_time = char_time / 5; + if (char_time == 0) + char_time = 1; + if (timeout < 0) + timeout = 0; + if (timeout) + char_time = MIN(char_time, timeout); +#ifdef CY_DEBUG_WAIT_UNTIL_SENT + printk("In cy_wait_until_sent(%d) check=%lu...", timeout, char_time); + printk("jiff=%lu...", jiffies); +#endif + card = info->card; + channel = (info->line) - (cy_card[card].first_line); + if (!IS_CYC_Z(cy_card[card])) { + chip = channel>>2; + channel &= 0x03; + index = cy_card[card].bus_index; + base_addr = (unsigned char *) + (cy_card[card].base_addr + (cy_chip_offset[chip]<state = TASK_INTERRUPTIBLE; + current->counter = 0; /* make us low-priority */ + current->timeout = jiffies + char_time; + schedule(); + if (signal_pending(current)) + break; + if (timeout && ((orig_jiffies + timeout) < jiffies)) + break; + } + current->state = TASK_RUNNING; + } else { + // Nothing to do! + } + /* Run one more char cycle */ + current->state = TASK_INTERRUPTIBLE; + current->counter = 0; /* make us low-priority */ + current->timeout = jiffies + (char_time * 5); + schedule(); + current->state = TASK_RUNNING; +#ifdef CY_DEBUG_WAIT_UNTIL_SENT + printk("Clean (jiff=%lu)...done\n", jiffies); +#endif +} + /* * This routine is called when a particular tty device is closed. */ @@ -2570,7 +2611,7 @@ cy_close(struct tty_struct * tty, struct file * filp) struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; unsigned long flags; -#ifdef SERIAL_DEBUG_OTHER +#ifdef CY_DEBUG_OTHER printk("cyc:cy_close ttyC%d\n", info->line); #endif @@ -2578,7 +2619,7 @@ cy_close(struct tty_struct * tty, struct file * filp) || serial_paranoia_check(info, tty->device, "cy_close")){ return; } -#ifdef SERIAL_DEBUG_OPEN +#ifdef CY_DEBUG_OPEN printk("cyc:cy_close ttyC%d, count = %d\n", info->line, info->count); #endif @@ -2586,6 +2627,7 @@ cy_close(struct tty_struct * tty, struct file * filp) /* If the TTY is being hung up, nothing to do */ if (tty_hung_up_p(filp)) { + MOD_DEC_USE_COUNT; restore_flags(flags); return; } @@ -2602,18 +2644,18 @@ cy_close(struct tty_struct * tty, struct file * filp) "info->count is %d\n", info->count); info->count = 1; } -#ifdef SERIAL_DEBUG_COUNT +#ifdef CY_DEBUG_COUNT printk("cyc:cy_close at (%d): decrementing count to %d\n", current->pid, info->count - 1); #endif if (--info->count < 0) { -#ifdef SERIAL_DEBUG_COUNT +#ifdef CY_DEBUG_COUNT printk("cyc:cyc_close setting count to 0\n"); #endif info->count = 0; } if (info->count) { - MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; restore_flags(flags); return; } @@ -2632,28 +2674,25 @@ cy_close(struct tty_struct * tty, struct file * filp) * the line discipline to only process XON/XOFF characters. */ tty->closing = 1; - if (info->closing_wait2 != 0) { /* The port's being forced to wait, - independent on the port settings */ - tty_wait_until_sent(tty, info->closing_wait2*HZ); - } else { - if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, info->closing_wait*HZ); + if (info->closing_wait != CY_CLOSING_WAIT_NONE) { + tty_wait_until_sent(tty, info->closing_wait); } - /* Waiting for on-board buffers to be empty before closing the port */ if (!IS_CYC_Z(cy_card[info->card])) { -#ifdef NEW_INTR_FLOW unsigned char *base_addr = (unsigned char *) cy_card[info->card].base_addr; int index = cy_card[info->card].bus_index; - - if (cy_readb(base_addr+(CySRER<shutdown_wait); + /* Stop accepting input */ + cy_writeb((u_long)base_addr+(CySRER<flags & ASYNC_INITIALIZED) { + /* Waiting for on-board buffers to be empty before closing + the port */ + cy_wait_until_sent(tty, info->timeout); } -#endif } else { #ifdef Z_WAKE + /* Waiting for on-board buffers to be empty before closing the port */ unsigned char *base_addr = (unsigned char *) cy_card[info->card].base_addr; struct FIRM_ID *firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS); @@ -2693,7 +2732,7 @@ cy_close(struct tty_struct * tty, struct file * filp) ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); -#ifdef SERIAL_DEBUG_OTHER +#ifdef CY_DEBUG_OTHER printk(" cyc:cy_close done\n"); #endif @@ -2722,9 +2761,9 @@ cy_write(struct tty_struct * tty, int from_user, { struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; unsigned long flags; - int c, total = 0; + int c, ret = 0; -#ifdef SERIAL_DEBUG_IO +#ifdef CY_DEBUG_IO printk("cyc:cy_write ttyC%d\n", info->line); /* */ #endif @@ -2736,42 +2775,61 @@ cy_write(struct tty_struct * tty, int from_user, return 0; } - if (from_user) - down(&tmp_buf_sem); save_flags(flags); - while (1) { - 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) { - copy_from_user(tmp_buf, buf, c); - c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); - memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); - } else - memcpy(info->xmit_buf + info->xmit_head, buf, c); - info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); - info->xmit_cnt += c; - restore_flags(flags); - buf += c; - count -= c; - total += c; -#if 0 - SP("CW"); - CP16(c); - SP(" "); -#endif - } - if (from_user) + if (from_user) { + down(&tmp_buf_sem); + while (1) { + c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0) + break; + + c -= copy_from_user(tmp_buf, buf, c); + if (!c) { + if (!ret) { + ret = -EFAULT; + } + break; + } + cli(); + 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); + info->xmit_head = ((info->xmit_head + c) & (SERIAL_XMIT_SIZE-1)); + info->xmit_cnt += c; + restore_flags(flags); + buf += c; + count -= c; + ret += c; + } up(&tmp_buf_sem); + } else { + while (1) { + cli(); + c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0) { + restore_flags(flags); + break; + } + memcpy(info->xmit_buf + info->xmit_head, buf, c); + info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt += c; + restore_flags(flags); + buf += c; + count -= c; + ret += c; + } + } + + info->idle_stats.xmit_bytes += ret; + info->idle_stats.xmit_idle = jiffies; + if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) { start_xmit(info); } - restore_flags(flags); - return total; + return ret; } /* cy_write */ @@ -2788,7 +2846,7 @@ cy_put_char(struct tty_struct *tty, unsigned char ch) struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; unsigned long flags; -#ifdef SERIAL_DEBUG_IO +#ifdef CY_DEBUG_IO printk("cyc:cy_put_char ttyC%d\n", info->line); #endif @@ -2807,10 +2865,9 @@ cy_put_char(struct tty_struct *tty, unsigned char ch) info->xmit_buf[info->xmit_head++] = ch; info->xmit_head &= SERIAL_XMIT_SIZE - 1; info->xmit_cnt++; + info->idle_stats.xmit_bytes++; + info->idle_stats.xmit_idle = jiffies; restore_flags(flags); -#if 0 - SP("+"); -#endif } /* cy_put_char */ @@ -2826,7 +2883,7 @@ cy_flush_chars(struct tty_struct *tty) unsigned char *base_addr; int card,chip,channel,index; -#ifdef SERIAL_DEBUG_IO +#ifdef CY_DEBUG_IO printk("cyc:cy_flush_chars ttyC%d\n", info->line); /* */ #endif @@ -2871,7 +2928,7 @@ cy_write_room(struct tty_struct *tty) struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; int ret; -#ifdef SERIAL_DEBUG_IO +#ifdef CY_DEBUG_IO printk("cyc:cy_write_room ttyC%d\n", info->line); /* */ #endif @@ -2897,7 +2954,7 @@ cy_chars_in_buffer(struct tty_struct *tty) channel = (info->line) - (cy_card[card].first_line); if (!IS_CYC_Z(cy_card[card])) { -#ifdef SERIAL_DEBUG_IO +#ifdef CY_DEBUG_IO printk("cyc:cy_chars_in_buffer ttyC%d %d\n", info->line, info->xmit_cnt); /* */ #endif @@ -2923,7 +2980,7 @@ cy_chars_in_buffer(struct tty_struct *tty) char_count = tx_put - tx_get; else char_count = tx_put - tx_get + tx_bufsize; -#ifdef SERIAL_DEBUG_IO +#ifdef CY_DEBUG_IO printk("cyc:cy_chars_in_buffer ttyC%d %d\n", info->line, info->xmit_cnt + char_count); /* */ #endif @@ -2951,6 +3008,7 @@ set_line_char(struct cyclades_port * info) int card,chip,channel,index; unsigned cflag, iflag; unsigned short chip_number; + int baud; int i; @@ -2972,47 +3030,21 @@ set_line_char(struct cyclades_port * info) index = cy_card[card].bus_index; /* baud rate */ - i = cflag & CBAUD; - - if (i & CBAUDEX) { - if (i == B57600) - i = 16; -#ifdef B76800 - else if(i == B76800) - i = 17; -#endif - else if(i == B115200) - i = 18; - else if(i == B230400 && (info->chip_rev >= CD1400_REV_J)) { - /* It is a CD1400 rev. J or later */ - i = 20; + baud = tty_get_baud_rate(info->tty); + if (baud > CD1400_MAX_SPEED) { + baud = CD1400_MAX_SPEED; + } + /* find the baud index */ + for (i = 0; i < 20; i++) { + if (baud == baud_table[i]) { + break; } - else - info->tty->termios->c_cflag &= ~CBAUDEX; } + if (i == 20) { + i = 19; /* CD1400_MAX_SPEED */ + } + - if (i == 15) { - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - i += 1; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - i += 3; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST){ - switch(info->baud) { - case 57600: - i += 1; break; -#ifdef B76800 - case 76800: - i += 2; break; -#endif - case 115200: - i += 3; break; - case 230400: - i += 5; break; - default: - break; - } - } - } if(info->chip_rev >= CD1400_REV_J) { /* It is a CD1400 rev. J or later */ info->tbpr = baud_bpr_60[i]; /* Tx BPR */ @@ -3026,7 +3058,7 @@ set_line_char(struct cyclades_port * info) info->rco = baud_co_25[i]; /* Rx CO */ } if (baud_table[i] == 134) { - info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2; + info->timeout = (info->xmit_fifo_size*HZ*15/269) + 2; /* get it right for 134.5 baud */ } else if (baud_table[i]) { info->timeout = (info->xmit_fifo_size*HZ*15/baud_table[i]) + 2; @@ -3168,7 +3200,7 @@ set_line_char(struct cyclades_port * info) } else { cy_writeb((u_long)base_addr+(CyMSVR2<buf_ctrl[channel]; /* baud rate */ - switch(i = cflag & CBAUD){ - /* - case B0: cy_writel(&ch_ctrl->comm_baud , 0); break; - */ - case B50: cy_writel(&ch_ctrl->comm_baud , 50); break; - case B75: cy_writel(&ch_ctrl->comm_baud , 75); break; - case B110: cy_writel(&ch_ctrl->comm_baud , 110); break; - case B134: cy_writel(&ch_ctrl->comm_baud , 134); break; - case B150: cy_writel(&ch_ctrl->comm_baud , 150); break; - case B200: cy_writel(&ch_ctrl->comm_baud , 200); break; - case B300: cy_writel(&ch_ctrl->comm_baud , 300); break; - case B600: cy_writel(&ch_ctrl->comm_baud , 600); break; - case B1200: cy_writel(&ch_ctrl->comm_baud , 1200); break; - case B1800: cy_writel(&ch_ctrl->comm_baud , 1800); break; - case B2400: cy_writel(&ch_ctrl->comm_baud , 2400); break; - case B4800: cy_writel(&ch_ctrl->comm_baud , 4800); break; - case B9600: cy_writel(&ch_ctrl->comm_baud , 9600); break; - case B19200: cy_writel(&ch_ctrl->comm_baud , 19200); break; - case B38400: - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI){ - cy_writel(&ch_ctrl->comm_baud , 57600); - }else if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI){ - cy_writel(&ch_ctrl->comm_baud , 115200); - }else if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST){ - cy_writel(&ch_ctrl->comm_baud , info->baud); - }else{ - cy_writel(&ch_ctrl->comm_baud , 38400); - } - break; - case B57600: cy_writel(&ch_ctrl->comm_baud , 57600); break; -#ifdef B76800 - case B76800: cy_writel(&ch_ctrl->comm_baud , 76800); break; -#endif - case B115200: cy_writel(&ch_ctrl->comm_baud , 115200); break; - case B230400: cy_writel(&ch_ctrl->comm_baud , 230400); break; - case B460800: cy_writel(&ch_ctrl->comm_baud , 460800); break; + baud = tty_get_baud_rate(info->tty); + if (baud > CD1400_MAX_SPEED) { + baud = CD1400_MAX_SPEED; } + cy_writel(&ch_ctrl->comm_baud , baud); - if ((i = cy_readl(&ch_ctrl->comm_baud)) == 134) { + if (baud == 134) { info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2; /* get it right for 134.5 baud */ - } else if (i) { - info->timeout = (info->xmit_fifo_size*HZ*15/i) + 2; + } else if (baud) { + info->timeout = (info->xmit_fifo_size*HZ*15/baud) + 2; /* this needs to be propagated into the card info */ } else { info->timeout = 0; @@ -3318,16 +3318,16 @@ set_line_char(struct cyclades_port * info) cy_readl(&ch_ctrl->sw_flow) & ~C_FL_OXX); } - if(i == 0){ /* baud rate is zero, turn off line */ + if(baud == 0){ /* baud rate is zero, turn off line */ cy_writel(&ch_ctrl->rs_control, cy_readl(&ch_ctrl->rs_control) & ~C_RS_DTR); -#ifdef SERIAL_DEBUG_DTR +#ifdef CY_DEBUG_DTR printk("cyc:set_line_char dropping Z DTR\n"); #endif }else{ cy_writel(&ch_ctrl->rs_control, cy_readl(&ch_ctrl->rs_control) | C_RS_DTR); -#ifdef SERIAL_DEBUG_DTR +#ifdef CY_DEBUG_DTR printk("cyc:set_line_char raising Z DTR\n"); #endif } @@ -3343,6 +3343,21 @@ set_line_char(struct cyclades_port * info) } } + /* + * Set up the tty->alt_speed kludge + */ + if (info->tty) { + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + info->tty->alt_speed = 57600; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + info->tty->alt_speed = 115200; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + info->tty->alt_speed = 230400; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + info->tty->alt_speed = 460800; + } + + } /* set_line_char */ @@ -3377,12 +3392,11 @@ set_serial_info(struct cyclades_port * info, struct serial_struct new_serial; struct cyclades_port old_info; - if (!new_info) - return -EFAULT; - copy_from_user(&new_serial,new_info,sizeof(new_serial)); + if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) + return -EFAULT; old_info = *info; - if (!suser()) { + if (!capable(CAP_SYS_ADMIN)) { if ((new_serial.close_delay != info->close_delay) || (new_serial.baud_base != info->baud) || ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) != @@ -3405,7 +3419,6 @@ set_serial_info(struct cyclades_port * info, (new_serial.flags & ASYNC_FLAGS)); info->close_delay = new_serial.close_delay * HZ/100; info->closing_wait = new_serial.closing_wait * HZ/100; - check_and_exit: if (info->flags & ASYNC_INITIALIZED){ @@ -3462,7 +3475,7 @@ get_modem_info(struct cyclades_port * info, unsigned int *value) } else { base_addr = (unsigned char*) (cy_card[card].base_addr); - if (cy_card[card].num_chips != 1){ + if (cy_card[card].num_chips != -1){ return -EINVAL; } @@ -3486,8 +3499,7 @@ get_modem_info(struct cyclades_port * info, unsigned int *value) } } - cy_put_user(result,(unsigned long *) value); - return 0; + return cy_put_user(result,(unsigned long *) value); } /* get_modem_info */ @@ -3535,7 +3547,7 @@ set_modem_info(struct cyclades_port * info, unsigned int cmd, } else { cy_writeb((u_long)base_addr+(CyMSVR2<default_threshold,value); - return 0; + return cy_put_user(info->default_threshold,value); }/* get_default_threshold */ @@ -3862,11 +3871,11 @@ get_timeout(struct cyclades_port * info, unsigned long *value) + (cy_chip_offset[chip]<default_timeout,value); - return 0; + return cy_put_user(info->default_timeout,value); }/* get_default_timeout */ /* @@ -3894,68 +3902,40 @@ static int cy_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { - int error; struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; int ret_val = 0; -#ifdef SERIAL_DEBUG_OTHER + if (serial_paranoia_check(info, tty->device, "cy_ioctl")) + return -ENODEV; + +#ifdef CY_DEBUG_OTHER printk("cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n", info->line, cmd, arg); /* */ #endif switch (cmd) { case CYGETMON: - error = verify_area(VERIFY_WRITE, (void *) arg - ,sizeof(struct cyclades_monitor)); - if (error){ - ret_val = error; - break; - } ret_val = get_mon_info(info, (struct cyclades_monitor *)arg); break; case CYGETTHRESH: - error = verify_area(VERIFY_WRITE, (void *) arg - ,sizeof(unsigned long)); - if (error){ - ret_val = error; - break; - } ret_val = get_threshold(info, (unsigned long *)arg); break; case CYSETTHRESH: ret_val = set_threshold(info, (unsigned long)arg); break; case CYGETDEFTHRESH: - error = verify_area(VERIFY_WRITE, (void *) arg - ,sizeof(unsigned long)); - if (error){ - ret_val = error; - break; - } ret_val = get_default_threshold(info, (unsigned long *)arg); break; case CYSETDEFTHRESH: ret_val = set_default_threshold(info, (unsigned long)arg); break; case CYGETTIMEOUT: - error = verify_area(VERIFY_WRITE, (void *) arg - ,sizeof(unsigned long)); - if (error){ - ret_val = error; - break; - } ret_val = get_timeout(info, (unsigned long *)arg); break; case CYSETTIMEOUT: ret_val = set_timeout(info, (unsigned long)arg); break; case CYGETDEFTIMEOUT: - error = verify_area(VERIFY_WRITE, (void *) arg - ,sizeof(unsigned long)); - if (error){ - ret_val = error; - break; - } ret_val = get_default_timeout(info, (unsigned long *)arg); break; case CYSETDEFTIMEOUT: @@ -3976,109 +3956,63 @@ cy_ioctl(struct tty_struct *tty, struct file * file, ret_val = info->rtsdtr_inv; break; case CYGETCARDINFO: - error = verify_area(VERIFY_WRITE, (void *) arg - ,sizeof(struct cyclades_card)); - if (error){ - ret_val = error; - break; - } - copy_to_user((void *)arg, (void *)&cy_card[info->card], - sizeof (struct cyclades_card)); + if (copy_to_user((void *)arg, (void *)&cy_card[info->card], + sizeof (struct cyclades_card))) { + ret_val = -EFAULT; + } ret_val = 0; break; case CYGETCD1400VER: ret_val = info->chip_rev; break; - case CYZPOLLCYCLE: - cyz_polling_cycle = (HZ * arg) / 1000; + case CYZSETPOLLCYCLE: + cyz_polling_cycle = (arg * HZ) / 1000; ret_val = 0; break; + case CYZGETPOLLCYCLE: + ret_val = (cyz_polling_cycle * 1000) / HZ; + break; case CYSETWAIT: - info->closing_wait2 = (unsigned short)arg; + info->closing_wait = (unsigned short)arg * HZ/100; ret_val = 0; break; case CYGETWAIT: - ret_val = info->closing_wait2; + ret_val = info->closing_wait / (HZ/100); break; - case TCSBRK: /* SVID version: non-zero arg --> no break */ - ret_val = tty_check_change(tty); - if (ret_val) - return ret_val; - tty_wait_until_sent(tty,0); - if (!arg) - send_break(info, HZ/4); /* 1/4 second */ - break; - case TCSBRKP: /* support for POSIX tcsendbreak() */ - ret_val = tty_check_change(tty); - if (ret_val) - return ret_val; - tty_wait_until_sent(tty,0); - send_break(info, arg ? arg*(HZ/10) : HZ/4); + case TCSBRK: /* SVID version: non-zero arg --> no break */ + ret_val = tty_check_change(tty); + if (ret_val) + return ret_val; + tty_wait_until_sent(tty,0); + if (!arg) + send_break(info, HZ/4); /* 1/4 second */ + break; + case TCSBRKP: /* support for POSIX tcsendbreak() */ + ret_val = tty_check_change(tty); + if (ret_val) + return ret_val; + tty_wait_until_sent(tty,0); + send_break(info, arg ? arg*(HZ/10) : HZ/4); + break; + case TIOCMGET: + ret_val = get_modem_info(info, (unsigned int *) arg); break; case TIOCMBIS: case TIOCMBIC: case TIOCMSET: ret_val = set_modem_info(info, cmd, (unsigned int *) arg); break; - -/* The following commands are incompletely implemented!!! */ - case TIOCGSOFTCAR: - error = verify_area(VERIFY_WRITE, (void *) arg - ,sizeof(unsigned int *)); - if (error){ - ret_val = error; - break; - } - cy_put_user(C_CLOCAL(tty) ? 1 : 0, - (unsigned long *) arg); - break; - case TIOCSSOFTCAR: - error = verify_area(VERIFY_READ, (void *) arg - ,sizeof(unsigned long *)); - if (error) { - ret_val = error; - break; - } - - arg = cy_get_user((unsigned long *) arg); - tty->termios->c_cflag = - ((tty->termios->c_cflag & ~CLOCAL) | - (arg ? CLOCAL : 0)); - break; - case TIOCMGET: - error = verify_area(VERIFY_WRITE, (void *) arg - ,sizeof(unsigned int *)); - if (error){ - ret_val = error; - break; - } - ret_val = get_modem_info(info, (unsigned int *) arg); - break; case TIOCGSERIAL: - error = verify_area(VERIFY_WRITE, (void *) arg - ,sizeof(struct serial_struct)); - if (error){ - ret_val = error; - break; - } - ret_val = get_serial_info(info, - (struct serial_struct *) arg); + ret_val = get_serial_info(info, (struct serial_struct *) arg); break; case TIOCSSERIAL: - error = verify_area(VERIFY_READ, (void *) arg - ,sizeof(struct serial_struct)); - if (error){ - ret_val = error; - break; - } - ret_val = set_serial_info(info, - (struct serial_struct *) arg); + ret_val = set_serial_info(info, (struct serial_struct *) arg); break; default: ret_val = -ENOIOCTLCMD; } -#ifdef SERIAL_DEBUG_OTHER +#ifdef CY_DEBUG_OTHER printk(" cyc:cy_ioctl done\n"); #endif @@ -4097,7 +4031,7 @@ cy_set_termios(struct tty_struct *tty, struct termios * old_termios) { struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; -#ifdef SERIAL_DEBUG_OTHER +#ifdef CY_DEBUG_OTHER printk("cyc:cy_set_termios ttyC%d\n", info->line); #endif @@ -4141,7 +4075,7 @@ cy_throttle(struct tty_struct * tty) unsigned char *base_addr; int card,chip,channel,index; -#ifdef SERIAL_DEBUG_THROTTLE +#ifdef CY_DEBUG_THROTTLE char buf[64]; printk("cyc:throttle %s: %d....ttyC%d\n", @@ -4197,7 +4131,7 @@ cy_unthrottle(struct tty_struct * tty) unsigned char *base_addr; int card,chip,channel,index; -#ifdef SERIAL_DEBUG_THROTTLE +#ifdef CY_DEBUG_THROTTLE char buf[64]; printk("cyc:unthrottle %s: %d....ttyC%d\n", @@ -4255,7 +4189,7 @@ cy_stop(struct tty_struct *tty) int chip,channel,index; unsigned long flags; -#ifdef SERIAL_DEBUG_OTHER +#ifdef CY_DEBUG_OTHER printk("cyc:cy_stop ttyC%d\n", info->line); /* */ #endif @@ -4295,7 +4229,7 @@ cy_start(struct tty_struct *tty) int chip,channel,index; unsigned long flags; -#ifdef SERIAL_DEBUG_OTHER +#ifdef CY_DEBUG_OTHER printk("cyc:cy_start ttyC%d\n", info->line); /* */ #endif @@ -4333,7 +4267,7 @@ cy_flush_buffer(struct tty_struct *tty) int card, channel; unsigned long flags; -#ifdef SERIAL_DEBUG_IO +#ifdef CY_DEBUG_IO printk("cyc:cy_flush_buffer ttyC%d\n", info->line); /* */ #endif @@ -4377,7 +4311,7 @@ cy_hangup(struct tty_struct *tty) { struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; -#ifdef SERIAL_DEBUG_OTHER +#ifdef CY_DEBUG_OTHER printk("cyc:cy_hangup ttyC%d\n", info->line); /* */ #endif @@ -4388,7 +4322,7 @@ cy_hangup(struct tty_struct *tty) shutdown(info); info->event = 0; info->count = 0; -#ifdef SERIAL_DEBUG_COUNT +#ifdef CY_DEBUG_COUNT printk("cyc:cy_hangup (%d): setting count to 0\n", current->pid); #endif info->tty = 0; @@ -4422,7 +4356,7 @@ cyy_init_card(volatile ucchar *true_base_addr,int index)) for(chip_number=0; chip_numberirq; cy_pci_addr0 = pdev->base_address[0]; cy_pci_addr1 = pdev->base_address[1]; cy_pci_addr2 = pdev->base_address[2]; pci_read_config_byte(pdev, PCI_REVISION_ID, &cyy_rev_id); -#else - pcibios_read_config_byte(cyy_bus, cyy_dev_fn, - PCI_INTERRUPT_LINE, &cy_pci_irq); - pcibios_read_config_dword(cyy_bus, cyy_dev_fn, - PCI_BASE_ADDRESS_0, - (unsigned int *) &cy_pci_addr0); - pcibios_read_config_dword(cyy_bus, cyy_dev_fn, - PCI_BASE_ADDRESS_1, - (unsigned int *) &cy_pci_addr1); - pcibios_read_config_dword(cyy_bus, cyy_dev_fn, - PCI_BASE_ADDRESS_2, - (unsigned int *) &cy_pci_addr2); - pcibios_read_config_byte(cyy_bus, cyy_dev_fn, - PCI_REVISION_ID, &cyy_rev_id); -#endif if ((device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) || (device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi)){ #ifdef CY_PCI_DEBUG printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ", -#ifdef NEW_PCI pdev->bus->number, pdev->devfn); -#else - cyy_bus, cyy_dev_fn); -#endif printk("rev_id=%d) IRQ%d\n", cyy_rev_id, (int)cy_pci_irq); printk("Cyclom-Y/PCI:found winaddr=0x%lx ioaddr=0x%lx\n", @@ -4686,11 +4577,7 @@ cy_detect_pci(void)) #if defined(__alpha__) if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */ printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ", -#ifdef NEW_PCI pdev->bus->number, pdev->devfn); -#else - cyy_bus, cyy_dev_fn); -#endif printk("rev_id=%d) IRQ%d\n", cyy_rev_id, (int)cy_pci_irq); printk("Cyclom-Y/PCI:found winaddr=0x%lx ioaddr=0x%lx\n", @@ -4775,11 +4662,7 @@ cy_detect_pci(void)) }else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo){ /* print message */ printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ", -#ifdef NEW_PCI pdev->bus->number, pdev->devfn); -#else - cyy_bus, cyy_dev_fn); -#endif printk("rev_id=%d) IRQ%d\n", cyy_rev_id, (int)cy_pci_irq); printk("Cyclades-Z/PCI: found winaddr=0x%lx ctladdr=0x%lx\n", @@ -4789,11 +4672,7 @@ cy_detect_pci(void)) }else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi){ #ifdef CY_PCI_DEBUG printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ", -#ifdef NEW_PCI pdev->bus->number, pdev->devfn); -#else - cyy_bus, cyy_dev_fn); -#endif printk("rev_id=%d) IRQ%d\n", cyy_rev_id, (int)cy_pci_irq); printk("Cyclades-Z/PCI: found winaddr=0x%lx ctladdr=0x%lx\n", @@ -4908,7 +4787,7 @@ cy_detect_pci(void)) cy_card[j].irq = (int) cy_pci_irq; cy_card[j].bus_index = 1; cy_card[j].first_line = cy_next_channel; - cy_card[j].num_chips = 1; + cy_card[j].num_chips = -1; IRQ_cards[cy_pci_irq] = &cy_card[j]; /* print message */ @@ -4991,7 +4870,7 @@ cy_detect_pci(void)) cy_card[j].irq = (int) cy_pci_irq; cy_card[j].bus_index = 1; cy_card[j].first_line = cy_next_channel; - cy_card[j].num_chips = 1; + cy_card[j].num_chips = -1; IRQ_cards[cy_pci_irq] = &cy_card[j]; /* print message */ @@ -5041,6 +4920,65 @@ show_version(void) __DATE__, __TIME__); } /* show_version */ +#ifdef CONFIG_PROC_FS +static int +cyclades_get_proc_info(char *buf, char **start, off_t offset, int length, + int *eof, void *data) +{ + struct cyclades_port *info; + int i; + int len=0; + off_t begin=0; + off_t pos=0; + int size; + __u32 cur_jifs = jiffies; + + size = sprintf(buf, "Dev TimeOpen BytesOut IdleOut BytesIn IdleIn Overruns Ldisc\n"); + + pos += size; + len += size; + + /* Output one line for each known port */ + for (i = 0; i < NR_PORTS && cy_port[i].line >= 0; i++) { + info = &cy_port[i]; + + if (info->count) + size = sprintf(buf+len, + "%3d %8lu %10lu %8lu %10lu %8lu %9lu %6d\n", + info->line, + JIFFIES_DIFF(info->idle_stats.in_use, cur_jifs) / HZ, + info->idle_stats.xmit_bytes, + JIFFIES_DIFF(info->idle_stats.xmit_idle, cur_jifs) / HZ, + info->idle_stats.recv_bytes, + JIFFIES_DIFF(info->idle_stats.recv_idle, cur_jifs) / HZ, + info->idle_stats.overruns, + (long) info->tty->ldisc.num); + else + size = sprintf(buf+len, + "%3d %8lu %10lu %8lu %10lu %8lu %9lu %6ld\n", + info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L); + len += size; + pos = begin + len; + + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + goto done; + } + *eof = 1; +done: + *start = buf + (offset - begin); /* Start of wanted data */ + len -= (offset - begin); /* Start slop */ + if (len > length) + len = length; /* Ending slop */ + if (len < 0) + len = 0; + return len; +} +#endif + /* The serial driver boot-time initialization code! Hardware I/O ports are mapped to character special devices on a @@ -5070,6 +5008,7 @@ cy_init(void)) unsigned long mailbox; unsigned short chip_number; int nports; + struct proc_dir_entry *ent; show_version(); @@ -5077,6 +5016,7 @@ cy_init(void)) memset(&cy_serial_driver, 0, sizeof(struct tty_driver)); cy_serial_driver.magic = TTY_DRIVER_MAGIC; + cy_serial_driver.name = "cyclades"; cy_serial_driver.name = "ttyC"; cy_serial_driver.major = CYCLADES_MAJOR; cy_serial_driver.minor_start = 0; @@ -5106,6 +5046,7 @@ cy_init(void)) cy_serial_driver.stop = cy_stop; cy_serial_driver.start = cy_start; cy_serial_driver.hangup = cy_hangup; + cy_serial_driver.wait_until_sent = cy_wait_until_sent; /* * The callout device is just like normal device except for @@ -5115,6 +5056,9 @@ cy_init(void)) cy_callout_driver.name = "cub"; cy_callout_driver.major = CYCLADESAUX_MAJOR; cy_callout_driver.subtype = SERIAL_TYPE_CALLOUT; + cy_callout_driver.read_proc = 0; + cy_callout_driver.proc_entry = 0; + if (tty_register_driver(&cy_serial_driver)) panic("Couldn't register Cyclades serial driver\n"); @@ -5123,7 +5067,7 @@ cy_init(void)) init_bh(CYCLADES_BH, do_cyclades_bh); - for (i = 0; i < 16; i++) { + for (i = 0; i < NR_IRQS; i++) { IRQ_cards[i] = 0; } @@ -5167,7 +5111,7 @@ cy_init(void)) /* initialize per-port data structures for each valid board found */ for (board = 0 ; board < cy_nboard ; board++) { cinfo = &cy_card[board]; - if (cinfo->num_chips == 1){ /* Cyclades-Z */ + if (cinfo->num_chips == -1){ /* Cyclades-Z */ number_z_boards++; mailbox = cy_readl(&((struct RUNTIME_9060 *) cy_card[board].ctl_addr)->mail_box_0); @@ -5199,11 +5143,10 @@ cy_init(void)) info->rco = 0; info->close_delay = 5*HZ/10; info->closing_wait = CLOSING_WAIT_DELAY; - info->closing_wait2 = 0; info->x_char = 0; info->event = 0; info->count = 0; -#ifdef SERIAL_DEBUG_COUNT +#ifdef CY_DEBUG_COUNT // printk("cyc:cy_init(1) setting Z count to 0\n"); #endif info->blocked_open = 0; @@ -5250,7 +5193,6 @@ cy_init(void)) info->cor5 = 0; info->close_delay = 5*HZ/10; info->closing_wait = CLOSING_WAIT_DELAY; - info->closing_wait2 = 0; chip_number = (port - cinfo->first_line) / 4; if ((info->chip_rev = cy_readb(cinfo->base_addr + (cy_chip_offset[chip_number]<x_char = 0; info->event = 0; info->count = 0; -#ifdef SERIAL_DEBUG_COUNT +#ifdef CY_DEBUG_COUNT // printk("cyc:cy_init(2) setting Y count to 0\n"); #endif info->blocked_open = 0; @@ -5307,6 +5249,16 @@ cy_init(void)) #endif } +#ifdef CONFIG_PROC_FS + ent = create_proc_entry("cyclades", S_IFREG | S_IRUGO, 0); + ent->read_proc = cyclades_get_proc_info; +#endif +#if 0 +#ifdef CONFIG_PROC_FS + proc_register(&proc_root, &cyclades_proc_entry); +#endif +#endif + return 0; } /* cy_init */ @@ -5349,6 +5301,10 @@ cleanup_module(void) free_irq(cy_card[i].irq,NULL); } } +#ifdef CONFIG_PROC_FS + remove_proc_entry("cyclades", 0); +#endif + } /* cleanup_module */ #else /* called by linux/init/main.c to parse command line options */ -- cgit v1.2.3