X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fchar%2Fgeneric_serial.c;h=e2a0b6f3d336317ccc842e1ea88a4f3743f08c95;hb=refs%2Fheads%2Fvserver;hp=71435d1cb069efa893a498f9451c39755828984c;hpb=6a77f38946aaee1cd85eeec6cf4229b204c15071;p=linux-2.6.git diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c index 71435d1cb..e2a0b6f3d 100644 --- a/drivers/char/generic_serial.c +++ b/drivers/char/generic_serial.c @@ -26,15 +26,13 @@ #include #include #include +#include #include #include #include #define DEBUG -static char * tmp_buf; -static DECLARE_MUTEX(tmp_buf_sem); - static int gs_debug; #ifdef DEBUG @@ -45,11 +43,11 @@ static int gs_debug; #define func_enter() gs_dprintk (GS_DEBUG_FLOW, "gs: enter %s\n", __FUNCTION__) #define func_exit() gs_dprintk (GS_DEBUG_FLOW, "gs: exit %s\n", __FUNCTION__) - -#ifdef NEW_WRITE_LOCKING +#define NEW_WRITE_LOCKING 1 +#if NEW_WRITE_LOCKING #define DECL /* Nothing */ -#define LOCKIT down (& port->port_write_sem); -#define RELEASEIT up (&port->port_write_sem); +#define LOCKIT mutex_lock(& port->port_write_mutex); +#define RELEASEIT mutex_unlock(&port->port_write_mutex); #else #define DECL unsigned long flags; #define LOCKIT save_flags (flags);cli () @@ -124,14 +122,14 @@ int gs_write(struct tty_struct * tty, /* get exclusive "write" access to this port (problem 3) */ /* This is not a spinlock because we can have a disk access (page fault) in copy_from_user */ - down (& port->port_write_sem); + mutex_lock(& port->port_write_mutex); while (1) { c = count; /* This is safe because we "OWN" the "head". Noone else can - change the "head": we own the port_write_sem. */ + change the "head": we own the port_write_mutex. */ /* Don't overrun the end of the buffer */ t = SERIAL_XMIT_SIZE - port->xmit_head; if (t < c) c = t; @@ -153,7 +151,7 @@ int gs_write(struct tty_struct * tty, count -= c; total += c; } - up (& port->port_write_sem); + mutex_unlock(& port->port_write_mutex); gs_dprintk (GS_DEBUG_WRITE, "write: interrupts are %s\n", (port->flags & GS_TX_INTEN)?"enabled": "disabled"); @@ -205,16 +203,16 @@ int gs_write(struct tty_struct * tty, if (!tty) return -EIO; port = tty->driver_data; - if (!port || !port->xmit_buf || !tmp_buf) + if (!port || !port->xmit_buf) return -EIO; - save_flags(flags); + local_save_flags(flags); while (1) { cli(); c = count; /* This is safe because we "OWN" the "head". Noone else can - change the "head": we own the port_write_sem. */ + change the "head": we own the port_write_mutex. */ /* Don't overrun the end of the buffer */ t = SERIAL_XMIT_SIZE - port->xmit_head; if (t < c) c = t; @@ -227,14 +225,14 @@ int gs_write(struct tty_struct * tty, /* Can't copy more? break out! */ if (c <= 0) { - restore_flags(flags); + local_restore_flags(flags); break; } memcpy(port->xmit_buf + port->xmit_head, buf, c); port->xmit_head = ((port->xmit_head + c) & (SERIAL_XMIT_SIZE-1)); port->xmit_cnt += c; - restore_flags(flags); + local_restore_flags(flags); buf += c; count -= c; total += c; @@ -295,7 +293,7 @@ static int gs_real_chars_in_buffer(struct tty_struct *tty) } -static int gs_wait_tx_flushed (void * ptr, int timeout) +static int gs_wait_tx_flushed (void * ptr, unsigned long timeout) { struct gs_port *port = ptr; unsigned long end_jiffies; @@ -380,9 +378,9 @@ void gs_flush_buffer(struct tty_struct *tty) if (!port) return; /* XXX Would the write semaphore do? */ - save_flags(flags); cli(); + spin_lock_irqsave (&port->driver_lock, flags); port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; - restore_flags(flags); + spin_unlock_irqrestore (&port->driver_lock, flags); wake_up_interruptible(&tty->write_wait); tty_wakeup(tty); @@ -468,8 +466,7 @@ static void gs_shutdown_port (struct gs_port *port) if (!(port->flags & ASYNC_INITIALIZED)) return; - save_flags (flags); - cli (); + spin_lock_irqsave(&port->driver_lock, flags); if (port->xmit_buf) { free_page((unsigned long) port->xmit_buf); @@ -482,7 +479,7 @@ static void gs_shutdown_port (struct gs_port *port) port->rd->shutdown_port (port); port->flags &= ~ASYNC_INITIALIZED; - restore_flags (flags); + spin_unlock_irqrestore(&port->driver_lock, flags); func_exit(); } @@ -519,6 +516,7 @@ int gs_block_til_ready(void *port_, struct file * filp) int do_clocal = 0; int CD; struct tty_struct *tty; + unsigned long flags; func_enter (); @@ -570,10 +568,11 @@ int gs_block_til_ready(void *port_, struct file * filp) add_wait_queue(&port->open_wait, &wait); gs_dprintk (GS_DEBUG_BTR, "after add waitq.\n"); - cli(); - if (!tty_hung_up_p(filp)) + spin_lock_irqsave(&port->driver_lock, flags); + if (!tty_hung_up_p(filp)) { port->count--; - sti(); + } + spin_unlock_irqrestore(&port->driver_lock, flags); port->blocked_open++; while (1) { CD = port->rd->get_CD (port); @@ -602,8 +601,9 @@ int gs_block_til_ready(void *port_, struct file * filp) port->blocked_open); set_current_state (TASK_RUNNING); remove_wait_queue(&port->open_wait, &wait); - if (!tty_hung_up_p(filp)) + if (!tty_hung_up_p(filp)) { port->count++; + } port->blocked_open--; if (retval) return retval; @@ -633,27 +633,29 @@ void gs_close(struct tty_struct * tty, struct file * filp) port->tty = tty; } - save_flags(flags); cli(); + spin_lock_irqsave(&port->driver_lock, flags); if (tty_hung_up_p(filp)) { - restore_flags(flags); - port->rd->hungup (port); + spin_unlock_irqrestore(&port->driver_lock, flags); + if (port->rd->hungup) + port->rd->hungup (port); func_exit (); return; } if ((tty->count == 1) && (port->count != 1)) { - printk(KERN_ERR "gs: gs_close: bad port count;" - " tty->count is 1, port count is %d\n", port->count); + printk(KERN_ERR "gs: gs_close port %p: bad port count;" + " tty->count is 1, port count is %d\n", port, port->count); port->count = 1; } if (--port->count < 0) { - printk(KERN_ERR "gs: gs_close: bad port count: %d\n", port->count); + printk(KERN_ERR "gs: gs_close port %p: bad port count: %d\n", port, port->count); port->count = 0; } + if (port->count) { - gs_dprintk(GS_DEBUG_CLOSE, "gs_close: count: %d\n", port->count); - restore_flags(flags); + gs_dprintk(GS_DEBUG_CLOSE, "gs_close port %p: count: %d\n", port, port->count); + spin_unlock_irqrestore(&port->driver_lock, flags); func_exit (); return; } @@ -675,16 +677,17 @@ void gs_close(struct tty_struct * tty, struct file * filp) */ port->rd->disable_rx_interrupts (port); + spin_unlock_irqrestore(&port->driver_lock, flags); /* close has no way of returning "EINTR", so discard return value */ if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) - gs_wait_tx_flushed (port, port->closing_wait); + gs_wait_tx_flushed (port, port->closing_wait); port->flags &= ~GS_ACTIVE; if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - + tty_ldisc_flush(tty); tty->closing = 0; @@ -695,30 +698,25 @@ void gs_close(struct tty_struct * tty, struct file * filp) if (port->blocked_open) { if (port->close_delay) { + spin_unlock_irqrestore(&port->driver_lock, flags); msleep_interruptible(jiffies_to_msecs(port->close_delay)); + spin_lock_irqsave(&port->driver_lock, flags); } wake_up_interruptible(&port->open_wait); } port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING | ASYNC_INITIALIZED); wake_up_interruptible(&port->close_wait); - restore_flags(flags); func_exit (); } -static unsigned int gs_baudrates[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600 -}; - - void gs_set_termios (struct tty_struct * tty, - struct termios * old_termios) + struct ktermios * old_termios) { struct gs_port *port; int baudrate, tmp, rv; - struct termios *tiosp; + struct ktermios *tiosp; func_enter(); @@ -727,6 +725,12 @@ void gs_set_termios (struct tty_struct * tty, port = tty->driver_data; if (!port) return; + if (!port->tty) { + /* This seems to happen when this is called after gs_close. */ + gs_dprintk (GS_DEBUG_TERMIOS, "gs: Odd: port->tty is NULL\n"); + port->tty = tty; + } + tiosp = tty->termios; @@ -734,11 +738,9 @@ void gs_set_termios (struct tty_struct * tty, gs_dprintk (GS_DEBUG_TERMIOS, "termios structure (%p):\n", tiosp); } -#if 0 /* This is an optimization that is only allowed for dumb cards */ /* Smart cards require knowledge of iflags and oflags too: that might change hardware cooking mode.... */ -#endif if (old_termios) { if( (tiosp->c_iflag == old_termios->c_iflag) && (tiosp->c_oflag == old_termios->c_oflag) @@ -762,16 +764,8 @@ void gs_set_termios (struct tty_struct * tty, if(!memcmp(tiosp->c_cc, old_termios->c_cc, NCC)) printk("c_cc changed\n"); } - baudrate = tiosp->c_cflag & CBAUD; - if (baudrate & CBAUDEX) { - baudrate &= ~CBAUDEX; - if ((baudrate < 1) || (baudrate > 4)) - tiosp->c_cflag &= ~CBAUDEX; - else - baudrate += 15; - } + baudrate = tty_get_baud_rate(tty); - baudrate = gs_baudrates[baudrate]; if ((tiosp->c_cflag & CBAUD) == B38400) { if ( (port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) baudrate = 57600; @@ -821,7 +815,7 @@ void gs_set_termios (struct tty_struct * tty, if (!(old_termios->c_cflag & CLOCAL) && (tty->termios->c_cflag & CLOCAL)) - wake_up_interruptible(&info->open_wait); + wake_up_interruptible(&port->gs.open_wait); #endif func_exit(); @@ -834,58 +828,43 @@ void gs_set_termios (struct tty_struct * tty, int gs_init_port(struct gs_port *port) { unsigned long flags; - unsigned long page; - - save_flags (flags); - if (!tmp_buf) { - page = get_zeroed_page(GFP_KERNEL); - - cli (); /* Don't expect this to make a difference. */ - if (tmp_buf) - free_page(page); - else - tmp_buf = (unsigned char *) page; - restore_flags (flags); - if (!tmp_buf) { - return -ENOMEM; - } - } + func_enter (); - if (port->flags & ASYNC_INITIALIZED) + if (port->flags & ASYNC_INITIALIZED) { + func_exit (); return 0; - + } if (!port->xmit_buf) { /* We may sleep in get_zeroed_page() */ unsigned long tmp; tmp = get_zeroed_page(GFP_KERNEL); - - /* Spinlock? */ - cli (); + spin_lock_irqsave (&port->driver_lock, flags); if (port->xmit_buf) free_page (tmp); else port->xmit_buf = (unsigned char *) tmp; - restore_flags (flags); - - if (!port->xmit_buf) + spin_unlock_irqrestore(&port->driver_lock, flags); + if (!port->xmit_buf) { + func_exit (); return -ENOMEM; + } } - cli(); - + spin_lock_irqsave (&port->driver_lock, flags); if (port->tty) clear_bit(TTY_IO_ERROR, &port->tty->flags); - + mutex_init(&port->port_write_mutex); port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; - + spin_unlock_irqrestore(&port->driver_lock, flags); gs_set_termios(port->tty, NULL); - + spin_lock_irqsave (&port->driver_lock, flags); port->flags |= ASYNC_INITIALIZED; port->flags &= ~GS_TX_INTEN; - restore_flags(flags); + spin_unlock_irqrestore(&port->driver_lock, flags); + func_exit (); return 0; } @@ -956,13 +935,15 @@ int gs_getserial(struct gs_port *port, struct serial_struct __user *sp) void gs_got_break(struct gs_port *port) { + func_enter (); + + tty_insert_flip_char(port->tty, 0, TTY_BREAK); + tty_schedule_flip(port->tty); if (port->flags & ASYNC_SAK) { do_SAK (port->tty); } - *(port->tty->flip.flag_buf_ptr) = TTY_BREAK; - port->tty->flip.flag_buf_ptr++; - port->tty->flip.char_buf_ptr++; - port->tty->flip.count++; + + func_exit (); }