diff options
Diffstat (limited to 'drivers/usb/serial/cypress_m8.c')
| -rw-r--r-- | drivers/usb/serial/cypress_m8.c | 82 |
1 files changed, 40 insertions, 42 deletions
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index a591ebec0f89..baf74b44e6ed 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c | |||
| @@ -66,17 +66,15 @@ | |||
| 66 | #include <linux/serial.h> | 66 | #include <linux/serial.h> |
| 67 | #include <linux/delay.h> | 67 | #include <linux/delay.h> |
| 68 | #include <linux/uaccess.h> | 68 | #include <linux/uaccess.h> |
| 69 | #include <asm/unaligned.h> | ||
| 69 | 70 | ||
| 70 | #include "cypress_m8.h" | 71 | #include "cypress_m8.h" |
| 71 | 72 | ||
| 72 | 73 | ||
| 73 | #ifdef CONFIG_USB_SERIAL_DEBUG | 74 | static int debug; |
| 74 | static int debug = 1; | ||
| 75 | #else | ||
| 76 | static int debug; | ||
| 77 | #endif | ||
| 78 | static int stats; | 75 | static int stats; |
| 79 | static int interval; | 76 | static int interval; |
| 77 | static int unstable_bauds; | ||
| 80 | 78 | ||
| 81 | /* | 79 | /* |
| 82 | * Version Information | 80 | * Version Information |
| @@ -89,24 +87,24 @@ static int interval; | |||
| 89 | #define CYPRESS_BUF_SIZE 1024 | 87 | #define CYPRESS_BUF_SIZE 1024 |
| 90 | #define CYPRESS_CLOSING_WAIT (30*HZ) | 88 | #define CYPRESS_CLOSING_WAIT (30*HZ) |
| 91 | 89 | ||
| 92 | static struct usb_device_id id_table_earthmate [] = { | 90 | static const struct usb_device_id id_table_earthmate[] = { |
| 93 | { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) }, | 91 | { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) }, |
| 94 | { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) }, | 92 | { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) }, |
| 95 | { } /* Terminating entry */ | 93 | { } /* Terminating entry */ |
| 96 | }; | 94 | }; |
| 97 | 95 | ||
| 98 | static struct usb_device_id id_table_cyphidcomrs232 [] = { | 96 | static const struct usb_device_id id_table_cyphidcomrs232[] = { |
| 99 | { USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) }, | 97 | { USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) }, |
| 100 | { USB_DEVICE(VENDOR_ID_POWERCOM, PRODUCT_ID_UPS) }, | 98 | { USB_DEVICE(VENDOR_ID_POWERCOM, PRODUCT_ID_UPS) }, |
| 101 | { } /* Terminating entry */ | 99 | { } /* Terminating entry */ |
| 102 | }; | 100 | }; |
| 103 | 101 | ||
| 104 | static struct usb_device_id id_table_nokiaca42v2 [] = { | 102 | static const struct usb_device_id id_table_nokiaca42v2[] = { |
| 105 | { USB_DEVICE(VENDOR_ID_DAZZLE, PRODUCT_ID_CA42) }, | 103 | { USB_DEVICE(VENDOR_ID_DAZZLE, PRODUCT_ID_CA42) }, |
| 106 | { } /* Terminating entry */ | 104 | { } /* Terminating entry */ |
| 107 | }; | 105 | }; |
| 108 | 106 | ||
| 109 | static struct usb_device_id id_table_combined [] = { | 107 | static const struct usb_device_id id_table_combined[] = { |
| 110 | { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) }, | 108 | { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) }, |
| 111 | { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) }, | 109 | { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) }, |
| 112 | { USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) }, | 110 | { USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) }, |
| @@ -295,6 +293,9 @@ static int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate) | |||
| 295 | struct cypress_private *priv; | 293 | struct cypress_private *priv; |
| 296 | priv = usb_get_serial_port_data(port); | 294 | priv = usb_get_serial_port_data(port); |
| 297 | 295 | ||
| 296 | if (unstable_bauds) | ||
| 297 | return new_rate; | ||
| 298 | |||
| 298 | /* | 299 | /* |
| 299 | * The general purpose firmware for the Cypress M8 allows for | 300 | * The general purpose firmware for the Cypress M8 allows for |
| 300 | * a maximum speed of 57600bps (I have no idea whether DeLorme | 301 | * a maximum speed of 57600bps (I have no idea whether DeLorme |
| @@ -344,7 +345,8 @@ static int cypress_serial_control(struct tty_struct *tty, | |||
| 344 | { | 345 | { |
| 345 | int new_baudrate = 0, retval = 0, tries = 0; | 346 | int new_baudrate = 0, retval = 0, tries = 0; |
| 346 | struct cypress_private *priv; | 347 | struct cypress_private *priv; |
| 347 | __u8 feature_buffer[5]; | 348 | u8 *feature_buffer; |
| 349 | const unsigned int feature_len = 5; | ||
| 348 | unsigned long flags; | 350 | unsigned long flags; |
| 349 | 351 | ||
| 350 | dbg("%s", __func__); | 352 | dbg("%s", __func__); |
| @@ -354,17 +356,18 @@ static int cypress_serial_control(struct tty_struct *tty, | |||
| 354 | if (!priv->comm_is_ok) | 356 | if (!priv->comm_is_ok) |
| 355 | return -ENODEV; | 357 | return -ENODEV; |
| 356 | 358 | ||
| 359 | feature_buffer = kcalloc(feature_len, sizeof(u8), GFP_KERNEL); | ||
| 360 | if (!feature_buffer) | ||
| 361 | return -ENOMEM; | ||
| 362 | |||
| 357 | switch (cypress_request_type) { | 363 | switch (cypress_request_type) { |
| 358 | case CYPRESS_SET_CONFIG: | 364 | case CYPRESS_SET_CONFIG: |
| 359 | new_baudrate = priv->baud_rate; | ||
| 360 | /* 0 means 'Hang up' so doesn't change the true bit rate */ | 365 | /* 0 means 'Hang up' so doesn't change the true bit rate */ |
| 361 | if (baud_rate == 0) | 366 | new_baudrate = priv->baud_rate; |
| 362 | new_baudrate = priv->baud_rate; | 367 | if (baud_rate && baud_rate != priv->baud_rate) { |
| 363 | /* Change of speed ? */ | ||
| 364 | else if (baud_rate != priv->baud_rate) { | ||
| 365 | dbg("%s - baud rate is changing", __func__); | 368 | dbg("%s - baud rate is changing", __func__); |
| 366 | retval = analyze_baud_rate(port, baud_rate); | 369 | retval = analyze_baud_rate(port, baud_rate); |
| 367 | if (retval >= 0) { | 370 | if (retval >= 0) { |
| 368 | new_baudrate = retval; | 371 | new_baudrate = retval; |
| 369 | dbg("%s - New baud rate set to %d", | 372 | dbg("%s - New baud rate set to %d", |
| 370 | __func__, new_baudrate); | 373 | __func__, new_baudrate); |
| @@ -373,9 +376,8 @@ static int cypress_serial_control(struct tty_struct *tty, | |||
| 373 | dbg("%s - baud rate is being sent as %d", | 376 | dbg("%s - baud rate is being sent as %d", |
| 374 | __func__, new_baudrate); | 377 | __func__, new_baudrate); |
| 375 | 378 | ||
| 376 | memset(feature_buffer, 0, sizeof(feature_buffer)); | ||
| 377 | /* fill the feature_buffer with new configuration */ | 379 | /* fill the feature_buffer with new configuration */ |
| 378 | *((u_int32_t *)feature_buffer) = new_baudrate; | 380 | put_unaligned_le32(new_baudrate, feature_buffer); |
| 379 | feature_buffer[4] |= data_bits; /* assign data bits in 2 bit space ( max 3 ) */ | 381 | feature_buffer[4] |= data_bits; /* assign data bits in 2 bit space ( max 3 ) */ |
| 380 | /* 1 bit gap */ | 382 | /* 1 bit gap */ |
| 381 | feature_buffer[4] |= (stop_bits << 3); /* assign stop bits in 1 bit space */ | 383 | feature_buffer[4] |= (stop_bits << 3); /* assign stop bits in 1 bit space */ |
| @@ -397,15 +399,15 @@ static int cypress_serial_control(struct tty_struct *tty, | |||
| 397 | HID_REQ_SET_REPORT, | 399 | HID_REQ_SET_REPORT, |
| 398 | USB_DIR_OUT | USB_RECIP_INTERFACE | USB_TYPE_CLASS, | 400 | USB_DIR_OUT | USB_RECIP_INTERFACE | USB_TYPE_CLASS, |
| 399 | 0x0300, 0, feature_buffer, | 401 | 0x0300, 0, feature_buffer, |
| 400 | sizeof(feature_buffer), 500); | 402 | feature_len, 500); |
| 401 | 403 | ||
| 402 | if (tries++ >= 3) | 404 | if (tries++ >= 3) |
| 403 | break; | 405 | break; |
| 404 | 406 | ||
| 405 | } while (retval != sizeof(feature_buffer) && | 407 | } while (retval != feature_len && |
| 406 | retval != -ENODEV); | 408 | retval != -ENODEV); |
| 407 | 409 | ||
| 408 | if (retval != sizeof(feature_buffer)) { | 410 | if (retval != feature_len) { |
| 409 | dev_err(&port->dev, "%s - failed sending serial " | 411 | dev_err(&port->dev, "%s - failed sending serial " |
| 410 | "line settings - %d\n", __func__, retval); | 412 | "line settings - %d\n", __func__, retval); |
| 411 | cypress_set_dead(port); | 413 | cypress_set_dead(port); |
| @@ -425,43 +427,42 @@ static int cypress_serial_control(struct tty_struct *tty, | |||
| 425 | /* Not implemented for this device, | 427 | /* Not implemented for this device, |
| 426 | and if we try to do it we're likely | 428 | and if we try to do it we're likely |
| 427 | to crash the hardware. */ | 429 | to crash the hardware. */ |
| 428 | return -ENOTTY; | 430 | retval = -ENOTTY; |
| 431 | goto out; | ||
| 429 | } | 432 | } |
| 430 | dbg("%s - retreiving serial line settings", __func__); | 433 | dbg("%s - retreiving serial line settings", __func__); |
| 431 | /* set initial values in feature buffer */ | ||
| 432 | memset(feature_buffer, 0, sizeof(feature_buffer)); | ||
| 433 | |||
| 434 | do { | 434 | do { |
| 435 | retval = usb_control_msg(port->serial->dev, | 435 | retval = usb_control_msg(port->serial->dev, |
| 436 | usb_rcvctrlpipe(port->serial->dev, 0), | 436 | usb_rcvctrlpipe(port->serial->dev, 0), |
| 437 | HID_REQ_GET_REPORT, | 437 | HID_REQ_GET_REPORT, |
| 438 | USB_DIR_IN | USB_RECIP_INTERFACE | USB_TYPE_CLASS, | 438 | USB_DIR_IN | USB_RECIP_INTERFACE | USB_TYPE_CLASS, |
| 439 | 0x0300, 0, feature_buffer, | 439 | 0x0300, 0, feature_buffer, |
| 440 | sizeof(feature_buffer), 500); | 440 | feature_len, 500); |
| 441 | 441 | ||
| 442 | if (tries++ >= 3) | 442 | if (tries++ >= 3) |
| 443 | break; | 443 | break; |
| 444 | } while (retval != sizeof(feature_buffer) | 444 | } while (retval != feature_len |
| 445 | && retval != -ENODEV); | 445 | && retval != -ENODEV); |
| 446 | 446 | ||
| 447 | if (retval != sizeof(feature_buffer)) { | 447 | if (retval != feature_len) { |
| 448 | dev_err(&port->dev, "%s - failed to retrieve serial " | 448 | dev_err(&port->dev, "%s - failed to retrieve serial " |
| 449 | "line settings - %d\n", __func__, retval); | 449 | "line settings - %d\n", __func__, retval); |
| 450 | cypress_set_dead(port); | 450 | cypress_set_dead(port); |
| 451 | return retval; | 451 | goto out; |
| 452 | } else { | 452 | } else { |
| 453 | spin_lock_irqsave(&priv->lock, flags); | 453 | spin_lock_irqsave(&priv->lock, flags); |
| 454 | /* store the config in one byte, and later | 454 | /* store the config in one byte, and later |
| 455 | use bit masks to check values */ | 455 | use bit masks to check values */ |
| 456 | priv->current_config = feature_buffer[4]; | 456 | priv->current_config = feature_buffer[4]; |
| 457 | priv->baud_rate = *((u_int32_t *)feature_buffer); | 457 | priv->baud_rate = get_unaligned_le32(feature_buffer); |
| 458 | spin_unlock_irqrestore(&priv->lock, flags); | 458 | spin_unlock_irqrestore(&priv->lock, flags); |
| 459 | } | 459 | } |
| 460 | } | 460 | } |
| 461 | spin_lock_irqsave(&priv->lock, flags); | 461 | spin_lock_irqsave(&priv->lock, flags); |
| 462 | ++priv->cmd_count; | 462 | ++priv->cmd_count; |
| 463 | spin_unlock_irqrestore(&priv->lock, flags); | 463 | spin_unlock_irqrestore(&priv->lock, flags); |
| 464 | 464 | out: | |
| 465 | kfree(feature_buffer); | ||
| 465 | return retval; | 466 | return retval; |
| 466 | } /* cypress_serial_control */ | 467 | } /* cypress_serial_control */ |
| 467 | 468 | ||
| @@ -690,7 +691,6 @@ static void cypress_dtr_rts(struct usb_serial_port *port, int on) | |||
| 690 | { | 691 | { |
| 691 | struct cypress_private *priv = usb_get_serial_port_data(port); | 692 | struct cypress_private *priv = usb_get_serial_port_data(port); |
| 692 | /* drop dtr and rts */ | 693 | /* drop dtr and rts */ |
| 693 | priv = usb_get_serial_port_data(port); | ||
| 694 | spin_lock_irq(&priv->lock); | 694 | spin_lock_irq(&priv->lock); |
| 695 | if (on == 0) | 695 | if (on == 0) |
| 696 | priv->line_control = 0; | 696 | priv->line_control = 0; |
| @@ -1307,13 +1307,9 @@ static void cypress_read_int_callback(struct urb *urb) | |||
| 1307 | spin_unlock_irqrestore(&priv->lock, flags); | 1307 | spin_unlock_irqrestore(&priv->lock, flags); |
| 1308 | 1308 | ||
| 1309 | /* process read if there is data other than line status */ | 1309 | /* process read if there is data other than line status */ |
| 1310 | if (tty && (bytes > i)) { | 1310 | if (tty && bytes > i) { |
| 1311 | bytes = tty_buffer_request_room(tty, bytes); | 1311 | tty_insert_flip_string_fixed_flag(tty, data + i, |
| 1312 | for (; i < bytes ; ++i) { | 1312 | bytes - i, tty_flag); |
| 1313 | dbg("pushing byte number %d - %d - %c", i, data[i], | ||
| 1314 | data[i]); | ||
| 1315 | tty_insert_flip_char(tty, data[i], tty_flag); | ||
| 1316 | } | ||
| 1317 | tty_flip_buffer_push(tty); | 1313 | tty_flip_buffer_push(tty); |
| 1318 | } | 1314 | } |
| 1319 | 1315 | ||
| @@ -1325,9 +1321,9 @@ static void cypress_read_int_callback(struct urb *urb) | |||
| 1325 | continue_read: | 1321 | continue_read: |
| 1326 | tty_kref_put(tty); | 1322 | tty_kref_put(tty); |
| 1327 | 1323 | ||
| 1328 | /* Continue trying to always read... unless the port has closed. */ | 1324 | /* Continue trying to always read */ |
| 1329 | 1325 | ||
| 1330 | if (port->port.count > 0 && priv->comm_is_ok) { | 1326 | if (priv->comm_is_ok) { |
| 1331 | usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev, | 1327 | usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev, |
| 1332 | usb_rcvintpipe(port->serial->dev, | 1328 | usb_rcvintpipe(port->serial->dev, |
| 1333 | port->interrupt_in_endpointAddress), | 1329 | port->interrupt_in_endpointAddress), |
| @@ -1336,7 +1332,7 @@ continue_read: | |||
| 1336 | cypress_read_int_callback, port, | 1332 | cypress_read_int_callback, port, |
| 1337 | priv->read_urb_interval); | 1333 | priv->read_urb_interval); |
| 1338 | result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); | 1334 | result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); |
| 1339 | if (result) { | 1335 | if (result && result != -EPERM) { |
| 1340 | dev_err(&urb->dev->dev, "%s - failed resubmitting " | 1336 | dev_err(&urb->dev->dev, "%s - failed resubmitting " |
| 1341 | "read urb, error %d\n", __func__, | 1337 | "read urb, error %d\n", __func__, |
| 1342 | result); | 1338 | result); |
| @@ -1650,3 +1646,5 @@ module_param(stats, bool, S_IRUGO | S_IWUSR); | |||
| 1650 | MODULE_PARM_DESC(stats, "Enable statistics or not"); | 1646 | MODULE_PARM_DESC(stats, "Enable statistics or not"); |
| 1651 | module_param(interval, int, S_IRUGO | S_IWUSR); | 1647 | module_param(interval, int, S_IRUGO | S_IWUSR); |
| 1652 | MODULE_PARM_DESC(interval, "Overrides interrupt interval"); | 1648 | MODULE_PARM_DESC(interval, "Overrides interrupt interval"); |
| 1649 | module_param(unstable_bauds, bool, S_IRUGO | S_IWUSR); | ||
| 1650 | MODULE_PARM_DESC(unstable_bauds, "Allow unstable baud rates"); | ||
