aboutsummaryrefslogtreecommitdiffstats
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.c132
1 files changed, 101 insertions, 31 deletions
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 5de76efe1b37..e1173c1aee37 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -48,7 +48,6 @@
48/* Code originates and was built up from ftdi_sio, belkin, pl2303 and others. */ 48/* Code originates and was built up from ftdi_sio, belkin, pl2303 and others. */
49 49
50 50
51#include <linux/config.h>
52#include <linux/kernel.h> 51#include <linux/kernel.h>
53#include <linux/errno.h> 52#include <linux/errno.h>
54#include <linux/init.h> 53#include <linux/init.h>
@@ -60,11 +59,11 @@
60#include <linux/moduleparam.h> 59#include <linux/moduleparam.h>
61#include <linux/spinlock.h> 60#include <linux/spinlock.h>
62#include <linux/usb.h> 61#include <linux/usb.h>
62#include <linux/usb/serial.h>
63#include <linux/serial.h> 63#include <linux/serial.h>
64#include <linux/delay.h> 64#include <linux/delay.h>
65#include <asm/uaccess.h> 65#include <asm/uaccess.h>
66 66
67#include "usb-serial.h"
68#include "cypress_m8.h" 67#include "cypress_m8.h"
69 68
70 69
@@ -130,6 +129,9 @@ struct cypress_private {
130 int cmd_ctrl; /* always set this to 1 before issuing a command */ 129 int cmd_ctrl; /* always set this to 1 before issuing a command */
131 struct cypress_buf *buf; /* write buffer */ 130 struct cypress_buf *buf; /* write buffer */
132 int write_urb_in_use; /* write urb in use indicator */ 131 int write_urb_in_use; /* write urb in use indicator */
132 int write_urb_interval; /* interval to use for write urb */
133 int read_urb_interval; /* interval to use for read urb */
134 int comm_is_ok; /* true if communication is (still) ok */
133 int termios_initialized; 135 int termios_initialized;
134 __u8 line_control; /* holds dtr / rts value */ 136 __u8 line_control; /* holds dtr / rts value */
135 __u8 current_status; /* received from last read - info on dsr,cts,cd,ri,etc */ 137 __u8 current_status; /* received from last read - info on dsr,cts,cd,ri,etc */
@@ -169,6 +171,7 @@ static int cypress_tiocmset (struct usb_serial_port *port, struct file *file,
169static int cypress_chars_in_buffer (struct usb_serial_port *port); 171static int cypress_chars_in_buffer (struct usb_serial_port *port);
170static void cypress_throttle (struct usb_serial_port *port); 172static void cypress_throttle (struct usb_serial_port *port);
171static void cypress_unthrottle (struct usb_serial_port *port); 173static void cypress_unthrottle (struct usb_serial_port *port);
174static void cypress_set_dead (struct usb_serial_port *port);
172static void cypress_read_int_callback (struct urb *urb, struct pt_regs *regs); 175static void cypress_read_int_callback (struct urb *urb, struct pt_regs *regs);
173static void cypress_write_int_callback (struct urb *urb, struct pt_regs *regs); 176static void cypress_write_int_callback (struct urb *urb, struct pt_regs *regs);
174/* baud helper functions */ 177/* baud helper functions */
@@ -289,6 +292,9 @@ static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_m
289 292
290 priv = usb_get_serial_port_data(port); 293 priv = usb_get_serial_port_data(port);
291 294
295 if (!priv->comm_is_ok)
296 return -ENODEV;
297
292 switch(cypress_request_type) { 298 switch(cypress_request_type) {
293 case CYPRESS_SET_CONFIG: 299 case CYPRESS_SET_CONFIG:
294 300
@@ -366,13 +372,12 @@ static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_m
366 if (tries++ >= 3) 372 if (tries++ >= 3)
367 break; 373 break;
368 374
369 if (retval == EPIPE) 375 } while (retval != 8 && retval != -ENODEV);
370 usb_clear_halt(port->serial->dev, 0x00);
371 } while (retval != 8 && retval != ENODEV);
372 376
373 if (retval != 8) 377 if (retval != 8) {
374 err("%s - failed sending serial line settings - %d", __FUNCTION__, retval); 378 err("%s - failed sending serial line settings - %d", __FUNCTION__, retval);
375 else { 379 cypress_set_dead(port);
380 } else {
376 spin_lock_irqsave(&priv->lock, flags); 381 spin_lock_irqsave(&priv->lock, flags);
377 priv->baud_rate = new_baudrate; 382 priv->baud_rate = new_baudrate;
378 priv->cbr_mask = baud_mask; 383 priv->cbr_mask = baud_mask;
@@ -393,12 +398,11 @@ static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_m
393 if (tries++ >= 3) 398 if (tries++ >= 3)
394 break; 399 break;
395 400
396 if (retval == EPIPE) 401 } while (retval != 5 && retval != -ENODEV);
397 usb_clear_halt(port->serial->dev, 0x00);
398 } while (retval != 5 && retval != ENODEV);
399 402
400 if (retval != 5) { 403 if (retval != 5) {
401 err("%s - failed to retrieve serial line settings - %d", __FUNCTION__, retval); 404 err("%s - failed to retrieve serial line settings - %d", __FUNCTION__, retval);
405 cypress_set_dead(port);
402 return retval; 406 return retval;
403 } else { 407 } else {
404 spin_lock_irqsave(&priv->lock, flags); 408 spin_lock_irqsave(&priv->lock, flags);
@@ -420,6 +424,24 @@ static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_m
420} /* cypress_serial_control */ 424} /* cypress_serial_control */
421 425
422 426
427static void cypress_set_dead(struct usb_serial_port *port)
428{
429 struct cypress_private *priv = usb_get_serial_port_data(port);
430 unsigned long flags;
431
432 spin_lock_irqsave(&priv->lock, flags);
433 if (!priv->comm_is_ok) {
434 spin_unlock_irqrestore(&priv->lock, flags);
435 return;
436 }
437 priv->comm_is_ok = 0;
438 spin_unlock_irqrestore(&priv->lock, flags);
439
440 err("cypress_m8 suspending failing port %d - interval might be too short",
441 port->number);
442}
443
444
423/* given a baud mask, it will return integer baud on success */ 445/* given a baud mask, it will return integer baud on success */
424static int mask_to_rate (unsigned mask) 446static int mask_to_rate (unsigned mask)
425{ 447{
@@ -473,13 +495,15 @@ static unsigned rate_to_mask (int rate)
473static int generic_startup (struct usb_serial *serial) 495static int generic_startup (struct usb_serial *serial)
474{ 496{
475 struct cypress_private *priv; 497 struct cypress_private *priv;
498 struct usb_serial_port *port = serial->port[0];
476 499
477 dbg("%s - port %d", __FUNCTION__, serial->port[0]->number); 500 dbg("%s - port %d", __FUNCTION__, port->number);
478 501
479 priv = kzalloc(sizeof (struct cypress_private), GFP_KERNEL); 502 priv = kzalloc(sizeof (struct cypress_private), GFP_KERNEL);
480 if (!priv) 503 if (!priv)
481 return -ENOMEM; 504 return -ENOMEM;
482 505
506 priv->comm_is_ok = !0;
483 spin_lock_init(&priv->lock); 507 spin_lock_init(&priv->lock);
484 priv->buf = cypress_buf_alloc(CYPRESS_BUF_SIZE); 508 priv->buf = cypress_buf_alloc(CYPRESS_BUF_SIZE);
485 if (priv->buf == NULL) { 509 if (priv->buf == NULL) {
@@ -490,13 +514,24 @@ static int generic_startup (struct usb_serial *serial)
490 514
491 usb_reset_configuration (serial->dev); 515 usb_reset_configuration (serial->dev);
492 516
493 interval = 1;
494 priv->cmd_ctrl = 0; 517 priv->cmd_ctrl = 0;
495 priv->line_control = 0; 518 priv->line_control = 0;
496 priv->termios_initialized = 0; 519 priv->termios_initialized = 0;
497 priv->rx_flags = 0; 520 priv->rx_flags = 0;
498 priv->cbr_mask = B300; 521 priv->cbr_mask = B300;
499 usb_set_serial_port_data(serial->port[0], priv); 522 if (interval > 0) {
523 priv->write_urb_interval = interval;
524 priv->read_urb_interval = interval;
525 dbg("%s - port %d read & write intervals forced to %d",
526 __FUNCTION__,port->number,interval);
527 } else {
528 priv->write_urb_interval = port->interrupt_out_urb->interval;
529 priv->read_urb_interval = port->interrupt_in_urb->interval;
530 dbg("%s - port %d intervals: read=%d write=%d",
531 __FUNCTION__,port->number,
532 priv->read_urb_interval,priv->write_urb_interval);
533 }
534 usb_set_serial_port_data(port, priv);
500 535
501 return 0; 536 return 0;
502} 537}
@@ -586,6 +621,9 @@ static int cypress_open (struct usb_serial_port *port, struct file *filp)
586 621
587 dbg("%s - port %d", __FUNCTION__, port->number); 622 dbg("%s - port %d", __FUNCTION__, port->number);
588 623
624 if (!priv->comm_is_ok)
625 return -EIO;
626
589 /* clear halts before open */ 627 /* clear halts before open */
590 usb_clear_halt(serial->dev, 0x81); 628 usb_clear_halt(serial->dev, 0x81);
591 usb_clear_halt(serial->dev, 0x02); 629 usb_clear_halt(serial->dev, 0x02);
@@ -625,11 +663,12 @@ static int cypress_open (struct usb_serial_port *port, struct file *filp)
625 usb_fill_int_urb(port->interrupt_in_urb, serial->dev, 663 usb_fill_int_urb(port->interrupt_in_urb, serial->dev,
626 usb_rcvintpipe(serial->dev, port->interrupt_in_endpointAddress), 664 usb_rcvintpipe(serial->dev, port->interrupt_in_endpointAddress),
627 port->interrupt_in_urb->transfer_buffer, port->interrupt_in_urb->transfer_buffer_length, 665 port->interrupt_in_urb->transfer_buffer, port->interrupt_in_urb->transfer_buffer_length,
628 cypress_read_int_callback, port, interval); 666 cypress_read_int_callback, port, priv->read_urb_interval);
629 result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); 667 result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
630 668
631 if (result){ 669 if (result){
632 dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result); 670 dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result);
671 cypress_set_dead(port);
633 } 672 }
634 673
635 return result; 674 return result;
@@ -734,6 +773,9 @@ static void cypress_send(struct usb_serial_port *port)
734 struct cypress_private *priv = usb_get_serial_port_data(port); 773 struct cypress_private *priv = usb_get_serial_port_data(port);
735 unsigned long flags; 774 unsigned long flags;
736 775
776 if (!priv->comm_is_ok)
777 return;
778
737 dbg("%s - port %d", __FUNCTION__, port->number); 779 dbg("%s - port %d", __FUNCTION__, port->number);
738 dbg("%s - interrupt out size is %d", __FUNCTION__, port->interrupt_out_size); 780 dbg("%s - interrupt out size is %d", __FUNCTION__, port->interrupt_out_size);
739 781
@@ -807,14 +849,16 @@ send:
807 usb_serial_debug_data(debug, &port->dev, __FUNCTION__, port->interrupt_out_size, 849 usb_serial_debug_data(debug, &port->dev, __FUNCTION__, port->interrupt_out_size,
808 port->interrupt_out_urb->transfer_buffer); 850 port->interrupt_out_urb->transfer_buffer);
809 851
810 port->interrupt_out_urb->transfer_buffer_length = actual_size; 852 usb_fill_int_urb(port->interrupt_out_urb, port->serial->dev,
811 port->interrupt_out_urb->dev = port->serial->dev; 853 usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress),
812 port->interrupt_out_urb->interval = interval; 854 port->interrupt_out_buffer, port->interrupt_out_size,
855 cypress_write_int_callback, port, priv->write_urb_interval);
813 result = usb_submit_urb (port->interrupt_out_urb, GFP_ATOMIC); 856 result = usb_submit_urb (port->interrupt_out_urb, GFP_ATOMIC);
814 if (result) { 857 if (result) {
815 dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, 858 dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__,
816 result); 859 result);
817 priv->write_urb_in_use = 0; 860 priv->write_urb_in_use = 0;
861 cypress_set_dead(port);
818 } 862 }
819 863
820 spin_lock_irqsave(&priv->lock, flags); 864 spin_lock_irqsave(&priv->lock, flags);
@@ -1215,13 +1259,18 @@ static void cypress_unthrottle (struct usb_serial_port *port)
1215 priv->rx_flags = 0; 1259 priv->rx_flags = 0;
1216 spin_unlock_irqrestore(&priv->lock, flags); 1260 spin_unlock_irqrestore(&priv->lock, flags);
1217 1261
1262 if (!priv->comm_is_ok)
1263 return;
1264
1218 if (actually_throttled) { 1265 if (actually_throttled) {
1219 port->interrupt_in_urb->dev = port->serial->dev; 1266 port->interrupt_in_urb->dev = port->serial->dev;
1220 1267
1221 result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); 1268 result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
1222 if (result) 1269 if (result) {
1223 dev_err(&port->dev, "%s - failed submitting read urb, " 1270 dev_err(&port->dev, "%s - failed submitting read urb, "
1224 "error %d\n", __FUNCTION__, result); 1271 "error %d\n", __FUNCTION__, result);
1272 cypress_set_dead(port);
1273 }
1225 } 1274 }
1226} 1275}
1227 1276
@@ -1241,9 +1290,22 @@ static void cypress_read_int_callback(struct urb *urb, struct pt_regs *regs)
1241 1290
1242 dbg("%s - port %d", __FUNCTION__, port->number); 1291 dbg("%s - port %d", __FUNCTION__, port->number);
1243 1292
1244 if (urb->status) { 1293 switch (urb->status) {
1245 dbg("%s - nonzero read status received: %d", __FUNCTION__, 1294 case 0: /* success */
1246 urb->status); 1295 break;
1296 case -ECONNRESET:
1297 case -ENOENT:
1298 case -ESHUTDOWN:
1299 /* precursor to disconnect so just go away */
1300 return;
1301 case -EPIPE:
1302 usb_clear_halt(port->serial->dev,0x81);
1303 break;
1304 default:
1305 /* something ugly is going on... */
1306 dev_err(&urb->dev->dev,"%s - unexpected nonzero read status received: %d\n",
1307 __FUNCTION__,urb->status);
1308 cypress_set_dead(port);
1247 return; 1309 return;
1248 } 1310 }
1249 1311
@@ -1344,18 +1406,20 @@ continue_read:
1344 1406
1345 /* Continue trying to always read... unless the port has closed. */ 1407 /* Continue trying to always read... unless the port has closed. */
1346 1408
1347 if (port->open_count > 0) { 1409 if (port->open_count > 0 && priv->comm_is_ok) {
1348 usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev, 1410 usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev,
1349 usb_rcvintpipe(port->serial->dev, 1411 usb_rcvintpipe(port->serial->dev,
1350 port->interrupt_in_endpointAddress), 1412 port->interrupt_in_endpointAddress),
1351 port->interrupt_in_urb->transfer_buffer, 1413 port->interrupt_in_urb->transfer_buffer,
1352 port->interrupt_in_urb->transfer_buffer_length, 1414 port->interrupt_in_urb->transfer_buffer_length,
1353 cypress_read_int_callback, port, interval); 1415 cypress_read_int_callback, port, priv->read_urb_interval);
1354 result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); 1416 result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
1355 if (result) 1417 if (result) {
1356 dev_err(&urb->dev->dev, "%s - failed resubmitting " 1418 dev_err(&urb->dev->dev, "%s - failed resubmitting "
1357 "read urb, error %d\n", __FUNCTION__, 1419 "read urb, error %d\n", __FUNCTION__,
1358 result); 1420 result);
1421 cypress_set_dead(port);
1422 }
1359 } 1423 }
1360 1424
1361 return; 1425 return;
@@ -1381,20 +1445,26 @@ static void cypress_write_int_callback(struct urb *urb, struct pt_regs *regs)
1381 dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); 1445 dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
1382 priv->write_urb_in_use = 0; 1446 priv->write_urb_in_use = 0;
1383 return; 1447 return;
1384 case -EPIPE: /* no break needed */ 1448 case -EPIPE: /* no break needed; clear halt and resubmit */
1449 if (!priv->comm_is_ok)
1450 break;
1385 usb_clear_halt(port->serial->dev, 0x02); 1451 usb_clear_halt(port->serial->dev, 0x02);
1386 default:
1387 /* error in the urb, so we have to resubmit it */ 1452 /* error in the urb, so we have to resubmit it */
1388 dbg("%s - Overflow in write", __FUNCTION__);
1389 dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); 1453 dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
1390 port->interrupt_out_urb->transfer_buffer_length = 1; 1454 port->interrupt_out_urb->transfer_buffer_length = 1;
1391 port->interrupt_out_urb->dev = port->serial->dev; 1455 port->interrupt_out_urb->dev = port->serial->dev;
1392 result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC); 1456 result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);
1393 if (result) 1457 if (!result)
1394 dev_err(&urb->dev->dev, "%s - failed resubmitting write urb, error %d\n",
1395 __FUNCTION__, result);
1396 else
1397 return; 1458 return;
1459 dev_err(&urb->dev->dev, "%s - failed resubmitting write urb, error %d\n",
1460 __FUNCTION__, result);
1461 cypress_set_dead(port);
1462 break;
1463 default:
1464 dev_err(&urb->dev->dev,"%s - unexpected nonzero write status received: %d\n",
1465 __FUNCTION__,urb->status);
1466 cypress_set_dead(port);
1467 break;
1398 } 1468 }
1399 1469
1400 priv->write_urb_in_use = 0; 1470 priv->write_urb_in_use = 0;