* to TASK_RUNNING will be lost and write_chan's subsequent call to
* schedule() will never return (unless it catches a signal).
* This race condition occurs because write_bulk_callback() (and thus
-* the wakeup) are called asynchonously from an interrupt, rather than
+* the wakeup) are called asynchronously from an interrupt, rather than
* from the scheduler. We can avoid the race by calling the wakeup
* from the scheduler queue and that's our fix: Now, at the end of
* write_bulk_callback() we queue up a wakeup call on the scheduler
* $Id: digi_acceleport.c,v 1.80.1.2 2000/11/02 05:45:08 root Exp $
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/workqueue.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/wait.h>
+#include <linux/usb/serial.h>
/* Defines */
int dp_in_close; /* close in progress */
wait_queue_head_t dp_close_wait; /* wait queue for close */
struct work_struct dp_wakeup_work;
+ struct usb_serial_port *dp_port;
};
/* Local Function Declarations */
static void digi_wakeup_write( struct usb_serial_port *port );
-static void digi_wakeup_write_lock(void *);
+static void digi_wakeup_write_lock(struct work_struct *work);
static int digi_write_oob_command( struct usb_serial_port *port,
unsigned char *buf, int count, int interruptible );
static int digi_write_inb_command( struct usb_serial_port *port,
static void digi_rx_throttle (struct usb_serial_port *port);
static void digi_rx_unthrottle (struct usb_serial_port *port);
static void digi_set_termios( struct usb_serial_port *port,
- struct termios *old_termios );
+ struct ktermios *old_termios );
static void digi_break_ctl( struct usb_serial_port *port, int break_state );
static int digi_ioctl( struct usb_serial_port *port, struct file *file,
unsigned int cmd, unsigned long arg );
static int digi_tiocmset( struct usb_serial_port *port, struct file *file,
unsigned int set, unsigned int clear );
static int digi_write( struct usb_serial_port *port, const unsigned char *buf, int count );
-static void digi_write_bulk_callback( struct urb *urb, struct pt_regs *regs );
+static void digi_write_bulk_callback( struct urb *urb );
static int digi_write_room( struct usb_serial_port *port );
static int digi_chars_in_buffer( struct usb_serial_port *port );
static int digi_open( struct usb_serial_port *port, struct file *filp );
static int digi_startup_device( struct usb_serial *serial );
static int digi_startup( struct usb_serial *serial );
static void digi_shutdown( struct usb_serial *serial );
-static void digi_read_bulk_callback( struct urb *urb, struct pt_regs *regs );
+static void digi_read_bulk_callback( struct urb *urb );
static int digi_read_inb_callback( struct urb *urb );
static int digi_read_oob_callback( struct urb *urb );
MODULE_DEVICE_TABLE (usb, id_table_combined);
static struct usb_driver digi_driver = {
- .owner = THIS_MODULE,
.name = "digi_acceleport",
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table_combined,
+ .no_dynamic_id = 1,
};
/* device info needed for the Digi serial converter */
-static struct usb_serial_device_type digi_acceleport_2_device = {
- .owner = THIS_MODULE,
- .name = "Digi 2 port USB adapter",
- .short_name = "digi_2",
+static struct usb_serial_driver digi_acceleport_2_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "digi_2",
+ },
+ .description = "Digi 2 port USB adapter",
.id_table = id_table_2,
.num_interrupt_in = 0,
.num_bulk_in = 4,
.shutdown = digi_shutdown,
};
-static struct usb_serial_device_type digi_acceleport_4_device = {
- .owner = THIS_MODULE,
- .name = "Digi 4 port USB adapter",
- .short_name = "digi_4",
+static struct usb_serial_driver digi_acceleport_4_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "digi_4",
+ },
+ .description = "Digi 4 port USB adapter",
.id_table = id_table_4,
.num_interrupt_in = 0,
.num_bulk_in = 5,
* and the sleep. In other words, spin_unlock_irqrestore and
* interruptible_sleep_on_timeout are "atomic" with respect to
* wake ups. This is used to implement condition variables.
+*
+* interruptible_sleep_on_timeout is deprecated and has been replaced
+* with the equivalent code.
*/
static inline long cond_wait_interruptible_timeout_irqrestore(
wait_queue_head_t *q, long timeout,
spinlock_t *lock, unsigned long flags )
{
+ DEFINE_WAIT(wait);
- wait_queue_t wait;
-
-
- init_waitqueue_entry( &wait, current );
-
- set_current_state( TASK_INTERRUPTIBLE );
-
- add_wait_queue( q, &wait );
-
- spin_unlock_irqrestore( lock, flags );
-
+ prepare_to_wait(q, &wait, TASK_INTERRUPTIBLE);
+ spin_unlock_irqrestore(lock, flags);
timeout = schedule_timeout(timeout);
+ finish_wait(q, &wait);
- remove_wait_queue( q, &wait );
-
- return( timeout );
-
+ return timeout;
}
* on writes.
*/
-static void digi_wakeup_write_lock(void *arg)
+static void digi_wakeup_write_lock(struct work_struct *work)
{
- struct usb_serial_port *port = arg;
+ struct digi_port *priv =
+ container_of(work, struct digi_port, dp_wakeup_work);
+ struct usb_serial_port *port = priv->dp_port;
unsigned long flags;
- struct digi_port *priv = usb_get_serial_port_data(port);
spin_lock_irqsave( &priv->dp_port_lock, flags );
spin_lock_irqsave( &priv->dp_port_lock, flags );
/* send any buffered chars from throttle time on to tty subsystem */
- len = min(priv->dp_in_buf_len, TTY_FLIPBUF_SIZE - tty->flip.count );
+
+ len = tty_buffer_request_room(tty, priv->dp_in_buf_len);
if( len > 0 ) {
- memcpy( tty->flip.char_buf_ptr, priv->dp_in_buf, len );
- memcpy( tty->flip.flag_buf_ptr, priv->dp_in_flag_buf, len );
- tty->flip.char_buf_ptr += len;
- tty->flip.flag_buf_ptr += len;
- tty->flip.count += len;
+ tty_insert_flip_string_flags(tty, priv->dp_in_buf, priv->dp_in_flag_buf, len);
tty_flip_buffer_push( tty );
}
static void digi_set_termios( struct usb_serial_port *port,
- struct termios *old_termios )
+ struct ktermios *old_termios )
{
struct digi_port *priv = usb_get_serial_port_data(port);
}
-static void digi_write_bulk_callback( struct urb *urb, struct pt_regs *regs )
+static void digi_write_bulk_callback( struct urb *urb )
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
int ret;
unsigned char buf[32];
struct digi_port *priv = usb_get_serial_port_data(port);
- struct termios not_termios;
+ struct ktermios not_termios;
unsigned long flags = 0;
static void digi_close( struct usb_serial_port *port, struct file *filp )
{
-
+ DEFINE_WAIT(wait);
int ret;
unsigned char buf[32];
struct tty_struct *tty = port->tty;
dbg( "digi_close: write oob failed, ret=%d", ret );
/* wait for final commands on oob port to complete */
- interruptible_sleep_on_timeout( &priv->dp_flush_wait,
- DIGI_CLOSE_TIMEOUT );
+ prepare_to_wait(&priv->dp_flush_wait, &wait, TASK_INTERRUPTIBLE);
+ schedule_timeout(DIGI_CLOSE_TIMEOUT);
+ finish_wait(&priv->dp_flush_wait, &wait);
/* shutdown any outstanding bulk writes */
usb_kill_urb(port->write_urb);
for( i=0; i<serial->type->num_ports+1; i++ ) {
/* allocate port private structure */
- priv = (struct digi_port *)kmalloc( sizeof(struct digi_port),
+ priv = kmalloc( sizeof(struct digi_port),
GFP_KERNEL );
if( priv == (struct digi_port *)0 ) {
while( --i >= 0 )
init_waitqueue_head( &priv->dp_flush_wait );
priv->dp_in_close = 0;
init_waitqueue_head( &priv->dp_close_wait );
- INIT_WORK(&priv->dp_wakeup_work,
- digi_wakeup_write_lock, serial->port[i]);
+ INIT_WORK(&priv->dp_wakeup_work, digi_wakeup_write_lock);
+ priv->dp_port = serial->port[i];
/* initialize write wait queue for this port */
init_waitqueue_head( &serial->port[i]->write_wait );
}
/* allocate serial private structure */
- serial_priv = (struct digi_serial *)kmalloc( sizeof(struct digi_serial),
+ serial_priv = kmalloc( sizeof(struct digi_serial),
GFP_KERNEL );
if( serial_priv == (struct digi_serial *)0 ) {
for( i=0; i<serial->type->num_ports+1; i++ )
}
-static void digi_read_bulk_callback( struct urb *urb, struct pt_regs *regs )
+static void digi_read_bulk_callback( struct urb *urb )
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
int status = ((unsigned char *)urb->transfer_buffer)[2];
unsigned char *data = ((unsigned char *)urb->transfer_buffer)+3;
int flag,throttled;
+ int i;
/* do not process callbacks on closed ports */
/* but do continue the read chain */
}
} else {
-
- len = min( len, TTY_FLIPBUF_SIZE - tty->flip.count );
-
+ len = tty_buffer_request_room(tty, len);
if( len > 0 ) {
- memcpy( tty->flip.char_buf_ptr, data, len );
- memset( tty->flip.flag_buf_ptr, flag, len );
- tty->flip.char_buf_ptr += len;
- tty->flip.flag_buf_ptr += len;
- tty->flip.count += len;
+ /* Hot path */
+ if(flag == TTY_NORMAL)
+ tty_insert_flip_string(tty, data, len);
+ else {
+ for(i = 0; i < len; i++)
+ tty_insert_flip_char(tty, data[i], flag);
+ }
tty_flip_buffer_push( tty );
}
-
}
-
}
spin_unlock( &priv->dp_port_lock );