diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-05-27 10:40:37 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-05-27 10:40:37 -0300 |
commit | fa6bf06d0bc8a417de4d20da09191a12baf5b6a4 (patch) | |
tree | 13405dea17647d9e929895152fb308320ca0795c /linux/drivers/media/video | |
parent | e04d6d72df5f7dfbf9d9355950617c7d3a041ea0 (diff) | |
parent | e869f37a082df276cbc412d3f7da04fd3b41fed4 (diff) | |
download | mediapointer-dvb-s2-fa6bf06d0bc8a417de4d20da09191a12baf5b6a4.tar.gz mediapointer-dvb-s2-fa6bf06d0bc8a417de4d20da09191a12baf5b6a4.tar.bz2 |
merge: http://linuxtv.org/hg/~jfrancois/v4l-dvb
From: Mauro Carvalho Chehab <mchehab@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'linux/drivers/media/video')
37 files changed, 576 insertions, 411 deletions
diff --git a/linux/drivers/media/video/bt8xx/bttv-driver.c b/linux/drivers/media/video/bt8xx/bttv-driver.c index 622807b54..8d2075186 100644 --- a/linux/drivers/media/video/bt8xx/bttv-driver.c +++ b/linux/drivers/media/video/bt8xx/bttv-driver.c @@ -4198,7 +4198,6 @@ static struct video_device *vdev_init(struct bttv *btv, if (NULL == vfd) return NULL; *vfd = *template; - vfd->minor = -1; vfd->v4l2_dev = &btv->c.v4l2_dev; vfd->release = video_device_release; vfd->debug = bttv_debug; diff --git a/linux/drivers/media/video/bt8xx/bttv-i2c.c b/linux/drivers/media/video/bt8xx/bttv-i2c.c index bf94551c3..31f2f07d9 100644 --- a/linux/drivers/media/video/bt8xx/bttv-i2c.c +++ b/linux/drivers/media/video/bt8xx/bttv-i2c.c @@ -405,6 +405,27 @@ int __devinit init_bttv_i2c(struct bttv *btv) } if (0 == btv->i2c_rc && i2c_scan) do_i2c_scan(btv->c.v4l2_dev.name, &btv->i2c_client); + + /* Instantiate the IR receiver device, if present */ + if (0 == btv->i2c_rc) { + struct i2c_board_info info; + /* The external IR receiver is at i2c address 0x34 (0x35 for + reads). Future Hauppauge cards will have an internal + receiver at 0x30 (0x31 for reads). In theory, both can be + fitted, and Hauppauge suggest an external overrides an + internal. + + That's why we probe 0x1a (~0x34) first. CB + */ + const unsigned short addr_list[] = { + 0x1a, 0x18, 0x4b, 0x64, 0x30, + I2C_CLIENT_END + }; + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); + i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list); + } return btv->i2c_rc; } diff --git a/linux/drivers/media/video/cx18/cx18-av-core.c b/linux/drivers/media/video/cx18/cx18-av-core.c index 2b07b1563..0b3d840cc 100644 --- a/linux/drivers/media/video/cx18/cx18-av-core.c +++ b/linux/drivers/media/video/cx18/cx18-av-core.c @@ -277,8 +277,15 @@ void cx18_av_std_setup(struct cx18 *cx) struct cx18_av_state *state = &cx->av_state; struct v4l2_subdev *sd = &state->sd; v4l2_std_id std = state->std; + + /* + * Video ADC crystal clock to pixel clock SRC decimation ratio + * 28.636360 MHz/13.5 Mpps * 256 = 0x21f.07b + */ + const int src_decimation = 0x21f; + int hblank, hactive, burst, vblank, vactive, sc; - int vblank656, src_decimation; + int vblank656; int luma_lpf, uv_lpf, comb; u32 pll_int, pll_frac, pll_post; @@ -288,40 +295,96 @@ void cx18_av_std_setup(struct cx18 *cx) else cx18_av_write(cx, 0x49f, 0x14); + /* + * Note: At the end of a field, there are 3 sets of half line duration + * (double horizontal rate) pulses: + * + * 5 (625) or 6 (525) half-lines to blank for the vertical retrace + * 5 (625) or 6 (525) vertical sync pulses of half line duration + * 5 (625) or 6 (525) half-lines of equalization pulses + */ if (std & V4L2_STD_625_50) { - /* FIXME - revisit these for Sliced VBI */ + /* + * The following relationships of half line counts should hold: + * 625 = vblank656 + vactive + * 10 = vblank656 - vblank = vsync pulses + equalization pulses + * + * vblank656: half lines after line 625/mid-313 of blanked video + * vblank: half lines, after line 5/317, of blanked video + * vactive: half lines of active video + + * 5 half lines after the end of active video + * + * As far as I can tell: + * vblank656 starts counting from the falling edge of the first + * vsync pulse (start of line 1 or mid-313) + * vblank starts counting from the after the 5 vsync pulses and + * 5 or 4 equalization pulses (start of line 6 or 318) + * + * For 625 line systems the driver will extract VBI information + * from lines 6-23 and lines 318-335 (but the slicer can only + * handle 17 lines, not the 18 in the vblank region). + * In addition, we need vblank656 and vblank to be one whole + * line longer, to cover line 24 and 336, so the SAV/EAV RP + * codes get generated such that the encoder can actually + * extract line 23 & 335 (WSS). We'll lose 1 line in each field + * at the top of the screen. + * + * It appears the 5 half lines that happen after active + * video must be included in vactive (579 instead of 574), + * otherwise the colors get badly displayed in various regions + * of the screen. I guess the chroma comb filter gets confused + * without them (at least when a PVR-350 is the PAL source). + */ + vblank656 = 48; /* lines 1 - 24 & 313 - 336 */ + vblank = 38; /* lines 6 - 24 & 318 - 336 */ + vactive = 579; /* lines 24 - 313 & 337 - 626 */ + + /* + * For a 13.5 Mpps clock and 15,625 Hz line rate, a line is + * is 864 pixels = 720 active + 144 blanking. ITU-R BT.601 + * specifies 12 luma clock periods or ~ 0.9 * 13.5 Mpps after + * the end of active video to start a horizontal line, so that + * leaves 132 pixels of hblank to ignore. + */ hblank = 132; hactive = 720; - burst = 93; - vblank = 36; - vactive = 580; - vblank656 = 40; - src_decimation = 0x21f; + /* + * Burst gate delay (for 625 line systems) + * Hsync leading edge to color burst rise = 5.6 us + * Color burst width = 2.25 us + * Gate width = 4 pixel clocks + * (5.6 us + 2.25/2 us) * 13.5 Mpps + 4/2 clocks = 92.79 clocks + */ + burst = 93; luma_lpf = 2; if (std & V4L2_STD_PAL) { uv_lpf = 1; comb = 0x20; - sc = 688739; + /* sc = 4433618.75 * src_decimation/28636360 * 2^13 */ + sc = 688700; } else if (std == V4L2_STD_PAL_Nc) { uv_lpf = 1; comb = 0x20; - sc = 556453; + /* sc = 3582056.25 * src_decimation/28636360 * 2^13 */ + sc = 556422; } else { /* SECAM */ uv_lpf = 0; comb = 0; - sc = 672351; + /* (fr + fb)/2 = (4406260 + 4250000)/2 = 4328130 */ + /* sc = 4328130 * src_decimation/28636360 * 2^13 */ + sc = 672314; } } else { /* * The following relationships of half line counts should hold: - * 525 = vsync + vactive + vblank656 - * 12 = vblank656 - vblank + * 525 = prevsync + vblank656 + vactive + * 12 = vblank656 - vblank = vsync pulses + equalization pulses * - * vsync: always 6 half-lines of vsync pulses - * vactive: half lines of active video + * prevsync: 6 half-lines before the vsync pulses * vblank656: half lines, after line 3/mid-266, of blanked video * vblank: half lines, after line 9/272, of blanked video + * vactive: half lines of active video * * As far as I can tell: * vblank656 starts counting from the falling edge of the first @@ -348,20 +411,30 @@ void cx18_av_std_setup(struct cx18 *cx) luma_lpf = 1; uv_lpf = 1; - src_decimation = 0x21f; + /* + * Burst gate delay (for 525 line systems) + * Hsync leading edge to color burst rise = 5.3 us + * Color burst width = 2.5 us + * Gate width = 4 pixel clocks + * (5.3 us + 2.5/2 us) * 13.5 Mpps + 4/2 clocks = 90.425 clocks + */ if (std == V4L2_STD_PAL_60) { - burst = 0x5b; + burst = 90; luma_lpf = 2; comb = 0x20; - sc = 688739; + /* sc = 4433618.75 * src_decimation/28636360 * 2^13 */ + sc = 688700; } else if (std == V4L2_STD_PAL_M) { - burst = 0x61; + /* The 97 needs to be verified against PAL-M timings */ + burst = 97; comb = 0x20; - sc = 555452; + /* sc = 3575611.49 * src_decimation/28636360 * 2^13 */ + sc = 555421; } else { - burst = 0x5b; + burst = 90; comb = 0x66; - sc = 556063; + /* sc = 3579545.45.. * src_decimation/28636360 * 2^13 */ + sc = 556032; } } @@ -373,23 +446,23 @@ void cx18_av_std_setup(struct cx18 *cx) pll_int, pll_frac, pll_post); if (pll_post) { - int fin, fsc, pll; + int fsc, pll; pll = (28636360L * ((((u64)pll_int) << 25) + pll_frac)) >> 25; pll /= pll_post; - CX18_DEBUG_INFO_DEV(sd, "PLL = %d.%06d MHz\n", + CX18_DEBUG_INFO_DEV(sd, "Video PLL = %d.%06d MHz\n", pll / 1000000, pll % 1000000); - CX18_DEBUG_INFO_DEV(sd, "PLL/8 = %d.%06d MHz\n", + CX18_DEBUG_INFO_DEV(sd, "Pixel rate = %d.%06d Mpixel/sec\n", pll / 8000000, (pll / 8) % 1000000); - fin = ((u64)src_decimation * pll) >> 12; - CX18_DEBUG_INFO_DEV(sd, "ADC Sampling freq = %d.%06d MHz\n", - fin / 1000000, fin % 1000000); + CX18_DEBUG_INFO_DEV(sd, "ADC XTAL/pixel clock decimation ratio " + "= %d.%03d\n", src_decimation / 256, + ((src_decimation % 256) * 1000) / 256); - fsc = (((u64)sc) * pll) >> 24L; + fsc = ((((u64)sc) * 28636360)/src_decimation) >> 13L; CX18_DEBUG_INFO_DEV(sd, - "Chroma sub-carrier freq = %d.%06d MHz\n", - fsc / 1000000, fsc % 1000000); + "Chroma sub-carrier initial freq = %d.%06d " + "MHz\n", fsc / 1000000, fsc % 1000000); CX18_DEBUG_INFO_DEV(sd, "hblank %i, hactive %i, vblank %i, " "vactive %i, vblank656 %i, src_dec %i, " @@ -954,9 +1027,9 @@ static int cx18_av_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) * cx18_av_std_setup(), above standard values: * * 480 + 1 for 60 Hz systems - * 576 + 4 for 50 Hz systems + * 576 + 3 for 50 Hz systems */ - Vlines = pix->height + (is_50Hz ? 4 : 1); + Vlines = pix->height + (is_50Hz ? 3 : 1); /* * Invalid height and width scaling requests are: diff --git a/linux/drivers/media/video/cx18/cx18-av-vbi.c b/linux/drivers/media/video/cx18/cx18-av-vbi.c index 23b31670b..a51732bcc 100644 --- a/linux/drivers/media/video/cx18/cx18-av-vbi.c +++ b/linux/drivers/media/video/cx18/cx18-av-vbi.c @@ -255,8 +255,8 @@ int cx18_av_vbi_s_fmt(struct cx18 *cx, struct v4l2_format *fmt) } cx18_av_write(cx, 0x43c, 0x16); - /* FIXME - should match vblank set in cx18_av_std_setup() */ - cx18_av_write(cx, 0x474, is_pal ? 0x2a : 26); + /* Should match vblank set in cx18_av_std_setup() */ + cx18_av_write(cx, 0x474, is_pal ? 38 : 26); return 0; } diff --git a/linux/drivers/media/video/cx18/cx18-streams.c b/linux/drivers/media/video/cx18/cx18-streams.c index 142302ba5..c134927b3 100644 --- a/linux/drivers/media/video/cx18/cx18-streams.c +++ b/linux/drivers/media/video/cx18/cx18-streams.c @@ -376,9 +376,14 @@ static void cx18_vbi_setup(struct cx18_stream *s) * Tell the encoder to capture 21-4+1=18 lines per field, * since we want lines 10 through 21. * - * FIXME - revisit for 625/50 systems + * For 625/50 systems, according to the VIP 2 & BT.656 std: + * The EAV RP code's Field bit toggles on line 1, a few lines + * after the Vertcal Blank bit has already toggled. + * (We've actually set the digitizer so that the Field bit + * toggles on line 2.) Tell the encoder to capture 23-2+1=22 + * lines per field, since we want lines 6 through 23. */ - lines = cx->is_60hz ? (21 - 4 + 1) * 2 : 38; + lines = cx->is_60hz ? (21 - 4 + 1) * 2 : (23 - 2 + 1) * 2; } data[0] = s->handle; diff --git a/linux/drivers/media/video/cx231xx/cx231xx-cards.c b/linux/drivers/media/video/cx231xx/cx231xx-cards.c index af6169516..68f92da9e 100644 --- a/linux/drivers/media/video/cx231xx/cx231xx-cards.c +++ b/linux/drivers/media/video/cx231xx/cx231xx-cards.c @@ -282,12 +282,12 @@ static void cx231xx_config_tuner(struct cx231xx *dev) } /* ----------------------------------------------------------------------- */ -void cx231xx_set_ir(struct cx231xx *dev, struct IR_i2c *ir) +void cx231xx_register_i2c_ir(struct cx231xx *dev) { - if (disable_ir) { - ir->get_key = NULL; + if (disable_ir) return; - } + + /* REVISIT: instantiate IR device */ /* detect & configure */ switch (dev->model) { diff --git a/linux/drivers/media/video/cx231xx/cx231xx-i2c.c b/linux/drivers/media/video/cx231xx/cx231xx-i2c.c index d196fe666..e71005c59 100644 --- a/linux/drivers/media/video/cx231xx/cx231xx-i2c.c +++ b/linux/drivers/media/video/cx231xx/cx231xx-i2c.c @@ -424,34 +424,6 @@ static u32 functionality(struct i2c_adapter *adap) return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; } -/* - * attach_inform() - * gets called when a device attaches to the i2c bus - * does some basic configuration - */ -static int attach_inform(struct i2c_client *client) -{ - struct cx231xx_i2c *bus = i2c_get_adapdata(client->adapter); - struct cx231xx *dev = bus->dev; - - switch (client->addr << 1) { - case 0x8e: - { - struct IR_i2c *ir = i2c_get_clientdata(client); - dprintk1(1, "attach_inform: IR detected (%s).\n", - ir->phys); - cx231xx_set_ir(dev, ir); - break; - } - break; - - default: - break; - } - - return 0; -} - static struct i2c_algorithm cx231xx_algo = { .master_xfer = cx231xx_i2c_xfer, .functionality = functionality, @@ -465,7 +437,6 @@ static struct i2c_adapter cx231xx_adap_template = { .name = "cx231xx", .id = I2C_HW_B_CX231XX, .algo = &cx231xx_algo, - .client_register = attach_inform, }; static struct i2c_client cx231xx_client_template = { @@ -540,6 +511,9 @@ int cx231xx_i2c_register(struct cx231xx_i2c *bus) if (0 == bus->i2c_rc) { if (i2c_scan) cx231xx_do_i2c_scan(dev, &bus->i2c_client); + + /* Instantiate the IR receiver device, if present */ + cx231xx_register_i2c_ir(dev); } else cx231xx_warn("%s: i2c bus %d register FAILED\n", dev->name, bus->nr); diff --git a/linux/drivers/media/video/cx231xx/cx231xx-input.c b/linux/drivers/media/video/cx231xx/cx231xx-input.c index 04d954cca..3171b0177 100644 --- a/linux/drivers/media/video/cx231xx/cx231xx-input.c +++ b/linux/drivers/media/video/cx231xx/cx231xx-input.c @@ -37,7 +37,7 @@ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); #define i2cdprintk(fmt, arg...) \ if (ir_debug) { \ - printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg); \ + printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \ } #define dprintk(fmt, arg...) \ diff --git a/linux/drivers/media/video/cx231xx/cx231xx.h b/linux/drivers/media/video/cx231xx/cx231xx.h index 21b4023dd..d3c05186e 100644 --- a/linux/drivers/media/video/cx231xx/cx231xx.h +++ b/linux/drivers/media/video/cx231xx/cx231xx.h @@ -747,7 +747,7 @@ extern void cx231xx_card_setup(struct cx231xx *dev); extern struct cx231xx_board cx231xx_boards[]; extern struct usb_device_id cx231xx_id_table[]; extern const unsigned int cx231xx_bcount; -void cx231xx_set_ir(struct cx231xx *dev, struct IR_i2c *ir); +void cx231xx_register_i2c_ir(struct cx231xx *dev); int cx231xx_tuner_callback(void *ptr, int component, int command, int arg); /* Provided by cx231xx-input.c */ diff --git a/linux/drivers/media/video/cx23885/cx23885-417.c b/linux/drivers/media/video/cx23885/cx23885-417.c index 574cdb385..9974d9a78 100644 --- a/linux/drivers/media/video/cx23885/cx23885-417.c +++ b/linux/drivers/media/video/cx23885/cx23885-417.c @@ -1749,7 +1749,6 @@ static struct video_device *cx23885_video_dev_alloc( if (NULL == vfd) return NULL; *vfd = *template; - vfd->minor = -1; snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, type, cx23885_boards[tsport->dev->board].name); vfd->parent = &pci->dev; diff --git a/linux/drivers/media/video/cx23885/cx23885-dvb.c b/linux/drivers/media/video/cx23885/cx23885-dvb.c index ba120b9cf..4efc7dee1 100644 --- a/linux/drivers/media/video/cx23885/cx23885-dvb.c +++ b/linux/drivers/media/video/cx23885/cx23885-dvb.c @@ -125,7 +125,9 @@ static struct tda10048_config hauppauge_hvr1200_config = { .output_mode = TDA10048_SERIAL_OUTPUT, .fwbulkwritelen = TDA10048_BULKWRITE_200, .inversion = TDA10048_INVERSION_ON, - .if_freq_khz = TDA10048_IF_4300, + .dtv6_if_freq_khz = TDA10048_IF_3300, + .dtv7_if_freq_khz = TDA10048_IF_3800, + .dtv8_if_freq_khz = TDA10048_IF_4300, .clk_freq_khz = TDA10048_CLK_16000, }; @@ -134,7 +136,9 @@ static struct tda10048_config hauppauge_hvr1210_config = { .output_mode = TDA10048_SERIAL_OUTPUT, .fwbulkwritelen = TDA10048_BULKWRITE_200, .inversion = TDA10048_INVERSION_ON, - .if_freq_khz = TDA10048_IF_4000, + .dtv6_if_freq_khz = TDA10048_IF_3300, + .dtv7_if_freq_khz = TDA10048_IF_3500, + .dtv8_if_freq_khz = TDA10048_IF_4000, .clk_freq_khz = TDA10048_CLK_16000, }; diff --git a/linux/drivers/media/video/cx23885/cx23885-i2c.c b/linux/drivers/media/video/cx23885/cx23885-i2c.c index a5d9f7530..4369470a3 100644 --- a/linux/drivers/media/video/cx23885/cx23885-i2c.c +++ b/linux/drivers/media/video/cx23885/cx23885-i2c.c @@ -364,6 +364,18 @@ int cx23885_i2c_register(struct cx23885_i2c *bus) printk(KERN_WARNING "%s: i2c bus %d register FAILED\n", dev->name, bus->nr); + /* Instantiate the IR receiver device, if present */ + if (0 == bus->i2c_rc) { + struct i2c_board_info info; + const unsigned short addr_list[] = { + 0x6b, I2C_CLIENT_END + }; + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); + i2c_new_probed_device(&bus->i2c_adap, &info, addr_list); + } + return bus->i2c_rc; } diff --git a/linux/drivers/media/video/cx88/cx88-core.c b/linux/drivers/media/video/cx88/cx88-core.c index 39cbd152a..fddba2d51 100644 --- a/linux/drivers/media/video/cx88/cx88-core.c +++ b/linux/drivers/media/video/cx88/cx88-core.c @@ -1057,7 +1057,6 @@ struct video_device *cx88_vdev_init(struct cx88_core *core, if (NULL == vfd) return NULL; *vfd = *template; - vfd->minor = -1; vfd->v4l2_dev = &core->v4l2_dev; vfd->parent = &pci->dev; vfd->release = video_device_release; diff --git a/linux/drivers/media/video/cx88/cx88-i2c.c b/linux/drivers/media/video/cx88/cx88-i2c.c index 680a8c889..dbd629511 100644 --- a/linux/drivers/media/video/cx88/cx88-i2c.c +++ b/linux/drivers/media/video/cx88/cx88-i2c.c @@ -186,6 +186,19 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) do_i2c_scan(core->name,&core->i2c_client); } else printk("%s: i2c register FAILED\n", core->name); + + /* Instantiate the IR receiver device, if present */ + if (0 == core->i2c_rc) { + struct i2c_board_info info; + const unsigned short addr_list[] = { + 0x18, 0x6b, 0x71, + I2C_CLIENT_END + }; + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); + i2c_new_probed_device(&core->i2c_adap, &info, addr_list); + } return core->i2c_rc; } diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index fb83e4f6e..c765d769b 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -153,6 +153,16 @@ static struct em28xx_reg_seq compro_mute_gpio[] = { { -1, -1, -1, -1}, }; +/* Terratec AV350 */ +static struct em28xx_reg_seq terratec_av350_mute_gpio[] = { + {EM28XX_R08_GPIO, 0xff, 0x7f, 10}, + { -1, -1, -1, -1}, +}; + +static struct em28xx_reg_seq terratec_av350_unmute_gpio[] = { + {EM28XX_R08_GPIO, 0xff, 0xff, 10}, + { -1, -1, -1, -1}, +}; /* * Board definitions */ @@ -1412,6 +1422,42 @@ struct em28xx_board em28xx_boards[] = { .amux = EM28XX_AMUX_VIDEO, } }, }, + [EM2860_BOARD_TERRATEC_GRABBY] = { + .name = "Terratec Grabby", + .vchannels = 2, + .tuner_type = TUNER_ABSENT, + .decoder = EM28XX_SAA711X, + .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_VIDEO2, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_VIDEO2, + } }, + }, + [EM2860_BOARD_TERRATEC_AV350] = { + .name = "Terratec AV350", + .vchannels = 2, + .tuner_type = TUNER_ABSENT, + .decoder = EM28XX_TVP5150, + .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, + .mute_gpio = terratec_av350_mute_gpio, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = EM28XX_AUDIO_SRC_LINE, + .gpio = terratec_av350_unmute_gpio, + + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AUDIO_SRC_LINE, + .gpio = terratec_av350_unmute_gpio, + } }, + }, }; const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); @@ -1479,6 +1525,10 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2870_BOARD_TERRATEC_XS }, { USB_DEVICE(0x0ccd, 0x0047), .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS }, + { USB_DEVICE(0x0ccd, 0x0084), + .driver_info = EM2860_BOARD_TERRATEC_AV350 }, + { USB_DEVICE(0x0ccd, 0x0096), + .driver_info = EM2860_BOARD_TERRATEC_GRABBY }, { USB_DEVICE(0x185b, 0x2870), .driver_info = EM2870_BOARD_COMPRO_VIDEOMATE }, { USB_DEVICE(0x185b, 0x2041), @@ -1931,12 +1981,20 @@ static int em28xx_hint_board(struct em28xx *dev) } /* ----------------------------------------------------------------------- */ -void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir) +void em28xx_register_i2c_ir(struct em28xx *dev) { - if (disable_ir) { - ir->get_key = NULL; - return ; - } + struct i2c_board_info info; + struct IR_i2c_init_data init_data; + const unsigned short addr_list[] = { + 0x30, 0x47, I2C_CLIENT_END + }; + + if (disable_ir) + return; + + memset(&info, 0, sizeof(struct i2c_board_info)); + memset(&init_data, 0, sizeof(struct IR_i2c_init_data)); + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); /* detect & configure */ switch (dev->model) { @@ -1946,22 +2004,19 @@ void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir) break; case (EM2800_BOARD_TERRATEC_CINERGY_200): case (EM2820_BOARD_TERRATEC_CINERGY_250): - ir->ir_codes = ir_codes_em_terratec; - ir->get_key = em28xx_get_key_terratec; - snprintf(ir->c.name, sizeof(ir->c.name), - "i2c IR (EM28XX Terratec)"); + init_data.ir_codes = ir_codes_em_terratec; + init_data.get_key = em28xx_get_key_terratec; + init_data.name = "i2c IR (EM28XX Terratec)"; break; case (EM2820_BOARD_PINNACLE_USB_2): - ir->ir_codes = ir_codes_pinnacle_grey; - ir->get_key = em28xx_get_key_pinnacle_usb_grey; - snprintf(ir->c.name, sizeof(ir->c.name), - "i2c IR (EM28XX Pinnacle PCTV)"); + init_data.ir_codes = ir_codes_pinnacle_grey; + init_data.get_key = em28xx_get_key_pinnacle_usb_grey; + init_data.name = "i2c IR (EM28XX Pinnacle PCTV)"; break; case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2): - ir->ir_codes = ir_codes_hauppauge_new; - ir->get_key = em28xx_get_key_em_haup; - snprintf(ir->c.name, sizeof(ir->c.name), - "i2c IR (EM2840 Hauppauge)"); + init_data.ir_codes = ir_codes_hauppauge_new; + init_data.get_key = em28xx_get_key_em_haup; + init_data.name = "i2c IR (EM2840 Hauppauge)"; break; case (EM2820_BOARD_MSI_VOX_USB_2): break; @@ -1972,6 +2027,10 @@ void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir) case (EM2800_BOARD_GRABBEEX_USB2800): break; } + + if (init_data.name) + info.platform_data = &init_data; + i2c_new_probed_device(&dev->i2c_adap, &info, addr_list); } void em28xx_card_setup(struct em28xx *dev) diff --git a/linux/drivers/media/video/em28xx/em28xx-i2c.c b/linux/drivers/media/video/em28xx/em28xx-i2c.c index 24456cebd..fd6be0e2c 100644 --- a/linux/drivers/media/video/em28xx/em28xx-i2c.c +++ b/linux/drivers/media/video/em28xx/em28xx-i2c.c @@ -451,27 +451,6 @@ static u32 functionality(struct i2c_adapter *adap) return I2C_FUNC_SMBUS_EMUL; } -/* - * attach_inform() - * gets called when a device attaches to the i2c bus - * does some basic configuration - */ -static int attach_inform(struct i2c_client *client) -{ - struct em28xx *dev = client->adapter->algo_data; - struct IR_i2c *ir = i2c_get_clientdata(client); - - switch (client->addr << 1) { - case 0x60: - case 0x8e: - dprintk1(1, "attach_inform: IR detected (%s).\n", ir->phys); - em28xx_set_ir(dev, ir); - break; - } - - return 0; -} - static struct i2c_algorithm em28xx_algo = { .master_xfer = em28xx_i2c_xfer, .functionality = functionality, @@ -488,7 +467,6 @@ static struct i2c_adapter em28xx_adap_template = { .name = "em28xx", .id = I2C_HW_B_EM28XX, .algo = &em28xx_algo, - .client_register = attach_inform, }; static struct i2c_client em28xx_client_template = { @@ -581,6 +559,9 @@ int em28xx_i2c_register(struct em28xx *dev) if (i2c_scan) em28xx_do_i2c_scan(dev); + /* Instantiate the IR receiver device, if present */ + em28xx_register_i2c_ir(dev); + return 0; } diff --git a/linux/drivers/media/video/em28xx/em28xx-input.c b/linux/drivers/media/video/em28xx/em28xx-input.c index 5382a6064..bfe2cb8f6 100644 --- a/linux/drivers/media/video/em28xx/em28xx-input.c +++ b/linux/drivers/media/video/em28xx/em28xx-input.c @@ -41,7 +41,7 @@ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); #define i2cdprintk(fmt, arg...) \ if (ir_debug) { \ - printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg); \ + printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \ } #define dprintk(fmt, arg...) \ @@ -86,7 +86,7 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) unsigned char b; /* poll IR chip */ - if (1 != i2c_master_recv(&ir->c, &b, 1)) { + if (1 != i2c_master_recv(ir->c, &b, 1)) { i2cdprintk("read error\n"); return -EIO; } @@ -115,7 +115,7 @@ int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) unsigned char code; /* poll IR chip */ - if (2 != i2c_master_recv(&ir->c, buf, 2)) + if (2 != i2c_master_recv(ir->c, buf, 2)) return -EIO; /* Does eliminate repeated parity code */ @@ -153,7 +153,7 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, /* poll IR chip */ - if (3 != i2c_master_recv(&ir->c, buf, 3)) { + if (3 != i2c_master_recv(ir->c, buf, 3)) { i2cdprintk("read error\n"); return -EIO; } diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h index 3403a45e8..e4ddc50c5 100644 --- a/linux/drivers/media/video/em28xx/em28xx.h +++ b/linux/drivers/media/video/em28xx/em28xx.h @@ -104,6 +104,8 @@ #define EM2860_BOARD_EASYCAP 64 #define EM2820_BOARD_IODATA_GVMVP_SZ 65 #define EM2880_BOARD_EMPIRE_DUAL_TV 66 +#define EM2860_BOARD_TERRATEC_GRABBY 67 +#define EM2860_BOARD_TERRATEC_AV350 68 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 @@ -650,7 +652,7 @@ extern void em28xx_card_setup(struct em28xx *dev); extern struct em28xx_board em28xx_boards[]; extern struct usb_device_id em28xx_id_table[]; extern const unsigned int em28xx_bcount; -void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir); +void em28xx_register_i2c_ir(struct em28xx *dev); int em28xx_tuner_callback(void *ptr, int component, int command, int arg); void em28xx_release_resources(struct em28xx *dev); diff --git a/linux/drivers/media/video/ir-kbd-i2c.c b/linux/drivers/media/video/ir-kbd-i2c.c index 7bae57ad3..0a18d07c7 100644 --- a/linux/drivers/media/video/ir-kbd-i2c.c +++ b/linux/drivers/media/video/ir-kbd-i2c.c @@ -75,7 +75,7 @@ static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw, int start, range, toggle, dev, code, ircode; /* poll IR chip */ - if (size != i2c_master_recv(&ir->c,buf,size)) + if (size != i2c_master_recv(ir->c, buf, size)) return -EIO; /* split rc5 data block ... */ @@ -138,7 +138,7 @@ static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) unsigned char b; /* poll IR chip */ - if (1 != i2c_master_recv(&ir->c,&b,1)) { + if (1 != i2c_master_recv(ir->c, &b, 1)) { dprintk(1,"read error\n"); return -EIO; } @@ -152,7 +152,7 @@ static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) unsigned char b; /* poll IR chip */ - if (1 != i2c_master_recv(&ir->c,&b,1)) { + if (1 != i2c_master_recv(ir->c, &b, 1)) { dprintk(1,"read error\n"); return -EIO; } @@ -172,7 +172,7 @@ static int get_key_fusionhdtv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) unsigned char buf[4]; /* poll IR chip */ - if (4 != i2c_master_recv(&ir->c,buf,4)) { + if (4 != i2c_master_recv(ir->c, buf, 4)) { dprintk(1,"read error\n"); return -EIO; } @@ -196,7 +196,7 @@ static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) unsigned char b; /* poll IR chip */ - if (1 != i2c_master_recv(&ir->c,&b,1)) { + if (1 != i2c_master_recv(ir->c, &b, 1)) { dprintk(1,"read error\n"); return -EIO; } @@ -223,12 +223,12 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { unsigned char subaddr, key, keygroup; - struct i2c_msg msg[] = { { .addr = ir->c.addr, .flags = 0, + struct i2c_msg msg[] = { { .addr = ir->c->addr, .flags = 0, .buf = &subaddr, .len = 1}, - { .addr = ir->c.addr, .flags = I2C_M_RD, + { .addr = ir->c->addr, .flags = I2C_M_RD, .buf = &key, .len = 1} }; subaddr = 0x0d; - if (2 != i2c_transfer(ir->c.adapter, msg, 2)) { + if (2 != i2c_transfer(ir->c->adapter, msg, 2)) { dprintk(1, "read error\n"); return -EIO; } @@ -238,7 +238,7 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir, subaddr = 0x0b; msg[1].buf = &keygroup; - if (2 != i2c_transfer(ir->c.adapter, msg, 2)) { + if (2 != i2c_transfer(ir->c->adapter, msg, 2)) { dprintk(1, "read error\n"); return -EIO; } @@ -295,7 +295,7 @@ static void ir_work(struct work_struct *work) /* MSI TV@nywhere Plus requires more frequent polling otherwise it will miss some keypresses */ - if (ir->c.adapter->id == I2C_HW_SAA7134 && ir->c.addr == 0x30) + if (ir->c->adapter->id == I2C_HW_SAA7134 && ir->c->addr == 0x30) polling_interval = 50; ir_key_poll(ir); @@ -304,34 +304,15 @@ static void ir_work(struct work_struct *work) /* ----------------------------------------------------------------------- */ -static int ir_attach(struct i2c_adapter *adap, int addr, - unsigned short flags, int kind); -static int ir_detach(struct i2c_client *client); -static int ir_probe(struct i2c_adapter *adap); - -static struct i2c_driver driver = { - .driver = { - .name = "ir-kbd-i2c", - }, - .id = I2C_DRIVERID_INFRARED, - .attach_adapter = ir_probe, - .detach_client = ir_detach, -}; - -static struct i2c_client client_template = -{ - .name = "unset", - .driver = &driver -}; - -static int ir_attach(struct i2c_adapter *adap, int addr, - unsigned short flags, int kind) +static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) { IR_KEYTAB_TYPE *ir_codes = NULL; - char *name; + const char *name = NULL; int ir_type; struct IR_i2c *ir; struct input_dev *input_dev; + struct i2c_adapter *adap = client->adapter; + unsigned short addr = client->addr; int err; ir = kzalloc(sizeof(struct IR_i2c),GFP_KERNEL); @@ -341,13 +322,9 @@ static int ir_attach(struct i2c_adapter *adap, int addr, goto err_out_free; } - ir->c = client_template; + ir->c = client; ir->input = input_dev; - - ir->c.adapter = adap; - ir->c.addr = addr; - - i2c_set_clientdata(&ir->c, ir); + i2c_set_clientdata(client, ir); switch(addr) { case 0x64: @@ -412,44 +389,46 @@ static int ir_attach(struct i2c_adapter *adap, int addr, ir_codes = ir_codes_avermedia_cardbus; break; default: - /* shouldn't happen */ - printk(DEVNAME ": Huh? unknown i2c address (0x%02x)?\n", addr); + dprintk(1, DEVNAME ": Unsupported i2c address 0x%02x\n", addr); err = -ENODEV; goto err_out_free; } - /* Sets name */ - snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (%s)", name); - ir->ir_codes = ir_codes; + /* Let the caller override settings */ + if (client->dev.platform_data) { + const struct IR_i2c_init_data *init_data = + client->dev.platform_data; - /* register i2c device - * At device register, IR codes may be changed to be - * board dependent. - */ - err = i2c_attach_client(&ir->c); - if (err) - goto err_out_free; + ir_codes = init_data->ir_codes; + name = init_data->name; + ir->get_key = init_data->get_key; + } - /* If IR not supported or disabled, unregisters driver */ - if (ir->get_key == NULL) { + /* Make sure we are all setup before going on */ + if (!name || !ir->get_key || !ir_codes) { + dprintk(1, DEVNAME ": Unsupported device at address 0x%02x\n", + addr); err = -ENODEV; - goto err_out_detach; + goto err_out_free; } - /* Phys addr can only be set after attaching (for ir->c.dev) */ + /* Sets name */ + snprintf(ir->name, sizeof(ir->name), "i2c IR (%s)", name); + ir->ir_codes = ir_codes; + snprintf(ir->phys, sizeof(ir->phys), "%s/%s/ir0", - dev_name(&ir->c.adapter->dev), - dev_name(&ir->c.dev)); + dev_name(&adap->dev), + dev_name(&client->dev)); /* init + register input device */ ir_input_init(input_dev, &ir->ir, ir_type, ir->ir_codes); input_dev->id.bustype = BUS_I2C; - input_dev->name = ir->c.name; + input_dev->name = ir->name; input_dev->phys = ir->phys; err = input_register_device(ir->input); if (err) - goto err_out_detach; + goto err_out_free; printk(DEVNAME ": %s detected at %s [%s]\n", ir->input->name, ir->input->phys, adap->name); @@ -464,135 +443,42 @@ static int ir_attach(struct i2c_adapter *adap, int addr, return 0; - err_out_detach: - i2c_detach_client(&ir->c); err_out_free: input_free_device(input_dev); kfree(ir); return err; } -static int ir_detach(struct i2c_client *client) +static int ir_remove(struct i2c_client *client) { struct IR_i2c *ir = i2c_get_clientdata(client); /* kill outstanding polls */ cancel_delayed_work_sync(&ir->work); - /* unregister devices */ + /* unregister device */ input_unregister_device(ir->input); - i2c_detach_client(&ir->c); /* free memory */ kfree(ir); return 0; } -static int ir_probe(struct i2c_adapter *adap) -{ - - /* The external IR receiver is at i2c address 0x34 (0x35 for - reads). Future Hauppauge cards will have an internal - receiver at 0x30 (0x31 for reads). In theory, both can be - fitted, and Hauppauge suggest an external overrides an - internal. - - That's why we probe 0x1a (~0x34) first. CB - */ - - static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1}; - static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, 0x2d, -1 }; - static const int probe_em28XX[] = { 0x30, 0x47, -1 }; - static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 }; - static const int probe_cx23885[] = { 0x6b, -1 }; - const int *probe; - struct i2c_msg msg = { - .flags = I2C_M_RD, - .len = 0, - .buf = NULL, - }; - int i, rc; - - switch (adap->id) { - case I2C_HW_B_BT848: - probe = probe_bttv; - break; - case I2C_HW_B_CX2341X: - probe = probe_bttv; - break; - case I2C_HW_SAA7134: - probe = probe_saa7134; - break; - case I2C_HW_B_EM28XX: - probe = probe_em28XX; - break; - case I2C_HW_B_CX2388x: - probe = probe_cx88; - break; - case I2C_HW_B_CX23885: - probe = probe_cx23885; - break; - default: - return 0; - } - - for (i = 0; -1 != probe[i]; i++) { - msg.addr = probe[i]; - rc = i2c_transfer(adap, &msg, 1); - dprintk(1,"probe 0x%02x @ %s: %s\n", - probe[i], adap->name, - (1 == rc) ? "yes" : "no"); - if (1 == rc) { - ir_attach(adap, probe[i], 0, 0); - return 0; - } - } - - /* Special case for MSI TV@nywhere Plus remote */ - if (adap->id == I2C_HW_SAA7134) { - u8 temp; - - /* MSI TV@nywhere Plus controller doesn't seem to - respond to probes unless we read something from - an existing device. Weird... */ - - msg.addr = 0x50; - rc = i2c_transfer(adap, &msg, 1); - dprintk(1, "probe 0x%02x @ %s: %s\n", - msg.addr, adap->name, - (1 == rc) ? "yes" : "no"); - - /* Now do the probe. The controller does not respond - to 0-byte reads, so we use a 1-byte read instead. */ - msg.addr = 0x30; - msg.len = 1; - msg.buf = &temp; - rc = i2c_transfer(adap, &msg, 1); - dprintk(1, "probe 0x%02x @ %s: %s\n", - msg.addr, adap->name, - (1 == rc) ? "yes" : "no"); - if (1 == rc) - ir_attach(adap, msg.addr, 0, 0); - } - - /* Special case for AVerMedia Cardbus remote */ - if (adap->id == I2C_HW_SAA7134) { - unsigned char subaddr, data; - struct i2c_msg msg[] = { { .addr = 0x40, .flags = 0, - .buf = &subaddr, .len = 1}, - { .addr = 0x40, .flags = I2C_M_RD, - .buf = &data, .len = 1} }; - subaddr = 0x0d; - rc = i2c_transfer(adap, msg, 2); - dprintk(1, "probe 0x%02x/0x%02x @ %s: %s\n", - msg[0].addr, subaddr, adap->name, - (2 == rc) ? "yes" : "no"); - if (2 == rc) - ir_attach(adap, msg[0].addr, 0, 0); - } +static const struct i2c_device_id ir_kbd_id[] = { + /* Generic entry for any IR receiver */ + { "ir_video", 0 }, + /* IR device specific entries could be added here */ + { } +}; - return 0; -} +static struct i2c_driver driver = { + .driver = { + .name = "ir-kbd-i2c", + }, + .probe = ir_probe, + .remove = ir_remove, + .id_table = ir_kbd_id, +}; /* ----------------------------------------------------------------------- */ diff --git a/linux/drivers/media/video/ivtv/ivtv-i2c.c b/linux/drivers/media/video/ivtv/ivtv-i2c.c index 984c73b5e..0d18c2220 100644 --- a/linux/drivers/media/video/ivtv/ivtv-i2c.c +++ b/linux/drivers/media/video/ivtv/ivtv-i2c.c @@ -592,9 +592,11 @@ static struct i2c_client ivtv_i2c_client_template = { .name = "ivtv internal", }; -/* init + register i2c algo-bit adapter */ +/* init + register i2c adapter + instantiate IR receiver */ int init_ivtv_i2c(struct ivtv *itv) { + int retval; + IVTV_DEBUG_I2C("i2c init\n"); /* Sanity checks for the I2C hardware arrays. They must be the @@ -634,9 +636,37 @@ int init_ivtv_i2c(struct ivtv *itv) ivtv_setsda(itv, 1); if (itv->options.newi2c > 0) - return i2c_add_adapter(&itv->i2c_adap); + retval = i2c_add_adapter(&itv->i2c_adap); else - return i2c_bit_add_bus(&itv->i2c_adap); + retval = i2c_bit_add_bus(&itv->i2c_adap); + + /* Instantiate the IR receiver device, if present */ + if (retval == 0) { + struct i2c_board_info info; + /* The external IR receiver is at i2c address 0x34 (0x35 for + reads). Future Hauppauge cards will have an internal + receiver at 0x30 (0x31 for reads). In theory, both can be + fitted, and Hauppauge suggest an external overrides an + internal. + + That's why we probe 0x1a (~0x34) first. CB + */ + const unsigned short addr_list[] = { + 0x1a, /* Hauppauge IR external */ + 0x18, /* Hauppauge IR internal */ + 0x71, /* Hauppauge IR (PVR150) */ + 0x64, /* Pixelview IR */ + 0x30, /* KNC ONE IR */ + 0x6b, /* Adaptec IR */ + I2C_CLIENT_END + }; + + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); + i2c_new_probed_device(&itv->i2c_adap, &info, addr_list); + } + + return retval; } void exit_ivtv_i2c(struct ivtv *itv) diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c index 341af4355..336a20ede 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -285,7 +285,9 @@ static struct tda10048_config hauppauge_tda10048_config = { .output_mode = TDA10048_PARALLEL_OUTPUT, .fwbulkwritelen = TDA10048_BULKWRITE_50, .inversion = TDA10048_INVERSION_ON, - .if_freq_khz = TDA10048_IF_4300, + .dtv6_if_freq_khz = TDA10048_IF_3300, + .dtv7_if_freq_khz = TDA10048_IF_3800, + .dtv8_if_freq_khz = TDA10048_IF_4300, .clk_freq_khz = TDA10048_CLK_16000, .disable_gate_access = 1, }; diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index 28463489a..694e51f58 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -43,7 +43,7 @@ static int ir_mode[PVR_NUM] = { [0 ... PVR_NUM-1] = 1 }; module_param_array(ir_mode, int, NULL, 0444); MODULE_PARM_DESC(ir_mode,"specify: 0=disable IR reception, 1=normal IR"); -static int pvr2_disable_ir_video = 1; +static int pvr2_disable_ir_video; module_param_named(disable_autoload_ir_video, pvr2_disable_ir_video, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(disable_autoload_ir_video, diff --git a/linux/drivers/media/video/s2255drv.c b/linux/drivers/media/video/s2255drv.c index 8a939387a..203f6e3ff 100644 --- a/linux/drivers/media/video/s2255drv.c +++ b/linux/drivers/media/video/s2255drv.c @@ -110,6 +110,8 @@ #define SCALE_4CIFS 1 /* 640x480(NTSC) or 704x576(PAL) */ #define SCALE_2CIFS 2 /* 640x240(NTSC) or 704x288(PAL) */ #define SCALE_1CIFS 3 /* 320x240(NTSC) or 352x288(PAL) */ +/* SCALE_4CIFSI is the 2 fields interpolated into one */ +#define SCALE_4CIFSI 4 /* 640x480(NTSC) or 704x576(PAL) high quality */ #define COLOR_YUVPL 1 /* YUV planar */ #define COLOR_YUVPK 2 /* YUV packed */ @@ -239,6 +241,8 @@ struct s2255_dev { struct s2255_mode mode[MAX_CHANNELS]; /* jpeg compression */ struct v4l2_jpegcompression jc[MAX_CHANNELS]; + /* capture parameters (for high quality mode full size) */ + struct v4l2_captureparm cap_parm[MAX_CHANNELS]; const struct s2255_fmt *cur_fmt[MAX_CHANNELS]; int cur_frame[MAX_CHANNELS]; int last_frame[MAX_CHANNELS]; @@ -1021,9 +1025,16 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, fh->type = f->type; norm = norm_minw(fh->dev->vdev[fh->channel]); if (fh->width > norm_minw(fh->dev->vdev[fh->channel])) { - if (fh->height > norm_minh(fh->dev->vdev[fh->channel])) - fh->mode.scale = SCALE_4CIFS; - else + if (fh->height > norm_minh(fh->dev->vdev[fh->channel])) { + if (fh->dev->cap_parm[fh->channel].capturemode & + V4L2_MODE_HIGHQUALITY) { + fh->mode.scale = SCALE_4CIFSI; + dprintk(2, "scale 4CIFSI\n"); + } else { + fh->mode.scale = SCALE_4CIFS; + dprintk(2, "scale 4CIFS\n"); + } + } else fh->mode.scale = SCALE_2CIFS; } else { @@ -1124,6 +1135,7 @@ static u32 get_transfer_size(struct s2255_mode *mode) if (mode->format == FORMAT_NTSC) { switch (mode->scale) { case SCALE_4CIFS: + case SCALE_4CIFSI: linesPerFrame = NUM_LINES_4CIFS_NTSC * 2; pixelsPerLine = LINE_SZ_4CIFS_NTSC; break; @@ -1141,6 +1153,7 @@ static u32 get_transfer_size(struct s2255_mode *mode) } else if (mode->format == FORMAT_PAL) { switch (mode->scale) { case SCALE_4CIFS: + case SCALE_4CIFSI: linesPerFrame = NUM_LINES_4CIFS_PAL * 2; pixelsPerLine = LINE_SZ_4CIFS_PAL; break; @@ -1496,6 +1509,33 @@ static int vidioc_s_jpegcomp(struct file *file, void *priv, dprintk(2, "setting jpeg quality %d\n", jc->quality); return 0; } + +static int vidioc_g_parm(struct file *file, void *priv, + struct v4l2_streamparm *sp) +{ + struct s2255_fh *fh = priv; + struct s2255_dev *dev = fh->dev; + if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + sp->parm.capture.capturemode = dev->cap_parm[fh->channel].capturemode; + dprintk(2, "getting parm %d\n", sp->parm.capture.capturemode); + return 0; +} + +static int vidioc_s_parm(struct file *file, void *priv, + struct v4l2_streamparm *sp) +{ + struct s2255_fh *fh = priv; + struct s2255_dev *dev = fh->dev; + + if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + dev->cap_parm[fh->channel].capturemode = sp->parm.capture.capturemode; + dprintk(2, "setting param capture mode %d\n", + sp->parm.capture.capturemode); + return 0; +} static int s2255_open(struct file *file) { int minor = video_devdata(file)->minor; @@ -1787,6 +1827,8 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = { #endif .vidioc_s_jpegcomp = vidioc_s_jpegcomp, .vidioc_g_jpegcomp = vidioc_g_jpegcomp, + .vidioc_s_parm = vidioc_s_parm, + .vidioc_g_parm = vidioc_g_parm, }; static struct video_device template = { diff --git a/linux/drivers/media/video/saa7134/Kconfig b/linux/drivers/media/video/saa7134/Kconfig index 0ba68987b..5bcce092e 100644 --- a/linux/drivers/media/video/saa7134/Kconfig +++ b/linux/drivers/media/video/saa7134/Kconfig @@ -44,6 +44,7 @@ config VIDEO_SAA7134_DVB select DVB_LNBP21 if !DVB_FE_CUSTOMISE select DVB_ZL10353 if !DVB_FE_CUSTOMISE select DVB_LGDT3305 if !DVB_FE_CUSTOMISE + select DVB_TDA10048 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE ---help--- diff --git a/linux/drivers/media/video/saa7134/saa7134-cards.c b/linux/drivers/media/video/saa7134/saa7134-cards.c index a4e3deac2..587209fdd 100644 --- a/linux/drivers/media/video/saa7134/saa7134-cards.c +++ b/linux/drivers/media/video/saa7134/saa7134-cards.c @@ -3403,13 +3403,15 @@ struct saa7134_board saa7134_boards[] = { }, }, [SAA7134_BOARD_HAUPPAUGE_HVR1110R3] = { - .name = "Hauppauge WinTV-HVR1110r3", + .name = "Hauppauge WinTV-HVR1110r3 DVB-T/Hybrid", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_TDA8290, .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tuner_config = 3, + .mpeg = SAA7134_MPEG_DVB, + .ts_type = SAA7134_MPEG_TS_SERIAL, .gpiomask = 0x0800100, /* GPIO 21 is an INPUT */ .inputs = {{ .name = name_tv, diff --git a/linux/drivers/media/video/saa7134/saa7134-core.c b/linux/drivers/media/video/saa7134/saa7134-core.c index 69a214417..dc692d7a7 100644 --- a/linux/drivers/media/video/saa7134/saa7134-core.c +++ b/linux/drivers/media/video/saa7134/saa7134-core.c @@ -836,7 +836,6 @@ static struct video_device *vdev_init(struct saa7134_dev *dev, if (NULL == vfd) return NULL; *vfd = *template; - vfd->minor = -1; vfd->v4l2_dev = &dev->v4l2_dev; vfd->release = video_device_release; vfd->debug = video_debug; diff --git a/linux/drivers/media/video/saa7134/saa7134-dvb.c b/linux/drivers/media/video/saa7134/saa7134-dvb.c index 2e1344ecf..360fbdf19 100644 --- a/linux/drivers/media/video/saa7134/saa7134-dvb.c +++ b/linux/drivers/media/video/saa7134/saa7134-dvb.c @@ -48,6 +48,7 @@ #include "isl6405.h" #include "lnbp21.h" #include "tuner-simple.h" +#include "tda10048.h" #include "tda18271.h" #include "lgdt3305.h" #include "tda8290.h" @@ -978,6 +979,18 @@ static struct lgdt3305_config hcw_lgdt3305_config = { .vsb_if_khz = 3250, }; +static struct tda10048_config hcw_tda10048_config = { + .demod_address = 0x10 >> 1, + .output_mode = TDA10048_SERIAL_OUTPUT, + .fwbulkwritelen = TDA10048_BULKWRITE_200, + .inversion = TDA10048_INVERSION_ON, + .dtv6_if_freq_khz = TDA10048_IF_3300, + .dtv7_if_freq_khz = TDA10048_IF_3500, + .dtv8_if_freq_khz = TDA10048_IF_4000, + .clk_freq_khz = TDA10048_CLK_16000, + .disable_gate_access = 1, +}; + static struct tda18271_std_map hauppauge_tda18271_std_map = { .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 4, .if_lvl = 1, .rfagc_top = 0x58, }, @@ -1106,6 +1119,19 @@ static int dvb_init(struct saa7134_dev *dev) &tda827x_cfg_2) < 0) goto dettach_frontend; break; + case SAA7134_BOARD_HAUPPAUGE_HVR1110R3: + fe0->dvb.frontend = dvb_attach(tda10048_attach, + &hcw_tda10048_config, + &dev->i2c_adap); + if (fe0->dvb.frontend != NULL) { + dvb_attach(tda829x_attach, fe0->dvb.frontend, + &dev->i2c_adap, 0x4b, + &tda829x_no_probe); + dvb_attach(tda18271_attach, fe0->dvb.frontend, + 0x60, &dev->i2c_adap, + &hcw_tda18271_config); + } + break; case SAA7134_BOARD_PHILIPS_TIGER: if (configure_tda827x_fe(dev, &philips_tiger_config, &tda827x_cfg_0) < 0) diff --git a/linux/drivers/media/video/saa7134/saa7134-i2c.c b/linux/drivers/media/video/saa7134/saa7134-i2c.c index 3eb60aabe..a8185693f 100644 --- a/linux/drivers/media/video/saa7134/saa7134-i2c.c +++ b/linux/drivers/media/video/saa7134/saa7134-i2c.c @@ -264,7 +264,7 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap, /* workaround for a saa7134 i2c bug * needed to talk to the mt352 demux * thanks to pinnacle for the hint */ - int quirk = 0xfd; + int quirk = 0xfe; d1printk(" [%02x quirk]",quirk); i2c_send_byte(dev,START,quirk); i2c_recv_byte(dev); @@ -326,33 +326,6 @@ static u32 functionality(struct i2c_adapter *adap) return I2C_FUNC_SMBUS_EMUL; } -static int attach_inform(struct i2c_client *client) -{ - struct saa7134_dev *dev = client->adapter->algo_data; - - d1printk( "%s i2c attach [addr=0x%x,client=%s]\n", - client->driver->driver.name, client->addr, client->name); - - /* Am I an i2c remote control? */ - - switch (client->addr) { - case 0x7a: - case 0x47: - case 0x71: - case 0x2d: - case 0x30: - { - struct IR_i2c *ir = i2c_get_clientdata(client); - d1printk("%s i2c IR detected (%s).\n", - client->driver->driver.name, ir->phys); - saa7134_set_i2c_ir(dev,ir); - break; - } - } - - return 0; -} - static struct i2c_algorithm saa7134_algo = { .master_xfer = saa7134_i2c_xfer, .functionality = functionality, @@ -369,7 +342,6 @@ static struct i2c_adapter saa7134_adap_template = { .name = "saa7134", .id = I2C_HW_SAA7134, .algo = &saa7134_algo, - .client_register = attach_inform, }; static struct i2c_client saa7134_client_template = { @@ -444,6 +416,9 @@ int saa7134_i2c_register(struct saa7134_dev *dev) saa7134_i2c_eeprom(dev,dev->eedata,sizeof(dev->eedata)); if (i2c_scan) do_i2c_scan(dev->name,&dev->i2c_client); + + /* Instantiate the IR receiver device, if present */ + saa7134_probe_i2c_ir(dev); return 0; } diff --git a/linux/drivers/media/video/saa7134/saa7134-input.c b/linux/drivers/media/video/saa7134/saa7134-input.c index 80a4cc23d..36913d22b 100644 --- a/linux/drivers/media/video/saa7134/saa7134-input.c +++ b/linux/drivers/media/video/saa7134/saa7134-input.c @@ -60,7 +60,7 @@ MODULE_PARM_DESC(disable_other_ir, "disable full codes of " #define dprintk(fmt, arg...) if (ir_debug) \ printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg) #define i2cdprintk(fmt, arg...) if (ir_debug) \ - printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg) + printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg) /* Helper functions for RC5 and NEC decoding at GPIO16 or GPIO18 */ static int saa7134_rc5_irq(struct saa7134_dev *dev); @@ -134,10 +134,10 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key, int gpio; /* <dev> is needed to access GPIO. Used by the saa_readl macro. */ - struct saa7134_dev *dev = ir->c.adapter->algo_data; + struct saa7134_dev *dev = ir->c->adapter->algo_data; if (dev == NULL) { dprintk("get_key_msi_tvanywhere_plus: " - "gir->c.adapter->algo_data is NULL!\n"); + "gir->c->adapter->algo_data is NULL!\n"); return -EIO; } @@ -156,7 +156,7 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key, /* GPIO says there is a button press. Get it. */ - if (1 != i2c_master_recv(&ir->c, &b, 1)) { + if (1 != i2c_master_recv(ir->c, &b, 1)) { i2cdprintk("read error\n"); return -EIO; } @@ -179,7 +179,7 @@ static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) unsigned char b; /* poll IR chip */ - if (1 != i2c_master_recv(&ir->c,&b,1)) { + if (1 != i2c_master_recv(ir->c, &b, 1)) { i2cdprintk("read error\n"); return -EIO; } @@ -202,7 +202,7 @@ static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) unsigned char buf[5], cod4, code3, code4; /* poll IR chip */ - if (5 != i2c_master_recv(&ir->c,buf,5)) + if (5 != i2c_master_recv(ir->c, buf, 5)) return -EIO; cod4 = buf[4]; @@ -224,7 +224,7 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) unsigned char data[12]; u32 gpio; - struct saa7134_dev *dev = ir->c.adapter->algo_data; + struct saa7134_dev *dev = ir->c->adapter->algo_data; /* rising SAA7134_GPIO_GPRESCAN reads the status */ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); @@ -235,9 +235,9 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) if (0x400000 & ~gpio) return 0; /* No button press */ - ir->c.addr = 0x5a >> 1; + ir->c->addr = 0x5a >> 1; - if (12 != i2c_master_recv(&ir->c, data, 12)) { + if (12 != i2c_master_recv(ir->c, data, 12)) { i2cdprintk("read error\n"); return -EIO; } @@ -267,7 +267,7 @@ static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw, unsigned int start = 0,parity = 0,code = 0; /* poll IR chip */ - if (4 != i2c_master_recv(&ir->c, b, 4)) { + if (4 != i2c_master_recv(ir->c, b, 4)) { i2cdprintk("read error\n"); return -EIO; } @@ -686,40 +686,68 @@ void saa7134_input_fini(struct saa7134_dev *dev) dev->remote = NULL; } -void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir) +void saa7134_probe_i2c_ir(struct saa7134_dev *dev) { + struct i2c_board_info info; + struct IR_i2c_init_data init_data; + const unsigned short addr_list[] = { + 0x7a, 0x47, 0x71, 0x2d, + I2C_CLIENT_END + }; + + struct i2c_msg msg_msi = { + .addr = 0x50, + .flags = I2C_M_RD, + .len = 0, + .buf = NULL, + }; + + int rc; + if (disable_ir) { - dprintk("Found supported i2c remote, but IR has been disabled\n"); - ir->get_key=NULL; + dprintk("IR has been disabled, not probing for i2c remote\n"); return; } + memset(&info, 0, sizeof(struct i2c_board_info)); + memset(&init_data, 0, sizeof(struct IR_i2c_init_data)); + strlcpy(info.type, "ir_video", I2C_NAME_SIZE); + switch (dev->board) { case SAA7134_BOARD_PINNACLE_PCTV_110i: case SAA7134_BOARD_PINNACLE_PCTV_310i: - snprintf(ir->c.name, sizeof(ir->c.name), "Pinnacle PCTV"); + init_data.name = "Pinnacle PCTV"; if (pinnacle_remote == 0) { - ir->get_key = get_key_pinnacle_color; - ir->ir_codes = ir_codes_pinnacle_color; + init_data.get_key = get_key_pinnacle_color; + init_data.ir_codes = ir_codes_pinnacle_color; } else { - ir->get_key = get_key_pinnacle_grey; - ir->ir_codes = ir_codes_pinnacle_grey; + init_data.get_key = get_key_pinnacle_grey; + init_data.ir_codes = ir_codes_pinnacle_grey; } break; case SAA7134_BOARD_UPMOST_PURPLE_TV: - snprintf(ir->c.name, sizeof(ir->c.name), "Purple TV"); - ir->get_key = get_key_purpletv; - ir->ir_codes = ir_codes_purpletv; + init_data.name = "Purple TV"; + init_data.get_key = get_key_purpletv; + init_data.ir_codes = ir_codes_purpletv; break; case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS: - snprintf(ir->c.name, sizeof(ir->c.name), "MSI TV@nywhere Plus"); - ir->get_key = get_key_msi_tvanywhere_plus; - ir->ir_codes = ir_codes_msi_tvanywhere_plus; + init_data.name = "MSI TV@nywhere Plus"; + init_data.get_key = get_key_msi_tvanywhere_plus; + init_data.ir_codes = ir_codes_msi_tvanywhere_plus; + info.addr = 0x30; + /* MSI TV@nywhere Plus controller doesn't seem to + respond to probes unless we read something from + an existing device. Weird... + REVISIT: might no longer be needed */ + rc = i2c_transfer(&dev->i2c_adap, &msg_msi, 1); + dprintk(KERN_DEBUG "probe 0x%02x @ %s: %s\n", + msg_msi.addr, dev->i2c_adap.name, + (1 == rc) ? "yes" : "no"); break; case SAA7134_BOARD_HAUPPAUGE_HVR1110: - snprintf(ir->c.name, sizeof(ir->c.name), "HVR 1110"); - ir->get_key = get_key_hvr1110; - ir->ir_codes = ir_codes_hauppauge_new; + init_data.name = "HVR 1110"; + init_data.get_key = get_key_hvr1110; + init_data.ir_codes = ir_codes_hauppauge_new; break; case SAA7134_BOARD_BEHOLD_607FM_MK3: case SAA7134_BOARD_BEHOLD_607FM_MK5: @@ -733,15 +761,26 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir) case SAA7134_BOARD_BEHOLD_M63: case SAA7134_BOARD_BEHOLD_M6_EXTRA: case SAA7134_BOARD_BEHOLD_H6: - snprintf(ir->c.name, sizeof(ir->c.name), "BeholdTV"); - ir->get_key = get_key_beholdm6xx; - ir->ir_codes = ir_codes_behold; + init_data.name = "BeholdTV"; + init_data.get_key = get_key_beholdm6xx; + init_data.ir_codes = ir_codes_behold; break; - default: - dprintk("Shouldn't get here: Unknown board %x for I2C IR?\n",dev->board); + case SAA7134_BOARD_AVERMEDIA_CARDBUS_501: + case SAA7134_BOARD_AVERMEDIA_CARDBUS_506: + info.addr = 0x40; break; } + if (init_data.name) + info.platform_data = &init_data; + /* No need to probe if address is known */ + if (info.addr) { + i2c_new_device(&dev->i2c_adap, &info); + return; + } + + /* Address not known, fallback to probing */ + i2c_new_probed_device(&dev->i2c_adap, &info, addr_list); } static int saa7134_rc5_irq(struct saa7134_dev *dev) diff --git a/linux/drivers/media/video/saa7134/saa7134-video.c b/linux/drivers/media/video/saa7134/saa7134-video.c index 5f68bed54..26f1727e6 100644 --- a/linux/drivers/media/video/saa7134/saa7134-video.c +++ b/linux/drivers/media/video/saa7134/saa7134-video.c @@ -1423,11 +1423,13 @@ video_poll(struct file *file, struct poll_table_struct *wait) { struct saa7134_fh *fh = file->private_data; struct videobuf_buffer *buf = NULL; + unsigned int rc = 0; if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) return videobuf_poll_stream(file, &fh->vbi, wait); if (res_check(fh,RESOURCE_VIDEO)) { + mutex_lock(&fh->cap.vb_lock); if (!list_empty(&fh->cap.stream)) buf = list_entry(fh->cap.stream.next, struct videobuf_buffer, stream); } else { @@ -1446,13 +1448,14 @@ video_poll(struct file *file, struct poll_table_struct *wait) } if (!buf) - return POLLERR; + rc = POLLERR; poll_wait(file, &buf->done, wait); if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) - return POLLIN|POLLRDNORM; - return 0; + rc = POLLIN|POLLRDNORM; + mutex_unlock(&fh->cap.vb_lock); + return rc; err: mutex_unlock(&fh->cap.vb_lock); diff --git a/linux/drivers/media/video/saa7134/saa7134.h b/linux/drivers/media/video/saa7134/saa7134.h index ae7ba8923..be6763dde 100644 --- a/linux/drivers/media/video/saa7134/saa7134.h +++ b/linux/drivers/media/video/saa7134/saa7134.h @@ -804,7 +804,7 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status); int saa7134_input_init1(struct saa7134_dev *dev); void saa7134_input_fini(struct saa7134_dev *dev); void saa7134_input_irq(struct saa7134_dev *dev); -void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir); +void saa7134_probe_i2c_ir(struct saa7134_dev *dev); void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir); void saa7134_ir_stop(struct saa7134_dev *dev); diff --git a/linux/drivers/media/video/uvc/uvc_driver.c b/linux/drivers/media/video/uvc/uvc_driver.c index 4a69a3af6..8d193376c 100644 --- a/linux/drivers/media/video/uvc/uvc_driver.c +++ b/linux/drivers/media/video/uvc/uvc_driver.c @@ -289,10 +289,8 @@ static int uvc_parse_format(struct uvc_device *dev, struct uvc_format_desc *fmtdesc; struct uvc_frame *frame; const unsigned char *start = buffer; - unsigned char *_buffer; unsigned int interval; unsigned int i, n; - int _buflen; __u8 ftype; format->type = buffer[2]; @@ -303,7 +301,7 @@ static int uvc_parse_format(struct uvc_device *dev, case VS_FORMAT_FRAME_BASED: n = buffer[2] == VS_FORMAT_UNCOMPRESSED ? 27 : 28; if (buflen < n) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming" + uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " "interface %d FORMAT error\n", dev->udev->devnum, alts->desc.bInterfaceNumber); @@ -338,7 +336,7 @@ static int uvc_parse_format(struct uvc_device *dev, case VS_FORMAT_MJPEG: if (buflen < 11) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming" + uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " "interface %d FORMAT error\n", dev->udev->devnum, alts->desc.bInterfaceNumber); @@ -354,7 +352,7 @@ static int uvc_parse_format(struct uvc_device *dev, case VS_FORMAT_DV: if (buflen < 9) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming" + uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " "interface %d FORMAT error\n", dev->udev->devnum, alts->desc.bInterfaceNumber); @@ -372,7 +370,7 @@ static int uvc_parse_format(struct uvc_device *dev, strlcpy(format->name, "HD-DV", sizeof format->name); break; default: - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming" + uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " "interface %d: unknown DV format %u\n", dev->udev->devnum, alts->desc.bInterfaceNumber, buffer[8]); @@ -401,7 +399,7 @@ static int uvc_parse_format(struct uvc_device *dev, case VS_FORMAT_STREAM_BASED: /* Not supported yet. */ default: - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming" + uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " "interface %d unsupported format %u\n", dev->udev->devnum, alts->desc.bInterfaceNumber, buffer[2]); @@ -413,20 +411,11 @@ static int uvc_parse_format(struct uvc_device *dev, buflen -= buffer[0]; buffer += buffer[0]; - /* Count the number of frame descriptors to test the bFrameIndex - * field when parsing the descriptors. We can't rely on the - * bNumFrameDescriptors field as some cameras don't initialize it - * properly. - */ - for (_buflen = buflen, _buffer = buffer; - _buflen > 2 && _buffer[2] == ftype; - _buflen -= _buffer[0], _buffer += _buffer[0]) - format->nframes++; - /* Parse the frame descriptors. Only uncompressed, MJPEG and frame * based formats have frame descriptors. */ while (buflen > 2 && buffer[2] == ftype) { + frame = &format->frame[format->nframes]; if (ftype != VS_FRAME_FRAME_BASED) n = buflen > 25 ? buffer[25] : 0; else @@ -435,22 +424,12 @@ static int uvc_parse_format(struct uvc_device *dev, n = n ? n : 3; if (buflen < 26 + 4*n) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming" + uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " "interface %d FRAME error\n", dev->udev->devnum, alts->desc.bInterfaceNumber); return -EINVAL; } - if (buffer[3] - 1 >= format->nframes) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming" - "interface %d frame index %u out of range\n", - dev->udev->devnum, alts->desc.bInterfaceNumber, - buffer[3]); - return -EINVAL; - } - - frame = &format->frame[buffer[3] - 1]; - frame->bFrameIndex = buffer[3]; frame->bmCapabilities = buffer[4]; frame->wWidth = get_unaligned_le16(&buffer[5]); @@ -507,6 +486,7 @@ static int uvc_parse_format(struct uvc_device *dev, 10000000/frame->dwDefaultFrameInterval, (100000000/frame->dwDefaultFrameInterval)%10); + format->nframes++; buflen -= buffer[0]; buffer += buffer[0]; } @@ -518,7 +498,7 @@ static int uvc_parse_format(struct uvc_device *dev, if (buflen > 2 && buffer[2] == VS_COLORFORMAT) { if (buflen < 6) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming" + uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " "interface %d COLORFORMAT error\n", dev->udev->devnum, alts->desc.bInterfaceNumber); @@ -1316,7 +1296,7 @@ static int uvc_scan_chain_forward(struct uvc_video_device *video, continue; if (forward->extension.bNrInPins != 1) { - uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has" + uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has " "more than 1 input pin.\n", entity->id); return -1; } @@ -1614,6 +1594,7 @@ static int uvc_probe(struct usb_interface *intf, INIT_LIST_HEAD(&dev->entities); INIT_LIST_HEAD(&dev->streaming); kref_init(&dev->kref); + atomic_set(&dev->users, 0); dev->udev = usb_get_dev(udev); dev->intf = usb_get_intf(intf); @@ -1929,7 +1910,7 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_STREAM_NO_FID }, - /* Lenovo Thinkpad SL500 */ + /* Lenovo Thinkpad SL400/SL500 */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x17ef, diff --git a/linux/drivers/media/video/uvc/uvc_status.c b/linux/drivers/media/video/uvc/uvc_status.c index 1e1bda413..b05df63b4 100644 --- a/linux/drivers/media/video/uvc/uvc_status.c +++ b/linux/drivers/media/video/uvc/uvc_status.c @@ -206,7 +206,7 @@ int uvc_status_init(struct uvc_device *dev) dev->status, UVC_MAX_STATUS_SIZE, uvc_status_complete, dev, interval); - return usb_submit_urb(dev->int_urb, GFP_KERNEL); + return 0; } void uvc_status_cleanup(struct uvc_device *dev) @@ -217,15 +217,30 @@ void uvc_status_cleanup(struct uvc_device *dev) uvc_input_cleanup(dev); } -int uvc_status_suspend(struct uvc_device *dev) +int uvc_status_start(struct uvc_device *dev) +{ + if (dev->int_urb == NULL) + return 0; + + return usb_submit_urb(dev->int_urb, GFP_KERNEL); +} + +void uvc_status_stop(struct uvc_device *dev) { usb_kill_urb(dev->int_urb); +} + +int uvc_status_suspend(struct uvc_device *dev) +{ + if (atomic_read(&dev->users)) + usb_kill_urb(dev->int_urb); + return 0; } int uvc_status_resume(struct uvc_device *dev) { - if (dev->int_urb == NULL) + if (dev->int_urb == NULL || atomic_read(&dev->users) == 0) return 0; return usb_submit_urb(dev->int_urb, GFP_NOIO); diff --git a/linux/drivers/media/video/uvc/uvc_v4l2.c b/linux/drivers/media/video/uvc/uvc_v4l2.c index bc13dbf05..160c01314 100644 --- a/linux/drivers/media/video/uvc/uvc_v4l2.c +++ b/linux/drivers/media/video/uvc/uvc_v4l2.c @@ -443,6 +443,17 @@ static int uvc_v4l2_open(struct file *file) goto done; } + if (atomic_inc_return(&video->dev->users) == 1) { + if ((ret = uvc_status_start(video->dev)) < 0) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) + usb_autopm_put_interface(video->dev->intf); +#endif + atomic_dec(&video->dev->users); + kfree(handle); + goto done; + } + } + handle->device = video; handle->state = UVC_HANDLE_PASSIVE; file->private_data = handle; @@ -477,6 +488,9 @@ 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 LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) usb_autopm_put_interface(video->dev->intf); #endif diff --git a/linux/drivers/media/video/uvc/uvc_video.c b/linux/drivers/media/video/uvc/uvc_video.c index c5df33de9..07e755ba7 100644 --- a/linux/drivers/media/video/uvc/uvc_video.c +++ b/linux/drivers/media/video/uvc/uvc_video.c @@ -65,7 +65,8 @@ static void uvc_fixup_video_ctrl(struct uvc_video_device *video, struct uvc_streaming_control *ctrl) { struct uvc_format *format; - struct uvc_frame *frame; + struct uvc_frame *frame = NULL; + unsigned int i; if (ctrl->bFormatIndex <= 0 || ctrl->bFormatIndex > video->streaming->nformats) @@ -73,11 +74,15 @@ static void uvc_fixup_video_ctrl(struct uvc_video_device *video, format = &video->streaming->format[ctrl->bFormatIndex - 1]; - if (ctrl->bFrameIndex <= 0 || - ctrl->bFrameIndex > format->nframes) - return; + for (i = 0; i < format->nframes; ++i) { + if (format->frame[i].bFrameIndex == ctrl->bFrameIndex) { + frame = &format->frame[i]; + break; + } + } - frame = &format->frame[ctrl->bFrameIndex - 1]; + if (frame == NULL) + return; if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) || (ctrl->dwMaxVideoFrameSize == 0 && @@ -1093,7 +1098,7 @@ int uvc_video_init(struct uvc_video_device *video) /* Zero bFrameIndex might be correct. Stream-based formats (including * MPEG-2 TS and DV) do not support frames but have a dummy frame * descriptor with bFrameIndex set to zero. If the default frame - * descriptor is not found, use the first avalable frame. + * descriptor is not found, use the first available frame. */ for (i = format->nframes; i > 0; --i) { frame = &format->frame[i-1]; diff --git a/linux/drivers/media/video/uvc/uvcvideo.h b/linux/drivers/media/video/uvc/uvcvideo.h index 53d5c9e0c..6b254fd39 100644 --- a/linux/drivers/media/video/uvc/uvcvideo.h +++ b/linux/drivers/media/video/uvc/uvcvideo.h @@ -635,6 +635,7 @@ struct uvc_device { enum uvc_device_state state; struct kref kref; struct list_head list; + atomic_t users; /* Video control interface */ __u16 uvc_version; @@ -771,6 +772,8 @@ extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, /* Status */ extern int uvc_status_init(struct uvc_device *dev); extern void uvc_status_cleanup(struct uvc_device *dev); +extern int uvc_status_start(struct uvc_device *dev); +extern void uvc_status_stop(struct uvc_device *dev); extern int uvc_status_suspend(struct uvc_device *dev); extern int uvc_status_resume(struct uvc_device *dev); diff --git a/linux/drivers/media/video/videobuf-dma-sg.c b/linux/drivers/media/video/videobuf-dma-sg.c index ed38145e1..623e2fc12 100644 --- a/linux/drivers/media/video/videobuf-dma-sg.c +++ b/linux/drivers/media/video/videobuf-dma-sg.c @@ -59,9 +59,10 @@ videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages) struct page *pg; int i; - sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL); + sglist = vmalloc(nr_pages * sizeof(*sglist)); if (NULL == sglist) return NULL; + memset(sglist, 0, nr_pages * sizeof(*sglist)); sg_init_table(sglist, nr_pages); for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) { pg = vmalloc_to_page(virt); @@ -73,7 +74,7 @@ videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages) return sglist; err: - kfree(sglist); + vfree(sglist); return NULL; } @@ -85,7 +86,7 @@ videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset) if (NULL == pages[0]) return NULL; - sglist = kmalloc(nr_pages * sizeof(*sglist), GFP_KERNEL); + sglist = vmalloc(nr_pages * sizeof(*sglist)); if (NULL == sglist) return NULL; sg_init_table(sglist, nr_pages); @@ -105,12 +106,12 @@ videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset) nopage: dprintk(2,"sgl: oops - no page\n"); - kfree(sglist); + vfree(sglist); return NULL; highmem: dprintk(2,"sgl: oops - highmem page\n"); - kfree(sglist); + vfree(sglist); return NULL; } @@ -231,7 +232,7 @@ int videobuf_dma_map(struct videobuf_queue* q, struct videobuf_dmabuf *dma) (dma->vmalloc,dma->nr_pages); } if (dma->bus_addr) { - dma->sglist = kmalloc(sizeof(struct scatterlist), GFP_KERNEL); + dma->sglist = vmalloc(sizeof(*dma->sglist)); if (NULL != dma->sglist) { dma->sglen = 1; sg_dma_address(&dma->sglist[0]) = dma->bus_addr & PAGE_MASK; @@ -249,7 +250,7 @@ int videobuf_dma_map(struct videobuf_queue* q, struct videobuf_dmabuf *dma) if (0 == dma->sglen) { printk(KERN_WARNING "%s: videobuf_map_sg failed\n",__func__); - kfree(dma->sglist); + vfree(dma->sglist); dma->sglist = NULL; dma->sglen = 0; return -EIO; @@ -275,7 +276,7 @@ int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma) dma_unmap_sg(q->dev, dma->sglist, dma->nr_pages, dma->direction); - kfree(dma->sglist); + vfree(dma->sglist); dma->sglist = NULL; dma->sglen = 0; return 0; |