aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMike Isely <isely@pobox.com>2006-08-29 23:07:11 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-09-27 14:58:59 -0400
commit78aef519ed07797f94cff1d0d66dd01704474916 (patch)
treea0faf74c0e128badd7e7989d45ca0076459d1627 /drivers
parent48298e50e0f7dfc7273ebfaa37ffd225428e83ed (diff)
cypress_m8: implement graceful failure handling
When receiving a fatal error from the USB core, e.g. EILSEQ (which can happen if the polling interval is too short), fail gracefully. Previously the driver would fill the log with useless error messages or (more alarmingly) silently spin forever trying to write updated control information to the device. This change implements a new flag which if cleared indicates that the driver has failed. The flag will be set on initialization, cleared on fatal errors, and anything else that touches the USB port in the driver will abort if the flag is clear. When the flag is cleared, a message will be logged indicating that the driver has failed. Signed-off-by: Mike Isely <isely@pobox.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/serial/cypress_m8.c90
1 files changed, 75 insertions, 15 deletions
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 12a265c4a13b..e1173c1aee37 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -131,6 +131,7 @@ struct cypress_private {
131 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 */ 132 int write_urb_interval; /* interval to use for write urb */
133 int read_urb_interval; /* interval to use for read urb */ 133 int read_urb_interval; /* interval to use for read urb */
134 int comm_is_ok; /* true if communication is (still) ok */
134 int termios_initialized; 135 int termios_initialized;
135 __u8 line_control; /* holds dtr / rts value */ 136 __u8 line_control; /* holds dtr / rts value */
136 __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 */
@@ -170,6 +171,7 @@ static int cypress_tiocmset (struct usb_serial_port *port, struct file *file,
170static int cypress_chars_in_buffer (struct usb_serial_port *port); 171static int cypress_chars_in_buffer (struct usb_serial_port *port);
171static void cypress_throttle (struct usb_serial_port *port); 172static void cypress_throttle (struct usb_serial_port *port);
172static 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);
173static 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);
174static 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);
175/* baud helper functions */ 177/* baud helper functions */
@@ -290,6 +292,9 @@ static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_m
290 292
291 priv = usb_get_serial_port_data(port); 293 priv = usb_get_serial_port_data(port);
292 294
295 if (!priv->comm_is_ok)
296 return -ENODEV;
297
293 switch(cypress_request_type) { 298 switch(cypress_request_type) {
294 case CYPRESS_SET_CONFIG: 299 case CYPRESS_SET_CONFIG:
295 300
@@ -369,9 +374,10 @@ static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_m
369 374
370 } while (retval != 8 && retval != -ENODEV); 375 } while (retval != 8 && retval != -ENODEV);
371 376
372 if (retval != 8) 377 if (retval != 8) {
373 err("%s - failed sending serial line settings - %d", __FUNCTION__, retval); 378 err("%s - failed sending serial line settings - %d", __FUNCTION__, retval);
374 else { 379 cypress_set_dead(port);
380 } else {
375 spin_lock_irqsave(&priv->lock, flags); 381 spin_lock_irqsave(&priv->lock, flags);
376 priv->baud_rate = new_baudrate; 382 priv->baud_rate = new_baudrate;
377 priv->cbr_mask = baud_mask; 383 priv->cbr_mask = baud_mask;
@@ -396,6 +402,7 @@ static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_m
396 402
397 if (retval != 5) { 403 if (retval != 5) {
398 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);
399 return retval; 406 return retval;
400 } else { 407 } else {
401 spin_lock_irqsave(&priv->lock, flags); 408 spin_lock_irqsave(&priv->lock, flags);
@@ -417,6 +424,24 @@ static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_m
417} /* cypress_serial_control */ 424} /* cypress_serial_control */
418 425
419 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
420/* given a baud mask, it will return integer baud on success */ 445/* given a baud mask, it will return integer baud on success */
421static int mask_to_rate (unsigned mask) 446static int mask_to_rate (unsigned mask)
422{ 447{
@@ -478,6 +503,7 @@ static int generic_startup (struct usb_serial *serial)
478 if (!priv) 503 if (!priv)
479 return -ENOMEM; 504 return -ENOMEM;
480 505
506 priv->comm_is_ok = !0;
481 spin_lock_init(&priv->lock); 507 spin_lock_init(&priv->lock);
482 priv->buf = cypress_buf_alloc(CYPRESS_BUF_SIZE); 508 priv->buf = cypress_buf_alloc(CYPRESS_BUF_SIZE);
483 if (priv->buf == NULL) { 509 if (priv->buf == NULL) {
@@ -595,6 +621,9 @@ static int cypress_open (struct usb_serial_port *port, struct file *filp)
595 621
596 dbg("%s - port %d", __FUNCTION__, port->number); 622 dbg("%s - port %d", __FUNCTION__, port->number);
597 623
624 if (!priv->comm_is_ok)
625 return -EIO;
626
598 /* clear halts before open */ 627 /* clear halts before open */
599 usb_clear_halt(serial->dev, 0x81); 628 usb_clear_halt(serial->dev, 0x81);
600 usb_clear_halt(serial->dev, 0x02); 629 usb_clear_halt(serial->dev, 0x02);
@@ -639,6 +668,7 @@ static int cypress_open (struct usb_serial_port *port, struct file *filp)
639 668
640 if (result){ 669 if (result){
641 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);
642 } 672 }
643 673
644 return result; 674 return result;
@@ -743,6 +773,9 @@ static void cypress_send(struct usb_serial_port *port)
743 struct cypress_private *priv = usb_get_serial_port_data(port); 773 struct cypress_private *priv = usb_get_serial_port_data(port);
744 unsigned long flags; 774 unsigned long flags;
745 775
776 if (!priv->comm_is_ok)
777 return;
778
746 dbg("%s - port %d", __FUNCTION__, port->number); 779 dbg("%s - port %d", __FUNCTION__, port->number);
747 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);
748 781
@@ -825,6 +858,7 @@ send:
825 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__,
826 result); 859 result);
827 priv->write_urb_in_use = 0; 860 priv->write_urb_in_use = 0;
861 cypress_set_dead(port);
828 } 862 }
829 863
830 spin_lock_irqsave(&priv->lock, flags); 864 spin_lock_irqsave(&priv->lock, flags);
@@ -1225,13 +1259,18 @@ static void cypress_unthrottle (struct usb_serial_port *port)
1225 priv->rx_flags = 0; 1259 priv->rx_flags = 0;
1226 spin_unlock_irqrestore(&priv->lock, flags); 1260 spin_unlock_irqrestore(&priv->lock, flags);
1227 1261
1262 if (!priv->comm_is_ok)
1263 return;
1264
1228 if (actually_throttled) { 1265 if (actually_throttled) {
1229 port->interrupt_in_urb->dev = port->serial->dev; 1266 port->interrupt_in_urb->dev = port->serial->dev;
1230 1267
1231 result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); 1268 result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
1232 if (result) 1269 if (result) {
1233 dev_err(&port->dev, "%s - failed submitting read urb, " 1270 dev_err(&port->dev, "%s - failed submitting read urb, "
1234 "error %d\n", __FUNCTION__, result); 1271 "error %d\n", __FUNCTION__, result);
1272 cypress_set_dead(port);
1273 }
1235 } 1274 }
1236} 1275}
1237 1276
@@ -1251,9 +1290,22 @@ static void cypress_read_int_callback(struct urb *urb, struct pt_regs *regs)
1251 1290
1252 dbg("%s - port %d", __FUNCTION__, port->number); 1291 dbg("%s - port %d", __FUNCTION__, port->number);
1253 1292
1254 if (urb->status) { 1293 switch (urb->status) {
1255 dbg("%s - nonzero read status received: %d", __FUNCTION__, 1294 case 0: /* success */
1256 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);
1257 return; 1309 return;
1258 } 1310 }
1259 1311
@@ -1354,7 +1406,7 @@ continue_read:
1354 1406
1355 /* Continue trying to always read... unless the port has closed. */ 1407 /* Continue trying to always read... unless the port has closed. */
1356 1408
1357 if (port->open_count > 0) { 1409 if (port->open_count > 0 && priv->comm_is_ok) {
1358 usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev, 1410 usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev,
1359 usb_rcvintpipe(port->serial->dev, 1411 usb_rcvintpipe(port->serial->dev,
1360 port->interrupt_in_endpointAddress), 1412 port->interrupt_in_endpointAddress),
@@ -1362,10 +1414,12 @@ continue_read:
1362 port->interrupt_in_urb->transfer_buffer_length, 1414 port->interrupt_in_urb->transfer_buffer_length,
1363 cypress_read_int_callback, port, priv->read_urb_interval); 1415 cypress_read_int_callback, port, priv->read_urb_interval);
1364 result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); 1416 result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
1365 if (result) 1417 if (result) {
1366 dev_err(&urb->dev->dev, "%s - failed resubmitting " 1418 dev_err(&urb->dev->dev, "%s - failed resubmitting "
1367 "read urb, error %d\n", __FUNCTION__, 1419 "read urb, error %d\n", __FUNCTION__,
1368 result); 1420 result);
1421 cypress_set_dead(port);
1422 }
1369 } 1423 }
1370 1424
1371 return; 1425 return;
@@ -1391,20 +1445,26 @@ static void cypress_write_int_callback(struct urb *urb, struct pt_regs *regs)
1391 dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); 1445 dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
1392 priv->write_urb_in_use = 0; 1446 priv->write_urb_in_use = 0;
1393 return; 1447 return;
1394 case -EPIPE: /* no break needed */ 1448 case -EPIPE: /* no break needed; clear halt and resubmit */
1449 if (!priv->comm_is_ok)
1450 break;
1395 usb_clear_halt(port->serial->dev, 0x02); 1451 usb_clear_halt(port->serial->dev, 0x02);
1396 default:
1397 /* error in the urb, so we have to resubmit it */ 1452 /* error in the urb, so we have to resubmit it */
1398 dbg("%s - Overflow in write", __FUNCTION__);
1399 dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); 1453 dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
1400 port->interrupt_out_urb->transfer_buffer_length = 1; 1454 port->interrupt_out_urb->transfer_buffer_length = 1;
1401 port->interrupt_out_urb->dev = port->serial->dev; 1455 port->interrupt_out_urb->dev = port->serial->dev;
1402 result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC); 1456 result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);
1403 if (result) 1457 if (!result)
1404 dev_err(&urb->dev->dev, "%s - failed resubmitting write urb, error %d\n",
1405 __FUNCTION__, result);
1406 else
1407 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;
1408 } 1468 }
1409 1469
1410 priv->write_urb_in_use = 0; 1470 priv->write_urb_in_use = 0;