[PATCH] USB cypress_m8: update kernel driver with current source

Fixed problem where setting or retreiving the serial config would fail
with EPIPE.  Removed CRTS toggling so the driver behaves more like other
usbserial adapters.  Issued new interval of 1ms instead of the default
bInterval.  As a result, transfer speed has been substantially
increased.  From avg. 850bps to avg. 3300bps.  Also added new module
parameter 'interval' to tweak the interval in case this change causes
problems for someone.  Cleaned up code and formatting issues so source
is more readable.  Replaced the C++ style comments.  Various other code
cleanups.

Signed-off-by: Lonnie Mendez <lmendez19@austin.rr.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Lonnie Mendez 2005-05-03 17:02:20 -05:00 committed by Greg KH
parent 093cf723b2
commit 3cb4a4f739

View File

@ -16,6 +16,14 @@
* See http://geocities.com/i0xox0i for information on this driver and the * See http://geocities.com/i0xox0i for information on this driver and the
* earthmate usb device. * earthmate usb device.
* *
* Lonnie Mendez <dignome@gmail.com>
* 4-29-2005
* Fixed problem where setting or retreiving the serial config would fail with
* EPIPE. Removed CRTS toggling so the driver behaves more like other usbserial
* adapters. Issued new interval of 1ms instead of the default 10ms. As a
* result, transfer speed has been substantially increased. From avg. 850bps to
* avg. 3300bps. initial termios has also been modified. Cleaned up code and
* formatting issues so it is more readable. Replaced the C++ style comments.
* *
* Lonnie Mendez <dignome@gmail.com> * Lonnie Mendez <dignome@gmail.com>
* 12-15-2004 * 12-15-2004
@ -32,12 +40,6 @@
* 10-2003 * 10-2003
* Driver first released. * Driver first released.
* *
*
* Long Term TODO:
* Improve transfer speeds - both read/write are somewhat slow
* at this point.
* Improve debugging. Show modem line status with debug output and
* implement filtering for certain data as a module parameter.
*/ */
/* Thanks to Neil Whelchel for writing the first cypress m8 implementation for linux. */ /* Thanks to Neil Whelchel for writing the first cypress m8 implementation for linux. */
@ -72,11 +74,12 @@
static int debug; static int debug;
#endif #endif
static int stats; static int stats;
static int interval;
/* /*
* Version Information * Version Information
*/ */
#define DRIVER_VERSION "v1.08" #define DRIVER_VERSION "v1.09"
#define DRIVER_AUTHOR "Lonnie Mendez <dignome@gmail.com>, Neil Whelchel <koyama@firstlight.net>" #define DRIVER_AUTHOR "Lonnie Mendez <dignome@gmail.com>, Neil Whelchel <koyama@firstlight.net>"
#define DRIVER_DESC "Cypress USB to Serial Driver" #define DRIVER_DESC "Cypress USB to Serial Driver"
@ -130,7 +133,6 @@ struct cypress_private {
char prev_status, diff_status; /* used for TIOCMIWAIT */ char prev_status, diff_status; /* used for TIOCMIWAIT */
/* we pass a pointer to this as the arguement sent to cypress_set_termios old_termios */ /* we pass a pointer to this as the arguement sent to cypress_set_termios old_termios */
struct termios tmp_termios; /* stores the old termios settings */ struct termios tmp_termios; /* stores the old termios settings */
char calledfromopen; /* used when issuing lines on open - fixes rts drop bug */
}; };
/* write buffer structure */ /* write buffer structure */
@ -168,10 +170,8 @@ static void cypress_buf_free(struct cypress_buf *cb);
static void cypress_buf_clear(struct cypress_buf *cb); static void cypress_buf_clear(struct cypress_buf *cb);
static unsigned int cypress_buf_data_avail(struct cypress_buf *cb); static unsigned int cypress_buf_data_avail(struct cypress_buf *cb);
static unsigned int cypress_buf_space_avail(struct cypress_buf *cb); static unsigned int cypress_buf_space_avail(struct cypress_buf *cb);
static unsigned int cypress_buf_put(struct cypress_buf *cb, const char *buf, static unsigned int cypress_buf_put(struct cypress_buf *cb, const char *buf, unsigned int count);
unsigned int count); static unsigned int cypress_buf_get(struct cypress_buf *cb, char *buf, unsigned int count);
static unsigned int cypress_buf_get(struct cypress_buf *cb, char *buf,
unsigned int count);
static struct usb_serial_device_type cypress_earthmate_device = { static struct usb_serial_device_type cypress_earthmate_device = {
@ -238,10 +238,9 @@ static struct usb_serial_device_type cypress_hidcom_device = {
static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_mask, int data_bits, int stop_bits, static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_mask, int data_bits, int stop_bits,
int parity_enable, int parity_type, int reset, int cypress_request_type) int parity_enable, int parity_type, int reset, int cypress_request_type)
{ {
int i, n_baud_rate = 0, retval = 0; int new_baudrate = 0, retval = 0, tries = 0;
struct cypress_private *priv; struct cypress_private *priv;
__u8 feature_buffer[5]; __u8 feature_buffer[8];
__u8 config;
unsigned long flags; unsigned long flags;
dbg("%s", __FUNCTION__); dbg("%s", __FUNCTION__);
@ -256,7 +255,8 @@ static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_m
* of 57600bps (I have no idea whether DeLorme chose to use the general purpose * of 57600bps (I have no idea whether DeLorme chose to use the general purpose
* firmware or not), if you need to modify this speed setting for your own * firmware or not), if you need to modify this speed setting for your own
* project please add your own chiptype and modify the code likewise. The * project please add your own chiptype and modify the code likewise. The
* Cypress HID->COM device will work successfully up to 115200bps. * Cypress HID->COM device will work successfully up to 115200bps (but the
* actual throughput is around 3kBps).
*/ */
if (baud_mask != priv->cbr_mask) { if (baud_mask != priv->cbr_mask) {
dbg("%s - baud rate is changing", __FUNCTION__); dbg("%s - baud rate is changing", __FUNCTION__);
@ -265,109 +265,114 @@ static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_m
* but are not used with NMEA and SiRF protocols */ * but are not used with NMEA and SiRF protocols */
if ( (baud_mask == B300) || (baud_mask == B600) ) { if ( (baud_mask == B300) || (baud_mask == B600) ) {
err("%s - failed setting baud rate, unsupported speed (default to 4800)", err("%s - failed setting baud rate, unsupported speed",
__FUNCTION__); __FUNCTION__);
n_baud_rate = 4800; new_baudrate = priv->baud_rate;
} else if ( (n_baud_rate = mask_to_rate(baud_mask)) == -1) { } else if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) {
err("%s - failed setting baud rate, unsupported speed (default to 4800)", err("%s - failed setting baud rate, unsupported speed",
__FUNCTION__); __FUNCTION__);
n_baud_rate = 4800; new_baudrate = priv->baud_rate;
} }
} else if (priv->chiptype == CT_CYPHIDCOM) { } else if (priv->chiptype == CT_CYPHIDCOM) {
if ( (n_baud_rate = mask_to_rate(baud_mask)) == -1) { if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) {
err("%s - failed setting baud rate, unsupported speed (default to 4800)", err("%s - failed setting baud rate, unsupported speed",
__FUNCTION__); __FUNCTION__);
n_baud_rate = 4800; new_baudrate = priv->baud_rate;
} }
} else if (priv->chiptype == CT_GENERIC) { } else if (priv->chiptype == CT_GENERIC) {
if ( (n_baud_rate = mask_to_rate(baud_mask)) == -1) { if ( (new_baudrate = mask_to_rate(baud_mask)) == -1) {
err("%s - failed setting baud rate, unsupported speed (default to 4800)", err("%s - failed setting baud rate, unsupported speed",
__FUNCTION__); __FUNCTION__);
n_baud_rate = 4800; new_baudrate = priv->baud_rate;
} }
} else { } else {
info("%s - please define your chiptype, using 4800bps default", __FUNCTION__); info("%s - please define your chiptype", __FUNCTION__);
n_baud_rate = 4800; new_baudrate = priv->baud_rate;
} }
} else { /* baud rate not changing, keep the old */ } else { /* baud rate not changing, keep the old */
n_baud_rate = priv->baud_rate; new_baudrate = priv->baud_rate;
} }
dbg("%s - baud rate is being sent as %d", __FUNCTION__, n_baud_rate); dbg("%s - baud rate is being sent as %d", __FUNCTION__, new_baudrate);
/* memset(feature_buffer, 0, 8);
* This algorithm accredited to Jiang Jay Zhang... thanks for all the help! /* fill the feature_buffer with new configuration */
*/ *((u_int32_t *)feature_buffer) = new_baudrate;
for (i = 0; i < 4; ++i) {
feature_buffer[i] = ( n_baud_rate >> (i*8) & 0xFF );
}
config = 0; // reset config byte feature_buffer[4] |= data_bits; /* assign data bits in 2 bit space ( max 3 ) */
config |= data_bits; // assign data bits in 2 bit space ( max 3 )
/* 1 bit gap */ /* 1 bit gap */
config |= (stop_bits << 3); // assign stop bits in 1 bit space feature_buffer[4] |= (stop_bits << 3); /* assign stop bits in 1 bit space */
config |= (parity_enable << 4); // assign parity flag in 1 bit space feature_buffer[4] |= (parity_enable << 4); /* assign parity flag in 1 bit space */
config |= (parity_type << 5); // assign parity type in 1 bit space feature_buffer[4] |= (parity_type << 5); /* assign parity type in 1 bit space */
/* 1 bit gap */ /* 1 bit gap */
config |= (reset << 7); // assign reset at end of byte, 1 bit space feature_buffer[4] |= (reset << 7); /* assign reset at end of byte, 1 bit space */
feature_buffer[4] = config;
dbg("%s - device is being sent this feature report:", __FUNCTION__); dbg("%s - device is being sent this feature report:", __FUNCTION__);
dbg("%s - %02X - %02X - %02X - %02X - %02X", __FUNCTION__, feature_buffer[0], feature_buffer[1], dbg("%s - %02X - %02X - %02X - %02X - %02X", __FUNCTION__, feature_buffer[0], feature_buffer[1],
feature_buffer[2], feature_buffer[3], feature_buffer[4]); feature_buffer[2], feature_buffer[3], feature_buffer[4]);
do {
retval = usb_control_msg (port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), retval = usb_control_msg (port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0),
HID_REQ_SET_REPORT, USB_DIR_OUT | USB_RECIP_INTERFACE | USB_TYPE_CLASS, HID_REQ_SET_REPORT, USB_DIR_OUT | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
0x0300, 0, feature_buffer, 5, 500); 0x0300, 0, feature_buffer, 8, 500);
if (retval != 5) if (tries++ >= 3)
break;
if (retval == EPIPE)
usb_clear_halt(port->serial->dev, 0x00);
} while (retval != 8 && retval != ENODEV);
if (retval != 8)
err("%s - failed sending serial line settings - %d", __FUNCTION__, retval); err("%s - failed sending serial line settings - %d", __FUNCTION__, retval);
else { else {
spin_lock_irqsave(&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
priv->baud_rate = n_baud_rate; priv->baud_rate = new_baudrate;
priv->cbr_mask = baud_mask; priv->cbr_mask = baud_mask;
priv->current_config = config; priv->current_config = feature_buffer[4];
++priv->cmd_count;
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
} }
break; break;
case CYPRESS_GET_CONFIG: case CYPRESS_GET_CONFIG:
dbg("%s - retreiving serial line settings", __FUNCTION__); dbg("%s - retreiving serial line settings", __FUNCTION__);
/* reset values in feature buffer */ /* set initial values in feature buffer */
memset(feature_buffer, 0, 5); memset(feature_buffer, 0, 8);
do {
retval = usb_control_msg (port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), retval = usb_control_msg (port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0),
HID_REQ_GET_REPORT, USB_DIR_IN | USB_RECIP_INTERFACE | USB_TYPE_CLASS, HID_REQ_GET_REPORT, USB_DIR_IN | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
0x0300, 0, feature_buffer, 5, 500); 0x0300, 0, feature_buffer, 8, 500);
if (tries++ >= 3)
break;
if (retval == EPIPE)
usb_clear_halt(port->serial->dev, 0x00);
} while (retval != 5 && retval != ENODEV);
if (retval != 5) { if (retval != 5) {
err("%s - failed to retreive serial line settings - %d", __FUNCTION__, retval); err("%s - failed to retreive serial line settings - %d", __FUNCTION__, retval);
return retval; return retval;
} else { } else {
spin_lock_irqsave(&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
/* store the config in one byte, and later use bit masks to check values */ /* store the config in one byte, and later use bit masks to check values */
priv->current_config = feature_buffer[4]; priv->current_config = feature_buffer[4];
/* reverse the process above to get the baud_mask value */ priv->baud_rate = *((u_int32_t *)feature_buffer);
n_baud_rate = 0; // reset bits
for (i = 0; i < 4; ++i) {
n_baud_rate |= ( feature_buffer[i] << (i*8) );
}
priv->baud_rate = n_baud_rate; if ( (priv->cbr_mask = rate_to_mask(priv->baud_rate)) == 0x40)
if ( (priv->cbr_mask = rate_to_mask(n_baud_rate)) == 0x40)
dbg("%s - failed setting the baud mask (not defined)", __FUNCTION__); dbg("%s - failed setting the baud mask (not defined)", __FUNCTION__);
++priv->cmd_count;
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
} }
break;
default:
err("%s - unsupported serial control command issued", __FUNCTION__);
} }
spin_lock_irqsave(&priv->lock, flags);
++priv->cmd_count;
spin_unlock_irqrestore(&priv->lock, flags);
return retval; return retval;
} /* cypress_serial_control */ } /* cypress_serial_control */
/* given a baud mask, it will return speed on success */ /* given a baud mask, it will return integer baud on success */
static int mask_to_rate (unsigned mask) static int mask_to_rate (unsigned mask)
{ {
int rate; int rate;
@ -438,11 +443,12 @@ static int generic_startup (struct usb_serial *serial)
usb_reset_configuration (serial->dev); usb_reset_configuration (serial->dev);
interval = 1;
priv->cmd_ctrl = 0; priv->cmd_ctrl = 0;
priv->line_control = 0; priv->line_control = 0;
priv->termios_initialized = 0; priv->termios_initialized = 0;
priv->calledfromopen = 0;
priv->rx_flags = 0; priv->rx_flags = 0;
priv->cbr_mask = B300;
usb_set_serial_port_data(serial->port[0], priv); usb_set_serial_port_data(serial->port[0], priv);
return (0); return (0);
@ -513,7 +519,6 @@ static int cypress_open (struct usb_serial_port *port, struct file *filp)
dbg("%s - port %d", __FUNCTION__, port->number); dbg("%s - port %d", __FUNCTION__, port->number);
/* clear halts before open */ /* clear halts before open */
usb_clear_halt(serial->dev, 0x00);
usb_clear_halt(serial->dev, 0x81); usb_clear_halt(serial->dev, 0x81);
usb_clear_halt(serial->dev, 0x02); usb_clear_halt(serial->dev, 0x02);
@ -531,7 +536,6 @@ static int cypress_open (struct usb_serial_port *port, struct file *filp)
/* raise both lines and set termios */ /* raise both lines and set termios */
spin_lock_irqsave(&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
priv->line_control = CONTROL_DTR | CONTROL_RTS; priv->line_control = CONTROL_DTR | CONTROL_RTS;
priv->calledfromopen = 1;
priv->cmd_ctrl = 1; priv->cmd_ctrl = 1;
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
result = cypress_write(port, NULL, 0); result = cypress_write(port, NULL, 0);
@ -553,7 +557,7 @@ static int cypress_open (struct usb_serial_port *port, struct file *filp)
usb_fill_int_urb(port->interrupt_in_urb, serial->dev, usb_fill_int_urb(port->interrupt_in_urb, serial->dev,
usb_rcvintpipe(serial->dev, port->interrupt_in_endpointAddress), usb_rcvintpipe(serial->dev, port->interrupt_in_endpointAddress),
port->interrupt_in_urb->transfer_buffer, port->interrupt_in_urb->transfer_buffer_length, port->interrupt_in_urb->transfer_buffer, port->interrupt_in_urb->transfer_buffer_length,
cypress_read_int_callback, port, port->interrupt_in_urb->interval); cypress_read_int_callback, port, interval);
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result){ if (result){
@ -680,12 +684,12 @@ static void cypress_send(struct usb_serial_port *port)
spin_lock_irqsave(&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
switch (port->interrupt_out_size) { switch (port->interrupt_out_size) {
case 32: case 32:
// this is for the CY7C64013... /* this is for the CY7C64013... */
offset = 2; offset = 2;
port->interrupt_out_buffer[0] = priv->line_control; port->interrupt_out_buffer[0] = priv->line_control;
break; break;
case 8: case 8:
// this is for the CY7C63743... /* this is for the CY7C63743... */
offset = 1; offset = 1;
port->interrupt_out_buffer[0] = priv->line_control; port->interrupt_out_buffer[0] = priv->line_control;
break; break;
@ -738,6 +742,7 @@ static void cypress_send(struct usb_serial_port *port)
port->interrupt_out_urb->transfer_buffer_length = actual_size; port->interrupt_out_urb->transfer_buffer_length = actual_size;
port->interrupt_out_urb->dev = port->serial->dev; port->interrupt_out_urb->dev = port->serial->dev;
port->interrupt_out_urb->interval = interval;
result = usb_submit_urb (port->interrupt_out_urb, GFP_ATOMIC); result = usb_submit_urb (port->interrupt_out_urb, GFP_ATOMIC);
if (result) { if (result) {
dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__,
@ -910,7 +915,7 @@ static void cypress_set_termios (struct usb_serial_port *port, struct termios *o
unsigned cflag, iflag, baud_mask; unsigned cflag, iflag, baud_mask;
unsigned long flags; unsigned long flags;
__u8 oldlines; __u8 oldlines;
int linechange; int linechange = 0;
dbg("%s - port %d", __FUNCTION__, port->number); dbg("%s - port %d", __FUNCTION__, port->number);
@ -996,15 +1001,7 @@ static void cypress_set_termios (struct usb_serial_port *port, struct termios *o
case B115200: dbg("%s - setting baud 115200bps", __FUNCTION__); break; case B115200: dbg("%s - setting baud 115200bps", __FUNCTION__); break;
default: dbg("%s - unknown masked baud rate", __FUNCTION__); default: dbg("%s - unknown masked baud rate", __FUNCTION__);
} }
priv->line_control |= CONTROL_DTR; priv->line_control = (CONTROL_DTR | CONTROL_RTS);
/* toggle CRTSCTS? - don't do this if being called from cypress_open */
if (!priv->calledfromopen) {
if (cflag & CRTSCTS)
priv->line_control |= CONTROL_RTS;
else
priv->line_control &= ~CONTROL_RTS;
}
} }
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
@ -1014,8 +1011,6 @@ static void cypress_set_termios (struct usb_serial_port *port, struct termios *o
cypress_serial_control(port, baud_mask, data_bits, stop_bits, parity_enable, cypress_serial_control(port, baud_mask, data_bits, stop_bits, parity_enable,
parity_type, 0, CYPRESS_SET_CONFIG); parity_type, 0, CYPRESS_SET_CONFIG);
msleep(50); /* give some time between change and read (50ms) */
/* we perform a CYPRESS_GET_CONFIG so that the current settings are filled into the private structure /* we perform a CYPRESS_GET_CONFIG so that the current settings are filled into the private structure
* this should confirm that all is working if it returns what we just set */ * this should confirm that all is working if it returns what we just set */
cypress_serial_control(port, 0, 0, 0, 0, 0, 0, CYPRESS_GET_CONFIG); cypress_serial_control(port, 0, 0, 0, 0, 0, 0, CYPRESS_GET_CONFIG);
@ -1031,7 +1026,6 @@ static void cypress_set_termios (struct usb_serial_port *port, struct termios *o
dbg("Using custom termios settings for a baud rate of 4800bps."); dbg("Using custom termios settings for a baud rate of 4800bps.");
/* define custom termios settings for NMEA protocol */ /* define custom termios settings for NMEA protocol */
tty->termios->c_iflag /* input modes - */ tty->termios->c_iflag /* input modes - */
&= ~(IGNBRK /* disable ignore break */ &= ~(IGNBRK /* disable ignore break */
| BRKINT /* disable break causes interrupt */ | BRKINT /* disable break causes interrupt */
@ -1052,23 +1046,16 @@ static void cypress_set_termios (struct usb_serial_port *port, struct termios *o
| ISIG /* disable interrupt, quit, and suspend special characters */ | ISIG /* disable interrupt, quit, and suspend special characters */
| IEXTEN); /* disable non-POSIX special characters */ | IEXTEN); /* disable non-POSIX special characters */
} else if (priv->chiptype == CT_CYPHIDCOM) { } /* CT_CYPHIDCOM: Application should handle this for device */
// Software app handling it for device...
}
linechange = (priv->line_control != oldlines); linechange = (priv->line_control != oldlines);
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
/* if necessary, set lines */ /* if necessary, set lines */
if (!priv->calledfromopen && linechange) { if (linechange) {
priv->cmd_ctrl = 1; priv->cmd_ctrl = 1;
cypress_write(port, NULL, 0); cypress_write(port, NULL, 0);
} }
if (priv->calledfromopen)
priv->calledfromopen = 0;
} /* cypress_set_termios */ } /* cypress_set_termios */
@ -1164,7 +1151,7 @@ static void cypress_read_int_callback(struct urb *urb, struct pt_regs *regs)
spin_lock_irqsave(&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
switch(urb->actual_length) { switch(urb->actual_length) {
case 32: case 32:
// This is for the CY7C64013... /* This is for the CY7C64013... */
priv->current_status = data[0] & 0xF8; priv->current_status = data[0] & 0xF8;
bytes = data[1]+2; bytes = data[1]+2;
i=2; i=2;
@ -1172,7 +1159,7 @@ static void cypress_read_int_callback(struct urb *urb, struct pt_regs *regs)
havedata = 1; havedata = 1;
break; break;
case 8: case 8:
// This is for the CY7C63743... /* This is for the CY7C63743... */
priv->current_status = data[0] & 0xF8; priv->current_status = data[0] & 0xF8;
bytes = (data[0] & 0x07)+1; bytes = (data[0] & 0x07)+1;
i=1; i=1;
@ -1245,7 +1232,7 @@ static void cypress_read_int_callback(struct urb *urb, struct pt_regs *regs)
port->interrupt_in_urb->transfer_buffer, port->interrupt_in_urb->transfer_buffer,
port->interrupt_in_urb->transfer_buffer_length, port->interrupt_in_urb->transfer_buffer_length,
cypress_read_int_callback, port, cypress_read_int_callback, port,
port->interrupt_in_urb->interval); interval);
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
if (result) if (result)
dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result); dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
@ -1274,6 +1261,8 @@ static void cypress_write_int_callback(struct urb *urb, struct pt_regs *regs)
dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
priv->write_urb_in_use = 0; priv->write_urb_in_use = 0;
return; return;
case -EPIPE: /* no break needed */
usb_clear_halt(port->serial->dev, 0x02);
default: default:
/* error in the urb, so we have to resubmit it */ /* error in the urb, so we have to resubmit it */
dbg("%s - Overflow in write", __FUNCTION__); dbg("%s - Overflow in write", __FUNCTION__);
@ -1535,3 +1524,5 @@ module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not"); MODULE_PARM_DESC(debug, "Debug enabled or not");
module_param(stats, bool, S_IRUGO | S_IWUSR); module_param(stats, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(stats, "Enable statistics or not"); MODULE_PARM_DESC(stats, "Enable statistics or not");
module_param(interval, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(interval, "Overrides interrupt interval");