diff options
Diffstat (limited to 'linux/drivers/media/video')
-rw-r--r-- | linux/drivers/media/video/cx88/cx88-cards.c | 80 | ||||
-rw-r--r-- | linux/drivers/media/video/cx88/cx88-tvaudio.c | 13 | ||||
-rw-r--r-- | linux/drivers/media/video/cx88/cx88-video.c | 8 | ||||
-rw-r--r-- | linux/drivers/media/video/cx88/cx88.h | 1 | ||||
-rw-r--r-- | linux/drivers/media/video/et61x251/et61x251_core.c | 37 | ||||
-rw-r--r-- | linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c | 141 | ||||
-rw-r--r-- | linux/drivers/media/video/pwc/pwc-if.c | 41 | ||||
-rw-r--r-- | linux/drivers/media/video/sn9c102/sn9c102_core.c | 71 | ||||
-rw-r--r-- | linux/drivers/media/video/stv680.c | 21 | ||||
-rw-r--r-- | linux/drivers/media/video/tuner-types.c | 1 | ||||
-rw-r--r-- | linux/drivers/media/video/videodev.c | 11 |
11 files changed, 339 insertions, 86 deletions
diff --git a/linux/drivers/media/video/cx88/cx88-cards.c b/linux/drivers/media/video/cx88/cx88-cards.c index f014fc508..184903779 100644 --- a/linux/drivers/media/video/cx88/cx88-cards.c +++ b/linux/drivers/media/video/cx88/cx88-cards.c @@ -282,18 +282,22 @@ struct cx88_board cx88_boards[] = { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0000bde2, + .extadc = 1, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x0000bde6, + .extadc = 1, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0000bde6, + .extadc = 1, }}, .radio = { .type = CX88_RADIO, .gpio0 = 0x0000bd62, + .extadc = 1, }, .mpeg = CX88_MPEG_BLACKBIRD, }, @@ -354,6 +358,7 @@ struct cx88_board cx88_boards[] = { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0000fde6, // 0x0000fda6 L,R RCA audio in? + .extadc = 1, }}, .radio = { .type = CX88_RADIO, @@ -524,6 +529,7 @@ struct cx88_board cx88_boards[] = { .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, + .extadc = 1, }}, .mpeg = CX88_MPEG_BLACKBIRD, }, @@ -647,18 +653,22 @@ struct cx88_board cx88_boards[] = { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00009d80, + .extadc = 1, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00009d76, + .extadc = 1, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00009d76, + .extadc = 1, }}, .radio = { .type = CX88_RADIO, .gpio0 = 0x00009d00, + .extadc = 1, }, .mpeg = CX88_MPEG_BLACKBIRD, }, @@ -787,25 +797,29 @@ struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .mpeg = CX88_MPEG_BLACKBIRD, .input = {{ .type = CX88_VMUX_COMPOSITE1, .vmux = 0, .gpio0 = 0x0000cd73, + .extadc = 1, },{ .type = CX88_VMUX_SVIDEO, .vmux = 1, .gpio0 = 0x0000cd73, + .extadc = 1, },{ .type = CX88_VMUX_TELEVISION, .vmux = 3, .gpio0 = 0x0000cdb3, + .extadc = 1, }}, .radio = { .type = CX88_RADIO, .vmux = 2, .gpio0 = 0x0000cdf3, + .extadc = 1, }, + .mpeg = CX88_MPEG_BLACKBIRD, }, [CX88_BOARD_KWORLD_VSTREAM_EXPERT_DVD] = { /* Alexander Wold <awold@bigfoot.com> */ @@ -1051,7 +1065,6 @@ struct cx88_board cx88_boards[] = { .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT] = { - /* FIXME: Audio not working for s-video / composite inputs. */ .name = "KWorld HardwareMpegTV XPert", .tuner_type = TUNER_PHILIPS_TDA8290, .radio_type = UNSET, @@ -1066,10 +1079,12 @@ struct cx88_board cx88_boards[] = { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x3de6, + .extadc = 1, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x3de6, + .extadc = 1, }}, .radio = { .type = CX88_RADIO, @@ -1285,35 +1300,35 @@ struct cx88_board cx88_boards[] = { .gpio0 = 0x070b, }}, }, - [CX88_BOARD_TE_DTV_250_OEM_SWANN] = { - .name = "Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM", - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x003fffff, - .gpio1 = 0x00e00000, - .gpio2 = 0x003fffff, - .gpio3 = 0x02000000, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x003fffff, - .gpio1 = 0x00e00000, - .gpio2 = 0x003fffff, - .gpio3 = 0x02000000, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x003fffff, - .gpio1 = 0x00e00000, - .gpio2 = 0x003fffff, - .gpio3 = 0x02000000, - }}, - }, + [CX88_BOARD_TE_DTV_250_OEM_SWANN] = { + .name = "Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM", + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x003fffff, + .gpio1 = 0x00e00000, + .gpio2 = 0x003fffff, + .gpio3 = 0x02000000, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x003fffff, + .gpio1 = 0x00e00000, + .gpio2 = 0x003fffff, + .gpio3 = 0x02000000, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x003fffff, + .gpio1 = 0x00e00000, + .gpio2 = 0x003fffff, + .gpio3 = 0x02000000, + }}, + }, [CX88_BOARD_HAUPPAUGE_HVR1300] = { .name = "Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder", .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, @@ -1326,14 +1341,17 @@ struct cx88_board cx88_boards[] = { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xe780, + .extadc = 1, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0xe780, + .extadc = 1, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0xe780, + .extadc = 1, }}, /* fixme: Add radio support */ .mpeg = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD, diff --git a/linux/drivers/media/video/cx88/cx88-tvaudio.c b/linux/drivers/media/video/cx88/cx88-tvaudio.c index 6528c05d0..4f2b52012 100644 --- a/linux/drivers/media/video/cx88/cx88-tvaudio.c +++ b/linux/drivers/media/video/cx88/cx88-tvaudio.c @@ -146,19 +146,6 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl) cx88_start_audio_dma(core); if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) { - /* sets sound input from external adc */ - switch (core->board) { - case CX88_BOARD_HAUPPAUGE_ROSLYN: - case CX88_BOARD_KWORLD_MCE200_DELUXE: - case CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT: - case CX88_BOARD_PIXELVIEW_PLAYTV_P7000: - case CX88_BOARD_ASUS_PVR_416: - cx_clear(AUD_CTL, EN_I2SIN_ENABLE); - break; - default: - cx_set(AUD_CTL, EN_I2SIN_ENABLE); - } - cx_write(AUD_I2SINPUTCNTL, 4); cx_write(AUD_BAUDRATE, 1); /* 'pass-thru mode': this enables the i2s output to the mpeg encoder */ diff --git a/linux/drivers/media/video/cx88/cx88-video.c b/linux/drivers/media/video/cx88/cx88-video.c index 1f1640f0f..46de90a1b 100644 --- a/linux/drivers/media/video/cx88/cx88-video.c +++ b/linux/drivers/media/video/cx88/cx88-video.c @@ -477,6 +477,14 @@ static int video_mux(struct cx88_core *core, unsigned int input) cx_clear(MO_FILTER_ODD, 0x00002020); break; } + + if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) { + /* sets sound input from external adc */ + if (INPUT(input)->extadc) + cx_set(AUD_CTL, EN_I2SIN_ENABLE); + else + cx_clear(AUD_CTL, EN_I2SIN_ENABLE); + } return 0; } diff --git a/linux/drivers/media/video/cx88/cx88.h b/linux/drivers/media/video/cx88/cx88.h index 436847b70..657dc9414 100644 --- a/linux/drivers/media/video/cx88/cx88.h +++ b/linux/drivers/media/video/cx88/cx88.h @@ -233,6 +233,7 @@ struct cx88_input { enum cx88_itype type; unsigned int vmux; u32 gpio0, gpio1, gpio2, gpio3; + unsigned int extadc:1; }; struct cx88_board { diff --git a/linux/drivers/media/video/et61x251/et61x251_core.c b/linux/drivers/media/video/et61x251/et61x251_core.c index 8992b6e62..cf59793cf 100644 --- a/linux/drivers/media/video/et61x251/et61x251_core.c +++ b/linux/drivers/media/video/et61x251/et61x251_core.c @@ -973,16 +973,32 @@ static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, et61x251_show_i2c_val, et61x251_store_i2c_val); -static void et61x251_create_sysfs(struct et61x251_device* cam) +static int et61x251_create_sysfs(struct et61x251_device* cam) { struct video_device *v4ldev = cam->v4ldev; + int rc; - video_device_create_file(v4ldev, &class_device_attr_reg); - video_device_create_file(v4ldev, &class_device_attr_val); + rc = video_device_create_file(v4ldev, &class_device_attr_reg); + if (rc) goto err; + rc = video_device_create_file(v4ldev, &class_device_attr_val); + if (rc) goto err_reg; if (cam->sensor.sysfs_ops) { - video_device_create_file(v4ldev, &class_device_attr_i2c_reg); - video_device_create_file(v4ldev, &class_device_attr_i2c_val); + rc = video_device_create_file(v4ldev, &class_device_attr_i2c_reg); + if (rc) goto err_val; + rc = video_device_create_file(v4ldev, &class_device_attr_i2c_val); + if (rc) goto err_i2c_reg; } + + return 0; + +err_i2c_reg: + video_device_remove_file(v4ldev, &class_device_attr_i2c_reg); +err_val: + video_device_remove_file(v4ldev, &class_device_attr_val); +err_reg: + video_device_remove_file(v4ldev, &class_device_attr_reg); +err: + return rc; } #endif /* CONFIG_VIDEO_ADV_DEBUG */ @@ -2534,7 +2550,9 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0; #ifdef CONFIG_VIDEO_ADV_DEBUG - et61x251_create_sysfs(cam); + err = et61x251_create_sysfs(cam); + if (err) + goto fail2; DBG(2, "Optional device control through 'sysfs' interface ready"); #endif @@ -2544,6 +2562,13 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) return 0; +#ifdef CONFIG_VIDEO_ADV_DEBUG +fail2: + video_nr[dev_nr] = -1; + dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0; + mutex_unlock(&cam->dev_mutex); + video_unregister_device(cam->v4ldev); +#endif fail: if (cam) { kfree(cam->control_buffer); diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index ebfe184ab..760cb5c7f 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -200,6 +200,139 @@ static int pvr2_i2c_basic_op(struct pvr2_hdw *hdw, } } +#if 0 +/* This is special code for spying on IR transactions for 29xxx devices. + We use this to reverse-engineer the IR protocol in order to simulate it + correctly for 24xxx devices. */ +static int i2c_29xxx_ir(struct pvr2_hdw *hdw, + u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen) +{ + char buf[200]; + unsigned int c1,c2; + unsigned int idx,stat; + if (!(rlen || wlen)) { + /* This is a probe attempt. Just let it succeed. */ + pvr2_trace(PVR2_TRACE_DEBUG,"IR: probe"); + return 0; + } + stat = pvr2_i2c_basic_op(hdw,i2c_addr,wdata,wlen,rdata,rlen); + if ((wlen == 0) && (rlen == 3) && (stat == 0) && + (rdata[0] == 0) && (rdata[1] == 0) && (rdata[2] == 0xc1)) { + return stat; + } + c1 = 0; + c2 = scnprintf(buf+c1,sizeof(buf)-c1, + "IR: stat=%d",stat); + c1 += c2; + if (wlen) { + c2 = scnprintf(buf+c1,sizeof(buf)-c1, + " write ["); + c1 += c2; + for (idx = 0; idx < wlen; idx++) { + c2 = scnprintf(buf+c1,sizeof(buf)-c1, + "%s%02x",idx == 0 ? "" : " ", + wdata[idx]); + c1 += c2; + } + c2 = scnprintf(buf+c1,sizeof(buf)-c1, + "]"); + c1 += c2; + } + if (rlen && (stat == 0)) { + c2 = scnprintf(buf+c1,sizeof(buf)-c1, + " read ["); + c1 += c2; + for (idx = 0; idx < rlen; idx++) { + c2 = scnprintf(buf+c1,sizeof(buf)-c1, + "%s%02x",idx == 0 ? "" : " ", + rdata[idx]); + c1 += c2; + } + c2 = scnprintf(buf+c1,sizeof(buf)-c1, + "]"); + c1 += c2; + } else if (rlen) { + c2 = scnprintf(buf+c1,sizeof(buf)-c1, + " read cnt=%u",rlen); + c1 += c2; + } + pvr2_trace(PVR2_TRACE_DEBUG,"%.*s",c1,buf); + return stat; +} +#endif + +/* This is a special entry point for cases of I2C transaction attempts to + the IR receiver. The implementation here simulates the IR receiver by + issuing a command to the FX2 firmware and using that response to return + what the real I2C receiver would have returned. We use this for 24xxx + devices, where the IR receiver chip has been removed and replaced with + FX2 related logic. */ +static int i2c_24xxx_ir(struct pvr2_hdw *hdw, + u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen) +{ + u8 dat[4]; + unsigned int stat; + + if (!(rlen || wlen)) { + /* This is a probe attempt. Just let it succeed. */ + return 0; + } + + /* We don't understand this kind of transaction */ + if ((wlen != 0) || (rlen == 0)) return -EIO; + + if (rlen < 3) { + /* Mike Isely <isely@pobox.com> Appears to be a probe + attempt from lirc. Just fill in zeroes and return. If + we try instead to do the full transaction here, then bad + things seem to happen within the lirc driver module + (version 0.8.0-7 sources from Debian, when run under + vanilla 2.6.17.6 kernel) - and I don't have the patience + to chase it down. */ + if (rlen > 0) rdata[0] = 0; + if (rlen > 1) rdata[1] = 0; + return 0; + } + + /* Issue a command to the FX2 to read the IR receiver. */ + LOCK_TAKE(hdw->ctl_lock); do { + hdw->cmd_buffer[0] = 0xec; + stat = pvr2_send_request(hdw, + hdw->cmd_buffer,1, + hdw->cmd_buffer,4); + dat[0] = hdw->cmd_buffer[0]; + dat[1] = hdw->cmd_buffer[1]; + dat[2] = hdw->cmd_buffer[2]; + dat[3] = hdw->cmd_buffer[3]; + } while (0); LOCK_GIVE(hdw->ctl_lock); + + /* Give up if that operation failed. */ + if (stat != 0) return stat; + + /* Mangle the results into something that looks like the real IR + receiver. */ + rdata[2] = 0xc1; + if (dat[0] != 1) { + /* No code received. */ + rdata[0] = 0; + rdata[1] = 0; + } else { + u16 val; + /* Mash the FX2 firmware-provided IR code into something + that the normal i2c chip-level driver expects. */ + val = dat[1]; + val <<= 8; + val |= dat[2]; + val >>= 1; + val &= ~0x0003; + val |= 0x8000; + rdata[0] = (val >> 8) & 0xffu; + rdata[1] = val & 0xffu; + } + + return 0; +} + /* This is a special entry point that is entered if an I2C operation is attempted to a wm8775 chip on model 24xxx hardware. Autodetect of this part doesn't work, but we know it is really there. So let's look for @@ -913,17 +1046,17 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw) { unsigned int idx; - // The default action for all possible I2C addresses is just to do - // the transfer normally. + /* The default action for all possible I2C addresses is just to do + the transfer normally. */ for (idx = 0; idx < PVR2_I2C_FUNC_CNT; idx++) { hdw->i2c_func[idx] = pvr2_i2c_basic_op; } - // If however we're dealing with new hardware, insert some hacks in - // the I2C transfer stack to let things work better. + /* However, deal with various special cases for 24xxx hardware. */ if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) { hdw->i2c_func[0x1b] = i2c_hack_wm8775; hdw->i2c_func[0x44] = i2c_hack_cx25840; + hdw->i2c_func[0x18] = i2c_24xxx_ir; } // Configure the adapter and set up everything else related to it. diff --git a/linux/drivers/media/video/pwc/pwc-if.c b/linux/drivers/media/video/pwc/pwc-if.c index f00a606c5..c05eab846 100644 --- a/linux/drivers/media/video/pwc/pwc-if.c +++ b/linux/drivers/media/video/pwc/pwc-if.c @@ -1057,12 +1057,25 @@ static ssize_t show_snapshot_button_status(struct class_device *class_dev, char static CLASS_DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status, NULL); -static void pwc_create_sysfs_files(struct video_device *vdev) +static int pwc_create_sysfs_files(struct video_device *vdev) { struct pwc_device *pdev = video_get_drvdata(vdev); - if (pdev->features & FEATURE_MOTOR_PANTILT) - video_device_create_file(vdev, &class_device_attr_pan_tilt); - video_device_create_file(vdev, &class_device_attr_button); + int rc; + + rc = video_device_create_file(vdev, &class_device_attr_button); + if (rc) + goto err; + if (pdev->features & FEATURE_MOTOR_PANTILT) { + rc = video_device_create_file(vdev,&class_device_attr_pan_tilt); + if (rc) goto err_button; + } + + return 0; + +err_button: + video_device_remove_file(vdev, &class_device_attr_button); +err: + return rc; } static void pwc_remove_sysfs_files(struct video_device *vdev) @@ -1447,7 +1460,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id struct usb_device *udev = interface_to_usbdev(intf); struct pwc_device *pdev = NULL; int vendor_id, product_id, type_id; - int i, hint; + int i, hint, rc; int features = 0; int video_nr = -1; /* default: use next available device */ char serial_number[30], *name; @@ -1757,9 +1770,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr); if (i < 0) { PWC_ERROR("Failed to register as video device (%d).\n", i); - video_device_release(pdev->vdev); /* Drip... drip... drip... */ - kfree(pdev); /* Oops, no memory leaks please */ - return -EIO; + rc = i; + goto err; } else { PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F); @@ -1771,13 +1783,24 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev); usb_set_intfdata (intf, pdev); - pwc_create_sysfs_files(pdev->vdev); + rc = pwc_create_sysfs_files(pdev->vdev); + if (rc) + goto err_unreg; /* Set the leds off */ pwc_set_leds(pdev, 0, 0); pwc_camera_power(pdev, 0); return 0; + +err_unreg: + if (hint < MAX_DEV_HINTS) + device_hint[hint].pdev = NULL; + video_unregister_device(pdev->vdev); +err: + video_device_release(pdev->vdev); /* Drip... drip... drip... */ + kfree(pdev); /* Oops, no memory leaks please */ + return rc; } /* The user janked out the cable... */ diff --git a/linux/drivers/media/video/sn9c102/sn9c102_core.c b/linux/drivers/media/video/sn9c102/sn9c102_core.c index 38b149dac..bb02282f0 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_core.c +++ b/linux/drivers/media/video/sn9c102/sn9c102_core.c @@ -1240,23 +1240,53 @@ static CLASS_DEVICE_ATTR(frame_header, S_IRUGO, sn9c102_show_frame_header, NULL); -static void sn9c102_create_sysfs(struct sn9c102_device* cam) +static int sn9c102_create_sysfs(struct sn9c102_device* cam) { struct video_device *v4ldev = cam->v4ldev; + int rc; + + rc = video_device_create_file(v4ldev, &class_device_attr_reg); + if (rc) goto err; + rc = video_device_create_file(v4ldev, &class_device_attr_val); + if (rc) goto err_reg; + rc = video_device_create_file(v4ldev, &class_device_attr_frame_header); + if (rc) goto err_val; - video_device_create_file(v4ldev, &class_device_attr_reg); - video_device_create_file(v4ldev, &class_device_attr_val); - video_device_create_file(v4ldev, &class_device_attr_frame_header); - if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) - video_device_create_file(v4ldev, &class_device_attr_green); - else if (cam->bridge == BRIDGE_SN9C103) { - video_device_create_file(v4ldev, &class_device_attr_blue); - video_device_create_file(v4ldev, &class_device_attr_red); - } if (cam->sensor.sysfs_ops) { - video_device_create_file(v4ldev, &class_device_attr_i2c_reg); - video_device_create_file(v4ldev, &class_device_attr_i2c_val); + rc = video_device_create_file(v4ldev, &class_device_attr_i2c_reg); + if (rc) goto err_frhead; + rc = video_device_create_file(v4ldev, &class_device_attr_i2c_val); + if (rc) goto err_i2c_reg; + } + + if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) { + rc = video_device_create_file(v4ldev, &class_device_attr_green); + if (rc) goto err_i2c_val; + } else if (cam->bridge == BRIDGE_SN9C103) { + rc = video_device_create_file(v4ldev, &class_device_attr_blue); + if (rc) goto err_i2c_val; + rc = video_device_create_file(v4ldev, &class_device_attr_red); + if (rc) goto err_blue; } + + return 0; + +err_blue: + video_device_remove_file(v4ldev, &class_device_attr_blue); +err_i2c_val: + if (cam->sensor.sysfs_ops) + video_device_remove_file(v4ldev, &class_device_attr_i2c_val); +err_i2c_reg: + if (cam->sensor.sysfs_ops) + video_device_remove_file(v4ldev, &class_device_attr_i2c_reg); +err_frhead: + video_device_remove_file(v4ldev, &class_device_attr_frame_header); +err_val: + video_device_remove_file(v4ldev, &class_device_attr_val); +err_reg: + video_device_remove_file(v4ldev, &class_device_attr_reg); +err: + return rc; } #endif /* CONFIG_VIDEO_ADV_DEBUG */ @@ -2815,10 +2845,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) DBG(1, "V4L2 device registration failed"); if (err == -ENFILE && video_nr[dev_nr] == -1) DBG(1, "Free /dev/videoX node not found"); - video_nr[dev_nr] = -1; - dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; - mutex_unlock(&cam->dev_mutex); - goto fail; + goto fail2; } DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor); @@ -2829,7 +2856,9 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; #ifdef CONFIG_VIDEO_ADV_DEBUG - sn9c102_create_sysfs(cam); + err = sn9c102_create_sysfs(cam); + if (err) + goto fail3; DBG(2, "Optional device control through 'sysfs' interface ready"); #endif @@ -2839,6 +2868,14 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) return 0; +#ifdef CONFIG_VIDEO_ADV_DEBUG +fail3: + video_unregister_device(cam->v4ldev); +#endif +fail2: + video_nr[dev_nr] = -1; + dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0; + mutex_unlock(&cam->dev_mutex); fail: if (cam) { kfree(cam->control_buffer); diff --git a/linux/drivers/media/video/stv680.c b/linux/drivers/media/video/stv680.c index f8e9f1cbd..44ff13f36 100644 --- a/linux/drivers/media/video/stv680.c +++ b/linux/drivers/media/video/stv680.c @@ -690,7 +690,7 @@ static int stv680_start_stream (struct usb_stv *stv680) stv680->sbuf[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL); if (stv680->sbuf[i].data == NULL) { PDEBUG (0, "STV(e): Could not kmalloc raw data buffer %i", i); - return -1; + goto nomem_err; } } @@ -701,7 +701,7 @@ static int stv680_start_stream (struct usb_stv *stv680) stv680->scratch[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL); if (stv680->scratch[i].data == NULL) { PDEBUG (0, "STV(e): Could not kmalloc raw scratch buffer %i", i); - return -1; + goto nomem_err; } stv680->scratch[i].state = BUFFER_UNUSED; } @@ -709,7 +709,7 @@ static int stv680_start_stream (struct usb_stv *stv680) for (i = 0; i < STV680_NUMSBUF; i++) { urb = usb_alloc_urb (0, GFP_KERNEL); if (!urb) - return -ENOMEM; + goto nomem_err; /* sbuf is urb->transfer_buffer, later gets memcpyed to scratch */ usb_fill_bulk_urb (urb, stv680->udev, @@ -724,6 +724,21 @@ static int stv680_start_stream (struct usb_stv *stv680) stv680->framecount = 0; return 0; + + nomem_err: + for (i = 0; i < STV680_NUMSCRATCH; i++) { + kfree(stv680->scratch[i].data); + stv680->scratch[i].data = NULL; + } + for (i = 0; i < STV680_NUMSBUF; i++) { + usb_kill_urb(stv680->urb[i]); + usb_free_urb(stv680->urb[i]); + stv680->urb[i] = NULL; + kfree(stv680->sbuf[i].data); + stv680->sbuf[i].data = NULL; + } + return -ENOMEM; + } static int stv680_stop_stream (struct usb_stv *stv680) diff --git a/linux/drivers/media/video/tuner-types.c b/linux/drivers/media/video/tuner-types.c index 31de9c872..357098c17 100644 --- a/linux/drivers/media/video/tuner-types.c +++ b/linux/drivers/media/video/tuner-types.c @@ -1094,7 +1094,6 @@ static struct tuner_params tuner_samsung_tcpn_2121p30a_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_samsung_tcpn_2121p30a_ntsc_ranges, .count = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_ntsc_ranges), - .has_tda9887 = 1, }, }; diff --git a/linux/drivers/media/video/videodev.c b/linux/drivers/media/video/videodev.c index a8705f7d7..bcaee23da 100644 --- a/linux/drivers/media/video/videodev.c +++ b/linux/drivers/media/video/videodev.c @@ -1307,6 +1307,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, ret=vfd->vidioc_g_parm(file, fh, p); } else { struct v4l2_standard s; + int i; if (!vfd->tvnormsize) { printk (KERN_WARNING "%s: no TV norms defined!\n", @@ -1317,8 +1318,14 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - v4l2_video_std_construct(&s, vfd->tvnorms[vfd->current_norm].id, - vfd->tvnorms[vfd->current_norm].name); + for (i = 0; i < vfd->tvnormsize; i++) + if (vfd->tvnorms[i].id == vfd->current_norm) + break; + if (i >= vfd->tvnormsize) + return -EINVAL; + + v4l2_video_std_construct(&s, vfd->current_norm, + vfd->tvnorms[i].name); memset(p,0,sizeof(*p)); |