diff options
Diffstat (limited to 'linux/drivers/media/video')
39 files changed, 1007 insertions, 347 deletions
diff --git a/linux/drivers/media/video/cx18/cx18-av-vbi.c b/linux/drivers/media/video/cx18/cx18-av-vbi.c index 02fdf57bb..1527ea4f6 100644 --- a/linux/drivers/media/video/cx18/cx18-av-vbi.c +++ b/linux/drivers/media/video/cx18/cx18-av-vbi.c @@ -141,10 +141,11 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg) u8 lcr[24]; fmt = arg; - if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) + if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE && + fmt->type != V4L2_BUF_TYPE_VBI_CAPTURE) return -EINVAL; svbi = &fmt->fmt.sliced; - if (svbi->service_set == 0) { + if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) { /* raw VBI */ memset(svbi, 0, sizeof(*svbi)); diff --git a/linux/drivers/media/video/cx18/cx18-cards.c b/linux/drivers/media/video/cx18/cx18-cards.c index 23bd871b7..10cddba3e 100644 --- a/linux/drivers/media/video/cx18/cx18-cards.c +++ b/linux/drivers/media/video/cx18/cx18-cards.c @@ -51,7 +51,7 @@ static struct cx18_card_tuner_i2c cx18_i2c_std = { static const struct cx18_card cx18_card_hvr1600_esmt = { .type = CX18_CARD_HVR_1600_ESMT, .name = "Hauppauge HVR-1600", - .comment = "VBI is not yet supported\n", + .comment = "Raw VBI supported; Sliced VBI is not yet supported\n", .v4l2_capabilities = CX18_CAP_ENCODER, .hw_audio_ctrl = CX18_HW_CX23418, .hw_muxer = CX18_HW_CS5345, @@ -97,7 +97,7 @@ static const struct cx18_card cx18_card_hvr1600_esmt = { static const struct cx18_card cx18_card_hvr1600_samsung = { .type = CX18_CARD_HVR_1600_SAMSUNG, .name = "Hauppauge HVR-1600 (Preproduction)", - .comment = "VBI is not yet supported\n", + .comment = "Raw VBI supported; Sliced VBI is not yet supported\n", .v4l2_capabilities = CX18_CAP_ENCODER, .hw_audio_ctrl = CX18_HW_CX23418, .hw_muxer = CX18_HW_CS5345, @@ -152,7 +152,7 @@ static const struct cx18_card_pci_info cx18_pci_h900[] = { static const struct cx18_card cx18_card_h900 = { .type = CX18_CARD_COMPRO_H900, .name = "Compro VideoMate H900", - .comment = "VBI is not yet supported\n", + .comment = "Raw VBI supported; Sliced VBI is not yet supported\n", .v4l2_capabilities = CX18_CAP_ENCODER, .hw_audio_ctrl = CX18_HW_CX23418, .hw_all = CX18_HW_TUNER, @@ -249,7 +249,7 @@ static const struct cx18_card_pci_info cx18_pci_cnxt_raptor_pal[] = { static const struct cx18_card cx18_card_cnxt_raptor_pal = { .type = CX18_CARD_CNXT_RAPTOR_PAL, .name = "Conexant Raptor PAL/SECAM", - .comment = "VBI is not yet supported\n", + .comment = "Raw VBI supported; Sliced VBI is not yet supported\n", .v4l2_capabilities = CX18_CAP_ENCODER, .hw_audio_ctrl = CX18_HW_CX23418, .hw_muxer = CX18_HW_GPIO, diff --git a/linux/drivers/media/video/cx18/cx18-cards.h b/linux/drivers/media/video/cx18/cx18-cards.h index a54aae9ed..6fa7bcb42 100644 --- a/linux/drivers/media/video/cx18/cx18-cards.h +++ b/linux/drivers/media/video/cx18/cx18-cards.h @@ -48,8 +48,9 @@ /* V4L2 capability aliases */ #define CX18_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \ - V4L2_CAP_AUDIO | V4L2_CAP_READWRITE) -/* | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE) not yet */ + V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | \ + V4L2_CAP_VBI_CAPTURE) +/* | V4L2_CAP_SLICED_VBI_CAPTURE) not yet */ struct cx18_card_video_input { u8 video_type; /* video input type */ diff --git a/linux/drivers/media/video/cx18/cx18-driver.c b/linux/drivers/media/video/cx18/cx18-driver.c index 1fa9a670b..cea4735b6 100644 --- a/linux/drivers/media/video/cx18/cx18-driver.c +++ b/linux/drivers/media/video/cx18/cx18-driver.c @@ -56,9 +56,6 @@ struct cx18 *cx18_cards[CX18_MAX_CARDS]; /* Protects cx18_cards_active */ DEFINE_SPINLOCK(cx18_cards_lock); -/* Queue for deferrable IRQ handling work for all cx18 cards in system */ -struct workqueue_struct *cx18_work_queue; - /* add your revision and whatnot here */ static struct pci_device_id cx18_pci_tbl[] __devinitdata = { {PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418, @@ -86,12 +83,28 @@ static char secam[] = "--"; static char ntsc[] = "-"; /* Buffers */ -static int enc_mpg_buffers = CX18_DEFAULT_ENC_MPG_BUFFERS; static int enc_ts_buffers = CX18_DEFAULT_ENC_TS_BUFFERS; +static int enc_mpg_buffers = CX18_DEFAULT_ENC_MPG_BUFFERS; +static int enc_idx_buffers = CX18_DEFAULT_ENC_IDX_BUFFERS; static int enc_yuv_buffers = CX18_DEFAULT_ENC_YUV_BUFFERS; static int enc_vbi_buffers = CX18_DEFAULT_ENC_VBI_BUFFERS; static int enc_pcm_buffers = CX18_DEFAULT_ENC_PCM_BUFFERS; +static int enc_ts_bufsize = CX18_DEFAULT_ENC_TS_BUFSIZE; +static int enc_mpg_bufsize = CX18_DEFAULT_ENC_MPG_BUFSIZE; +static int enc_idx_bufsize = CX18_DEFAULT_ENC_IDX_BUFSIZE; +static int enc_yuv_bufsize = CX18_DEFAULT_ENC_YUV_BUFSIZE; +/* VBI bufsize based on standards supported by card tuner for now */ +static int enc_pcm_bufsize = CX18_DEFAULT_ENC_PCM_BUFSIZE; + +static int enc_ts_bufs = -1; +static int enc_mpg_bufs = -1; +static int enc_idx_bufs = -1; +static int enc_yuv_bufs = -1; +static int enc_vbi_bufs = -1; +static int enc_pcm_bufs = -1; + + static int cx18_pci_latency = 1; static int mmio_ndelay; @@ -111,12 +124,27 @@ module_param(retry_mmio, int, 0644); module_param(cx18_pci_latency, int, 0644); module_param(cx18_first_minor, int, 0644); -module_param(enc_mpg_buffers, int, 0644); module_param(enc_ts_buffers, int, 0644); +module_param(enc_mpg_buffers, int, 0644); +module_param(enc_idx_buffers, int, 0644); module_param(enc_yuv_buffers, int, 0644); module_param(enc_vbi_buffers, int, 0644); module_param(enc_pcm_buffers, int, 0644); +module_param(enc_ts_bufsize, int, 0644); +module_param(enc_mpg_bufsize, int, 0644); +module_param(enc_idx_bufsize, int, 0644); +module_param(enc_yuv_bufsize, int, 0644); +/* VBI bufsize based on standards supported by card tuner for now */ +module_param(enc_pcm_bufsize, int, 0644); + +module_param(enc_ts_bufs, int, 0644); +module_param(enc_mpg_bufs, int, 0644); +module_param(enc_idx_bufs, int, 0644); +module_param(enc_yuv_bufs, int, 0644); +module_param(enc_vbi_bufs, int, 0644); +module_param(enc_pcm_bufs, int, 0644); + MODULE_PARM_DESC(tuner, "Tuner type selection,\n" "\t\t\tsee tuner.h for values"); MODULE_PARM_DESC(radio, @@ -157,21 +185,57 @@ MODULE_PARM_DESC(retry_mmio, MODULE_PARM_DESC(mmio_ndelay, "(Deprecated) MMIO accesses are now never purposely delayed\n" "\t\t\tEffectively: 0 ns"); -MODULE_PARM_DESC(enc_mpg_buffers, - "Encoder MPG Buffers (in MB)\n" - "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS)); MODULE_PARM_DESC(enc_ts_buffers, - "Encoder TS Buffers (in MB)\n" + "Encoder TS buffer memory (MB). (enc_ts_bufs can override)\n" "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFFERS)); +MODULE_PARM_DESC(enc_ts_bufsize, + "Size of an encoder TS buffer (kB)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFSIZE)); +MODULE_PARM_DESC(enc_ts_bufs, + "Number of encoder TS buffers\n" + "\t\t\tDefault is computed from other enc_ts_* parameters"); +MODULE_PARM_DESC(enc_mpg_buffers, + "Encoder MPG buffer memory (MB). (enc_mpg_bufs can override)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS)); +MODULE_PARM_DESC(enc_mpg_bufsize, + "Size of an encoder MPG buffer (kB)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFSIZE)); +MODULE_PARM_DESC(enc_mpg_bufs, + "Number of encoder MPG buffers\n" + "\t\t\tDefault is computed from other enc_mpg_* parameters"); +MODULE_PARM_DESC(enc_idx_buffers, + "Encoder IDX buffer memory (MB). (enc_idx_bufs can override)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_IDX_BUFFERS)); +MODULE_PARM_DESC(enc_idx_bufsize, + "Size of an encoder IDX buffer (kB)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_IDX_BUFSIZE)); +MODULE_PARM_DESC(enc_idx_bufs, + "Number of encoder IDX buffers\n" + "\t\t\tDefault is computed from other enc_idx_* parameters"); MODULE_PARM_DESC(enc_yuv_buffers, - "Encoder YUV Buffers (in MB)\n" + "Encoder YUV buffer memory (MB). (enc_yuv_bufs can override)\n" "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFFERS)); +MODULE_PARM_DESC(enc_yuv_bufsize, + "Size of an encoder YUV buffer (kB)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFSIZE)); +MODULE_PARM_DESC(enc_yuv_bufs, + "Number of encoder YUV buffers\n" + "\t\t\tDefault is computed from other enc_yuv_* parameters"); MODULE_PARM_DESC(enc_vbi_buffers, - "Encoder VBI Buffers (in MB)\n" + "Encoder VBI buffer memory (MB). (enc_vbi_bufs can override)\n" "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_VBI_BUFFERS)); +MODULE_PARM_DESC(enc_vbi_bufs, + "Number of encoder VBI buffers\n" + "\t\t\tDefault is computed from enc_vbi_buffers & tuner std"); MODULE_PARM_DESC(enc_pcm_buffers, - "Encoder PCM buffers (in MB)\n" + "Encoder PCM buffer memory (MB). (enc_pcm_bufs can override)\n" "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFFERS)); +MODULE_PARM_DESC(enc_pcm_bufsize, + "Size of an encoder PCM buffer (kB)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFSIZE)); +MODULE_PARM_DESC(enc_pcm_bufs, + "Number of encoder PCM buffers\n" + "\t\t\tDefault is computed from other enc_pcm_* parameters"); MODULE_PARM_DESC(cx18_first_minor, "Set kernel number assigned to first card"); @@ -364,11 +428,65 @@ static void cx18_process_options(struct cx18 *cx) { int i, j; - cx->options.megabytes[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers; cx->options.megabytes[CX18_ENC_STREAM_TYPE_TS] = enc_ts_buffers; + cx->options.megabytes[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers; + cx->options.megabytes[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_buffers; cx->options.megabytes[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers; cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers; cx->options.megabytes[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers; + cx->options.megabytes[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control only */ + + cx->stream_buffers[CX18_ENC_STREAM_TYPE_TS] = enc_ts_bufs; + cx->stream_buffers[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufs; + cx->stream_buffers[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufs; + cx->stream_buffers[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufs; + cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_bufs; + cx->stream_buffers[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufs; + cx->stream_buffers[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control, no data */ + + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_TS] = enc_ts_bufsize; + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufsize; + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufsize; + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufsize; + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = 0; /* computed later */ + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufsize; + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control no data */ + + /* Except for VBI ensure stream_buffers & stream_buf_size are valid */ + for (i = 0; i < CX18_MAX_STREAMS; i++) { + /* User said to use 0 buffers */ + if (cx->stream_buffers[i] == 0) { + cx->options.megabytes[i] = 0; + cx->stream_buf_size[i] = 0; + continue; + } + /* User said to use 0 MB total */ + if (cx->options.megabytes[i] <= 0) { + cx->options.megabytes[i] = 0; + cx->stream_buffers[i] = 0; + cx->stream_buf_size[i] = 0; + continue; + } + /* VBI is computed later or user said buffer has size 0 */ + if (cx->stream_buf_size[i] <= 0) { + if (i != CX18_ENC_STREAM_TYPE_VBI) { + cx->options.megabytes[i] = 0; + cx->stream_buffers[i] = 0; + cx->stream_buf_size[i] = 0; + } + continue; + } + if (cx->stream_buffers[i] < 0) { + cx->stream_buffers[i] = cx->options.megabytes[i] * 1024 + / cx->stream_buf_size[i]; + } else { + /* N.B. This might round down to 0 */ + cx->options.megabytes[i] = + cx->stream_buffers[i] * cx->stream_buf_size[i] / 1024; + } + cx->stream_buf_size[i] *= 1024; /* convert from kB to bytes */ + } + cx->options.cardtype = cardtype[cx->num]; cx->options.tuner = tuner[cx->num]; cx->options.radio = radio[cx->num]; @@ -446,6 +564,12 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) spin_lock_init(&cx->lock); + cx->work_queue = create_singlethread_workqueue(cx->name); + if (cx->work_queue == NULL) { + CX18_ERR("Unable to create work hander thread\n"); + return -ENOMEM; + } + for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++) { cx->epu_work_order[i].cx = cx; cx->epu_work_order[i].str = cx->epu_debug_str; @@ -475,15 +599,49 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) init_waitqueue_head(&cx->dma_waitq); /* VBI */ - cx->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; + cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE; cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced; - cx->vbi.raw_size = 1456; - cx->vbi.raw_decoder_line_size = 1456; - cx->vbi.raw_decoder_sav_odd_field = 0x20; - cx->vbi.raw_decoder_sav_even_field = 0x60; - cx->vbi.sliced_decoder_line_size = 272; - cx->vbi.sliced_decoder_sav_odd_field = 0xB0; - cx->vbi.sliced_decoder_sav_even_field = 0xF0; + + /* + * The VBI line sizes depend on the pixel clock and the horiz rate + * + * (1/Fh)*(2*Fp) = Samples/line + * = 4 bytes EAV + Anc data in hblank + 4 bytes SAV + active samples + * + * Sliced VBI is sent as ancillary data during horizontal blanking + * Raw VBI is sent as active video samples during vertcal blanking + * + * We use a BT.656 pxiel clock of 13.5 MHz and a BT.656 active line + * length of 720 pixels @ 4:2:2 sampling. Thus... + * + * For NTSC: + * + * (1/15,734 kHz) * 2 * 13.5 MHz = 1716 samples/line = + * 4 bytes SAV + 268 bytes anc data + 4 bytes SAV + 1440 active samples + * + * For PAL: + * + * (1/15,625 kHz) * 2 * 13.5 MHz = 1728 samples/line = + * 4 bytes SAV + 280 bytes anc data + 4 bytes SAV + 1440 active samples + * + */ + + /* CX18-AV-Core number of VBI samples output per horizontal line */ + cx->vbi.raw_decoder_line_size = 1444; /* 4 byte SAV + 2 * 720 */ + cx->vbi.sliced_decoder_line_size = 272; /* 60 Hz: 268+4, 50 Hz: 280+4 */ + + /* CX18-AV-Core VBI samples/line possibly rounded up */ + cx->vbi.raw_size = 1444; /* Real max size is 1444 */ + cx->vbi.sliced_size = 284; /* Real max size is 284 */ + + /* + * CX18-AV-Core SAV/EAV RP codes in VIP 1.x mode + * Task Field VerticalBlank HorizontalBlank 0 0 0 0 + */ + cx->vbi.raw_decoder_sav_odd_field = 0x20; /* V */ + cx->vbi.raw_decoder_sav_even_field = 0x60; /* FV */ + cx->vbi.sliced_decoder_sav_odd_field = 0xB0; /* T VH - actually EAV */ + cx->vbi.sliced_decoder_sav_even_field = 0xF0; /* TFVH - actually EAV */ return 0; } @@ -516,6 +674,7 @@ static void __devinit cx18_init_struct2(struct cx18 *cx) cx->av_state.aud_input = CX18_AV_AUDIO8; cx->av_state.audclk_freq = 48000; cx->av_state.audmode = V4L2_TUNER_MODE_LANG1; + /* FIXME - 8 is NTSC value, investigate */ cx->av_state.vbi_line_offset = 8; } @@ -660,12 +819,9 @@ static int __devinit cx18_probe(struct pci_dev *dev, /* PCI Device Setup */ retval = cx18_setup_pci(cx, dev, pci_id); - if (retval != 0) { - if (retval == -EIO) - goto free_workqueue; - else if (retval == -ENXIO) - goto free_mem; - } + if (retval != 0) + goto free_workqueue; + /* save cx in the pci struct for later use */ pci_set_drvdata(dev, cx); @@ -773,13 +929,18 @@ static int __devinit cx18_probe(struct pci_dev *dev, } cx->params.video_gop_size = cx->is_60hz ? 15 : 12; - cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = 0x08000; - cx->stream_buf_size[CX18_ENC_STREAM_TYPE_TS] = 0x08000; - cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = 0x01200; - cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = 0x20000; vbi_buf_size = cx->vbi.raw_size * (cx->is_60hz ? 24 : 36) / 2; cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_buf_size; + if (cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] < 0) + cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] = + cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] * 1024 * 1024 + / vbi_buf_size; + else + cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] = + cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] * vbi_buf_size + / (1024 * 1024); + if (cx->options.radio > 0) cx->v4l2_cap |= V4L2_CAP_RADIO; @@ -835,6 +996,7 @@ free_map: free_mem: release_mem_region(cx->base_addr, CX18_MEM_SIZE); free_workqueue: + destroy_workqueue(cx->work_queue); err: if (retval == 0) retval = -ENODEV; @@ -917,6 +1079,7 @@ int cx18_init_on_first_open(struct cx18 *cx) return 0; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) static void cx18_cancel_epu_work_orders(struct cx18 *cx) { int i; @@ -924,6 +1087,7 @@ static void cx18_cancel_epu_work_orders(struct cx18 *cx) cancel_work_sync(&cx->epu_work_order[i].work); } +#endif static void cx18_remove(struct pci_dev *pci_dev) { struct cx18 *cx = pci_get_drvdata(pci_dev); @@ -937,11 +1101,22 @@ static void cx18_remove(struct pci_dev *pci_dev) /* Interrupts */ cx18_sw1_irq_disable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); cx18_halt_firmware(cx); cx18_cancel_epu_work_orders(cx); +#else + + flush_workqueue(cx->work_queue); + + cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); + + cx18_halt_firmware(cx); +#endif + + destroy_workqueue(cx->work_queue); cx18_streams_cleanup(cx, 1); @@ -984,17 +1159,8 @@ static int module_start(void) printk(KERN_INFO "cx18: Debug value must be >= 0 and <= 511!\n"); } - cx18_work_queue = create_singlethread_workqueue("cx18"); - if (cx18_work_queue == NULL) { - printk(KERN_ERR - "cx18: Unable to create work hander thread\n"); - return -ENOMEM; - } - if (pci_register_driver(&cx18_pci_driver)) { printk(KERN_ERR "cx18: Error detecting PCI card\n"); - destroy_workqueue(cx18_work_queue); - cx18_work_queue = NULL; return -ENODEV; } printk(KERN_INFO "cx18: End initialization\n"); @@ -1007,9 +1173,6 @@ static void module_cleanup(void) pci_unregister_driver(&cx18_pci_driver); - destroy_workqueue(cx18_work_queue); - cx18_work_queue = NULL; - for (i = 0; i < cx18_cards_active; i++) { if (cx18_cards[i] == NULL) continue; diff --git a/linux/drivers/media/video/cx18/cx18-driver.h b/linux/drivers/media/video/cx18/cx18-driver.h index ca1f43781..018d98f94 100644 --- a/linux/drivers/media/video/cx18/cx18-driver.h +++ b/linux/drivers/media/video/cx18/cx18-driver.h @@ -115,6 +115,17 @@ #define CX18_DEFAULT_ENC_VBI_BUFFERS 1 #define CX18_DEFAULT_ENC_PCM_BUFFERS 1 +/* Maximum firmware DMA buffers per stream */ +#define CX18_MAX_MDLS_PER_STREAM 63 + +/* DMA buffer, default size in kB allocated */ +#define CX18_DEFAULT_ENC_TS_BUFSIZE 32 +#define CX18_DEFAULT_ENC_MPG_BUFSIZE 32 +#define CX18_DEFAULT_ENC_IDX_BUFSIZE 32 +#define CX18_DEFAULT_ENC_YUV_BUFSIZE 128 +/* Default VBI bufsize based on standards supported by card tuner for now */ +#define CX18_DEFAULT_ENC_PCM_BUFSIZE 4 + /* i2c stuff */ #define I2C_CLIENTS_MAX 16 @@ -289,8 +300,8 @@ struct cx18_stream { /* Buffer Queues */ struct cx18_queue q_free; /* free buffers */ - struct cx18_queue q_full; /* full buffers */ - struct cx18_queue q_io; /* waiting for I/O */ + struct cx18_queue q_busy; /* busy buffers - in use by firmware */ + struct cx18_queue q_full; /* full buffers - data for user apps */ /* DVB / Digital Transport */ struct cx18_dvb dvb; @@ -408,6 +419,7 @@ struct cx18 { struct mutex serialize_lock; /* mutex used to serialize open/close/start/stop/ioctl operations */ struct cx18_options options; /* User options */ + int stream_buffers[CX18_MAX_STREAMS]; /* # of buffers for each stream */ int stream_buf_size[CX18_MAX_STREAMS]; /* Stream buffer size */ struct cx18_stream streams[CX18_MAX_STREAMS]; /* Stream data */ unsigned long i_flags; /* global cx18 flags */ @@ -447,6 +459,7 @@ struct cx18 { u32 sw2_irq_mask; u32 hw2_irq_mask; + struct workqueue_struct *work_queue; struct cx18_epu_work_order epu_work_order[CX18_MAX_EPU_WORK_ORDERS]; char epu_debug_str[256]; /* CX18_EPU_DEBUG is rare: use shared space */ @@ -478,7 +491,6 @@ extern struct cx18 *cx18_cards[]; extern int cx18_cards_active; extern int cx18_first_minor; extern spinlock_t cx18_cards_lock; -extern struct workqueue_struct *cx18_work_queue; /*==============Prototypes==================*/ @@ -492,4 +504,10 @@ void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv); /* First-open initialization: load firmware, etc. */ int cx18_init_on_first_open(struct cx18 *cx); +/* Test if the current VBI mode is raw (1) or sliced (0) */ +static inline int cx18_raw_vbi(const struct cx18 *cx) +{ + return cx->vbi.in.type == V4L2_BUF_TYPE_VBI_CAPTURE; +} + #endif /* CX18_DRIVER_H */ diff --git a/linux/drivers/media/video/cx18/cx18-dvb.c b/linux/drivers/media/video/cx18/cx18-dvb.c index 034e09a37..bd5e6f3fd 100644 --- a/linux/drivers/media/video/cx18/cx18-dvb.c +++ b/linux/drivers/media/video/cx18/cx18-dvb.c @@ -217,6 +217,10 @@ int cx18_dvb_register(struct cx18_stream *stream) dvb_net_init(dvb_adapter, &dvb->dvbnet, dmx); CX18_INFO("DVB Frontend registered\n"); + CX18_INFO("Registered DVB adapter%d for %s (%d x %d kB)\n", + stream->dvb.dvb_adapter.num, stream->name, + stream->buffers, stream->buf_size/1024); + mutex_init(&dvb->feedlock); dvb->enabled = 1; return ret; diff --git a/linux/drivers/media/video/cx18/cx18-fileops.c b/linux/drivers/media/video/cx18/cx18-fileops.c index 45b5f402e..ef4589ef6 100644 --- a/linux/drivers/media/video/cx18/cx18-fileops.c +++ b/linux/drivers/media/video/cx18/cx18-fileops.c @@ -67,12 +67,11 @@ static int cx18_claim_stream(struct cx18_open_id *id, int type) } s->id = id->open_id; - /* CX18_DEC_STREAM_TYPE_MPG needs to claim CX18_DEC_STREAM_TYPE_VBI, - CX18_ENC_STREAM_TYPE_MPG needs to claim CX18_ENC_STREAM_TYPE_VBI + /* CX18_ENC_STREAM_TYPE_MPG needs to claim CX18_ENC_STREAM_TYPE_VBI (provided VBI insertion is on and sliced VBI is selected), for all other streams we're done */ if (type == CX18_ENC_STREAM_TYPE_MPG && - cx->vbi.insert_mpeg && cx->vbi.sliced_in->service_set) { + cx->vbi.insert_mpeg && !cx18_raw_vbi(cx)) { vbi_type = CX18_ENC_STREAM_TYPE_VBI; } else { return 0; @@ -224,8 +223,10 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block, !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { while ((buf = cx18_dequeue(s_vbi, &s_vbi->q_full))) { /* byteswap and process VBI data */ -/* cx18_process_vbi_data(cx, buf, s_vbi->dma_pts, s_vbi->type); */ - cx18_enqueue(s_vbi, buf, &s_vbi->q_free); + cx18_process_vbi_data(cx, buf, + s_vbi->dma_pts, + s_vbi->type); + cx18_stream_put_buf_fw(s_vbi, buf); } } buf = &cx->vbi.sliced_mpeg_buf; @@ -233,11 +234,6 @@ static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block, return buf; } - /* do we have leftover data? */ - buf = cx18_dequeue(s, &s->q_io); - if (buf) - return buf; - /* do we have new data? */ buf = cx18_dequeue(s, &s->q_full); if (buf) { @@ -301,7 +297,7 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s, if (len > ucount) len = ucount; if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG && - cx->vbi.sliced_in->service_set && buf != &cx->vbi.sliced_mpeg_buf) { + !cx18_raw_vbi(cx) && buf != &cx->vbi.sliced_mpeg_buf) { const char *start = buf->buf + buf->readpos; const char *p = start + 1; const u8 *q; @@ -376,8 +372,7 @@ static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf, /* Each VBI buffer is one frame, the v4l2 API says that for VBI the frames should arrive one-by-one, so make sure we never output more than one VBI frame at a time */ - if (s->type == CX18_ENC_STREAM_TYPE_VBI && - cx->vbi.sliced_in->service_set) + if (s->type == CX18_ENC_STREAM_TYPE_VBI && !cx18_raw_vbi(cx)) single_frame = 1; for (;;) { @@ -404,16 +399,10 @@ static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf, tot_count - tot_written); if (buf != &cx->vbi.sliced_mpeg_buf) { - if (buf->readpos == buf->bytesused) { - cx18_buf_sync_for_device(s, buf); - cx18_enqueue(s, buf, &s->q_free); - cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, - s->handle, - (void __iomem *)&cx->scb->cpu_mdl[buf->id] - - cx->enc_mem, - 1, buf->id, s->buf_size); - } else - cx18_enqueue(s, buf, &s->q_io); + if (buf->readpos == buf->bytesused) + cx18_stream_put_buf_fw(s, buf); + else + cx18_push(s, buf, &s->q_full); } else if (buf->readpos == buf->bytesused) { int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES; @@ -557,7 +546,7 @@ unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait) CX18_DEBUG_HI_FILE("Encoder poll\n"); poll_wait(filp, &s->waitq, wait); - if (atomic_read(&s->q_full.buffers) || atomic_read(&s->q_io.buffers)) + if (atomic_read(&s->q_full.buffers)) return POLLIN | POLLRDNORM; if (eof) return POLLHUP; diff --git a/linux/drivers/media/video/cx18/cx18-io.h b/linux/drivers/media/video/cx18/cx18-io.h index e6716dcb1..2635b3a8c 100644 --- a/linux/drivers/media/video/cx18/cx18-io.h +++ b/linux/drivers/media/video/cx18/cx18-io.h @@ -83,10 +83,14 @@ void cx18_writel_expect(struct cx18 *cx, u32 val, void __iomem *addr, u32 eval, u32 mask) { int i; + u32 r; eval &= mask; for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) { cx18_writel_noretry(cx, val, addr); - if (eval == (cx18_readl(cx, addr) & mask)) + r = cx18_readl(cx, addr); + if (r == 0xffffffff && eval != 0xffffffff) + continue; + if (eval == (r & mask)) break; } } diff --git a/linux/drivers/media/video/cx18/cx18-ioctl.c b/linux/drivers/media/video/cx18/cx18-ioctl.c index 5d9c1146e..c83fcc0c5 100644 --- a/linux/drivers/media/video/cx18/cx18-ioctl.c +++ b/linux/drivers/media/video/cx18/cx18-ioctl.c @@ -284,13 +284,12 @@ static int cx18_s_fmt_vbi_cap(struct file *file, void *fh, if (ret) return ret; - if (id->type == CX18_ENC_STREAM_TYPE_VBI && - cx->vbi.sliced_in->service_set && - atomic_read(&cx->ana_capturing) > 0) + if (!cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0) return -EBUSY; cx->vbi.sliced_in->service_set = 0; - cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in); + cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE; + cx18_av_cmd(cx, VIDIOC_S_FMT, fmt); return cx18_g_fmt_vbi_cap(file, fh, fmt); } @@ -315,9 +314,9 @@ static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh, if (check_service_set(vbifmt, cx->is_50hz) == 0) return -EINVAL; - if (atomic_read(&cx->ana_capturing) > 0 && - cx->vbi.sliced_in->service_set == 0) + if (cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0) return -EBUSY; + cx->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; cx18_av_cmd(cx, VIDIOC_S_FMT, fmt); memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in)); return 0; @@ -851,8 +850,7 @@ static int cx18_log_status(struct file *file, void *fh) continue; CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags, - (s->buffers - atomic_read(&s->q_free.buffers)) - * 100 / s->buffers, + atomic_read(&s->q_full.buffers) * 100 / s->buffers, (s->buffers * s->buf_size) / 1024, s->buffers); } CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n", diff --git a/linux/drivers/media/video/cx18/cx18-mailbox.c b/linux/drivers/media/video/cx18/cx18-mailbox.c index 8415b9683..eb5c31af6 100644 --- a/linux/drivers/media/video/cx18/cx18-mailbox.c +++ b/linux/drivers/media/video/cx18/cx18-mailbox.c @@ -163,7 +163,7 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_epu_work_order *order) * it's filled in). * * cx18_queue_get buf() will detect the lost buffers - * and put them back in rotation eventually. + * and send them back to q_free for fw rotation eventually. */ if ((order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) && !(id >= s->mdl_offset && @@ -174,33 +174,27 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_epu_work_order *order) break; } buf = cx18_queue_get_buf(s, id, mdl_ack->data_used); + CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id); if (buf == NULL) { CX18_WARN("Could not find buf %d for stream %s\n", id, s->name); + /* Put as many buffers as possible back into fw use */ + cx18_stream_load_fw_queue(s); continue; } - cx18_buf_sync_for_cpu(s, buf); if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) { CX18_DEBUG_HI_DMA("TS recv bytesused = %d\n", buf->bytesused); - dvb_dmx_swfilter(&s->dvb.demux, buf->buf, buf->bytesused); - - cx18_buf_sync_for_device(s, buf); - cx18_enqueue(s, buf, &s->q_free); - - if (s->handle != CX18_INVALID_TASK_HANDLE && - test_bit(CX18_F_S_STREAMING, &s->s_flags)) - cx18_vapi(cx, - CX18_CPU_DE_SET_MDL, 5, s->handle, - (void __iomem *) - &cx->scb->cpu_mdl[buf->id] - cx->enc_mem, - 1, buf->id, s->buf_size); - } else - set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags); + } + /* Put as many buffers as possible back into fw use */ + cx18_stream_load_fw_queue(s); + /* Put back TS buffer, since it was removed from all queues */ + if (s->type == CX18_ENC_STREAM_TYPE_TS) + cx18_stream_put_buf_fw(s, buf); } wake_up(&cx->dma_waitq); if (s->id != -1) @@ -460,7 +454,7 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu) */ submit = epu_cmd_irq(cx, order); if (submit > 0) { - queue_work(cx18_work_queue, &order->work); + queue_work(cx->work_queue, &order->work); } } diff --git a/linux/drivers/media/video/cx18/cx18-queue.c b/linux/drivers/media/video/cx18/cx18-queue.c index 7b09c9a3e..a6b0666f0 100644 --- a/linux/drivers/media/video/cx18/cx18-queue.c +++ b/linux/drivers/media/video/cx18/cx18-queue.c @@ -42,21 +42,32 @@ void cx18_queue_init(struct cx18_queue *q) q->bytesused = 0; } -void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, - struct cx18_queue *q) +struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, + struct cx18_queue *q, int to_front) { - /* clear the buffer if it is going to be enqueued to the free queue */ - if (q == &s->q_free) { + /* clear the buffer if it is not to be enqueued to the full queue */ + if (q != &s->q_full) { buf->bytesused = 0; buf->readpos = 0; buf->b_flags = 0; buf->skipped = 0; } + mutex_lock(&s->qlock); - list_add_tail(&buf->list, &q->list); - atomic_inc(&q->buffers); + + /* q_busy is restricted to 63 buffers to stay within firmware limits */ + if (q == &s->q_busy && atomic_read(&q->buffers) >= 63) + q = &s->q_free; + + if (to_front) + list_add(&buf->list, &q->list); /* LIFO */ + else + list_add_tail(&buf->list, &q->list); /* FIFO */ q->bytesused += buf->bytesused - buf->readpos; + atomic_inc(&q->buffers); + mutex_unlock(&s->qlock); + return q; } struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) @@ -67,9 +78,9 @@ struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) if (!list_empty(&q->list)) { buf = list_entry(q->list.next, struct cx18_buffer, list); list_del_init(q->list.next); - atomic_dec(&q->buffers); q->bytesused -= buf->bytesused - buf->readpos; buf->skipped = 0; + atomic_dec(&q->buffers); } mutex_unlock(&s->qlock); return buf; @@ -82,59 +93,51 @@ struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id, struct cx18_buffer *buf; struct cx18_buffer *ret = NULL; struct list_head *p, *t; - LIST_HEAD(r); mutex_lock(&s->qlock); - list_for_each_safe(p, t, &s->q_free.list) { + list_for_each_safe(p, t, &s->q_busy.list) { buf = list_entry(p, struct cx18_buffer, list); if (buf->id != id) { buf->skipped++; - if (buf->skipped >= atomic_read(&s->q_free.buffers)-1) { + if (buf->skipped >= atomic_read(&s->q_busy.buffers)-1) { /* buffer must have fallen out of rotation */ - atomic_dec(&s->q_free.buffers); - list_move_tail(&buf->list, &r); CX18_WARN("Skipped %s, buffer %d, %d " "times - it must have dropped out of " "rotation\n", s->name, buf->id, buf->skipped); + /* move it to q_free */ + list_move_tail(&buf->list, &s->q_free.list); + buf->bytesused = buf->readpos = buf->b_flags = + buf->skipped = 0; + atomic_dec(&s->q_busy.buffers); + atomic_inc(&s->q_free.buffers); } continue; } buf->bytesused = bytesused; - atomic_dec(&s->q_free.buffers); + /* Sync the buffer before we release the qlock */ + cx18_buf_sync_for_cpu(s, buf); if (s->type == CX18_ENC_STREAM_TYPE_TS) { /* - * TS doesn't use q_full, but for sweeping up lost - * buffers, we want the TS to requeue the buffer just - * before sending the MDL back to the firmware, so we - * pull it off the list here. + * TS doesn't use q_full. As we pull the buffer off of + * the queue here, the caller will have to put it back. */ list_del_init(&buf->list); } else { - atomic_inc(&s->q_full.buffers); - s->q_full.bytesused += buf->bytesused; + /* Move buffer from q_busy to q_full */ list_move_tail(&buf->list, &s->q_full.list); + set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags); + s->q_full.bytesused += buf->bytesused; + atomic_inc(&s->q_full.buffers); } + atomic_dec(&s->q_busy.buffers); ret = buf; break; } mutex_unlock(&s->qlock); - - /* Put lost buffers back into firmware transfer rotation */ - while (!list_empty(&r)) { - buf = list_entry(r.next, struct cx18_buffer, list); - list_del_init(r.next); - cx18_enqueue(s, buf, &s->q_free); - cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, - (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem, - 1, buf->id, s->buf_size); - CX18_INFO("Returning %s, buffer %d back to transfer rotation\n", - s->name, buf->id); - /* and there was much rejoicing... */ - } return ret; } @@ -159,7 +162,7 @@ static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q) void cx18_flush_queues(struct cx18_stream *s) { - cx18_queue_flush(s, &s->q_io); + cx18_queue_flush(s, &s->q_busy); cx18_queue_flush(s, &s->q_full); } diff --git a/linux/drivers/media/video/cx18/cx18-queue.h b/linux/drivers/media/video/cx18/cx18-queue.h index ff50a2b7e..456cec3bc 100644 --- a/linux/drivers/media/video/cx18/cx18-queue.h +++ b/linux/drivers/media/video/cx18/cx18-queue.h @@ -43,9 +43,24 @@ static inline void cx18_buf_sync_for_device(struct cx18_stream *s, void cx18_buf_swap(struct cx18_buffer *buf); /* cx18_queue utility functions */ +struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, + struct cx18_queue *q, int to_front); + +static inline +struct cx18_queue *cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, + struct cx18_queue *q) +{ + return _cx18_enqueue(s, buf, q, 0); /* FIFO */ +} + +static inline +struct cx18_queue *cx18_push(struct cx18_stream *s, struct cx18_buffer *buf, + struct cx18_queue *q) +{ + return _cx18_enqueue(s, buf, q, 1); /* LIFO */ +} + void cx18_queue_init(struct cx18_queue *q); -void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, - struct cx18_queue *q); struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q); struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id, u32 bytesused); diff --git a/linux/drivers/media/video/cx18/cx18-streams.c b/linux/drivers/media/video/cx18/cx18-streams.c index f7a7f38d8..9ed542624 100644 --- a/linux/drivers/media/video/cx18/cx18-streams.c +++ b/linux/drivers/media/video/cx18/cx18-streams.c @@ -111,7 +111,6 @@ static void cx18_stream_init(struct cx18 *cx, int type) { struct cx18_stream *s = &cx->streams[type]; struct video_device *dev = s->v4l2dev; - u32 max_size = cx->options.megabytes[type] * 1024 * 1024; /* we need to keep v4l2dev, so restore it afterwards */ memset(s, 0, sizeof(*s)); @@ -124,21 +123,15 @@ static void cx18_stream_init(struct cx18 *cx, int type) s->handle = CX18_INVALID_TASK_HANDLE; s->dma = cx18_stream_info[type].dma; + s->buffers = cx->stream_buffers[type]; s->buf_size = cx->stream_buf_size[type]; - if (s->buf_size) - s->buffers = max_size / s->buf_size; - if (s->buffers > 63) { - /* Each stream has a maximum of 63 buffers, - ensure we do not exceed that. */ - s->buffers = 63; - s->buf_size = (max_size / s->buffers) & ~0xfff; - } + mutex_init(&s->qlock); init_waitqueue_head(&s->waitq); s->id = -1; cx18_queue_init(&s->q_free); + cx18_queue_init(&s->q_busy); cx18_queue_init(&s->q_full); - cx18_queue_init(&s->q_io); } static int cx18_prep_dev(struct cx18 *cx, int type) @@ -168,7 +161,7 @@ static int cx18_prep_dev(struct cx18 *cx, int type) /* User explicitly selected 0 buffers for these streams, so don't create them. */ if (cx18_stream_info[type].dma != PCI_DMA_NONE && - cx->options.megabytes[type] == 0) { + cx->stream_buffers[type] == 0) { CX18_INFO("Disabled %s device\n", cx18_stream_info[type].name); return 0; } @@ -268,8 +261,9 @@ static int cx18_reg_dev(struct cx18 *cx, int type) switch (vfl_type) { case VFL_TYPE_GRABBER: - CX18_INFO("Registered device video%d for %s (%d MB)\n", - num, s->name, cx->options.megabytes[type]); + CX18_INFO("Registered device video%d for %s (%d x %d kB)\n", + num, s->name, cx->stream_buffers[type], + cx->stream_buf_size[type]/1024); break; case VFL_TYPE_RADIO: @@ -278,10 +272,11 @@ static int cx18_reg_dev(struct cx18 *cx, int type) break; case VFL_TYPE_VBI: - if (cx->options.megabytes[type]) - CX18_INFO("Registered device vbi%d for %s (%d MB)\n", - num, - s->name, cx->options.megabytes[type]); + if (cx->stream_buffers[type]) + CX18_INFO("Registered device vbi%d for %s " + "(%d x %d bytes)\n", + num, s->name, cx->stream_buffers[type], + cx->stream_buf_size[type]); else CX18_INFO("Registered device vbi%d for %s\n", num, s->name); @@ -345,7 +340,7 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister) static void cx18_vbi_setup(struct cx18_stream *s) { struct cx18 *cx = s->cx; - int raw = cx->vbi.sliced_in->service_set == 0; + int raw = cx18_raw_vbi(cx); u32 data[CX2341X_MBOX_MAX_DATA]; int lines; @@ -363,8 +358,7 @@ static void cx18_vbi_setup(struct cx18_stream *s) cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in); /* determine number of lines and total number of VBI bytes. - A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1 - The '- 1' byte is probably an unused U or V byte. Or something... + A raw line takes 1444 bytes: 4 byte SAV code + 2 * 720 A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal header, 42 data bytes + checksum (to be confirmed) */ if (raw) { @@ -382,14 +376,15 @@ static void cx18_vbi_setup(struct cx18_stream *s) /* Lines per field */ data[1] = (lines / 2) | ((lines / 2) << 16); /* bytes per line */ - data[2] = (raw ? cx->vbi.raw_size : cx->vbi.sliced_size); + data[2] = (raw ? cx->vbi.raw_decoder_line_size + : cx->vbi.sliced_decoder_line_size); /* Every X number of frames a VBI interrupt arrives (frames as in 25 or 30 fps) */ data[3] = 1; /* Setup VBI for the cx25840 digitizer */ if (raw) { data[4] = 0x20602060; - data[5] = 0x30703070; + data[5] = 0x307090d0; } else { data[4] = 0xB0F0B0F0; data[5] = 0xA0E0A0E0; @@ -402,11 +397,52 @@ static void cx18_vbi_setup(struct cx18_stream *s) cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data); } +struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s, + struct cx18_buffer *buf) +{ + struct cx18 *cx = s->cx; + struct cx18_queue *q; + + /* Don't give it to the firmware, if we're not running a capture */ + if (s->handle == CX18_INVALID_TASK_HANDLE || + !test_bit(CX18_F_S_STREAMING, &s->s_flags)) + return cx18_enqueue(s, buf, &s->q_free); + + q = cx18_enqueue(s, buf, &s->q_busy); + if (q != &s->q_busy) + return q; /* The firmware has the max buffers it can handle */ + + cx18_buf_sync_for_device(s, buf); + cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, + (void __iomem *) &cx->scb->cpu_mdl[buf->id] - cx->enc_mem, + 1, buf->id, s->buf_size); + return q; +} + +void cx18_stream_load_fw_queue(struct cx18_stream *s) +{ + struct cx18_queue *q; + struct cx18_buffer *buf; + + if (atomic_read(&s->q_free.buffers) == 0 || + atomic_read(&s->q_busy.buffers) >= 63) + return; + + /* Move from q_free to q_busy notifying the firmware, until the limit */ + do { + buf = cx18_dequeue(s, &s->q_free); + if (buf == NULL) + break; + q = cx18_stream_put_buf_fw(s, buf); + } while (atomic_read(&s->q_busy.buffers) < 63 && q == &s->q_busy); +} + int cx18_start_v4l2_encode_stream(struct cx18_stream *s) { u32 data[MAX_MB_ARGUMENTS]; struct cx18 *cx = s->cx; struct list_head *p; + struct cx18_buffer *buf; int ts = 0; int captype = 0; @@ -435,8 +471,8 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) captype = CAPTURE_CHANNEL_TYPE_PCM; break; case CX18_ENC_STREAM_TYPE_VBI: - captype = cx->vbi.sliced_in->service_set ? - CAPTURE_CHANNEL_TYPE_SLICED_VBI : CAPTURE_CHANNEL_TYPE_VBI; + captype = cx18_raw_vbi(cx) ? + CAPTURE_CHANNEL_TYPE_VBI : CAPTURE_CHANNEL_TYPE_SLICED_VBI; cx->vbi.frame = 0; cx->vbi.inserted_frame = 0; memset(cx->vbi.sliced_mpeg_size, @@ -489,16 +525,18 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][0] - cx->enc_mem, (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem); + /* Init all the cpu_mdls for this stream */ + cx18_flush_queues(s); + mutex_lock(&s->qlock); list_for_each(p, &s->q_free.list) { - struct cx18_buffer *buf = list_entry(p, struct cx18_buffer, list); - + buf = list_entry(p, struct cx18_buffer, list); cx18_writel(cx, buf->dma_handle, &cx->scb->cpu_mdl[buf->id].paddr); cx18_writel(cx, s->buf_size, &cx->scb->cpu_mdl[buf->id].length); - cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, - (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem, - 1, buf->id, s->buf_size); } + mutex_unlock(&s->qlock); + cx18_stream_load_fw_queue(s); + /* begin_capture */ if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) { CX18_DEBUG_WARN("Error starting capture!\n"); @@ -507,9 +545,15 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, 1); else cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle); + clear_bit(CX18_F_S_STREAMING, &s->s_flags); + /* FIXME - CX18_F_S_STREAMOFF as well? */ cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle); cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); - /* FIXME - clean-up DSP0_INT mask, i_flags, s_flags, etc. */ + s->handle = CX18_INVALID_TASK_HANDLE; + if (atomic_read(&cx->tot_capturing) == 0) { + set_bit(CX18_F_I_EOS, &cx->i_flags); + cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK); + } return -EINVAL; } diff --git a/linux/drivers/media/video/cx18/cx18-streams.h b/linux/drivers/media/video/cx18/cx18-streams.h index 7218b1504..420e0a172 100644 --- a/linux/drivers/media/video/cx18/cx18-streams.h +++ b/linux/drivers/media/video/cx18/cx18-streams.h @@ -29,6 +29,9 @@ int cx18_streams_register(struct cx18 *cx); void cx18_streams_cleanup(struct cx18 *cx, int unregister); /* Capture related */ +void cx18_stream_load_fw_queue(struct cx18_stream *s); +struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s, + struct cx18_buffer *buf); int cx18_start_v4l2_encode_stream(struct cx18_stream *s); int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end); diff --git a/linux/drivers/media/video/cx18/cx18-vbi.c b/linux/drivers/media/video/cx18/cx18-vbi.c index 22e76ee3f..fb595bd54 100644 --- a/linux/drivers/media/video/cx18/cx18-vbi.c +++ b/linux/drivers/media/video/cx18/cx18-vbi.c @@ -160,11 +160,14 @@ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf, return; /* Raw VBI data */ - if (cx->vbi.sliced_in->service_set == 0) { + if (cx18_raw_vbi(cx)) { u8 type; cx18_buf_swap(buf); + /* Skip 12 bytes of header that gets stuffed in */ + size -= 12; + memcpy(p, &buf->buf[12], size); type = p[3]; size = buf->bytesused = compress_raw_buf(cx, p, size); diff --git a/linux/drivers/media/video/cx18/cx18-version.h b/linux/drivers/media/video/cx18/cx18-version.h index eb043d599..84c0ff13b 100644 --- a/linux/drivers/media/video/cx18/cx18-version.h +++ b/linux/drivers/media/video/cx18/cx18-version.h @@ -25,7 +25,7 @@ #define CX18_DRIVER_NAME "cx18" #define CX18_DRIVER_VERSION_MAJOR 1 #define CX18_DRIVER_VERSION_MINOR 0 -#define CX18_DRIVER_VERSION_PATCHLEVEL 3 +#define CX18_DRIVER_VERSION_PATCHLEVEL 4 #define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL) #define CX18_DRIVER_VERSION KERNEL_VERSION(CX18_DRIVER_VERSION_MAJOR, \ diff --git a/linux/drivers/media/video/cx23885/cx23885-cards.c b/linux/drivers/media/video/cx23885/cx23885-cards.c index dc3f79638..db1e8bdab 100644 --- a/linux/drivers/media/video/cx23885/cx23885-cards.c +++ b/linux/drivers/media/video/cx23885/cx23885-cards.c @@ -159,6 +159,10 @@ struct cx23885_board cx23885_boards[] = { .name = "Leadtek Winfast PxDVR3200 H", .portc = CX23885_MPEG_DVB, }, + [CX23885_BOARD_COMPRO_VIDEOMATE_E650F] = { + .name = "Compro VideoMate E650F", + .portc = CX23885_MPEG_DVB, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -238,6 +242,10 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x107d, .subdevice = 0x6681, .card = CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H, + }, { + .subvendor = 0x185b, + .subdevice = 0xe800, + .card = CX23885_BOARD_COMPRO_VIDEOMATE_E650F, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -391,6 +399,7 @@ int cx23885_tuner_callback(void *priv, int component, int command, int arg) case CX23885_BOARD_HAUPPAUGE_HVR1500: case CX23885_BOARD_HAUPPAUGE_HVR1500Q: case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: + case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: /* Tuner Reset Command */ bitmask = 0x04; break; @@ -531,6 +540,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) cx_set(GP0_IO, 0x000f000f); break; case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: + case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: /* GPIO-2 xc3028 tuner reset */ /* The following GPIO's are on the internal AVCore (cx25840) */ @@ -631,6 +641,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1700: case CX23885_BOARD_HAUPPAUGE_HVR1400: case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: + case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: default: ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ @@ -645,6 +656,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1800lp: case CX23885_BOARD_HAUPPAUGE_HVR1700: case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: + case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: request_module("cx25840"); break; } diff --git a/linux/drivers/media/video/cx23885/cx23885-dvb.c b/linux/drivers/media/video/cx23885/cx23885-dvb.c index a11fdbfb5..990fd217b 100644 --- a/linux/drivers/media/video/cx23885/cx23885-dvb.c +++ b/linux/drivers/media/video/cx23885/cx23885-dvb.c @@ -503,6 +503,7 @@ static int dvb_register(struct cx23885_tsport *port) break; } case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: + case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: i2c_bus = &dev->i2c_bus[0]; fe0->dvb.frontend = dvb_attach(zl10353_attach, diff --git a/linux/drivers/media/video/cx23885/cx23885.h b/linux/drivers/media/video/cx23885/cx23885.h index 26f755354..ad93e0e88 100644 --- a/linux/drivers/media/video/cx23885/cx23885.h +++ b/linux/drivers/media/video/cx23885/cx23885.h @@ -67,6 +67,7 @@ #define CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP 10 #define CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP 11 #define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H 12 +#define CX23885_BOARD_COMPRO_VIDEOMATE_E650F 13 /* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */ #define CX23885_NORMS (\ diff --git a/linux/drivers/media/video/cx88/cx88-alsa.c b/linux/drivers/media/video/cx88/cx88-alsa.c index 3dd2f6629..f7171586d 100644 --- a/linux/drivers/media/video/cx88/cx88-alsa.c +++ b/linux/drivers/media/video/cx88/cx88-alsa.c @@ -795,7 +795,6 @@ static int __devinit snd_cx88_create(struct snd_card *card, core = cx88_core_get(pci); if (NULL == core) { err = -EINVAL; - kfree (chip); return err; } @@ -872,7 +871,7 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, err = snd_cx88_create(card, pci, &chip); if (err < 0) - return (err); + goto error; err = snd_cx88_pcm(chip, 0, "CX88 Digital"); if (err < 0) diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index d38b3ba72..23d3820a2 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -687,6 +687,32 @@ struct em28xx_board em28xx_boards[] = { .gpio = hauppauge_wintv_hvr_900_analog, } }, }, + [EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850] = { + .name = "Hauppauge WinTV HVR 850", + .tuner_type = TUNER_XC2028, + .tuner_gpio = default_tuner_gpio, + .mts_firmware = 1, + .has_dvb = 1, + .dvb_gpio = hauppauge_wintv_hvr_900_digital, + .ir_codes = ir_codes_hauppauge_new, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO, + .gpio = hauppauge_wintv_hvr_900_analog, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + .gpio = hauppauge_wintv_hvr_900_analog, + } }, + }, [EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950] = { .name = "Hauppauge WinTV HVR 950", .tuner_type = TUNER_XC2028, @@ -1212,19 +1238,17 @@ struct em28xx_board em28xx_boards[] = { }, [EM2883_BOARD_KWORLD_HYBRID_A316] = { .name = "Kworld PlusTV HD Hybrid 330", - .valid = EM28XX_BOARD_NOT_VALIDATED, .tuner_type = TUNER_XC2028, .tuner_gpio = default_tuner_gpio, .decoder = EM28XX_TVP5150, -#if 0 /* FIXME: add an entry at em28xx-dvb */ + .mts_firmware = 1, .has_dvb = 1, - .dvb_gpio = hauppauge_wintv_hvr_900_digital, -#endif + .dvb_gpio = default_digital, .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = EM28XX_AMUX_VIDEO, - .gpio = hauppauge_wintv_hvr_900_analog, + .gpio = default_analog, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, @@ -1354,8 +1378,8 @@ struct usb_device_id em28xx_id_table [] = { .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 }, { USB_DEVICE(0x2040, 0x651b), /* RP HVR-950 */ .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 }, - { USB_DEVICE(0x2040, 0x651f), /* HCW HVR-850 */ - .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 }, + { USB_DEVICE(0x2040, 0x651f), + .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 }, { USB_DEVICE(0x0438, 0xb002), .driver_info = EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 }, { USB_DEVICE(0x2001, 0xf112), @@ -1575,6 +1599,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl) ctl->demod = XC3028_FE_DEFAULT; ctl->fname = XC3028L_DEFAULT_FIRMWARE; break; + case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850: case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: /* FIXME: Better to specify the needed IF */ @@ -1759,6 +1784,7 @@ void em28xx_card_setup(struct em28xx *dev) case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: + case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850: case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: { struct tveeprom tv; diff --git a/linux/drivers/media/video/em28xx/em28xx-dvb.c b/linux/drivers/media/video/em28xx/em28xx-dvb.c index a06659f28..8d3ed7dc8 100644 --- a/linux/drivers/media/video/em28xx/em28xx-dvb.c +++ b/linux/drivers/media/video/em28xx/em28xx-dvb.c @@ -410,8 +410,10 @@ static int dvb_init(struct em28xx *dev) em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); /* init frontend */ switch (dev->model) { + case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850: case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: + case EM2883_BOARD_KWORLD_HYBRID_A316: case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: dvb->frontend = dvb_attach(lgdt330x_attach, &em2880_lgdt3303_dev, diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c index 00d49c45f..ff960f90c 100644 --- a/linux/drivers/media/video/em28xx/em28xx-video.c +++ b/linux/drivers/media/video/em28xx/em28xx-video.c @@ -1758,6 +1758,9 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp) return 0; } + /* Save some power by putting tuner to sleep */ + em28xx_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL); + /* do this before setting alternate! */ em28xx_uninit_isoc(dev); em28xx_set_mode(dev, EM28XX_SUSPEND); @@ -2203,6 +2206,9 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, mutex_unlock(&em28xx_extension_devlist_lock); mutex_unlock(&em28xx_devlist_mutex); + /* Save some power by putting tuner to sleep */ + em28xx_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL); + return 0; fail_reg_devices: diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h index 667cb70cf..4de9a8190 100644 --- a/linux/drivers/media/video/em28xx/em28xx.h +++ b/linux/drivers/media/video/em28xx/em28xx.h @@ -99,6 +99,7 @@ #define EM2883_BOARD_KWORLD_HYBRID_A316 57 #define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU 58 #define EM2874_BOARD_PINNACLE_PCTV_80E 59 +#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 60 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 diff --git a/linux/drivers/media/video/mt9m001.c b/linux/drivers/media/video/mt9m001.c index 228183c54..edacba723 100644 --- a/linux/drivers/media/video/mt9m001.c +++ b/linux/drivers/media/video/mt9m001.c @@ -285,8 +285,8 @@ static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd) width_flag; } -static int mt9m001_set_fmt_cap(struct soc_camera_device *icd, - __u32 pixfmt, struct v4l2_rect *rect) +static int mt9m001_set_fmt(struct soc_camera_device *icd, + __u32 pixfmt, struct v4l2_rect *rect) { struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); int ret; @@ -298,7 +298,7 @@ static int mt9m001_set_fmt_cap(struct soc_camera_device *icd, ret = reg_write(icd, MT9M001_VERTICAL_BLANKING, vblank); /* The caller provides a supported format, as verified per - * call to icd->try_fmt_cap() */ + * call to icd->try_fmt() */ if (!ret) ret = reg_write(icd, MT9M001_COLUMN_START, rect->left); if (!ret) @@ -325,8 +325,8 @@ static int mt9m001_set_fmt_cap(struct soc_camera_device *icd, return ret; } -static int mt9m001_try_fmt_cap(struct soc_camera_device *icd, - struct v4l2_format *f) +static int mt9m001_try_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) { if (f->fmt.pix.height < 32 + icd->y_skip_top) f->fmt.pix.height = 32 + icd->y_skip_top; @@ -447,8 +447,8 @@ static struct soc_camera_ops mt9m001_ops = { .release = mt9m001_release, .start_capture = mt9m001_start_capture, .stop_capture = mt9m001_stop_capture, - .set_fmt_cap = mt9m001_set_fmt_cap, - .try_fmt_cap = mt9m001_try_fmt_cap, + .set_fmt = mt9m001_set_fmt, + .try_fmt = mt9m001_try_fmt, .set_bus_param = mt9m001_set_bus_param, .query_bus_param = mt9m001_query_bus_param, .controls = mt9m001_controls, diff --git a/linux/drivers/media/video/mt9m111.c b/linux/drivers/media/video/mt9m111.c index ceff40edc..1fde94514 100644 --- a/linux/drivers/media/video/mt9m111.c +++ b/linux/drivers/media/video/mt9m111.c @@ -452,8 +452,8 @@ static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt) return ret; } -static int mt9m111_set_fmt_cap(struct soc_camera_device *icd, - __u32 pixfmt, struct v4l2_rect *rect) +static int mt9m111_set_fmt(struct soc_camera_device *icd, + __u32 pixfmt, struct v4l2_rect *rect) { struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); int ret; @@ -473,8 +473,8 @@ static int mt9m111_set_fmt_cap(struct soc_camera_device *icd, return ret; } -static int mt9m111_try_fmt_cap(struct soc_camera_device *icd, - struct v4l2_format *f) +static int mt9m111_try_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) { if (f->fmt.pix.height > MT9M111_MAX_HEIGHT) f->fmt.pix.height = MT9M111_MAX_HEIGHT; @@ -597,8 +597,8 @@ static struct soc_camera_ops mt9m111_ops = { .release = mt9m111_release, .start_capture = mt9m111_start_capture, .stop_capture = mt9m111_stop_capture, - .set_fmt_cap = mt9m111_set_fmt_cap, - .try_fmt_cap = mt9m111_try_fmt_cap, + .set_fmt = mt9m111_set_fmt, + .try_fmt = mt9m111_try_fmt, .query_bus_param = mt9m111_query_bus_param, .set_bus_param = mt9m111_set_bus_param, .controls = mt9m111_controls, diff --git a/linux/drivers/media/video/mt9v022.c b/linux/drivers/media/video/mt9v022.c index bea695a2c..1ca28c087 100644 --- a/linux/drivers/media/video/mt9v022.c +++ b/linux/drivers/media/video/mt9v022.c @@ -337,14 +337,14 @@ static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd) width_flag; } -static int mt9v022_set_fmt_cap(struct soc_camera_device *icd, - __u32 pixfmt, struct v4l2_rect *rect) +static int mt9v022_set_fmt(struct soc_camera_device *icd, + __u32 pixfmt, struct v4l2_rect *rect) { struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); int ret; /* The caller provides a supported format, as verified per call to - * icd->try_fmt_cap(), datawidth is from our supported format list */ + * icd->try_fmt(), datawidth is from our supported format list */ switch (pixfmt) { case V4L2_PIX_FMT_GREY: case V4L2_PIX_FMT_Y16: @@ -400,8 +400,8 @@ static int mt9v022_set_fmt_cap(struct soc_camera_device *icd, return 0; } -static int mt9v022_try_fmt_cap(struct soc_camera_device *icd, - struct v4l2_format *f) +static int mt9v022_try_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) { if (f->fmt.pix.height < 32 + icd->y_skip_top) f->fmt.pix.height = 32 + icd->y_skip_top; @@ -538,8 +538,8 @@ static struct soc_camera_ops mt9v022_ops = { .release = mt9v022_release, .start_capture = mt9v022_start_capture, .stop_capture = mt9v022_stop_capture, - .set_fmt_cap = mt9v022_set_fmt_cap, - .try_fmt_cap = mt9v022_try_fmt_cap, + .set_fmt = mt9v022_set_fmt, + .try_fmt = mt9v022_try_fmt, .set_bus_param = mt9v022_set_bus_param, .query_bus_param = mt9v022_query_bus_param, .controls = mt9v022_controls, diff --git a/linux/drivers/media/video/ov772x.c b/linux/drivers/media/video/ov772x.c index 2ddc2ab70..c023bbc84 100644 --- a/linux/drivers/media/video/ov772x.c +++ b/linux/drivers/media/video/ov772x.c @@ -112,34 +112,34 @@ #define AREF7 0x55 /* Analog reference control */ #define UFIX 0x60 /* U channel fixed value output */ #define VFIX 0x61 /* V channel fixed value output */ -#define AW_BB_BLK 0x62 /* AWB option for advanced AWB */ -#define AW_B_CTRL0 0x63 /* AWB control byte 0 */ +#define AWBB_BLK 0x62 /* AWB option for advanced AWB */ +#define AWB_CTRL0 0x63 /* AWB control byte 0 */ #define DSP_CTRL1 0x64 /* DSP control byte 1 */ #define DSP_CTRL2 0x65 /* DSP control byte 2 */ #define DSP_CTRL3 0x66 /* DSP control byte 3 */ #define DSP_CTRL4 0x67 /* DSP control byte 4 */ -#define AW_B_BIAS 0x68 /* AWB BLC level clip */ -#define AW_BCTRL1 0x69 /* AWB control 1 */ -#define AW_BCTRL2 0x6A /* AWB control 2 */ -#define AW_BCTRL3 0x6B /* AWB control 3 */ -#define AW_BCTRL4 0x6C /* AWB control 4 */ -#define AW_BCTRL5 0x6D /* AWB control 5 */ -#define AW_BCTRL6 0x6E /* AWB control 6 */ -#define AW_BCTRL7 0x6F /* AWB control 7 */ -#define AW_BCTRL8 0x70 /* AWB control 8 */ -#define AW_BCTRL9 0x71 /* AWB control 9 */ -#define AW_BCTRL10 0x72 /* AWB control 10 */ -#define AW_BCTRL11 0x73 /* AWB control 11 */ -#define AW_BCTRL12 0x74 /* AWB control 12 */ -#define AW_BCTRL13 0x75 /* AWB control 13 */ -#define AW_BCTRL14 0x76 /* AWB control 14 */ -#define AW_BCTRL15 0x77 /* AWB control 15 */ -#define AW_BCTRL16 0x78 /* AWB control 16 */ -#define AW_BCTRL17 0x79 /* AWB control 17 */ -#define AW_BCTRL18 0x7A /* AWB control 18 */ -#define AW_BCTRL19 0x7B /* AWB control 19 */ -#define AW_BCTRL20 0x7C /* AWB control 20 */ -#define AW_BCTRL21 0x7D /* AWB control 21 */ +#define AWB_BIAS 0x68 /* AWB BLC level clip */ +#define AWB_CTRL1 0x69 /* AWB control 1 */ +#define AWB_CTRL2 0x6A /* AWB control 2 */ +#define AWB_CTRL3 0x6B /* AWB control 3 */ +#define AWB_CTRL4 0x6C /* AWB control 4 */ +#define AWB_CTRL5 0x6D /* AWB control 5 */ +#define AWB_CTRL6 0x6E /* AWB control 6 */ +#define AWB_CTRL7 0x6F /* AWB control 7 */ +#define AWB_CTRL8 0x70 /* AWB control 8 */ +#define AWB_CTRL9 0x71 /* AWB control 9 */ +#define AWB_CTRL10 0x72 /* AWB control 10 */ +#define AWB_CTRL11 0x73 /* AWB control 11 */ +#define AWB_CTRL12 0x74 /* AWB control 12 */ +#define AWB_CTRL13 0x75 /* AWB control 13 */ +#define AWB_CTRL14 0x76 /* AWB control 14 */ +#define AWB_CTRL15 0x77 /* AWB control 15 */ +#define AWB_CTRL16 0x78 /* AWB control 16 */ +#define AWB_CTRL17 0x79 /* AWB control 17 */ +#define AWB_CTRL18 0x7A /* AWB control 18 */ +#define AWB_CTRL19 0x7B /* AWB control 19 */ +#define AWB_CTRL20 0x7C /* AWB control 20 */ +#define AWB_CTRL21 0x7D /* AWB control 21 */ #define GAM1 0x7E /* Gamma Curve 1st segment input end point */ #define GAM2 0x7F /* Gamma Curve 2nd segment input end point */ #define GAM3 0x80 /* Gamma Curve 3rd segment input end point */ @@ -593,12 +593,30 @@ static int ov772x_reset(struct i2c_client *client) static int ov772x_init(struct soc_camera_device *icd) { - return 0; + struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); + int ret = 0; + + if (priv->info->link.power) { + ret = priv->info->link.power(&priv->client->dev, 1); + if (ret < 0) + return ret; + } + + if (priv->info->link.reset) + ret = priv->info->link.reset(&priv->client->dev); + + return ret; } static int ov772x_release(struct soc_camera_device *icd) { - return 0; + struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); + int ret = 0; + + if (priv->info->link.power) + ret = priv->info->link.power(&priv->client->dev, 0); + + return ret; } static int ov772x_start_capture(struct soc_camera_device *icd) @@ -737,9 +755,9 @@ static int ov772x_set_register(struct soc_camera_device *icd, } #endif -static int ov772x_set_fmt_cap(struct soc_camera_device *icd, - __u32 pixfmt, - struct v4l2_rect *rect) +static int ov772x_set_fmt(struct soc_camera_device *icd, + __u32 pixfmt, + struct v4l2_rect *rect) { struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); int ret = -EINVAL; @@ -760,8 +778,8 @@ static int ov772x_set_fmt_cap(struct soc_camera_device *icd, return ret; } -static int ov772x_try_fmt_cap(struct soc_camera_device *icd, - struct v4l2_format *f) +static int ov772x_try_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) { struct v4l2_pix_format *pix = &f->fmt.pix; struct ov772x_priv *priv; @@ -814,9 +832,6 @@ static int ov772x_video_probe(struct soc_camera_device *icd) icd->formats = ov772x_fmt_lists; icd->num_formats = ARRAY_SIZE(ov772x_fmt_lists); - if (priv->info->link.power) - priv->info->link.power(&priv->client->dev, 1); - /* * check and show product ID and manufacturer ID */ @@ -824,8 +839,8 @@ static int ov772x_video_probe(struct soc_camera_device *icd) ver = i2c_smbus_read_byte_data(priv->client, VER); if (pid != 0x77 || ver != 0x21) { - if (priv->info->link.power) - priv->info->link.power(&priv->client->dev, 0); + dev_err(&icd->dev, + "Product ID error %x:%x\n", pid, ver); return -ENODEV; } @@ -842,13 +857,7 @@ static int ov772x_video_probe(struct soc_camera_device *icd) static void ov772x_video_remove(struct soc_camera_device *icd) { - struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); - soc_camera_video_stop(icd); - - if (priv->info->link.power) - priv->info->link.power(&priv->client->dev, 0); - } static struct soc_camera_ops ov772x_ops = { @@ -859,8 +868,8 @@ static struct soc_camera_ops ov772x_ops = { .release = ov772x_release, .start_capture = ov772x_start_capture, .stop_capture = ov772x_stop_capture, - .set_fmt_cap = ov772x_set_fmt_cap, - .try_fmt_cap = ov772x_try_fmt_cap, + .set_fmt = ov772x_set_fmt, + .try_fmt = ov772x_try_fmt, .set_bus_param = ov772x_set_bus_param, .query_bus_param = ov772x_query_bus_param, .get_chip_id = ov772x_get_chip_id, diff --git a/linux/drivers/media/video/pxa_camera.c b/linux/drivers/media/video/pxa_camera.c index 08723ed84..210a99780 100644 --- a/linux/drivers/media/video/pxa_camera.c +++ b/linux/drivers/media/video/pxa_camera.c @@ -770,6 +770,9 @@ static int test_platform_param(struct pxa_camera_dev *pcdev, if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8)) return -EINVAL; *flags |= SOCAM_DATAWIDTH_8; + break; + default: + return -EINVAL; } return 0; @@ -828,12 +831,10 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) * We fix bit-per-pixel equal to data-width... */ switch (common_flags & SOCAM_DATAWIDTH_MASK) { case SOCAM_DATAWIDTH_10: - icd->buswidth = 10; dw = 4; bpp = 0x40; break; case SOCAM_DATAWIDTH_9: - icd->buswidth = 9; dw = 3; bpp = 0x20; break; @@ -841,7 +842,6 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) /* Actually it can only be 8 now, * default is just to silence compiler warnings */ case SOCAM_DATAWIDTH_8: - icd->buswidth = 8; dw = 2; bpp = 0; } @@ -867,7 +867,17 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) case V4L2_PIX_FMT_YUV422P: pcdev->channels = 3; cicr1 |= CICR1_YCBCR_F; + /* + * Normally, pxa bus wants as input UYVY format. We allow all + * reorderings of the YUV422 format, as no processing is done, + * and the YUV stream is just passed through without any + * transformation. Note that UYVY is the only format that + * should be used if pxa framebuffer Overlay2 is used. + */ + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: cicr1 |= CICR1_COLOR_SP_VAL(2); break; case V4L2_PIX_FMT_RGB555: @@ -893,13 +903,14 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) return 0; } -static int pxa_camera_try_bus_param(struct soc_camera_device *icd, __u32 pixfmt) +static int pxa_camera_try_bus_param(struct soc_camera_device *icd, + unsigned char buswidth) { struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct pxa_camera_dev *pcdev = ici->priv; unsigned long bus_flags, camera_flags; - int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags); + int ret = test_platform_param(pcdev, buswidth, &bus_flags); if (ret < 0) return ret; @@ -909,28 +920,174 @@ static int pxa_camera_try_bus_param(struct soc_camera_device *icd, __u32 pixfmt) return soc_camera_bus_param_compatible(camera_flags, bus_flags) ? 0 : -EINVAL; } -static int pxa_camera_set_fmt_cap(struct soc_camera_device *icd, - __u32 pixfmt, struct v4l2_rect *rect) +static const struct soc_camera_data_format pxa_camera_formats[] = { + { + .name = "Planar YUV422 16 bit", + .depth = 16, + .fourcc = V4L2_PIX_FMT_YUV422P, + .colorspace = V4L2_COLORSPACE_JPEG, + }, +}; + +static bool buswidth_supported(struct soc_camera_device *icd, int depth) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct pxa_camera_dev *pcdev = ici->priv; + + switch (depth) { + case 8: + return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8); + case 9: + return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9); + case 10: + return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10); + } + return false; +} + +static int required_buswidth(const struct soc_camera_data_format *fmt) +{ + switch (fmt->fourcc) { + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB555: + return 8; + default: + return fmt->depth; + } +} + +static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx, + struct soc_camera_format_xlate *xlate) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + int formats = 0, buswidth, ret; + + buswidth = required_buswidth(icd->formats + idx); + + if (!buswidth_supported(icd, buswidth)) + return 0; + + ret = pxa_camera_try_bus_param(icd, buswidth); + if (ret < 0) + return 0; + + switch (icd->formats[idx].fourcc) { + case V4L2_PIX_FMT_UYVY: + formats++; + if (xlate) { + xlate->host_fmt = &pxa_camera_formats[0]; + xlate->cam_fmt = icd->formats + idx; + xlate->buswidth = buswidth; + xlate++; + dev_dbg(&ici->dev, "Providing format %s using %s\n", + pxa_camera_formats[0].name, + icd->formats[idx].name); + } + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB555: + formats++; + if (xlate) { + xlate->host_fmt = icd->formats + idx; + xlate->cam_fmt = icd->formats + idx; + xlate->buswidth = buswidth; + xlate++; + dev_dbg(&ici->dev, "Providing format %s packed\n", + icd->formats[idx].name); + } + break; + default: + /* Generic pass-through */ + formats++; + if (xlate) { + xlate->host_fmt = icd->formats + idx; + xlate->cam_fmt = icd->formats + idx; + xlate->buswidth = icd->formats[idx].depth; + xlate++; + dev_dbg(&ici->dev, + "Providing format %s in pass-through mode\n", + icd->formats[idx].name); + } + } + + return formats; +} + +static int pxa_camera_set_fmt(struct soc_camera_device *icd, + __u32 pixfmt, struct v4l2_rect *rect) { - return icd->ops->set_fmt_cap(icd, pixfmt, rect); + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + const struct soc_camera_data_format *host_fmt, *cam_fmt = NULL; + const struct soc_camera_format_xlate *xlate; + int ret, buswidth; + + xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); + if (!xlate) { + dev_warn(&ici->dev, "Format %x not found\n", pixfmt); + return -EINVAL; + } + + buswidth = xlate->buswidth; + host_fmt = xlate->host_fmt; + cam_fmt = xlate->cam_fmt; + + switch (pixfmt) { + case 0: /* Only geometry change */ + ret = icd->ops->set_fmt(icd, pixfmt, rect); + break; + default: + ret = icd->ops->set_fmt(icd, cam_fmt->fourcc, rect); + } + + if (ret < 0) + dev_warn(&ici->dev, "Failed to configure for format %x\n", + pixfmt); + + if (pixfmt && !ret) { + icd->buswidth = buswidth; + icd->current_fmt = host_fmt; + } + + return ret; } -static int pxa_camera_try_fmt_cap(struct soc_camera_device *icd, - struct v4l2_format *f) +static int pxa_camera_try_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) { + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + const struct soc_camera_format_xlate *xlate; + struct v4l2_pix_format *pix = &f->fmt.pix; + __u32 pixfmt = pix->pixelformat; + + xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); + if (!xlate) { + dev_warn(&ici->dev, "Format %x not found\n", pixfmt); + return -EINVAL; + } + /* limit to pxa hardware capabilities */ - if (f->fmt.pix.height < 32) - f->fmt.pix.height = 32; - if (f->fmt.pix.height > 2048) - f->fmt.pix.height = 2048; - if (f->fmt.pix.width < 48) - f->fmt.pix.width = 48; - if (f->fmt.pix.width > 2048) - f->fmt.pix.width = 2048; - f->fmt.pix.width &= ~0x01; + if (pix->height < 32) + pix->height = 32; + if (pix->height > 2048) + pix->height = 2048; + if (pix->width < 48) + pix->width = 48; + if (pix->width > 2048) + pix->width = 2048; + pix->width &= ~0x01; + + pix->bytesperline = pix->width * + DIV_ROUND_UP(xlate->host_fmt->depth, 8); + pix->sizeimage = pix->height * pix->bytesperline; /* limit to sensor capabilities */ - return icd->ops->try_fmt_cap(icd, f); + return icd->ops->try_fmt(icd, f); } static int pxa_camera_reqbufs(struct soc_camera_file *icf, @@ -1038,13 +1195,13 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = { .remove = pxa_camera_remove_device, .suspend = pxa_camera_suspend, .resume = pxa_camera_resume, - .set_fmt_cap = pxa_camera_set_fmt_cap, - .try_fmt_cap = pxa_camera_try_fmt_cap, + .get_formats = pxa_camera_get_formats, + .set_fmt = pxa_camera_set_fmt, + .try_fmt = pxa_camera_try_fmt, .init_videobuf = pxa_camera_init_videobuf, .reqbufs = pxa_camera_reqbufs, .poll = pxa_camera_poll, .querycap = pxa_camera_querycap, - .try_bus_param = pxa_camera_try_bus_param, .set_bus_param = pxa_camera_set_bus_param, }; diff --git a/linux/drivers/media/video/saa7134/saa7134-cards.c b/linux/drivers/media/video/saa7134/saa7134-cards.c index d4c432cb3..54be8314f 100644 --- a/linux/drivers/media/video/saa7134/saa7134-cards.c +++ b/linux/drivers/media/video/saa7134/saa7134-cards.c @@ -4645,6 +4645,43 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x0200000, }, }, + [SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG] = { + .name = "Kworld Plus TV Analog Lite PCI", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_YMEC_TVF_5533MF, + .radio_type = TUNER_TEA5767, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .gpiomask = 0x80000700, + .inputs = { { + .name = name_tv, + .vmux = 1, + .amux = LINE2, + .tv = 1, + .gpio = 0x100, + }, { + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + .gpio = 0x200, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + .gpio = 0x200, + } }, + .radio = { + .name = name_radio, + .vmux = 1, + .amux = LINE1, + .gpio = 0x100, + }, + .mute = { + .name = name_mute, + .vmux = 8, + .amux = 2, + }, + }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -4775,6 +4812,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .driver_data = SAA7134_BOARD_MD7134, },{ .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x16be, /* CTX946 analog TV, HW mpeg, DVB-T */ + .subdevice = 0x5000, /* only analog TV and DVB-T for now */ + .driver_data = SAA7134_BOARD_MD7134, + }, { + .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, .subvendor = 0x1048, .subdevice = 0x226b, @@ -5692,6 +5735,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subdevice = 0x4878, /* REV:1.02G */ .driver_data = SAA7134_BOARD_ASUSTeK_TIGER_3IN1, }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x17de, + .subdevice = 0x7128, + .driver_data = SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG, + }, { /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, @@ -5979,6 +6028,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_BEHOLD_507_9FM: case SAA7134_BOARD_GENIUS_TVGO_A11MCE: case SAA7134_BOARD_REAL_ANGEL_220: + case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG: dev->has_remote = SAA7134_REMOTE_GPIO; break; case SAA7134_BOARD_FLYDVBS_LR300: diff --git a/linux/drivers/media/video/saa7134/saa7134-input.c b/linux/drivers/media/video/saa7134/saa7134-input.c index 1c4bd413e..272490b92 100644 --- a/linux/drivers/media/video/saa7134/saa7134-input.c +++ b/linux/drivers/media/video/saa7134/saa7134-input.c @@ -97,6 +97,15 @@ static int build_key(struct saa7134_dev *dev) dprintk("build_key gpio=0x%x mask=0x%x data=%d\n", gpio, ir->mask_keycode, data); + switch (dev->board) { + case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG: + if (data == ir->mask_keycode) + ir_input_nokey(ir->dev, &ir->ir); + else + ir_input_keydown(ir->dev, &ir->ir, data, data); + return 0; + } + if (ir->polling) { if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) || (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) { @@ -586,6 +595,11 @@ int saa7134_input_init1(struct saa7134_dev *dev) mask_keyup = 0x4000; polling = 50; /* ms */ break; + case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG: + ir_codes = ir_codes_kworld_plus_tv_analog; + mask_keycode = 0x7f; + polling = 40; /* ms */ + break; } if (NULL == ir_codes) { printk("%s: Oops: IR config error [card=%d]\n", diff --git a/linux/drivers/media/video/saa7134/saa7134.h b/linux/drivers/media/video/saa7134/saa7134.h index 82f9a889a..3bb599673 100644 --- a/linux/drivers/media/video/saa7134/saa7134.h +++ b/linux/drivers/media/video/saa7134/saa7134.h @@ -276,6 +276,7 @@ struct saa7134_format { #define SAA7134_BOARD_REAL_ANGEL_220 150 #define SAA7134_BOARD_ADS_INSTANT_HDTV_PCI 151 #define SAA7134_BOARD_ASUSTeK_TIGER 152 +#define SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG 153 #define SAA7134_MAXBOARDS 32 #define SAA7134_INPUT_MAX 8 diff --git a/linux/drivers/media/video/sh_mobile_ceu_camera.c b/linux/drivers/media/video/sh_mobile_ceu_camera.c index 2fb8bee0b..e2e816213 100644 --- a/linux/drivers/media/video/sh_mobile_ceu_camera.c +++ b/linux/drivers/media/video/sh_mobile_ceu_camera.c @@ -445,15 +445,46 @@ static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd, return 0; } -static int sh_mobile_ceu_set_fmt_cap(struct soc_camera_device *icd, - __u32 pixfmt, struct v4l2_rect *rect) +static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, + __u32 pixfmt, struct v4l2_rect *rect) { - return icd->ops->set_fmt_cap(icd, pixfmt, rect); + const struct soc_camera_data_format *cam_fmt; + int ret; + + /* + * TODO: find a suitable supported by the SoC output format, check + * whether the sensor supports one of acceptable input formats. + */ + if (pixfmt) { + cam_fmt = soc_camera_format_by_fourcc(icd, pixfmt); + if (!cam_fmt) + return -EINVAL; + } + + ret = icd->ops->set_fmt(icd, pixfmt, rect); + if (pixfmt && !ret) + icd->current_fmt = cam_fmt; + + return ret; } -static int sh_mobile_ceu_try_fmt_cap(struct soc_camera_device *icd, - struct v4l2_format *f) +static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) { + const struct soc_camera_data_format *cam_fmt; + int ret = sh_mobile_ceu_try_bus_param(icd, f->fmt.pix.pixelformat); + + if (ret < 0) + return ret; + + /* + * TODO: find a suitable supported by the SoC output format, check + * whether the sensor supports one of acceptable input formats. + */ + cam_fmt = soc_camera_format_by_fourcc(icd, f->fmt.pix.pixelformat); + if (!cam_fmt) + return -EINVAL; + /* FIXME: calculate using depth and bus width */ if (f->fmt.pix.height < 4) @@ -467,8 +498,12 @@ static int sh_mobile_ceu_try_fmt_cap(struct soc_camera_device *icd, f->fmt.pix.width &= ~0x01; f->fmt.pix.height &= ~0x03; + f->fmt.pix.bytesperline = f->fmt.pix.width * + DIV_ROUND_UP(cam_fmt->depth, 8); + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + /* limit to sensor capabilities */ - return icd->ops->try_fmt_cap(icd, f); + return icd->ops->try_fmt(icd, f); } static int sh_mobile_ceu_reqbufs(struct soc_camera_file *icf, @@ -536,12 +571,11 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = { .owner = THIS_MODULE, .add = sh_mobile_ceu_add_device, .remove = sh_mobile_ceu_remove_device, - .set_fmt_cap = sh_mobile_ceu_set_fmt_cap, - .try_fmt_cap = sh_mobile_ceu_try_fmt_cap, + .set_fmt = sh_mobile_ceu_set_fmt, + .try_fmt = sh_mobile_ceu_try_fmt, .reqbufs = sh_mobile_ceu_reqbufs, .poll = sh_mobile_ceu_poll, .querycap = sh_mobile_ceu_querycap, - .try_bus_param = sh_mobile_ceu_try_bus_param, .set_bus_param = sh_mobile_ceu_set_bus_param, .init_videobuf = sh_mobile_ceu_init_videobuf, }; diff --git a/linux/drivers/media/video/soc_camera.c b/linux/drivers/media/video/soc_camera.c index 7a46697c4..4a9c52c37 100644 --- a/linux/drivers/media/video/soc_camera.c +++ b/linux/drivers/media/video/soc_camera.c @@ -36,8 +36,8 @@ static LIST_HEAD(devices); static DEFINE_MUTEX(list_lock); static DEFINE_MUTEX(video_lock); -const static struct soc_camera_data_format* -format_by_fourcc(struct soc_camera_device *icd, unsigned int fourcc) +const struct soc_camera_data_format *soc_camera_format_by_fourcc( + struct soc_camera_device *icd, unsigned int fourcc) { unsigned int i; @@ -46,52 +46,47 @@ format_by_fourcc(struct soc_camera_device *icd, unsigned int fourcc) return icd->formats + i; return NULL; } +EXPORT_SYMBOL(soc_camera_format_by_fourcc); + +const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( + struct soc_camera_device *icd, unsigned int fourcc) +{ + unsigned int i; + + for (i = 0; i < icd->num_user_formats; i++) + if (icd->user_formats[i].host_fmt->fourcc == fourcc) + return icd->user_formats + i; + return NULL; +} +EXPORT_SYMBOL(soc_camera_xlate_by_fourcc); static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) + struct v4l2_format *f) { struct soc_camera_file *icf = file->private_data; struct soc_camera_device *icd = icf->icd; struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); enum v4l2_field field; - const struct soc_camera_data_format *fmt; int ret; WARN_ON(priv != file->private_data); - fmt = format_by_fourcc(icd, f->fmt.pix.pixelformat); - if (!fmt) { - dev_dbg(&icd->dev, "invalid format 0x%08x\n", - f->fmt.pix.pixelformat); - return -EINVAL; - } - - dev_dbg(&icd->dev, "fmt: 0x%08x\n", fmt->fourcc); - + /* + * TODO: this might also have to migrate to host-drivers, if anyone + * wishes to support other fields + */ field = f->fmt.pix.field; if (field == V4L2_FIELD_ANY) { - field = V4L2_FIELD_NONE; - } else if (V4L2_FIELD_NONE != field) { + f->fmt.pix.field = V4L2_FIELD_NONE; + } else if (field != V4L2_FIELD_NONE) { dev_err(&icd->dev, "Field type invalid.\n"); return -EINVAL; } - /* test physical bus parameters */ - ret = ici->ops->try_bus_param(icd, f->fmt.pix.pixelformat); - if (ret) - return ret; - /* limit format to hardware capabilities */ - ret = ici->ops->try_fmt_cap(icd, f); - - /* calculate missing fields */ - f->fmt.pix.field = field; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; + ret = ici->ops->try_fmt(icd, f); return ret; } @@ -179,6 +174,59 @@ static int soc_camera_dqbuf(struct file *file, void *priv, return videobuf_dqbuf(&icf->vb_vidq, p, file->f_flags & O_NONBLOCK); } +static int soc_camera_init_user_formats(struct soc_camera_device *icd) +{ + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + int i, fmts = 0; + + if (!ici->ops->get_formats) + /* + * Fallback mode - the host will have to serve all + * sensor-provided formats one-to-one to the user + */ + fmts = icd->num_formats; + else + /* + * First pass - only count formats this host-sensor + * configuration can provide + */ + for (i = 0; i < icd->num_formats; i++) + fmts += ici->ops->get_formats(icd, i, NULL); + + if (!fmts) + return -ENXIO; + + icd->user_formats = + vmalloc(fmts * sizeof(struct soc_camera_format_xlate)); + if (!icd->user_formats) + return -ENOMEM; + + icd->num_user_formats = fmts; + fmts = 0; + + dev_dbg(&icd->dev, "Found %d supported formats.\n", fmts); + + /* Second pass - actually fill data formats */ + for (i = 0; i < icd->num_formats; i++) + if (!ici->ops->get_formats) { + icd->user_formats[i].host_fmt = icd->formats + i; + icd->user_formats[i].cam_fmt = icd->formats + i; + icd->user_formats[i].buswidth = icd->formats[i].depth; + } else { + fmts += ici->ops->get_formats(icd, i, + &icd->user_formats[fmts]); + } + + icd->current_fmt = icd->user_formats[0].host_fmt; + + return 0; +} + +static void soc_camera_free_user_formats(struct soc_camera_device *icd) +{ + vfree(icd->user_formats); +} + static int soc_camera_open(struct inode *inode, struct file *file) { struct video_device *vdev; @@ -215,10 +263,12 @@ static int soc_camera_open(struct inode *inode, struct file *file) /* Now we really have to activate the camera */ if (icd->use_count == 1) { + ret = soc_camera_init_user_formats(icd); + if (ret < 0) + goto eiufmt; ret = ici->ops->add(icd); if (ret < 0) { dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret); - icd->use_count--; goto eiciadd; } } @@ -234,6 +284,9 @@ static int soc_camera_open(struct inode *inode, struct file *file) /* All errors are entered with the video_lock held */ eiciadd: + soc_camera_free_user_formats(icd); +eiufmt: + icd->use_count--; module_put(ici->ops->owner); emgi: module_put(icd->ops->owner); @@ -252,8 +305,10 @@ static int soc_camera_close(struct inode *inode, struct file *file) mutex_lock(&video_lock); icd->use_count--; - if (!icd->use_count) + if (!icd->use_count) { ici->ops->remove(icd); + soc_camera_free_user_formats(icd); + } module_put(icd->ops->owner); module_put(ici->ops->owner); mutex_unlock(&video_lock); @@ -266,7 +321,7 @@ static int soc_camera_close(struct inode *inode, struct file *file) } static ssize_t soc_camera_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) + size_t count, loff_t *ppos) { struct soc_camera_file *icf = file->private_data; struct soc_camera_device *icd = icf->icd; @@ -311,7 +366,6 @@ static unsigned int soc_camera_poll(struct file *file, poll_table *pt) return ici->ops->poll(file, pt); } - static struct file_operations soc_camera_fops = { .owner = THIS_MODULE, .open = soc_camera_open, @@ -323,28 +377,20 @@ static struct file_operations soc_camera_fops = { .llseek = no_llseek, }; - static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) + struct v4l2_format *f) { struct soc_camera_file *icf = file->private_data; struct soc_camera_device *icd = icf->icd; struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + __u32 pixfmt = f->fmt.pix.pixelformat; int ret; struct v4l2_rect rect; - const static struct soc_camera_data_format *data_fmt; WARN_ON(priv != file->private_data); - data_fmt = format_by_fourcc(icd, f->fmt.pix.pixelformat); - if (!data_fmt) - return -EINVAL; - - /* buswidth may be further adjusted by the ici */ - icd->buswidth = data_fmt->depth; - - ret = soc_camera_try_fmt_vid_cap(file, icf, f); + ret = soc_camera_try_fmt_vid_cap(file, priv, f); if (ret < 0) return ret; @@ -352,15 +398,20 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, rect.top = icd->y_current; rect.width = f->fmt.pix.width; rect.height = f->fmt.pix.height; - ret = ici->ops->set_fmt_cap(icd, f->fmt.pix.pixelformat, &rect); - if (ret < 0) + ret = ici->ops->set_fmt(icd, f->fmt.pix.pixelformat, &rect); + if (ret < 0) { return ret; + } else if (!icd->current_fmt || + icd->current_fmt->fourcc != pixfmt) { + dev_err(&ici->dev, + "Host driver hasn't set up current format correctly!\n"); + return -EINVAL; + } - icd->current_fmt = data_fmt; icd->width = rect.width; icd->height = rect.height; icf->vb_vidq.field = f->fmt.pix.field; - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != f->type) + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n", f->type); @@ -368,11 +419,11 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, icd->width, icd->height); /* set physical bus parameters */ - return ici->ops->set_bus_param(icd, f->fmt.pix.pixelformat); + return ici->ops->set_bus_param(icd, pixfmt); } static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) + struct v4l2_fmtdesc *f) { struct soc_camera_file *icf = file->private_data; struct soc_camera_device *icd = icf->icd; @@ -380,10 +431,10 @@ static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv, WARN_ON(priv != file->private_data); - if (f->index >= icd->num_formats) + if (f->index >= icd->num_user_formats) return -EINVAL; - format = &icd->formats[f->index]; + format = icd->user_formats[f->index].host_fmt; strlcpy(f->description, format->name, sizeof(f->description)); f->pixelformat = format->fourcc; @@ -391,7 +442,7 @@ static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv, } static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) + struct v4l2_format *f) { struct soc_camera_file *icf = file->private_data; struct soc_camera_device *icd = icf->icd; @@ -402,10 +453,9 @@ static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.height = icd->height; f->fmt.pix.field = icf->vb_vidq.field; f->fmt.pix.pixelformat = icd->current_fmt->fourcc; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * icd->current_fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; + f->fmt.pix.bytesperline = f->fmt.pix.width * + DIV_ROUND_UP(icd->current_fmt->depth, 8); + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n", icd->current_fmt->fourcc); return 0; @@ -575,7 +625,7 @@ static int soc_camera_s_crop(struct file *file, void *fh, if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - ret = ici->ops->set_fmt_cap(icd, 0, &a->c); + ret = ici->ops->set_fmt(icd, 0, &a->c); if (!ret) { icd->width = a->c.width; icd->height = a->c.height; @@ -941,8 +991,6 @@ int soc_camera_video_start(struct soc_camera_device *icd) vdev->minor = -1; vdev->tvnorms = V4L2_STD_UNKNOWN, - icd->current_fmt = &icd->formats[0]; - err = video_register_device(vdev, VFL_TYPE_GRABBER, vdev->minor); if (err < 0) { dev_err(vdev->parent, "video_register_device failed\n"); diff --git a/linux/drivers/media/video/soc_camera_platform.c b/linux/drivers/media/video/soc_camera_platform.c index bb7a9d480..c23871e4c 100644 --- a/linux/drivers/media/video/soc_camera_platform.c +++ b/linux/drivers/media/video/soc_camera_platform.c @@ -79,14 +79,14 @@ soc_camera_platform_query_bus_param(struct soc_camera_device *icd) return p->bus_param; } -static int soc_camera_platform_set_fmt_cap(struct soc_camera_device *icd, - __u32 pixfmt, struct v4l2_rect *rect) +static int soc_camera_platform_set_fmt(struct soc_camera_device *icd, + __u32 pixfmt, struct v4l2_rect *rect) { return 0; } -static int soc_camera_platform_try_fmt_cap(struct soc_camera_device *icd, - struct v4l2_format *f) +static int soc_camera_platform_try_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) { struct soc_camera_platform_info *p = soc_camera_platform_get_info(icd); @@ -124,8 +124,8 @@ static struct soc_camera_ops soc_camera_platform_ops = { .release = soc_camera_platform_release, .start_capture = soc_camera_platform_start_capture, .stop_capture = soc_camera_platform_stop_capture, - .set_fmt_cap = soc_camera_platform_set_fmt_cap, - .try_fmt_cap = soc_camera_platform_try_fmt_cap, + .set_fmt = soc_camera_platform_set_fmt, + .try_fmt = soc_camera_platform_try_fmt, .set_bus_param = soc_camera_platform_set_bus_param, .query_bus_param = soc_camera_platform_query_bus_param, }; diff --git a/linux/drivers/media/video/uvc/uvc_ctrl.c b/linux/drivers/media/video/uvc/uvc_ctrl.c index 9de8a1db5..01c72935d 100644 --- a/linux/drivers/media/video/uvc/uvc_ctrl.c +++ b/linux/drivers/media/video/uvc/uvc_ctrl.c @@ -545,11 +545,16 @@ static inline __u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id) return ctrl->data + id * ctrl->info->size; } -static inline int uvc_get_bit(const __u8 *data, int bit) +static inline int uvc_test_bit(const __u8 *data, int bit) { return (data[bit >> 3] >> (bit & 7)) & 1; } +static inline void uvc_clear_bit(__u8 *data, int bit) +{ + data[bit >> 3] &= ~(1 << (bit & 7)); +} + /* Extract the bit string specified by mapping->offset and mapping->size * from the little-endian data stored at 'data' and return the result as * a signed 32bit integer. Sign extension will be performed if the mapping @@ -1308,6 +1313,51 @@ end: } /* + * Prune an entity of its bogus controls. This currently includes processing + * unit auto controls for which no corresponding manual control is available. + * Such auto controls make little sense if any, and are known to crash at + * least the SiGma Micro webcam. + */ +static void +uvc_ctrl_prune_entity(struct uvc_entity *entity) +{ + static const struct { + u8 idx_manual; + u8 idx_auto; + } blacklist[] = { + { 2, 11 }, /* Hue */ + { 6, 12 }, /* White Balance Temperature */ + { 7, 13 }, /* White Balance Component */ + }; + + u8 *controls; + unsigned int size; + unsigned int i; + + if (UVC_ENTITY_TYPE(entity) != VC_PROCESSING_UNIT) + return; + + controls = entity->processing.bmControls; + size = entity->processing.bControlSize; + + for (i = 0; i < ARRAY_SIZE(blacklist); ++i) { + if (blacklist[i].idx_auto >= 8 * size || + blacklist[i].idx_manual >= 8 * size) + continue; + + if (!uvc_test_bit(controls, blacklist[i].idx_auto) || + uvc_test_bit(controls, blacklist[i].idx_manual)) + continue; + + uvc_trace(UVC_TRACE_CONTROL, "Auto control %u/%u has no " + "matching manual control, removing it.\n", entity->id, + blacklist[i].idx_auto); + + uvc_clear_bit(controls, blacklist[i].idx_auto); + } +} + +/* * Initialize device controls. */ int uvc_ctrl_init_device(struct uvc_device *dev) @@ -1333,6 +1383,9 @@ int uvc_ctrl_init_device(struct uvc_device *dev) bControlSize = entity->camera.bControlSize; } + if (dev->quirks & UVC_QUIRK_PRUNE_CONTROLS) + uvc_ctrl_prune_entity(entity); + for (i = 0; i < bControlSize; ++i) ncontrols += hweight8(bmControls[i]); @@ -1347,7 +1400,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev) ctrl = entity->controls; for (i = 0; i < bControlSize * 8; ++i) { - if (uvc_get_bit(bmControls, i) == 0) + if (uvc_test_bit(bmControls, i) == 0) continue; ctrl->entity = entity; diff --git a/linux/drivers/media/video/uvc/uvc_driver.c b/linux/drivers/media/video/uvc/uvc_driver.c index 0a0ef6611..343792f0f 100644 --- a/linux/drivers/media/video/uvc/uvc_driver.c +++ b/linux/drivers/media/video/uvc/uvc_driver.c @@ -44,6 +44,7 @@ #define DRIVER_VERSION "v0.1.0" #endif +unsigned int uvc_no_drop_param; static unsigned int uvc_quirks_param; unsigned int uvc_trace_param; @@ -1895,7 +1896,8 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_PROBE_MINMAX - | UVC_QUIRK_IGNORE_SELECTOR_UNIT}, + | UVC_QUIRK_IGNORE_SELECTOR_UNIT + | UVC_QUIRK_PRUNE_CONTROLS }, /* Generic USB Video Class */ { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) }, {} @@ -1945,6 +1947,8 @@ static void __exit uvc_cleanup(void) module_init(uvc_init); module_exit(uvc_cleanup); +module_param_named(nodrop, uvc_no_drop_param, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(nodrop, "Don't drop incomplete frames"); module_param_named(quirks, uvc_quirks_param, uint, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(quirks, "Forced device quirks"); module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR); diff --git a/linux/drivers/media/video/uvc/uvc_video.c b/linux/drivers/media/video/uvc/uvc_video.c index 3be776a47..b19e91dd5 100644 --- a/linux/drivers/media/video/uvc/uvc_video.c +++ b/linux/drivers/media/video/uvc/uvc_video.c @@ -1007,7 +1007,8 @@ int uvc_video_enable(struct uvc_video_device *video, int enable) return 0; } - if (video->streaming->cur_format->flags & UVC_FMT_FLAG_COMPRESSED) + if ((video->streaming->cur_format->flags & UVC_FMT_FLAG_COMPRESSED) || + uvc_no_drop_param) video->queue.flags &= ~UVC_QUEUE_DROP_INCOMPLETE; else video->queue.flags |= UVC_QUEUE_DROP_INCOMPLETE; diff --git a/linux/drivers/media/video/uvc/uvcvideo.h b/linux/drivers/media/video/uvc/uvcvideo.h index f95040380..a699c0bb1 100644 --- a/linux/drivers/media/video/uvc/uvcvideo.h +++ b/linux/drivers/media/video/uvc/uvcvideo.h @@ -4,8 +4,6 @@ #include <linux/kernel.h> #include <linux/videodev2.h> -#include "compat.h" - /* * Dynamic controls */ @@ -69,6 +67,7 @@ struct uvc_xu_control { #ifdef __KERNEL__ #include <linux/poll.h> +#include "compat.h" /* -------------------------------------------------------------------------- * UVC constants @@ -317,6 +316,7 @@ struct uvc_xu_control { #define UVC_QUIRK_BUILTIN_ISIGHT 0x00000008 #define UVC_QUIRK_STREAM_NO_FID 0x00000010 #define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020 +#define UVC_QUIRK_PRUNE_CONTROLS 0x00000040 /* Format flags */ #define UVC_FMT_FLAG_COMPRESSED 0x00000001 @@ -684,6 +684,7 @@ struct uvc_driver { #define UVC_WARN_MINMAX 0 #define UVC_WARN_PROBE_DEF 1 +extern unsigned int uvc_no_drop_param; extern unsigned int uvc_trace_param; #define uvc_trace(flag, msg...) \ |