X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fchar%2Fserial167.c;h=3b23270eaa65385f56a2cef7652aeb2ccea77055;hb=0d2b405a628309310b4fc02b26d713b855ad5f68;hp=f1497cecffd815248a7eb374a0346e4e8fb88e2f;hpb=5f7e08ca7b657f5678dd62a080f7f3a8f923ad02;p=linux-2.6-omap-h63xx.git diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index f1497cecffd..3b23270eaa6 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c @@ -90,8 +90,6 @@ #define STD_COM_FLAGS (0) -#define SERIAL_TYPE_NORMAL 1 - static struct tty_driver *cy_serial_driver; extern int serial_console; static struct cyclades_port *serial_console_info = NULL; @@ -359,18 +357,6 @@ static void cy_start(struct tty_struct *tty) local_irq_restore(flags); } /* cy_start */ -/* - * This routine is used by the interrupt handler to schedule - * processing in the software interrupt portion of the driver - * (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) -{ - 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. @@ -485,10 +471,12 @@ static irqreturn_t cd2401_modem_interrupt(int irq, void *dev_id) && (info->flags & ASYNC_CHECK_CD)) { if (mdm_status & CyDCD) { /* CP('!'); */ - cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP); + wake_up_interruptible(&info->open_wait); } else { /* CP('@'); */ - cy_sched_event(info, Cy_EVENT_HANGUP); + tty_hangup(info->tty); + wake_up_interruptible(&info->open_wait); + info->flags &= ~ASYNC_NORMAL_ACTIVE; } } if ((mdm_change & CyCTS) @@ -498,8 +486,7 @@ static irqreturn_t cd2401_modem_interrupt(int irq, void *dev_id) /* !!! cy_start isn't used because... */ info->tty->stopped = 0; base_addr[CyIER] |= CyTxMpty; - cy_sched_event(info, - Cy_EVENT_WRITE_WAKEUP); + tty_wakeup(info->tty); } } else { if (!(mdm_status & CyCTS)) { @@ -545,9 +532,6 @@ static irqreturn_t cd2401_tx_interrupt(int irq, void *dev_id) 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; } @@ -629,9 +613,9 @@ static irqreturn_t cd2401_tx_interrupt(int irq, void *dev_id) } } - if (info->xmit_cnt < WAKEUP_CHARS) { - cy_sched_event(info, Cy_EVENT_WRITE_WAKEUP); - } + if (info->xmit_cnt < WAKEUP_CHARS) + tty_wakeup(info->tty); + base_addr[CyTEOIR] = (char_count != saved_cnt) ? 0 : CyNOTRANS; return IRQ_HANDLED; } /* cy_tx_interrupt */ @@ -692,49 +676,6 @@ static irqreturn_t cd2401_rx_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } /* cy_rx_interrupt */ -/* - * This routine is used to handle the "bottom half" processing for the - * serial driver, known also the "software interrupt" processing. - * This processing is done at the kernel interrupt level, after the - * cy#/_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This - * is where time-consuming activities which can not be done in the - * interrupt driver proper are done; the interrupt driver schedules - * them using cy_sched_event(), and they get done here. - * - * This is done through one level of indirection--the task queue. - * When a hardware interrupt service routine wants service by the - * driver's bottom half, it enqueues the appropriate tq_struct (one - * per port) to the keventd work queue and sets a request flag - * that the work queue be processed. - * - * Although this may seem unwieldy, it gives the system a way to - * pass an argument (in this case the pointer to the cyclades_port - * 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) -{ - struct cyclades_port *info = - container_of(ugly_api, 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); - } - 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. */ @@ -1119,7 +1060,7 @@ static void config_setup(struct cyclades_port *info) } /* config_setup */ -static void cy_put_char(struct tty_struct *tty, unsigned char ch) +static int cy_put_char(struct tty_struct *tty, unsigned char ch) { struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; unsigned long flags; @@ -1129,21 +1070,22 @@ static void cy_put_char(struct tty_struct *tty, unsigned char ch) #endif if (serial_paranoia_check(info, tty->name, "cy_put_char")) - return; + return 0; if (!info->xmit_buf) - return; + return 0; local_irq_save(flags); if (info->xmit_cnt >= PAGE_SIZE - 1) { local_irq_restore(flags); - return; + return 0; } info->xmit_buf[info->xmit_head++] = ch; info->xmit_head &= PAGE_SIZE - 1; info->xmit_cnt++; local_irq_restore(flags); + return 1; } /* cy_put_char */ static void cy_flush_chars(struct tty_struct *tty) @@ -1598,6 +1540,8 @@ cy_ioctl(struct tty_struct *tty, struct file *file, printk("cy_ioctl %s, cmd = %x arg = %lx\n", tty->name, cmd, arg); /* */ #endif + lock_kernel(); + switch (cmd) { case CYGETMON: ret_val = get_mon_info(info, argp); @@ -1643,18 +1587,6 @@ cy_ioctl(struct tty_struct *tty, struct file *file, break; /* The following commands are incompletely implemented!!! */ - case TIOCGSOFTCAR: - ret_val = - put_user(C_CLOCAL(tty) ? 1 : 0, - (unsigned long __user *)argp); - break; - case TIOCSSOFTCAR: - ret_val = get_user(val, (unsigned long __user *)argp); - if (ret_val) - break; - tty->termios->c_cflag = - ((tty->termios->c_cflag & ~CLOCAL) | (val ? CLOCAL : 0)); - break; case TIOCGSERIAL: ret_val = get_serial_info(info, argp); break; @@ -1664,6 +1596,7 @@ cy_ioctl(struct tty_struct *tty, struct file *file, default: ret_val = -ENOIOCTLCMD; } + unlock_kernel(); #ifdef SERIAL_DEBUG_OTHER printk("cy_ioctl done\n"); @@ -1742,10 +1675,8 @@ static void cy_close(struct tty_struct *tty, struct file *filp) if (info->flags & ASYNC_INITIALIZED) tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */ shutdown(info); - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + cy_flush_buffer(tty); tty_ldisc_flush(tty); - info->event = 0; info->tty = NULL; if (info->blocked_open) { if (info->close_delay) { @@ -2236,7 +2167,6 @@ static int __init serial167_init(void) info->rco = baud_co[DefSpeed] >> 5; /* Rx CO */ info->close_delay = 0; info->x_char = 0; - info->event = 0; info->count = 0; #ifdef SERIAL_DEBUG_COUNT printk("cyc: %d: setting count to 0\n", @@ -2245,7 +2175,6 @@ static int __init serial167_init(void) info->blocked_open = 0; info->default_threshold = 0; info->default_timeout = 0; - INIT_WORK(&info->tqueue, do_softint); init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); /* info->session */