diff options
Diffstat (limited to 'drivers/usb/serial/cypress_m8.c')
-rw-r--r-- | drivers/usb/serial/cypress_m8.c | 111 |
1 files changed, 66 insertions, 45 deletions
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 155b82a25d18..c42d3bdbe98c 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 | ||
125 | enum 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 | |||
125 | struct cypress_private { | 130 | struct 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); |