aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 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
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 */