diff options
Diffstat (limited to 'linux')
54 files changed, 1372 insertions, 682 deletions
diff --git a/linux/Documentation/video4linux/CARDLIST.cx88 b/linux/Documentation/video4linux/CARDLIST.cx88 index 12e600d74..0d08f1edc 100644 --- a/linux/Documentation/video4linux/CARDLIST.cx88 +++ b/linux/Documentation/video4linux/CARDLIST.cx88 @@ -74,3 +74,6 @@ 73 -> TeVii S420 DVB-S [d420:9022] 74 -> Prolink Pixelview Global Extreme [1554:4976] 75 -> PROF 7300 DVB-S/S2 [B033:3033] + 76 -> SATTRADE ST4200 DVB-S/S2 [b200:4200] + 77 -> TBS 8910 DVB-S [8910:8888] + 78 -> Prof 6200 DVB-S [b022:3022] diff --git a/linux/Documentation/video4linux/CARDLIST.em28xx b/linux/Documentation/video4linux/CARDLIST.em28xx index 187cc48d0..ea537f5ae 100644 --- a/linux/Documentation/video4linux/CARDLIST.em28xx +++ b/linux/Documentation/video4linux/CARDLIST.em28xx @@ -57,3 +57,4 @@ 56 -> Pinnacle Hybrid Pro (2) (em2882) [2304:0226] 57 -> Kworld PlusTV HD Hybrid 330 (em2883) [eb1a:a316] 58 -> Compro VideoMate ForYou/Stereo (em2820/em2840) [185b:2041] + 59 -> Pinnacle PCTV HD Mini (em2874) [2304:023f] diff --git a/linux/Documentation/video4linux/bttv/CONTRIBUTORS b/linux/Documentation/video4linux/bttv/CONTRIBUTORS index 8aad6dd93..eb41b2650 100644 --- a/linux/Documentation/video4linux/bttv/CONTRIBUTORS +++ b/linux/Documentation/video4linux/bttv/CONTRIBUTORS @@ -3,7 +3,7 @@ Contributors to bttv: Michael Chu <mmchu@pobox.com> AverMedia fix and more flexible card recognition -Alan Cox <alan@redhat.com> +Alan Cox <alan@lxorguk.ukuu.org.uk> Video4Linux interface and 2.1.x kernel adaptation Chris Kleitsch diff --git a/linux/Documentation/video4linux/gspca.txt b/linux/Documentation/video4linux/gspca.txt index 004818fab..2a23fe31e 100644 --- a/linux/Documentation/video4linux/gspca.txt +++ b/linux/Documentation/video4linux/gspca.txt @@ -263,6 +263,7 @@ etoms 102c:6251 Qcam xxxxxx VGA zc3xx 10fd:0128 Typhoon Webshot II USB 300k 0x0128 spca561 10fd:7e50 FlyCam Usb 100 zc3xx 10fd:8050 Typhoon Webshot II USB 300k +pac207 145f:013a Trust WB-1300N spca501 1776:501c Arowana 300K CMOS Camera t613 17a1:0128 TASCORP JPEG Webcam, NGS Cyclops vc032x 17ef:4802 Lenovo Vc0323+MI1310_SOC diff --git a/linux/drivers/media/dvb/dm1105/dm1105.c b/linux/drivers/media/dvb/dm1105/dm1105.c index f578cbdb6..100a7f661 100644 --- a/linux/drivers/media/dvb/dm1105/dm1105.c +++ b/linux/drivers/media/dvb/dm1105/dm1105.c @@ -375,7 +375,7 @@ static void dm1105dvb_dma_unmap(struct dm1105dvb *dm1105dvb) pci_free_consistent(dm1105dvb->pdev, 6*DM1105_DMA_BYTES, dm1105dvb->ts_buf, dm1105dvb->dma_addr); } -static void __devinit dm1105dvb_enable_irqs(struct dm1105dvb *dm1105dvb) +static void dm1105dvb_enable_irqs(struct dm1105dvb *dm1105dvb) { outb(INTMAK_ALLMASK, dm_io_mem(DM1105_INTMAK)); outb(1, dm_io_mem(DM1105_CR)); diff --git a/linux/drivers/media/dvb/dvb-usb/dw2102.c b/linux/drivers/media/dvb/dvb-usb/dw2102.c index c9431713d..bc5e47a2b 100644 --- a/linux/drivers/media/dvb/dvb-usb/dw2102.c +++ b/linux/drivers/media/dvb/dvb-usb/dw2102.c @@ -26,6 +26,10 @@ #define USB_PID_DW2104 0x2104 #endif +#ifndef USB_PID_CINERGY_S +#define USB_PID_CINERGY_S 0x0064 +#endif + #define DW210X_READ_MSG 0 #define DW210X_WRITE_MSG 1 @@ -577,6 +581,7 @@ static struct usb_device_id dw2102_table[] = { {USB_DEVICE(USB_VID_CYPRESS, 0x2101)}, {USB_DEVICE(USB_VID_CYPRESS, 0x2104)}, {USB_DEVICE(0x9022, 0xd650)}, + {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)}, { } }; @@ -646,6 +651,7 @@ static int dw2102_load_firmware(struct usb_device *dev, dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, DW210X_WRITE_MSG); break; + case USB_PID_CINERGY_S: case USB_PID_DW2102: dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, DW210X_WRITE_MSG); @@ -725,7 +731,7 @@ static struct dvb_usb_device_properties dw2102_properties = { }, } }, - .num_device_descs = 2, + .num_device_descs = 3, .devices = { {"DVBWorld DVB-S 2102 USB2.0", {&dw2102_table[0], NULL}, @@ -735,6 +741,10 @@ static struct dvb_usb_device_properties dw2102_properties = { {&dw2102_table[1], NULL}, {NULL}, }, + {"TerraTec Cinergy S USB", + {&dw2102_table[4], NULL}, + {NULL}, + }, } }; diff --git a/linux/drivers/media/dvb/dvb-usb/usb-urb.c b/linux/drivers/media/dvb/dvb-usb/usb-urb.c index 5caec2034..eb3aaaf7a 100644 --- a/linux/drivers/media/dvb/dvb-usb/usb-urb.c +++ b/linux/drivers/media/dvb/dvb-usb/usb-urb.c @@ -139,7 +139,7 @@ stream->buf_list[stream->buf_num], (long long)stream->dma_addr[stream->buf_num]) static int usb_bulk_urb_init(struct usb_data_stream *stream) { - int i; + int i, j; if ((i = usb_allocate_stream_buffers(stream,stream->props.count, stream->props.u.bulk.buffersize)) < 0) @@ -147,9 +147,13 @@ static int usb_bulk_urb_init(struct usb_data_stream *stream) /* allocate the URBs */ for (i = 0; i < stream->props.count; i++) { - if ((stream->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC)) == NULL) + stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); + if (!stream->urb_list[i]) { + deb_mem("not enough memory for urb_alloc_urb!.\n"); + for (j = 0; j < i; j++) + usb_free_urb(stream->urb_list[i]); return -ENOMEM; - + } usb_fill_bulk_urb( stream->urb_list[i], stream->udev, usb_rcvbulkpipe(stream->udev,stream->props.endpoint), stream->buf_list[i], @@ -174,9 +178,14 @@ static int usb_isoc_urb_init(struct usb_data_stream *stream) for (i = 0; i < stream->props.count; i++) { struct urb *urb; int frame_offset = 0; - if ((stream->urb_list[i] = - usb_alloc_urb(stream->props.u.isoc.framesperurb,GFP_ATOMIC)) == NULL) + + stream->urb_list[i] = usb_alloc_urb(stream->props.u.isoc.framesperurb, GFP_ATOMIC); + if (!stream->urb_list[i]) { + deb_mem("not enough memory for urb_alloc_urb!\n"); + for (j = 0; j < i; j++) + usb_free_urb(stream->urb_list[i]); return -ENOMEM; + } urb = stream->urb_list[i]; diff --git a/linux/drivers/media/dvb/frontends/Makefile b/linux/drivers/media/dvb/frontends/Makefile index fd24de4ae..7a19c0c7b 100644 --- a/linux/drivers/media/dvb/frontends/Makefile +++ b/linux/drivers/media/dvb/frontends/Makefile @@ -6,7 +6,6 @@ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ EXTRA_CFLAGS += -Idrivers/media/common/tuners/ s921-objs := s921_module.o s921_core.o - stb0899-objs = stb0899_drv.o stb0899_algo.o obj-$(CONFIG_DVB_PLL) += dvb-pll.o diff --git a/linux/drivers/media/dvb/frontends/stb0899_algo.c b/linux/drivers/media/dvb/frontends/stb0899_algo.c index be4546751..156906f5d 100644 --- a/linux/drivers/media/dvb/frontends/stb0899_algo.c +++ b/linux/drivers/media/dvb/frontends/stb0899_algo.c @@ -91,7 +91,7 @@ static u32 stb0899_set_srate(struct stb0899_state *state, u32 master_clk, u32 sr * SFR = (srate << 21 + master_clk) / (2 * master_clk) * * stored as 20 bit number with an offset of 4 bit: - * sfr = SFR << 4; + * sfr = SFR << 4; */ tmp = stb0899_do_div((((u64)srate) << 21) + master_clk, 2 * master_clk); diff --git a/linux/drivers/media/dvb/frontends/stb0899_cfg.h b/linux/drivers/media/dvb/frontends/stb0899_cfg.h index 45934a110..1c860e469 100644 --- a/linux/drivers/media/dvb/frontends/stb0899_cfg.h +++ b/linux/drivers/media/dvb/frontends/stb0899_cfg.h @@ -210,12 +210,12 @@ static const struct stb0899_s1_reg stb0899_s1_init_3[] = { { STB0899_RCOMPC , 0xc9 }, { STB0899_AGC1CN , 0x01 }, { STB0899_AGC1REF , 0x10 }, - { STB0899_RTC , 0x23 }, + { STB0899_RTC , 0x23 }, { STB0899_TMGCFG , 0x4e }, { STB0899_AGC2REF , 0x34 }, { STB0899_TLSR , 0x84 }, { STB0899_CFD , 0xf7 }, - { STB0899_ACLC , 0x87 }, + { STB0899_ACLC , 0x87 }, { STB0899_BCLC , 0x94 }, { STB0899_EQON , 0x41 }, { STB0899_LDT , 0xf1 }, @@ -268,10 +268,10 @@ static const struct stb0899_s1_reg stb0899_s1_init_3[] = { { STB0899_ECNT3M , 0x0a }, { STB0899_ECNT3L , 0xad }, { STB0899_FECAUTO1 , 0x06 }, - { STB0899_FECM , 0x01 }, + { STB0899_FECM , 0x01 }, { STB0899_VTH12 , 0xb0 }, { STB0899_VTH23 , 0x7a }, - { STB0899_VTH34 , 0x58 }, + { STB0899_VTH34 , 0x58 }, { STB0899_VTH56 , 0x38 }, { STB0899_VTH67 , 0x34 }, { STB0899_VTH78 , 0x24 }, @@ -280,7 +280,7 @@ static const struct stb0899_s1_reg stb0899_s1_init_3[] = { { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ { STB0899_TSULC , 0x42 }, { STB0899_RSLLC , 0x41 }, - { STB0899_TSLPL , 0x12 }, + { STB0899_TSLPL , 0x12 }, { STB0899_TSCFGH , 0x0c }, { STB0899_TSCFGM , 0x00 }, { STB0899_TSCFGL , 0x00 }, diff --git a/linux/drivers/media/dvb/frontends/stb0899_priv.h b/linux/drivers/media/dvb/frontends/stb0899_priv.h index 3d3fa6584..e57ff227b 100644 --- a/linux/drivers/media/dvb/frontends/stb0899_priv.h +++ b/linux/drivers/media/dvb/frontends/stb0899_priv.h @@ -257,10 +257,10 @@ extern int stb0899_i2c_gate_ctrl(struct dvb_frontend *fe, int enable); #if 0 extern int _stb0899_write_s2reg(struct stb0899_state *state, - u32 stb0899_i2cdev, - u32 stb0899_base_addr, - u16 stb0899_reg_offset, - u32 stb0899_data); + u32 stb0899_i2cdev, + u32 stb0899_base_addr, + u16 stb0899_reg_offset, + u32 stb0899_data); #endif #define STB0899_READ_S2REG(DEVICE, REG) (_stb0899_read_s2reg(state, DEVICE, STB0899_BASE_##REG, STB0899_OFF0_##REG)) diff --git a/linux/drivers/media/dvb/frontends/tda8261.h b/linux/drivers/media/dvb/frontends/tda8261.h index 3a0545da3..006e45351 100644 --- a/linux/drivers/media/dvb/frontends/tda8261.h +++ b/linux/drivers/media/dvb/frontends/tda8261.h @@ -43,7 +43,7 @@ extern struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe, #else static inline struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe, - const struct tda8261_config *config, + const struct tda8261_config *config, struct i2c_adapter *i2c) { printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__); diff --git a/linux/drivers/media/dvb/ttpci/budget-ci.c b/linux/drivers/media/dvb/ttpci/budget-ci.c index cfaee802e..89797e1bd 100644 --- a/linux/drivers/media/dvb/ttpci/budget-ci.c +++ b/linux/drivers/media/dvb/ttpci/budget-ci.c @@ -1178,12 +1178,12 @@ static const struct stb0899_s1_reg tt3200_stb0899_s1_init_3[] = { { STB0899_RCOMPC , 0xc9 }, { STB0899_AGC1CN , 0x41 }, { STB0899_AGC1REF , 0x10 }, - { STB0899_RTC , 0x7a }, + { STB0899_RTC , 0x7a }, { STB0899_TMGCFG , 0x4e }, { STB0899_AGC2REF , 0x34 }, { STB0899_TLSR , 0x84 }, { STB0899_CFD , 0xc7 }, - { STB0899_ACLC , 0x87 }, + { STB0899_ACLC , 0x87 }, { STB0899_BCLC , 0x94 }, { STB0899_EQON , 0x41 }, { STB0899_LDT , 0xdd }, @@ -1236,10 +1236,10 @@ static const struct stb0899_s1_reg tt3200_stb0899_s1_init_3[] = { { STB0899_ECNT3M , 0x00 }, { STB0899_ECNT3L , 0x00 }, { STB0899_FECAUTO1 , 0x06 }, - { STB0899_FECM , 0x01 }, + { STB0899_FECM , 0x01 }, { STB0899_VTH12 , 0xf0 }, { STB0899_VTH23 , 0xa0 }, - { STB0899_VTH34 , 0x78 }, + { STB0899_VTH34 , 0x78 }, { STB0899_VTH56 , 0x4e }, { STB0899_VTH67 , 0x48 }, { STB0899_VTH78 , 0x38 }, @@ -1248,7 +1248,7 @@ static const struct stb0899_s1_reg tt3200_stb0899_s1_init_3[] = { { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ { STB0899_TSULC , 0x42 }, { STB0899_RSLLC , 0x40 }, - { STB0899_TSLPL , 0x12 }, + { STB0899_TSLPL , 0x12 }, { STB0899_TSCFGH , 0x0c }, { STB0899_TSCFGM , 0x00 }, { STB0899_TSCFGL , 0x0c }, diff --git a/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index 13085a8e2..8775b78af 100644 --- a/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -828,6 +828,12 @@ static int ttusb_alloc_iso_urbs(struct ttusb *ttusb) ISO_BUF_COUNT, &ttusb->iso_dma_handle); + if (!ttusb->iso_buffer) { + dprintk("%s: pci_alloc_consistent - not enough memory\n", + __func__); + return -ENOMEM; + } + memset(ttusb->iso_buffer, 0, ISO_FRAME_SIZE * FRAMES_PER_ISO_BUF * ISO_BUF_COUNT); @@ -1679,7 +1685,14 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i ttusb_setup_interfaces(ttusb); - ttusb_alloc_iso_urbs(ttusb); + result = ttusb_alloc_iso_urbs(ttusb); + if (result < 0) { + dprintk("%s: ttusb_alloc_iso_urbs - failed\n", __func__); + mutex_unlock(&ttusb->semi2c); + kfree(ttusb); + return result; + } + if (ttusb_init_controller(ttusb)) printk("ttusb_init_controller: error\n"); diff --git a/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c index 5c2885e17..7cfc2e4d0 100644 --- a/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -1166,6 +1166,12 @@ static int ttusb_dec_alloc_iso_urbs(struct ttusb_dec *dec) ISO_BUF_COUNT), &dec->iso_dma_handle); + if (!dec->iso_buffer) { + dprintk("%s: pci_alloc_consistent - not enough memory\n", + __func__); + return -ENOMEM; + } + memset(dec->iso_buffer, 0, ISO_FRAME_SIZE * (FRAMES_PER_ISO_BUF * ISO_BUF_COUNT)); @@ -1263,6 +1269,7 @@ static int ttusb_dec_init_usb(struct ttusb_dec *dec) dec->irq_buffer = usb_buffer_alloc(dec->udev,IRQ_PACKET_SIZE, GFP_ATOMIC, &dec->irq_dma_handle); if(!dec->irq_buffer) { + usb_free_urb(dec->irq_urb); return -ENOMEM; } usb_fill_int_urb(dec->irq_urb, dec->udev,dec->irq_pipe, diff --git a/linux/drivers/media/radio/dsbr100.c b/linux/drivers/media/radio/dsbr100.c index 752478fad..d1865b164 100644 --- a/linux/drivers/media/radio/dsbr100.c +++ b/linux/drivers/media/radio/dsbr100.c @@ -94,8 +94,8 @@ */ #include <linux/version.h> /* for KERNEL_VERSION MACRO */ -#define DRIVER_VERSION "v0.41" -#define RADIO_VERSION KERNEL_VERSION(0,4,1) +#define DRIVER_VERSION "v0.43" +#define RADIO_VERSION KERNEL_VERSION(0, 4, 3) static struct v4l2_queryctrl radio_qctrl[] = { { @@ -105,7 +105,27 @@ static struct v4l2_queryctrl radio_qctrl[] = { .maximum = 1, .default_value = 1, .type = V4L2_CTRL_TYPE_BOOLEAN, - } + }, +/* HINT: the disabled controls are only here to satify kradio and such apps */ + { .id = V4L2_CID_AUDIO_VOLUME, + .flags = V4L2_CTRL_FLAG_DISABLED, + }, + { + .id = V4L2_CID_AUDIO_BALANCE, + .flags = V4L2_CTRL_FLAG_DISABLED, + }, + { + .id = V4L2_CID_AUDIO_BASS, + .flags = V4L2_CTRL_FLAG_DISABLED, + }, + { + .id = V4L2_CID_AUDIO_TREBLE, + .flags = V4L2_CTRL_FLAG_DISABLED, + }, + { + .id = V4L2_CID_AUDIO_LOUDNESS, + .flags = V4L2_CTRL_FLAG_DISABLED, + }, }; #define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>" @@ -132,6 +152,9 @@ static int usb_dsbr100_probe(struct usb_interface *intf, static void usb_dsbr100_disconnect(struct usb_interface *intf); static int usb_dsbr100_open(struct inode *inode, struct file *file); static int usb_dsbr100_close(struct inode *inode, struct file *file); +static int usb_dsbr100_suspend(struct usb_interface *intf, + pm_message_t message); +static int usb_dsbr100_resume(struct usb_interface *intf); static int radio_nr = -1; module_param(radio_nr, int, 0); @@ -158,10 +181,16 @@ MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table); /* USB subsystem interface */ static struct usb_driver usb_dsbr100_driver = { - .name = "dsbr100", - .probe = usb_dsbr100_probe, - .disconnect = usb_dsbr100_disconnect, - .id_table = usb_dsbr100_device_table, + .name = "dsbr100", + .probe = usb_dsbr100_probe, + .disconnect = usb_dsbr100_disconnect, + .id_table = usb_dsbr100_device_table, + .suspend = usb_dsbr100_suspend, + .resume = usb_dsbr100_resume, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) + .reset_resume = usb_dsbr100_resume, +#endif + .supports_autosuspend = 0, }; /* Low-level device interface begins here */ @@ -449,6 +478,36 @@ static int usb_dsbr100_close(struct inode *inode, struct file *file) return 0; } +/* Suspend device - stop device. */ +static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct dsbr100_device *radio = usb_get_intfdata(intf); + int retval; + + retval = dsbr100_stop(radio); + if (retval == -1) + dev_warn(&intf->dev, "dsbr100_stop failed\n"); + + dev_info(&intf->dev, "going into suspend..\n"); + + return 0; +} + +/* Resume device - start device. */ +static int usb_dsbr100_resume(struct usb_interface *intf) +{ + struct dsbr100_device *radio = usb_get_intfdata(intf); + int retval; + + retval = dsbr100_start(radio); + if (retval == -1) + dev_warn(&intf->dev, "dsbr100_start failed\n"); + + dev_info(&intf->dev, "coming out of suspend..\n"); + + return 0; +} + /* File system interface */ static const struct file_operations usb_dsbr100_fops = { .owner = THIS_MODULE, diff --git a/linux/drivers/media/video/cx18/cx18-driver.c b/linux/drivers/media/video/cx18/cx18-driver.c index 542beb333..54f0fde42 100644 --- a/linux/drivers/media/video/cx18/cx18-driver.c +++ b/linux/drivers/media/video/cx18/cx18-driver.c @@ -187,7 +187,7 @@ MODULE_VERSION(CX18_VERSION); /* Generic utility functions */ int cx18_msleep_timeout(unsigned int msecs, int intr) { - int timeout = msecs_to_jiffies(msecs); + long int timeout = msecs_to_jiffies(msecs); int sig; do { @@ -446,15 +446,11 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) mutex_init(&cx->i2c_bus_lock[0]); mutex_init(&cx->i2c_bus_lock[1]); mutex_init(&cx->gpio_lock); + mutex_init(&cx->epu2apu_mb_lock); + mutex_init(&cx->epu2cpu_mb_lock); spin_lock_init(&cx->lock); - cx->work_queue = create_singlethread_workqueue(cx->name); - if (cx->work_queue == NULL) { - CX18_ERR("Could not create work queue\n"); - return -1; - } - #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) INIT_WORK(&cx->work, cx18_work_handler); #else @@ -476,8 +472,6 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) init_waitqueue_head(&cx->cap_w); init_waitqueue_head(&cx->mb_apu_waitq); init_waitqueue_head(&cx->mb_cpu_waitq); - init_waitqueue_head(&cx->mb_epu_waitq); - init_waitqueue_head(&cx->mb_hpu_waitq); init_waitqueue_head(&cx->dma_waitq); /* VBI */ @@ -841,7 +835,6 @@ free_map: free_mem: release_mem_region(cx->base_addr, CX18_MEM_SIZE); free_workqueue: - destroy_workqueue(cx->work_queue); err: if (retval == 0) retval = -ENODEV; @@ -942,8 +935,7 @@ static void cx18_remove(struct pci_dev *pci_dev) cx18_halt_firmware(cx); - flush_workqueue(cx->work_queue); - destroy_workqueue(cx->work_queue); + flush_scheduled_work(); cx18_streams_cleanup(cx, 1); diff --git a/linux/drivers/media/video/cx18/cx18-driver.h b/linux/drivers/media/video/cx18/cx18-driver.h index fe9e5bb97..ce7680675 100644 --- a/linux/drivers/media/video/cx18/cx18-driver.h +++ b/linux/drivers/media/video/cx18/cx18-driver.h @@ -207,7 +207,6 @@ struct cx18_options { #define CX18_F_I_WORK_HANDLER_DVB 18 /* work to be done for DVB */ #define CX18_F_I_INITED 21 /* set after first open */ #define CX18_F_I_FAILED 22 /* set if first open failed */ -#define CX18_F_I_WORK_INITED 23 /* worker thread initialized */ /* These are the VBI types as they appear in the embedded VBI private packets. */ #define CX18_SLICED_TYPE_TELETEXT_B (1) @@ -361,6 +360,12 @@ struct cx18_mmio_stats { atomic_t retried_read[CX18_MAX_MMIO_RD_RETRIES+1]; }; +#define CX18_MAX_MB_ACK_DELAY 100 + +struct cx18_mbox_stats { + atomic_t mb_ack_delay[CX18_MAX_MB_ACK_DELAY+1]; +}; + /* Struct to hold info about cx18 cards */ struct cx18 { int num; /* board number, -1 during init! */ @@ -379,7 +384,10 @@ struct cx18 { u32 v4l2_cap; /* V4L2 capabilities of card */ u32 hw_flags; /* Hardware description of the board */ unsigned mdl_offset; - struct cx18_scb __iomem *scb; /* pointer to SCB */ + struct cx18_scb __iomem *scb; /* pointer to SCB */ + struct mutex epu2apu_mb_lock; /* protect driver to chip mailbox in SCB*/ + struct mutex epu2cpu_mb_lock; /* protect driver to chip mailbox in SCB*/ + struct cx18_av_state av_state; @@ -429,13 +437,10 @@ struct cx18 { wait_queue_head_t mb_apu_waitq; wait_queue_head_t mb_cpu_waitq; - wait_queue_head_t mb_epu_waitq; - wait_queue_head_t mb_hpu_waitq; wait_queue_head_t cap_w; /* when the current DMA is finished this queue is woken up */ wait_queue_head_t dma_waitq; - struct workqueue_struct *work_queue; struct work_struct work; /* i2c */ @@ -453,6 +458,7 @@ struct cx18 { /* Statistics */ struct cx18_mmio_stats mmio_stats; + struct cx18_mbox_stats mbox_stats; /* v4l2 and User settings */ diff --git a/linux/drivers/media/video/cx18/cx18-dvb.c b/linux/drivers/media/video/cx18/cx18-dvb.c index 4542e2e5e..4845f732e 100644 --- a/linux/drivers/media/video/cx18/cx18-dvb.c +++ b/linux/drivers/media/video/cx18/cx18-dvb.c @@ -109,20 +109,23 @@ static int cx18_dvb_start_feed(struct dvb_demux_feed *feed) if (!demux->dmx.frontend) return -EINVAL; - if (stream) { - mutex_lock(&stream->dvb.feedlock); - if (stream->dvb.feeding++ == 0) { - CX18_DEBUG_INFO("Starting Transport DMA\n"); - ret = cx18_start_v4l2_encode_stream(stream); - if (ret < 0) { - CX18_DEBUG_INFO( - "Failed to start Transport DMA\n"); - stream->dvb.feeding--; - } - } else - ret = 0; - mutex_unlock(&stream->dvb.feedlock); - } + if (!stream) + return -EINVAL; + + mutex_lock(&stream->dvb.feedlock); + if (stream->dvb.feeding++ == 0) { + CX18_DEBUG_INFO("Starting Transport DMA\n"); + set_bit(CX18_F_S_STREAMING, &stream->s_flags); + ret = cx18_start_v4l2_encode_stream(stream); + if (ret < 0) { + CX18_DEBUG_INFO("Failed to start Transport DMA\n"); + stream->dvb.feeding--; + if (stream->dvb.feeding == 0) + clear_bit(CX18_F_S_STREAMING, &stream->s_flags); + } + } else + ret = 0; + mutex_unlock(&stream->dvb.feedlock); return ret; } @@ -313,9 +316,11 @@ void cx18_dvb_work_handler(struct cx18 *cx) dvb_dmx_swfilter(&s->dvb.demux, buf->buf, buf->bytesused); - cx18_enqueue(s, buf, &s->q_free); cx18_buf_sync_for_device(s, buf); - if (s->handle == CX18_INVALID_TASK_HANDLE) /* FIXME: improve */ + cx18_enqueue(s, buf, &s->q_free); + + if (s->handle == CX18_INVALID_TASK_HANDLE || + !test_bit(CX18_F_S_STREAMING, &s->s_flags)) continue; cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, diff --git a/linux/drivers/media/video/cx18/cx18-firmware.c b/linux/drivers/media/video/cx18/cx18-firmware.c index 7a7c89032..d9c5f55ab 100644 --- a/linux/drivers/media/video/cx18/cx18-firmware.c +++ b/linux/drivers/media/video/cx18/cx18-firmware.c @@ -134,7 +134,8 @@ static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx) return size; } -static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx) +static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, + u32 *entry_addr) { const struct firmware *fw = NULL; int i, j; @@ -152,6 +153,7 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx) return -ENOMEM; } + *entry_addr = 0; src = (const u32 *)fw->data; vers = fw->data + sizeof(seghdr); sz = fw->size; @@ -168,10 +170,12 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx) } CX18_DEBUG_INFO("load segment %x-%x\n", seghdr.addr, seghdr.addr + seghdr.size - 1); + if (*entry_addr == 0) + *entry_addr = seghdr.addr; if (offset + seghdr.size > sz) break; for (i = 0; i < seghdr.size; i += 4096) { - cx18_setup_page(cx, offset + i); + cx18_setup_page(cx, seghdr.addr + i); for (j = i; j < seghdr.size && j < i + 4096; j += 4) { /* no need for endianness conversion on the ppc */ cx18_raw_writel(cx, src[(offset + j) / 4], @@ -192,8 +196,6 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx) fn, apu_version, fw->size); size = fw->size; release_firmware(fw); - /* Clear bit0 for APU to start from 0 */ - cx18_write_reg(cx, cx18_read_reg(cx, 0xc72030) & ~1, 0xc72030); return size; } @@ -338,11 +340,19 @@ int cx18_firmware_init(struct cx18 *cx) /* Only if the processor is not running */ if (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 8) { + u32 fw_entry_addr = 0; int sz = load_apu_fw_direct("v4l-cx23418-apu.fw", - cx->enc_mem, cx); + cx->enc_mem, cx, &fw_entry_addr); + + if (sz <= 0) + return sz; + + /* Clear bit0 for APU to start from 0 */ + cx18_write_reg(cx, cx18_read_reg(cx, 0xc72030) & ~1, 0xc72030); + + cx18_write_enc(cx, 0xE51FF004, 0); /* ldr pc, [pc, #-4] */ + cx18_write_enc(cx, fw_entry_addr, 4); - cx18_write_enc(cx, 0xE51FF004, 0); - cx18_write_enc(cx, 0xa00000, 4); /* todo: not hardcoded */ /* Start APU */ cx18_write_reg_expect(cx, 0x00010000, CX18_PROC_SOFT_RESET, 0x00000000, 0x00010001); @@ -373,6 +383,17 @@ int cx18_firmware_init(struct cx18 *cx) if (sz <= 0) return -EIO; } + + /* + * The CPU firmware apparently sets up to receive an interrupt for it's + * outgoing IRQ_CPU_TO_EPU_ACK to us (*boggle*). We get an interrupt + * when it sends us an ack, but by the time we process it, that flag in + * the SW2 status register has been cleared by the CPU firmware. + * We'll prevent that not so useful behavior by clearing the CPU's + * interrupt enables for Ack IRQ's we want to process. + */ + cx18_sw2_irq_disable_cpu(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); + /* initialize GPIO */ cx18_write_reg_expect(cx, 0x14001400, 0xc78110, 0x00001400, 0x14001400); return 0; diff --git a/linux/drivers/media/video/cx18/cx18-io.c b/linux/drivers/media/video/cx18/cx18-io.c index 0ad8dea3e..3c6485fce 100644 --- a/linux/drivers/media/video/cx18/cx18-io.c +++ b/linux/drivers/media/video/cx18/cx18-io.c @@ -37,6 +37,10 @@ void cx18_log_statistics(struct cx18 *cx) for (i = 0; i <= CX18_MAX_MMIO_RD_RETRIES; i++) CX18_DEBUG_INFO("retried_read[%d] = %d\n", i, atomic_read(&cx->mmio_stats.retried_read[i])); + for (i = 0; i <= CX18_MAX_MB_ACK_DELAY; i++) + if (atomic_read(&cx->mbox_stats.mb_ack_delay[i])) + CX18_DEBUG_INFO("mb_ack_delay[%d] = %d\n", i, + atomic_read(&cx->mbox_stats.mb_ack_delay[i])); return; } @@ -258,6 +262,13 @@ void cx18_sw2_irq_disable(struct cx18 *cx, u32 val) cx18_write_reg(cx, r & ~val, SW2_INT_ENABLE_PCI); } +void cx18_sw2_irq_disable_cpu(struct cx18 *cx, u32 val) +{ + u32 r; + r = cx18_read_reg(cx, SW2_INT_ENABLE_CPU); + cx18_write_reg(cx, r & ~val, SW2_INT_ENABLE_CPU); +} + void cx18_setup_page(struct cx18 *cx, u32 addr) { u32 val; diff --git a/linux/drivers/media/video/cx18/cx18-io.h b/linux/drivers/media/video/cx18/cx18-io.h index cb695a596..4486b73fa 100644 --- a/linux/drivers/media/video/cx18/cx18-io.h +++ b/linux/drivers/media/video/cx18/cx18-io.h @@ -390,6 +390,7 @@ void cx18_sw1_irq_enable(struct cx18 *cx, u32 val); void cx18_sw1_irq_disable(struct cx18 *cx, u32 val); void cx18_sw2_irq_enable(struct cx18 *cx, u32 val); void cx18_sw2_irq_disable(struct cx18 *cx, u32 val); +void cx18_sw2_irq_disable_cpu(struct cx18 *cx, u32 val); void cx18_setup_page(struct cx18 *cx, u32 addr); #endif /* CX18_IO_H */ diff --git a/linux/drivers/media/video/cx18/cx18-irq.c b/linux/drivers/media/video/cx18/cx18-irq.c index aff5a3abd..3e23fc350 100644 --- a/linux/drivers/media/video/cx18/cx18-irq.c +++ b/linux/drivers/media/video/cx18/cx18-irq.c @@ -40,17 +40,11 @@ void cx18_work_handler(void *arg) { struct cx18 *cx = arg; #endif - if (test_and_clear_bit(CX18_F_I_WORK_INITED, &cx->i_flags)) { - struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; - /* This thread must use the FIFO scheduler as it - * is realtime sensitive. */ - sched_setscheduler(current, SCHED_FIFO, ¶m); - } if (test_and_clear_bit(CX18_F_I_WORK_HANDLER_DVB, &cx->i_flags)) cx18_dvb_work_handler(cx); } -static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb) +static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb, int rpu) { u32 handle = mb->args[0]; struct cx18_stream *s = NULL; @@ -71,7 +65,7 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb) " handle %d\n", handle); mb->error = CXERR_NOT_OPEN; mb->cmd = 0; - cx18_mb_ack(cx, mb); + cx18_mb_ack(cx, mb, rpu); return; } @@ -98,13 +92,13 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb) } mb->error = 0; mb->cmd = 0; - cx18_mb_ack(cx, mb); + cx18_mb_ack(cx, mb, rpu); wake_up(&cx->dma_waitq); if (s->id != -1) wake_up(&s->waitq); } -static void epu_debug(struct cx18 *cx, struct cx18_mailbox *mb) +static void epu_debug(struct cx18 *cx, struct cx18_mailbox *mb, int rpu) { char str[256] = { 0 }; char *p; @@ -114,7 +108,7 @@ static void epu_debug(struct cx18 *cx, struct cx18_mailbox *mb) cx18_memcpy_fromio(cx, str, cx->enc_mem + mb->args[1], 252); str[252] = 0; } - cx18_mb_ack(cx, mb); + cx18_mb_ack(cx, mb, rpu); CX18_DEBUG_INFO("%x %s\n", mb->args[0], str); p = strchr(str, '.'); if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > str) @@ -131,10 +125,10 @@ static void epu_cmd(struct cx18 *cx, u32 sw1) switch (mb.cmd) { case CX18_EPU_DMA_DONE: - epu_dma_done(cx, &mb); + epu_dma_done(cx, &mb, CPU); break; case CX18_EPU_DEBUG: - epu_debug(cx, &mb); + epu_debug(cx, &mb, CPU); break; default: CX18_WARN("Unknown CPU_TO_EPU mailbox command %#08x\n", @@ -147,11 +141,6 @@ static void epu_cmd(struct cx18 *cx, u32 sw1) cx18_memcpy_fromio(cx, &mb, &cx->scb->apu2epu_mb, sizeof(mb)); CX18_WARN("Unknown APU_TO_EPU mailbox command %#08x\n", mb.cmd); } - - if (sw1 & IRQ_HPU_TO_EPU) { - cx18_memcpy_fromio(cx, &mb, &cx->scb->hpu2epu_mb, sizeof(mb)); - CX18_WARN("Unknown HPU_TO_EPU mailbox command %#08x\n", mb.cmd); - } } static void xpu_ack(struct cx18 *cx, u32 sw2) @@ -160,8 +149,6 @@ static void xpu_ack(struct cx18 *cx, u32 sw2) wake_up(&cx->mb_cpu_waitq); if (sw2 & IRQ_APU_TO_EPU_ACK) wake_up(&cx->mb_apu_waitq); - if (sw2 & IRQ_HPU_TO_EPU_ACK) - wake_up(&cx->mb_hpu_waitq); } #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) @@ -190,7 +177,8 @@ irqreturn_t cx18_irq_handler(int irq, void *dev_id) cx18_write_reg_expect(cx, hw2, HW2_INT_CLR_STATUS, ~hw2, hw2); if (sw1 || sw2 || hw2) - CX18_DEBUG_HI_IRQ("SW1: %x SW2: %x HW2: %x\n", sw1, sw2, hw2); + CX18_DEBUG_HI_IRQ("received interrupts " + "SW1: %x SW2: %x HW2: %x\n", sw1, sw2, hw2); /* To do: interrupt-based I2C handling if (hw2 & (HW2_I2C1_INT|HW2_I2C2_INT)) { @@ -204,7 +192,7 @@ irqreturn_t cx18_irq_handler(int irq, void *dev_id) epu_cmd(cx, sw1); if (test_and_clear_bit(CX18_F_I_HAVE_WORK, &cx->i_flags)) - queue_work(cx->work_queue, &cx->work); + schedule_work(&cx->work); return (sw1 || sw2 || hw2) ? IRQ_HANDLED : IRQ_NONE; } diff --git a/linux/drivers/media/video/cx18/cx18-irq.h b/linux/drivers/media/video/cx18/cx18-irq.h index d1d9d1967..6472e42c6 100644 --- a/linux/drivers/media/video/cx18/cx18-irq.h +++ b/linux/drivers/media/video/cx18/cx18-irq.h @@ -28,6 +28,7 @@ #define SW1_INT_ENABLE_PCI 0xc7311c #define SW2_INT_SET 0xc73140 #define SW2_INT_STATUS 0xc73144 +#define SW2_INT_ENABLE_CPU 0xc73158 #define SW2_INT_ENABLE_PCI 0xc7315c #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) diff --git a/linux/drivers/media/video/cx18/cx18-mailbox.c b/linux/drivers/media/video/cx18/cx18-mailbox.c index acff7dfb6..35f7188d4 100644 --- a/linux/drivers/media/video/cx18/cx18-mailbox.c +++ b/linux/drivers/media/video/cx18/cx18-mailbox.c @@ -30,11 +30,6 @@ #define API_FAST (1 << 2) /* Short timeout */ #define API_SLOW (1 << 3) /* Additional 300ms timeout */ -#define APU 0 -#define CPU 1 -#define EPU 2 -#define HPU 3 - struct cx18_api_info { u32 cmd; u8 flags; /* Flags, see above */ @@ -97,70 +92,12 @@ static const struct cx18_api_info *find_api_info(u32 cmd) return NULL; } -static struct cx18_mailbox __iomem *cx18_mb_is_complete(struct cx18 *cx, int rpu, - u32 *state, u32 *irq, u32 *req) +long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb, int rpu) { - struct cx18_mailbox __iomem *mb = NULL; - int wait_count = 0; - u32 ack; - - switch (rpu) { - case APU: - mb = &cx->scb->epu2apu_mb; - *state = cx18_readl(cx, &cx->scb->apu_state); - *irq = cx18_readl(cx, &cx->scb->epu2apu_irq); - break; - - case CPU: - mb = &cx->scb->epu2cpu_mb; - *state = cx18_readl(cx, &cx->scb->cpu_state); - *irq = cx18_readl(cx, &cx->scb->epu2cpu_irq); - break; - - case HPU: - mb = &cx->scb->epu2hpu_mb; - *state = cx18_readl(cx, &cx->scb->hpu_state); - *irq = cx18_readl(cx, &cx->scb->epu2hpu_irq); - break; - } - - if (mb == NULL) - return mb; - - do { - *req = cx18_readl(cx, &mb->request); - ack = cx18_readl(cx, &mb->ack); - wait_count++; - } while (*req != ack && wait_count < 600); - - if (*req == ack) { - (*req)++; - if (*req == 0 || *req == 0xffffffff) - *req = 1; - return mb; - } - return NULL; -} - -long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb) -{ - const struct cx18_api_info *info = find_api_info(mb->cmd); struct cx18_mailbox __iomem *ack_mb; u32 ack_irq; - u8 rpu = CPU; - - if (info == NULL && mb->cmd) { - CX18_WARN("Cannot ack unknown command %x\n", mb->cmd); - return -EINVAL; - } - if (info) - rpu = info->rpu; switch (rpu) { - case HPU: - ack_irq = IRQ_EPU_TO_HPU_ACK; - ack_mb = &cx->scb->hpu2epu_mb; - break; case APU: ack_irq = IRQ_EPU_TO_APU_ACK; ack_mb = &cx->scb->apu2epu_mb; @@ -170,7 +107,8 @@ long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb) ack_mb = &cx->scb->cpu2epu_mb; break; default: - CX18_WARN("Unknown RPU for command %x\n", mb->cmd); + CX18_WARN("Unhandled RPU (%d) for command %x ack\n", + rpu, mb->cmd); return -EINVAL; } @@ -180,16 +118,22 @@ long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb) return 0; } +static void cx18_api_log_ack_delay(struct cx18 *cx, int msecs) +{ + if (msecs > CX18_MAX_MB_ACK_DELAY) + msecs = CX18_MAX_MB_ACK_DELAY; + atomic_inc(&cx->mbox_stats.mb_ack_delay[msecs]); +} static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) { const struct cx18_api_info *info = find_api_info(cmd); - u32 state = 0, irq = 0, req, oldreq, err; + u32 state, irq, req, ack, err; struct cx18_mailbox __iomem *mb; + u32 __iomem *xpu_state; wait_queue_head_t *waitq; - int timeout = 100; - int cnt = 0; - int sig = 0; + struct mutex *mb_lock; + long int timeout, ret; int i; if (info == NULL) { @@ -201,50 +145,116 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) CX18_DEBUG_HI_API("%s\n", info->name); else CX18_DEBUG_API("%s\n", info->name); - cx18_setup_page(cx, SCB_OFFSET); - mb = cx18_mb_is_complete(cx, info->rpu, &state, &irq, &req); - if (mb == NULL) { - CX18_ERR("mb %s busy\n", info->name); - return -EBUSY; + switch (info->rpu) { + case APU: + waitq = &cx->mb_apu_waitq; + mb_lock = &cx->epu2apu_mb_lock; + irq = IRQ_EPU_TO_APU; + mb = &cx->scb->epu2apu_mb; + xpu_state = &cx->scb->apu_state; + break; + case CPU: + waitq = &cx->mb_cpu_waitq; + mb_lock = &cx->epu2cpu_mb_lock; + irq = IRQ_EPU_TO_CPU; + mb = &cx->scb->epu2cpu_mb; + xpu_state = &cx->scb->cpu_state; + break; + default: + CX18_WARN("Unknown RPU (%d) for API call\n", info->rpu); + return -EINVAL; } - oldreq = req - 1; + mutex_lock(mb_lock); + cx18_setup_page(cx, SCB_OFFSET); + + /* + * Wait for an in-use mailbox to complete + * + * If the XPU is responding with Ack's, the mailbox shouldn't be in + * a busy state, since we serialize access to it on our end. + * + * If the wait for ack after sending a previous command was interrupted + * by a signal, we may get here and find a busy mailbox. After waiting, + * mark it "not busy" from our end, if the XPU hasn't ack'ed it still. + */ + state = cx18_readl(cx, xpu_state); + req = cx18_readl(cx, &mb->request); + timeout = msecs_to_jiffies(20); /* 1 field at 50 Hz vertical refresh */ + ret = wait_event_timeout(*waitq, + (ack = cx18_readl(cx, &mb->ack)) == req, + timeout); + if (req != ack) { + /* waited long enough, make the mbox "not busy" from our end */ + cx18_writel(cx, req, &mb->ack); + CX18_ERR("mbox was found stuck busy when setting up for %s; " + "clearing busy and trying to proceed\n", info->name); + } else if (ret != timeout) + CX18_DEBUG_API("waited %u usecs for busy mbox to be acked\n", + jiffies_to_usecs(timeout-ret)); + + /* Build the outgoing mailbox */ + req = ((req & 0xfffffffe) == 0xfffffffe) ? 1 : req + 1; + cx18_writel(cx, cmd, &mb->cmd); for (i = 0; i < args; i++) cx18_writel(cx, data[i], &mb->args[i]); cx18_writel(cx, 0, &mb->error); cx18_writel(cx, req, &mb->request); + cx18_writel(cx, req - 1, &mb->ack); /* ensure ack & req are distinct */ - switch (info->rpu) { - case APU: waitq = &cx->mb_apu_waitq; break; - case CPU: waitq = &cx->mb_cpu_waitq; break; - case EPU: waitq = &cx->mb_epu_waitq; break; - case HPU: waitq = &cx->mb_hpu_waitq; break; - default: return -EINVAL; - } - if (info->flags & API_FAST) - timeout /= 2; + /* + * Notify the XPU and wait for it to send an Ack back + * 21 ms = ~ 0.5 frames at a frame rate of 24 fps + * 42 ms = ~ 1 frame at a frame rate of 24 fps + */ + timeout = msecs_to_jiffies((info->flags & API_FAST) ? 21 : 42); + + CX18_DEBUG_HI_IRQ("sending interrupt SW1: %x to send %s\n", + irq, info->name); cx18_write_reg_expect(cx, irq, SW1_INT_SET, irq, irq); - while (!sig && cx18_readl(cx, &mb->ack) != cx18_readl(cx, &mb->request) - && cnt < 660) { - if (cnt > 200 && !in_atomic()) - sig = cx18_msleep_timeout(10, 1); - cnt++; - } - if (sig) - return -EINTR; - if (cnt == 660) { - cx18_writel(cx, oldreq, &mb->request); - CX18_ERR("mb %s failed\n", info->name); + ret = wait_event_timeout( + *waitq, + cx18_readl(cx, &mb->ack) == cx18_readl(cx, &mb->request), + timeout); + if (ret == 0) { + /* Timed out */ + mutex_unlock(mb_lock); + i = jiffies_to_msecs(timeout); + cx18_api_log_ack_delay(cx, i); + CX18_WARN("sending %s timed out waiting %d msecs for RPU " + "acknowledgement\n", info->name, i); return -EINVAL; + } else if (ret < 0) { + /* Interrupted */ + mutex_unlock(mb_lock); + CX18_WARN("sending %s was interrupted waiting for RPU" + "acknowledgement\n", info->name); + return -EINTR; } + + i = jiffies_to_msecs(timeout-ret); + cx18_api_log_ack_delay(cx, i); + if (ret != timeout) + CX18_DEBUG_HI_API("waited %u msecs for %s to be acked\n", + i, info->name); + + /* Collect data returned by the XPU */ for (i = 0; i < MAX_MB_ARGUMENTS; i++) data[i] = cx18_readl(cx, &mb->args[i]); err = cx18_readl(cx, &mb->error); - if (!in_atomic() && (info->flags & API_SLOW)) + mutex_unlock(mb_lock); + + /* + * Wait for XPU to perform extra actions for the caller in some cases. + * e.g. CX18_CPU_DE_RELEASE_MDL will cause the CPU to send all buffers + * back in a burst shortly thereafter + */ + if (info->flags & API_SLOW) cx18_msleep_timeout(300, 0); + if (err) CX18_DEBUG_API("mailbox error %08x for command %s\n", err, info->name); @@ -253,12 +263,7 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]) { - int res = cx18_api_call(cx, cmd, args, data); - - /* Allow a single retry, probably already too late though. - If there is no free mailbox then that is usually an indication - of a more serious problem. */ - return (res == -EBUSY) ? cx18_api_call(cx, cmd, args, data) : res; + return cx18_api_call(cx, cmd, args, data); } static int cx18_set_filter_param(struct cx18_stream *s) diff --git a/linux/drivers/media/video/cx18/cx18-mailbox.h b/linux/drivers/media/video/cx18/cx18-mailbox.h index d99564153..54758f32d 100644 --- a/linux/drivers/media/video/cx18/cx18-mailbox.h +++ b/linux/drivers/media/video/cx18/cx18-mailbox.h @@ -30,6 +30,11 @@ #define MB_RESERVED_HANDLE_0 0 #define MB_RESERVED_HANDLE_1 0xFFFFFFFF +#define APU 0 +#define CPU 1 +#define EPU 2 +#define HPU 3 + struct cx18; /* The cx18_mailbox struct is the mailbox structure which is used for passing @@ -68,6 +73,6 @@ int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], u32 cmd, int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...); int cx18_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]); -long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb); +long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb, int rpu); #endif diff --git a/linux/drivers/media/video/cx18/cx18-streams.c b/linux/drivers/media/video/cx18/cx18-streams.c index 8ead4025e..d29a0b61b 100644 --- a/linux/drivers/media/video/cx18/cx18-streams.c +++ b/linux/drivers/media/video/cx18/cx18-streams.c @@ -587,9 +587,6 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end) #endif } - /* Tell the CX23418 it can't use our buffers anymore */ - cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle); - if (s->type != CX18_ENC_STREAM_TYPE_TS) atomic_dec(&cx->ana_capturing); atomic_dec(&cx->tot_capturing); @@ -597,6 +594,9 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end) /* Clear capture and no-read bits */ clear_bit(CX18_F_S_STREAMING, &s->s_flags); + /* Tell the CX23418 it can't use our buffers anymore */ + cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle); + cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); s->handle = CX18_INVALID_TASK_HANDLE; diff --git a/linux/drivers/media/video/cx18/cx18-version.h b/linux/drivers/media/video/cx18/cx18-version.h index 9f6be2d45..366cc1472 100644 --- a/linux/drivers/media/video/cx18/cx18-version.h +++ b/linux/drivers/media/video/cx18/cx18-version.h @@ -25,7 +25,7 @@ #define CX18_DRIVER_NAME "cx18" #define CX18_DRIVER_VERSION_MAJOR 1 #define CX18_DRIVER_VERSION_MINOR 0 -#define CX18_DRIVER_VERSION_PATCHLEVEL 1 +#define CX18_DRIVER_VERSION_PATCHLEVEL 2 #define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL) #define CX18_DRIVER_VERSION KERNEL_VERSION(CX18_DRIVER_VERSION_MAJOR, \ diff --git a/linux/drivers/media/video/cx88/cx88-cards.c b/linux/drivers/media/video/cx88/cx88-cards.c index cd72ee5cb..f9b5a9c09 100644 --- a/linux/drivers/media/video/cx88/cx88-cards.c +++ b/linux/drivers/media/video/cx88/cx88-cards.c @@ -1270,7 +1270,6 @@ static const struct cx88_board cx88_boards[] = { }, }, [CX88_BOARD_WINFAST_DTV2000H] = { - /* video inputs and radio still in testing */ .name = "WinFast DTV2000 H", .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, .radio_type = UNSET, @@ -1284,7 +1283,35 @@ static const struct cx88_board cx88_boards[] = { .gpio1 = 0x00008203, .gpio2 = 0x00017304, .gpio3 = 0x02000000, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0001d701, + .gpio1 = 0x0000b207, + .gpio2 = 0x0001d701, + .gpio3 = 0x02000000, + }, { + .type = CX88_VMUX_COMPOSITE2, + .vmux = 2, + .gpio0 = 0x0001d503, + .gpio1 = 0x0000b207, + .gpio2 = 0x0001d503, + .gpio3 = 0x02000000, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 3, + .gpio0 = 0x0001d701, + .gpio1 = 0x0000b207, + .gpio2 = 0x0001d701, + .gpio3 = 0x02000000, }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x00015702, + .gpio1 = 0x0000f207, + .gpio2 = 0x00015702, + .gpio3 = 0x02000000, + }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_GENIATECH_DVBS] = { @@ -1880,6 +1907,18 @@ static const struct cx88_board cx88_boards[] = { } }, .mpeg = CX88_MPEG_DVB, }, + [CX88_BOARD_TBS_8910] = { + .name = "TBS 8910 DVB-S", + .tuner_type = UNSET, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + } }, + .mpeg = CX88_MPEG_DVB, + }, [CX88_BOARD_TBS_8920] = { .name = "TBS 8920 DVB-S/S2", .tuner_type = TUNER_ABSENT, @@ -1892,6 +1931,18 @@ static const struct cx88_board cx88_boards[] = { } }, .mpeg = CX88_MPEG_DVB, }, + [CX88_BOARD_PROF_6200] = { + .name = "Prof 6200 DVB-S", + .tuner_type = UNSET, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + } }, + .mpeg = CX88_MPEG_DVB, + }, [CX88_BOARD_PROF_7300] = { .name = "PROF 7300 DVB-S/S2", .tuner_type = UNSET, @@ -1904,6 +1955,18 @@ static const struct cx88_board cx88_boards[] = { } }, .mpeg = CX88_MPEG_DVB, }, + [CX88_BOARD_SATTRADE_ST4200] = { + .name = "SATTRADE ST4200 DVB-S/S2", + .tuner_type = UNSET, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + } }, + .mpeg = CX88_MPEG_DVB, + }, }; /* ------------------------------------------------------------------ */ @@ -2294,13 +2357,25 @@ static const struct cx88_subid cx88_subids[] = { .subdevice = 0x2011, .card = CX88_BOARD_OMICOM_SS4_PCI, }, { + .subvendor = 0x8910, + .subdevice = 0x8888, + .card = CX88_BOARD_TBS_8910, + }, { .subvendor = 0x8920, .subdevice = 0x8888, .card = CX88_BOARD_TBS_8920, }, { + .subvendor = 0xb022, + .subdevice = 0x3022, + .card = CX88_BOARD_PROF_6200, + }, { .subvendor = 0xB033, .subdevice = 0x3033, .card = CX88_BOARD_PROF_7300, + }, { + .subvendor = 0xb200, + .subdevice = 0x4200, + .card = CX88_BOARD_SATTRADE_ST4200, }, }; @@ -2911,8 +2986,11 @@ static void cx88_card_setup(struct cx88_core *core) case CX88_BOARD_TEVII_S420: case CX88_BOARD_TEVII_S460: case CX88_BOARD_OMICOM_SS4_PCI: + case CX88_BOARD_TBS_8910: case CX88_BOARD_TBS_8920: + case CX88_BOARD_PROF_6200: case CX88_BOARD_PROF_7300: + case CX88_BOARD_SATTRADE_ST4200: cx_write(MO_SRST_IO, 0); msleep(100); cx_write(MO_SRST_IO, 1); diff --git a/linux/drivers/media/video/cx88/cx88-dvb.c b/linux/drivers/media/video/cx88/cx88-dvb.c index 2eb7cb117..5a9fafd25 100644 --- a/linux/drivers/media/video/cx88/cx88-dvb.c +++ b/linux/drivers/media/video/cx88/cx88-dvb.c @@ -613,7 +613,7 @@ static int dvb_register(struct cx8802_dev *dev) /* Get the first frontend */ fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1); if (!fe0) - return -EINVAL; + goto frontend_detach; /* multi-frontend gate control is undefined or defaults to fe0 */ dev->frontends.gate = 0; @@ -660,38 +660,35 @@ static int dvb_register(struct cx8802_dev *dev) } break; case CX88_BOARD_HAUPPAUGE_HVR3000: + /* MFE frontend 1 */ + mfe_shared = 1; + dev->frontends.gate = 2; /* DVB-S init */ fe0->dvb.frontend = dvb_attach(cx24123_attach, - &hauppauge_novas_config, - &dev->core->i2c_adap); + &hauppauge_novas_config, + &dev->core->i2c_adap); if (fe0->dvb.frontend) { - if (!dvb_attach(isl6421_attach, fe0->dvb.frontend, - &dev->core->i2c_adap, 0x08, ISL6421_DCL, 0x00)) { - dprintk( 1, "%s(): HVR3000 - DVB-S LNB Init: failed\n", __func__); - } - } else { - dprintk( 1, "%s(): HVR3000 - DVB-S Init: failed\n", __func__); + if (!dvb_attach(isl6421_attach, + fe0->dvb.frontend, + &dev->core->i2c_adap, + 0x08, ISL6421_DCL, 0x00)) + goto frontend_detach; } - /* DVB-T init */ + /* MFE frontend 2 */ fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2); - if (fe1) { - dev->frontends.gate = 2; - mfe_shared = 1; - fe1->dvb.frontend = dvb_attach(cx22702_attach, - &hauppauge_hvr_config, - &dev->core->i2c_adap); - if (fe1->dvb.frontend) { - fe1->dvb.frontend->id = 1; - if(!dvb_attach(simple_tuner_attach, fe1->dvb.frontend, - &dev->core->i2c_adap, 0x61, - TUNER_PHILIPS_FMD1216ME_MK3)) { - dprintk( 1, "%s(): HVR3000 - DVB-T misc Init: failed\n", __func__); - } - } else { - dprintk( 1, "%s(): HVR3000 - DVB-T Init: failed\n", __func__); - } - } else { - dprintk( 1, "%s(): HVR3000 - DVB-T Init: can't find frontend 2.\n", __func__); + if (!fe1) + goto frontend_detach; + /* DVB-T init */ + fe1->dvb.frontend = dvb_attach(cx22702_attach, + &hauppauge_hvr_config, + &dev->core->i2c_adap); + if (fe1->dvb.frontend) { + fe1->dvb.frontend->id = 1; + if (!dvb_attach(simple_tuner_attach, + fe1->dvb.frontend, + &dev->core->i2c_adap, + 0x61, TUNER_PHILIPS_FMD1216ME_MK3)) + goto frontend_detach; } break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS: @@ -1005,50 +1002,51 @@ static int dvb_register(struct cx8802_dev *dev) } break; case CX88_BOARD_HAUPPAUGE_HVR4000: + /* MFE frontend 1 */ + mfe_shared = 1; + dev->frontends.gate = 2; /* DVB-S/S2 Init */ fe0->dvb.frontend = dvb_attach(cx24116_attach, - &hauppauge_hvr4000_config, - &dev->core->i2c_adap); + &hauppauge_hvr4000_config, + &dev->core->i2c_adap); if (fe0->dvb.frontend) { - if(!dvb_attach(isl6421_attach, fe0->dvb.frontend, - &dev->core->i2c_adap, 0x08, ISL6421_DCL, 0x00)) { - dprintk( 1, "%s(): HVR4000 - DVB-S LNB Init: failed\n", __func__); - } - } else { - dprintk( 1, "%s(): HVR4000 - DVB-S Init: failed\n", __func__); + if (!dvb_attach(isl6421_attach, + fe0->dvb.frontend, + &dev->core->i2c_adap, + 0x08, ISL6421_DCL, 0x00)) + goto frontend_detach; } - /* DVB-T Init */ + /* MFE frontend 2 */ fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2); - if (fe1) { - dev->frontends.gate = 2; - mfe_shared = 1; - fe1->dvb.frontend = dvb_attach(cx22702_attach, - &hauppauge_hvr_config, - &dev->core->i2c_adap); - if (fe1->dvb.frontend) { - fe1->dvb.frontend->id = 1; - if(!dvb_attach(simple_tuner_attach, fe1->dvb.frontend, - &dev->core->i2c_adap, 0x61, - TUNER_PHILIPS_FMD1216ME_MK3)) { - dprintk( 1, "%s(): HVR4000 - DVB-T misc Init: failed\n", __func__); - } - } else { - dprintk( 1, "%s(): HVR4000 - DVB-T Init: failed\n", __func__); - } - } else { - dprintk( 1, "%s(): HVR4000 - DVB-T Init: can't find frontend 2.\n", __func__); + if (!fe1) + goto frontend_detach; + /* DVB-T Init */ + fe1->dvb.frontend = dvb_attach(cx22702_attach, + &hauppauge_hvr_config, + &dev->core->i2c_adap); + if (fe1->dvb.frontend) { + fe1->dvb.frontend->id = 1; + if (!dvb_attach(simple_tuner_attach, + fe1->dvb.frontend, + &dev->core->i2c_adap, + 0x61, TUNER_PHILIPS_FMD1216ME_MK3)) + goto frontend_detach; } break; case CX88_BOARD_HAUPPAUGE_HVR4000LITE: fe0->dvb.frontend = dvb_attach(cx24116_attach, - &hauppauge_hvr4000_config, - &dev->core->i2c_adap); + &hauppauge_hvr4000_config, + &dev->core->i2c_adap); if (fe0->dvb.frontend) { - dvb_attach(isl6421_attach, fe0->dvb.frontend, - &dev->core->i2c_adap, - 0x08, ISL6421_DCL, 0x00); + if (!dvb_attach(isl6421_attach, + fe0->dvb.frontend, + &dev->core->i2c_adap, + 0x08, ISL6421_DCL, 0x00)) + goto frontend_detach; } break; + case CX88_BOARD_PROF_6200: + case CX88_BOARD_TBS_8910: case CX88_BOARD_TEVII_S420: fe0->dvb.frontend = dvb_attach(stv0299_attach, &tevii_tuner_sharp_config, @@ -1077,21 +1075,18 @@ static int dvb_register(struct cx8802_dev *dev) fe0->dvb.frontend = dvb_attach(cx24116_attach, &tevii_s460_config, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { - core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage; + if (fe0->dvb.frontend != NULL) fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage; - } break; case CX88_BOARD_OMICOM_SS4_PCI: case CX88_BOARD_TBS_8920: case CX88_BOARD_PROF_7300: + case CX88_BOARD_SATTRADE_ST4200: fe0->dvb.frontend = dvb_attach(cx24116_attach, &hauppauge_hvr4000_config, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { - core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage; + if (fe0->dvb.frontend != NULL) fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage; - } break; default: printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n", @@ -1103,7 +1098,7 @@ static int dvb_register(struct cx8802_dev *dev) printk(KERN_ERR "%s/2: frontend initialization failed\n", core->name); - return -EINVAL; + goto frontend_detach; } /* define general-purpose callback pointer */ fe0->dvb.frontend->callback = cx88_tuner_callback; diff --git a/linux/drivers/media/video/cx88/cx88.h b/linux/drivers/media/video/cx88/cx88.h index b03bfca54..6f8e575a3 100644 --- a/linux/drivers/media/video/cx88/cx88.h +++ b/linux/drivers/media/video/cx88/cx88.h @@ -229,6 +229,9 @@ extern struct sram_channel cx88_sram_channels[]; #define CX88_BOARD_TEVII_S420 73 #define CX88_BOARD_PROLINK_PV_GLOBAL_XTREME 74 #define CX88_BOARD_PROF_7300 75 +#define CX88_BOARD_SATTRADE_ST4200 76 +#define CX88_BOARD_TBS_8910 77 +#define CX88_BOARD_PROF_6200 78 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, diff --git a/linux/drivers/media/video/em28xx/em28xx-audio.c b/linux/drivers/media/video/em28xx/em28xx-audio.c index bec42349e..b86b0870d 100644 --- a/linux/drivers/media/video/em28xx/em28xx-audio.c +++ b/linux/drivers/media/video/em28xx/em28xx-audio.c @@ -496,11 +496,12 @@ static int em28xx_audio_init(struct em28xx *dev) struct snd_card *card; #endif static int devnr; - int ret, err; + int err; - if (dev->has_audio_class) { + if (dev->has_alsa_audio != 1) { /* This device does not support the extension (in this case - the device is expecting the snd-usb-audio module) */ + the device is expecting the snd-usb-audio module or + doesn't have analog audio support at all) */ return 0; } @@ -552,9 +553,10 @@ static int em28xx_audio_fini(struct em28xx *dev) if (dev == NULL) return 0; - if (dev->has_audio_class) { + if (dev->has_alsa_audio != 1) { /* This device does not support the extension (in this case - the device is expecting the snd-usb-audio module */ + the device is expecting the snd-usb-audio module or + doesn't have analog audio support at all) */ return 0; } diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index 4f078da31..8d92cb05b 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -1088,6 +1088,20 @@ struct em28xx_board em28xx_boards[] = { .amux = EM28XX_AMUX_LINE_IN, } }, }, + [EM2874_BOARD_PINNACLE_PCTV_80E] = { + .name = "Pinnacle PCTV HD Mini", + .vchannels = 0, + .tuner_type = TUNER_ABSENT, + .has_dvb = 1, + .decoder = EM28XX_NODECODER, +#ifdef DJH_DEBUG + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + } }, +#endif + }, }; const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); @@ -1185,6 +1199,8 @@ struct usb_device_id em28xx_id_table [] = { .driver_info = EM2882_BOARD_PINNACLE_HYBRID_PRO }, { USB_DEVICE(0x2304, 0x0227), .driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO }, + { USB_DEVICE(0x2304, 0x023f), + .driver_info = EM2874_BOARD_PINNACLE_PCTV_80E }, { USB_DEVICE(0x0413, 0x6023), .driver_info = EM2800_BOARD_LEADTEK_WINFAST_USBII }, { USB_DEVICE(0x093b, 0xa005), @@ -1260,6 +1276,17 @@ static struct em28xx_reg_seq em2882_terratec_hybrid_xs_digital[] = { { -1, -1, -1, -1}, }; +/* Pinnacle PCTV HD Mini (80e) GPIOs + 0-5: not used + 6: demod reset, active low + 7: LED on, active high */ +static struct em28xx_reg_seq em2874_pinnacle_80e_digital[] = { + {EM28XX_R06_I2C_CLK, 0x45, 0xff, 10}, /*400 KHz*/ + {EM2874_R80_GPIO, 0x80, 0xff, 100},/*Demod reset*/ + {EM2874_R80_GPIO, 0xc0, 0xff, 10}, + { -1, -1, -1, -1}, +}; + /* * EEPROM hash table for devices with generic USB IDs */ @@ -1317,17 +1344,25 @@ void em28xx_pre_card_setup(struct em28xx *dev) { int rc; - rc = em28xx_read_reg(dev, EM2880_R04_GPO); - if (rc >= 0) - dev->reg_gpo = rc; + /* Set the default GPO/GPIO for legacy devices */ + dev->reg_gpo_num = EM2880_R04_GPO; + dev->reg_gpio_num = EM28XX_R08_GPIO; dev->wait_after_write = 5; + + /* Based on the Chip ID, set the device configuration */ rc = em28xx_read_reg(dev, EM28XX_R0A_CHIPID); if (rc > 0) { + dev->chip_id = rc; switch (rc) { case CHIP_ID_EM2860: em28xx_info("chip ID is em2860\n"); break; + case CHIP_ID_EM2874: + em28xx_info("chip ID is em2874\n"); + dev->reg_gpio_num = EM2874_R80_GPIO; + dev->wait_after_write = 0; + break; case CHIP_ID_EM2883: em28xx_info("chip ID is em2882/em2883\n"); dev->wait_after_write = 0; @@ -1336,6 +1371,12 @@ void em28xx_pre_card_setup(struct em28xx *dev) em28xx_info("em28xx chip ID = %d\n", rc); } } + + /* Prepopulate cached GPO register content */ + rc = em28xx_read_reg(dev, dev->reg_gpo_num); + if (rc >= 0) + dev->reg_gpo = rc; + em28xx_set_model(dev); /* request some modules */ @@ -1509,6 +1550,13 @@ void em28xx_pre_card_setup(struct em28xx *dev) /* enables audio for that device */ em28xx_write_regs_req(dev, 0x00, 0x08, "\xfd", 1); break; + + case EM2874_BOARD_PINNACLE_PCTV_80E: + /* Set 400 KHz clock */ + em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x45", 1); + + dev->digital_gpio = em2874_pinnacle_80e_digital; + break; } em28xx_gpio_set(dev, dev->tun_analog_gpio); @@ -1800,4 +1848,6 @@ void em28xx_card_setup(struct em28xx *dev) #endif em28xx_config_tuner(dev); + + em28xx_ir_init(dev); } diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c index 1a30e361c..48c2caabe 100644 --- a/linux/drivers/media/video/em28xx/em28xx-core.c +++ b/linux/drivers/media/video/em28xx/em28xx-core.c @@ -175,9 +175,9 @@ int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len) Not sure what happens on reading GPO register. */ if (rc >= 0) { - if (reg == EM2880_R04_GPO) + if (reg == dev->reg_gpo_num) dev->reg_gpo = buf[0]; - else if (reg == EM28XX_R08_GPIO) + else if (reg == dev->reg_gpio_num) dev->reg_gpio = buf[0]; } @@ -196,9 +196,9 @@ static int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, u8 newval; /* Uses cache for gpo/gpio registers */ - if (reg == EM2880_R04_GPO) + if (reg == dev->reg_gpo_num) oldval = dev->reg_gpo; - else if (reg == EM28XX_R08_GPIO) + else if (reg == dev->reg_gpio_num) oldval = dev->reg_gpio; else oldval = em28xx_read_reg(dev, reg); @@ -359,6 +359,24 @@ int em28xx_colorlevels_set_default(struct em28xx *dev) int em28xx_capture_start(struct em28xx *dev, int start) { int rc; + + if (dev->chip_id == CHIP_ID_EM2874) { + /* The Transport Stream Enable Register moved in em2874 */ + if (!start) { + rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE, + 0x00, + EM2874_TS1_CAPTURE_ENABLE); + return rc; + } + + /* Enable Transport Stream */ + rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE, + EM2874_TS1_CAPTURE_ENABLE, + EM2874_TS1_CAPTURE_ENABLE); + return rc; + } + + /* FIXME: which is the best order? */ /* video registers are sampled by VREF */ rc = em28xx_write_reg_bits(dev, EM28XX_R0C_USBSUSP, diff --git a/linux/drivers/media/video/em28xx/em28xx-i2c.c b/linux/drivers/media/video/em28xx/em28xx-i2c.c index 3bab56b99..51ecdcd34 100644 --- a/linux/drivers/media/video/em28xx/em28xx-i2c.c +++ b/linux/drivers/media/video/em28xx/em28xx-i2c.c @@ -332,6 +332,17 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) struct em28xx_eeprom *em_eeprom = (void *)eedata; int i, err, size = len, block; + if (dev->chip_id == CHIP_ID_EM2874) { + /* Empia switched to a 16-bit addressable eeprom in newer + devices. While we could certainly write a routine to read + the eeprom, there is nothing of use in there that cannot be + accessed through registers, and there is the risk that we + could corrupt the eeprom (since a 16-bit read call is + interpreted as a write call by 8-bit eeproms). + */ + return 0; + } + dev->i2c_client.addr = 0xa0 >> 1; /* Check if board has eeprom */ diff --git a/linux/drivers/media/video/em28xx/em28xx-input.c b/linux/drivers/media/video/em28xx/em28xx-input.c index 8d21eaad9..c3c9cba30 100644 --- a/linux/drivers/media/video/em28xx/em28xx-input.c +++ b/linux/drivers/media/video/em28xx/em28xx-input.c @@ -39,12 +39,42 @@ static unsigned int ir_debug; module_param(ir_debug, int, 0644); MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); -#define dprintk(fmt, arg...) \ +#define i2cdprintk(fmt, arg...) \ if (ir_debug) { \ printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg); \ } -/* ----------------------------------------------------------------------- */ +#define dprintk(fmt, arg...) \ + if (ir_debug) { \ + printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \ + } + +/********************************************************** + Polling structure used by em28xx IR's + **********************************************************/ + +struct em28xx_IR { + struct em28xx *dev; + struct input_dev *input; + struct ir_input_state ir; + char name[32]; + char phys[32]; + + /* poll external decoder */ + int polling; + struct work_struct work; + struct timer_list timer; + u32 last_gpio; + u32 mask_keycode; + u32 mask_keydown; + u32 mask_keyup; + + int (*get_key)(struct em28xx_IR *); +}; + +/********************************************************** + I2C IR based get keycodes - should be used with ir-kbd-i2c + **********************************************************/ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { @@ -52,7 +82,7 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) /* poll IR chip */ if (1 != i2c_master_recv(&ir->c, &b, 1)) { - dprintk("read error\n"); + i2cdprintk("read error\n"); return -EIO; } @@ -60,7 +90,7 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) down, while 0xff indicates that no button is hold down. 0xfe sequences are sometimes interrupted by 0xFF */ - dprintk("key %02x\n", b); + i2cdprintk("key %02x\n", b); if (b == 0xff) return 0; @@ -74,7 +104,6 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) return 1; } - int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { unsigned char buf[2]; @@ -103,7 +132,7 @@ int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) ((buf[0]&0x10)>>3) | /* 0000 0010 */ ((buf[0]&0x20)>>5); /* 0000 0001 */ - dprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x)\n", + i2cdprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x)\n", code, buf[0]); /* return key */ @@ -120,11 +149,11 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, /* poll IR chip */ if (3 != i2c_master_recv(&ir->c, buf, 3)) { - dprintk("read error\n"); + i2cdprintk("read error\n"); return -EIO; } - dprintk("key %02x\n", buf[2]&0x3f); + i2cdprintk("key %02x\n", buf[2]&0x3f); if (buf[0] != 0x00) return 0; @@ -134,6 +163,215 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, return 1; } +/********************************************************** + Poll based get keycode functions + **********************************************************/ + +static int default_polling_getkey(struct em28xx_IR *ir) +{ + struct em28xx *dev = ir->dev; + int rc; + u32 msg; + + /* Read key toggle, brand, and key code */ + rc = dev->em28xx_read_reg_req_len(dev, 0, EM28XX_R45_IR, + (u8 *)&msg, sizeof(msg)); + if (rc < 0) + return rc; + + return (int)(msg & 0x7fffffffl); +} + +/********************************************************** + Polling code for em28xx + **********************************************************/ + +static void em28xx_ir_handle_key(struct em28xx_IR *ir) +{ + int gpio; + u32 data; + + /* read gpio value */ + gpio = ir->get_key(ir); + if (gpio < 0) + return; + + if (gpio == ir->last_gpio) + return; + ir->last_gpio = gpio; + + /* extract data */ + data = ir_extract_bits(gpio, ir->mask_keycode); + dprintk("irq gpio=0x%x code=%d | poll%s%s\n", + gpio, data, + (gpio & ir->mask_keydown) ? " down" : "", + (gpio & ir->mask_keyup) ? " up" : ""); + + /* Generate keyup/keydown events */ + if (ir->mask_keydown) { + /* bit set on keydown */ + if (gpio & ir->mask_keydown) + ir_input_keydown(ir->input, &ir->ir, data, data); + else + ir_input_nokey(ir->input, &ir->ir); + } else if (ir->mask_keyup) { + /* bit cleared on keydown */ + if (!(gpio & ir->mask_keyup)) + ir_input_keydown(ir->input, &ir->ir, data, data); + else + ir_input_nokey(ir->input, &ir->ir); + } else { + /* can't distinguish keydown/up :-/ */ + ir_input_keydown(ir->input, &ir->ir, data, data); + ir_input_nokey(ir->input, &ir->ir); + } +} + +static void ir_timer(unsigned long data) +{ + struct em28xx_IR *ir = (struct em28xx_IR *)data; + + schedule_work(&ir->work); +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) +static void em28xx_ir_work(void *data) +#else +static void em28xx_ir_work(struct work_struct *work) +#endif +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) + struct em28xx_IR *ir = data; +#else + struct em28xx_IR *ir = container_of(work, struct em28xx_IR, work); +#endif + + em28xx_ir_handle_key(ir); + mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling)); +} + +void em28xx_ir_start(struct em28xx_IR *ir) +{ + setup_timer(&ir->timer, ir_timer, (unsigned long)ir); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) + INIT_WORK(&ir->work, em28xx_ir_work, ir); +#else + INIT_WORK(&ir->work, em28xx_ir_work); +#endif + schedule_work(&ir->work); +} + +static void em28xx_ir_stop(struct em28xx_IR *ir) +{ + del_timer_sync(&ir->timer); + flush_scheduled_work(); +} + +int em28xx_ir_init(struct em28xx *dev) +{ + struct em28xx_IR *ir; + struct input_dev *input_dev; + IR_KEYTAB_TYPE *ir_codes = NULL; + int ir_type = IR_TYPE_OTHER; + int err = -ENOMEM; + + ir = kzalloc(sizeof(*ir), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!ir || !input_dev) + goto err_out_free; + + ir->input = input_dev; + + /* */ + ir->get_key = default_polling_getkey; + ir->polling = 50; /* ms */ + + /* detect & configure */ + switch (dev->model) { +#if 0 + /* dummy entry, just as a reference, while we don't add + other entries here + */ + case EM2820_BOARD_UNKNOWN: + ir_type = IR_TYPE_OTHER; + ir_codes = ir_codes_empty; + ir->mask_keycode = 0x007f0000; + break; + } +#endif + } + + if (NULL == ir_codes) { + err = -ENODEV; + goto err_out_free; + } + + /* Get the current key status, to avoid adding an + unexistent key code */ + ir->last_gpio = ir->get_key(ir); + + /* init input device */ + snprintf(ir->name, sizeof(ir->name), "em28xx IR (%s)", + dev->name); + + usb_make_path(dev->udev, ir->phys, sizeof(ir->phys)); + strlcat(ir->phys, "/input0", sizeof(ir->phys)); + + ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); + input_dev->name = ir->name; + input_dev->phys = ir->phys; + input_dev->id.bustype = BUS_USB; + input_dev->id.version = 1; + input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); + input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) + input_dev->dev.parent = &dev->udev->dev; +#else + input_dev->cdev.dev = &dev->udev->dev; +#endif + /* record handles to ourself */ + ir->dev = dev; + dev->ir = ir; + + em28xx_ir_start(ir); + + /* all done */ + err = input_register_device(ir->input); + if (err) + goto err_out_stop; + + return 0; + err_out_stop: + em28xx_ir_stop(ir); + dev->ir = NULL; + err_out_free: + input_free_device(input_dev); + kfree(ir); + return err; +} + +int em28xx_ir_fini(struct em28xx *dev) +{ + struct em28xx_IR *ir = dev->ir; + + /* skip detach on non attached boards */ + if (!ir) + return 0; + + em28xx_ir_stop(ir); + input_unregister_device(ir->input); + kfree(ir); + + /* done */ + dev->ir = NULL; + return 0; +} + +/********************************************************** + Handle Webcam snapshot button + **********************************************************/ + #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) static void em28xx_query_sbutton(void *data) #else @@ -232,9 +470,3 @@ void em28xx_deregister_snapshot_button(struct em28xx *dev) } return; } - -/* ---------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/linux/drivers/media/video/em28xx/em28xx-reg.h b/linux/drivers/media/video/em28xx/em28xx-reg.h index fac1ab23f..f67955a1b 100644 --- a/linux/drivers/media/video/em28xx/em28xx-reg.h +++ b/linux/drivers/media/video/em28xx/em28xx-reg.h @@ -71,11 +71,30 @@ #define EM28XX_R42_AC97ADDR 0x42 #define EM28XX_R43_AC97BUSY 0x43 +#define EM28XX_R45_IR 0x45 + /* 0x45 bit 7 - parity bit + bits 6-0 - count + 0x46 IR brand + 0x47 IR data + */ + /* em202 registers */ #define EM28XX_R02_MASTER_AC97 0x02 #define EM28XX_R10_LINE_IN_AC97 0x10 #define EM28XX_R14_VIDEO_AC97 0x14 +/* em2874 registers */ +#define EM2874_R5F_TS_ENABLE 0x5f +#define EM2874_R80_GPIO 0x80 + +/* em2874 Transport Stream Enable Register (0x5f) */ +#define EM2874_TS1_CAPTURE_ENABLE (1 << 0) +#define EM2874_TS1_FILTER_ENABLE (1 << 1) +#define EM2874_TS1_NULL_DISCARD (1 << 2) +#define EM2874_TS2_CAPTURE_ENABLE (1 << 4) +#define EM2874_TS2_FILTER_ENABLE (1 << 5) +#define EM2874_TS2_NULL_DISCARD (1 << 6) + /* register settings */ #define EM2800_AUDIO_SRC_TUNER 0x0d #define EM2800_AUDIO_SRC_LINE 0x0c @@ -86,4 +105,5 @@ enum em28xx_chip_id { CHIP_ID_EM2860 = 34, CHIP_ID_EM2883 = 36, + CHIP_ID_EM2874 = 65, }; diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c index a4493da8a..09886d567 100644 --- a/linux/drivers/media/video/em28xx/em28xx-video.c +++ b/linux/drivers/media/video/em28xx/em28xx-video.c @@ -1656,11 +1656,13 @@ static void em28xx_release_resources(struct em28xx *dev) /*FIXME: I2C IR should be disconnected */ - em28xx_info("V4L2 devices /dev/video%d and /dev/vbi%d deregistered\n", - dev->vdev->num, dev->vbi_dev->num); list_del(&dev->devlist); if (dev->sbutton_input_dev) em28xx_deregister_snapshot_button(dev); + + if (dev->ir) + em28xx_ir_fini(dev); + if (dev->radio_dev) { if (-1 != dev->radio_dev->minor) video_unregister_device(dev->radio_dev); @@ -1669,6 +1671,8 @@ static void em28xx_release_resources(struct em28xx *dev) dev->radio_dev = NULL; } if (dev->vbi_dev) { + em28xx_info("V4L2 device /dev/vbi%d deregistered\n", + dev->vbi_dev->num); if (-1 != dev->vbi_dev->minor) video_unregister_device(dev->vbi_dev); else @@ -1676,6 +1680,8 @@ static void em28xx_release_resources(struct em28xx *dev) dev->vbi_dev = NULL; } if (dev->vdev) { + em28xx_info("V4L2 device /dev/video%d deregistered\n", + dev->vdev->num); if (-1 != dev->vdev->minor) video_unregister_device(dev->vdev); else @@ -1982,6 +1988,19 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev, return vfd; } +int em28xx_supports_audio_extension(struct em28xx *dev) +{ + /* The chip dictates whether we support the Empia analog audio + extension */ + switch (dev->chip_id) { + case CHIP_ID_EM2874: + /* Either a digital-only device or provides AC97 audio */ + return 0; + case CHIP_ID_EM2883: + default: + return 1; + } +} /* * em28xx_init_dev() @@ -2171,7 +2190,7 @@ static void request_module_async(struct work_struct *work) if (dev->has_audio_class) request_module("snd-usb-audio"); - else + else if (dev->has_alsa_audio) request_module("em28xx-alsa"); if (dev->has_dvb) @@ -2204,7 +2223,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, struct usb_interface *uif; struct em28xx *dev = NULL; int retval = -ENODEV; - int i, nr, ifnum; + int i, nr, ifnum, isoc_pipe; udev = usb_get_dev(interface_to_usbdev(interface)); ifnum = interface->altsetting[0].desc.bInterfaceNumber; @@ -2231,19 +2250,29 @@ static int em28xx_usb_probe(struct usb_interface *interface, ifnum, interface->altsetting[0].desc.bInterfaceClass); - endpoint = &interface->cur_altsetting->endpoint[1].desc; + endpoint = &interface->cur_altsetting->endpoint[0].desc; /* check if the device has the iso in endpoint at the correct place */ - if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != - USB_ENDPOINT_XFER_ISOC) { - em28xx_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n"); - em28xx_devused &= ~(1<<nr); - return -ENODEV; - } - if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) { - em28xx_err(DRIVER_NAME " probing error: endpoint is ISO OUT endpoint!\n"); - em28xx_devused &= ~(1<<nr); - return -ENODEV; + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_ISOC && + (interface->altsetting[1].endpoint[0].desc.wMaxPacketSize == 940)) + { + /* It's a newer em2874/em2875 device */ + isoc_pipe = 0; + } else { + isoc_pipe = 1; + endpoint = &interface->cur_altsetting->endpoint[1].desc; + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != + USB_ENDPOINT_XFER_ISOC) { + em28xx_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n"); + em28xx_devused &= ~(1<<nr); + return -ENODEV; + } + if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) { + em28xx_err(DRIVER_NAME " probing error: endpoint is ISO OUT endpoint!\n"); + em28xx_devused &= ~(1<<nr); + return -ENODEV; + } } if (nr >= EM28XX_MAXBOARDS) { @@ -2275,9 +2304,6 @@ static int em28xx_usb_probe(struct usb_interface *interface, } } - printk(KERN_INFO DRIVER_NAME " %s usb audio class\n", - dev->has_audio_class ? "Has" : "Doesn't have"); - /* compute alternate max packet sizes */ uif = udev->actconfig->interface[0]; @@ -2294,7 +2320,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, } for (i = 0; i < dev->num_alt ; i++) { - u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[1].desc. + u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc. wMaxPacketSize); dev->alt_max_pkt_size[i] = (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); @@ -2312,6 +2338,17 @@ static int em28xx_usb_probe(struct usb_interface *interface, em28xx_info("Found %s\n", em28xx_boards[dev->model].name); + if (dev->has_audio_class == 0) { + /* We don't have a USB audio class, let's see if we support + ALSA Audio */ + dev->has_alsa_audio = em28xx_supports_audio_extension(dev); + if (dev->has_alsa_audio) + printk(KERN_INFO DRIVER_NAME " supports alsa audio\n"); + } else { + printk(KERN_INFO DRIVER_NAME " has usb audio class\n"); + } + + /* save our data pointer in this interface device */ usb_set_intfdata(interface, dev); diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h index d73b8c983..1bccb9ee4 100644 --- a/linux/drivers/media/video/em28xx/em28xx.h +++ b/linux/drivers/media/video/em28xx/em28xx.h @@ -98,6 +98,7 @@ #define EM2882_BOARD_PINNACLE_HYBRID_PRO 56 #define EM2883_BOARD_KWORLD_HYBRID_A316 57 #define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU 58 +#define EM2874_BOARD_PINNACLE_PCTV_80E 59 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 @@ -269,6 +270,7 @@ struct em28xx_input { #define INPUT(nr) (&em28xx_boards[dev->model].input[nr]) enum em28xx_decoder { + EM28XX_NODECODER, EM28XX_TVP5150, EM28XX_SAA7113, EM28XX_SAA7114 @@ -375,17 +377,21 @@ struct em28xx { char name[30]; /* name (including minor) of the device */ int model; /* index in the device_data struct */ int devno; /* marks the number of this device */ + enum em28xx_chip_id chip_id; unsigned int is_em2800:1; unsigned int has_msp34xx:1; unsigned int has_tda9887:1; unsigned int stream_on:1; /* Locks streams */ unsigned int has_audio_class:1; + unsigned int has_alsa_audio:1; unsigned int has_12mhz_i2s:1; unsigned int max_range_640_480:1; unsigned int has_dvb:1; unsigned int has_snapshot_button:1; unsigned int valid:1; /* report for validated boards */ + struct em28xx_IR *ir; + /* Some older em28xx chips needs a waiting time after writing */ unsigned int wait_after_write; @@ -472,6 +478,9 @@ struct em28xx { enum em28xx_mode mode; + /* register numbers for GPO/GPIO registers */ + u16 reg_gpo_num, reg_gpio_num; + /* Caches GPO and GPIO registers */ unsigned char reg_gpo, reg_gpio; @@ -544,7 +553,6 @@ void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir); int em28xx_tuner_callback(void *ptr, int component, int command, int arg); /* Provided by em28xx-input.c */ -/* TODO: Check if the standard get_key handlers on ir-common can be used */ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, @@ -552,6 +560,9 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, void em28xx_register_snapshot_button(struct em28xx *dev); void em28xx_deregister_snapshot_button(struct em28xx *dev); +int em28xx_ir_init(struct em28xx *dev); +int em28xx_ir_fini(struct em28xx *dev); + /* printk macros */ #define em28xx_err(fmt, arg...) do {\ diff --git a/linux/drivers/media/video/gspca/Kconfig b/linux/drivers/media/video/gspca/Kconfig index 96a16db3d..6b557c057 100644 --- a/linux/drivers/media/video/gspca/Kconfig +++ b/linux/drivers/media/video/gspca/Kconfig @@ -201,7 +201,7 @@ config USB_GSPCA_VC032X module will be called gspca_vc032x. config USB_GSPCA_ZC3XX - tristate "VC3xx USB Camera Driver" + tristate "ZC3XX USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA help Say Y here if you want support for cameras based on the ZC3XX chip. diff --git a/linux/drivers/media/video/gspca/finepix.c b/linux/drivers/media/video/gspca/finepix.c index 65d3cbfe6..d3e3f085b 100644 --- a/linux/drivers/media/video/gspca/finepix.c +++ b/linux/drivers/media/video/gspca/finepix.c @@ -308,9 +308,6 @@ static int sd_start(struct gspca_dev *gspca_dev) int ret; int size_ret; - /* Reset bulk in endpoint */ - usb_clear_halt(gspca_dev->dev, gspca_dev->cam.epaddr); - /* Init the device */ memset(gspca_dev->usb_buf, 0, 12); gspca_dev->usb_buf[0] = 0xc6; diff --git a/linux/drivers/media/video/gspca/gspca.c b/linux/drivers/media/video/gspca/gspca.c index 4e0e7a32a..7a2006c3e 100644 --- a/linux/drivers/media/video/gspca/gspca.c +++ b/linux/drivers/media/video/gspca/gspca.c @@ -49,7 +49,7 @@ MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>"); MODULE_DESCRIPTION("GSPCA USB Camera Driver"); MODULE_LICENSE("GPL"); -#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 3, 0) +#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 4, 0) static int video_nr = -1; @@ -154,8 +154,11 @@ static void fill_frame(struct gspca_dev *gspca_dev, /* check the packet status and length */ len = urb->iso_frame_desc[i].actual_length; - if (len == 0) + if (len == 0) { + if (gspca_dev->empty_packet == 0) + gspca_dev->empty_packet = 1; continue; + } st = urb->iso_frame_desc[i].status; if (st) { PDEBUG(D_ERR, @@ -607,6 +610,12 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) if (ret < 0) goto out; + /* clear the bulk endpoint */ + if (gspca_dev->alt == 0) /* if bulk transfer */ + usb_clear_halt(gspca_dev->dev, + usb_rcvintpipe(gspca_dev->dev, + gspca_dev->cam.epaddr)); + /* start the cam */ ret = gspca_dev->sd_desc->start(gspca_dev); if (ret < 0) { @@ -1860,6 +1869,7 @@ int gspca_dev_probe(struct usb_interface *intf, gspca_dev->nbalt = intf->num_altsetting; gspca_dev->sd_desc = sd_desc; gspca_dev->nbufread = 2; + gspca_dev->empty_packet = -1; /* don't check the empty packets */ /* configure the subdriver and initialize the USB device */ ret = gspca_dev->sd_desc->config(gspca_dev, id); @@ -1998,7 +2008,7 @@ int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum, desired lumination fast (with the risc of a slight overshoot) */ steps = abs(desired_avg_lum - avg_lum) / deadzone; - PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d\n", + PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d", avg_lum, desired_avg_lum, steps); for (i = 0; i < steps; i++) { diff --git a/linux/drivers/media/video/gspca/gspca.h b/linux/drivers/media/video/gspca/gspca.h index 1d9dc90b4..6f097f4a1 100644 --- a/linux/drivers/media/video/gspca/gspca.h +++ b/linux/drivers/media/video/gspca/gspca.h @@ -142,22 +142,21 @@ struct gspca_dev { char fr_q; /* next frame to queue */ char fr_o; /* next frame to dequeue */ signed char fr_queue[GSPCA_MAX_FRAMES]; /* frame queue */ - char last_packet_type; + __u8 last_packet_type; + __s8 empty_packet; /* if (-1) don't check empty packets */ + __u8 streaming; - __u8 iface; /* USB interface number */ - __u8 alt; /* USB alternate setting */ __u8 curr_mode; /* current camera mode */ __u32 pixfmt; /* current mode parameters */ __u16 width; __u16 height; + __u32 sequence; /* frame sequence number */ atomic_t nevent; /* number of frames done */ wait_queue_head_t wq; /* wait queue */ struct mutex usb_lock; /* usb exchange protection */ struct mutex read_lock; /* read protection */ struct mutex queue_lock; /* ISOC queue protection */ - __u32 sequence; /* frame sequence number */ - char streaming; #ifdef CONFIG_PM char frozen; /* suspend - resume */ #endif @@ -166,6 +165,8 @@ struct gspca_dev { char nbufread; /* number of buffers for read() */ char nurbs; /* number of allocated URBs */ char memory; /* memory type (V4L2_MEMORY_xxx) */ + __u8 iface; /* USB interface number */ + __u8 alt; /* USB alternate setting */ __u8 nbalt; /* number of USB alternate settings */ }; diff --git a/linux/drivers/media/video/gspca/ov519.c b/linux/drivers/media/video/gspca/ov519.c index 895bcf082..b18d98191 100644 --- a/linux/drivers/media/video/gspca/ov519.c +++ b/linux/drivers/media/video/gspca/ov519.c @@ -40,22 +40,18 @@ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ /* Determined by sensor type */ - char sif; + __u8 sif; - unsigned char primary_i2c_slave; /* I2C write id of sensor */ - - unsigned char brightness; - unsigned char contrast; - unsigned char colors; + __u8 brightness; + __u8 contrast; + __u8 colors; __u8 hflip; __u8 vflip; - char compress; /* Should the next frame be compressed? */ - char compress_inited; /* Are compression params uploaded? */ - char stopped; /* Streaming is temporarily paused */ + __u8 stopped; /* Streaming is temporarily paused */ - char frame_rate; /* current Framerate (OV519 only) */ - char clockdiv; /* clockdiv override for OV519 only */ + __u8 frame_rate; /* current Framerate (OV519 only) */ + __u8 clockdiv; /* clockdiv override for OV519 only */ char sensor; /* Type of image sensor chip (SEN_*) */ #define SEN_UNKNOWN 0 @@ -67,7 +63,6 @@ struct sd { #define SEN_OV7670 6 #define SEN_OV76BE 7 #define SEN_OV8610 8 - }; /* V4L2 controls supported by the driver */ @@ -184,15 +179,15 @@ static struct v4l2_pix_format sif_mode[] = { }; /* OV519 Camera interface register numbers */ -#define OV519_CAM_H_SIZE 0x10 -#define OV519_CAM_V_SIZE 0x11 -#define OV519_CAM_X_OFFSETL 0x12 -#define OV519_CAM_X_OFFSETH 0x13 -#define OV519_CAM_Y_OFFSETL 0x14 -#define OV519_CAM_Y_OFFSETH 0x15 -#define OV519_CAM_DIVIDER 0x16 -#define OV519_CAM_DFR 0x20 -#define OV519_CAM_FORMAT 0x25 +#define OV519_R10_H_SIZE 0x10 +#define OV519_R11_V_SIZE 0x11 +#define OV519_R12_X_OFFSETL 0x12 +#define OV519_R13_X_OFFSETH 0x13 +#define OV519_R14_Y_OFFSETL 0x14 +#define OV519_R15_Y_OFFSETH 0x15 +#define OV519_R16_DIVIDER 0x16 +#define OV519_R20_DFR 0x20 +#define OV519_R25_FORMAT 0x25 /* OV519 System Controller register numbers */ #define OV519_SYS_RESET1 0x51 @@ -562,8 +557,8 @@ static const struct ov_i2c_regvals norm_7670[] = { { OV7670_REG_VSTOP, 0x7a }, { OV7670_REG_VREF, 0x0a }, - { OV7670_REG_COM3, 0 }, - { OV7670_REG_COM14, 0 }, + { OV7670_REG_COM3, 0x00 }, + { OV7670_REG_COM14, 0x00 }, /* Mystery scaling numbers */ { 0x70, 0x3a }, { 0x71, 0x35 }, @@ -595,8 +590,8 @@ static const struct ov_i2c_regvals norm_7670[] = { { OV7670_REG_COM8, OV7670_COM8_FASTAEC | OV7670_COM8_AECSTEP | OV7670_COM8_BFILT }, - { OV7670_REG_GAIN, 0 }, - { OV7670_REG_AECH, 0 }, + { OV7670_REG_GAIN, 0x00 }, + { OV7670_REG_AECH, 0x00 }, { OV7670_REG_COM4, 0x40 }, /* magic reserved bit */ { OV7670_REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */ { OV7670_REG_BD50MAX, 0x05 }, @@ -634,16 +629,16 @@ static const struct ov_i2c_regvals norm_7670[] = { { OV7670_REG_COM12, 0x78 }, { 0x4d, 0x40 }, { 0x4e, 0x20 }, - { OV7670_REG_GFIX, 0 }, + { OV7670_REG_GFIX, 0x00 }, { 0x6b, 0x4a }, { 0x74, 0x10 }, { 0x8d, 0x4f }, - { 0x8e, 0 }, - { 0x8f, 0 }, - { 0x90, 0 }, - { 0x91, 0 }, - { 0x96, 0 }, - { 0x9a, 0 }, + { 0x8e, 0x00 }, + { 0x8f, 0x00 }, + { 0x90, 0x00 }, + { 0x91, 0x00 }, + { 0x96, 0x00 }, + { 0x9a, 0x00 }, { 0xb0, 0x84 }, { 0xb1, 0x0c }, { 0xb2, 0x0e }, @@ -681,17 +676,17 @@ static const struct ov_i2c_regvals norm_7670[] = { /* Matrix coefficients */ { 0x4f, 0x80 }, { 0x50, 0x80 }, - { 0x51, 0 }, + { 0x51, 0x00 }, { 0x52, 0x22 }, { 0x53, 0x5e }, { 0x54, 0x80 }, { 0x58, 0x9e }, { OV7670_REG_COM16, OV7670_COM16_AWBGAIN }, - { OV7670_REG_EDGE, 0 }, + { OV7670_REG_EDGE, 0x00 }, { 0x75, 0x05 }, { 0x76, 0xe1 }, - { 0x4c, 0 }, + { 0x4c, 0x00 }, { 0x77, 0x01 }, { OV7670_REG_COM13, OV7670_COM13_GAMMA | OV7670_COM13_UVSAT @@ -704,7 +699,7 @@ static const struct ov_i2c_regvals norm_7670[] = { { 0x34, 0x11 }, { OV7670_REG_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO }, { 0xa4, 0x88 }, - { 0x96, 0 }, + { 0x96, 0x00 }, { 0x97, 0x30 }, { 0x98, 0x20 }, { 0x99, 0x30 }, @@ -942,11 +937,11 @@ static int i2c_w(struct sd *sd, /* Initiate 3-byte write cycle */ rc = reg_w(sd, R518_I2C_CTL, 0x01); + if (rc < 0) + return rc; /* wait for write complete */ msleep(4); - if (rc < 0) - return rc; return reg_r8(sd, R518_I2C_CTL); } @@ -1029,7 +1024,7 @@ static inline int ov51x_restart(struct sd *sd) */ static int init_ov_sensor(struct sd *sd) { - int i, success; + int i; /* Reset the sensor */ if (i2c_w(sd, 0x12, 0x80) < 0) @@ -1038,11 +1033,11 @@ static int init_ov_sensor(struct sd *sd) /* Wait for it to initialize */ msleep(150); - for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) { + for (i = 0; i < i2c_detect_tries; i++) { if (i2c_r(sd, OV7610_REG_ID_HIGH) == 0x7f && i2c_r(sd, OV7610_REG_ID_LOW) == 0xa2) { - success = 1; - continue; + PDEBUG(D_PROBE, "I2C synced in %d attempt(s)", i); + return 0; } /* Reset the sensor */ @@ -1054,10 +1049,7 @@ static int init_ov_sensor(struct sd *sd) if (i2c_r(sd, 0x00) < 0) return -EIO; } - if (!success) - return -EIO; - PDEBUG(D_PROBE, "I2C synced in %d attempt(s)", i); - return 0; + return -EIO; } /* Set the read and write slave IDs. The "slave" argument is the write slave, @@ -1073,7 +1065,6 @@ static int ov51x_set_slave_ids(struct sd *sd, rc = reg_w(sd, R51x_I2C_W_SID, slave); if (rc < 0) return rc; - sd->primary_i2c_slave = slave; return reg_w(sd, R51x_I2C_R_SID, slave + 1); } @@ -1285,7 +1276,6 @@ static int ov6xx0_configure(struct sd *sd) /* Turns on or off the LED. Only has an effect with OV511+/OV518(+)/OV519 */ static void ov51x_led_control(struct sd *sd, int on) { -/* PDEBUG(D_STREAM, "LED (%s)", on ? "on" : "off"); */ reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1); /* 0 / 1 */ } @@ -1352,7 +1342,7 @@ static int sd_config(struct gspca_dev *gspca_dev, } if (ov8xx0_configure(sd) < 0) { PDEBUG(D_ERR, - "Failed to configure OV8xx0 sensor"); + "Failed to configure OV8xx0 sensor"); goto error; } } @@ -1482,7 +1472,7 @@ static int ov519_mode_init_regs(struct sd *sd) return -EIO; if (sd->sensor == SEN_OV7640) { /* Select 8-bit input mode */ - reg_w_mask(sd, OV519_CAM_DFR, 0x10, 0x10); + reg_w_mask(sd, OV519_R20_DFR, 0x10, 0x10); } } else { if (write_regvals(sd, mode_init_519_ov7670, @@ -1490,14 +1480,14 @@ static int ov519_mode_init_regs(struct sd *sd) return -EIO; } - reg_w(sd, OV519_CAM_H_SIZE, sd->gspca_dev.width >> 4); - reg_w(sd, OV519_CAM_V_SIZE, sd->gspca_dev.height >> 3); - reg_w(sd, OV519_CAM_X_OFFSETL, 0x00); - reg_w(sd, OV519_CAM_X_OFFSETH, 0x00); - reg_w(sd, OV519_CAM_Y_OFFSETL, 0x00); - reg_w(sd, OV519_CAM_Y_OFFSETH, 0x00); - reg_w(sd, OV519_CAM_DIVIDER, 0x00); - reg_w(sd, OV519_CAM_FORMAT, 0x03); /* YUV422 */ + reg_w(sd, OV519_R10_H_SIZE, sd->gspca_dev.width >> 4); + reg_w(sd, OV519_R11_V_SIZE, sd->gspca_dev.height >> 3); + reg_w(sd, OV519_R12_X_OFFSETL, 0x00); + reg_w(sd, OV519_R13_X_OFFSETH, 0x00); + reg_w(sd, OV519_R14_Y_OFFSETL, 0x00); + reg_w(sd, OV519_R15_Y_OFFSETH, 0x00); + reg_w(sd, OV519_R16_DIVIDER, 0x00); + reg_w(sd, OV519_R25_FORMAT, 0x03); /* YUV422 */ reg_w(sd, 0x26, 0x00); /* Undocumented */ /******** Set the framerate ********/ @@ -1509,8 +1499,8 @@ static int ov519_mode_init_regs(struct sd *sd) switch (sd->sensor) { case SEN_OV7640: switch (sd->frame_rate) { -/*fixme: default was 30 fps */ - case 30: + default: +/* case 30: */ reg_w(sd, 0xa4, 0x0c); reg_w(sd, 0x23, 0xff); break; @@ -1522,8 +1512,7 @@ static int ov519_mode_init_regs(struct sd *sd) reg_w(sd, 0xa4, 0x0c); reg_w(sd, 0x23, 0x1b); break; - default: -/* case 15: */ + case 15: reg_w(sd, 0xa4, 0x04); reg_w(sd, 0x23, 0xff); sd->clockdiv = 1; @@ -1576,7 +1565,6 @@ static int ov519_mode_init_regs(struct sd *sd) } break; } - return 0; } @@ -1692,7 +1680,7 @@ static int mode_init_ov_sensor_regs(struct sd *sd) * the gain or the contrast. The "reserved" bits seem * to have some effect in this case. */ i2c_w(sd, 0x2d, 0x85); - } else if (sd->clockdiv >= 0) { + } else { i2c_w(sd, 0x11, sd->clockdiv); } @@ -1894,7 +1882,6 @@ static int sd_start(struct gspca_dev *gspca_dev) ret = ov51x_restart(sd); if (ret < 0) goto out; - PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt); ov51x_led_control(sd, 1); return 0; out: @@ -1904,8 +1891,10 @@ out: static void sd_stopN(struct gspca_dev *gspca_dev) { - ov51x_stop((struct sd *) gspca_dev); - ov51x_led_control((struct sd *) gspca_dev, 0); + struct sd *sd = (struct sd *) gspca_dev; + + ov51x_stop(sd); + ov51x_led_control(sd, 0); } static void sd_pkt_scan(struct gspca_dev *gspca_dev, @@ -1960,9 +1949,6 @@ static void setbrightness(struct gspca_dev *gspca_dev) int val; val = sd->brightness; - PDEBUG(D_CONF, "brightness:%d", val); -/* if (gspca_dev->streaming) - * ov51x_stop(sd); */ switch (sd->sensor) { case SEN_OV8610: case SEN_OV7610: @@ -1984,8 +1970,6 @@ static void setbrightness(struct gspca_dev *gspca_dev) i2c_w(sd, OV7670_REG_BRIGHT, ov7670_abs_to_sm(val)); break; } -/* if (gspca_dev->streaming) - * ov51x_restart(sd); */ } static void setcontrast(struct gspca_dev *gspca_dev) @@ -1994,9 +1978,6 @@ static void setcontrast(struct gspca_dev *gspca_dev) int val; val = sd->contrast; - PDEBUG(D_CONF, "contrast:%d", val); -/* if (gspca_dev->streaming) - ov51x_stop(sd); */ switch (sd->sensor) { case SEN_OV7610: case SEN_OV6620: @@ -2032,8 +2013,6 @@ static void setcontrast(struct gspca_dev *gspca_dev) i2c_w(sd, OV7670_REG_CONTRAS, val >> 1); break; } -/* if (gspca_dev->streaming) - ov51x_restart(sd); */ } static void setcolors(struct gspca_dev *gspca_dev) @@ -2042,9 +2021,6 @@ static void setcolors(struct gspca_dev *gspca_dev) int val; val = sd->colors; - PDEBUG(D_CONF, "saturation:%d", val); -/* if (gspca_dev->streaming) - ov51x_stop(sd); */ switch (sd->sensor) { case SEN_OV8610: case SEN_OV7610: @@ -2069,8 +2045,6 @@ static void setcolors(struct gspca_dev *gspca_dev) /* set REG_COM13 values for UV sat auto mode */ break; } -/* if (gspca_dev->streaming) - ov51x_restart(sd); */ } static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) @@ -2078,7 +2052,8 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) struct sd *sd = (struct sd *) gspca_dev; sd->brightness = val; - setbrightness(gspca_dev); + if (gspca_dev->streaming) + setbrightness(gspca_dev); return 0; } @@ -2095,7 +2070,8 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) struct sd *sd = (struct sd *) gspca_dev; sd->contrast = val; - setcontrast(gspca_dev); + if (gspca_dev->streaming) + setcontrast(gspca_dev); return 0; } @@ -2112,7 +2088,8 @@ static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) struct sd *sd = (struct sd *) gspca_dev; sd->colors = val; - setcolors(gspca_dev); + if (gspca_dev->streaming) + setcolors(gspca_dev); return 0; } @@ -2129,7 +2106,8 @@ static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val) struct sd *sd = (struct sd *) gspca_dev; sd->hflip = val; - sethvflip(sd); + if (gspca_dev->streaming) + sethvflip(sd); return 0; } @@ -2146,7 +2124,8 @@ static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val) struct sd *sd = (struct sd *) gspca_dev; sd->vflip = val; - sethvflip(sd); + if (gspca_dev->streaming) + sethvflip(sd); return 0; } @@ -2187,7 +2166,7 @@ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x05a9, 0x8519)}, {} }; -#undef DVNAME + MODULE_DEVICE_TABLE(usb, device_table); /* -- device connect -- */ diff --git a/linux/drivers/media/video/gspca/pac207.c b/linux/drivers/media/video/gspca/pac207.c index 0b0c573d0..39473e6b9 100644 --- a/linux/drivers/media/video/gspca/pac207.c +++ b/linux/drivers/media/video/gspca/pac207.c @@ -536,6 +536,7 @@ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x093a, 0x2471)}, {USB_DEVICE(0x093a, 0x2472)}, {USB_DEVICE(0x093a, 0x2476)}, + {USB_DEVICE(0x145f, 0x013a)}, {USB_DEVICE(0x2001, 0xf115)}, {} }; diff --git a/linux/drivers/media/video/gspca/sonixb.c b/linux/drivers/media/video/gspca/sonixb.c index 4bae911da..5ca8ab780 100644 --- a/linux/drivers/media/video/gspca/sonixb.c +++ b/linux/drivers/media/video/gspca/sonixb.c @@ -132,8 +132,6 @@ struct sensor_data { ignore atleast the 2 next frames for the new settings to come into effect before doing any other adjustments */ #define AUTOGAIN_IGNORE_FRAMES 3 -#define AUTOGAIN_DEADZONE 1000 -#define DESIRED_AVG_LUM 7000 /* V4L2 controls supported by the driver */ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); @@ -857,18 +855,29 @@ static void setfreq(struct gspca_dev *gspca_dev) static void do_autogain(struct gspca_dev *gspca_dev) { + int deadzone, desired_avg_lum; struct sd *sd = (struct sd *) gspca_dev; int avg_lum = atomic_read(&sd->avg_lum); if (avg_lum == -1) return; + /* SIF / VGA sensors have a different autoexposure area and thus + different avg_lum values for the same picture brightness */ + if (sensor_data[sd->sensor].flags & F_SIF) { + deadzone = 1000; + desired_avg_lum = 7000; + } else { + deadzone = 3000; + desired_avg_lum = 23000; + } + if (sd->autogain_ignore_frames > 0) sd->autogain_ignore_frames--; else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, - sd->brightness * DESIRED_AVG_LUM / 127, - AUTOGAIN_DEADZONE, GAIN_KNEE, EXPOSURE_KNEE)) { - PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d\n", + sd->brightness * desired_avg_lum / 127, + deadzone, GAIN_KNEE, EXPOSURE_KNEE)) { + PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d", (int)sd->gain, (int)sd->exposure); sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES; } @@ -1256,8 +1265,8 @@ static __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x0c45, 0x6025), SB(TAS5130CXX, 102)}, {USB_DEVICE(0x0c45, 0x6028), SB(PAS202, 102)}, {USB_DEVICE(0x0c45, 0x6029), SB(PAS106, 102)}, - {USB_DEVICE(0x0c45, 0x602c), SB(OV7630, 102)}, #endif + {USB_DEVICE(0x0c45, 0x602c), SB(OV7630, 102)}, {USB_DEVICE(0x0c45, 0x602d), SB(HV7131R, 102)}, #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE {USB_DEVICE(0x0c45, 0x602e), SB(OV7630, 102)}, diff --git a/linux/drivers/media/video/gspca/sonixj.c b/linux/drivers/media/video/gspca/sonixj.c index aa11df134..8b5eb91e1 100644 --- a/linux/drivers/media/video/gspca/sonixj.c +++ b/linux/drivers/media/video/gspca/sonixj.c @@ -24,6 +24,8 @@ #include "gspca.h" #include "jpeg.h" +#define V4L2_CID_INFRARED (V4L2_CID_PRIVATE_BASE + 0) + MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>"); MODULE_DESCRIPTION("GSPCA/SONIX JPEG USB Camera Driver"); MODULE_LICENSE("GPL"); @@ -40,6 +42,7 @@ struct sd { unsigned char colors; unsigned char autogain; __u8 vflip; /* ov7630 only */ + __u8 infrared; /* mi0360 only */ signed char ag_cnt; #define AG_CNT_START 13 @@ -73,6 +76,8 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val); static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setinfrared(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getinfrared(struct gspca_dev *gspca_dev, __s32 *val); static struct ctrl sd_ctrls[] = { { @@ -150,6 +155,22 @@ static struct ctrl sd_ctrls[] = { .set = sd_setvflip, .get = sd_getvflip, }, +/* mi0360 only */ +#define INFRARED_IDX 5 + { + { + .id = V4L2_CID_INFRARED, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Infrared", + .minimum = 0, + .maximum = 1, + .step = 1, +#define INFRARED_DEF 0 + .default_value = INFRARED_DEF, + }, + .set = sd_setinfrared, + .get = sd_getinfrared, + }, }; static struct v4l2_pix_format vga_mode[] = { @@ -971,6 +992,8 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->colors = COLOR_DEF; sd->autogain = AUTOGAIN_DEF; sd->ag_cnt = -1; + sd->vflip = VFLIP_DEF; + sd->infrared = INFRARED_DEF; switch (sd->sensor) { case SENSOR_OV7630: @@ -981,7 +1004,8 @@ static int sd_config(struct gspca_dev *gspca_dev, } if (sd->sensor != SENSOR_OV7630) gspca_dev->ctrl_dis |= (1 << VFLIP_IDX); - + if (sd->sensor != SENSOR_MI0360) + gspca_dev->ctrl_dis |= (1 << INFRARED_IDX); return 0; } @@ -1208,12 +1232,24 @@ static void setautogain(struct gspca_dev *gspca_dev) static void setvflip(struct sd *sd) { - if (sd->sensor != SENSOR_OV7630) - return; i2c_w1(&sd->gspca_dev, 0x75, /* COMN */ sd->vflip ? 0x82 : 0x02); } +static void setinfrared(struct sd *sd) +{ +/*fixme: different sequence for StarCam Clip and StarCam 370i */ +#if 1 +/* Clip */ + i2c_w1(&sd->gspca_dev, 0x02, /* gpio */ + sd->infrared ? 0x66 : 0x64); +#else +/* 370i */ + i2c_w1(&sd->gspca_dev, 0x02, /* gpio */ + sd->infrared ? 0x55 : 0x54); +#endif +} + /* -- start the camera -- */ static int sd_start(struct gspca_dev *gspca_dev) { @@ -1358,8 +1394,10 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w1(gspca_dev, 0x17, reg17); switch (sd->sensor) { - case SENSOR_HV7131R: case SENSOR_MI0360: + setinfrared(sd); + /* fall thru */ + case SENSOR_HV7131R: case SENSOR_MO4000: case SENSOR_OM6802: setbrightness(gspca_dev); @@ -1613,6 +1651,24 @@ static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) return 0; } +static int sd_setinfrared(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->infrared = val; + if (gspca_dev->streaming) + setinfrared(sd); + return 0; +} + +static int sd_getinfrared(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->infrared; + return 0; +} + /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, @@ -1638,8 +1694,8 @@ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x045e, 0x00f5), BSI(SN9C105, OV7660, 0x21)}, {USB_DEVICE(0x045e, 0x00f7), BSI(SN9C105, OV7660, 0x21)}, {USB_DEVICE(0x0471, 0x0327), BSI(SN9C105, MI0360, 0x5d)}, - {USB_DEVICE(0x0471, 0x0328), BSI(SN9C105, MI0360, 0x5d)}, #endif + {USB_DEVICE(0x0471, 0x0328), BSI(SN9C105, MI0360, 0x5d)}, {USB_DEVICE(0x0471, 0x0330), BSI(SN9C105, MI0360, 0x5d)}, {USB_DEVICE(0x0c45, 0x6040), BSI(SN9C102P, HV7131R, 0x11)}, /* bw600.inf: diff --git a/linux/drivers/media/video/gspca/tv8532.c b/linux/drivers/media/video/gspca/tv8532.c index 8204dabb1..4e18f90ba 100644 --- a/linux/drivers/media/video/gspca/tv8532.c +++ b/linux/drivers/media/video/gspca/tv8532.c @@ -30,15 +30,10 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - int buflen; /* current length of tmpbuf */ - __u8 tmpbuf[352 * 288 + 10 * 288]; /* no protection... */ - __u8 tmpbuf2[352 * 288]; /* no protection... */ + __u16 brightness; + __u16 contrast; - unsigned short brightness; - unsigned short contrast; - - char packet; - char synchro; + __u8 packet; }; /* V4L2 controls supported by the driver */ @@ -392,6 +387,8 @@ static void setbrightness(struct gspca_dev *gspca_dev) /* -- start the camera -- */ static int sd_start(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; + reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32); reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00); tv_8532ReadRegisters(gspca_dev); @@ -443,6 +440,10 @@ static int sd_start(struct gspca_dev *gspca_dev) /************************************************/ tv_8532_PollReg(gspca_dev); reg_w_1(gspca_dev, TV8532_UDP_UPDATE, 0x00); /* 0x31 */ + + gspca_dev->empty_packet = 0; /* check the empty packets */ + sd->packet = 0; /* ignore the first packets */ + return 0; } @@ -451,111 +452,36 @@ static void sd_stopN(struct gspca_dev *gspca_dev) reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b); } -static void tv8532_preprocess(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; -/* we should received a whole frame with header and EOL marker - * in gspca_dev->tmpbuf and return a GBRG pattern in gspca_dev->tmpbuf2 - * sequence 2bytes header the Alternate pixels bayer GB 4 bytes - * Alternate pixels bayer RG 4 bytes EOL */ - int width = gspca_dev->width; - int height = gspca_dev->height; - unsigned char *dst = sd->tmpbuf2; - unsigned char *data = sd->tmpbuf; - int i; - - /* precompute where is the good bayer line */ - if (((data[3] + data[width + 7]) >> 1) - + (data[4] >> 2) - + (data[width + 6] >> 1) >= ((data[2] + data[width + 6]) >> 1) - + (data[3] >> 2) - + (data[width + 5] >> 1)) - data += 3; - else - data += 2; - for (i = 0; i < height / 2; i++) { - memcpy(dst, data, width); - data += width + 3; - dst += width; - memcpy(dst, data, width); - data += width + 7; - dst += width; - } -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ int len) /* iso packet length */ { struct sd *sd = (struct sd *) gspca_dev; - - if (data[0] != 0x80) { - sd->packet++; - if (sd->buflen + len > sizeof sd->tmpbuf) { - if (gspca_dev->last_packet_type != DISCARD_PACKET) { - PDEBUG(D_PACK, "buffer overflow"); - gspca_dev->last_packet_type = DISCARD_PACKET; - } - return; - } - memcpy(&sd->tmpbuf[sd->buflen], data, len); - sd->buflen += len; - return; - } - - /* here we detect 0x80 */ - /* counter is limited so we need few header for a frame :) */ - - /* header 0x80 0x80 0x80 0x80 0x80 */ - /* packet 00 63 127 145 00 */ - /* sof 0 1 1 0 0 */ - - /* update sequence */ - if (sd->packet == 63 || sd->packet == 127) - sd->synchro = 1; - - /* is there a frame start ? */ - if (sd->packet >= (gspca_dev->height >> 1) - 1) { - PDEBUG(D_PACK, "SOF > %d packet %d", sd->synchro, - sd->packet); - if (!sd->synchro) { /* start of frame */ - if (gspca_dev->last_packet_type == FIRST_PACKET) { - tv8532_preprocess(gspca_dev); - frame = gspca_frame_add(gspca_dev, - LAST_PACKET, - frame, sd->tmpbuf2, - gspca_dev->width * - gspca_dev->width); - } - gspca_frame_add(gspca_dev, FIRST_PACKET, - frame, data, 0); - memcpy(sd->tmpbuf, data, len); - sd->buflen = len; - sd->packet = 0; - return; - } - if (gspca_dev->last_packet_type != DISCARD_PACKET) { - PDEBUG(D_PACK, - "Warning wrong TV8532 frame detection %d", - sd->packet); - gspca_dev->last_packet_type = DISCARD_PACKET; - } - return; - } - - if (!sd->synchro) { - /* Drop packet frame corrupt */ - PDEBUG(D_PACK, "DROP SOF %d packet %d", - sd->synchro, sd->packet); - sd->packet = 0; - gspca_dev->last_packet_type = DISCARD_PACKET; - return; - } - sd->synchro = 1; - sd->packet++; - memcpy(&sd->tmpbuf[sd->buflen], data, len); - sd->buflen += len; + int packet_type0, packet_type1; + + packet_type0 = packet_type1 = INTER_PACKET; + if (gspca_dev->empty_packet) { + gspca_dev->empty_packet = 0; + sd->packet = gspca_dev->height / 2; + packet_type0 = FIRST_PACKET; + } else if (sd->packet == 0) + return; /* 2 more lines in 352x288 ! */ + sd->packet--; + if (sd->packet == 0) + packet_type1 = LAST_PACKET; + + /* each packet contains: + * - header 2 bytes + * - RG line + * - 4 bytes + * - GB line + * - 4 bytes + */ + gspca_frame_add(gspca_dev, packet_type0, + frame, data + 2, gspca_dev->width); + gspca_frame_add(gspca_dev, packet_type1, + frame, data + gspca_dev->width + 6, gspca_dev->width); } static void setcontrast(struct gspca_dev *gspca_dev) diff --git a/linux/drivers/media/video/gspca/zc3xx.c b/linux/drivers/media/video/gspca/zc3xx.c index 0b1871cec..b74ce0ef1 100644 --- a/linux/drivers/media/video/gspca/zc3xx.c +++ b/linux/drivers/media/video/gspca/zc3xx.c @@ -2266,7 +2266,7 @@ static const struct usb_action hdcs2020b_NoFliker[] = { {} }; -static const struct usb_action hv7131bxx_Initial[] = { +static const struct usb_action hv7131bxx_Initial[] = { /* 320x240 */ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, {0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT}, @@ -2290,7 +2290,7 @@ static const struct usb_action hv7131bxx_Initial[] = { {0xaa, 0x14, 0x0001}, {0xaa, 0x15, 0x00e8}, {0xaa, 0x16, 0x0002}, - {0xaa, 0x17, 0x0086}, + {0xaa, 0x17, 0x0086}, /* 00,17,88,aa */ {0xaa, 0x31, 0x0038}, {0xaa, 0x32, 0x0038}, {0xaa, 0x33, 0x0038}, @@ -2309,72 +2309,11 @@ static const struct usb_action hv7131bxx_Initial[] = { {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, - {0xaa, 0x02, 0x0080}, /* {0xaa, 0x02, 0x0090}; */ - {0xa1, 0x01, 0x0002}, - {0xa0, 0x00, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x02, ZC3XX_R090_I2CCOMMAND}, - {0xa1, 0x01, 0x0091}, - {0xa1, 0x01, 0x0095}, - {0xa1, 0x01, 0x0096}, - - {0xa1, 0x01, 0x0008}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ - {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ - {0xa1, 0x01, 0x01c8}, - {0xa1, 0x01, 0x01c9}, - {0xa1, 0x01, 0x01ca}, - {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ - - {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */ - {0xa0, 0xf8, ZC3XX_R10B_RGB01}, - {0xa0, 0xf8, ZC3XX_R10C_RGB02}, - {0xa0, 0xf8, ZC3XX_R10D_RGB10}, - {0xa0, 0x50, ZC3XX_R10E_RGB11}, - {0xa0, 0xf8, ZC3XX_R10F_RGB12}, - {0xa0, 0xf8, ZC3XX_R110_RGB20}, - {0xa0, 0xf8, ZC3XX_R111_RGB21}, - {0xa0, 0x50, ZC3XX_R112_RGB22}, - {0xa1, 0x01, 0x0180}, - {0xa0, 0x10, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xaa, 0x25, 0x0007}, - {0xaa, 0x26, 0x00a1}, - {0xaa, 0x27, 0x0020}, - {0xaa, 0x20, 0x0000}, - {0xaa, 0x21, 0x00a0}, - {0xaa, 0x22, 0x0016}, - {0xaa, 0x23, 0x0040}, - - {0xa0, 0x10, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 2F */ - {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 4d */ - {0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x86, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0xa0, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x07, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x0f, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0xa0, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0x16, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0x40, ZC3XX_R020_HSYNC_3}, - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, - {0xa1, 0x01, 0x001d}, - {0xa1, 0x01, 0x001e}, - {0xa1, 0x01, 0x001f}, - {0xa1, 0x01, 0x0020}, - {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa1, 0x01, 0x0180}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x40, ZC3XX_R116_RGAIN}, - {0xa0, 0x40, ZC3XX_R117_GGAIN}, - {0xa0, 0x40, ZC3XX_R118_BGAIN}, -/* {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, */ + {0xaa, 0x02, 0x0090}, /* 00,02,80,aa */ {} }; -static const struct usb_action hv7131bxx_InitialScale[] = { +static const struct usb_action hv7131bxx_InitialScale[] = { /* 640x480*/ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, {0xa0, 0x00, ZC3XX_R010_CMOSSENSORSELECT}, @@ -2418,65 +2357,156 @@ static const struct usb_action hv7131bxx_InitialScale[] = { {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, {0xaa, 0x02, 0x0090}, /* {0xaa, 0x02, 0x0080}, */ - {0xa1, 0x01, 0x0002}, - {0xa0, 0x00, ZC3XX_R092_I2CADDRESSSELECT}, - {0xa0, 0x02, ZC3XX_R090_I2CCOMMAND}, - {0xa1, 0x01, 0x0091}, - {0xa1, 0x01, 0x0095}, - {0xa1, 0x01, 0x0096}, - {0xa1, 0x01, 0x0008}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ - {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ - {0xa1, 0x01, 0x01c8}, - {0xa1, 0x01, 0x01c9}, - {0xa1, 0x01, 0x01ca}, - {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ - - {0xa0, 0x50, ZC3XX_R10A_RGB00}, /* matrix */ - {0xa0, 0xf8, ZC3XX_R10B_RGB01}, - {0xa0, 0xf8, ZC3XX_R10C_RGB02}, - {0xa0, 0xf8, ZC3XX_R10D_RGB10}, - {0xa0, 0x50, ZC3XX_R10E_RGB11}, - {0xa0, 0xf8, ZC3XX_R10F_RGB12}, - {0xa0, 0xf8, ZC3XX_R110_RGB20}, - {0xa0, 0xf8, ZC3XX_R111_RGB21}, - {0xa0, 0x50, ZC3XX_R112_RGB22}, - {0xa1, 0x01, 0x0180}, - {0xa0, 0x10, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xaa, 0x25, 0x0007}, - {0xaa, 0x26, 0x00a1}, - {0xaa, 0x27, 0x0020}, - {0xaa, 0x20, 0x0000}, - {0xaa, 0x21, 0x0040}, - {0xaa, 0x22, 0x0013}, - {0xaa, 0x23, 0x004c}, - {0xa0, 0x10, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 2f */ - {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 4d */ - {0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW}, /* 60 */ - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0xc3, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x50, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0x40, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0x13, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0x4c, ZC3XX_R020_HSYNC_3}, - {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN}, - {0xa1, 0x01, 0x001d}, - {0xa1, 0x01, 0x001e}, - {0xa1, 0x01, 0x001f}, - {0xa1, 0x01, 0x0020}, - {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa1, 0x01, 0x0180}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x40, ZC3XX_R116_RGAIN}, - {0xa0, 0x40, ZC3XX_R117_GGAIN}, - {0xa0, 0x40, ZC3XX_R118_BGAIN}, -/* {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, */ + {} +}; +static const struct usb_action hv7131b_50HZ[] = { /* 640x480*/ + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x25, 0x0007}, /* 00,25,07,aa */ + {0xaa, 0x26, 0x0053}, /* 00,26,53,aa */ + {0xaa, 0x27, 0x0000}, /* 00,27,00,aa */ + {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ + {0xaa, 0x21, 0x0050}, /* 00,21,50,aa */ + {0xaa, 0x22, 0x001b}, /* 00,22,1b,aa */ + {0xaa, 0x23, 0x00fc}, /* 00,23,fc,aa */ + {0xa0, 0x2f, ZC3XX_R190_SYNC00LOW}, /* 01,90,2f,cc */ + {0xa0, 0x9b, ZC3XX_R191_SYNC00MID}, /* 01,91,9b,cc */ + {0xa0, 0x80, ZC3XX_R192_SYNC00HIGH}, /* 01,92,80,cc */ + {0xa0, 0x00, ZC3XX_R195_SYNC01LOW}, /* 01,95,00,cc */ + {0xa0, 0xea, ZC3XX_R196_SYNC01MID}, /* 01,96,ea,cc */ + {0xa0, 0x60, ZC3XX_R197_SYNC01HIGH}, /* 01,97,60,cc */ + {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0c,cc */ + {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,18,cc */ + {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,18,cc */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ + {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, /* 00,1d,00,cc */ + {0xa0, 0x50, ZC3XX_R01E_HSYNC_1}, /* 00,1e,50,cc */ + {0xa0, 0x1b, ZC3XX_R01F_HSYNC_2}, /* 00,1f,1b,cc */ + {0xa0, 0xfc, ZC3XX_R020_HSYNC_3}, /* 00,20,fc,cc */ + {} +}; +static const struct usb_action hv7131b_50HZScale[] = { /* 320x240 */ + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x25, 0x0007}, /* 00,25,07,aa */ + {0xaa, 0x26, 0x0053}, /* 00,26,53,aa */ + {0xaa, 0x27, 0x0000}, /* 00,27,00,aa */ + {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ + {0xaa, 0x21, 0x0050}, /* 00,21,50,aa */ + {0xaa, 0x22, 0x0012}, /* 00,22,12,aa */ + {0xaa, 0x23, 0x0080}, /* 00,23,80,aa */ + {0xa0, 0x2f, ZC3XX_R190_SYNC00LOW}, /* 01,90,2f,cc */ + {0xa0, 0x9b, ZC3XX_R191_SYNC00MID}, /* 01,91,9b,cc */ + {0xa0, 0x80, ZC3XX_R192_SYNC00HIGH}, /* 01,92,80,cc */ + {0xa0, 0x01, ZC3XX_R195_SYNC01LOW}, /* 01,95,01,cc */ + {0xa0, 0xd4, ZC3XX_R196_SYNC01MID}, /* 01,96,d4,cc */ + {0xa0, 0xc0, ZC3XX_R197_SYNC01HIGH}, /* 01,97,c0,cc */ + {0xa0, 0x07, ZC3XX_R18C_AEFREEZE}, /* 01,8c,07,cc */ + {0xa0, 0x0f, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,0f,cc */ + {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,18,cc */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ + {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, /* 00,1d,00,cc */ + {0xa0, 0x50, ZC3XX_R01E_HSYNC_1}, /* 00,1e,50,cc */ + {0xa0, 0x12, ZC3XX_R01F_HSYNC_2}, /* 00,1f,12,cc */ + {0xa0, 0x80, ZC3XX_R020_HSYNC_3}, /* 00,20,80,cc */ + {} +}; +static const struct usb_action hv7131b_60HZ[] = { /* 640x480*/ + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x25, 0x0007}, /* 00,25,07,aa */ + {0xaa, 0x26, 0x00a1}, /* 00,26,a1,aa */ + {0xaa, 0x27, 0x0020}, /* 00,27,20,aa */ + {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ + {0xaa, 0x21, 0x0040}, /* 00,21,40,aa */ + {0xaa, 0x22, 0x0013}, /* 00,22,13,aa */ + {0xaa, 0x23, 0x004c}, /* 00,23,4c,aa */ + {0xa0, 0x2f, ZC3XX_R190_SYNC00LOW}, /* 01,90,2f,cc */ + {0xa0, 0x4d, ZC3XX_R191_SYNC00MID}, /* 01,91,4d,cc */ + {0xa0, 0x60, ZC3XX_R192_SYNC00HIGH}, /* 01,92,60,cc */ + {0xa0, 0x00, ZC3XX_R195_SYNC01LOW}, /* 01,95,00,cc */ + {0xa0, 0xc3, ZC3XX_R196_SYNC01MID}, /* 01,96,c3,cc */ + {0xa0, 0x50, ZC3XX_R197_SYNC01HIGH}, /* 01,97,50,cc */ + {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0c,cc */ + {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,18,cc */ + {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,18,cc */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ + {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, /* 00,1d,00,cc */ + {0xa0, 0x40, ZC3XX_R01E_HSYNC_1}, /* 00,1e,40,cc */ + {0xa0, 0x13, ZC3XX_R01F_HSYNC_2}, /* 00,1f,13,cc */ + {0xa0, 0x4c, ZC3XX_R020_HSYNC_3}, /* 00,20,4c,cc */ + {} +}; +static const struct usb_action hv7131b_60HZScale[] = { /* 320x240 */ + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x25, 0x0007}, /* 00,25,07,aa */ + {0xaa, 0x26, 0x00a1}, /* 00,26,a1,aa */ + {0xaa, 0x27, 0x0020}, /* 00,27,20,aa */ + {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ + {0xaa, 0x21, 0x00a0}, /* 00,21,a0,aa */ + {0xaa, 0x22, 0x0016}, /* 00,22,16,aa */ + {0xaa, 0x23, 0x0040}, /* 00,23,40,aa */ + {0xa0, 0x2f, ZC3XX_R190_SYNC00LOW}, /* 01,90,2f,cc */ + {0xa0, 0x4d, ZC3XX_R191_SYNC00MID}, /* 01,91,4d,cc */ + {0xa0, 0x60, ZC3XX_R192_SYNC00HIGH}, /* 01,92,60,cc */ + {0xa0, 0x01, ZC3XX_R195_SYNC01LOW}, /* 01,95,01,cc */ + {0xa0, 0x86, ZC3XX_R196_SYNC01MID}, /* 01,96,86,cc */ + {0xa0, 0xa0, ZC3XX_R197_SYNC01HIGH}, /* 01,97,a0,cc */ + {0xa0, 0x07, ZC3XX_R18C_AEFREEZE}, /* 01,8c,07,cc */ + {0xa0, 0x0f, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,0f,cc */ + {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,18,cc */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ + {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, /* 00,1d,00,cc */ + {0xa0, 0xa0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,a0,cc */ + {0xa0, 0x16, ZC3XX_R01F_HSYNC_2}, /* 00,1f,16,cc */ + {0xa0, 0x40, ZC3XX_R020_HSYNC_3}, /* 00,20,40,cc */ + {} +}; +static const struct usb_action hv7131b_NoFliker[] = { /* 640x480*/ + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x25, 0x0003}, /* 00,25,03,aa */ + {0xaa, 0x26, 0x0000}, /* 00,26,00,aa */ + {0xaa, 0x27, 0x0000}, /* 00,27,00,aa */ + {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ + {0xaa, 0x21, 0x0010}, /* 00,21,10,aa */ + {0xaa, 0x22, 0x0000}, /* 00,22,00,aa */ + {0xaa, 0x23, 0x0003}, /* 00,23,03,aa */ + {0xa0, 0x2f, ZC3XX_R190_SYNC00LOW}, /* 01,90,2f,cc */ + {0xa0, 0xf8, ZC3XX_R191_SYNC00MID}, /* 01,91,f8,cc */ + {0xa0, 0x00, ZC3XX_R192_SYNC00HIGH}, /* 01,92,00,cc */ + {0xa0, 0x00, ZC3XX_R195_SYNC01LOW}, /* 01,95,00,cc */ + {0xa0, 0x02, ZC3XX_R196_SYNC01MID}, /* 01,96,02,cc */ + {0xa0, 0x00, ZC3XX_R197_SYNC01HIGH}, /* 01,97,00,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ + {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, /* 00,1d,00,cc */ + {0xa0, 0x10, ZC3XX_R01E_HSYNC_1}, /* 00,1e,10,cc */ + {0xa0, 0x00, ZC3XX_R01F_HSYNC_2}, /* 00,1f,00,cc */ + {0xa0, 0x03, ZC3XX_R020_HSYNC_3}, /* 00,20,03,cc */ + {} +}; +static const struct usb_action hv7131b_NoFlikerScale[] = { /* 320x240 */ + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xaa, 0x25, 0x0003}, /* 00,25,03,aa */ + {0xaa, 0x26, 0x0000}, /* 00,26,00,aa */ + {0xaa, 0x27, 0x0000}, /* 00,27,00,aa */ + {0xaa, 0x20, 0x0000}, /* 00,20,00,aa */ + {0xaa, 0x21, 0x00a0}, /* 00,21,a0,aa */ + {0xaa, 0x22, 0x0016}, /* 00,22,16,aa */ + {0xaa, 0x23, 0x0040}, /* 00,23,40,aa */ + {0xa0, 0x2f, ZC3XX_R190_SYNC00LOW}, /* 01,90,2f,cc */ + {0xa0, 0xf8, ZC3XX_R191_SYNC00MID}, /* 01,91,f8,cc */ + {0xa0, 0x00, ZC3XX_R192_SYNC00HIGH}, /* 01,92,00,cc */ + {0xa0, 0x00, ZC3XX_R195_SYNC01LOW}, /* 01,95,00,cc */ + {0xa0, 0x02, ZC3XX_R196_SYNC01MID}, /* 01,96,02,cc */ + {0xa0, 0x00, ZC3XX_R197_SYNC01HIGH}, /* 01,97,00,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ + {0xa0, 0x00, ZC3XX_R01D_HSYNC_0}, /* 00,1d,00,cc */ + {0xa0, 0xa0, ZC3XX_R01E_HSYNC_1}, /* 00,1e,a0,cc */ + {0xa0, 0x16, ZC3XX_R01F_HSYNC_2}, /* 00,1f,16,cc */ + {0xa0, 0x40, ZC3XX_R020_HSYNC_3}, /* 00,20,40,cc */ {} }; @@ -6358,6 +6388,7 @@ static void setmatrix(struct gspca_dev *gspca_dev) switch (sd->sensor) { case SENSOR_GC0305: + case SENSOR_HV7131B: matrix = gc0305_matrix; break; case SENSOR_MC501CB: @@ -6393,6 +6424,8 @@ static void setbrightness(struct gspca_dev *gspca_dev) /*fixme: is it really write to 011d and 018d for all other sensors? */ brightness = sd->brightness; reg_w(gspca_dev->dev, brightness, 0x011d); + if (sd->sensor == SENSOR_HV7131B) + return; if (brightness < 0x70) brightness += 0x10; else @@ -6534,6 +6567,7 @@ static void setquality(struct gspca_dev *gspca_dev) switch (sd->sensor) { case SENSOR_GC0305: + case SENSOR_HV7131B: case SENSOR_OV7620: case SENSOR_PO2030: return; @@ -6596,9 +6630,9 @@ static int setlightfreq(struct gspca_dev *gspca_dev) hdcs2020b_50HZ, hdcs2020b_50HZ, hdcs2020b_60HZ, hdcs2020b_60HZ}, /* SENSOR_HV7131B 5 */ - {NULL, NULL, - NULL, NULL, - NULL, NULL}, + {hv7131b_NoFlikerScale, hv7131b_NoFliker, + hv7131b_50HZScale, hv7131b_50HZ, + hv7131b_60HZScale, hv7131b_60HZ}, /* SENSOR_HV7131C 6 */ {NULL, NULL, NULL, NULL, @@ -7155,7 +7189,6 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->gamma = gamma[(int) sd->sensor]; sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value; sd->lightfreq = sd_ctrls[SD_FREQ].qctrl.default_value; - sd->sharpness = sd_ctrls[SD_SHARPNESS].qctrl.default_value; switch (sd->sensor) { case SENSOR_GC0305: @@ -7214,7 +7247,6 @@ static int sd_start(struct gspca_dev *gspca_dev) mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; zc3_init = init_tb[(int) sd->sensor][mode]; switch (sd->sensor) { - case SENSOR_HV7131B: case SENSOR_HV7131C: zcxx_probeSensor(gspca_dev); break; diff --git a/linux/drivers/media/video/saa7134/saa7134-dvb.c b/linux/drivers/media/video/saa7134/saa7134-dvb.c index 099761046..704442f55 100644 --- a/linux/drivers/media/video/saa7134/saa7134-dvb.c +++ b/linux/drivers/media/video/saa7134/saa7134-dvb.c @@ -954,20 +954,14 @@ static int dvb_init(struct saa7134_dev *dev) /* FIXME: add support for multi-frontend */ mutex_init(&dev->frontends.lock); INIT_LIST_HEAD(&dev->frontends.felist); - dev->frontends.active_fe_id = 0; printk(KERN_INFO "%s() allocating 1 frontend\n", __func__); - - if (videobuf_dvb_alloc_frontend(&dev->frontends, 1) == NULL) { + fe0 = videobuf_dvb_alloc_frontend(&dev->frontends, 1); + if (!fe0) { printk(KERN_ERR "%s() failed to alloc\n", __func__); return -ENOMEM; } - /* Get the first frontend */ - fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1); - if (!fe0) - return -EINVAL; - /* init struct videobuf_dvb */ dev->ts.nr_bufs = 32; dev->ts.nr_packets = 32*4; @@ -1380,7 +1374,7 @@ static int dvb_init(struct saa7134_dev *dev) }; if (!fe0->dvb.frontend) - return -1; + goto dettach_frontend; fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg); if (!fe) { @@ -1392,7 +1386,7 @@ static int dvb_init(struct saa7134_dev *dev) if (NULL == fe0->dvb.frontend) { printk(KERN_ERR "%s/dvb: frontend initialization failed\n", dev->name); - return -1; + goto dettach_frontend; } /* define general-purpose callback pointer */ fe0->dvb.frontend->callback = saa7134_tuner_callback; @@ -1415,11 +1409,8 @@ static int dvb_init(struct saa7134_dev *dev) return ret; dettach_frontend: - if (fe0->dvb.frontend) - dvb_frontend_detach(fe0->dvb.frontend); - fe0->dvb.frontend = NULL; - - return -1; + videobuf_dvb_dealloc_frontends(&dev->frontends); + return -EINVAL; } static int dvb_fini(struct saa7134_dev *dev) @@ -1458,8 +1449,7 @@ static int dvb_fini(struct saa7134_dev *dev) } } } - if (fe0->dvb.frontend) - videobuf_dvb_unregister_bus(&dev->frontends); + videobuf_dvb_unregister_bus(&dev->frontends); return 0; } diff --git a/linux/drivers/media/video/sn9c102/sn9c102_devtable.h b/linux/drivers/media/video/sn9c102/sn9c102_devtable.h index e23734f6d..390722003 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_devtable.h +++ b/linux/drivers/media/video/sn9c102/sn9c102_devtable.h @@ -55,7 +55,9 @@ static const struct usb_device_id sn9c102_id_table[] = { { SN9C102_USB_DEVICE(0x0c45, 0x6029, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x602a, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x602b, BRIDGE_SN9C102), }, +#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE { SN9C102_USB_DEVICE(0x0c45, 0x602c, BRIDGE_SN9C102), }, +#endif /* { SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), }, HV7131R */ { SN9C102_USB_DEVICE(0x0c45, 0x602e, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), }, @@ -94,7 +96,9 @@ static const struct usb_device_id sn9c102_id_table[] = { { SN9C102_USB_DEVICE(0x045e, 0x00f5, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x045e, 0x00f7, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), }, +#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE { SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), }, +#endif { SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0c45, 0x60c2, BRIDGE_SN9C105), }, { SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), }, diff --git a/linux/drivers/media/video/v4l2-ioctl.c b/linux/drivers/media/video/v4l2-ioctl.c index b38d4954c..86dd04026 100644 --- a/linux/drivers/media/video/v4l2-ioctl.c +++ b/linux/drivers/media/video/v4l2-ioctl.c @@ -1480,9 +1480,15 @@ static int __video_do_ioctl(struct file *file, case VIDIOC_G_CROP: { struct v4l2_crop *p = arg; + __u32 type; if (!ops->vidioc_g_crop) break; + + type = p->type; + memset(p, 0, sizeof(*p)); + p->type = type; + dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); ret = ops->vidioc_g_crop(file, fh, p); if (!ret) @@ -1503,10 +1509,16 @@ static int __video_do_ioctl(struct file *file, case VIDIOC_CROPCAP: { struct v4l2_cropcap *p = arg; + __u32 type; /*FIXME: Should also show v4l2_fract pixelaspect */ if (!ops->vidioc_cropcap) break; + + type = p->type; + memset(p, 0, sizeof(*p)); + p->type = type; + dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); ret = ops->vidioc_cropcap(file, fh, p); if (!ret) { @@ -1521,6 +1533,9 @@ static int __video_do_ioctl(struct file *file, if (!ops->vidioc_g_jpegcomp) break; + + memset(p, 0, sizeof(*p)); + ret = ops->vidioc_g_jpegcomp(file, fh, p); if (!ret) dbgarg(cmd, "quality=%d, APPn=%d, " @@ -1748,6 +1763,77 @@ static int __video_do_ioctl(struct file *file, ret = ops->vidioc_s_hw_freq_seek(file, fh, p); break; } + case VIDIOC_ENUM_FRAMESIZES: + { + struct v4l2_frmsizeenum *p = arg; + + if (!ops->vidioc_enum_framesizes) + break; + + memset(p, 0, sizeof(*p)); + + ret = ops->vidioc_enum_framesizes(file, fh, p); + dbgarg(cmd, + "index=%d, pixelformat=%d, type=%d ", + p->index, p->pixel_format, p->type); + switch (p->type) { + case V4L2_FRMSIZE_TYPE_DISCRETE: + dbgarg2("width = %d, height=%d\n", + p->discrete.width, p->discrete.height); + break; + case V4L2_FRMSIZE_TYPE_STEPWISE: + dbgarg2("min %dx%d, max %dx%d, step %dx%d\n", + p->stepwise.min_width, p->stepwise.min_height, + p->stepwise.step_width, p->stepwise.step_height, + p->stepwise.max_width, p->stepwise.max_height); + break; + case V4L2_FRMSIZE_TYPE_CONTINUOUS: + dbgarg2("continuous\n"); + break; + default: + dbgarg2("- Unknown type!\n"); + } + + break; + } + case VIDIOC_ENUM_FRAMEINTERVALS: + { + struct v4l2_frmivalenum *p = arg; + + if (!ops->vidioc_enum_frameintervals) + break; + + memset(p, 0, sizeof(*p)); + + ret = ops->vidioc_enum_frameintervals(file, fh, p); + dbgarg(cmd, + "index=%d, pixelformat=%d, width=%d, height=%d, type=%d ", + p->index, p->pixel_format, + p->width, p->height, p->type); + switch (p->type) { + case V4L2_FRMIVAL_TYPE_DISCRETE: + dbgarg2("fps=%d/%d\n", + p->discrete.numerator, + p->discrete.denominator); + break; + case V4L2_FRMIVAL_TYPE_STEPWISE: + dbgarg2("min=%d/%d, max=%d/%d, step=%d/%d\n", + p->stepwise.min.numerator, + p->stepwise.min.denominator, + p->stepwise.max.numerator, + p->stepwise.max.denominator, + p->stepwise.step.numerator, + p->stepwise.step.denominator); + break; + case V4L2_FRMIVAL_TYPE_CONTINUOUS: + dbgarg2("continuous\n"); + break; + default: + dbgarg2("- Unknown type!\n"); + } + break; + } + default: { if (!ops->vidioc_default) diff --git a/linux/include/media/v4l2-ioctl.h b/linux/include/media/v4l2-ioctl.h index f5985724c..c884432f9 100644 --- a/linux/include/media/v4l2-ioctl.h +++ b/linux/include/media/v4l2-ioctl.h @@ -232,6 +232,12 @@ struct v4l2_ioctl_ops { int (*vidioc_g_chip_ident) (struct file *file, void *fh, struct v4l2_chip_ident *chip); + int (*vidioc_enum_framesizes) (struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize); + + int (*vidioc_enum_frameintervals) (struct file *file, void *fh, + struct v4l2_frmivalenum *fival); + /* For other private ioctls */ int (*vidioc_default) (struct file *file, void *fh, int cmd, void *arg); diff --git a/linux/sound/pci/bt87x.c b/linux/sound/pci/bt87x.c index 0dd872610..8b6868462 100644 --- a/linux/sound/pci/bt87x.c +++ b/linux/sound/pci/bt87x.c @@ -775,8 +775,7 @@ static int __devinit snd_bt87x_create(struct snd_card *card, pci_disable_device(pci); return err; } - chip->mmio = ioremap_nocache(pci_resource_start(pci, 0), - pci_resource_len(pci, 0)); + chip->mmio = pci_ioremap_bar(pci, 0); if (!chip->mmio) { snd_printk(KERN_ERR "cannot remap io memory\n"); err = -ENOMEM; |