diff options
author | Frank Schaefer <fschaefer.oss@googlemail.com> | 2013-03-26 12:38:38 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-03-28 16:47:57 -0400 |
commit | e507e0e513c41ccfc68d6f619faa212f97c88ddb (patch) | |
tree | 29d61558f2a92148b8d869bdec1fc55f0cfb067c /drivers/media/usb | |
parent | 736a320bd285b4b90cdc49d1506461518979f240 (diff) |
[media] em28xx: add support for em25xx/em276x/em277x/em278x frame data processing
The em25xx/em276x/em277x/em278x frame data format is different to the one used
by the em2710/em2750/em28xx chips.
With the recent cleanups and reorganization of the frame data processing code it
can be easily extended to support these devices.
Signed-off-by: Frank Schäfer <fschaefer.oss@googlemail.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/usb')
-rw-r--r-- | drivers/media/usb/em28xx/em28xx-video.c | 74 |
1 files changed, 73 insertions, 1 deletions
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index b1817231f50c..ef1959bbd23f 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c | |||
@@ -76,6 +76,16 @@ MODULE_DESCRIPTION(DRIVER_DESC); | |||
76 | MODULE_LICENSE("GPL"); | 76 | MODULE_LICENSE("GPL"); |
77 | MODULE_VERSION(EM28XX_VERSION); | 77 | MODULE_VERSION(EM28XX_VERSION); |
78 | 78 | ||
79 | |||
80 | #define EM25XX_FRMDATAHDR_BYTE1 0x02 | ||
81 | #define EM25XX_FRMDATAHDR_BYTE2_STILL_IMAGE 0x20 | ||
82 | #define EM25XX_FRMDATAHDR_BYTE2_FRAME_END 0x02 | ||
83 | #define EM25XX_FRMDATAHDR_BYTE2_FRAME_ID 0x01 | ||
84 | #define EM25XX_FRMDATAHDR_BYTE2_MASK (EM25XX_FRMDATAHDR_BYTE2_STILL_IMAGE | \ | ||
85 | EM25XX_FRMDATAHDR_BYTE2_FRAME_END | \ | ||
86 | EM25XX_FRMDATAHDR_BYTE2_FRAME_ID) | ||
87 | |||
88 | |||
79 | static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U }; | 89 | static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U }; |
80 | static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U }; | 90 | static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U }; |
81 | static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U }; | 91 | static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U }; |
@@ -408,6 +418,62 @@ static inline void process_frame_data_em28xx(struct em28xx *dev, | |||
408 | em28xx_copy_video(dev, buf, data_pkt, data_len); | 418 | em28xx_copy_video(dev, buf, data_pkt, data_len); |
409 | } | 419 | } |
410 | 420 | ||
421 | /* | ||
422 | * Process data packet according to the em25xx/em276x/7x/8x frame data format | ||
423 | */ | ||
424 | static inline void process_frame_data_em25xx(struct em28xx *dev, | ||
425 | unsigned char *data_pkt, | ||
426 | unsigned int data_len) | ||
427 | { | ||
428 | struct em28xx_buffer *buf = dev->usb_ctl.vid_buf; | ||
429 | struct em28xx_dmaqueue *dmaq = &dev->vidq; | ||
430 | bool frame_end = 0; | ||
431 | |||
432 | /* Check for header */ | ||
433 | /* NOTE: at least with bulk transfers, only the first packet | ||
434 | * has a header and has always set the FRAME_END bit */ | ||
435 | if (data_len >= 2) { /* em25xx header is only 2 bytes long */ | ||
436 | if ((data_pkt[0] == EM25XX_FRMDATAHDR_BYTE1) && | ||
437 | ((data_pkt[1] & ~EM25XX_FRMDATAHDR_BYTE2_MASK) == 0x00)) { | ||
438 | dev->top_field = !(data_pkt[1] & | ||
439 | EM25XX_FRMDATAHDR_BYTE2_FRAME_ID); | ||
440 | frame_end = data_pkt[1] & | ||
441 | EM25XX_FRMDATAHDR_BYTE2_FRAME_END; | ||
442 | data_pkt += 2; | ||
443 | data_len -= 2; | ||
444 | } | ||
445 | |||
446 | /* Finish field and prepare next (BULK only) */ | ||
447 | if (dev->analog_xfer_bulk && frame_end) { | ||
448 | buf = finish_field_prepare_next(dev, buf, dmaq); | ||
449 | dev->usb_ctl.vid_buf = buf; | ||
450 | } | ||
451 | /* NOTE: in ISOC mode when a new frame starts and buf==NULL, | ||
452 | * we COULD already prepare a buffer here to avoid skipping the | ||
453 | * first frame. | ||
454 | */ | ||
455 | } | ||
456 | |||
457 | /* Copy data */ | ||
458 | if (buf != NULL && data_len > 0) | ||
459 | em28xx_copy_video(dev, buf, data_pkt, data_len); | ||
460 | |||
461 | /* Finish frame (ISOC only) => avoids lag of 1 frame */ | ||
462 | if (!dev->analog_xfer_bulk && frame_end) { | ||
463 | buf = finish_field_prepare_next(dev, buf, dmaq); | ||
464 | dev->usb_ctl.vid_buf = buf; | ||
465 | } | ||
466 | |||
467 | /* NOTE: Tested with USB bulk transfers only ! | ||
468 | * The wording in the datasheet suggests that isoc might work different. | ||
469 | * The current code assumes that with isoc transfers each packet has a | ||
470 | * header like with the other em28xx devices. | ||
471 | */ | ||
472 | /* NOTE: Support for interlaced mode is pure theory. It has not been | ||
473 | * tested and it is unknown if these devices actually support it. */ | ||
474 | /* NOTE: No VBI support yet (these chips likely do not support VBI). */ | ||
475 | } | ||
476 | |||
411 | /* Processes and copies the URB data content (video and VBI data) */ | 477 | /* Processes and copies the URB data content (video and VBI data) */ |
412 | static inline int em28xx_urb_data_copy(struct em28xx *dev, struct urb *urb) | 478 | static inline int em28xx_urb_data_copy(struct em28xx *dev, struct urb *urb) |
413 | { | 479 | { |
@@ -460,7 +526,13 @@ static inline int em28xx_urb_data_copy(struct em28xx *dev, struct urb *urb) | |||
460 | continue; | 526 | continue; |
461 | } | 527 | } |
462 | 528 | ||
463 | process_frame_data_em28xx(dev, usb_data_pkt, usb_data_len); | 529 | if (dev->is_em25xx) |
530 | process_frame_data_em25xx(dev, | ||
531 | usb_data_pkt, usb_data_len); | ||
532 | else | ||
533 | process_frame_data_em28xx(dev, | ||
534 | usb_data_pkt, usb_data_len); | ||
535 | |||
464 | } | 536 | } |
465 | return 1; | 537 | return 1; |
466 | } | 538 | } |