aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/gspca
diff options
context:
space:
mode:
authorJean-Francois Moine <moinejf@free.fr>2008-09-04 06:01:50 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-10-12 07:36:58 -0400
commit0be01004ddc0694d8c592fff05ab88dabd45f476 (patch)
tree0166291c8d3e5c443adb3229c323a64f9bd662ee /drivers/media/video/gspca
parentd45b9b8ab43c8973a9630ac54f4ede6c3e009f9e (diff)
V4L/DVB (8910): gspca: Add support of image transfer by bulk and minor change.
- image transfer by bulk - set the max number of transfer URS's to 4 (was 16) Signed-off-by: Jean-Francois Moine <moinejf@free.fr> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/gspca')
-rw-r--r--drivers/media/video/gspca/gspca.c115
-rw-r--r--drivers/media/video/gspca/gspca.h5
2 files changed, 91 insertions, 29 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 */
183static 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 */
379static struct usb_host_endpoint *alt_isoc(struct usb_host_interface *alt, 421static 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 */
407static struct usb_host_endpoint *get_isoc_ep(struct gspca_dev *gspca_dev) 450static 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 */
439static int create_urbs(struct gspca_dev *gspca_dev, 486static 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;
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h
index c17625cff9ba..78a35a88cf97 100644
--- a/drivers/media/video/gspca/gspca.h
+++ b/drivers/media/video/gspca/gspca.h
@@ -49,8 +49,8 @@ extern int gspca_debug;
49 } while (0) 49 } while (0)
50 50
51#define GSPCA_MAX_FRAMES 16 /* maximum number of video frame buffers */ 51#define GSPCA_MAX_FRAMES 16 /* maximum number of video frame buffers */
52/* ISOC transfers */ 52/* image transfers */
53#define MAX_NURBS 16 /* max number of URBs */ 53#define MAX_NURBS 4 /* max number of URBs */
54#define ISO_MAX_PKT 32 /* max number of packets in an ISOC transfer */ 54#define ISO_MAX_PKT 32 /* max number of packets in an ISOC transfer */
55#define ISO_MAX_SIZE 0x8000 /* max size of one URB buffer (32 Kb) */ 55#define ISO_MAX_SIZE 0x8000 /* max size of one URB buffer (32 Kb) */
56 56
@@ -143,6 +143,7 @@ struct gspca_dev {
143 143
144 __u8 iface; /* USB interface number */ 144 __u8 iface; /* USB interface number */
145 __u8 alt; /* USB alternate setting */ 145 __u8 alt; /* USB alternate setting */
146 __u8 bulk; /* image transfer by isoc (0) or bulk (1) */
146 __u8 curr_mode; /* current camera mode */ 147 __u8 curr_mode; /* current camera mode */
147 __u32 pixfmt; /* current mode parameters */ 148 __u32 pixfmt; /* current mode parameters */
148 __u16 width; 149 __u16 width;