diff options
| author | Johan Hovold <jhovold@gmail.com> | 2010-05-18 18:01:40 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-05-20 16:21:50 -0400 |
| commit | 60b3013cdaf3fa8a17243ca46b19db3cbe08d943 (patch) | |
| tree | adcd171323c298313160cdbe7500a0c731df6c90 | |
| parent | ff8c195ff56d5d4226d4c1586e89b7b2e96c120a (diff) | |
USB: kl5usb105: reimplement using generic framework
Kill custom read and write implementations (static per-port,
singleton(!) urb pool).
Also remove changelog header (can be retrieved through git).
Read processing and write-buffer handling tested using a cp210x device
in a loopback setup.
Signed-off-by: Johan Hovold <jhovold@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
| -rw-r--r-- | drivers/usb/serial/kl5kusb105.c | 380 |
1 files changed, 47 insertions, 333 deletions
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index ad168255cc04..cdbe8bf7f674 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * KLSI KL5KUSB105 chip RS232 converter driver | 2 | * KLSI KL5KUSB105 chip RS232 converter driver |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2010 Johan Hovold <jhovold@gmail.com> | ||
| 4 | * Copyright (C) 2001 Utz-Uwe Haus <haus@uuhaus.de> | 5 | * Copyright (C) 2001 Utz-Uwe Haus <haus@uuhaus.de> |
| 5 | * | 6 | * |
| 6 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
| @@ -34,17 +35,6 @@ | |||
| 34 | * implement handshaking or decide that we do not support it | 35 | * implement handshaking or decide that we do not support it |
| 35 | */ | 36 | */ |
| 36 | 37 | ||
| 37 | /* History: | ||
| 38 | * 0.3a - implemented pools of write URBs | ||
| 39 | * 0.3 - alpha version for public testing | ||
| 40 | * 0.2 - TIOCMGET works, so autopilot(1) can be used! | ||
| 41 | * 0.1 - can be used to do pilot-xfer -p /dev/ttyUSB0 -l | ||
| 42 | * | ||
| 43 | * The driver skeleton is mainly based on mct_u232.c and various other | ||
| 44 | * pieces of code shamelessly copied from the drivers/usb/serial/ directory. | ||
| 45 | */ | ||
| 46 | |||
| 47 | |||
| 48 | #include <linux/kernel.h> | 38 | #include <linux/kernel.h> |
| 49 | #include <linux/errno.h> | 39 | #include <linux/errno.h> |
| 50 | #include <linux/init.h> | 40 | #include <linux/init.h> |
| @@ -64,8 +54,8 @@ static int debug; | |||
| 64 | /* | 54 | /* |
| 65 | * Version Information | 55 | * Version Information |
| 66 | */ | 56 | */ |
| 67 | #define DRIVER_VERSION "v0.3a" | 57 | #define DRIVER_VERSION "v0.4" |
| 68 | #define DRIVER_AUTHOR "Utz-Uwe Haus <haus@uuhaus.de>" | 58 | #define DRIVER_AUTHOR "Utz-Uwe Haus <haus@uuhaus.de>, Johan Hovold <jhovold@gmail.com>" |
| 69 | #define DRIVER_DESC "KLSI KL5KUSB105 chipset USB->Serial Converter driver" | 59 | #define DRIVER_DESC "KLSI KL5KUSB105 chipset USB->Serial Converter driver" |
| 70 | 60 | ||
| 71 | 61 | ||
| @@ -73,23 +63,17 @@ static int debug; | |||
| 73 | * Function prototypes | 63 | * Function prototypes |
| 74 | */ | 64 | */ |
| 75 | static int klsi_105_startup(struct usb_serial *serial); | 65 | static int klsi_105_startup(struct usb_serial *serial); |
| 76 | static void klsi_105_disconnect(struct usb_serial *serial); | ||
| 77 | static void klsi_105_release(struct usb_serial *serial); | 66 | static void klsi_105_release(struct usb_serial *serial); |
| 78 | static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port); | 67 | static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port); |
| 79 | static void klsi_105_close(struct usb_serial_port *port); | 68 | static void klsi_105_close(struct usb_serial_port *port); |
| 80 | static int klsi_105_write(struct tty_struct *tty, | ||
| 81 | struct usb_serial_port *port, const unsigned char *buf, int count); | ||
| 82 | static void klsi_105_write_bulk_callback(struct urb *urb); | ||
| 83 | static int klsi_105_chars_in_buffer(struct tty_struct *tty); | ||
| 84 | static int klsi_105_write_room(struct tty_struct *tty); | ||
| 85 | static void klsi_105_read_bulk_callback(struct urb *urb); | ||
| 86 | static void klsi_105_set_termios(struct tty_struct *tty, | 69 | static void klsi_105_set_termios(struct tty_struct *tty, |
| 87 | struct usb_serial_port *port, struct ktermios *old); | 70 | struct usb_serial_port *port, struct ktermios *old); |
| 88 | static void klsi_105_throttle(struct tty_struct *tty); | ||
| 89 | static void klsi_105_unthrottle(struct tty_struct *tty); | ||
| 90 | static int klsi_105_tiocmget(struct tty_struct *tty, struct file *file); | 71 | static int klsi_105_tiocmget(struct tty_struct *tty, struct file *file); |
| 91 | static int klsi_105_tiocmset(struct tty_struct *tty, struct file *file, | 72 | static int klsi_105_tiocmset(struct tty_struct *tty, struct file *file, |
| 92 | unsigned int set, unsigned int clear); | 73 | unsigned int set, unsigned int clear); |
| 74 | static void klsi_105_process_read_urb(struct urb *urb); | ||
| 75 | static int klsi_105_prepare_write_buffer(struct usb_serial_port *port, | ||
| 76 | void *dest, size_t size); | ||
| 93 | 77 | ||
| 94 | /* | 78 | /* |
| 95 | * All of the device info needed for the KLSI converters. | 79 | * All of the device info needed for the KLSI converters. |
| @@ -119,22 +103,19 @@ static struct usb_serial_driver kl5kusb105d_device = { | |||
| 119 | .usb_driver = &kl5kusb105d_driver, | 103 | .usb_driver = &kl5kusb105d_driver, |
| 120 | .id_table = id_table, | 104 | .id_table = id_table, |
| 121 | .num_ports = 1, | 105 | .num_ports = 1, |
| 106 | .bulk_out_size = 64, | ||
| 122 | .open = klsi_105_open, | 107 | .open = klsi_105_open, |
| 123 | .close = klsi_105_close, | 108 | .close = klsi_105_close, |
| 124 | .write = klsi_105_write, | ||
| 125 | .write_bulk_callback = klsi_105_write_bulk_callback, | ||
| 126 | .chars_in_buffer = klsi_105_chars_in_buffer, | ||
| 127 | .write_room = klsi_105_write_room, | ||
| 128 | .read_bulk_callback = klsi_105_read_bulk_callback, | ||
| 129 | .set_termios = klsi_105_set_termios, | 109 | .set_termios = klsi_105_set_termios, |
| 130 | /*.break_ctl = klsi_105_break_ctl,*/ | 110 | /*.break_ctl = klsi_105_break_ctl,*/ |
| 131 | .tiocmget = klsi_105_tiocmget, | 111 | .tiocmget = klsi_105_tiocmget, |
| 132 | .tiocmset = klsi_105_tiocmset, | 112 | .tiocmset = klsi_105_tiocmset, |
| 133 | .attach = klsi_105_startup, | 113 | .attach = klsi_105_startup, |
| 134 | .disconnect = klsi_105_disconnect, | ||
| 135 | .release = klsi_105_release, | 114 | .release = klsi_105_release, |
| 136 | .throttle = klsi_105_throttle, | 115 | .throttle = usb_serial_generic_throttle, |
| 137 | .unthrottle = klsi_105_unthrottle, | 116 | .unthrottle = usb_serial_generic_unthrottle, |
| 117 | .process_read_urb = klsi_105_process_read_urb, | ||
| 118 | .prepare_write_buffer = klsi_105_prepare_write_buffer, | ||
| 138 | }; | 119 | }; |
| 139 | 120 | ||
| 140 | struct klsi_105_port_settings { | 121 | struct klsi_105_port_settings { |
| @@ -145,18 +126,11 @@ struct klsi_105_port_settings { | |||
| 145 | __u8 unknown2; | 126 | __u8 unknown2; |
| 146 | } __attribute__ ((packed)); | 127 | } __attribute__ ((packed)); |
| 147 | 128 | ||
| 148 | /* we implement a pool of NUM_URBS urbs per usb_serial */ | ||
| 149 | #define NUM_URBS 1 | ||
| 150 | #define URB_TRANSFER_BUFFER_SIZE 64 | ||
| 151 | struct klsi_105_private { | 129 | struct klsi_105_private { |
| 152 | struct klsi_105_port_settings cfg; | 130 | struct klsi_105_port_settings cfg; |
| 153 | struct ktermios termios; | 131 | struct ktermios termios; |
| 154 | unsigned long line_state; /* modem line settings */ | 132 | unsigned long line_state; /* modem line settings */ |
| 155 | /* write pool */ | ||
| 156 | struct urb *write_urb_pool[NUM_URBS]; | ||
| 157 | spinlock_t lock; | 133 | spinlock_t lock; |
| 158 | unsigned long bytes_in; | ||
| 159 | unsigned long bytes_out; | ||
| 160 | }; | 134 | }; |
| 161 | 135 | ||
| 162 | 136 | ||
| @@ -259,7 +233,7 @@ static int klsi_105_get_line_state(struct usb_serial_port *port, | |||
| 259 | static int klsi_105_startup(struct usb_serial *serial) | 233 | static int klsi_105_startup(struct usb_serial *serial) |
| 260 | { | 234 | { |
| 261 | struct klsi_105_private *priv; | 235 | struct klsi_105_private *priv; |
| 262 | int i, j; | 236 | int i; |
| 263 | 237 | ||
| 264 | /* check if we support the product id (see keyspan.c) | 238 | /* check if we support the product id (see keyspan.c) |
| 265 | * FIXME | 239 | * FIXME |
| @@ -283,29 +257,9 @@ static int klsi_105_startup(struct usb_serial *serial) | |||
| 283 | 257 | ||
| 284 | priv->line_state = 0; | 258 | priv->line_state = 0; |
| 285 | 259 | ||
| 286 | priv->bytes_in = 0; | ||
| 287 | priv->bytes_out = 0; | ||
| 288 | usb_set_serial_port_data(serial->port[i], priv); | 260 | usb_set_serial_port_data(serial->port[i], priv); |
| 289 | 261 | ||
| 290 | spin_lock_init(&priv->lock); | 262 | spin_lock_init(&priv->lock); |
| 291 | for (j = 0; j < NUM_URBS; j++) { | ||
| 292 | struct urb *urb = usb_alloc_urb(0, GFP_KERNEL); | ||
| 293 | |||
| 294 | priv->write_urb_pool[j] = urb; | ||
| 295 | if (urb == NULL) { | ||
| 296 | dev_err(&serial->dev->dev, "No more urbs???\n"); | ||
| 297 | goto err_cleanup; | ||
| 298 | } | ||
| 299 | |||
| 300 | urb->transfer_buffer = | ||
| 301 | kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); | ||
| 302 | if (!urb->transfer_buffer) { | ||
| 303 | dev_err(&serial->dev->dev, | ||
| 304 | "%s - out of memory for urb buffers.\n", | ||
| 305 | __func__); | ||
| 306 | goto err_cleanup; | ||
| 307 | } | ||
| 308 | } | ||
| 309 | 263 | ||
| 310 | /* priv->termios is left uninitalized until port opening */ | 264 | /* priv->termios is left uninitalized until port opening */ |
| 311 | init_waitqueue_head(&serial->port[i]->write_wait); | 265 | init_waitqueue_head(&serial->port[i]->write_wait); |
| @@ -316,56 +270,20 @@ static int klsi_105_startup(struct usb_serial *serial) | |||
| 316 | err_cleanup: | 270 | err_cleanup: |
| 317 | for (; i >= 0; i--) { | 271 | for (; i >= 0; i--) { |
| 318 | priv = usb_get_serial_port_data(serial->port[i]); | 272 | priv = usb_get_serial_port_data(serial->port[i]); |
| 319 | for (j = 0; j < NUM_URBS; j++) { | ||
| 320 | if (priv->write_urb_pool[j]) { | ||
| 321 | kfree(priv->write_urb_pool[j]->transfer_buffer); | ||
| 322 | usb_free_urb(priv->write_urb_pool[j]); | ||
| 323 | } | ||
| 324 | } | ||
| 325 | kfree(priv); | 273 | kfree(priv); |
| 326 | usb_set_serial_port_data(serial->port[i], NULL); | 274 | usb_set_serial_port_data(serial->port[i], NULL); |
| 327 | } | 275 | } |
| 328 | return -ENOMEM; | 276 | return -ENOMEM; |
| 329 | } | 277 | } |
| 330 | 278 | ||
| 331 | static void klsi_105_disconnect(struct usb_serial *serial) | ||
| 332 | { | ||
| 333 | int i; | ||
| 334 | |||
| 335 | dbg("%s", __func__); | ||
| 336 | |||
| 337 | /* stop reads and writes on all ports */ | ||
| 338 | for (i = 0; i < serial->num_ports; ++i) { | ||
| 339 | struct klsi_105_private *priv = | ||
| 340 | usb_get_serial_port_data(serial->port[i]); | ||
| 341 | |||
| 342 | if (priv) { | ||
| 343 | /* kill our write urb pool */ | ||
| 344 | int j; | ||
| 345 | struct urb **write_urbs = priv->write_urb_pool; | ||
| 346 | |||
| 347 | for (j = 0; j < NUM_URBS; j++) { | ||
| 348 | if (write_urbs[j]) { | ||
| 349 | usb_kill_urb(write_urbs[j]); | ||
| 350 | usb_free_urb(write_urbs[j]); | ||
| 351 | } | ||
| 352 | } | ||
| 353 | } | ||
| 354 | } | ||
| 355 | } | ||
| 356 | |||
| 357 | static void klsi_105_release(struct usb_serial *serial) | 279 | static void klsi_105_release(struct usb_serial *serial) |
| 358 | { | 280 | { |
| 359 | int i; | 281 | int i; |
| 360 | 282 | ||
| 361 | dbg("%s", __func__); | 283 | dbg("%s", __func__); |
| 362 | 284 | ||
| 363 | for (i = 0; i < serial->num_ports; ++i) { | 285 | for (i = 0; i < serial->num_ports; ++i) |
| 364 | struct klsi_105_private *priv = | 286 | kfree(usb_get_serial_port_data(serial->port[i])); |
| 365 | usb_get_serial_port_data(serial->port[i]); | ||
| 366 | |||
| 367 | kfree(priv); | ||
| 368 | } | ||
| 369 | } | 287 | } |
| 370 | 288 | ||
| 371 | static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) | 289 | static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) |
| @@ -416,18 +334,8 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) | |||
| 416 | spin_unlock_irqrestore(&priv->lock, flags); | 334 | spin_unlock_irqrestore(&priv->lock, flags); |
| 417 | 335 | ||
| 418 | /* READ_ON and urb submission */ | 336 | /* READ_ON and urb submission */ |
| 419 | usb_fill_bulk_urb(port->read_urb, port->serial->dev, | 337 | rc = usb_serial_generic_open(tty, port); |
| 420 | usb_rcvbulkpipe(port->serial->dev, | ||
| 421 | port->bulk_in_endpointAddress), | ||
| 422 | port->read_urb->transfer_buffer, | ||
| 423 | port->read_urb->transfer_buffer_length, | ||
| 424 | klsi_105_read_bulk_callback, | ||
| 425 | port); | ||
| 426 | |||
| 427 | rc = usb_submit_urb(port->read_urb, GFP_KERNEL); | ||
| 428 | if (rc) { | 338 | if (rc) { |
| 429 | dev_err(&port->dev, "%s - failed submitting read urb, " | ||
| 430 | "error %d\n", __func__, rc); | ||
| 431 | retval = rc; | 339 | retval = rc; |
| 432 | goto exit; | 340 | goto exit; |
| 433 | } | 341 | } |
| @@ -464,7 +372,6 @@ exit: | |||
| 464 | 372 | ||
| 465 | static void klsi_105_close(struct usb_serial_port *port) | 373 | static void klsi_105_close(struct usb_serial_port *port) |
| 466 | { | 374 | { |
| 467 | struct klsi_105_private *priv = usb_get_serial_port_data(port); | ||
| 468 | int rc; | 375 | int rc; |
| 469 | 376 | ||
| 470 | dbg("%s port %d", __func__, port->number); | 377 | dbg("%s port %d", __func__, port->number); |
| @@ -487,232 +394,61 @@ static void klsi_105_close(struct usb_serial_port *port) | |||
| 487 | mutex_unlock(&port->serial->disc_mutex); | 394 | mutex_unlock(&port->serial->disc_mutex); |
| 488 | 395 | ||
| 489 | /* shutdown our bulk reads and writes */ | 396 | /* shutdown our bulk reads and writes */ |
| 490 | usb_kill_urb(port->write_urb); | 397 | usb_serial_generic_close(port); |
| 491 | usb_kill_urb(port->read_urb); | 398 | |
| 492 | /* unlink our write pool */ | ||
| 493 | /* FIXME */ | ||
| 494 | /* wgg - do I need this? I think so. */ | 399 | /* wgg - do I need this? I think so. */ |
| 495 | usb_kill_urb(port->interrupt_in_urb); | 400 | usb_kill_urb(port->interrupt_in_urb); |
| 496 | dev_info(&port->serial->dev->dev, | ||
| 497 | "port stats: %ld bytes in, %ld bytes out\n", | ||
| 498 | priv->bytes_in, priv->bytes_out); | ||
| 499 | } | 401 | } |
| 500 | 402 | ||
| 501 | /* We need to write a complete 64-byte data block and encode the | 403 | /* We need to write a complete 64-byte data block and encode the |
| 502 | * number actually sent in the first double-byte, LSB-order. That | 404 | * number actually sent in the first double-byte, LSB-order. That |
| 503 | * leaves at most 62 bytes of payload. | 405 | * leaves at most 62 bytes of payload. |
| 504 | */ | 406 | */ |
| 505 | #define KLSI_105_DATA_OFFSET 2 /* in the bulk urb data block */ | 407 | #define KLSI_HDR_LEN 2 |
| 506 | 408 | static int klsi_105_prepare_write_buffer(struct usb_serial_port *port, | |
| 507 | static int klsi_105_write(struct tty_struct *tty, | 409 | void *dest, size_t size) |
| 508 | struct usb_serial_port *port, const unsigned char *buf, int count) | ||
| 509 | { | ||
| 510 | struct klsi_105_private *priv = usb_get_serial_port_data(port); | ||
| 511 | int result, size; | ||
| 512 | int bytes_sent = 0; | ||
| 513 | |||
| 514 | dbg("%s - port %d", __func__, port->number); | ||
| 515 | |||
| 516 | while (count > 0) { | ||
| 517 | /* try to find a free urb (write 0 bytes if none) */ | ||
| 518 | struct urb *urb = NULL; | ||
| 519 | unsigned long flags; | ||
| 520 | int i; | ||
| 521 | /* since the pool is per-port we might not need | ||
| 522 | the spin lock !? */ | ||
| 523 | spin_lock_irqsave(&priv->lock, flags); | ||
| 524 | for (i = 0; i < NUM_URBS; i++) { | ||
| 525 | if (priv->write_urb_pool[i]->status != -EINPROGRESS) { | ||
| 526 | urb = priv->write_urb_pool[i]; | ||
| 527 | dbg("%s - using pool URB %d", __func__, i); | ||
| 528 | break; | ||
| 529 | } | ||
| 530 | } | ||
| 531 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 532 | |||
| 533 | if (urb == NULL) { | ||
| 534 | dbg("%s - no more free urbs", __func__); | ||
| 535 | goto exit; | ||
| 536 | } | ||
| 537 | |||
| 538 | if (urb->transfer_buffer == NULL) { | ||
| 539 | urb->transfer_buffer = | ||
| 540 | kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_ATOMIC); | ||
| 541 | if (urb->transfer_buffer == NULL) { | ||
| 542 | dev_err(&port->dev, | ||
| 543 | "%s - no more kernel memory...\n", | ||
| 544 | __func__); | ||
| 545 | goto exit; | ||
| 546 | } | ||
| 547 | } | ||
| 548 | |||
| 549 | size = min(count, port->bulk_out_size - KLSI_105_DATA_OFFSET); | ||
| 550 | size = min(size, URB_TRANSFER_BUFFER_SIZE - | ||
| 551 | KLSI_105_DATA_OFFSET); | ||
| 552 | |||
| 553 | memcpy(urb->transfer_buffer + KLSI_105_DATA_OFFSET, buf, size); | ||
| 554 | |||
| 555 | /* write payload size into transfer buffer */ | ||
| 556 | ((__u8 *)urb->transfer_buffer)[0] = (__u8) (size & 0xFF); | ||
| 557 | ((__u8 *)urb->transfer_buffer)[1] = (__u8) ((size & 0xFF00)>>8); | ||
| 558 | |||
| 559 | /* set up our urb */ | ||
| 560 | usb_fill_bulk_urb(urb, port->serial->dev, | ||
| 561 | usb_sndbulkpipe(port->serial->dev, | ||
| 562 | port->bulk_out_endpointAddress), | ||
| 563 | urb->transfer_buffer, | ||
| 564 | URB_TRANSFER_BUFFER_SIZE, | ||
| 565 | klsi_105_write_bulk_callback, | ||
| 566 | port); | ||
| 567 | |||
| 568 | /* send the data out the bulk port */ | ||
| 569 | result = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 570 | if (result) { | ||
| 571 | dev_err(&port->dev, | ||
| 572 | "%s - failed submitting write urb, error %d\n", | ||
| 573 | __func__, result); | ||
| 574 | goto exit; | ||
| 575 | } | ||
| 576 | buf += size; | ||
| 577 | bytes_sent += size; | ||
| 578 | count -= size; | ||
| 579 | } | ||
| 580 | exit: | ||
| 581 | /* lockless, but it's for debug info only... */ | ||
| 582 | priv->bytes_out += bytes_sent; | ||
| 583 | |||
| 584 | return bytes_sent; /* that's how much we wrote */ | ||
| 585 | } | ||
| 586 | |||
| 587 | static void klsi_105_write_bulk_callback(struct urb *urb) | ||
| 588 | { | 410 | { |
| 589 | struct usb_serial_port *port = urb->context; | 411 | unsigned char *buf = dest; |
| 590 | int status = urb->status; | 412 | int count; |
| 591 | |||
| 592 | dbg("%s - port %d", __func__, port->number); | ||
| 593 | 413 | ||
| 594 | if (status) { | 414 | count = kfifo_out_locked(&port->write_fifo, buf + KLSI_HDR_LEN, size, |
| 595 | dbg("%s - nonzero write bulk status received: %d", __func__, | 415 | &port->lock); |
| 596 | status); | 416 | put_unaligned_le16(count, buf); |
| 597 | return; | ||
| 598 | } | ||
| 599 | 417 | ||
| 600 | usb_serial_port_softint(port); | 418 | return count + KLSI_HDR_LEN; |
| 601 | } | 419 | } |
| 602 | 420 | ||
| 603 | /* return number of characters currently in the writing process */ | 421 | /* The data received is preceded by a length double-byte in LSB-first order. |
| 604 | static int klsi_105_chars_in_buffer(struct tty_struct *tty) | 422 | */ |
| 605 | { | 423 | static void klsi_105_process_read_urb(struct urb *urb) |
| 606 | struct usb_serial_port *port = tty->driver_data; | ||
| 607 | int chars = 0; | ||
| 608 | int i; | ||
| 609 | unsigned long flags; | ||
| 610 | struct klsi_105_private *priv = usb_get_serial_port_data(port); | ||
| 611 | |||
| 612 | spin_lock_irqsave(&priv->lock, flags); | ||
| 613 | |||
| 614 | for (i = 0; i < NUM_URBS; ++i) { | ||
| 615 | if (priv->write_urb_pool[i]->status == -EINPROGRESS) | ||
| 616 | chars += URB_TRANSFER_BUFFER_SIZE; | ||
| 617 | } | ||
| 618 | |||
| 619 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 620 | |||
| 621 | dbg("%s - returns %d", __func__, chars); | ||
| 622 | return chars; | ||
| 623 | } | ||
| 624 | |||
| 625 | static int klsi_105_write_room(struct tty_struct *tty) | ||
| 626 | { | ||
| 627 | struct usb_serial_port *port = tty->driver_data; | ||
| 628 | unsigned long flags; | ||
| 629 | int i; | ||
| 630 | int room = 0; | ||
| 631 | struct klsi_105_private *priv = usb_get_serial_port_data(port); | ||
| 632 | |||
| 633 | spin_lock_irqsave(&priv->lock, flags); | ||
| 634 | for (i = 0; i < NUM_URBS; ++i) { | ||
| 635 | if (priv->write_urb_pool[i]->status != -EINPROGRESS) | ||
| 636 | room += URB_TRANSFER_BUFFER_SIZE; | ||
| 637 | } | ||
| 638 | |||
| 639 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 640 | |||
| 641 | dbg("%s - returns %d", __func__, room); | ||
| 642 | return room; | ||
| 643 | } | ||
| 644 | |||
| 645 | static void klsi_105_read_bulk_callback(struct urb *urb) | ||
| 646 | { | 424 | { |
| 647 | struct usb_serial_port *port = urb->context; | 425 | struct usb_serial_port *port = urb->context; |
| 648 | struct klsi_105_private *priv = usb_get_serial_port_data(port); | ||
| 649 | struct tty_struct *tty; | ||
| 650 | unsigned char *data = urb->transfer_buffer; | 426 | unsigned char *data = urb->transfer_buffer; |
| 651 | int rc; | 427 | struct tty_struct *tty; |
| 652 | int status = urb->status; | 428 | unsigned len; |
| 653 | 429 | ||
| 654 | dbg("%s - port %d", __func__, port->number); | 430 | /* empty urbs seem to happen, we ignore them */ |
| 431 | if (!urb->actual_length) | ||
| 432 | return; | ||
| 655 | 433 | ||
| 656 | /* The urb might have been killed. */ | 434 | if (urb->actual_length <= KLSI_HDR_LEN) { |
| 657 | if (status) { | 435 | dbg("%s - malformed packet", __func__); |
| 658 | dbg("%s - nonzero read bulk status received: %d", __func__, | ||
| 659 | status); | ||
| 660 | return; | 436 | return; |
| 661 | } | 437 | } |
| 662 | 438 | ||
| 663 | /* The data received is again preceded by a length double-byte in LSB- | 439 | tty = tty_port_tty_get(&port->port); |
| 664 | * first order (see klsi_105_write() ) | 440 | if (!tty) |
| 665 | */ | 441 | return; |
| 666 | if (urb->actual_length == 0) { | ||
| 667 | /* empty urbs seem to happen, we ignore them */ | ||
| 668 | /* dbg("%s - emtpy URB", __func__); */ | ||
| 669 | ; | ||
| 670 | } else if (urb->actual_length <= 2) { | ||
| 671 | dbg("%s - size %d URB not understood", __func__, | ||
| 672 | urb->actual_length); | ||
| 673 | usb_serial_debug_data(debug, &port->dev, __func__, | ||
| 674 | urb->actual_length, data); | ||
| 675 | } else { | ||
| 676 | int bytes_sent = ((__u8 *) data)[0] + | ||
| 677 | ((unsigned int) ((__u8 *) data)[1] << 8); | ||
| 678 | tty = tty_port_tty_get(&port->port); | ||
| 679 | /* we should immediately resubmit the URB, before attempting | ||
| 680 | * to pass the data on to the tty layer. But that needs locking | ||
| 681 | * against re-entry an then mixed-up data because of | ||
| 682 | * intermixed tty_flip_buffer_push()s | ||
| 683 | * FIXME | ||
| 684 | */ | ||
| 685 | usb_serial_debug_data(debug, &port->dev, __func__, | ||
| 686 | urb->actual_length, data); | ||
| 687 | |||
| 688 | if (bytes_sent + 2 > urb->actual_length) { | ||
| 689 | dbg("%s - trying to read more data than available" | ||
| 690 | " (%d vs. %d)", __func__, | ||
| 691 | bytes_sent+2, urb->actual_length); | ||
| 692 | /* cap at implied limit */ | ||
| 693 | bytes_sent = urb->actual_length - 2; | ||
| 694 | } | ||
| 695 | |||
| 696 | tty_insert_flip_string(tty, data + 2, bytes_sent); | ||
| 697 | tty_flip_buffer_push(tty); | ||
| 698 | tty_kref_put(tty); | ||
| 699 | 442 | ||
| 700 | /* again lockless, but debug info only */ | 443 | len = get_unaligned_le16(data); |
| 701 | priv->bytes_in += bytes_sent; | 444 | if (len > urb->actual_length - KLSI_HDR_LEN) { |
| 445 | dbg("%s - packet length mismatch", __func__); | ||
| 446 | len = urb->actual_length - KLSI_HDR_LEN; | ||
| 702 | } | 447 | } |
| 703 | /* Continue trying to always read */ | 448 | |
| 704 | usb_fill_bulk_urb(port->read_urb, port->serial->dev, | 449 | tty_insert_flip_string(tty, data + KLSI_HDR_LEN, len); |
| 705 | usb_rcvbulkpipe(port->serial->dev, | 450 | tty_flip_buffer_push(tty); |
| 706 | port->bulk_in_endpointAddress), | 451 | tty_kref_put(tty); |
| 707 | port->read_urb->transfer_buffer, | ||
| 708 | port->read_urb->transfer_buffer_length, | ||
| 709 | klsi_105_read_bulk_callback, | ||
| 710 | port); | ||
| 711 | rc = usb_submit_urb(port->read_urb, GFP_ATOMIC); | ||
| 712 | if (rc) | ||
| 713 | dev_err(&port->dev, | ||
| 714 | "%s - failed resubmitting read urb, error %d\n", | ||
| 715 | __func__, rc); | ||
| 716 | } | 452 | } |
| 717 | 453 | ||
| 718 | static void klsi_105_set_termios(struct tty_struct *tty, | 454 | static void klsi_105_set_termios(struct tty_struct *tty, |
| @@ -954,28 +690,6 @@ static int klsi_105_tiocmset(struct tty_struct *tty, struct file *file, | |||
| 954 | return retval; | 690 | return retval; |
| 955 | } | 691 | } |
| 956 | 692 | ||
| 957 | static void klsi_105_throttle(struct tty_struct *tty) | ||
| 958 | { | ||
| 959 | struct usb_serial_port *port = tty->driver_data; | ||
| 960 | dbg("%s - port %d", __func__, port->number); | ||
| 961 | usb_kill_urb(port->read_urb); | ||
| 962 | } | ||
| 963 | |||
| 964 | static void klsi_105_unthrottle(struct tty_struct *tty) | ||
| 965 | { | ||
| 966 | struct usb_serial_port *port = tty->driver_data; | ||
| 967 | int result; | ||
| 968 | |||
| 969 | dbg("%s - port %d", __func__, port->number); | ||
| 970 | |||
| 971 | port->read_urb->dev = port->serial->dev; | ||
| 972 | result = usb_submit_urb(port->read_urb, GFP_KERNEL); | ||
| 973 | if (result) | ||
| 974 | dev_err(&port->dev, | ||
| 975 | "%s - failed submitting read urb, error %d\n", | ||
| 976 | __func__, result); | ||
| 977 | } | ||
| 978 | |||
| 979 | 693 | ||
| 980 | static int __init klsi_105_init(void) | 694 | static int __init klsi_105_init(void) |
| 981 | { | 695 | { |
