aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@suse.de>2007-06-20 01:22:23 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-07-12 19:34:37 -0400
commit17c2327419a889293fb955baf0c69a7d38c5809c (patch)
tree6eacf6dd5ff7a01798fba38a9bd76b428ae33d47 /drivers
parent05400013698776a71b1e401ceacf709bda3d1517 (diff)
USB: sierra: remove incorrect usage of the urb status field
You can't rely on the fact that the status really is correct like it was. Also simplified the write path and now we allocate the urb and data on the fly, instead of trying to do that really odd timeout check which I am guessing doesn't really work properly. This should speed up the device by keeping the hardware queue full easier. As a benefit, this reduces the size of the driver. Cc: Kevin Lloyd <linux@sierrawireless.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/serial/sierra.c221
1 files changed, 107 insertions, 114 deletions
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index 6ee0b89a56de..551c6ce89f66 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
91struct sierra_port_private { 90struct 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
110static int sierra_send_setup(struct usb_serial_port *port) 107static 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
197static 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 */
201static int sierra_write(struct usb_serial_port *port, 221static 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;
281error:
282 usb_free_urb(urb);
283error_no_urb:
284 kfree(buffer);
285error_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
296static 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
307static void sierra_instat_callback(struct urb *urb) 330static 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
361static int sierra_write_room(struct usb_serial_port *port) 384static 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
380static int sierra_chars_in_buffer(struct usb_serial_port *port) 404static 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
398static int sierra_open(struct usb_serial_port *port, struct file *filp) 417static 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
573static void sierra_shutdown(struct usb_serial *serial) 574static 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 */