diff options
Diffstat (limited to 'drivers/media/video/cx18')
-rw-r--r-- | drivers/media/video/cx18/Kconfig | 4 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-cards.c | 18 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-cards.h | 2 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-driver.c | 27 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-driver.h | 25 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-fileops.c | 70 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-fileops.h | 2 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-ioctl.c | 144 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-mailbox.c | 58 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-streams.c | 177 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-version.h | 2 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx23418.h | 6 |
12 files changed, 517 insertions, 18 deletions
diff --git a/drivers/media/video/cx18/Kconfig b/drivers/media/video/cx18/Kconfig index d9d2f6ad6ff..53b3c770257 100644 --- a/drivers/media/video/cx18/Kconfig +++ b/drivers/media/video/cx18/Kconfig | |||
@@ -2,6 +2,7 @@ config VIDEO_CX18 | |||
2 | tristate "Conexant cx23418 MPEG encoder support" | 2 | tristate "Conexant cx23418 MPEG encoder support" |
3 | depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL | 3 | depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL |
4 | select I2C_ALGOBIT | 4 | select I2C_ALGOBIT |
5 | select VIDEOBUF_VMALLOC | ||
5 | depends on RC_CORE | 6 | depends on RC_CORE |
6 | select VIDEO_TUNER | 7 | select VIDEO_TUNER |
7 | select VIDEO_TVEEPROM | 8 | select VIDEO_TVEEPROM |
@@ -9,6 +10,9 @@ config VIDEO_CX18 | |||
9 | select VIDEO_CS5345 | 10 | select VIDEO_CS5345 |
10 | select DVB_S5H1409 if !DVB_FE_CUSTOMISE | 11 | select DVB_S5H1409 if !DVB_FE_CUSTOMISE |
11 | select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE | 12 | select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE |
13 | select DVB_S5H1411 if !DVB_FE_CUSTOMISE | ||
14 | select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE | ||
15 | select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE | ||
12 | ---help--- | 16 | ---help--- |
13 | This is a video4linux driver for Conexant cx23418 based | 17 | This is a video4linux driver for Conexant cx23418 based |
14 | PCI combo video recorder devices. | 18 | PCI combo video recorder devices. |
diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c index 68ad1963f42..c07c849b1aa 100644 --- a/drivers/media/video/cx18/cx18-cards.c +++ b/drivers/media/video/cx18/cx18-cards.c | |||
@@ -39,6 +39,16 @@ static struct cx18_card_tuner_i2c cx18_i2c_std = { | |||
39 | .tv = { 0x61, 0x60, I2C_CLIENT_END }, | 39 | .tv = { 0x61, 0x60, I2C_CLIENT_END }, |
40 | }; | 40 | }; |
41 | 41 | ||
42 | /* | ||
43 | * usual i2c tuner addresses to probe with additional demod address for | ||
44 | * an NXP TDA8295 at 0x42 (N.B. it can possibly be at 0x4b or 0x4c too). | ||
45 | */ | ||
46 | static struct cx18_card_tuner_i2c cx18_i2c_nxp = { | ||
47 | .radio = { I2C_CLIENT_END }, | ||
48 | .demod = { 0x42, 0x43, I2C_CLIENT_END }, | ||
49 | .tv = { 0x61, 0x60, I2C_CLIENT_END }, | ||
50 | }; | ||
51 | |||
42 | /* Please add new PCI IDs to: http://pci-ids.ucw.cz/ | 52 | /* Please add new PCI IDs to: http://pci-ids.ucw.cz/ |
43 | This keeps the PCI ID database up to date. Note that the entries | 53 | This keeps the PCI ID database up to date. Note that the entries |
44 | must be added under vendor 0x4444 (Conexant) as subsystem IDs. | 54 | must be added under vendor 0x4444 (Conexant) as subsystem IDs. |
@@ -131,15 +141,15 @@ static const struct cx18_card cx18_card_hvr1600_s5h1411 = { | |||
131 | .tune_lane = 0, | 141 | .tune_lane = 0, |
132 | .initial_emrs = 0, | 142 | .initial_emrs = 0, |
133 | }, | 143 | }, |
134 | .gpio_init.initial_value = 0x3001, | 144 | .gpio_init.initial_value = 0x3801, |
135 | .gpio_init.direction = 0x3001, | 145 | .gpio_init.direction = 0x3801, |
136 | .gpio_i2c_slave_reset = { | 146 | .gpio_i2c_slave_reset = { |
137 | .active_lo_mask = 0x3001, | 147 | .active_lo_mask = 0x3801, |
138 | .msecs_asserted = 10, | 148 | .msecs_asserted = 10, |
139 | .msecs_recovery = 40, | 149 | .msecs_recovery = 40, |
140 | .ir_reset_mask = 0x0001, | 150 | .ir_reset_mask = 0x0001, |
141 | }, | 151 | }, |
142 | .i2c = &cx18_i2c_std, | 152 | .i2c = &cx18_i2c_nxp, |
143 | }; | 153 | }; |
144 | 154 | ||
145 | static const struct cx18_card cx18_card_hvr1600_samsung = { | 155 | static const struct cx18_card cx18_card_hvr1600_samsung = { |
diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h index 3e750068f27..add7391ecab 100644 --- a/drivers/media/video/cx18/cx18-cards.h +++ b/drivers/media/video/cx18/cx18-cards.h | |||
@@ -109,7 +109,7 @@ struct cx18_card_tuner { | |||
109 | 109 | ||
110 | struct cx18_card_tuner_i2c { | 110 | struct cx18_card_tuner_i2c { |
111 | unsigned short radio[2];/* radio tuner i2c address to probe */ | 111 | unsigned short radio[2];/* radio tuner i2c address to probe */ |
112 | unsigned short demod[2];/* demodulator i2c address to probe */ | 112 | unsigned short demod[3];/* demodulator i2c address to probe */ |
113 | unsigned short tv[4]; /* tv tuner i2c addresses to probe */ | 113 | unsigned short tv[4]; /* tv tuner i2c addresses to probe */ |
114 | }; | 114 | }; |
115 | 115 | ||
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index 321c1b79794..9e2f870f425 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c | |||
@@ -423,7 +423,16 @@ static void cx18_process_eeprom(struct cx18 *cx) | |||
423 | return; | 423 | return; |
424 | 424 | ||
425 | /* autodetect tuner standard */ | 425 | /* autodetect tuner standard */ |
426 | if (tv.tuner_formats & V4L2_STD_PAL) { | 426 | #define TVEEPROM_TUNER_FORMAT_ALL (V4L2_STD_B | V4L2_STD_GH | \ |
427 | V4L2_STD_MN | \ | ||
428 | V4L2_STD_PAL_I | \ | ||
429 | V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC | \ | ||
430 | V4L2_STD_DK) | ||
431 | if ((tv.tuner_formats & TVEEPROM_TUNER_FORMAT_ALL) | ||
432 | == TVEEPROM_TUNER_FORMAT_ALL) { | ||
433 | CX18_DEBUG_INFO("Worldwide tuner detected\n"); | ||
434 | cx->std = V4L2_STD_ALL; | ||
435 | } else if (tv.tuner_formats & V4L2_STD_PAL) { | ||
427 | CX18_DEBUG_INFO("PAL tuner detected\n"); | 436 | CX18_DEBUG_INFO("PAL tuner detected\n"); |
428 | cx->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H; | 437 | cx->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H; |
429 | } else if (tv.tuner_formats & V4L2_STD_NTSC) { | 438 | } else if (tv.tuner_formats & V4L2_STD_NTSC) { |
@@ -818,7 +827,7 @@ static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev, | |||
818 | cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; | 827 | cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; |
819 | pci_write_config_word(pci_dev, PCI_COMMAND, cmd); | 828 | pci_write_config_word(pci_dev, PCI_COMMAND, cmd); |
820 | 829 | ||
821 | pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &cx->card_rev); | 830 | cx->card_rev = pci_dev->revision; |
822 | pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency); | 831 | pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency); |
823 | 832 | ||
824 | if (pci_latency < 64 && cx18_pci_latency) { | 833 | if (pci_latency < 64 && cx18_pci_latency) { |
@@ -1001,7 +1010,15 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev, | |||
1001 | if (cx->card->hw_all & CX18_HW_TVEEPROM) { | 1010 | if (cx->card->hw_all & CX18_HW_TVEEPROM) { |
1002 | /* Based on the model number the cardtype may be changed. | 1011 | /* Based on the model number the cardtype may be changed. |
1003 | The PCI IDs are not always reliable. */ | 1012 | The PCI IDs are not always reliable. */ |
1013 | const struct cx18_card *orig_card = cx->card; | ||
1004 | cx18_process_eeprom(cx); | 1014 | cx18_process_eeprom(cx); |
1015 | |||
1016 | if (cx->card != orig_card) { | ||
1017 | /* Changed the cardtype; re-reset the I2C chips */ | ||
1018 | cx18_gpio_init(cx); | ||
1019 | cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL, | ||
1020 | core, reset, (u32) CX18_GPIO_RESET_I2C); | ||
1021 | } | ||
1005 | } | 1022 | } |
1006 | if (cx->card->comment) | 1023 | if (cx->card->comment) |
1007 | CX18_INFO("%s", cx->card->comment); | 1024 | CX18_INFO("%s", cx->card->comment); |
@@ -1087,6 +1104,8 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev, | |||
1087 | /* The tuner is fixed to the standard. The other inputs (e.g. S-Video) | 1104 | /* The tuner is fixed to the standard. The other inputs (e.g. S-Video) |
1088 | are not. */ | 1105 | are not. */ |
1089 | cx->tuner_std = cx->std; | 1106 | cx->tuner_std = cx->std; |
1107 | if (cx->std == V4L2_STD_ALL) | ||
1108 | cx->std = V4L2_STD_NTSC_M; | ||
1090 | 1109 | ||
1091 | retval = cx18_streams_setup(cx); | 1110 | retval = cx18_streams_setup(cx); |
1092 | if (retval) { | 1111 | if (retval) { |
@@ -1133,6 +1152,7 @@ int cx18_init_on_first_open(struct cx18 *cx) | |||
1133 | int fw_retry_count = 3; | 1152 | int fw_retry_count = 3; |
1134 | struct v4l2_frequency vf; | 1153 | struct v4l2_frequency vf; |
1135 | struct cx18_open_id fh; | 1154 | struct cx18_open_id fh; |
1155 | v4l2_std_id std; | ||
1136 | 1156 | ||
1137 | fh.cx = cx; | 1157 | fh.cx = cx; |
1138 | 1158 | ||
@@ -1220,7 +1240,8 @@ int cx18_init_on_first_open(struct cx18 *cx) | |||
1220 | /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code | 1240 | /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code |
1221 | in one place. */ | 1241 | in one place. */ |
1222 | cx->std++; /* Force full standard initialization */ | 1242 | cx->std++; /* Force full standard initialization */ |
1223 | cx18_s_std(NULL, &fh, &cx->tuner_std); | 1243 | std = (cx->tuner_std == V4L2_STD_ALL) ? V4L2_STD_NTSC_M : cx->tuner_std; |
1244 | cx18_s_std(NULL, &fh, &std); | ||
1224 | cx18_s_frequency(NULL, &fh, &vf); | 1245 | cx18_s_frequency(NULL, &fh, &vf); |
1225 | return 0; | 1246 | return 0; |
1226 | } | 1247 | } |
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h index b86a740c68d..086427288de 100644 --- a/drivers/media/video/cx18/cx18-driver.h +++ b/drivers/media/video/cx18/cx18-driver.h | |||
@@ -65,6 +65,10 @@ | |||
65 | #include "dvb_net.h" | 65 | #include "dvb_net.h" |
66 | #include "dvbdev.h" | 66 | #include "dvbdev.h" |
67 | 67 | ||
68 | /* Videobuf / YUV support */ | ||
69 | #include <media/videobuf-core.h> | ||
70 | #include <media/videobuf-vmalloc.h> | ||
71 | |||
68 | #ifndef CONFIG_PCI | 72 | #ifndef CONFIG_PCI |
69 | # error "This driver requires kernel PCI support." | 73 | # error "This driver requires kernel PCI support." |
70 | #endif | 74 | #endif |
@@ -403,6 +407,23 @@ struct cx18_stream { | |||
403 | struct cx18_queue q_idle; /* idle - not in rotation */ | 407 | struct cx18_queue q_idle; /* idle - not in rotation */ |
404 | 408 | ||
405 | struct work_struct out_work_order; | 409 | struct work_struct out_work_order; |
410 | |||
411 | /* Videobuf for YUV video */ | ||
412 | u32 pixelformat; | ||
413 | struct list_head vb_capture; /* video capture queue */ | ||
414 | spinlock_t vb_lock; | ||
415 | struct timer_list vb_timeout; | ||
416 | |||
417 | struct videobuf_queue vbuf_q; | ||
418 | spinlock_t vbuf_q_lock; /* Protect vbuf_q */ | ||
419 | enum v4l2_buf_type vb_type; | ||
420 | }; | ||
421 | |||
422 | struct cx18_videobuf_buffer { | ||
423 | /* Common video buffer sub-system struct */ | ||
424 | struct videobuf_buffer vb; | ||
425 | v4l2_std_id tvnorm; /* selected tv norm */ | ||
426 | u32 bytes_used; | ||
406 | }; | 427 | }; |
407 | 428 | ||
408 | struct cx18_open_id { | 429 | struct cx18_open_id { |
@@ -410,6 +431,10 @@ struct cx18_open_id { | |||
410 | u32 open_id; | 431 | u32 open_id; |
411 | int type; | 432 | int type; |
412 | struct cx18 *cx; | 433 | struct cx18 *cx; |
434 | |||
435 | struct videobuf_queue vbuf_q; | ||
436 | spinlock_t s_lock; /* Protect vbuf_q */ | ||
437 | enum v4l2_buf_type vb_type; | ||
413 | }; | 438 | }; |
414 | 439 | ||
415 | static inline struct cx18_open_id *fh2id(struct v4l2_fh *fh) | 440 | static inline struct cx18_open_id *fh2id(struct v4l2_fh *fh) |
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c index e9802d99439..07411f34885 100644 --- a/drivers/media/video/cx18/cx18-fileops.c +++ b/drivers/media/video/cx18/cx18-fileops.c | |||
@@ -597,6 +597,13 @@ ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count, | |||
597 | mutex_unlock(&cx->serialize_lock); | 597 | mutex_unlock(&cx->serialize_lock); |
598 | if (rc) | 598 | if (rc) |
599 | return rc; | 599 | return rc; |
600 | |||
601 | if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) && | ||
602 | (id->type == CX18_ENC_STREAM_TYPE_YUV)) { | ||
603 | return videobuf_read_stream(&s->vbuf_q, buf, count, pos, 0, | ||
604 | filp->f_flags & O_NONBLOCK); | ||
605 | } | ||
606 | |||
600 | return cx18_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK); | 607 | return cx18_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK); |
601 | } | 608 | } |
602 | 609 | ||
@@ -622,6 +629,15 @@ unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait) | |||
622 | CX18_DEBUG_FILE("Encoder poll started capture\n"); | 629 | CX18_DEBUG_FILE("Encoder poll started capture\n"); |
623 | } | 630 | } |
624 | 631 | ||
632 | if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) && | ||
633 | (id->type == CX18_ENC_STREAM_TYPE_YUV)) { | ||
634 | int videobuf_poll = videobuf_poll_stream(filp, &s->vbuf_q, wait); | ||
635 | if (eof && videobuf_poll == POLLERR) | ||
636 | return POLLHUP; | ||
637 | else | ||
638 | return videobuf_poll; | ||
639 | } | ||
640 | |||
625 | /* add stream's waitq to the poll list */ | 641 | /* add stream's waitq to the poll list */ |
626 | CX18_DEBUG_HI_FILE("Encoder poll\n"); | 642 | CX18_DEBUG_HI_FILE("Encoder poll\n"); |
627 | poll_wait(filp, &s->waitq, wait); | 643 | poll_wait(filp, &s->waitq, wait); |
@@ -633,6 +649,58 @@ unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait) | |||
633 | return 0; | 649 | return 0; |
634 | } | 650 | } |
635 | 651 | ||
652 | int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma) | ||
653 | { | ||
654 | struct cx18_open_id *id = file->private_data; | ||
655 | struct cx18 *cx = id->cx; | ||
656 | struct cx18_stream *s = &cx->streams[id->type]; | ||
657 | int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags); | ||
658 | |||
659 | if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) && | ||
660 | (id->type == CX18_ENC_STREAM_TYPE_YUV)) { | ||
661 | |||
662 | /* Start a capture if there is none */ | ||
663 | if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) { | ||
664 | int rc; | ||
665 | |||
666 | mutex_lock(&cx->serialize_lock); | ||
667 | rc = cx18_start_capture(id); | ||
668 | mutex_unlock(&cx->serialize_lock); | ||
669 | if (rc) { | ||
670 | CX18_DEBUG_INFO( | ||
671 | "Could not start capture for %s (%d)\n", | ||
672 | s->name, rc); | ||
673 | return -EINVAL; | ||
674 | } | ||
675 | CX18_DEBUG_FILE("Encoder mmap started capture\n"); | ||
676 | } | ||
677 | |||
678 | return videobuf_mmap_mapper(&s->vbuf_q, vma); | ||
679 | } | ||
680 | |||
681 | return -EINVAL; | ||
682 | } | ||
683 | |||
684 | void cx18_vb_timeout(unsigned long data) | ||
685 | { | ||
686 | struct cx18_stream *s = (struct cx18_stream *)data; | ||
687 | struct cx18_videobuf_buffer *buf; | ||
688 | unsigned long flags; | ||
689 | |||
690 | /* Return all of the buffers in error state, so the vbi/vid inode | ||
691 | * can return from blocking. | ||
692 | */ | ||
693 | spin_lock_irqsave(&s->vb_lock, flags); | ||
694 | while (!list_empty(&s->vb_capture)) { | ||
695 | buf = list_entry(s->vb_capture.next, | ||
696 | struct cx18_videobuf_buffer, vb.queue); | ||
697 | list_del(&buf->vb.queue); | ||
698 | buf->vb.state = VIDEOBUF_ERROR; | ||
699 | wake_up(&buf->vb.done); | ||
700 | } | ||
701 | spin_unlock_irqrestore(&s->vb_lock, flags); | ||
702 | } | ||
703 | |||
636 | void cx18_stop_capture(struct cx18_open_id *id, int gop_end) | 704 | void cx18_stop_capture(struct cx18_open_id *id, int gop_end) |
637 | { | 705 | { |
638 | struct cx18 *cx = id->cx; | 706 | struct cx18 *cx = id->cx; |
@@ -716,6 +784,8 @@ int cx18_v4l2_close(struct file *filp) | |||
716 | cx18_release_stream(s); | 784 | cx18_release_stream(s); |
717 | } else { | 785 | } else { |
718 | cx18_stop_capture(id, 0); | 786 | cx18_stop_capture(id, 0); |
787 | if (id->type == CX18_ENC_STREAM_TYPE_YUV) | ||
788 | videobuf_mmap_free(&id->vbuf_q); | ||
719 | } | 789 | } |
720 | kfree(id); | 790 | kfree(id); |
721 | mutex_unlock(&cx->serialize_lock); | 791 | mutex_unlock(&cx->serialize_lock); |
diff --git a/drivers/media/video/cx18/cx18-fileops.h b/drivers/media/video/cx18/cx18-fileops.h index 5c8fcb884f0..b9e5110ad04 100644 --- a/drivers/media/video/cx18/cx18-fileops.h +++ b/drivers/media/video/cx18/cx18-fileops.h | |||
@@ -33,6 +33,8 @@ int cx18_start_capture(struct cx18_open_id *id); | |||
33 | void cx18_stop_capture(struct cx18_open_id *id, int gop_end); | 33 | void cx18_stop_capture(struct cx18_open_id *id, int gop_end); |
34 | void cx18_mute(struct cx18 *cx); | 34 | void cx18_mute(struct cx18 *cx); |
35 | void cx18_unmute(struct cx18 *cx); | 35 | void cx18_unmute(struct cx18 *cx); |
36 | int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma); | ||
37 | void cx18_vb_timeout(unsigned long data); | ||
36 | 38 | ||
37 | /* Shared with cx18-alsa module */ | 39 | /* Shared with cx18-alsa module */ |
38 | int cx18_claim_stream(struct cx18_open_id *id, int type); | 40 | int cx18_claim_stream(struct cx18_open_id *id, int type); |
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c index 4f041c033c5..1933d4d11bf 100644 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ b/drivers/media/video/cx18/cx18-ioctl.c | |||
@@ -150,6 +150,7 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh, | |||
150 | { | 150 | { |
151 | struct cx18_open_id *id = fh2id(fh); | 151 | struct cx18_open_id *id = fh2id(fh); |
152 | struct cx18 *cx = id->cx; | 152 | struct cx18 *cx = id->cx; |
153 | struct cx18_stream *s = &cx->streams[id->type]; | ||
153 | struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; | 154 | struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; |
154 | 155 | ||
155 | pixfmt->width = cx->cxhdl.width; | 156 | pixfmt->width = cx->cxhdl.width; |
@@ -158,9 +159,13 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh, | |||
158 | pixfmt->field = V4L2_FIELD_INTERLACED; | 159 | pixfmt->field = V4L2_FIELD_INTERLACED; |
159 | pixfmt->priv = 0; | 160 | pixfmt->priv = 0; |
160 | if (id->type == CX18_ENC_STREAM_TYPE_YUV) { | 161 | if (id->type == CX18_ENC_STREAM_TYPE_YUV) { |
161 | pixfmt->pixelformat = V4L2_PIX_FMT_HM12; | 162 | pixfmt->pixelformat = s->pixelformat; |
162 | /* YUV size is (Y=(h*720) + UV=(h*(720/2))) */ | 163 | /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2))) |
163 | pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2; | 164 | UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */ |
165 | if (s->pixelformat == V4L2_PIX_FMT_HM12) | ||
166 | pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2; | ||
167 | else | ||
168 | pixfmt->sizeimage = pixfmt->height * 720 * 2; | ||
164 | pixfmt->bytesperline = 720; | 169 | pixfmt->bytesperline = 720; |
165 | } else { | 170 | } else { |
166 | pixfmt->pixelformat = V4L2_PIX_FMT_MPEG; | 171 | pixfmt->pixelformat = V4L2_PIX_FMT_MPEG; |
@@ -237,7 +242,6 @@ static int cx18_try_fmt_vid_cap(struct file *file, void *fh, | |||
237 | h = min(h, cx->is_50hz ? 576 : 480); | 242 | h = min(h, cx->is_50hz ? 576 : 480); |
238 | h = max(h, min_h); | 243 | h = max(h, min_h); |
239 | 244 | ||
240 | cx18_g_fmt_vid_cap(file, fh, fmt); | ||
241 | fmt->fmt.pix.width = w; | 245 | fmt->fmt.pix.width = w; |
242 | fmt->fmt.pix.height = h; | 246 | fmt->fmt.pix.height = h; |
243 | return 0; | 247 | return 0; |
@@ -274,6 +278,7 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh, | |||
274 | struct cx18_open_id *id = fh2id(fh); | 278 | struct cx18_open_id *id = fh2id(fh); |
275 | struct cx18 *cx = id->cx; | 279 | struct cx18 *cx = id->cx; |
276 | struct v4l2_mbus_framefmt mbus_fmt; | 280 | struct v4l2_mbus_framefmt mbus_fmt; |
281 | struct cx18_stream *s = &cx->streams[id->type]; | ||
277 | int ret; | 282 | int ret; |
278 | int w, h; | 283 | int w, h; |
279 | 284 | ||
@@ -283,12 +288,15 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh, | |||
283 | w = fmt->fmt.pix.width; | 288 | w = fmt->fmt.pix.width; |
284 | h = fmt->fmt.pix.height; | 289 | h = fmt->fmt.pix.height; |
285 | 290 | ||
286 | if (cx->cxhdl.width == w && cx->cxhdl.height == h) | 291 | if (cx->cxhdl.width == w && cx->cxhdl.height == h && |
292 | s->pixelformat == fmt->fmt.pix.pixelformat) | ||
287 | return 0; | 293 | return 0; |
288 | 294 | ||
289 | if (atomic_read(&cx->ana_capturing) > 0) | 295 | if (atomic_read(&cx->ana_capturing) > 0) |
290 | return -EBUSY; | 296 | return -EBUSY; |
291 | 297 | ||
298 | s->pixelformat = fmt->fmt.pix.pixelformat; | ||
299 | |||
292 | mbus_fmt.width = cx->cxhdl.width = w; | 300 | mbus_fmt.width = cx->cxhdl.width = w; |
293 | mbus_fmt.height = cx->cxhdl.height = h; | 301 | mbus_fmt.height = cx->cxhdl.height = h; |
294 | mbus_fmt.code = V4L2_MBUS_FMT_FIXED; | 302 | mbus_fmt.code = V4L2_MBUS_FMT_FIXED; |
@@ -540,16 +548,19 @@ static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop) | |||
540 | static int cx18_enum_fmt_vid_cap(struct file *file, void *fh, | 548 | static int cx18_enum_fmt_vid_cap(struct file *file, void *fh, |
541 | struct v4l2_fmtdesc *fmt) | 549 | struct v4l2_fmtdesc *fmt) |
542 | { | 550 | { |
543 | static struct v4l2_fmtdesc formats[] = { | 551 | static const struct v4l2_fmtdesc formats[] = { |
544 | { 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0, | 552 | { 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0, |
545 | "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 } | 553 | "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 } |
546 | }, | 554 | }, |
547 | { 1, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FMT_FLAG_COMPRESSED, | 555 | { 1, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FMT_FLAG_COMPRESSED, |
548 | "MPEG", V4L2_PIX_FMT_MPEG, { 0, 0, 0, 0 } | 556 | "MPEG", V4L2_PIX_FMT_MPEG, { 0, 0, 0, 0 } |
549 | } | 557 | }, |
558 | { 2, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0, | ||
559 | "UYVY 4:2:2", V4L2_PIX_FMT_UYVY, { 0, 0, 0, 0 } | ||
560 | }, | ||
550 | }; | 561 | }; |
551 | 562 | ||
552 | if (fmt->index > 1) | 563 | if (fmt->index > ARRAY_SIZE(formats) - 1) |
553 | return -EINVAL; | 564 | return -EINVAL; |
554 | *fmt = formats[fmt->index]; | 565 | *fmt = formats[fmt->index]; |
555 | return 0; | 566 | return 0; |
@@ -863,6 +874,117 @@ static int cx18_g_enc_index(struct file *file, void *fh, | |||
863 | return 0; | 874 | return 0; |
864 | } | 875 | } |
865 | 876 | ||
877 | static struct videobuf_queue *cx18_vb_queue(struct cx18_open_id *id) | ||
878 | { | ||
879 | struct videobuf_queue *q = NULL; | ||
880 | struct cx18 *cx = id->cx; | ||
881 | struct cx18_stream *s = &cx->streams[id->type]; | ||
882 | |||
883 | switch (s->vb_type) { | ||
884 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
885 | q = &s->vbuf_q; | ||
886 | break; | ||
887 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
888 | break; | ||
889 | default: | ||
890 | break; | ||
891 | } | ||
892 | return q; | ||
893 | } | ||
894 | |||
895 | static int cx18_streamon(struct file *file, void *priv, | ||
896 | enum v4l2_buf_type type) | ||
897 | { | ||
898 | struct cx18_open_id *id = file->private_data; | ||
899 | struct cx18 *cx = id->cx; | ||
900 | struct cx18_stream *s = &cx->streams[id->type]; | ||
901 | |||
902 | /* Start the hardware only if we're the video device */ | ||
903 | if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && | ||
904 | (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) | ||
905 | return -EINVAL; | ||
906 | |||
907 | if (id->type != CX18_ENC_STREAM_TYPE_YUV) | ||
908 | return -EINVAL; | ||
909 | |||
910 | /* Establish a buffer timeout */ | ||
911 | mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies); | ||
912 | |||
913 | return videobuf_streamon(cx18_vb_queue(id)); | ||
914 | } | ||
915 | |||
916 | static int cx18_streamoff(struct file *file, void *priv, | ||
917 | enum v4l2_buf_type type) | ||
918 | { | ||
919 | struct cx18_open_id *id = file->private_data; | ||
920 | struct cx18 *cx = id->cx; | ||
921 | struct cx18_stream *s = &cx->streams[id->type]; | ||
922 | |||
923 | /* Start the hardware only if we're the video device */ | ||
924 | if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && | ||
925 | (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) | ||
926 | return -EINVAL; | ||
927 | |||
928 | if (id->type != CX18_ENC_STREAM_TYPE_YUV) | ||
929 | return -EINVAL; | ||
930 | |||
931 | return videobuf_streamoff(cx18_vb_queue(id)); | ||
932 | } | ||
933 | |||
934 | static int cx18_reqbufs(struct file *file, void *priv, | ||
935 | struct v4l2_requestbuffers *rb) | ||
936 | { | ||
937 | struct cx18_open_id *id = file->private_data; | ||
938 | struct cx18 *cx = id->cx; | ||
939 | struct cx18_stream *s = &cx->streams[id->type]; | ||
940 | |||
941 | if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && | ||
942 | (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) | ||
943 | return -EINVAL; | ||
944 | |||
945 | return videobuf_reqbufs(cx18_vb_queue(id), rb); | ||
946 | } | ||
947 | |||
948 | static int cx18_querybuf(struct file *file, void *priv, | ||
949 | struct v4l2_buffer *b) | ||
950 | { | ||
951 | struct cx18_open_id *id = file->private_data; | ||
952 | struct cx18 *cx = id->cx; | ||
953 | struct cx18_stream *s = &cx->streams[id->type]; | ||
954 | |||
955 | if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && | ||
956 | (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) | ||
957 | return -EINVAL; | ||
958 | |||
959 | return videobuf_querybuf(cx18_vb_queue(id), b); | ||
960 | } | ||
961 | |||
962 | static int cx18_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) | ||
963 | { | ||
964 | struct cx18_open_id *id = file->private_data; | ||
965 | struct cx18 *cx = id->cx; | ||
966 | struct cx18_stream *s = &cx->streams[id->type]; | ||
967 | |||
968 | if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && | ||
969 | (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) | ||
970 | return -EINVAL; | ||
971 | |||
972 | return videobuf_qbuf(cx18_vb_queue(id), b); | ||
973 | } | ||
974 | |||
975 | static int cx18_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) | ||
976 | { | ||
977 | struct cx18_open_id *id = file->private_data; | ||
978 | struct cx18 *cx = id->cx; | ||
979 | struct cx18_stream *s = &cx->streams[id->type]; | ||
980 | |||
981 | if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && | ||
982 | (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) | ||
983 | return -EINVAL; | ||
984 | |||
985 | return videobuf_dqbuf(cx18_vb_queue(id), b, file->f_flags & O_NONBLOCK); | ||
986 | } | ||
987 | |||
866 | static int cx18_encoder_cmd(struct file *file, void *fh, | 988 | static int cx18_encoder_cmd(struct file *file, void *fh, |
867 | struct v4l2_encoder_cmd *enc) | 989 | struct v4l2_encoder_cmd *enc) |
868 | { | 990 | { |
@@ -1081,6 +1203,12 @@ static const struct v4l2_ioctl_ops cx18_ioctl_ops = { | |||
1081 | .vidioc_s_register = cx18_s_register, | 1203 | .vidioc_s_register = cx18_s_register, |
1082 | #endif | 1204 | #endif |
1083 | .vidioc_default = cx18_default, | 1205 | .vidioc_default = cx18_default, |
1206 | .vidioc_streamon = cx18_streamon, | ||
1207 | .vidioc_streamoff = cx18_streamoff, | ||
1208 | .vidioc_reqbufs = cx18_reqbufs, | ||
1209 | .vidioc_querybuf = cx18_querybuf, | ||
1210 | .vidioc_qbuf = cx18_qbuf, | ||
1211 | .vidioc_dqbuf = cx18_dqbuf, | ||
1084 | }; | 1212 | }; |
1085 | 1213 | ||
1086 | void cx18_set_funcs(struct video_device *vdev) | 1214 | void cx18_set_funcs(struct video_device *vdev) |
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c index 9605d54bd08..c07191e09fc 100644 --- a/drivers/media/video/cx18/cx18-mailbox.c +++ b/drivers/media/video/cx18/cx18-mailbox.c | |||
@@ -81,6 +81,7 @@ static const struct cx18_api_info api_info[] = { | |||
81 | API_ENTRY(CPU, CX18_CPU_SET_SLICED_VBI_PARAM, 0), | 81 | API_ENTRY(CPU, CX18_CPU_SET_SLICED_VBI_PARAM, 0), |
82 | API_ENTRY(CPU, CX18_CPU_SET_USERDATA_PLACE_HOLDER, 0), | 82 | API_ENTRY(CPU, CX18_CPU_SET_USERDATA_PLACE_HOLDER, 0), |
83 | API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0), | 83 | API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0), |
84 | API_ENTRY(CPU, CX18_CPU_SET_VFC_PARAM, 0), | ||
84 | API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0), | 85 | API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0), |
85 | API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST), | 86 | API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST), |
86 | API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL, API_SLOW), | 87 | API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL, API_SLOW), |
@@ -158,6 +159,60 @@ static void cx18_mdl_send_to_dvb(struct cx18_stream *s, struct cx18_mdl *mdl) | |||
158 | } | 159 | } |
159 | } | 160 | } |
160 | 161 | ||
162 | static void cx18_mdl_send_to_videobuf(struct cx18_stream *s, | ||
163 | struct cx18_mdl *mdl) | ||
164 | { | ||
165 | struct cx18_videobuf_buffer *vb_buf; | ||
166 | struct cx18_buffer *buf; | ||
167 | u8 *p; | ||
168 | u32 offset = 0; | ||
169 | int dispatch = 0; | ||
170 | |||
171 | if (mdl->bytesused == 0) | ||
172 | return; | ||
173 | |||
174 | /* Acquire a videobuf buffer, clone to and and release it */ | ||
175 | spin_lock(&s->vb_lock); | ||
176 | if (list_empty(&s->vb_capture)) | ||
177 | goto out; | ||
178 | |||
179 | vb_buf = list_first_entry(&s->vb_capture, struct cx18_videobuf_buffer, | ||
180 | vb.queue); | ||
181 | |||
182 | p = videobuf_to_vmalloc(&vb_buf->vb); | ||
183 | if (!p) | ||
184 | goto out; | ||
185 | |||
186 | offset = vb_buf->bytes_used; | ||
187 | list_for_each_entry(buf, &mdl->buf_list, list) { | ||
188 | if (buf->bytesused == 0) | ||
189 | break; | ||
190 | |||
191 | if ((offset + buf->bytesused) <= vb_buf->vb.bsize) { | ||
192 | memcpy(p + offset, buf->buf, buf->bytesused); | ||
193 | offset += buf->bytesused; | ||
194 | vb_buf->bytes_used += buf->bytesused; | ||
195 | } | ||
196 | } | ||
197 | |||
198 | /* If we've filled the buffer as per the callers res then dispatch it */ | ||
199 | if (vb_buf->bytes_used >= (vb_buf->vb.width * vb_buf->vb.height * 2)) { | ||
200 | dispatch = 1; | ||
201 | vb_buf->bytes_used = 0; | ||
202 | } | ||
203 | |||
204 | if (dispatch) { | ||
205 | vb_buf->vb.ts = ktime_to_timeval(ktime_get()); | ||
206 | list_del(&vb_buf->vb.queue); | ||
207 | vb_buf->vb.state = VIDEOBUF_DONE; | ||
208 | wake_up(&vb_buf->vb.done); | ||
209 | } | ||
210 | |||
211 | mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies); | ||
212 | |||
213 | out: | ||
214 | spin_unlock(&s->vb_lock); | ||
215 | } | ||
161 | 216 | ||
162 | static void cx18_mdl_send_to_alsa(struct cx18 *cx, struct cx18_stream *s, | 217 | static void cx18_mdl_send_to_alsa(struct cx18 *cx, struct cx18_stream *s, |
163 | struct cx18_mdl *mdl) | 218 | struct cx18_mdl *mdl) |
@@ -263,6 +318,9 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order) | |||
263 | } else { | 318 | } else { |
264 | cx18_enqueue(s, mdl, &s->q_full); | 319 | cx18_enqueue(s, mdl, &s->q_full); |
265 | } | 320 | } |
321 | } else if (s->type == CX18_ENC_STREAM_TYPE_YUV) { | ||
322 | cx18_mdl_send_to_videobuf(s, mdl); | ||
323 | cx18_enqueue(s, mdl, &s->q_free); | ||
266 | } else { | 324 | } else { |
267 | cx18_enqueue(s, mdl, &s->q_full); | 325 | cx18_enqueue(s, mdl, &s->q_full); |
268 | if (s->type == CX18_ENC_STREAM_TYPE_IDX) | 326 | if (s->type == CX18_ENC_STREAM_TYPE_IDX) |
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index 6fbc356113c..852f420fd27 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c | |||
@@ -44,6 +44,7 @@ static struct v4l2_file_operations cx18_v4l2_enc_fops = { | |||
44 | .unlocked_ioctl = cx18_v4l2_ioctl, | 44 | .unlocked_ioctl = cx18_v4l2_ioctl, |
45 | .release = cx18_v4l2_close, | 45 | .release = cx18_v4l2_close, |
46 | .poll = cx18_v4l2_enc_poll, | 46 | .poll = cx18_v4l2_enc_poll, |
47 | .mmap = cx18_v4l2_mmap, | ||
47 | }; | 48 | }; |
48 | 49 | ||
49 | /* offset from 0 to register ts v4l2 minors on */ | 50 | /* offset from 0 to register ts v4l2 minors on */ |
@@ -97,6 +98,141 @@ static struct { | |||
97 | }, | 98 | }, |
98 | }; | 99 | }; |
99 | 100 | ||
101 | |||
102 | void cx18_dma_free(struct videobuf_queue *q, | ||
103 | struct cx18_stream *s, struct cx18_videobuf_buffer *buf) | ||
104 | { | ||
105 | videobuf_waiton(q, &buf->vb, 0, 0); | ||
106 | videobuf_vmalloc_free(&buf->vb); | ||
107 | buf->vb.state = VIDEOBUF_NEEDS_INIT; | ||
108 | } | ||
109 | |||
110 | static int cx18_prepare_buffer(struct videobuf_queue *q, | ||
111 | struct cx18_stream *s, | ||
112 | struct cx18_videobuf_buffer *buf, | ||
113 | u32 pixelformat, | ||
114 | unsigned int width, unsigned int height, | ||
115 | enum v4l2_field field) | ||
116 | { | ||
117 | struct cx18 *cx = s->cx; | ||
118 | int rc = 0; | ||
119 | |||
120 | /* check settings */ | ||
121 | buf->bytes_used = 0; | ||
122 | |||
123 | if ((width < 48) || (height < 32)) | ||
124 | return -EINVAL; | ||
125 | |||
126 | buf->vb.size = (width * height * 2); | ||
127 | if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size)) | ||
128 | return -EINVAL; | ||
129 | |||
130 | /* alloc + fill struct (if changed) */ | ||
131 | if (buf->vb.width != width || buf->vb.height != height || | ||
132 | buf->vb.field != field || s->pixelformat != pixelformat || | ||
133 | buf->tvnorm != cx->std) { | ||
134 | |||
135 | buf->vb.width = width; | ||
136 | buf->vb.height = height; | ||
137 | buf->vb.field = field; | ||
138 | buf->tvnorm = cx->std; | ||
139 | s->pixelformat = pixelformat; | ||
140 | |||
141 | cx18_dma_free(q, s, buf); | ||
142 | } | ||
143 | |||
144 | if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size)) | ||
145 | return -EINVAL; | ||
146 | |||
147 | if (buf->vb.field == 0) | ||
148 | buf->vb.field = V4L2_FIELD_INTERLACED; | ||
149 | |||
150 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { | ||
151 | buf->vb.width = width; | ||
152 | buf->vb.height = height; | ||
153 | buf->vb.field = field; | ||
154 | buf->tvnorm = cx->std; | ||
155 | s->pixelformat = pixelformat; | ||
156 | |||
157 | rc = videobuf_iolock(q, &buf->vb, NULL); | ||
158 | if (rc != 0) | ||
159 | goto fail; | ||
160 | } | ||
161 | buf->vb.state = VIDEOBUF_PREPARED; | ||
162 | return 0; | ||
163 | |||
164 | fail: | ||
165 | cx18_dma_free(q, s, buf); | ||
166 | return rc; | ||
167 | |||
168 | } | ||
169 | |||
170 | /* VB_MIN_BUFSIZE is lcm(1440 * 480, 1440 * 576) | ||
171 | 1440 is a single line of 4:2:2 YUV at 720 luma samples wide | ||
172 | */ | ||
173 | #define VB_MIN_BUFFERS 32 | ||
174 | #define VB_MIN_BUFSIZE 4147200 | ||
175 | |||
176 | static int buffer_setup(struct videobuf_queue *q, | ||
177 | unsigned int *count, unsigned int *size) | ||
178 | { | ||
179 | struct cx18_stream *s = q->priv_data; | ||
180 | struct cx18 *cx = s->cx; | ||
181 | |||
182 | *size = 2 * cx->cxhdl.width * cx->cxhdl.height; | ||
183 | if (*count == 0) | ||
184 | *count = VB_MIN_BUFFERS; | ||
185 | |||
186 | while (*size * *count > VB_MIN_BUFFERS * VB_MIN_BUFSIZE) | ||
187 | (*count)--; | ||
188 | |||
189 | q->field = V4L2_FIELD_INTERLACED; | ||
190 | q->last = V4L2_FIELD_INTERLACED; | ||
191 | |||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | static int buffer_prepare(struct videobuf_queue *q, | ||
196 | struct videobuf_buffer *vb, | ||
197 | enum v4l2_field field) | ||
198 | { | ||
199 | struct cx18_videobuf_buffer *buf = | ||
200 | container_of(vb, struct cx18_videobuf_buffer, vb); | ||
201 | struct cx18_stream *s = q->priv_data; | ||
202 | struct cx18 *cx = s->cx; | ||
203 | |||
204 | return cx18_prepare_buffer(q, s, buf, s->pixelformat, | ||
205 | cx->cxhdl.width, cx->cxhdl.height, field); | ||
206 | } | ||
207 | |||
208 | static void buffer_release(struct videobuf_queue *q, | ||
209 | struct videobuf_buffer *vb) | ||
210 | { | ||
211 | struct cx18_videobuf_buffer *buf = | ||
212 | container_of(vb, struct cx18_videobuf_buffer, vb); | ||
213 | struct cx18_stream *s = q->priv_data; | ||
214 | |||
215 | cx18_dma_free(q, s, buf); | ||
216 | } | ||
217 | |||
218 | static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) | ||
219 | { | ||
220 | struct cx18_videobuf_buffer *buf = | ||
221 | container_of(vb, struct cx18_videobuf_buffer, vb); | ||
222 | struct cx18_stream *s = q->priv_data; | ||
223 | |||
224 | buf->vb.state = VIDEOBUF_QUEUED; | ||
225 | |||
226 | list_add_tail(&buf->vb.queue, &s->vb_capture); | ||
227 | } | ||
228 | |||
229 | static struct videobuf_queue_ops cx18_videobuf_qops = { | ||
230 | .buf_setup = buffer_setup, | ||
231 | .buf_prepare = buffer_prepare, | ||
232 | .buf_queue = buffer_queue, | ||
233 | .buf_release = buffer_release, | ||
234 | }; | ||
235 | |||
100 | static void cx18_stream_init(struct cx18 *cx, int type) | 236 | static void cx18_stream_init(struct cx18 *cx, int type) |
101 | { | 237 | { |
102 | struct cx18_stream *s = &cx->streams[type]; | 238 | struct cx18_stream *s = &cx->streams[type]; |
@@ -132,6 +268,26 @@ static void cx18_stream_init(struct cx18 *cx, int type) | |||
132 | cx18_queue_init(&s->q_idle); | 268 | cx18_queue_init(&s->q_idle); |
133 | 269 | ||
134 | INIT_WORK(&s->out_work_order, cx18_out_work_handler); | 270 | INIT_WORK(&s->out_work_order, cx18_out_work_handler); |
271 | |||
272 | INIT_LIST_HEAD(&s->vb_capture); | ||
273 | s->vb_timeout.function = cx18_vb_timeout; | ||
274 | s->vb_timeout.data = (unsigned long)s; | ||
275 | init_timer(&s->vb_timeout); | ||
276 | spin_lock_init(&s->vb_lock); | ||
277 | if (type == CX18_ENC_STREAM_TYPE_YUV) { | ||
278 | spin_lock_init(&s->vbuf_q_lock); | ||
279 | |||
280 | s->vb_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
281 | videobuf_queue_vmalloc_init(&s->vbuf_q, &cx18_videobuf_qops, | ||
282 | &cx->pci_dev->dev, &s->vbuf_q_lock, | ||
283 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
284 | V4L2_FIELD_INTERLACED, | ||
285 | sizeof(struct cx18_videobuf_buffer), | ||
286 | s, &cx->serialize_lock); | ||
287 | |||
288 | /* Assume the previous pixel default */ | ||
289 | s->pixelformat = V4L2_PIX_FMT_HM12; | ||
290 | } | ||
135 | } | 291 | } |
136 | 292 | ||
137 | static int cx18_prep_dev(struct cx18 *cx, int type) | 293 | static int cx18_prep_dev(struct cx18 *cx, int type) |
@@ -372,6 +528,9 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister) | |||
372 | if (vdev == NULL) | 528 | if (vdev == NULL) |
373 | continue; | 529 | continue; |
374 | 530 | ||
531 | if (type == CX18_ENC_STREAM_TYPE_YUV) | ||
532 | videobuf_mmap_free(&cx->streams[type].vbuf_q); | ||
533 | |||
375 | cx18_stream_free(&cx->streams[type]); | 534 | cx18_stream_free(&cx->streams[type]); |
376 | 535 | ||
377 | /* Unregister or release device */ | 536 | /* Unregister or release device */ |
@@ -581,7 +740,10 @@ static void cx18_stream_configure_mdls(struct cx18_stream *s) | |||
581 | * Set the MDL size to the exact size needed for one frame. | 740 | * Set the MDL size to the exact size needed for one frame. |
582 | * Use enough buffers per MDL to cover the MDL size | 741 | * Use enough buffers per MDL to cover the MDL size |
583 | */ | 742 | */ |
584 | s->mdl_size = 720 * s->cx->cxhdl.height * 3 / 2; | 743 | if (s->pixelformat == V4L2_PIX_FMT_HM12) |
744 | s->mdl_size = 720 * s->cx->cxhdl.height * 3 / 2; | ||
745 | else | ||
746 | s->mdl_size = 720 * s->cx->cxhdl.height * 2; | ||
585 | s->bufs_per_mdl = s->mdl_size / s->buf_size; | 747 | s->bufs_per_mdl = s->mdl_size / s->buf_size; |
586 | if (s->mdl_size % s->buf_size) | 748 | if (s->mdl_size % s->buf_size) |
587 | s->bufs_per_mdl++; | 749 | s->bufs_per_mdl++; |
@@ -729,6 +891,19 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) | |||
729 | test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) | 891 | test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) |
730 | cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, | 892 | cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, |
731 | (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8) | 1); | 893 | (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8) | 1); |
894 | |||
895 | /* Enable the Video Format Converter for UYVY 4:2:2 support, | ||
896 | * rather than the default HM12 Macroblovk 4:2:0 support. | ||
897 | */ | ||
898 | if (captype == CAPTURE_CHANNEL_TYPE_YUV) { | ||
899 | if (s->pixelformat == V4L2_PIX_FMT_UYVY) | ||
900 | cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2, | ||
901 | s->handle, 1); | ||
902 | else | ||
903 | /* If in doubt, default to HM12 */ | ||
904 | cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2, | ||
905 | s->handle, 0); | ||
906 | } | ||
732 | } | 907 | } |
733 | 908 | ||
734 | if (atomic_read(&cx->tot_capturing) == 0) { | 909 | if (atomic_read(&cx->tot_capturing) == 0) { |
diff --git a/drivers/media/video/cx18/cx18-version.h b/drivers/media/video/cx18/cx18-version.h index 3e1aec4bcfd..cd189b6bbe2 100644 --- a/drivers/media/video/cx18/cx18-version.h +++ b/drivers/media/video/cx18/cx18-version.h | |||
@@ -24,7 +24,7 @@ | |||
24 | 24 | ||
25 | #define CX18_DRIVER_NAME "cx18" | 25 | #define CX18_DRIVER_NAME "cx18" |
26 | #define CX18_DRIVER_VERSION_MAJOR 1 | 26 | #define CX18_DRIVER_VERSION_MAJOR 1 |
27 | #define CX18_DRIVER_VERSION_MINOR 4 | 27 | #define CX18_DRIVER_VERSION_MINOR 5 |
28 | #define CX18_DRIVER_VERSION_PATCHLEVEL 0 | 28 | #define CX18_DRIVER_VERSION_PATCHLEVEL 0 |
29 | 29 | ||
30 | #define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL) | 30 | #define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL) |
diff --git a/drivers/media/video/cx18/cx23418.h b/drivers/media/video/cx18/cx23418.h index 935f557acbd..767a8d23e3f 100644 --- a/drivers/media/video/cx18/cx23418.h +++ b/drivers/media/video/cx18/cx23418.h | |||
@@ -342,6 +342,12 @@ | |||
342 | ReturnCode */ | 342 | ReturnCode */ |
343 | #define CX18_CPU_GET_ENC_PTS (CPU_CMD_MASK_CAPTURE | 0x0022) | 343 | #define CX18_CPU_GET_ENC_PTS (CPU_CMD_MASK_CAPTURE | 0x0022) |
344 | 344 | ||
345 | /* Description: Set VFC parameters | ||
346 | IN[0] - task handle | ||
347 | IN[1] - VFC enable flag, 1 - enable, 0 - disable | ||
348 | */ | ||
349 | #define CX18_CPU_SET_VFC_PARAM (CPU_CMD_MASK_CAPTURE | 0x0023) | ||
350 | |||
345 | /* Below is the list of commands related to the data exchange */ | 351 | /* Below is the list of commands related to the data exchange */ |
346 | #define CPU_CMD_MASK_DE (CPU_CMD_MASK | 0x040000) | 352 | #define CPU_CMD_MASK_DE (CPU_CMD_MASK | 0x040000) |
347 | 353 | ||