diff options
-rw-r--r-- | drivers/usb/serial/sierra.c | 221 |
1 files changed, 107 insertions, 114 deletions
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 6ee0b89a56..551c6ce89f 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c | |||
@@ -86,15 +86,14 @@ static int debug; | |||
86 | #define N_IN_URB 4 | 86 | #define N_IN_URB 4 |
87 | #define N_OUT_URB 4 | 87 | #define N_OUT_URB 4 |
88 | #define IN_BUFLEN 4096 | 88 | #define IN_BUFLEN 4096 |
89 | #define OUT_BUFLEN 128 | ||
90 | 89 | ||
91 | struct sierra_port_private { | 90 | struct sierra_port_private { |
91 | spinlock_t lock; /* lock the structure */ | ||
92 | int outstanding_urbs; /* number of out urbs in flight */ | ||
93 | |||
92 | /* Input endpoints and buffer for this port */ | 94 | /* Input endpoints and buffer for this port */ |
93 | struct urb *in_urbs[N_IN_URB]; | 95 | struct urb *in_urbs[N_IN_URB]; |
94 | char in_buffer[N_IN_URB][IN_BUFLEN]; | 96 | char in_buffer[N_IN_URB][IN_BUFLEN]; |
95 | /* Output endpoints and buffer for this port */ | ||
96 | struct urb *out_urbs[N_OUT_URB]; | ||
97 | char out_buffer[N_OUT_URB][OUT_BUFLEN]; | ||
98 | 97 | ||
99 | /* Settings for the port */ | 98 | /* Settings for the port */ |
100 | int rts_state; /* Handshaking pins (outputs) */ | 99 | int rts_state; /* Handshaking pins (outputs) */ |
@@ -103,8 +102,6 @@ struct sierra_port_private { | |||
103 | int dsr_state; | 102 | int dsr_state; |
104 | int dcd_state; | 103 | int dcd_state; |
105 | int ri_state; | 104 | int ri_state; |
106 | |||
107 | unsigned long tx_start_time[N_OUT_URB]; | ||
108 | }; | 105 | }; |
109 | 106 | ||
110 | static int sierra_send_setup(struct usb_serial_port *port) | 107 | static int sierra_send_setup(struct usb_serial_port *port) |
@@ -197,61 +194,98 @@ static int sierra_ioctl(struct usb_serial_port *port, struct file *file, | |||
197 | return -ENOIOCTLCMD; | 194 | return -ENOIOCTLCMD; |
198 | } | 195 | } |
199 | 196 | ||
197 | static void sierra_outdat_callback(struct urb *urb) | ||
198 | { | ||
199 | struct usb_serial_port *port = urb->context; | ||
200 | struct sierra_port_private *portdata = usb_get_serial_port_data(port); | ||
201 | int status = urb->status; | ||
202 | unsigned long flags; | ||
203 | |||
204 | dbg("%s - port %d", __FUNCTION__, port->number); | ||
205 | |||
206 | /* free up the transfer buffer, as usb_free_urb() does not do this */ | ||
207 | kfree(urb->transfer_buffer); | ||
208 | |||
209 | if (status) | ||
210 | dbg("%s - nonzero write bulk status received: %d", | ||
211 | __FUNCTION__, status); | ||
212 | |||
213 | spin_lock_irqsave(&portdata->lock, flags); | ||
214 | --portdata->outstanding_urbs; | ||
215 | spin_unlock_irqrestore(&portdata->lock, flags); | ||
216 | |||
217 | usb_serial_port_softint(port); | ||
218 | } | ||
219 | |||
200 | /* Write */ | 220 | /* Write */ |
201 | static int sierra_write(struct usb_serial_port *port, | 221 | static int sierra_write(struct usb_serial_port *port, |
202 | const unsigned char *buf, int count) | 222 | const unsigned char *buf, int count) |
203 | { | 223 | { |
204 | struct sierra_port_private *portdata; | 224 | struct sierra_port_private *portdata = usb_get_serial_port_data(port); |
205 | int i; | 225 | struct usb_serial *serial = port->serial; |
206 | int left, todo; | 226 | unsigned long flags; |
207 | struct urb *this_urb = NULL; /* spurious */ | 227 | unsigned char *buffer; |
208 | int err; | 228 | struct urb *urb; |
229 | int status; | ||
209 | 230 | ||
210 | portdata = usb_get_serial_port_data(port); | 231 | portdata = usb_get_serial_port_data(port); |
211 | 232 | ||
212 | dbg("%s: write (%d chars)", __FUNCTION__, count); | 233 | dbg("%s: write (%d chars)", __FUNCTION__, count); |
213 | 234 | ||
214 | i = 0; | 235 | spin_lock_irqsave(&portdata->lock, flags); |
215 | left = count; | 236 | if (portdata->outstanding_urbs > N_OUT_URB) { |
216 | for (i=0; left > 0 && i < N_OUT_URB; i++) { | 237 | spin_unlock_irqrestore(&portdata->lock, flags); |
217 | todo = left; | 238 | dbg("%s - write limit hit\n", __FUNCTION__); |
218 | if (todo > OUT_BUFLEN) | 239 | return 0; |
219 | todo = OUT_BUFLEN; | 240 | } |
220 | 241 | portdata->outstanding_urbs++; | |
221 | this_urb = portdata->out_urbs[i]; | 242 | spin_unlock_irqrestore(&portdata->lock, flags); |
222 | if (this_urb->status == -EINPROGRESS) { | 243 | |
223 | if (time_before(jiffies, | 244 | buffer = kmalloc(count, GFP_ATOMIC); |
224 | portdata->tx_start_time[i] + 10 * HZ)) | 245 | if (!buffer) { |
225 | continue; | 246 | dev_err(&port->dev, "out of memory\n"); |
226 | usb_unlink_urb(this_urb); | 247 | count = -ENOMEM; |
227 | continue; | 248 | goto error_no_buffer; |
228 | } | 249 | } |
229 | if (this_urb->status != 0) | ||
230 | dbg("usb_write %p failed (err=%d)", | ||
231 | this_urb, this_urb->status); | ||
232 | 250 | ||
233 | dbg("%s: endpoint %d buf %d", __FUNCTION__, | 251 | urb = usb_alloc_urb(0, GFP_ATOMIC); |
234 | usb_pipeendpoint(this_urb->pipe), i); | 252 | if (!urb) { |
253 | dev_err(&port->dev, "no more free urbs\n"); | ||
254 | count = -ENOMEM; | ||
255 | goto error_no_urb; | ||
256 | } | ||
235 | 257 | ||
236 | /* send the data */ | 258 | memcpy(buffer, buf, count); |
237 | memcpy (this_urb->transfer_buffer, buf, todo); | ||
238 | this_urb->transfer_buffer_length = todo; | ||
239 | 259 | ||
240 | this_urb->dev = port->serial->dev; | 260 | usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, buffer); |
241 | err = usb_submit_urb(this_urb, GFP_ATOMIC); | 261 | |
242 | if (err) { | 262 | usb_fill_bulk_urb(urb, serial->dev, |
243 | dbg("usb_submit_urb %p (write bulk) failed " | 263 | usb_sndbulkpipe(serial->dev, |
244 | "(%d, has %d)", this_urb, | 264 | port->bulk_out_endpointAddress), |
245 | err, this_urb->status); | 265 | buffer, count, sierra_outdat_callback, port); |
246 | continue; | 266 | |
247 | } | 267 | /* send it down the pipe */ |
248 | portdata->tx_start_time[i] = jiffies; | 268 | status = usb_submit_urb(urb, GFP_ATOMIC); |
249 | buf += todo; | 269 | if (status) { |
250 | left -= todo; | 270 | dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed " |
271 | "with status = %d\n", __FUNCTION__, status); | ||
272 | count = status; | ||
273 | goto error; | ||
251 | } | 274 | } |
252 | 275 | ||
253 | count -= left; | 276 | /* we are done with this urb, so let the host driver |
254 | dbg("%s: wrote (did %d)", __FUNCTION__, count); | 277 | * really free it when it is finished with it */ |
278 | usb_free_urb(urb); | ||
279 | |||
280 | return count; | ||
281 | error: | ||
282 | usb_free_urb(urb); | ||
283 | error_no_urb: | ||
284 | kfree(buffer); | ||
285 | error_no_buffer: | ||
286 | spin_lock_irqsave(&portdata->lock, flags); | ||
287 | --portdata->outstanding_urbs; | ||
288 | spin_unlock_irqrestore(&portdata->lock, flags); | ||
255 | return count; | 289 | return count; |
256 | } | 290 | } |
257 | 291 | ||
@@ -286,24 +320,13 @@ static void sierra_indat_callback(struct urb *urb) | |||
286 | if (port->open_count && status != -ESHUTDOWN) { | 320 | if (port->open_count && status != -ESHUTDOWN) { |
287 | err = usb_submit_urb(urb, GFP_ATOMIC); | 321 | err = usb_submit_urb(urb, GFP_ATOMIC); |
288 | if (err) | 322 | if (err) |
289 | printk(KERN_ERR "%s: resubmit read urb failed. " | 323 | dev_err(&port->dev, "resubmit read urb failed." |
290 | "(%d)", __FUNCTION__, err); | 324 | "(%d)", err); |
291 | } | 325 | } |
292 | } | 326 | } |
293 | return; | 327 | return; |
294 | } | 328 | } |
295 | 329 | ||
296 | static void sierra_outdat_callback(struct urb *urb) | ||
297 | { | ||
298 | struct usb_serial_port *port; | ||
299 | |||
300 | dbg("%s", __FUNCTION__); | ||
301 | |||
302 | port = (struct usb_serial_port *) urb->context; | ||
303 | |||
304 | usb_serial_port_softint(port); | ||
305 | } | ||
306 | |||
307 | static void sierra_instat_callback(struct urb *urb) | 330 | static void sierra_instat_callback(struct urb *urb) |
308 | { | 331 | { |
309 | int err; | 332 | int err; |
@@ -360,39 +383,35 @@ static void sierra_instat_callback(struct urb *urb) | |||
360 | 383 | ||
361 | static int sierra_write_room(struct usb_serial_port *port) | 384 | static int sierra_write_room(struct usb_serial_port *port) |
362 | { | 385 | { |
363 | struct sierra_port_private *portdata; | 386 | struct sierra_port_private *portdata = usb_get_serial_port_data(port); |
364 | int i; | 387 | unsigned long flags; |
365 | int data_len = 0; | ||
366 | struct urb *this_urb; | ||
367 | 388 | ||
368 | portdata = usb_get_serial_port_data(port); | 389 | dbg("%s - port %d", __FUNCTION__, port->number); |
369 | 390 | ||
370 | for (i=0; i < N_OUT_URB; i++) { | 391 | /* try to give a good number back based on if we have any free urbs at |
371 | this_urb = portdata->out_urbs[i]; | 392 | * this point in time */ |
372 | if (this_urb && this_urb->status != -EINPROGRESS) | 393 | spin_lock_irqsave(&portdata->lock, flags); |
373 | data_len += OUT_BUFLEN; | 394 | if (portdata->outstanding_urbs > N_OUT_URB * 2 / 3) { |
395 | spin_unlock_irqrestore(&portdata->lock, flags); | ||
396 | dbg("%s - write limit hit\n", __FUNCTION__); | ||
397 | return 0; | ||
374 | } | 398 | } |
399 | spin_unlock_irqrestore(&portdata->lock, flags); | ||
375 | 400 | ||
376 | dbg("%s: %d", __FUNCTION__, data_len); | 401 | return 2048; |
377 | return data_len; | ||
378 | } | 402 | } |
379 | 403 | ||
380 | static int sierra_chars_in_buffer(struct usb_serial_port *port) | 404 | static int sierra_chars_in_buffer(struct usb_serial_port *port) |
381 | { | 405 | { |
382 | struct sierra_port_private *portdata; | 406 | dbg("%s - port %d", __FUNCTION__, port->number); |
383 | int i; | 407 | |
384 | int data_len = 0; | 408 | /* |
385 | struct urb *this_urb; | 409 | * We can't really account for how much data we |
386 | 410 | * have sent out, but hasn't made it through to the | |
387 | portdata = usb_get_serial_port_data(port); | 411 | * device as we can't see the backend here, so just |
388 | 412 | * tell the tty layer that everything is flushed. | |
389 | for (i=0; i < N_OUT_URB; i++) { | 413 | */ |
390 | this_urb = portdata->out_urbs[i]; | 414 | return 0; |
391 | if (this_urb && this_urb->status == -EINPROGRESS) | ||
392 | data_len += this_urb->transfer_buffer_length; | ||
393 | } | ||
394 | dbg("%s: %d", __FUNCTION__, data_len); | ||
395 | return data_len; | ||
396 | } | 415 | } |
397 | 416 | ||
398 | static int sierra_open(struct usb_serial_port *port, struct file *filp) | 417 | static int sierra_open(struct usb_serial_port *port, struct file *filp) |
@@ -437,16 +456,6 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp) | |||
437 | } | 456 | } |
438 | } | 457 | } |
439 | 458 | ||
440 | /* Reset low level data toggle on out endpoints */ | ||
441 | for (i = 0; i < N_OUT_URB; i++) { | ||
442 | urb = portdata->out_urbs[i]; | ||
443 | if (! urb) | ||
444 | continue; | ||
445 | urb->dev = serial->dev; | ||
446 | /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), | ||
447 | usb_pipeout(urb->pipe), 0); */ | ||
448 | } | ||
449 | |||
450 | port->tty->low_latency = 1; | 459 | port->tty->low_latency = 1; |
451 | 460 | ||
452 | /* set mode to D0 */ | 461 | /* set mode to D0 */ |
@@ -478,8 +487,6 @@ static void sierra_close(struct usb_serial_port *port, struct file *filp) | |||
478 | /* Stop reading/writing urbs */ | 487 | /* Stop reading/writing urbs */ |
479 | for (i = 0; i < N_IN_URB; i++) | 488 | for (i = 0; i < N_IN_URB; i++) |
480 | usb_unlink_urb(portdata->in_urbs[i]); | 489 | usb_unlink_urb(portdata->in_urbs[i]); |
481 | for (i = 0; i < N_OUT_URB; i++) | ||
482 | usb_unlink_urb(portdata->out_urbs[i]); | ||
483 | } | 490 | } |
484 | port->tty = NULL; | 491 | port->tty = NULL; |
485 | } | 492 | } |
@@ -527,13 +534,6 @@ static void sierra_setup_urbs(struct usb_serial *serial) | |||
527 | port->bulk_in_endpointAddress, USB_DIR_IN, port, | 534 | port->bulk_in_endpointAddress, USB_DIR_IN, port, |
528 | portdata->in_buffer[j], IN_BUFLEN, sierra_indat_callback); | 535 | portdata->in_buffer[j], IN_BUFLEN, sierra_indat_callback); |
529 | } | 536 | } |
530 | |||
531 | /* outdat endpoints */ | ||
532 | for (j = 0; j < N_OUT_URB; ++j) { | ||
533 | portdata->out_urbs[j] = sierra_setup_urb (serial, | ||
534 | port->bulk_out_endpointAddress, USB_DIR_OUT, port, | ||
535 | portdata->out_buffer[j], OUT_BUFLEN, sierra_outdat_callback); | ||
536 | } | ||
537 | } | 537 | } |
538 | } | 538 | } |
539 | 539 | ||
@@ -552,8 +552,9 @@ static int sierra_startup(struct usb_serial *serial) | |||
552 | if (!portdata) { | 552 | if (!portdata) { |
553 | dbg("%s: kmalloc for sierra_port_private (%d) failed!.", | 553 | dbg("%s: kmalloc for sierra_port_private (%d) failed!.", |
554 | __FUNCTION__, i); | 554 | __FUNCTION__, i); |
555 | return (1); | 555 | return -ENOMEM; |
556 | } | 556 | } |
557 | spin_lock_init(&portdata->lock); | ||
557 | 558 | ||
558 | usb_set_serial_port_data(port, portdata); | 559 | usb_set_serial_port_data(port, portdata); |
559 | 560 | ||
@@ -567,7 +568,7 @@ static int sierra_startup(struct usb_serial *serial) | |||
567 | 568 | ||
568 | sierra_setup_urbs(serial); | 569 | sierra_setup_urbs(serial); |
569 | 570 | ||
570 | return (0); | 571 | return 0; |
571 | } | 572 | } |
572 | 573 | ||
573 | static void sierra_shutdown(struct usb_serial *serial) | 574 | static void sierra_shutdown(struct usb_serial *serial) |
@@ -589,8 +590,6 @@ static void sierra_shutdown(struct usb_serial *serial) | |||
589 | 590 | ||
590 | for (j = 0; j < N_IN_URB; j++) | 591 | for (j = 0; j < N_IN_URB; j++) |
591 | usb_unlink_urb(portdata->in_urbs[j]); | 592 | usb_unlink_urb(portdata->in_urbs[j]); |
592 | for (j = 0; j < N_OUT_URB; j++) | ||
593 | usb_unlink_urb(portdata->out_urbs[j]); | ||
594 | } | 593 | } |
595 | 594 | ||
596 | /* Now free them */ | 595 | /* Now free them */ |
@@ -608,12 +607,6 @@ static void sierra_shutdown(struct usb_serial *serial) | |||
608 | portdata->in_urbs[j] = NULL; | 607 | portdata->in_urbs[j] = NULL; |
609 | } | 608 | } |
610 | } | 609 | } |
611 | for (j = 0; j < N_OUT_URB; j++) { | ||
612 | if (portdata->out_urbs[j]) { | ||
613 | usb_free_urb(portdata->out_urbs[j]); | ||
614 | portdata->out_urbs[j] = NULL; | ||
615 | } | ||
616 | } | ||
617 | } | 610 | } |
618 | 611 | ||
619 | /* Now free per port private data */ | 612 | /* Now free per port private data */ |