diff options
Diffstat (limited to 'drivers/media/video/gspca/gspca.c')
-rw-r--r-- | drivers/media/video/gspca/gspca.c | 115 |
1 files changed, 88 insertions, 27 deletions
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index ac95c55887df..496d58d479da 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c | |||
@@ -178,6 +178,48 @@ static void isoc_irq(struct urb *urb | |||
178 | } | 178 | } |
179 | 179 | ||
180 | /* | 180 | /* |
181 | * bulk message interrupt from the USB device | ||
182 | */ | ||
183 | static void bulk_irq(struct urb *urb | ||
184 | ) | ||
185 | { | ||
186 | struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context; | ||
187 | struct gspca_frame *frame; | ||
188 | int j, ret; | ||
189 | |||
190 | PDEBUG(D_PACK, "bulk irq"); | ||
191 | if (!gspca_dev->streaming) | ||
192 | return; | ||
193 | if (urb->status != 0 && urb->status != -ECONNRESET) { | ||
194 | #ifdef CONFIG_PM | ||
195 | if (!gspca_dev->frozen) | ||
196 | #endif | ||
197 | PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status); | ||
198 | return; /* disconnection ? */ | ||
199 | } | ||
200 | |||
201 | /* check the availability of the frame buffer */ | ||
202 | j = gspca_dev->fr_i; | ||
203 | j = gspca_dev->fr_queue[j]; | ||
204 | frame = &gspca_dev->frame[j]; | ||
205 | if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS) | ||
206 | != V4L2_BUF_FLAG_QUEUED) { | ||
207 | gspca_dev->last_packet_type = DISCARD_PACKET; | ||
208 | } else { | ||
209 | PDEBUG(D_PACK, "packet l:%d", urb->actual_length); | ||
210 | gspca_dev->sd_desc->pkt_scan(gspca_dev, | ||
211 | frame, | ||
212 | urb->transfer_buffer, | ||
213 | urb->actual_length); | ||
214 | } | ||
215 | /* resubmit the URB */ | ||
216 | urb->status = 0; | ||
217 | ret = usb_submit_urb(urb, GFP_ATOMIC); | ||
218 | if (ret < 0) | ||
219 | PDEBUG(D_ERR|D_PACK, "usb_submit_urb() ret %d", ret); | ||
220 | } | ||
221 | |||
222 | /* | ||
181 | * add data to the current frame | 223 | * add data to the current frame |
182 | * | 224 | * |
183 | * This function is called by the subdrivers at interrupt level. | 225 | * This function is called by the subdrivers at interrupt level. |
@@ -374,10 +416,11 @@ static void destroy_urbs(struct gspca_dev *gspca_dev) | |||
374 | } | 416 | } |
375 | 417 | ||
376 | /* | 418 | /* |
377 | * search an input isochronous endpoint in an alternate setting | 419 | * search an input transfer endpoint in an alternate setting |
378 | */ | 420 | */ |
379 | static struct usb_host_endpoint *alt_isoc(struct usb_host_interface *alt, | 421 | static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt, |
380 | __u8 epaddr) | 422 | __u8 epaddr, |
423 | __u8 xfer) | ||
381 | { | 424 | { |
382 | struct usb_host_endpoint *ep; | 425 | struct usb_host_endpoint *ep; |
383 | int i, attr; | 426 | int i, attr; |
@@ -388,7 +431,7 @@ static struct usb_host_endpoint *alt_isoc(struct usb_host_interface *alt, | |||
388 | if (ep->desc.bEndpointAddress == epaddr) { | 431 | if (ep->desc.bEndpointAddress == epaddr) { |
389 | attr = ep->desc.bmAttributes | 432 | attr = ep->desc.bmAttributes |
390 | & USB_ENDPOINT_XFERTYPE_MASK; | 433 | & USB_ENDPOINT_XFERTYPE_MASK; |
391 | if (attr == USB_ENDPOINT_XFER_ISOC) | 434 | if (attr == xfer) |
392 | return ep; | 435 | return ep; |
393 | break; | 436 | break; |
394 | } | 437 | } |
@@ -397,14 +440,14 @@ static struct usb_host_endpoint *alt_isoc(struct usb_host_interface *alt, | |||
397 | } | 440 | } |
398 | 441 | ||
399 | /* | 442 | /* |
400 | * search an input isochronous endpoint | 443 | * search an input (isoc or bulk) endpoint |
401 | * | 444 | * |
402 | * The endpoint is defined by the subdriver. | 445 | * The endpoint is defined by the subdriver. |
403 | * Use only the first isoc (some Zoran - 0x0572:0x0001 - have two such ep). | 446 | * Use only the first isoc (some Zoran - 0x0572:0x0001 - have two such ep). |
404 | * This routine may be called many times when the bandwidth is too small | 447 | * This routine may be called many times when the bandwidth is too small |
405 | * (the bandwidth is checked on urb submit). | 448 | * (the bandwidth is checked on urb submit). |
406 | */ | 449 | */ |
407 | static struct usb_host_endpoint *get_isoc_ep(struct gspca_dev *gspca_dev) | 450 | static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev) |
408 | { | 451 | { |
409 | struct usb_interface *intf; | 452 | struct usb_interface *intf; |
410 | struct usb_host_endpoint *ep; | 453 | struct usb_host_endpoint *ep; |
@@ -414,15 +457,19 @@ static struct usb_host_endpoint *get_isoc_ep(struct gspca_dev *gspca_dev) | |||
414 | ep = NULL; | 457 | ep = NULL; |
415 | i = gspca_dev->alt; /* previous alt setting */ | 458 | i = gspca_dev->alt; /* previous alt setting */ |
416 | while (--i > 0) { /* alt 0 is unusable */ | 459 | while (--i > 0) { /* alt 0 is unusable */ |
417 | ep = alt_isoc(&intf->altsetting[i], gspca_dev->cam.epaddr); | 460 | ep = alt_xfer(&intf->altsetting[i], |
461 | gspca_dev->cam.epaddr, | ||
462 | gspca_dev->bulk | ||
463 | ? USB_ENDPOINT_XFER_BULK | ||
464 | : USB_ENDPOINT_XFER_ISOC); | ||
418 | if (ep) | 465 | if (ep) |
419 | break; | 466 | break; |
420 | } | 467 | } |
421 | if (ep == NULL) { | 468 | if (ep == NULL) { |
422 | err("no ISOC endpoint found"); | 469 | err("no transfer endpoint found"); |
423 | return NULL; | 470 | return NULL; |
424 | } | 471 | } |
425 | PDEBUG(D_STREAM, "use ISOC alt %d ep 0x%02x", | 472 | PDEBUG(D_STREAM, "use alt %d ep 0x%02x", |
426 | i, ep->desc.bEndpointAddress); | 473 | i, ep->desc.bEndpointAddress); |
427 | ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i); | 474 | ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i); |
428 | if (ret < 0) { | 475 | if (ret < 0) { |
@@ -434,7 +481,7 @@ static struct usb_host_endpoint *get_isoc_ep(struct gspca_dev *gspca_dev) | |||
434 | } | 481 | } |
435 | 482 | ||
436 | /* | 483 | /* |
437 | * create the isochronous URBs | 484 | * create the URBs for image transfer |
438 | */ | 485 | */ |
439 | static int create_urbs(struct gspca_dev *gspca_dev, | 486 | static int create_urbs(struct gspca_dev *gspca_dev, |
440 | struct usb_host_endpoint *ep) | 487 | struct usb_host_endpoint *ep) |
@@ -447,12 +494,20 @@ static int create_urbs(struct gspca_dev *gspca_dev, | |||
447 | 494 | ||
448 | /* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */ | 495 | /* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */ |
449 | psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); | 496 | psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); |
450 | npkt = ISO_MAX_SIZE / psize; | 497 | if (!gspca_dev->bulk) { |
451 | if (npkt > ISO_MAX_PKT) | 498 | npkt = ISO_MAX_SIZE / psize; |
452 | npkt = ISO_MAX_PKT; | 499 | if (npkt > ISO_MAX_PKT) |
453 | bsize = psize * npkt; | 500 | npkt = ISO_MAX_PKT; |
454 | PDEBUG(D_STREAM, | 501 | bsize = psize * npkt; |
455 | "isoc %d pkts size %d (bsize:%d)", npkt, psize, bsize); | 502 | PDEBUG(D_STREAM, |
503 | "isoc %d pkts size %d = bsize:%d", | ||
504 | npkt, psize, bsize); | ||
505 | } else { | ||
506 | npkt = 0; | ||
507 | bsize = psize; | ||
508 | PDEBUG(D_STREAM, "bulk bsize:%d", bsize); | ||
509 | } | ||
510 | |||
456 | nurbs = DEF_NURBS; | 511 | nurbs = DEF_NURBS; |
457 | gspca_dev->nurbs = nurbs; | 512 | gspca_dev->nurbs = nurbs; |
458 | for (n = 0; n < nurbs; n++) { | 513 | for (n = 0; n < nurbs; n++) { |
@@ -476,17 +531,23 @@ static int create_urbs(struct gspca_dev *gspca_dev, | |||
476 | gspca_dev->urb[n] = urb; | 531 | gspca_dev->urb[n] = urb; |
477 | urb->dev = gspca_dev->dev; | 532 | urb->dev = gspca_dev->dev; |
478 | urb->context = gspca_dev; | 533 | urb->context = gspca_dev; |
479 | urb->pipe = usb_rcvisocpipe(gspca_dev->dev, | ||
480 | ep->desc.bEndpointAddress); | ||
481 | urb->transfer_flags = URB_ISO_ASAP | ||
482 | | URB_NO_TRANSFER_DMA_MAP; | ||
483 | urb->interval = ep->desc.bInterval; | ||
484 | urb->complete = isoc_irq; | ||
485 | urb->number_of_packets = npkt; | ||
486 | urb->transfer_buffer_length = bsize; | 534 | urb->transfer_buffer_length = bsize; |
487 | for (i = 0; i < npkt; i++) { | 535 | if (npkt != 0) { /* ISOC */ |
488 | urb->iso_frame_desc[i].length = psize; | 536 | urb->pipe = usb_rcvisocpipe(gspca_dev->dev, |
489 | urb->iso_frame_desc[i].offset = psize * i; | 537 | ep->desc.bEndpointAddress); |
538 | urb->transfer_flags = URB_ISO_ASAP | ||
539 | | URB_NO_TRANSFER_DMA_MAP; | ||
540 | urb->interval = ep->desc.bInterval; | ||
541 | urb->complete = isoc_irq; | ||
542 | urb->number_of_packets = npkt; | ||
543 | for (i = 0; i < npkt; i++) { | ||
544 | urb->iso_frame_desc[i].length = psize; | ||
545 | urb->iso_frame_desc[i].offset = psize * i; | ||
546 | } | ||
547 | } else { /* bulk */ | ||
548 | urb->pipe = usb_rcvbulkpipe(gspca_dev->dev, | ||
549 | ep->desc.bEndpointAddress), | ||
550 | urb->complete = bulk_irq; | ||
490 | } | 551 | } |
491 | } | 552 | } |
492 | return 0; | 553 | return 0; |
@@ -508,7 +569,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) | |||
508 | gspca_dev->alt = gspca_dev->nbalt; | 569 | gspca_dev->alt = gspca_dev->nbalt; |
509 | for (;;) { | 570 | for (;;) { |
510 | PDEBUG(D_STREAM, "init transfer alt %d", gspca_dev->alt); | 571 | PDEBUG(D_STREAM, "init transfer alt %d", gspca_dev->alt); |
511 | ep = get_isoc_ep(gspca_dev); | 572 | ep = get_ep(gspca_dev); |
512 | if (ep == NULL) { | 573 | if (ep == NULL) { |
513 | ret = -EIO; | 574 | ret = -EIO; |
514 | goto out; | 575 | goto out; |