diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-08-11 13:56:40 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-08-11 13:56:40 -0300 |
commit | 6971a9d650f6ab06dfedc4464665366c87da4bbc (patch) | |
tree | 6274d376e8d2ee13a4fecb2d0f9e294bc35935ef /linux/drivers/media/video | |
parent | 6355bbe94603dee693331f5ae62c8c1a109a8007 (diff) | |
parent | 796c449e9807bc070a33bcbbab2f4cae6cfc6d14 (diff) | |
download | mediapointer-dvb-s2-6971a9d650f6ab06dfedc4464665366c87da4bbc.tar.gz mediapointer-dvb-s2-6971a9d650f6ab06dfedc4464665366c87da4bbc.tar.bz2 |
merge: http://www.kernellabs.com/hg/~dheitmueller/ttxs-remote/
From: Mauro Carvalho Chehab <mchehab@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'linux/drivers/media/video')
36 files changed, 1206 insertions, 743 deletions
diff --git a/linux/drivers/media/video/Kconfig b/linux/drivers/media/video/Kconfig index 8460013a0..e8a6e4de4 100644 --- a/linux/drivers/media/video/Kconfig +++ b/linux/drivers/media/video/Kconfig @@ -991,6 +991,8 @@ source "drivers/media/video/pwc/Kconfig" config USB_ZR364XX tristate "USB ZR364XX Camera support" depends on VIDEO_V4L2 + select VIDEOBUF_GEN + select VIDEOBUF_VMALLOC ---help--- Say Y here if you want to connect this type of camera to your computer's USB port. diff --git a/linux/drivers/media/video/bw-qcam.c b/linux/drivers/media/video/bw-qcam.c index 3702baad6..8f6bb845e 100644 --- a/linux/drivers/media/video/bw-qcam.c +++ b/linux/drivers/media/video/bw-qcam.c @@ -993,7 +993,7 @@ static int accept_bwqcam(struct parport *port) if (parport[0] && strncmp(parport[0], "auto", 4) != 0) { /* user gave parport parameters */ - for(n=0; parport[n] && n<MAX_CAMS; n++){ + for (n = 0; n < MAX_CAMS && parport[n]; n++) { char *ep; unsigned long r; r = simple_strtoul(parport[n], &ep, 0); diff --git a/linux/drivers/media/video/cx88/cx88-cards.c b/linux/drivers/media/video/cx88/cx88-cards.c index bf0f26c03..19d57e698 100644 --- a/linux/drivers/media/video/cx88/cx88-cards.c +++ b/linux/drivers/media/video/cx88/cx88-cards.c @@ -1316,6 +1316,51 @@ static const struct cx88_board cx88_boards[] = { }, .mpeg = CX88_MPEG_DVB, }, + [CX88_BOARD_WINFAST_DTV2000H_J] = { + .name = "WinFast DTV2000 H rev. J", + .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x00017300, + .gpio1 = 0x00008207, + .gpio2 = 0x00000000, + .gpio3 = 0x02000000, + },{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x00018300, + .gpio1 = 0x0000f207, + .gpio2 = 0x00017304, + .gpio3 = 0x02000000, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x00018301, + .gpio1 = 0x0000f207, + .gpio2 = 0x00017304, + .gpio3 = 0x02000000, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x00018301, + .gpio1 = 0x0000f207, + .gpio2 = 0x00017304, + .gpio3 = 0x02000000, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x00015702, + .gpio1 = 0x0000f207, + .gpio2 = 0x00015702, + .gpio3 = 0x02000000, + }, + .mpeg = CX88_MPEG_DVB, + }, [CX88_BOARD_GENIATECH_DVBS] = { .name = "Geniatech DVB-S", .tuner_type = TUNER_ABSENT, @@ -2315,6 +2360,10 @@ static const struct cx88_subid cx88_subids[] = { .subdevice = 0x665e, .card = CX88_BOARD_WINFAST_DTV2000H, },{ + .subvendor = 0x107d, + .subdevice = 0x6f2b, + .card = CX88_BOARD_WINFAST_DTV2000H_J, + },{ .subvendor = 0x18ac, .subdevice = 0xd800, /* FusionHDTV 3 Gold (original revision) */ .card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q, @@ -3036,6 +3085,14 @@ void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl) case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: ctl->demod = XC3028_FE_OREN538; break; + case CX88_BOARD_GENIATECH_X8000_MT: + /* FIXME: For this board, the xc3028 never recovers after being + powered down (the reset GPIO probably is not set properly). + We don't have access to the hardware so we cannot determine + which GPIO is used for xc3028, so just disable power xc3028 + power management for now */ + ctl->disable_power_mgmt = 1; + break; case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME: case CX88_BOARD_PROLINK_PV_8000GT: diff --git a/linux/drivers/media/video/cx88/cx88-dvb.c b/linux/drivers/media/video/cx88/cx88-dvb.c index 36f35f0b5..ab84c085f 100644 --- a/linux/drivers/media/video/cx88/cx88-dvb.c +++ b/linux/drivers/media/video/cx88/cx88-dvb.c @@ -502,6 +502,7 @@ static struct zl10353_config cx88_pinnacle_hybrid_pctv = { static struct zl10353_config cx88_geniatech_x8000_mt = { .demod_address = (0x1e >> 1), .no_tuner = 1, + .disable_i2c_gate_ctrl = 1, #if 0 .input_frequency = 0xe609, .parallel_ts = 1, @@ -702,6 +703,7 @@ static int dvb_register(struct cx8802_dev *dev) } break; case CX88_BOARD_WINFAST_DTV2000H: + case CX88_BOARD_WINFAST_DTV2000H_J: case CX88_BOARD_HAUPPAUGE_HVR1100: case CX88_BOARD_HAUPPAUGE_HVR1100LP: case CX88_BOARD_HAUPPAUGE_HVR1300: diff --git a/linux/drivers/media/video/cx88/cx88-input.c b/linux/drivers/media/video/cx88/cx88-input.c index 7c5e94916..8d0042ab2 100644 --- a/linux/drivers/media/video/cx88/cx88-input.c +++ b/linux/drivers/media/video/cx88/cx88-input.c @@ -238,6 +238,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) ir->sampling = 1; break; case CX88_BOARD_WINFAST_DTV2000H: + case CX88_BOARD_WINFAST_DTV2000H_J: case CX88_BOARD_WINFAST_DTV1800H: ir_codes = ir_codes_winfast; ir->gpio_addr = MO_GP0_IO; diff --git a/linux/drivers/media/video/cx88/cx88.h b/linux/drivers/media/video/cx88/cx88.h index 59fc01a53..014004acd 100644 --- a/linux/drivers/media/video/cx88/cx88.h +++ b/linux/drivers/media/video/cx88/cx88.h @@ -238,6 +238,7 @@ extern struct sram_channel cx88_sram_channels[]; #define CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII 79 #define CX88_BOARD_HAUPPAUGE_IRONLY 80 #define CX88_BOARD_WINFAST_DTV1800H 81 +#define CX88_BOARD_WINFAST_DTV2000H_J 82 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index daa710b36..c936e7660 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -231,9 +231,10 @@ static struct em28xx_reg_seq silvercrest_reg_seq[] = { struct em28xx_board em28xx_boards[] = { [EM2750_BOARD_UNKNOWN] = { .name = "EM2710/EM2750/EM2751 webcam grabber", - .xclk = EM28XX_XCLK_FREQUENCY_48MHZ, + .xclk = EM28XX_XCLK_FREQUENCY_20MHZ, .tuner_type = TUNER_ABSENT, .is_webcam = 1, + .no_audio = 1, .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = 0, @@ -261,6 +262,7 @@ struct em28xx_board em28xx_boards[] = { .name = "Unknown EM2750/28xx video grabber", .tuner_type = TUNER_ABSENT, .is_webcam = 1, /* To enable sensor probe */ + .no_audio = 1, }, [EM2750_BOARD_DLCW_130] = { /* Beijing Huaqi Information Digital Technology Co., Ltd */ @@ -481,6 +483,7 @@ struct em28xx_board em28xx_boards[] = { .name = "Silvercrest Webcam 1.3mpix", .tuner_type = TUNER_ABSENT, .is_webcam = 1, + .no_audio = 1, .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = 0, @@ -1612,6 +1615,8 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2750_BOARD_UNKNOWN }, { USB_DEVICE(0xeb1a, 0x2800), .driver_info = EM2800_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2710), + .driver_info = EM2820_BOARD_UNKNOWN }, { USB_DEVICE(0xeb1a, 0x2820), .driver_info = EM2820_BOARD_UNKNOWN }, { USB_DEVICE(0xeb1a, 0x2821), @@ -1728,7 +1733,7 @@ static struct em28xx_hash_table em28xx_eeprom_hash[] = { {0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF}, {0x72cc5a8b, EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2, TUNER_YMEC_TVF_5533MF}, {0x966a0441, EM2880_BOARD_KWORLD_DVB_310U, TUNER_XC2028}, - {0x9567eb1a, EM2880_BOARD_EMPIRE_DUAL_TV, TUNER_XC2028}, + {0x166a0441, EM2880_BOARD_EMPIRE_DUAL_TV, TUNER_XC2028}, {0xcee44a99, EM2882_BOARD_EVGA_INDTUBE, TUNER_XC2028}, {0xb8846b20, EM2881_BOARD_PINNACLE_HYBRID_PRO, TUNER_XC2028}, }; @@ -1835,6 +1840,7 @@ static int em28xx_hint_sensor(struct em28xx *dev) __be16 version_be; u16 version; + /* Micron sensor detection */ dev->i2c_client.addr = 0xba >> 1; cmd = 0; i2c_master_send(&dev->i2c_client, &cmd, 1); @@ -1843,16 +1849,27 @@ static int em28xx_hint_sensor(struct em28xx *dev) return -EINVAL; version = be16_to_cpu(version_be); - switch (version) { case 0x8232: /* mt9v011 640x480 1.3 Mpix sensor */ case 0x8243: /* mt9v011 rev B 640x480 1.3 Mpix sensor */ dev->model = EM2820_BOARD_SILVERCREST_WEBCAM; + em28xx_set_model(dev); + sensor_name = "mt9v011"; dev->em28xx_sensor = EM28XX_MT9V011; dev->sensor_xres = 640; dev->sensor_yres = 480; - dev->sensor_xtal = 6300000; + /* + * FIXME: mt9v011 uses I2S speed as xtal clk - at least with + * the Silvercrest cam I have here for testing - for higher + * resolutions, a high clock cause horizontal artifacts, so we + * need to use a lower xclk frequency. + * Yet, it would be possible to adjust xclk depending on the + * desired resolution, since this affects directly the + * frame rate. + */ + dev->board.xclk = EM28XX_XCLK_FREQUENCY_4_3MHZ; + dev->sensor_xtal = 4300000; /* probably means GRGB 16 bit bayer */ dev->vinmode = 0x0d; @@ -1865,6 +1882,8 @@ static int em28xx_hint_sensor(struct em28xx *dev) #endif case 0x8431: dev->model = EM2750_BOARD_UNKNOWN; + em28xx_set_model(dev); + sensor_name = "mt9m001"; dev->em28xx_sensor = EM28XX_MT9M001; em28xx_initialize_mt9m001(dev); @@ -1881,6 +1900,9 @@ static int em28xx_hint_sensor(struct em28xx *dev) return -EINVAL; } + /* Setup webcam defaults */ + em28xx_pre_card_setup(dev); + em28xx_errdev("Sensor is %s, using model %s entry.\n", sensor_name, em28xx_boards[dev->model].name); @@ -1892,60 +1914,6 @@ static int em28xx_hint_sensor(struct em28xx *dev) */ void em28xx_pre_card_setup(struct em28xx *dev) { - int rc; - - em28xx_set_model(dev); - - em28xx_info("Identified as %s (card=%d)\n", - dev->board.name, dev->model); - - /* 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 (dev->chip_id) { - case CHIP_ID_EM2750: - em28xx_info("chip ID is em2750\n"); - break; - case CHIP_ID_EM2820: - em28xx_info("chip ID is em2710 or em2820\n"); - break; - case CHIP_ID_EM2840: - em28xx_info("chip ID is em2840\n"); - break; - case CHIP_ID_EM2860: - em28xx_info("chip ID is em2860\n"); - break; - case CHIP_ID_EM2870: - em28xx_info("chip ID is em2870\n"); - dev->wait_after_write = 0; - 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; - break; - default: - em28xx_info("em28xx chip ID = %d\n", dev->chip_id); - } - } - - /* Prepopulate cached GPO register content */ - rc = em28xx_read_reg(dev, dev->reg_gpo_num); - if (rc >= 0) - dev->reg_gpo = rc; - /* Set the initial XCLK and I2C clock values based on the board definition */ em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk & 0x7f); @@ -2328,7 +2296,20 @@ void em28xx_register_i2c_ir(struct em28xx *dev) void em28xx_card_setup(struct em28xx *dev) { - em28xx_set_model(dev); + /* + * If the device can be a webcam, seek for a sensor. + * If sensor is not found, then it isn't a webcam. + */ + if (dev->board.is_webcam) { + if (em28xx_hint_sensor(dev) < 0) + dev->board.is_webcam = 0; + else + dev->progressive = 1; + } else + em28xx_set_model(dev); + + em28xx_info("Identified as %s (card=%d)\n", + dev->board.name, dev->model); dev->tuner_type = em28xx_boards[dev->model].tuner_type; if (em28xx_boards[dev->model].tuner_addr) @@ -2402,10 +2383,6 @@ void em28xx_card_setup(struct em28xx *dev) em28xx_gpio_set(dev, dev->board.tuner_gpio); em28xx_set_mode(dev, EM28XX_ANALOG_MODE); break; - case EM2820_BOARD_SILVERCREST_WEBCAM: - /* FIXME: need to document the registers bellow */ - em28xx_write_reg(dev, 0x0d, 0x42); - em28xx_write_reg(dev, 0x13, 0x08); } if (dev->board.has_snapshot_button) @@ -2562,7 +2539,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, int minor) { struct em28xx *dev = *devhandle; - int retval = -ENOMEM; + int retval; int errCode; dev->udev = udev; @@ -2579,6 +2556,58 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, dev->em28xx_read_reg_req = em28xx_read_reg_req; dev->board.is_em2800 = em28xx_boards[dev->model].is_em2800; + em28xx_set_model(dev); + + /* 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 */ + retval = em28xx_read_reg(dev, EM28XX_R0A_CHIPID); + if (retval > 0) { + dev->chip_id = retval; + + switch (dev->chip_id) { + case CHIP_ID_EM2710: + em28xx_info("chip ID is em2710\n"); + break; + case CHIP_ID_EM2750: + em28xx_info("chip ID is em2750\n"); + break; + case CHIP_ID_EM2820: + em28xx_info("chip ID is em2820 (or em2710)\n"); + break; + case CHIP_ID_EM2840: + em28xx_info("chip ID is em2840\n"); + break; + case CHIP_ID_EM2860: + em28xx_info("chip ID is em2860\n"); + break; + case CHIP_ID_EM2870: + em28xx_info("chip ID is em2870\n"); + dev->wait_after_write = 0; + 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; + break; + default: + em28xx_info("em28xx chip ID = %d\n", dev->chip_id); + } + } + + /* Prepopulate cached GPO register content */ + retval = em28xx_read_reg(dev, dev->reg_gpo_num); + if (retval >= 0) + dev->reg_gpo = retval; + em28xx_pre_card_setup(dev); if (!dev->board.is_em2800) { @@ -2613,14 +2642,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, dev->vinmode = 0x10; dev->vinctl = 0x11; - /* - * If the device can be a webcam, seek for a sensor. - * If sensor is not found, then it isn't a webcam. - */ - if (dev->board.is_webcam) - if (em28xx_hint_sensor(dev) < 0) - dev->board.is_webcam = 0; - /* Do board specific init and eeprom reading */ em28xx_card_setup(dev); diff --git a/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c index f24af40df..46cb13182 100644 --- a/linux/drivers/media/video/em28xx/em28xx-core.c +++ b/linux/drivers/media/video/em28xx/em28xx-core.c @@ -494,7 +494,7 @@ int em28xx_audio_setup(struct em28xx *dev) /* If device doesn't support Usb Audio Class, use vendor class */ if (!dev->has_audio_class) - dev->has_alsa_audio = 1; + dev->has_alsa_audio = ~dev->board.no_audio; dev->audio_mode.has_audio = 1; @@ -632,6 +632,9 @@ int em28xx_capture_start(struct em28xx *dev, int start) return rc; } + if (dev->board.is_webcam) + rc = em28xx_write_reg(dev, 0x13, 0x0c); + /* enable video capture */ rc = em28xx_write_reg(dev, 0x48, 0x00); @@ -720,7 +723,10 @@ int em28xx_resolution_set(struct em28xx *dev) { int width, height; width = norm_maxw(dev); - height = norm_maxh(dev) >> 1; + height = norm_maxh(dev); + + if (!dev->progressive) + height >>= norm_maxh(dev); em28xx_set_outfmt(dev); diff --git a/linux/drivers/media/video/em28xx/em28xx-dvb.c b/linux/drivers/media/video/em28xx/em28xx-dvb.c index e32267383..3d522d547 100644 --- a/linux/drivers/media/video/em28xx/em28xx-dvb.c +++ b/linux/drivers/media/video/em28xx/em28xx-dvb.c @@ -479,7 +479,6 @@ static int dvb_init(struct em28xx *dev) } break; case EM2880_BOARD_KWORLD_DVB_310U: - case EM2880_BOARD_EMPIRE_DUAL_TV: dvb->frontend = dvb_attach(zl10353_attach, &em28xx_zl10353_with_xc3028, &dev->i2c_adap); @@ -489,6 +488,7 @@ static int dvb_init(struct em28xx *dev) } break; case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: + case EM2880_BOARD_EMPIRE_DUAL_TV: dvb->frontend = dvb_attach(zl10353_attach, &em28xx_zl10353_xc3028_no_i2c_gate, &dev->i2c_adap); diff --git a/linux/drivers/media/video/em28xx/em28xx-reg.h b/linux/drivers/media/video/em28xx/em28xx-reg.h index a2676d63c..6bf84bd78 100644 --- a/linux/drivers/media/video/em28xx/em28xx-reg.h +++ b/linux/drivers/media/video/em28xx/em28xx-reg.h @@ -176,7 +176,8 @@ /* FIXME: Need to be populated with the other chip ID's */ enum em28xx_chip_id { - CHIP_ID_EM2820 = 18, /* Also used by em2710 */ + CHIP_ID_EM2710 = 17, + CHIP_ID_EM2820 = 18, /* Also used by some em2710 */ CHIP_ID_EM2840 = 20, CHIP_ID_EM2750 = 33, CHIP_ID_EM2860 = 34, diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c index fcb99fb71..c7d723a03 100644 --- a/linux/drivers/media/video/em28xx/em28xx-video.c +++ b/linux/drivers/media/video/em28xx/em28xx-video.c @@ -212,15 +212,24 @@ static void em28xx_copy_video(struct em28xx *dev, startread = p; remain = len; - /* Interlaces frame */ - if (buf->top_field) + if (dev->progressive) fieldstart = outp; - else - fieldstart = outp + bytesperline; + else { + /* Interlaces two half frames */ + if (buf->top_field) + fieldstart = outp; + else + fieldstart = outp + bytesperline; + } linesdone = dma_q->pos / bytesperline; currlinedone = dma_q->pos % bytesperline; - offset = linesdone * bytesperline * 2 + currlinedone; + + if (dev->progressive) + offset = linesdone * bytesperline + currlinedone; + else + offset = linesdone * bytesperline * 2 + currlinedone; + startwrite = fieldstart + offset; lencopy = bytesperline - currlinedone; lencopy = lencopy > remain ? remain : lencopy; @@ -398,7 +407,7 @@ static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb) em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2], len, (p[2] & 1) ? "odd" : "even"); - if (!(p[2] & 1)) { + if (dev->progressive || !(p[2] & 1)) { if (buf != NULL) buffer_filled(dev, dma_q, buf); get_next_buf(dma_q, &buf); @@ -742,7 +751,10 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */ - f->fmt.pix.field = dev->interlaced ? + if (dev->progressive) + f->fmt.pix.field = V4L2_FIELD_NONE; + else + f->fmt.pix.field = dev->interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; mutex_unlock(&dev->lock); @@ -806,7 +818,11 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.bytesperline = (dev->width * fmt->depth + 7) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - f->fmt.pix.field = V4L2_FIELD_INTERLACED; + if (dev->progressive) + f->fmt.pix.field = V4L2_FIELD_NONE; + else + f->fmt.pix.field = dev->interlaced ? + V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; return 0; } @@ -899,6 +915,41 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) return 0; } +static int vidioc_g_parm(struct file *file, void *priv, + struct v4l2_streamparm *p) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc = 0; + + if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (dev->board.is_webcam) + rc = v4l2_device_call_until_err(&dev->v4l2_dev, 0, + video, g_parm, p); + else + v4l2_video_std_frame_period(dev->norm, + &p->parm.capture.timeperframe); + + return rc; +} + +static int vidioc_s_parm(struct file *file, void *priv, + struct v4l2_streamparm *p) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + + if (!dev->board.is_webcam) + return -EINVAL; + + if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + return v4l2_device_call_until_err(&dev->v4l2_dev, 0, video, s_parm, p); +} + static const char *iname[] = { [EM28XX_VMUX_COMPOSITE1] = "Composite1", [EM28XX_VMUX_COMPOSITE2] = "Composite2", @@ -976,6 +1027,9 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; + if (!dev->audio_mode.has_audio) + return -EINVAL; + switch (a->index) { case EM28XX_AMUX_VIDEO: strcpy(a->name, "Television"); @@ -1022,6 +1076,9 @@ static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) return -EINVAL; #else + if (!dev->audio_mode.has_audio) + return -EINVAL; + if (a->index >= MAX_EM28XX_INPUT) return -EINVAL; if (0 == INPUT(a->index)->type) @@ -1285,8 +1342,9 @@ static int vidioc_g_register(struct file *file, void *priv, v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg); return 0; case V4L2_CHIP_MATCH_I2C_ADDR: - /* Not supported yet */ - return -EINVAL; + /* TODO: is this correct? */ + v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg); + return 0; default: if (!v4l2_chip_match_host(®->match)) return -EINVAL; @@ -1337,8 +1395,9 @@ static int vidioc_s_register(struct file *file, void *priv, v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg); return 0; case V4L2_CHIP_MATCH_I2C_ADDR: - /* Not supported yet */ - return -EINVAL; + /* TODO: is this correct? */ + v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg); + return 0; default: if (!v4l2_chip_match_host(®->match)) return -EINVAL; @@ -1444,9 +1503,11 @@ static int vidioc_querycap(struct file *file, void *priv, #endif V4L2_CAP_SLICED_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + if (dev->audio_mode.has_audio) + cap->capabilities |= V4L2_CAP_AUDIO; + if (dev->tuner_type != TUNER_ABSENT) cap->capabilities |= V4L2_CAP_TUNER; @@ -1722,6 +1783,7 @@ static int em28xx_v4l2_open(struct file *filp) struct em28xx *dev; enum v4l2_buf_type fh_type; struct em28xx_fh *fh; + enum v4l2_field field; dev = em28xx_get_device(minor, &fh_type, &radio); @@ -1778,8 +1840,13 @@ static int em28xx_v4l2_open(struct file *filp) dev->users++; + if (dev->progressive) + field = V4L2_FIELD_NONE; + else + field = V4L2_FIELD_INTERLACED; + videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops, - NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED, + NULL, &dev->slock, fh->type, field, sizeof(struct em28xx_buffer), fh); mutex_unlock(&dev->lock); @@ -2003,6 +2070,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_qbuf = vidioc_qbuf, .vidioc_dqbuf = vidioc_dqbuf, .vidioc_s_std = vidioc_s_std, + .vidioc_g_parm = vidioc_g_parm, + .vidioc_s_parm = vidioc_s_parm, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h index df7fe9af7..c76da6985 100644 --- a/linux/drivers/media/video/em28xx/em28xx.h +++ b/linux/drivers/media/video/em28xx/em28xx.h @@ -397,6 +397,7 @@ struct em28xx_board { unsigned int has_dvb:1; unsigned int has_snapshot_button:1; unsigned int is_webcam:1; + unsigned int no_audio:1; unsigned int valid:1; unsigned char xclk, i2c_speed; @@ -493,6 +494,9 @@ struct em28xx { int sensor_xres, sensor_yres; int sensor_xtal; + /* Allows progressive (e. g. non-interlaced) mode */ + int progressive; + /* Vinmode/Vinctl used at the driver */ int vinmode, vinctl; diff --git a/linux/drivers/media/video/gspca/gspca.c b/linux/drivers/media/video/gspca/gspca.c index 2e5197073..670091e42 100644 --- a/linux/drivers/media/video/gspca/gspca.c +++ b/linux/drivers/media/video/gspca/gspca.c @@ -1504,12 +1504,6 @@ static int vidioc_s_parm(struct file *filp, void *priv, return 0; } -static int vidioc_s_std(struct file *filp, void *priv, - v4l2_std_id *parm) -{ - return 0; -} - #ifdef CONFIG_VIDEO_V4L1_COMPAT static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) @@ -1980,7 +1974,6 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = { .vidioc_s_jpegcomp = vidioc_s_jpegcomp, .vidioc_g_parm = vidioc_g_parm, .vidioc_s_parm = vidioc_s_parm, - .vidioc_s_std = vidioc_s_std, .vidioc_enum_framesizes = vidioc_enum_framesizes, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = vidioc_g_register, diff --git a/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c b/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c index 7127321ac..6b89f33a4 100644 --- a/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c +++ b/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c @@ -178,8 +178,10 @@ sensor_found: sens_priv->settings = kmalloc(sizeof(s32)*ARRAY_SIZE(s5k83a_ctrls), GFP_KERNEL); - if (!sens_priv->settings) + if (!sens_priv->settings) { + kfree(sens_priv); return -ENOMEM; + } sd->gspca_dev.cam.cam_mode = s5k83a_modes; sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k83a_modes); diff --git a/linux/drivers/media/video/gspca/vc032x.c b/linux/drivers/media/video/gspca/vc032x.c index 44dea7949..6f9aab89c 100644 --- a/linux/drivers/media/video/gspca/vc032x.c +++ b/linux/drivers/media/video/gspca/vc032x.c @@ -3135,10 +3135,10 @@ static void sethvflip(struct gspca_dev *gspca_dev) hflip = sd->hflip; if (sd->flags & FL_HFLIP) - hflip != hflip; + hflip = !hflip; vflip = sd->vflip; if (sd->flags & FL_VFLIP) - vflip != vflip; + vflip = !vflip; switch (sd->sensor) { case SENSOR_MI1310_SOC: case SENSOR_MI1320_SOC: diff --git a/linux/drivers/media/video/hdpvr/hdpvr-video.c b/linux/drivers/media/video/hdpvr/hdpvr-video.c index 5937de23c..2eb9dc2eb 100644 --- a/linux/drivers/media/video/hdpvr/hdpvr-video.c +++ b/linux/drivers/media/video/hdpvr/hdpvr-video.c @@ -1222,6 +1222,8 @@ static const struct video_device hdpvr_video_template = { V4L2_STD_PAL_G | V4L2_STD_PAL_H | V4L2_STD_PAL_I | V4L2_STD_PAL_D | V4L2_STD_PAL_M | V4L2_STD_PAL_N | V4L2_STD_PAL_60, + .current_norm = V4L2_STD_NTSC | V4L2_STD_PAL_M | + V4L2_STD_PAL_60, }; int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent, diff --git a/linux/drivers/media/video/mt9v011.c b/linux/drivers/media/video/mt9v011.c index c9706b889..70d359d84 100644 --- a/linux/drivers/media/video/mt9v011.c +++ b/linux/drivers/media/video/mt9v011.c @@ -62,13 +62,34 @@ static struct v4l2_queryctrl mt9v011_qctrl[] = { .step = 1, .default_value = 0, .flags = 0, - }, + }, { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Vflip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, { + } }; struct mt9v011 { struct v4l2_subdev sd; unsigned width, height; unsigned xtal; + unsigned hflip:1; + unsigned vflip:1; u16 global_gain, red_bal, blue_bal; }; @@ -141,7 +162,6 @@ static const struct i2c_reg_value mt9v011_init_default[] = { { R0A_MT9V011_CLK_SPEED, 0x0000 }, { R1E_MT9V011_DIGITAL_ZOOM, 0x0000 }, - { R20_MT9V011_READ_MODE, 0x1000 }, { R07_MT9V011_OUT_CTRL, 0x0002 }, /* chip enable */ }; @@ -166,7 +186,7 @@ static void set_balance(struct v4l2_subdev *sd) mt9v011_write(sd, R2D_MT9V011_RED_GAIN, red_gain); } -static void calc_fps(struct v4l2_subdev *sd) +static void calc_fps(struct v4l2_subdev *sd, u32 *numerator, u32 *denominator) { struct mt9v011 *core = to_mt9v011(sd); unsigned height, width, hblank, vblank, speed; @@ -189,6 +209,51 @@ static void calc_fps(struct v4l2_subdev *sd) v4l2_dbg(1, debug, sd, "Programmed to %u.%03u fps (%d pixel clcks)\n", tmp / 1000, tmp % 1000, t_time); + + if (numerator && denominator) { + *numerator = 1000; + *denominator = (u32)frames_per_ms; + } +} + +static u16 calc_speed(struct v4l2_subdev *sd, u32 numerator, u32 denominator) +{ + struct mt9v011 *core = to_mt9v011(sd); + unsigned height, width, hblank, vblank; + unsigned row_time, line_time; + u64 t_time, speed; + + /* Avoid bogus calculus */ + if (!numerator || !denominator) + return 0; + + height = mt9v011_read(sd, R03_MT9V011_HEIGHT); + width = mt9v011_read(sd, R04_MT9V011_WIDTH); + hblank = mt9v011_read(sd, R05_MT9V011_HBLANK); + vblank = mt9v011_read(sd, R06_MT9V011_VBLANK); + + row_time = width + 113 + hblank; + line_time = height + vblank + 1; + + t_time = core->xtal * ((u64)numerator); + /* round to the closest value */ + t_time += denominator / 2; + do_div(t_time, denominator); + + speed = t_time; + do_div(speed, row_time * line_time); + + /* Avoid having a negative value for speed */ + if (speed < 2) + speed = 0; + else + speed -= 2; + + /* Avoid speed overflow */ + if (speed > 15) + return 15; + + return (u16)speed; } static void set_res(struct v4l2_subdev *sd) @@ -217,9 +282,23 @@ static void set_res(struct v4l2_subdev *sd) mt9v011_write(sd, R03_MT9V011_HEIGHT, core->height); mt9v011_write(sd, R06_MT9V011_VBLANK, 508 - core->height); - calc_fps(sd); + calc_fps(sd, NULL, NULL); }; +static void set_read_mode(struct v4l2_subdev *sd) +{ + struct mt9v011 *core = to_mt9v011(sd); + unsigned mode = 0x1000; + + if (core->hflip) + mode |= 0x4000; + + if (core->vflip) + mode |= 0x8000; + + mt9v011_write(sd, R20_MT9V011_READ_MODE, mode); +} + static int mt9v011_reset(struct v4l2_subdev *sd, u32 val) { int i; @@ -230,6 +309,7 @@ static int mt9v011_reset(struct v4l2_subdev *sd, u32 val) set_balance(sd); set_res(sd); + set_read_mode(sd); return 0; }; @@ -250,6 +330,12 @@ static int mt9v011_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) case V4L2_CID_BLUE_BALANCE: ctrl->value = core->blue_bal; return 0; + case V4L2_CID_HFLIP: + ctrl->value = core->hflip ? 1 : 0; + return 0; + case V4L2_CID_VFLIP: + ctrl->value = core->vflip ? 1 : 0; + return 0; } return -EINVAL; } @@ -298,6 +384,14 @@ static int mt9v011_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) case V4L2_CID_BLUE_BALANCE: core->blue_bal = ctrl->value; break; + case V4L2_CID_HFLIP: + core->hflip = ctrl->value; + set_read_mode(sd); + return 0; + case V4L2_CID_VFLIP: + core->vflip = ctrl->value; + set_read_mode(sd); + return 0; default: return -EINVAL; } @@ -332,6 +426,44 @@ static int mt9v011_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) return 0; } +static int mt9v011_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +{ + struct v4l2_captureparm *cp = &parms->parm.capture; + + if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + memset(cp, 0, sizeof(struct v4l2_captureparm)); + cp->capability = V4L2_CAP_TIMEPERFRAME; + calc_fps(sd, + &cp->timeperframe.numerator, + &cp->timeperframe.denominator); + + return 0; +} + +static int mt9v011_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +{ + struct v4l2_captureparm *cp = &parms->parm.capture; + struct v4l2_fract *tpf = &cp->timeperframe; + u16 speed; + + if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (cp->extendedmode != 0) + return -EINVAL; + + speed = calc_speed(sd, tpf->numerator, tpf->denominator); + + mt9v011_write(sd, R0A_MT9V011_CLK_SPEED, speed); + v4l2_dbg(1, debug, sd, "Setting speed to %d\n", speed); + + /* Recalculate and update fps info */ + calc_fps(sd, &tpf->numerator, &tpf->denominator); + + return 0; +} + static int mt9v011_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) { struct v4l2_pix_format *pix = &fmt->fmt.pix; @@ -429,6 +561,8 @@ static const struct v4l2_subdev_video_ops mt9v011_video_ops = { .enum_fmt = mt9v011_enum_fmt, .try_fmt = mt9v011_try_fmt, .s_fmt = mt9v011_s_fmt, + .g_parm = mt9v011_g_parm, + .s_parm = mt9v011_s_parm, }; static const struct v4l2_subdev_ops mt9v011_ops = { diff --git a/linux/drivers/media/video/mx1_camera.c b/linux/drivers/media/video/mx1_camera.c index 2d075205b..736c31d23 100644 --- a/linux/drivers/media/video/mx1_camera.c +++ b/linux/drivers/media/video/mx1_camera.c @@ -234,6 +234,7 @@ static int mx1_camera_setup_dma(struct mx1_camera_dev *pcdev) return ret; } +/* Called under spinlock_irqsave(&pcdev->lock, ...) */ static void mx1_videobuf_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) { @@ -241,13 +242,10 @@ static void mx1_videobuf_queue(struct videobuf_queue *vq, struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct mx1_camera_dev *pcdev = ici->priv; struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb); - unsigned long flags; dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, vb->baddr, vb->bsize); - spin_lock_irqsave(&pcdev->lock, flags); - list_add_tail(&vb->queue, &pcdev->capture); vb->state = VIDEOBUF_ACTIVE; @@ -264,8 +262,6 @@ static void mx1_videobuf_queue(struct videobuf_queue *vq, __raw_writel(temp, pcdev->base + CSICR1); } } - - spin_unlock_irqrestore(&pcdev->lock, flags); } static void mx1_videobuf_release(struct videobuf_queue *vq, diff --git a/linux/drivers/media/video/mx3_camera.c b/linux/drivers/media/video/mx3_camera.c index e605c076e..9770cb793 100644 --- a/linux/drivers/media/video/mx3_camera.c +++ b/linux/drivers/media/video/mx3_camera.c @@ -332,7 +332,10 @@ static enum pixel_fmt fourcc_to_ipu_pix(__u32 fourcc) } } -/* Called with .vb_lock held */ +/* + * Called with .vb_lock mutex held and + * under spinlock_irqsave(&mx3_cam->lock, ...) + */ static void mx3_videobuf_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) { @@ -346,7 +349,8 @@ static void mx3_videobuf_queue(struct videobuf_queue *vq, struct idmac_video_param *video = &ichan->params.video; const struct soc_camera_data_format *data_fmt = icd->current_fmt; dma_cookie_t cookie; - unsigned long flags; + + BUG_ON(!irqs_disabled()); /* This is the configuration of one sg-element */ video->out_pixel_fmt = fourcc_to_ipu_pix(data_fmt->fourcc); @@ -359,8 +363,6 @@ static void mx3_videobuf_queue(struct videobuf_queue *vq, memset((void *)vb->baddr, 0xaa, vb->bsize); #endif - spin_lock_irqsave(&mx3_cam->lock, flags); - list_add_tail(&vb->queue, &mx3_cam->capture); if (!mx3_cam->active) { @@ -370,24 +372,23 @@ static void mx3_videobuf_queue(struct videobuf_queue *vq, vb->state = VIDEOBUF_QUEUED; } - spin_unlock_irqrestore(&mx3_cam->lock, flags); + spin_unlock_irq(&mx3_cam->lock); cookie = txd->tx_submit(txd); dev_dbg(&icd->dev, "Submitted cookie %d DMA 0x%08x\n", cookie, sg_dma_address(&buf->sg)); + + spin_lock_irq(&mx3_cam->lock); + if (cookie >= 0) return; /* Submit error */ vb->state = VIDEOBUF_PREPARED; - spin_lock_irqsave(&mx3_cam->lock, flags); - list_del_init(&vb->queue); if (mx3_cam->active == buf) mx3_cam->active = NULL; - - spin_unlock_irqrestore(&mx3_cam->lock, flags); } /* Called with .vb_lock held */ diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c b/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c index 42875ec21..d8c9e6632 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c @@ -66,9 +66,10 @@ void pvr2_msp3400_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) u32 input; pvr2_trace(PVR2_TRACE_CHIPS, "subdev msp3400 v4l2 set_stereo"); + sp = (sid < ARRAY_SIZE(routing_schemes)) ? + routing_schemes[sid] : NULL; - if ((sid < ARRAY_SIZE(routing_schemes)) && - ((sp = routing_schemes[sid]) != NULL) && + if ((sp != NULL) && (hdw->input_val >= 0) && (hdw->input_val < sp->cnt)) { input = sp->def[hdw->input_val]; diff --git a/linux/drivers/media/video/pwc/pwc-v4l.c b/linux/drivers/media/video/pwc/pwc-v4l.c index 2876ce084..bdb4ced57 100644 --- a/linux/drivers/media/video/pwc/pwc-v4l.c +++ b/linux/drivers/media/video/pwc/pwc-v4l.c @@ -1033,7 +1033,7 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (std->index != 0) return -EINVAL; std->id = V4L2_STD_UNKNOWN; - strncpy(std->name, "webcam", sizeof(std->name)); + strlcpy(std->name, "webcam", sizeof(std->name)); return 0; } diff --git a/linux/drivers/media/video/pxa_camera.c b/linux/drivers/media/video/pxa_camera.c index 3f1b63e4e..92fb8b191 100644 --- a/linux/drivers/media/video/pxa_camera.c +++ b/linux/drivers/media/video/pxa_camera.c @@ -624,6 +624,7 @@ static void pxa_camera_stop_capture(struct pxa_camera_dev *pcdev) dev_dbg(pcdev->soc_host.dev, "%s\n", __func__); } +/* Called under spinlock_irqsave(&pcdev->lock, ...) */ static void pxa_videobuf_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) { @@ -631,13 +632,10 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq, struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct pxa_camera_dev *pcdev = ici->priv; struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); - unsigned long flags; dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d active=%p\n", __func__, vb, vb->baddr, vb->bsize, pcdev->active); - spin_lock_irqsave(&pcdev->lock, flags); - list_add_tail(&vb->queue, &pcdev->capture); vb->state = VIDEOBUF_ACTIVE; @@ -645,8 +643,6 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq, if (!pcdev->active) pxa_camera_start_capture(pcdev); - - spin_unlock_irqrestore(&pcdev->lock, flags); } static void pxa_videobuf_release(struct videobuf_queue *vq, diff --git a/linux/drivers/media/video/saa7134/saa7134-cards.c b/linux/drivers/media/video/saa7134/saa7134-cards.c index e2d98ff5c..3ab7732e6 100644 --- a/linux/drivers/media/video/saa7134/saa7134-cards.c +++ b/linux/drivers/media/video/saa7134/saa7134-cards.c @@ -1633,7 +1633,7 @@ struct saa7134_board saa7134_boards[] = { }}, .radio = { .name = name_radio, - .amux = LINE1, + .amux = TV, .gpio = 0x00300001, }, .mute = { @@ -3370,8 +3370,8 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x0200100, }, }, - [SAA7134_BOARD_HAUPPAUGE_HVR1120] = { - .name = "Hauppauge WinTV-HVR1120 ATSC/QAM-Hybrid", + [SAA7134_BOARD_HAUPPAUGE_HVR1150] = { + .name = "Hauppauge WinTV-HVR1150 ATSC/QAM-Hybrid", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_TDA8290, .radio_type = UNSET, @@ -3402,8 +3402,8 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x0800100, /* GPIO 23 HI for FM */ }, }, - [SAA7134_BOARD_HAUPPAUGE_HVR1110R3] = { - .name = "Hauppauge WinTV-HVR1110r3 DVB-T/Hybrid", + [SAA7134_BOARD_HAUPPAUGE_HVR1120] = { + .name = "Hauppauge WinTV-HVR1120 DVB-T/Hybrid", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_TDA8290, .radio_type = UNSET, @@ -4900,7 +4900,7 @@ struct saa7134_board saa7134_boards[] = { /* Igor Kuznetsov <igk@igk.ru> */ .name = "Beholder BeholdTV H6", .audio_clock = 0x00187de7, - .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, + .tuner_type = TUNER_PHILIPS_FMD1216MEX_MK3, .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, @@ -5901,31 +5901,31 @@ struct pci_device_id saa7134_pci_tbl[] = { .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x0070, .subdevice = 0x6706, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1150, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x0070, .subdevice = 0x6707, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110R3, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x0070, .subdevice = 0x6708, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1150, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x0070, .subdevice = 0x6709, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110R3, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x0070, .subdevice = 0x670a, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110R3, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, @@ -6458,8 +6458,8 @@ static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev, switch (command) { case TDA18271_CALLBACK_CMD_AGC_ENABLE: /* 0 */ switch (dev->board) { + case SAA7134_BOARD_HAUPPAUGE_HVR1150: case SAA7134_BOARD_HAUPPAUGE_HVR1120: - case SAA7134_BOARD_HAUPPAUGE_HVR1110R3: ret = saa7134_tda18271_hvr11x0_toggle_agc(dev, arg); break; default: @@ -6479,8 +6479,8 @@ static int saa7134_tda8290_callback(struct saa7134_dev *dev, int ret; switch (dev->board) { + case SAA7134_BOARD_HAUPPAUGE_HVR1150: case SAA7134_BOARD_HAUPPAUGE_HVR1120: - case SAA7134_BOARD_HAUPPAUGE_HVR1110R3: /* tda8290 + tda18271 */ ret = saa7134_tda8290_18271_callback(dev, command, arg); break; @@ -6526,7 +6526,7 @@ static void hauppauge_eeprom(struct saa7134_dev *dev, u8 *eeprom_data) switch (tv.model) { case 67019: /* WinTV-HVR1110 (Retail, IR Blaster, hybrid, FM, SVid/Comp, 3.5mm audio in) */ case 67109: /* WinTV-HVR1000 (Retail, IR Receive, analog, no FM, SVid/Comp, 3.5mm audio in) */ - case 67201: /* WinTV-HVR1120 (Retail, IR Receive, hybrid, FM, SVid/Comp, 3.5mm audio in) */ + case 67201: /* WinTV-HVR1150 (Retail, IR Receive, hybrid, FM, SVid/Comp, 3.5mm audio in) */ case 67301: /* WinTV-HVR1000 (Retail, IR Receive, analog, no FM, SVid/Comp, 3.5mm audio in) */ case 67209: /* WinTV-HVR1110 (Retail, IR Receive, hybrid, FM, SVid/Comp, 3.5mm audio in) */ case 67559: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */ @@ -6534,7 +6534,7 @@ static void hauppauge_eeprom(struct saa7134_dev *dev, u8 *eeprom_data) case 67579: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM) */ case 67589: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */ case 67599: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */ - case 67651: /* WinTV-HVR1120 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */ + case 67651: /* WinTV-HVR1150 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */ case 67659: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */ break; default: @@ -6728,8 +6728,8 @@ int saa7134_board_init1(struct saa7134_dev *dev) saa_writeb (SAA7134_PRODUCTION_TEST_MODE, 0x00); break; + case SAA7134_BOARD_HAUPPAUGE_HVR1150: case SAA7134_BOARD_HAUPPAUGE_HVR1120: - case SAA7134_BOARD_HAUPPAUGE_HVR1110R3: /* GPIO 26 high for digital, low for analog */ saa7134_set_gpio(dev, 26, 0); msleep(1); @@ -6994,8 +6994,8 @@ int saa7134_board_init2(struct saa7134_dev *dev) dev->name, saa7134_boards[dev->board].name); } break; + case SAA7134_BOARD_HAUPPAUGE_HVR1150: case SAA7134_BOARD_HAUPPAUGE_HVR1120: - case SAA7134_BOARD_HAUPPAUGE_HVR1110R3: hauppauge_eeprom(dev, dev->eedata+0x80); break; case SAA7134_BOARD_HAUPPAUGE_HVR1110: diff --git a/linux/drivers/media/video/saa7134/saa7134-dvb.c b/linux/drivers/media/video/saa7134/saa7134-dvb.c index 360fbdf19..afd9b7e5c 100644 --- a/linux/drivers/media/video/saa7134/saa7134-dvb.c +++ b/linux/drivers/media/video/saa7134/saa7134-dvb.c @@ -1119,7 +1119,7 @@ static int dvb_init(struct saa7134_dev *dev) &tda827x_cfg_2) < 0) goto dettach_frontend; break; - case SAA7134_BOARD_HAUPPAUGE_HVR1110R3: + case SAA7134_BOARD_HAUPPAUGE_HVR1120: fe0->dvb.frontend = dvb_attach(tda10048_attach, &hcw_tda10048_config, &dev->i2c_adap); @@ -1147,7 +1147,7 @@ static int dvb_init(struct saa7134_dev *dev) &tda827x_cfg_1) < 0) goto dettach_frontend; break; - case SAA7134_BOARD_HAUPPAUGE_HVR1120: + case SAA7134_BOARD_HAUPPAUGE_HVR1150: fe0->dvb.frontend = dvb_attach(lgdt3305_attach, &hcw_lgdt3305_config, &dev->i2c_adap); @@ -1461,7 +1461,7 @@ static int dvb_init(struct saa7134_dev *dev) if (fe0->dvb.frontend) { dvb_attach(simple_tuner_attach, fe0->dvb.frontend, &dev->i2c_adap, 0x61, - TUNER_PHILIPS_FMD1216ME_MK3); + TUNER_PHILIPS_FMD1216MEX_MK3); } break; case SAA7134_BOARD_AVERMEDIA_A700_PRO: diff --git a/linux/drivers/media/video/saa7134/saa7134.h b/linux/drivers/media/video/saa7134/saa7134.h index be5abf059..6b0742ad7 100644 --- a/linux/drivers/media/video/saa7134/saa7134.h +++ b/linux/drivers/media/video/saa7134/saa7134.h @@ -279,8 +279,8 @@ struct saa7134_format { #define SAA7134_BOARD_ASUSTeK_TIGER 152 #define SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG 153 #define SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS 154 -#define SAA7134_BOARD_HAUPPAUGE_HVR1120 155 -#define SAA7134_BOARD_HAUPPAUGE_HVR1110R3 156 +#define SAA7134_BOARD_HAUPPAUGE_HVR1150 155 +#define SAA7134_BOARD_HAUPPAUGE_HVR1120 156 #define SAA7134_BOARD_AVERMEDIA_STUDIO_507UA 157 #define SAA7134_BOARD_AVERMEDIA_CARDBUS_501 158 #define SAA7134_BOARD_BEHOLD_505RDS 159 diff --git a/linux/drivers/media/video/sh_mobile_ceu_camera.c b/linux/drivers/media/video/sh_mobile_ceu_camera.c index 7ea2a0edf..1bae28a98 100644 --- a/linux/drivers/media/video/sh_mobile_ceu_camera.c +++ b/linux/drivers/media/video/sh_mobile_ceu_camera.c @@ -283,27 +283,24 @@ out: return ret; } +/* Called under spinlock_irqsave(&pcdev->lock, ...) */ static void sh_mobile_ceu_videobuf_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) { struct soc_camera_device *icd = vq->priv_data; struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct sh_mobile_ceu_dev *pcdev = ici->priv; - unsigned long flags; dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__, vb, vb->baddr, vb->bsize); vb->state = VIDEOBUF_QUEUED; - spin_lock_irqsave(&pcdev->lock, flags); list_add_tail(&vb->queue, &pcdev->capture); if (!pcdev->active) { pcdev->active = vb; sh_mobile_ceu_capture(pcdev); } - - spin_unlock_irqrestore(&pcdev->lock, flags); } static void sh_mobile_ceu_videobuf_release(struct videobuf_queue *vq, diff --git a/linux/drivers/media/video/stk-webcam.c b/linux/drivers/media/video/stk-webcam.c index 849867ab2..aaeee8319 100644 --- a/linux/drivers/media/video/stk-webcam.c +++ b/linux/drivers/media/video/stk-webcam.c @@ -1051,8 +1051,8 @@ static int stk_setup_format(struct stk_camera *dev) depth = 1; else depth = 2; - while (stk_sizes[i].m != dev->vsettings.mode - && i < ARRAY_SIZE(stk_sizes)) + while (i < ARRAY_SIZE(stk_sizes) && + stk_sizes[i].m != dev->vsettings.mode) i++; if (i == ARRAY_SIZE(stk_sizes)) { STK_ERROR("Something is broken in %s\n", __func__); diff --git a/linux/drivers/media/video/uvc/uvc_ctrl.c b/linux/drivers/media/video/uvc/uvc_ctrl.c index 81928f838..57b6fe937 100644 --- a/linux/drivers/media/video/uvc/uvc_ctrl.c +++ b/linux/drivers/media/video/uvc/uvc_ctrl.c @@ -731,7 +731,7 @@ static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id, } } -struct uvc_control *uvc_find_control(struct uvc_video_device *video, +struct uvc_control *uvc_find_control(struct uvc_video_chain *chain, __u32 v4l2_id, struct uvc_control_mapping **mapping) { struct uvc_control *ctrl = NULL; @@ -744,17 +744,17 @@ struct uvc_control *uvc_find_control(struct uvc_video_device *video, v4l2_id &= V4L2_CTRL_ID_MASK; /* Find the control. */ - __uvc_find_control(video->processing, v4l2_id, mapping, &ctrl, next); + __uvc_find_control(chain->processing, v4l2_id, mapping, &ctrl, next); if (ctrl && !next) return ctrl; - list_for_each_entry(entity, &video->iterms, chain) { + list_for_each_entry(entity, &chain->iterms, chain) { __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next); if (ctrl && !next) return ctrl; } - list_for_each_entry(entity, &video->extensions, chain) { + list_for_each_entry(entity, &chain->extensions, chain) { __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next); if (ctrl && !next) return ctrl; @@ -767,7 +767,7 @@ struct uvc_control *uvc_find_control(struct uvc_video_device *video, return ctrl; } -int uvc_query_v4l2_ctrl(struct uvc_video_device *video, +int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, struct v4l2_queryctrl *v4l2_ctrl) { struct uvc_control *ctrl; @@ -777,7 +777,7 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video, __u8 *data; int ret; - ctrl = uvc_find_control(video, v4l2_ctrl->id, &mapping); + ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping); if (ctrl == NULL) return -EINVAL; @@ -795,9 +795,9 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video, v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; if (ctrl->info->flags & UVC_CONTROL_GET_DEF) { - ret = uvc_query_ctrl(video->dev, UVC_GET_DEF, ctrl->entity->id, - video->dev->intfnum, ctrl->info->selector, data, - ctrl->info->size); + ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id, + chain->dev->intfnum, ctrl->info->selector, + data, ctrl->info->size); if (ret < 0) goto out; v4l2_ctrl->default_value = @@ -833,25 +833,25 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video, } if (ctrl->info->flags & UVC_CONTROL_GET_MIN) { - ret = uvc_query_ctrl(video->dev, UVC_GET_MIN, ctrl->entity->id, - video->dev->intfnum, ctrl->info->selector, data, - ctrl->info->size); + ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id, + chain->dev->intfnum, ctrl->info->selector, + data, ctrl->info->size); if (ret < 0) goto out; v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN, data); } if (ctrl->info->flags & UVC_CONTROL_GET_MAX) { - ret = uvc_query_ctrl(video->dev, UVC_GET_MAX, ctrl->entity->id, - video->dev->intfnum, ctrl->info->selector, data, - ctrl->info->size); + ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id, + chain->dev->intfnum, ctrl->info->selector, + data, ctrl->info->size); if (ret < 0) goto out; v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX, data); } if (ctrl->info->flags & UVC_CONTROL_GET_RES) { - ret = uvc_query_ctrl(video->dev, UVC_GET_RES, ctrl->entity->id, - video->dev->intfnum, ctrl->info->selector, data, - ctrl->info->size); + ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id, + chain->dev->intfnum, ctrl->info->selector, + data, ctrl->info->size); if (ret < 0) goto out; v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES, data); @@ -888,9 +888,9 @@ out: * (UVC_CTRL_DATA_BACKUP) for all dirty controls. Both functions release the * control lock. */ -int uvc_ctrl_begin(struct uvc_video_device *video) +int uvc_ctrl_begin(struct uvc_video_chain *chain) { - return mutex_lock_interruptible(&video->ctrl_mutex) ? -ERESTARTSYS : 0; + return mutex_lock_interruptible(&chain->ctrl_mutex) ? -ERESTARTSYS : 0; } static int uvc_ctrl_commit_entity(struct uvc_device *dev, @@ -940,34 +940,34 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev, return 0; } -int __uvc_ctrl_commit(struct uvc_video_device *video, int rollback) +int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback) { struct uvc_entity *entity; int ret = 0; /* Find the control. */ - ret = uvc_ctrl_commit_entity(video->dev, video->processing, rollback); + ret = uvc_ctrl_commit_entity(chain->dev, chain->processing, rollback); if (ret < 0) goto done; - list_for_each_entry(entity, &video->iterms, chain) { - ret = uvc_ctrl_commit_entity(video->dev, entity, rollback); + list_for_each_entry(entity, &chain->iterms, chain) { + ret = uvc_ctrl_commit_entity(chain->dev, entity, rollback); if (ret < 0) goto done; } - list_for_each_entry(entity, &video->extensions, chain) { - ret = uvc_ctrl_commit_entity(video->dev, entity, rollback); + list_for_each_entry(entity, &chain->extensions, chain) { + ret = uvc_ctrl_commit_entity(chain->dev, entity, rollback); if (ret < 0) goto done; } done: - mutex_unlock(&video->ctrl_mutex); + mutex_unlock(&chain->ctrl_mutex); return ret; } -int uvc_ctrl_get(struct uvc_video_device *video, +int uvc_ctrl_get(struct uvc_video_chain *chain, struct v4l2_ext_control *xctrl) { struct uvc_control *ctrl; @@ -976,13 +976,13 @@ int uvc_ctrl_get(struct uvc_video_device *video, unsigned int i; int ret; - ctrl = uvc_find_control(video, xctrl->id, &mapping); + ctrl = uvc_find_control(chain, xctrl->id, &mapping); if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0) return -EINVAL; if (!ctrl->loaded) { - ret = uvc_query_ctrl(video->dev, UVC_GET_CUR, ctrl->entity->id, - video->dev->intfnum, ctrl->info->selector, + ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, ctrl->entity->id, + chain->dev->intfnum, ctrl->info->selector, uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), ctrl->info->size); if (ret < 0) @@ -1007,7 +1007,7 @@ int uvc_ctrl_get(struct uvc_video_device *video, return 0; } -int uvc_ctrl_set(struct uvc_video_device *video, +int uvc_ctrl_set(struct uvc_video_chain *chain, struct v4l2_ext_control *xctrl) { struct uvc_control *ctrl; @@ -1015,7 +1015,7 @@ int uvc_ctrl_set(struct uvc_video_device *video, s32 value = xctrl->value; int ret; - ctrl = uvc_find_control(video, xctrl->id, &mapping); + ctrl = uvc_find_control(chain, xctrl->id, &mapping); if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_SET_CUR) == 0) return -EINVAL; @@ -1030,8 +1030,8 @@ int uvc_ctrl_set(struct uvc_video_device *video, memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), 0, ctrl->info->size); } else { - ret = uvc_query_ctrl(video->dev, UVC_GET_CUR, - ctrl->entity->id, video->dev->intfnum, + ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, + ctrl->entity->id, chain->dev->intfnum, ctrl->info->selector, uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), ctrl->info->size); @@ -1060,7 +1060,7 @@ int uvc_ctrl_set(struct uvc_video_device *video, * Dynamic controls */ -int uvc_xu_ctrl_query(struct uvc_video_device *video, +int uvc_xu_ctrl_query(struct uvc_video_chain *chain, struct uvc_xu_control *xctrl, int set) { struct uvc_entity *entity; @@ -1070,7 +1070,7 @@ int uvc_xu_ctrl_query(struct uvc_video_device *video, int ret; /* Find the extension unit. */ - list_for_each_entry(entity, &video->extensions, chain) { + list_for_each_entry(entity, &chain->extensions, chain) { if (entity->id == xctrl->unit) break; } @@ -1109,7 +1109,7 @@ int uvc_xu_ctrl_query(struct uvc_video_device *video, (!set && !(ctrl->info->flags & UVC_CONTROL_GET_CUR))) return -EINVAL; - if (mutex_lock_interruptible(&video->ctrl_mutex)) + if (mutex_lock_interruptible(&chain->ctrl_mutex)) return -ERESTARTSYS; memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP), @@ -1122,8 +1122,8 @@ int uvc_xu_ctrl_query(struct uvc_video_device *video, goto out; } - ret = uvc_query_ctrl(video->dev, set ? UVC_SET_CUR : UVC_GET_CUR, - xctrl->unit, video->dev->intfnum, xctrl->selector, + ret = uvc_query_ctrl(chain->dev, set ? UVC_SET_CUR : UVC_GET_CUR, + xctrl->unit, chain->dev->intfnum, xctrl->selector, data, xctrl->size); if (ret < 0) goto out; @@ -1139,7 +1139,7 @@ out: uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP), xctrl->size); - mutex_unlock(&video->ctrl_mutex); + mutex_unlock(&chain->ctrl_mutex); return ret; } diff --git a/linux/drivers/media/video/uvc/uvc_driver.c b/linux/drivers/media/video/uvc/uvc_driver.c index 1d09751a3..09b2e4ad5 100644 --- a/linux/drivers/media/video/uvc/uvc_driver.c +++ b/linux/drivers/media/video/uvc/uvc_driver.c @@ -276,8 +276,20 @@ static struct uvc_entity *uvc_entity_by_reference(struct uvc_device *dev, return NULL; } +static struct uvc_streaming *uvc_stream_by_id(struct uvc_device *dev, int id) +{ + struct uvc_streaming *stream; + + list_for_each_entry(stream, &dev->streams, list) { + if (stream->header.bTerminalLink == id) + return stream; + } + + return NULL; +} + /* ------------------------------------------------------------------------ - * Descriptors handling + * Descriptors parsing */ static int uvc_parse_format(struct uvc_device *dev, @@ -551,6 +563,7 @@ static int uvc_parse_streaming(struct uvc_device *dev, } mutex_init(&streaming->mutex); + streaming->dev = dev; streaming->intf = usb_get_intf(intf); streaming->intfnum = intf->cur_altsetting->desc.bInterfaceNumber; @@ -751,7 +764,7 @@ static int uvc_parse_streaming(struct uvc_device *dev, streaming->maxpsize = psize; } - list_add_tail(&streaming->list, &dev->streaming); + list_add_tail(&streaming->list, &dev->streams); return 0; error: @@ -1159,39 +1172,36 @@ next_descriptor: } /* ------------------------------------------------------------------------ - * USB probe and disconnect + * UVC device scan */ /* - * Unregister the video devices. - */ -static void uvc_unregister_video(struct uvc_device *dev) -{ - if (dev->video.vdev) { - if (dev->video.vdev->minor == -1) - video_device_release(dev->video.vdev); - else - video_unregister_device(dev->video.vdev); - dev->video.vdev = NULL; - } -} - -/* * Scan the UVC descriptors to locate a chain starting at an Output Terminal * and containing the following units: * - * - one Output Terminal (USB Streaming or Display) + * - one or more Output Terminals (USB Streaming or Display) * - zero or one Processing Unit - * - zero, one or mode single-input Selector Units + * - zero, one or more single-input Selector Units * - zero or one multiple-input Selector Units, provided all inputs are * connected to input terminals * - zero, one or mode single-input Extension Units * - one or more Input Terminals (Camera, External or USB Streaming) * - * A side forward scan is made on each detected entity to check for additional - * extension units. + * The terminal and units must match on of the following structures: + * + * ITT_*(0) -> +---------+ +---------+ +---------+ -> TT_STREAMING(0) + * ... | SU{0,1} | -> | PU{0,1} | -> | XU{0,n} | ... + * ITT_*(n) -> +---------+ +---------+ +---------+ -> TT_STREAMING(n) + * + * +---------+ +---------+ -> OTT_*(0) + * TT_STREAMING -> | PU{0,1} | -> | XU{0,n} | ... + * +---------+ +---------+ -> OTT_*(n) + * + * The Processing Unit and Extension Units can be in any order. Additional + * Extension Units connected to the main chain as single-unit branches are + * also supported. Single-input Selector Units are ignored. */ -static int uvc_scan_chain_entity(struct uvc_video_device *video, +static int uvc_scan_chain_entity(struct uvc_video_chain *chain, struct uvc_entity *entity) { switch (UVC_ENTITY_TYPE(entity)) { @@ -1205,20 +1215,20 @@ static int uvc_scan_chain_entity(struct uvc_video_device *video, return -1; } - list_add_tail(&entity->chain, &video->extensions); + list_add_tail(&entity->chain, &chain->extensions); break; case UVC_VC_PROCESSING_UNIT: if (uvc_trace_param & UVC_TRACE_PROBE) printk(" <- PU %d", entity->id); - if (video->processing != NULL) { + if (chain->processing != NULL) { uvc_trace(UVC_TRACE_DESCR, "Found multiple " "Processing Units in chain.\n"); return -1; } - video->processing = entity; + chain->processing = entity; break; case UVC_VC_SELECTOR_UNIT: @@ -1229,13 +1239,13 @@ static int uvc_scan_chain_entity(struct uvc_video_device *video, if (entity->selector.bNrInPins == 1) break; - if (video->selector != NULL) { + if (chain->selector != NULL) { uvc_trace(UVC_TRACE_DESCR, "Found multiple Selector " "Units in chain.\n"); return -1; } - video->selector = entity; + chain->selector = entity; break; case UVC_ITT_VENDOR_SPECIFIC: @@ -1244,7 +1254,7 @@ static int uvc_scan_chain_entity(struct uvc_video_device *video, if (uvc_trace_param & UVC_TRACE_PROBE) printk(" <- IT %d\n", entity->id); - list_add_tail(&entity->chain, &video->iterms); + list_add_tail(&entity->chain, &chain->iterms); break; case UVC_TT_STREAMING: @@ -1257,14 +1267,7 @@ static int uvc_scan_chain_entity(struct uvc_video_device *video, return -1; } - if (video->sterm != NULL) { - uvc_trace(UVC_TRACE_DESCR, "Found multiple streaming " - "entities in chain.\n"); - return -1; - } - - list_add_tail(&entity->chain, &video->iterms); - video->sterm = entity; + list_add_tail(&entity->chain, &chain->iterms); break; default: @@ -1276,7 +1279,7 @@ static int uvc_scan_chain_entity(struct uvc_video_device *video, return 0; } -static int uvc_scan_chain_forward(struct uvc_video_device *video, +static int uvc_scan_chain_forward(struct uvc_video_chain *chain, struct uvc_entity *entity, struct uvc_entity *prev) { struct uvc_entity *forward; @@ -1287,28 +1290,51 @@ static int uvc_scan_chain_forward(struct uvc_video_device *video, found = 0; while (1) { - forward = uvc_entity_by_reference(video->dev, entity->id, + forward = uvc_entity_by_reference(chain->dev, entity->id, forward); if (forward == NULL) break; - - if (UVC_ENTITY_TYPE(forward) != UVC_VC_EXTENSION_UNIT || - forward == prev) + if (forward == prev) continue; - if (forward->extension.bNrInPins != 1) { - uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has " - "more than 1 input pin.\n", entity->id); - return -1; - } + switch (UVC_ENTITY_TYPE(forward)) { + case UVC_VC_EXTENSION_UNIT: + if (forward->extension.bNrInPins != 1) { + uvc_trace(UVC_TRACE_DESCR, "Extension unit %d " + "has more than 1 input pin.\n", + entity->id); + return -EINVAL; + } - list_add_tail(&forward->chain, &video->extensions); - if (uvc_trace_param & UVC_TRACE_PROBE) { - if (!found) - printk(" (-> XU"); + list_add_tail(&forward->chain, &chain->extensions); + if (uvc_trace_param & UVC_TRACE_PROBE) { + if (!found) + printk(" (->"); - printk(" %d", forward->id); - found = 1; + printk(" XU %d", forward->id); + found = 1; + } + break; + + case UVC_OTT_VENDOR_SPECIFIC: + case UVC_OTT_DISPLAY: + case UVC_OTT_MEDIA_TRANSPORT_OUTPUT: + case UVC_TT_STREAMING: + if (UVC_ENTITY_IS_ITERM(forward)) { + uvc_trace(UVC_TRACE_DESCR, "Unsupported input " + "terminal %u.\n", forward->id); + return -EINVAL; + } + + list_add_tail(&forward->chain, &chain->oterms); + if (uvc_trace_param & UVC_TRACE_PROBE) { + if (!found) + printk(" (->"); + + printk(" OT %d", forward->id); + found = 1; + } + break; } } if (found) @@ -1317,7 +1343,7 @@ static int uvc_scan_chain_forward(struct uvc_video_device *video, return 0; } -static int uvc_scan_chain_backward(struct uvc_video_device *video, +static int uvc_scan_chain_backward(struct uvc_video_chain *chain, struct uvc_entity *entity) { struct uvc_entity *term; @@ -1342,10 +1368,10 @@ static int uvc_scan_chain_backward(struct uvc_video_device *video, if (uvc_trace_param & UVC_TRACE_PROBE) printk(" <- IT"); - video->selector = entity; + chain->selector = entity; for (i = 0; i < entity->selector.bNrInPins; ++i) { id = entity->selector.baSourceID[i]; - term = uvc_entity_by_id(video->dev, id); + term = uvc_entity_by_id(chain->dev, id); if (term == NULL || !UVC_ENTITY_IS_ITERM(term)) { uvc_trace(UVC_TRACE_DESCR, "Selector unit %d " "input %d isn't connected to an " @@ -1356,8 +1382,8 @@ static int uvc_scan_chain_backward(struct uvc_video_device *video, if (uvc_trace_param & UVC_TRACE_PROBE) printk(" %d", term->id); - list_add_tail(&term->chain, &video->iterms); - uvc_scan_chain_forward(video, term, entity); + list_add_tail(&term->chain, &chain->iterms); + uvc_scan_chain_forward(chain, term, entity); } if (uvc_trace_param & UVC_TRACE_PROBE) @@ -1370,125 +1396,170 @@ static int uvc_scan_chain_backward(struct uvc_video_device *video, return id; } -static int uvc_scan_chain(struct uvc_video_device *video) +static int uvc_scan_chain(struct uvc_video_chain *chain, + struct uvc_entity *oterm) { struct uvc_entity *entity, *prev; int id; - entity = video->oterm; + entity = oterm; + list_add_tail(&entity->chain, &chain->oterms); uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain: OT %d", entity->id); - if (UVC_ENTITY_TYPE(entity) == UVC_TT_STREAMING) - video->sterm = entity; - id = entity->output.bSourceID; while (id != 0) { prev = entity; - entity = uvc_entity_by_id(video->dev, id); + entity = uvc_entity_by_id(chain->dev, id); if (entity == NULL) { uvc_trace(UVC_TRACE_DESCR, "Found reference to " "unknown entity %d.\n", id); - return -1; + return -EINVAL; + } + + if (entity->chain.next || entity->chain.prev) { + uvc_trace(UVC_TRACE_DESCR, "Found reference to " + "entity %d already in chain.\n", id); + return -EINVAL; } /* Process entity */ - if (uvc_scan_chain_entity(video, entity) < 0) - return -1; + if (uvc_scan_chain_entity(chain, entity) < 0) + return -EINVAL; /* Forward scan */ - if (uvc_scan_chain_forward(video, entity, prev) < 0) - return -1; + if (uvc_scan_chain_forward(chain, entity, prev) < 0) + return -EINVAL; /* Stop when a terminal is found. */ - if (!UVC_ENTITY_IS_UNIT(entity)) + if (UVC_ENTITY_IS_TERM(entity)) break; /* Backward scan */ - id = uvc_scan_chain_backward(video, entity); + id = uvc_scan_chain_backward(chain, entity); if (id < 0) return id; } - if (video->sterm == NULL) { - uvc_trace(UVC_TRACE_DESCR, "No streaming entity found in " - "chain.\n"); - return -1; + return 0; +} + +static unsigned int uvc_print_terms(struct list_head *terms, char *buffer) +{ + struct uvc_entity *term; + unsigned int nterms = 0; + char *p = buffer; + + list_for_each_entry(term, terms, chain) { + p += sprintf(p, "%u", term->id); + if (term->chain.next != terms) { + p += sprintf(p, ","); + if (++nterms >= 4) { + p += sprintf(p, "..."); + break; + } + } } - return 0; + return p - buffer; +} + +static const char *uvc_print_chain(struct uvc_video_chain *chain) +{ + static char buffer[43]; + char *p = buffer; + + p += uvc_print_terms(&chain->iterms, p); + p += sprintf(p, " -> "); + uvc_print_terms(&chain->oterms, p); + + return buffer; } /* - * Register the video devices. + * Scan the device for video chains and register video devices. * - * The driver currently supports a single video device per control interface - * only. The terminal and units must match the following structure: - * - * ITT_* -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> TT_STREAMING - * TT_STREAMING -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> OTT_* - * - * The Extension Units, if present, must have a single input pin. The - * Processing Unit and Extension Units can be in any order. Additional - * Extension Units connected to the main chain as single-unit branches are - * also supported. + * Chains are scanned starting at their output terminals and walked backwards. */ -static int uvc_register_video(struct uvc_device *dev) +static int uvc_scan_device(struct uvc_device *dev) { - struct video_device *vdev; + struct uvc_video_chain *chain; struct uvc_entity *term; - int found = 0, ret; - /* Check if the control interface matches the structure we expect. */ list_for_each_entry(term, &dev->entities, list) { - struct uvc_streaming *streaming; - - if (!UVC_ENTITY_IS_TERM(term) || !UVC_ENTITY_IS_OTERM(term)) + if (!UVC_ENTITY_IS_OTERM(term)) continue; - memset(&dev->video, 0, sizeof dev->video); - mutex_init(&dev->video.ctrl_mutex); - INIT_LIST_HEAD(&dev->video.iterms); - INIT_LIST_HEAD(&dev->video.extensions); - dev->video.oterm = term; - dev->video.dev = dev; - if (uvc_scan_chain(&dev->video) < 0) + /* If the terminal is already included in a chain, skip it. + * This can happen for chains that have multiple output + * terminals, where all output terminals beside the first one + * will be inserted in the chain in forward scans. + */ + if (term->chain.next || term->chain.prev) continue; - list_for_each_entry(streaming, &dev->streaming, list) { - if (streaming->header.bTerminalLink == - dev->video.sterm->id) { - dev->video.streaming = streaming; - found = 1; - break; - } + chain = kzalloc(sizeof(*chain), GFP_KERNEL); + if (chain == NULL) + return -ENOMEM; + + INIT_LIST_HEAD(&chain->iterms); + INIT_LIST_HEAD(&chain->oterms); + INIT_LIST_HEAD(&chain->extensions); + mutex_init(&chain->ctrl_mutex); + chain->dev = dev; + + if (uvc_scan_chain(chain, term) < 0) { + kfree(chain); + continue; } - if (found) - break; + uvc_trace(UVC_TRACE_PROBE, "Found a valid video chain (%s).\n", + uvc_print_chain(chain)); + + list_add_tail(&chain->list, &dev->chains); } - if (!found) { + if (list_empty(&dev->chains)) { uvc_printk(KERN_INFO, "No valid video chain found.\n"); return -1; } - if (uvc_trace_param & UVC_TRACE_PROBE) { - uvc_printk(KERN_INFO, "Found a valid video chain ("); - list_for_each_entry(term, &dev->video.iterms, chain) { - printk("%d", term->id); - if (term->chain.next != &dev->video.iterms) - printk(","); - } - printk(" -> %d).\n", dev->video.oterm->id); + return 0; +} + +/* ------------------------------------------------------------------------ + * Video device registration and unregistration + */ + +/* + * Unregister the video devices. + */ +static void uvc_unregister_video(struct uvc_device *dev) +{ + struct uvc_streaming *stream; + + list_for_each_entry(stream, &dev->streams, list) { + if (stream->vdev == NULL) + continue; + + if (stream->vdev->minor == -1) + video_device_release(stream->vdev); + else + video_unregister_device(stream->vdev); + stream->vdev = NULL; } +} - /* Initialize the video buffers queue. */ - uvc_queue_init(&dev->video.queue, dev->video.streaming->type); +static int uvc_register_video(struct uvc_device *dev, + struct uvc_streaming *stream) +{ + struct video_device *vdev; + int ret; /* Initialize the streaming interface with default streaming * parameters. */ - if ((ret = uvc_video_init(&dev->video)) < 0) { + ret = uvc_video_init(stream); + if (ret < 0) { uvc_printk(KERN_ERR, "Failed to initialize the device " "(%d).\n", ret); return ret; @@ -1496,8 +1567,11 @@ static int uvc_register_video(struct uvc_device *dev) /* Register the device with V4L. */ vdev = video_device_alloc(); - if (vdev == NULL) - return -1; + if (vdev == NULL) { + uvc_printk(KERN_ERR, "Failed to allocate video device (%d).\n", + ret); + return -ENOMEM; + } /* We already hold a reference to dev->udev. The video device will be * unregistered before the reference is released, so we don't need to @@ -1512,19 +1586,74 @@ static int uvc_register_video(struct uvc_device *dev) /* Set the driver data before calling video_register_device, otherwise * uvc_v4l2_open might race us. */ - dev->video.vdev = vdev; - video_set_drvdata(vdev, &dev->video); - - if (video_register_device(vdev, VFL_TYPE_GRABBER, -1) < 0) { - dev->video.vdev = NULL; + stream->vdev = vdev; + video_set_drvdata(vdev, stream); + + ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); + if (ret < 0) { + uvc_printk(KERN_ERR, "Failed to register video device (%d).\n", + ret); + stream->vdev = NULL; video_device_release(vdev); - return -1; + return ret; } return 0; } /* + * Register all video devices in all chains. + */ +static int uvc_register_terms(struct uvc_device *dev, + struct uvc_video_chain *chain, struct list_head *terms) +{ + struct uvc_streaming *stream; + struct uvc_entity *term; + int ret; + + list_for_each_entry(term, terms, chain) { + if (UVC_ENTITY_TYPE(term) != UVC_TT_STREAMING) + continue; + + stream = uvc_stream_by_id(dev, term->id); + if (stream == NULL) { + uvc_printk(KERN_INFO, "No streaming interface found " + "for terminal %u.", term->id); + continue; + } + + stream->chain = chain; + ret = uvc_register_video(dev, stream); + if (ret < 0) + return ret; + } + + return 0; +} + +static int uvc_register_chains(struct uvc_device *dev) +{ + struct uvc_video_chain *chain; + int ret; + + list_for_each_entry(chain, &dev->chains, list) { + ret = uvc_register_terms(dev, chain, &chain->iterms); + if (ret < 0) + return ret; + + ret = uvc_register_terms(dev, chain, &chain->oterms); + if (ret < 0) + return ret; + } + + return 0; +} + +/* ------------------------------------------------------------------------ + * USB probe, disconnect, suspend and resume + */ + +/* * Delete the UVC device. * * Called by the kernel when the last reference to the uvc_device structure @@ -1545,7 +1674,7 @@ void uvc_delete(struct kref *kref) struct uvc_device *dev = container_of(kref, struct uvc_device, kref); struct list_head *p, *n; - /* Unregister the video device. */ + /* Unregister the video devices. */ uvc_unregister_video(dev); usb_put_intf(dev->intf); usb_put_dev(dev->udev); @@ -1553,13 +1682,19 @@ void uvc_delete(struct kref *kref) uvc_status_cleanup(dev); uvc_ctrl_cleanup_device(dev); + list_for_each_safe(p, n, &dev->chains) { + struct uvc_video_chain *chain; + chain = list_entry(p, struct uvc_video_chain, list); + kfree(chain); + } + list_for_each_safe(p, n, &dev->entities) { struct uvc_entity *entity; entity = list_entry(p, struct uvc_entity, list); kfree(entity); } - list_for_each_safe(p, n, &dev->streaming) { + list_for_each_safe(p, n, &dev->streams) { struct uvc_streaming *streaming; streaming = list_entry(p, struct uvc_streaming, list); usb_driver_release_interface(&uvc_driver.driver, @@ -1593,7 +1728,8 @@ static int uvc_probe(struct usb_interface *intf, return -ENOMEM; INIT_LIST_HEAD(&dev->entities); - INIT_LIST_HEAD(&dev->streaming); + INIT_LIST_HEAD(&dev->chains); + INIT_LIST_HEAD(&dev->streams); kref_init(&dev->kref); atomic_set(&dev->users, 0); @@ -1634,8 +1770,12 @@ static int uvc_probe(struct usb_interface *intf, if (uvc_ctrl_init_device(dev) < 0) goto error; - /* Register the video devices. */ - if (uvc_register_video(dev) < 0) + /* Scan the device for video chains. */ + if (uvc_scan_device(dev) < 0) + goto error; + + /* Register video devices. */ + if (uvc_register_chains(dev) < 0) goto error; /* Save our data pointer in the interface data. */ @@ -1689,6 +1829,7 @@ static void uvc_disconnect(struct usb_interface *intf) static int uvc_suspend(struct usb_interface *intf, pm_message_t message) { struct uvc_device *dev = usb_get_intfdata(intf); + struct uvc_streaming *stream; uvc_trace(UVC_TRACE_SUSPEND, "Suspending interface %u\n", intf->cur_altsetting->desc.bInterfaceNumber); @@ -1698,18 +1839,20 @@ static int uvc_suspend(struct usb_interface *intf, pm_message_t message) UVC_SC_VIDEOCONTROL) return uvc_status_suspend(dev); - if (dev->video.streaming->intf != intf) { - uvc_trace(UVC_TRACE_SUSPEND, "Suspend: video streaming USB " - "interface mismatch.\n"); - return -EINVAL; + list_for_each_entry(stream, &dev->streams, list) { + if (stream->intf == intf) + return uvc_video_suspend(stream); } - return uvc_video_suspend(&dev->video); + uvc_trace(UVC_TRACE_SUSPEND, "Suspend: video streaming USB interface " + "mismatch.\n"); + return -EINVAL; } static int __uvc_resume(struct usb_interface *intf, int reset) { struct uvc_device *dev = usb_get_intfdata(intf); + struct uvc_streaming *stream; uvc_trace(UVC_TRACE_SUSPEND, "Resuming interface %u\n", intf->cur_altsetting->desc.bInterfaceNumber); @@ -1726,13 +1869,14 @@ static int __uvc_resume(struct usb_interface *intf, int reset) return uvc_status_resume(dev); } - if (dev->video.streaming->intf != intf) { - uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB " - "interface mismatch.\n"); - return -EINVAL; + list_for_each_entry(stream, &dev->streams, list) { + if (stream->intf == intf) + return uvc_video_resume(stream); } - return uvc_video_resume(&dev->video); + uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB interface " + "mismatch.\n"); + return -EINVAL; } static int uvc_resume(struct usb_interface *intf) @@ -1852,7 +1996,7 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_STREAM_NO_FID }, /* ViMicro Vega */ - { .match_flags = USB_DEVICE_ID_MATCH_VENDOR + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x0ac8, .idProduct = 0x332d, @@ -1861,7 +2005,7 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_FIX_BANDWIDTH }, /* ViMicro - Minoru3D */ - { .match_flags = USB_DEVICE_ID_MATCH_VENDOR + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x0ac8, .idProduct = 0x3410, @@ -1870,7 +2014,7 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_FIX_BANDWIDTH }, /* ViMicro Venus - Minoru3D */ - { .match_flags = USB_DEVICE_ID_MATCH_VENDOR + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x0ac8, .idProduct = 0x3420, diff --git a/linux/drivers/media/video/uvc/uvc_isight.c b/linux/drivers/media/video/uvc/uvc_isight.c index 436f46268..a9285b570 100644 --- a/linux/drivers/media/video/uvc/uvc_isight.c +++ b/linux/drivers/media/video/uvc/uvc_isight.c @@ -99,7 +99,7 @@ static int isight_decode(struct uvc_video_queue *queue, struct uvc_buffer *buf, return 0; } -void uvc_video_decode_isight(struct urb *urb, struct uvc_video_device *video, +void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream, struct uvc_buffer *buf) { int ret, i; @@ -120,7 +120,7 @@ void uvc_video_decode_isight(struct urb *urb, struct uvc_video_device *video, * processes the data of the first payload of the new frame. */ do { - ret = isight_decode(&video->queue, buf, + ret = isight_decode(&stream->queue, buf, urb->transfer_buffer + urb->iso_frame_desc[i].offset, urb->iso_frame_desc[i].actual_length); @@ -130,7 +130,8 @@ void uvc_video_decode_isight(struct urb *urb, struct uvc_video_device *video, if (buf->state == UVC_BUF_STATE_DONE || buf->state == UVC_BUF_STATE_ERROR) - buf = uvc_queue_next_buffer(&video->queue, buf); + buf = uvc_queue_next_buffer(&stream->queue, + buf); } while (ret == -EAGAIN); } } diff --git a/linux/drivers/media/video/uvc/uvc_status.c b/linux/drivers/media/video/uvc/uvc_status.c index b05df63b4..48614d39c 100644 --- a/linux/drivers/media/video/uvc/uvc_status.c +++ b/linux/drivers/media/video/uvc/uvc_status.c @@ -157,8 +157,8 @@ static void uvc_status_complete(struct urb *urb) break; default: - uvc_printk(KERN_INFO, "unknown event type %u.\n", - dev->status[0]); + uvc_trace(UVC_TRACE_STATUS, "Unknown status event " + "type %u.\n", dev->status[0]); break; } } diff --git a/linux/drivers/media/video/uvc/uvc_v4l2.c b/linux/drivers/media/video/uvc/uvc_v4l2.c index 31a9ed4ff..b5a16acb6 100644 --- a/linux/drivers/media/video/uvc/uvc_v4l2.c +++ b/linux/drivers/media/video/uvc/uvc_v4l2.c @@ -40,7 +40,7 @@ * table for the controls that can be mapped directly, and handle the others * manually. */ -static int uvc_v4l2_query_menu(struct uvc_video_device *video, +static int uvc_v4l2_query_menu(struct uvc_video_chain *chain, struct v4l2_querymenu *query_menu) { struct uvc_menu_info *menu_info; @@ -49,7 +49,7 @@ static int uvc_v4l2_query_menu(struct uvc_video_device *video, u32 index = query_menu->index; u32 id = query_menu->id; - ctrl = uvc_find_control(video, query_menu->id, &mapping); + ctrl = uvc_find_control(chain, query_menu->id, &mapping); if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) return -EINVAL; @@ -103,7 +103,7 @@ static __u32 uvc_try_frame_interval(struct uvc_frame *frame, __u32 interval) return interval; } -static int uvc_v4l2_try_format(struct uvc_video_device *video, +static int uvc_v4l2_try_format(struct uvc_streaming *stream, struct v4l2_format *fmt, struct uvc_streaming_control *probe, struct uvc_format **uvc_format, struct uvc_frame **uvc_frame) { @@ -116,7 +116,7 @@ static int uvc_v4l2_try_format(struct uvc_video_device *video, int ret = 0; __u8 *fcc; - if (fmt->type != video->streaming->type) + if (fmt->type != stream->type) return -EINVAL; fcc = (__u8 *)&fmt->fmt.pix.pixelformat; @@ -126,8 +126,8 @@ static int uvc_v4l2_try_format(struct uvc_video_device *video, fmt->fmt.pix.width, fmt->fmt.pix.height); /* Check if the hardware supports the requested format. */ - for (i = 0; i < video->streaming->nformats; ++i) { - format = &video->streaming->format[i]; + for (i = 0; i < stream->nformats; ++i) { + format = &stream->format[i]; if (format->fcc == fmt->fmt.pix.pixelformat) break; } @@ -191,12 +191,13 @@ static int uvc_v4l2_try_format(struct uvc_video_device *video, * developers test their webcams with the Linux driver as well as with * the Windows driver). */ - if (video->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS) + if (stream->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS) probe->dwMaxVideoFrameSize = - video->streaming->ctrl.dwMaxVideoFrameSize; + stream->ctrl.dwMaxVideoFrameSize; /* Probe the device. */ - if ((ret = uvc_probe_video(video, probe)) < 0) + ret = uvc_probe_video(stream, probe); + if (ret < 0) goto done; fmt->fmt.pix.width = frame->wWidth; @@ -216,13 +217,13 @@ done: return ret; } -static int uvc_v4l2_get_format(struct uvc_video_device *video, +static int uvc_v4l2_get_format(struct uvc_streaming *stream, struct v4l2_format *fmt) { - struct uvc_format *format = video->streaming->cur_format; - struct uvc_frame *frame = video->streaming->cur_frame; + struct uvc_format *format = stream->cur_format; + struct uvc_frame *frame = stream->cur_frame; - if (fmt->type != video->streaming->type) + if (fmt->type != stream->type) return -EINVAL; if (format == NULL || frame == NULL) @@ -233,14 +234,14 @@ static int uvc_v4l2_get_format(struct uvc_video_device *video, fmt->fmt.pix.height = frame->wHeight; fmt->fmt.pix.field = V4L2_FIELD_NONE; fmt->fmt.pix.bytesperline = format->bpp * frame->wWidth / 8; - fmt->fmt.pix.sizeimage = video->streaming->ctrl.dwMaxVideoFrameSize; + fmt->fmt.pix.sizeimage = stream->ctrl.dwMaxVideoFrameSize; fmt->fmt.pix.colorspace = format->colorspace; fmt->fmt.pix.priv = 0; return 0; } -static int uvc_v4l2_set_format(struct uvc_video_device *video, +static int uvc_v4l2_set_format(struct uvc_streaming *stream, struct v4l2_format *fmt) { struct uvc_streaming_control probe; @@ -248,39 +249,39 @@ static int uvc_v4l2_set_format(struct uvc_video_device *video, struct uvc_frame *frame; int ret; - if (fmt->type != video->streaming->type) + if (fmt->type != stream->type) return -EINVAL; - if (uvc_queue_allocated(&video->queue)) + if (uvc_queue_allocated(&stream->queue)) return -EBUSY; - ret = uvc_v4l2_try_format(video, fmt, &probe, &format, &frame); + ret = uvc_v4l2_try_format(stream, fmt, &probe, &format, &frame); if (ret < 0) return ret; - memcpy(&video->streaming->ctrl, &probe, sizeof probe); - video->streaming->cur_format = format; - video->streaming->cur_frame = frame; + memcpy(&stream->ctrl, &probe, sizeof probe); + stream->cur_format = format; + stream->cur_frame = frame; return 0; } -static int uvc_v4l2_get_streamparm(struct uvc_video_device *video, +static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream, struct v4l2_streamparm *parm) { uint32_t numerator, denominator; - if (parm->type != video->streaming->type) + if (parm->type != stream->type) return -EINVAL; - numerator = video->streaming->ctrl.dwFrameInterval; + numerator = stream->ctrl.dwFrameInterval; denominator = 10000000; uvc_simplify_fraction(&numerator, &denominator, 8, 333); memset(parm, 0, sizeof *parm); - parm->type = video->streaming->type; + parm->type = stream->type; - if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; parm->parm.capture.capturemode = 0; parm->parm.capture.timeperframe.numerator = numerator; @@ -297,19 +298,19 @@ static int uvc_v4l2_get_streamparm(struct uvc_video_device *video, return 0; } -static int uvc_v4l2_set_streamparm(struct uvc_video_device *video, +static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream, struct v4l2_streamparm *parm) { - struct uvc_frame *frame = video->streaming->cur_frame; + struct uvc_frame *frame = stream->cur_frame; struct uvc_streaming_control probe; struct v4l2_fract timeperframe; uint32_t interval; int ret; - if (parm->type != video->streaming->type) + if (parm->type != stream->type) return -EINVAL; - if (uvc_queue_streaming(&video->queue)) + if (uvc_queue_streaming(&stream->queue)) return -EBUSY; if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) @@ -317,7 +318,7 @@ static int uvc_v4l2_set_streamparm(struct uvc_video_device *video, else timeperframe = parm->parm.output.timeperframe; - memcpy(&probe, &video->streaming->ctrl, sizeof probe); + memcpy(&probe, &stream->ctrl, sizeof probe); interval = uvc_fraction_to_interval(timeperframe.numerator, timeperframe.denominator); @@ -326,10 +327,11 @@ static int uvc_v4l2_set_streamparm(struct uvc_video_device *video, probe.dwFrameInterval = uvc_try_frame_interval(frame, interval); /* Probe the device with the new settings. */ - if ((ret = uvc_probe_video(video, &probe)) < 0) + ret = uvc_probe_video(stream, &probe); + if (ret < 0) return ret; - memcpy(&video->streaming->ctrl, &probe, sizeof probe); + memcpy(&stream->ctrl, &probe, sizeof probe); /* Return the actual frame period. */ timeperframe.numerator = probe.dwFrameInterval; @@ -382,8 +384,8 @@ static int uvc_acquire_privileges(struct uvc_fh *handle) /* Check if the device already has a privileged handle. */ mutex_lock(&uvc_driver.open_mutex); - if (atomic_inc_return(&handle->device->active) != 1) { - atomic_dec(&handle->device->active); + if (atomic_inc_return(&handle->stream->active) != 1) { + atomic_dec(&handle->stream->active); ret = -EBUSY; goto done; } @@ -398,7 +400,7 @@ done: static void uvc_dismiss_privileges(struct uvc_fh *handle) { if (handle->state == UVC_HANDLE_ACTIVE) - atomic_dec(&handle->device->active); + atomic_dec(&handle->stream->active); handle->state = UVC_HANDLE_PASSIVE; } @@ -414,21 +416,21 @@ static int uvc_has_privileges(struct uvc_fh *handle) static int uvc_v4l2_open(struct file *file) { - struct uvc_video_device *video; + struct uvc_streaming *stream; struct uvc_fh *handle; int ret = 0; uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_open\n"); mutex_lock(&uvc_driver.open_mutex); - video = video_drvdata(file); + stream = video_drvdata(file); - if (video->dev->state & UVC_DEV_DISCONNECTED) { + if (stream->dev->state & UVC_DEV_DISCONNECTED) { ret = -ENODEV; goto done; } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) - ret = usb_autopm_get_interface(video->dev->intf); + ret = usb_autopm_get_interface(stream->dev->intf); if (ret < 0) goto done; #endif @@ -437,28 +439,30 @@ static int uvc_v4l2_open(struct file *file) handle = kzalloc(sizeof *handle, GFP_KERNEL); if (handle == NULL) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) - usb_autopm_put_interface(video->dev->intf); + usb_autopm_put_interface(stream->dev->intf); #endif ret = -ENOMEM; goto done; } - if (atomic_inc_return(&video->dev->users) == 1) { - if ((ret = uvc_status_start(video->dev)) < 0) { + if (atomic_inc_return(&stream->dev->users) == 1) { + ret = uvc_status_start(stream->dev); + if (ret < 0) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) - usb_autopm_put_interface(video->dev->intf); + usb_autopm_put_interface(stream->dev->intf); #endif - atomic_dec(&video->dev->users); + atomic_dec(&stream->dev->users); kfree(handle); goto done; } } - handle->device = video; + handle->chain = stream->chain; + handle->stream = stream; handle->state = UVC_HANDLE_PASSIVE; file->private_data = handle; - kref_get(&video->dev->kref); + kref_get(&stream->dev->kref); done: mutex_unlock(&uvc_driver.open_mutex); @@ -467,20 +471,20 @@ done: static int uvc_v4l2_release(struct file *file) { - struct uvc_video_device *video = video_drvdata(file); struct uvc_fh *handle = (struct uvc_fh *)file->private_data; + struct uvc_streaming *stream = handle->stream; uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_release\n"); /* Only free resources if this is a privileged handle. */ if (uvc_has_privileges(handle)) { - uvc_video_enable(video, 0); + uvc_video_enable(stream, 0); - mutex_lock(&video->queue.mutex); - if (uvc_free_buffers(&video->queue) < 0) + mutex_lock(&stream->queue.mutex); + if (uvc_free_buffers(&stream->queue) < 0) uvc_printk(KERN_ERR, "uvc_v4l2_release: Unable to " "free buffers.\n"); - mutex_unlock(&video->queue.mutex); + mutex_unlock(&stream->queue.mutex); } /* Release the file handle. */ @@ -488,21 +492,22 @@ static int uvc_v4l2_release(struct file *file) kfree(handle); file->private_data = NULL; - if (atomic_dec_return(&video->dev->users) == 0) - uvc_status_stop(video->dev); + if (atomic_dec_return(&stream->dev->users) == 0) + uvc_status_stop(stream->dev); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) - usb_autopm_put_interface(video->dev->intf); + usb_autopm_put_interface(stream->dev->intf); #endif - kref_put(&video->dev->kref, uvc_delete); + kref_put(&stream->dev->kref, uvc_delete); return 0; } static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct video_device *vdev = video_devdata(file); - struct uvc_video_device *video = video_get_drvdata(vdev); struct uvc_fh *handle = (struct uvc_fh *)file->private_data; + struct uvc_video_chain *chain = handle->chain; + struct uvc_streaming *stream = handle->stream; long ret = 0; switch (cmd) { @@ -514,10 +519,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) memset(cap, 0, sizeof *cap); strlcpy(cap->driver, "uvcvideo", sizeof cap->driver); strlcpy(cap->card, vdev->name, sizeof cap->card); - usb_make_path(video->dev->udev, + usb_make_path(stream->dev->udev, cap->bus_info, sizeof(cap->bus_info)); cap->version = DRIVER_VERSION_NUMBER; - if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; else @@ -528,7 +533,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) /* Get, Set & Query control */ case VIDIOC_QUERYCTRL: - return uvc_query_v4l2_ctrl(video, arg); + return uvc_query_v4l2_ctrl(chain, arg); case VIDIOC_G_CTRL: { @@ -538,12 +543,12 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) memset(&xctrl, 0, sizeof xctrl); xctrl.id = ctrl->id; - ret = uvc_ctrl_begin(video); - if (ret < 0) + ret = uvc_ctrl_begin(chain); + if (ret < 0) return ret; - ret = uvc_ctrl_get(video, &xctrl); - uvc_ctrl_rollback(video); + ret = uvc_ctrl_get(chain, &xctrl); + uvc_ctrl_rollback(chain); if (ret >= 0) ctrl->value = xctrl.value; break; @@ -558,21 +563,21 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) xctrl.id = ctrl->id; xctrl.value = ctrl->value; - ret = uvc_ctrl_begin(video); - if (ret < 0) + uvc_ctrl_begin(chain); + if (ret < 0) return ret; - ret = uvc_ctrl_set(video, &xctrl); + ret = uvc_ctrl_set(chain, &xctrl); if (ret < 0) { - uvc_ctrl_rollback(video); + uvc_ctrl_rollback(chain); return ret; } - ret = uvc_ctrl_commit(video); + ret = uvc_ctrl_commit(chain); break; } case VIDIOC_QUERYMENU: - return uvc_v4l2_query_menu(video, arg); + return uvc_v4l2_query_menu(chain, arg); case VIDIOC_G_EXT_CTRLS: { @@ -580,20 +585,20 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) struct v4l2_ext_control *ctrl = ctrls->controls; unsigned int i; - ret = uvc_ctrl_begin(video); - if (ret < 0) + ret = uvc_ctrl_begin(chain); + if (ret < 0) return ret; for (i = 0; i < ctrls->count; ++ctrl, ++i) { - ret = uvc_ctrl_get(video, ctrl); + ret = uvc_ctrl_get(chain, ctrl); if (ret < 0) { - uvc_ctrl_rollback(video); + uvc_ctrl_rollback(chain); ctrls->error_idx = i; return ret; } } ctrls->error_idx = 0; - ret = uvc_ctrl_rollback(video); + ret = uvc_ctrl_rollback(chain); break; } @@ -604,14 +609,14 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) struct v4l2_ext_control *ctrl = ctrls->controls; unsigned int i; - ret = uvc_ctrl_begin(video); + ret = uvc_ctrl_begin(chain); if (ret < 0) return ret; for (i = 0; i < ctrls->count; ++ctrl, ++i) { - ret = uvc_ctrl_set(video, ctrl); + ret = uvc_ctrl_set(chain, ctrl); if (ret < 0) { - uvc_ctrl_rollback(video); + uvc_ctrl_rollback(chain); ctrls->error_idx = i; return ret; } @@ -620,31 +625,31 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) ctrls->error_idx = 0; if (cmd == VIDIOC_S_EXT_CTRLS) - ret = uvc_ctrl_commit(video); + ret = uvc_ctrl_commit(chain); else - ret = uvc_ctrl_rollback(video); + ret = uvc_ctrl_rollback(chain); break; } /* Get, Set & Enum input */ case VIDIOC_ENUMINPUT: { - const struct uvc_entity *selector = video->selector; + const struct uvc_entity *selector = chain->selector; struct v4l2_input *input = arg; struct uvc_entity *iterm = NULL; u32 index = input->index; int pin = 0; if (selector == NULL || - (video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) { + (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) { if (index != 0) return -EINVAL; - iterm = list_first_entry(&video->iterms, + iterm = list_first_entry(&chain->iterms, struct uvc_entity, chain); pin = iterm->id; } else if (pin < selector->selector.bNrInPins) { pin = selector->selector.baSourceID[index]; - list_for_each_entry(iterm, video->iterms.next, chain) { + list_for_each_entry(iterm, chain->iterms.next, chain) { if (iterm->id == pin) break; } @@ -665,14 +670,14 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) { u8 input; - if (video->selector == NULL || - (video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) { + if (chain->selector == NULL || + (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) { *(int *)arg = 0; break; } - ret = uvc_query_ctrl(video->dev, UVC_GET_CUR, - video->selector->id, video->dev->intfnum, + ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, + chain->selector->id, chain->dev->intfnum, UVC_SU_INPUT_SELECT_CONTROL, &input, 1); if (ret < 0) return ret; @@ -688,18 +693,18 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) if ((ret = uvc_acquire_privileges(handle)) < 0) return ret; - if (video->selector == NULL || - (video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) { + if (chain->selector == NULL || + (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) { if (input != 1) return -EINVAL; break; } - if (input == 0 || input > video->selector->selector.bNrInPins) + if (input == 0 || input > chain->selector->selector.bNrInPins) return -EINVAL; - return uvc_query_ctrl(video->dev, UVC_SET_CUR, - video->selector->id, video->dev->intfnum, + return uvc_query_ctrl(chain->dev, UVC_SET_CUR, + chain->selector->id, chain->dev->intfnum, UVC_SU_INPUT_SELECT_CONTROL, &input, 1); } @@ -711,15 +716,15 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) enum v4l2_buf_type type = fmt->type; __u32 index = fmt->index; - if (fmt->type != video->streaming->type || - fmt->index >= video->streaming->nformats) + if (fmt->type != stream->type || + fmt->index >= stream->nformats) return -EINVAL; memset(fmt, 0, sizeof(*fmt)); fmt->index = index; fmt->type = type; - format = &video->streaming->format[fmt->index]; + format = &stream->format[fmt->index]; fmt->flags = 0; if (format->flags & UVC_FMT_FLAG_COMPRESSED) fmt->flags |= V4L2_FMT_FLAG_COMPRESSED; @@ -737,17 +742,17 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) if ((ret = uvc_acquire_privileges(handle)) < 0) return ret; - return uvc_v4l2_try_format(video, arg, &probe, NULL, NULL); + return uvc_v4l2_try_format(stream, arg, &probe, NULL, NULL); } case VIDIOC_S_FMT: if ((ret = uvc_acquire_privileges(handle)) < 0) return ret; - return uvc_v4l2_set_format(video, arg); + return uvc_v4l2_set_format(stream, arg); case VIDIOC_G_FMT: - return uvc_v4l2_get_format(video, arg); + return uvc_v4l2_get_format(stream, arg); /* Frame size enumeration */ case VIDIOC_ENUM_FRAMESIZES: @@ -758,10 +763,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) int i; /* Look for the given pixel format */ - for (i = 0; i < video->streaming->nformats; i++) { - if (video->streaming->format[i].fcc == + for (i = 0; i < stream->nformats; i++) { + if (stream->format[i].fcc == fsize->pixel_format) { - format = &video->streaming->format[i]; + format = &stream->format[i]; break; } } @@ -787,10 +792,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) int i; /* Look for the given pixel format and frame size */ - for (i = 0; i < video->streaming->nformats; i++) { - if (video->streaming->format[i].fcc == + for (i = 0; i < stream->nformats; i++) { + if (stream->format[i].fcc == fival->pixel_format) { - format = &video->streaming->format[i]; + format = &stream->format[i]; break; } } @@ -840,21 +845,21 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) /* Get & Set streaming parameters */ case VIDIOC_G_PARM: - return uvc_v4l2_get_streamparm(video, arg); + return uvc_v4l2_get_streamparm(stream, arg); case VIDIOC_S_PARM: if ((ret = uvc_acquire_privileges(handle)) < 0) return ret; - return uvc_v4l2_set_streamparm(video, arg); + return uvc_v4l2_set_streamparm(stream, arg); /* Cropping and scaling */ case VIDIOC_CROPCAP: { struct v4l2_cropcap *ccap = arg; - struct uvc_frame *frame = video->streaming->cur_frame; + struct uvc_frame *frame = stream->cur_frame; - if (ccap->type != video->streaming->type) + if (ccap->type != stream->type) return -EINVAL; ccap->bounds.left = 0; @@ -878,16 +883,16 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct v4l2_requestbuffers *rb = arg; unsigned int bufsize = - video->streaming->ctrl.dwMaxVideoFrameSize; + stream->ctrl.dwMaxVideoFrameSize; - if (rb->type != video->streaming->type || + if (rb->type != stream->type || rb->memory != V4L2_MEMORY_MMAP) return -EINVAL; if ((ret = uvc_acquire_privileges(handle)) < 0) return ret; - ret = uvc_alloc_buffers(&video->queue, rb->count, bufsize); + ret = uvc_alloc_buffers(&stream->queue, rb->count, bufsize); if (ret < 0) return ret; @@ -900,39 +905,40 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct v4l2_buffer *buf = arg; - if (buf->type != video->streaming->type) + if (buf->type != stream->type) return -EINVAL; if (!uvc_has_privileges(handle)) return -EBUSY; - return uvc_query_buffer(&video->queue, buf); + return uvc_query_buffer(&stream->queue, buf); } case VIDIOC_QBUF: if (!uvc_has_privileges(handle)) return -EBUSY; - return uvc_queue_buffer(&video->queue, arg); + return uvc_queue_buffer(&stream->queue, arg); case VIDIOC_DQBUF: if (!uvc_has_privileges(handle)) return -EBUSY; - return uvc_dequeue_buffer(&video->queue, arg, + return uvc_dequeue_buffer(&stream->queue, arg, file->f_flags & O_NONBLOCK); case VIDIOC_STREAMON: { int *type = arg; - if (*type != video->streaming->type) + if (*type != stream->type) return -EINVAL; if (!uvc_has_privileges(handle)) return -EBUSY; - if ((ret = uvc_video_enable(video, 1)) < 0) + ret = uvc_video_enable(stream, 1); + if (ret < 0) return ret; break; } @@ -941,13 +947,13 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) { int *type = arg; - if (*type != video->streaming->type) + if (*type != stream->type) return -EINVAL; if (!uvc_has_privileges(handle)) return -EBUSY; - return uvc_video_enable(video, 0); + return uvc_video_enable(stream, 0); } /* Analog video standards make no sense for digital cameras. */ @@ -1021,10 +1027,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) } case UVCIOC_CTRL_GET: - return uvc_xu_ctrl_query(video, arg, 0); + return uvc_xu_ctrl_query(chain, arg, 0); case UVCIOC_CTRL_SET: - return uvc_xu_ctrl_query(video, arg, 1); + return uvc_xu_ctrl_query(chain, arg, 1); default: if ((ret = v4l_compat_translate_ioctl(file, cmd, arg, @@ -1078,7 +1084,9 @@ static struct vm_operations_struct uvc_vm_ops = { static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma) { - struct uvc_video_device *video = video_drvdata(file); + struct uvc_fh *handle = (struct uvc_fh *)file->private_data; + struct uvc_streaming *stream = handle->stream; + struct uvc_video_queue *queue = &stream->queue; struct uvc_buffer *uninitialized_var(buffer); struct page *page; unsigned long addr, start, size; @@ -1090,15 +1098,15 @@ static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma) start = vma->vm_start; size = vma->vm_end - vma->vm_start; - mutex_lock(&video->queue.mutex); + mutex_lock(&queue->mutex); - for (i = 0; i < video->queue.count; ++i) { - buffer = &video->queue.buffer[i]; + for (i = 0; i < queue->count; ++i) { + buffer = &queue->buffer[i]; if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff) break; } - if (i == video->queue.count || size != video->queue.buf_size) { + if (i == queue->count || size != queue->buf_size) { ret = -EINVAL; goto done; } @@ -1109,7 +1117,7 @@ static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma) */ vma->vm_flags |= VM_IO; - addr = (unsigned long)video->queue.mem + buffer->buf.m.offset; + addr = (unsigned long)queue->mem + buffer->buf.m.offset; while (size > 0) { page = vmalloc_to_page((void *)addr); if ((ret = vm_insert_page(vma, start, page)) < 0) @@ -1125,17 +1133,18 @@ static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma) uvc_vm_open(vma); done: - mutex_unlock(&video->queue.mutex); + mutex_unlock(&queue->mutex); return ret; } static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait) { - struct uvc_video_device *video = video_drvdata(file); + struct uvc_fh *handle = (struct uvc_fh *)file->private_data; + struct uvc_streaming *stream = handle->stream; uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_poll\n"); - return uvc_queue_poll(&video->queue, file, wait); + return uvc_queue_poll(&stream->queue, file, wait); } const struct v4l2_file_operations uvc_fops = { diff --git a/linux/drivers/media/video/uvc/uvc_video.c b/linux/drivers/media/video/uvc/uvc_video.c index f4f4e1bb3..792a93a1c 100644 --- a/linux/drivers/media/video/uvc/uvc_video.c +++ b/linux/drivers/media/video/uvc/uvc_video.c @@ -61,7 +61,7 @@ int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, return 0; } -static void uvc_fixup_video_ctrl(struct uvc_video_device *video, +static void uvc_fixup_video_ctrl(struct uvc_streaming *stream, struct uvc_streaming_control *ctrl) { struct uvc_format *format; @@ -69,10 +69,10 @@ static void uvc_fixup_video_ctrl(struct uvc_video_device *video, unsigned int i; if (ctrl->bFormatIndex <= 0 || - ctrl->bFormatIndex > video->streaming->nformats) + ctrl->bFormatIndex > stream->nformats) return; - format = &video->streaming->format[ctrl->bFormatIndex - 1]; + format = &stream->format[ctrl->bFormatIndex - 1]; for (i = 0; i < format->nframes; ++i) { if (format->frame[i].bFrameIndex == ctrl->bFrameIndex) { @@ -86,12 +86,12 @@ static void uvc_fixup_video_ctrl(struct uvc_video_device *video, if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) || (ctrl->dwMaxVideoFrameSize == 0 && - video->dev->uvc_version < 0x0110)) + stream->dev->uvc_version < 0x0110)) ctrl->dwMaxVideoFrameSize = frame->dwMaxVideoFrameBufferSize; - if (video->dev->quirks & UVC_QUIRK_FIX_BANDWIDTH && - video->streaming->intf->num_altsetting > 1) { + if (stream->dev->quirks & UVC_QUIRK_FIX_BANDWIDTH && + stream->intf->num_altsetting > 1) { u32 interval; u32 bandwidth; @@ -108,7 +108,7 @@ static void uvc_fixup_video_ctrl(struct uvc_video_device *video, bandwidth = frame->wWidth * frame->wHeight / 8 * format->bpp; bandwidth *= 10000000 / interval + 1; bandwidth /= 1000; - if (video->dev->udev->speed == USB_SPEED_HIGH) + if (stream->dev->udev->speed == USB_SPEED_HIGH) bandwidth /= 8; bandwidth += 12; @@ -116,22 +116,22 @@ static void uvc_fixup_video_ctrl(struct uvc_video_device *video, } } -static int uvc_get_video_ctrl(struct uvc_video_device *video, +static int uvc_get_video_ctrl(struct uvc_streaming *stream, struct uvc_streaming_control *ctrl, int probe, __u8 query) { __u8 *data; __u16 size; int ret; - size = video->dev->uvc_version >= 0x0110 ? 34 : 26; + size = stream->dev->uvc_version >= 0x0110 ? 34 : 26; data = kmalloc(size, GFP_KERNEL); if (data == NULL) return -ENOMEM; - if ((video->dev->quirks & UVC_QUIRK_PROBE_DEF) && query == UVC_GET_DEF) + if ((stream->dev->quirks & UVC_QUIRK_PROBE_DEF) && query == UVC_GET_DEF) return -EIO; - ret = __uvc_query_ctrl(video->dev, query, 0, video->streaming->intfnum, + ret = __uvc_query_ctrl(stream->dev, query, 0, stream->intfnum, probe ? UVC_VS_PROBE_CONTROL : UVC_VS_COMMIT_CONTROL, data, size, UVC_CTRL_STREAMING_TIMEOUT); @@ -140,7 +140,7 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video, * answer a GET_MIN or GET_MAX request with the wCompQuality * field only. */ - uvc_warn_once(video->dev, UVC_WARN_MINMAX, "UVC non " + uvc_warn_once(stream->dev, UVC_WARN_MINMAX, "UVC non " "compliance - GET_MIN/MAX(PROBE) incorrectly " "supported. Enabling workaround.\n"); memset(ctrl, 0, sizeof ctrl); @@ -152,7 +152,7 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video, * video probe control. Warn once and return, the caller will * fall back to GET_CUR. */ - uvc_warn_once(video->dev, UVC_WARN_PROBE_DEF, "UVC non " + uvc_warn_once(stream->dev, UVC_WARN_PROBE_DEF, "UVC non " "compliance - GET_DEF(PROBE) not supported. " "Enabling workaround.\n"); ret = -EIO; @@ -184,7 +184,7 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video, ctrl->bMinVersion = data[32]; ctrl->bMaxVersion = data[33]; } else { - ctrl->dwClockFrequency = video->dev->clock_frequency; + ctrl->dwClockFrequency = stream->dev->clock_frequency; ctrl->bmFramingInfo = 0; ctrl->bPreferedVersion = 0; ctrl->bMinVersion = 0; @@ -195,7 +195,7 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video, * dwMaxPayloadTransferSize fields. Try to get the value from the * format and frame descriptors. */ - uvc_fixup_video_ctrl(video, ctrl); + uvc_fixup_video_ctrl(stream, ctrl); ret = 0; out: @@ -203,14 +203,14 @@ out: return ret; } -static int uvc_set_video_ctrl(struct uvc_video_device *video, +static int uvc_set_video_ctrl(struct uvc_streaming *stream, struct uvc_streaming_control *ctrl, int probe) { __u8 *data; __u16 size; int ret; - size = video->dev->uvc_version >= 0x0110 ? 34 : 26; + size = stream->dev->uvc_version >= 0x0110 ? 34 : 26; data = kzalloc(size, GFP_KERNEL); if (data == NULL) return -ENOMEM; @@ -235,8 +235,7 @@ static int uvc_set_video_ctrl(struct uvc_video_device *video, data[33] = ctrl->bMaxVersion; } - ret = __uvc_query_ctrl(video->dev, UVC_SET_CUR, 0, - video->streaming->intfnum, + ret = __uvc_query_ctrl(stream->dev, UVC_SET_CUR, 0, stream->intfnum, probe ? UVC_VS_PROBE_CONTROL : UVC_VS_COMMIT_CONTROL, data, size, UVC_CTRL_STREAMING_TIMEOUT); if (ret != size) { @@ -250,7 +249,7 @@ static int uvc_set_video_ctrl(struct uvc_video_device *video, return ret; } -int uvc_probe_video(struct uvc_video_device *video, +int uvc_probe_video(struct uvc_streaming *stream, struct uvc_streaming_control *probe) { struct uvc_streaming_control probe_min, probe_max; @@ -258,7 +257,7 @@ int uvc_probe_video(struct uvc_video_device *video, unsigned int i; int ret; - mutex_lock(&video->streaming->mutex); + mutex_lock(&stream->mutex); /* Perform probing. The device should adjust the requested values * according to its capabilities. However, some devices, namely the @@ -267,15 +266,16 @@ int uvc_probe_video(struct uvc_video_device *video, * that reason, if the needed bandwidth exceeds the maximum available * bandwidth, try to lower the quality. */ - if ((ret = uvc_set_video_ctrl(video, probe, 1)) < 0) + ret = uvc_set_video_ctrl(stream, probe, 1); + if (ret < 0) goto done; /* Get the minimum and maximum values for compression settings. */ - if (!(video->dev->quirks & UVC_QUIRK_PROBE_MINMAX)) { - ret = uvc_get_video_ctrl(video, &probe_min, 1, UVC_GET_MIN); + if (!(stream->dev->quirks & UVC_QUIRK_PROBE_MINMAX)) { + ret = uvc_get_video_ctrl(stream, &probe_min, 1, UVC_GET_MIN); if (ret < 0) goto done; - ret = uvc_get_video_ctrl(video, &probe_max, 1, UVC_GET_MAX); + ret = uvc_get_video_ctrl(stream, &probe_max, 1, UVC_GET_MAX); if (ret < 0) goto done; @@ -283,21 +283,21 @@ int uvc_probe_video(struct uvc_video_device *video, } for (i = 0; i < 2; ++i) { - ret = uvc_set_video_ctrl(video, probe, 1); + ret = uvc_set_video_ctrl(stream, probe, 1); if (ret < 0) goto done; - ret = uvc_get_video_ctrl(video, probe, 1, UVC_GET_CUR); + ret = uvc_get_video_ctrl(stream, probe, 1, UVC_GET_CUR); if (ret < 0) goto done; - if (video->streaming->intf->num_altsetting == 1) + if (stream->intf->num_altsetting == 1) break; bandwidth = probe->dwMaxPayloadTransferSize; - if (bandwidth <= video->streaming->maxpsize) + if (bandwidth <= stream->maxpsize) break; - if (video->dev->quirks & UVC_QUIRK_PROBE_MINMAX) { + if (stream->dev->quirks & UVC_QUIRK_PROBE_MINMAX) { ret = -ENOSPC; goto done; } @@ -310,14 +310,14 @@ int uvc_probe_video(struct uvc_video_device *video, } done: - mutex_unlock(&video->streaming->mutex); + mutex_unlock(&stream->mutex); return ret; } -int uvc_commit_video(struct uvc_video_device *video, +int uvc_commit_video(struct uvc_streaming *stream, struct uvc_streaming_control *probe) { - return uvc_set_video_ctrl(video, probe, 0); + return uvc_set_video_ctrl(stream, probe, 0); } /* ------------------------------------------------------------------------ @@ -369,7 +369,7 @@ int uvc_commit_video(struct uvc_video_device *video, * to be called with a NULL buf parameter. uvc_video_decode_data and * uvc_video_decode_end will never be called with a NULL buffer. */ -static int uvc_video_decode_start(struct uvc_video_device *video, +static int uvc_video_decode_start(struct uvc_streaming *stream, struct uvc_buffer *buf, const __u8 *data, int len) { __u8 fid; @@ -395,25 +395,25 @@ static int uvc_video_decode_start(struct uvc_video_device *video, * NULL. */ if (buf == NULL) { - video->last_fid = fid; + stream->last_fid = fid; return -ENODATA; } /* Synchronize to the input stream by waiting for the FID bit to be * toggled when the the buffer state is not UVC_BUF_STATE_ACTIVE. - * video->last_fid is initialized to -1, so the first isochronous + * stream->last_fid is initialized to -1, so the first isochronous * frame will always be in sync. * - * If the device doesn't toggle the FID bit, invert video->last_fid + * If the device doesn't toggle the FID bit, invert stream->last_fid * when the EOF bit is set to force synchronisation on the next packet. */ if (buf->state != UVC_BUF_STATE_ACTIVE) { - if (fid == video->last_fid) { + if (fid == stream->last_fid) { uvc_trace(UVC_TRACE_FRAME, "Dropping payload (out of " "sync).\n"); - if ((video->dev->quirks & UVC_QUIRK_STREAM_NO_FID) && + if ((stream->dev->quirks & UVC_QUIRK_STREAM_NO_FID) && (data[1] & UVC_STREAM_EOF)) - video->last_fid ^= UVC_STREAM_FID; + stream->last_fid ^= UVC_STREAM_FID; return -ENODATA; } @@ -428,7 +428,7 @@ static int uvc_video_decode_start(struct uvc_video_device *video, * last payload can be lost anyway). We thus must check if the FID has * been toggled. * - * video->last_fid is initialized to -1, so the first isochronous + * stream->last_fid is initialized to -1, so the first isochronous * frame will never trigger an end of frame detection. * * Empty buffers (bytesused == 0) don't trigger end of frame detection @@ -436,22 +436,22 @@ static int uvc_video_decode_start(struct uvc_video_device *video, * avoids detecting end of frame conditions at FID toggling if the * previous payload had the EOF bit set. */ - if (fid != video->last_fid && buf->buf.bytesused != 0) { + if (fid != stream->last_fid && buf->buf.bytesused != 0) { uvc_trace(UVC_TRACE_FRAME, "Frame complete (FID bit " "toggled).\n"); buf->state = UVC_BUF_STATE_DONE; return -EAGAIN; } - video->last_fid = fid; + stream->last_fid = fid; return data[0]; } -static void uvc_video_decode_data(struct uvc_video_device *video, +static void uvc_video_decode_data(struct uvc_streaming *stream, struct uvc_buffer *buf, const __u8 *data, int len) { - struct uvc_video_queue *queue = &video->queue; + struct uvc_video_queue *queue = &stream->queue; unsigned int maxlen, nbytes; void *mem; @@ -472,7 +472,7 @@ static void uvc_video_decode_data(struct uvc_video_device *video, } } -static void uvc_video_decode_end(struct uvc_video_device *video, +static void uvc_video_decode_end(struct uvc_streaming *stream, struct uvc_buffer *buf, const __u8 *data, int len) { /* Mark the buffer as done if the EOF marker is set. */ @@ -481,8 +481,8 @@ static void uvc_video_decode_end(struct uvc_video_device *video, if (data[0] == len) uvc_trace(UVC_TRACE_FRAME, "EOF in empty payload.\n"); buf->state = UVC_BUF_STATE_DONE; - if (video->dev->quirks & UVC_QUIRK_STREAM_NO_FID) - video->last_fid ^= UVC_STREAM_FID; + if (stream->dev->quirks & UVC_QUIRK_STREAM_NO_FID) + stream->last_fid ^= UVC_STREAM_FID; } } @@ -497,26 +497,26 @@ static void uvc_video_decode_end(struct uvc_video_device *video, * uvc_video_encode_data is called for every URB and copies the data from the * video buffer to the transfer buffer. */ -static int uvc_video_encode_header(struct uvc_video_device *video, +static int uvc_video_encode_header(struct uvc_streaming *stream, struct uvc_buffer *buf, __u8 *data, int len) { data[0] = 2; /* Header length */ data[1] = UVC_STREAM_EOH | UVC_STREAM_EOF - | (video->last_fid & UVC_STREAM_FID); + | (stream->last_fid & UVC_STREAM_FID); return 2; } -static int uvc_video_encode_data(struct uvc_video_device *video, +static int uvc_video_encode_data(struct uvc_streaming *stream, struct uvc_buffer *buf, __u8 *data, int len) { - struct uvc_video_queue *queue = &video->queue; + struct uvc_video_queue *queue = &stream->queue; unsigned int nbytes; void *mem; /* Copy video data to the URB buffer. */ mem = queue->mem + buf->buf.m.offset + queue->buf_used; nbytes = min((unsigned int)len, buf->buf.bytesused - queue->buf_used); - nbytes = min(video->bulk.max_payload_size - video->bulk.payload_size, + nbytes = min(stream->bulk.max_payload_size - stream->bulk.payload_size, nbytes); memcpy(data, mem, nbytes); @@ -532,8 +532,8 @@ static int uvc_video_encode_data(struct uvc_video_device *video, /* * Completion handler for video URBs. */ -static void uvc_video_decode_isoc(struct urb *urb, - struct uvc_video_device *video, struct uvc_buffer *buf) +static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream, + struct uvc_buffer *buf) { u8 *mem; int ret, i; @@ -548,31 +548,32 @@ static void uvc_video_decode_isoc(struct urb *urb, /* Decode the payload header. */ mem = urb->transfer_buffer + urb->iso_frame_desc[i].offset; do { - ret = uvc_video_decode_start(video, buf, mem, + ret = uvc_video_decode_start(stream, buf, mem, urb->iso_frame_desc[i].actual_length); if (ret == -EAGAIN) - buf = uvc_queue_next_buffer(&video->queue, buf); + buf = uvc_queue_next_buffer(&stream->queue, + buf); } while (ret == -EAGAIN); if (ret < 0) continue; /* Decode the payload data. */ - uvc_video_decode_data(video, buf, mem + ret, + uvc_video_decode_data(stream, buf, mem + ret, urb->iso_frame_desc[i].actual_length - ret); /* Process the header again. */ - uvc_video_decode_end(video, buf, mem, + uvc_video_decode_end(stream, buf, mem, urb->iso_frame_desc[i].actual_length); if (buf->state == UVC_BUF_STATE_DONE || buf->state == UVC_BUF_STATE_ERROR) - buf = uvc_queue_next_buffer(&video->queue, buf); + buf = uvc_queue_next_buffer(&stream->queue, buf); } } -static void uvc_video_decode_bulk(struct urb *urb, - struct uvc_video_device *video, struct uvc_buffer *buf) +static void uvc_video_decode_bulk(struct urb *urb, struct uvc_streaming *stream, + struct uvc_buffer *buf) { u8 *mem; int len, ret; @@ -582,24 +583,25 @@ static void uvc_video_decode_bulk(struct urb *urb, mem = urb->transfer_buffer; len = urb->actual_length; - video->bulk.payload_size += len; + stream->bulk.payload_size += len; /* If the URB is the first of its payload, decode and save the * header. */ - if (video->bulk.header_size == 0 && !video->bulk.skip_payload) { + if (stream->bulk.header_size == 0 && !stream->bulk.skip_payload) { do { - ret = uvc_video_decode_start(video, buf, mem, len); + ret = uvc_video_decode_start(stream, buf, mem, len); if (ret == -EAGAIN) - buf = uvc_queue_next_buffer(&video->queue, buf); + buf = uvc_queue_next_buffer(&stream->queue, + buf); } while (ret == -EAGAIN); /* If an error occured skip the rest of the payload. */ if (ret < 0 || buf == NULL) { - video->bulk.skip_payload = 1; + stream->bulk.skip_payload = 1; } else { - memcpy(video->bulk.header, mem, ret); - video->bulk.header_size = ret; + memcpy(stream->bulk.header, mem, ret); + stream->bulk.header_size = ret; mem += ret; len -= ret; @@ -612,33 +614,34 @@ static void uvc_video_decode_bulk(struct urb *urb, */ /* Process video data. */ - if (!video->bulk.skip_payload && buf != NULL) - uvc_video_decode_data(video, buf, mem, len); + if (!stream->bulk.skip_payload && buf != NULL) + uvc_video_decode_data(stream, buf, mem, len); /* Detect the payload end by a URB smaller than the maximum size (or * a payload size equal to the maximum) and process the header again. */ if (urb->actual_length < urb->transfer_buffer_length || - video->bulk.payload_size >= video->bulk.max_payload_size) { - if (!video->bulk.skip_payload && buf != NULL) { - uvc_video_decode_end(video, buf, video->bulk.header, - video->bulk.payload_size); + stream->bulk.payload_size >= stream->bulk.max_payload_size) { + if (!stream->bulk.skip_payload && buf != NULL) { + uvc_video_decode_end(stream, buf, stream->bulk.header, + stream->bulk.payload_size); if (buf->state == UVC_BUF_STATE_DONE || buf->state == UVC_BUF_STATE_ERROR) - buf = uvc_queue_next_buffer(&video->queue, buf); + buf = uvc_queue_next_buffer(&stream->queue, + buf); } - video->bulk.header_size = 0; - video->bulk.skip_payload = 0; - video->bulk.payload_size = 0; + stream->bulk.header_size = 0; + stream->bulk.skip_payload = 0; + stream->bulk.payload_size = 0; } } -static void uvc_video_encode_bulk(struct urb *urb, - struct uvc_video_device *video, struct uvc_buffer *buf) +static void uvc_video_encode_bulk(struct urb *urb, struct uvc_streaming *stream, + struct uvc_buffer *buf) { u8 *mem = urb->transfer_buffer; - int len = video->urb_size, ret; + int len = stream->urb_size, ret; if (buf == NULL) { urb->transfer_buffer_length = 0; @@ -646,34 +649,34 @@ static void uvc_video_encode_bulk(struct urb *urb, } /* If the URB is the first of its payload, add the header. */ - if (video->bulk.header_size == 0) { - ret = uvc_video_encode_header(video, buf, mem, len); - video->bulk.header_size = ret; - video->bulk.payload_size += ret; + if (stream->bulk.header_size == 0) { + ret = uvc_video_encode_header(stream, buf, mem, len); + stream->bulk.header_size = ret; + stream->bulk.payload_size += ret; mem += ret; len -= ret; } /* Process video data. */ - ret = uvc_video_encode_data(video, buf, mem, len); + ret = uvc_video_encode_data(stream, buf, mem, len); - video->bulk.payload_size += ret; + stream->bulk.payload_size += ret; len -= ret; - if (buf->buf.bytesused == video->queue.buf_used || - video->bulk.payload_size == video->bulk.max_payload_size) { - if (buf->buf.bytesused == video->queue.buf_used) { - video->queue.buf_used = 0; + if (buf->buf.bytesused == stream->queue.buf_used || + stream->bulk.payload_size == stream->bulk.max_payload_size) { + if (buf->buf.bytesused == stream->queue.buf_used) { + stream->queue.buf_used = 0; buf->state = UVC_BUF_STATE_DONE; - uvc_queue_next_buffer(&video->queue, buf); - video->last_fid ^= UVC_STREAM_FID; + uvc_queue_next_buffer(&stream->queue, buf); + stream->last_fid ^= UVC_STREAM_FID; } - video->bulk.header_size = 0; - video->bulk.payload_size = 0; + stream->bulk.header_size = 0; + stream->bulk.payload_size = 0; } - urb->transfer_buffer_length = video->urb_size - len; + urb->transfer_buffer_length = stream->urb_size - len; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) @@ -682,8 +685,8 @@ static void uvc_video_complete(struct urb *urb, struct pt_regs *regs) static void uvc_video_complete(struct urb *urb) #endif { - struct uvc_video_device *video = urb->context; - struct uvc_video_queue *queue = &video->queue; + struct uvc_streaming *stream = urb->context; + struct uvc_video_queue *queue = &stream->queue; struct uvc_buffer *buf = NULL; unsigned long flags; int ret; @@ -697,7 +700,7 @@ static void uvc_video_complete(struct urb *urb) "completion handler.\n", urb->status); case -ENOENT: /* usb_kill_urb() called. */ - if (video->frozen) + if (stream->frozen) return; case -ECONNRESET: /* usb_unlink_urb() called. */ @@ -712,7 +715,7 @@ static void uvc_video_complete(struct urb *urb) queue); spin_unlock_irqrestore(&queue->irqlock, flags); - video->decode(urb, video, buf); + stream->decode(urb, stream, buf); if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n", @@ -723,19 +726,19 @@ static void uvc_video_complete(struct urb *urb) /* * Free transfer buffers. */ -static void uvc_free_urb_buffers(struct uvc_video_device *video) +static void uvc_free_urb_buffers(struct uvc_streaming *stream) { unsigned int i; for (i = 0; i < UVC_URBS; ++i) { - if (video->urb_buffer[i]) { - usb_buffer_free(video->dev->udev, video->urb_size, - video->urb_buffer[i], video->urb_dma[i]); - video->urb_buffer[i] = NULL; + if (stream->urb_buffer[i]) { + usb_buffer_free(stream->dev->udev, stream->urb_size, + stream->urb_buffer[i], stream->urb_dma[i]); + stream->urb_buffer[i] = NULL; } } - video->urb_size = 0; + stream->urb_size = 0; } /* @@ -749,15 +752,15 @@ static void uvc_free_urb_buffers(struct uvc_video_device *video) * * Return the number of allocated packets on success or 0 when out of memory. */ -static int uvc_alloc_urb_buffers(struct uvc_video_device *video, +static int uvc_alloc_urb_buffers(struct uvc_streaming *stream, unsigned int size, unsigned int psize, gfp_t gfp_flags) { unsigned int npackets; unsigned int i; /* Buffers are already allocated, bail out. */ - if (video->urb_size) - return video->urb_size / psize; + if (stream->urb_size) + return stream->urb_size / psize; /* Compute the number of packets. Bulk endpoints might transfer UVC * payloads accross multiple URBs. @@ -769,17 +772,17 @@ static int uvc_alloc_urb_buffers(struct uvc_video_device *video, /* Retry allocations until one succeed. */ for (; npackets > 1; npackets /= 2) { for (i = 0; i < UVC_URBS; ++i) { - video->urb_buffer[i] = usb_buffer_alloc( - video->dev->udev, psize * npackets, - gfp_flags | __GFP_NOWARN, &video->urb_dma[i]); - if (!video->urb_buffer[i]) { - uvc_free_urb_buffers(video); + stream->urb_buffer[i] = usb_buffer_alloc( + stream->dev->udev, psize * npackets, + gfp_flags | __GFP_NOWARN, &stream->urb_dma[i]); + if (!stream->urb_buffer[i]) { + uvc_free_urb_buffers(stream); break; } } if (i == UVC_URBS) { - video->urb_size = psize * npackets; + stream->urb_size = psize * npackets; return npackets; } } @@ -790,29 +793,30 @@ static int uvc_alloc_urb_buffers(struct uvc_video_device *video, /* * Uninitialize isochronous/bulk URBs and free transfer buffers. */ -static void uvc_uninit_video(struct uvc_video_device *video, int free_buffers) +static void uvc_uninit_video(struct uvc_streaming *stream, int free_buffers) { struct urb *urb; unsigned int i; for (i = 0; i < UVC_URBS; ++i) { - if ((urb = video->urb[i]) == NULL) + urb = stream->urb[i]; + if (urb == NULL) continue; usb_kill_urb(urb); usb_free_urb(urb); - video->urb[i] = NULL; + stream->urb[i] = NULL; } if (free_buffers) - uvc_free_urb_buffers(video); + uvc_free_urb_buffers(stream); } /* * Initialize isochronous URBs and allocate transfer buffers. The packet size * is given by the endpoint. */ -static int uvc_init_video_isoc(struct uvc_video_device *video, +static int uvc_init_video_isoc(struct uvc_streaming *stream, struct usb_host_endpoint *ep, gfp_t gfp_flags) { struct urb *urb; @@ -822,9 +826,9 @@ static int uvc_init_video_isoc(struct uvc_video_device *video, psize = le16_to_cpu(ep->desc.wMaxPacketSize); psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); - size = video->streaming->ctrl.dwMaxVideoFrameSize; + size = stream->ctrl.dwMaxVideoFrameSize; - npackets = uvc_alloc_urb_buffers(video, size, psize, gfp_flags); + npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags); if (npackets == 0) return -ENOMEM; @@ -833,18 +837,18 @@ static int uvc_init_video_isoc(struct uvc_video_device *video, for (i = 0; i < UVC_URBS; ++i) { urb = usb_alloc_urb(npackets, gfp_flags); if (urb == NULL) { - uvc_uninit_video(video, 1); + uvc_uninit_video(stream, 1); return -ENOMEM; } - urb->dev = video->dev->udev; - urb->context = video; - urb->pipe = usb_rcvisocpipe(video->dev->udev, + urb->dev = stream->dev->udev; + urb->context = stream; + urb->pipe = usb_rcvisocpipe(stream->dev->udev, ep->desc.bEndpointAddress); urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; urb->interval = ep->desc.bInterval; - urb->transfer_buffer = video->urb_buffer[i]; - urb->transfer_dma = video->urb_dma[i]; + urb->transfer_buffer = stream->urb_buffer[i]; + urb->transfer_dma = stream->urb_dma[i]; urb->complete = uvc_video_complete; urb->number_of_packets = npackets; urb->transfer_buffer_length = size; @@ -854,7 +858,7 @@ static int uvc_init_video_isoc(struct uvc_video_device *video, urb->iso_frame_desc[j].length = psize; } - video->urb[i] = urb; + stream->urb[i] = urb; } return 0; @@ -864,7 +868,7 @@ static int uvc_init_video_isoc(struct uvc_video_device *video, * Initialize bulk URBs and allocate transfer buffers. The packet size is * given by the endpoint. */ -static int uvc_init_video_bulk(struct uvc_video_device *video, +static int uvc_init_video_bulk(struct uvc_streaming *stream, struct usb_host_endpoint *ep, gfp_t gfp_flags) { struct urb *urb; @@ -873,39 +877,39 @@ static int uvc_init_video_bulk(struct uvc_video_device *video, u32 size; psize = le16_to_cpu(ep->desc.wMaxPacketSize) & 0x07ff; - size = video->streaming->ctrl.dwMaxPayloadTransferSize; - video->bulk.max_payload_size = size; + size = stream->ctrl.dwMaxPayloadTransferSize; + stream->bulk.max_payload_size = size; - npackets = uvc_alloc_urb_buffers(video, size, psize, gfp_flags); + npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags); if (npackets == 0) return -ENOMEM; size = npackets * psize; if (usb_endpoint_dir_in(&ep->desc)) - pipe = usb_rcvbulkpipe(video->dev->udev, + pipe = usb_rcvbulkpipe(stream->dev->udev, ep->desc.bEndpointAddress); else - pipe = usb_sndbulkpipe(video->dev->udev, + pipe = usb_sndbulkpipe(stream->dev->udev, ep->desc.bEndpointAddress); - if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + if (stream->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) size = 0; for (i = 0; i < UVC_URBS; ++i) { urb = usb_alloc_urb(0, gfp_flags); if (urb == NULL) { - uvc_uninit_video(video, 1); + uvc_uninit_video(stream, 1); return -ENOMEM; } - usb_fill_bulk_urb(urb, video->dev->udev, pipe, - video->urb_buffer[i], size, uvc_video_complete, - video); + usb_fill_bulk_urb(urb, stream->dev->udev, pipe, + stream->urb_buffer[i], size, uvc_video_complete, + stream); urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; - urb->transfer_dma = video->urb_dma[i]; + urb->transfer_dma = stream->urb_dma[i]; - video->urb[i] = urb; + stream->urb[i] = urb; } return 0; @@ -914,35 +918,35 @@ static int uvc_init_video_bulk(struct uvc_video_device *video, /* * Initialize isochronous/bulk URBs and allocate transfer buffers. */ -static int uvc_init_video(struct uvc_video_device *video, gfp_t gfp_flags) +static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags) { - struct usb_interface *intf = video->streaming->intf; + struct usb_interface *intf = stream->intf; struct usb_host_interface *alts; struct usb_host_endpoint *ep = NULL; - int intfnum = video->streaming->intfnum; + int intfnum = stream->intfnum; unsigned int bandwidth, psize, i; int ret; - video->last_fid = -1; - video->bulk.header_size = 0; - video->bulk.skip_payload = 0; - video->bulk.payload_size = 0; + stream->last_fid = -1; + stream->bulk.header_size = 0; + stream->bulk.skip_payload = 0; + stream->bulk.payload_size = 0; if (intf->num_altsetting > 1) { /* Isochronous endpoint, select the alternate setting. */ - bandwidth = video->streaming->ctrl.dwMaxPayloadTransferSize; + bandwidth = stream->ctrl.dwMaxPayloadTransferSize; if (bandwidth == 0) { uvc_printk(KERN_WARNING, "device %s requested null " "bandwidth, defaulting to lowest.\n", - video->vdev->name); + stream->dev->name); bandwidth = 1; } for (i = 0; i < intf->num_altsetting; ++i) { alts = &intf->altsetting[i]; ep = uvc_find_endpoint(alts, - video->streaming->header.bEndpointAddress); + stream->header.bEndpointAddress); if (ep == NULL) continue; @@ -956,18 +960,19 @@ static int uvc_init_video(struct uvc_video_device *video, gfp_t gfp_flags) if (i >= intf->num_altsetting) return -EIO; - if ((ret = usb_set_interface(video->dev->udev, intfnum, i)) < 0) + ret = usb_set_interface(stream->dev->udev, intfnum, i); + if (ret < 0) return ret; - ret = uvc_init_video_isoc(video, ep, gfp_flags); + ret = uvc_init_video_isoc(stream, ep, gfp_flags); } else { /* Bulk endpoint, proceed to URB initialization. */ ep = uvc_find_endpoint(&intf->altsetting[0], - video->streaming->header.bEndpointAddress); + stream->header.bEndpointAddress); if (ep == NULL) return -EIO; - ret = uvc_init_video_bulk(video, ep, gfp_flags); + ret = uvc_init_video_bulk(stream, ep, gfp_flags); } if (ret < 0) @@ -975,10 +980,11 @@ static int uvc_init_video(struct uvc_video_device *video, gfp_t gfp_flags) /* Submit the URBs. */ for (i = 0; i < UVC_URBS; ++i) { - if ((ret = usb_submit_urb(video->urb[i], gfp_flags)) < 0) { + ret = usb_submit_urb(stream->urb[i], gfp_flags); + if (ret < 0) { uvc_printk(KERN_ERR, "Failed to submit URB %u " "(%d).\n", i, ret); - uvc_uninit_video(video, 1); + uvc_uninit_video(stream, 1); return ret; } } @@ -997,14 +1003,14 @@ static int uvc_init_video(struct uvc_video_device *video, gfp_t gfp_flags) * video buffers in any way. We mark the device as frozen to make sure the URB * completion handler won't try to cancel the queue when we kill the URBs. */ -int uvc_video_suspend(struct uvc_video_device *video) +int uvc_video_suspend(struct uvc_streaming *stream) { - if (!uvc_queue_streaming(&video->queue)) + if (!uvc_queue_streaming(&stream->queue)) return 0; - video->frozen = 1; - uvc_uninit_video(video, 0); - usb_set_interface(video->dev->udev, video->streaming->intfnum, 0); + stream->frozen = 1; + uvc_uninit_video(stream, 0); + usb_set_interface(stream->dev->udev, stream->intfnum, 0); return 0; } @@ -1016,22 +1022,24 @@ int uvc_video_suspend(struct uvc_video_device *video) * buffers, making sure userspace applications are notified of the problem * instead of waiting forever. */ -int uvc_video_resume(struct uvc_video_device *video) +int uvc_video_resume(struct uvc_streaming *stream) { int ret; - video->frozen = 0; + stream->frozen = 0; - if ((ret = uvc_commit_video(video, &video->streaming->ctrl)) < 0) { - uvc_queue_enable(&video->queue, 0); + ret = uvc_commit_video(stream, &stream->ctrl); + if (ret < 0) { + uvc_queue_enable(&stream->queue, 0); return ret; } - if (!uvc_queue_streaming(&video->queue)) + if (!uvc_queue_streaming(&stream->queue)) return 0; - if ((ret = uvc_init_video(video, GFP_NOIO)) < 0) - uvc_queue_enable(&video->queue, 0); + ret = uvc_init_video(stream, GFP_NOIO); + if (ret < 0) + uvc_queue_enable(&stream->queue, 0); return ret; } @@ -1050,48 +1058,53 @@ int uvc_video_resume(struct uvc_video_device *video) * * This function is called before registering the device with V4L. */ -int uvc_video_init(struct uvc_video_device *video) +int uvc_video_init(struct uvc_streaming *stream) { - struct uvc_streaming_control *probe = &video->streaming->ctrl; + struct uvc_streaming_control *probe = &stream->ctrl; struct uvc_format *format = NULL; struct uvc_frame *frame = NULL; unsigned int i; int ret; - if (video->streaming->nformats == 0) { + if (stream->nformats == 0) { uvc_printk(KERN_INFO, "No supported video formats found.\n"); return -EINVAL; } + atomic_set(&stream->active, 0); + + /* Initialize the video buffers queue. */ + uvc_queue_init(&stream->queue, stream->type); + /* Alternate setting 0 should be the default, yet the XBox Live Vision * Cam (and possibly other devices) crash or otherwise misbehave if * they don't receive a SET_INTERFACE request before any other video * control request. */ - usb_set_interface(video->dev->udev, video->streaming->intfnum, 0); + usb_set_interface(stream->dev->udev, stream->intfnum, 0); /* Set the streaming probe control with default streaming parameters * retrieved from the device. Webcams that don't suport GET_DEF * requests on the probe control will just keep their current streaming * parameters. */ - if (uvc_get_video_ctrl(video, probe, 1, UVC_GET_DEF) == 0) - uvc_set_video_ctrl(video, probe, 1); + if (uvc_get_video_ctrl(stream, probe, 1, UVC_GET_DEF) == 0) + uvc_set_video_ctrl(stream, probe, 1); /* Initialize the streaming parameters with the probe control current * value. This makes sure SET_CUR requests on the streaming commit * control will always use values retrieved from a successful GET_CUR * request on the probe control, as required by the UVC specification. */ - ret = uvc_get_video_ctrl(video, probe, 1, UVC_GET_CUR); + ret = uvc_get_video_ctrl(stream, probe, 1, UVC_GET_CUR); if (ret < 0) return ret; /* Check if the default format descriptor exists. Use the first * available format otherwise. */ - for (i = video->streaming->nformats; i > 0; --i) { - format = &video->streaming->format[i-1]; + for (i = stream->nformats; i > 0; --i) { + format = &stream->format[i-1]; if (format->index == probe->bFormatIndex) break; } @@ -1116,21 +1129,20 @@ int uvc_video_init(struct uvc_video_device *video) probe->bFormatIndex = format->index; probe->bFrameIndex = frame->bFrameIndex; - video->streaming->cur_format = format; - video->streaming->cur_frame = frame; - atomic_set(&video->active, 0); + stream->cur_format = format; + stream->cur_frame = frame; /* Select the video decoding function */ - if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - if (video->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT) - video->decode = uvc_video_decode_isight; - else if (video->streaming->intf->num_altsetting > 1) - video->decode = uvc_video_decode_isoc; + if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + if (stream->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT) + stream->decode = uvc_video_decode_isight; + else if (stream->intf->num_altsetting > 1) + stream->decode = uvc_video_decode_isoc; else - video->decode = uvc_video_decode_bulk; + stream->decode = uvc_video_decode_bulk; } else { - if (video->streaming->intf->num_altsetting == 1) - video->decode = uvc_video_encode_bulk; + if (stream->intf->num_altsetting == 1) + stream->decode = uvc_video_encode_bulk; else { uvc_printk(KERN_INFO, "Isochronous endpoints are not " "supported for video output devices.\n"); @@ -1144,31 +1156,32 @@ int uvc_video_init(struct uvc_video_device *video) /* * Enable or disable the video stream. */ -int uvc_video_enable(struct uvc_video_device *video, int enable) +int uvc_video_enable(struct uvc_streaming *stream, int enable) { int ret; if (!enable) { - uvc_uninit_video(video, 1); - usb_set_interface(video->dev->udev, - video->streaming->intfnum, 0); - uvc_queue_enable(&video->queue, 0); + uvc_uninit_video(stream, 1); + usb_set_interface(stream->dev->udev, stream->intfnum, 0); + uvc_queue_enable(&stream->queue, 0); return 0; } - if ((video->streaming->cur_format->flags & UVC_FMT_FLAG_COMPRESSED) || + if ((stream->cur_format->flags & UVC_FMT_FLAG_COMPRESSED) || uvc_no_drop_param) - video->queue.flags &= ~UVC_QUEUE_DROP_INCOMPLETE; + stream->queue.flags &= ~UVC_QUEUE_DROP_INCOMPLETE; else - video->queue.flags |= UVC_QUEUE_DROP_INCOMPLETE; + stream->queue.flags |= UVC_QUEUE_DROP_INCOMPLETE; - if ((ret = uvc_queue_enable(&video->queue, 1)) < 0) + ret = uvc_queue_enable(&stream->queue, 1); + if (ret < 0) return ret; /* Commit the streaming parameters. */ - if ((ret = uvc_commit_video(video, &video->streaming->ctrl)) < 0) + ret = uvc_commit_video(stream, &stream->ctrl); + if (ret < 0) return ret; - return uvc_init_video(video, GFP_KERNEL); + return uvc_init_video(stream, GFP_KERNEL); } diff --git a/linux/drivers/media/video/uvc/uvcvideo.h b/linux/drivers/media/video/uvc/uvcvideo.h index e700bdc20..30a17f24e 100644 --- a/linux/drivers/media/video/uvc/uvcvideo.h +++ b/linux/drivers/media/video/uvc/uvcvideo.h @@ -81,9 +81,11 @@ struct uvc_xu_control { #define UVC_ENTITY_IS_UNIT(entity) (((entity)->type & 0xff00) == 0) #define UVC_ENTITY_IS_TERM(entity) (((entity)->type & 0xff00) != 0) #define UVC_ENTITY_IS_ITERM(entity) \ - (((entity)->type & 0x8000) == UVC_TERM_INPUT) + (UVC_ENTITY_IS_TERM(entity) && \ + ((entity)->type & 0x8000) == UVC_TERM_INPUT) #define UVC_ENTITY_IS_OTERM(entity) \ - (((entity)->type & 0x8000) == UVC_TERM_OUTPUT) + (UVC_ENTITY_IS_TERM(entity) && \ + ((entity)->type & 0x8000) == UVC_TERM_OUTPUT) /* ------------------------------------------------------------------------ @@ -362,26 +364,6 @@ struct uvc_streaming_header { __u8 bTriggerUsage; }; -struct uvc_streaming { - struct list_head list; - - struct usb_interface *intf; - int intfnum; - __u16 maxpsize; - - struct uvc_streaming_header header; - enum v4l2_buf_type type; - - unsigned int nformats; - struct uvc_format *format; - - struct uvc_streaming_control ctrl; - struct uvc_format *cur_format; - struct uvc_frame *cur_frame; - - struct mutex mutex; -}; - enum uvc_buffer_state { UVC_BUF_STATE_IDLE = 0, UVC_BUF_STATE_QUEUED = 1, @@ -423,26 +405,45 @@ struct uvc_video_queue { struct list_head irqqueue; }; -struct uvc_video_device { +struct uvc_video_chain { struct uvc_device *dev; - struct video_device *vdev; - atomic_t active; - unsigned int frozen : 1; + struct list_head list; struct list_head iterms; /* Input terminals */ - struct uvc_entity *oterm; /* Output terminal */ - struct uvc_entity *sterm; /* USB streaming terminal */ - struct uvc_entity *processing; - struct uvc_entity *selector; - struct list_head extensions; + struct list_head oterms; /* Output terminals */ + struct uvc_entity *processing; /* Processing unit */ + struct uvc_entity *selector; /* Selector unit */ + struct list_head extensions; /* Extension units */ + struct mutex ctrl_mutex; +}; - struct uvc_video_queue queue; +struct uvc_streaming { + struct list_head list; + struct uvc_device *dev; + struct video_device *vdev; + struct uvc_video_chain *chain; + atomic_t active; + + struct usb_interface *intf; + int intfnum; + __u16 maxpsize; + + struct uvc_streaming_header header; + enum v4l2_buf_type type; - /* Video streaming object, must always be non-NULL. */ - struct uvc_streaming *streaming; + unsigned int nformats; + struct uvc_format *format; - void (*decode) (struct urb *urb, struct uvc_video_device *video, + struct uvc_streaming_control ctrl; + struct uvc_format *cur_format; + struct uvc_frame *cur_frame; + + struct mutex mutex; + + unsigned int frozen : 1; + struct uvc_video_queue queue; + void (*decode) (struct urb *urb, struct uvc_streaming *video, struct uvc_buffer *buf); /* Context data used by the bulk completion handler. */ @@ -484,8 +485,10 @@ struct uvc_device { __u32 clock_frequency; struct list_head entities; + struct list_head chains; - struct uvc_video_device video; + /* Video Streaming interfaces */ + struct list_head streams; /* Status Interrupt Endpoint */ struct usb_host_endpoint *int_ep; @@ -493,9 +496,6 @@ struct uvc_device { __u8 *status; struct input_dev *input; char input_phys[64]; - - /* Video Streaming interfaces */ - struct list_head streaming; }; enum uvc_handle_state { @@ -504,7 +504,8 @@ enum uvc_handle_state { }; struct uvc_fh { - struct uvc_video_device *device; + struct uvc_video_chain *chain; + struct uvc_streaming *stream; enum uvc_handle_state state; }; @@ -601,13 +602,13 @@ static inline int uvc_queue_streaming(struct uvc_video_queue *queue) extern const struct v4l2_file_operations uvc_fops; /* Video */ -extern int uvc_video_init(struct uvc_video_device *video); -extern int uvc_video_suspend(struct uvc_video_device *video); -extern int uvc_video_resume(struct uvc_video_device *video); -extern int uvc_video_enable(struct uvc_video_device *video, int enable); -extern int uvc_probe_video(struct uvc_video_device *video, +extern int uvc_video_init(struct uvc_streaming *stream); +extern int uvc_video_suspend(struct uvc_streaming *stream); +extern int uvc_video_resume(struct uvc_streaming *stream); +extern int uvc_video_enable(struct uvc_streaming *stream, int enable); +extern int uvc_probe_video(struct uvc_streaming *stream, struct uvc_streaming_control *probe); -extern int uvc_commit_video(struct uvc_video_device *video, +extern int uvc_commit_video(struct uvc_streaming *stream, struct uvc_streaming_control *ctrl); extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, __u8 intfnum, __u8 cs, void *data, __u16 size); @@ -621,9 +622,9 @@ extern int uvc_status_suspend(struct uvc_device *dev); extern int uvc_status_resume(struct uvc_device *dev); /* Controls */ -extern struct uvc_control *uvc_find_control(struct uvc_video_device *video, +extern struct uvc_control *uvc_find_control(struct uvc_video_chain *chain, __u32 v4l2_id, struct uvc_control_mapping **mapping); -extern int uvc_query_v4l2_ctrl(struct uvc_video_device *video, +extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, struct v4l2_queryctrl *v4l2_ctrl); extern int uvc_ctrl_add_info(struct uvc_control_info *info); @@ -633,23 +634,23 @@ extern void uvc_ctrl_cleanup_device(struct uvc_device *dev); extern int uvc_ctrl_resume_device(struct uvc_device *dev); extern void uvc_ctrl_init(void); -extern int uvc_ctrl_begin(struct uvc_video_device *video); -extern int __uvc_ctrl_commit(struct uvc_video_device *video, int rollback); -static inline int uvc_ctrl_commit(struct uvc_video_device *video) +extern int uvc_ctrl_begin(struct uvc_video_chain *chain); +extern int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback); +static inline int uvc_ctrl_commit(struct uvc_video_chain *chain) { - return __uvc_ctrl_commit(video, 0); + return __uvc_ctrl_commit(chain, 0); } -static inline int uvc_ctrl_rollback(struct uvc_video_device *video) +static inline int uvc_ctrl_rollback(struct uvc_video_chain *chain) { - return __uvc_ctrl_commit(video, 1); + return __uvc_ctrl_commit(chain, 1); } -extern int uvc_ctrl_get(struct uvc_video_device *video, +extern int uvc_ctrl_get(struct uvc_video_chain *chain, struct v4l2_ext_control *xctrl); -extern int uvc_ctrl_set(struct uvc_video_device *video, +extern int uvc_ctrl_set(struct uvc_video_chain *chain, struct v4l2_ext_control *xctrl); -extern int uvc_xu_ctrl_query(struct uvc_video_device *video, +extern int uvc_xu_ctrl_query(struct uvc_video_chain *chain, struct uvc_xu_control *ctrl, int set); /* Utility functions */ @@ -661,7 +662,7 @@ extern struct usb_host_endpoint *uvc_find_endpoint( struct usb_host_interface *alts, __u8 epaddr); /* Quirks support */ -void uvc_video_decode_isight(struct urb *urb, struct uvc_video_device *video, +void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream, struct uvc_buffer *buf); #endif /* __KERNEL__ */ diff --git a/linux/drivers/media/video/v4l2-ioctl.c b/linux/drivers/media/video/v4l2-ioctl.c index 80c94dc5a..d746d9555 100644 --- a/linux/drivers/media/video/v4l2-ioctl.c +++ b/linux/drivers/media/video/v4l2-ioctl.c @@ -1088,8 +1088,10 @@ static long __video_do_ioctl(struct file *file, /* Calls the specific handler */ if (ops->vidioc_g_std) ret = ops->vidioc_g_std(file, fh, id); - else + else if (vfd->current_norm) *id = vfd->current_norm; + else + ret = -EINVAL; if (!ret) dbgarg(cmd, "std=0x%08Lx\n", (long long unsigned)*id); @@ -1560,12 +1562,19 @@ static long __video_do_ioctl(struct file *file, break; ret = ops->vidioc_g_parm(file, fh, p); } else { + v4l2_std_id std = vfd->current_norm; + if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - v4l2_video_std_frame_period(vfd->current_norm, - &p->parm.capture.timeperframe); ret = 0; + if (ops->vidioc_g_std) + ret = ops->vidioc_g_std(file, fh, &std); + else if (std == 0) + ret = -EINVAL; + if (ret == 0) + v4l2_video_std_frame_period(std, + &p->parm.capture.timeperframe); } dbgarg(cmd, "type=%d\n", p->type); diff --git a/linux/drivers/media/video/zoran/zoran_card.c b/linux/drivers/media/video/zoran/zoran_card.c index 217fec9e4..375f158fd 100644 --- a/linux/drivers/media/video/zoran/zoran_card.c +++ b/linux/drivers/media/video/zoran/zoran_card.c @@ -1169,7 +1169,7 @@ zoran_setup_videocodec (struct zoran *zr, m->type = 0; m->flags = CODEC_FLAG_ENCODER | CODEC_FLAG_DECODER; - strncpy(m->name, ZR_DEVNAME(zr), sizeof(m->name)); + strlcpy(m->name, ZR_DEVNAME(zr), sizeof(m->name)); m->data = zr; switch (type) |