diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-01-22 20:52:03 -0200 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-01-22 20:52:03 -0200 |
commit | de00985e053e5742126ccd5299ac49047fecec88 (patch) | |
tree | 552032607812c7512db3b0a271ee76c2d43626d5 /linux/drivers/media/video | |
parent | 942a41fc50cf6a55b959fd4470ce7a1ace120dfb (diff) | |
parent | c475839553c110df9e43e58998cd37d05a34de20 (diff) | |
download | mediapointer-dvb-s2-de00985e053e5742126ccd5299ac49047fecec88.tar.gz mediapointer-dvb-s2-de00985e053e5742126ccd5299ac49047fecec88.tar.bz2 |
merge: http://linuxtv.org/hg/~anttip/af9015/
From: Mauro Carvalho Chehab <mchehab@redhat.com>
Priority: normal
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'linux/drivers/media/video')
58 files changed, 1616 insertions, 1044 deletions
diff --git a/linux/drivers/media/video/cx18/cx18-av-firmware.c b/linux/drivers/media/video/cx18/cx18-av-firmware.c index c64fd0a05..b374c74d3 100644 --- a/linux/drivers/media/video/cx18/cx18-av-firmware.c +++ b/linux/drivers/media/video/cx18/cx18-av-firmware.c @@ -36,7 +36,7 @@ int cx18_av_loadfw(struct cx18 *cx) int i; int retries1 = 0; - if (request_firmware(&fw, FWFILE, &cx->dev->dev) != 0) { + if (request_firmware(&fw, FWFILE, &cx->pci_dev->dev) != 0) { CX18_ERR("unable to open firmware %s\n", FWFILE); return -EINVAL; } @@ -115,9 +115,9 @@ int cx18_av_loadfw(struct cx18 *cx) are generated) */ cx18_av_write4(cx, CXADEC_I2S_OUT_CTL, 0x000001A0); - /* set alt I2s master clock to /16 and enable alt divider i2s + /* set alt I2s master clock to /0x16 and enable alt divider i2s passthrough */ - cx18_av_write4(cx, CXADEC_PIN_CFG3, 0x5000B687); + cx18_av_write4(cx, CXADEC_PIN_CFG3, 0x5600B687); cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, 0x000000F6, 0x000000F6, 0x3F00FFFF); diff --git a/linux/drivers/media/video/cx18/cx18-cards.c b/linux/drivers/media/video/cx18/cx18-cards.c index 10cddba3e..53217cf45 100644 --- a/linux/drivers/media/video/cx18/cx18-cards.c +++ b/linux/drivers/media/video/cx18/cx18-cards.c @@ -349,13 +349,14 @@ static const struct cx18_card cx18_card_toshiba_qosmio_dvbt = { /* Leadtek WinFast PVR2100 */ static const struct cx18_card_pci_info cx18_pci_leadtek_pvr2100[] = { - { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6f27 }, + { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6f27 }, /* PVR2100 */ + { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6690 }, /* DVR3100 H */ { 0, 0, 0 } }; static const struct cx18_card cx18_card_leadtek_pvr2100 = { .type = CX18_CARD_LEADTEK_PVR2100, - .name = "Leadtek WinFast PVR2100", + .name = "Leadtek WinFast PVR2100/DVR3100 H", .comment = "Experimenters and photos needed for device to work well.\n" "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n", .v4l2_capabilities = CX18_CAP_ENCODER, diff --git a/linux/drivers/media/video/cx18/cx18-driver.c b/linux/drivers/media/video/cx18/cx18-driver.c index e447b4ce7..fe2324ef2 100644 --- a/linux/drivers/media/video/cx18/cx18-driver.c +++ b/linux/drivers/media/video/cx18/cx18-driver.c @@ -159,7 +159,7 @@ MODULE_PARM_DESC(cardtype, "\t\t\t 4 = Yuan MPC718\n" "\t\t\t 5 = Conexant Raptor PAL/SECAM\n" "\t\t\t 6 = Toshiba Qosmio DVB-T/Analog\n" - "\t\t\t 7 = Leadtek WinFast PVR2100\n" + "\t\t\t 7 = Leadtek WinFast PVR2100/DVR3100 H\n" "\t\t\t 0 = Autodetect (default)\n" "\t\t\t-1 = Ignore this card\n\t\t"); MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60"); @@ -502,7 +502,7 @@ static void cx18_process_options(struct cx18 *cx) else if (cx->options.cardtype != 0) CX18_ERR("Unknown user specified type, trying to autodetect card\n"); if (cx->card == NULL) { - if (cx->dev->subsystem_vendor == CX18_PCI_ID_HAUPPAUGE) { + if (cx->pci_dev->subsystem_vendor == CX18_PCI_ID_HAUPPAUGE) { cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); CX18_INFO("Autodetected Hauppauge card\n"); } @@ -512,13 +512,13 @@ static void cx18_process_options(struct cx18 *cx) if (cx->card->pci_list == NULL) continue; for (j = 0; cx->card->pci_list[j].device; j++) { - if (cx->dev->device != + if (cx->pci_dev->device != cx->card->pci_list[j].device) continue; - if (cx->dev->subsystem_vendor != + if (cx->pci_dev->subsystem_vendor != cx->card->pci_list[j].subsystem_vendor) continue; - if (cx->dev->subsystem_device != + if (cx->pci_dev->subsystem_device != cx->card->pci_list[j].subsystem_device) continue; CX18_INFO("Autodetected %s card\n", cx->card->name); @@ -531,9 +531,10 @@ done: if (cx->card == NULL) { cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); CX18_ERR("Unknown card: vendor/device: [%04x:%04x]\n", - cx->dev->vendor, cx->dev->device); + cx->pci_dev->vendor, cx->pci_dev->device); CX18_ERR(" subsystem vendor/device: [%04x:%04x]\n", - cx->dev->subsystem_vendor, cx->dev->subsystem_device); + cx->pci_dev->subsystem_vendor, + cx->pci_dev->subsystem_device); CX18_ERR("Defaulting to %s card\n", cx->card->name); CX18_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n"); CX18_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n"); @@ -553,7 +554,7 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) { int i; - cx->base_addr = pci_resource_start(cx->dev, 0); + cx->base_addr = pci_resource_start(cx->pci_dev, 0); mutex_init(&cx->serialize_lock); mutex_init(&cx->i2c_bus_lock[0]); @@ -592,7 +593,7 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) (cx->params.video_temporal_filter_mode << 1) | (cx->params.video_median_filter_type << 2); cx->params.port = CX2341X_PORT_MEMORY; - cx->params.capabilities = CX2341X_CAP_HAS_TS; + cx->params.capabilities = CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_AC3; init_waitqueue_head(&cx->cap_w); init_waitqueue_head(&cx->mb_apu_waitq); init_waitqueue_head(&cx->mb_cpu_waitq); @@ -681,7 +682,7 @@ static void __devinit cx18_init_struct2(struct cx18 *cx) cx->av_state.vbi_line_offset = 8; } -static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *dev, +static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { u16 cmd; @@ -689,11 +690,11 @@ static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *dev, CX18_DEBUG_INFO("Enabling pci device\n"); - if (pci_enable_device(dev)) { + if (pci_enable_device(pci_dev)) { CX18_ERR("Can't enable device %d!\n", cx->num); return -EIO; } - if (pci_set_dma_mask(dev, 0xffffffff)) { + if (pci_set_dma_mask(pci_dev, 0xffffffff)) { CX18_ERR("No suitable DMA available on card %d.\n", cx->num); return -EIO; } @@ -703,25 +704,25 @@ static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *dev, } /* Enable bus mastering and memory mapped IO for the CX23418 */ - pci_read_config_word(dev, PCI_COMMAND, &cmd); + pci_read_config_word(pci_dev, PCI_COMMAND, &cmd); cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; - pci_write_config_word(dev, PCI_COMMAND, cmd); + pci_write_config_word(pci_dev, PCI_COMMAND, cmd); - pci_read_config_byte(dev, PCI_CLASS_REVISION, &cx->card_rev); - pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency); + pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &cx->card_rev); + pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency); if (pci_latency < 64 && cx18_pci_latency) { CX18_INFO("Unreasonably low latency timer, " "setting to 64 (was %d)\n", pci_latency); - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64); - pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency); + pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, 64); + pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency); } CX18_DEBUG_INFO("cx%d (rev %d) at %02x:%02x.%x, " "irq: %d, latency: %d, memory: 0x%lx\n", - cx->dev->device, cx->card_rev, dev->bus->number, - PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), - cx->dev->irq, pci_latency, (unsigned long)cx->base_addr); + cx->pci_dev->device, cx->card_rev, pci_dev->bus->number, + PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn), + cx->pci_dev->irq, pci_latency, (unsigned long)cx->base_addr); return 0; } @@ -732,7 +733,7 @@ static u32 cx18_request_module(struct cx18 *cx, u32 hw, { if ((hw & id) == 0) return hw; - if (request_module(name) != 0) { + if (request_module("%s", name) != 0) { CX18_ERR("Failed to load module %s\n", name); return hw & ~id; } @@ -776,7 +777,7 @@ static void cx18_load_and_init_modules(struct cx18 *cx) hw = cx->hw_flags; } -static int __devinit cx18_probe(struct pci_dev *dev, +static int __devinit cx18_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { int retval = 0; @@ -801,33 +802,37 @@ static int __devinit cx18_probe(struct pci_dev *dev, return -ENOMEM; } cx18_cards[cx18_cards_active] = cx; - cx->dev = dev; cx->num = cx18_cards_active++; snprintf(cx->name, sizeof(cx->name), "cx18-%d", cx->num); CX18_INFO("Initializing card #%d\n", cx->num); spin_unlock(&cx18_cards_lock); + cx->pci_dev = pci_dev; + retval = v4l2_device_register(&pci_dev->dev, &cx->v4l2_dev); + if (retval) { + CX18_ERR("Call to v4l2_device_register() failed\n"); + goto err; + } + CX18_DEBUG_INFO("registered v4l2_device name: %s\n", cx->v4l2_dev.name); + cx18_process_options(cx); if (cx->options.cardtype == -1) { retval = -ENODEV; - goto err; + goto unregister_v4l2; } if (cx18_init_struct1(cx)) { retval = -ENOMEM; - goto err; + goto unregister_v4l2; } CX18_DEBUG_INFO("base addr: 0x%08x\n", cx->base_addr); /* PCI Device Setup */ - retval = cx18_setup_pci(cx, dev, pci_id); + retval = cx18_setup_pci(cx, pci_dev, pci_id); if (retval != 0) goto free_workqueue; - /* save cx in the pci struct for later use */ - pci_set_drvdata(dev, cx); - /* map io memory */ CX18_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", cx->base_addr + CX18_MEM_OFFSET, CX18_MEM_SIZE); @@ -886,7 +891,7 @@ static int __devinit cx18_probe(struct pci_dev *dev, cx18_init_scb(cx); /* Register IRQ */ - retval = request_irq(cx->dev->irq, cx18_irq_handler, + retval = request_irq(cx->pci_dev->irq, cx18_irq_handler, IRQF_SHARED | IRQF_DISABLED, cx->name, (void *)cx); if (retval) { CX18_ERR("Failed to register irq %d\n", retval); @@ -997,7 +1002,7 @@ static int __devinit cx18_probe(struct pci_dev *dev, free_streams: cx18_streams_cleanup(cx, 1); free_irq: - free_irq(cx->dev->irq, (void *)cx); + free_irq(cx->pci_dev->irq, (void *)cx); free_i2c: exit_cx18_i2c(cx); free_map: @@ -1006,6 +1011,8 @@ free_mem: release_mem_region(cx->base_addr, CX18_MEM_SIZE); free_workqueue: destroy_workqueue(cx->work_queue); +unregister_v4l2: + v4l2_device_unregister(&cx->v4l2_dev); err: if (retval == 0) retval = -ENODEV; @@ -1048,8 +1055,21 @@ int cx18_init_on_first_open(struct cx18 *cx) } set_bit(CX18_F_I_LOADED_FW, &cx->i_flags); - /* Init the firmware twice to work around a silicon bug - * transport related. */ + /* + * Init the firmware twice to work around a silicon bug + * with the digital TS. + * + * The second firmware load requires us to normalize the APU state, + * or the audio for the first analog capture will be badly incorrect. + * + * I can't seem to call APU_RESETAI and have it succeed without the + * APU capturing audio, so we start and stop it here to do the reset + */ + + /* MPEG Encoding, 224 kbps, MPEG Layer II, 48 ksps */ + cx18_vapi(cx, CX18_APU_START, 2, CX18_APU_ENCODING_METHOD_MPEG|0xb9, 0); + cx18_vapi(cx, CX18_APU_RESETAI, 0); + cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG); fw_retry_count = 3; while (--fw_retry_count > 0) { @@ -1099,7 +1119,8 @@ static void cx18_cancel_epu_work_orders(struct cx18 *cx) #endif static void cx18_remove(struct pci_dev *pci_dev) { - struct cx18 *cx = pci_get_drvdata(pci_dev); + struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); + struct cx18 *cx = container_of(v4l2_dev, struct cx18, v4l2_dev); CX18_DEBUG_INFO("Removing Card #%d\n", cx->num); @@ -1131,13 +1152,15 @@ static void cx18_remove(struct pci_dev *pci_dev) exit_cx18_i2c(cx); - free_irq(cx->dev->irq, (void *)cx); + free_irq(cx->pci_dev->irq, (void *)cx); cx18_iounmap(cx); release_mem_region(cx->base_addr, CX18_MEM_SIZE); - pci_disable_device(cx->dev); + pci_disable_device(cx->pci_dev); + + v4l2_device_unregister(v4l2_dev); CX18_INFO("Removed %s, card #%d\n", cx->card_name, cx->num); } diff --git a/linux/drivers/media/video/cx18/cx18-driver.h b/linux/drivers/media/video/cx18/cx18-driver.h index 0d2edebc3..3a21013cd 100644 --- a/linux/drivers/media/video/cx18/cx18-driver.h +++ b/linux/drivers/media/video/cx18/cx18-driver.h @@ -48,6 +48,7 @@ #include <linux/dvb/audio.h> #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-device.h> #include <media/tuner.h> #include "cx18-mailbox.h" #include "cx18-av-core.h" @@ -79,7 +80,7 @@ #define CX18_CARD_YUAN_MPC718 3 /* Yuan MPC718 */ #define CX18_CARD_CNXT_RAPTOR_PAL 4 /* Conexant Raptor PAL */ #define CX18_CARD_TOSHIBA_QOSMIO_DVBT 5 /* Toshiba Qosmio Interal DVB-T/Analog*/ -#define CX18_CARD_LEADTEK_PVR2100 6 /* Leadtek WinFast PVR2100 */ +#define CX18_CARD_LEADTEK_PVR2100 6 /* Leadtek WinFast PVR2100/DVR3100 H */ #define CX18_CARD_LAST 6 #define CX18_ENC_STREAM_TYPE_MPG 0 @@ -279,7 +280,7 @@ struct cx18_epu_work_order { struct cx18_stream { /* These first four fields are always set, even if the stream is not actually created. */ - struct video_device *v4l2dev; /* NULL when stream not created */ + struct video_device *video_dev; /* NULL when stream not created */ struct cx18 *cx; /* for ease of use */ const char *name; /* name of the stream */ int type; /* stream type */ @@ -385,7 +386,9 @@ struct cx18_i2c_algo_callback_data { struct cx18 { int num; /* board number, -1 during init! */ char name[8]; /* board name for printk and interrupts (e.g. 'cx180') */ - struct pci_dev *dev; /* PCI device */ + struct pci_dev *pci_dev; + struct v4l2_device v4l2_dev; + const struct cx18_card *card; /* card information */ const char *card_name; /* full name of the card */ const struct cx18_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */ @@ -413,7 +416,7 @@ struct cx18 { /* dualwatch */ unsigned long dualwatch_jiffies; - u16 dualwatch_stereo_mode; + u32 dualwatch_stereo_mode; /* Digitizer type */ int digitizer; /* 0x00EF = saa7114 0x00FO = saa7115 0x0106 = mic */ diff --git a/linux/drivers/media/video/cx18/cx18-dvb.c b/linux/drivers/media/video/cx18/cx18-dvb.c index bd5e6f3fd..3b86f57cd 100644 --- a/linux/drivers/media/video/cx18/cx18-dvb.c +++ b/linux/drivers/media/video/cx18/cx18-dvb.c @@ -167,7 +167,7 @@ int cx18_dvb_register(struct cx18_stream *stream) ret = dvb_register_adapter(&dvb->dvb_adapter, CX18_DRIVER_NAME, - THIS_MODULE, &cx->dev->dev, adapter_nr); + THIS_MODULE, &cx->pci_dev->dev, adapter_nr); if (ret < 0) goto err_out; diff --git a/linux/drivers/media/video/cx18/cx18-fileops.c b/linux/drivers/media/video/cx18/cx18-fileops.c index 0aaea0e7f..36c380b66 100644 --- a/linux/drivers/media/video/cx18/cx18-fileops.c +++ b/linux/drivers/media/video/cx18/cx18-fileops.c @@ -128,10 +128,10 @@ static void cx18_release_stream(struct cx18_stream *s) static void cx18_dualwatch(struct cx18 *cx) { struct v4l2_tuner vt; - u16 new_bitmap; - u16 new_stereo_mode; - const u16 stereo_mask = 0x0300; - const u16 dual = 0x0200; + u32 new_bitmap; + u32 new_stereo_mode; + const u32 stereo_mask = 0x0300; + const u32 dual = 0x0200; u32 h; new_stereo_mode = cx->params.audio_properties & stereo_mask; @@ -703,7 +703,7 @@ int cx18_v4l2_open(struct file *filp) if (cx18_cards[x] == NULL) continue; s = &cx18_cards[x]->streams[y]; - if (s->v4l2dev && s->v4l2dev->minor == minor) { + if (s->video_dev && s->video_dev->minor == minor) { cx = cx18_cards[x]; break; } diff --git a/linux/drivers/media/video/cx18/cx18-firmware.c b/linux/drivers/media/video/cx18/cx18-firmware.c index 1fa95da15..aa89bee65 100644 --- a/linux/drivers/media/video/cx18/cx18-firmware.c +++ b/linux/drivers/media/video/cx18/cx18-firmware.c @@ -107,7 +107,7 @@ static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx) u32 __iomem *dst = (u32 __iomem *)mem; const u32 *src; - if (request_firmware(&fw, fn, &cx->dev->dev)) { + if (request_firmware(&fw, fn, &cx->pci_dev->dev)) { CX18_ERR("Unable to open firmware %s\n", fn); CX18_ERR("Did you put the firmware in the hotplug firmware directory?\n"); return -ENOMEM; @@ -151,7 +151,7 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, u32 apu_version = 0; int sz; - if (request_firmware(&fw, fn, &cx->dev->dev)) { + if (request_firmware(&fw, fn, &cx->pci_dev->dev)) { CX18_ERR("unable to open firmware %s\n", fn); CX18_ERR("did you put the firmware in the hotplug firmware directory?\n"); cx18_setup_page(cx, 0); diff --git a/linux/drivers/media/video/cx18/cx18-i2c.c b/linux/drivers/media/video/cx18/cx18-i2c.c index efae2301a..fe6fa60a7 100644 --- a/linux/drivers/media/video/cx18/cx18-i2c.c +++ b/linux/drivers/media/video/cx18/cx18-i2c.c @@ -393,7 +393,7 @@ int init_cx18_i2c(struct cx18 *cx) strlen(cx->i2c_client[i].name), "%d", i); cx->i2c_client[i].adapter = &cx->i2c_adap[i]; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) - cx->i2c_adap[i].dev.parent = &cx->dev->dev; + cx->i2c_adap[i].dev.parent = &cx->pci_dev->dev; #endif } diff --git a/linux/drivers/media/video/cx18/cx18-ioctl.c b/linux/drivers/media/video/cx18/cx18-ioctl.c index 84d6381aa..4a49b0819 100644 --- a/linux/drivers/media/video/cx18/cx18-ioctl.c +++ b/linux/drivers/media/video/cx18/cx18-ioctl.c @@ -407,7 +407,8 @@ static int cx18_querycap(struct file *file, void *fh, strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver)); strlcpy(vcap->card, cx->card_name, sizeof(vcap->card)); - snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(cx->dev)); + snprintf(vcap->bus_info, sizeof(vcap->bus_info), + "PCI:%s", pci_name(cx->pci_dev)); vcap->version = CX18_DRIVER_VERSION; /* version */ vcap->capabilities = cx->v4l2_cap; /* capabilities */ return 0; @@ -813,7 +814,9 @@ static int cx18_log_status(struct file *file, void *fh) struct v4l2_audio audin; int i; - CX18_INFO("================= START STATUS CARD #%d =================\n", cx->num); + CX18_INFO("================= START STATUS CARD #%d " + "=================\n", cx->num); + CX18_INFO("Version: %s Card: %s\n", CX18_VERSION, cx->card_name); if (cx->hw_flags & CX18_HW_TVEEPROM) { struct tveeprom tv; @@ -835,7 +838,7 @@ static int cx18_log_status(struct file *file, void *fh) for (i = 0; i < CX18_MAX_STREAMS; i++) { struct cx18_stream *s = &cx->streams[i]; - if (s->v4l2dev == NULL || s->buffers == 0) + if (s->video_dev == NULL || s->buffers == 0) continue; CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags, diff --git a/linux/drivers/media/video/cx18/cx18-mailbox.c b/linux/drivers/media/video/cx18/cx18-mailbox.c index 89a45f51f..66964722f 100644 --- a/linux/drivers/media/video/cx18/cx18-mailbox.c +++ b/linux/drivers/media/video/cx18/cx18-mailbox.c @@ -83,6 +83,8 @@ static const struct cx18_api_info api_info[] = { API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0), API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST), API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL, API_SLOW), + API_ENTRY(APU, CX18_APU_START, 0), + API_ENTRY(APU, CX18_APU_STOP, 0), API_ENTRY(APU, CX18_APU_RESETAI, 0), API_ENTRY(CPU, CX18_CPU_DEBUG_PEEK32, 0), API_ENTRY(0, 0, 0), @@ -98,21 +100,30 @@ static const struct cx18_api_info *find_api_info(u32 cmd) return NULL; } -static void dump_mb(struct cx18 *cx, struct cx18_mailbox *mb, char *name) +/* Call with buf of n*11+1 bytes */ +static char *u32arr2hex(u32 data[], int n, char *buf) { - char argstr[MAX_MB_ARGUMENTS*11+1]; char *p; int i; + for (i = 0, p = buf; i < n; i++, p += 11) { + /* kernel snprintf() appends '\0' always */ + snprintf(p, 12, " %#010x", data[i]); + } + *p = '\0'; + return buf; +} + +static void dump_mb(struct cx18 *cx, struct cx18_mailbox *mb, char *name) +{ + char argstr[MAX_MB_ARGUMENTS*11+1]; + if (!(cx18_debug & CX18_DBGFLG_API)) return; - for (i = 0, p = argstr; i < MAX_MB_ARGUMENTS; i++, p += 11) { - /* kernel snprintf() appends '\0' always */ - snprintf(p, 12, " %#010x", mb->args[i]); - } CX18_DEBUG_API("%s: req %#010x ack %#010x cmd %#010x err %#010x args%s" - "\n", name, mb->request, mb->ack, mb->cmd, mb->error, argstr); + "\n", name, mb->request, mb->ack, mb->cmd, mb->error, + u32arr2hex(mb->args, MAX_MB_ARGUMENTS, argstr)); } @@ -445,7 +456,8 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu) "incoming %s to EPU mailbox (sequence no. %u)" "\n", rpu_str[rpu], rpu_str[rpu], order_mb->request); - dump_mb(cx, order_mb, "incoming"); + if (cx18_debug & CX18_DBGFLG_WARN) + dump_mb(cx, order_mb, "incoming"); order->flags = CX18_F_EWO_MB_STALE_UPON_RECEIPT; } @@ -474,16 +486,24 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) struct mutex *mb_lock; long int timeout, ret; int i; + char argstr[MAX_MB_ARGUMENTS*11+1]; if (info == NULL) { CX18_WARN("unknown cmd %x\n", cmd); return -EINVAL; } - if (cmd == CX18_CPU_DE_SET_MDL) - CX18_DEBUG_HI_API("%s\n", info->name); - else - CX18_DEBUG_API("%s\n", info->name); + if (cx18_debug & CX18_DBGFLG_API) { /* only call u32arr2hex if needed */ + if (cmd == CX18_CPU_DE_SET_MDL) { + if (cx18_debug & CX18_DBGFLG_HIGHVOL) + CX18_DEBUG_HI_API("%s\tcmd %#010x args%s\n", + info->name, cmd, + u32arr2hex(data, args, argstr)); + } else + CX18_DEBUG_API("%s\tcmd %#010x args%s\n", + info->name, cmd, + u32arr2hex(data, args, argstr)); + } switch (info->rpu) { case APU: diff --git a/linux/drivers/media/video/cx18/cx18-queue.c b/linux/drivers/media/video/cx18/cx18-queue.c index 8d9441e88..3046b8e74 100644 --- a/linux/drivers/media/video/cx18/cx18-queue.c +++ b/linux/drivers/media/video/cx18/cx18-queue.c @@ -204,7 +204,7 @@ int cx18_stream_alloc(struct cx18_stream *s) } buf->id = cx->buffer_id++; INIT_LIST_HEAD(&buf->list); - buf->dma_handle = pci_map_single(s->cx->dev, + buf->dma_handle = pci_map_single(s->cx->pci_dev, buf->buf, s->buf_size, s->dma); cx18_buf_sync_for_cpu(s, buf); cx18_enqueue(s, buf, &s->q_free); @@ -227,7 +227,7 @@ void cx18_stream_free(struct cx18_stream *s) /* empty q_free */ while ((buf = cx18_dequeue(s, &s->q_free))) { - pci_unmap_single(s->cx->dev, buf->dma_handle, + pci_unmap_single(s->cx->pci_dev, buf->dma_handle, s->buf_size, s->dma); kfree(buf->buf); kfree(buf); diff --git a/linux/drivers/media/video/cx18/cx18-queue.h b/linux/drivers/media/video/cx18/cx18-queue.h index 456cec3bc..4de06269d 100644 --- a/linux/drivers/media/video/cx18/cx18-queue.h +++ b/linux/drivers/media/video/cx18/cx18-queue.h @@ -29,14 +29,14 @@ static inline void cx18_buf_sync_for_cpu(struct cx18_stream *s, struct cx18_buffer *buf) { - pci_dma_sync_single_for_cpu(s->cx->dev, buf->dma_handle, + pci_dma_sync_single_for_cpu(s->cx->pci_dev, buf->dma_handle, s->buf_size, s->dma); } static inline void cx18_buf_sync_for_device(struct cx18_stream *s, struct cx18_buffer *buf) { - pci_dma_sync_single_for_device(s->cx->dev, buf->dma_handle, + pci_dma_sync_single_for_device(s->cx->pci_dev, buf->dma_handle, s->buf_size, s->dma); } diff --git a/linux/drivers/media/video/cx18/cx18-streams.c b/linux/drivers/media/video/cx18/cx18-streams.c index 5eb99ea7b..88b101401 100644 --- a/linux/drivers/media/video/cx18/cx18-streams.c +++ b/linux/drivers/media/video/cx18/cx18-streams.c @@ -101,11 +101,11 @@ static struct { static void cx18_stream_init(struct cx18 *cx, int type) { struct cx18_stream *s = &cx->streams[type]; - struct video_device *dev = s->v4l2dev; + struct video_device *video_dev = s->video_dev; - /* we need to keep v4l2dev, so restore it afterwards */ + /* we need to keep video_dev, so restore it afterwards */ memset(s, 0, sizeof(*s)); - s->v4l2dev = dev; + s->video_dev = video_dev; /* initialize cx18_stream fields */ s->cx = cx; @@ -132,10 +132,10 @@ static int cx18_prep_dev(struct cx18 *cx, int type) int num_offset = cx18_stream_info[type].num_offset; int num = cx->num + cx18_first_minor + num_offset; - /* These four fields are always initialized. If v4l2dev == NULL, then + /* These four fields are always initialized. If video_dev == NULL, then this stream is not in use. In that case no other fields but these four can be used. */ - s->v4l2dev = NULL; + s->video_dev = NULL; s->cx = cx; s->type = type; s->name = cx18_stream_info[type].name; @@ -163,22 +163,22 @@ static int cx18_prep_dev(struct cx18 *cx, int type) return 0; /* allocate and initialize the v4l2 video device structure */ - s->v4l2dev = video_device_alloc(); - if (s->v4l2dev == NULL) { + s->video_dev = video_device_alloc(); + if (s->video_dev == NULL) { CX18_ERR("Couldn't allocate v4l2 video_device for %s\n", s->name); return -ENOMEM; } - snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "cx18-%d", + snprintf(s->video_dev->name, sizeof(s->video_dev->name), "cx18-%d", cx->num); - s->v4l2dev->num = num; - s->v4l2dev->parent = &cx->dev->dev; - s->v4l2dev->fops = &cx18_v4l2_enc_fops; - s->v4l2dev->release = video_device_release; - s->v4l2dev->tvnorms = V4L2_STD_ALL; - cx18_set_funcs(s->v4l2dev); + s->video_dev->num = num; + s->video_dev->parent = &cx->pci_dev->dev; + s->video_dev->fops = &cx18_v4l2_enc_fops; + s->video_dev->release = video_device_release; + s->video_dev->tvnorms = V4L2_STD_ALL; + cx18_set_funcs(s->video_dev); return 0; } @@ -227,28 +227,29 @@ static int cx18_reg_dev(struct cx18 *cx, int type) } } - if (s->v4l2dev == NULL) + if (s->video_dev == NULL) return 0; - num = s->v4l2dev->num; + num = s->video_dev->num; /* card number + user defined offset + device offset */ if (type != CX18_ENC_STREAM_TYPE_MPG) { struct cx18_stream *s_mpg = &cx->streams[CX18_ENC_STREAM_TYPE_MPG]; - if (s_mpg->v4l2dev) - num = s_mpg->v4l2dev->num + cx18_stream_info[type].num_offset; + if (s_mpg->video_dev) + num = s_mpg->video_dev->num + + cx18_stream_info[type].num_offset; } /* Register device. First try the desired minor, then any free one. */ - ret = video_register_device(s->v4l2dev, vfl_type, num); + ret = video_register_device(s->video_dev, vfl_type, num); if (ret < 0) { CX18_ERR("Couldn't register v4l2 device for %s kernel number %d\n", s->name, num); - video_device_release(s->v4l2dev); - s->v4l2dev = NULL; + video_device_release(s->video_dev); + s->video_dev = NULL; return ret; } - num = s->v4l2dev->num; + num = s->video_dev->num; switch (vfl_type) { case VFL_TYPE_GRABBER: @@ -312,9 +313,9 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister) cx->streams[type].dvb.enabled = false; } - vdev = cx->streams[type].v4l2dev; + vdev = cx->streams[type].video_dev; - cx->streams[type].v4l2dev = NULL; + cx->streams[type].video_dev = NULL; if (vdev == NULL) continue; @@ -437,7 +438,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) int ts = 0; int captype = 0; - if (s->v4l2dev == NULL && s->dvb.enabled == 0) + if (s->video_dev == NULL && s->dvb.enabled == 0) return -EINVAL; CX18_DEBUG_INFO("Start encoder stream %s\n", s->name); @@ -565,7 +566,7 @@ void cx18_stop_all_captures(struct cx18 *cx) for (i = CX18_MAX_STREAMS - 1; i >= 0; i--) { struct cx18_stream *s = &cx->streams[i]; - if (s->v4l2dev == NULL && s->dvb.enabled == 0) + if (s->video_dev == NULL && s->dvb.enabled == 0) continue; if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) cx18_stop_v4l2_encode_stream(s, 0); @@ -577,7 +578,7 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end) struct cx18 *cx = s->cx; unsigned long then; - if (s->v4l2dev == NULL && s->dvb.enabled == 0) + if (s->video_dev == NULL && s->dvb.enabled == 0) return -EINVAL; /* This function assumes that you are allowed to stop the capture @@ -656,7 +657,7 @@ u32 cx18_find_handle(struct cx18 *cx) for (i = 0; i < CX18_MAX_STREAMS; i++) { struct cx18_stream *s = &cx->streams[i]; - if (s->v4l2dev && (s->handle != CX18_INVALID_TASK_HANDLE)) + if (s->video_dev && (s->handle != CX18_INVALID_TASK_HANDLE)) return s->handle; } return CX18_INVALID_TASK_HANDLE; @@ -674,7 +675,7 @@ struct cx18_stream *cx18_handle_to_stream(struct cx18 *cx, u32 handle) s = &cx->streams[i]; if (s->handle != handle) continue; - if (s->v4l2dev || s->dvb.enabled) + if (s->video_dev || s->dvb.enabled) return s; } return NULL; diff --git a/linux/drivers/media/video/cx18/cx23418.h b/linux/drivers/media/video/cx18/cx23418.h index 601f3a2ab..9956abf57 100644 --- a/linux/drivers/media/video/cx18/cx23418.h +++ b/linux/drivers/media/video/cx18/cx23418.h @@ -56,6 +56,22 @@ #define APU_CMD_MASK 0x10000000 #define APU_CMD_MASK_ACK (APU_CMD_MASK | 0x80000000) +#define CX18_APU_ENCODING_METHOD_MPEG (0 << 28) +#define CX18_APU_ENCODING_METHOD_AC3 (1 << 28) + +/* Description: Command APU to start audio + IN[0] - audio parameters (same as CX18_CPU_SET_AUDIO_PARAMETERS?) + IN[1] - caller buffer address, or 0 + ReturnCode - ??? */ +#define CX18_APU_START (APU_CMD_MASK | 0x01) + +/* Description: Command APU to stop audio + IN[0] - encoding method to stop + ReturnCode - ??? */ +#define CX18_APU_STOP (APU_CMD_MASK | 0x02) + +/* Description: Command APU to reset the AI + ReturnCode - ??? */ #define CX18_APU_RESETAI (APU_CMD_MASK | 0x05) /* Description: This command indicates that a Memory Descriptor List has been diff --git a/linux/drivers/media/video/cx2341x.c b/linux/drivers/media/video/cx2341x.c index f31f11e3f..c92b98135 100644 --- a/linux/drivers/media/video/cx2341x.c +++ b/linux/drivers/media/video/cx2341x.c @@ -1,5 +1,5 @@ /* - * cx2341x - generic code for cx23415/6 based devices + * cx2341x - generic code for cx23415/6/8 based devices * * Copyright (C) 2006 Hans Verkuil <hverkuil@xs4all.nl> * @@ -31,7 +31,7 @@ #include <media/v4l2-common.h> #include "compat.h" -MODULE_DESCRIPTION("cx23415/6 driver"); +MODULE_DESCRIPTION("cx23415/6/8 driver"); MODULE_AUTHOR("Hans Verkuil"); MODULE_LICENSE("GPL"); @@ -46,6 +46,7 @@ const u32 cx2341x_mpeg_ctrls[] = { V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, V4L2_CID_MPEG_AUDIO_ENCODING, V4L2_CID_MPEG_AUDIO_L2_BITRATE, + V4L2_CID_MPEG_AUDIO_AC3_BITRATE, V4L2_CID_MPEG_AUDIO_MODE, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION, V4L2_CID_MPEG_AUDIO_EMPHASIS, @@ -95,6 +96,7 @@ static const struct cx2341x_mpeg_params default_params = { .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, .audio_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2, .audio_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_224K, + .audio_ac3_bitrate = V4L2_MPEG_AUDIO_AC3_BITRATE_224K, .audio_mode = V4L2_MPEG_AUDIO_MODE_STEREO, .audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4, .audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE, @@ -149,6 +151,9 @@ static int cx2341x_get_ctrl(const struct cx2341x_mpeg_params *params, case V4L2_CID_MPEG_AUDIO_L2_BITRATE: ctrl->value = params->audio_l2_bitrate; break; + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: + ctrl->value = params->audio_ac3_bitrate; + break; case V4L2_CID_MPEG_AUDIO_MODE: ctrl->value = params->audio_mode; break; @@ -257,6 +262,12 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy, params->audio_sampling_freq = ctrl->value; break; case V4L2_CID_MPEG_AUDIO_ENCODING: + if (busy) + return -EBUSY; + if (params->capabilities & CX2341X_CAP_HAS_AC3) + if (ctrl->value != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 && + ctrl->value != V4L2_MPEG_AUDIO_ENCODING_AC3) + return -ERANGE; params->audio_encoding = ctrl->value; break; case V4L2_CID_MPEG_AUDIO_L2_BITRATE: @@ -264,6 +275,13 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy, return -EBUSY; params->audio_l2_bitrate = ctrl->value; break; + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: + if (busy) + return -EBUSY; + if (!(params->capabilities & CX2341X_CAP_HAS_AC3)) + return -EINVAL; + params->audio_ac3_bitrate = ctrl->value; + break; case V4L2_CID_MPEG_AUDIO_MODE: params->audio_mode = ctrl->value; break; @@ -483,21 +501,55 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params, switch (qctrl->id) { case V4L2_CID_MPEG_AUDIO_ENCODING: + if (params->capabilities & CX2341X_CAP_HAS_AC3) { + /* + * The state of L2 & AC3 bitrate controls can change + * when this control changes, but v4l2_ctrl_query_fill() + * already sets V4L2_CTRL_FLAG_UPDATE for + * V4L2_CID_MPEG_AUDIO_ENCODING, so we don't here. + */ + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_ENCODING_LAYER_2, + V4L2_MPEG_AUDIO_ENCODING_AC3, 1, + default_params.audio_encoding); + } + return v4l2_ctrl_query_fill(qctrl, V4L2_MPEG_AUDIO_ENCODING_LAYER_2, V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1, default_params.audio_encoding); case V4L2_CID_MPEG_AUDIO_L2_BITRATE: - return v4l2_ctrl_query_fill(qctrl, + err = v4l2_ctrl_query_fill(qctrl, V4L2_MPEG_AUDIO_L2_BITRATE_192K, V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1, default_params.audio_l2_bitrate); + if (err) + return err; + if (params->capabilities & CX2341X_CAP_HAS_AC3 && + params->audio_encoding != V4L2_MPEG_AUDIO_ENCODING_LAYER_2) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + return 0; case V4L2_CID_MPEG_AUDIO_L1_BITRATE: case V4L2_CID_MPEG_AUDIO_L3_BITRATE: return -EINVAL; + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: + err = v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_AC3_BITRATE_48K, + V4L2_MPEG_AUDIO_AC3_BITRATE_448K, 1, + default_params.audio_ac3_bitrate); + if (err) + return err; + if (params->capabilities & CX2341X_CAP_HAS_AC3) { + if (params->audio_encoding != + V4L2_MPEG_AUDIO_ENCODING_AC3) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + } else + qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; + return 0; + case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: err = v4l2_ctrl_query_fill_std(qctrl); if (err == 0 && @@ -672,6 +724,15 @@ const char **cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id) NULL }; + static const char *mpeg_audio_encoding_l2_ac3[] = { + "", + "MPEG-1/2 Layer II", + "", + "", + "AC-3", + NULL + }; + static const char *cx2341x_video_spatial_filter_mode_menu[] = { "Manual", "Auto", @@ -712,6 +773,9 @@ const char **cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id) case V4L2_CID_MPEG_STREAM_TYPE: return (p->capabilities & CX2341X_CAP_HAS_TS) ? mpeg_stream_type_with_ts : mpeg_stream_type_without_ts; + case V4L2_CID_MPEG_AUDIO_ENCODING: + return (p->capabilities & CX2341X_CAP_HAS_AC3) ? + mpeg_audio_encoding_l2_ac3 : v4l2_ctrl_get_menu(id); case V4L2_CID_MPEG_AUDIO_L1_BITRATE: case V4L2_CID_MPEG_AUDIO_L3_BITRATE: return NULL; @@ -731,16 +795,36 @@ const char **cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id) } EXPORT_SYMBOL(cx2341x_ctrl_get_menu); +/* definitions for audio properties bits 29-28 */ +#define CX2341X_AUDIO_ENCODING_METHOD_MPEG 0 +#define CX2341X_AUDIO_ENCODING_METHOD_AC3 1 +#define CX2341X_AUDIO_ENCODING_METHOD_LPCM 2 + static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params) { - params->audio_properties = (params->audio_sampling_freq << 0) | - ((3 - params->audio_encoding) << 2) | - ((1 + params->audio_l2_bitrate) << 4) | + params->audio_properties = + (params->audio_sampling_freq << 0) | (params->audio_mode << 8) | (params->audio_mode_extension << 10) | (((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) ? 3 : params->audio_emphasis) << 12) | (params->audio_crc << 14); + + if ((params->capabilities & CX2341X_CAP_HAS_AC3) && + params->audio_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3) { + params->audio_properties |= +#if 1 + /* Not sure if this MPEG Layer II setting is required */ + ((3 - V4L2_MPEG_AUDIO_ENCODING_LAYER_2) << 2) | +#endif + (params->audio_ac3_bitrate << 4) | + (CX2341X_AUDIO_ENCODING_METHOD_AC3 << 28); + } else { + /* Assuming MPEG Layer II */ + params->audio_properties |= + ((3 - params->audio_encoding) << 2) | + ((1 + params->audio_l2_bitrate) << 4); + } } int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy, @@ -1023,7 +1107,10 @@ void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix) prefix, cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ), cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING), - cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE), + cx2341x_menu_item(p, + p->audio_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3 + ? V4L2_CID_MPEG_AUDIO_AC3_BITRATE + : V4L2_CID_MPEG_AUDIO_L2_BITRATE), cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE), p->audio_mute ? " (muted)" : ""); if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) diff --git a/linux/drivers/media/video/cx23885/cx23885-cards.c b/linux/drivers/media/video/cx23885/cx23885-cards.c index db1e8bdab..a8201ceaa 100644 --- a/linux/drivers/media/video/cx23885/cx23885-cards.c +++ b/linux/drivers/media/video/cx23885/cx23885-cards.c @@ -163,6 +163,18 @@ struct cx23885_board cx23885_boards[] = { .name = "Compro VideoMate E650F", .portc = CX23885_MPEG_DVB, }, + [CX23885_BOARD_TBS_6920] = { + .name = "TurboSight TBS 6920", + .portb = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_TEVII_S470] = { + .name = "TeVii S470", + .portb = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_DVBWORLD_2005] = { + .name = "DVBWorld DVB-S2 2005", + .portb = CX23885_MPEG_DVB, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -246,6 +258,18 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x185b, .subdevice = 0xe800, .card = CX23885_BOARD_COMPRO_VIDEOMATE_E650F, + }, { + .subvendor = 0x6920, + .subdevice = 0x8888, + .card = CX23885_BOARD_TBS_6920, + }, { + .subvendor = 0xd470, + .subdevice = 0x9022, + .card = CX23885_BOARD_TEVII_S470, + }, { + .subvendor = 0x0001, + .subdevice = 0x2005, + .card = CX23885_BOARD_DVBWORLD_2005, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -553,6 +577,12 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) mdelay(20); cx_set(GP0_IO, 0x00040004); break; + case CX23885_BOARD_TBS_6920: + case CX23885_BOARD_TEVII_S470: + cx_write(MC417_CTL, 0x00000036); + cx_write(MC417_OEN, 0x00001000); + cx_write(MC417_RWD, 0x00001800); + break; } } @@ -633,6 +663,13 @@ void cx23885_card_setup(struct cx23885_dev *dev) ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; break; + case CX23885_BOARD_TEVII_S470: + case CX23885_BOARD_TBS_6920: + case CX23885_BOARD_DVBWORLD_2005: + ts1->gen_ctrl_val = 0x5; /* Parallel */ + ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + break; case CX23885_BOARD_HAUPPAUGE_HVR1250: case CX23885_BOARD_HAUPPAUGE_HVR1500: case CX23885_BOARD_HAUPPAUGE_HVR1500Q: diff --git a/linux/drivers/media/video/cx23885/cx23885-dvb.c b/linux/drivers/media/video/cx23885/cx23885-dvb.c index 990fd217b..90dbf49ea 100644 --- a/linux/drivers/media/video/cx23885/cx23885-dvb.c +++ b/linux/drivers/media/video/cx23885/cx23885-dvb.c @@ -44,6 +44,7 @@ #include "dib7000p.h" #include "dibx000_common.h" #include "zl10353.h" +#include "cx24116.h" static unsigned int debug; @@ -309,6 +310,32 @@ static struct zl10353_config dvico_fusionhdtv_xc3028 = { .no_tuner = 1, }; +static int tbs_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + struct cx23885_tsport *port = fe->dvb->priv; + struct cx23885_dev *dev = port->dev; + + if (voltage == SEC_VOLTAGE_18) + cx_write(MC417_RWD, 0x00001e00);/* GPIO-13 high */ + else if (voltage == SEC_VOLTAGE_13) + cx_write(MC417_RWD, 0x00001a00);/* GPIO-13 low */ + else + cx_write(MC417_RWD, 0x00001800);/* GPIO-12 low */ + return 0; +} + +static struct cx24116_config tbs_cx24116_config = { + .demod_address = 0x05, +}; + +static struct cx24116_config tevii_cx24116_config = { + .demod_address = 0x55, +}; + +static struct cx24116_config dvbworld_cx24116_config = { + .demod_address = 0x05, +}; + static int dvb_register(struct cx23885_tsport *port) { struct cx23885_dev *dev = port->dev; @@ -527,6 +554,33 @@ static int dvb_register(struct cx23885_tsport *port) fe->ops.tuner_ops.set_config(fe, &ctl); } break; + case CX23885_BOARD_TBS_6920: + i2c_bus = &dev->i2c_bus[0]; + + fe0->dvb.frontend = dvb_attach(cx24116_attach, + &tbs_cx24116_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) + fe0->dvb.frontend->ops.set_voltage = tbs_set_voltage; + + break; + case CX23885_BOARD_TEVII_S470: + i2c_bus = &dev->i2c_bus[1]; + + fe0->dvb.frontend = dvb_attach(cx24116_attach, + &tevii_cx24116_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) + fe0->dvb.frontend->ops.set_voltage = tbs_set_voltage; + + break; + case CX23885_BOARD_DVBWORLD_2005: + i2c_bus = &dev->i2c_bus[1]; + + fe0->dvb.frontend = dvb_attach(cx24116_attach, + &dvbworld_cx24116_config, + &i2c_bus->i2c_adap); + break; default: printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " " isn't supported yet\n", diff --git a/linux/drivers/media/video/cx23885/cx23885.h b/linux/drivers/media/video/cx23885/cx23885.h index ad93e0e88..cae0a74bd 100644 --- a/linux/drivers/media/video/cx23885/cx23885.h +++ b/linux/drivers/media/video/cx23885/cx23885.h @@ -68,6 +68,9 @@ #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 +#define CX23885_BOARD_TBS_6920 14 +#define CX23885_BOARD_TEVII_S470 15 +#define CX23885_BOARD_DVBWORLD_2005 16 /* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */ #define CX23885_NORMS (\ diff --git a/linux/drivers/media/video/cx25840/cx25840-core.c b/linux/drivers/media/video/cx25840/cx25840-core.c index 479700c8c..6d324002a 100644 --- a/linux/drivers/media/video/cx25840/cx25840-core.c +++ b/linux/drivers/media/video/cx25840/cx25840-core.c @@ -1120,6 +1120,16 @@ static void log_audio_status(struct i2c_client *client) /* ----------------------------------------------------------------------- */ +/* This init operation must be called to load the driver's firmware. + Without this the audio standard detection will fail and you will + only get mono. + + Since loading the firmware is often problematic when the driver is + compiled into the kernel I recommend postponing calling this function + until the first open of the video device. Another reason for + postponing it is that loading this firmware takes a long time (seconds) + due to the slow i2c bus speed. So it will speed up the boot process if + you can avoid loading the fw as long as the video device isn't used. */ static int cx25840_init(struct v4l2_subdev *sd, u32 val) { struct cx25840_state *state = to_state(sd); @@ -1401,6 +1411,14 @@ static int cx25840_log_status(struct v4l2_subdev *sd) static int cx25840_command(struct i2c_client *client, unsigned cmd, void *arg) { + /* ignore this command */ + if (cmd == TUNER_SET_TYPE_ADDR) + return 0; + + /* Old-style drivers rely on initialization on first use, so + call the init whenever a command is issued to this driver. + New-style drivers using v4l2_subdev should call init explicitly. */ + cx25840_init(i2c_get_clientdata(client), 0); return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg); } diff --git a/linux/drivers/media/video/cx88/cx88-dvb.c b/linux/drivers/media/video/cx88/cx88-dvb.c index 712bd9039..488126ad6 100644 --- a/linux/drivers/media/video/cx88/cx88-dvb.c +++ b/linux/drivers/media/video/cx88/cx88-dvb.c @@ -621,34 +621,41 @@ static struct stv0288_config tevii_tuner_earda_config = { .set_ts_params = cx24116_set_ts_param, }; -static int dvb_register(struct cx8802_dev *dev) +static int cx8802_alloc_frontends(struct cx8802_dev *dev) { struct cx88_core *core = dev->core; - struct videobuf_dvb_frontend *fe0, *fe1 = NULL; - int mfe_shared = 0; /* bus not shared by default */ + struct videobuf_dvb_frontend *fe = NULL; int i; - if (0 != core->i2c_rc) { - printk(KERN_ERR "%s/2: no i2c-bus available, cannot attach dvb drivers\n", core->name); - goto frontend_detach; - } - - if (!core->board.num_frontends) - return -EINVAL; - mutex_init(&dev->frontends.lock); INIT_LIST_HEAD(&dev->frontends.felist); + if (!core->board.num_frontends) + return -ENODEV; + printk(KERN_INFO "%s() allocating %d frontend(s)\n", __func__, core->board.num_frontends); for (i = 1; i <= core->board.num_frontends; i++) { - fe0 = videobuf_dvb_alloc_frontend(&dev->frontends, i); - if (!fe0) { + fe = videobuf_dvb_alloc_frontend(&dev->frontends, i); + if (!fe) { printk(KERN_ERR "%s() failed to alloc\n", __func__); videobuf_dvb_dealloc_frontends(&dev->frontends); - goto frontend_detach; + return -ENOMEM; } } + return 0; +} + +static int dvb_register(struct cx8802_dev *dev) +{ + struct cx88_core *core = dev->core; + struct videobuf_dvb_frontend *fe0, *fe1 = NULL; + int mfe_shared = 0; /* bus not shared by default */ + + if (0 != core->i2c_rc) { + printk(KERN_ERR "%s/2: no i2c-bus available, cannot attach dvb drivers\n", core->name); + goto frontend_detach; + } /* Get the first frontend */ fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1); @@ -1253,6 +1260,8 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) struct cx88_core *core = drv->core; struct cx8802_dev *dev = drv->core->dvbdev; int err; + struct videobuf_dvb_frontend *fe; + int i; dprintk( 1, "%s\n", __func__); dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", @@ -1268,39 +1277,34 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) /* If vp3054 isn't enabled, a stub will just return 0 */ err = vp3054_i2c_probe(dev); if (0 != err) - goto fail_probe; + goto fail_core; /* dvb stuff */ printk(KERN_INFO "%s/2: cx2388x based DVB/ATSC card\n", core->name); dev->ts_gen_cntrl = 0x0c; + err = cx8802_alloc_frontends(dev); + if (err) + goto fail_core; + err = -ENODEV; - if (core->board.num_frontends) { - struct videobuf_dvb_frontend *fe; - int i; - - for (i = 1; i <= core->board.num_frontends; i++) { - fe = videobuf_dvb_get_frontend(&core->dvbdev->frontends, i); - if (fe == NULL) { - printk(KERN_ERR "%s() failed to get frontend(%d)\n", + for (i = 1; i <= core->board.num_frontends; i++) { + fe = videobuf_dvb_get_frontend(&core->dvbdev->frontends, i); + if (fe == NULL) { + printk(KERN_ERR "%s() failed to get frontend(%d)\n", __func__, i); - goto fail_probe; - } - videobuf_queue_sg_init(&fe->dvb.dvbq, &dvb_qops, + goto fail_probe; + } + videobuf_queue_sg_init(&fe->dvb.dvbq, &dvb_qops, &dev->pci->dev, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP, sizeof(struct cx88_buffer), dev); - /* init struct videobuf_dvb */ - fe->dvb.name = dev->core->name; - } - } else { - /* no frontends allocated */ - printk(KERN_ERR "%s/2 .num_frontends should be non-zero\n", - core->name); - goto fail_core; + /* init struct videobuf_dvb */ + fe->dvb.name = dev->core->name; } + err = dvb_register(dev); if (err) /* frontends/adapter de-allocated in dvb_register */ diff --git a/linux/drivers/media/video/em28xx/em28xx-audio.c b/linux/drivers/media/video/em28xx/em28xx-audio.c index 34c494d68..62dab8696 100644 --- a/linux/drivers/media/video/em28xx/em28xx-audio.c +++ b/linux/drivers/media/video/em28xx/em28xx-audio.c @@ -63,9 +63,12 @@ static int em28xx_isoc_audio_deinit(struct em28xx *dev) dprintk("Stopping isoc\n"); for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { - usb_unlink_urb(dev->adev.urb[i]); + usb_kill_urb(dev->adev.urb[i]); usb_free_urb(dev->adev.urb[i]); dev->adev.urb[i] = NULL; + + kfree(dev->adev.transfer_buffer[i]); + dev->adev.transfer_buffer[i] = NULL; } return 0; @@ -458,11 +461,15 @@ static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream *substream) #endif { - struct em28xx *dev; + unsigned long flags; + struct em28xx *dev; snd_pcm_uframes_t hwptr_done; + dev = snd_pcm_substream_chip(substream); + spin_lock_irqsave(&dev->adev.slock, flags); hwptr_done = dev->adev.hwptr_done_capture; + spin_unlock_irqrestore(&dev->adev.slock, flags); return hwptr_done; } diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index 73a41bcd5..60eae02b0 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -115,6 +115,18 @@ static struct em28xx_reg_seq em2870_kworld_355u_digital[] = { }; #endif +static struct em28xx_reg_seq kworld_330u_analog[] = { + {EM28XX_R08_GPIO, 0x6d, ~EM_GPIO_4, 10}, + {EM2880_R04_GPO, 0x00, 0xff, 10}, + { -1, -1, -1, -1}, +}; + +static struct em28xx_reg_seq kworld_330u_digital[] = { + {EM28XX_R08_GPIO, 0x6e, ~EM_GPIO_4, 10}, + {EM2880_R04_GPO, 0x08, 0xff, 10}, + { -1, -1, -1, -1}, +}; + /* Callback for the most boards */ static struct em28xx_reg_seq default_tuner_gpio[] = { {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10}, @@ -1242,29 +1254,33 @@ struct em28xx_board em28xx_boards[] = { .gpio = hauppauge_wintv_hvr_900_analog, } }, }, - [EM2883_BOARD_KWORLD_HYBRID_A316] = { + [EM2883_BOARD_KWORLD_HYBRID_330U] = { .name = "Kworld PlusTV HD Hybrid 330", .tuner_type = TUNER_XC2028, .tuner_gpio = default_tuner_gpio, .decoder = EM28XX_TVP5150, .mts_firmware = 1, .has_dvb = 1, - .dvb_gpio = default_digital, + .dvb_gpio = kworld_330u_digital, + .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_EEPROM_ON_BOARD | EM28XX_I2C_EEPROM_KEY_VALID, .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = EM28XX_AMUX_VIDEO, - .gpio = default_analog, + .gpio = kworld_330u_analog, + .aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = TVP5150_COMPOSITE1, .amux = EM28XX_AMUX_LINE_IN, - .gpio = hauppauge_wintv_hvr_900_analog, + .gpio = kworld_330u_analog, + .aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, .amux = EM28XX_AMUX_LINE_IN, - .gpio = hauppauge_wintv_hvr_900_analog, + .gpio = kworld_330u_analog, } }, }, [EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU] = { @@ -1318,7 +1334,7 @@ struct usb_device_id em28xx_id_table [] = { .driver_info = EM2880_BOARD_KWORLD_DVB_310U }, #endif { USB_DEVICE(0xeb1a, 0xa316), - .driver_info = EM2883_BOARD_KWORLD_HYBRID_A316 }, + .driver_info = EM2883_BOARD_KWORLD_HYBRID_330U }, { USB_DEVICE(0xeb1a, 0xe320), .driver_info = EM2880_BOARD_MSI_DIGIVOX_AD_II }, { USB_DEVICE(0xeb1a, 0xe323), @@ -1595,6 +1611,10 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl) /* FIXME: Better to specify the needed IF */ ctl->demod = XC3028_FE_DEFAULT; break; + case EM2883_BOARD_KWORLD_HYBRID_330U: + ctl->demod = XC3028_FE_CHINA; + ctl->fname = XC2028_DEFAULT_FIRMWARE; + break; default: ctl->demod = XC3028_FE_OREN538; } diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c index 440e3b538..5cf99aaf7 100644 --- a/linux/drivers/media/video/em28xx/em28xx-core.c +++ b/linux/drivers/media/video/em28xx/em28xx-core.c @@ -424,7 +424,7 @@ int em28xx_audio_analog_set(struct em28xx *dev) xclk = dev->board.xclk & 0x7f; if (!dev->mute) - xclk |= 0x80; + xclk |= EM28XX_XCLK_AUDIO_UNMUTE; ret = em28xx_write_reg(dev, EM28XX_R0F_XCLK, xclk); if (ret < 0) @@ -438,6 +438,10 @@ int em28xx_audio_analog_set(struct em28xx *dev) if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { int vol; + em28xx_write_ac97(dev, AC97_POWER_DOWN_CTRL, 0x4200); + em28xx_write_ac97(dev, AC97_EXT_AUD_CTRL, 0x0031); + em28xx_write_ac97(dev, AC97_PCM_IN_SRATE, 0xbb80); + /* LSB: left channel - both channels with the same level */ vol = (0x1f - dev->volume) | ((0x1f - dev->volume) << 8); diff --git a/linux/drivers/media/video/em28xx/em28xx-dvb.c b/linux/drivers/media/video/em28xx/em28xx-dvb.c index 8d3ed7dc8..c76dbc029 100644 --- a/linux/drivers/media/video/em28xx/em28xx-dvb.c +++ b/linux/drivers/media/video/em28xx/em28xx-dvb.c @@ -29,6 +29,7 @@ #include "lgdt330x.h" #include "zl10353.h" +#include "s5h1409.h" #ifdef EM28XX_DRX397XD_SUPPORT #include "drx397xD.h" #endif @@ -233,6 +234,15 @@ static struct zl10353_config em28xx_zl10353_with_xc3028 = { .if2 = 45600, }; +static struct s5h1409_config em28xx_s5h1409_with_xc3028 = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_PARALLEL_OUTPUT, + .gpio = S5H1409_GPIO_OFF, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK +}; + #ifdef EM28XX_DRX397XD_SUPPORT /* [TODO] djh - not sure yet what the device config needs to contain */ static struct drx397xD_config em28xx_drx397xD_with_xc3028 = { @@ -413,7 +423,6 @@ static int dvb_init(struct em28xx *dev) 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, @@ -434,6 +443,15 @@ static int dvb_init(struct em28xx *dev) goto out_free; } break; + case EM2883_BOARD_KWORLD_HYBRID_330U: + dvb->frontend = dvb_attach(s5h1409_attach, + &em28xx_s5h1409_with_xc3028, + &dev->i2c_adap); + if (attach_xc3028(0x61, dev) < 0) { + result = -EINVAL; + goto out_free; + } + break; case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: #ifdef EM28XX_DRX397XD_SUPPORT /* We don't have the config structure properly populated, so diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c index a2657fa3d..37577a670 100644 --- a/linux/drivers/media/video/em28xx/em28xx-video.c +++ b/linux/drivers/media/video/em28xx/em28xx-video.c @@ -2023,6 +2023,7 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev, int em28xx_register_analog_devices(struct em28xx *dev) { + u8 val; int ret; printk(KERN_INFO "%s: v4l2 driver version %d.%d.%d\n", @@ -2051,7 +2052,8 @@ int em28xx_register_analog_devices(struct em28xx *dev) /* enable vbi capturing */ /* em28xx_write_reg(dev, EM28XX_R0E_AUDIOSRC, 0xc0); audio register */ -/* em28xx_write_reg(dev, EM28XX_R0F_XCLK, 0x80); clk register */ + val = (u8)em28xx_read_reg(dev, EM28XX_R0F_XCLK); + em28xx_write_reg(dev, EM28XX_R0F_XCLK, (EM28XX_XCLK_AUDIO_UNMUTE | val)); em28xx_write_reg(dev, EM28XX_R11_VINCTRL, 0x51); #endif diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h index 04397c7ad..bc5ebbe61 100644 --- a/linux/drivers/media/video/em28xx/em28xx.h +++ b/linux/drivers/media/video/em28xx/em28xx.h @@ -95,7 +95,7 @@ #define EM2882_BOARD_KWORLD_VS_DVBT 54 #define EM2882_BOARD_TERRATEC_HYBRID_XS 55 #define EM2882_BOARD_PINNACLE_HYBRID_PRO 56 -#define EM2883_BOARD_KWORLD_HYBRID_A316 57 +#define EM2883_BOARD_KWORLD_HYBRID_330U 57 #define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU 58 #define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 60 #define EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2 61 @@ -322,7 +322,7 @@ enum em28xx_aout { EM28XX_AOUT_PCM_PHONE = 7 << 8, }; -static int ac97_return_record_select(int a_out) +static inline int ac97_return_record_select(int a_out) { return (a_out & 0x700) >> 8; } diff --git a/linux/drivers/media/video/hexium_gemini.c b/linux/drivers/media/video/hexium_gemini.c index 043a3080b..bcd8144c5 100644 --- a/linux/drivers/media/video/hexium_gemini.c +++ b/linux/drivers/media/video/hexium_gemini.c @@ -57,17 +57,6 @@ struct hexium_data u8 byte; }; -static struct saa7146_extension_ioctls ioctls[] = { - { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE }, - { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE }, - { VIDIOC_QUERYCTRL, SAA7146_BEFORE }, - { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE }, - { VIDIOC_S_STD, SAA7146_AFTER }, - { VIDIOC_G_CTRL, SAA7146_BEFORE }, - { VIDIOC_S_CTRL, SAA7146_BEFORE }, - { 0, 0 } -}; - #define HEXIUM_CONTROLS 1 static struct v4l2_queryctrl hexium_controls[] = { { V4L2_CID_PRIVATE_BASE, V4L2_CTRL_TYPE_BOOLEAN, "B/W", 0, 1, 1, 0, 0 }, @@ -232,6 +221,132 @@ static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec) return 0; } +static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) +{ + DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); + + if (i->index < 0 || i->index >= HEXIUM_INPUTS) + return -EINVAL; + + memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input)); + + DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index)); + return 0; +} + +static int vidioc_g_input(struct file *file, void *fh, unsigned int *input) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct hexium *hexium = (struct hexium *) dev->ext_priv; + + *input = hexium->cur_input; + + DEB_D(("VIDIOC_G_INPUT: %d\n", *input)); + return 0; +} + +static int vidioc_s_input(struct file *file, void *fh, unsigned int input) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct hexium *hexium = (struct hexium *) dev->ext_priv; + + DEB_EE(("VIDIOC_S_INPUT %d.\n", input)); + + if (input < 0 || input >= HEXIUM_INPUTS) + return -EINVAL; + + hexium->cur_input = input; + hexium_set_input(hexium, input); + return 0; +} + +/* the saa7146 provides some controls (brightness, contrast, saturation) + which gets registered *after* this function. because of this we have + to return with a value != 0 even if the function succeded.. */ +static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + int i; + + for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { + if (hexium_controls[i].id == qc->id) { + *qc = hexium_controls[i]; + DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id)); + return 0; + } + } + return dev->ext_vv_data->core_ops->vidioc_queryctrl(file, fh, qc); +} + +static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct hexium *hexium = (struct hexium *) dev->ext_priv; + int i; + + for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { + if (hexium_controls[i].id == vc->id) + break; + } + + if (i < 0) + return dev->ext_vv_data->core_ops->vidioc_g_ctrl(file, fh, vc); + + if (vc->id == V4L2_CID_PRIVATE_BASE) { + vc->value = hexium->cur_bw; + DEB_D(("VIDIOC_G_CTRL BW:%d.\n", vc->value)); + return 0; + } + return -EINVAL; +} + +static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct hexium *hexium = (struct hexium *) dev->ext_priv; + int i = 0; + + for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { + if (hexium_controls[i].id == vc->id) + break; + } + + if (i < 0) + return dev->ext_vv_data->core_ops->vidioc_s_ctrl(file, fh, vc); + + if (vc->id == V4L2_CID_PRIVATE_BASE) + hexium->cur_bw = vc->value; + + DEB_D(("VIDIOC_S_CTRL BW:%d.\n", hexium->cur_bw)); + + if (0 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) { + hexium_set_standard(hexium, hexium_pal); + return 0; + } + if (0 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) { + hexium_set_standard(hexium, hexium_ntsc); + return 0; + } + if (0 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) { + hexium_set_standard(hexium, hexium_secam); + return 0; + } + if (1 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) { + hexium_set_standard(hexium, hexium_pal_bw); + return 0; + } + if (1 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) { + hexium_set_standard(hexium, hexium_ntsc_bw); + return 0; + } + if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) + /* fixme: is there no bw secam mode? */ + return -EINVAL; + + return -EINVAL; +} + + static struct saa7146_ext_vv vv_data; /* this function only gets called when the probing was successful */ @@ -280,6 +395,12 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d hexium->cur_input = 0; saa7146_vv_init(dev, &vv_data); + vv_data.ops.vidioc_queryctrl = vidioc_queryctrl; + vv_data.ops.vidioc_g_ctrl = vidioc_g_ctrl; + vv_data.ops.vidioc_s_ctrl = vidioc_s_ctrl; + vv_data.ops.vidioc_enum_input = vidioc_enum_input; + vv_data.ops.vidioc_g_input = vidioc_g_input; + vv_data.ops.vidioc_s_input = vidioc_s_input; if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER)) { printk("hexium_gemini: cannot register capture v4l2 device. skipping.\n"); return -1; @@ -307,153 +428,6 @@ static int hexium_detach(struct saa7146_dev *dev) return 0; } -static long hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) -{ - struct saa7146_dev *dev = fh->dev; - struct hexium *hexium = (struct hexium *) dev->ext_priv; -/* - struct saa7146_vv *vv = dev->vv_data; -*/ - switch (cmd) { - case VIDIOC_ENUMINPUT: - { - struct v4l2_input *i = arg; - DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); - - if (i->index < 0 || i->index >= HEXIUM_INPUTS) { - return -EINVAL; - } - - memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input)); - - DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index)); - return 0; - } - case VIDIOC_G_INPUT: - { - int *input = (int *) arg; - *input = hexium->cur_input; - - DEB_D(("VIDIOC_G_INPUT: %d\n", *input)); - return 0; - } - case VIDIOC_S_INPUT: - { - int input = *(int *) arg; - - DEB_EE(("VIDIOC_S_INPUT %d.\n", input)); - - if (input < 0 || input >= HEXIUM_INPUTS) { - return -EINVAL; - } - - hexium->cur_input = input; - hexium_set_input(hexium, input); - - return 0; - } - /* the saa7146 provides some controls (brightness, contrast, saturation) - which gets registered *after* this function. because of this we have - to return with a value != 0 even if the function succeded.. */ - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *qc = arg; - int i; - - for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { - if (hexium_controls[i].id == qc->id) { - *qc = hexium_controls[i]; - DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id)); - return 0; - } - } - return -EAGAIN; - } - case VIDIOC_G_CTRL: - { - struct v4l2_control *vc = arg; - int i; - - for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { - if (hexium_controls[i].id == vc->id) { - break; - } - } - - if (i < 0) { - return -EAGAIN; - } - - switch (vc->id) { - case V4L2_CID_PRIVATE_BASE:{ - vc->value = hexium->cur_bw; - DEB_D(("VIDIOC_G_CTRL BW:%d.\n", vc->value)); - return 0; - } - } - return -EINVAL; - } - - case VIDIOC_S_CTRL: - { - struct v4l2_control *vc = arg; - int i = 0; - - for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { - if (hexium_controls[i].id == vc->id) { - break; - } - } - - if (i < 0) { - return -EAGAIN; - } - - switch (vc->id) { - case V4L2_CID_PRIVATE_BASE:{ - hexium->cur_bw = vc->value; - break; - } - } - - DEB_D(("VIDIOC_S_CTRL BW:%d.\n", hexium->cur_bw)); - - if (0 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) { - hexium_set_standard(hexium, hexium_pal); - return 0; - } - if (0 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) { - hexium_set_standard(hexium, hexium_ntsc); - return 0; - } - if (0 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) { - hexium_set_standard(hexium, hexium_secam); - return 0; - } - if (1 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) { - hexium_set_standard(hexium, hexium_pal_bw); - return 0; - } - if (1 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) { - hexium_set_standard(hexium, hexium_ntsc_bw); - return 0; - } - if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) { - /* fixme: is there no bw secam mode? */ - return -EINVAL; - } - - return -EINVAL; - } - default: -/* - DEB_D(("hexium_ioctl() does not handle this ioctl.\n")); -*/ - return -ENOIOCTLCMD; - } - return 0; -} - static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std) { struct hexium *hexium = (struct hexium *) dev->ext_priv; @@ -515,8 +489,6 @@ static struct saa7146_ext_vv vv_data = { .stds = &hexium_standards[0], .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard), .std_callback = &std_callback, - .ioctls = &ioctls[0], - .ioctl = hexium_ioctl, }; static struct saa7146_extension hexium_extension = { diff --git a/linux/drivers/media/video/hexium_orion.c b/linux/drivers/media/video/hexium_orion.c index 847518f78..4178edcc2 100644 --- a/linux/drivers/media/video/hexium_orion.c +++ b/linux/drivers/media/video/hexium_orion.c @@ -58,14 +58,6 @@ struct hexium_data u8 byte; }; -static struct saa7146_extension_ioctls ioctls[] = { - { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE }, - { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE }, - { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE }, - { VIDIOC_S_STD, SAA7146_AFTER }, - { 0, 0 } -}; - struct hexium { int type; @@ -330,6 +322,44 @@ static int hexium_set_input(struct hexium *hexium, int input) return 0; } +static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) +{ + DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); + + if (i->index < 0 || i->index >= HEXIUM_INPUTS) + return -EINVAL; + + memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input)); + + DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index)); + return 0; +} + +static int vidioc_g_input(struct file *file, void *fh, unsigned int *input) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct hexium *hexium = (struct hexium *) dev->ext_priv; + + *input = hexium->cur_input; + + DEB_D(("VIDIOC_G_INPUT: %d\n", *input)); + return 0; +} + +static int vidioc_s_input(struct file *file, void *fh, unsigned int input) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct hexium *hexium = (struct hexium *) dev->ext_priv; + + if (input < 0 || input >= HEXIUM_INPUTS) + return -EINVAL; + + hexium->cur_input = input; + hexium_set_input(hexium, input); + + return 0; +} + static struct saa7146_ext_vv vv_data; /* this function only gets called when the probing was successful */ @@ -340,6 +370,9 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d DEB_EE((".\n")); saa7146_vv_init(dev, &vv_data); + vv_data.ops.vidioc_enum_input = vidioc_enum_input; + vv_data.ops.vidioc_g_input = vidioc_g_input; + vv_data.ops.vidioc_s_input = vidioc_s_input; if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) { printk("hexium_orion: cannot register capture v4l2 device. skipping.\n"); return -1; @@ -371,58 +404,6 @@ static int hexium_detach(struct saa7146_dev *dev) return 0; } -static long hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) -{ - struct saa7146_dev *dev = fh->dev; - struct hexium *hexium = (struct hexium *) dev->ext_priv; -/* - struct saa7146_vv *vv = dev->vv_data; -*/ - switch (cmd) { - case VIDIOC_ENUMINPUT: - { - struct v4l2_input *i = arg; - DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); - - if (i->index < 0 || i->index >= HEXIUM_INPUTS) { - return -EINVAL; - } - - memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input)); - - DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index)); - return 0; - } - case VIDIOC_G_INPUT: - { - int *input = (int *) arg; - *input = hexium->cur_input; - - DEB_D(("VIDIOC_G_INPUT: %d\n", *input)); - return 0; - } - case VIDIOC_S_INPUT: - { - int input = *(int *) arg; - - if (input < 0 || input >= HEXIUM_INPUTS) { - return -EINVAL; - } - - hexium->cur_input = input; - hexium_set_input(hexium, input); - - return 0; - } - default: -/* - DEB_D(("hexium_ioctl() does not handle this ioctl.\n")); -*/ - return -ENOIOCTLCMD; - } - return 0; -} - static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std) { return 0; @@ -480,8 +461,6 @@ static struct saa7146_ext_vv vv_data = { .stds = &hexium_standards[0], .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard), .std_callback = &std_callback, - .ioctls = &ioctls[0], - .ioctl = hexium_ioctl, }; static struct saa7146_extension extension = { diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.c b/linux/drivers/media/video/ivtv/ivtv-driver.c index b712c29e7..05bba3928 100644 --- a/linux/drivers/media/video/ivtv/ivtv-driver.c +++ b/linux/drivers/media/video/ivtv/ivtv-driver.c @@ -953,8 +953,10 @@ static int __devinit ivtv_probe(struct pci_dev *dev, itv->instance = atomic_inc_return(&ivtv_instance) - 1; retval = v4l2_device_register(&dev->dev, &itv->device); - if (retval) + if (retval) { + kfree(itv); return retval; + } /* "ivtv + PCI ID" is a bit of a mouthful, so use "ivtv + instance" instead. */ snprintf(itv->device.name, sizeof(itv->device.name), diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.h b/linux/drivers/media/video/ivtv/ivtv-driver.h index 51f6e54ba..03df1cb7d 100644 --- a/linux/drivers/media/video/ivtv/ivtv-driver.h +++ b/linux/drivers/media/video/ivtv/ivtv-driver.h @@ -697,7 +697,7 @@ struct ivtv { u64 vbi_data_inserted; /* number of VBI bytes inserted into the MPEG stream */ u32 last_dec_timing[3]; /* cache last retrieved pts/scr/frame values */ unsigned long dualwatch_jiffies;/* jiffies value of the previous dualwatch check */ - u16 dualwatch_stereo_mode; /* current detected dualwatch stereo mode */ + u32 dualwatch_stereo_mode; /* current detected dualwatch stereo mode */ /* VBI state info */ diff --git a/linux/drivers/media/video/ivtv/ivtv-fileops.c b/linux/drivers/media/video/ivtv/ivtv-fileops.c index d594bc29f..617667d1c 100644 --- a/linux/drivers/media/video/ivtv/ivtv-fileops.c +++ b/linux/drivers/media/video/ivtv/ivtv-fileops.c @@ -148,10 +148,10 @@ void ivtv_release_stream(struct ivtv_stream *s) static void ivtv_dualwatch(struct ivtv *itv) { struct v4l2_tuner vt; - u16 new_bitmap; - u16 new_stereo_mode; - const u16 stereo_mask = 0x0300; - const u16 dual = 0x0200; + u32 new_bitmap; + u32 new_stereo_mode; + const u32 stereo_mask = 0x0300; + const u32 dual = 0x0200; new_stereo_mode = itv->params.audio_properties & stereo_mask; memset(&vt, 0, sizeof(vt)); diff --git a/linux/drivers/media/video/mxb.c b/linux/drivers/media/video/mxb.c index 974d9bcbd..e7b94e6b1 100644 --- a/linux/drivers/media/video/mxb.c +++ b/linux/drivers/media/video/mxb.c @@ -111,26 +111,6 @@ static struct v4l2_queryctrl mxb_controls[] = { { V4L2_CID_AUDIO_MUTE, V4L2_CTRL_TYPE_BOOLEAN, "Mute", 0, 1, 1, 0, 0 }, }; -static struct saa7146_extension_ioctls ioctls[] = { - { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE }, - { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE }, - { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE }, - { VIDIOC_QUERYCTRL, SAA7146_BEFORE }, - { VIDIOC_G_CTRL, SAA7146_BEFORE }, - { VIDIOC_S_CTRL, SAA7146_BEFORE }, - { VIDIOC_G_TUNER, SAA7146_EXCLUSIVE }, - { VIDIOC_S_TUNER, SAA7146_EXCLUSIVE }, - { VIDIOC_G_FREQUENCY, SAA7146_EXCLUSIVE }, - { VIDIOC_S_FREQUENCY, SAA7146_EXCLUSIVE }, - { VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE }, - { VIDIOC_S_AUDIO, SAA7146_EXCLUSIVE }, - { VIDIOC_DBG_G_REGISTER, SAA7146_EXCLUSIVE }, - { VIDIOC_DBG_S_REGISTER, SAA7146_EXCLUSIVE }, - { MXB_S_AUDIO_CD, SAA7146_EXCLUSIVE }, /* custom control */ - { MXB_S_AUDIO_LINE, SAA7146_EXCLUSIVE }, /* custom control */ - { 0, 0 } -}; - struct mxb { struct video_device *video_dev; @@ -425,387 +405,430 @@ void mxb_irq_bh(struct saa7146_dev* dev, u32* irq_mask) } */ -static struct saa7146_ext_vv vv_data; - -/* this function only gets called when the probing was successful */ -static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) +static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc) { - struct mxb *mxb = (struct mxb *)dev->ext_priv; + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + int i; - DEB_EE(("dev:%p\n", dev)); + for (i = MAXCONTROLS - 1; i >= 0; i--) { + if (mxb_controls[i].id == qc->id) { + *qc = mxb_controls[i]; + DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id)); + return 0; + } + } + return dev->ext_vv_data->core_ops->vidioc_queryctrl(file, fh, qc); +} - /* checking for i2c-devices can be omitted here, because we - already did this in "mxb_vl42_probe" */ +static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; + int i; - saa7146_vv_init(dev, &vv_data); - if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) { - ERR(("cannot register capture v4l2 device. skipping.\n")); - return -1; + for (i = MAXCONTROLS - 1; i >= 0; i--) { + if (mxb_controls[i].id == vc->id) + break; } - /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/ - if (MXB_BOARD_CAN_DO_VBI(dev)) { - if (saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) { - ERR(("cannot register vbi v4l2 device. skipping.\n")); - } - } + if (i < 0) + return dev->ext_vv_data->core_ops->vidioc_g_ctrl(file, fh, vc); - i2c_use_client(mxb->tea6420_1); - i2c_use_client(mxb->tea6420_2); - i2c_use_client(mxb->tea6415c); - i2c_use_client(mxb->tda9840); - i2c_use_client(mxb->saa7111a); - i2c_use_client(mxb->tuner); - - printk("mxb: found Multimedia eXtension Board #%d.\n", mxb_num); + if (vc->id == V4L2_CID_AUDIO_MUTE) { + vc->value = mxb->cur_mute; + DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value)); + return 0; + } - mxb_num++; - mxb_init_done(dev); + DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value)); return 0; } -static int mxb_detach(struct saa7146_dev *dev) +static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc) { + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; struct mxb *mxb = (struct mxb *)dev->ext_priv; + int i = 0; - DEB_EE(("dev:%p\n", dev)); - - i2c_release_client(mxb->tea6420_1); - i2c_release_client(mxb->tea6420_2); - i2c_release_client(mxb->tea6415c); - i2c_release_client(mxb->tda9840); - i2c_release_client(mxb->saa7111a); - i2c_release_client(mxb->tuner); - - saa7146_unregister_device(&mxb->video_dev,dev); - if (MXB_BOARD_CAN_DO_VBI(dev)) - saa7146_unregister_device(&mxb->vbi_dev, dev); - saa7146_vv_release(dev); + for (i = MAXCONTROLS - 1; i >= 0; i--) { + if (mxb_controls[i].id == vc->id) + break; + } - mxb_num--; + if (i < 0) + return dev->ext_vv_data->core_ops->vidioc_s_ctrl(file, fh, vc); - i2c_del_adapter(&mxb->i2c_adapter); - kfree(mxb); + if (vc->id == V4L2_CID_AUDIO_MUTE) { + mxb->cur_mute = vc->value; + if (!vc->value) { + /* switch the audio-source */ + mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, + &TEA6420_line[video_audio_connect[mxb->cur_input]][0]); + mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, + &TEA6420_line[video_audio_connect[mxb->cur_input]][1]); + } else { + mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, + &TEA6420_line[6][0]); + mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, + &TEA6420_line[6][1]); + } + DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n", vc->value)); + } + return 0; +} +static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) +{ + DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); + if (i->index < 0 || i->index >= MXB_INPUTS) + return -EINVAL; + memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input)); return 0; } -static long mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) +static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) { - struct saa7146_dev *dev = fh->dev; + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; struct mxb *mxb = (struct mxb *)dev->ext_priv; - struct saa7146_vv *vv = dev->vv_data; + *i = mxb->cur_input; - switch(cmd) { - case VIDIOC_ENUMINPUT: - { - struct v4l2_input *i = arg; + DEB_EE(("VIDIOC_G_INPUT %d.\n", *i)); + return 0; +} - DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index)); - if (i->index < 0 || i->index >= MXB_INPUTS) - return -EINVAL; - memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input)); - return 0; - } - /* the saa7146 provides some controls (brightness, contrast, saturation) - which gets registered *after* this function. because of this we have - to return with a value != 0 even if the function succeded.. */ - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *qc = arg; - int i; - - for (i = MAXCONTROLS - 1; i >= 0; i--) { - if (mxb_controls[i].id == qc->id) { - *qc = mxb_controls[i]; - DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id)); - return 0; - } - } - return -EAGAIN; - } - case VIDIOC_G_CTRL: - { - struct v4l2_control *vc = arg; - int i; +static int vidioc_s_input(struct file *file, void *fh, unsigned int input) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; + struct tea6415c_multiplex vm; + struct v4l2_routing route; + int i = 0; - for (i = MAXCONTROLS - 1; i >= 0; i--) { - if (mxb_controls[i].id == vc->id) - break; - } + DEB_EE(("VIDIOC_S_INPUT %d.\n", input)); - if (i < 0) - return -EAGAIN; + if (input < 0 || input >= MXB_INPUTS) + return -EINVAL; - if (vc->id == V4L2_CID_AUDIO_MUTE) { - vc->value = mxb->cur_mute; - DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value)); - return 0; - } + mxb->cur_input = input; - DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value)); - return 0; - } + saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, + input_port_selection[input].hps_sync); - case VIDIOC_S_CTRL: - { - struct v4l2_control *vc = arg; - int i = 0; + /* prepare switching of tea6415c and saa7111a; + have a look at the 'background'-file for further informations */ + switch (input) { + case TUNER: + i = SAA7115_COMPOSITE0; + vm.in = 3; + vm.out = 17; - for (i = MAXCONTROLS - 1; i >= 0; i--) { - if (mxb_controls[i].id == vc->id) - break; + if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) { + printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #1\n"); + return -EFAULT; } + /* connect tuner-output always to multicable */ + vm.in = 3; + vm.out = 13; + break; + case AUX3_YC: + /* nothing to be done here. aux3_yc is + directly connected to the saa711a */ + i = SAA7115_SVIDEO1; + break; + case AUX3: + /* nothing to be done here. aux3 is + directly connected to the saa711a */ + i = SAA7115_COMPOSITE1; + break; + case AUX1: + i = SAA7115_COMPOSITE0; + vm.in = 1; + vm.out = 17; + break; + } - if (i < 0) - return -EAGAIN; - - if (vc->id == V4L2_CID_AUDIO_MUTE) { - mxb->cur_mute = vc->value; - if (!vc->value) { - /* switch the audio-source */ - mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, - &TEA6420_line[video_audio_connect[mxb->cur_input]][0]); - mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, - &TEA6420_line[video_audio_connect[mxb->cur_input]][1]); - } else { - mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, - &TEA6420_line[6][0]); - mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, - &TEA6420_line[6][1]); - } - DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n", vc->value)); + /* switch video in tea6415c only if necessary */ + switch (input) { + case TUNER: + case AUX1: + if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) { + printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #3\n"); + return -EFAULT; } - return 0; + break; + default: + break; } - case VIDIOC_G_INPUT: - { - int *input = (int *)arg; - *input = mxb->cur_input; - DEB_EE(("VIDIOC_G_INPUT %d.\n", *input)); - return 0; + /* switch video in saa7111a */ + route.input = i; + route.output = 0; + if (mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route)) + printk(KERN_ERR "VIDIOC_S_INPUT: could not address saa7111a #1.\n"); + + /* switch the audio-source only if necessary */ + if (0 == mxb->cur_mute) { + mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, + &TEA6420_line[video_audio_connect[input]][0]); + mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, + &TEA6420_line[video_audio_connect[input]][1]); } - case VIDIOC_S_INPUT: - { - int input = *(int *)arg; - struct tea6415c_multiplex vm; - struct v4l2_routing route; - int i = 0; - DEB_EE(("VIDIOC_S_INPUT %d.\n", input)); + return 0; +} - if (input < 0 || input >= MXB_INPUTS) - return -EINVAL; +static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; - mxb->cur_input = input; + if (t->index) { + DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index)); + return -EINVAL; + } - saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, - input_port_selection[input].hps_sync); + DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index)); - /* prepare switching of tea6415c and saa7111a; - have a look at the 'background'-file for further informations */ - switch (input) { - case TUNER: - i = SAA7115_COMPOSITE0; - vm.in = 3; - vm.out = 17; + memset(t, 0, sizeof(*t)); + i2c_clients_command(&mxb->i2c_adapter, VIDIOC_G_TUNER, t); - if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) { - printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #1\n"); - return -EFAULT; - } - /* connect tuner-output always to multicable */ - vm.in = 3; - vm.out = 13; - break; - case AUX3_YC: - /* nothing to be done here. aux3_yc is - directly connected to the saa711a */ - i = SAA7115_SVIDEO1; - break; - case AUX3: - /* nothing to be done here. aux3 is - directly connected to the saa711a */ - i = SAA7115_COMPOSITE1; - break; - case AUX1: - i = SAA7115_COMPOSITE0; - vm.in = 1; - vm.out = 17; - break; - } + strlcpy(t->name, "TV Tuner", sizeof(t->name)); + t->type = V4L2_TUNER_ANALOG_TV; + t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; + t->audmode = mxb->cur_mode; + return 0; +} - /* switch video in tea6415c only if necessary */ - switch (input) { - case TUNER: - case AUX1: - if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) { - printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #3\n"); - return -EFAULT; - } - break; - default: - break; - } +static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; - /* switch video in saa7111a */ - route.input = i; - route.output = 0; - if (mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route)) - printk("VIDIOC_S_INPUT: could not address saa7111a #1.\n"); + if (t->index) { + DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n", t->index)); + return -EINVAL; + } - /* switch the audio-source only if necessary */ - if( 0 == mxb->cur_mute ) { - mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, - &TEA6420_line[video_audio_connect[input]][0]); - mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, - &TEA6420_line[video_audio_connect[input]][1]); - } + mxb->cur_mode = t->audmode; + i2c_clients_command(&mxb->i2c_adapter, VIDIOC_S_TUNER, t); + return 0; +} - return 0; +static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; + + if (mxb->cur_input) { + DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n", + mxb->cur_input)); + return -EINVAL; } - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *t = arg; - if (t->index) { - DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index)); - return -EINVAL; - } + *f = mxb->cur_freq; - DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index)); + DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency)); + return 0; +} - memset(t, 0, sizeof(*t)); - i2c_clients_command(&mxb->i2c_adapter, cmd, arg); +static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; + struct saa7146_vv *vv = dev->vv_data; - strlcpy(t->name, "TV Tuner", sizeof(t->name)); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | \ - V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; - t->audmode = mxb->cur_mode; - return 0; - } - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *t = arg; + if (f->tuner) + return -EINVAL; - if (t->index) { - DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n",t->index)); - return -EINVAL; - } + if (V4L2_TUNER_ANALOG_TV != f->type) + return -EINVAL; - mxb->cur_mode = t->audmode; - i2c_clients_command(&mxb->i2c_adapter, cmd, arg); - return 0; + if (mxb->cur_input) { + DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n", mxb->cur_input)); + return -EINVAL; } - case VIDIOC_G_FREQUENCY: - { - struct v4l2_frequency *f = arg; - if (mxb->cur_input) { - DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n", - mxb->cur_input)); - return -EINVAL; - } + mxb->cur_freq = *f; + DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency)); - *f = mxb->cur_freq; + /* tune in desired frequency */ + mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, &mxb->cur_freq); - DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency)); - return 0; + /* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */ + spin_lock(&dev->slock); + vv->vbi_fieldcount = 0; + spin_unlock(&dev->slock); + + return 0; +} + +static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; + + if (a->index < 0 || a->index > MXB_INPUTS) { + DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index)); + return -EINVAL; } - case VIDIOC_S_FREQUENCY: - { - struct v4l2_frequency *f = arg; - if (f->tuner) - return -EINVAL; + DEB_EE(("VIDIOC_G_AUDIO %d.\n", a->index)); + memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio)); + return 0; +} - if (V4L2_TUNER_ANALOG_TV != f->type) - return -EINVAL; +static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a) +{ + DEB_D(("VIDIOC_S_AUDIO %d.\n", a->index)); + return 0; +} - if (mxb->cur_input) { - DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n", mxb->cur_input)); - return -EINVAL; - } +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; - mxb->cur_freq = *f; - DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency)); + i2c_clients_command(&mxb->i2c_adapter, VIDIOC_DBG_G_REGISTER, reg); + return 0; +} - /* tune in desired frequency */ - mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, &mxb->cur_freq); +static int vidioc_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; - /* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */ - spin_lock(&dev->slock); - vv->vbi_fieldcount = 0; - spin_unlock(&dev->slock); + i2c_clients_command(&mxb->i2c_adapter, VIDIOC_DBG_S_REGISTER, reg); + return 0; +} +#endif - return 0; - } +static long vidioc_default(struct file *file, void *fh, int cmd, void *arg) +{ + struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; + struct mxb *mxb = (struct mxb *)dev->ext_priv; + + switch (cmd) { case MXB_S_AUDIO_CD: { - int i = *(int*)arg; + int i = *(int *)arg; if (i < 0 || i >= MXB_AUDIOS) { - DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n",i)); + DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n", i)); return -EINVAL; } - DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n",i)); + DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n", i)); - mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[i][0]); - mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_cd[i][1]); + mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, &TEA6420_cd[i][0]); + mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, &TEA6420_cd[i][1]); return 0; } case MXB_S_AUDIO_LINE: { - int i = *(int*)arg; + int i = *(int *)arg; if (i < 0 || i >= MXB_AUDIOS) { - DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n",i)); + DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n", i)); return -EINVAL; } - DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n",i)); - mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[i][0]); - mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[i][1]); + DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n", i)); + mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, &TEA6420_line[i][0]); + mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, &TEA6420_line[i][1]); return 0; } - case VIDIOC_G_AUDIO: - { - struct v4l2_audio *a = arg; + default: +/* + DEB2(printk("does not handle this ioctl.\n")); +*/ + return -ENOIOCTLCMD; + } + return 0; +} - if (a->index < 0 || a->index > MXB_INPUTS) { - DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index)); - return -EINVAL; - } +static struct saa7146_ext_vv vv_data; + +/* this function only gets called when the probing was successful */ +static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) +{ + struct mxb *mxb = (struct mxb *)dev->ext_priv; - DEB_EE(("VIDIOC_G_AUDIO %d.\n", a->index)); - memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio)); + DEB_EE(("dev:%p\n", dev)); - return 0; - } - case VIDIOC_S_AUDIO: - { - struct v4l2_audio *a = arg; + /* checking for i2c-devices can be omitted here, because we + already did this in "mxb_vl42_probe" */ - DEB_D(("VIDIOC_S_AUDIO %d.\n", a->index)); - return 0; - } + saa7146_vv_init(dev, &vv_data); + vv_data.ops.vidioc_queryctrl = vidioc_queryctrl; + vv_data.ops.vidioc_g_ctrl = vidioc_g_ctrl; + vv_data.ops.vidioc_s_ctrl = vidioc_s_ctrl; + vv_data.ops.vidioc_enum_input = vidioc_enum_input; + vv_data.ops.vidioc_g_input = vidioc_g_input; + vv_data.ops.vidioc_s_input = vidioc_s_input; + vv_data.ops.vidioc_g_tuner = vidioc_g_tuner; + vv_data.ops.vidioc_s_tuner = vidioc_s_tuner; + vv_data.ops.vidioc_g_frequency = vidioc_g_frequency; + vv_data.ops.vidioc_s_frequency = vidioc_s_frequency; + vv_data.ops.vidioc_g_audio = vidioc_g_audio; + vv_data.ops.vidioc_s_audio = vidioc_s_audio; #ifdef CONFIG_VIDEO_ADV_DEBUG - case VIDIOC_DBG_S_REGISTER: - case VIDIOC_DBG_G_REGISTER: - i2c_clients_command(&mxb->i2c_adapter, cmd, arg); - return 0; + vv_data.ops.vidioc_g_register = vidioc_g_register; + vv_data.ops.vidioc_s_register = vidioc_s_register; #endif - default: -/* - DEB2(printk("does not handle this ioctl.\n")); -*/ - return -ENOIOCTLCMD; + vv_data.ops.vidioc_default = vidioc_default; + if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) { + ERR(("cannot register capture v4l2 device. skipping.\n")); + return -1; + } + + /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/ + if (MXB_BOARD_CAN_DO_VBI(dev)) { + if (saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) { + ERR(("cannot register vbi v4l2 device. skipping.\n")); + } } + + i2c_use_client(mxb->tea6420_1); + i2c_use_client(mxb->tea6420_2); + i2c_use_client(mxb->tea6415c); + i2c_use_client(mxb->tda9840); + i2c_use_client(mxb->saa7111a); + i2c_use_client(mxb->tuner); + + printk("mxb: found Multimedia eXtension Board #%d.\n", mxb_num); + + mxb_num++; + mxb_init_done(dev); + return 0; +} + +static int mxb_detach(struct saa7146_dev *dev) +{ + struct mxb *mxb = (struct mxb *)dev->ext_priv; + + DEB_EE(("dev:%p\n", dev)); + + i2c_release_client(mxb->tea6420_1); + i2c_release_client(mxb->tea6420_2); + i2c_release_client(mxb->tea6415c); + i2c_release_client(mxb->tda9840); + i2c_release_client(mxb->saa7111a); + i2c_release_client(mxb->tuner); + + saa7146_unregister_device(&mxb->video_dev,dev); + if (MXB_BOARD_CAN_DO_VBI(dev)) + saa7146_unregister_device(&mxb->vbi_dev, dev); + saa7146_vv_release(dev); + + mxb_num--; + + i2c_del_adapter(&mxb->i2c_adapter); + kfree(mxb); + return 0; } @@ -886,8 +909,6 @@ static struct saa7146_ext_vv vv_data = { .stds = &standard[0], .num_stds = sizeof(standard)/sizeof(struct saa7146_standard), .std_callback = &std_callback, - .ioctls = &ioctls[0], - .ioctl = mxb_ioctl, }; static struct saa7146_extension extension = { diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h index de7ee7264..d96f0f510 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h @@ -195,8 +195,20 @@ struct pvr2_hdw { struct mutex big_lock_mutex; int big_lock_held; /* For debugging */ + /* This is a simple string which identifies the instance of this + driver. It is unique within the set of existing devices, but + there is no attempt to keep the name consistent with the same + physical device each time. */ char name[32]; + /* This is a simple string which identifies the physical device + instance itself - if possible. (If not possible, then it is + based on the specific driver instance, similar to name above.) + The idea here is that userspace might hopefully be able to use + this recognize specific tuners. It will encode a serial number, + if available. */ + char identifier[32]; + /* I2C stuff */ struct i2c_adapter i2c_adap; struct i2c_algorithm i2c_algo; diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 21fdc66b4..ad34cc74a 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -1284,6 +1284,12 @@ const char *pvr2_hdw_get_bus_info(struct pvr2_hdw *hdw) } +const char *pvr2_hdw_get_device_identifier(struct pvr2_hdw *hdw) +{ + return hdw->identifier; +} + + unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *hdw) { return hdw->freqSelector ? hdw->freqValTelevision : hdw->freqValRadio; @@ -2041,6 +2047,19 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) hdw->std_mask_eeprom = V4L2_STD_ALL; } + if (hdw->serial_number) { + idx = scnprintf(hdw->identifier, sizeof(hdw->identifier) - 1, + "sn-%lu", hdw->serial_number); + } else if (hdw->unit_number >= 0) { + idx = scnprintf(hdw->identifier, sizeof(hdw->identifier) - 1, + "unit-%c", + hdw->unit_number + 'a'); + } else { + idx = scnprintf(hdw->identifier, sizeof(hdw->identifier) - 1, + "unit-??"); + } + hdw->identifier[idx] = 0; + pvr2_hdw_setup_std(hdw); if (!get_default_tuner_type(hdw)) { @@ -3747,7 +3766,11 @@ void pvr2_hdw_device_reset(struct pvr2_hdw *hdw) int ret; pvr2_trace(PVR2_TRACE_INIT,"Performing a device reset..."); ret = usb_lock_device_for_reset(hdw->usb_dev,NULL); - if (ret == 1) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) + /* Due to the API changes, the ret value for success changed */ + ret = ret != 1; +#endif + if (ret == 0) { ret = usb_reset_device(hdw->usb_dev); usb_unlock_device(hdw->usb_dev); } else { diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h index 732546fa3..e4d04a7fe 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h @@ -138,6 +138,9 @@ unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *); /* Retrieve bus location info of device */ const char *pvr2_hdw_get_bus_info(struct pvr2_hdw *); +/* Retrieve per-instance string identifier for this specific device */ +const char *pvr2_hdw_get_device_identifier(struct pvr2_hdw *); + /* Called when hardware has been unplugged */ void pvr2_hdw_disconnect(struct pvr2_hdw *); @@ -242,8 +245,7 @@ void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *, enum pvr2_v4l_type index,int); /* Direct read/write access to chip's registers: - match_type - how to interpret match_chip (e.g. driver ID, i2c address) - match_chip - chip match value (e.g. I2C_DRIVERD_xxxx) + match - specify criteria to identify target chip (this is a v4l dbg struct) reg_id - register number to access setFl - true to set the register, false to read it val_ptr - storage location for source / result. */ diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c index 1b1424955..073b02a4b 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c @@ -32,17 +32,19 @@ #define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__) -#define OP_STANDARD 0 -#define OP_AUDIOMODE 1 -#define OP_BCSH 2 -#define OP_VOLUME 3 -#define OP_FREQ 4 -#define OP_AUDIORATE 5 -#define OP_CROP 6 -#define OP_SIZE 7 -#define OP_LOG 8 +#define OP_INIT 0 /* MUST come first so it is run first */ +#define OP_STANDARD 1 +#define OP_AUDIOMODE 2 +#define OP_BCSH 3 +#define OP_VOLUME 4 +#define OP_FREQ 5 +#define OP_AUDIORATE 6 +#define OP_CROP 7 +#define OP_SIZE 8 +#define OP_LOG 9 static const struct pvr2_i2c_op * const ops[] = { + [OP_INIT] = &pvr2_i2c_op_v4l2_init, [OP_STANDARD] = &pvr2_i2c_op_v4l2_standard, [OP_AUDIOMODE] = &pvr2_i2c_op_v4l2_audiomode, [OP_BCSH] = &pvr2_i2c_op_v4l2_bcsh, @@ -57,7 +59,8 @@ void pvr2_i2c_probe(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp) { int id; id = cp->client->driver->id; - cp->ctl_mask = ((1 << OP_STANDARD) | + cp->ctl_mask = ((1 << OP_INIT) | + (1 << OP_STANDARD) | (1 << OP_AUDIOMODE) | (1 << OP_BCSH) | (1 << OP_VOLUME) | diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c index ab703d6d5..db61c1fb0 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c @@ -26,6 +26,20 @@ #include <media/v4l2-common.h> #include "compat.h" +static void execute_init(struct pvr2_hdw *hdw) +{ + u32 dummy = 0; + pvr2_trace(PVR2_TRACE_CHIPS, "i2c v4l2 init"); + pvr2_i2c_core_cmd(hdw, VIDIOC_INT_INIT, &dummy); +} + + +const struct pvr2_i2c_op pvr2_i2c_op_v4l2_init = { + .update = execute_init, + .name = "v4l2_init", +}; + + static void set_standard(struct pvr2_hdw *hdw) { pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_standard"); diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h index eb744a206..69a63f2a8 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h @@ -24,6 +24,7 @@ #include "pvrusb2-i2c-core.h" +extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_init; extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_standard; extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_radio; extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_bcsh; diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index 877c8f7b1..d95abcc55 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -838,7 +838,7 @@ int pvr2_i2c_core_check_stale(struct pvr2_hdw *hdw) if (!(msk & pm)) continue; pm &= ~msk; opf = pvr2_i2c_get_op(idx); - if (!opf) continue; + if (!(opf && opf->check)) continue; if (opf->check(hdw)) { sm |= msk; } diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-main.c b/linux/drivers/media/video/pvrusb2/pvrusb2-main.c index 2399959a8..196e08246 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-main.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-main.c @@ -138,10 +138,10 @@ static int __init pvr_init(void) ret = usb_register(&pvr_driver); if (ret == 0) - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" + printk(KERN_INFO "pvrusb2: " DRIVER_VERSION ":" DRIVER_DESC "\n"); if (pvrusb2_debug) - printk(KERN_INFO KBUILD_MODNAME ": Debug mask is %d (0x%x)\n", + printk(KERN_INFO "pvrusb2: Debug mask is %d (0x%x)\n", pvrusb2_debug,pvrusb2_debug); pvr2_trace(PVR2_TRACE_INIT,"pvr_init complete"); diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index 770f31e60..84379d6e0 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -636,16 +636,8 @@ static void class_dev_create(struct pvr2_sysfs *sfp, pvr2_sysfs_trace("Creating class_dev id=%p",class_dev); class_dev->class = &class_ptr->class; - if (pvr2_hdw_get_sn(sfp->channel.hdw)) { - dev_set_name(class_dev, "sn-%lu", - pvr2_hdw_get_sn(sfp->channel.hdw)); - } else if (pvr2_hdw_get_unit_number(sfp->channel.hdw) >= 0) { - dev_set_name(class_dev, "unit-%c", - pvr2_hdw_get_unit_number(sfp->channel.hdw) + 'a'); - } else { - kfree(class_dev); - return; - } + dev_set_name(class_dev, "%s", + pvr2_hdw_get_device_identifier(sfp->channel.hdw)); class_dev->parent = &usb_dev->dev; diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 7340f4815..26da521f1 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -92,7 +92,7 @@ static struct v4l2_capability pvr_capability ={ .card = "Hauppauge WinTV pvr-usb2", .bus_info = "usb", .version = KERNEL_VERSION(0,8,0), - .capabilities = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE | + .capabilities = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO | V4L2_CAP_READWRITE), .reserved = {0,0,0,0} diff --git a/linux/drivers/media/video/pwc/Kconfig b/linux/drivers/media/video/pwc/Kconfig index 7298cf2e1..8b9f0aa84 100644 --- a/linux/drivers/media/video/pwc/Kconfig +++ b/linux/drivers/media/video/pwc/Kconfig @@ -35,3 +35,13 @@ config USB_PWC_DEBUG Say Y here in order to have the pwc driver generate verbose debugging messages. A special module options 'trace' is used to control the verbosity. + +config USB_PWC_INPUT_EVDEV + bool "USB Philips Cameras input events device support" + default y + depends on USB_PWC && INPUT + ---help--- + This option makes USB Philips cameras register the snapshot button as + an input device to report button events. + + If you are in doubt, say Y. diff --git a/linux/drivers/media/video/pwc/pwc-if.c b/linux/drivers/media/video/pwc/pwc-if.c index e314a6383..49a918636 100644 --- a/linux/drivers/media/video/pwc/pwc-if.c +++ b/linux/drivers/media/video/pwc/pwc-if.c @@ -53,6 +53,7 @@ - Xavier Roche: QuickCam Pro 4000 ID - Jens Knudsen: QuickCam Zoom ID - J. Debert: QuickCam for Notebooks ID + - Pham Thanh Nam: webcam snapshot button as an event input device */ #include <linux/errno.h> @@ -61,6 +62,13 @@ #include <linux/module.h> #include <linux/poll.h> #include <linux/slab.h> +#ifdef CONFIG_USB_PWC_INPUT_EVDEV +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) +#include <linux/usb_input.h> +#else +#include <linux/usb/input.h> +#endif +#endif #include <linux/vmalloc.h> #include <asm/io.h> @@ -586,6 +594,23 @@ static void pwc_frame_dumped(struct pwc_device *pdev) pdev->vframe_count); } +static void pwc_snapshot_button(struct pwc_device *pdev, int down) +{ + if (down) { + PWC_TRACE("Snapshot button pressed.\n"); + pdev->snapshot_button_status = 1; + } else { + PWC_TRACE("Snapshot button released.\n"); + } + +#ifdef CONFIG_USB_PWC_INPUT_EVDEV + if (pdev->button_dev) { + input_report_key(pdev->button_dev, BTN_0, down); + input_sync(pdev->button_dev); + } +#endif +} + static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_buf *fbuf) { int awake = 0; @@ -603,13 +628,7 @@ static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_ pdev->vframes_error++; } if ((ptr[0] ^ pdev->vmirror) & 0x01) { - if (ptr[0] & 0x01) { - pdev->snapshot_button_status = 1; - PWC_TRACE("Snapshot button pressed.\n"); - } - else { - PWC_TRACE("Snapshot button released.\n"); - } + pwc_snapshot_button(pdev, ptr[0] & 0x01); } if ((ptr[0] ^ pdev->vmirror) & 0x02) { if (ptr[0] & 0x02) @@ -633,12 +652,7 @@ static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_ else if (pdev->type == 740 || pdev->type == 720) { unsigned char *ptr = (unsigned char *)fbuf->data; if ((ptr[0] ^ pdev->vmirror) & 0x01) { - if (ptr[0] & 0x01) { - pdev->snapshot_button_status = 1; - PWC_TRACE("Snapshot button pressed.\n"); - } - else - PWC_TRACE("Snapshot button released.\n"); + pwc_snapshot_button(pdev, ptr[0] & 0x01); } pdev->vmirror = ptr[0] & 0x03; } @@ -1220,6 +1234,15 @@ static void pwc_cleanup(struct pwc_device *pdev) { pwc_remove_sysfs_files(pdev->vdev); video_unregister_device(pdev->vdev); + +#ifdef CONFIG_USB_PWC_INPUT_EVDEV + if (pdev->button_dev) { + input_unregister_device(pdev->button_dev); + input_free_device(pdev->button_dev); + kfree(pdev->button_dev->phys); + pdev->button_dev = NULL; + } +#endif } /* Note that all cleanup is done in the reverse order as in _open */ @@ -1487,6 +1510,9 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id int features = 0; int video_nr = -1; /* default: use next available device */ char serial_number[30], *name; +#ifdef CONFIG_USB_PWC_INPUT_EVDEV + char *phys = NULL; +#endif vendor_id = le16_to_cpu(udev->descriptor.idVendor); product_id = le16_to_cpu(udev->descriptor.idProduct); @@ -1811,6 +1837,39 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id pwc_set_leds(pdev, 0, 0); pwc_camera_power(pdev, 0); +#ifdef CONFIG_USB_PWC_INPUT_EVDEV + /* register webcam snapshot button input device */ + pdev->button_dev = input_allocate_device(); + if (!pdev->button_dev) { + PWC_ERROR("Err, insufficient memory for webcam snapshot button device."); + return -ENOMEM; + } + + pdev->button_dev->name = "PWC snapshot button"; + phys = kasprintf(GFP_KERNEL,"usb-%s-%s", pdev->udev->bus->bus_name, pdev->udev->devpath); + if (!phys) { + input_free_device(pdev->button_dev); + return -ENOMEM; + } + pdev->button_dev->phys = phys; + usb_to_input_id(pdev->udev, &pdev->button_dev->id); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) + pdev->button_dev->dev.parent = &pdev->udev->dev; +#else + pdev->button_dev->cdev.dev = &pdev->udev->dev; +#endif + pdev->button_dev->evbit[0] = BIT_MASK(EV_KEY); + pdev->button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0); + + rc = input_register_device(pdev->button_dev); + if (rc) { + input_free_device(pdev->button_dev); + kfree(pdev->button_dev->phys); + pdev->button_dev = NULL; + return rc; + } +#endif + return 0; err_unreg: diff --git a/linux/drivers/media/video/pwc/pwc.h b/linux/drivers/media/video/pwc/pwc.h index a76971ead..3a89dca13 100644 --- a/linux/drivers/media/video/pwc/pwc.h +++ b/linux/drivers/media/video/pwc/pwc.h @@ -38,6 +38,9 @@ #include <linux/videodev.h> #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> +#ifdef CONFIG_USB_PWC_INPUT_EVDEV +#include <linux/input.h> +#endif #include "pwc-uncompress.h" #include <media/pwc-ioctl.h> @@ -256,6 +259,9 @@ struct pwc_device int pan_angle; /* in degrees * 100 */ int tilt_angle; /* absolute angle; 0,0 is home position */ int snapshot_button_status; /* set to 1 when the user push the button, reset to 0 when this value is read */ +#ifdef CONFIG_USB_PWC_INPUT_EVDEV + struct input_dev *button_dev; /* webcam snapshot button input */ +#endif /*** Misc. data ***/ wait_queue_head_t frameq; /* When waiting for a frame to finish... */ diff --git a/linux/drivers/media/video/saa7134/saa6752hs.c b/linux/drivers/media/video/saa7134/saa6752hs.c index f2d4aea16..2e2871de1 100644 --- a/linux/drivers/media/video/saa7134/saa6752hs.c +++ b/linux/drivers/media/video/saa7134/saa6752hs.c @@ -34,9 +34,10 @@ #include <linux/types.h> #include "compat.h" #include <linux/videodev2.h> +#include <media/v4l2-device.h> #include <media/v4l2-common.h> #include <media/v4l2-chip-ident.h> -#include <media/v4l2-i2c-drv-legacy.h> +#include <media/v4l2-i2c-drv.h> #include <linux/init.h> #include <linux/crc32.h> @@ -45,10 +46,12 @@ #define MPEG_TOTAL_TARGET_BITRATE_MAX 27000 #define MPEG_PID_MAX ((1 << 14) - 1) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) /* Addresses to scan */ static unsigned short normal_i2c[] = {0x20, I2C_CLIENT_END}; I2C_CLIENT_INSMOD; +#endif MODULE_DESCRIPTION("device driver for saa6752hs MPEG2 encoder"); MODULE_AUTHOR("Andrew de Quincey"); @@ -96,6 +99,7 @@ static const struct v4l2_format v4l2_format_table[] = }; struct saa6752hs_state { + struct v4l2_subdev sd; int chip; u32 revision; int has_ac3; @@ -116,6 +120,11 @@ enum saa6752hs_command { SAA6752HS_COMMAND_MAX }; +static inline struct saa6752hs_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct saa6752hs_state, sd); +} + /* ---------------------------------------------------------------------- */ static u8 PAT[] = { @@ -361,185 +370,191 @@ static int saa6752hs_set_bitrate(struct i2c_client *client, return 0; } -static void saa6752hs_set_subsampling(struct i2c_client *client, - struct v4l2_format *f) -{ - struct saa6752hs_state *h = i2c_get_clientdata(client); - int dist_352, dist_480, dist_720; - - /* - FIXME: translate and round width/height into EMPRESS - subsample type: - type | PAL | NTSC - --------------------------- - SIF | 352x288 | 352x240 - 1/2 D1 | 352x576 | 352x480 - 2/3 D1 | 480x576 | 480x480 - D1 | 720x576 | 720x480 - */ - - dist_352 = abs(f->fmt.pix.width - 352); - dist_480 = abs(f->fmt.pix.width - 480); - dist_720 = abs(f->fmt.pix.width - 720); - if (dist_720 < dist_480) { - f->fmt.pix.width = 720; - f->fmt.pix.height = 576; - h->video_format = SAA6752HS_VF_D1; - } - else if (dist_480 < dist_352) { - f->fmt.pix.width = 480; - f->fmt.pix.height = 576; - h->video_format = SAA6752HS_VF_2_3_D1; - } - else { - f->fmt.pix.width = 352; - if (abs(f->fmt.pix.height - 576) < - abs(f->fmt.pix.height - 288)) { - f->fmt.pix.height = 576; - h->video_format = SAA6752HS_VF_1_2_D1; - } - else { - f->fmt.pix.height = 288; - h->video_format = SAA6752HS_VF_SIF; - } +static int get_ctrl(int has_ac3, struct saa6752hs_mpeg_params *params, + struct v4l2_ext_control *ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_MPEG_STREAM_TYPE: + ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG2_TS; + break; + case V4L2_CID_MPEG_STREAM_PID_PMT: + ctrl->value = params->ts_pid_pmt; + break; + case V4L2_CID_MPEG_STREAM_PID_AUDIO: + ctrl->value = params->ts_pid_audio; + break; + case V4L2_CID_MPEG_STREAM_PID_VIDEO: + ctrl->value = params->ts_pid_video; + break; + case V4L2_CID_MPEG_STREAM_PID_PCR: + ctrl->value = params->ts_pid_pcr; + break; + case V4L2_CID_MPEG_AUDIO_ENCODING: + ctrl->value = params->au_encoding; + break; + case V4L2_CID_MPEG_AUDIO_L2_BITRATE: + ctrl->value = params->au_l2_bitrate; + break; + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: + if (!has_ac3) + return -EINVAL; + ctrl->value = params->au_ac3_bitrate; + break; + case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: + ctrl->value = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000; + break; + case V4L2_CID_MPEG_VIDEO_ENCODING: + ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_2; + break; + case V4L2_CID_MPEG_VIDEO_ASPECT: + ctrl->value = params->vi_aspect; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE: + ctrl->value = params->vi_bitrate * 1000; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: + ctrl->value = params->vi_bitrate_peak * 1000; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + ctrl->value = params->vi_bitrate_mode; + break; + default: + return -EINVAL; } + return 0; } - static int handle_ctrl(int has_ac3, struct saa6752hs_mpeg_params *params, - struct v4l2_ext_control *ctrl, unsigned int cmd) + struct v4l2_ext_control *ctrl, int set) { int old = 0, new; - int set = (cmd == VIDIOC_S_EXT_CTRLS); new = ctrl->value; switch (ctrl->id) { - case V4L2_CID_MPEG_STREAM_TYPE: - old = V4L2_MPEG_STREAM_TYPE_MPEG2_TS; - if (set && new != old) - return -ERANGE; - new = old; - break; - case V4L2_CID_MPEG_STREAM_PID_PMT: - old = params->ts_pid_pmt; - if (set && new > MPEG_PID_MAX) - return -ERANGE; - if (new > MPEG_PID_MAX) - new = MPEG_PID_MAX; - params->ts_pid_pmt = new; - break; - case V4L2_CID_MPEG_STREAM_PID_AUDIO: - old = params->ts_pid_audio; - if (set && new > MPEG_PID_MAX) - return -ERANGE; - if (new > MPEG_PID_MAX) - new = MPEG_PID_MAX; - params->ts_pid_audio = new; - break; - case V4L2_CID_MPEG_STREAM_PID_VIDEO: - old = params->ts_pid_video; - if (set && new > MPEG_PID_MAX) - return -ERANGE; - if (new > MPEG_PID_MAX) - new = MPEG_PID_MAX; - params->ts_pid_video = new; - break; - case V4L2_CID_MPEG_STREAM_PID_PCR: - old = params->ts_pid_pcr; - if (set && new > MPEG_PID_MAX) - return -ERANGE; - if (new > MPEG_PID_MAX) - new = MPEG_PID_MAX; - params->ts_pid_pcr = new; - break; - case V4L2_CID_MPEG_AUDIO_ENCODING: - old = params->au_encoding; - if (set && new != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 && - (!has_ac3 || new != V4L2_MPEG_AUDIO_ENCODING_AC3)) - return -ERANGE; - new = old; - break; - case V4L2_CID_MPEG_AUDIO_L2_BITRATE: - old = params->au_l2_bitrate; - if (set && new != V4L2_MPEG_AUDIO_L2_BITRATE_256K && - new != V4L2_MPEG_AUDIO_L2_BITRATE_384K) - return -ERANGE; - if (new <= V4L2_MPEG_AUDIO_L2_BITRATE_256K) - new = V4L2_MPEG_AUDIO_L2_BITRATE_256K; - else - new = V4L2_MPEG_AUDIO_L2_BITRATE_384K; - params->au_l2_bitrate = new; - break; - case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: - if (!has_ac3) - return -EINVAL; - old = params->au_ac3_bitrate; - if (set && new != V4L2_MPEG_AUDIO_AC3_BITRATE_256K && - new != V4L2_MPEG_AUDIO_AC3_BITRATE_384K) - return -ERANGE; - if (new <= V4L2_MPEG_AUDIO_AC3_BITRATE_256K) - new = V4L2_MPEG_AUDIO_AC3_BITRATE_256K; - else - new = V4L2_MPEG_AUDIO_AC3_BITRATE_384K; - params->au_ac3_bitrate = new; - break; - case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: - old = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000; - if (set && new != old) - return -ERANGE; - new = old; - break; - case V4L2_CID_MPEG_VIDEO_ENCODING: - old = V4L2_MPEG_VIDEO_ENCODING_MPEG_2; - if (set && new != old) - return -ERANGE; - new = old; - break; - case V4L2_CID_MPEG_VIDEO_ASPECT: - old = params->vi_aspect; - if (set && new != V4L2_MPEG_VIDEO_ASPECT_16x9 && - new != V4L2_MPEG_VIDEO_ASPECT_4x3) - return -ERANGE; - if (new != V4L2_MPEG_VIDEO_ASPECT_16x9) - new = V4L2_MPEG_VIDEO_ASPECT_4x3; - params->vi_aspect = new; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE: - old = params->vi_bitrate * 1000; - new = 1000 * (new / 1000); - if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000) - return -ERANGE; - if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000) - new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000; - params->vi_bitrate = new / 1000; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: - old = params->vi_bitrate_peak * 1000; - new = 1000 * (new / 1000); - if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000) - return -ERANGE; - if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000) - new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000; - params->vi_bitrate_peak = new / 1000; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: - old = params->vi_bitrate_mode; - params->vi_bitrate_mode = new; - break; - default: + case V4L2_CID_MPEG_STREAM_TYPE: + old = V4L2_MPEG_STREAM_TYPE_MPEG2_TS; + if (set && new != old) + return -ERANGE; + new = old; + break; + case V4L2_CID_MPEG_STREAM_PID_PMT: + old = params->ts_pid_pmt; + if (set && new > MPEG_PID_MAX) + return -ERANGE; + if (new > MPEG_PID_MAX) + new = MPEG_PID_MAX; + params->ts_pid_pmt = new; + break; + case V4L2_CID_MPEG_STREAM_PID_AUDIO: + old = params->ts_pid_audio; + if (set && new > MPEG_PID_MAX) + return -ERANGE; + if (new > MPEG_PID_MAX) + new = MPEG_PID_MAX; + params->ts_pid_audio = new; + break; + case V4L2_CID_MPEG_STREAM_PID_VIDEO: + old = params->ts_pid_video; + if (set && new > MPEG_PID_MAX) + return -ERANGE; + if (new > MPEG_PID_MAX) + new = MPEG_PID_MAX; + params->ts_pid_video = new; + break; + case V4L2_CID_MPEG_STREAM_PID_PCR: + old = params->ts_pid_pcr; + if (set && new > MPEG_PID_MAX) + return -ERANGE; + if (new > MPEG_PID_MAX) + new = MPEG_PID_MAX; + params->ts_pid_pcr = new; + break; + case V4L2_CID_MPEG_AUDIO_ENCODING: + old = params->au_encoding; + if (set && new != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 && + (!has_ac3 || new != V4L2_MPEG_AUDIO_ENCODING_AC3)) + return -ERANGE; + new = old; + break; + case V4L2_CID_MPEG_AUDIO_L2_BITRATE: + old = params->au_l2_bitrate; + if (set && new != V4L2_MPEG_AUDIO_L2_BITRATE_256K && + new != V4L2_MPEG_AUDIO_L2_BITRATE_384K) + return -ERANGE; + if (new <= V4L2_MPEG_AUDIO_L2_BITRATE_256K) + new = V4L2_MPEG_AUDIO_L2_BITRATE_256K; + else + new = V4L2_MPEG_AUDIO_L2_BITRATE_384K; + params->au_l2_bitrate = new; + break; + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: + if (!has_ac3) return -EINVAL; + old = params->au_ac3_bitrate; + if (set && new != V4L2_MPEG_AUDIO_AC3_BITRATE_256K && + new != V4L2_MPEG_AUDIO_AC3_BITRATE_384K) + return -ERANGE; + if (new <= V4L2_MPEG_AUDIO_AC3_BITRATE_256K) + new = V4L2_MPEG_AUDIO_AC3_BITRATE_256K; + else + new = V4L2_MPEG_AUDIO_AC3_BITRATE_384K; + params->au_ac3_bitrate = new; + break; + case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: + old = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000; + if (set && new != old) + return -ERANGE; + new = old; + break; + case V4L2_CID_MPEG_VIDEO_ENCODING: + old = V4L2_MPEG_VIDEO_ENCODING_MPEG_2; + if (set && new != old) + return -ERANGE; + new = old; + break; + case V4L2_CID_MPEG_VIDEO_ASPECT: + old = params->vi_aspect; + if (set && new != V4L2_MPEG_VIDEO_ASPECT_16x9 && + new != V4L2_MPEG_VIDEO_ASPECT_4x3) + return -ERANGE; + if (new != V4L2_MPEG_VIDEO_ASPECT_16x9) + new = V4L2_MPEG_VIDEO_ASPECT_4x3; + params->vi_aspect = new; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE: + old = params->vi_bitrate * 1000; + new = 1000 * (new / 1000); + if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000) + return -ERANGE; + if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000) + new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000; + params->vi_bitrate = new / 1000; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: + old = params->vi_bitrate_peak * 1000; + new = 1000 * (new / 1000); + if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000) + return -ERANGE; + if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000) + new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000; + params->vi_bitrate_peak = new / 1000; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + old = params->vi_bitrate_mode; + params->vi_bitrate_mode = new; + break; + default: + return -EINVAL; } - if (cmd == VIDIOC_G_EXT_CTRLS) - ctrl->value = old; - else - ctrl->value = new; + ctrl->value = new; return 0; } -static int saa6752hs_qctrl(struct saa6752hs_state *h, - struct v4l2_queryctrl *qctrl) + +static int saa6752hs_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl) { + struct saa6752hs_state *h = to_state(sd); struct saa6752hs_mpeg_params *params = &h->params; int err; @@ -611,8 +626,7 @@ static int saa6752hs_qctrl(struct saa6752hs_state *h, return -EINVAL; } -static int saa6752hs_qmenu(struct saa6752hs_state *h, - struct v4l2_querymenu *qmenu) +static int saa6752hs_querymenu(struct v4l2_subdev *sd, struct v4l2_querymenu *qmenu) { static const u32 mpeg_audio_encoding[] = { V4L2_MPEG_AUDIO_ENCODING_LAYER_2, @@ -633,11 +647,12 @@ static int saa6752hs_qmenu(struct saa6752hs_state *h, V4L2_MPEG_AUDIO_AC3_BITRATE_384K, V4L2_CTRL_MENU_IDS_END }; + struct saa6752hs_state *h = to_state(sd); struct v4l2_queryctrl qctrl; int err; qctrl.id = qmenu->id; - err = saa6752hs_qctrl(h, &qctrl); + err = saa6752hs_queryctrl(sd, &qctrl); if (err) return err; switch (qmenu->id) { @@ -657,17 +672,16 @@ static int saa6752hs_qmenu(struct saa6752hs_state *h, return v4l2_ctrl_query_menu(qmenu, &qctrl, NULL); } -static int saa6752hs_init(struct i2c_client *client, u32 leading_null_bytes) +static int saa6752hs_init(struct v4l2_subdev *sd, u32 leading_null_bytes) { unsigned char buf[9], buf2[4]; - struct saa6752hs_state *h; + struct saa6752hs_state *h = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); unsigned size; u32 crc; unsigned char localPAT[256]; unsigned char localPMT[256]; - h = i2c_get_clientdata(client); - /* Set video format - must be done first as it resets other settings */ set_reg8(client, 0x41, h->video_format); @@ -763,7 +777,7 @@ static int saa6752hs_init(struct i2c_client *client, u32 leading_null_bytes) buf[3] = 0x82; buf[4] = 0xB0; buf[5] = buf2[0]; - switch(h->params.vi_aspect) { + switch (h->params.vi_aspect) { case V4L2_MPEG_VIDEO_ASPECT_16x9: buf[6] = buf2[1] | 0x40; break; @@ -771,7 +785,6 @@ static int saa6752hs_init(struct i2c_client *client, u32 leading_null_bytes) default: buf[6] = buf2[1] & 0xBF; break; - break; } buf[7] = buf2[2]; buf[8] = buf2[3]; @@ -780,81 +793,162 @@ static int saa6752hs_init(struct i2c_client *client, u32 leading_null_bytes) return 0; } -static int -saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg) +static int saa6752hs_do_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls, int set) { - struct saa6752hs_state *h = i2c_get_clientdata(client); - struct v4l2_ext_controls *ctrls = arg; + struct saa6752hs_state *h = to_state(sd); struct saa6752hs_mpeg_params params; - int err = 0; int i; - switch (cmd) { - case VIDIOC_INT_INIT: - /* apply settings and start encoder */ - saa6752hs_init(client, *(u32 *)arg); - break; - case VIDIOC_S_EXT_CTRLS: - if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - /* fall through */ - case VIDIOC_TRY_EXT_CTRLS: - case VIDIOC_G_EXT_CTRLS: - if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - params = h->params; - for (i = 0; i < ctrls->count; i++) { - err = handle_ctrl(h->has_ac3, ¶ms, ctrls->controls + i, cmd); - if (err) { - ctrls->error_idx = i; - return err; - } + if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) + return -EINVAL; + + params = h->params; + for (i = 0; i < ctrls->count; i++) { + int err = handle_ctrl(h->has_ac3, ¶ms, ctrls->controls + i, set); + + if (err) { + ctrls->error_idx = i; + return err; } - h->params = params; - break; - case VIDIOC_QUERYCTRL: - return saa6752hs_qctrl(h, arg); - case VIDIOC_QUERYMENU: - return saa6752hs_qmenu(h, arg); - case VIDIOC_G_FMT: - { - struct v4l2_format *f = arg; - - if (h->video_format == SAA6752HS_VF_UNKNOWN) - h->video_format = SAA6752HS_VF_D1; - f->fmt.pix.width = - v4l2_format_table[h->video_format].fmt.pix.width; - f->fmt.pix.height = - v4l2_format_table[h->video_format].fmt.pix.height; - break ; } - case VIDIOC_S_FMT: - { - struct v4l2_format *f = arg; + if (set) + h->params = params; + return 0; +} - saa6752hs_set_subsampling(client, f); - break; +static int saa6752hs_s_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls) +{ + return saa6752hs_do_ext_ctrls(sd, ctrls, 1); +} + +static int saa6752hs_try_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls) +{ + return saa6752hs_do_ext_ctrls(sd, ctrls, 0); +} + +static int saa6752hs_g_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *ctrls) +{ + struct saa6752hs_state *h = to_state(sd); + int i; + + if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) + return -EINVAL; + + for (i = 0; i < ctrls->count; i++) { + int err = get_ctrl(h->has_ac3, &h->params, ctrls->controls + i); + + if (err) { + ctrls->error_idx = i; + return err; + } } - case VIDIOC_S_STD: - h->standard = *((v4l2_std_id *) arg); - break; + return 0; +} - case VIDIOC_DBG_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, - arg, h->chip, h->revision); +static int saa6752hs_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct saa6752hs_state *h = to_state(sd); - default: - /* nothing */ - break; + if (h->video_format == SAA6752HS_VF_UNKNOWN) + h->video_format = SAA6752HS_VF_D1; + f->fmt.pix.width = + v4l2_format_table[h->video_format].fmt.pix.width; + f->fmt.pix.height = + v4l2_format_table[h->video_format].fmt.pix.height; + return 0; +} + +static int saa6752hs_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +{ + struct saa6752hs_state *h = to_state(sd); + int dist_352, dist_480, dist_720; + + /* + FIXME: translate and round width/height into EMPRESS + subsample type: + + type | PAL | NTSC + --------------------------- + SIF | 352x288 | 352x240 + 1/2 D1 | 352x576 | 352x480 + 2/3 D1 | 480x576 | 480x480 + D1 | 720x576 | 720x480 + */ + + dist_352 = abs(f->fmt.pix.width - 352); + dist_480 = abs(f->fmt.pix.width - 480); + dist_720 = abs(f->fmt.pix.width - 720); + if (dist_720 < dist_480) { + f->fmt.pix.width = 720; + f->fmt.pix.height = 576; + h->video_format = SAA6752HS_VF_D1; + } else if (dist_480 < dist_352) { + f->fmt.pix.width = 480; + f->fmt.pix.height = 576; + h->video_format = SAA6752HS_VF_2_3_D1; + } else { + f->fmt.pix.width = 352; + if (abs(f->fmt.pix.height - 576) < + abs(f->fmt.pix.height - 288)) { + f->fmt.pix.height = 576; + h->video_format = SAA6752HS_VF_1_2_D1; + } else { + f->fmt.pix.height = 288; + h->video_format = SAA6752HS_VF_SIF; + } } + return 0; +} + +static int saa6752hs_s_std(struct v4l2_subdev *sd, v4l2_std_id std) +{ + struct saa6752hs_state *h = to_state(sd); + + h->standard = std; + return 0; +} - return err; +static int saa6752hs_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct saa6752hs_state *h = to_state(sd); + + return v4l2_chip_ident_i2c_client(client, + chip, h->chip, h->revision); } +/* ----------------------------------------------------------------------- */ + +static const struct v4l2_subdev_core_ops saa6752hs_core_ops = { + .g_chip_ident = saa6752hs_g_chip_ident, + .init = saa6752hs_init, + .queryctrl = saa6752hs_queryctrl, + .querymenu = saa6752hs_querymenu, + .g_ext_ctrls = saa6752hs_g_ext_ctrls, + .s_ext_ctrls = saa6752hs_s_ext_ctrls, + .try_ext_ctrls = saa6752hs_try_ext_ctrls, +}; + +static const struct v4l2_subdev_tuner_ops saa6752hs_tuner_ops = { + .s_std = saa6752hs_s_std, +}; + +static const struct v4l2_subdev_video_ops saa6752hs_video_ops = { + .s_fmt = saa6752hs_s_fmt, + .g_fmt = saa6752hs_g_fmt, +}; + +static const struct v4l2_subdev_ops saa6752hs_ops = { + .core = &saa6752hs_core_ops, + .tuner = &saa6752hs_tuner_ops, + .video = &saa6752hs_video_ops, +}; + static int saa6752hs_probe(struct i2c_client *client, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { struct saa6752hs_state *h = kzalloc(sizeof(*h), GFP_KERNEL); + struct v4l2_subdev *sd; u8 addr = 0x13; u8 data[12]; @@ -862,6 +956,8 @@ static int saa6752hs_probe(struct i2c_client *client, client->addr << 1, client->adapter->name); if (h == NULL) return -ENOMEM; + sd = &h->sd; + v4l2_i2c_subdev_init(sd, client, &saa6752hs_ops); i2c_master_send(client, &addr, 1); i2c_master_recv(client, data, sizeof(data)); @@ -875,14 +971,15 @@ static int saa6752hs_probe(struct i2c_client *client, } h->params = param_defaults; h->standard = 0; /* Assume 625 input lines */ - - i2c_set_clientdata(client, h); return 0; } static int saa6752hs_remove(struct i2c_client *client) { - kfree(i2c_get_clientdata(client)); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + v4l2_device_unregister_subdev(sd); + kfree(to_state(sd)); return 0; } @@ -896,8 +993,6 @@ MODULE_DEVICE_TABLE(i2c, saa6752hs_id); #endif static struct v4l2_i2c_driver_data v4l2_i2c_data = { .name = "saa6752hs", - .driverid = I2C_DRIVERID_SAA6752HS, - .command = saa6752hs_command, .probe = saa6752hs_probe, .remove = saa6752hs_remove, #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) diff --git a/linux/drivers/media/video/saa7134/saa7134-cards.c b/linux/drivers/media/video/saa7134/saa7134-cards.c index 12893f09b..7740c1601 100644 --- a/linux/drivers/media/video/saa7134/saa7134-cards.c +++ b/linux/drivers/media/video/saa7134/saa7134-cards.c @@ -4650,7 +4650,7 @@ struct saa7134_board saa7134_boards[] = { .tuner_type = TUNER_YMEC_TVF_5533MF, .radio_type = TUNER_TEA5767, .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, + .radio_addr = 0x60, .gpiomask = 0x80000700, .inputs = { { .name = name_tv, @@ -6212,7 +6212,7 @@ static void saa7134_tuner_setup(struct saa7134_dev *dev) tun_setup.mode_mask = T_RADIO; - saa7134_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); + saa_call_all(dev, tuner, s_type_addr, &tun_setup); mode_mask &= ~T_RADIO; } @@ -6224,7 +6224,7 @@ static void saa7134_tuner_setup(struct saa7134_dev *dev) tun_setup.mode_mask = mode_mask; - saa7134_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); + saa_call_all(dev, tuner, s_type_addr, &tun_setup); } if (dev->tda9887_conf) { @@ -6233,8 +6233,7 @@ static void saa7134_tuner_setup(struct saa7134_dev *dev) tda9887_cfg.tuner = TUNER_TDA9887; tda9887_cfg.priv = &dev->tda9887_conf; - saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, - &tda9887_cfg); + saa_call_all(dev, tuner, s_config, &tda9887_cfg); } if (dev->tuner_type == TUNER_XC2028) { @@ -6261,7 +6260,7 @@ static void saa7134_tuner_setup(struct saa7134_dev *dev) xc2028_cfg.tuner = TUNER_XC2028; xc2028_cfg.priv = &ctl; - saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg); + saa_call_all(dev, tuner, s_config, &xc2028_cfg); } } @@ -6504,7 +6503,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) ctl.xtal_freq = TEA5767_HIGH_LO_13MHz; tea5767_cfg.tuner = TUNER_TEA5767; tea5767_cfg.priv = &ctl; - saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &tea5767_cfg); + saa_call_all(dev, tuner, s_config, &tea5767_cfg); break; } } /* switch() */ diff --git a/linux/drivers/media/video/saa7134/saa7134-core.c b/linux/drivers/media/video/saa7134/saa7134-core.c index 624ac4537..1ba80210e 100644 --- a/linux/drivers/media/video/saa7134/saa7134-core.c +++ b/linux/drivers/media/video/saa7134/saa7134-core.c @@ -912,6 +912,10 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, if (NULL == dev) return -ENOMEM; + err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev); + if (err) + goto fail0; + /* pci init */ dev->pci = pci_dev; if (pci_enable_device(pci_dev)) { @@ -988,6 +992,8 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, dev->autodetected = card[dev->nr] != dev->board; dev->tuner_type = saa7134_boards[dev->board].tuner_type; dev->tuner_addr = saa7134_boards[dev->board].tuner_addr; + dev->radio_type = saa7134_boards[dev->board].radio_type; + dev->radio_addr = saa7134_boards[dev->board].radio_addr; dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf; if (UNSET != tuner[dev->nr]) dev->tuner_type = tuner[dev->nr]; @@ -1034,15 +1040,40 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, saa7134_i2c_register(dev); /* initialize hardware #2 */ - if (TUNER_ABSENT != dev->tuner_type) - request_module("tuner"); + if (TUNER_ABSENT != dev->tuner_type) { + int has_demod = (dev->tda9887_conf & TDA9887_PRESENT); + + /* Note: radio tuner address is always filled in, + so we do not need to probe for a radio tuner device. */ + if (dev->radio_type != UNSET) + v4l2_i2c_new_subdev(&dev->i2c_adap, + "tuner", "tuner", dev->radio_addr); + if (has_demod) + v4l2_i2c_new_probed_subdev(&dev->i2c_adap, "tuner", + "tuner", v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); + if (dev->tuner_addr == ADDR_UNSET) { + enum v4l2_i2c_tuner_type type = + has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV; + + v4l2_i2c_new_probed_subdev(&dev->i2c_adap, "tuner", + "tuner", v4l2_i2c_tuner_addrs(type)); + } else { + v4l2_i2c_new_subdev(&dev->i2c_adap, + "tuner", "tuner", dev->tuner_addr); + } + } saa7134_board_init2(dev); saa7134_hwinit2(dev); /* load i2c helpers */ if (card_is_empress(dev)) { - request_module("saa6752hs"); + struct v4l2_subdev *sd = + v4l2_i2c_new_subdev(&dev->i2c_adap, "saa6752hs", + "saa6752hs", 0x20); + + if (sd) + sd->grp_id = GRP_EMPRESS; } request_submodules(dev); @@ -1084,7 +1115,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, } /* everything worked */ - pci_set_drvdata(pci_dev,dev); saa7134_devcount++; mutex_lock(&devlist_lock); @@ -1101,7 +1131,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, } if (TUNER_ABSENT != dev->tuner_type) - saa7134_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL); + saa_call_all(dev, core, s_standby, 0); return 0; @@ -1116,13 +1146,16 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, release_mem_region(pci_resource_start(pci_dev,0), pci_resource_len(pci_dev,0)); fail1: + v4l2_device_unregister(&dev->v4l2_dev); + fail0: kfree(dev); return err; } static void __devexit saa7134_finidev(struct pci_dev *pci_dev) { - struct saa7134_dev *dev = pci_get_drvdata(pci_dev); + struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); + struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev); struct saa7134_mpeg_ops *mops; /* Release DMA sound modules if present */ @@ -1177,7 +1210,8 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev) #if 0 /* causes some trouble when reinserting the driver ... */ pci_disable_device(pci_dev); #endif - pci_set_drvdata(pci_dev, NULL); + + v4l2_device_unregister(&dev->v4l2_dev); /* free memory */ kfree(dev); @@ -1212,8 +1246,8 @@ static int saa7134_buffer_requeue(struct saa7134_dev *dev, static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state) { - - struct saa7134_dev *dev = pci_get_drvdata(pci_dev); + struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); + struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev); /* disable overlay - apps should enable it explicitly on resume*/ dev->ovenable = 0; @@ -1252,7 +1286,8 @@ static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state) static int saa7134_resume(struct pci_dev *pci_dev) { - struct saa7134_dev *dev = pci_get_drvdata(pci_dev); + struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); + struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev); unsigned long flags; pci_set_power_state(pci_dev, PCI_D0); @@ -1374,7 +1409,6 @@ module_exit(saa7134_fini); /* ----------------------------------------------------------- */ EXPORT_SYMBOL(saa7134_set_gpio); -EXPORT_SYMBOL(saa7134_i2c_call_clients); EXPORT_SYMBOL(saa7134_devlist); EXPORT_SYMBOL(saa7134_boards); diff --git a/linux/drivers/media/video/saa7134/saa7134-dvb.c b/linux/drivers/media/video/saa7134/saa7134-dvb.c index 0bbb97b1b..27a4d9c83 100644 --- a/linux/drivers/media/video/saa7134/saa7134-dvb.c +++ b/linux/drivers/media/video/saa7134/saa7134-dvb.c @@ -189,7 +189,7 @@ static int mt352_pinnacle_tuner_set_params(struct dvb_frontend* fe, if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); i2c_transfer(&dev->i2c_adap, &msg, 1); - saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,&f); + saa_call_all(dev, tuner, s_frequency, &f); msg.buf = on; if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); @@ -1452,7 +1452,7 @@ static int dvb_fini(struct saa7134_dev *dev) tda9887_cfg.priv = &on; /* otherwise we don't detect the tuner on next insmod */ - saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &tda9887_cfg); + saa_call_all(dev, tuner, s_config, &tda9887_cfg); } else if (dev->board == SAA7134_BOARD_MEDION_MD8800_QUADRO) { if ((dev->eedata[2] == 0x07) && use_frontend) { /* turn off the 2nd lnb supply */ diff --git a/linux/drivers/media/video/saa7134/saa7134-empress.c b/linux/drivers/media/video/saa7134/saa7134-empress.c index 6955db2fe..3b0b42545 100644 --- a/linux/drivers/media/video/saa7134/saa7134-empress.c +++ b/linux/drivers/media/video/saa7134/saa7134-empress.c @@ -76,7 +76,7 @@ static int ts_init_encoder(struct saa7134_dev* dev) break; } ts_reset_encoder(dev); - saa7134_i2c_call_clients(dev, VIDIOC_INT_INIT, &leading_null_bytes); + saa_call_all(dev, core, init, leading_null_bytes); dev->empress_started = 1; return 0; } @@ -234,7 +234,7 @@ static int empress_g_fmt_vid_cap(struct file *file, void *priv, { struct saa7134_dev *dev = file->private_data; - saa7134_i2c_call_clients(dev, VIDIOC_G_FMT, f); + saa_call_all(dev, video, g_fmt, f); f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; @@ -247,7 +247,7 @@ static int empress_s_fmt_vid_cap(struct file *file, void *priv, { struct saa7134_dev *dev = file->private_data; - saa7134_i2c_call_clients(dev, VIDIOC_S_FMT, f); + saa_call_all(dev, video, s_fmt, f); f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; @@ -317,7 +317,7 @@ static int empress_s_ext_ctrls(struct file *file, void *priv, if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) return -EINVAL; - err = saa7134_i2c_call_saa6752(dev, VIDIOC_S_EXT_CTRLS, ctrls); + err = saa_call_empress(dev, core, s_ext_ctrls, ctrls); ts_init_encoder(dev); return err; @@ -330,7 +330,7 @@ static int empress_g_ext_ctrls(struct file *file, void *priv, if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) return -EINVAL; - return saa7134_i2c_call_saa6752(dev, VIDIOC_G_EXT_CTRLS, ctrls); + return saa_call_empress(dev, core, g_ext_ctrls, ctrls); } static int empress_g_ctrl(struct file *file, void *priv, @@ -391,7 +391,7 @@ static int empress_queryctrl(struct file *file, void *priv, return v4l2_ctrl_query_fill_std(c); if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG) return saa7134_queryctrl(file, priv, c); - return saa7134_i2c_call_saa6752(dev, VIDIOC_QUERYCTRL, c); + return saa_call_empress(dev, core, queryctrl, c); } static int empress_querymenu(struct file *file, void *priv, @@ -401,7 +401,7 @@ static int empress_querymenu(struct file *file, void *priv, if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG) return -EINVAL; - return saa7134_i2c_call_saa6752(dev, VIDIOC_QUERYMENU, c); + return saa_call_empress(dev, core, querymenu, c); } static int empress_g_chip_ident(struct file *file, void *fh, @@ -411,14 +411,12 @@ static int empress_g_chip_ident(struct file *file, void *fh, chip->ident = V4L2_IDENT_NONE; chip->revision = 0; - if (dev->mpeg_i2c_client == NULL) - return -EINVAL; if (chip->match.type == V4L2_CHIP_MATCH_I2C_DRIVER && !strcmp(chip->match.name, "saa6752hs")) - return saa7134_i2c_call_saa6752(dev, VIDIOC_DBG_G_CHIP_IDENT, chip); + return saa_call_empress(dev, core, g_chip_ident, chip); if (chip->match.type == V4L2_CHIP_MATCH_I2C_ADDR && - chip->match.addr == dev->mpeg_i2c_client->addr) - return saa7134_i2c_call_saa6752(dev, VIDIOC_DBG_G_CHIP_IDENT, chip); + chip->match.addr == 0x20) + return saa_call_empress(dev, core, g_chip_ident, chip); return -EINVAL; } diff --git a/linux/drivers/media/video/saa7134/saa7134-i2c.c b/linux/drivers/media/video/saa7134/saa7134-i2c.c index 3f7d4eb80..4b4d5ef76 100644 --- a/linux/drivers/media/video/saa7134/saa7134-i2c.c +++ b/linux/drivers/media/video/saa7134/saa7134-i2c.c @@ -332,8 +332,6 @@ static int attach_inform(struct i2c_client *client) d1printk( "%s i2c attach [addr=0x%x,client=%s]\n", client->driver->driver.name, client->addr, client->name); - if (client->addr == 0x20 && client->driver && client->driver->command) - dev->mpeg_i2c_client = client; /* Am I an i2c remote control? */ @@ -365,7 +363,9 @@ static struct i2c_algorithm saa7134_algo = { static struct i2c_adapter saa7134_adap_template = { .owner = THIS_MODULE, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) .class = I2C_CLASS_TV_ANALOG, +#endif .name = "saa7134", .id = I2C_HW_SAA7134, .algo = &saa7134_algo, @@ -429,29 +429,13 @@ static void do_i2c_scan(char *name, struct i2c_client *c) } } -void saa7134_i2c_call_clients(struct saa7134_dev *dev, - unsigned int cmd, void *arg) -{ - BUG_ON(NULL == dev->i2c_adap.algo_data); - i2c_clients_command(&dev->i2c_adap, cmd, arg); -} - -int saa7134_i2c_call_saa6752(struct saa7134_dev *dev, - unsigned int cmd, void *arg) -{ - if (dev->mpeg_i2c_client == NULL) - return -EINVAL; - return dev->mpeg_i2c_client->driver->command(dev->mpeg_i2c_client, - cmd, arg); -} -EXPORT_SYMBOL_GPL(saa7134_i2c_call_saa6752); - int saa7134_i2c_register(struct saa7134_dev *dev) { dev->i2c_adap = saa7134_adap_template; dev->i2c_adap.dev.parent = &dev->pci->dev; strcpy(dev->i2c_adap.name,dev->name); dev->i2c_adap.algo_data = dev; + i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev); i2c_add_adapter(&dev->i2c_adap); dev->i2c_client = saa7134_client_template; diff --git a/linux/drivers/media/video/saa7134/saa7134-video.c b/linux/drivers/media/video/saa7134/saa7134-video.c index 37dec30a4..2180527b3 100644 --- a/linux/drivers/media/video/saa7134/saa7134-video.c +++ b/linux/drivers/media/video/saa7134/saa7134-video.c @@ -627,10 +627,10 @@ void saa7134_set_tvnorm_hw(struct saa7134_dev *dev) saa7134_set_decoder(dev); if (card_in(dev, dev->ctl_input).tv) - saa7134_i2c_call_clients(dev, VIDIOC_S_STD, &dev->tvnorm->id); + saa_call_all(dev, tuner, s_std, dev->tvnorm->id); /* Set the correct norm for the saa6752hs. This function does nothing if there is no saa6752hs. */ - saa7134_i2c_call_saa6752(dev, VIDIOC_S_STD, &dev->tvnorm->id); + saa_call_empress(dev, tuner, s_std, dev->tvnorm->id); } static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale) @@ -1266,8 +1266,7 @@ int saa7134_s_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, str else dev->tda9887_conf &= ~TDA9887_AUTOMUTE; - saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, - &tda9887_cfg); + saa_call_all(dev, tuner, s_config, &tda9887_cfg); } break; } @@ -1387,7 +1386,7 @@ static int video_open(struct file *file) if (fh->radio) { /* switch to radio mode */ saa7134_tvaudio_setinput(dev,&card(dev).radio); - saa7134_i2c_call_clients(dev,AUDC_SET_RADIO, NULL); + saa_call_all(dev, tuner, s_radio); } else { /* switch to video/vbi mode */ video_mux(dev,dev->ctl_input); @@ -1498,7 +1497,7 @@ static int video_release(struct file *file) saa_andorb(SAA7134_OFMT_DATA_A, 0x1f, 0); saa_andorb(SAA7134_OFMT_DATA_B, 0x1f, 0); - saa7134_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL); + saa_call_all(dev, core, s_standby, 0); /* free stuff */ videobuf_mmap_free(&fh->cap); @@ -2048,7 +2047,7 @@ static int saa7134_s_frequency(struct file *file, void *priv, mutex_lock(&dev->lock); dev->ctl_freq = f->frequency; - saa7134_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f); + saa_call_all(dev, tuner, s_frequency, f); saa7134_tvaudio_do_scan(dev); mutex_unlock(&dev->lock); @@ -2306,7 +2305,7 @@ static int radio_g_tuner(struct file *file, void *priv, strcpy(t->name, "Radio"); t->type = V4L2_TUNER_RADIO; - saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t); + saa_call_all(dev, tuner, g_tuner, t); if (dev->input->amux == TV) { t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11); t->rxsubchans = (saa_readb(0x529) & 0x08) ? @@ -2323,7 +2322,7 @@ static int radio_s_tuner(struct file *file, void *priv, if (0 != t->index) return -EINVAL; - saa7134_i2c_call_clients(dev, VIDIOC_S_TUNER, t); + saa_call_all(dev, tuner, s_tuner, t); return 0; } diff --git a/linux/drivers/media/video/saa7134/saa7134.h b/linux/drivers/media/video/saa7134/saa7134.h index bb973d363..9e3b37c73 100644 --- a/linux/drivers/media/video/saa7134/saa7134.h +++ b/linux/drivers/media/video/saa7134/saa7134.h @@ -36,6 +36,7 @@ #include "compat.h" #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-device.h> #include <media/tuner.h> #include <media/ir-common.h> #include <media/ir-kbd-i2c.h> @@ -487,6 +488,7 @@ struct saa7134_dev { struct mutex lock; spinlock_t slock; struct v4l2_prio_state prio; + struct v4l2_device v4l2_dev; /* workstruct for loading modules */ struct work_struct request_module_wk; @@ -577,7 +579,6 @@ struct saa7134_dev { enum saa7134_ts_status ts_state; unsigned int buff_cnt; struct saa7134_mpeg_ops *mops; - struct i2c_client *mpeg_i2c_client; /* SAA7134_MPEG_EMPRESS only */ struct video_device *empress_dev; @@ -621,6 +622,12 @@ struct saa7134_dev { V4L2_STD_NTSC | V4L2_STD_PAL_M | \ V4L2_STD_PAL_60) +#define GRP_EMPRESS (1) +#define saa_call_all(dev, o, f, args...) \ + v4l2_device_call_all(&(dev)->v4l2_dev, 0, o, f , ##args) +#define saa_call_empress(dev, o, f, args...) \ + v4l2_device_call_until_err(&(dev)->v4l2_dev, GRP_EMPRESS, o, f , ##args) + /* ----------------------------------------------------------- */ /* saa7134-core.c */ @@ -673,10 +680,6 @@ int saa7134_tuner_callback(void *priv, int component, int command, int arg); int saa7134_i2c_register(struct saa7134_dev *dev); int saa7134_i2c_unregister(struct saa7134_dev *dev); -void saa7134_i2c_call_clients(struct saa7134_dev *dev, - unsigned int cmd, void *arg); -int saa7134_i2c_call_saa6752(struct saa7134_dev *dev, - unsigned int cmd, void *arg); /* ----------------------------------------------------------- */ diff --git a/linux/drivers/media/video/tda9875.c b/linux/drivers/media/video/tda9875.c index 2e72c36a9..8e9c905e4 100644 --- a/linux/drivers/media/video/tda9875.c +++ b/linux/drivers/media/video/tda9875.c @@ -256,7 +256,7 @@ static int tda9875_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) static int tda9875_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { struct tda9875 *t = to_state(sd); - int chvol=0, volume, balance, left, right; + int chvol = 0, volume = 0, balance = 0, left, right; switch (ctrl->id) { case V4L2_CID_AUDIO_VOLUME: diff --git a/linux/drivers/media/video/usbvision/usbvision-i2c.c b/linux/drivers/media/video/usbvision/usbvision-i2c.c index 58f65e03a..1d37e6206 100644 --- a/linux/drivers/media/video/usbvision/usbvision-i2c.c +++ b/linux/drivers/media/video/usbvision/usbvision-i2c.c @@ -158,7 +158,7 @@ usbvision_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) struct i2c_msg *pmsg; struct usb_usbvision *usbvision; int i, ret; - unsigned char addr; + unsigned char addr = 0; usbvision = (struct usb_usbvision *)i2c_get_adapdata(i2c_adap); diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c index 27af4d97a..6cc7d4058 100644 --- a/linux/drivers/media/video/v4l2-common.c +++ b/linux/drivers/media/video/v4l2-common.c @@ -556,7 +556,7 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste qctrl->step = step; qctrl->default_value = def; qctrl->reserved[0] = qctrl->reserved[1] = 0; - snprintf(qctrl->name, sizeof(qctrl->name), name); + strlcpy(qctrl->name, name, sizeof(qctrl->name)); return 0; } EXPORT_SYMBOL(v4l2_ctrl_query_fill); @@ -721,7 +721,7 @@ int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qc for (i = 0; i < qmenu->index && menu_items[i]; i++) ; if (menu_items[i] == NULL || menu_items[i][0] == '\0') return -EINVAL; - snprintf(qmenu->name, sizeof(qmenu->name), menu_items[qmenu->index]); + strlcpy(qmenu->name, menu_items[qmenu->index], sizeof(qmenu->name)); return 0; } EXPORT_SYMBOL(v4l2_ctrl_query_menu); @@ -738,8 +738,8 @@ int v4l2_ctrl_query_menu_valid_items(struct v4l2_querymenu *qmenu, const u32 *id return -EINVAL; while (*ids != V4L2_CTRL_MENU_IDS_END) { if (*ids++ == qmenu->index) { - snprintf(qmenu->name, sizeof(qmenu->name), - menu_items[qmenu->index]); + strlcpy(qmenu->name, menu_items[qmenu->index], + sizeof(qmenu->name)); return 0; } } @@ -1049,4 +1049,40 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct i2c_adapter *adapter, } EXPORT_SYMBOL_GPL(v4l2_i2c_new_probed_subdev); +/* Return a list of I2C tuner addresses to probe. Use only if the tuner + addresses are unknown. */ +const unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type) +{ + static const unsigned short radio_addrs[] = { +#if defined(CONFIG_MEDIA_TUNER_TEA5761) || defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) + 0x10, +#endif + 0x60, + I2C_CLIENT_END + }; + static const unsigned short demod_addrs[] = { + 0x42, 0x43, 0x4a, 0x4b, + I2C_CLIENT_END + }; + static const unsigned short tv_addrs[] = { + 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */ + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + I2C_CLIENT_END + }; + + switch (type) { + case ADDRS_RADIO: + return radio_addrs; + case ADDRS_DEMOD: + return demod_addrs; + case ADDRS_TV: + return tv_addrs; + case ADDRS_TV_WITH_DEMOD: + return tv_addrs + 4; + } + return NULL; +} +EXPORT_SYMBOL_GPL(v4l2_i2c_tuner_addrs); + #endif diff --git a/linux/drivers/media/video/v4l2-subdev.c b/linux/drivers/media/video/v4l2-subdev.c index fbe9cc0d4..158bc55de 100644 --- a/linux/drivers/media/video/v4l2-subdev.c +++ b/linux/drivers/media/video/v4l2-subdev.c @@ -28,13 +28,19 @@ int v4l2_subdev_command(struct v4l2_subdev *sd, unsigned cmd, void *arg) { switch (cmd) { case VIDIOC_QUERYCTRL: - return v4l2_subdev_call(sd, core, querymenu, arg); + return v4l2_subdev_call(sd, core, queryctrl, arg); case VIDIOC_G_CTRL: return v4l2_subdev_call(sd, core, g_ctrl, arg); case VIDIOC_S_CTRL: return v4l2_subdev_call(sd, core, s_ctrl, arg); + case VIDIOC_G_EXT_CTRLS: + return v4l2_subdev_call(sd, core, g_ext_ctrls, arg); + case VIDIOC_S_EXT_CTRLS: + return v4l2_subdev_call(sd, core, s_ext_ctrls, arg); + case VIDIOC_TRY_EXT_CTRLS: + return v4l2_subdev_call(sd, core, try_ext_ctrls, arg); case VIDIOC_QUERYMENU: - return v4l2_subdev_call(sd, core, queryctrl, arg); + return v4l2_subdev_call(sd, core, querymenu, arg); case VIDIOC_LOG_STATUS: return v4l2_subdev_call(sd, core, log_status); case VIDIOC_DBG_G_CHIP_IDENT: diff --git a/linux/drivers/media/video/zr364xx.c b/linux/drivers/media/video/zr364xx.c index 6bd4d6a14..698b7b9ba 100644 --- a/linux/drivers/media/video/zr364xx.c +++ b/linux/drivers/media/video/zr364xx.c @@ -97,6 +97,7 @@ static struct usb_device_id device_table[] = { {USB_DEVICE(0x06d6, 0x003b), .driver_info = METHOD0 }, {USB_DEVICE(0x0a17, 0x004e), .driver_info = METHOD2 }, {USB_DEVICE(0x041e, 0x405d), .driver_info = METHOD2 }, + {USB_DEVICE(0x08ca, 0x2102), .driver_info = METHOD2 }, {} /* Terminating entry */ }; |