aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial
diff options
context:
space:
mode:
authorMike Isely <isely@pobox.com>2008-02-10 21:23:19 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2008-04-25 00:16:37 -0400
commit3416eaa1f8f8d516b77de514e14cf8da256d28fb (patch)
tree80c87eeef1b5599e29b088e28eab4386b3ab43be /drivers/usb/serial
parent93075544d6c6e9aaa14c44edb6eb3f71144bdeeb (diff)
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: Mike Isely <isely@pobox.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/serial')
-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 = {
122 .no_dynamic_id = 1, 122 .no_dynamic_id = 1,
123}; 123};
124 124
125enum packet_format {
126 packet_format_1, /* b0:status, b1:payload count */
127 packet_format_2 /* b0[7:3]:status, b0[2:0]:payload count */
128};
129
125struct cypress_private { 130struct cypress_private {
126 spinlock_t lock; /* private lock */ 131 spinlock_t lock; /* private lock */
127 int chiptype; /* identifier of device, for quirks/etc */ 132 int chiptype; /* identifier of device, for quirks/etc */
@@ -139,6 +144,7 @@ struct cypress_private {
139 __u8 current_status; /* received from last read - info on dsr,cts,cd,ri,etc */ 144 __u8 current_status; /* received from last read - info on dsr,cts,cd,ri,etc */
140 __u8 current_config; /* stores the current configuration byte */ 145 __u8 current_config; /* stores the current configuration byte */
141 __u8 rx_flags; /* throttling - used from whiteheat/ftdi_sio */ 146 __u8 rx_flags; /* throttling - used from whiteheat/ftdi_sio */
147 enum packet_format pkt_fmt; /* format to use for packet send / receive */
142 int baud_rate; /* stores current baud rate in integer form */ 148 int baud_rate; /* stores current baud rate in integer form */
143 int cbr_mask; /* stores current baud rate in masked form */ 149 int cbr_mask; /* stores current baud rate in masked form */
144 int isthrottled; /* if throttled, discard reads */ 150 int isthrottled; /* if throttled, discard reads */
@@ -532,6 +538,17 @@ static int generic_startup (struct usb_serial *serial)
532 priv->termios_initialized = 0; 538 priv->termios_initialized = 0;
533 priv->rx_flags = 0; 539 priv->rx_flags = 0;
534 priv->cbr_mask = B300; 540 priv->cbr_mask = B300;
541 /* Default packet format setting is determined by packet size.
542 Anything with a size larger then 9 must have a separate
543 count field since the 3 bit count field is otherwise too
544 small. Otherwise we can use the slightly more compact
545 format. This is in accordance with the cypress_m8 serial
546 converter app note. */
547 if (port->interrupt_out_size > 9) {
548 priv->pkt_fmt = packet_format_1;
549 } else {
550 priv->pkt_fmt = packet_format_2;
551 }
535 if (interval > 0) { 552 if (interval > 0) {
536 priv->write_urb_interval = interval; 553 priv->write_urb_interval = interval;
537 priv->read_urb_interval = interval; 554 priv->read_urb_interval = interval;
@@ -564,6 +581,9 @@ static int cypress_earthmate_startup (struct usb_serial *serial)
564 581
565 priv = usb_get_serial_port_data(serial->port[0]); 582 priv = usb_get_serial_port_data(serial->port[0]);
566 priv->chiptype = CT_EARTHMATE; 583 priv->chiptype = CT_EARTHMATE;
584 /* All Earthmate devices use the separated-count packet
585 format! Idiotic. */
586 priv->pkt_fmt = packet_format_1;
567 587
568 return 0; 588 return 0;
569} /* cypress_earthmate_startup */ 589} /* cypress_earthmate_startup */
@@ -811,21 +831,18 @@ static void cypress_send(struct usb_serial_port *port)
811 memset(port->interrupt_out_urb->transfer_buffer, 0, port->interrupt_out_size); 831 memset(port->interrupt_out_urb->transfer_buffer, 0, port->interrupt_out_size);
812 832
813 spin_lock_irqsave(&priv->lock, flags); 833 spin_lock_irqsave(&priv->lock, flags);
814 switch (port->interrupt_out_size) { 834 switch (priv->pkt_fmt) {
815 case 32: 835 default:
816 /* this is for the CY7C64013... */ 836 case packet_format_1:
817 offset = 2; 837 /* this is for the CY7C64013... */
818 port->interrupt_out_buffer[0] = priv->line_control; 838 offset = 2;
819 break; 839 port->interrupt_out_buffer[0] = priv->line_control;
820 case 8: 840 break;
821 /* this is for the CY7C63743... */ 841 case packet_format_2:
822 offset = 1; 842 /* this is for the CY7C63743... */
823 port->interrupt_out_buffer[0] = priv->line_control; 843 offset = 1;
824 break; 844 port->interrupt_out_buffer[0] = priv->line_control;
825 default: 845 break;
826 dbg("%s - wrong packet size", __FUNCTION__);
827 spin_unlock_irqrestore(&priv->lock, flags);
828 return;
829 } 846 }
830 847
831 if (priv->line_control & CONTROL_RESET) 848 if (priv->line_control & CONTROL_RESET)
@@ -846,12 +863,13 @@ static void cypress_send(struct usb_serial_port *port)
846 return; 863 return;
847 } 864 }
848 865
849 switch (port->interrupt_out_size) { 866 switch (priv->pkt_fmt) {
850 case 32: 867 default:
851 port->interrupt_out_buffer[1] = count; 868 case packet_format_1:
852 break; 869 port->interrupt_out_buffer[1] = count;
853 case 8: 870 break;
854 port->interrupt_out_buffer[0] |= count; 871 case packet_format_2:
872 port->interrupt_out_buffer[0] |= count;
855 } 873 }
856 874
857 dbg("%s - count is %d", __FUNCTION__, count); 875 dbg("%s - count is %d", __FUNCTION__, count);
@@ -864,8 +882,9 @@ send:
864 if (priv->cmd_ctrl) 882 if (priv->cmd_ctrl)
865 actual_size = 1; 883 actual_size = 1;
866 else 884 else
867 actual_size = count + (port->interrupt_out_size == 32 ? 2 : 1); 885 actual_size = count +
868 886 (priv->pkt_fmt == packet_format_1 ? 2 : 1);
887
869 usb_serial_debug_data(debug, &port->dev, __FUNCTION__, port->interrupt_out_size, 888 usb_serial_debug_data(debug, &port->dev, __FUNCTION__, port->interrupt_out_size,
870 port->interrupt_out_urb->transfer_buffer); 889 port->interrupt_out_urb->transfer_buffer);
871 890
@@ -1331,30 +1350,32 @@ static void cypress_read_int_callback(struct urb *urb)
1331 } 1350 }
1332 1351
1333 spin_lock_irqsave(&priv->lock, flags); 1352 spin_lock_irqsave(&priv->lock, flags);
1334 switch(urb->actual_length) { 1353 result = urb->actual_length;
1335 case 32: 1354 switch (priv->pkt_fmt) {
1336 /* This is for the CY7C64013... */ 1355 default:
1337 priv->current_status = data[0] & 0xF8; 1356 case packet_format_1:
1338 bytes = data[1] + 2; 1357 /* This is for the CY7C64013... */
1339 i = 2; 1358 priv->current_status = data[0] & 0xF8;
1340 if (bytes > 2) 1359 bytes = data[1] + 2;
1341 havedata = 1; 1360 i = 2;
1342 break; 1361 if (bytes > 2)
1343 case 8: 1362 havedata = 1;
1344 /* This is for the CY7C63743... */ 1363 break;
1345 priv->current_status = data[0] & 0xF8; 1364 case packet_format_2:
1346 bytes = (data[0] & 0x07) + 1; 1365 /* This is for the CY7C63743... */
1347 i = 1; 1366 priv->current_status = data[0] & 0xF8;
1348 if (bytes > 1) 1367 bytes = (data[0] & 0x07) + 1;
1349 havedata = 1; 1368 i = 1;
1350 break; 1369 if (bytes > 1)
1351 default: 1370 havedata = 1;
1352 dbg("%s - wrong packet size - received %d bytes", 1371 break;
1353 __FUNCTION__, urb->actual_length);
1354 spin_unlock_irqrestore(&priv->lock, flags);
1355 goto continue_read;
1356 } 1372 }
1357 spin_unlock_irqrestore(&priv->lock, flags); 1373 spin_unlock_irqrestore(&priv->lock, flags);
1374 if (result < bytes) {
1375 dbg("%s - wrong packet size - received %d bytes but packet "
1376 "said %d bytes", __func__, result, bytes);
1377 goto continue_read;
1378 }
1358 1379
1359 usb_serial_debug_data (debug, &port->dev, __FUNCTION__, 1380 usb_serial_debug_data (debug, &port->dev, __FUNCTION__,
1360 urb->actual_length, data); 1381 urb->actual_length, data);