summaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/cypress_m8.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial/cypress_m8.c')
-rw-r--r--drivers/usb/serial/cypress_m8.c111
1 files changed, 66 insertions, 45 deletions
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 155b82a25d1..c42d3bdbe98 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -122,6 +122,11 @@ static struct usb_driver cypress_driver = {
.no_dynamic_id = 1,
};
+enum packet_format {
+ packet_format_1, /* b0:status, b1:payload count */
+ packet_format_2 /* b0[7:3]:status, b0[2:0]:payload count */
+};
+
struct cypress_private {
spinlock_t lock; /* private lock */
int chiptype; /* identifier of device, for quirks/etc */
@@ -139,6 +144,7 @@ struct cypress_private {
__u8 current_status; /* received from last read - info on dsr,cts,cd,ri,etc */
__u8 current_config; /* stores the current configuration byte */
__u8 rx_flags; /* throttling - used from whiteheat/ftdi_sio */
+ enum packet_format pkt_fmt; /* format to use for packet send / receive */
int baud_rate; /* stores current baud rate in integer form */
int cbr_mask; /* stores current baud rate in masked form */
int isthrottled; /* if throttled, discard reads */
@@ -532,6 +538,17 @@ static int generic_startup (struct usb_serial *serial)
priv->termios_initialized = 0;
priv->rx_flags = 0;
priv->cbr_mask = B300;
+ /* Default packet format setting is determined by packet size.
+ Anything with a size larger then 9 must have a separate
+ count field since the 3 bit count field is otherwise too
+ small. Otherwise we can use the slightly more compact
+ format. This is in accordance with the cypress_m8 serial
+ converter app note. */
+ if (port->interrupt_out_size > 9) {
+ priv->pkt_fmt = packet_format_1;
+ } else {
+ priv->pkt_fmt = packet_format_2;
+ }
if (interval > 0) {
priv->write_urb_interval = interval;
priv->read_urb_interval = interval;
@@ -564,6 +581,9 @@ static int cypress_earthmate_startup (struct usb_serial *serial)
priv = usb_get_serial_port_data(serial->port[0]);
priv->chiptype = CT_EARTHMATE;
+ /* All Earthmate devices use the separated-count packet
+ format! Idiotic. */
+ priv->pkt_fmt = packet_format_1;
return 0;
} /* cypress_earthmate_startup */
@@ -811,21 +831,18 @@ static void cypress_send(struct usb_serial_port *port)
memset(port->interrupt_out_urb->transfer_buffer, 0, port->interrupt_out_size);
spin_lock_irqsave(&priv->lock, flags);
- switch (port->interrupt_out_size) {
- case 32:
- /* this is for the CY7C64013... */
- offset = 2;
- port->interrupt_out_buffer[0] = priv->line_control;
- break;
- case 8:
- /* this is for the CY7C63743... */
- offset = 1;
- port->interrupt_out_buffer[0] = priv->line_control;
- break;
- default:
- dbg("%s - wrong packet size", __FUNCTION__);
- spin_unlock_irqrestore(&priv->lock, flags);
- return;
+ switch (priv->pkt_fmt) {
+ default:
+ case packet_format_1:
+ /* this is for the CY7C64013... */
+ offset = 2;
+ port->interrupt_out_buffer[0] = priv->line_control;
+ break;
+ case packet_format_2:
+ /* this is for the CY7C63743... */
+ offset = 1;
+ port->interrupt_out_buffer[0] = priv->line_control;
+ break;
}
if (priv->line_control & CONTROL_RESET)
@@ -846,12 +863,13 @@ static void cypress_send(struct usb_serial_port *port)
return;
}
- switch (port->interrupt_out_size) {
- case 32:
- port->interrupt_out_buffer[1] = count;
- break;
- case 8:
- port->interrupt_out_buffer[0] |= count;
+ switch (priv->pkt_fmt) {
+ default:
+ case packet_format_1:
+ port->interrupt_out_buffer[1] = count;
+ break;
+ case packet_format_2:
+ port->interrupt_out_buffer[0] |= count;
}
dbg("%s - count is %d", __FUNCTION__, count);
@@ -864,8 +882,9 @@ send:
if (priv->cmd_ctrl)
actual_size = 1;
else
- actual_size = count + (port->interrupt_out_size == 32 ? 2 : 1);
-
+ actual_size = count +
+ (priv->pkt_fmt == packet_format_1 ? 2 : 1);
+
usb_serial_debug_data(debug, &port->dev, __FUNCTION__, port->interrupt_out_size,
port->interrupt_out_urb->transfer_buffer);
@@ -1331,30 +1350,32 @@ static void cypress_read_int_callback(struct urb *urb)
}
spin_lock_irqsave(&priv->lock, flags);
- switch(urb->actual_length) {
- case 32:
- /* This is for the CY7C64013... */
- priv->current_status = data[0] & 0xF8;
- bytes = data[1] + 2;
- i = 2;
- if (bytes > 2)
- havedata = 1;
- break;
- case 8:
- /* This is for the CY7C63743... */
- priv->current_status = data[0] & 0xF8;
- bytes = (data[0] & 0x07) + 1;
- i = 1;
- if (bytes > 1)
- havedata = 1;
- break;
- default:
- dbg("%s - wrong packet size - received %d bytes",
- __FUNCTION__, urb->actual_length);
- spin_unlock_irqrestore(&priv->lock, flags);
- goto continue_read;
+ result = urb->actual_length;
+ switch (priv->pkt_fmt) {
+ default:
+ case packet_format_1:
+ /* This is for the CY7C64013... */
+ priv->current_status = data[0] & 0xF8;
+ bytes = data[1] + 2;
+ i = 2;
+ if (bytes > 2)
+ havedata = 1;
+ break;
+ case packet_format_2:
+ /* This is for the CY7C63743... */
+ priv->current_status = data[0] & 0xF8;
+ bytes = (data[0] & 0x07) + 1;
+ i = 1;
+ if (bytes > 1)
+ havedata = 1;
+ break;
}
spin_unlock_irqrestore(&priv->lock, flags);
+ if (result < bytes) {
+ dbg("%s - wrong packet size - received %d bytes but packet "
+ "said %d bytes", __func__, result, bytes);
+ goto continue_read;
+ }
usb_serial_debug_data (debug, &port->dev, __FUNCTION__,
urb->actual_length, data);