Commit 3416eaa1 authored by Mike Isely's avatar Mike Isely Committed by Greg Kroah-Hartman

USB: cypress_m8: Packet format is separate from characteristic size

cypress_m8: Packet format is separate from characteristic size

The Cypress app note states that when using an 8 byte packet buffer
size that the packet format is modified (to be more compact).  However
I have since discovered that newer DeLorme Earthmate LT-20 devices
(those that are low speed USB with 8 byte packet size) STILL use the
format that is really supposed to correspond to 32 byte packets.
Further confusing things is the subsequent discovery that there are
actually two different types of LT-20 - older LT-20's use 32 byte
packets which is probably why this issue wasn't originally
encountered.  The solution here is to flag the packet format
separately from the buffer size.  Then at initialization time,
identify the correct combination and set it up.  This is a critical
fix for anyone with a newer LT-20.  Older devices and non-Earthmate
devices should remain unaffected by this change.  (If other devices
behave in this, uh, unexpected manner, it's now just a simple 1 line
change to fix them as well (change the pkt_fmt member for that
device).  Default behavior with this patch is still to drive the
format as per the app-note; of course for Earthmate devices this is
overridden.
Signed-off-by: default avatarMike Isely <isely@pobox.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 93075544
......@@ -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:
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 8:
case packet_format_2:
/* 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;
}
if (priv->line_control & CONTROL_RESET)
......@@ -846,11 +863,12 @@ static void cypress_send(struct usb_serial_port *port)
return;
}
switch (port->interrupt_out_size) {
case 32:
switch (priv->pkt_fmt) {
default:
case packet_format_1:
port->interrupt_out_buffer[1] = count;
break;
case 8:
case packet_format_2:
port->interrupt_out_buffer[0] |= count;
}
......@@ -864,7 +882,8 @@ static void cypress_send(struct usb_serial_port *port)
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,8 +1350,10 @@ static void cypress_read_int_callback(struct urb *urb)
}
spin_lock_irqsave(&priv->lock, flags);
switch(urb->actual_length) {
case 32:
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;
......@@ -1340,7 +1361,7 @@ static void cypress_read_int_callback(struct urb *urb)
if (bytes > 2)
havedata = 1;
break;
case 8:
case packet_format_2:
/* This is for the CY7C63743... */
priv->current_status = data[0] & 0xF8;
bytes = (data[0] & 0x07) + 1;
......@@ -1348,13 +1369,13 @@ static void cypress_read_int_callback(struct urb *urb)
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);
if (result < bytes) {
dbg("%s - wrong packet size - received %d bytes but packet "
"said %d bytes", __func__, result, bytes);
goto continue_read;
}
spin_unlock_irqrestore(&priv->lock, flags);
usb_serial_debug_data (debug, &port->dev, __FUNCTION__,
urb->actual_length, data);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment