From c2625bff997f195e067ae11c9b0aa7217fb32991 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 29 Oct 2006 11:12:27 -0300 Subject: V4L/DVB (4786): Pvrusb2: use NULL instead of 0 Fix sparse NULL usage warnings: drivers/media/video/pvrusb2/pvrusb2-v4l2.c:714:14: warning: Using plain integer as NULL pointer drivers/media/video/pvrusb2/pvrusb2-v4l2.c:715:16: warning: Using plain integer as NULL pointer drivers/media/video/pvrusb2/pvrusb2-v4l2.c:1079:10: warning: Using plain integer as NULL pointer drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c:224:58: warning: Using plain integer as NULL pointer Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c | 2 +- drivers/media/video/pvrusb2/pvrusb2-v4l2.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c index df8feac16ae..c80c26be6e4 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c +++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c @@ -221,7 +221,7 @@ static unsigned int decoder_describe(struct pvr2_v4l_cx2584x *ctxt, static void decoder_reset(struct pvr2_v4l_cx2584x *ctxt) { int ret; - ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_RESET,0); + ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_RESET,NULL); pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx25840 decoder_reset (ret=%d)",ret); } diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 97e974d9b9c..bb40e908597 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -711,8 +711,8 @@ static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip) dip->devbase.minor,pvr2_config_get_name(dip->config)); /* Paranoia */ - dip->v4lp = 0; - dip->stream = 0; + dip->v4lp = NULL; + dip->stream = NULL; /* Actual deallocation happens later when all internal references are gone. */ @@ -1076,7 +1076,7 @@ struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp) vp->vdev = kmalloc(sizeof(*vp->vdev),GFP_KERNEL); if (!vp->vdev) { kfree(vp); - return 0; + return NULL; } memset(vp->vdev,0,sizeof(*vp->vdev)); pvr2_channel_init(&vp->channel,mnp); -- cgit v1.2.3 From 588f98312c7fd1d86290583189d2eb24da70f752 Mon Sep 17 00:00:00 2001 From: Hartmut Hackmann Date: Wed, 18 Oct 2006 17:30:42 -0300 Subject: V4L/DVB (4770): Fix mode switch of Compro Videomate T300 The board did not return to analog mode since the board specific "demod sleep" function was not called. Signed-off-by: Hartmut Hackmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-dvb.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media/video') diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 1ba53b525ad..6b61d9b2fcb 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -1147,6 +1147,8 @@ static int dvb_init(struct saa7134_dev *dev) &philips_europa_config, &dev->i2c_adap); if (dev->dvb.frontend) { + dev->original_demod_sleep = dev->dvb.frontend->ops.sleep; + dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep; dev->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init; dev->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep; dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params; -- cgit v1.2.3 From ff97d93d6a311759db1b74b9b90dd6bcb8ce0aee Mon Sep 17 00:00:00 2001 From: Hermann Pitton Date: Fri, 3 Nov 2006 10:45:52 -0300 Subject: V4L/DVB (4802): Cx88: fix remote control on WinFast 2000XP Expert fix remote control on WinFast 2000XP Expert by setting timing back to 1 ms, like it was in the original patch by Robert Reid. Signed-off-by: Hermann Pitton Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-input.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index ee48995a4ab..57e1c024a54 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -202,13 +202,19 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) ir->sampling = 1; break; case CX88_BOARD_WINFAST_DTV2000H: - case CX88_BOARD_WINFAST2000XP_EXPERT: ir_codes = ir_codes_winfast; ir->gpio_addr = MO_GP0_IO; ir->mask_keycode = 0x8f8; ir->mask_keyup = 0x100; ir->polling = 50; /* ms */ break; + case CX88_BOARD_WINFAST2000XP_EXPERT: + ir_codes = ir_codes_winfast; + ir->gpio_addr = MO_GP0_IO; + ir->mask_keycode = 0x8f8; + ir->mask_keyup = 0x100; + ir->polling = 1; /* ms */ + break; case CX88_BOARD_IODATA_GVBCTV7E: ir_codes = ir_codes_iodata_bctv7e; ir->gpio_addr = MO_GP0_IO; @@ -216,7 +222,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) ir->mask_keydown = 0x02; ir->polling = 5; /* ms */ break; - case CX88_BOARD_PROLINK_PLAYTVPVR: + case CX88_BOARD_PROLINK_PLAYTVPVR: case CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO: ir_codes = ir_codes_pixelview; ir->gpio_addr = MO_GP1_IO; -- cgit v1.2.3 From ce48d5ecf3f52378064f317e0094b601508e9b3e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 5 Nov 2006 09:02:13 -0300 Subject: V4L/DVB (4804): Fix missing i2c dependency for saa7110 drivers/media/video/saa7110.c:112: undefined reference to `i2c_master_send' drivers/built-in.o: In function `saa7110_read': drivers/media/video/saa7110.c:130: undefined reference to `i2c_smbus_read_byte' drivers/media/video/saa7110.c:130: undefined reference to `i2c_smbus_read_byte' Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index fbe5b6168cc..bf267552941 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -186,7 +186,7 @@ config VIDEO_KS0127 config VIDEO_SAA7110 tristate "Philips SAA7110 video decoder" - depends on VIDEO_V4L1 + depends on VIDEO_V4L1 && I2C ---help--- Support for the Philips SAA7110 video decoders. -- cgit v1.2.3 From 450efcfd2e1d941e302a8c89322fbfcef237be98 Mon Sep 17 00:00:00 2001 From: "pasky@ucw.cz" Date: Sun, 12 Nov 2006 14:22:32 -0300 Subject: V4L/DVB (4814): Remote support for Avermedia 777 I didn't test it personally since I don't have this card, but A16AR uses the same interface and that one certainly does work perfectly (see the next patch). This patch was originally sent in http://marc.theaimsgroup.com/?l=linux-video&m=114743413825375&w=2 https://www.redhat.com/mailman/private/video4linux-list/2006-May/msg00103.html but never got applied. This version has some trivial modifications and drops the weird gpio hack (it's not clear what practical purpose does it serve). Signed-off-by: Jose Alberto Reguero Signed-off-by: Petr Baudis Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-cards.c | 1 + drivers/media/video/saa7134/saa7134-input.c | 8 ++++++++ 2 files changed, 9 insertions(+) (limited to 'drivers/media/video') diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index c9d8e3b9cc3..94324b3c34e 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -3718,6 +3718,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_AVERMEDIA_STUDIO_307: case SAA7134_BOARD_AVERMEDIA_307: case SAA7134_BOARD_AVERMEDIA_GO_007_FM: + case SAA7134_BOARD_AVERMEDIA_777: /* case SAA7134_BOARD_SABRENT_SBTTVFM: */ /* not finished yet */ case SAA7134_BOARD_VIDEOMATE_TV_PVR: case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS: diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index ff5991136f4..e8dcb6f9f8f 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -194,6 +194,14 @@ int saa7134_input_init1(struct saa7134_dev *dev) saa_setb(SAA7134_GPIO_GPMODE0, 0x4); saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4); break; + case SAA7134_BOARD_AVERMEDIA_777: + ir_codes = ir_codes_avermedia; + mask_keycode = 0x02F200; + mask_keydown = 0x000400; + polling = 50; // ms + /* Without this we won't receive key up events */ + saa_setb(SAA7134_GPIO_GPMODE1, 0x1); + saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1); case SAA7134_BOARD_KWORLD_TERMINATOR: ir_codes = ir_codes_pixelview; mask_keycode = 0x00001f; -- cgit v1.2.3 From 29e0f1a136d39c5683d998741911b769d0172d52 Mon Sep 17 00:00:00 2001 From: "pasky@ucw.cz" Date: Sun, 12 Nov 2006 14:23:32 -0300 Subject: V4L/DVB (4815): Remote support for Avermedia A16AR The remote as well as the GPIO interface is the same as what comes with 777. For an example of mplayer lirc configuration, see http://pasky.or.cz/~pasky/dev/v4l/lircrc Signed-off-by: Petr Baudis Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-cards.c | 2 +- drivers/media/video/saa7134/saa7134-input.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 94324b3c34e..1a402e45912 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -3735,6 +3735,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_FLYDVBT_LR301: case SAA7134_BOARD_FLYDVBTDUO: case SAA7134_BOARD_PROTEUS_2309: + case SAA7134_BOARD_AVERMEDIA_A16AR: dev->has_remote = SAA7134_REMOTE_GPIO; break; case SAA7134_BOARD_FLYDVBS_LR300: @@ -3773,7 +3774,6 @@ int saa7134_board_init1(struct saa7134_dev *dev) saa_writeb(SAA7134_GPIO_GPMODE3, 0x08); saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x00); break; - case SAA7134_BOARD_AVERMEDIA_A16AR: case SAA7134_BOARD_AVERMEDIA_CARDBUS: /* power-up tuner chip */ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0xffffffff, 0xffffffff); diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index e8dcb6f9f8f..7f62403b195 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -185,7 +185,6 @@ int saa7134_input_init1(struct saa7134_dev *dev) case SAA7134_BOARD_AVERMEDIA_STUDIO_305: case SAA7134_BOARD_AVERMEDIA_STUDIO_307: case SAA7134_BOARD_AVERMEDIA_GO_007_FM: - case SAA7134_BOARD_AVERMEDIA_A16AR: ir_codes = ir_codes_avermedia; mask_keycode = 0x0007C8; mask_keydown = 0x000010; @@ -195,6 +194,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4); break; case SAA7134_BOARD_AVERMEDIA_777: + case SAA7134_BOARD_AVERMEDIA_A16AR: ir_codes = ir_codes_avermedia; mask_keycode = 0x02F200; mask_keydown = 0x000400; -- cgit v1.2.3 From 0871a8849b80646074cd28b2b078c8e002e51282 Mon Sep 17 00:00:00 2001 From: "pasky@ucw.cz" Date: Sun, 12 Nov 2006 14:24:57 -0300 Subject: V4L/DVB (4816): Change tuner type for Avermedia A16AR This changes it from TDA8290 which is allegedly very unlikely to TD1316 which is allegedly very likely. I didn't get it to work with either, but expected that this got applied when Mauro sent it to me, so here it goes again; feel free to drop it to the floor. :-) Signed-off-by: Petr Baudis Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-cards.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 1a402e45912..51f0cfdcb68 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -2969,7 +2969,7 @@ struct saa7134_board saa7134_boards[] = { /* Petr Baudis */ .name = "AVerMedia TV Hybrid A16AR", .audio_clock = 0x187de7, - .tuner_type = TUNER_PHILIPS_TDA8290, /* untested */ + .tuner_type = TUNER_PHILIPS_TD1316, /* untested */ .radio_type = TUNER_TEA5767, /* untested */ .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, -- cgit v1.2.3 From fef4fa1475db6a53237e29451c88c15167d69cc4 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 9 Nov 2006 17:25:28 -0300 Subject: V4L/DVB (4817): Fix uses of "&&" where "&" was intended Fix uses of "&&" where "&" was intended in bttv-cards.c and tveeprom.c Signed-off-by: Jean Delvare Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-cards.c | 2 +- drivers/media/video/tveeprom.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index a84903e0d81..21ebe8f1381 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -4001,7 +4001,7 @@ static void __devinit init_PXC200(struct bttv *btv) * - sleep 1ms * - write 0x0E * read from GPIO_DATA into buf (uint_32) - * - if ( buf>>18 & 0x01 ) || ( buf>>19 && 0x01 != 0 ) + * - if ( buf>>18 & 0x01 ) || ( buf>>19 & 0x01 != 0 ) * error. ERROR_CPLD_Check_Failed. */ /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index e6baaee038b..6b9ef731b83 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -468,7 +468,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, (eeprom_data[i+6] << 8) + (eeprom_data[i+7] << 16); - if ( (eeprom_data[i + 8] && 0xf0) && + if ( (eeprom_data[i + 8] & 0xf0) && (tvee->serial_number < 0xffffff) ) { tvee->MAC_address[0] = 0x00; tvee->MAC_address[1] = 0x0D; -- cgit v1.2.3 From 4dd7406e9c7e7a5422425ef699780463490b8745 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 13 Nov 2006 09:50:11 -0800 Subject: [dvb saa7134] Fix missing 'break' for avermedia card case MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 450efcfd2e1d941e302a8c89322fbfcef237be98 broke Avermedia 777 support. Added obvious missing "break" statement. Cc: José Suárez Cc: Michael Krufky Cc: Mauro Carvalho Chehab Signed-off-by: Linus Torvalds --- drivers/media/video/saa7134/saa7134-input.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media/video') diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 7f62403b195..dee83552e68 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -202,6 +202,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) /* Without this we won't receive key up events */ saa_setb(SAA7134_GPIO_GPMODE1, 0x1); saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1); + break; case SAA7134_BOARD_KWORLD_TERMINATOR: ir_codes = ir_codes_pixelview; mask_keycode = 0x00001f; -- cgit v1.2.3 From c4028958b6ecad064b1a6303a6a5906d4fe48d73 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 22 Nov 2006 14:57:56 +0000 Subject: WorkStruct: make allyesconfig Fix up for make allyesconfig. Signed-Off-By: David Howells --- drivers/media/video/cpia_pp.c | 20 +++++++++++++++++++- drivers/media/video/cx88/cx88-input.c | 6 +++--- drivers/media/video/ir-kbd-i2c.c | 6 +++--- drivers/media/video/pvrusb2/pvrusb2-context.c | 13 +++++++++---- drivers/media/video/saa6588.c | 6 +++--- drivers/media/video/saa7134/saa7134-empress.c | 9 +++++---- 6 files changed, 42 insertions(+), 18 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/cpia_pp.c b/drivers/media/video/cpia_pp.c index 41f4b8d1755..b12cec94f4c 100644 --- a/drivers/media/video/cpia_pp.c +++ b/drivers/media/video/cpia_pp.c @@ -82,6 +82,8 @@ struct pp_cam_entry { struct pardevice *pdev; struct parport *port; struct work_struct cb_task; + void (*cb_func)(void *cbdata); + void *cb_data; int open_count; wait_queue_head_t wq_stream; /* image state flags */ @@ -130,6 +132,20 @@ static void cpia_parport_disable_irq( struct parport *port ) { #define PARPORT_CHUNK_SIZE PAGE_SIZE +static void cpia_pp_run_callback(struct work_struct *work) +{ + void (*cb_func)(void *cbdata); + void *cb_data; + struct pp_cam_entry *cam; + + cam = container_of(work, struct pp_cam_entry, cb_task); + cb_func = cam->cb_func; + cb_data = cam->cb_data; + work_release(work); + + cb_func(cb_data); +} + /**************************************************************************** * * CPiA-specific low-level parport functions for nibble uploads @@ -664,7 +680,9 @@ static int cpia_pp_registerCallback(void *privdata, void (*cb)(void *cbdata), vo int retval = 0; if(cam->port->irq != PARPORT_IRQ_NONE) { - INIT_WORK(&cam->cb_task, cb, cbdata); + cam->cb_func = cb; + cam->cb_data = cbdata; + INIT_WORK_NAR(&cam->cb_task, cpia_pp_run_callback); } else { retval = -1; } diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index 57e1c024a54..e60a0a52e4b 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -145,9 +145,9 @@ static void ir_timer(unsigned long data) schedule_work(&ir->work); } -static void cx88_ir_work(void *data) +static void cx88_ir_work(struct work_struct *work) { - struct cx88_IR *ir = data; + struct cx88_IR *ir = container_of(work, struct cx88_IR, work); unsigned long timeout; cx88_ir_handle_key(ir); @@ -308,7 +308,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) core->ir = ir; if (ir->polling) { - INIT_WORK(&ir->work, cx88_ir_work, ir); + INIT_WORK(&ir->work, cx88_ir_work); init_timer(&ir->timer); ir->timer.function = ir_timer; ir->timer.data = (unsigned long)ir; diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 1457b160222..ab87e7bfe84 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -268,9 +268,9 @@ static void ir_timer(unsigned long data) schedule_work(&ir->work); } -static void ir_work(void *data) +static void ir_work(struct work_struct *work) { - struct IR_i2c *ir = data; + struct IR_i2c *ir = container_of(work, struct IR_i2c, work); ir_key_poll(ir); mod_timer(&ir->timer, jiffies+HZ/10); } @@ -400,7 +400,7 @@ static int ir_attach(struct i2c_adapter *adap, int addr, ir->input->name,ir->input->phys,adap->name); /* start polling via eventd */ - INIT_WORK(&ir->work, ir_work, ir); + INIT_WORK(&ir->work, ir_work); init_timer(&ir->timer); ir->timer.function = ir_timer; ir->timer.data = (unsigned long)ir; diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c index f129f316d20..cf129746205 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-context.c +++ b/drivers/media/video/pvrusb2/pvrusb2-context.c @@ -45,16 +45,21 @@ static void pvr2_context_trigger_poll(struct pvr2_context *mp) } -static void pvr2_context_poll(struct pvr2_context *mp) +static void pvr2_context_poll(struct work_struct *work) { + struct pvr2_context *mp = + container_of(work, struct pvr2_context, workpoll); pvr2_context_enter(mp); do { pvr2_hdw_poll(mp->hdw); } while (0); pvr2_context_exit(mp); } -static void pvr2_context_setup(struct pvr2_context *mp) +static void pvr2_context_setup(struct work_struct *work) { + struct pvr2_context *mp = + container_of(work, struct pvr2_context, workinit); + pvr2_context_enter(mp); do { if (!pvr2_hdw_dev_ok(mp->hdw)) break; pvr2_hdw_setup(mp->hdw); @@ -92,8 +97,8 @@ struct pvr2_context *pvr2_context_create( } mp->workqueue = create_singlethread_workqueue("pvrusb2"); - INIT_WORK(&mp->workinit,(void (*)(void*))pvr2_context_setup,mp); - INIT_WORK(&mp->workpoll,(void (*)(void*))pvr2_context_poll,mp); + INIT_WORK(&mp->workinit, pvr2_context_setup); + INIT_WORK(&mp->workpoll, pvr2_context_poll); queue_work(mp->workqueue,&mp->workinit); done: return mp; diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c index a81285ca7d5..8ba05c214ca 100644 --- a/drivers/media/video/saa6588.c +++ b/drivers/media/video/saa6588.c @@ -322,9 +322,9 @@ static void saa6588_timer(unsigned long data) schedule_work(&s->work); } -static void saa6588_work(void *data) +static void saa6588_work(struct work_struct *work) { - struct saa6588 *s = (struct saa6588 *)data; + struct saa6588 *s = container_of(work, struct saa6588, work); saa6588_i2c_poll(s); mod_timer(&s->timer, jiffies + msecs_to_jiffies(20)); @@ -417,7 +417,7 @@ static int saa6588_attach(struct i2c_adapter *adap, int addr, int kind) saa6588_configure(s); /* start polling via eventd */ - INIT_WORK(&s->work, saa6588_work, s); + INIT_WORK(&s->work, saa6588_work); init_timer(&s->timer); s->timer.function = saa6588_timer; s->timer.data = (unsigned long)s; diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index 65d044086ce..daaae870a2c 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -343,9 +343,10 @@ static struct video_device saa7134_empress_template = .minor = -1, }; -static void empress_signal_update(void* data) +static void empress_signal_update(struct work_struct *work) { - struct saa7134_dev* dev = (struct saa7134_dev*) data; + struct saa7134_dev* dev = + container_of(work, struct saa7134_dev, empress_workqueue); if (dev->nosignal) { dprintk("no video signal\n"); @@ -378,7 +379,7 @@ static int empress_init(struct saa7134_dev *dev) "%s empress (%s)", dev->name, saa7134_boards[dev->board].name); - INIT_WORK(&dev->empress_workqueue, empress_signal_update, (void*) dev); + INIT_WORK(&dev->empress_workqueue, empress_signal_update); err = video_register_device(dev->empress_dev,VFL_TYPE_GRABBER, empress_nr[dev->nr]); @@ -399,7 +400,7 @@ static int empress_init(struct saa7134_dev *dev) sizeof(struct saa7134_buf), dev); - empress_signal_update(dev); + empress_signal_update(&dev->empress_workqueue); return 0; } -- cgit v1.2.3 From a5bbc7d94cf1dcb2100eeaf68791a401ad7ce54d Mon Sep 17 00:00:00 2001 From: Ira Snyder Date: Mon, 20 Nov 2006 07:20:48 -0300 Subject: V4L/DVB (4849): Add missing spin_unlock to saa6588 decoder driver Sparse noticed a lock imbalance in read_from_buf(). Further inspection shows that the lock should not be held when the function exits. This adds a spin_unlock_irqrestore(), so that every exit path of the read_from_buf() function is consistent. The unlock was missing on an error path. Signed-off-by: Ira W. Snyder Signed-off-by: Hans J. Koch Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa6588.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c index a81285ca7d5..7b9859c3301 100644 --- a/drivers/media/video/saa6588.c +++ b/drivers/media/video/saa6588.c @@ -212,8 +212,10 @@ static void read_from_buf(struct saa6588 *s, struct rds_command *a) if (rd_blocks > s->block_count) rd_blocks = s->block_count; - if (!rd_blocks) + if (!rd_blocks) { + spin_unlock_irqrestore(&s->lock, flags); return; + } for (i = 0; i < rd_blocks; i++) { if (block_to_user_buf(s, buf_ptr)) { -- cgit v1.2.3 From 5718bbd2d92b9c2aa2f5700e4d3ed9d72f72f47e Mon Sep 17 00:00:00 2001 From: Luca Risolia Date: Tue, 21 Nov 2006 08:13:59 -0300 Subject: V4L/DVB (4865): Fix: Slot 0 not NULL on disconnecting SN9C10x PC Camera The patch fix bug 5748. Signed-off-by: Luca Risolia Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/et61x251/et61x251_core.c | 3 +-- drivers/media/video/sn9c102/sn9c102_core.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index f786ab11d2c..86e353b26b5 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -1182,8 +1182,6 @@ static void et61x251_release_resources(struct et61x251_device* cam) video_set_drvdata(cam->v4ldev, NULL); video_unregister_device(cam->v4ldev); - usb_put_dev(cam->usbdev); - mutex_unlock(&et61x251_sysfs_lock); kfree(cam->control_buffer); @@ -1275,6 +1273,7 @@ static int et61x251_release(struct inode* inode, struct file* filp) if (cam->state & DEV_DISCONNECTED) { et61x251_release_resources(cam); + usb_put_dev(cam->usbdev); mutex_unlock(&cam->dev_mutex); kfree(cam); return 0; diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index a4702d3c2ac..42fb60d985b 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -1462,8 +1462,6 @@ static void sn9c102_release_resources(struct sn9c102_device* cam) video_set_drvdata(cam->v4ldev, NULL); video_unregister_device(cam->v4ldev); - usb_put_dev(cam->usbdev); - mutex_unlock(&sn9c102_sysfs_lock); kfree(cam->control_buffer); @@ -1555,6 +1553,7 @@ static int sn9c102_release(struct inode* inode, struct file* filp) if (cam->state & DEV_DISCONNECTED) { sn9c102_release_resources(cam); + usb_put_dev(cam->usbdev); mutex_unlock(&cam->dev_mutex); kfree(cam); return 0; -- cgit v1.2.3 From f7668162a366d1ce0fe84122d11108e13a8ce950 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 25 Nov 2006 09:40:28 -0300 Subject: V4L/DVB (4885): Improve saa711x check The old code would accept any device on the same i2c address as the saa711x chips as an saa711x. However, this fails with saa717x chips, which use that same address and so are misdetected as a saa7111. Now check whether the chip is really a saa711x model. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7115.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index c5719f7bd1a..f28398dd9d9 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -1464,8 +1464,6 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind) client->driver = &i2c_driver_saa711x; snprintf(client->name, sizeof(client->name) - 1, "saa7115"); - v4l_dbg(1, debug, client, "detecting saa7115 client on address 0x%x\n", address << 1); - for (i=0;i<0x0f;i++) { saa711x_write(client, 0, i); name[i] = (saa711x_read(client, 0) &0x0f) +'0'; @@ -1477,6 +1475,13 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind) saa711x_write(client, 0, 5); chip_id = saa711x_read(client, 0) & 0x0f; + /* Check whether this chip is part of the saa711x series */ + if (memcmp(name, "1f711", 5)) { + v4l_dbg(1, debug, client, "chip found @ 0x%x (ID %s) does not match a known saa711x chip.\n", + address << 1, name); + return 0; + } + snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id); v4l_info(client, "saa711%d found (%s) @ 0x%x (%s)\n", chip_id, name, address << 1, adapter->name); -- cgit v1.2.3 From 3cb2fccc5f48a4d6269dfd00b4db570fca2a04d5 Mon Sep 17 00:00:00 2001 From: Matt LaPlante Date: Thu, 30 Nov 2006 05:22:59 +0100 Subject: Fix misc Kconfig typos Fix various Kconfig typos. Signed-off-by: Matt LaPlante Acked-by: Randy Dunlap Signed-off-by: Adrian Bunk --- drivers/media/video/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index bf267552941..b8fde5cf473 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -24,7 +24,7 @@ config VIDEO_HELPER_CHIPS_AUTO decode audio/video standards. This option will autoselect all pertinent modules to each selected video module. - Unselect this only if you know exaclty what you are doing, since + Unselect this only if you know exactly what you are doing, since it may break support on some boards. In doubt, say Y. -- cgit v1.2.3 From 5d9a276a3eb073251737cb92b790bfdb9f0b9139 Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn Date: Thu, 30 Nov 2006 05:26:46 +0100 Subject: BUG_ON conversion for drivers/media/video/pwc/pwc-if.c This patch converts a if () BUG(); construct to BUG_ON(); which occupies less space, uses unlikely and is safer when BUG() is disabled. Signed-off-by: Eric Sesterhenn Signed-off-by: Adrian Bunk --- drivers/media/video/pwc/pwc-if.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 46c11483088..e8db6e58d39 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -1095,8 +1095,7 @@ static int pwc_video_open(struct inode *inode, struct file *file) PWC_DEBUG_OPEN(">> video_open called(vdev = 0x%p).\n", vdev); pdev = (struct pwc_device *)vdev->priv; - if (pdev == NULL) - BUG(); + BUG_ON(!pdev); if (pdev->vopen) { PWC_DEBUG_OPEN("I'm busy, someone is using the device.\n"); return -EBUSY; -- cgit v1.2.3 From 444f4f91fda54bea57a0e31098a75f54548e8b28 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Thu, 16 Nov 2006 16:38:57 +0100 Subject: USB: pwc-if loop fix We should free urbs starting at [i-1] not [i]. Signed-off-by: Mariusz Kozlowski Signed-off-by: Greg Kroah-Hartman --- drivers/media/video/pwc/pwc-if.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 46c11483088..83739b213e7 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -866,11 +866,10 @@ int pwc_isoc_init(struct pwc_device *pdev) } if (ret) { /* De-allocate in reverse order */ - while (i >= 0) { + while (i--) { if (pdev->sbuf[i].urb != NULL) usb_free_urb(pdev->sbuf[i].urb); pdev->sbuf[i].urb = NULL; - i--; } return ret; } -- cgit v1.2.3 From 5e55d2cea80254faa6ba5c13f3053070db57b63f Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Wed, 8 Nov 2006 15:34:31 +0100 Subject: usb: pvrusb2-hdw free unlink urb cleanup - usb_free_urb() cleanup - usb_unlink_urb() cleanup Signed-off-by: Mariusz Kozlowski Signed-off-by: Greg Kroah-Hartman --- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index f920e0ccacd..1f787333d18 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -1953,8 +1953,8 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, return hdw; fail: if (hdw) { - if (hdw->ctl_read_urb) usb_free_urb(hdw->ctl_read_urb); - if (hdw->ctl_write_urb) usb_free_urb(hdw->ctl_write_urb); + usb_free_urb(hdw->ctl_read_urb); + usb_free_urb(hdw->ctl_write_urb); if (hdw->ctl_read_buffer) kfree(hdw->ctl_read_buffer); if (hdw->ctl_write_buffer) kfree(hdw->ctl_write_buffer); if (hdw->controls) kfree(hdw->controls); @@ -2575,12 +2575,10 @@ static void pvr2_ctl_timeout(unsigned long data) struct pvr2_hdw *hdw = (struct pvr2_hdw *)data; if (hdw->ctl_write_pend_flag || hdw->ctl_read_pend_flag) { hdw->ctl_timeout_flag = !0; - if (hdw->ctl_write_pend_flag && hdw->ctl_write_urb) { + if (hdw->ctl_write_pend_flag) usb_unlink_urb(hdw->ctl_write_urb); - } - if (hdw->ctl_read_pend_flag && hdw->ctl_read_urb) { + if (hdw->ctl_read_pend_flag) usb_unlink_urb(hdw->ctl_read_urb); - } } } -- cgit v1.2.3 From 4c6f7d4a889ad997483a4c0318111b4a506f0fe3 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Wed, 8 Nov 2006 15:34:50 +0100 Subject: usb: pvrusb2-io free urb cleanup - usb_free_urb() cleanup Signed-off-by: Mariusz Kozlowski Signed-off-by: Greg Kroah-Hartman --- drivers/media/video/pvrusb2/pvrusb2-io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/pvrusb2/pvrusb2-io.c b/drivers/media/video/pvrusb2/pvrusb2-io.c index 70aa63eba0c..57fb3203354 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-io.c +++ b/drivers/media/video/pvrusb2/pvrusb2-io.c @@ -289,7 +289,7 @@ static void pvr2_buffer_done(struct pvr2_buffer *bp) pvr2_buffer_set_none(bp); bp->signature = 0; bp->stream = NULL; - if (bp->purb) usb_free_urb(bp->purb); + usb_free_urb(bp->purb); pvr2_trace(PVR2_TRACE_BUF_POOL,"/*---TRACE_FLOW---*/" " bufferDone %p",bp); } -- cgit v1.2.3 From 90b2625a5159607e37871cd75370c189fc22d208 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Wed, 8 Nov 2006 15:34:55 +0100 Subject: usb: pwc-if free urb cleanup - usb_free_urb() cleanup Signed-off-by: Mariusz Kozlowski Signed-off-by: Greg Kroah-Hartman --- drivers/media/video/pwc/pwc-if.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 83739b213e7..62070b9049e 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -867,8 +867,7 @@ int pwc_isoc_init(struct pwc_device *pdev) if (ret) { /* De-allocate in reverse order */ while (i--) { - if (pdev->sbuf[i].urb != NULL) - usb_free_urb(pdev->sbuf[i].urb); + usb_free_urb(pdev->sbuf[i].urb); pdev->sbuf[i].urb = NULL; } return ret; -- cgit v1.2.3 From 14d2707b80d6a9d1e8e92718885f99b77531b339 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Wed, 8 Nov 2006 15:34:59 +0100 Subject: usb: sn9c102_core free urb cleanup - usb_free_urb() cleanup Signed-off-by: Mariusz Kozlowski Signed-off-by: Greg Kroah-Hartman --- drivers/media/video/sn9c102/sn9c102_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index 42fb60d985b..18458d46c0f 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -775,7 +775,7 @@ static int sn9c102_start_transfer(struct sn9c102_device* cam) return 0; free_urbs: - for (i = 0; (i < SN9C102_URBS) && cam->urb[i]; i++) + for (i = 0; i < SN9C102_URBS; i++) usb_free_urb(cam->urb[i]); free_buffers: -- cgit v1.2.3 From 926b1e90093688d91cbc358e5339ad2861c86e46 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Wed, 8 Nov 2006 15:35:02 +0100 Subject: usb: quickcam_messenger free urb cleanup - usb_free_urb() cleanup Signed-off-by: Mariusz Kozlowski Signed-off-by: Greg Kroah-Hartman --- drivers/media/video/usbvideo/quickcam_messenger.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c index 9a26b9484aa..bbf2beeeb44 100644 --- a/drivers/media/video/usbvideo/quickcam_messenger.c +++ b/drivers/media/video/usbvideo/quickcam_messenger.c @@ -190,8 +190,7 @@ static int qcm_alloc_int_urb(struct qcm *cam) static void qcm_free_int(struct qcm *cam) { - if (cam->button_urb) - usb_free_urb(cam->button_urb); + usb_free_urb(cam->button_urb); } #endif /* CONFIG_INPUT */ -- cgit v1.2.3 From 8563650da0fb2df5755ea133d5fb182ded9d2ae8 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Wed, 8 Nov 2006 15:35:12 +0100 Subject: usb: zc0301_core free urb cleanup - usb_free_urb() cleanup Signed-off-by: Mariusz Kozlowski Signed-off-by: Greg Kroah-Hartman --- drivers/media/video/zc0301/zc0301_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c index 5b556342442..52d0f759ee0 100644 --- a/drivers/media/video/zc0301/zc0301_core.c +++ b/drivers/media/video/zc0301/zc0301_core.c @@ -489,7 +489,7 @@ static int zc0301_start_transfer(struct zc0301_device* cam) return 0; free_urbs: - for (i = 0; (i < ZC0301_URBS) && cam->urb[i]; i++) + for (i = 0; i < ZC0301_URBS; i++) usb_free_urb(cam->urb[i]); free_buffers: -- cgit v1.2.3 From 7dfb71030f7636a0d65200158113c37764552f93 Mon Sep 17 00:00:00 2001 From: Nigel Cunningham Date: Wed, 6 Dec 2006 20:34:23 -0800 Subject: [PATCH] Add include/linux/freezer.h and move definitions from sched.h Move process freezing functions from include/linux/sched.h to freezer.h, so that modifications to the freezer or the kernel configuration don't require recompiling just about everything. [akpm@osdl.org: fix ueagle driver] Signed-off-by: Nigel Cunningham Cc: "Rafael J. Wysocki" Cc: Pavel Machek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/msp3400-driver.c | 2 +- drivers/media/video/tvaudio.c | 1 + drivers/media/video/video-buf-dvb.c | 2 +- drivers/media/video/vivi.c | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index cf43df3fe70..e1b56dc13c3 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -56,7 +56,7 @@ #include #include #include -#include +#include #include "msp3400-driver.h" /* ---------------------------------------------------------------------- */ diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index fcaef4bf828..d506dfaa45a 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c index f53edf1923b..fcc5467e763 100644 --- a/drivers/media/video/video-buf-dvb.c +++ b/drivers/media/video/video-buf-dvb.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 3c8dc72dc8e..9986de5cb3d 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -36,6 +36,7 @@ #include #include #include +#include /* Wake up at about 30 fps */ #define WAKE_NUMERATOR 30 -- cgit v1.2.3 From 723731b2eef6599cf09af1fbfe0b12857b439e2d Mon Sep 17 00:00:00 2001 From: Josef Sipek Date: Fri, 8 Dec 2006 02:37:47 -0800 Subject: [PATCH] struct path: convert v4l Signed-off-by: Josef Sipek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/video/compat_ioctl32.c | 2 +- drivers/media/video/videodev.c | 2 +- drivers/media/video/zoran_procfs.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c index d82a488f12a..f065ad12cc6 100644 --- a/drivers/media/video/compat_ioctl32.c +++ b/drivers/media/video/compat_ioctl32.c @@ -118,7 +118,7 @@ static int native_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ret = file->f_op->unlocked_ioctl(file, cmd, arg); else if (file->f_op->ioctl) { lock_kernel(); - ret = file->f_op->ioctl(file->f_dentry->d_inode, file, cmd, arg); + ret = file->f_op->ioctl(file->f_path.dentry->d_inode, file, cmd, arg); unlock_kernel(); } diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index d424a4129d6..41ec0c4b35a 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -105,7 +105,7 @@ static DEFINE_MUTEX(videodev_lock); struct video_device* video_devdata(struct file *file) { - return video_device[iminor(file->f_dentry->d_inode)]; + return video_device[iminor(file->f_path.dentry->d_inode)]; } /* diff --git a/drivers/media/video/zoran_procfs.c b/drivers/media/video/zoran_procfs.c index c7f6f648836..c374c76b375 100644 --- a/drivers/media/video/zoran_procfs.c +++ b/drivers/media/video/zoran_procfs.c @@ -144,7 +144,7 @@ static int zoran_open(struct inode *inode, struct file *file) static ssize_t zoran_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { - struct zoran *zr = PDE(file->f_dentry->d_inode)->data; + struct zoran *zr = PDE(file->f_path.dentry->d_inode)->data; char *string, *sp; char *line, *ldelim, *varname, *svar, *tdelim; @@ -165,7 +165,7 @@ static ssize_t zoran_write(struct file *file, const char __user *buffer, } string[count] = 0; dprintk(4, KERN_INFO "%s: write_proc: name=%s count=%zu zr=%p\n", - ZR_DEVNAME(zr), file->f_dentry->d_name.name, count, zr); + ZR_DEVNAME(zr), file->f_path.dentry->d_name.name, count, zr); ldelim = " \t\n"; tdelim = "="; line = strpbrk(sp, ldelim); -- cgit v1.2.3 From 902fc997adb7b917e1bd06ad6f2f0d38aa482578 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Wed, 4 Oct 2006 20:33:51 -0300 Subject: V4L/DVB (4722): Cx88: Add support for VIDIOC_INT_[SR]_REGISTER ioctls Add support for the advanced debugging ioctls, to allow access to the cx88 registers from userspace. Only i2c_id == 0 is supported, for access to the cx88 adapter itself. There isn't any support for access to I2C clients of the adapter. Most of them don't have R/W registers anyway, and its necessary to use i2c-dev to talk to them from userspace. Signed-off-by: Trent Piepho Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-video.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers/media/video') diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 90e298d074d..f27312189d7 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1490,6 +1490,30 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio, mutex_unlock(&core->lock); return 0; } +#ifdef CONFIG_VIDEO_ADV_DEBUG + /* ioctls to allow direct acces to the cx2388x registers */ + case VIDIOC_INT_G_REGISTER: + { + struct v4l2_register *reg = arg; + + if (reg->i2c_id != 0) + return -EINVAL; + /* cx2388x has a 24-bit register space */ + reg->val = cx_read(reg->reg&0xffffff); + return 0; + } + case VIDIOC_INT_S_REGISTER: + { + struct v4l2_register *reg = arg; + + if (reg->i2c_id != 0) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + cx_write(reg->reg&0xffffff, reg->val); + return 0; + } +#endif default: return v4l_compat_translate_ioctl(inode,file,cmd,arg, -- cgit v1.2.3 From 6c5be74c86f102c2d4e123bc51d2fa93155fd794 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Sat, 2 Dec 2006 21:15:51 -0200 Subject: V4L/DVB (4676): Dynamic cx88 mpeg port management for HVR1300 MPEG2/DVB-T support. A series of patches to change the cx88 framework to allow the PCI mpeg port to be shared dynamically between different types of drivers or applications. This patch changes the cx88-dvb and cx88-blackbird drivers to become 'sub drivers' of a higher single cx88-mpeg driver. The cx88-mpeg driver is a superset of the previous cx88-mpeg/blackbird drivers and now owns the IRQ. cx88-dvb/blackbird now become mini drivers, registering themselves with cx88-mpeg through a standard interface with callbacks. Sub drivers request access to hardware via the cx88-mpeg driver. In turn the cx88-mpeg driver determines whether the hardware is busy and accepts or refuses the request, grant access using callbacks into the sub drivers. The net effect is that you are no longer able to tamper with the mpeg port from multiple different applications at the same time, potentially breaking a live mpeg2 hardware encoding or dvb stream. The mechanism extends to enable multiple dvb frontends to be registered and share the single resource. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-blackbird.c | 178 ++++++++++------ drivers/media/video/cx88/cx88-cards.c | 2 +- drivers/media/video/cx88/cx88-dvb.c | 197 +++++++++-------- drivers/media/video/cx88/cx88-mpeg.c | 344 ++++++++++++++++++++++++++++-- drivers/media/video/cx88/cx88.h | 46 ++++ 5 files changed, 591 insertions(+), 176 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 46738321ada..0037188d77d 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -50,7 +50,6 @@ MODULE_PARM_DESC(debug,"enable debug messages [blackbird]"); #define dprintk(level,fmt, arg...) if (debug >= level) \ printk(KERN_DEBUG "%s/2-bb: " fmt, dev->core->name , ## arg) -static LIST_HEAD(cx8802_devlist); /* ------------------------------------------------------------------ */ @@ -882,7 +881,7 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file, BLACKBIRD_MPEG_CAPTURE, BLACKBIRD_RAW_BITS_NONE); - cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, mpeg_do_ioctl); + cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook); blackbird_initialize_codec(dev); cx88_set_scale(dev->core, dev->width, dev->height, @@ -914,11 +913,15 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file, } default: - return cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, mpeg_do_ioctl); + return cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook); } return 0; } +int (*cx88_ioctl_hook)(struct inode *inode, struct file *file, + unsigned int cmd, void *arg); +unsigned int (*cx88_ioctl_translator)(unsigned int cmd); + static unsigned int mpeg_translate_ioctl(unsigned int cmd) { return cmd; @@ -927,33 +930,48 @@ static unsigned int mpeg_translate_ioctl(unsigned int cmd) static int mpeg_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - cmd = mpeg_translate_ioctl( cmd ); - return video_usercopy(inode, file, cmd, arg, mpeg_do_ioctl); + cmd = cx88_ioctl_translator( cmd ); + return video_usercopy(inode, file, cmd, arg, cx88_ioctl_hook); } static int mpeg_open(struct inode *inode, struct file *file) { int minor = iminor(inode); - struct cx8802_dev *h,*dev = NULL; + struct cx8802_dev *dev = NULL; struct cx8802_fh *fh; - struct list_head *list; + struct cx8802_driver *drv = NULL; + int err; - list_for_each(list,&cx8802_devlist) { - h = list_entry(list, struct cx8802_dev, devlist); - if (h->mpeg_dev->minor == minor) - dev = h; - } - if (NULL == dev) + dprintk( 1, "%s\n", __FUNCTION__); + + dev = cx8802_get_device(inode); + if (dev == NULL) return -ENODEV; - if (blackbird_initialize_codec(dev) < 0) + /* Make sure we can acquire the hardware */ + drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD); + if (drv) { + err = drv->request_acquire(drv); + if(err != 0) { + dprintk(1,"%s: Unable to acquire hardware, %d\n", __FUNCTION__, err); + return err; + } + } + + if (blackbird_initialize_codec(dev) < 0) { + if (drv) + drv->request_release(drv); return -EINVAL; + } dprintk(1,"open minor=%d\n",minor); /* allocate + initialize per filehandle data */ fh = kzalloc(sizeof(*fh),GFP_KERNEL); - if (NULL == fh) + if (NULL == fh) { + if (drv) + drv->request_release(drv); return -ENOMEM; + } file->private_data = fh; fh->dev = dev; @@ -974,6 +992,8 @@ static int mpeg_open(struct inode *inode, struct file *file) static int mpeg_release(struct inode *inode, struct file *file) { struct cx8802_fh *fh = file->private_data; + struct cx8802_dev *dev = NULL; + struct cx8802_driver *drv = NULL; /* blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, BLACKBIRD_END_NOW, 0, 0x13); */ blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, @@ -992,6 +1012,16 @@ static int mpeg_release(struct inode *inode, struct file *file) videobuf_mmap_free(&fh->mpegq); file->private_data = NULL; kfree(fh); + + /* Make sure we release the hardware */ + dev = cx8802_get_device(inode); + if (dev == NULL) + return -ENODEV; + + drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD); + if (drv) + drv->request_release(drv); + return 0; } @@ -1043,6 +1073,44 @@ static struct video_device cx8802_mpeg_template = /* ------------------------------------------------------------------ */ +/* The CX8802 MPEG API will call this when we can use the hardware */ +static int cx8802_blackbird_advise_acquire(struct cx8802_driver *drv) +{ + struct cx88_core *core = drv->core; + int err = 0; + + switch (core->board) { + case CX88_BOARD_HAUPPAUGE_HVR1300: + /* By default, core setup will leave the cx22702 out of reset, on the bus. + * We left the hardware on power up with the cx22702 active. + * We're being given access to re-arrange the GPIOs. + * Take the bus off the cx22702 and put the cx23416 on it. + */ + cx_clear(MO_GP0_IO, 0x00000080); /* cx22702 in reset */ + cx_set(MO_GP0_IO, 0x00000004); /* Disable the cx22702 */ + break; + default: + err = -ENODEV; + } + return err; +} + +/* The CX8802 MPEG API will call this when we need to release the hardware */ +static int cx8802_blackbird_advise_release(struct cx8802_driver *drv) +{ + struct cx88_core *core = drv->core; + int err = 0; + + switch (core->board) { + case CX88_BOARD_HAUPPAUGE_HVR1300: + /* Exit leaving the cx23416 on the bus */ + break; + default: + err = -ENODEV; + } + return err; +} + static void blackbird_unregister_video(struct cx8802_dev *dev) { if (dev->mpeg_dev) { @@ -1073,28 +1141,23 @@ static int blackbird_register_video(struct cx8802_dev *dev) /* ----------------------------------------------------------- */ -static int __devinit blackbird_probe(struct pci_dev *pci_dev, - const struct pci_device_id *pci_id) +static int cx8802_blackbird_probe(struct cx8802_driver *drv) { - struct cx8802_dev *dev; - struct cx88_core *core; + struct cx88_core *core = drv->core; + struct cx8802_dev *dev = core->dvbdev; int err; - /* general setup */ - core = cx88_core_get(pci_dev); - if (NULL == core) - return -EINVAL; + dprintk( 1, "%s\n", __FUNCTION__); + dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", + core->board, + core->name, + core->pci_bus, + core->pci_slot); err = -ENODEV; if (!(cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD)) goto fail_core; - err = -ENOMEM; - dev = kzalloc(sizeof(*dev),GFP_KERNEL); - if (NULL == dev) - goto fail_core; - dev->pci = pci_dev; - dev->core = core; dev->width = 720; dev->height = 576; cx2341x_fill_defaults(&dev->params); @@ -1106,64 +1169,36 @@ static int __devinit blackbird_probe(struct pci_dev *pci_dev, dev->height = 576; } - err = cx8802_init_common(dev); - if (0 != err) - goto fail_free; - /* blackbird stuff */ printk("%s/2: cx23416 based mpeg encoder (blackbird reference design)\n", core->name); host_setup(dev->core); - list_add_tail(&dev->devlist,&cx8802_devlist); blackbird_register_video(dev); /* initial device configuration: needed ? */ return 0; - fail_free: - kfree(dev); fail_core: - cx88_core_put(core,pci_dev); return err; } -static void __devexit blackbird_remove(struct pci_dev *pci_dev) +static int cx8802_blackbird_remove(struct cx8802_driver *drv) { - struct cx8802_dev *dev = pci_get_drvdata(pci_dev); - /* blackbird */ - blackbird_unregister_video(dev); - list_del(&dev->devlist); + blackbird_unregister_video(drv->core->dvbdev); - /* common */ - cx8802_fini_common(dev); - cx88_core_put(dev->core,dev->pci); - kfree(dev); + return 0; } -static struct pci_device_id cx8802_pci_tbl[] = { - { - .vendor = 0x14f1, - .device = 0x8802, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - },{ - /* --- end of list --- */ - } -}; -MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl); - -static struct pci_driver blackbird_pci_driver = { - .name = "cx88-blackbird", - .id_table = cx8802_pci_tbl, - .probe = blackbird_probe, - .remove = __devexit_p(blackbird_remove), -#ifdef CONFIG_PM - .suspend = cx8802_suspend_common, - .resume = cx8802_resume_common, -#endif +static struct cx8802_driver cx8802_blackbird_driver = { + .type_id = CX88_MPEG_BLACKBIRD, + .hw_access = CX8802_DRVCTL_SHARED, + .probe = cx8802_blackbird_probe, + .remove = cx8802_blackbird_remove, + .advise_acquire = cx8802_blackbird_advise_acquire, + .advise_release = cx8802_blackbird_advise_release, }; static int blackbird_init(void) @@ -1176,17 +1211,22 @@ static int blackbird_init(void) printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); #endif - return pci_register_driver(&blackbird_pci_driver); + cx88_ioctl_hook = mpeg_do_ioctl; + cx88_ioctl_translator = mpeg_translate_ioctl; + return cx8802_register_driver(&cx8802_blackbird_driver); } static void blackbird_fini(void) { - pci_unregister_driver(&blackbird_pci_driver); + cx8802_unregister_driver(&cx8802_blackbird_driver); } module_init(blackbird_init); module_exit(blackbird_fini); +EXPORT_SYMBOL(cx88_ioctl_hook); +EXPORT_SYMBOL(cx88_ioctl_translator); + /* ----------------------------------------------------------- */ /* * Local variables: diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index f764a57c56b..1c5db2070a6 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -1303,7 +1303,7 @@ struct cx88_board cx88_boards[] = { .gpio0 = 0xe780, }}, /* fixme: Add radio support */ - .mpeg = CX88_MPEG_DVB, + .mpeg = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD, }, }; const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards); diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 0ef13e7efa2..8150c09cd2c 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -57,7 +57,7 @@ module_param(debug, int, 0644); MODULE_PARM_DESC(debug,"enable debug messages [dvb]"); #define dprintk(level,fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->core->name , ## arg) + printk(KERN_DEBUG "%s/2-dvb: " fmt, core->name, ## arg) /* ------------------------------------------------------------------ */ @@ -315,20 +315,36 @@ static struct cx22702_config hauppauge_novat_config = { .demod_address = 0x43, .output_mode = CX22702_SERIAL_OUTPUT, }; - static struct cx22702_config hauppauge_hvr1100_config = { .demod_address = 0x63, .output_mode = CX22702_SERIAL_OUTPUT, }; - -static struct cx22702_config hauppauge_hvr1300_config = { +static struct cx22702_config hauppauge_hvr3000_config = { .demod_address = 0x63, .output_mode = CX22702_SERIAL_OUTPUT, }; -static struct cx22702_config hauppauge_hvr3000_config = { +static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, + int acquire) +{ + struct cx8802_dev *dev= fe->dvb->priv; + struct cx8802_driver *drv = NULL; + int ret = 0; + + drv = cx8802_get_driver(dev, CX88_MPEG_DVB); + if (drv) { + if(acquire) + ret = drv->request_acquire(drv); + else + ret = drv->request_release(drv); + } + + return ret; +} + +static struct cx22702_config hauppauge_hvr1300_config = { .demod_address = 0x63, - .output_mode = CX22702_SERIAL_OUTPUT, + .output_mode = CX22702_SERIAL_OUTPUT, }; static int or51132_set_ts_param(struct dvb_frontend* fe, @@ -555,26 +571,6 @@ static int dvb_register(struct cx8802_dev *dev) &dvb_pll_fmd1216me); } break; - case CX88_BOARD_HAUPPAUGE_HVR1300: - dev->dvb.frontend = dvb_attach(cx22702_attach, - &hauppauge_hvr1300_config, - &dev->core->i2c_adap); - if (dev->dvb.frontend != NULL) { - dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, - &dev->core->i2c_adap, - &dvb_pll_fmd1216me); - } - break; - case CX88_BOARD_HAUPPAUGE_HVR3000: - dev->dvb.frontend = dvb_attach(cx22702_attach, - &hauppauge_hvr3000_config, - &dev->core->i2c_adap); - if (dev->dvb.frontend != NULL) { - dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, - &dev->core->i2c_adap, - &dvb_pll_fmd1216me); - } - break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS: dev->dvb.frontend = dvb_attach(mt352_attach, &dvico_fusionhdtv, @@ -782,6 +778,26 @@ static int dvb_register(struct cx8802_dev *dev) dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage; } break; + case CX88_BOARD_HAUPPAUGE_HVR1300: + dev->dvb.frontend = dvb_attach(cx22702_attach, + &hauppauge_hvr1300_config, + &dev->core->i2c_adap); + if (dev->dvb.frontend != NULL) { + dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, + &dev->core->i2c_adap, + &dvb_pll_fmd1216me); + } + break; + case CX88_BOARD_HAUPPAUGE_HVR3000: + dev->dvb.frontend = dvb_attach(cx22702_attach, + &hauppauge_hvr3000_config, + &dev->core->i2c_adap); + if (dev->dvb.frontend != NULL) { + dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, + &dev->core->i2c_adap, + &dvb_pll_fmd1216me); + } + break; default: printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", dev->core->name); @@ -796,6 +812,8 @@ static int dvb_register(struct cx8802_dev *dev) dev->dvb.frontend->ops.info.frequency_min = dev->core->pll_desc->min; dev->dvb.frontend->ops.info.frequency_max = dev->core->pll_desc->max; } + /* Ensure all frontends negotiate bus access */ + dev->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl; /* Put the analog decoder in standby to keep it quiet */ cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL); @@ -806,37 +824,67 @@ static int dvb_register(struct cx8802_dev *dev) /* ----------------------------------------------------------- */ -static int __devinit dvb_probe(struct pci_dev *pci_dev, - const struct pci_device_id *pci_id) +/* CX8802 MPEG -> mini driver - We have been given the hardware */ +static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv) { - struct cx8802_dev *dev; - struct cx88_core *core; + struct cx88_core *core = drv->core; + int err = 0; + dprintk( 1, "%s\n", __FUNCTION__); + + switch (core->board) { + case CX88_BOARD_HAUPPAUGE_HVR1300: + /* We arrive here with either the cx23416 or the cx22702 + * on the bus. Take the bus from the cx23416 and enable the + * cx22702 demod + */ + cx_set(MO_GP0_IO, 0x00000080); /* cx22702 out of reset and enable */ + cx_clear(MO_GP0_IO, 0x00000004); + udelay(1000); + break; + default: + err = -ENODEV; + } + return err; +} + +/* CX8802 MPEG -> mini driver - We no longer have the hardware */ +static int cx8802_dvb_advise_release(struct cx8802_driver *drv) +{ + struct cx88_core *core = drv->core; + int err = 0; + dprintk( 1, "%s\n", __FUNCTION__); + + switch (core->board) { + case CX88_BOARD_HAUPPAUGE_HVR1300: + /* Do Nothing, leave the cx22702 on the bus. */ + break; + default: + err = -ENODEV; + } + return err; +} + +static int cx8802_dvb_probe(struct cx8802_driver *drv) +{ + struct cx88_core *core = drv->core; + struct cx8802_dev *dev = drv->core->dvbdev; int err; - /* general setup */ - core = cx88_core_get(pci_dev); - if (NULL == core) - return -EINVAL; + dprintk( 1, "%s\n", __FUNCTION__); + dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", + core->board, + core->name, + core->pci_bus, + core->pci_slot); err = -ENODEV; if (!(cx88_boards[core->board].mpeg & CX88_MPEG_DVB)) goto fail_core; - err = -ENOMEM; - dev = kzalloc(sizeof(*dev),GFP_KERNEL); - if (NULL == dev) - goto fail_core; - dev->pci = pci_dev; - dev->core = core; - - err = cx8802_init_common(dev); - if (0 != err) - goto fail_free; - #ifdef HAVE_VP3054_I2C err = vp3054_i2c_probe(dev); if (0 != err) - goto fail_free; + goto fail_core; #endif /* dvb stuff */ @@ -848,28 +896,16 @@ static int __devinit dvb_probe(struct pci_dev *pci_dev, sizeof(struct cx88_buffer), dev); err = dvb_register(dev); - if (0 != err) - goto fail_fini; - - /* Maintain a reference to cx88-video can query the 8802 device. */ - core->dvbdev = dev; - return 0; + if (err != 0) + printk("%s dvb_register failed err = %d\n", __FUNCTION__, err); - fail_fini: - cx8802_fini_common(dev); - fail_free: - kfree(dev); fail_core: - cx88_core_put(core,pci_dev); return err; } -static void __devexit dvb_remove(struct pci_dev *pci_dev) +static int cx8802_dvb_remove(struct cx8802_driver *drv) { - struct cx8802_dev *dev = pci_get_drvdata(pci_dev); - - /* Destroy any 8802 reference. */ - dev->core->dvbdev = NULL; + struct cx8802_dev *dev = drv->core->dvbdev; /* dvb */ videobuf_dvb_unregister(&dev->dvb); @@ -878,33 +914,16 @@ static void __devexit dvb_remove(struct pci_dev *pci_dev) vp3054_i2c_remove(dev); #endif - /* common */ - cx8802_fini_common(dev); - cx88_core_put(dev->core,dev->pci); - kfree(dev); + return 0; } -static struct pci_device_id cx8802_pci_tbl[] = { - { - .vendor = 0x14f1, - .device = 0x8802, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - },{ - /* --- end of list --- */ - } -}; -MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl); - -static struct pci_driver dvb_pci_driver = { - .name = "cx88-dvb", - .id_table = cx8802_pci_tbl, - .probe = dvb_probe, - .remove = __devexit_p(dvb_remove), -#ifdef CONFIG_PM - .suspend = cx8802_suspend_common, - .resume = cx8802_resume_common, -#endif +static struct cx8802_driver cx8802_dvb_driver = { + .type_id = CX88_MPEG_DVB, + .hw_access = CX8802_DRVCTL_SHARED, + .probe = cx8802_dvb_probe, + .remove = cx8802_dvb_remove, + .advise_acquire = cx8802_dvb_advise_acquire, + .advise_release = cx8802_dvb_advise_release, }; static int dvb_init(void) @@ -917,12 +936,12 @@ static int dvb_init(void) printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); #endif - return pci_register_driver(&dvb_pci_driver); + return cx8802_register_driver(&cx8802_dvb_driver); } static void dvb_fini(void) { - pci_unregister_driver(&dvb_pci_driver); + cx8802_unregister_driver(&cx8802_dvb_driver); } module_init(dvb_init); diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 6b23a4e6f66..6f155713ee0 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -44,8 +44,12 @@ module_param(debug,int,0644); MODULE_PARM_DESC(debug,"enable debug messages [mpeg]"); #define dprintk(level,fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "%s/2: " fmt, dev->core->name , ## arg) + printk(KERN_DEBUG "%s/2-mpeg: " fmt, dev->core->name, ## arg) +#define mpeg_dbg(level,fmt, arg...) if (debug >= level) \ + printk(KERN_DEBUG "%s/2-mpeg: " fmt, core->name, ## arg) + +static LIST_HEAD(cx8802_devlist); /* ------------------------------------------------------------------ */ static int cx8802_start_dma(struct cx8802_dev *dev, @@ -65,17 +69,13 @@ static int cx8802_start_dma(struct cx8802_dev *dev, /* FIXME: this needs a review. * also: move to cx88-blackbird + cx88-dvb source files? */ - if (cx88_boards[core->board].mpeg == (CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD) ) { - /* Report a warning until the mini driver patch is applied, - * else the following conditions will set the dma registers incorrectly. - * This will be removed in the next major patch and changes to the conditions - * will be made. - */ - printk(KERN_INFO "%s() board->(CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD) is invalid\n", __FUNCTION__); - return -EINVAL; - } - if (cx88_boards[core->board].mpeg & CX88_MPEG_DVB) { + dprintk( 1, "core->active_type_id = 0x%08x\n", core->active_type_id); + + if ( (core->active_type_id == CX88_MPEG_DVB) && + (cx88_boards[core->board].mpeg & CX88_MPEG_DVB) ) { + + dprintk( 1, "cx8802_start_dma doing .dvb\n"); /* negedge driven & software reset */ cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl); udelay(100); @@ -93,15 +93,17 @@ static int cx8802_start_dma(struct cx8802_dev *dev, cx_write(MO_PINMUX_IO, 0x88); /* Enable MPEG parallel IO and video signal pins */ udelay(100); break; + case CX88_BOARD_HAUPPAUGE_HVR1300: + break; default: cx_write(TS_SOP_STAT, 0x00); break; } cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl); udelay(100); - } - - if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) { + } else if ( (core->active_type_id == CX88_MPEG_BLACKBIRD) && + (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) ) { + dprintk( 1, "cx8802_start_dma doing .blackbird\n"); cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */ cx_write(TS_GEN_CNTRL, 0x46); /* punctured clock TS & posedge driven & software reset */ @@ -112,6 +114,10 @@ static int cx8802_start_dma(struct cx8802_dev *dev, cx_write(TS_GEN_CNTRL, 0x06); /* punctured clock TS & posedge driven */ udelay(100); + } else { + printk( "%s() Failed. Unsupported value in .mpeg (0x%08x)\n", __FUNCTION__, + cx88_boards[core->board].mpeg ); + return -EINVAL; } /* reset counter */ @@ -542,8 +548,311 @@ int cx8802_resume_common(struct pci_dev *pci_dev) return 0; } +struct cx8802_dev * cx8802_get_device(struct inode *inode) +{ + int minor = iminor(inode); + struct cx8802_dev *h = NULL; + struct list_head *list; + + list_for_each(list,&cx8802_devlist) { + h = list_entry(list, struct cx8802_dev, devlist); + if (h->mpeg_dev->minor == minor) + return h; + } + + return NULL; +} + +struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype) +{ + struct cx8802_dev *h = NULL; + struct cx8802_driver *d = NULL; + struct list_head *list; + struct list_head *list2; + + list_for_each(list,&cx8802_devlist) { + h = list_entry(list, struct cx8802_dev, devlist); + + list_for_each(list2, &h->drvlist.devlist) { + d = list_entry(list2, struct cx8802_driver, devlist); + + /* only unregister the correct driver type */ + if (d->type_id == btype) { + return d; + } + } + } + + return NULL; +} + +/* Driver asked for hardware access. */ +int cx8802_request_acquire(struct cx8802_driver *drv) +{ + struct cx88_core *core = drv->core; + + /* Fail a request for hardware if the device is busy. */ + if (core->active_type_id != CX88_BOARD_NONE) + return -EBUSY; + + if (drv->advise_acquire) + { + core->active_type_id = drv->type_id; + drv->advise_acquire(drv); + + mpeg_dbg(1,"%s() Post acquire GPIO=%x\n", __FUNCTION__, cx_read(MO_GP0_IO)); + } + + return 0; +} + +/* Driver asked to release hardware. */ +int cx8802_request_release(struct cx8802_driver *drv) +{ + struct cx88_core *core = drv->core; + + if (drv->advise_release) + { + drv->advise_release(drv); + core->active_type_id = CX88_BOARD_NONE; + mpeg_dbg(1,"%s() Post release GPIO=%x\n", __FUNCTION__, cx_read(MO_GP0_IO)); + } + + return 0; +} + +static int cx8802_check_driver(struct cx8802_driver *drv) +{ + if (drv == NULL) + return -ENODEV; + + if ((drv->type_id != CX88_MPEG_DVB) && + (drv->type_id != CX88_MPEG_BLACKBIRD)) + return -EINVAL; + + if ((drv->hw_access != CX8802_DRVCTL_SHARED) && + (drv->hw_access != CX8802_DRVCTL_EXCLUSIVE)) + return -EINVAL; + + if ((drv->probe == NULL) || + (drv->remove == NULL) || + (drv->advise_acquire == NULL) || + (drv->advise_release == NULL)) + return -EINVAL; + + return 0; +} + +int cx8802_register_driver(struct cx8802_driver *drv) +{ + struct cx8802_dev *h; + struct cx8802_driver *driver; + struct list_head *list; + int err = 0, i = 0; + + printk(KERN_INFO "%s() ->registering driver type=%s access=%s\n", __FUNCTION__ , + drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird", + drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive"); + + if ((err = cx8802_check_driver(drv)) != 0) { + printk(KERN_INFO "%s() cx8802_driver is invalid\n", __FUNCTION__ ); + return err; + } + + list_for_each(list,&cx8802_devlist) { + i++; + h = list_entry(list, struct cx8802_dev, devlist); + + printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n", + h->core->name,h->pci->subsystem_vendor, + h->pci->subsystem_device,cx88_boards[h->core->board].name, + h->core->board); + + /* Bring up a new struct for each driver instance */ + driver = kzalloc(sizeof(*drv),GFP_KERNEL); + if (driver == NULL) + return -ENOMEM; + + /* Snapshot of the driver registration data */ + drv->core = h->core; + drv->suspend = cx8802_suspend_common; + drv->resume = cx8802_resume_common; + drv->request_acquire = cx8802_request_acquire; + drv->request_release = cx8802_request_release; + memcpy(driver, drv, sizeof(*driver)); + + err = drv->probe(driver); + if (err == 0) { + mutex_lock(&drv->core->lock); + list_add_tail(&driver->devlist,&h->drvlist.devlist); + mutex_unlock(&drv->core->lock); + } else { + printk(KERN_ERR "%s() ->probe failed err = %d\n", __FUNCTION__, err); + } + + } + if (i == 0) + err = -ENODEV; + + return err; +} + +int cx8802_unregister_driver(struct cx8802_driver *drv) +{ + struct cx8802_dev *h; + struct cx8802_driver *d; + struct list_head *list; + struct list_head *list2, *q; + int err = 0, i = 0; + + printk(KERN_INFO "%s() ->unregistering driver type=%s\n", __FUNCTION__ , + drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird"); + + list_for_each(list,&cx8802_devlist) { + i++; + h = list_entry(list, struct cx8802_dev, devlist); + + printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n", + h->core->name,h->pci->subsystem_vendor, + h->pci->subsystem_device,cx88_boards[h->core->board].name, + h->core->board); + + list_for_each_safe(list2, q, &h->drvlist.devlist) { + d = list_entry(list2, struct cx8802_driver, devlist); + + /* only unregister the correct driver type */ + if (d->type_id != drv->type_id) + continue; + + err = d->remove(d); + if (err == 0) { + mutex_lock(&drv->core->lock); + list_del(list2); + mutex_unlock(&drv->core->lock); + } else + printk(KERN_ERR "%s() ->remove failed err = %d\n", __FUNCTION__, err); + + } + + } + + return err; +} + /* ----------------------------------------------------------- */ +static int __devinit cx8802_probe(struct pci_dev *pci_dev, + const struct pci_device_id *pci_id) +{ + struct cx8802_dev *dev; + struct cx88_core *core; + int err; + + /* general setup */ + core = cx88_core_get(pci_dev); + if (NULL == core) + return -EINVAL; + + printk("%s/2: cx2388x 8802 Driver Manager\n", core->name); + + err = -ENODEV; + if (!cx88_boards[core->board].mpeg) + goto fail_core; + + err = -ENOMEM; + dev = kzalloc(sizeof(*dev),GFP_KERNEL); + if (NULL == dev) + goto fail_core; + dev->pci = pci_dev; + dev->core = core; + + err = cx8802_init_common(dev); + if (err != 0) + goto fail_free; + + INIT_LIST_HEAD(&dev->drvlist.devlist); + list_add_tail(&dev->devlist,&cx8802_devlist); + /* Maintain a reference so cx88-video can query the 8802 device. */ + core->dvbdev = dev; + return 0; + + fail_free: + kfree(dev); + fail_core: + cx88_core_put(core,pci_dev); + return err; +} + +static void __devexit cx8802_remove(struct pci_dev *pci_dev) +{ + struct cx8802_dev *dev; + struct cx8802_driver *h; + struct list_head *list; + + dev = pci_get_drvdata(pci_dev); + + dprintk( 1, "%s\n", __FUNCTION__); + + list_for_each(list,&dev->drvlist.devlist) { + h = list_entry(list, struct cx8802_driver, devlist); + dprintk( 1, " ->driver\n"); + if (h->remove == NULL) { + printk(KERN_ERR "%s .. skipping driver, no probe function\n", __FUNCTION__); + continue; + } + printk(KERN_INFO "%s .. Removing driver type %d\n", __FUNCTION__, h->type_id); + cx8802_unregister_driver(h); + list_del(&dev->drvlist.devlist); + } + + /* Destroy any 8802 reference. */ + dev->core->dvbdev = NULL; + + /* common */ + cx8802_fini_common(dev); + cx88_core_put(dev->core,dev->pci); + kfree(dev); +} + +static struct pci_device_id cx8802_pci_tbl[] = { + { + .vendor = 0x14f1, + .device = 0x8802, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + },{ + /* --- end of list --- */ + } +}; +MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl); + +static struct pci_driver cx8802_pci_driver = { + .name = "cx88-mpeg driver manager", + .id_table = cx8802_pci_tbl, + .probe = cx8802_probe, + .remove = __devexit_p(cx8802_remove), +}; + +static int cx8802_init(void) +{ + printk(KERN_INFO "cx2388x cx88-mpeg Driver Manager version %d.%d.%d loaded\n", + (CX88_VERSION_CODE >> 16) & 0xff, + (CX88_VERSION_CODE >> 8) & 0xff, + CX88_VERSION_CODE & 0xff); +#ifdef SNAPSHOT + printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", + SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); +#endif + return pci_register_driver(&cx8802_pci_driver); +} + +static void cx8802_fini(void) +{ + pci_unregister_driver(&cx8802_pci_driver); +} + +module_init(cx8802_init); +module_exit(cx8802_fini); EXPORT_SYMBOL(cx8802_buf_prepare); EXPORT_SYMBOL(cx8802_buf_queue); EXPORT_SYMBOL(cx8802_cancel_buffers); @@ -551,9 +860,10 @@ EXPORT_SYMBOL(cx8802_cancel_buffers); EXPORT_SYMBOL(cx8802_init_common); EXPORT_SYMBOL(cx8802_fini_common); -EXPORT_SYMBOL(cx8802_suspend_common); -EXPORT_SYMBOL(cx8802_resume_common); - +EXPORT_SYMBOL(cx8802_register_driver); +EXPORT_SYMBOL(cx8802_unregister_driver); +EXPORT_SYMBOL(cx8802_get_device); +EXPORT_SYMBOL(cx8802_get_driver); /* ----------------------------------------------------------- */ /* * Local variables: diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 3bc91aad4fe..5980e47aee1 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -74,6 +74,11 @@ enum cx88_board_type { CX88_MPEG_BLACKBIRD }; +enum cx8802_board_access { + CX8802_DRVCTL_SHARED = 1, + CX8802_DRVCTL_EXCLUSIVE = 2, +}; + /* ----------------------------------------------------------- */ /* tv norms */ @@ -330,6 +335,7 @@ struct cx88_core { /* cx88-video needs to access cx8802 for hybrid tuner pll access. */ struct cx8802_dev *dvbdev; + enum cx88_board_type active_type_id; }; struct cx8800_dev; @@ -405,6 +411,31 @@ struct cx8802_suspend_state { int disabled; }; +struct cx8802_driver { + struct cx88_core *core; + struct list_head devlist; + + /* Type of driver and access required */ + enum cx88_board_type type_id; + enum cx8802_board_access hw_access; + + /* MPEG 8802 internal only */ + int (*suspend)(struct pci_dev *pci_dev, pm_message_t state); + int (*resume)(struct pci_dev *pci_dev); + + /* MPEG 8802 -> mini driver - Driver probe and configuration */ + int (*probe)(struct cx8802_driver *drv); + int (*remove)(struct cx8802_driver *drv); + + /* MPEG 8802 -> mini driver - Access for hardware control */ + int (*advise_acquire)(struct cx8802_driver *drv); + int (*advise_release)(struct cx8802_driver *drv); + + /* MPEG 8802 <- mini driver - Access for hardware control */ + int (*request_acquire)(struct cx8802_driver *drv); + int (*request_release)(struct cx8802_driver *drv); +}; + struct cx8802_dev { struct cx88_core *core; spinlock_t slock; @@ -439,6 +470,9 @@ struct cx8802_dev { /* mpeg params */ struct cx2341x_mpeg_params params; + + /* List of attached drivers */ + struct cx8802_driver drvlist; }; /* ----------------------------------------------------------- */ @@ -571,6 +605,11 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t); void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual); int cx88_audio_thread(void *data); +int cx8802_register_driver(struct cx8802_driver *drv); +int cx8802_unregister_driver(struct cx8802_driver *drv); +struct cx8802_dev * cx8802_get_device(struct inode *inode); +struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype); + /* ----------------------------------------------------------- */ /* cx88-input.c */ @@ -600,6 +639,13 @@ extern int cx88_do_ioctl(struct inode *inode, struct file *file, int radio, extern const u32 cx88_user_ctrls[]; extern int cx8800_ctrl_query(struct v4l2_queryctrl *qctrl); +/* ----------------------------------------------------------- */ +/* cx88-blackbird.c */ +/* used by cx88-ivtv ioctl emulation layer */ +extern int (*cx88_ioctl_hook)(struct inode *inode, struct file *file, + unsigned int cmd, void *arg); +extern unsigned int (*cx88_ioctl_translator)(unsigned int cmd); + /* * Local variables: * c-basic-offset: 8 -- cgit v1.2.3 From 7343826370dd5fe14a2dcec20968f2d3a4431ce6 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Thu, 5 Oct 2006 21:28:24 -0300 Subject: V4L/DVB (4723): Bugfix: Select the correct cx8802_dev when enumerating by CX88_MPEG_type A bug in cx8802_get_driver() meant that in multiboard environments, when testing frontends on the non primary board, the incorrect device was returned resulting in "Unsupported value in .mpeg.." messages. Depending on the electrical design of the hardware (serial, parallel, rising/falling edge detect), transport would still be delivered and the problem went unnoticed. This patch ensures the correct instance of cx8802_dev is returned. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-mpeg.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media/video') diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 6f155713ee0..3d8e6d74e06 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -572,6 +572,8 @@ struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board list_for_each(list,&cx8802_devlist) { h = list_entry(list, struct cx8802_dev, devlist); + if (h != dev) + continue; list_for_each(list2, &h->drvlist.devlist) { d = list_entry(list2, struct cx8802_driver, devlist); -- cgit v1.2.3 From 587d2fd7f296dfb5ccf348e48d6d751bcc6a423a Mon Sep 17 00:00:00 2001 From: Hartmut Hackmann Date: Fri, 6 Oct 2006 19:13:50 -0300 Subject: V4L/DVB (4726): Add support for Pinnacle 310i The driver supports analog TV, radio and DVB-T. It is based on the preliminary patch by Pierluigi Rolando. Signed-off-by: Hartmut Hackmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-cards.c | 41 ++++++++++++++++++++ drivers/media/video/saa7134/saa7134-dvb.c | 60 ++++++++++++++++++++++------- drivers/media/video/saa7134/saa7134.h | 1 + 3 files changed, 88 insertions(+), 14 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 51f0cfdcb68..100cfc53dc9 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -3022,6 +3022,39 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE1, }, }, + [SAA7134_BOARD_PINNACLE_PCTV_310i] = { + .name = "Pinnacle PCTV 310i", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .mpeg = SAA7134_MPEG_DVB, + .gpiomask = 0x000200000, + .inputs = {{ + .name = name_tv, + .vmux = 4, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE2, + },{ + .name = name_comp2, + .vmux = 0, + .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + }}, + .radio = { + .name = name_radio, + .amux = TV, + .gpio = 0x0200000, + }, + }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -3630,6 +3663,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x1043, .subdevice = 0x4860, .driver_data = SAA7134_BOARD_ASUS_EUROPA2_HYBRID, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x11bd, + .subdevice = 0x002f, + .driver_data = SAA7134_BOARD_PINNACLE_PCTV_310i, },{ /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, @@ -3793,6 +3832,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) break; /* i2c remotes */ case SAA7134_BOARD_PINNACLE_PCTV_110i: + case SAA7134_BOARD_PINNACLE_PCTV_310i: case SAA7134_BOARD_UPMOST_PURPLE_TV: dev->has_remote = SAA7134_REMOTE_I2C; break; @@ -3924,6 +3964,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) } break; case SAA7134_BOARD_PHILIPS_TIGER: + case SAA7134_BOARD_PINNACLE_PCTV_310i: case SAA7134_BOARD_TEVION_DVBT_220RF: case SAA7134_BOARD_ASUSTeK_P7131_DUAL: case SAA7134_BOARD_MEDION_MD8800_QUADRO: diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 6b61d9b2fcb..88e4b0f16da 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -293,7 +293,7 @@ static int philips_tu1216_tuner_60_set_params(struct dvb_frontend *fe, struct dv return philips_tda6651_pll_set(0x60, fe, params); } -static int philips_tu1216_request_firmware(struct dvb_frontend *fe, +static int philips_tda1004x_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name) { struct saa7134_dev *dev = fe->dvb->priv; @@ -308,7 +308,7 @@ static struct tda1004x_config philips_tu1216_60_config = { .xtal_freq = TDA10046_XTAL_4M, .agc_config = TDA10046_AGC_DEFAULT, .if_freq = TDA10046_FREQ_3617, - .request_firmware = philips_tu1216_request_firmware, + .request_firmware = philips_tda1004x_request_firmware, }; /* ------------------------------------------------------------------ */ @@ -331,7 +331,7 @@ static struct tda1004x_config philips_tu1216_61_config = { .xtal_freq = TDA10046_XTAL_4M, .agc_config = TDA10046_AGC_DEFAULT, .if_freq = TDA10046_FREQ_3617, - .request_firmware = philips_tu1216_request_firmware, + .request_firmware = philips_tda1004x_request_firmware, }; /* ------------------------------------------------------------------ */ @@ -812,32 +812,40 @@ static int philips_tda827xa_tuner_sleep(u8 addr, struct dvb_frontend *fe) if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); i2c_transfer(&dev->i2c_adap, &tuner_msg, 1); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); return 0; } /* ------------------------------------------------------------------ */ -static int philips_tiger_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int tda8290_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) { - int ret; struct saa7134_dev *dev = fe->dvb->priv; static u8 tda8290_close[] = { 0x21, 0xc0}; static u8 tda8290_open[] = { 0x21, 0x80}; struct i2c_msg tda8290_msg = {.addr = 0x4b,.flags = 0, .len = 2}; - - /* close tda8290 i2c bridge */ - tda8290_msg.buf = tda8290_close; - ret = i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1); - if (ret != 1) + if (enable) { + tda8290_msg.buf = tda8290_close; + } else { + tda8290_msg.buf = tda8290_open; + } + if (i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1) != 1) return -EIO; msleep(20); + return 0; +} + +/* ------------------------------------------------------------------ */ + +static int philips_tiger_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + int ret; + ret = philips_tda827xa_pll_set(0x61, fe, params); if (ret != 0) return ret; - /* open tda8290 i2c bridge */ - tda8290_msg.buf = tda8290_open; - i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1); - return ret; + return 0; } static int philips_tiger_tuner_init(struct dvb_frontend *fe) @@ -874,6 +882,18 @@ static struct tda1004x_config philips_tiger_config = { /* ------------------------------------------------------------------ */ +static struct tda1004x_config pinnacle_pctv_310i_config = { + .demod_address = 0x08, + .invert = 1, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_16M, + .agc_config = TDA10046_AGC_TDA827X, + .if_freq = TDA10046_FREQ_045, + .request_firmware = philips_tda1004x_request_firmware, +}; + +/* ------------------------------------------------------------------ */ + static int asus_p7131_dual_tuner_init(struct dvb_frontend *fe) { struct saa7134_dev *dev = fe->dvb->priv; @@ -1168,6 +1188,18 @@ static int dvb_init(struct saa7134_dev *dev) &philips_tiger_config, &dev->i2c_adap); if (dev->dvb.frontend) { + dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; + dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init; + dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep; + dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params; + } + break; + case SAA7134_BOARD_PINNACLE_PCTV_310i: + dev->dvb.frontend = dvb_attach(tda10046_attach, + &pinnacle_pctv_310i_config, + &dev->i2c_adap); + if (dev->dvb.frontend) { + dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init; dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep; dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 7cf96b43025..2de92ceb4f6 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -227,6 +227,7 @@ struct saa7134_format { #define SAA7134_BOARD_PROTEUS_2309 98 #define SAA7134_BOARD_AVERMEDIA_A16AR 99 #define SAA7134_BOARD_ASUS_EUROPA2_HYBRID 100 +#define SAA7134_BOARD_PINNACLE_PCTV_310i 101 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 -- cgit v1.2.3 From 3ac706d2f77fd7bbef037a6137d08a72d7dc8334 Mon Sep 17 00:00:00 2001 From: Mikhail Fedotov Date: Fri, 6 Oct 2006 20:23:47 -0300 Subject: V4L/DVB (4728): Add support for AverMedia AverTV Studio 507 This is just an additional analog board configuration. Signed-off-by: Mikhail Fedotov Signed-off-by: Hartmut Hackmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-cards.c | 50 +++++++++++++++++++++++++++++ drivers/media/video/saa7134/saa7134-input.c | 1 + drivers/media/video/saa7134/saa7134.h | 1 + 3 files changed, 52 insertions(+) (limited to 'drivers/media/video') diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 100cfc53dc9..2a00cb40f11 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -3055,6 +3055,49 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x0200000, }, }, + [SAA7134_BOARD_AVERMEDIA_STUDIO_507] = { + /* Mikhail Fedotov */ + .name = "Avermedia AVerTV Studio 507", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1256_IH3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .gpiomask = 0x03, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + .gpio = 0x00, + },{ + .name = name_comp1, + .vmux = 0, + .amux = LINE2, + .gpio = 0x00, + },{ + .name = name_comp2, + .vmux = 3, + .amux = LINE2, + .gpio = 0x00, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + .gpio = 0x00, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + .gpio = 0x01, + }, + .mute = { + .name = name_mute, + .amux = LINE1, + .gpio = 0x00, + }, + }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -3669,6 +3712,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x11bd, .subdevice = 0x002f, .driver_data = SAA7134_BOARD_PINNACLE_PCTV_310i, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0x9715, + .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_507, },{ /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, @@ -3756,6 +3805,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_AVERMEDIA_305: case SAA7134_BOARD_AVERMEDIA_STUDIO_307: case SAA7134_BOARD_AVERMEDIA_307: + case SAA7134_BOARD_AVERMEDIA_STUDIO_507: case SAA7134_BOARD_AVERMEDIA_GO_007_FM: case SAA7134_BOARD_AVERMEDIA_777: /* case SAA7134_BOARD_SABRENT_SBTTVFM: */ /* not finished yet */ diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index dee83552e68..0548bd35d0f 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -184,6 +184,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) case SAA7134_BOARD_AVERMEDIA_307: case SAA7134_BOARD_AVERMEDIA_STUDIO_305: case SAA7134_BOARD_AVERMEDIA_STUDIO_307: + case SAA7134_BOARD_AVERMEDIA_STUDIO_507: case SAA7134_BOARD_AVERMEDIA_GO_007_FM: ir_codes = ir_codes_avermedia; mask_keycode = 0x0007C8; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 2de92ceb4f6..799a7149ff6 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -228,6 +228,7 @@ struct saa7134_format { #define SAA7134_BOARD_AVERMEDIA_A16AR 99 #define SAA7134_BOARD_ASUS_EUROPA2_HYBRID 100 #define SAA7134_BOARD_PINNACLE_PCTV_310i 101 +#define SAA7134_BOARD_AVERMEDIA_STUDIO_507 102 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 -- cgit v1.2.3 From 019391e426266a346ac2f1b3d3c70c26b482ff31 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Fri, 6 Oct 2006 21:29:25 -0300 Subject: V4L/DVB (4736): Cx88-blackbird module is rejected during probe. If the last cx88 board probed is not backbird based, and a previous board was, the entire module is unloaded leading to an oops during mpeg_open on the first /dev/videoN device. Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-mpeg.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 3d8e6d74e06..1fe1a833c7c 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -662,7 +662,6 @@ int cx8802_register_driver(struct cx8802_driver *drv) } list_for_each(list,&cx8802_devlist) { - i++; h = list_entry(list, struct cx8802_dev, devlist); printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n", @@ -685,6 +684,7 @@ int cx8802_register_driver(struct cx8802_driver *drv) err = drv->probe(driver); if (err == 0) { + i++; mutex_lock(&drv->core->lock); list_add_tail(&driver->devlist,&h->drvlist.devlist); mutex_unlock(&drv->core->lock); @@ -695,6 +695,8 @@ int cx8802_register_driver(struct cx8802_driver *drv) } if (i == 0) err = -ENODEV; + else + err = 0; return err; } -- cgit v1.2.3 From 5b26c82f959e72cbd642ef4039a356ff8385cd58 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 16 Oct 2006 16:07:51 -0300 Subject: V4L/DVB (4756): Cx88: cleanups - fixed whitespace, replaced leading spaces with tabs - moved .mpeg descriptor below input settings Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-cards.c | 60 +++++++++++++++++------------------ 1 file changed, 30 insertions(+), 30 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 1c5db2070a6..35979933cd0 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -786,7 +786,6 @@ struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .mpeg = CX88_MPEG_BLACKBIRD, .input = {{ .type = CX88_VMUX_COMPOSITE1, .vmux = 0, @@ -805,6 +804,7 @@ struct cx88_board cx88_boards[] = { .vmux = 2, .gpio0 = 0x0000cdf3, }, + .mpeg = CX88_MPEG_BLACKBIRD, }, [CX88_BOARD_KWORLD_VSTREAM_EXPERT_DVD] = { /* Alexander Wold */ @@ -1252,35 +1252,35 @@ struct cx88_board cx88_boards[] = { .gpio0 = 0x070b, }}, }, - [CX88_BOARD_TE_DTV_250_OEM_SWANN] = { - .name = "Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM", - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .radio_type = UNSET, - .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, - .input = {{ - .type = CX88_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0x003fffff, - .gpio1 = 0x00e00000, - .gpio2 = 0x003fffff, - .gpio3 = 0x02000000, - },{ - .type = CX88_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0x003fffff, - .gpio1 = 0x00e00000, - .gpio2 = 0x003fffff, - .gpio3 = 0x02000000, - },{ - .type = CX88_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0x003fffff, - .gpio1 = 0x00e00000, - .gpio2 = 0x003fffff, - .gpio3 = 0x02000000, - }}, - }, + [CX88_BOARD_TE_DTV_250_OEM_SWANN] = { + .name = "Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM", + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x003fffff, + .gpio1 = 0x00e00000, + .gpio2 = 0x003fffff, + .gpio3 = 0x02000000, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x003fffff, + .gpio1 = 0x00e00000, + .gpio2 = 0x003fffff, + .gpio3 = 0x02000000, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x003fffff, + .gpio1 = 0x00e00000, + .gpio2 = 0x003fffff, + .gpio3 = 0x02000000, + }}, + }, [CX88_BOARD_HAUPPAUGE_HVR1300] = { .name = "Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder", .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, -- cgit v1.2.3 From f24546a95ade39b9cd292f06f92232becbbf35ae Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 16 Oct 2006 16:51:11 -0300 Subject: V4L/DVB (4757): Cx88: determine whether or not to use external adc Some cx88-blackbird boards use an external adc, but not necessarily for all inputs. Thus, this needs to be configurable on the card level for each input. This patch allows for the usage of the external adc to be determined by a bit setting in the cx88_input struct for cards based on the cx88 blackbird design. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-cards.c | 16 ++++++++++++++++ drivers/media/video/cx88/cx88-tvaudio.c | 13 ------------- drivers/media/video/cx88/cx88-video.c | 8 ++++++++ drivers/media/video/cx88/cx88.h | 1 + 4 files changed, 25 insertions(+), 13 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 35979933cd0..d7cf54b9531 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -281,18 +281,22 @@ struct cx88_board cx88_boards[] = { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0000bde2, + .extadc = 1, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x0000bde6, + .extadc = 1, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0000bde6, + .extadc = 1, }}, .radio = { .type = CX88_RADIO, .gpio0 = 0x0000bd62, + .extadc = 1, }, .mpeg = CX88_MPEG_BLACKBIRD, }, @@ -523,6 +527,7 @@ struct cx88_board cx88_boards[] = { .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, + .extadc = 1, }}, .mpeg = CX88_MPEG_BLACKBIRD, }, @@ -646,18 +651,22 @@ struct cx88_board cx88_boards[] = { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00009d80, + .extadc = 1, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00009d76, + .extadc = 1, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00009d76, + .extadc = 1, }}, .radio = { .type = CX88_RADIO, .gpio0 = 0x00009d00, + .extadc = 1, }, .mpeg = CX88_MPEG_BLACKBIRD, }, @@ -790,19 +799,23 @@ struct cx88_board cx88_boards[] = { .type = CX88_VMUX_COMPOSITE1, .vmux = 0, .gpio0 = 0x0000cd73, + .extadc = 1, },{ .type = CX88_VMUX_SVIDEO, .vmux = 1, .gpio0 = 0x0000cd73, + .extadc = 1, },{ .type = CX88_VMUX_TELEVISION, .vmux = 3, .gpio0 = 0x0000cdb3, + .extadc = 1, }}, .radio = { .type = CX88_RADIO, .vmux = 2, .gpio0 = 0x0000cdf3, + .extadc = 1, }, .mpeg = CX88_MPEG_BLACKBIRD, }, @@ -1293,14 +1306,17 @@ struct cx88_board cx88_boards[] = { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xe780, + .extadc = 1, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0xe780, + .extadc = 1, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0xe780, + .extadc = 1, }}, /* fixme: Add radio support */ .mpeg = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD, diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c index 58ba9f77352..3482e0114d4 100644 --- a/drivers/media/video/cx88/cx88-tvaudio.c +++ b/drivers/media/video/cx88/cx88-tvaudio.c @@ -143,19 +143,6 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl) cx88_start_audio_dma(core); if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) { - /* sets sound input from external adc */ - switch (core->board) { - case CX88_BOARD_HAUPPAUGE_ROSLYN: - case CX88_BOARD_KWORLD_MCE200_DELUXE: - case CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT: - case CX88_BOARD_PIXELVIEW_PLAYTV_P7000: - case CX88_BOARD_ASUS_PVR_416: - cx_clear(AUD_CTL, EN_I2SIN_ENABLE); - break; - default: - cx_set(AUD_CTL, EN_I2SIN_ENABLE); - } - cx_write(AUD_I2SINPUTCNTL, 4); cx_write(AUD_BAUDRATE, 1); /* 'pass-thru mode': this enables the i2s output to the mpeg encoder */ diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index f27312189d7..8613378428f 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -454,6 +454,14 @@ static int video_mux(struct cx88_core *core, unsigned int input) cx_clear(MO_FILTER_ODD, 0x00002020); break; } + + if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) { + /* sets sound input from external adc */ + if (INPUT(input)->extadc) + cx_set(AUD_CTL, EN_I2SIN_ENABLE); + else + cx_clear(AUD_CTL, EN_I2SIN_ENABLE); + } return 0; } diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 5980e47aee1..7054e941f1d 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -225,6 +225,7 @@ struct cx88_input { enum cx88_itype type; unsigned int vmux; u32 gpio0, gpio1, gpio2, gpio3; + unsigned int extadc:1; }; struct cx88_board { -- cgit v1.2.3 From cc0f3f51357f46c08e2f34a7a22df1100f082de5 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 16 Oct 2006 16:53:01 -0300 Subject: V4L/DVB (4758): Cx88: use external adc for svideo/composite For the KWorld HardwareMpegTV XPert, the external adc must be used for svideo / composite inputs, but television / radio inputs use the internal adc. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-cards.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index d7cf54b9531..43e5af5dfec 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -1063,7 +1063,6 @@ struct cx88_board cx88_boards[] = { .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT] = { - /* FIXME: Audio not working for s-video / composite inputs. */ .name = "KWorld HardwareMpegTV XPert", .tuner_type = TUNER_PHILIPS_TDA8290, .radio_type = UNSET, @@ -1078,10 +1077,12 @@ struct cx88_board cx88_boards[] = { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x3de6, + .extadc = 1, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x3de6, + .extadc = 1, }}, .radio = { .type = CX88_RADIO, -- cgit v1.2.3 From fe16af26c849eb75134855c7be22352f1a15844c Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Mon, 16 Oct 2006 20:47:14 -0300 Subject: V4L/DVB (4759): Cx88: use external adc for rca audio inputs on the ASUS PVR-416 For the ASUS PVR-416, the external adc must be used for the rca audio inputs, but television / radio inputs use the internal adc. Thanks to Alex Deucher for lending his card to me. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-cards.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media/video') diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 43e5af5dfec..f30f88965f0 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -357,6 +357,7 @@ struct cx88_board cx88_boards[] = { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0000fde6, // 0x0000fda6 L,R RCA audio in? + .extadc = 1, }}, .radio = { .type = CX88_RADIO, -- cgit v1.2.3 From c85f49d49f437605550322bd2739af18230cf85b Mon Sep 17 00:00:00 2001 From: Amit Choudhary Date: Tue, 17 Oct 2006 11:39:06 -0300 Subject: V4L/DVB (4761): Stv680.c: check kmalloc() return value. Signed-off-by: Amit Choudhary Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/stv680.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c index 6d1ef1e2e8e..a1ec3aca3f9 100644 --- a/drivers/media/video/stv680.c +++ b/drivers/media/video/stv680.c @@ -687,7 +687,7 @@ static int stv680_start_stream (struct usb_stv *stv680) stv680->sbuf[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL); if (stv680->sbuf[i].data == NULL) { PDEBUG (0, "STV(e): Could not kmalloc raw data buffer %i", i); - return -1; + goto nomem_err; } } @@ -698,7 +698,7 @@ static int stv680_start_stream (struct usb_stv *stv680) stv680->scratch[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL); if (stv680->scratch[i].data == NULL) { PDEBUG (0, "STV(e): Could not kmalloc raw scratch buffer %i", i); - return -1; + goto nomem_err; } stv680->scratch[i].state = BUFFER_UNUSED; } @@ -706,7 +706,7 @@ static int stv680_start_stream (struct usb_stv *stv680) for (i = 0; i < STV680_NUMSBUF; i++) { urb = usb_alloc_urb (0, GFP_KERNEL); if (!urb) - return -ENOMEM; + goto nomem_err; /* sbuf is urb->transfer_buffer, later gets memcpyed to scratch */ usb_fill_bulk_urb (urb, stv680->udev, @@ -721,6 +721,21 @@ static int stv680_start_stream (struct usb_stv *stv680) stv680->framecount = 0; return 0; + + nomem_err: + for (i = 0; i < STV680_NUMSCRATCH; i++) { + kfree(stv680->scratch[i].data); + stv680->scratch[i].data = NULL; + } + for (i = 0; i < STV680_NUMSBUF; i++) { + usb_kill_urb(stv680->urb[i]); + usb_free_urb(stv680->urb[i]); + stv680->urb[i] = NULL; + kfree(stv680->sbuf[i].data); + stv680->sbuf[i].data = NULL; + } + return -ENOMEM; + } static int stv680_stop_stream (struct usb_stv *stv680) -- cgit v1.2.3 From cc75aede1b1ce29a478911ad7dadee94ecd45bbf Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sun, 15 Oct 2006 21:35:14 -0300 Subject: V4L/DVB (4763): Pvrusb2: Implement IR reception for 24xxx devices Unlike 29xxx devices, the 24xxx model series does not have a dedicated I2C device for reception of IR codes. Instead IR is handled directly by the FX2 microcontroller and the results are communicated via commands to the FX2. Rather than implement a whole new IR reception pathway for 24xxx devices, this changeset instead emulates the presence of the 29xxx device's I2C based IR receiver by intercepting commands to that chip and issuing appropriate FX2 commands to do the needed action. This has the result of allowing all the usual IR frameworks (ir-kbd-i2c or lirc) to continue working unmodified for 24xxx devices. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-i2c-core.c | 81 ++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 4 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index 3b9012f8e38..f9bb41d8f4f 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -185,6 +185,79 @@ static int pvr2_i2c_basic_op(struct pvr2_hdw *hdw, } } + +/* This is a special entry point for cases of I2C transaction attempts to + the IR receiver. The implementation here simulates the IR receiver by + issuing a command to the FX2 firmware and using that response to return + what the real I2C receiver would have returned. We use this for 24xxx + devices, where the IR receiver chip has been removed and replaced with + FX2 related logic. */ +static int i2c_24xxx_ir(struct pvr2_hdw *hdw, + u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen) +{ + u8 dat[4]; + unsigned int stat; + + if (!(rlen || wlen)) { + /* This is a probe attempt. Just let it succeed. */ + return 0; + } + + /* We don't understand this kind of transaction */ + if ((wlen != 0) || (rlen == 0)) return -EIO; + + if (rlen < 3) { + /* Mike Isely Appears to be a probe + attempt from lirc. Just fill in zeroes and return. If + we try instead to do the full transaction here, then bad + things seem to happen within the lirc driver module + (version 0.8.0-7 sources from Debian, when run under + vanilla 2.6.17.6 kernel) - and I don't have the patience + to chase it down. */ + if (rlen > 0) rdata[0] = 0; + if (rlen > 1) rdata[1] = 0; + return 0; + } + + /* Issue a command to the FX2 to read the IR receiver. */ + LOCK_TAKE(hdw->ctl_lock); do { + hdw->cmd_buffer[0] = 0xec; + stat = pvr2_send_request(hdw, + hdw->cmd_buffer,1, + hdw->cmd_buffer,4); + dat[0] = hdw->cmd_buffer[0]; + dat[1] = hdw->cmd_buffer[1]; + dat[2] = hdw->cmd_buffer[2]; + dat[3] = hdw->cmd_buffer[3]; + } while (0); LOCK_GIVE(hdw->ctl_lock); + + /* Give up if that operation failed. */ + if (stat != 0) return stat; + + /* Mangle the results into something that looks like the real IR + receiver. */ + rdata[2] = 0xc1; + if (dat[0] != 1) { + /* No code received. */ + rdata[0] = 0; + rdata[1] = 0; + } else { + u16 val; + /* Mash the FX2 firmware-provided IR code into something + that the normal i2c chip-level driver expects. */ + val = dat[1]; + val <<= 8; + val |= dat[2]; + val >>= 1; + val &= ~0x0003; + val |= 0x8000; + rdata[0] = (val >> 8) & 0xffu; + rdata[1] = val & 0xffu; + } + + return 0; +} + /* This is a special entry point that is entered if an I2C operation is attempted to a wm8775 chip on model 24xxx hardware. Autodetect of this part doesn't work, but we know it is really there. So let's look for @@ -887,17 +960,17 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw) { unsigned int idx; - // The default action for all possible I2C addresses is just to do - // the transfer normally. + /* The default action for all possible I2C addresses is just to do + the transfer normally. */ for (idx = 0; idx < PVR2_I2C_FUNC_CNT; idx++) { hdw->i2c_func[idx] = pvr2_i2c_basic_op; } - // If however we're dealing with new hardware, insert some hacks in - // the I2C transfer stack to let things work better. + /* However, deal with various special cases for 24xxx hardware. */ if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) { hdw->i2c_func[0x1b] = i2c_hack_wm8775; hdw->i2c_func[0x44] = i2c_hack_cx25840; + hdw->i2c_func[0x18] = i2c_24xxx_ir; } // Configure the adapter and set up everything else related to it. -- cgit v1.2.3 From eb591af3a3703cb79e3efb5ad87b36dcd32b0712 Mon Sep 17 00:00:00 2001 From: Hartmut Hackmann Date: Thu, 12 Oct 2006 19:46:16 -0300 Subject: V4L/DVB (4767): Make Remote control of the Pinnacle PCTV 310i work The remote control works, but we still need a better keymap. Signed-off-by: Hartmut Hackmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-input.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media/video') diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 0548bd35d0f..83887d1876a 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -336,6 +336,7 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir) 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"); if (pinnacle_remote == 0) { ir->get_key = get_key_pinnacle_color; -- cgit v1.2.3 From 7da6894a96ebbc1505763213c42b8fcf66aa3d90 Mon Sep 17 00:00:00 2001 From: Hermann Pitton Date: Thu, 12 Oct 2006 20:00:56 -0300 Subject: V4L/DVB (4768): Add the Asus P7131 Dual hybrid to the new tda8290_i2c_gate_ctrl The gate control was moved to a separate function. Signed-off-by: Hermann Pitton Signed-off-by: Hartmut Hackmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-dvb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media/video') diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 88e4b0f16da..69092f092bb 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -1210,6 +1210,7 @@ static int dvb_init(struct saa7134_dev *dev) &philips_tiger_config, &dev->i2c_adap); if (dev->dvb.frontend) { + dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; dev->dvb.frontend->ops.tuner_ops.init = asus_p7131_dual_tuner_init; dev->dvb.frontend->ops.tuner_ops.sleep = asus_p7131_dual_tuner_sleep; dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params; -- cgit v1.2.3 From 8364681766cc18b948cf9d7bd46d1b92f343743b Mon Sep 17 00:00:00 2001 From: Hartmut Hackmann Date: Thu, 12 Oct 2006 20:38:51 -0300 Subject: V4L/DVB (4769): Added support for a ASUSTEK P7131 Dual DVB-T variant This card has no firmware eeprom. The old version still should not need a firmware file due to an undocumented feature of the TDA10046. The patch also includes Hermann Pitton's proposal for improved antenna switch handling Signed-off-by: Hartmut Hackmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-cards.c | 9 +++++++++ drivers/media/video/saa7134/saa7134-dvb.c | 12 +++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 2a00cb40f11..8109c8ef09f 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -2462,14 +2462,17 @@ struct saa7134_board saa7134_boards[] = { .vmux = 1, .amux = TV, .tv = 1, + .gpio = 0x0000000, },{ .name = name_comp1, .vmux = 3, .amux = LINE2, + .gpio = 0x0200000, },{ .name = name_svideo, .vmux = 8, .amux = LINE2, + .gpio = 0x0200000, }}, .radio = { .name = name_radio, @@ -3718,6 +3721,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x1461, /* Avermedia Technologies Inc */ .subdevice = 0x9715, .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_507, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x1043, + .subdevice = 0x4876, + .driver_data = SAA7134_BOARD_ASUSTeK_P7131_DUAL, },{ /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 69092f092bb..706450c27a5 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -894,6 +894,16 @@ static struct tda1004x_config pinnacle_pctv_310i_config = { /* ------------------------------------------------------------------ */ +static struct tda1004x_config asus_p7131_dual_config = { + .demod_address = 0x08, + .invert = 1, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_16M, + .agc_config = TDA10046_AGC_TDA827X, + .if_freq = TDA10046_FREQ_045, + .request_firmware = philips_tda1004x_request_firmware, +}; + static int asus_p7131_dual_tuner_init(struct dvb_frontend *fe) { struct saa7134_dev *dev = fe->dvb->priv; @@ -1207,7 +1217,7 @@ static int dvb_init(struct saa7134_dev *dev) break; case SAA7134_BOARD_ASUSTeK_P7131_DUAL: dev->dvb.frontend = dvb_attach(tda10046_attach, - &philips_tiger_config, + &asus_p7131_dual_config, &dev->i2c_adap); if (dev->dvb.frontend) { dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; -- cgit v1.2.3 From a75ec3f033625fb02ccc855fcd2e322275633fc4 Mon Sep 17 00:00:00 2001 From: Hartmut Hackmann Date: Mon, 30 Oct 2006 19:56:59 -0300 Subject: V4L/DVB (4791): Added autodetected flag to the saa7134_dev structure In case the exact board type needs to be determined by probing or evaluating the eeprom, this flag allows to still set the board type via the card=xx insmod option. This is an extract of a patch by Francis Barber. Signed-off-by: Hartmut Hackmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-core.c | 11 ++++++----- drivers/media/video/saa7134/saa7134.h | 3 +++ 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 5c9e63dfbea..ed038fff3b4 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -889,15 +889,16 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, must_configure_manually(); dev->board = SAA7134_BOARD_UNKNOWN; } + dev->autodetected = card[dev->nr] != dev->board; dev->tuner_type = saa7134_boards[dev->board].tuner_type; dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf; if (UNSET != tuner[dev->nr]) dev->tuner_type = tuner[dev->nr]; - printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", - dev->name,pci_dev->subsystem_vendor, - pci_dev->subsystem_device,saa7134_boards[dev->board].name, - dev->board, card[dev->nr] == dev->board ? - "insmod option" : "autodetected"); + printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", + dev->name,pci_dev->subsystem_vendor, + pci_dev->subsystem_device,saa7134_boards[dev->board].name, + dev->board, dev->autodetected ? + "autodetected" : "insmod option"); /* get mmio */ if (!request_mem_region(pci_resource_start(pci_dev,0), diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 799a7149ff6..40603f39214 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -448,6 +448,9 @@ struct saa7134_dev { struct v4l2_prio_state prio; #endif + /* insmod option/autodetected */ + int autodetected; + /* various device info */ unsigned int resources; struct video_device *video_dev; -- cgit v1.2.3 From cbb94521cff24c98c2dbee28fb95e007c6bcaa43 Mon Sep 17 00:00:00 2001 From: Hartmut Hackmann Date: Mon, 30 Oct 2006 20:00:16 -0300 Subject: V4L/DVB (4792): Add support for the Compro Videomate DVB-T200A This board has the same PCI ID as the T200, so the exact board type is determined from the eeprom. The original patch was provided by Francis Barber Signed-off-by: Hartmut Hackmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-cards.c | 49 +++++++++++++++++++++++++++++ drivers/media/video/saa7134/saa7134-dvb.c | 40 +++++++++++++++-------- drivers/media/video/saa7134/saa7134.h | 1 + 3 files changed, 77 insertions(+), 13 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 8109c8ef09f..f5ad450dd7c 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -3101,6 +3101,31 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x00, }, }, + [SAA7134_BOARD_VIDEOMATE_DVBT_200A] = { + /* Francis Barber */ + .name = "Compro Videomate DVB-T200A", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE, + .mpeg = SAA7134_MPEG_DVB, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + }}, + }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -3823,6 +3848,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII: case SAA7134_BOARD_VIDEOMATE_DVBT_300: case SAA7134_BOARD_VIDEOMATE_DVBT_200: + case SAA7134_BOARD_VIDEOMATE_DVBT_200A: case SAA7134_BOARD_MANLI_MTV001: case SAA7134_BOARD_MANLI_MTV002: case SAA7134_BOARD_BEHOLD_409FM: @@ -4064,6 +4090,29 @@ int saa7134_board_init2(struct saa7134_dev *dev) dev->name, i); } break; + case SAA7134_BOARD_VIDEOMATE_DVBT_200: + case SAA7134_BOARD_VIDEOMATE_DVBT_200A: + /* The T200 and the T200A share the same pci id. Consequently, + * we are going to query eeprom to try to find out which one we + * are actually looking at. */ + + /* Don't do this if the board was specifically selected with an + * insmod option or if we have the default configuration T200*/ + if(!dev->autodetected || (dev->eedata[0x41] == 0xd0)) + break; + if(dev->eedata[0x41] == 0x02) { + /* Reconfigure board as T200A */ + dev->board = SAA7134_BOARD_VIDEOMATE_DVBT_200A; + dev->tuner_type = saa7134_boards[dev->board].tuner_type; + dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf; + printk(KERN_INFO "%s: Reconfigured board as %s\n", + dev->name, saa7134_boards[dev->board].name); + } else { + printk(KERN_WARNING "%s: Unexpected tuner type info: %x in eeprom\n", + dev->name, dev->eedata[0x41]); + break; + } + break; } return 0; } diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 706450c27a5..098d8a6a081 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -336,7 +336,7 @@ static struct tda1004x_config philips_tu1216_61_config = { /* ------------------------------------------------------------------ */ -static int philips_europa_tuner_init(struct dvb_frontend *fe) +static int philips_td1316_tuner_init(struct dvb_frontend *fe) { struct saa7134_dev *dev = fe->dvb->priv; static u8 msg[] = { 0x0b, 0xf5, 0x86, 0xab }; @@ -347,18 +347,8 @@ static int philips_europa_tuner_init(struct dvb_frontend *fe) fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1) return -EIO; - msleep(1); - - /* switch the board to dvb mode */ - init_msg.addr = 0x43; - init_msg.len = 0x02; - msg[0] = 0x00; - msg[1] = 0x40; if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1) - return -EIO; - + fe->ops.i2c_gate_ctrl(fe, 0); return 0; } @@ -367,6 +357,22 @@ static int philips_td1316_tuner_set_params(struct dvb_frontend *fe, struct dvb_f return philips_tda6651_pll_set(0x61, fe, params); } +static int philips_europa_tuner_init(struct dvb_frontend *fe) +{ + struct saa7134_dev *dev = fe->dvb->priv; + static u8 msg[] = { 0x00, 0x40}; + struct i2c_msg init_msg = {.addr = 0x43,.flags = 0,.buf = msg,.len = sizeof(msg) }; + + + if (philips_td1316_tuner_init(fe)) + return -EIO; + msleep(1); + if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1) + return -EIO; + + return 0; +} + static int philips_europa_tuner_sleep(struct dvb_frontend *fe) { struct saa7134_dev *dev = fe->dvb->priv; @@ -1324,7 +1330,15 @@ static int dvb_init(struct saa7134_dev *dev) dev->dvb.frontend->ops.tuner_ops.set_params = philips_fmd1216_tuner_set_params; } break; - + case SAA7134_BOARD_VIDEOMATE_DVBT_200A: + dev->dvb.frontend = dvb_attach(tda10046_attach, + &philips_europa_config, + &dev->i2c_adap); + if (dev->dvb.frontend) { + dev->dvb.frontend->ops.tuner_ops.init = philips_td1316_tuner_init; + dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params; + } + break; default: printk("%s: Huh? unknown DVB card?\n",dev->name); break; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 40603f39214..0c0f4651bd0 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -229,6 +229,7 @@ struct saa7134_format { #define SAA7134_BOARD_ASUS_EUROPA2_HYBRID 100 #define SAA7134_BOARD_PINNACLE_PCTV_310i 101 #define SAA7134_BOARD_AVERMEDIA_STUDIO_507 102 +#define SAA7134_BOARD_VIDEOMATE_DVBT_200A 103 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 -- cgit v1.2.3 From d905b382d797a213e15868cbf3204f50ed52e30b Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Sat, 4 Nov 2006 09:25:53 -0300 Subject: V4L/DVB (4797): Marvell 88ALP01 "cafe" driver A driver for the Marvell M88ALP01 "CAFE" CMOS integrated camera controller. This driver has been renamed "cafe_ccic" since my previous patch set. Signed-off-by: Jonathan Corbet Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 9 + drivers/media/video/Makefile | 2 + drivers/media/video/cafe_ccic-regs.h | 160 +++ drivers/media/video/cafe_ccic.c | 2237 ++++++++++++++++++++++++++++++++++ 4 files changed, 2408 insertions(+) create mode 100644 drivers/media/video/cafe_ccic-regs.h create mode 100644 drivers/media/video/cafe_ccic.c (limited to 'drivers/media/video') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index b8fde5cf473..4ea1d0ebf5f 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -670,6 +670,15 @@ config VIDEO_M32R_AR_M64278 To compile this driver as a module, choose M here: the module will be called arv. +config VIDEO_CAFE_CCIC + tristate "Marvell 88ALP01 (Cafe) CMOS Camera Controller support" + depends on I2C && VIDEO_V4L2 + select VIDEO_OV7670 + ---help--- + This is a video4linux2 driver for the Marvell 88ALP01 integrated + CMOS camera controller. This is the controller found on first- + generation OLPC systems. + # # USB Multimedia device configuration # diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index af57abce8a6..8ff787a4cf6 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -92,6 +92,8 @@ obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o +obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o + obj-$(CONFIG_USB_DABUSB) += dabusb.o obj-$(CONFIG_USB_OV511) += ov511.o obj-$(CONFIG_USB_SE401) += se401.o diff --git a/drivers/media/video/cafe_ccic-regs.h b/drivers/media/video/cafe_ccic-regs.h new file mode 100644 index 00000000000..b2c22a0d664 --- /dev/null +++ b/drivers/media/video/cafe_ccic-regs.h @@ -0,0 +1,160 @@ +/* + * Register definitions for the m88alp01 camera interface. Offsets in bytes + * as given in the spec. + * + * Copyright 2006 One Laptop Per Child Association, Inc. + * + * Written by Jonathan Corbet, corbet@lwn.net. + * + * This file may be distributed under the terms of the GNU General + * Public License, version 2. + */ +#define REG_Y0BAR 0x00 +#define REG_Y1BAR 0x04 +#define REG_Y2BAR 0x08 +/* ... */ + +#define REG_IMGPITCH 0x24 /* Image pitch register */ +#define IMGP_YP_SHFT 2 /* Y pitch params */ +#define IMGP_YP_MASK 0x00003ffc /* Y pitch field */ +#define IMGP_UVP_SHFT 18 /* UV pitch (planar) */ +#define IMGP_UVP_MASK 0x3ffc0000 +#define REG_IRQSTATRAW 0x28 /* RAW IRQ Status */ +#define IRQ_EOF0 0x00000001 /* End of frame 0 */ +#define IRQ_EOF1 0x00000002 /* End of frame 1 */ +#define IRQ_EOF2 0x00000004 /* End of frame 2 */ +#define IRQ_SOF0 0x00000008 /* Start of frame 0 */ +#define IRQ_SOF1 0x00000010 /* Start of frame 1 */ +#define IRQ_SOF2 0x00000020 /* Start of frame 2 */ +#define IRQ_OVERFLOW 0x00000040 /* FIFO overflow */ +#define IRQ_TWSIW 0x00010000 /* TWSI (smbus) write */ +#define IRQ_TWSIR 0x00020000 /* TWSI read */ +#define IRQ_TWSIE 0x00040000 /* TWSI error */ +#define TWSIIRQS (IRQ_TWSIW|IRQ_TWSIR|IRQ_TWSIE) +#define FRAMEIRQS (IRQ_EOF0|IRQ_EOF1|IRQ_EOF2|IRQ_SOF0|IRQ_SOF1|IRQ_SOF2) +#define ALLIRQS (TWSIIRQS|FRAMEIRQS|IRQ_OVERFLOW) +#define REG_IRQMASK 0x2c /* IRQ mask - same bits as IRQSTAT */ +#define REG_IRQSTAT 0x30 /* IRQ status / clear */ + +#define REG_IMGSIZE 0x34 /* Image size */ +#define IMGSZ_V_MASK 0x1fff0000 +#define IMGSZ_V_SHIFT 16 +#define IMGSZ_H_MASK 0x00003fff +#define REG_IMGOFFSET 0x38 /* IMage offset */ + +#define REG_CTRL0 0x3c /* Control 0 */ +#define C0_ENABLE 0x00000001 /* Makes the whole thing go */ + +/* Mask for all the format bits */ +#define C0_DF_MASK 0x00fffffc /* Bits 2-23 */ + +/* RGB ordering */ +#define C0_RGB4_RGBX 0x00000000 +#define C0_RGB4_XRGB 0x00000004 +#define C0_RGB4_BGRX 0x00000008 +#define C0_RGB4_XBGR 0x0000000c +#define C0_RGB5_RGGB 0x00000000 +#define C0_RGB5_GRBG 0x00000004 +#define C0_RGB5_GBRG 0x00000008 +#define C0_RGB5_BGGR 0x0000000c + +/* Spec has two fields for DIN and DOUT, but they must match, so + combine them here. */ +#define C0_DF_YUV 0x00000000 /* Data is YUV */ +#define C0_DF_RGB 0x000000a0 /* ... RGB */ +#define C0_DF_BAYER 0x00000140 /* ... Bayer */ +/* 8-8-8 must be missing from the below - ask */ +#define C0_RGBF_565 0x00000000 +#define C0_RGBF_444 0x00000800 +#define C0_RGB_BGR 0x00001000 /* Blue comes first */ +#define C0_YUV_PLANAR 0x00000000 /* YUV 422 planar format */ +#define C0_YUV_PACKED 0x00008000 /* YUV 422 packed */ +#define C0_YUV_420PL 0x0000a000 /* YUV 420 planar */ +/* Think that 420 packed must be 111 - ask */ +#define C0_YUVE_YUYV 0x00000000 /* Y1CbY0Cr */ +#define C0_YUVE_YVYU 0x00010000 /* Y1CrY0Cb */ +#define C0_YUVE_VYUY 0x00020000 /* CrY1CbY0 */ +#define C0_YUVE_UYVY 0x00030000 /* CbY1CrY0 */ +#define C0_YUVE_XYUV 0x00000000 /* 420: .YUV */ +#define C0_YUVE_XYVU 0x00010000 /* 420: .YVU */ +#define C0_YUVE_XUVY 0x00020000 /* 420: .UVY */ +#define C0_YUVE_XVUY 0x00030000 /* 420: .VUY */ +/* Bayer bits 18,19 if needed */ +#define C0_HPOL_LOW 0x01000000 /* HSYNC polarity active low */ +#define C0_VPOL_LOW 0x02000000 /* VSYNC polarity active low */ +#define C0_VCLK_LOW 0x04000000 /* VCLK on falling edge */ +#define C0_DOWNSCALE 0x08000000 /* Enable downscaler */ +#define C0_SIFM_MASK 0xc0000000 /* SIF mode bits */ +#define C0_SIF_HVSYNC 0x00000000 /* Use H/VSYNC */ +#define CO_SOF_NOSYNC 0x40000000 /* Use inband active signaling */ + + +#define REG_CTRL1 0x40 /* Control 1 */ +#define C1_444ALPHA 0x00f00000 /* Alpha field in RGB444 */ +#define C1_ALPHA_SHFT 20 +#define C1_DMAB32 0x00000000 /* 32-byte DMA burst */ +#define C1_DMAB16 0x02000000 /* 16-byte DMA burst */ +#define C1_DMAB64 0x04000000 /* 64-byte DMA burst */ +#define C1_DMAB_MASK 0x06000000 +#define C1_TWOBUFS 0x08000000 /* Use only two DMA buffers */ +#define C1_PWRDWN 0x10000000 /* Power down */ + +#define REG_CLKCTRL 0x88 /* Clock control */ +#define CLK_DIV_MASK 0x0000ffff /* Upper bits RW "reserved" */ + +#define REG_GPR 0xb4 /* General purpose register. This + controls inputs to the power and reset + pins on the OV7670 used with OLPC; + other deployments could differ. */ +#define GPR_C1EN 0x00000020 /* Pad 1 (power down) enable */ +#define GPR_C0EN 0x00000010 /* Pad 0 (reset) enable */ +#define GPR_C1 0x00000002 /* Control 1 value */ +/* + * Control 0 is wired to reset on OLPC machines. For ov7x sensors, + * it is active low, for 0v6x, instead, it's active high. What + * fun. + */ +#define GPR_C0 0x00000001 /* Control 0 value */ + +#define REG_TWSIC0 0xb8 /* TWSI (smbus) control 0 */ +#define TWSIC0_EN 0x00000001 /* TWSI enable */ +#define TWSIC0_MODE 0x00000002 /* 1 = 16-bit, 0 = 8-bit */ +#define TWSIC0_SID 0x000003fc /* Slave ID */ +#define TWSIC0_SID_SHIFT 2 +#define TWSIC0_CLKDIV 0x0007fc00 /* Clock divider */ +#define TWSIC0_MASKACK 0x00400000 /* Mask ack from sensor */ +#define TWSIC0_OVMAGIC 0x00800000 /* Make it work on OV sensors */ + +#define REG_TWSIC1 0xbc /* TWSI control 1 */ +#define TWSIC1_DATA 0x0000ffff /* Data to/from camchip */ +#define TWSIC1_ADDR 0x00ff0000 /* Address (register) */ +#define TWSIC1_ADDR_SHIFT 16 +#define TWSIC1_READ 0x01000000 /* Set for read op */ +#define TWSIC1_WSTAT 0x02000000 /* Write status */ +#define TWSIC1_RVALID 0x04000000 /* Read data valid */ +#define TWSIC1_ERROR 0x08000000 /* Something screwed up */ + + +#define REG_UBAR 0xc4 /* Upper base address register */ + +/* + * Here's the weird global control registers which are said to live + * way up here. + */ +#define REG_GL_CSR 0x3004 /* Control/status register */ +#define GCSR_SRS 0x00000001 /* SW Reset set */ +#define GCSR_SRC 0x00000002 /* SW Reset clear */ +#define GCSR_MRS 0x00000004 /* Master reset set */ +#define GCSR_MRC 0x00000008 /* HW Reset clear */ +#define GCSR_CCIC_EN 0x00004000 /* CCIC Clock enable */ +#define REG_GL_IMASK 0x300c /* Interrupt mask register */ +#define GIMSK_CCIC_EN 0x00000004 /* CCIC Interrupt enable */ + +#define REG_LEN REG_GL_IMASK + 4 + + +/* + * Useful stuff that probably belongs somewhere global. + */ +#define VGA_WIDTH 640 +#define VGA_HEIGHT 480 diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c new file mode 100644 index 00000000000..2026c4983b2 --- /dev/null +++ b/drivers/media/video/cafe_ccic.c @@ -0,0 +1,2237 @@ +/* + * A driver for the CMOS camera controller in the Marvell 88ALP01 "cafe" + * multifunction chip. Currently works with the Omnivision OV7670 + * sensor. + * + * Copyright 2006 One Laptop Per Child Association, Inc. + * + * Written by Jonathan Corbet, corbet@lwn.net. + * + * This file may be distributed under the terms of the GNU General + * Public License, version 2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "cafe_ccic-regs.h" + +#define CAFE_VERSION 0x000001 + + +/* + * Parameters. + */ +MODULE_AUTHOR("Jonathan Corbet "); +MODULE_DESCRIPTION("Marvell 88ALP01 CMOS Camera Controller driver"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("Video"); + +/* + * Internal DMA buffer management. Since the controller cannot do S/G I/O, + * we must have physically contiguous buffers to bring frames into. + * These parameters control how many buffers we use, whether we + * allocate them at load time (better chance of success, but nails down + * memory) or when somebody tries to use the camera (riskier), and, + * for load-time allocation, how big they should be. + * + * The controller can cycle through three buffers. We could use + * more by flipping pointers around, but it probably makes little + * sense. + */ + +#define MAX_DMA_BUFS 3 +static int alloc_bufs_at_load = 0; +module_param(alloc_bufs_at_load, bool, 0444); +MODULE_PARM_DESC(alloc_bufs_at_load, + "Non-zero value causes DMA buffers to be allocated at module " + "load time. This increases the chances of successfully getting " + "those buffers, but at the cost of nailing down the memory from " + "the outset."); + +static int n_dma_bufs = 3; +module_param(n_dma_bufs, uint, 0644); +MODULE_PARM_DESC(n_dma_bufs, + "The number of DMA buffers to allocate. Can be either two " + "(saves memory, makes timing tighter) or three."); + +static int dma_buf_size = VGA_WIDTH * VGA_HEIGHT * 2; /* Worst case */ +module_param(dma_buf_size, uint, 0444); +MODULE_PARM_DESC(dma_buf_size, + "The size of the allocated DMA buffers. If actual operating " + "parameters require larger buffers, an attempt to reallocate " + "will be made."); + +static int min_buffers = 1; +module_param(min_buffers, uint, 0644); +MODULE_PARM_DESC(min_buffers, + "The minimum number of streaming I/O buffers we are willing " + "to work with."); + +static int max_buffers = 10; +module_param(max_buffers, uint, 0644); +MODULE_PARM_DESC(max_buffers, + "The maximum number of streaming I/O buffers an application " + "will be allowed to allocate. These buffers are big and live " + "in vmalloc space."); + +static int flip = 0; +module_param(flip, bool, 0444); +MODULE_PARM_DESC(flip, + "If set, the sensor will be instructed to flip the image " + "vertically."); + + +enum cafe_state { + S_NOTREADY, /* Not yet initialized */ + S_IDLE, /* Just hanging around */ + S_FLAKED, /* Some sort of problem */ + S_SINGLEREAD, /* In read() */ + S_SPECREAD, /* Speculative read (for future read()) */ + S_STREAMING /* Streaming data */ +}; + +/* + * Tracking of streaming I/O buffers. + */ +struct cafe_sio_buffer { + struct list_head list; + struct v4l2_buffer v4lbuf; + char *buffer; /* Where it lives in kernel space */ + int mapcount; + struct cafe_camera *cam; +}; + +/* + * A description of one of our devices. + * Locking: controlled by s_mutex. Certain fields, however, require + * the dev_lock spinlock; they are marked as such by comments. + * dev_lock is also required for access to device registers. + */ +struct cafe_camera +{ + enum cafe_state state; + unsigned long flags; /* Buffer status, mainly (dev_lock) */ + int users; /* How many open FDs */ + struct file *owner; /* Who has data access (v4l2) */ + + /* + * Subsystem structures. + */ + struct pci_dev *pdev; + struct video_device v4ldev; + struct i2c_adapter i2c_adapter; + struct i2c_client *sensor; + + unsigned char __iomem *regs; + struct list_head dev_list; /* link to other devices */ + + /* DMA buffers */ + unsigned int nbufs; /* How many are alloc'd */ + int next_buf; /* Next to consume (dev_lock) */ + unsigned int dma_buf_size; /* allocated size */ + void *dma_bufs[MAX_DMA_BUFS]; /* Internal buffer addresses */ + dma_addr_t dma_handles[MAX_DMA_BUFS]; /* Buffer bus addresses */ + unsigned int specframes; /* Unconsumed spec frames (dev_lock) */ + unsigned int sequence; /* Frame sequence number */ + unsigned int buf_seq[MAX_DMA_BUFS]; /* Sequence for individual buffers */ + + /* Streaming buffers */ + unsigned int n_sbufs; /* How many we have */ + struct cafe_sio_buffer *sb_bufs; /* The array of housekeeping structs */ + struct list_head sb_avail; /* Available for data (we own) (dev_lock) */ + struct list_head sb_full; /* With data (user space owns) (dev_lock) */ + struct tasklet_struct s_tasklet; + + /* Current operating parameters */ + enum v4l2_chip_ident sensor_type; /* Currently ov7670 only */ + struct v4l2_pix_format pix_format; + + /* Locks */ + struct mutex s_mutex; /* Access to this structure */ + spinlock_t dev_lock; /* Access to device */ + + /* Misc */ + wait_queue_head_t smbus_wait; /* Waiting on i2c events */ + wait_queue_head_t iowait; /* Waiting on frame data */ +#ifdef CONFIG_VIDEO_ADV_DEBUG + struct dentry *dfs_regs; + struct dentry *dfs_cam_regs; +#endif +}; + +/* + * Status flags. Always manipulated with bit operations. + */ +#define CF_BUF0_VALID 0 /* Buffers valid - first three */ +#define CF_BUF1_VALID 1 +#define CF_BUF2_VALID 2 +#define CF_DMA_ACTIVE 3 /* A frame is incoming */ +#define CF_CONFIG_NEEDED 4 /* Must configure hardware */ + + + +/* + * Start over with DMA buffers - dev_lock needed. + */ +static void cafe_reset_buffers(struct cafe_camera *cam) +{ + int i; + + cam->next_buf = -1; + for (i = 0; i < cam->nbufs; i++) + clear_bit(i, &cam->flags); + cam->specframes = 0; +} + +static inline int cafe_needs_config(struct cafe_camera *cam) +{ + return test_bit(CF_CONFIG_NEEDED, &cam->flags); +} + +static void cafe_set_config_needed(struct cafe_camera *cam, int needed) +{ + if (needed) + set_bit(CF_CONFIG_NEEDED, &cam->flags); + else + clear_bit(CF_CONFIG_NEEDED, &cam->flags); +} + + + + +/* + * Debugging and related. + */ +#define cam_err(cam, fmt, arg...) \ + dev_err(&(cam)->pdev->dev, fmt, ##arg); +#define cam_warn(cam, fmt, arg...) \ + dev_warn(&(cam)->pdev->dev, fmt, ##arg); +#define cam_dbg(cam, fmt, arg...) \ + dev_dbg(&(cam)->pdev->dev, fmt, ##arg); + + +/* ---------------------------------------------------------------------*/ +/* + * We keep a simple list of known devices to search at open time. + */ +static LIST_HEAD(cafe_dev_list); +static DEFINE_MUTEX(cafe_dev_list_lock); + +static void cafe_add_dev(struct cafe_camera *cam) +{ + mutex_lock(&cafe_dev_list_lock); + list_add_tail(&cam->dev_list, &cafe_dev_list); + mutex_unlock(&cafe_dev_list_lock); +} + +static void cafe_remove_dev(struct cafe_camera *cam) +{ + mutex_lock(&cafe_dev_list_lock); + list_del(&cam->dev_list); + mutex_unlock(&cafe_dev_list_lock); +} + +static struct cafe_camera *cafe_find_dev(int minor) +{ + struct cafe_camera *cam; + + mutex_lock(&cafe_dev_list_lock); + list_for_each_entry(cam, &cafe_dev_list, dev_list) { + if (cam->v4ldev.minor == minor) + goto done; + } + cam = NULL; + done: + mutex_unlock(&cafe_dev_list_lock); + return cam; +} + + +static struct cafe_camera *cafe_find_by_pdev(struct pci_dev *pdev) +{ + struct cafe_camera *cam; + + mutex_lock(&cafe_dev_list_lock); + list_for_each_entry(cam, &cafe_dev_list, dev_list) { + if (cam->pdev == pdev) + goto done; + } + cam = NULL; + done: + mutex_unlock(&cafe_dev_list_lock); + return cam; +} + + +/* ------------------------------------------------------------------------ */ +/* + * Device register I/O + */ +static inline void cafe_reg_write(struct cafe_camera *cam, unsigned int reg, + unsigned int val) +{ + iowrite32(val, cam->regs + reg); +} + +static inline unsigned int cafe_reg_read(struct cafe_camera *cam, + unsigned int reg) +{ + return ioread32(cam->regs + reg); +} + + +static inline void cafe_reg_write_mask(struct cafe_camera *cam, unsigned int reg, + unsigned int val, unsigned int mask) +{ + unsigned int v = cafe_reg_read(cam, reg); + + v = (v & ~mask) | (val & mask); + cafe_reg_write(cam, reg, v); +} + +static inline void cafe_reg_clear_bit(struct cafe_camera *cam, + unsigned int reg, unsigned int val) +{ + cafe_reg_write_mask(cam, reg, 0, val); +} + +static inline void cafe_reg_set_bit(struct cafe_camera *cam, + unsigned int reg, unsigned int val) +{ + cafe_reg_write_mask(cam, reg, val, val); +} + + + +/* -------------------------------------------------------------------- */ +/* + * The I2C/SMBUS interface to the camera itself starts here. The + * controller handles SMBUS itself, presenting a relatively simple register + * interface; all we have to do is to tell it where to route the data. + */ +#define CAFE_SMBUS_TIMEOUT (HZ) /* generous */ + +static int cafe_smbus_write_done(struct cafe_camera *cam) +{ + unsigned long flags; + int c1; + + /* + * We must delay after the interrupt, or the controller gets confused + * and never does give us good status. Fortunately, we don't do this + * often. + */ + udelay(20); + spin_lock_irqsave(&cam->dev_lock, flags); + c1 = cafe_reg_read(cam, REG_TWSIC1); + spin_unlock_irqrestore(&cam->dev_lock, flags); + return (c1 & (TWSIC1_WSTAT|TWSIC1_ERROR)) != TWSIC1_WSTAT; +} + +static int cafe_smbus_write_data(struct cafe_camera *cam, + u16 addr, u8 command, u8 value) +{ + unsigned int rval; + unsigned long flags; + + spin_lock_irqsave(&cam->dev_lock, flags); + rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID); + rval |= TWSIC0_OVMAGIC; /* Make OV sensors work */ + /* + * Marvell sez set clkdiv to all 1's for now. + */ + rval |= TWSIC0_CLKDIV; + cafe_reg_write(cam, REG_TWSIC0, rval); + (void) cafe_reg_read(cam, REG_TWSIC1); /* force write */ + rval = value | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR); + cafe_reg_write(cam, REG_TWSIC1, rval); + spin_unlock_irqrestore(&cam->dev_lock, flags); + msleep(2); /* Required or things flake */ + + wait_event_timeout(cam->smbus_wait, cafe_smbus_write_done(cam), + CAFE_SMBUS_TIMEOUT); + spin_lock_irqsave(&cam->dev_lock, flags); + rval = cafe_reg_read(cam, REG_TWSIC1); + spin_unlock_irqrestore(&cam->dev_lock, flags); + + if (rval & TWSIC1_WSTAT) { + cam_err(cam, "SMBUS write (%02x/%02x/%02x) timed out\n", addr, + command, value); + return -EIO; + } + if (rval & TWSIC1_ERROR) { + cam_err(cam, "SMBUS write (%02x/%02x/%02x) error\n", addr, + command, value); + return -EIO; + } + return 0; +} + + + +static int cafe_smbus_read_done(struct cafe_camera *cam) +{ + unsigned long flags; + int c1; + + /* + * We must delay after the interrupt, or the controller gets confused + * and never does give us good status. Fortunately, we don't do this + * often. + */ + udelay(20); + spin_lock_irqsave(&cam->dev_lock, flags); + c1 = cafe_reg_read(cam, REG_TWSIC1); + spin_unlock_irqrestore(&cam->dev_lock, flags); + return c1 & (TWSIC1_RVALID|TWSIC1_ERROR); +} + + + +static int cafe_smbus_read_data(struct cafe_camera *cam, + u16 addr, u8 command, u8 *value) +{ + unsigned int rval; + unsigned long flags; + + spin_lock_irqsave(&cam->dev_lock, flags); + rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID); + rval |= TWSIC0_OVMAGIC; /* Make OV sensors work */ + /* + * Marvel sez set clkdiv to all 1's for now. + */ + rval |= TWSIC0_CLKDIV; + cafe_reg_write(cam, REG_TWSIC0, rval); + (void) cafe_reg_read(cam, REG_TWSIC1); /* force write */ + rval = TWSIC1_READ | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR); + cafe_reg_write(cam, REG_TWSIC1, rval); + spin_unlock_irqrestore(&cam->dev_lock, flags); + + wait_event_timeout(cam->smbus_wait, + cafe_smbus_read_done(cam), CAFE_SMBUS_TIMEOUT); + spin_lock_irqsave(&cam->dev_lock, flags); + rval = cafe_reg_read(cam, REG_TWSIC1); + spin_unlock_irqrestore(&cam->dev_lock, flags); + + if (rval & TWSIC1_ERROR) { + cam_err(cam, "SMBUS read (%02x/%02x) error\n", addr, command); + return -EIO; + } + if (! (rval & TWSIC1_RVALID)) { + cam_err(cam, "SMBUS read (%02x/%02x) timed out\n", addr, + command); + return -EIO; + } + *value = rval & 0xff; + return 0; +} + +/* + * Perform a transfer over SMBUS. This thing is called under + * the i2c bus lock, so we shouldn't race with ourselves... + */ +static int cafe_smbus_xfer(struct i2c_adapter *adapter, u16 addr, + unsigned short flags, char rw, u8 command, + int size, union i2c_smbus_data *data) +{ + struct cafe_camera *cam = i2c_get_adapdata(adapter); + int ret = -EINVAL; + + /* + * Refuse to talk to anything but OV cam chips. We should + * never even see an attempt to do so, but one never knows. + */ + if (cam->sensor && addr != cam->sensor->addr) { + cam_err(cam, "funky smbus addr %d\n", addr); + return -EINVAL; + } + /* + * This interface would appear to only do byte data ops. OK + * it can do word too, but the cam chip has no use for that. + */ + if (size != I2C_SMBUS_BYTE_DATA) { + cam_err(cam, "funky xfer size %d\n", size); + return -EINVAL; + } + + if (rw == I2C_SMBUS_WRITE) + ret = cafe_smbus_write_data(cam, addr, command, data->byte); + else if (rw == I2C_SMBUS_READ) + ret = cafe_smbus_read_data(cam, addr, command, &data->byte); + return ret; +} + + +static void cafe_smbus_enable_irq(struct cafe_camera *cam) +{ + unsigned long flags; + + spin_lock_irqsave(&cam->dev_lock, flags); + cafe_reg_set_bit(cam, REG_IRQMASK, TWSIIRQS); + spin_unlock_irqrestore(&cam->dev_lock, flags); +} + +static u32 cafe_smbus_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_SMBUS_READ_BYTE_DATA | + I2C_FUNC_SMBUS_WRITE_BYTE_DATA; +} + +static struct i2c_algorithm cafe_smbus_algo = { + .smbus_xfer = cafe_smbus_xfer, + .functionality = cafe_smbus_func +}; + +/* Somebody is on the bus */ +static int cafe_cam_init(struct cafe_camera *cam); + +static int cafe_smbus_attach(struct i2c_client *client) +{ + struct cafe_camera *cam = i2c_get_adapdata(client->adapter); + + /* + * Don't talk to chips we don't recognize. + */ + cam_err(cam, "smbus_attach id = %d\n", client->driver->id); + if (client->driver->id == I2C_DRIVERID_OV7670) { + cam->sensor = client; + return cafe_cam_init(cam); + } + return -EINVAL; +} + +static int cafe_smbus_detach(struct i2c_client *client) +{ + struct cafe_camera *cam = i2c_get_adapdata(client->adapter); + + if (cam->sensor == client) + cam->sensor = NULL; /* Bummer, no camera */ + return 0; +} + +static int cafe_smbus_setup(struct cafe_camera *cam) +{ + struct i2c_adapter *adap = &cam->i2c_adapter; + int ret; + + cafe_smbus_enable_irq(cam); + adap->id = I2C_HW_SMBUS_CAFE; + adap->class = I2C_CLASS_CAM_DIGITAL; + adap->owner = THIS_MODULE; + adap->client_register = cafe_smbus_attach; + adap->client_unregister = cafe_smbus_detach; + adap->algo = &cafe_smbus_algo; + strcpy(adap->name, "cafe_ccic"); + i2c_set_adapdata(adap, cam); + ret = i2c_add_adapter(adap); + if (ret) + printk(KERN_ERR "Unable to register cafe i2c adapter\n"); + return ret; +} + +static void cafe_smbus_shutdown(struct cafe_camera *cam) +{ + i2c_del_adapter(&cam->i2c_adapter); +} + + +/* ------------------------------------------------------------------- */ +/* + * Deal with the controller. + */ + +/* + * Do everything we think we need to have the interface operating + * according to the desired format. + */ +static void cafe_ctlr_dma(struct cafe_camera *cam) +{ + /* + * Store the first two Y buffers (we aren't supporting + * planar formats for now, so no UV bufs). Then either + * set the third if it exists, or tell the controller + * to just use two. + */ + cafe_reg_write(cam, REG_Y0BAR, cam->dma_handles[0]); + cafe_reg_write(cam, REG_Y1BAR, cam->dma_handles[1]); + if (cam->nbufs > 2) { + cafe_reg_write(cam, REG_Y2BAR, cam->dma_handles[2]); + cafe_reg_clear_bit(cam, REG_CTRL1, C1_TWOBUFS); + } + else + cafe_reg_set_bit(cam, REG_CTRL1, C1_TWOBUFS); + cafe_reg_write(cam, REG_UBAR, 0); /* 32 bits only for now */ +} + +static void cafe_ctlr_image(struct cafe_camera *cam) +{ + int imgsz; + struct v4l2_pix_format *fmt = &cam->pix_format; + + imgsz = ((fmt->height << IMGSZ_V_SHIFT) & IMGSZ_V_MASK) | + (fmt->bytesperline & IMGSZ_H_MASK); + cafe_reg_write(cam, REG_IMGSIZE, imgsz); + cafe_reg_write(cam, REG_IMGOFFSET, 0); + /* YPITCH just drops the last two bits */ + cafe_reg_write_mask(cam, REG_IMGPITCH, fmt->bytesperline, + IMGP_YP_MASK); + /* + * Tell the controller about the image format we are using. + */ + switch (cam->pix_format.pixelformat) { + case V4L2_PIX_FMT_YUYV: + cafe_reg_write_mask(cam, REG_CTRL0, + C0_DF_YUV|C0_YUV_PACKED|C0_YUVE_YUYV, + C0_DF_MASK); + break; + + /* + * For "fake rgb32" get the image pitch right. + */ + case V4L2_PIX_FMT_RGB32: + cafe_reg_write_mask(cam, REG_IMGPITCH, fmt->bytesperline/2, + IMGP_YP_MASK); + imgsz = ((fmt->height << IMGSZ_V_SHIFT) & IMGSZ_V_MASK) | + ((fmt->bytesperline/2) & IMGSZ_H_MASK); + cafe_reg_write(cam, REG_IMGSIZE, imgsz); + /* fall into ... */ + case V4L2_PIX_FMT_RGB444: + cafe_reg_write_mask(cam, REG_CTRL0, + C0_DF_RGB|C0_RGBF_444|C0_RGB4_XRGB, + C0_DF_MASK); + /* Alpha value? */ + break; + + case V4L2_PIX_FMT_RGB565: + cafe_reg_write_mask(cam, REG_CTRL0, + C0_DF_RGB|C0_RGBF_565|C0_RGB5_BGGR, + C0_DF_MASK); + break; + + default: + cam_err(cam, "Unknown format %x\n", cam->pix_format.pixelformat); + break; + } + /* + * Make sure it knows we want to use hsync/vsync. + */ + cafe_reg_write_mask(cam, REG_CTRL0, C0_SIF_HVSYNC, + C0_SIFM_MASK); +} + + +/* + * Configure the controller for operation; caller holds the + * device mutex. + */ +static int cafe_ctlr_configure(struct cafe_camera *cam) +{ + unsigned long flags; + + spin_lock_irqsave(&cam->dev_lock, flags); + cafe_ctlr_dma(cam); + cafe_ctlr_image(cam); + cafe_set_config_needed(cam, 0); + spin_unlock_irqrestore(&cam->dev_lock, flags); + return 0; +} + +static void cafe_ctlr_irq_enable(struct cafe_camera *cam) +{ + /* + * Clear any pending interrupts, since we do not + * expect to have I/O active prior to enabling. + */ + cafe_reg_write(cam, REG_IRQSTAT, FRAMEIRQS); + cafe_reg_set_bit(cam, REG_IRQMASK, FRAMEIRQS); +} + +static void cafe_ctlr_irq_disable(struct cafe_camera *cam) +{ + cafe_reg_clear_bit(cam, REG_IRQMASK, FRAMEIRQS); +} + +/* + * Make the controller start grabbing images. Everything must + * be set up before doing this. + */ +static void cafe_ctlr_start(struct cafe_camera *cam) +{ + /* set_bit performs a read, so no other barrier should be + needed here */ + cafe_reg_set_bit(cam, REG_CTRL0, C0_ENABLE); +} + +static void cafe_ctlr_stop(struct cafe_camera *cam) +{ + cafe_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE); +} + +static void cafe_ctlr_init(struct cafe_camera *cam) +{ + unsigned long flags; + + spin_lock_irqsave(&cam->dev_lock, flags); + /* + * Added magic to bring up the hardware on the B-Test board + */ + cafe_reg_write(cam, 0x3038, 0x8); + cafe_reg_write(cam, 0x315c, 0x80008); + /* + * Go through the dance needed to wake the device up. + * Note that these registers are global and shared + * with the NAND and SD devices. Interaction between the + * three still needs to be examined. + */ + cafe_reg_write(cam, REG_GL_CSR, GCSR_SRS|GCSR_MRS); /* Needed? */ + cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRC); + cafe_reg_write(cam, REG_GL_CSR, GCSR_SRC|GCSR_MRS); + mdelay(5); /* FIXME revisit this */ + cafe_reg_write(cam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC); + cafe_reg_set_bit(cam, REG_GL_IMASK, GIMSK_CCIC_EN); + /* + * Make sure it's not powered down. + */ + cafe_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN); + /* + * Turn off the enable bit. It sure should be off anyway, + * but it's good to be sure. + */ + cafe_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE); + /* + * Mask all interrupts. + */ + cafe_reg_write(cam, REG_IRQMASK, 0); + /* + * Clock the sensor appropriately. Controller clock should + * be 48MHz, sensor "typical" value is half that. + */ + cafe_reg_write_mask(cam, REG_CLKCTRL, 2, CLK_DIV_MASK); + spin_unlock_irqrestore(&cam->dev_lock, flags); +} + + +/* + * Stop the controller, and don't return until we're really sure that no + * further DMA is going on. + */ +static void cafe_ctlr_stop_dma(struct cafe_camera *cam) +{ + unsigned long flags; + + /* + * Theory: stop the camera controller (whether it is operating + * or not). Delay briefly just in case we race with the SOF + * interrupt, then wait until no DMA is active. + */ + spin_lock_irqsave(&cam->dev_lock, flags); + cafe_ctlr_stop(cam); + spin_unlock_irqrestore(&cam->dev_lock, flags); + mdelay(1); + wait_event_timeout(cam->iowait, + !test_bit(CF_DMA_ACTIVE, &cam->flags), HZ); + if (test_bit(CF_DMA_ACTIVE, &cam->flags)) + cam_err(cam, "Timeout waiting for DMA to end\n"); + /* This would be bad news - what now? */ + spin_lock_irqsave(&cam->dev_lock, flags); + cam->state = S_IDLE; + cafe_ctlr_irq_disable(cam); + spin_unlock_irqrestore(&cam->dev_lock, flags); +} + +/* + * Power up and down. + */ +static void cafe_ctlr_power_up(struct cafe_camera *cam) +{ + unsigned long flags; + + spin_lock_irqsave(&cam->dev_lock, flags); + cafe_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN); + /* + * Put the sensor into operational mode (assumes OLPC-style + * wiring). Control 0 is reset - set to 1 to operate. + * Control 1 is power down, set to 0 to operate. + */ + cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C1); + mdelay(1); /* Marvell says 1ms will do it */ + cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0); + mdelay(1); /* Enough? */ + spin_unlock_irqrestore(&cam->dev_lock, flags); +} + +static void cafe_ctlr_power_down(struct cafe_camera *cam) +{ + unsigned long flags; + + spin_lock_irqsave(&cam->dev_lock, flags); + cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C1); + cafe_reg_set_bit(cam, REG_CTRL1, C1_PWRDWN); + spin_unlock_irqrestore(&cam->dev_lock, flags); +} + +/* -------------------------------------------------------------------- */ +/* + * Communications with the sensor. + */ + +static int __cafe_cam_cmd(struct cafe_camera *cam, int cmd, void *arg) +{ + struct i2c_client *sc = cam->sensor; + int ret; + + if (sc == NULL || sc->driver == NULL || sc->driver->command == NULL) + return -EINVAL; + ret = sc->driver->command(sc, cmd, arg); + if (ret == -EPERM) /* Unsupported command */ + return 0; + return ret; +} + +static int __cafe_cam_reset(struct cafe_camera *cam) +{ + int zero = 0; + return __cafe_cam_cmd(cam, VIDIOC_INT_RESET, &zero); +} + +/* + * We have found the sensor on the i2c. Let's try to have a + * conversation. + */ +static int cafe_cam_init(struct cafe_camera *cam) +{ + int ret; + + mutex_lock(&cam->s_mutex); + if (cam->state != S_NOTREADY) + cam_warn(cam, "Cam init with device in funky state %d", + cam->state); + ret = __cafe_cam_reset(cam); + if (ret) + goto out; + ret = __cafe_cam_cmd(cam, VIDIOC_INT_G_CHIP_IDENT, &cam->sensor_type); + if (ret) + goto out; +// if (cam->sensor->addr != OV7xx0_SID) { + if (cam->sensor_type != V4L2_IDENT_OV7670) { + cam_err(cam, "Unsupported sensor type %d", cam->sensor->addr); + ret = -EINVAL; + goto out; + } +/* Get/set parameters? */ + ret = 0; + cam->state = S_IDLE; + out: + mutex_unlock(&cam->s_mutex); + return ret; +} + +/* + * Configure the sensor to match the parameters we have. Caller should + * hold s_mutex + */ +static int cafe_cam_set_flip(struct cafe_camera *cam) +{ + struct v4l2_control ctrl; + + memset(&ctrl, 0, sizeof(ctrl)); + ctrl.id = V4L2_CID_VFLIP; + ctrl.value = flip; + return __cafe_cam_cmd(cam, VIDIOC_S_CTRL, &ctrl); +} + + +static int cafe_cam_configure(struct cafe_camera *cam) +{ + struct v4l2_format fmt; + int ret, zero = 0; + + if (cam->state != S_IDLE) + return -EINVAL; + fmt.fmt.pix = cam->pix_format; + ret = __cafe_cam_cmd(cam, VIDIOC_INT_INIT, &zero); + if (ret == 0) + ret = __cafe_cam_cmd(cam, VIDIOC_S_FMT, &fmt); + /* + * OV7670 does weird things if flip is set *before* format... + */ + ret += cafe_cam_set_flip(cam); + return ret; +} + +/* -------------------------------------------------------------------- */ +/* + * DMA buffer management. These functions need s_mutex held. + */ + +/* FIXME: this is inefficient as hell, since dma_alloc_coherent just + * does a get_free_pages() call, and we waste a good chunk of an orderN + * allocation. Should try to allocate the whole set in one chunk. + */ +static int cafe_alloc_dma_bufs(struct cafe_camera *cam, int loadtime) +{ + int i; + + cafe_set_config_needed(cam, 1); + if (loadtime) + cam->dma_buf_size = dma_buf_size; + else { + cam->dma_buf_size = cam->pix_format.sizeimage; + if (cam->pix_format.pixelformat == V4L2_PIX_FMT_RGB32) + cam->dma_buf_size /= 2; + } + if (n_dma_bufs > 3) + n_dma_bufs = 3; + + cam->nbufs = 0; + for (i = 0; i < n_dma_bufs; i++) { + cam->dma_bufs[i] = dma_alloc_coherent(&cam->pdev->dev, + cam->dma_buf_size, cam->dma_handles + i, + GFP_KERNEL); + if (cam->dma_bufs[i] == NULL) { + cam_warn(cam, "Failed to allocate DMA buffer\n"); + break; + } + /* For debug, remove eventually */ + memset(cam->dma_bufs[i], 0xcc, cam->dma_buf_size); + (cam->nbufs)++; + } + + switch (cam->nbufs) { + case 1: + dma_free_coherent(&cam->pdev->dev, cam->dma_buf_size, + cam->dma_bufs[0], cam->dma_handles[0]); + cam->nbufs = 0; + case 0: + cam_err(cam, "Insufficient DMA buffers, cannot operate\n"); + return -ENOMEM; + + case 2: + if (n_dma_bufs > 2) + cam_warn(cam, "Will limp along with only 2 buffers\n"); + break; + } + return 0; +} + +static void cafe_free_dma_bufs(struct cafe_camera *cam) +{ + int i; + + for (i = 0; i < cam->nbufs; i++) { + dma_free_coherent(&cam->pdev->dev, cam->dma_buf_size, + cam->dma_bufs[i], cam->dma_handles[i]); + cam->dma_bufs[i] = NULL; + } + cam->nbufs = 0; +} + + + + + +/* ----------------------------------------------------------------------- */ +/* + * Here starts the V4L2 interface code. + */ + +/* + * Read an image from the device. + */ +static ssize_t cafe_deliver_buffer(struct cafe_camera *cam, + char __user *buffer, size_t len, loff_t *pos) +{ + int bufno; + unsigned long flags; + + spin_lock_irqsave(&cam->dev_lock, flags); + if (cam->next_buf < 0) { + cam_err(cam, "deliver_buffer: No next buffer\n"); + spin_unlock_irqrestore(&cam->dev_lock, flags); + return -EIO; + } + bufno = cam->next_buf; + clear_bit(bufno, &cam->flags); + if (++(cam->next_buf) >= cam->nbufs) + cam->next_buf = 0; + if (! test_bit(cam->next_buf, &cam->flags)) + cam->next_buf = -1; + cam->specframes = 0; + spin_unlock_irqrestore(&cam->dev_lock, flags); + + if (len > cam->pix_format.sizeimage) + len = cam->pix_format.sizeimage; + if (copy_to_user(buffer, cam->dma_bufs[bufno], len)) + return -EFAULT; + (*pos) += len; + return len; +} + +/* + * Get everything ready, and start grabbing frames. + */ +static int cafe_read_setup(struct cafe_camera *cam, enum cafe_state state) +{ + int ret; + unsigned long flags; + + /* + * Configuration. If we still don't have DMA buffers, + * make one last, desperate attempt. + */ + if (cam->nbufs == 0) + if (cafe_alloc_dma_bufs(cam, 0)) + return -ENOMEM; + + if (cafe_needs_config(cam)) { + cafe_cam_configure(cam); + ret = cafe_ctlr_configure(cam); + if (ret) + return ret; + } + + /* + * Turn it loose. + */ + spin_lock_irqsave(&cam->dev_lock, flags); + cafe_reset_buffers(cam); + cafe_ctlr_irq_enable(cam); + cam->state = state; + cafe_ctlr_start(cam); + spin_unlock_irqrestore(&cam->dev_lock, flags); + return 0; +} + + +static ssize_t cafe_v4l_read(struct file *filp, + char __user *buffer, size_t len, loff_t *pos) +{ + struct cafe_camera *cam = filp->private_data; + int ret; + + /* + * Perhaps we're in speculative read mode and already + * have data? + */ + mutex_lock(&cam->s_mutex); + if (cam->state == S_SPECREAD) { + if (cam->next_buf >= 0) { + ret = cafe_deliver_buffer(cam, buffer, len, pos); + if (ret != 0) + goto out_unlock; + } + } else if (cam->state == S_FLAKED || cam->state == S_NOTREADY) { + ret = -EIO; + goto out_unlock; + } else if (cam->state != S_IDLE) { + ret = -EBUSY; + goto out_unlock; + } + + /* + * v4l2: multiple processes can open the device, but only + * one gets to grab data from it. + */ + if (cam->owner && cam->owner != filp) { + ret = -EBUSY; + goto out_unlock; + } + cam->owner = filp; + + /* + * Do setup if need be. + */ + if (cam->state != S_SPECREAD) { + ret = cafe_read_setup(cam, S_SINGLEREAD); + if (ret) + goto out_unlock; + } + /* + * Wait for something to happen. This should probably + * be interruptible (FIXME). + */ + wait_event_timeout(cam->iowait, cam->next_buf >= 0, HZ); + if (cam->next_buf < 0) { + cam_err(cam, "read() operation timed out\n"); + cafe_ctlr_stop_dma(cam); + ret = -EIO; + goto out_unlock; + } + /* + * Give them their data and we should be done. + */ + ret = cafe_deliver_buffer(cam, buffer, len, pos); + + out_unlock: + mutex_unlock(&cam->s_mutex); + return ret; +} + + + + + + + + +/* + * Streaming I/O support. + */ + + + +static int cafe_vidioc_streamon(struct file *filp, void *priv, + enum v4l2_buf_type type) +{ + struct cafe_camera *cam = filp->private_data; + int ret = -EINVAL; + + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + goto out; + mutex_lock(&cam->s_mutex); + if (cam->state != S_IDLE || cam->n_sbufs == 0) + goto out_unlock; + + cam->sequence = 0; + ret = cafe_read_setup(cam, S_STREAMING); + + out_unlock: + mutex_unlock(&cam->s_mutex); + out: + return ret; +} + + +static int cafe_vidioc_streamoff(struct file *filp, void *priv, + enum v4l2_buf_type type) +{ + struct cafe_camera *cam = filp->private_data; + int ret = -EINVAL; + + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + goto out; + mutex_lock(&cam->s_mutex); + if (cam->state != S_STREAMING) + goto out_unlock; + + cafe_ctlr_stop_dma(cam); + ret = 0; + + out_unlock: + mutex_unlock(&cam->s_mutex); + out: + return ret; +} + + + +static int cafe_setup_siobuf(struct cafe_camera *cam, int index) +{ + struct cafe_sio_buffer *buf = cam->sb_bufs + index; + + INIT_LIST_HEAD(&buf->list); + buf->v4lbuf.length = PAGE_ALIGN(cam->pix_format.sizeimage); + buf->buffer = vmalloc_user(buf->v4lbuf.length); + if (buf->buffer == NULL) + return -ENOMEM; + buf->mapcount = 0; + buf->cam = cam; + + buf->v4lbuf.index = index; + buf->v4lbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf->v4lbuf.field = V4L2_FIELD_NONE; + buf->v4lbuf.memory = V4L2_MEMORY_MMAP; + /* + * Offset: must be 32-bit even on a 64-bit system. video-buf + * just uses the length times the index, but the spec warns + * against doing just that - vma merging problems. So we + * leave a gap between each pair of buffers. + */ + buf->v4lbuf.m.offset = 2*index*buf->v4lbuf.length; + return 0; +} + +static int cafe_free_sio_buffers(struct cafe_camera *cam) +{ + int i; + + /* + * If any buffers are mapped, we cannot free them at all. + */ + for (i = 0; i < cam->n_sbufs; i++) + if (cam->sb_bufs[i].mapcount > 0) + return -EBUSY; + /* + * OK, let's do it. + */ + for (i = 0; i < cam->n_sbufs; i++) + vfree(cam->sb_bufs[i].buffer); + cam->n_sbufs = 0; + kfree(cam->sb_bufs); + cam->sb_bufs = NULL; + INIT_LIST_HEAD(&cam->sb_avail); + INIT_LIST_HEAD(&cam->sb_full); + return 0; +} + + + +static int cafe_vidioc_reqbufs(struct file *filp, void *priv, + struct v4l2_requestbuffers *req) +{ + struct cafe_camera *cam = filp->private_data; + int ret; + + /* + * Make sure it's something we can do. User pointers could be + * implemented without great pain, but that's not been done yet. + */ + if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (req->memory != V4L2_MEMORY_MMAP) + return -EINVAL; + /* + * If they ask for zero buffers, they really want us to stop streaming + * (if it's happening) and free everything. Should we check owner? + */ + mutex_lock(&cam->s_mutex); + if (req->count == 0) { + if (cam->state == S_STREAMING) + cafe_ctlr_stop_dma(cam); + ret = cafe_free_sio_buffers (cam); + goto out; + } + /* + * Device needs to be idle and working. We *could* try to do the + * right thing in S_SPECREAD by shutting things down, but it + * probably doesn't matter. + */ + if (cam->state != S_IDLE || (cam->owner && cam->owner != filp)) { + ret = -EBUSY; + goto out; + } + cam->owner = filp; + + if (req->count < min_buffers) + req->count = min_buffers; + else if (req->count > max_buffers) + req->count = max_buffers; + if (cam->n_sbufs > 0) { + ret = cafe_free_sio_buffers(cam); + if (ret) + goto out; + } + + cam->sb_bufs = kzalloc(req->count*sizeof(struct cafe_sio_buffer), + GFP_KERNEL); + if (cam->sb_bufs == NULL) { + ret = -ENOMEM; + goto out; + } + for (cam->n_sbufs = 0; cam->n_sbufs < req->count; (cam->n_sbufs++)) { + ret = cafe_setup_siobuf(cam, cam->n_sbufs); + if (ret) + break; + } + + if (cam->n_sbufs == 0) /* no luck at all - ret already set */ + kfree(cam->sb_bufs); + else + ret = 0; + req->count = cam->n_sbufs; /* In case of partial success */ + + out: + mutex_unlock(&cam->s_mutex); + return ret; +} + + +static int cafe_vidioc_querybuf(struct file *filp, void *priv, + struct v4l2_buffer *buf) +{ + struct cafe_camera *cam = filp->private_data; + int ret = -EINVAL; + + mutex_lock(&cam->s_mutex); + if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + goto out; + if (buf->index < 0 || buf->index >= cam->n_sbufs) + goto out; + *buf = cam->sb_bufs[buf->index].v4lbuf; + ret = 0; + out: + mutex_unlock(&cam->s_mutex); + return ret; +} + +static int cafe_vidioc_qbuf(struct file *filp, void *priv, + struct v4l2_buffer *buf) +{ + struct cafe_camera *cam = filp->private_data; + struct cafe_sio_buffer *sbuf; + int ret = -EINVAL; + unsigned long flags; + + mutex_lock(&cam->s_mutex); + if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + goto out; + if (buf->index < 0 || buf->index >= cam->n_sbufs) + goto out; + sbuf = cam->sb_bufs + buf->index; + if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED) { + ret = 0; /* Already queued?? */ + goto out; + } + if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_DONE) { + /* Spec doesn't say anything, seems appropriate tho */ + ret = -EBUSY; + goto out; + } + sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_QUEUED; + spin_lock_irqsave(&cam->dev_lock, flags); + list_add(&sbuf->list, &cam->sb_avail); + spin_unlock_irqrestore(&cam->dev_lock, flags); + ret = 0; + out: + mutex_unlock(&cam->s_mutex); + return ret; +} + +static int cafe_vidioc_dqbuf(struct file *filp, void *priv, + struct v4l2_buffer *buf) +{ + struct cafe_camera *cam = filp->private_data; + struct cafe_sio_buffer *sbuf; + int ret = -EINVAL; + unsigned long flags; + + mutex_lock(&cam->s_mutex); + if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + goto out_unlock; + if (cam->state != S_STREAMING) + goto out_unlock; + if (list_empty(&cam->sb_full) && filp->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + goto out_unlock; + } + + while (list_empty(&cam->sb_full) && cam->state == S_STREAMING) { + mutex_unlock(&cam->s_mutex); + if (wait_event_interruptible(cam->iowait, + !list_empty(&cam->sb_full))) { + ret = -ERESTARTSYS; + goto out; + } + mutex_lock(&cam->s_mutex); + } + + if (cam->state != S_STREAMING) + ret = -EINTR; + else { + spin_lock_irqsave(&cam->dev_lock, flags); + /* Should probably recheck !list_empty() here */ + sbuf = list_entry(cam->sb_full.next, + struct cafe_sio_buffer, list); + list_del_init(&sbuf->list); + spin_unlock_irqrestore(&cam->dev_lock, flags); + sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE; + *buf = sbuf->v4lbuf; + ret = 0; + } + + out_unlock: + mutex_unlock(&cam->s_mutex); + out: + return ret; +} + + + +static void cafe_v4l_vm_open(struct vm_area_struct *vma) +{ + struct cafe_sio_buffer *sbuf = vma->vm_private_data; + /* + * Locking: done under mmap_sem, so we don't need to + * go back to the camera lock here. + */ + sbuf->mapcount++; +} + + +static void cafe_v4l_vm_close(struct vm_area_struct *vma) +{ + struct cafe_sio_buffer *sbuf = vma->vm_private_data; + + mutex_lock(&sbuf->cam->s_mutex); + sbuf->mapcount--; + /* Docs say we should stop I/O too... */ + if (sbuf->mapcount == 0) + sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_MAPPED; + mutex_unlock(&sbuf->cam->s_mutex); +} + +static struct vm_operations_struct cafe_v4l_vm_ops = { + .open = cafe_v4l_vm_open, + .close = cafe_v4l_vm_close +}; + + +static int cafe_v4l_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct cafe_camera *cam = filp->private_data; + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + int ret = -EINVAL; + int i; + struct cafe_sio_buffer *sbuf = NULL; + + if (! (vma->vm_flags & VM_WRITE) || ! (vma->vm_flags & VM_SHARED)) + return -EINVAL; + /* + * Find the buffer they are looking for. + */ + mutex_lock(&cam->s_mutex); + for (i = 0; i < cam->n_sbufs; i++) + if (cam->sb_bufs[i].v4lbuf.m.offset == offset) { + sbuf = cam->sb_bufs + i; + break; + } + if (sbuf == NULL) + goto out; + + ret = remap_vmalloc_range(vma, sbuf->buffer, 0); + if (ret) + goto out; + vma->vm_flags |= VM_DONTEXPAND; + vma->vm_private_data = sbuf; + vma->vm_ops = &cafe_v4l_vm_ops; + sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_MAPPED; + cafe_v4l_vm_open(vma); + ret = 0; + out: + mutex_unlock(&cam->s_mutex); + return ret; +} + + + +static int cafe_v4l_open(struct inode *inode, struct file *filp) +{ + struct cafe_camera *cam; + + cam = cafe_find_dev(iminor(inode)); + if (cam == NULL) + return -ENODEV; + filp->private_data = cam; + + mutex_lock(&cam->s_mutex); + if (cam->users == 0) { + cafe_ctlr_power_up(cam); + __cafe_cam_reset(cam); + cafe_set_config_needed(cam, 1); + /* FIXME make sure this is complete */ + } + (cam->users)++; + mutex_unlock(&cam->s_mutex); + return 0; +} + + +static int cafe_v4l_release(struct inode *inode, struct file *filp) +{ + struct cafe_camera *cam = filp->private_data; + + mutex_lock(&cam->s_mutex); + (cam->users)--; + if (filp == cam->owner) { + cafe_ctlr_stop_dma(cam); + cafe_free_sio_buffers(cam); + cam->owner = NULL; + } + if (cam->users == 0) + cafe_ctlr_power_down(cam); + mutex_unlock(&cam->s_mutex); + return 0; +} + + + +static unsigned int cafe_v4l_poll(struct file *filp, + struct poll_table_struct *pt) +{ + struct cafe_camera *cam = filp->private_data; + + poll_wait(filp, &cam->iowait, pt); + if (cam->next_buf >= 0) + return POLLIN | POLLRDNORM; + return 0; +} + + + +static int cafe_vidioc_queryctrl(struct file *filp, void *priv, + struct v4l2_queryctrl *qc) +{ + struct cafe_camera *cam = filp->private_data; + int ret; + + mutex_lock(&cam->s_mutex); + ret = __cafe_cam_cmd(cam, VIDIOC_QUERYCTRL, qc); + mutex_unlock(&cam->s_mutex); + return ret; +} + + +static int cafe_vidioc_g_ctrl(struct file *filp, void *priv, + struct v4l2_control *ctrl) +{ + struct cafe_camera *cam = filp->private_data; + int ret; + + mutex_lock(&cam->s_mutex); + ret = __cafe_cam_cmd(cam, VIDIOC_G_CTRL, ctrl); + mutex_unlock(&cam->s_mutex); + return ret; +} + + +static int cafe_vidioc_s_ctrl(struct file *filp, void *priv, + struct v4l2_control *ctrl) +{ + struct cafe_camera *cam = filp->private_data; + int ret; + + mutex_lock(&cam->s_mutex); + ret = __cafe_cam_cmd(cam, VIDIOC_S_CTRL, ctrl); + mutex_unlock(&cam->s_mutex); + return ret; +} + + + + + +static int cafe_vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strcpy(cap->driver, "cafe_ccic"); + strcpy(cap->card, "cafe_ccic"); + cap->version = CAFE_VERSION; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + return 0; +} + + +/* + * The default format we use until somebody says otherwise. + */ +static struct v4l2_pix_format cafe_def_pix_format = { + .width = VGA_WIDTH, + .height = VGA_HEIGHT, + .pixelformat = V4L2_PIX_FMT_YUYV, + .field = V4L2_FIELD_NONE, + .bytesperline = VGA_WIDTH*2, + .sizeimage = VGA_WIDTH*VGA_HEIGHT*2, +}; + +static int cafe_vidioc_enum_fmt_cap(struct file *filp, + void *priv, struct v4l2_fmtdesc *fmt) +{ + struct cafe_camera *cam = priv; + int ret; + + if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + mutex_lock(&cam->s_mutex); + ret = __cafe_cam_cmd(cam, VIDIOC_ENUM_FMT, fmt); + mutex_unlock(&cam->s_mutex); + return ret; +} + + +static int cafe_vidioc_try_fmt_cap (struct file *filp, void *priv, + struct v4l2_format *fmt) +{ + struct cafe_camera *cam = priv; + int ret; + + mutex_lock(&cam->s_mutex); + ret = __cafe_cam_cmd(cam, VIDIOC_TRY_FMT, fmt); + mutex_unlock(&cam->s_mutex); + return ret; +} + +static int cafe_vidioc_s_fmt_cap(struct file *filp, void *priv, + struct v4l2_format *fmt) +{ + struct cafe_camera *cam = priv; + int ret; + + /* + * Can't do anything if the device is not idle + * Also can't if there are streaming buffers in place. + */ + if (cam->state != S_IDLE || cam->n_sbufs > 0) + return -EBUSY; + /* + * See if the formatting works in principle. + */ + ret = cafe_vidioc_try_fmt_cap(filp, priv, fmt); + if (ret) + return ret; + /* + * Now we start to change things for real, so let's do it + * under lock. + */ + mutex_lock(&cam->s_mutex); + cam->pix_format = fmt->fmt.pix; + /* + * Make sure we have appropriate DMA buffers. + */ + ret = -ENOMEM; + if (cam->nbufs > 0 && cam->dma_buf_size < cam->pix_format.sizeimage) + cafe_free_dma_bufs(cam); + if (cam->nbufs == 0) { + if (cafe_alloc_dma_bufs(cam, 0)) + goto out; + } + /* + * It looks like this might work, so let's program the sensor. + */ + ret = cafe_cam_configure(cam); + if (! ret) + ret = cafe_ctlr_configure(cam); + out: + mutex_unlock(&cam->s_mutex); + return ret; +} + +/* + * Return our stored notion of how the camera is/should be configured. + * The V4l2 spec wants us to be smarter, and actually get this from + * the camera (and not mess with it at open time). Someday. + */ +static int cafe_vidioc_g_fmt_cap(struct file *filp, void *priv, + struct v4l2_format *f) +{ + struct cafe_camera *cam = priv; + + f->fmt.pix = cam->pix_format; + return 0; +} + +/* + * We only have one input - the sensor - so minimize the nonsense here. + */ +static int cafe_vidioc_enum_input(struct file *filp, void *priv, + struct v4l2_input *input) +{ + if (input->index != 0) + return -EINVAL; + + input->type = V4L2_INPUT_TYPE_CAMERA; + input->std = V4L2_STD_ALL; /* Not sure what should go here */ + strcpy(input->name, "Camera"); + return 0; +} + +static int cafe_vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int cafe_vidioc_s_input(struct file *filp, void *priv, unsigned int i) +{ + if (i != 0) + return -EINVAL; + return 0; +} + +/* from vivi.c */ +static int cafe_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id a) +{ + return 0; +} + + +/* + * The TV Norm stuff is weird - we're a camera with little to do with TV, + * really. The following is what vivi does. + */ +static struct v4l2_tvnorm cafe_tvnorm[] = { + { + .name = "NTSC-M", + .id = V4L2_STD_NTSC_M, + } +}; + + +void cafe_v4l_dev_release(struct video_device *vd) +{ + struct cafe_camera *cam = container_of(vd, struct cafe_camera, v4ldev); + + kfree(cam); +} + + +/* + * This template device holds all of those v4l2 methods; we + * clone it for specific real devices. + */ + +static struct file_operations cafe_v4l_fops = { + .owner = THIS_MODULE, + .open = cafe_v4l_open, + .release = cafe_v4l_release, + .read = cafe_v4l_read, + .poll = cafe_v4l_poll, + .mmap = cafe_v4l_mmap, + .ioctl = video_ioctl2, + .llseek = no_llseek, +}; + +static struct video_device cafe_v4l_template = { + .name = "cafe", + .type = VFL_TYPE_GRABBER, + .type2 = VID_TYPE_CAPTURE, + .minor = -1, /* Get one dynamically */ + .tvnorms = cafe_tvnorm, + .tvnormsize = 1, + .current_norm = V4L2_STD_NTSC_M, /* make mplayer happy */ + + .fops = &cafe_v4l_fops, + .release = cafe_v4l_dev_release, + + .vidioc_querycap = cafe_vidioc_querycap, + .vidioc_enum_fmt_cap = cafe_vidioc_enum_fmt_cap, + .vidioc_try_fmt_cap = cafe_vidioc_try_fmt_cap, + .vidioc_s_fmt_cap = cafe_vidioc_s_fmt_cap, + .vidioc_g_fmt_cap = cafe_vidioc_g_fmt_cap, + .vidioc_enum_input = cafe_vidioc_enum_input, + .vidioc_g_input = cafe_vidioc_g_input, + .vidioc_s_input = cafe_vidioc_s_input, + .vidioc_s_std = cafe_vidioc_s_std, + .vidioc_reqbufs = cafe_vidioc_reqbufs, + .vidioc_querybuf = cafe_vidioc_querybuf, + .vidioc_qbuf = cafe_vidioc_qbuf, + .vidioc_dqbuf = cafe_vidioc_dqbuf, + .vidioc_streamon = cafe_vidioc_streamon, + .vidioc_streamoff = cafe_vidioc_streamoff, + .vidioc_queryctrl = cafe_vidioc_queryctrl, + .vidioc_g_ctrl = cafe_vidioc_g_ctrl, + .vidioc_s_ctrl = cafe_vidioc_s_ctrl, + /* Do cropping someday */ +}; + + + + + + + +/* ---------------------------------------------------------------------- */ +/* + * Interrupt handler stuff + */ + +/* + * Create RGB32 from RGB444 so it can be displayed before the applications + * know about the latter format. + */ +static void cafe_fake_rgb32(struct cafe_camera *cam, char *dest, char *src) +{ + int i; + u16 *ssrc = (u16 *) src; + + /* RGB444 version */ + for (i = 0; i < cam->pix_format.sizeimage; i += 4) { + // dest[0] = (*ssrc & 0xf000) >> 8; + dest[0] = (*ssrc & 0x000f) << 4; + dest[1] = (*ssrc & 0x00f0); + dest[2] = (*ssrc & 0x0f00) >> 4; + dest[3] = (*ssrc & 0xf000); /* Alpha */ + dest += 4; + ssrc++; + } +} + + +static void cafe_frame_tasklet(unsigned long data) +{ + struct cafe_camera *cam = (struct cafe_camera *) data; + int i; + unsigned long flags; + struct cafe_sio_buffer *sbuf; + + spin_lock_irqsave(&cam->dev_lock, flags); + for (i = 0; i < cam->nbufs; i++) { + int bufno = cam->next_buf; + if (bufno < 0) { /* "will never happen" */ + cam_err(cam, "No valid bufs in tasklet!\n"); + break; + } + if (++(cam->next_buf) >= cam->nbufs) + cam->next_buf = 0; + if (! test_bit(bufno, &cam->flags)) + continue; + if (list_empty(&cam->sb_avail)) + break; /* Leave it valid, hope for better later */ + clear_bit(bufno, &cam->flags); + /* + * We could perhaps drop the spinlock during this + * big copy. Something to consider. + */ + sbuf = list_entry(cam->sb_avail.next, + struct cafe_sio_buffer, list); + if (cam->pix_format.pixelformat == V4L2_PIX_FMT_RGB32) + cafe_fake_rgb32(cam, sbuf->buffer, cam->dma_bufs[bufno]); + else + memcpy(sbuf->buffer, cam->dma_bufs[bufno], + cam->pix_format.sizeimage); + sbuf->v4lbuf.bytesused = cam->pix_format.sizeimage; + sbuf->v4lbuf.sequence = cam->buf_seq[bufno]; + sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED; + sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE; + list_move_tail(&sbuf->list, &cam->sb_full); + } + if (! list_empty(&cam->sb_full)) + wake_up(&cam->iowait); + spin_unlock_irqrestore(&cam->dev_lock, flags); +} + + + +static void cafe_frame_complete(struct cafe_camera *cam, int frame) +{ + /* + * Basic frame housekeeping. + */ + if (test_bit(frame, &cam->flags) && printk_ratelimit()) + cam_err(cam, "Frame overrun on %d, frames lost\n", frame); + set_bit(frame, &cam->flags); + clear_bit(CF_DMA_ACTIVE, &cam->flags); + if (cam->next_buf < 0) + cam->next_buf = frame; + cam->buf_seq[frame] = ++(cam->sequence); + + switch (cam->state) { + /* + * If in single read mode, try going speculative. + */ + case S_SINGLEREAD: + cam->state = S_SPECREAD; + cam->specframes = 0; + wake_up(&cam->iowait); + break; + + /* + * If we are already doing speculative reads, and nobody is + * reading them, just stop. + */ + case S_SPECREAD: + if (++(cam->specframes) >= cam->nbufs) { + cafe_ctlr_stop(cam); + cafe_ctlr_irq_disable(cam); + cam->state = S_IDLE; + } + wake_up(&cam->iowait); + break; + /* + * For the streaming case, we defer the real work to the + * camera tasklet. + * + * FIXME: if the application is not consuming the buffers, + * we should eventually put things on hold and restart in + * vidioc_dqbuf(). + */ + case S_STREAMING: + tasklet_schedule(&cam->s_tasklet); + break; + + default: + cam_err(cam, "Frame interrupt in non-operational state\n"); + break; + } +} + + + + +static void cafe_frame_irq(struct cafe_camera *cam, unsigned int irqs) +{ + unsigned int frame; + + cafe_reg_write(cam, REG_IRQSTAT, FRAMEIRQS); /* Clear'em all */ + /* + * Handle any frame completions. There really should + * not be more than one of these, or we have fallen + * far behind. + */ + for (frame = 0; frame < cam->nbufs; frame++) + if (irqs & (IRQ_EOF0 << frame)) + cafe_frame_complete(cam, frame); + /* + * If a frame starts, note that we have DMA active. This + * code assumes that we won't get multiple frame interrupts + * at once; may want to rethink that. + */ + if (irqs & (IRQ_SOF0 | IRQ_SOF1 | IRQ_SOF2)) + set_bit(CF_DMA_ACTIVE, &cam->flags); +} + + + +static irqreturn_t cafe_irq(int irq, void *data) +{ + struct cafe_camera *cam = data; + unsigned int irqs; + + spin_lock(&cam->dev_lock); + irqs = cafe_reg_read(cam, REG_IRQSTAT); + if ((irqs & ALLIRQS) == 0) { + spin_unlock(&cam->dev_lock); + return IRQ_NONE; + } + if (irqs & FRAMEIRQS) + cafe_frame_irq(cam, irqs); + if (irqs & TWSIIRQS) { + cafe_reg_write(cam, REG_IRQSTAT, TWSIIRQS); + wake_up(&cam->smbus_wait); + } + spin_unlock(&cam->dev_lock); + return IRQ_HANDLED; +} + + +/* -------------------------------------------------------------------------- */ +#ifdef CONFIG_VIDEO_ADV_DEBUG +/* + * Debugfs stuff. + */ + +static char cafe_debug_buf[1024]; +static struct dentry *cafe_dfs_root; + +static void cafe_dfs_setup(void) +{ + cafe_dfs_root = debugfs_create_dir("cafe_ccic", NULL); + if (IS_ERR(cafe_dfs_root)) { + cafe_dfs_root = NULL; /* Never mind */ + printk(KERN_NOTICE "cafe_ccic unable to set up debugfs\n"); + } +} + +static void cafe_dfs_shutdown(void) +{ + if (cafe_dfs_root) + debugfs_remove(cafe_dfs_root); +} + +static int cafe_dfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t cafe_dfs_read_regs(struct file *file, + char __user *buf, size_t count, loff_t *ppos) +{ + struct cafe_camera *cam = file->private_data; + char *s = cafe_debug_buf; + int offset; + + for (offset = 0; offset < 0x44; offset += 4) + s += sprintf(s, "%02x: %08x\n", offset, + cafe_reg_read(cam, offset)); + for (offset = 0x88; offset <= 0x90; offset += 4) + s += sprintf(s, "%02x: %08x\n", offset, + cafe_reg_read(cam, offset)); + for (offset = 0xb4; offset <= 0xbc; offset += 4) + s += sprintf(s, "%02x: %08x\n", offset, + cafe_reg_read(cam, offset)); + for (offset = 0x3000; offset <= 0x300c; offset += 4) + s += sprintf(s, "%04x: %08x\n", offset, + cafe_reg_read(cam, offset)); + return simple_read_from_buffer(buf, count, ppos, cafe_debug_buf, + s - cafe_debug_buf); +} + +static struct file_operations cafe_dfs_reg_ops = { + .owner = THIS_MODULE, + .read = cafe_dfs_read_regs, + .open = cafe_dfs_open +}; + +static ssize_t cafe_dfs_read_cam(struct file *file, + char __user *buf, size_t count, loff_t *ppos) +{ + struct cafe_camera *cam = file->private_data; + char *s = cafe_debug_buf; + int offset; + + if (! cam->sensor) + return -EINVAL; + for (offset = 0x0; offset < 0x8a; offset++) + { + u8 v; + + cafe_smbus_read_data(cam, cam->sensor->addr, offset, &v); + s += sprintf(s, "%02x: %02x\n", offset, v); + } + return simple_read_from_buffer(buf, count, ppos, cafe_debug_buf, + s - cafe_debug_buf); +} + +static struct file_operations cafe_dfs_cam_ops = { + .owner = THIS_MODULE, + .read = cafe_dfs_read_cam, + .open = cafe_dfs_open +}; + + + +static void cafe_dfs_cam_setup(struct cafe_camera *cam) +{ + char fname[40]; + + if (!cafe_dfs_root) + return; + sprintf(fname, "regs-%d", cam->v4ldev.minor); + cam->dfs_regs = debugfs_create_file(fname, 0444, cafe_dfs_root, + cam, &cafe_dfs_reg_ops); + sprintf(fname, "cam-%d", cam->v4ldev.minor); + cam->dfs_cam_regs = debugfs_create_file(fname, 0444, cafe_dfs_root, + cam, &cafe_dfs_cam_ops); +} + + +static void cafe_dfs_cam_shutdown(struct cafe_camera *cam) +{ + if (! IS_ERR(cam->dfs_regs)) + debugfs_remove(cam->dfs_regs); + if (! IS_ERR(cam->dfs_cam_regs)) + debugfs_remove(cam->dfs_cam_regs); +} + +#else + +#define cafe_dfs_setup() +#define cafe_dfs_shutdown() +#define cafe_dfs_cam_setup(cam) +#define cafe_dfs_cam_shutdown(cam) +#endif /* CONFIG_VIDEO_ADV_DEBUG */ + + + + +/* ------------------------------------------------------------------------*/ +/* + * PCI interface stuff. + */ + +static int cafe_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int ret; + u16 classword; + struct cafe_camera *cam; + /* + * Make sure we have a camera here - we'll get calls for + * the other cafe devices as well. + */ + pci_read_config_word(pdev, PCI_CLASS_DEVICE, &classword); + if (classword != PCI_CLASS_MULTIMEDIA_VIDEO) + return -ENODEV; + /* + * Start putting together one of our big camera structures. + */ + ret = -ENOMEM; + cam = kzalloc(sizeof(struct cafe_camera), GFP_KERNEL); + if (cam == NULL) + goto out; + mutex_init(&cam->s_mutex); + mutex_lock(&cam->s_mutex); + spin_lock_init(&cam->dev_lock); + cam->state = S_NOTREADY; + cafe_set_config_needed(cam, 1); + init_waitqueue_head(&cam->smbus_wait); + init_waitqueue_head(&cam->iowait); + cam->pdev = pdev; + cam->pix_format = cafe_def_pix_format; + INIT_LIST_HEAD(&cam->dev_list); + INIT_LIST_HEAD(&cam->sb_avail); + INIT_LIST_HEAD(&cam->sb_full); + tasklet_init(&cam->s_tasklet, cafe_frame_tasklet, (unsigned long) cam); + /* + * Get set up on the PCI bus. + */ + ret = pci_enable_device(pdev); + if (ret) + goto out_free; + pci_set_master(pdev); + + ret = -EIO; + cam->regs = pci_iomap(pdev, 0, 0); + if (! cam->regs) { + printk(KERN_ERR "Unable to ioremap cafe-ccic regs\n"); + goto out_free; + } + ret = request_irq(pdev->irq, cafe_irq, IRQF_SHARED, "cafe-ccic", cam); + if (ret) + goto out_iounmap; + cafe_ctlr_init(cam); + cafe_ctlr_power_up(cam); + /* + * Set up I2C/SMBUS communications + */ + mutex_unlock(&cam->s_mutex); /* attach can deadlock */ + ret = cafe_smbus_setup(cam); + if (ret) + goto out_freeirq; + /* + * Get the v4l2 setup done. + */ + mutex_lock(&cam->s_mutex); + cam->v4ldev = cafe_v4l_template; + cam->v4ldev.debug = 0; +// cam->v4ldev.debug = V4L2_DEBUG_IOCTL_ARG; + ret = video_register_device(&cam->v4ldev, VFL_TYPE_GRABBER, -1); + if (ret) + goto out_smbus; + /* + * If so requested, try to get our DMA buffers now. + */ + if (alloc_bufs_at_load) { + if (cafe_alloc_dma_bufs(cam, 1)) + cam_warn(cam, "Unable to alloc DMA buffers at load" + " will try again later."); + } + + cafe_dfs_cam_setup(cam); + mutex_unlock(&cam->s_mutex); + cafe_add_dev(cam); + return 0; + + out_smbus: + cafe_smbus_shutdown(cam); + out_freeirq: + cafe_ctlr_power_down(cam); + free_irq(pdev->irq, cam); + out_iounmap: + pci_iounmap(pdev, cam->regs); + out_free: + kfree(cam); + out: + return ret; +} + + +/* + * Shut down an initialized device + */ +static void cafe_shutdown(struct cafe_camera *cam) +{ +/* FIXME: Make sure we take care of everything here */ + cafe_dfs_cam_shutdown(cam); + if (cam->n_sbufs > 0) + /* What if they are still mapped? Shouldn't be, but... */ + cafe_free_sio_buffers(cam); + cafe_remove_dev(cam); + cafe_ctlr_stop_dma(cam); + cafe_ctlr_power_down(cam); + cafe_smbus_shutdown(cam); + cafe_free_dma_bufs(cam); + free_irq(cam->pdev->irq, cam); + pci_iounmap(cam->pdev, cam->regs); + video_unregister_device(&cam->v4ldev); + /* kfree(cam); done in v4l_release () */ +} + + +static void cafe_pci_remove(struct pci_dev *pdev) +{ + struct cafe_camera *cam = cafe_find_by_pdev(pdev); + + if (cam == NULL) { + cam_warn(cam, "pci_remove on unknown pdev %p\n", pdev); + return; + } + mutex_lock(&cam->s_mutex); + if (cam->users > 0) + cam_warn(cam, "Removing a device with users!\n"); + cafe_shutdown(cam); +/* No unlock - it no longer exists */ +} + + + + +static struct pci_device_id cafe_ids[] = { + { PCI_DEVICE(0x1148, 0x4340) }, /* Temporary ID on devel board */ + { PCI_DEVICE(0x11ab, 0x4100) }, /* Eventual real ID */ + { PCI_DEVICE(0x11ab, 0x4102) }, /* Really eventual real ID */ + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, cafe_ids); + +static struct pci_driver cafe_pci_driver = { + .name = "cafe1000-ccic", + .id_table = cafe_ids, + .probe = cafe_pci_probe, + .remove = cafe_pci_remove, +}; + + + + +static int __init cafe_init(void) +{ + int ret; + + printk(KERN_NOTICE "Marvell M88ALP01 'CAFE' Camera Controller version %d\n", + CAFE_VERSION); + cafe_dfs_setup(); + ret = pci_register_driver(&cafe_pci_driver); + if (ret) { + printk(KERN_ERR "Unable to register cafe_ccic driver\n"); + goto out; + } + request_module("ov7670"); /* FIXME want something more general */ + ret = 0; + + out: + return ret; +} + + +static void __exit cafe_exit(void) +{ + pci_unregister_driver(&cafe_pci_driver); + cafe_dfs_shutdown(); +} + +module_init(cafe_init); +module_exit(cafe_exit); -- cgit v1.2.3 From 111f33564e19b2b5f70e3df9a8f92c08c1c91fd9 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Sat, 4 Nov 2006 09:26:00 -0300 Subject: V4L/DVB (4798): OmniVision OV7670 driver This patch adds a V4L2 driver for the OmniVision OV7670 camera. Signed-off-by: Jonathan Corbet Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 8 + drivers/media/video/Makefile | 1 + drivers/media/video/ov7670.c | 1002 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1011 insertions(+) create mode 100644 drivers/media/video/ov7670.c (limited to 'drivers/media/video') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 4ea1d0ebf5f..c95735cd688 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -184,6 +184,14 @@ config VIDEO_KS0127 To compile this driver as a module, choose M here: the module will be called ks0127. +config VIDEO_OV7670 + tristate "OmniVision OV7670 sensor support" + depends on I2C && VIDEO_V4L2 + ---help--- + This is a Video4Linux2 sensor-level driver for the OmniVision + OV7670 VGA camera. It currently only works with the M88ALP01 + controller. + config VIDEO_SAA7110 tristate "Philips SAA7110 video decoder" depends on VIDEO_V4L1 && I2C diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 8ff787a4cf6..2adb56d01ef 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -93,6 +93,7 @@ obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o +obj-$(CONFIG_VIDEO_OV7670) += ov7670.o obj-$(CONFIG_USB_DABUSB) += dabusb.o obj-$(CONFIG_USB_OV511) += ov511.o diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c new file mode 100644 index 00000000000..382aa83b73c --- /dev/null +++ b/drivers/media/video/ov7670.c @@ -0,0 +1,1002 @@ +/* + * A V4L2 driver for OmniVision OV7670 cameras. + * + * Copyright 2006 One Laptop Per Child Association, Inc. Written + * by Jonathan Corbet with substantial inspiration from Mark + * McClelland's ovcamchip code. + * + * This file may be distributed under the terms of the GNU General + * Public License, version 2. + */ +#include +#include +#include +#include +#include +#include +#include +#include + + +MODULE_AUTHOR("Jonathan Corbet 0) + *value = (unsigned char) ret; + return ret; +} + + +static int ov7670_write(struct i2c_client *c, unsigned char reg, + unsigned char value) +{ + return i2c_smbus_write_byte_data(c, reg, value); +} + + +/* + * Write a list of register settings; ff/ff stops the process. + */ +static int ov7670_write_array(struct i2c_client *c, struct regval_list *vals) +{ + while (vals->reg_num != 0xff || vals->value != 0xff) { + int ret = ov7670_write(c, vals->reg_num, vals->value); + if (ret < 0) + return ret; + vals++; + } + return 0; +} + + +/* + * Stuff that knows about the sensor. + */ +static void ov7670_reset(struct i2c_client *client) +{ + ov7670_write(client, REG_COM7, COM7_RESET); + msleep(1); +} + + +static int ov7670_init(struct i2c_client *client) +{ + return ov7670_write_array(client, ov7670_default_regs); +} + + + +static int ov7670_detect(struct i2c_client *client) +{ + unsigned char v; + int ret; + + ret = ov7670_init(client); + if (ret < 0) + return ret; + ret = ov7670_read(client, REG_MIDH, &v); + if (ret < 0) + return ret; + if (v != 0x7f) /* OV manuf. id. */ + return -ENODEV; + ret = ov7670_read(client, REG_MIDL, &v); + if (ret < 0) + return ret; + if (v != 0xa2) + return -ENODEV; + /* + * OK, we know we have an OmniVision chip...but which one? + */ + ret = ov7670_read(client, REG_PID, &v); + if (ret < 0) + return ret; + if (v != 0x76) /* PID + VER = 0x76 / 0x73 */ + return -ENODEV; + ret = ov7670_read(client, REG_VER, &v); + if (ret < 0) + return ret; + if (v != 0x73) /* PID + VER = 0x76 / 0x73 */ + return -ENODEV; + return 0; +} + + + + + +static struct ov7670_format_struct { + __u8 *desc; + __u32 pixelformat; + struct regval_list *regs; +} ov7670_formats[] = { + { + .desc = "YUYV 4:2:2", + .pixelformat = V4L2_PIX_FMT_YUYV, + .regs = ov7670_fmt_yuv422, + }, + { + .desc = "RGB 444", + .pixelformat = V4L2_PIX_FMT_RGB444, + .regs = ov7670_fmt_rgb444, + }, + { + .desc = "RGB 565", + .pixelformat = V4L2_PIX_FMT_RGB565, + .regs = ov7670_fmt_rgb565, + }, + /* + * Pretend we do RGB32. This is here on the assumption that the + * upper layer will reformat RGB444 appropriately. + * + * The entire purpose for this thing's existence is to enable easy + * display of RGB444 for debugging purposes. It will come out soon. + */ + { + .desc = "RGB32 (faked)", + .pixelformat = V4L2_PIX_FMT_RGB32, + .regs = ov7670_fmt_rgb444, + }, +}; +#define N_OV7670_FMTS (sizeof(ov7670_formats)/sizeof(ov7670_formats[0])) + +/* + * All formats we support are 2 bytes/pixel. + */ +#define BYTES_PER_PIXEL 2 + +/* + * Then there is the issue of window sizes. Try to capture the info here. + */ +static struct ov7670_win_size { + int width; + int height; + unsigned char com7_bit; + int hstart; /* Start/stop values for the camera. Note */ + int hstop; /* that they do not always make complete */ + int vstart; /* sense to humans, but evidently the sensor */ + int vstop; /* will do the right thing... */ +/* h/vref stuff */ +} ov7670_win_sizes[] = { + /* VGA */ + { + .width = VGA_WIDTH, + .height = VGA_HEIGHT, + .com7_bit = COM7_FMT_VGA, + .hstart = 158, /* These values from */ + .hstop = 14, /* Omnivision */ + .vstart = 10, + .vstop = 490, + }, + /* CIF */ + { + .width = CIF_WIDTH, + .height = CIF_HEIGHT, + .com7_bit = COM7_FMT_CIF, + .hstart = 170, /* Empirically determined */ + .hstop = 90, + .vstart = 14, + .vstop = 494, + }, + /* QVGA */ + { + .width = QVGA_WIDTH, + .height = QVGA_HEIGHT, + .com7_bit = COM7_FMT_QVGA, + .hstart = 164, /* Empirically determined */ + .hstop = 20, + .vstart = 14, + .vstop = 494, + }, +}; + +#define N_WIN_SIZES (sizeof(ov7670_win_sizes)/sizeof(ov7670_win_sizes[0])) + + +/* + * Store a set of start/stop values into the camera. + */ +static int ov7670_set_hw(struct i2c_client *client, int hstart, int hstop, + int vstart, int vstop) +{ + int ret; + unsigned char v; +/* + * Horizontal: 11 bits, top 8 live in hstart and hstop. Bottom 3 of + * hstart are in href[2:0], bottom 3 of hstop in href[5:3]. There is + * a mystery "edge offset" value in the top two bits of href. + */ + ret = ov7670_write(client, REG_HSTART, (hstart >> 3) & 0xff); + ret += ov7670_write(client, REG_HSTOP, (hstop >> 3) & 0xff); + ret += ov7670_read(client, REG_HREF, &v); + v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7); + msleep(10); + ret += ov7670_write(client, REG_HREF, v); +/* + * Vertical: similar arrangement, but only 10 bits. + */ + ret += ov7670_write(client, REG_VSTART, (vstart >> 2) & 0xff); + ret += ov7670_write(client, REG_VSTOP, (vstop >> 2) & 0xff); + ret += ov7670_read(client, REG_VREF, &v); + v = (v & 0xf0) | ((vstop & 0x3) << 2) | (vstart & 0x3); + msleep(10); + ret += ov7670_write(client, REG_VREF, v); + return ret; +} + + +static int ov7670_enum_fmt(struct i2c_client *c, struct v4l2_fmtdesc *fmt) +{ + struct ov7670_format_struct *ofmt; + + if (fmt->index >= N_OV7670_FMTS) + return -EINVAL; + + ofmt = ov7670_formats + fmt->index; + fmt->flags = 0; + strcpy(fmt->description, ofmt->desc); + fmt->pixelformat = ofmt->pixelformat; + return 0; +} + + +static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt, + struct ov7670_format_struct **ret_fmt, + struct ov7670_win_size **ret_wsize) +{ + int index; + struct ov7670_win_size *wsize; + struct v4l2_pix_format *pix = &fmt->fmt.pix; + + for (index = 0; index < N_OV7670_FMTS; index++) + if (ov7670_formats[index].pixelformat == pix->pixelformat) + break; + if (index >= N_OV7670_FMTS) + return -EINVAL; + if (ret_fmt != NULL) + *ret_fmt = ov7670_formats + index; + /* + * Fields: the OV devices claim to be progressive. + */ + if (pix->field == V4L2_FIELD_ANY) + pix->field = V4L2_FIELD_NONE; + else if (pix->field != V4L2_FIELD_NONE) + return -EINVAL; + /* + * Round requested image size down to the nearest + * we support, but not below the smallest. + */ + for (wsize = ov7670_win_sizes; wsize < ov7670_win_sizes + N_WIN_SIZES; + wsize++) + if (pix->width >= wsize->width && pix->height >= wsize->height) + break; + if (wsize > ov7670_win_sizes + N_WIN_SIZES) + wsize--; /* Take the smallest one */ + if (ret_wsize != NULL) + *ret_wsize = wsize; + /* + * Note the size we'll actually handle. + */ + pix->width = wsize->width; + pix->height = wsize->height; + pix->bytesperline = pix->width*BYTES_PER_PIXEL; + if (pix->pixelformat == V4L2_PIX_FMT_RGB32) + pix->bytesperline *= 2; + pix->sizeimage = pix->height*pix->bytesperline; + return 0; + +} + +/* + * Set a format. + */ +static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt) +{ + int ret; + struct ov7670_format_struct *ovfmt; + struct ov7670_win_size *wsize; + unsigned char com7; + + ret = ov7670_try_fmt(c, fmt, &ovfmt, &wsize); + if (ret) + return ret; + /* + * COM7 is a pain in the ass, it doesn't like to be read then + * quickly written afterward. But we have everything we need + * to set it absolutely here, as long as the format-specific + * register sets list it first. + */ + com7 = ovfmt->regs[0].value; + com7 |= wsize->com7_bit; + ov7670_write(c, REG_COM7, com7); + /* + * Now write the rest of the array. Also store start/stops + */ + ov7670_write_array(c, ovfmt->regs + 1); + ov7670_set_hw(c, wsize->hstart, wsize->hstop, wsize->vstart, + wsize->vstop); + return 0; +} + +/* + * Code for dealing with controls. + */ + +/* + * Some weird registers seem to store values in a sign/magnitude format! + */ +static unsigned char ov7670_sm_to_abs(unsigned char v) +{ + if ((v & 0x80) == 0) + return v + 128; + else + return 128 - (v & 0x7f); +} + + +static unsigned char ov7670_abs_to_sm(unsigned char v) +{ + if (v > 127) + return v & 0x7f; + else + return (128 - v) | 0x80; +} + +static int ov7670_t_brightness(struct i2c_client *client, unsigned char value) +{ + unsigned char com8; + int ret; + + ov7670_read(client, REG_COM8, &com8); + com8 &= ~COM8_AEC; + ov7670_write(client, REG_COM8, com8); + value = ov7670_abs_to_sm(value); + ret = ov7670_write(client, REG_BRIGHT, value); + return ret; +} + +static int ov7670_q_brightness(struct i2c_client *client, unsigned char *value) +{ + int ret; + ret = ov7670_read(client, REG_BRIGHT, value); + *value = ov7670_sm_to_abs(*value); + return ret; +} + +static int ov7670_t_contrast(struct i2c_client *client, unsigned char value) +{ + return ov7670_write(client, REG_CONTRAS, value); +} + +static int ov7670_q_contrast(struct i2c_client *client, unsigned char *value) +{ + return ov7670_read(client, REG_CONTRAS, value); +} + +static int ov7670_q_hflip(struct i2c_client *client, unsigned char *value) +{ + int ret; + unsigned char v; + + ret = ov7670_read(client, REG_MVFP, &v); + *value = (v & MVFP_MIRROR) == MVFP_MIRROR; + return ret; +} + + +static int ov7670_t_hflip(struct i2c_client *client, unsigned char value) +{ + unsigned char v; + int ret; + + ret = ov7670_read(client, REG_MVFP, &v); + if (value) + v |= MVFP_MIRROR; + else + v &= ~MVFP_MIRROR; + msleep(10); /* FIXME */ + ret += ov7670_write(client, REG_MVFP, v); + return ret; +} + + + +static int ov7670_q_vflip(struct i2c_client *client, unsigned char *value) +{ + int ret; + unsigned char v; + + ret = ov7670_read(client, REG_MVFP, &v); + *value = (v & MVFP_FLIP) == MVFP_FLIP; + return ret; +} + + +static int ov7670_t_vflip(struct i2c_client *client, unsigned char value) +{ + unsigned char v; + int ret; + + ret = ov7670_read(client, REG_MVFP, &v); + if (value) + v |= MVFP_FLIP; + else + v &= ~MVFP_FLIP; + msleep(10); /* FIXME */ + ret += ov7670_write(client, REG_MVFP, v); + return ret; +} + + +static struct ov7670_control { + struct v4l2_queryctrl qc; + int (*query)(struct i2c_client *c, unsigned char *value); + int (*tweak)(struct i2c_client *c, unsigned char value); +} ov7670_controls[] = +{ + { + .qc = { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 0x80, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .tweak = ov7670_t_brightness, + .query = ov7670_q_brightness, + }, + { + .qc = { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 127, + .step = 1, + .default_value = 0x40, /* XXX ov7670 spec */ + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .tweak = ov7670_t_contrast, + .query = ov7670_q_contrast, + }, + { + .qc = { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Vertical flip", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + .tweak = ov7670_t_vflip, + .query = ov7670_q_vflip, + }, + { + .qc = { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Horizontal mirror", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + .tweak = ov7670_t_hflip, + .query = ov7670_q_hflip, + }, +}; +#define N_CONTROLS (sizeof(ov7670_controls)/sizeof(ov7670_controls[0])) + +static struct ov7670_control *ov7670_find_control(__u32 id) +{ + int i; + + for (i = 0; i < N_CONTROLS; i++) + if (ov7670_controls[i].qc.id == id) + return ov7670_controls + i; + return NULL; +} + + +static int ov7670_queryctrl(struct i2c_client *client, + struct v4l2_queryctrl *qc) +{ + struct ov7670_control *ctrl = ov7670_find_control(qc->id); + + if (ctrl == NULL) + return -EINVAL; + *qc = ctrl->qc; + return 0; +} + +static int ov7670_g_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) +{ + struct ov7670_control *octrl = ov7670_find_control(ctrl->id); + int ret; + unsigned char v; + + if (octrl == NULL) + return -EINVAL; + ret = octrl->query(client, &v); + if (ret >= 0) { + ctrl->value = v; + return 0; + } + return ret; +} + +static int ov7670_s_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) +{ + struct ov7670_control *octrl = ov7670_find_control(ctrl->id); + + if (octrl == NULL) + return -EINVAL; + return octrl->tweak(client, ctrl->value); +} + + + + + + + +/* + * Basic i2c stuff. + */ +static struct i2c_driver ov7670_driver; + +static int ov7670_attach(struct i2c_adapter *adapter) +{ + int ret; + struct i2c_client *client; + + printk(KERN_ERR "ov7670 attach, id = %d\n", adapter->id); + /* + * For now: only deal with adapters we recognize. + */ + if (adapter->id != I2C_HW_SMBUS_CAFE) + return -ENODEV; + + printk(KERN_ERR "ov7670 accepting\n"); + client = kzalloc(sizeof (struct i2c_client), GFP_KERNEL); + if (! client) + return -ENOMEM; + client->adapter = adapter; + client->addr = OV7670_I2C_ADDR; + client->driver = &ov7670_driver, + strcpy(client->name, "OV7670"); + /* Do we need clientdata? */ + + /* + * Make sure it's an ov7670 + */ + ret = ov7670_detect(client); + printk(KERN_ERR "detect result is %d\n", ret); + if (ret) + goto out_free; + i2c_attach_client(client); + return 0; + + out_free: + kfree(client); + return ret; +} + + +static int ov7670_detach(struct i2c_client *client) +{ + i2c_detach_client(client); + kfree(client); + return 0; +} + + +static int ov7670_command(struct i2c_client *client, unsigned int cmd, + void *arg) +{ + switch (cmd) { + case VIDIOC_INT_G_CHIP_IDENT: + * (enum v4l2_chip_ident *) arg = V4L2_IDENT_OV7670; + return 0; + + case VIDIOC_INT_RESET: + ov7670_reset(client); + return 0; + + case VIDIOC_INT_INIT: + return ov7670_init(client); + + case VIDIOC_ENUM_FMT: + return ov7670_enum_fmt(client, (struct v4l2_fmtdesc *) arg); + case VIDIOC_TRY_FMT: + return ov7670_try_fmt(client, (struct v4l2_format *) arg, NULL, NULL); + case VIDIOC_S_FMT: + return ov7670_s_fmt(client, (struct v4l2_format *) arg); + case VIDIOC_QUERYCTRL: + return ov7670_queryctrl(client, (struct v4l2_queryctrl *) arg); + case VIDIOC_S_CTRL: + return ov7670_s_ctrl(client, (struct v4l2_control *) arg); + case VIDIOC_G_CTRL: + return ov7670_g_ctrl(client, (struct v4l2_control *) arg); + /* Todo: + g/s_parm + initialization + */ + } + return -EINVAL; +} + + + +static struct i2c_driver ov7670_driver = { + .driver = { + .name = "ov7670", + }, + .id = I2C_DRIVERID_OV7670, + .class = I2C_CLASS_CAM_DIGITAL, + .attach_adapter = ov7670_attach, + .detach_client = ov7670_detach, + .command = ov7670_command, +}; + + +/* + * Module initialization + */ +static int __init ov7670_mod_init(void) +{ + printk(KERN_NOTICE "OmniVision ov7670 sensor driver, at your service\n"); + return i2c_add_driver(&ov7670_driver); +} + +static void __exit ov7670_mod_exit(void) +{ + i2c_del_driver(&ov7670_driver); +} + +module_init(ov7670_mod_init); +module_exit(ov7670_mod_exit); -- cgit v1.2.3 From c6e53daffc2c6e66069304b3970256744074abec Mon Sep 17 00:00:00 2001 From: Thomas Genty Date: Sun, 5 Nov 2006 14:17:30 -0300 Subject: V4L/DVB (4806): Saa7134: add support for Hauppauge WinTV-HVR1110 DVB-T/Hybrid This patch adds support for the Hauppauge WinTV-HVR1110 DVB-T/Hybrid Signed-off-by: Thomas Genty Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-cards.c | 29 +++++++++++++++++++++++++++++ drivers/media/video/saa7134/saa7134-dvb.c | 23 +++++++++++++++++++++++ drivers/media/video/saa7134/saa7134.h | 1 + 3 files changed, 53 insertions(+) (limited to 'drivers/media/video') diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index f5ad450dd7c..d8d8142d921 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -3126,6 +3126,28 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE2, }}, }, + [SAA7134_BOARD_HAUPPAUGE_HVR1110] = { + /* Thomas Genty */ + .name = "Hauppauge WinTV-HVR1110 DVB-T/Hybrid", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .mpeg = SAA7134_MPEG_DVB, + .gpiomask = 0x000200000, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + }}, + .radio = { + .name = name_radio, + .amux = TV, + .gpio = 0x0200000, + }, + }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -3752,6 +3774,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x1043, .subdevice = 0x4876, .driver_data = SAA7134_BOARD_ASUSTeK_P7131_DUAL, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0070, + .subdevice = 0x6701, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, },{ /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, @@ -4053,6 +4081,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) case SAA7134_BOARD_TEVION_DVBT_220RF: case SAA7134_BOARD_ASUSTeK_P7131_DUAL: case SAA7134_BOARD_MEDION_MD8800_QUADRO: + case SAA7134_BOARD_HAUPPAUGE_HVR1110: /* this is a hybrid board, initialize to analog mode * and configure firmware eeprom address */ diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 098d8a6a081..a51264f636f 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -900,6 +900,18 @@ static struct tda1004x_config pinnacle_pctv_310i_config = { /* ------------------------------------------------------------------ */ +static struct tda1004x_config hauppauge_hvr_1110_config = { + .demod_address = 0x08, + .invert = 1, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_16M, + .agc_config = TDA10046_AGC_TDA827X, + .if_freq = TDA10046_FREQ_045, + .request_firmware = philips_tda1004x_request_firmware, +}; + +/* ------------------------------------------------------------------ */ + static struct tda1004x_config asus_p7131_dual_config = { .demod_address = 0x08, .invert = 1, @@ -1221,6 +1233,17 @@ static int dvb_init(struct saa7134_dev *dev) dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params; } break; + case SAA7134_BOARD_HAUPPAUGE_HVR1110: + dev->dvb.frontend = dvb_attach(tda10046_attach, + &hauppauge_hvr_1110_config, + &dev->i2c_adap); + if (dev->dvb.frontend) { + dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; + dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init; + dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep; + dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params; + } + break; case SAA7134_BOARD_ASUSTeK_P7131_DUAL: dev->dvb.frontend = dvb_attach(tda10046_attach, &asus_p7131_dual_config, diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 0c0f4651bd0..fee75123f9a 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -230,6 +230,7 @@ struct saa7134_format { #define SAA7134_BOARD_PINNACLE_PCTV_310i 101 #define SAA7134_BOARD_AVERMEDIA_STUDIO_507 102 #define SAA7134_BOARD_VIDEOMATE_DVBT_200A 103 +#define SAA7134_BOARD_HAUPPAUGE_HVR1110 104 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 -- cgit v1.2.3 From f2520106e78b250c2c4662608cb8db1169932a2d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 12 Nov 2006 09:28:46 -0300 Subject: V4L/DVB (4812): Detect presence of IR receiver/IR transmitter in tveeprom Thanks to input from Steven Toth from Hauppauge the tveeprom module has been extended to detect the presence of an IR transmitter (aka IR-blaster). Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tveeprom.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index 6b9ef731b83..2624e3f7dd2 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -430,7 +430,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, tvee->has_radio = eeprom_data[i+len-1]; /* old style tag, don't know how to detect IR presence, mark as unknown. */ - tvee->has_ir = 2; + tvee->has_ir = -1; tvee->model = eeprom_data[i+8] + (eeprom_data[i+9] << 8); @@ -653,13 +653,14 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, STRM(decoderIC, tvee->decoder_processor), tvee->decoder_processor); } - if (tvee->has_ir == 2) + if (tvee->has_ir == -1) tveeprom_info("has %sradio\n", tvee->has_radio ? "" : "no "); else - tveeprom_info("has %sradio, has %sIR remote\n", + tveeprom_info("has %sradio, has %sIR receiver, has %sIR transmitter\n", tvee->has_radio ? "" : "no ", - tvee->has_ir ? "" : "no "); + (tvee->has_ir & 1) ? "" : "no ", + (tvee->has_ir & 2) ? "" : "no "); } EXPORT_SYMBOL(tveeprom_hauppauge_analog); -- cgit v1.2.3 From 5d9d171aaed2e0b1c5caac96efd4d4150eec97e1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 14 Nov 2006 12:40:07 -0300 Subject: V4L/DVB (4825): FIX bug 5760: audio were not working on some bttv drivers This fixes a bug introduced by the -git commit: bbf7871e1cd58b89f77b1152f457250c6e94b614 It seems that some bttv apps can't work fine when audioset=0. Thanks to Christian Casteyde for pointing this. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 6e1ddad9f0c..3c8e4742dcc 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -1793,7 +1793,7 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) memset(i,0,sizeof(*i)); i->index = n; i->type = V4L2_INPUT_TYPE_CAMERA; - i->audioset = 0; + i->audioset = 1; if (i->index == bttv_tvcards[btv->c.type].tuner) { sprintf(i->name, "Television"); i->type = V4L2_INPUT_TYPE_TUNER; -- cgit v1.2.3 From ed5801477addfbf5a40408866f5b2837e100451f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 16 Nov 2006 11:02:28 -0300 Subject: V4L/DVB (4829): v4l2_type_names table is incomplete Sliced VBI types are missing at the tables. Fixing it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-common.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 78d28b03ec9..b0b4abe5c29 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -184,11 +184,13 @@ char *v4l2_field_names[] = { }; char *v4l2_type_names[] = { - [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "video-cap", - [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "video-over", - [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "video-out", - [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap", - [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", + [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "video-cap", + [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "video-over", + [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "video-out", + [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap", + [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", + [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap", + [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "slicec-vbi-out", }; static char *v4l2_memory_names[] = { -- cgit v1.2.3 From ab33668f8e1bd686ebc87d51be3a0cf99a267a9f Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 17 Nov 2006 11:59:22 -0300 Subject: V4L/DVB (4834): Cafe_ccic.c: make a function static This patch makes the needlessly global cafe_v4l_dev_release() static. Signed-off-by: Adrian Bunk Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cafe_ccic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index 2026c4983b2..684d817ccfe 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -1688,7 +1688,7 @@ static struct v4l2_tvnorm cafe_tvnorm[] = { }; -void cafe_v4l_dev_release(struct video_device *vd) +static void cafe_v4l_dev_release(struct video_device *vd) { struct cafe_camera *cam = container_of(vd, struct cafe_camera, v4ldev); -- cgit v1.2.3 From 550a9a5e5f8086ae410832f134a5d80b9bd7fdb6 Mon Sep 17 00:00:00 2001 From: Hartmut Hackmann Date: Wed, 15 Nov 2006 21:31:54 -0300 Subject: V4L/DVB (4835): Added support for the Terratec Cinergy HT PCMCIA module This is a hybrid cardbus module. Besides the card support, i modified the definition names for AGC and GPIO of the tda10046. Signed-off-by: Hartmut Hackmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-cards.c | 37 +++++++++++++++++ drivers/media/video/saa7134/saa7134-dvb.c | 63 ++++++++++++++++++++++++----- drivers/media/video/saa7134/saa7134.h | 3 +- 3 files changed, 93 insertions(+), 10 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index d8d8142d921..d0ddc65d7eb 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -3148,6 +3148,29 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x0200000, }, }, + [SAA7134_BOARD_CINERGY_HT_PCMCIA] = { + .name = "Terratec Cinergy HT PCMCIA", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .mpeg = SAA7134_MPEG_DVB, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 0, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 6, + .amux = LINE1, + }}, + }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -3780,6 +3803,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x0070, .subdevice = 0x6701, .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x153b, + .subdevice = 0x1172, + .driver_data = SAA7134_BOARD_CINERGY_HT_PCMCIA, },{ /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, @@ -4107,6 +4136,14 @@ int saa7134_board_init2(struct saa7134_dev *dev) i2c_transfer(&dev->i2c_adap, &msg, 1); } break; + case SAA7134_BOARD_CINERGY_HT_PCMCIA: + /* make the tda10046 find its eeprom */ + { + u8 data[] = { 0x3c, 0x33, 0x60}; + struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; + i2c_transfer(&dev->i2c_adap, &msg, 1); + } + break; case SAA7134_BOARD_KWORLD_ATSC110: { /* enable tuner */ diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index a51264f636f..ce888f70495 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -677,7 +677,7 @@ static struct tda1004x_config tda827x_lifeview_config = { .invert = 1, .invert_oclk = 0, .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, + .agc_config = TDA10046_AGC_TDA827X_GP11, .if_freq = TDA10046_FREQ_045, .request_firmware = NULL, }; @@ -881,7 +881,40 @@ static struct tda1004x_config philips_tiger_config = { .invert = 1, .invert_oclk = 0, .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, + .agc_config = TDA10046_AGC_TDA827X_GP11, + .if_freq = TDA10046_FREQ_045, + .request_firmware = NULL, +}; +/* ------------------------------------------------------------------ */ + +static int cinergy_ht_tuner_init(struct dvb_frontend *fe) +{ + struct saa7134_dev *dev = fe->dvb->priv; + static u8 data[] = { 0x3c, 0x33, 0x62}; + struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; + + if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) + return -EIO; + return 0; +} + +static int cinergy_ht_tuner_sleep(struct dvb_frontend *fe) +{ + struct saa7134_dev *dev = fe->dvb->priv; + static u8 data[] = { 0x3c, 0x33, 0x60}; + struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; + + i2c_transfer(&dev->i2c_adap, &msg, 1); + philips_tda827xa_tuner_sleep( 0x61, fe); + return 0; +} + +static struct tda1004x_config cinergy_ht_config = { + .demod_address = 0x08, + .invert = 1, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_16M, + .agc_config = TDA10046_AGC_TDA827X_GP01, .if_freq = TDA10046_FREQ_045, .request_firmware = NULL, }; @@ -893,7 +926,7 @@ static struct tda1004x_config pinnacle_pctv_310i_config = { .invert = 1, .invert_oclk = 0, .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, + .agc_config = TDA10046_AGC_TDA827X_GP11, .if_freq = TDA10046_FREQ_045, .request_firmware = philips_tda1004x_request_firmware, }; @@ -905,7 +938,7 @@ static struct tda1004x_config hauppauge_hvr_1110_config = { .invert = 1, .invert_oclk = 0, .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, + .agc_config = TDA10046_AGC_TDA827X_GP11, .if_freq = TDA10046_FREQ_045, .request_firmware = philips_tda1004x_request_firmware, }; @@ -917,7 +950,7 @@ static struct tda1004x_config asus_p7131_dual_config = { .invert = 1, .invert_oclk = 0, .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, + .agc_config = TDA10046_AGC_TDA827X_GP11, .if_freq = TDA10046_FREQ_045, .request_firmware = philips_tda1004x_request_firmware, }; @@ -969,7 +1002,7 @@ static struct tda1004x_config lifeview_trio_config = { .invert = 1, .invert_oclk = 0, .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X_GPL, + .agc_config = TDA10046_AGC_TDA827X_GP00, .if_freq = TDA10046_FREQ_045, .request_firmware = NULL, }; @@ -1006,7 +1039,7 @@ static struct tda1004x_config ads_tech_duo_config = { .invert = 1, .invert_oclk = 0, .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X_GPL, + .agc_config = TDA10046_AGC_TDA827X_GP00, .if_freq = TDA10046_FREQ_045, .request_firmware = NULL, }; @@ -1031,7 +1064,7 @@ static struct tda1004x_config tevion_dvbt220rf_config = { .invert = 1, .invert_oclk = 0, .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, + .agc_config = TDA10046_AGC_TDA827X_GP11, .if_freq = TDA10046_FREQ_045, .request_firmware = NULL, }; @@ -1076,7 +1109,7 @@ static struct tda1004x_config md8800_dvbt_config = { .invert = 1, .invert_oclk = 0, .xtal_freq = TDA10046_XTAL_16M, - .agc_config = TDA10046_AGC_TDA827X, + .agc_config = TDA10046_AGC_TDA827X_GP11, .if_freq = TDA10046_FREQ_045, .request_firmware = NULL, }; @@ -1362,6 +1395,18 @@ static int dvb_init(struct saa7134_dev *dev) dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params; } break; + case SAA7134_BOARD_CINERGY_HT_PCMCIA: + dev->dvb.frontend = dvb_attach(tda10046_attach, + &cinergy_ht_config, + &dev->i2c_adap); + if (dev->dvb.frontend) { + dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl; + dev->dvb.frontend->ops.tuner_ops.init = cinergy_ht_tuner_init; + dev->dvb.frontend->ops.tuner_ops.sleep = cinergy_ht_tuner_sleep; + dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params; + + } + break; default: printk("%s: Huh? unknown DVB card?\n",dev->name); break; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index fee75123f9a..e88ad7b40c4 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -230,7 +230,8 @@ struct saa7134_format { #define SAA7134_BOARD_PINNACLE_PCTV_310i 101 #define SAA7134_BOARD_AVERMEDIA_STUDIO_507 102 #define SAA7134_BOARD_VIDEOMATE_DVBT_200A 103 -#define SAA7134_BOARD_HAUPPAUGE_HVR1110 104 +#define SAA7134_BOARD_HAUPPAUGE_HVR1110 104 +#define SAA7134_BOARD_CINERGY_HT_PCMCIA 105 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 -- cgit v1.2.3 From 1f683cd8bc8512c02a7d1b8358d71937d4c5134b Mon Sep 17 00:00:00 2001 From: Nico Sabbi Date: Wed, 15 Nov 2006 22:06:56 -0300 Subject: V4L/DVB (4836): Added support for both DVB frontends of the Lifeview Trio This card (like some others) supports both, DVB-T and a DVB-S. The patch adds an insmod option to select the frontend: use_frontend=0 -> DVB-T use_frontend=1 -> DVB-S Signed-off-by: Nico Sabbi Signed-off-by: Hartmut Hackmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-dvb.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index ce888f70495..fa833987909 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -50,6 +50,10 @@ static unsigned int antenna_pwr = 0; module_param(antenna_pwr, int, 0444); MODULE_PARM_DESC(antenna_pwr,"enable antenna power (Pinnacle 300i)"); +static int use_frontent = 0; +module_param(use_frontent, int, 0644); +MODULE_PARM_DESC(use_frontent,"for cards with multiple frontends (0: terrestrial, 1: satellite)"); + /* ------------------------------------------------------------------ */ static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on) { @@ -1299,12 +1303,27 @@ static int dvb_init(struct saa7134_dev *dev) } break; case SAA7134_BOARD_FLYDVB_TRIO: - dev->dvb.frontend = dvb_attach(tda10046_attach, - &lifeview_trio_config, - &dev->i2c_adap); - if (dev->dvb.frontend) { - dev->dvb.frontend->ops.tuner_ops.sleep = lifeview_trio_tuner_sleep; - dev->dvb.frontend->ops.tuner_ops.set_params = lifeview_trio_tuner_set_params; + if(! use_frontent) { //terrestrial + dev->dvb.frontend = dvb_attach(tda10046_attach, + &lifeview_trio_config, + &dev->i2c_adap); + if (dev->dvb.frontend) { + dev->dvb.frontend->ops.tuner_ops.sleep = lifeview_trio_tuner_sleep; + dev->dvb.frontend->ops.tuner_ops.set_params = + lifeview_trio_tuner_set_params; + } + } else { //satellite + dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap); + if (dev->dvb.frontend) { + if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x63, + &dev->i2c_adap, 0) == NULL) { + printk("%s: Lifeview Trio, No tda826x found!\n", __FUNCTION__); + } + if (dvb_attach(isl6421_attach, dev->dvb.frontend, &dev->i2c_adap, + 0x08, 0, 0) == NULL) { + printk("%s: Lifeview Trio, No ISL6421 found!\n", __FUNCTION__); + } + } } break; case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: -- cgit v1.2.3 From 49c6b46a05ade5e1c572431844b77755527a152c Mon Sep 17 00:00:00 2001 From: Jelle Foks Date: Sat, 18 Nov 2006 15:47:11 -0300 Subject: V4L/DVB (4838): Fix cx88-blackbird null pointer Allows 'debug=1' for cx88-blackbird module (dev needs to be valid for dprintk). Fixes a null-pointer dereference when using debug=1. Signed-off-by: Jelle Foks Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-blackbird.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 0037188d77d..0cf0360588e 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -942,9 +942,10 @@ static int mpeg_open(struct inode *inode, struct file *file) struct cx8802_driver *drv = NULL; int err; + dev = cx8802_get_device(inode); + dprintk( 1, "%s\n", __FUNCTION__); - dev = cx8802_get_device(inode); if (dev == NULL) return -ENODEV; -- cgit v1.2.3 From 2d90fa4412549faa3830789ca606b77827cde827 Mon Sep 17 00:00:00 2001 From: Jelle Foks Date: Sat, 18 Nov 2006 15:47:15 -0300 Subject: V4L/DVB (4839): Add support ptv-305 Add subvendor/device of the ADSTech Instant TV Deluxe PTV-305 to the card list as card=45 (KWORLD_HARDWARE_MPEG_TV_XPERT). Signed-off-by: Jelle Foks Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-cards.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/media/video') diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index f30f88965f0..c791708b133 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -1531,6 +1531,10 @@ struct cx88_subid cx88_subids[] = { },{ .subvendor = 0x17de, .subdevice = 0x0840, + .card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT, + },{ + .subvendor = 0x1421, + .subdevice = 0x0305, .card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT, },{ .subvendor = 0x18ac, -- cgit v1.2.3 From f9a7615686a854cb94b5252e66b836a0a539ad9e Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Sun, 19 Nov 2006 19:04:55 -0300 Subject: V4L/DVB (4842): Updated camera driver A couple of Cafe driver fixes, and support for the hue and saturation controls. Signed-off-by: Jonathan Corbet Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cafe_ccic.c | 17 +- drivers/media/video/ov7670.c | 366 +++++++++++++++++++++++++++++++++++----- 2 files changed, 338 insertions(+), 45 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index 684d817ccfe..dc6e16c2b83 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -505,6 +505,8 @@ static struct i2c_algorithm cafe_smbus_algo = { /* Somebody is on the bus */ static int cafe_cam_init(struct cafe_camera *cam); +static void cafe_ctlr_stop_dma(struct cafe_camera *cam); +static void cafe_ctlr_power_down(struct cafe_camera *cam); static int cafe_smbus_attach(struct i2c_client *client) { @@ -513,7 +515,6 @@ static int cafe_smbus_attach(struct i2c_client *client) /* * Don't talk to chips we don't recognize. */ - cam_err(cam, "smbus_attach id = %d\n", client->driver->id); if (client->driver->id == I2C_DRIVERID_OV7670) { cam->sensor = client; return cafe_cam_init(cam); @@ -525,8 +526,13 @@ static int cafe_smbus_detach(struct i2c_client *client) { struct cafe_camera *cam = i2c_get_adapdata(client->adapter); - if (cam->sensor == client) + if (cam->sensor == client) { + cafe_ctlr_stop_dma(cam); + cafe_ctlr_power_down(cam); + cam_err(cam, "lost the sensor!\n"); cam->sensor = NULL; /* Bummer, no camera */ + cam->state = S_NOTREADY; + } return 0; } @@ -774,7 +780,7 @@ static void cafe_ctlr_power_up(struct cafe_camera *cam) * wiring). Control 0 is reset - set to 1 to operate. * Control 1 is power down, set to 0 to operate. */ - cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C1); + cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN); /* pwr up, reset */ mdelay(1); /* Marvell says 1ms will do it */ cafe_reg_write(cam, REG_GPR, GPR_C1EN|GPR_C0EN|GPR_C0); mdelay(1); /* Enough? */ @@ -1468,8 +1474,11 @@ static int cafe_v4l_release(struct inode *inode, struct file *filp) cafe_free_sio_buffers(cam); cam->owner = NULL; } - if (cam->users == 0) + if (cam->users == 0) { cafe_ctlr_power_down(cam); + if (! alloc_bufs_at_load) + cafe_free_dma_bufs(cam); + } mutex_unlock(&cam->s_mutex); return 0; } diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c index 382aa83b73c..b7d824ee03e 100644 --- a/drivers/media/video/ov7670.c +++ b/drivers/media/video/ov7670.c @@ -138,6 +138,20 @@ MODULE_LICENSE("GPL"); #define COM17_AECWIN 0xc0 /* AEC window - must match COM4 */ #define COM17_CBAR 0x08 /* DSP Color bar */ +/* + * This matrix defines how the colors are generated, must be + * tweaked to adjust hue and saturation. + * + * Order: v-red, v-green, v-blue, u-red, u-green, u-blue + * + * They are nine-bit signed quantities, with the sign bit + * stored in 0x58. Sign for v-red is bit 0, and up from there. + */ +#define REG_CMATRIX_BASE 0x4f +#define CMATRIX_LEN 6 +#define REG_CMATRIX_SIGN 0x58 + + #define REG_BRIGHT 0x55 /* Brightness */ #define REG_CONTRAS 0x56 /* Contrast control */ @@ -159,6 +173,19 @@ MODULE_LICENSE("GPL"); #define REG_BD60MAX 0xab /* 60hz banding step limit */ +/* + * Information we maintain about a known sensor. + */ +struct ov7670_format_struct; /* coming later */ +struct ov7670_info { + struct ov7670_format_struct *fmt; /* Current format */ + unsigned char sat; /* Saturation value */ + int hue; /* Hue value */ +}; + + + + /* * The default register settings, as obtained from OmniVision. There * is really no making sense of most of these - lots of "reserved" values @@ -179,7 +206,7 @@ static struct regval_list ov7670_default_regs[] = { * 2 = 20fps * 1 = 30fps */ - { REG_CLKRC, 0x1 }, /* OV: clock scale (15 fps) */ + { REG_CLKRC, 0x1 }, /* OV: clock scale (30 fps) */ { REG_TSLB, 0x04 }, /* OV */ { REG_COM7, 0 }, /* VGA */ /* @@ -286,10 +313,6 @@ static struct regval_list ov7670_default_regs[] = { { 0x79, 0x05 }, { 0xc8, 0x30 }, { 0x79, 0x26 }, - /* Not sure if these should be here */ - { 0xf1, 0x10 }, { 0x0f, 0x1d }, - { 0x0f, 0x1f }, - { 0xff, 0xff }, /* END MARKER */ }; @@ -312,6 +335,7 @@ static struct regval_list ov7670_fmt_yuv422[] = { { REG_COM9, 0x18 }, /* 4x gain ceiling; 0x8 is reserved bit */ { 0x4f, 0x80 }, /* "matrix coefficient 1" */ { 0x50, 0x80 }, /* "matrix coefficient 2" */ + { 0x51, 0 }, /* vb */ { 0x52, 0x22 }, /* "matrix coefficient 4" */ { 0x53, 0x5e }, /* "matrix coefficient 5" */ { 0x54, 0x80 }, /* "matrix coefficient 6" */ @@ -327,6 +351,7 @@ static struct regval_list ov7670_fmt_rgb565[] = { { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ { 0x50, 0xb3 }, /* "matrix coefficient 2" */ + { 0x51, 0 }, /* vb */ { 0x52, 0x3d }, /* "matrix coefficient 4" */ { 0x53, 0xa7 }, /* "matrix coefficient 5" */ { 0x54, 0xe4 }, /* "matrix coefficient 6" */ @@ -342,6 +367,7 @@ static struct regval_list ov7670_fmt_rgb444[] = { { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ { 0x50, 0xb3 }, /* "matrix coefficient 2" */ + { 0x51, 0 }, /* vb */ { 0x52, 0x3d }, /* "matrix coefficient 4" */ { 0x53, 0xa7 }, /* "matrix coefficient 5" */ { 0x54, 0xe4 }, /* "matrix coefficient 6" */ @@ -362,7 +388,7 @@ static int ov7670_read(struct i2c_client *c, unsigned char reg, int ret; ret = i2c_smbus_read_byte_data(c, reg); - if (ret > 0) + if (ret >= 0) *value = (unsigned char) ret; return ret; } @@ -442,28 +468,34 @@ static int ov7670_detect(struct i2c_client *client) } - - - +/* + * Store information about the video data format. The color matrix + * is deeply tied into the format, so keep the relevant values here. + * The magic matrix nubmers come from OmniVision. + */ static struct ov7670_format_struct { __u8 *desc; __u32 pixelformat; struct regval_list *regs; + int cmatrix[CMATRIX_LEN]; } ov7670_formats[] = { { .desc = "YUYV 4:2:2", .pixelformat = V4L2_PIX_FMT_YUYV, .regs = ov7670_fmt_yuv422, + .cmatrix = { 128, -128, 0, -34, -94, 128 }, }, { .desc = "RGB 444", .pixelformat = V4L2_PIX_FMT_RGB444, .regs = ov7670_fmt_rgb444, + .cmatrix = { 179, -179, 0, -61, -176, 228 }, }, { .desc = "RGB 565", .pixelformat = V4L2_PIX_FMT_RGB565, .regs = ov7670_fmt_rgb565, + .cmatrix = { 179, -179, 0, -61, -176, 228 }, }, /* * Pretend we do RGB32. This is here on the assumption that the @@ -476,6 +508,7 @@ static struct ov7670_format_struct { .desc = "RGB32 (faked)", .pixelformat = V4L2_PIX_FMT_RGB32, .regs = ov7670_fmt_rgb444, + .cmatrix = { 179, -179, 0, -61, -176, 228 }, }, }; #define N_OV7670_FMTS (sizeof(ov7670_formats)/sizeof(ov7670_formats[0])) @@ -488,6 +521,32 @@ static struct ov7670_format_struct { /* * Then there is the issue of window sizes. Try to capture the info here. */ + +/* + * QCIF mode is done (by OV) in a very strange way - it actually looks like + * VGA with weird scaling options - they do *not* use the canned QCIF mode + * which is allegedly provided by the sensor. So here's the weird register + * settings. + */ +static struct regval_list ov7670_qcif_regs[] = { + { REG_COM3, COM3_SCALEEN|COM3_DCWEN }, + { REG_COM3, COM3_DCWEN }, + { REG_COM14, COM14_DCWEN | 0x01}, + { 0x73, 0xf1 }, + { 0xa2, 0x52 }, + { 0x7b, 0x1c }, + { 0x7c, 0x28 }, + { 0x7d, 0x3c }, + { 0x7f, 0x69 }, + { REG_COM9, 0x38 }, + { 0xa1, 0x0b }, + { 0x74, 0x19 }, + { 0x9a, 0x80 }, + { 0x43, 0x14 }, + { REG_COM13, 0xc0 }, + { 0xff, 0xff }, +}; + static struct ov7670_win_size { int width; int height; @@ -496,6 +555,7 @@ static struct ov7670_win_size { int hstop; /* that they do not always make complete */ int vstart; /* sense to humans, but evidently the sensor */ int vstop; /* will do the right thing... */ + struct regval_list *regs; /* Regs to tweak */ /* h/vref stuff */ } ov7670_win_sizes[] = { /* VGA */ @@ -507,6 +567,7 @@ static struct ov7670_win_size { .hstop = 14, /* Omnivision */ .vstart = 10, .vstop = 490, + .regs = NULL, }, /* CIF */ { @@ -517,6 +578,7 @@ static struct ov7670_win_size { .hstop = 90, .vstart = 14, .vstop = 494, + .regs = NULL, }, /* QVGA */ { @@ -527,6 +589,18 @@ static struct ov7670_win_size { .hstop = 20, .vstart = 14, .vstop = 494, + .regs = NULL, + }, + /* QCIF */ + { + .width = QCIF_WIDTH, + .height = QCIF_HEIGHT, + .com7_bit = COM7_FMT_VGA, /* see comment above */ + .hstart = 456, /* Empirically determined */ + .hstop = 24, + .vstart = 14, + .vstop = 494, + .regs = ov7670_qcif_regs, }, }; @@ -610,7 +684,7 @@ static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt, wsize++) if (pix->width >= wsize->width && pix->height >= wsize->height) break; - if (wsize > ov7670_win_sizes + N_WIN_SIZES) + if (wsize >= ov7670_win_sizes + N_WIN_SIZES) wsize--; /* Take the smallest one */ if (ret_wsize != NULL) *ret_wsize = wsize; @@ -624,7 +698,6 @@ static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt, pix->bytesperline *= 2; pix->sizeimage = pix->height*pix->bytesperline; return 0; - } /* @@ -635,6 +708,7 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt) int ret; struct ov7670_format_struct *ovfmt; struct ov7670_win_size *wsize; + struct ov7670_info *info = i2c_get_clientdata(c); unsigned char com7; ret = ov7670_try_fmt(c, fmt, &ovfmt, &wsize); @@ -655,6 +729,10 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt) ov7670_write_array(c, ovfmt->regs + 1); ov7670_set_hw(c, wsize->hstart, wsize->hstop, wsize->vstart, wsize->vstop); + ret = 0; + if (wsize->regs) + ret = ov7670_write_array(c, wsize->regs); + info->fmt = ovfmt; return 0; } @@ -662,6 +740,168 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt) * Code for dealing with controls. */ + + + + +static int ov7670_store_cmatrix(struct i2c_client *client, + int matrix[CMATRIX_LEN]) +{ + int i, ret; + unsigned char signbits; + + /* + * Weird crap seems to exist in the upper part of + * the sign bits register, so let's preserve it. + */ + ret = ov7670_read(client, REG_CMATRIX_SIGN, &signbits); + signbits &= 0xc0; + + for (i = 0; i < CMATRIX_LEN; i++) { + unsigned char raw; + + if (matrix[i] < 0) { + signbits |= (1 << i); + if (matrix[i] < -255) + raw = 0xff; + else + raw = (-1 * matrix[i]) & 0xff; + } + else { + if (matrix[i] > 255) + raw = 0xff; + else + raw = matrix[i] & 0xff; + } + ret += ov7670_write(client, REG_CMATRIX_BASE + i, raw); + } + ret += ov7670_write(client, REG_CMATRIX_SIGN, signbits); + return ret; +} + + +/* + * Hue also requires messing with the color matrix. It also requires + * trig functions, which tend not to be well supported in the kernel. + * So here is a simple table of sine values, 0-90 degrees, in steps + * of five degrees. Values are multiplied by 1000. + * + * The following naive approximate trig functions require an argument + * carefully limited to -180 <= theta <= 180. + */ +#define SIN_STEP 5 +static const int ov7670_sin_table[] = { + 0, 87, 173, 258, 342, 422, + 499, 573, 642, 707, 766, 819, + 866, 906, 939, 965, 984, 996, + 1000 +}; + +static int ov7670_sine(int theta) +{ + int chs = 1; + int sine; + + if (theta < 0) { + theta = -theta; + chs = -1; + } + if (theta <= 90) + sine = ov7670_sin_table[theta/SIN_STEP]; + else { + theta -= 90; + sine = 1000 - ov7670_sin_table[theta/SIN_STEP]; + } + return sine*chs; +} + +static int ov7670_cosine(int theta) +{ + theta = 90 - theta; + if (theta > 180) + theta -= 360; + else if (theta < -180) + theta += 360; + return ov7670_sine(theta); +} + + + + +static void ov7670_calc_cmatrix(struct ov7670_info *info, + int matrix[CMATRIX_LEN]) +{ + int i; + /* + * Apply the current saturation setting first. + */ + for (i = 0; i < CMATRIX_LEN; i++) + matrix[i] = (info->fmt->cmatrix[i]*info->sat) >> 7; + /* + * Then, if need be, rotate the hue value. + */ + if (info->hue != 0) { + int sinth, costh, tmpmatrix[CMATRIX_LEN]; + + memcpy(tmpmatrix, matrix, CMATRIX_LEN*sizeof(int)); + sinth = ov7670_sine(info->hue); + costh = ov7670_cosine(info->hue); + + matrix[0] = (matrix[3]*sinth + matrix[0]*costh)/1000; + matrix[1] = (matrix[4]*sinth + matrix[1]*costh)/1000; + matrix[2] = (matrix[5]*sinth + matrix[2]*costh)/1000; + matrix[3] = (matrix[3]*costh - matrix[0]*sinth)/1000; + matrix[4] = (matrix[4]*costh - matrix[1]*sinth)/1000; + matrix[5] = (matrix[5]*costh - matrix[2]*sinth)/1000; + } +} + + + +static int ov7670_t_sat(struct i2c_client *client, int value) +{ + struct ov7670_info *info = i2c_get_clientdata(client); + int matrix[CMATRIX_LEN]; + int ret; + + info->sat = value; + ov7670_calc_cmatrix(info, matrix); + ret = ov7670_store_cmatrix(client, matrix); + return ret; +} + +static int ov7670_q_sat(struct i2c_client *client, __s32 *value) +{ + struct ov7670_info *info = i2c_get_clientdata(client); + + *value = info->sat; + return 0; +} + +static int ov7670_t_hue(struct i2c_client *client, int value) +{ + struct ov7670_info *info = i2c_get_clientdata(client); + int matrix[CMATRIX_LEN]; + int ret; + + if (value < -180 || value > 180) + return -EINVAL; + info->hue = value; + ov7670_calc_cmatrix(info, matrix); + ret = ov7670_store_cmatrix(client, matrix); + return ret; +} + + +static int ov7670_q_hue(struct i2c_client *client, __s32 *value) +{ + struct ov7670_info *info = i2c_get_clientdata(client); + + *value = info->hue; + return 0; +} + + /* * Some weird registers seem to store values in a sign/magnitude format! */ @@ -682,38 +922,43 @@ static unsigned char ov7670_abs_to_sm(unsigned char v) return (128 - v) | 0x80; } -static int ov7670_t_brightness(struct i2c_client *client, unsigned char value) +static int ov7670_t_brightness(struct i2c_client *client, int value) { - unsigned char com8; + unsigned char com8, v; int ret; ov7670_read(client, REG_COM8, &com8); com8 &= ~COM8_AEC; ov7670_write(client, REG_COM8, com8); - value = ov7670_abs_to_sm(value); - ret = ov7670_write(client, REG_BRIGHT, value); + v = ov7670_abs_to_sm(value); + ret = ov7670_write(client, REG_BRIGHT, v); return ret; } -static int ov7670_q_brightness(struct i2c_client *client, unsigned char *value) +static int ov7670_q_brightness(struct i2c_client *client, __s32 *value) { - int ret; - ret = ov7670_read(client, REG_BRIGHT, value); - *value = ov7670_sm_to_abs(*value); + unsigned char v; + int ret = ov7670_read(client, REG_BRIGHT, &v); + + *value = ov7670_sm_to_abs(v); return ret; } -static int ov7670_t_contrast(struct i2c_client *client, unsigned char value) +static int ov7670_t_contrast(struct i2c_client *client, int value) { - return ov7670_write(client, REG_CONTRAS, value); + return ov7670_write(client, REG_CONTRAS, (unsigned char) value); } -static int ov7670_q_contrast(struct i2c_client *client, unsigned char *value) +static int ov7670_q_contrast(struct i2c_client *client, __s32 *value) { - return ov7670_read(client, REG_CONTRAS, value); + unsigned char v; + int ret = ov7670_read(client, REG_CONTRAS, &v); + + *value = v; + return ret; } -static int ov7670_q_hflip(struct i2c_client *client, unsigned char *value) +static int ov7670_q_hflip(struct i2c_client *client, __s32 *value) { int ret; unsigned char v; @@ -724,7 +969,7 @@ static int ov7670_q_hflip(struct i2c_client *client, unsigned char *value) } -static int ov7670_t_hflip(struct i2c_client *client, unsigned char value) +static int ov7670_t_hflip(struct i2c_client *client, int value) { unsigned char v; int ret; @@ -741,7 +986,7 @@ static int ov7670_t_hflip(struct i2c_client *client, unsigned char value) -static int ov7670_q_vflip(struct i2c_client *client, unsigned char *value) +static int ov7670_q_vflip(struct i2c_client *client, __s32 *value) { int ret; unsigned char v; @@ -752,7 +997,7 @@ static int ov7670_q_vflip(struct i2c_client *client, unsigned char *value) } -static int ov7670_t_vflip(struct i2c_client *client, unsigned char value) +static int ov7670_t_vflip(struct i2c_client *client, int value) { unsigned char v; int ret; @@ -770,8 +1015,8 @@ static int ov7670_t_vflip(struct i2c_client *client, unsigned char value) static struct ov7670_control { struct v4l2_queryctrl qc; - int (*query)(struct i2c_client *c, unsigned char *value); - int (*tweak)(struct i2c_client *c, unsigned char value); + int (*query)(struct i2c_client *c, __s32 *value); + int (*tweak)(struct i2c_client *c, int value); } ov7670_controls[] = { { @@ -802,6 +1047,34 @@ static struct ov7670_control { .tweak = ov7670_t_contrast, .query = ov7670_q_contrast, }, + { + .qc = { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation", + .minimum = 0, + .maximum = 256, + .step = 1, + .default_value = 0x80, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .tweak = ov7670_t_sat, + .query = ov7670_q_sat, + }, + { + .qc = { + .id = V4L2_CID_HUE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "HUE", + .minimum = -180, + .maximum = 180, + .step = 5, + .default_value = 0, + .flags = V4L2_CTRL_FLAG_SLIDER + }, + .tweak = ov7670_t_hue, + .query = ov7670_q_hue, + }, { .qc = { .id = V4L2_CID_VFLIP, @@ -857,25 +1130,26 @@ static int ov7670_g_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) { struct ov7670_control *octrl = ov7670_find_control(ctrl->id); int ret; - unsigned char v; if (octrl == NULL) return -EINVAL; - ret = octrl->query(client, &v); - if (ret >= 0) { - ctrl->value = v; + ret = octrl->query(client, &ctrl->value); + if (ret >= 0) return 0; - } return ret; } static int ov7670_s_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) { struct ov7670_control *octrl = ov7670_find_control(ctrl->id); + int ret; if (octrl == NULL) return -EINVAL; - return octrl->tweak(client, ctrl->value); + ret = octrl->tweak(client, ctrl->value); + if (ret >= 0) + return 0; + return ret; } @@ -883,7 +1157,6 @@ static int ov7670_s_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) - /* * Basic i2c stuff. */ @@ -893,15 +1166,14 @@ static int ov7670_attach(struct i2c_adapter *adapter) { int ret; struct i2c_client *client; + struct ov7670_info *info; - printk(KERN_ERR "ov7670 attach, id = %d\n", adapter->id); /* * For now: only deal with adapters we recognize. */ if (adapter->id != I2C_HW_SMBUS_CAFE) return -ENODEV; - printk(KERN_ERR "ov7670 accepting\n"); client = kzalloc(sizeof (struct i2c_client), GFP_KERNEL); if (! client) return -ENOMEM; @@ -909,18 +1181,29 @@ static int ov7670_attach(struct i2c_adapter *adapter) client->addr = OV7670_I2C_ADDR; client->driver = &ov7670_driver, strcpy(client->name, "OV7670"); - /* Do we need clientdata? */ + /* + * Set up our info structure. + */ + info = kzalloc(sizeof (struct ov7670_info), GFP_KERNEL); + if (! info) { + ret = -ENOMEM; + goto out_free; + } + info->fmt = &ov7670_formats[0]; + info->sat = 128; /* Review this */ + i2c_set_clientdata(client, info); /* * Make sure it's an ov7670 */ ret = ov7670_detect(client); - printk(KERN_ERR "detect result is %d\n", ret); if (ret) - goto out_free; + goto out_free_info; i2c_attach_client(client); return 0; + out_free_info: + kfree(info); out_free: kfree(client); return ret; @@ -930,6 +1213,7 @@ static int ov7670_attach(struct i2c_adapter *adapter) static int ov7670_detach(struct i2c_client *client) { i2c_detach_client(client); + kfree(i2c_get_clientdata(client)); kfree(client); return 0; } -- cgit v1.2.3 From 76db93d03f1e9a9a3371f787ae30780cdf10400c Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sun, 19 Nov 2006 19:45:26 -0300 Subject: V4L/DVB (4846): Create new lgh06xf atsc tuner module This patch creates a new atsc tuner module for the LG TDVS-H06xF ATSC tuners, called lgh06xf. The purpose of this change is to reduce some duplicated code, and to allow the lgh06xf tuner code to take advantage of dvb_attach(). As a side effect, the dependency of dvb-bt8xx on dvb-pll has been removed, since the lgh06xf module itself will use dvb-pll, while remaining optional for the dvb-bt8xx driver through the use of DVB_FE_CUSTOMISE Acked-by: Andrew de Quincey Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/Kconfig | 1 + drivers/media/video/cx88/cx88-dvb.c | 20 +++++--------------- 2 files changed, 6 insertions(+), 15 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig index 0f9d9696361..b2a66ba625f 100644 --- a/drivers/media/video/cx88/Kconfig +++ b/drivers/media/video/cx88/Kconfig @@ -53,6 +53,7 @@ config VIDEO_CX88_DVB select DVB_OR51132 if !DVB_FE_CUSTOMISE select DVB_CX22702 if !DVB_FE_CUSTOMISE select DVB_LGDT330X if !DVB_FE_CUSTOMISE + select DVB_TUNER_LGH06XF if !DVB_FE_CUSTOMISE select DVB_NXT200X if !DVB_FE_CUSTOMISE select DVB_CX24123 if !DVB_FE_CUSTOMISE select DVB_ISL6421 if !DVB_FE_CUSTOMISE diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 8150c09cd2c..0266a3616ce 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -42,7 +42,7 @@ #include "cx22702.h" #include "or51132.h" #include "lgdt330x.h" -#include "lg_h06xf.h" +#include "lgh06xf.h" #include "nxt200x.h" #include "cx24123.h" #include "isl6421.h" @@ -392,18 +392,6 @@ static int lgdt3302_tuner_set_params(struct dvb_frontend* fe, return 0; } -static int lgdt3303_tuner_set_params(struct dvb_frontend* fe, - struct dvb_frontend_parameters* params) -{ - struct cx8802_dev *dev= fe->dvb->priv; - struct cx88_core *core = dev->core; - - /* Put the analog decoder in standby to keep it quiet */ - cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL); - - return lg_h06xf_pll_set(fe, &core->i2c_adap, params); -} - static int lgdt330x_pll_rf_set(struct dvb_frontend* fe, int index) { struct cx8802_dev *dev= fe->dvb->priv; @@ -719,7 +707,8 @@ static int dvb_register(struct cx8802_dev *dev) &fusionhdtv_5_gold, &dev->core->i2c_adap); if (dev->dvb.frontend != NULL) { - dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3303_tuner_set_params; + dvb_attach(lgh06xf_attach, dev->dvb.frontend, + &dev->core->i2c_adap); } } break; @@ -737,7 +726,8 @@ static int dvb_register(struct cx8802_dev *dev) &pchdtv_hd5500, &dev->core->i2c_adap); if (dev->dvb.frontend != NULL) { - dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3303_tuner_set_params; + dvb_attach(lgh06xf_attach, dev->dvb.frontend, + &dev->core->i2c_adap); } } break; -- cgit v1.2.3 From ff67c614e23bf5a3c16968e2c42ab442121c4beb Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sun, 19 Nov 2006 20:50:31 -0300 Subject: V4L/DVB (4852): Pvrusb2: Fix horizontal resolution setting problem for 24xxx devices Fix long-standing issue which prevented use of 24xxx devices at any horizontal resolution other an 720. The problem is in the cx25840 module, if no attempt is made to initialize VBI there. Such a thing should not be needed, but the pvrusb2 driver is updated now to deal with this. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c | 16 ++++++++++++++ drivers/media/video/pvrusb2/pvrusb2-hdw.c | 26 ----------------------- 2 files changed, 16 insertions(+), 26 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c index c80c26be6e4..848fb233d80 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c +++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c @@ -260,6 +260,22 @@ int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *hdw, sizeof(decoder_ops[0]))) - 1; hdw->decoder_ctrl = &ctxt->ctrl; cp->handler = &ctxt->handler; + { + /* + Mike Isely 19-Nov-2006 - This bit + of nuttiness for cx25840 causes that module to + correctly set up its video scaling. This is really + a problem in the cx25840 module itself, but we work + around it here. The problem has not been seen in + ivtv because there VBI is supported and set up. We + don't do VBI here (at least not yet) and thus we + never attempted to even set it up. + */ + struct v4l2_format fmt; + memset(&fmt,0,sizeof(fmt)); + fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; + pvr2_i2c_client_cmd(ctxt->client,VIDIOC_S_FMT,&fmt); + } pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x cx2584x V4L2 handler set up", cp->client->addr); return !0; diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 1f787333d18..d2004965187 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -356,28 +356,6 @@ static int ctrl_freq_set(struct pvr2_ctrl *cptr,int m,int v) return 0; } -static int ctrl_hres_max_get(struct pvr2_ctrl *cptr,int *vp) -{ - /* If we're dealing with a 24xxx device, force the horizontal - maximum to be 720 no matter what, since we can't get the device - to work properly with any other value. Otherwise just return - the normal value. */ - *vp = cptr->info->def.type_int.max_value; - if (cptr->hdw->hdw_type == PVR2_HDW_TYPE_24XXX) *vp = 720; - return 0; -} - -static int ctrl_hres_min_get(struct pvr2_ctrl *cptr,int *vp) -{ - /* If we're dealing with a 24xxx device, force the horizontal - minimum to be 720 no matter what, since we can't get the device - to work properly with any other value. Otherwise just return - the normal value. */ - *vp = cptr->info->def.type_int.min_value; - if (cptr->hdw->hdw_type == PVR2_HDW_TYPE_24XXX) *vp = 720; - return 0; -} - static int ctrl_vres_max_get(struct pvr2_ctrl *cptr,int *vp) { /* Actual maximum depends on the video standard in effect. */ @@ -758,10 +736,6 @@ static const struct pvr2_ctl_info control_defs[] = { .default_value = 720, DEFREF(res_hor), DEFINT(19,720), - /* Hook in check for clamp on horizontal resolution in - order to avoid unsolved problem involving cx25840. */ - .get_max_value = ctrl_hres_max_get, - .get_min_value = ctrl_hres_min_get, },{ .desc = "Vertical capture resolution", .name = "resolution_ver", -- cgit v1.2.3 From b07b4783fb30dee8c542fc76ed8993108d46d6aa Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 20 Nov 2006 10:23:04 -0300 Subject: V4L/DVB (4854): Handle errors from input_register_device() Also sprinkled some input_sync() throughout the code. Acked-by: Ricardo Cerqueira Acked-by: Oliver Endriss Acked-by: Andrew de Quincey Signed-off-by: Dmitry Torokhov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt8xx/bttv-input.c | 101 ++++++++++++---------- drivers/media/video/cx88/cx88-input.c | 77 ++++++++++------- drivers/media/video/ir-kbd-i2c.c | 43 +++++---- drivers/media/video/saa7134/saa7134-input.c | 48 +++++++--- drivers/media/video/usbvideo/quickcam_messenger.c | 9 +- 5 files changed, 172 insertions(+), 106 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c index 933d6db09ac..cbc012f71f5 100644 --- a/drivers/media/video/bt8xx/bttv-input.c +++ b/drivers/media/video/bt8xx/bttv-input.c @@ -259,24 +259,59 @@ static void bttv_rc5_timer_keyup(unsigned long data) /* ---------------------------------------------------------------------- */ +static void bttv_ir_start(struct bttv *btv, struct bttv_ir *ir) +{ + if (ir->polling) { + init_timer(&ir->timer); + ir->timer.function = bttv_input_timer; + ir->timer.data = (unsigned long)btv; + ir->timer.expires = jiffies + HZ; + add_timer(&ir->timer); + } else if (ir->rc5_gpio) { + /* set timer_end for code completion */ + init_timer(&ir->timer_end); + ir->timer_end.function = bttv_rc5_timer_end; + ir->timer_end.data = (unsigned long)ir; + + init_timer(&ir->timer_keyup); + ir->timer_keyup.function = bttv_rc5_timer_keyup; + ir->timer_keyup.data = (unsigned long)ir; + } +} + +static void bttv_ir_stop(struct bttv *btv) +{ + if (btv->remote->polling) { + del_timer_sync(&btv->remote->timer); + flush_scheduled_work(); + } + + if (btv->remote->rc5_gpio) { + u32 gpio; + + del_timer_sync(&btv->remote->timer_end); + flush_scheduled_work(); + + gpio = bttv_gpio_read(&btv->c); + bttv_gpio_write(&btv->c, gpio & ~(1 << 4)); + } +} + int bttv_input_init(struct bttv *btv) { struct bttv_ir *ir; IR_KEYTAB_TYPE *ir_codes = NULL; struct input_dev *input_dev; int ir_type = IR_TYPE_OTHER; + int err = -ENOMEM; if (!btv->has_remote) return -ENODEV; ir = kzalloc(sizeof(*ir),GFP_KERNEL); input_dev = input_allocate_device(); - if (!ir || !input_dev) { - kfree(ir); - input_free_device(input_dev); - return -ENOMEM; - } - memset(ir,0,sizeof(*ir)); + if (!ir || !input_dev) + goto err_out_free; /* detect & configure */ switch (btv->c.type) { @@ -348,10 +383,9 @@ int bttv_input_init(struct bttv *btv) break; } if (NULL == ir_codes) { - dprintk(KERN_INFO "Ooops: IR config error [card=%d]\n",btv->c.type); - kfree(ir); - input_free_device(input_dev); - return -ENODEV; + dprintk(KERN_INFO "Ooops: IR config error [card=%d]\n", btv->c.type); + err = -ENODEV; + goto err_out_free; } if (ir->rc5_gpio) { @@ -389,32 +423,26 @@ int bttv_input_init(struct bttv *btv) input_dev->cdev.dev = &btv->c.pci->dev; btv->remote = ir; - if (ir->polling) { - init_timer(&ir->timer); - ir->timer.function = bttv_input_timer; - ir->timer.data = (unsigned long)btv; - ir->timer.expires = jiffies + HZ; - add_timer(&ir->timer); - } else if (ir->rc5_gpio) { - /* set timer_end for code completion */ - init_timer(&ir->timer_end); - ir->timer_end.function = bttv_rc5_timer_end; - ir->timer_end.data = (unsigned long)ir; - - init_timer(&ir->timer_keyup); - ir->timer_keyup.function = bttv_rc5_timer_keyup; - ir->timer_keyup.data = (unsigned long)ir; - } + bttv_ir_start(btv, ir); /* all done */ - input_register_device(btv->remote->dev); - printk(DEVNAME ": %s detected at %s\n",ir->name,ir->phys); + err = input_register_device(btv->remote->dev); + if (err) + goto err_out_stop; /* the remote isn't as bouncy as a keyboard */ ir->dev->rep[REP_DELAY] = repeat_delay; ir->dev->rep[REP_PERIOD] = repeat_period; return 0; + + err_out_stop: + bttv_ir_stop(btv); + btv->remote = NULL; + err_out_free: + input_free_device(input_dev); + kfree(ir); + return err; } void bttv_input_fini(struct bttv *btv) @@ -422,22 +450,7 @@ void bttv_input_fini(struct bttv *btv) if (btv->remote == NULL) return; - if (btv->remote->polling) { - del_timer_sync(&btv->remote->timer); - flush_scheduled_work(); - } - - - if (btv->remote->rc5_gpio) { - u32 gpio; - - del_timer_sync(&btv->remote->timer_end); - flush_scheduled_work(); - - gpio = bttv_gpio_read(&btv->c); - bttv_gpio_write(&btv->c, gpio & ~(1 << 4)); - } - + bttv_ir_stop(btv); input_unregister_device(btv->remote->dev); kfree(btv->remote); btv->remote = NULL; diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index e60a0a52e4b..c6d412b1f21 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -155,6 +155,35 @@ static void cx88_ir_work(struct work_struct *work) mod_timer(&ir->timer, timeout); } +static void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir) +{ + if (ir->polling) { + INIT_WORK(&ir->work, cx88_ir_work, ir); + init_timer(&ir->timer); + ir->timer.function = ir_timer; + ir->timer.data = (unsigned long)ir; + schedule_work(&ir->work); + } + if (ir->sampling) { + core->pci_irqmask |= (1 << 18); /* IR_SMP_INT */ + cx_write(MO_DDS_IO, 0xa80a80); /* 4 kHz sample rate */ + cx_write(MO_DDSCFG_IO, 0x5); /* enable */ + } +} + +static void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir) +{ + if (ir->sampling) { + cx_write(MO_DDSCFG_IO, 0x0); + core->pci_irqmask &= ~(1 << 18); + } + + if (ir->polling) { + del_timer_sync(&ir->timer); + flush_scheduled_work(); + } +} + /* ---------------------------------------------------------------------- */ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) @@ -163,14 +192,12 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) struct input_dev *input_dev; IR_KEYTAB_TYPE *ir_codes = NULL; int ir_type = IR_TYPE_OTHER; + int err = -ENOMEM; ir = kzalloc(sizeof(*ir), GFP_KERNEL); input_dev = input_allocate_device(); - if (!ir || !input_dev) { - kfree(ir); - input_free_device(input_dev); - return -ENOMEM; - } + if (!ir || !input_dev) + goto err_out_free; ir->input = input_dev; @@ -280,9 +307,8 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) } if (NULL == ir_codes) { - kfree(ir); - input_free_device(input_dev); - return -ENODEV; + err = -ENODEV; + goto err_out_free; } /* init input device */ @@ -307,23 +333,22 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) ir->core = core; core->ir = ir; - if (ir->polling) { - INIT_WORK(&ir->work, cx88_ir_work); - init_timer(&ir->timer); - ir->timer.function = ir_timer; - ir->timer.data = (unsigned long)ir; - schedule_work(&ir->work); - } - if (ir->sampling) { - core->pci_irqmask |= (1 << 18); /* IR_SMP_INT */ - cx_write(MO_DDS_IO, 0xa80a80); /* 4 kHz sample rate */ - cx_write(MO_DDSCFG_IO, 0x5); /* enable */ - } + cx88_ir_start(core, ir); /* all done */ - input_register_device(ir->input); + err = input_register_device(ir->input); + if (err) + goto err_out_stop; return 0; + + err_out_stop: + cx88_ir_stop(core, ir); + core->ir = NULL; + err_out_free: + input_free_device(input_dev); + kfree(ir); + return err; } int cx88_ir_fini(struct cx88_core *core) @@ -334,15 +359,7 @@ int cx88_ir_fini(struct cx88_core *core) if (NULL == ir) return 0; - if (ir->sampling) { - cx_write(MO_DDSCFG_IO, 0x0); - core->pci_irqmask &= ~(1 << 18); - } - if (ir->polling) { - del_timer(&ir->timer); - flush_scheduled_work(); - } - + cx88_ir_stop(core, ir); input_unregister_device(ir->input); kfree(ir); diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index ab87e7bfe84..dd6341f2e39 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -305,15 +305,14 @@ static int ir_attach(struct i2c_adapter *adap, int addr, int ir_type; struct IR_i2c *ir; struct input_dev *input_dev; + int err; ir = kzalloc(sizeof(struct IR_i2c),GFP_KERNEL); input_dev = input_allocate_device(); if (!ir || !input_dev) { - input_free_device(input_dev); - kfree(ir); - return -ENOMEM; + err = -ENOMEM; + goto err_out_free; } - memset(ir,0,sizeof(*ir)); ir->c = client_template; ir->input = input_dev; @@ -361,26 +360,27 @@ static int ir_attach(struct i2c_adapter *adap, int addr, break; default: /* shouldn't happen */ - printk(DEVNAME ": Huh? unknown i2c address (0x%02x)?\n",addr); - kfree(ir); - return -1; + printk(DEVNAME ": Huh? unknown 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; + ir->ir_codes = ir_codes; /* register i2c device * At device register, IR codes may be changed to be * board dependent. */ - i2c_attach_client(&ir->c); + err = i2c_attach_client(&ir->c); + if (err) + goto err_out_free; /* If IR not supported or disabled, unregisters driver */ if (ir->get_key == NULL) { - i2c_detach_client(&ir->c); - kfree(ir); - return -1; + err = -ENODEV; + goto err_out_detach; } /* Phys addr can only be set after attaching (for ir->c.dev.bus_id) */ @@ -389,15 +389,17 @@ static int ir_attach(struct i2c_adapter *adap, int addr, ir->c.dev.bus_id); /* init + register input device */ - ir_input_init(input_dev,&ir->ir,ir_type,ir->ir_codes); + 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->phys = ir->phys; - /* register event device */ - input_register_device(ir->input); + err = input_register_device(ir->input); + if (err) + goto err_out_detach; + printk(DEVNAME ": %s detected at %s [%s]\n", - ir->input->name,ir->input->phys,adap->name); + ir->input->name, ir->input->phys, adap->name); /* start polling via eventd */ INIT_WORK(&ir->work, ir_work); @@ -407,6 +409,13 @@ static int ir_attach(struct i2c_adapter *adap, int addr, schedule_work(&ir->work); 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) @@ -414,7 +423,7 @@ static int ir_detach(struct i2c_client *client) struct IR_i2c *ir = i2c_get_clientdata(client); /* kill outstanding polls */ - del_timer(&ir->timer); + del_timer_sync(&ir->timer); flush_scheduled_work(); /* unregister devices */ diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 83887d1876a..5d2bf15239f 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -131,6 +131,23 @@ static void saa7134_input_timer(unsigned long data) mod_timer(&ir->timer, timeout); } +static void saa7134_ir_start(struct saa7134_dev *dev, struct saa7134_ir *ir) +{ + if (ir->polling) { + init_timer(&ir->timer); + ir->timer.function = saa7134_input_timer; + ir->timer.data = (unsigned long)dev; + ir->timer.expires = jiffies + HZ; + add_timer(&ir->timer); + } +} + +static void saa7134_ir_stop(struct saa7134_dev *dev) +{ + if (dev->remote->polling) + del_timer_sync(&dev->remote->timer); +} + int saa7134_input_init1(struct saa7134_dev *dev) { struct saa7134_ir *ir; @@ -141,6 +158,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) u32 mask_keyup = 0; int polling = 0; int ir_type = IR_TYPE_OTHER; + int err; if (dev->has_remote != SAA7134_REMOTE_GPIO) return -ENODEV; @@ -267,9 +285,8 @@ int saa7134_input_init1(struct saa7134_dev *dev) ir = kzalloc(sizeof(*ir), GFP_KERNEL); input_dev = input_allocate_device(); if (!ir || !input_dev) { - kfree(ir); - input_free_device(input_dev); - return -ENOMEM; + err = -ENOMEM; + goto err_out_free; } ir->dev = input_dev; @@ -300,18 +317,22 @@ int saa7134_input_init1(struct saa7134_dev *dev) } input_dev->cdev.dev = &dev->pci->dev; - /* all done */ dev->remote = ir; - if (ir->polling) { - init_timer(&ir->timer); - ir->timer.function = saa7134_input_timer; - ir->timer.data = (unsigned long)dev; - ir->timer.expires = jiffies + HZ; - add_timer(&ir->timer); - } + saa7134_ir_start(dev, ir); + + err = input_register_device(ir->dev); + if (err) + goto err_out_stop; - input_register_device(ir->dev); return 0; + + err_out_stop: + saa7134_ir_stop(dev); + dev->remote = NULL; + err_out_free: + input_free_device(input_dev); + kfree(ir); + return err; } void saa7134_input_fini(struct saa7134_dev *dev) @@ -319,8 +340,7 @@ void saa7134_input_fini(struct saa7134_dev *dev) if (NULL == dev->remote) return; - if (dev->remote->polling) - del_timer_sync(&dev->remote->timer); + saa7134_ir_stop(dev); input_unregister_device(dev->remote->dev); kfree(dev->remote); dev->remote = NULL; diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c index bbf2beeeb44..ec0ff2247f0 100644 --- a/drivers/media/video/usbvideo/quickcam_messenger.c +++ b/drivers/media/video/usbvideo/quickcam_messenger.c @@ -86,6 +86,7 @@ MODULE_DEVICE_TABLE(usb, qcm_table); static void qcm_register_input(struct qcm *cam, struct usb_device *dev) { struct input_dev *input_dev; + int error; usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname)); strncat(cam->input_physname, "/input0", sizeof(cam->input_physname)); @@ -106,7 +107,13 @@ static void qcm_register_input(struct qcm *cam, struct usb_device *dev) input_dev->private = cam; - input_register_device(cam->input); + error = input_register_device(cam->input); + if (error) { + warn("Failed to register camera's input device, err: %d\n", + error); + input_free_device(cam->input); + cam->input = NULL; + } } static void qcm_unregister_input(struct qcm *cam) -- cgit v1.2.3 From c6aeb11127a8a4266d613563f737a1d60cfae628 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 20 Nov 2006 12:06:54 -0300 Subject: V4L/DVB (4857): Cleans some ioctl structs before calling V4L2 counterpart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l1-compat.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c index 1d899e2db39..06221a0c38a 100644 --- a/drivers/media/video/v4l1-compat.c +++ b/drivers/media/video/v4l1-compat.c @@ -714,6 +714,7 @@ v4l_compat_translate_ioctl(struct inode *inode, case VIDIOCGFREQ: /* get frequency */ { unsigned long *freq = arg; + memset(&freq2,0,sizeof(freq2)); freq2.tuner = 0; err = drv(inode, file, VIDIOC_G_FREQUENCY, &freq2); @@ -726,8 +727,8 @@ v4l_compat_translate_ioctl(struct inode *inode, case VIDIOCSFREQ: /* set frequency */ { unsigned long *freq = arg; + memset(&freq2,0,sizeof(freq2)); - freq2.tuner = 0; drv(inode, file, VIDIOC_G_FREQUENCY, &freq2); freq2.frequency = *freq; err = drv(inode, file, VIDIOC_S_FREQUENCY, &freq2); @@ -738,6 +739,7 @@ v4l_compat_translate_ioctl(struct inode *inode, case VIDIOCGAUDIO: /* get audio properties/controls */ { struct video_audio *aud = arg; + memset(&aud2,0,sizeof(aud2)); err = drv(inode, file, VIDIOC_G_AUDIO, &aud2); if (err < 0) { @@ -898,6 +900,7 @@ v4l_compat_translate_ioctl(struct inode *inode, { int *i = arg; + memset(&buf2,0,sizeof(buf2)); buf2.index = *i; buf2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; err = drv(inode, file, VIDIOC_QUERYBUF, &buf2); -- cgit v1.2.3 From 2aa92ffd58493887adde850fe510031e48f12bac Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 20 Nov 2006 12:10:04 -0300 Subject: V4L/DVB (4858): Fix: implement missing VIDIOCSTUNER on v4l1-compat module Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l1-compat.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c index 06221a0c38a..701856e6adb 100644 --- a/drivers/media/video/v4l1-compat.c +++ b/drivers/media/video/v4l1-compat.c @@ -708,7 +708,16 @@ v4l_compat_translate_ioctl(struct inode *inode, } case VIDIOCSTUNER: /* select a tuner input */ { - err = 0; + struct video_tuner *tun = arg; + struct v4l2_tuner t; + memset(&t,0,sizeof(t)); + + t.index=tun->tuner; + + err = drv(inode, file, VIDIOC_S_INPUT, &t); + if (err < 0) + dprintk("VIDIOCSTUNER / VIDIOC_S_INPUT: %d\n",err); + break; } case VIDIOCGFREQ: /* get frequency */ -- cgit v1.2.3 From 7964b1b1c27dea88eb89b10f774893ec11cf973d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 20 Nov 2006 12:10:43 -0300 Subject: V4L/DVB (4859): Fix initializations on some video_ioctl2 handlers Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videodev.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/media/video') diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 41ec0c4b35a..9024ea2557f 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -1088,9 +1088,13 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_G_AUDIO: { struct v4l2_audio *p=arg; + __u32 index=p->index; if (!vfd->vidioc_g_audio) break; + + memset(p,0,sizeof(*p)); + p->index=index; dbgarg(cmd, "Get for index=%d\n", p->index); ret=vfd->vidioc_g_audio(file, fh, p); if (!ret) @@ -1329,8 +1333,14 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_G_TUNER: { struct v4l2_tuner *p=arg; + __u32 index=p->index; + if (!vfd->vidioc_g_tuner) break; + + memset(p,0,sizeof(*p)); + p->index=index; + ret=vfd->vidioc_g_tuner(file, fh, p); if (!ret) dbgarg (cmd, "index=%d, name=%s, type=%d, " @@ -1363,6 +1373,9 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_frequency *p=arg; if (!vfd->vidioc_g_frequency) break; + + memset(p,0,sizeof(*p)); + ret=vfd->vidioc_g_frequency(file, fh, p); if (!ret) dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n", -- cgit v1.2.3 From 207705cd7f82b9f160c6ed552d5788a823701fd1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 20 Nov 2006 12:13:25 -0300 Subject: V4L/DVB (4860): Optimization of v4l1 handling Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videodev.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 9024ea2557f..ad42deebdc4 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -428,6 +428,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, v4l_print_ioctl(vfd->name, cmd); } + if (_IOC_TYPE(cmd)=='v') + return v4l_compat_translate_ioctl(inode,file,cmd,arg, + __video_do_ioctl); + switch(cmd) { /* --- capabilities ------------------------------------------ */ case VIDIOC_QUERYCAP: @@ -1409,12 +1413,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, ret=vfd->vidioc_log_status(file, fh); break; } - - /* --- Others --------------------------------------------- */ - - default: - ret=v4l_compat_translate_ioctl(inode,file,cmd,arg,__video_do_ioctl); - } + } /* switch */ if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { if (ret<0) { -- cgit v1.2.3 From e75f9cee32827853fc2f9d1ceb6352e3edc33e9d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 20 Nov 2006 13:19:20 -0300 Subject: V4L/DVB (4861): Remove the need of a STD array for drivers using video_ioctl2 video_ioctl2 will auto-generate standard entries at ENUM_FMT. Also, now, a driver may return a subset of the video array at the return, to be stored as the current_norm. For example, a driver may ask for V4L2_STD_PAL. At return, driver may change it to V4L2_STD_PAL_B. This way, a futher call to G_STD will return the exact detected video std. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cafe_ccic.c | 18 +----- drivers/media/video/v4l2-common.c | 73 ++++++++++++++++++++++ drivers/media/video/videodev.c | 126 ++++++++++++++++++++++++-------------- drivers/media/video/vivi.c | 16 +---- 4 files changed, 159 insertions(+), 74 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index dc6e16c2b83..30864dac26a 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -1679,24 +1679,11 @@ static int cafe_vidioc_s_input(struct file *filp, void *priv, unsigned int i) } /* from vivi.c */ -static int cafe_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id a) +static int cafe_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a) { return 0; } - -/* - * The TV Norm stuff is weird - we're a camera with little to do with TV, - * really. The following is what vivi does. - */ -static struct v4l2_tvnorm cafe_tvnorm[] = { - { - .name = "NTSC-M", - .id = V4L2_STD_NTSC_M, - } -}; - - static void cafe_v4l_dev_release(struct video_device *vd) { struct cafe_camera *cam = container_of(vd, struct cafe_camera, v4ldev); @@ -1726,8 +1713,7 @@ static struct video_device cafe_v4l_template = { .type = VFL_TYPE_GRABBER, .type2 = VID_TYPE_CAPTURE, .minor = -1, /* Get one dynamically */ - .tvnorms = cafe_tvnorm, - .tvnormsize = 1, + .tvnorms = V4L2_STD_NTSC_M, .current_norm = V4L2_STD_NTSC_M, /* make mplayer happy */ .fops = &cafe_v4l_fops, diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index b0b4abe5c29..752c82c37f5 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -87,6 +87,78 @@ MODULE_LICENSE("GPL"); */ +char *v4l2_norm_to_name(v4l2_std_id id) +{ + char *name; + + switch (id) { + case V4L2_STD_PAL: + name="PAL"; break; + case V4L2_STD_PAL_BG: + name="PAL-BG"; break; + case V4L2_STD_PAL_DK: + name="PAL-DK"; break; + case V4L2_STD_PAL_B: + name="PAL-B"; break; + case V4L2_STD_PAL_B1: + name="PAL-B1"; break; + case V4L2_STD_PAL_G: + name="PAL-G"; break; + case V4L2_STD_PAL_H: + name="PAL-H"; break; + case V4L2_STD_PAL_I: + name="PAL-I"; break; + case V4L2_STD_PAL_D: + name="PAL-D"; break; + case V4L2_STD_PAL_D1: + name="PAL-D1"; break; + case V4L2_STD_PAL_K: + name="PAL-K"; break; + case V4L2_STD_PAL_M: + name="PAL-M"; break; + case V4L2_STD_PAL_N: + name="PAL-N"; break; + case V4L2_STD_PAL_Nc: + name="PAL-Nc"; break; + case V4L2_STD_PAL_60: + name="PAL-60"; break; + case V4L2_STD_NTSC: + name="NTSC"; break; + case V4L2_STD_NTSC_M: + name="NTSC-M"; break; + case V4L2_STD_NTSC_M_JP: + name="NTSC-M-JP"; break; + case V4L2_STD_NTSC_443: + name="NTSC-443"; break; + case V4L2_STD_NTSC_M_KR: + name="NTSC-M-KR"; break; + case V4L2_STD_SECAM: + name="SECAM"; break; + case V4L2_STD_SECAM_DK: + name="SECAM-DK"; break; + case V4L2_STD_SECAM_B: + name="SECAM-B"; break; + case V4L2_STD_SECAM_D: + name="SECAM-D"; break; + case V4L2_STD_SECAM_G: + name="SECAM-G"; break; + case V4L2_STD_SECAM_H: + name="SECAM-H"; break; + case V4L2_STD_SECAM_K: + name="SECAM-K"; break; + case V4L2_STD_SECAM_K1: + name="SECAM-K1"; break; + case V4L2_STD_SECAM_L: + name="SECAM-L"; break; + case V4L2_STD_SECAM_LC: + name="SECAM-LC"; break; + default: + name="Unknown"; break; + } + + return name; +} + /* Fill in the fields of a v4l2_standard structure according to the 'id' and 'transmission' parameters. Returns negative on error. */ int v4l2_video_std_construct(struct v4l2_standard *vs, @@ -1453,6 +1525,7 @@ u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id) /* ----------------------------------------------------------------- */ +EXPORT_SYMBOL(v4l2_norm_to_name); EXPORT_SYMBOL(v4l2_video_std_construct); EXPORT_SYMBOL(v4l2_prio_init); diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index ad42deebdc4..1be712757e4 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -833,20 +833,85 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_ENUMSTD: { struct v4l2_standard *p = arg; - unsigned int index = p->index; + v4l2_std_id id = vfd->tvnorms,curr_id=0; + unsigned int index = p->index,i; - if (!vfd->tvnormsize) { - printk (KERN_WARNING "%s: no TV norms defined!\n", - vfd->name); + if (index<0) { + ret=-EINVAL; break; } - if (index<0 || index >= vfd->tvnormsize) { - ret=-EINVAL; - break; + /* Return norm array on a canonical way */ + for (i=0;i<= index && id; i++) { + if ( (id & V4L2_STD_PAL) == V4L2_STD_PAL) { + curr_id = V4L2_STD_PAL; + } else if ( (id & V4L2_STD_PAL_BG) == V4L2_STD_PAL_BG) { + curr_id = V4L2_STD_PAL_BG; + } else if ( (id & V4L2_STD_PAL_DK) == V4L2_STD_PAL_DK) { + curr_id = V4L2_STD_PAL_DK; + } else if ( (id & V4L2_STD_PAL_B) == V4L2_STD_PAL_B) { + curr_id = V4L2_STD_PAL_B; + } else if ( (id & V4L2_STD_PAL_B1) == V4L2_STD_PAL_B1) { + curr_id = V4L2_STD_PAL_B1; + } else if ( (id & V4L2_STD_PAL_G) == V4L2_STD_PAL_G) { + curr_id = V4L2_STD_PAL_G; + } else if ( (id & V4L2_STD_PAL_H) == V4L2_STD_PAL_H) { + curr_id = V4L2_STD_PAL_H; + } else if ( (id & V4L2_STD_PAL_I) == V4L2_STD_PAL_I) { + curr_id = V4L2_STD_PAL_I; + } else if ( (id & V4L2_STD_PAL_D) == V4L2_STD_PAL_D) { + curr_id = V4L2_STD_PAL_D; + } else if ( (id & V4L2_STD_PAL_D1) == V4L2_STD_PAL_D1) { + curr_id = V4L2_STD_PAL_D1; + } else if ( (id & V4L2_STD_PAL_K) == V4L2_STD_PAL_K) { + curr_id = V4L2_STD_PAL_K; + } else if ( (id & V4L2_STD_PAL_M) == V4L2_STD_PAL_M) { + curr_id = V4L2_STD_PAL_M; + } else if ( (id & V4L2_STD_PAL_N) == V4L2_STD_PAL_N) { + curr_id = V4L2_STD_PAL_N; + } else if ( (id & V4L2_STD_PAL_Nc) == V4L2_STD_PAL_Nc) { + curr_id = V4L2_STD_PAL_Nc; + } else if ( (id & V4L2_STD_PAL_60) == V4L2_STD_PAL_60) { + curr_id = V4L2_STD_PAL_60; + } else if ( (id & V4L2_STD_NTSC) == V4L2_STD_NTSC) { + curr_id = V4L2_STD_NTSC; + } else if ( (id & V4L2_STD_NTSC_M) == V4L2_STD_NTSC_M) { + curr_id = V4L2_STD_NTSC_M; + } else if ( (id & V4L2_STD_NTSC_M_JP) == V4L2_STD_NTSC_M_JP) { + curr_id = V4L2_STD_NTSC_M_JP; + } else if ( (id & V4L2_STD_NTSC_443) == V4L2_STD_NTSC_443) { + curr_id = V4L2_STD_NTSC_443; + } else if ( (id & V4L2_STD_NTSC_M_KR) == V4L2_STD_NTSC_M_KR) { + curr_id = V4L2_STD_NTSC_M_KR; + } else if ( (id & V4L2_STD_SECAM) == V4L2_STD_SECAM) { + curr_id = V4L2_STD_SECAM; + } else if ( (id & V4L2_STD_SECAM_DK) == V4L2_STD_SECAM_DK) { + curr_id = V4L2_STD_SECAM_DK; + } else if ( (id & V4L2_STD_SECAM_B) == V4L2_STD_SECAM_B) { + curr_id = V4L2_STD_SECAM_B; + } else if ( (id & V4L2_STD_SECAM_D) == V4L2_STD_SECAM_D) { + curr_id = V4L2_STD_SECAM_D; + } else if ( (id & V4L2_STD_SECAM_G) == V4L2_STD_SECAM_G) { + curr_id = V4L2_STD_SECAM_G; + } else if ( (id & V4L2_STD_SECAM_H) == V4L2_STD_SECAM_H) { + curr_id = V4L2_STD_SECAM_H; + } else if ( (id & V4L2_STD_SECAM_K) == V4L2_STD_SECAM_K) { + curr_id = V4L2_STD_SECAM_K; + } else if ( (id & V4L2_STD_SECAM_K1) == V4L2_STD_SECAM_K1) { + curr_id = V4L2_STD_SECAM_K1; + } else if ( (id & V4L2_STD_SECAM_L) == V4L2_STD_SECAM_L) { + curr_id = V4L2_STD_SECAM_L; + } else if ( (id & V4L2_STD_SECAM_LC) == V4L2_STD_SECAM_LC) { + curr_id = V4L2_STD_SECAM_LC; + } else { + break; + } + id &= ~curr_id; } - v4l2_video_std_construct(p, vfd->tvnorms[p->index].id, - vfd->tvnorms[p->index].name); + if (i<=index) + return -EINVAL; + + v4l2_video_std_construct(p, curr_id,v4l2_norm_to_name(curr_id)); p->index = index; dbgarg (cmd, "index=%d, id=%Ld, name=%s, fps=%d/%d, " @@ -872,39 +937,23 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, } case VIDIOC_S_STD: { - v4l2_std_id *id = arg; - unsigned int i; - - if (!vfd->tvnormsize) { - printk (KERN_WARNING "%s: no TV norms defined!\n", - vfd->name); - break; - } + v4l2_std_id *id = arg,norm; dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id); - /* First search for exact match */ - for (i = 0; i < vfd->tvnormsize; i++) - if (*id == vfd->tvnorms[i].id) - break; - /* Then for a generic video std that contains desired std */ - if (i == vfd->tvnormsize) - for (i = 0; i < vfd->tvnormsize; i++) - if (*id & vfd->tvnorms[i].id) - break; - if (i == vfd->tvnormsize) { + norm = (*id) & vfd->tvnorms; + if ( vfd->tvnorms && !norm) /* Check if std is supported */ break; - } /* Calls the specific handler */ if (vfd->vidioc_s_std) - ret=vfd->vidioc_s_std(file, fh, i); + ret=vfd->vidioc_s_std(file, fh, &norm); else ret=-EINVAL; /* Updates standard information */ - if (!ret) - vfd->current_norm=*id; + if (ret>=0) + vfd->current_norm=norm; break; } @@ -1296,25 +1345,12 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, ret=vfd->vidioc_g_parm(file, fh, p); } else { struct v4l2_standard s; - int i; - - if (!vfd->tvnormsize) { - printk (KERN_WARNING "%s: no TV norms defined!\n", - vfd->name); - break; - } if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - for (i = 0; i < vfd->tvnormsize; i++) - if (vfd->tvnorms[i].id == vfd->current_norm) - break; - if (i >= vfd->tvnormsize) - return -EINVAL; - v4l2_video_std_construct(&s, vfd->current_norm, - vfd->tvnorms[i].name); + v4l2_norm_to_name(vfd->current_norm)); memset(p,0,sizeof(*p)); diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 9986de5cb3d..474ddb77964 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -1044,16 +1044,8 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) return (0); } -static struct v4l2_tvnorm tvnorms[] = { - { - .name = "NTSC-M", - .id = V4L2_STD_NTSC_M, - } -}; - -static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id a) +static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *i) { - return 0; } @@ -1333,8 +1325,8 @@ static struct video_device vivi = { #ifdef CONFIG_VIDEO_V4L1_COMPAT .vidiocgmbuf = vidiocgmbuf, #endif - .tvnorms = tvnorms, - .tvnormsize = ARRAY_SIZE(tvnorms), + .tvnorms = V4L2_STD_NTSC_M, + .current_norm = V4L2_STD_NTSC_M, }; /* ----------------------------------------------------------------- Initialization and module stuff @@ -1361,8 +1353,6 @@ static int __init vivi_init(void) dev->vidq.timeout.data = (unsigned long)dev; init_timer(&dev->vidq.timeout); - vivi.current_norm = tvnorms[0].id; - ret = video_register_device(&vivi, VFL_TYPE_GRABBER, video_nr); printk(KERN_INFO "Video Technology Magazine Virtual Video Capture Board (Load status: %d)\n", ret); return ret; -- cgit v1.2.3 From 499c18698990463b84c23ddc98104517fe759ee8 Mon Sep 17 00:00:00 2001 From: "audetto@tiscali.it" Date: Mon, 20 Nov 2006 18:27:44 -0300 Subject: V4L/DVB (4862): Fixes uninitialized variables passed to VIDIOC_G_FBUF. Signed-off-by: Andrea A Odetti Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l1-compat.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media/video') diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c index 701856e6adb..8a13e595304 100644 --- a/drivers/media/video/v4l1-compat.c +++ b/drivers/media/video/v4l1-compat.c @@ -350,6 +350,7 @@ v4l_compat_translate_ioctl(struct inode *inode, struct video_buffer *buffer = arg; memset(buffer, 0, sizeof(*buffer)); + memset(&fbuf2, 0, sizeof(fbuf2)); err = drv(inode, file, VIDIOC_G_FBUF, &fbuf2); if (err < 0) { @@ -616,6 +617,7 @@ v4l_compat_translate_ioctl(struct inode *inode, case VIDIOCSPICT: /* set tone controls & partial capture format */ { struct video_picture *pict = arg; + memset(&fbuf2, 0, sizeof(fbuf2)); set_v4l_control(inode, file, V4L2_CID_BRIGHTNESS, pict->brightness, drv); -- cgit v1.2.3 From 5cfbacd0d3ee0c9f68e1ad3f24c4e1f879cc47a7 Mon Sep 17 00:00:00 2001 From: Hartmut Hackmann Date: Tue, 21 Nov 2006 19:59:27 -0300 Subject: V4L/DVB (4872): Saa7134-alsa improvements The change does the following: - At device open, it sets the recording source to the current input instead of LINE2. So it is no longer necessary to set the recording source with a mixer application. - Connects the mixer volume control to the input sensitivity selection of the analog sound inputs. This allows only one 6db step. Signed-off-by: Hartmut Hackmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-alsa.c | 63 +++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 9 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c index 4abf5c03a74..ffb0f647a86 100644 --- a/drivers/media/video/saa7134/saa7134-alsa.c +++ b/drivers/media/video/saa7134/saa7134-alsa.c @@ -1,10 +1,6 @@ /* * SAA713x ALSA support for V4L * - * - * Caveats: - * - Volume doesn't work (it's always at max) - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 2 @@ -614,13 +610,18 @@ static int snd_card_saa7134_capture_open(struct snd_pcm_substream * substream) snd_card_saa7134_pcm_t *pcm; snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream); struct saa7134_dev *dev = saa7134->dev; - int err; + int amux, err; mutex_lock(&dev->dmasound.lock); dev->dmasound.read_count = 0; dev->dmasound.read_offset = 0; + amux = dev->input->amux; + if ((amux < 1) || (amux > 3)) + amux = 1; + dev->dmasound.input = amux - 1; + mutex_unlock(&dev->dmasound.lock); pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); @@ -713,6 +714,8 @@ static int snd_saa7134_volume_put(struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol) { snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol); + struct saa7134_dev *dev = chip->dev; + int change, addr = kcontrol->private_value; int left, right; @@ -727,10 +730,52 @@ static int snd_saa7134_volume_put(struct snd_kcontrol * kcontrol, if (right > 20) right = 20; spin_lock_irq(&chip->mixer_lock); - change = chip->mixer_volume[addr][0] != left || - chip->mixer_volume[addr][1] != right; - chip->mixer_volume[addr][0] = left; - chip->mixer_volume[addr][1] = right; + change = 0; + if (chip->mixer_volume[addr][0] != left) { + change = 1; + right = left; + } + if (chip->mixer_volume[addr][1] != right) { + change = 1; + left = right; + } + if (change) { + switch (dev->pci->device) { + case PCI_DEVICE_ID_PHILIPS_SAA7134: + switch (addr) { + case MIXER_ADDR_TVTUNER: + left = 20; + break; + case MIXER_ADDR_LINE1: + saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x10, + (left > 10) ? 0x00 : 0x10); + break; + case MIXER_ADDR_LINE2: + saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x20, + (left > 10) ? 0x00 : 0x20); + break; + } + break; + case PCI_DEVICE_ID_PHILIPS_SAA7133: + case PCI_DEVICE_ID_PHILIPS_SAA7135: + switch (addr) { + case MIXER_ADDR_TVTUNER: + left = 20; + break; + case MIXER_ADDR_LINE1: + saa_andorb(0x0594, 0x10, + (left > 10) ? 0x00 : 0x10); + break; + case MIXER_ADDR_LINE2: + saa_andorb(0x0594, 0x20, + (left > 10) ? 0x00 : 0x20); + break; + } + break; + } + chip->mixer_volume[addr][0] = left; + chip->mixer_volume[addr][1] = right; + } spin_unlock_irq(&chip->mixer_lock); return change; } -- cgit v1.2.3 From d0d30c03ed7d51bef6e40805988134bdd7042740 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 25 Nov 2006 09:45:50 -0300 Subject: V4L/DVB (4886): Minor coding style improvements Remove coding style inconsistencies. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7115.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index f28398dd9d9..c2374ed7ba9 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -851,7 +851,7 @@ static int saa711x_set_size(struct i2c_client *client, int width, int height) /* On 60Hz, it is using a higher Vertical Output Size */ if (!is_50hz) - res+=(VRES_60HZ-480)>>1; + res += (VRES_60HZ - 480) >> 1; /* height */ saa711x_write(client, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH, @@ -907,7 +907,7 @@ static int saa711x_set_size(struct i2c_client *client, int width, int height) /* Activates task "B" */ saa711x_write(client, R_80_GLOBAL_CNTL_1, - saa711x_read(client,R_80_GLOBAL_CNTL_1)|0x20); + saa711x_read(client,R_80_GLOBAL_CNTL_1) | 0x20); return 0; } @@ -932,11 +932,11 @@ static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std) if (std & V4L2_STD_525_60) { v4l_dbg(1, debug, client, "decoder set standard 60 Hz\n"); saa711x_writeregs(client, saa7115_cfg_60hz_video); - saa711x_set_size(client,720,480); + saa711x_set_size(client, 720, 480); } else { v4l_dbg(1, debug, client, "decoder set standard 50 Hz\n"); saa711x_writeregs(client, saa7115_cfg_50hz_video); - saa711x_set_size(client,720,576); + saa711x_set_size(client, 720, 576); } /* Register 0E - Bits D6-D4 on NO-AUTO mode @@ -1464,13 +1464,13 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind) client->driver = &i2c_driver_saa711x; snprintf(client->name, sizeof(client->name) - 1, "saa7115"); - for (i=0;i<0x0f;i++) { + for (i = 0; i < 0x0f; i++) { saa711x_write(client, 0, i); - name[i] = (saa711x_read(client, 0) &0x0f) +'0'; - if (name[i]>'9') - name[i]+='a'-'9'-1; + name[i] = (saa711x_read(client, 0) & 0x0f) + '0'; + if (name[i] > '9') + name[i] += 'a' - '9' - 1; } - name[i]='\0'; + name[i] = '\0'; saa711x_write(client, 0, 5); chip_id = saa711x_read(client, 0) & 0x0f; -- cgit v1.2.3 From af249982dc385b18ea340323f50f585e989b76e5 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 26 Nov 2006 09:47:07 -0300 Subject: V4L/DVB (4887): Remove the broken VIDEO_ZR36120 driver The VIDEO_ZR36120 driver has: - already been marked as BROKEN in 2.6.0 three years ago and - is still marked as BROKEN. Drivers that had been marked as BROKEN for such a long time seem to be unlikely to be revived in the forseeable future. But if anyone wants to ever revive this driver, the code is still present in the older kernel releases. Signed-off-by: Adrian Bunk Acked-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 12 - drivers/media/video/Makefile | 2 - drivers/media/video/zr36120.c | 2079 ------------------------------------- drivers/media/video/zr36120.h | 279 ----- drivers/media/video/zr36120_i2c.c | 132 --- drivers/media/video/zr36120_mem.c | 78 -- drivers/media/video/zr36120_mem.h | 3 - 7 files changed, 2585 deletions(-) delete mode 100644 drivers/media/video/zr36120.c delete mode 100644 drivers/media/video/zr36120.h delete mode 100644 drivers/media/video/zr36120_i2c.c delete mode 100644 drivers/media/video/zr36120_mem.c delete mode 100644 drivers/media/video/zr36120_mem.h (limited to 'drivers/media/video') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index c95735cd688..ef803106b79 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -575,18 +575,6 @@ config VIDEO_ZORAN_AVS6EYES help Support for the AverMedia 6 Eyes video surveillance card. -config VIDEO_ZR36120 - tristate "Zoran ZR36120/36125 Video For Linux" - depends on PCI && I2C && VIDEO_V4L1 && BROKEN - help - Support for ZR36120/ZR36125 based frame grabber/overlay boards. - This includes the Victor II, WaveWatcher, Video Wonder, Maxi-TV, - and Buster boards. Please read the material in - for more information. - - To compile this driver as a module, choose M here: the - module will be called zr36120. - config VIDEO_MEYE tristate "Sony Vaio Picturebook Motion Eye Video For Linux" depends on PCI && SONYPI && VIDEO_V4L1 diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 2adb56d01ef..20b9cbc144b 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -2,7 +2,6 @@ # Makefile for the video capture/playback device drivers. # -zoran-objs := zr36120.o zr36120_i2c.o zr36120_mem.o zr36067-objs := zoran_procfs.o zoran_device.o \ zoran_driver.o zoran_card.o tuner-objs := tuner-core.o tuner-types.o tuner-simple.o \ @@ -23,7 +22,6 @@ obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o -obj-$(CONFIG_VIDEO_ZR36120) += zoran.o obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o diff --git a/drivers/media/video/zr36120.c b/drivers/media/video/zr36120.c deleted file mode 100644 index 0cbf564388a..00000000000 --- a/drivers/media/video/zr36120.c +++ /dev/null @@ -1,2079 +0,0 @@ -/* - zr36120.c - Zoran 36120/36125 based framegrabbers - - Copyright (C) 1998-1999 Pauline Middelink - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "tuner.h" -#include "zr36120.h" -#include "zr36120_mem.h" - -/* mark an required function argument unused - lintism */ -#define UNUSED(x) (void)(x) - -/* sensible default */ -#ifndef CARDTYPE -#define CARDTYPE 0 -#endif - -/* Anybody who uses more than four? */ -#define ZORAN_MAX 4 - -static unsigned int triton1=0; /* triton1 chipset? */ -static unsigned int cardtype[ZORAN_MAX]={ [ 0 ... ZORAN_MAX-1 ] = CARDTYPE }; -static int video_nr = -1; -static int vbi_nr = -1; - -static struct pci_device_id zr36120_pci_tbl[] = { - { PCI_VENDOR_ID_ZORAN,PCI_DEVICE_ID_ZORAN_36120, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0 } -}; -MODULE_DEVICE_TABLE(pci, zr36120_pci_tbl); - -MODULE_AUTHOR("Pauline Middelink "); -MODULE_DESCRIPTION("Zoran ZR36120 based framegrabber"); -MODULE_LICENSE("GPL"); - -module_param(triton1, uint, 0); -module_param_array(cardtype, uint, NULL, 0); -module_param(video_nr, int, 0); -module_param(vbi_nr, int, 0); - -static int zoran_cards; -static struct zoran zorans[ZORAN_MAX]; - -/* - * the meaning of each element can be found in zr36120.h - * Determining the value of gpdir/gpval can be tricky. The - * best way is to run the card under the original software - * and read the values from the general purpose registers - * 0x28 and 0x2C. How you do that is left as an exercise - * to the impatient reader :) - */ -#define T 1 /* to separate the bools from the ints */ -#define F 0 -static struct tvcard tvcards[] = { - /* reported working by */ -/*0*/ { "Trust Victor II", - 2, 0, T, T, T, T, 0x7F, 0x80, { 1, SVHS(6) }, { 0 } }, - /* reported working by */ -/*1*/ { "Aitech WaveWatcher TV-PCI", - 3, 0, T, F, T, T, 0x7F, 0x80, { 1, TUNER(3), SVHS(6) }, { 0 } }, - /* reported working by ? */ -/*2*/ { "Genius Video Wonder PCI Video Capture Card", - 2, 0, T, T, T, T, 0x7F, 0x80, { 1, SVHS(6) }, { 0 } }, - /* reported working by */ -/*3*/ { "Guillemot Maxi-TV PCI", - 2, 0, T, T, T, T, 0x7F, 0x80, { 1, SVHS(6) }, { 0 } }, - /* reported working by "Craig Whitmore */ -/*4*/ { "Quadrant Buster", - 3, 3, T, F, T, T, 0x7F, 0x80, { SVHS(1), TUNER(2), 3 }, { 1, 2, 3 } }, - /* a debug entry which has all inputs mapped */ -/*5*/ { "ZR36120 based framegrabber (all inputs enabled)", - 6, 0, T, T, T, T, 0x7F, 0x80, { 1, 2, 3, 4, 5, 6 }, { 0 } } -}; -#undef T -#undef F -#define NRTVCARDS (sizeof(tvcards)/sizeof(tvcards[0])) - -#ifdef __sparc__ -#define ENDIANESS 0 -#else -#define ENDIANESS ZORAN_VFEC_LE -#endif - -static struct { const char name[8]; uint mode; uint bpp; } palette2fmt[] = { -/* n/a */ { "n/a", 0, 0 }, -/* GREY */ { "GRAY", 0, 0 }, -/* HI240 */ { "HI240", 0, 0 }, -/* RGB565 */ { "RGB565", ZORAN_VFEC_RGB_RGB565|ENDIANESS, 2 }, -/* RGB24 */ { "RGB24", ZORAN_VFEC_RGB_RGB888|ENDIANESS|ZORAN_VFEC_PACK24, 3 }, -/* RGB32 */ { "RGB32", ZORAN_VFEC_RGB_RGB888|ENDIANESS, 4 }, -/* RGB555 */ { "RGB555", ZORAN_VFEC_RGB_RGB555|ENDIANESS, 2 }, -/* YUV422 */ { "YUV422", ZORAN_VFEC_RGB_YUV422|ENDIANESS, 2 }, -/* YUYV */ { "YUYV", 0, 0 }, -/* UYVY */ { "UYVY", 0, 0 }, -/* YUV420 */ { "YUV420", 0, 0 }, -/* YUV411 */ { "YUV411", 0, 0 }, -/* RAW */ { "RAW", 0, 0 }, -/* YUV422P */ { "YUV422P", 0, 0 }, -/* YUV411P */ { "YUV411P", 0, 0 }}; -#define NRPALETTES (sizeof(palette2fmt)/sizeof(palette2fmt[0])) -#undef ENDIANESS - -/* ----------------------------------------------------------------------- */ -/* ZORAN chipset detector */ -/* shamelessly stolen from bttv.c */ -/* Reason for beeing here: we need to detect if we are running on a */ -/* Triton based chipset, and if so, enable a certain bit */ -/* ----------------------------------------------------------------------- */ -static -void __init handle_chipset(void) -{ - /* Just in case some nut set this to something dangerous */ - if (triton1) - triton1 = ZORAN_VDC_TRICOM; - - if (pci_pci_problems & PCIPCI_TRITON) { - printk(KERN_INFO "zoran: Host bridge 82437FX Triton PIIX\n"); - triton1 = ZORAN_VDC_TRICOM; - } -} - -/* ----------------------------------------------------------------------- */ -/* ZORAN functions */ -/* ----------------------------------------------------------------------- */ - -static void zoran_set_geo(struct zoran* ztv, struct vidinfo* i); - -#if 0 /* unused */ -static -void zoran_dump(struct zoran *ztv) -{ - char str[256]; - char *p=str; /* shut up, gcc! */ - int i; - - for (i=0; i<0x60; i+=4) { - if ((i % 16) == 0) { - if (i) printk("%s\n",str); - p = str; - p+= sprintf(str, KERN_DEBUG " %04x: ",i); - } - p += sprintf(p, "%08x ",zrread(i)); - } -} -#endif /* unused */ - -static -void reap_states(struct zoran* ztv) -{ - /* count frames */ - ztv->fieldnr++; - - /* - * Are we busy at all? - * This depends on if there is a workqueue AND the - * videotransfer is enabled on the chip... - */ - if (ztv->workqueue && (zrread(ZORAN_VDC) & ZORAN_VDC_VIDEN)) - { - struct vidinfo* newitem; - - /* did we get a complete frame? */ - if (zrread(ZORAN_VSTR) & ZORAN_VSTR_GRAB) - return; - -DEBUG(printk(CARD_DEBUG "completed %s at %p\n",CARD,ztv->workqueue->kindof==FBUFFER_GRAB?"grab":"read",ztv->workqueue)); - - /* we are done with this buffer, tell everyone */ - ztv->workqueue->status = FBUFFER_DONE; - ztv->workqueue->fieldnr = ztv->fieldnr; - /* not good, here for BTTV_FIELDNR reasons */ - ztv->lastfieldnr = ztv->fieldnr; - - switch (ztv->workqueue->kindof) { - case FBUFFER_GRAB: - wake_up_interruptible(&ztv->grabq); - break; - case FBUFFER_VBI: - wake_up_interruptible(&ztv->vbiq); - break; - default: - printk(CARD_INFO "somebody killed the workqueue (kindof=%d)!\n",CARD,ztv->workqueue->kindof); - } - - /* item completed, skip to next item in queue */ - write_lock(&ztv->lock); - newitem = ztv->workqueue->next; - ztv->workqueue->next = 0; /* mark completed */ - ztv->workqueue = newitem; - write_unlock(&ztv->lock); - } - - /* - * ok, so it seems we have nothing in progress right now. - * Lets see if we can find some work. - */ - if (ztv->workqueue) - { - struct vidinfo* newitem; -again: - -DEBUG(printk(CARD_DEBUG "starting %s at %p\n",CARD,ztv->workqueue->kindof==FBUFFER_GRAB?"grab":"read",ztv->workqueue)); - - /* loadup the frame settings */ - read_lock(&ztv->lock); - zoran_set_geo(ztv,ztv->workqueue); - read_unlock(&ztv->lock); - - switch (ztv->workqueue->kindof) { - case FBUFFER_GRAB: - case FBUFFER_VBI: - zrand(~ZORAN_OCR_OVLEN, ZORAN_OCR); - zror(ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR); - zror(ZORAN_VDC_VIDEN,ZORAN_VDC); - - /* start single-shot grab */ - zror(ZORAN_VSTR_GRAB, ZORAN_VSTR); - break; - default: - printk(CARD_INFO "what is this doing on the queue? (kindof=%d)\n",CARD,ztv->workqueue->kindof); - write_lock(&ztv->lock); - newitem = ztv->workqueue->next; - ztv->workqueue->next = 0; - ztv->workqueue = newitem; - write_unlock(&ztv->lock); - if (newitem) - goto again; /* yeah, sure.. */ - } - /* bye for now */ - return; - } -DEBUG(printk(CARD_DEBUG "nothing in queue\n",CARD)); - - /* - * What? Even the workqueue is empty? Am i really here - * for nothing? Did i come all that way to... do nothing? - */ - - /* do we need to overlay? */ - if (test_bit(STATE_OVERLAY, &ztv->state)) - { - /* are we already overlaying? */ - if (!(zrread(ZORAN_OCR) & ZORAN_OCR_OVLEN) || - !(zrread(ZORAN_VDC) & ZORAN_VDC_VIDEN)) - { -DEBUG(printk(CARD_DEBUG "starting overlay\n",CARD)); - - read_lock(&ztv->lock); - zoran_set_geo(ztv,&ztv->overinfo); - read_unlock(&ztv->lock); - - zror(ZORAN_OCR_OVLEN, ZORAN_OCR); - zrand(~ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR); - zror(ZORAN_VDC_VIDEN,ZORAN_VDC); - } - - /* - * leave overlaying on, but turn interrupts off. - */ - zrand(~ZORAN_ICR_EN,ZORAN_ICR); - return; - } - - /* do we have any VBI idle time processing? */ - if (test_bit(STATE_VBI, &ztv->state)) - { - struct vidinfo* item; - struct vidinfo* lastitem; - - /* protect the workqueue */ - write_lock(&ztv->lock); - lastitem = ztv->workqueue; - if (lastitem) - while (lastitem->next) lastitem = lastitem->next; - for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) - if (item->next == 0 && item->status == FBUFFER_FREE) - { -DEBUG(printk(CARD_DEBUG "%p added to queue\n",CARD,item)); - item->status = FBUFFER_BUSY; - if (!lastitem) - ztv->workqueue = item; - else - lastitem->next = item; - lastitem = item; - } - write_unlock(&ztv->lock); - if (ztv->workqueue) - goto again; /* hey, _i_ graduated :) */ - } - - /* - * Then we must be realy IDLE - */ -DEBUG(printk(CARD_DEBUG "turning off\n",CARD)); - /* nothing further to do, disable DMA and further IRQs */ - zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC); - zrand(~ZORAN_ICR_EN,ZORAN_ICR); -} - -static -void zoran_irq(int irq, void *dev_id) -{ - u32 stat,estat; - int count = 0; - struct zoran *ztv = dev_id; - - UNUSED(irq); - for (;;) { - /* get/clear interrupt status bits */ - stat=zrread(ZORAN_ISR); - estat=stat & zrread(ZORAN_ICR); - if (!estat) - return; - zrwrite(estat,ZORAN_ISR); - IDEBUG(printk(CARD_DEBUG "estat %08x\n",CARD,estat)); - IDEBUG(printk(CARD_DEBUG " stat %08x\n",CARD,stat)); - - if (estat & ZORAN_ISR_CODE) - { - IDEBUG(printk(CARD_DEBUG "CodReplIRQ\n",CARD)); - } - if (estat & ZORAN_ISR_GIRQ0) - { - IDEBUG(printk(CARD_DEBUG "GIRQ0\n",CARD)); - if (!ztv->card->usegirq1) - reap_states(ztv); - } - if (estat & ZORAN_ISR_GIRQ1) - { - IDEBUG(printk(CARD_DEBUG "GIRQ1\n",CARD)); - if (ztv->card->usegirq1) - reap_states(ztv); - } - - count++; - if (count > 10) - printk(CARD_ERR "irq loop %d (%x)\n",CARD,count,estat); - if (count > 20) - { - zrwrite(0, ZORAN_ICR); - printk(CARD_ERR "IRQ lockup, cleared int mask\n",CARD); - } - } -} - -static -int zoran_muxsel(struct zoran* ztv, int channel, int norm) -{ - int rv; - - /* set the new video norm */ - rv = i2c_control_device(&(ztv->i2c), I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm); - if (rv) - return rv; - ztv->norm = norm; - - /* map the given channel to the cards decoder's channel */ - channel = ztv->card->video_mux[channel] & CHANNEL_MASK; - - /* set the new channel */ - rv = i2c_control_device(&(ztv->i2c), I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &channel); - return rv; -} - -/* Tell the interrupt handler what to to. */ -static -void zoran_cap(struct zoran* ztv, int on) -{ -DEBUG(printk(CARD_DEBUG "zoran_cap(%d) state=%x\n",CARD,on,ztv->state)); - - if (on) { - ztv->running = 1; - - /* - * turn interrupts (back) on. The DMA will be enabled - * inside the irq handler when it detects a restart. - */ - zror(ZORAN_ICR_EN,ZORAN_ICR); - } - else { - /* - * turn both interrupts and DMA off - */ - zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC); - zrand(~ZORAN_ICR_EN,ZORAN_ICR); - - ztv->running = 0; - } -} - -static ulong dmask[] = { - 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFC, 0xFFFFFFF8, - 0xFFFFFFF0, 0xFFFFFFE0, 0xFFFFFFC0, 0xFFFFFF80, - 0xFFFFFF00, 0xFFFFFE00, 0xFFFFFC00, 0xFFFFF800, - 0xFFFFF000, 0xFFFFE000, 0xFFFFC000, 0xFFFF8000, - 0xFFFF0000, 0xFFFE0000, 0xFFFC0000, 0xFFF80000, - 0xFFF00000, 0xFFE00000, 0xFFC00000, 0xFF800000, - 0xFF000000, 0xFE000000, 0xFC000000, 0xF8000000, - 0xF0000000, 0xE0000000, 0xC0000000, 0x80000000 -}; - -static -void zoran_built_overlay(struct zoran* ztv, int count, struct video_clip *vcp) -{ - ulong* mtop; - int ystep = (ztv->vidXshift + ztv->vidWidth+31)/32; /* next DWORD */ - int i; - -DEBUG(printk(KERN_DEBUG " overlay at %p, ystep=%d, clips=%d\n",ztv->overinfo.overlay,ystep,count)); - - for (i=0; ix,vp->y,vp->width,vp->height)); - } - - /* - * activate the visible portion of the screen - * Note we take some shortcuts here, because we - * know the width can never be < 32. (I.e. a DWORD) - * We also assume the overlay starts somewhere in - * the FIRST dword. - */ - { - int start = ztv->vidXshift; - ulong firstd = dmask[start]; - ulong lastd = ~dmask[(start + ztv->overinfo.w) & 31]; - mtop = ztv->overinfo.overlay; - for (i=0; ioverinfo.h; i++) { - int w = ztv->vidWidth; - ulong* line = mtop; - if (start & 31) { - *line++ = firstd; - w -= 32-(start&31); - } - memset(line, ~0, w/8); - if (w & 31) - line[w/32] = lastd; - mtop += ystep; - } - } - - /* process clipping regions */ - for (i=0; ix < 0 || (uint)vcp->x > ztv->overinfo.w || - vcp->y < 0 || vcp->y > ztv->overinfo.h || - vcp->width < 0 || (uint)(vcp->x+vcp->width) > ztv->overinfo.w || - vcp->height < 0 || (vcp->y+vcp->height) > ztv->overinfo.h) - { - DEBUG(printk(CARD_DEBUG "invalid clipzone (%d,%d,%d,%d) not in (0,0,%d,%d), adapting\n",CARD,vcp->x,vcp->y,vcp->width,vcp->height,ztv->overinfo.w,ztv->overinfo.h)); - if (vcp->x < 0) vcp->x = 0; - if ((uint)vcp->x > ztv->overinfo.w) vcp->x = ztv->overinfo.w; - if (vcp->y < 0) vcp->y = 0; - if (vcp->y > ztv->overinfo.h) vcp->y = ztv->overinfo.h; - if (vcp->width < 0) vcp->width = 0; - if ((uint)(vcp->x+vcp->width) > ztv->overinfo.w) vcp->width = ztv->overinfo.w - vcp->x; - if (vcp->height < 0) vcp->height = 0; - if (vcp->y+vcp->height > ztv->overinfo.h) vcp->height = ztv->overinfo.h - vcp->y; -// continue; - } - - mtop = &ztv->overinfo.overlay[vcp->y*ystep]; - for (h=0; h<=vcp->height; h++) { - int w; - int x = ztv->vidXshift + vcp->x; - for (w=0; w<=vcp->width; w++) { - clear_bit(x&31, &mtop[x/32]); - x++; - } - mtop += ystep; - } - ++vcp; - } - - mtop = ztv->overinfo.overlay; - zrwrite(virt_to_bus(mtop), ZORAN_MTOP); - zrwrite(virt_to_bus(mtop+ystep), ZORAN_MBOT); - zraor((ztv->vidInterlace*ystep)<<0,~ZORAN_OCR_MASKSTRIDE,ZORAN_OCR); -} - -struct tvnorm -{ - u16 Wt, Wa, Ht, Ha, HStart, VStart; -}; - -static struct tvnorm tvnorms[] = { - /* PAL-BDGHI */ -/* { 864, 720, 625, 576, 131, 21 },*/ -/*00*/ { 864, 768, 625, 576, 81, 17 }, - /* NTSC */ -/*01*/ { 858, 720, 525, 480, 121, 10 }, - /* SECAM */ -/*02*/ { 864, 720, 625, 576, 131, 21 }, - /* BW50 */ -/*03*/ { 864, 720, 625, 576, 131, 21 }, - /* BW60 */ -/*04*/ { 858, 720, 525, 480, 121, 10 } -}; -#define TVNORMS (sizeof(tvnorms)/sizeof(tvnorm)) - -/* - * Program the chip for a setup as described in the vidinfo struct. - * - * Side-effects: calculates vidXshift, vidInterlace, - * vidHeight, vidWidth which are used in a later stage - * to calculate the overlay mask - * - * This is an internal function, as such it does not check the - * validity of the struct members... Spectaculair crashes will - * follow /very/ quick when you're wrong and the chip right :) - */ -static -void zoran_set_geo(struct zoran* ztv, struct vidinfo* i) -{ - ulong top, bot; - int stride; - int winWidth, winHeight; - int maxWidth, maxHeight, maxXOffset, maxYOffset; - long vfec; - -DEBUG(printk(CARD_DEBUG "set_geo(rect=(%d,%d,%d,%d), norm=%d, format=%d, bpp=%d, bpl=%d, busadr=%lx, overlay=%p)\n",CARD,i->x,i->y,i->w,i->h,ztv->norm,i->format,i->bpp,i->bpl,i->busadr,i->overlay)); - - /* - * make sure the DMA transfers are inhibited during our - * reprogramming of the chip - */ - zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC); - - maxWidth = tvnorms[ztv->norm].Wa; - maxHeight = tvnorms[ztv->norm].Ha/2; - maxXOffset = tvnorms[ztv->norm].HStart; - maxYOffset = tvnorms[ztv->norm].VStart; - - /* setup vfec register (keep ExtFl,TopField and VCLKPol settings) */ - vfec = (zrread(ZORAN_VFEC) & (ZORAN_VFEC_EXTFL|ZORAN_VFEC_TOPFIELD|ZORAN_VFEC_VCLKPOL)) | - (palette2fmt[i->format].mode & (ZORAN_VFEC_RGB|ZORAN_VFEC_ERRDIF|ZORAN_VFEC_LE|ZORAN_VFEC_PACK24)); - - /* - * Set top, bottom ptrs. Since these must be DWORD aligned, - * possible adjust the x and the width of the window. - * so the endposition stay the same. The vidXshift will make - * sure we are not writing pixels before the requested x. - */ - ztv->vidXshift = 0; - winWidth = i->w; - if (winWidth < 0) - winWidth = -winWidth; - top = i->busadr + i->x*i->bpp + i->y*i->bpl; - if (top & 3) { - ztv->vidXshift = (top & 3) / i->bpp; - winWidth += ztv->vidXshift; - DEBUG(printk(KERN_DEBUG " window-x shifted %d pixels left\n",ztv->vidXshift)); - top &= ~3; - } - - /* - * bottom points to next frame but in interleaved mode we want - * to 'mix' the 2 frames to one capture, so 'bot' points to one - * (physical) line below the top line. - */ - bot = top + i->bpl; - zrwrite(top,ZORAN_VTOP); - zrwrite(bot,ZORAN_VBOT); - - /* - * Make sure the winWidth is DWORD aligned too, - * thereby automaticly making sure the stride to the - * next line is DWORD aligned too (as required by spec). - */ - if ((winWidth*i->bpp) & 3) { -DEBUG(printk(KERN_DEBUG " window-width enlarged by %d pixels\n",(winWidth*i->bpp) & 3)); - winWidth += (winWidth*i->bpp) & 3; - } - - /* determine the DispMode and stride */ - if (i->h >= 0 && i->h <= maxHeight) { - /* single frame grab suffices for this height. */ - vfec |= ZORAN_VFEC_DISPMOD; - ztv->vidInterlace = 0; - stride = i->bpl - (winWidth*i->bpp); - winHeight = i->h; - } - else { - /* interleaving needed for this height */ - ztv->vidInterlace = 1; - stride = i->bpl*2 - (winWidth*i->bpp); - winHeight = i->h/2; - } - if (winHeight < 0) /* can happen for VBI! */ - winHeight = -winHeight; - - /* safety net, sometimes bpl is too short??? */ - if (stride<0) { -DEBUG(printk(CARD_DEBUG "WARNING stride = %d\n",CARD,stride)); - stride = 0; - } - - zraor((winHeight<<12)|(winWidth<<0),~(ZORAN_VDC_VIDWINHT|ZORAN_VDC_VIDWINWID), ZORAN_VDC); - zraor(stride<<16,~ZORAN_VSTR_DISPSTRIDE,ZORAN_VSTR); - - /* remember vidWidth, vidHeight for overlay calculations */ - ztv->vidWidth = winWidth; - ztv->vidHeight = winHeight; -DEBUG(printk(KERN_DEBUG " top=%08lx, bottom=%08lx\n",top,bot)); -DEBUG(printk(KERN_DEBUG " winWidth=%d, winHeight=%d\n",winWidth,winHeight)); -DEBUG(printk(KERN_DEBUG " maxWidth=%d, maxHeight=%d\n",maxWidth,maxHeight)); -DEBUG(printk(KERN_DEBUG " stride=%d\n",stride)); - - /* - * determine horizontal scales and crops - */ - if (i->w < 0) { - int Hstart = 1; - int Hend = Hstart + winWidth; -DEBUG(printk(KERN_DEBUG " Y: scale=0, start=%d, end=%d\n", Hstart, Hend)); - zraor((Hstart<<10)|(Hend<<0),~(ZORAN_VFEH_HSTART|ZORAN_VFEH_HEND),ZORAN_VFEH); - } - else { - int Wa = maxWidth; - int X = (winWidth*64+Wa-1)/Wa; - int We = winWidth*64/X; - int HorDcm = 64-X; - int hcrop1 = 2*(Wa-We)/4; - /* - * BUGFIX: Juha Nurmela - * found the solution to the color phase shift. - * See ChangeLog for the full explanation) - */ - int Hstart = (maxXOffset + hcrop1) | 1; - int Hend = Hstart + We - 1; - -DEBUG(printk(KERN_DEBUG " X: scale=%d, start=%d, end=%d\n", HorDcm, Hstart, Hend)); - - zraor((Hstart<<10)|(Hend<<0),~(ZORAN_VFEH_HSTART|ZORAN_VFEH_HEND),ZORAN_VFEH); - vfec |= HorDcm<<14; - - if (HorDcm<16) - vfec |= ZORAN_VFEC_HFILTER_1; /* no filter */ - else if (HorDcm<32) - vfec |= ZORAN_VFEC_HFILTER_3; /* 3 tap filter */ - else if (HorDcm<48) - vfec |= ZORAN_VFEC_HFILTER_4; /* 4 tap filter */ - else vfec |= ZORAN_VFEC_HFILTER_5; /* 5 tap filter */ - } - - /* - * Determine vertical scales and crops - * - * when height is negative, we want to read starting at line 0 - * One day someone might need access to these lines... - */ - if (i->h < 0) { - int Vstart = 0; - int Vend = Vstart + winHeight; -DEBUG(printk(KERN_DEBUG " Y: scale=0, start=%d, end=%d\n", Vstart, Vend)); - zraor((Vstart<<10)|(Vend<<0),~(ZORAN_VFEV_VSTART|ZORAN_VFEV_VEND),ZORAN_VFEV); - } - else { - int Ha = maxHeight; - int Y = (winHeight*64+Ha-1)/Ha; - int He = winHeight*64/Y; - int VerDcm = 64-Y; - int vcrop1 = 2*(Ha-He)/4; - int Vstart = maxYOffset + vcrop1; - int Vend = Vstart + He - 1; - -DEBUG(printk(KERN_DEBUG " Y: scale=%d, start=%d, end=%d\n", VerDcm, Vstart, Vend)); - zraor((Vstart<<10)|(Vend<<0),~(ZORAN_VFEV_VSTART|ZORAN_VFEV_VEND),ZORAN_VFEV); - vfec |= VerDcm<<8; - } - -DEBUG(printk(KERN_DEBUG " F: format=%d(=%s)\n",i->format,palette2fmt[i->format].name)); - - /* setup the requested format */ - zrwrite(vfec, ZORAN_VFEC); -} - -static -void zoran_common_open(struct zoran* ztv, int flags) -{ - UNUSED(flags); - - /* already opened? */ - if (ztv->users++ != 0) - return; - - /* unmute audio */ - /* /what/ audio? */ - - ztv->state = 0; - - /* setup the encoder to the initial values */ - ztv->picture.colour=254<<7; - ztv->picture.brightness=128<<8; - ztv->picture.hue=128<<8; - ztv->picture.contrast=216<<7; - i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &ztv->picture); - - /* default to the composite input since my camera is there */ - zoran_muxsel(ztv, 0, VIDEO_MODE_PAL); -} - -static -void zoran_common_close(struct zoran* ztv) -{ - if (--ztv->users != 0) - return; - - /* mute audio */ - /* /what/ audio? */ - - /* stop the chip */ - zoran_cap(ztv, 0); -} - -/* - * Open a zoran card. Right now the flags are just a hack - */ -static int zoran_open(struct video_device *dev, int flags) -{ - struct zoran *ztv = (struct zoran*)dev; - struct vidinfo* item; - char* pos; - - DEBUG(printk(CARD_DEBUG "open(dev,%d)\n",CARD,flags)); - - /********************************************* - * We really should be doing lazy allocing... - *********************************************/ - /* allocate a frame buffer */ - if (!ztv->fbuffer) - ztv->fbuffer = bmalloc(ZORAN_MAX_FBUFSIZE); - if (!ztv->fbuffer) { - /* could not get a buffer, bail out */ - return -ENOBUFS; - } - /* at this time we _always_ have a framebuffer */ - memset(ztv->fbuffer,0,ZORAN_MAX_FBUFSIZE); - - if (!ztv->overinfo.overlay) - ztv->overinfo.overlay = kmalloc(1024*1024/8, GFP_KERNEL); - if (!ztv->overinfo.overlay) { - /* could not get an overlay buffer, bail out */ - bfree(ztv->fbuffer, ZORAN_MAX_FBUFSIZE); - return -ENOBUFS; - } - /* at this time we _always_ have a overlay */ - - /* clear buffer status, and give them a DMAable address */ - pos = ztv->fbuffer; - for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++) - { - item->status = FBUFFER_FREE; - item->memadr = pos; - item->busadr = virt_to_bus(pos); - pos += ZORAN_MAX_FBUFFER; - } - - /* do the common part of all open's */ - zoran_common_open(ztv, flags); - - return 0; -} - -static -void zoran_close(struct video_device* dev) -{ - struct zoran *ztv = (struct zoran*)dev; - - DEBUG(printk(CARD_DEBUG "close(dev)\n",CARD)); - - /* driver specific closure */ - clear_bit(STATE_OVERLAY, &ztv->state); - - zoran_common_close(ztv); - - /* - * This is sucky but right now I can't find a good way to - * be sure its safe to free the buffer. We wait 5-6 fields - * which is more than sufficient to be sure. - */ - msleep(100); /* Wait 1/10th of a second */ - - /* free the allocated framebuffer */ - bfree(ztv->fbuffer, ZORAN_MAX_FBUFSIZE); - ztv->fbuffer = 0; - kfree(ztv->overinfo.overlay); - ztv->overinfo.overlay = 0; - -} - -/* - * This read function could be used reentrant in a SMP situation. - * - * This is made possible by the spinlock which is kept till we - * found and marked a buffer for our own use. The lock must - * be released as soon as possible to prevent lock contention. - */ -static -long zoran_read(struct video_device* dev, char* buf, unsigned long count, int nonblock) -{ - struct zoran *ztv = (struct zoran*)dev; - unsigned long max; - struct vidinfo* unused = 0; - struct vidinfo* done = 0; - - DEBUG(printk(CARD_DEBUG "zoran_read(%p,%ld,%d)\n",CARD,buf,count,nonblock)); - - /* find ourself a free or completed buffer */ - for (;;) { - struct vidinfo* item; - - write_lock_irq(&ztv->lock); - for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++) - { - if (!unused && item->status == FBUFFER_FREE) - unused = item; - if (!done && item->status == FBUFFER_DONE) - done = item; - } - if (done || unused) - break; - - /* no more free buffers, wait for them. */ - write_unlock_irq(&ztv->lock); - if (nonblock) - return -EWOULDBLOCK; - interruptible_sleep_on(&ztv->grabq); - if (signal_pending(current)) - return -EINTR; - } - - /* Do we have 'ready' data? */ - if (!done) { - /* no? than this will take a while... */ - if (nonblock) { - write_unlock_irq(&ztv->lock); - return -EWOULDBLOCK; - } - - /* mark the unused buffer as wanted */ - unused->status = FBUFFER_BUSY; - unused->w = 320; - unused->h = 240; - unused->format = VIDEO_PALETTE_RGB24; - unused->bpp = palette2fmt[unused->format].bpp; - unused->bpl = unused->w * unused->bpp; - unused->next = 0; - { /* add to tail of queue */ - struct vidinfo* oldframe = ztv->workqueue; - if (!oldframe) ztv->workqueue = unused; - else { - while (oldframe->next) oldframe = oldframe->next; - oldframe->next = unused; - } - } - write_unlock_irq(&ztv->lock); - - /* tell the state machine we want it filled /NOW/ */ - zoran_cap(ztv, 1); - - /* wait till this buffer gets grabbed */ - wait_event_interruptible(ztv->grabq, - (unused->status != FBUFFER_BUSY)); - /* see if a signal did it */ - if (signal_pending(current)) - return -EINTR; - done = unused; - } - else - write_unlock_irq(&ztv->lock); - - /* Yes! we got data! */ - max = done->bpl * done->h; - if (count > max) - count = max; - if (copy_to_user((void*)buf, done->memadr, count)) - count = -EFAULT; - - /* keep the engine running */ - done->status = FBUFFER_FREE; -// zoran_cap(ztv,1); - - /* tell listeners this buffer became free */ - wake_up_interruptible(&ztv->grabq); - - /* goodbye */ - DEBUG(printk(CARD_DEBUG "zoran_read() returns %lu\n",CARD,count)); - return count; -} - -static -long zoran_write(struct video_device* dev, const char* buf, unsigned long count, int nonblock) -{ - struct zoran *ztv = (struct zoran *)dev; - UNUSED(ztv); UNUSED(dev); UNUSED(buf); UNUSED(count); UNUSED(nonblock); - DEBUG(printk(CARD_DEBUG "zoran_write\n",CARD)); - return -EINVAL; -} - -static -unsigned int zoran_poll(struct video_device *dev, struct file *file, poll_table *wait) -{ - struct zoran *ztv = (struct zoran *)dev; - struct vidinfo* item; - unsigned int mask = 0; - - poll_wait(file, &ztv->grabq, wait); - - for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++) - if (item->status == FBUFFER_DONE) - { - mask |= (POLLIN | POLLRDNORM); - break; - } - - DEBUG(printk(CARD_DEBUG "zoran_poll()=%x\n",CARD,mask)); - - return mask; -} - -/* append a new clipregion to the vector of video_clips */ -static -void new_clip(struct video_window* vw, struct video_clip* vcp, int x, int y, int w, int h) -{ - vcp[vw->clipcount].x = x; - vcp[vw->clipcount].y = y; - vcp[vw->clipcount].width = w; - vcp[vw->clipcount].height = h; - vw->clipcount++; -} - -static -int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg) -{ - struct zoran* ztv = (struct zoran*)dev; - - switch (cmd) { - case VIDIOCGCAP: - { - struct video_capability c; - DEBUG(printk(CARD_DEBUG "VIDIOCGCAP\n",CARD)); - - strcpy(c.name,ztv->video_dev.name); - c.type = VID_TYPE_CAPTURE| - VID_TYPE_OVERLAY| - VID_TYPE_CLIPPING| - VID_TYPE_FRAMERAM| - VID_TYPE_SCALES; - if (ztv->have_tuner) - c.type |= VID_TYPE_TUNER; - if (pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL)) - c.type &= ~VID_TYPE_OVERLAY; - if (ztv->have_decoder) { - c.channels = ztv->card->video_inputs; - c.audios = ztv->card->audio_inputs; - } else - /* no decoder -> no channels */ - c.channels = c.audios = 0; - c.maxwidth = 768; - c.maxheight = 576; - c.minwidth = 32; - c.minheight = 32; - if (copy_to_user(arg,&c,sizeof(c))) - return -EFAULT; - break; - } - - case VIDIOCGCHAN: - { - struct video_channel v; - int mux; - if (copy_from_user(&v, arg,sizeof(v))) - return -EFAULT; - DEBUG(printk(CARD_DEBUG "VIDIOCGCHAN(%d)\n",CARD,v.channel)); - v.flags=VIDEO_VC_AUDIO -#ifdef VIDEO_VC_NORM - |VIDEO_VC_NORM -#endif - ; - v.tuners=0; - v.type=VIDEO_TYPE_CAMERA; -#ifdef I_EXPECT_POSSIBLE_NORMS_IN_THE_API - v.norm=VIDEO_MODE_PAL| - VIDEO_MODE_NTSC| - VIDEO_MODE_SECAM; -#else - v.norm=VIDEO_MODE_PAL; -#endif - /* too many inputs? no decoder -> no channels */ - if (!ztv->have_decoder || v.channel < 0 || v.channel >= ztv->card->video_inputs) - return -EINVAL; - - /* now determine the name of the channel */ - mux = ztv->card->video_mux[v.channel]; - if (mux & IS_TUNER) { - /* lets assume only one tuner, yes? */ - strcpy(v.name,"Television"); - v.type = VIDEO_TYPE_TV; - if (ztv->have_tuner) { - v.flags |= VIDEO_VC_TUNER; - v.tuners = 1; - } - } - else if (mux & IS_SVHS) - sprintf(v.name,"S-Video-%d",v.channel); - else - sprintf(v.name,"CVBS-%d",v.channel); - - if (copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - break; - } - case VIDIOCSCHAN: - { /* set video channel */ - struct video_channel v; - if (copy_from_user(&v, arg,sizeof(v))) - return -EFAULT; - DEBUG(printk(CARD_DEBUG "VIDIOCSCHAN(%d,%d)\n",CARD,v.channel,v.norm)); - - /* too many inputs? no decoder -> no channels */ - if (!ztv->have_decoder || v.channel >= ztv->card->video_inputs || v.channel < 0) - return -EINVAL; - - if (v.norm != VIDEO_MODE_PAL && - v.norm != VIDEO_MODE_NTSC && - v.norm != VIDEO_MODE_SECAM && - v.norm != VIDEO_MODE_AUTO) - return -EOPNOTSUPP; - - /* make it happen, nr1! */ - return zoran_muxsel(ztv,v.channel,v.norm); - } - - case VIDIOCGTUNER: - { - struct video_tuner v; - if (copy_from_user(&v, arg,sizeof(v))) - return -EFAULT; - DEBUG(printk(CARD_DEBUG "VIDIOCGTUNER(%d)\n",CARD,v.tuner)); - - /* Only no or one tuner for now */ - if (!ztv->have_tuner || v.tuner) - return -EINVAL; - - strcpy(v.name,"Television"); - v.rangelow = 0; - v.rangehigh = ~0; - v.flags = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM; - v.mode = ztv->norm; - v.signal = 0xFFFF; /* unknown */ - - if (copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - break; - } - case VIDIOCSTUNER: - { - struct video_tuner v; - if (copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - DEBUG(printk(CARD_DEBUG "VIDIOCSTUNER(%d,%d)\n",CARD,v.tuner,v.mode)); - - /* Only no or one tuner for now */ - if (!ztv->have_tuner || v.tuner) - return -EINVAL; - - /* and it only has certain valid modes */ - if( v.mode != VIDEO_MODE_PAL && - v.mode != VIDEO_MODE_NTSC && - v.mode != VIDEO_MODE_SECAM) - return -EOPNOTSUPP; - - /* engage! */ - return zoran_muxsel(ztv,v.tuner,v.mode); - } - - case VIDIOCGPICT: - { - struct video_picture p = ztv->picture; - DEBUG(printk(CARD_DEBUG "VIDIOCGPICT\n",CARD)); - p.depth = ztv->depth; - switch (p.depth) { - case 8: p.palette=VIDEO_PALETTE_YUV422; - break; - case 15: p.palette=VIDEO_PALETTE_RGB555; - break; - case 16: p.palette=VIDEO_PALETTE_RGB565; - break; - case 24: p.palette=VIDEO_PALETTE_RGB24; - break; - case 32: p.palette=VIDEO_PALETTE_RGB32; - break; - } - if (copy_to_user(arg, &p, sizeof(p))) - return -EFAULT; - break; - } - case VIDIOCSPICT: - { - struct video_picture p; - if (copy_from_user(&p, arg,sizeof(p))) - return -EFAULT; - DEBUG(printk(CARD_DEBUG "VIDIOCSPICT(%d,%d,%d,%d,%d,%d,%d)\n",CARD,p.brightness,p.hue,p.colour,p.contrast,p.whiteness,p.depth,p.palette)); - - /* depth must match with framebuffer */ - if (p.depth != ztv->depth) - return -EINVAL; - - /* check if palette matches this bpp */ - if (p.palette>NRPALETTES || - palette2fmt[p.palette].bpp != ztv->overinfo.bpp) - return -EINVAL; - - write_lock_irq(&ztv->lock); - ztv->overinfo.format = p.palette; - ztv->picture = p; - write_unlock_irq(&ztv->lock); - - /* tell the decoder */ - i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &p); - break; - } - - case VIDIOCGWIN: - { - struct video_window vw; - DEBUG(printk(CARD_DEBUG "VIDIOCGWIN\n",CARD)); - read_lock(&ztv->lock); - vw.x = ztv->overinfo.x; - vw.y = ztv->overinfo.y; - vw.width = ztv->overinfo.w; - vw.height = ztv->overinfo.h; - vw.chromakey= 0; - vw.flags = 0; - if (ztv->vidInterlace) - vw.flags|=VIDEO_WINDOW_INTERLACE; - read_unlock(&ztv->lock); - if (copy_to_user(arg,&vw,sizeof(vw))) - return -EFAULT; - break; - } - case VIDIOCSWIN: - { - struct video_window vw; - struct video_clip *vcp; - int on; - if (copy_from_user(&vw,arg,sizeof(vw))) - return -EFAULT; - DEBUG(printk(CARD_DEBUG "VIDIOCSWIN(%d,%d,%d,%d,%x,%d)\n",CARD,vw.x,vw.y,vw.width,vw.height,vw.flags,vw.clipcount)); - - if (vw.flags) - return -EINVAL; - - if (vw.clipcount <0 || vw.clipcount>256) - return -EDOM; /* Too many! */ - - /* - * Do any clips. - */ - vcp = vmalloc(sizeof(struct video_clip)*(vw.clipcount+4)); - if (vcp==NULL) - return -ENOMEM; - if (vw.clipcount && copy_from_user(vcp,vw.clips,sizeof(struct video_clip)*vw.clipcount)) { - vfree(vcp); - return -EFAULT; - } - - on = ztv->running; - if (on) - zoran_cap(ztv, 0); - - /* - * strange, it seems xawtv sometimes calls us with 0 - * width and/or height. Ignore these values - */ - if (vw.x == 0) - vw.x = ztv->overinfo.x; - if (vw.y == 0) - vw.y = ztv->overinfo.y; - - /* by now we are committed to the new data... */ - write_lock_irq(&ztv->lock); - ztv->overinfo.x = vw.x; - ztv->overinfo.y = vw.y; - ztv->overinfo.w = vw.width; - ztv->overinfo.h = vw.height; - write_unlock_irq(&ztv->lock); - - /* - * Impose display clips - */ - if (vw.x+vw.width > ztv->swidth) - new_clip(&vw, vcp, ztv->swidth-vw.x, 0, vw.width-1, vw.height-1); - if (vw.y+vw.height > ztv->sheight) - new_clip(&vw, vcp, 0, ztv->sheight-vw.y, vw.width-1, vw.height-1); - - /* built the requested clipping zones */ - zoran_set_geo(ztv, &ztv->overinfo); - zoran_built_overlay(ztv, vw.clipcount, vcp); - vfree(vcp); - - /* if we were on, restart the video engine */ - if (on) - zoran_cap(ztv, 1); - break; - } - - case VIDIOCCAPTURE: - { - int v; - if (get_user(v, (int *)arg)) - return -EFAULT; - DEBUG(printk(CARD_DEBUG "VIDIOCCAPTURE(%d)\n",CARD,v)); - - if (v==0) { - clear_bit(STATE_OVERLAY, &ztv->state); - zoran_cap(ztv, 1); - } - else { - /* is VIDIOCSFBUF, VIDIOCSWIN done? */ - if (ztv->overinfo.busadr==0 || ztv->overinfo.w==0 || ztv->overinfo.h==0) - return -EINVAL; - - set_bit(STATE_OVERLAY, &ztv->state); - zoran_cap(ztv, 1); - } - break; - } - - case VIDIOCGFBUF: - { - struct video_buffer v; - DEBUG(printk(CARD_DEBUG "VIDIOCGFBUF\n",CARD)); - read_lock(&ztv->lock); - v.base = (void *)ztv->overinfo.busadr; - v.height = ztv->sheight; - v.width = ztv->swidth; - v.depth = ztv->depth; - v.bytesperline = ztv->overinfo.bpl; - read_unlock(&ztv->lock); - if(copy_to_user(arg, &v,sizeof(v))) - return -EFAULT; - break; - } - case VIDIOCSFBUF: - { - struct video_buffer v; - if(!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (pcipci_problems & (PCIPCI_FAIL|PCIAGP_FAIL)) - return -ENXIO; - if (copy_from_user(&v, arg,sizeof(v))) - return -EFAULT; - DEBUG(printk(CARD_DEBUG "VIDIOCSFBUF(%p,%d,%d,%d,%d)\n",CARD,v.base, v.width,v.height,v.depth,v.bytesperline)); - - if (v.depth!=15 && v.depth!=16 && v.depth!=24 && v.depth!=32) - return -EINVAL; - if (v.bytesperline<1) - return -EINVAL; - if (ztv->running) - return -EBUSY; - write_lock_irq(&ztv->lock); - ztv->overinfo.busadr = (ulong)v.base; - ztv->sheight = v.height; - ztv->swidth = v.width; - ztv->depth = v.depth; /* bits per pixel */ - ztv->overinfo.bpp = ((v.depth+1)&0x38)/8;/* bytes per pixel */ - ztv->overinfo.bpl = v.bytesperline; /* bytes per line */ - write_unlock_irq(&ztv->lock); - break; - } - - case VIDIOCKEY: - { - /* Will be handled higher up .. */ - break; - } - - case VIDIOCSYNC: - { - int i; - if (get_user(i, (int *) arg)) - return -EFAULT; - DEBUG(printk(CARD_DEBUG "VIDEOCSYNC(%d)\n",CARD,i)); - if (i<0 || i>ZORAN_MAX_FBUFFERS) - return -EINVAL; - switch (ztv->grabinfo[i].status) { - case FBUFFER_FREE: - return -EINVAL; - case FBUFFER_BUSY: - /* wait till this buffer gets grabbed */ - wait_event_interruptible(ztv->grabq, - (ztv->grabinfo[i].status != FBUFFER_BUSY)); - /* see if a signal did it */ - if (signal_pending(current)) - return -EINTR; - /* don't fall through; a DONE buffer is not UNUSED */ - break; - case FBUFFER_DONE: - ztv->grabinfo[i].status = FBUFFER_FREE; - /* tell ppl we have a spare buffer */ - wake_up_interruptible(&ztv->grabq); - break; - } - DEBUG(printk(CARD_DEBUG "VIDEOCSYNC(%d) returns\n",CARD,i)); - break; - } - - case VIDIOCMCAPTURE: - { - struct video_mmap vm; - struct vidinfo* frame; - if (copy_from_user(&vm,arg,sizeof(vm))) - return -EFAULT; - DEBUG(printk(CARD_DEBUG "VIDIOCMCAPTURE(%d,(%d,%d),%d)\n",CARD,vm.frame,vm.width,vm.height,vm.format)); - if (vm.frame<0 || vm.frame>ZORAN_MAX_FBUFFERS || - vm.width<32 || vm.width>768 || - vm.height<32 || vm.height>576 || - vm.format>NRPALETTES || - palette2fmt[vm.format].mode == 0) - return -EINVAL; - - /* we are allowed to take over UNUSED and DONE buffers */ - frame = &ztv->grabinfo[vm.frame]; - if (frame->status == FBUFFER_BUSY) - return -EBUSY; - - /* setup the other parameters if they are given */ - write_lock_irq(&ztv->lock); - frame->w = vm.width; - frame->h = vm.height; - frame->format = vm.format; - frame->bpp = palette2fmt[frame->format].bpp; - frame->bpl = frame->w*frame->bpp; - frame->status = FBUFFER_BUSY; - frame->next = 0; - { /* add to tail of queue */ - struct vidinfo* oldframe = ztv->workqueue; - if (!oldframe) ztv->workqueue = frame; - else { - while (oldframe->next) oldframe = oldframe->next; - oldframe->next = frame; - } - } - write_unlock_irq(&ztv->lock); - zoran_cap(ztv, 1); - break; - } - - case VIDIOCGMBUF: - { - struct video_mbuf mb; - int i; - DEBUG(printk(CARD_DEBUG "VIDIOCGMBUF\n",CARD)); - mb.size = ZORAN_MAX_FBUFSIZE; - mb.frames = ZORAN_MAX_FBUFFERS; - for (i=0; ivideo_dev.minor; - vu.vbi = ztv->vbi_dev.minor; - vu.radio = VIDEO_NO_UNIT; - vu.audio = VIDEO_NO_UNIT; - vu.teletext = VIDEO_NO_UNIT; - if(copy_to_user(arg, &vu,sizeof(vu))) - return -EFAULT; - break; - } - - case VIDIOCGFREQ: - { - unsigned long v = ztv->tuner_freq; - if (copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - DEBUG(printk(CARD_DEBUG "VIDIOCGFREQ\n",CARD)); - break; - } - case VIDIOCSFREQ: - { - unsigned long v; - if (copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - DEBUG(printk(CARD_DEBUG "VIDIOCSFREQ\n",CARD)); - - if (ztv->have_tuner) { - int fixme = v; - if (i2c_control_device(&(ztv->i2c), I2C_DRIVERID_TUNER, TUNER_SET_TVFREQ, &fixme) < 0) - return -EAGAIN; - } - ztv->tuner_freq = v; - break; - } - - /* Why isn't this in the API? - * And why doesn't it take a buffer number? - case BTTV_FIELDNR: - { - unsigned long v = ztv->lastfieldnr; - if (copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - DEBUG(printk(CARD_DEBUG "BTTV_FIELDNR\n",CARD)); - break; - } - */ - - default: - return -ENOIOCTLCMD; - } - return 0; -} - -static -int zoran_mmap(struct vm_area_struct *vma, struct video_device* dev, const char* adr, unsigned long size) -{ - struct zoran* ztv = (struct zoran*)dev; - unsigned long start = (unsigned long)adr; - unsigned long pos; - - DEBUG(printk(CARD_DEBUG "zoran_mmap(0x%p,%ld)\n",CARD,adr,size)); - - /* sanity checks */ - if (size > ZORAN_MAX_FBUFSIZE || !ztv->fbuffer) - return -EINVAL; - - /* start mapping the whole shabang to user memory */ - pos = (unsigned long)ztv->fbuffer; - while (size>0) { - unsigned long pfn = virt_to_phys((void*)pos) >> PAGE_SHIFT; - if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - start += PAGE_SIZE; - pos += PAGE_SIZE; - size -= PAGE_SIZE; - } - return 0; -} - -static struct video_device zr36120_template= -{ - .owner = THIS_MODULE, - .name = "UNSET", - .type = VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY, - .hardware = VID_HARDWARE_ZR36120, - .open = zoran_open, - .close = zoran_close, - .read = zoran_read, - .write = zoran_write, - .poll = zoran_poll, - .ioctl = zoran_ioctl, - .compat_ioctl = v4l_compat_ioctl32, - .mmap = zoran_mmap, - .minor = -1, -}; - -static -int vbi_open(struct video_device *dev, int flags) -{ - struct zoran *ztv = dev->priv; - struct vidinfo* item; - - DEBUG(printk(CARD_DEBUG "vbi_open(dev,%d)\n",CARD,flags)); - - /* - * During VBI device open, we continiously grab VBI-like - * data in the vbi buffer when we have nothing to do. - * Only when there is an explicit request for VBI data - * (read call) we /force/ a read. - */ - - /* allocate buffers */ - for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) - { - item->status = FBUFFER_FREE; - - /* alloc */ - if (!item->memadr) { - item->memadr = bmalloc(ZORAN_VBI_BUFSIZE); - if (!item->memadr) { - /* could not get a buffer, bail out */ - while (item != ztv->readinfo) { - item--; - bfree(item->memadr, ZORAN_VBI_BUFSIZE); - item->memadr = 0; - item->busadr = 0; - } - return -ENOBUFS; - } - } - - /* determine the DMAable address */ - item->busadr = virt_to_bus(item->memadr); - } - - /* do the common part of all open's */ - zoran_common_open(ztv, flags); - - set_bit(STATE_VBI, &ztv->state); - /* start read-ahead */ - zoran_cap(ztv, 1); - - return 0; -} - -static -void vbi_close(struct video_device *dev) -{ - struct zoran *ztv = dev->priv; - struct vidinfo* item; - - DEBUG(printk(CARD_DEBUG "vbi_close(dev)\n",CARD)); - - /* driver specific closure */ - clear_bit(STATE_VBI, &ztv->state); - - zoran_common_close(ztv); - - /* - * This is sucky but right now I can't find a good way to - * be sure its safe to free the buffer. We wait 5-6 fields - * which is more than sufficient to be sure. - */ - msleep(100); /* Wait 1/10th of a second */ - - for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) - { - if (item->memadr) - bfree(item->memadr, ZORAN_VBI_BUFSIZE); - item->memadr = 0; - } - -} - -/* - * This read function could be used reentrant in a SMP situation. - * - * This is made possible by the spinlock which is kept till we - * found and marked a buffer for our own use. The lock must - * be released as soon as possible to prevent lock contention. - */ -static -long vbi_read(struct video_device* dev, char* buf, unsigned long count, int nonblock) -{ - struct zoran *ztv = dev->priv; - unsigned long max; - struct vidinfo* unused = 0; - struct vidinfo* done = 0; - - DEBUG(printk(CARD_DEBUG "vbi_read(0x%p,%ld,%d)\n",CARD,buf,count,nonblock)); - - /* find ourself a free or completed buffer */ - for (;;) { - struct vidinfo* item; - - write_lock_irq(&ztv->lock); - for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) { - if (!unused && item->status == FBUFFER_FREE) - unused = item; - if (!done && item->status == FBUFFER_DONE) - done = item; - } - if (done || unused) - break; - - /* no more free buffers, wait for them. */ - write_unlock_irq(&ztv->lock); - if (nonblock) - return -EWOULDBLOCK; - interruptible_sleep_on(&ztv->vbiq); - if (signal_pending(current)) - return -EINTR; - } - - /* Do we have 'ready' data? */ - if (!done) { - /* no? than this will take a while... */ - if (nonblock) { - write_unlock_irq(&ztv->lock); - return -EWOULDBLOCK; - } - - /* mark the unused buffer as wanted */ - unused->status = FBUFFER_BUSY; - unused->next = 0; - { /* add to tail of queue */ - struct vidinfo* oldframe = ztv->workqueue; - if (!oldframe) ztv->workqueue = unused; - else { - while (oldframe->next) oldframe = oldframe->next; - oldframe->next = unused; - } - } - write_unlock_irq(&ztv->lock); - - /* tell the state machine we want it filled /NOW/ */ - zoran_cap(ztv, 1); - - /* wait till this buffer gets grabbed */ - wait_event_interruptible(ztv->vbiq, - (unused->status != FBUFFER_BUSY)); - /* see if a signal did it */ - if (signal_pending(current)) - return -EINTR; - done = unused; - } - else - write_unlock_irq(&ztv->lock); - - /* Yes! we got data! */ - max = done->bpl * -done->h; - if (count > max) - count = max; - - /* check if the user gave us enough room to write the data */ - if (!access_ok(VERIFY_WRITE, buf, count)) { - count = -EFAULT; - goto out; - } - - /* - * Now transform/strip the data from YUV to Y-only - * NB. Assume the Y is in the LSB of the YUV data. - */ - { - unsigned char* optr = buf; - unsigned char* eptr = buf+count; - - /* are we beeing accessed from an old driver? */ - if (count == 2*19*2048) { - /* - * Extreme HACK, old VBI programs expect 2048 points - * of data, and we only got 864 orso. Double each - * datapoint and clear the rest of the line. - * This way we have appear to have a - * sample_frequency of 29.5 Mc. - */ - int x,y; - unsigned char* iptr = done->memadr+1; - for (y=done->h; optrw; x++) - { - unsigned char a = iptr[x*2]; - __put_user(a, optr++); - __put_user(a, optr++); - } - /* and clear the rest of the line */ - for (x*=2; optrbpl; x++) - __put_user(0, optr++); - /* next line */ - iptr += done->bpl; - } - } - else { - /* - * Other (probably newer) programs asked - * us what geometry we are using, and are - * reading the correct size. - */ - int x,y; - unsigned char* iptr = done->memadr+1; - for (y=done->h; optrw; x++) - __put_user(iptr[x*2], optr++); - /* and clear the rest of the line */ - for (;optrbpl; x++) - __put_user(0, optr++); - /* next line */ - iptr += done->bpl; - } - } - - /* API compliance: - * place the framenumber (half fieldnr) in the last long - */ - __put_user(done->fieldnr/2, ((ulong*)eptr)[-1]); - } - - /* keep the engine running */ - done->status = FBUFFER_FREE; - zoran_cap(ztv, 1); - - /* tell listeners this buffer just became free */ - wake_up_interruptible(&ztv->vbiq); - - /* goodbye */ -out: - DEBUG(printk(CARD_DEBUG "vbi_read() returns %lu\n",CARD,count)); - return count; -} - -static -unsigned int vbi_poll(struct video_device *dev, struct file *file, poll_table *wait) -{ - struct zoran *ztv = dev->priv; - struct vidinfo* item; - unsigned int mask = 0; - - poll_wait(file, &ztv->vbiq, wait); - - for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) - if (item->status == FBUFFER_DONE) - { - mask |= (POLLIN | POLLRDNORM); - break; - } - - DEBUG(printk(CARD_DEBUG "vbi_poll()=%x\n",CARD,mask)); - - return mask; -} - -static -int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -{ - struct zoran* ztv = dev->priv; - - switch (cmd) { - case VIDIOCGVBIFMT: - { - struct vbi_format f; - DEBUG(printk(CARD_DEBUG "VIDIOCGVBIINFO\n",CARD)); - f.sampling_rate = 14750000UL; - f.samples_per_line = -ztv->readinfo[0].w; - f.sample_format = VIDEO_PALETTE_RAW; - f.start[0] = f.start[1] = ztv->readinfo[0].y; - f.start[1] += 312; - f.count[0] = f.count[1] = -ztv->readinfo[0].h; - f.flags = VBI_INTERLACED; - if (copy_to_user(arg,&f,sizeof(f))) - return -EFAULT; - break; - } - case VIDIOCSVBIFMT: - { - struct vbi_format f; - int i; - if (copy_from_user(&f, arg,sizeof(f))) - return -EFAULT; - DEBUG(printk(CARD_DEBUG "VIDIOCSVBIINFO(%d,%d,%d,%d,%d,%d,%d,%x)\n",CARD,f.sampling_rate,f.samples_per_line,f.sample_format,f.start[0],f.start[1],f.count[0],f.count[1],f.flags)); - - /* lots of parameters are fixed... (PAL) */ - if (f.sampling_rate != 14750000UL || - f.samples_per_line > 864 || - f.sample_format != VIDEO_PALETTE_RAW || - f.start[0] < 0 || - f.start[0] != f.start[1]-312 || - f.count[0] != f.count[1] || - f.start[0]+f.count[0] >= 288 || - f.flags != VBI_INTERLACED) - return -EINVAL; - - write_lock_irq(&ztv->lock); - ztv->readinfo[0].y = f.start[0]; - ztv->readinfo[0].w = -f.samples_per_line; - ztv->readinfo[0].h = -f.count[0]; - ztv->readinfo[0].bpl = f.samples_per_line*ztv->readinfo[0].bpp; - for (i=1; ireadinfo[i] = ztv->readinfo[i]; - write_unlock_irq(&ztv->lock); - break; - } - default: - return -ENOIOCTLCMD; - } - return 0; -} - -static struct video_device vbi_template= -{ - .owner = THIS_MODULE, - .name = "UNSET", - .type = VID_TYPE_CAPTURE|VID_TYPE_TELETEXT, - .hardware = VID_HARDWARE_ZR36120, - .open = vbi_open, - .close = vbi_close, - .read = vbi_read, - .write = zoran_write, - .poll = vbi_poll, - .ioctl = vbi_ioctl, - .minor = -1, -}; - -/* - * Scan for a Zoran chip, request the irq and map the io memory - */ -static -int __init find_zoran(void) -{ - int result; - struct zoran *ztv; - struct pci_dev *dev = NULL; - unsigned char revision; - int zoran_num = 0; - - while ((dev = pci_get_device(PCI_VENDOR_ID_ZORAN,PCI_DEVICE_ID_ZORAN_36120, dev))) - { - /* Ok, a ZR36120/ZR36125 found! */ - ztv = &zorans[zoran_num]; - ztv->dev = dev; - - if (pci_enable_device(dev)) - continue; - - pci_read_config_byte(dev, PCI_CLASS_REVISION, &revision); - printk(KERN_INFO "zoran: Zoran %x (rev %d) ", - dev->device, revision); - printk("bus: %d, devfn: %d, irq: %d, ", - dev->bus->number, dev->devfn, dev->irq); - printk("memory: 0x%08lx.\n", ztv->zoran_adr); - - ztv->zoran_mem = ioremap(ztv->zoran_adr, 0x1000); - DEBUG(printk(KERN_DEBUG "zoran: mapped-memory at 0x%p\n",ztv->zoran_mem)); - - result = request_irq(dev->irq, zoran_irq, - IRQF_SHARED|IRQF_DISABLED,"zoran", ztv); - if (result==-EINVAL) - { - iounmap(ztv->zoran_mem); - printk(KERN_ERR "zoran: Bad irq number or handler\n"); - continue; - } - if (result==-EBUSY) - printk(KERN_ERR "zoran: IRQ %d busy, change your PnP config in BIOS\n",dev->irq); - if (result < 0) { - iounmap(ztv->zoran_mem); - continue; - } - /* Enable bus-mastering */ - pci_set_master(dev); - /* Keep a reference */ - pci_dev_get(dev); - zoran_num++; - } - if(zoran_num) - printk(KERN_INFO "zoran: %d Zoran card(s) found.\n",zoran_num); - return zoran_num; -} - -static -int __init init_zoran(int card) -{ - struct zoran *ztv = &zorans[card]; - int i; - - /* if the given cardtype valid? */ - if (cardtype[card]>=NRTVCARDS) { - printk(KERN_INFO "invalid cardtype(%d) detected\n",cardtype[card]); - return -1; - } - - /* reset the zoran */ - zrand(~ZORAN_PCI_SOFTRESET,ZORAN_PCI); - udelay(10); - zror(ZORAN_PCI_SOFTRESET,ZORAN_PCI); - udelay(10); - - /* zoran chip specific details */ - ztv->card = tvcards+cardtype[card]; /* point to the selected card */ - ztv->norm = 0; /* PAL */ - ztv->tuner_freq = 0; - - /* videocard details */ - ztv->swidth = 800; - ztv->sheight = 600; - ztv->depth = 16; - - /* State details */ - ztv->fbuffer = 0; - ztv->overinfo.kindof = FBUFFER_OVERLAY; - ztv->overinfo.status = FBUFFER_FREE; - ztv->overinfo.x = 0; - ztv->overinfo.y = 0; - ztv->overinfo.w = 768; /* 640 */ - ztv->overinfo.h = 576; /* 480 */ - ztv->overinfo.format = VIDEO_PALETTE_RGB565; - ztv->overinfo.bpp = palette2fmt[ztv->overinfo.format].bpp; - ztv->overinfo.bpl = ztv->overinfo.bpp*ztv->swidth; - ztv->overinfo.busadr = 0; - ztv->overinfo.memadr = 0; - ztv->overinfo.overlay = 0; - for (i=0; igrabinfo[i] = ztv->overinfo; - ztv->grabinfo[i].kindof = FBUFFER_GRAB; - } - init_waitqueue_head(&ztv->grabq); - - /* VBI details */ - ztv->readinfo[0] = ztv->overinfo; - ztv->readinfo[0].kindof = FBUFFER_VBI; - ztv->readinfo[0].w = -864; - ztv->readinfo[0].h = -38; - ztv->readinfo[0].format = VIDEO_PALETTE_YUV422; - ztv->readinfo[0].bpp = palette2fmt[ztv->readinfo[0].format].bpp; - ztv->readinfo[0].bpl = 1024*ztv->readinfo[0].bpp; - for (i=1; ireadinfo[i] = ztv->readinfo[0]; - init_waitqueue_head(&ztv->vbiq); - - /* maintenance data */ - ztv->have_decoder = 0; - ztv->have_tuner = 0; - ztv->tuner_type = 0; - ztv->running = 0; - ztv->users = 0; - rwlock_init(&ztv->lock); - ztv->workqueue = 0; - ztv->fieldnr = 0; - ztv->lastfieldnr = 0; - - if (triton1) - zrand(~ZORAN_VDC_TRICOM, ZORAN_VDC); - - /* external FL determines TOP frame */ - zror(ZORAN_VFEC_EXTFL, ZORAN_VFEC); - - /* set HSpol */ - if (ztv->card->hsync_pos) - zrwrite(ZORAN_VFEH_HSPOL, ZORAN_VFEH); - /* set VSpol */ - if (ztv->card->vsync_pos) - zrwrite(ZORAN_VFEV_VSPOL, ZORAN_VFEV); - - /* Set the proper General Purpuse register bits */ - /* implicit: no softreset, 0 waitstates */ - zrwrite(ZORAN_PCI_SOFTRESET|(ztv->card->gpdir<<0),ZORAN_PCI); - /* implicit: 3 duration and recovery PCI clocks on guest 0-3 */ - zrwrite(ztv->card->gpval<<24,ZORAN_GUEST); - - /* clear interrupt status */ - zrwrite(~0, ZORAN_ISR); - - /* - * i2c template - */ - ztv->i2c = zoran_i2c_bus_template; - sprintf(ztv->i2c.name,"zoran-%d",card); - ztv->i2c.data = ztv; - - /* - * Now add the template and register the device unit - */ - ztv->video_dev = zr36120_template; - strcpy(ztv->video_dev.name, ztv->i2c.name); - ztv->video_dev.priv = ztv; - if (video_register_device(&ztv->video_dev, VFL_TYPE_GRABBER, video_nr) < 0) - return -1; - - ztv->vbi_dev = vbi_template; - strcpy(ztv->vbi_dev.name, ztv->i2c.name); - ztv->vbi_dev.priv = ztv; - if (video_register_device(&ztv->vbi_dev, VFL_TYPE_VBI, vbi_nr) < 0) { - video_unregister_device(&ztv->video_dev); - return -1; - } - i2c_register_bus(&ztv->i2c); - - /* set interrupt mask - the PIN enable will be set later */ - zrwrite(ZORAN_ICR_GIRQ0|ZORAN_ICR_GIRQ1|ZORAN_ICR_CODE, ZORAN_ICR); - - printk(KERN_INFO "%s: installed %s\n",ztv->i2c.name,ztv->card->name); - return 0; -} - -static -void release_zoran(int max) -{ - struct zoran *ztv; - int i; - - for (i=0;idev->irq,ztv); - - /* unregister i2c_bus */ - i2c_unregister_bus((&ztv->i2c)); - - /* unmap and free memory */ - if (ztv->zoran_mem) - iounmap(ztv->zoran_mem); - - /* Drop PCI device */ - pci_dev_put(ztv->dev); - - video_unregister_device(&ztv->video_dev); - video_unregister_device(&ztv->vbi_dev); - } -} - -void __exit zr36120_exit(void) -{ - release_zoran(zoran_cards); -} - -int __init zr36120_init(void) -{ - int card; - - handle_chipset(); - zoran_cards = find_zoran(); - if (zoran_cards <= 0) - return -EIO; - - /* initialize Zorans */ - for (card=0; card -#include - -#include -#include - -#include - -/* - * Debug macro's, place an x behind the ) for actual debug-compilation - * E.g. #define DEBUG(x...) x - */ -#define DEBUG(x...) /* Debug driver */ -#define IDEBUG(x...) /* Debug interrupt handler */ -#define PDEBUG 0 /* Debug PCI writes */ - -/* defined in zr36120_i2c */ -extern struct i2c_bus zoran_i2c_bus_template; - -#define ZORAN_MAX_FBUFFERS 2 -#define ZORAN_MAX_FBUFFER (768*576*2) -#define ZORAN_MAX_FBUFSIZE (ZORAN_MAX_FBUFFERS*ZORAN_MAX_FBUFFER) - -#define ZORAN_VBI_BUFFERS 2 -#define ZORAN_VBI_BUFSIZE (22*1024*2) - -struct tvcard { - char* name; /* name of the cardtype */ - int video_inputs; /* number of channels defined in video_mux */ - int audio_inputs; /* number of channels defined in audio_mux */ - __u32 swapi2c:1, /* need to swap i2c wires SDA/SCL? */ - usegirq1:1, /* VSYNC at GIRQ1 instead of GIRQ0? */ - vsync_pos:1, /* positive VSYNC signal? */ - hsync_pos:1, /* positive HSYNC signal? */ - gpdir:8, /* General Purpose Direction register */ - gpval:8; /* General Purpose Value register */ - int video_mux[6]; /* mapping channel number to physical input */ -#define IS_TUNER 0x80 -#define IS_SVHS 0x40 -#define CHANNEL_MASK 0x3F - int audio_mux[6]; /* mapping channel number to physical input */ -}; -#define TUNER(x) ((x)|IS_TUNER) -#define SVHS(x) ((x)|IS_SVHS) - -struct vidinfo { - struct vidinfo* next; /* next active buffer */ - uint kindof; -#define FBUFFER_OVERLAY 0 -#define FBUFFER_GRAB 1 -#define FBUFFER_VBI 2 - uint status; -#define FBUFFER_FREE 0 -#define FBUFFER_BUSY 1 -#define FBUFFER_DONE 2 - ulong fieldnr; /* # of field, not framer! */ - uint x,y; - int w,h; /* w,h can be negative! */ - uint format; /* index in palette2fmt[] */ - uint bpp; /* lookup from palette2fmt[] */ - uint bpl; /* calc: width * bpp */ - ulong busadr; /* bus addr for DMA engine */ - char* memadr; /* kernel addr for making copies */ - ulong* overlay; /* kernel addr of overlay mask */ -}; - -struct zoran -{ - struct video_device video_dev; -#define CARD_DEBUG KERN_DEBUG "%s(%lu): " -#define CARD_INFO KERN_INFO "%s(%lu): " -#define CARD_ERR KERN_ERR "%s(%lu): " -#define CARD ztv->video_dev.name,ztv->fieldnr - - /* zoran chip specific details */ - struct i2c_bus i2c; /* i2c registration data */ - struct pci_dev* dev; /* ptr to PCI device */ - ulong zoran_adr; /* bus address of IO memory */ - char* zoran_mem; /* kernel address of IO memory */ - struct tvcard* card; /* the cardtype */ - uint norm; /* 0=PAL, 1=NTSC, 2=SECAM */ - uint tuner_freq; /* Current freq in kHz */ - struct video_picture picture; /* Current picture params */ - - /* videocard details */ - uint swidth; /* screen width */ - uint sheight; /* screen height */ - uint depth; /* depth in bits */ - - /* State details */ - char* fbuffer; /* framebuffers for mmap */ - struct vidinfo overinfo; /* overlay data */ - struct vidinfo grabinfo[ZORAN_MAX_FBUFFERS]; /* grabbing data*/ - wait_queue_head_t grabq; /* grabbers queue */ - - /* VBI details */ - struct video_device vbi_dev; - struct vidinfo readinfo[2]; /* VBI data - flip buffers */ - wait_queue_head_t vbiq; /* vbi queue */ - - /* maintenance data */ - int have_decoder; /* did we detect a mux? */ - int have_tuner; /* did we detect a tuner? */ - int users; /* howmany video/vbi open? */ - int tuner_type; /* tuner type, when found */ - int running; /* are we rolling? */ - rwlock_t lock; - long state; /* what is requested of us? */ -#define STATE_OVERLAY 0 -#define STATE_VBI 1 - struct vidinfo* workqueue; /* buffers to grab, head is active */ - ulong fieldnr; /* #field, ticked every VSYNC */ - ulong lastfieldnr; /* #field, ticked every GRAB */ - - int vidInterlace; /* calculated */ - int vidXshift; /* calculated */ - uint vidWidth; /* calculated */ - uint vidHeight; /* calculated */ -}; - -#define zrwrite(dat,adr) writel((dat),(char *) (ztv->zoran_mem+(adr))) -#define zrread(adr) readl(ztv->zoran_mem+(adr)) - -#if PDEBUG == 0 -#define zrand(dat,adr) zrwrite((dat) & zrread(adr), adr) -#define zror(dat,adr) zrwrite((dat) | zrread(adr), adr) -#define zraor(dat,mask,adr) zrwrite( ((dat)&~(mask)) | ((mask)&zrread(adr)), adr) -#else -#define zrand(dat, adr) \ -do { \ - ulong data = (dat) & zrread((adr)); \ - zrwrite(data, (adr)); \ - if (0 != (~(dat) & zrread((adr)))) \ - printk(KERN_DEBUG "zoran: zrand at %d(%d) detected set bits(%x)\n", __LINE__, (adr), (dat)); \ -} while(0) - -#define zror(dat, adr) \ -do { \ - ulong data = (dat) | zrread((adr)); \ - zrwrite(data, (adr)); \ - if ((dat) != ((dat) & zrread(adr))) \ - printk(KERN_DEBUG "zoran: zror at %d(%d) detected unset bits(%x)\n", __LINE__, (adr), (dat)); \ -} while(0) - -#define zraor(dat, mask, adr) \ -do { \ - ulong data; \ - if ((dat) & (mask)) \ - printk(KERN_DEBUG "zoran: zraor at %d(%d) detected bits(%x:%x)\n", __LINE__, (adr), (dat), (mask)); \ - data = ((dat)&~(mask)) | ((mask) & zrread((adr))); \ - zrwrite(data,(adr)); \ - if ( (dat) != (~(mask) & zrread((adr))) ) \ - printk(KERN_DEBUG "zoran: zraor at %d(%d) could not set all bits(%x:%x)\n", __LINE__, (adr), (dat), (mask)); \ -} while(0) -#endif - -#endif - -/* zoran PCI address space */ -#define ZORAN_VFEH 0x000 /* Video Front End Horizontal Conf. */ -#define ZORAN_VFEH_HSPOL (1<<30) -#define ZORAN_VFEH_HSTART (0x3FF<<10) -#define ZORAN_VFEH_HEND (0x3FF<<0) - -#define ZORAN_VFEV 0x004 /* Video Front End Vertical Conf. */ -#define ZORAN_VFEV_VSPOL (1<<30) -#define ZORAN_VFEV_VSTART (0x3FF<<10) -#define ZORAN_VFEV_VEND (0x3FF<<0) - -#define ZORAN_VFEC 0x008 /* Video Front End Scaler and Pixel */ -#define ZORAN_VFEC_EXTFL (1<<26) -#define ZORAN_VFEC_TOPFIELD (1<<25) -#define ZORAN_VFEC_VCLKPOL (1<<24) -#define ZORAN_VFEC_HFILTER (7<<21) -#define ZORAN_VFEC_HFILTER_1 (0<<21) /* no lumi, 3-tap chromo */ -#define ZORAN_VFEC_HFILTER_2 (1<<21) /* 3-tap lumi, 3-tap chromo */ -#define ZORAN_VFEC_HFILTER_3 (2<<21) /* 4-tap lumi, 4-tap chromo */ -#define ZORAN_VFEC_HFILTER_4 (3<<21) /* 5-tap lumi, 4-tap chromo */ -#define ZORAN_VFEC_HFILTER_5 (4<<21) /* 4-tap lumi, 4-tap chromo */ -#define ZORAN_VFEC_DUPFLD (1<<20) -#define ZORAN_VFEC_HORDCM (63<<14) -#define ZORAN_VFEC_VERDCM (63<<8) -#define ZORAN_VFEC_DISPMOD (1<<6) -#define ZORAN_VFEC_RGB (3<<3) -#define ZORAN_VFEC_RGB_YUV422 (0<<3) -#define ZORAN_VFEC_RGB_RGB888 (1<<3) -#define ZORAN_VFEC_RGB_RGB565 (2<<3) -#define ZORAN_VFEC_RGB_RGB555 (3<<3) -#define ZORAN_VFEC_ERRDIF (1<<2) -#define ZORAN_VFEC_PACK24 (1<<1) -#define ZORAN_VFEC_LE (1<<0) - -#define ZORAN_VTOP 0x00C /* Video Display "Top" */ - -#define ZORAN_VBOT 0x010 /* Video Display "Bottom" */ - -#define ZORAN_VSTR 0x014 /* Video Display Stride */ -#define ZORAN_VSTR_DISPSTRIDE (0xFFFF<<16) -#define ZORAN_VSTR_VIDOVF (1<<8) -#define ZORAN_VSTR_SNAPSHOT (1<<1) -#define ZORAN_VSTR_GRAB (1<<0) - -#define ZORAN_VDC 0x018 /* Video Display Conf. */ -#define ZORAN_VDC_VIDEN (1<<31) -#define ZORAN_VDC_MINPIX (0x1F<<25) -#define ZORAN_VDC_TRICOM (1<<24) -#define ZORAN_VDC_VIDWINHT (0x3FF<<12) -#define ZORAN_VDC_VIDWINWID (0x3FF<<0) - -#define ZORAN_MTOP 0x01C /* Masking Map "Top" */ - -#define ZORAN_MBOT 0x020 /* Masking Map "Bottom" */ - -#define ZORAN_OCR 0x024 /* Overlay Control */ -#define ZORAN_OCR_OVLEN (1<<15) -#define ZORAN_OCR_MASKSTRIDE (0xFF<<0) - -#define ZORAN_PCI 0x028 /* System, PCI and GPP Control */ -#define ZORAN_PCI_SOFTRESET (1<<24) -#define ZORAN_PCI_WAITSTATE (3<<16) -#define ZORAN_PCI_GENPURDIR (0xFF<<0) - -#define ZORAN_GUEST 0x02C /* GuestBus Control */ - -#define ZORAN_CSOURCE 0x030 /* Code Source Address */ - -#define ZORAN_CTRANS 0x034 /* Code Transfer Control */ - -#define ZORAN_CMEM 0x038 /* Code Memory Pointer */ - -#define ZORAN_ISR 0x03C /* Interrupt Status Register */ -#define ZORAN_ISR_CODE (1<<28) -#define ZORAN_ISR_GIRQ0 (1<<29) -#define ZORAN_ISR_GIRQ1 (1<<30) - -#define ZORAN_ICR 0x040 /* Interrupt Control Register */ -#define ZORAN_ICR_EN (1<<24) -#define ZORAN_ICR_CODE (1<<28) -#define ZORAN_ICR_GIRQ0 (1<<29) -#define ZORAN_ICR_GIRQ1 (1<<30) - -#define ZORAN_I2C 0x044 /* I2C-Bus */ -#define ZORAN_I2C_SCL (1<<1) -#define ZORAN_I2C_SDA (1<<0) - -#define ZORAN_POST 0x48 /* PostOffice */ -#define ZORAN_POST_PEN (1<<25) -#define ZORAN_POST_TIME (1<<24) -#define ZORAN_POST_DIR (1<<23) -#define ZORAN_POST_GUESTID (3<<20) -#define ZORAN_POST_GUEST (7<<16) -#define ZORAN_POST_DATA (0xFF<<0) - -#endif diff --git a/drivers/media/video/zr36120_i2c.c b/drivers/media/video/zr36120_i2c.c deleted file mode 100644 index 21fde43a6ae..00000000000 --- a/drivers/media/video/zr36120_i2c.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - zr36120_i2c.c - Zoran 36120/36125 based framegrabbers - - Copyright (C) 1998-1999 Pauline Middelink - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include - -#include -#include - -#include "tuner.h" -#include "zr36120.h" - -/* ----------------------------------------------------------------------- */ -/* I2C functions */ -/* ----------------------------------------------------------------------- */ - -/* software I2C functions */ - -#define I2C_DELAY 10 - -static void i2c_setlines(struct i2c_bus *bus,int ctrl,int data) -{ - struct zoran *ztv = (struct zoran*)bus->data; - unsigned int b = 0; - if (data) b |= ztv->card->swapi2c ? ZORAN_I2C_SCL : ZORAN_I2C_SDA; - if (ctrl) b |= ztv->card->swapi2c ? ZORAN_I2C_SDA : ZORAN_I2C_SCL; - zrwrite(b, ZORAN_I2C); - udelay(I2C_DELAY); -} - -static int i2c_getdataline(struct i2c_bus *bus) -{ - struct zoran *ztv = (struct zoran*)bus->data; - if (ztv->card->swapi2c) - return zrread(ZORAN_I2C) & ZORAN_I2C_SCL; - return zrread(ZORAN_I2C) & ZORAN_I2C_SDA; -} - -static -void attach_inform(struct i2c_bus *bus, int id) -{ - struct zoran *ztv = (struct zoran*)bus->data; - struct video_decoder_capability dc; - int rv; - - switch (id) { - case I2C_DRIVERID_VIDEODECODER: - DEBUG(printk(CARD_INFO "decoder attached\n",CARD)); - - /* fetch the capabilities of the decoder */ - rv = i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_GET_CAPABILITIES, &dc); - if (rv) { - DEBUG(printk(CARD_DEBUG "decoder is not V4L aware!\n",CARD)); - break; - } - DEBUG(printk(CARD_DEBUG "capabilities %d %d %d\n",CARD,dc.flags,dc.inputs,dc.outputs)); - - /* Test if the decoder can de VBI transfers */ - if (dc.flags & 16 /*VIDEO_DECODER_VBI*/) - ztv->have_decoder = 2; - else - ztv->have_decoder = 1; - break; - case I2C_DRIVERID_TUNER: - ztv->have_tuner = 1; - DEBUG(printk(CARD_INFO "tuner attached\n",CARD)); - if (ztv->tuner_type >= 0) - { - if (i2c_control_device(&ztv->i2c,I2C_DRIVERID_TUNER,TUNER_SET_TYPE,&ztv->tuner_type)<0) - DEBUG(printk(CARD_INFO "attach_inform; tuner won't be set to type %d\n",CARD,ztv->tuner_type)); - } - break; - default: - DEBUG(printk(CARD_INFO "attach_inform; unknown device id=%d\n",CARD,id)); - break; - } -} - -static -void detach_inform(struct i2c_bus *bus, int id) -{ - struct zoran *ztv = (struct zoran*)bus->data; - - switch (id) { - case I2C_DRIVERID_VIDEODECODER: - ztv->have_decoder = 0; - DEBUG(printk(CARD_INFO "decoder detached\n",CARD)); - break; - case I2C_DRIVERID_TUNER: - ztv->have_tuner = 0; - DEBUG(printk(CARD_INFO "tuner detached\n",CARD)); - break; - default: - DEBUG(printk(CARD_INFO "detach_inform; unknown device id=%d\n",CARD,id)); - break; - } -} - -struct i2c_bus zoran_i2c_bus_template = -{ - "ZR36120", - I2C_BUSID_ZORAN, - NULL, - - SPIN_LOCK_UNLOCKED, - - attach_inform, - detach_inform, - - i2c_setlines, - i2c_getdataline, - NULL, - NULL -}; diff --git a/drivers/media/video/zr36120_mem.c b/drivers/media/video/zr36120_mem.c deleted file mode 100644 index 416eaa93b8a..00000000000 --- a/drivers/media/video/zr36120_mem.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - zr36120_mem.c - Zoran 36120/36125 based framegrabbers - - Copyright (C) 1998-1999 Pauline Middelink - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#ifdef CONFIG_BIGPHYS_AREA -#include -#endif - -#include "zr36120.h" -#include "zr36120_mem.h" - -/*******************************/ -/* Memory management functions */ -/*******************************/ - -void* bmalloc(unsigned long size) -{ - void* mem; -#ifdef CONFIG_BIGPHYS_AREA - mem = bigphysarea_alloc_pages(size/PAGE_SIZE, 1, GFP_KERNEL); -#else - /* - * The following function got a lot of memory at boottime, - * so we know its always there... - */ - mem = (void*)__get_free_pages(GFP_USER|GFP_DMA,get_order(size)); -#endif - if (mem) { - unsigned long adr = (unsigned long)mem; - while (size > 0) { - SetPageReserved(virt_to_page(phys_to_virt(adr))); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - } - return mem; -} - -void bfree(void* mem, unsigned long size) -{ - if (mem) { - unsigned long adr = (unsigned long)mem; - unsigned long siz = size; - while (siz > 0) { - ClearPageReserved(virt_to_page(phys_to_virt(adr))); - adr += PAGE_SIZE; - siz -= PAGE_SIZE; - } -#ifdef CONFIG_BIGPHYS_AREA - bigphysarea_free_pages(mem); -#else - free_pages((unsigned long)mem,get_order(size)); -#endif - } -} - -MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/zr36120_mem.h b/drivers/media/video/zr36120_mem.h deleted file mode 100644 index aad117acc91..00000000000 --- a/drivers/media/video/zr36120_mem.h +++ /dev/null @@ -1,3 +0,0 @@ -/* either kmalloc() or bigphysarea() alloced memory - continuous */ -void* bmalloc(unsigned long size); -void bfree(void* mem, unsigned long size); -- cgit v1.2.3 From a08cc44ec12e0a994ee85ba365315dbee982d6a7 Mon Sep 17 00:00:00 2001 From: Michael Hunold Date: Tue, 28 Nov 2006 08:13:58 -0300 Subject: V4L/DVB (4894): Mxb: fix to load the proper i2c modules Change order of module requests, so that tuner module is loaded at the end, because the tuner module probes multiple i2c addresses and might grab an i2c address that is not a tuner but something else. Signed-off-by: Michael Hunold Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mxb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c index b0aea4002d1..152cc6b3e15 100644 --- a/drivers/media/video/mxb.c +++ b/drivers/media/video/mxb.c @@ -160,10 +160,6 @@ static int mxb_probe(struct saa7146_dev* dev) printk("mxb: saa7111 i2c module not available.\n"); return -ENODEV; } - if ((result = request_module("tuner")) < 0) { - printk("mxb: tuner i2c module not available.\n"); - return -ENODEV; - } if ((result = request_module("tea6420")) < 0) { printk("mxb: tea6420 i2c module not available.\n"); return -ENODEV; @@ -176,6 +172,10 @@ static int mxb_probe(struct saa7146_dev* dev) printk("mxb: tda9840 i2c module not available.\n"); return -ENODEV; } + if ((result = request_module("tuner")) < 0) { + printk("mxb: tuner i2c module not available.\n"); + return -ENODEV; + } mxb = kzalloc(sizeof(struct mxb), GFP_KERNEL); if( NULL == mxb ) { -- cgit v1.2.3 From c28089a65ca03890db120ee2bf6a7eb0cf603817 Mon Sep 17 00:00:00 2001 From: Michael Hunold Date: Tue, 28 Nov 2006 08:14:44 -0300 Subject: V4L/DVB (4895): Accept tuners on saa7146 i2c bus only on address 0x60. Signed-off-by: Michael Hunold Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/media/video') diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 40590bae5ff..705daaa2a4f 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -443,6 +443,10 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) printk("%02x ",buffer[i]); printk("\n"); } + /* HACK: This test were added to avoid tuner to probe tda9840 and tea6415c on the MXB card */ + if (adap->id == I2C_HW_SAA7146 && addr < 0x4a) + return -ENODEV; + /* autodetection code based on the i2c addr */ if (!no_autodetect) { switch (addr) { -- cgit v1.2.3 From 177aaaf826856cd8c82e790cf125186b5634f492 Mon Sep 17 00:00:00 2001 From: Thomas Genty Date: Wed, 29 Nov 2006 21:57:24 -0300 Subject: V4L/DVB (4898): Saa7134: add support for remote control of Hauppauge HVR1110 This patch adds support for the remote control bundled with the Hauppauge HVR1110 Signed-off-by: Thomas Genty Signed-off-by: Nickolay V. Shmyrev Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ir-kbd-i2c.c | 3 ++- drivers/media/video/saa7134/saa7134-cards.c | 11 +++++++++-- drivers/media/video/saa7134/saa7134-i2c.c | 1 + drivers/media/video/saa7134/saa7134-input.c | 26 ++++++++++++++++++++++++++ 4 files changed, 38 insertions(+), 3 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index dd6341f2e39..59edf58204d 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -354,6 +354,7 @@ static int ir_attach(struct i2c_adapter *adap, int addr, break; case 0x7a: case 0x47: + case 0x71: /* Handled by saa7134-input */ name = "SAA713x remote"; ir_type = IR_TYPE_OTHER; @@ -448,7 +449,7 @@ static int ir_probe(struct i2c_adapter *adap) */ static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1}; - static const int probe_saa7134[] = { 0x7a, 0x47, -1 }; + static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, -1 }; static const int probe_em28XX[] = { 0x30, 0x47, -1 }; const int *probe = NULL; struct i2c_client c; diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index d0ddc65d7eb..4dead84aff4 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -3135,17 +3135,23 @@ struct saa7134_board saa7134_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .mpeg = SAA7134_MPEG_DVB, - .gpiomask = 0x000200000, .inputs = {{ .name = name_tv, .vmux = 1, .amux = TV, .tv = 1, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE2, /* FIXME: audio doesn't work on svideo/composite */ + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, /* FIXME: audio doesn't work on svideo/composite */ }}, .radio = { .name = name_radio, .amux = TV, - .gpio = 0x0200000, }, }, [SAA7134_BOARD_CINERGY_HT_PCMCIA] = { @@ -3976,6 +3982,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_PINNACLE_PCTV_110i: case SAA7134_BOARD_PINNACLE_PCTV_310i: case SAA7134_BOARD_UPMOST_PURPLE_TV: + case SAA7134_BOARD_HAUPPAUGE_HVR1110: dev->has_remote = SAA7134_REMOTE_I2C; break; case SAA7134_BOARD_AVERMEDIA_A169_B: diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c index 6162550c413..6f9fe86fed9 100644 --- a/drivers/media/video/saa7134/saa7134-i2c.c +++ b/drivers/media/video/saa7134/saa7134-i2c.c @@ -341,6 +341,7 @@ static int attach_inform(struct i2c_client *client) switch (client->addr) { case 0x7a: case 0x47: + case 0x71: { struct IR_i2c *ir = i2c_get_clientdata(client); d1printk("%s i2c IR detected (%s).\n", diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 5d2bf15239f..60b38defd9b 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -112,6 +112,27 @@ static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) return 1; } +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)) + return -EIO; + + cod4 = buf[4]; + code4 = (cod4 >> 2); + code3 = buf[3]; + if (code3 == 0) + /* no key pressed */ + return 0; + + /* return key */ + *ir_key = code4; + *ir_raw = code4; + return 1; +} + void saa7134_input_irq(struct saa7134_dev *dev) { struct saa7134_ir *ir = dev->remote; @@ -371,6 +392,11 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir) ir->get_key = get_key_purpletv; ir->ir_codes = ir_codes_purpletv; 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; + break; default: dprintk("Shouldn't get here: Unknown board %x for I2C IR?\n",dev->board); break; -- cgit v1.2.3 From bf5dbed6b499787809c78710b209efc76939592b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 1 Dec 2006 12:39:46 -0300 Subject: V4L/DVB (4901): Improve debug msgs to show fourcc and buffer length on video_ioctl2 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videodev.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 1be712757e4..6a0e8ca7294 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -342,7 +342,7 @@ static void dbgbuf(unsigned int cmd, struct video_device *vfd, dbgarg (cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, " "bytesused=%d, flags=0x%08d, " - "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx\n", + "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx, length=%d\n", (p->timestamp.tv_sec/3600), (int)(p->timestamp.tv_sec/60)%60, (int)(p->timestamp.tv_sec%60), @@ -352,7 +352,7 @@ static void dbgbuf(unsigned int cmd, struct video_device *vfd, p->bytesused,p->flags, p->field,p->sequence, prt_names(p->memory,v4l2_memory_names), - p->m.userptr); + p->m.userptr, p->length); dbgarg2 ("timecode= %02d:%02d:%02d type=%d, " "flags=0x%08d, frames=%d, userbits=0x%08x\n", tc->hours,tc->minutes,tc->seconds, @@ -369,9 +369,13 @@ static inline void dbgrect(struct video_device *vfd, char *s, static inline void v4l_print_pix_fmt (struct video_device *vfd, struct v4l2_pix_format *fmt) { - dbgarg2 ("width=%d, height=%d, format=0x%08x, field=%s, " + dbgarg2 ("width=%d, height=%d, format=%c%c%c%c, field=%s, " "bytesperline=%d sizeimage=%d, colorspace=%d\n", - fmt->width,fmt->height,fmt->pixelformat, + fmt->width,fmt->height, + (fmt->pixelformat & 0xff), + (fmt->pixelformat >> 8) & 0xff, + (fmt->pixelformat >> 16) & 0xff, + (fmt->pixelformat >> 24) & 0xff, prt_names(fmt->field,v4l2_field_names_FIXME), fmt->bytesperline,fmt->sizeimage,fmt->colorspace); }; @@ -530,12 +534,13 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, } if (!ret) dbgarg (cmd, "index=%d, type=%d, flags=%d, " - "description=%s," - " pixelformat=0x%8x\n", + "pixelformat=%c%c%c%c, description='%s'\n", f->index, f->type, f->flags, - f->description, - f->pixelformat); - + (f->pixelformat & 0xff), + (f->pixelformat >> 8) & 0xff, + (f->pixelformat >> 16) & 0xff, + (f->pixelformat >> 24) & 0xff, + f->description); break; } case VIDIOC_G_FMT: -- cgit v1.2.3 From a66d23368068d6027feedc010304d510e6d1fe56 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Fri, 1 Dec 2006 15:37:49 -0300 Subject: V4L/DVB (4908): Remove the fake RGB32 format from cafe_ccic Remove RGB32, useful for debugging, but with no place in production. Signed-off-by: Jonathan Corbet Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cafe_ccic.c | 42 +++-------------------------------------- drivers/media/video/ov7670.c | 15 --------------- 2 files changed, 3 insertions(+), 54 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index 30864dac26a..9d9844e2295 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -612,16 +612,6 @@ static void cafe_ctlr_image(struct cafe_camera *cam) C0_DF_MASK); break; - /* - * For "fake rgb32" get the image pitch right. - */ - case V4L2_PIX_FMT_RGB32: - cafe_reg_write_mask(cam, REG_IMGPITCH, fmt->bytesperline/2, - IMGP_YP_MASK); - imgsz = ((fmt->height << IMGSZ_V_SHIFT) & IMGSZ_V_MASK) | - ((fmt->bytesperline/2) & IMGSZ_H_MASK); - cafe_reg_write(cam, REG_IMGSIZE, imgsz); - /* fall into ... */ case V4L2_PIX_FMT_RGB444: cafe_reg_write_mask(cam, REG_CTRL0, C0_DF_RGB|C0_RGBF_444|C0_RGB4_XRGB, @@ -902,11 +892,8 @@ static int cafe_alloc_dma_bufs(struct cafe_camera *cam, int loadtime) cafe_set_config_needed(cam, 1); if (loadtime) cam->dma_buf_size = dma_buf_size; - else { + else cam->dma_buf_size = cam->pix_format.sizeimage; - if (cam->pix_format.pixelformat == V4L2_PIX_FMT_RGB32) - cam->dma_buf_size /= 2; - } if (n_dma_bufs > 3) n_dma_bufs = 3; @@ -1751,26 +1738,6 @@ static struct video_device cafe_v4l_template = { * Interrupt handler stuff */ -/* - * Create RGB32 from RGB444 so it can be displayed before the applications - * know about the latter format. - */ -static void cafe_fake_rgb32(struct cafe_camera *cam, char *dest, char *src) -{ - int i; - u16 *ssrc = (u16 *) src; - - /* RGB444 version */ - for (i = 0; i < cam->pix_format.sizeimage; i += 4) { - // dest[0] = (*ssrc & 0xf000) >> 8; - dest[0] = (*ssrc & 0x000f) << 4; - dest[1] = (*ssrc & 0x00f0); - dest[2] = (*ssrc & 0x0f00) >> 4; - dest[3] = (*ssrc & 0xf000); /* Alpha */ - dest += 4; - ssrc++; - } -} static void cafe_frame_tasklet(unsigned long data) @@ -1800,11 +1767,8 @@ static void cafe_frame_tasklet(unsigned long data) */ sbuf = list_entry(cam->sb_avail.next, struct cafe_sio_buffer, list); - if (cam->pix_format.pixelformat == V4L2_PIX_FMT_RGB32) - cafe_fake_rgb32(cam, sbuf->buffer, cam->dma_bufs[bufno]); - else - memcpy(sbuf->buffer, cam->dma_bufs[bufno], - cam->pix_format.sizeimage); + memcpy(sbuf->buffer, cam->dma_bufs[bufno], + cam->pix_format.sizeimage); sbuf->v4lbuf.bytesused = cam->pix_format.sizeimage; sbuf->v4lbuf.sequence = cam->buf_seq[bufno]; sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED; diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c index b7d824ee03e..7d380d76338 100644 --- a/drivers/media/video/ov7670.c +++ b/drivers/media/video/ov7670.c @@ -497,19 +497,6 @@ static struct ov7670_format_struct { .regs = ov7670_fmt_rgb565, .cmatrix = { 179, -179, 0, -61, -176, 228 }, }, - /* - * Pretend we do RGB32. This is here on the assumption that the - * upper layer will reformat RGB444 appropriately. - * - * The entire purpose for this thing's existence is to enable easy - * display of RGB444 for debugging purposes. It will come out soon. - */ - { - .desc = "RGB32 (faked)", - .pixelformat = V4L2_PIX_FMT_RGB32, - .regs = ov7670_fmt_rgb444, - .cmatrix = { 179, -179, 0, -61, -176, 228 }, - }, }; #define N_OV7670_FMTS (sizeof(ov7670_formats)/sizeof(ov7670_formats[0])) @@ -694,8 +681,6 @@ static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt, pix->width = wsize->width; pix->height = wsize->height; pix->bytesperline = pix->width*BYTES_PER_PIXEL; - if (pix->pixelformat == V4L2_PIX_FMT_RGB32) - pix->bytesperline *= 2; pix->sizeimage = pix->height*pix->bytesperline; return 0; } -- cgit v1.2.3 From c8f5b2f5607e78c61df229259c539a5d9488a013 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Fri, 1 Dec 2006 15:50:59 -0300 Subject: V4L/DVB (4909): Add s/g_parm to cafe_ccic Add s/g_parm support allowing applications to tweak the frame rate. Signed-off-by: Jonathan Corbet Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cafe_ccic.c | 34 ++++++++++++++++++- drivers/media/video/ov7670.c | 72 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 100 insertions(+), 6 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index 9d9844e2295..e347c7ebc98 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -1671,6 +1671,37 @@ static int cafe_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a) return 0; } +/* + * G/S_PARM. Most of this is done by the sensor, but we are + * the level which controls the number of read buffers. + */ +static int cafe_vidioc_g_parm(struct file *filp, void *priv, + struct v4l2_streamparm *parms) +{ + struct cafe_camera *cam = priv; + int ret; + + mutex_lock(&cam->s_mutex); + ret = __cafe_cam_cmd(cam, VIDIOC_G_PARM, parms); + mutex_unlock(&cam->s_mutex); + parms->parm.capture.readbuffers = n_dma_bufs; + return ret; +} + +static int cafe_vidioc_s_parm(struct file *filp, void *priv, + struct v4l2_streamparm *parms) +{ + struct cafe_camera *cam = priv; + int ret; + + mutex_lock(&cam->s_mutex); + ret = __cafe_cam_cmd(cam, VIDIOC_S_PARM, parms); + mutex_unlock(&cam->s_mutex); + parms->parm.capture.readbuffers = n_dma_bufs; + return ret; +} + + static void cafe_v4l_dev_release(struct video_device *vd) { struct cafe_camera *cam = container_of(vd, struct cafe_camera, v4ldev); @@ -1724,7 +1755,8 @@ static struct video_device cafe_v4l_template = { .vidioc_queryctrl = cafe_vidioc_queryctrl, .vidioc_g_ctrl = cafe_vidioc_g_ctrl, .vidioc_s_ctrl = cafe_vidioc_s_ctrl, - /* Do cropping someday */ + .vidioc_g_parm = cafe_vidioc_g_parm, + .vidioc_s_parm = cafe_vidioc_s_parm, }; diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c index 7d380d76338..89dd18c3c5c 100644 --- a/drivers/media/video/ov7670.c +++ b/drivers/media/video/ov7670.c @@ -35,6 +35,11 @@ MODULE_LICENSE("GPL"); #define QCIF_WIDTH 176 #define QCIF_HEIGHT 144 +/* + * Our nominal (default) frame rate. + */ +#define OV7670_FRAME_RATE 30 + /* * The 7670 sits on i2c with ID 0x42 */ @@ -291,7 +296,7 @@ static struct regval_list ov7670_default_regs[] = { { 0xc9, 0x60 }, { REG_COM16, 0x38 }, { 0x56, 0x40 }, - { 0x34, 0x11 }, { REG_COM11, COM11_EXP }, + { 0x34, 0x11 }, { REG_COM11, COM11_EXP|COM11_HZAUTO }, { 0xa4, 0x88 }, { 0x96, 0 }, { 0x97, 0x30 }, { 0x98, 0x20 }, { 0x99, 0x30 }, { 0x9a, 0x84 }, @@ -721,6 +726,63 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt) return 0; } +/* + * Implement G/S_PARM. There is a "high quality" mode we could try + * to do someday; for now, we just do the frame rate tweak. + */ +static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms) +{ + struct v4l2_captureparm *cp = &parms->parm.capture; + unsigned char clkrc; + int ret; + + if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + ret = ov7670_read(c, REG_CLKRC, &clkrc); + if (ret < 0) + return ret; + memset(cp, 0, sizeof(struct v4l2_captureparm)); + cp->capability = V4L2_CAP_TIMEPERFRAME; + cp->timeperframe.numerator = 1; + cp->timeperframe.denominator = OV7670_FRAME_RATE; + if ((clkrc & CLK_EXT) == 0 && (clkrc & CLK_SCALE) > 1) + cp->timeperframe.denominator /= (clkrc & CLK_SCALE); + return 0; +} + +static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms) +{ + struct v4l2_captureparm *cp = &parms->parm.capture; + struct v4l2_fract *tpf = &cp->timeperframe; + unsigned char clkrc; + int ret, div; + + if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (cp->extendedmode != 0) + return -EINVAL; + /* + * CLKRC has a reserved bit, so let's preserve it. + */ + ret = ov7670_read(c, REG_CLKRC, &clkrc); + if (ret < 0) + return ret; + if (tpf->numerator == 0 || tpf->denominator == 0) + div = 1; /* Reset to full rate */ + else + div = (tpf->numerator*OV7670_FRAME_RATE)/tpf->denominator; + if (div == 0) + div = 1; + else if (div > CLK_SCALE) + div = CLK_SCALE; + clkrc = (clkrc & 0x80) | div; + tpf->numerator = 1; + tpf->denominator = OV7670_FRAME_RATE/div; + return ov7670_write(c, REG_CLKRC, clkrc); +} + + + /* * Code for dealing with controls. */ @@ -1231,10 +1293,10 @@ static int ov7670_command(struct i2c_client *client, unsigned int cmd, return ov7670_s_ctrl(client, (struct v4l2_control *) arg); case VIDIOC_G_CTRL: return ov7670_g_ctrl(client, (struct v4l2_control *) arg); - /* Todo: - g/s_parm - initialization - */ + case VIDIOC_S_PARM: + return ov7670_s_parm(client, (struct v4l2_streamparm *) arg); + case VIDIOC_G_PARM: + return ov7670_g_parm(client, (struct v4l2_streamparm *) arg); } return -EINVAL; } -- cgit v1.2.3 From 122b5dbea6fa3727fc99fbdc2cf5e4d9b8a5bb00 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 3 Dec 2006 06:45:07 -0300 Subject: V4L/DVB (4913): Fix broken TUNER_LG_NTSC_TAPE radio support The TUNER_LG_NTSC_TAPE is identical in all respects to the TUNER_PHILIPS_FM1236_MK3. So use the params struct for the Philips tuner. Also add this LG_NTSC_TAPE tuner to the switches where radio specific parameters are set so it behaves like a TUNER_PHILIPS_FM1236_MK3. This change fixes the radio support for this tuner (the wrong bandswitch byte was used). Thanks to Andy Walls for finding this bug. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-simple.c | 2 ++ drivers/media/video/tuner-types.c | 14 ++------------ 2 files changed, 4 insertions(+), 12 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 63db4e97ae6..fcf8693e4d5 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -108,6 +108,7 @@ static int tuner_stereo(struct i2c_client *c) case TUNER_PHILIPS_FM1216ME_MK3: case TUNER_PHILIPS_FM1236_MK3: case TUNER_PHILIPS_FM1256_IH3: + case TUNER_LG_NTSC_TAPE: stereo = ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3); break; default: @@ -421,6 +422,7 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) case TUNER_PHILIPS_FM1216ME_MK3: case TUNER_PHILIPS_FM1236_MK3: case TUNER_PHILIPS_FMD1216ME_MK3: + case TUNER_LG_NTSC_TAPE: buffer[3] = 0x19; break; case TUNER_TNF_5335MF: diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c index 781682373b6..1256c64af4d 100644 --- a/drivers/media/video/tuner-types.c +++ b/drivers/media/video/tuner-types.c @@ -672,16 +672,6 @@ static struct tuner_params tuner_panasonic_vp27_params[] = { }, }; -/* ------------ TUNER_LG_NTSC_TAPE - LGINNOTEK NTSC ------------ */ - -static struct tuner_params tuner_lg_ntsc_tape_params[] = { - { - .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_fm1236_mk3_ntsc_ranges, - .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), - }, -}; - /* ------------ TUNER_TNF_8831BGFF - Philips PAL ------------ */ static struct tuner_range tuner_tnf_8831bgff_pal_ranges[] = { @@ -1331,8 +1321,8 @@ struct tunertype tuners[] = { }, [TUNER_LG_NTSC_TAPE] = { /* LGINNOTEK NTSC */ .name = "LG NTSC (TAPE series)", - .params = tuner_lg_ntsc_tape_params, - .count = ARRAY_SIZE(tuner_lg_ntsc_tape_params), + .params = tuner_fm1236_mk3_params, + .count = ARRAY_SIZE(tuner_fm1236_mk3_params), }, [TUNER_TNF_8831BGFF] = { /* Philips PAL */ .name = "Tenna TNF 8831 BGFF)", -- cgit v1.2.3 From 781aa1d1ab7ba13314af0af6c5d70c0eb0e96bf4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 4 Dec 2006 08:30:53 -0300 Subject: V4L/DVB (4922): Add usbvision driver This patch adds usbvision into V4L/DVB HG tree. Usbvision driver is a GPL driver, made by: Joerg Heckenbach and Dwaine Garden V4L2 migration made by: Thierry Merle Kconfig/Makefile scripts by: Mauro Carvalho Chehab Signed-off-by: Joerg Heckenbach Signed-off-by: Dwaine Garden Signed-off-by: Thierry Merle Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 12 + drivers/media/video/Makefile | 1 + drivers/media/video/usbvision/Makefile | 5 + drivers/media/video/usbvision/usbvision-core.c | 5880 +++++++++++++++++++++++ drivers/media/video/usbvision/usbvision-i2c.c | 265 + drivers/media/video/usbvision/usbvision-i2c.h | 58 + drivers/media/video/usbvision/usbvision.h | 594 +++ drivers/media/video/usbvision/usbvision_ioctl.h | 34 + 8 files changed, 6849 insertions(+) create mode 100644 drivers/media/video/usbvision/Makefile create mode 100644 drivers/media/video/usbvision/usbvision-core.c create mode 100644 drivers/media/video/usbvision/usbvision-i2c.c create mode 100644 drivers/media/video/usbvision/usbvision-i2c.h create mode 100644 drivers/media/video/usbvision/usbvision.h create mode 100644 drivers/media/video/usbvision/usbvision_ioctl.h (limited to 'drivers/media/video') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index ef803106b79..9365a8dd44e 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -686,6 +686,18 @@ source "drivers/media/video/pvrusb2/Kconfig" source "drivers/media/video/em28xx/Kconfig" +config VIDEO_USBVISION + tristate "USB video devices based on NT1003/1005/1005" + depends on I2C && VIDEO_V4L2 + select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO + ---help--- + There are more than 50 different USB video devices based on + NT1003/1004/1005 USB Bridges. This driver enables using those + devices. + + To compile this driver as a module, choose M here: the + module will be called ovcamchip. + source "drivers/media/video/usbvideo/Kconfig" source "drivers/media/video/et61x251/Kconfig" diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 20b9cbc144b..9b1f3f06bb7 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -62,6 +62,7 @@ obj-$(CONFIG_VIDEO_MEYE) += meye.o obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/ obj-$(CONFIG_VIDEO_CX88) += cx88/ obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ +obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/ obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o diff --git a/drivers/media/video/usbvision/Makefile b/drivers/media/video/usbvision/Makefile new file mode 100644 index 00000000000..bad2eee2dbb --- /dev/null +++ b/drivers/media/video/usbvision/Makefile @@ -0,0 +1,5 @@ +usbvision-objs := usbvision-core.o usbvision-i2c.o + +obj-$(CONFIG_VIDEO_USBVISION) += usbvision.o + +EXTRA_CFLAGS += -Idrivers/media/video diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c new file mode 100644 index 00000000000..62699ca020a --- /dev/null +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -0,0 +1,5880 @@ +/* + * USB USBVISION Video device driver 0.9.8.3cvs (For Kernel 2.4.19-2.4.32 + 2.6.0-2.6.16) + * + * + * + * Copyright (c) 1999-2005 Joerg Heckenbach + * + * This module is part of usbvision driver project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Let's call the version 0.... until compression decoding is completely + * implemented. + * + * This driver is written by Jose Ignacio Gijon and Joerg Heckenbach. + * It was based on USB CPiA driver written by Peter Pregler, + * Scott J. Bertin and Johannes Erdfelt + * Ideas are taken from bttv driver by Ralph Metzler, Marcus Metzler & + * Gerd Knorr and zoran 36120/36125 driver by Pauline Middelink + * Updates to driver completed by Dwaine P. Garden + * + * History: + * + * Mar. 2000 - 15.12.2000: (0.0.0 - 0.2.0) + * Several alpha drivers and the first beta. + * + * Since Dec. 2000: (0.2.1) or (v2.1) + * Code changes or updates by Dwaine Garden and every other person. + * + * Added: New Hauppauge TV device Vendor ID: 0x0573 + * Product ID: 0x4D01 + * (Thanks to Giovanni Garberoglio) + * + * Added: UK Hauppauge WinTV-USB Vendor ID: 0x0573 + * Product ID: 0x4D02 + * (Thanks to Derek Freeman-Jones) + * + * Feb, 2001 - Apr 08, 2001: (0.3.0) + * - Some fixes. Driver is now more stable. + * - Scratch is organized as ring-buffer now for better performance + * - DGA (overlay) is now supported. + * !!!!Danger!!!! Clipping is not yet implemented. Your system will + * crash if your video window leaves the screen!!! + * - Max. Framesize is set to 320x240. There isn't more memory on the + * nt1003 video device for the FIFO. + * - Supported video palettes: RGB565, RGB555, RGB24, RGB32 + * + * + * Apr 15, 2001: (0.3.1-test...) + * - Clipping is implemented + * - NTSC is now coloured (Thanks to Dwaine Garden) + * - Added SECAM colour detection in saa7111-new + * - Added: French Hauppauge WinTV USB Vendor ID: 0x0573 + * Product ID: 0x4D03 + * (Thanks to Julius Hrivnac) + * - Added: US Hauppauge WINTV USB Vendor ID: 0x0573 + * Product ID: 0x4D00 + * (Thanks to Derrick J Brashear) + * - Changes for adding new devices. There's now a table in usbvision.h. + * Adding your devices data to the usbvision_device_data table is all + * you need to add a new device. + * + * May 11, 2001: (0.3.2-test...) (Thanks to Derek Freeman-Jones) + * - Support YUV422 raw format for people with hardware scaling. + * - Only power on the device when opened (use option PowerOnAtOpen=0 to disable it). + * - Turn off audio so we can listen to Line In. + * + * July 5, 2001 - (Patch the driver to run with Kernel 2.4.6) + * - Fixed a problem with the number of parameters passed to video_register_device. + * + * July 6, 2001 - Added: HAUPPAUGE WINTV-USB FM USA Vendor ID: 0x0573 + * Product ID: 0x4D10 + * (Thanks to Braddock Gaskill) + * Added: USBGear USBG-V1 resp. HAMA USB + * Vendor ID: 0x0573 + * Product ID: 0x0003 + * (Thanks to Bradley A. Singletary and Juergen Weigert) + * + * Jan 24, 2002 - (0.3.3-test...) + * - Moved all global variables that are device specific the usb_usbvision struct + * - Fixed the 64x48 unchangable image in xawtv when starting it with overlay + * - Add VideoNorm and TunerType to the usb_device_data table + * - Checked the audio channels and mute for HAUPPAUGE WinTV USB FM + * - Implemented the power on when opening the device. But some software opens + * the device several times when starting. So the i2c parts are just registered + * by an open, when they become deregistered by the next close. You can speed + * up tuner detection, when adding "options tuner addr=your_addr" to /etc/modules.conf + * - Begin to resize the frame in width and height. So it will be possible to watch i.e. + * 384x288 pixels at 23 fps. + * + * Feb 10, 2002 + * - Added radio device + * + * + * Jul 30, 2002 - (Thanks Cameron Maxwell) + * - Changes to usbvision.h --fixed usbvision device data structure, incorrectly had (0x0573, 0x4d21) for WinTV-USB II, should be 0x4d20. + * - Changes for device WinTV-USB II (0x0573. 0x4D21). It does not have a FM tuner. + * - Added the real device HAUPPAUGE WINTV-USB II (PAL) to the device structure in usbvision.h. + * - Changes to saa7113-new, the video is 8 bit data for the Phillips SAA7113 not 16bit like SAA7111. + * - Tuned lots of setup registers for the Phillips SAA7113 video chipset. + * - Changes to the supplied makefile. (Dwaine Garden) Still needs to be fixed so it will compile modules on different distrubutions. + * + * + * Aug 10, 2002 - (Thanks Mike Klinke) + * - Changes to usbvision.txt -- Fixed instructions on the location to copy the contents of the tgz file. + * - Added device WinTV-USB FM Model 621 (0x0573. 0x4D30). There is another device which carries the same name. Kept that device in the device structure. + * + * Aug 12, 2002 - Dwaine Garden + * - Added the ability to read the NT100x chip for the MaxISOPacketLength and USB Bandwidth + * Setting of the video device. + * - Adjustments to the SAA7113H code for proper video output. + * - Changes to usbvision.h, so all the devices with FM tuners are working. + * + * Feb 10, 2003 - Joerg Heckenbach + * - fixed endian bug for Motorola PPC + * + * Feb 13, 2003 - Joerg Heckenbach + * - fixed Vin_Reg setting and presetting from usbvision_device_data() + * + * Apr 19, 2003 - Dwaine Garden + * - Fixed compiling errors under RedHat v9.0. from uvirt_to_kva and usbvision_mmap. (Thanks Cameron Maxwell) + * - Changed pte_offset to pte_offset_kernel. + * - Changed remap_page_range and added additional parameter to function. + * - Change setup parameters for the D-Link V100 USB device + * - Added a new device to the usbvision driver. Pinnacle Studio PCTV USB (PAL) 0x2304 0x0110 + * - Screwed up the sourceforge.net cvs respository! 8*) + * + * Apr 22, 2002 - Dwaine Garden + * - Added a new device to the usbvision driver. Dazzle DVC-80 (PAL) 0x07d0 0x0004. (Thanks Carl Anderson) + * - Changes to some of the comments. + * + * June 06, 2002 - Ivan, Dwaine Garden + * - Ivan updates for fine tuning device parameters without driver recompiling. (Ivan) + * - Changes to some of the comments. (Dwaine Garden) + * - Changes to the makefile - Better CPU settings. (Ivan) + * - Changes to device Hauppauge WinTv-USB III (PAL) FM Model 568 - Fine tuning parameters (Ivan) + * + * + * Oct 16, 2003 - 0.9.0 - Joerg Heckenbach + * - Implementation of the first part of the decompression algorithm for intra frames. + * The resolution has to be 320x240. A dynamic adaption of compression deepth is + * missing yet. + * + * Oct 22, 2003 - 0.9.1 - Joerg Heckenbach + * - Implementation of the decompression algorithm for inter frames. + * The resolution still has to be 320x240. + * + * Nov 2003 - Feb 2004 - 0.9.2 to 0.9.3 - Joerg Heckenbach + * - Implement last unknown compressed block type. But color is still noisy. + * - Finding criteria for adaptive compression adjustment. + * - Porting to 2.6 kernels, but still working under 2.4 + * + * Feb 04, 2004 - 0.9.4 Joerg Heckenbach + * - Found bug in color decompression. Color is OK now. + * + * Feb 09, 2004 - 0.9.5 Joerg Heckenbach + * - Add auto-recognition of chip type NT1003 or NT1004. + * - Add adaptive compression adjustment. + * - Patched saa7113 multiplexer switching (Thanks to Orlando F.S. Bordoni) + * + * Feb 24, 2004 - 0.9.6 Joerg Heckenbach + * - Add a timer to wait before poweroff at close, to save start time in + * some video applications + * + * Mar 4, 2004 - 0.9.6 Dwaine Garden + * - Added device Global Village GV-007 (NTSC) to usbvision.h (Thanks to Abe Skolnik) + * - Forgot to add this device to the driver. 8*) + * + * June 2, 2004 - 0.9.6 Dwaine Garden + * - Fixed sourceforge.net cvs repository. + * - Added #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,26) for .owner to help compiling under kernels 2.4.x which do not have the i2c v2.8.x updates. + * - Added device Hauppauge WinTv-USB III (PAL) FM Model 597 to usbvision.h + * + * July 1, 2004 -0.9.6 Dwaine Garden + * - Patch was submitted by Hal Finkel to fix the problem with the tuner not working under kernel 2.6.7. + * - Thanks Hal..... + * + * July 30, 2004 - 0.9.6 Dwaine Garden + * - Patch was submitted by Tobias Diaz to fix Model ID mismatch in usbvision.h. + * - Thanks..... + * + * August 12, 2004 - 0.9.6 Dwaine Garden + * - Updated the readme file so people could install the driver under the configuration file for kernel 2.6.x recompiles. Now people can use make xconfig! + * - Added new device "Camtel Technology Corp TVB330-USB FM". + * - Sourceforge.net CVS has been updated with all the changes. + * + * August 20, 2004 - 0.9.7 Dwaine Garden + * - Added Device "Hauppauge USB Live Model 600" + * - Fixed up all the devices which did not have a default tuner type in usbvision.h. It's best guess, at least until someone with the device tells me otherwise. + * - Sourceforge.net CVS has been updated with all the changes. + * - Clean up the driver. + * + * September 13, 2004 - 0.9.8 Dwaine Garden + * - Changed usbvision_muxsel to address the problem with black & white s-video output for NT1004 devices with saa7114 video decoder. Thanks to Emmanuel for the patch and testing. + * - Fixed up SECAM devices which could not properly output video. Changes to usbmuxsel. Thanks to Emmanuel for the patch and everyone with a SECAM device which help test. + * - Removed some commented out code. Clean up. + * - Tried to fix up the annoying empty directories in the sourceforge.net cvs. Fuck it up again. 8*( + * + * November 15, 2004 - 0.9.8 Dwaine Garden + * - Release new tar - 0.9.8 on sourceforge.net + * - Added some new devices to usbvision.h WinTV USB Model 602 40201 Rev B282, Hauppague WinTV USB Model 602 40201 Rev B285 + * - Added better compatibility for 2.6.x kernels. + * - Hardware full screen scaling in grabdisplay mode. + * - Better support for sysfs. More code to follow for both video device and radio device. Device information is located at /sys/class/video4linux/video0 + * - Added module_param so loaded module parameters are displayed in sysfs. Driver parameters should show up in /sys/module/usbvision + * - Adjusted the SAA7111 registers to match the 2.6.x kernel SAA7111 code. Thanks to the person which helped test. + * - Changed to wait_event_interruptible. For all the people running Fedora 2. + * - Added some screenshots of actual video captures on sourceforge.net. + * + * November 24, 2004 - 0.9.8.1cvs Dwaine Garden + * - Added patch to check for palette and format in VIDIOCSPICT. Helix Producer should work fine with the driver now. Thanks Jason Simpson + * - Two device description changes and two additions for the maintainer of usb.ids. + * + * December 2, 2004 - 0.9.8.1cvs Dwaine Garden + * - Added patch for YUV420P and YUV422P video output. Thanks to Alex Smith. + * - Better support for mythtv. + * + * January 2, 2005 - 0.9.8.1cvs Dwaine Garden + * - Setup that you can specify which device is used for video. Default is auto detect next available device number eg. /dev/videoX + * - Setup that you can specify which device is used for radio. Default is auto detect next available device number eg. /dev/radioX + * - usb_unlink_urb() is deprecated for synchronous unlinks. Using usb_kill_urb instead. + * - usbvision_kvirt_to_pa is deprecated. Removed. + * - Changes are related to kernel changes for 2.6.10. (Fedora 4) + * + * February 2, 2005 - 0.9.8.1cvs Dwaine Garden + * - Added a new device to usbvision.h Dazzle DVC 50. Thanks to Luiz S. + * + * March 29, 2005 - 0.9.8.1cvs Dwaine Garden + * - Fixed compile error with saa7113 under kernels 2.6.11+ + * - Added module parameter to help people with Black and White output with using s-video input. Some cables and input device are wired differently. + * - Removed the .id from the i2c usbvision template. There was a change to the i2c with kernels 2.6.11+. + * + * April 9, 2005 - 0.9.8.1cvs Dwaine Garden + * - Added in the 2.4 and 2.6 readme files the SwitchSVideoInput parameter information. This will help people setup the right values for the parameter. + * If your device experiences Black and White images with the S-Video Input. Set this parameter to 1 when loading the module. + * - Replaced the wrong 2.6 readme file. I lost the right version. Someone sent me the right version by e-mail. Thanks. + * - Released new module version on sourceforge.net. So everyone can enjoy all the fixes and additional device support. + * + * April 20, 2005 - 0.9.8.2cvs Dwaine Garden + * - Release lock in usbvision_v4l_read_done. -Thanks to nplanel for the patch. + * - Additional comments to the driver. + * - Fixed some spelling mistakes. 8*) + * + * April 23, 2005 - 0.9.8.2cvs Joerg Heckenbach + * - Found bug in usbvision line counting. Now there should be no spurious lines in the image any longer. + * - Swapped usbvision_register_video and usbvision_configure_video to fix problem with PowerOnAtOpen=0. + * Thanks to Erwan Velu + * + * April 26, 2005 - 0.9.8.2cvs Joerg Heckenbach + * - Fixed problem with rmmod module and oppses. Replaced vfree(usbvision->overlay_base) with iounmap(usbvision->overlay_base). + * - Added function usb_get_dev(dev) and ; To help with unloading the module multiple times without crashing. + * (Keep the reference count in kobjects correct) + * + * June 14, 2005 - 0.9.8.2cvs Dwaine + * - Missed a change in saa7113.c for checking kernel version. Added conditional if's. + * + * June 15, 2005 - 0.9.8.2cvs Dwaine + * - Added new device WinTV device VendorId 0573 and ProductId 4d29. + * - Hacked some support for newer NT1005 devices. This devices only seem to have one configuration, not multiple configurations like the NT1004. + * + * June 29, 2005 - 0.9.8.2cvs Dwaine + * - Added new device WinTV device VendorId 0573 and ProductId 4d37. + * - Because of the first empty entry in usbvision_table, modutils failed to create the necessary entries for modules.usbmap. + * This means hotplug won't work for usbvision. Thanks to Gary Ng. + * - Sent an e-mail to the maintainer of usb.ids. New devices identified need to be added. + * - Fixed compile error with saa7113 under kernel 2.6.12. + * + * July 6, 2005 - 0.9.8.2cvs Dwaine + * - Patch submitted by Gary Ng for two additional procfs entries. Device Input and Frequency setting. + * + * July 12, 2005 - 0.9.8.2cvs Dwaine + * - New tuner identified for some devices it's called TCL_MFPE05. This tuner uses the same API as tuner 38 in tuner.c. + * - Thanks to lynx31 for contacting Hauppage and asking them. + * - I have no clue as to which devices use this new tuner, so people will have to contact me and tell me. + * + * July 21, 2005 - 0.9.8.2cvs Dwaine + * - Patched usbvision.c with missing ifdef kernversion statement so the module will compile with older kernels and v4l. + * - Thanks to cipe007...... + * + * May 19, 2006 - 0.9.8.3cvs Dwaine + * - Patched usbvision.c and i2c-algo.c so they will compile with kernel 2.6.16 + * - Adjust device "Pinnacle Studio PCTV USB (PAL) FM" values in usbvision.h + * + * May 24, 2006 - 0.9.8.3cvs Dwaine + * -Pinnacle Studio PCTV USB (NTSC) FM uses saa7111, not saa7113 like first thought. + * -Updated usbvision.h + * + * Aug 15, 2006 - 0.9.8.3cvs Dwaine + * -Added saa711x module into cvs, since the newer saa7115 module in newer kernels is v4l2. The usbvision driver is only v4l. + * -Updated makefile to put compiled modules into correct location. + * + * Aug 21, 2006 - 0.9.8.3cvs Dwaine + * -Changed number of bytes for i2c write to 4 as per the NT100X spec sheet. Thanks to Merlum for finding it. + * -Remove the radio option for device Hauppauge WinTV USB device Model 40219 Rev E189. This device does not have a FM radio. Thanks to Shadwell. + * -Added radio option for device Hauppauge WinTV USB device Model 40219 Rev E189 again. Just got an e-mail indicating their device has one. 8*) + * + * Aug 27, 2006 - 0.9.8.3cvs Dwaine + * -Changed ifdef statement so the usbvision driver will compile with kernels at 2.6.12. + * -Updated readme files for new updated tuner list for v4l devices. + * + * + * + * TODO: + * - use submit_urb for all setup packets + * - Fix memory settings for nt1004. It is 4 times as big as the + * nt1003 memory. + * - Add audio on endpoint 3 for nt1004 chip. Seems impossible, needs a codec interface. Which one? + * - Clean up the driver. + * - optimization for performance. + * - Add Videotext capability (VBI). Working on it..... + * - Check audio for other devices + * - Add v4l2 interface + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "usbvision-i2c.h" + +#define USBVISION_DRIVER_VERSION_MAJOR 0 +#define USBVISION_DRIVER_VERSION_MINOR 8 +#define USBVISION_DRIVER_VERSION_PATCHLEVEL 0 + +#define USBVISION_VERSION __stringify(USBVISION_DRIVER_VERSION_MAJOR) "." __stringify(USBVISION_DRIVER_VERSION_MINOR) "." __stringify(USBVISION_DRIVER_VERSION_PATCHLEVEL) " " USBVISION_DRIVER_VERSION_COMMENT +#define USBVISION_DRIVER_VERSION KERNEL_VERSION(USBVISION_DRIVER_VERSION_MAJOR,USBVISION_DRIVER_VERSION_MINOR,USBVISION_DRIVER_VERSION_PATCHLEVEL) + +#include +#include +#include +#include + + #include + #include + +#ifdef CONFIG_KMOD +#include +#endif + +#include "usbvision.h" +#include "usbvision_ioctl.h" + + +#define DRIVER_VERSION "0.9.8.3cvs for Linux kernels 2.4.19-2.4.32 + 2.6.0-2.6.17, compiled at "__DATE__", "__TIME__ +#define EMAIL "joerg@heckenbach-aw.de" +#define DRIVER_AUTHOR "Joerg Heckenbach , Dwaine Garden " +#define DRIVER_DESC "USBVision USB Video Device Driver for Linux" +#define DRIVER_LICENSE "GPL" +#define DRIVER_ALIAS "USBVision" + +#define ENABLE_HEXDUMP 0 /* Enable if you need it */ + + +#define USBVISION_DEBUG /* Turn on debug messages */ + +#ifdef USBVISION_DEBUG + #define PDEBUG(level, fmt, args...) \ + if (debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args) +#else + #define PDEBUG(level, fmt, args...) do {} while(0) +#endif + +#define DBG_IOCTL 1<<3 +#define DBG_IO 1<<4 +#define DBG_RIO 1<<5 +#define DBG_HEADER 1<<7 +#define DBG_PROBE 1<<8 +#define DBG_IRQ 1<<9 +#define DBG_ISOC 1<<10 +#define DBG_PARSE 1<<11 +#define DBG_SCRATCH 1<<12 +#define DBG_FUNC 1<<13 +#define DBG_I2C 1<<14 + +#define DEBUG(x...) /* General Debug */ +#define IODEBUG(x...) /* Debug IO */ +#define OVDEBUG(x...) /* Debug overlay */ +#define MDEBUG(x...) /* Debug memory management */ + +//String operations +#define rmspace(str) while(*str==' ') str++; +#define goto2next(str) while(*str!=' ') str++; while(*str==' ') str++; + + +static int usbvision_nr = 0; // sequential number of usbvision device + + +static const int max_imgwidth = MAX_FRAME_WIDTH; +static const int max_imgheight = MAX_FRAME_HEIGHT; +static const int min_imgwidth = MIN_FRAME_WIDTH; +static const int min_imgheight = MIN_FRAME_HEIGHT; + +#define FRAMERATE_MIN 0 +#define FRAMERATE_MAX 31 + + +enum { + ISOC_MODE_YUV422 = 0x03, + ISOC_MODE_YUV420 = 0x14, + ISOC_MODE_COMPRESS = 0x60, +}; + +/* + * The value of 'scratch_buf_size' affects quality of the picture + * in many ways. Shorter buffers may cause loss of data when client + * is too slow. Larger buffers are memory-consuming and take longer + * to work with. This setting can be adjusted, but the default value + * should be OK for most desktop users. + */ +#define DEFAULT_SCRATCH_BUF_SIZE (0x20000) // 128kB memory scratch buffer +static const int scratch_buf_size = DEFAULT_SCRATCH_BUF_SIZE; + +static int init_brightness = 128; // Initalize the brightness of the video device +static int init_contrast = 192; // Initalize the contrast of the video device +static int init_saturation = 128; // Initalize the staturation mode of the video device +static int init_hue = 128; // Initalize the Hue settings of the video device + +// Function prototypes +static int usbvision_restart_isoc(struct usb_usbvision *usbvision); +static int usbvision_begin_streaming(struct usb_usbvision *usbvision); +static int usbvision_muxsel(struct usb_usbvision *usbvision, int channel, int norm); +static int usbvision_i2c_write(void *data, unsigned char addr, char *buf, short len); +static int usbvision_i2c_read(void *data, unsigned char addr, char *buf, short len); +static int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg); +static int usbvision_write_reg(struct usb_usbvision *usbvision, unsigned char reg, unsigned char value); +static int usbvision_request_intra (struct usb_usbvision *usbvision); +static int usbvision_unrequest_intra (struct usb_usbvision *usbvision); +static int usbvision_adjust_compression (struct usb_usbvision *usbvision); +static int usbvision_measure_bandwidth (struct usb_usbvision *usbvision); +static void usbvision_release(struct usb_usbvision *usbvision); +static int usbvision_set_input(struct usb_usbvision *usbvision); +static int usbvision_set_output(struct usb_usbvision *usbvision, int width, int height); +static void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd, void *arg); + + +// Bit flags (options) +#define FLAGS_RETRY_VIDIOCSYNC (1 << 0) +#define FLAGS_MONOCHROME (1 << 1) +#define FLAGS_DISPLAY_HINTS (1 << 2) +#define FLAGS_OSD_STATS (1 << 3) +#define FLAGS_FORCE_TESTPATTERN (1 << 4) +#define FLAGS_SEPARATE_FRAMES (1 << 5) +#define FLAGS_CLEAN_FRAMES (1 << 6) + +// Default initalization of device driver parameters +static int flags = 0; // Set the default Overlay Display mode of the device driver +static int debug = 0; // Set the default Debug Mode of the device driver +static int isocMode = ISOC_MODE_COMPRESS; // Set the default format for ISOC endpoint +static int adjustCompression = 1; // Set the compression to be adaptive +static int dga = 1; // Set the default Direct Graphic Access +static int PowerOnAtOpen = 1; // Set the default device to power on at startup +static int SwitchSVideoInput = 0; // To help people with Black and White output with using s-video input. Some cables and input device are wired differently. +static int video_nr = -1; // Sequential Number of Video Device +static int radio_nr = -1; // Sequential Number of Radio Device +static int vbi_nr = -1; // Sequential Number of VBI Device +static char *CustomDevice=NULL; // Set as nothing.... + +// Grab parameters for the device driver + +#if defined(module_param) // Showing parameters under SYSFS +module_param(flags, int, 0444); +module_param(debug, int, 0444); +module_param(isocMode, int, 0444); +module_param(adjustCompression, int, 0444); +module_param(dga, int, 0444); +module_param(PowerOnAtOpen, int, 0444); +module_param(SwitchSVideoInput, int, 0444); +module_param(video_nr, int, 0444); +module_param(radio_nr, int, 0444); +module_param(vbi_nr, int, 0444); +module_param(CustomDevice, charp, 0444); +#else // Old Style +MODULE_PARM(flags, "i"); // Grab the Overlay Display mode of the device driver +MODULE_PARM(debug, "i"); // Grab the Debug Mode of the device driver +MODULE_PARM(isocMode, "i"); // Grab the video format of the video device +MODULE_PARM(adjustCompression, "i"); // Grab the compression to be adaptive +MODULE_PARM(dga, "i"); // Grab the Direct Graphic Access +MODULE_PARM(PowerOnAtOpen, "i"); // Grab the device to power on at startup +MODULE_PARM(SwitchSVideoInput, "i"); // To help people with Black and White output with using s-video input. Some cables and input device are wired differently. +MODULE_PARM(video_nr, "i"); // video_nr option allows to specify a certain /dev/videoX device (like /dev/video0 or /dev/video1 ...) +MODULE_PARM(radio_nr, "i"); // radio_nr option allows to specify a certain /dev/radioX device (like /dev/radio0 or /dev/radio1 ...) +MODULE_PARM(vbi_nr, "i"); // vbi_nr option allows to specify a certain /dev/vbiX device (like /dev/vbi0 or /dev/vbi1 ...) +MODULE_PARM(CustomDevice, "s"); // .... CustomDevice +#endif + +MODULE_PARM_DESC(flags, " Set the default Overlay Display mode of the device driver. Default: 0 (Off)"); +MODULE_PARM_DESC(debug, " Set the default Debug Mode of the device driver. Default: 0 (Off)"); +MODULE_PARM_DESC(isocMode, " Set the default format for ISOC endpoint. Default: 0x60 (Compression On)"); +MODULE_PARM_DESC(adjustCompression, " Set the ADPCM compression for the device. Default: 1 (On)"); +MODULE_PARM_DESC(dga, " Set the Direct Graphic Access for the device. Default: 1 (On)"); +MODULE_PARM_DESC(PowerOnAtOpen, " Set the default device to power on when device is opened. Default: 1 (On)"); +MODULE_PARM_DESC(SwitchSVideoInput, " Set the S-Video input. Some cables and input device are wired differently. Default: 0 (Off)"); +MODULE_PARM_DESC(video_nr, "Set video device number (/dev/videoX). Default: -1 (autodetect)"); +MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)"); +MODULE_PARM_DESC(vbi_nr, "Set vbi device number (/dev/vbiX). Default: -1 (autodetect)"); +MODULE_PARM_DESC(CustomDevice, " Define the fine tuning parameters for the device. Default: null"); + + +// Misc stuff +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE(DRIVER_LICENSE); + MODULE_VERSION(DRIVER_VERSION); + MODULE_ALIAS(DRIVER_ALIAS); + +#ifdef MODULE +static unsigned int autoload = 1; +#else +static unsigned int autoload = 0; +#endif + + +/****************************************************************************************/ +/* SYSFS Code - Copied from the stv680.c usb module. */ +/* Device information is located at /sys/class/video4linux/video0 */ +/* Device parameters information is located at /sys/module/usbvision */ +/* Device USB Information is located at /sys/bus/usb/drivers/USBVision Video Grabber */ +/****************************************************************************************/ + + +#define YES_NO(x) ((x) ? "Yes" : "No") + +static inline struct usb_usbvision *cd_to_usbvision(struct class_device *cd) +{ + struct video_device *vdev = to_video_device(cd); + return video_get_drvdata(vdev); +} + +static ssize_t show_version(struct class_device *cd, char *buf) +{ + return sprintf(buf, "%s\n", DRIVER_VERSION); +} +static CLASS_DEVICE_ATTR(version, S_IRUGO, show_version, NULL); + +static ssize_t show_model(struct class_device *class_dev, char *buf) +{ + struct video_device *vdev = to_video_device(class_dev); + struct usb_usbvision *usbvision = video_get_drvdata(vdev); + return sprintf(buf, "%s\n", usbvision_device_data[usbvision->DevModel].ModelString); +} +static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL); + +static ssize_t show_hue(struct class_device *class_dev, char *buf) +{ + struct video_device *vdev = to_video_device(class_dev); + struct usb_usbvision *usbvision = video_get_drvdata(vdev); + return sprintf(buf, "%d\n", usbvision->hue >> 8); +} +static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); + +static ssize_t show_contrast(struct class_device *class_dev, char *buf) +{ + struct video_device *vdev = to_video_device(class_dev); + struct usb_usbvision *usbvision = video_get_drvdata(vdev); + return sprintf(buf, "%d\n", usbvision->contrast >> 8); +} +static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); + +static ssize_t show_brightness(struct class_device *class_dev, char *buf) +{ + struct video_device *vdev = to_video_device(class_dev); + struct usb_usbvision *usbvision = video_get_drvdata(vdev); + return sprintf(buf, "%d\n", usbvision->brightness >> 8); +} +static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); + +static ssize_t show_saturation(struct class_device *class_dev, char *buf) +{ + struct video_device *vdev = to_video_device(class_dev); + struct usb_usbvision *usbvision = video_get_drvdata(vdev); + return sprintf(buf, "%d\n", usbvision->saturation >> 8); +} +static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); + +static ssize_t show_streaming(struct class_device *class_dev, char *buf) +{ + struct video_device *vdev = to_video_device(class_dev); + struct usb_usbvision *usbvision = video_get_drvdata(vdev); + return sprintf(buf, "%s\n", YES_NO(usbvision->streaming)); +} +static CLASS_DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL); + +static ssize_t show_overlay(struct class_device *class_dev, char *buf) +{ + struct video_device *vdev = to_video_device(class_dev); + struct usb_usbvision *usbvision = video_get_drvdata(vdev); + return sprintf(buf, "%s\n", YES_NO(usbvision->overlay)); +} +static CLASS_DEVICE_ATTR(overlay, S_IRUGO, show_overlay, NULL); + +static ssize_t show_compression(struct class_device *class_dev, char *buf) +{ + struct video_device *vdev = to_video_device(class_dev); + struct usb_usbvision *usbvision = video_get_drvdata(vdev); + return sprintf(buf, "%s\n", YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS)); +} +static CLASS_DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL); + +static ssize_t show_device_bridge(struct class_device *class_dev, char *buf) +{ + struct video_device *vdev = to_video_device(class_dev); + struct usb_usbvision *usbvision = video_get_drvdata(vdev); + return sprintf(buf, "%d\n", usbvision->bridgeType); +} +static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL); + +static void usbvision_create_sysfs(struct video_device *vdev) +{ + if (vdev) { + video_device_create_file(vdev, &class_device_attr_version); + video_device_create_file(vdev, &class_device_attr_model); + video_device_create_file(vdev, &class_device_attr_hue); + video_device_create_file(vdev, &class_device_attr_contrast); + video_device_create_file(vdev, &class_device_attr_brightness); + video_device_create_file(vdev, &class_device_attr_saturation); + video_device_create_file(vdev, &class_device_attr_streaming); + video_device_create_file(vdev, &class_device_attr_overlay); + video_device_create_file(vdev, &class_device_attr_compression); + video_device_create_file(vdev, &class_device_attr_bridge); + } +} + +static void usbvision_remove_sysfs(struct video_device *vdev) +{ + if (vdev) { + video_device_remove_file(vdev, &class_device_attr_version); + video_device_remove_file(vdev, &class_device_attr_model); + video_device_remove_file(vdev, &class_device_attr_hue); + video_device_remove_file(vdev, &class_device_attr_contrast); + video_device_remove_file(vdev, &class_device_attr_brightness); + video_device_remove_file(vdev, &class_device_attr_saturation); + video_device_remove_file(vdev, &class_device_attr_streaming); + video_device_remove_file(vdev, &class_device_attr_overlay); + video_device_remove_file(vdev, &class_device_attr_compression); + video_device_remove_file(vdev, &class_device_attr_bridge); + } +} + + +/*******************************/ +/* Memory management functions */ +/*******************************/ + +/* + * Here we want the physical address of the memory. + * This is used when initializing the contents of the area. + */ + + +void *usbvision_rvmalloc(unsigned long size) +{ + void *mem; + unsigned long adr; + + size = PAGE_ALIGN(size); + mem = vmalloc_32(size); + if (!mem) + return NULL; + + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr = (unsigned long) mem; + while (size > 0) { + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + mem_map_reserve(vmalloc_to_page((void *)adr)); + #else + SetPageReserved(vmalloc_to_page((void *)adr)); + #endif + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + + return mem; +} + +void usbvision_rvfree(void *mem, unsigned long size) +{ + unsigned long adr; + + if (!mem) + return; + + adr = (unsigned long) mem; + while ((long) size > 0) { + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + mem_map_unreserve(vmalloc_to_page((void *)adr)); + #else + ClearPageReserved(vmalloc_to_page((void *)adr)); + #endif + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + vfree(mem); +} + + + + + + +#if ENABLE_HEXDUMP +static void usbvision_hexdump(const unsigned char *data, int len) +{ + char tmp[80]; + int i, k; + + for (i = k = 0; len > 0; i++, len--) { + if (i > 0 && (i % 16 == 0)) { + printk("%s\n", tmp); + k = 0; + } + k += sprintf(&tmp[k], "%02x ", data[i]); + } + if (k > 0) + printk("%s\n", tmp); +} +#endif + + +/* These procedures handle the scratch ring buffer */ +int scratch_len(struct usb_usbvision *usbvision) /*This returns the amount of data actually in the buffer */ +{ + int len = usbvision->scratch_write_ptr - usbvision->scratch_read_ptr; + if (len < 0) { + len += scratch_buf_size; + } + PDEBUG(DBG_SCRATCH, "scratch_len() = %d\n", len); + + return len; +} + + +/* This returns the free space left in the buffer */ +int scratch_free(struct usb_usbvision *usbvision) +{ + int free = usbvision->scratch_read_ptr - usbvision->scratch_write_ptr; + if (free <= 0) { + free += scratch_buf_size; + } + if (free) { + free -= 1; /* at least one byte in the buffer must */ + /* left blank, otherwise there is no chance to differ between full and empty */ + } + PDEBUG(DBG_SCRATCH, "return %d\n", free); + + return free; +} + + +void *debug_memcpy(void *dest, void *src, size_t len) +{ + printk(KERN_DEBUG "memcpy(%p, %p, %d);\n", dest, src, len); + return memcpy(dest, src, len); +} + + +/* This puts data into the buffer */ +int scratch_put(struct usb_usbvision *usbvision, unsigned char *data, int len) +{ + int len_part; + + if (usbvision->scratch_write_ptr + len < scratch_buf_size) { + memcpy(usbvision->scratch + usbvision->scratch_write_ptr, data, len); + usbvision->scratch_write_ptr += len; + } + else { + len_part = scratch_buf_size - usbvision->scratch_write_ptr; + memcpy(usbvision->scratch + usbvision->scratch_write_ptr, data, len_part); + if (len == len_part) { + usbvision->scratch_write_ptr = 0; /* just set write_ptr to zero */ + } + else { + memcpy(usbvision->scratch, data + len_part, len - len_part); + usbvision->scratch_write_ptr = len - len_part; + } + } + + PDEBUG(DBG_SCRATCH, "len=%d, new write_ptr=%d\n", len, usbvision->scratch_write_ptr); + + return len; +} + +/* This marks the write_ptr as position of new frame header */ +void scratch_mark_header(struct usb_usbvision *usbvision) +{ + PDEBUG(DBG_SCRATCH, "header at write_ptr=%d\n", usbvision->scratch_headermarker_write_ptr); + + usbvision->scratch_headermarker[usbvision->scratch_headermarker_write_ptr] = + usbvision->scratch_write_ptr; + usbvision->scratch_headermarker_write_ptr += 1; + usbvision->scratch_headermarker_write_ptr %= USBVISION_NUM_HEADERMARKER; +} + +/* This gets data from the buffer at the given "ptr" position */ +int scratch_get_extra(struct usb_usbvision *usbvision, unsigned char *data, int *ptr, int len) +{ + int len_part; + if (*ptr + len < scratch_buf_size) { + memcpy(data, usbvision->scratch + *ptr, len); + *ptr += len; + } + else { + len_part = scratch_buf_size - *ptr; + memcpy(data, usbvision->scratch + *ptr, len_part); + if (len == len_part) { + *ptr = 0; /* just set the y_ptr to zero */ + } + else { + memcpy(data + len_part, usbvision->scratch, len - len_part); + *ptr = len - len_part; + } + } + + PDEBUG(DBG_SCRATCH, "len=%d, new ptr=%d\n", len, *ptr); + + return len; +} + + +/* This sets the scratch extra read pointer */ +void scratch_set_extra_ptr(struct usb_usbvision *usbvision, int *ptr, int len) +{ + *ptr = (usbvision->scratch_read_ptr + len)%scratch_buf_size; + + PDEBUG(DBG_SCRATCH, "ptr=%d\n", *ptr); +} + + +/*This increments the scratch extra read pointer */ +void scratch_inc_extra_ptr(int *ptr, int len) +{ + *ptr = (*ptr + len) % scratch_buf_size; + + PDEBUG(DBG_SCRATCH, "ptr=%d\n", *ptr); +} + + +/* This gets data from the buffer */ +int scratch_get(struct usb_usbvision *usbvision, unsigned char *data, int len) +{ + int len_part; + if (usbvision->scratch_read_ptr + len < scratch_buf_size) { + memcpy(data, usbvision->scratch + usbvision->scratch_read_ptr, len); + usbvision->scratch_read_ptr += len; + } + else { + len_part = scratch_buf_size - usbvision->scratch_read_ptr; + memcpy(data, usbvision->scratch + usbvision->scratch_read_ptr, len_part); + if (len == len_part) { + usbvision->scratch_read_ptr = 0; /* just set the read_ptr to zero */ + } + else { + memcpy(data + len_part, usbvision->scratch, len - len_part); + usbvision->scratch_read_ptr = len - len_part; + } + } + + PDEBUG(DBG_SCRATCH, "len=%d, new read_ptr=%d\n", len, usbvision->scratch_read_ptr); + + return len; +} + + +/* This sets read pointer to next header and returns it */ +int scratch_get_header(struct usb_usbvision *usbvision,struct usbvision_frame_header *header) +{ + int errCode = 0; + + PDEBUG(DBG_SCRATCH, "from read_ptr=%d", usbvision->scratch_headermarker_read_ptr); + + while (usbvision->scratch_headermarker_write_ptr - + usbvision->scratch_headermarker_read_ptr != 0) { + usbvision->scratch_read_ptr = + usbvision->scratch_headermarker[usbvision->scratch_headermarker_read_ptr]; + usbvision->scratch_headermarker_read_ptr += 1; + usbvision->scratch_headermarker_read_ptr %= USBVISION_NUM_HEADERMARKER; + scratch_get(usbvision, (unsigned char *)header, USBVISION_HEADER_LENGTH); + if ((header->magic_1 == USBVISION_MAGIC_1) + && (header->magic_2 == USBVISION_MAGIC_2) + && (header->headerLength == USBVISION_HEADER_LENGTH)) { + errCode = USBVISION_HEADER_LENGTH; + header->frameWidth = header->frameWidthLo + (header->frameWidthHi << 8); + header->frameHeight = header->frameHeightLo + (header->frameHeightHi << 8); + break; + } + } + + return errCode; +} + + +/*This removes len bytes of old data from the buffer */ +void scratch_rm_old(struct usb_usbvision *usbvision, int len) +{ + + usbvision->scratch_read_ptr += len; + usbvision->scratch_read_ptr %= scratch_buf_size; + PDEBUG(DBG_SCRATCH, "read_ptr is now %d\n", usbvision->scratch_read_ptr); +} + + +/*This resets the buffer - kills all data in it too */ +void scratch_reset(struct usb_usbvision *usbvision) +{ + PDEBUG(DBG_SCRATCH, "\n"); + + usbvision->scratch_read_ptr = 0; + usbvision->scratch_write_ptr = 0; + usbvision->scratch_headermarker_read_ptr = 0; + usbvision->scratch_headermarker_write_ptr = 0; + usbvision->isocstate = IsocState_NoFrame; +} + + + +/* Here comes the OVERLAY stuff */ + +/* Tell the interrupt handler what to to. */ +static +void usbvision_cap(struct usb_usbvision* usbvision, int on) +{ + DEBUG(printk(KERN_DEBUG "usbvision_cap: overlay was %d, set it to %d\n", usbvision->overlay, on);) + + if (on) { + usbvision->overlay = 1; + } + else { + usbvision->overlay = 0; + } +} + + + + +/* append a new clipregion to the vector of video_clips */ +static +void usbvision_new_clip(struct v4l2_format* vf, struct v4l2_clip* vcp, int x, int y, int w, int h) +{ + vcp[vf->fmt.win.clipcount].c.left = x; + vcp[vf->fmt.win.clipcount].c.top = y; + vcp[vf->fmt.win.clipcount].c.width = w; + vcp[vf->fmt.win.clipcount].c.height = h; + vf->fmt.win.clipcount++; +} + + +#define mark_pixel(x,y) usbvision->clipmask[((x) + (y) * MAX_FRAME_WIDTH)/32] |= 0x00000001<<((x)%32) +#define clipped_pixel(index) usbvision->clipmask[(index)/32] & (0x00000001<<((index)%32)) + +static +void usbvision_built_overlay(struct usb_usbvision* usbvision, int count, struct v4l2_clip *vcp) +{ + usbvision->overlay_win = usbvision->overlay_base + + (signed int)usbvision->vid_win.fmt.win.w.left * usbvision->depth / 8 + + (signed int)usbvision->vid_win.fmt.win.w.top * usbvision->vid_buf.fmt.bytesperline; + + IODEBUG(printk(KERN_DEBUG "built_overlay base=%p, win=%p, bpl=%d, clips=%d, size=%dx%d\n", + usbvision->overlay_base, usbvision->overlay_win, + usbvision->vid_buf.fmt.bytesperline, count, + usbvision->vid_win.fmt.win.w.width, usbvision->vid_win.fmt.win.w.height);) + + + /* Add here generation of clipping mask */ +{ + int x_start, x_end, y_start, y_end; + int clip_index, x, y; + + memset(usbvision->clipmask, 0, USBVISION_CLIPMASK_SIZE); + + OVDEBUG(printk(KERN_DEBUG "clips = %d\n", count);) + + for(clip_index = 0; clip_index < count; clip_index++) { + OVDEBUG(printk(KERN_DEBUG "clip: %d,%d,%d,%d\n", vcp[clip_index].x, + vcp[clip_index].y, + vcp[clip_index].width, + vcp[clip_index].height);) + + x_start = vcp[clip_index].c.left; + if(x_start >= (int)usbvision->vid_win.fmt.win.w.width) { + OVDEBUG(printk(KERN_DEBUG "x_start=%d\n", x_start);) + continue; //clipping window is right of overlay window + } + x_end = x_start + vcp[clip_index].c.width; + if(x_end <= 0) { + OVDEBUG(printk(KERN_DEBUG "x_end=%d\n", x_end);) + continue; //clipping window is left of overlay window + } + + y_start = vcp[clip_index].c.top; + if(y_start >= (int)usbvision->vid_win.fmt.win.w.height) { + OVDEBUG(printk(KERN_DEBUG "y_start=%d\n", y_start);) + continue; //clipping window is below overlay window + } + y_end = y_start + vcp[clip_index].c.height; + if(y_end <= 0) { + OVDEBUG(printk(KERN_DEBUG "y_end=%d\n", y_end);) + continue; //clipping window is above overlay window + } + + //clip the clipping window + if (x_start < 0) { + x_start = 0; + } + if (x_end > (int)usbvision->vid_win.fmt.win.w.width) { + x_end = (int)usbvision->vid_win.fmt.win.w.width; + } + if (y_start < 0) { + y_start = 0; + } + if (y_end > (int)usbvision->vid_win.fmt.win.w.height) { + y_end = (int)usbvision->vid_win.fmt.win.w.height; + } + + OVDEBUG(printk(KERN_DEBUG "clip_o: %d,%d,%d,%d\n", x_start, y_start, x_end, y_end);) + + + + for(y = y_start; y < y_end; y++) { + for(x = x_start; x < x_end; x++) { + mark_pixel(x,y); + } + } + } +} + +} + + + +void usbvision_osd_char(struct usb_usbvision *usbvision, + struct usbvision_frame *frame, int x, int y, int ch) +{ + static const unsigned short digits[16] = { + 0xF6DE, /* 0 */ + 0x2492, /* 1 */ + 0xE7CE, /* 2 */ + 0xE79E, /* 3 */ + 0xB792, /* 4 */ + 0xF39E, /* 5 */ + 0xF3DE, /* 6 */ + 0xF492, /* 7 */ + 0xF7DE, /* 8 */ + 0xF79E, /* 9 */ + 0x77DA, /* a */ + 0xD75C, /* b */ + 0xF24E, /* c */ + 0xD6DC, /* d */ + 0xF34E, /* e */ + 0xF348 /* f */ + }; + unsigned short digit; + int ix, iy; + + if ((usbvision == NULL) || (frame == NULL)) + return; + + if (ch >= '0' && ch <= '9') + ch -= '0'; + else if (ch >= 'A' && ch <= 'F') + ch = 10 + (ch - 'A'); + else if (ch >= 'a' && ch <= 'f') + ch = 10 + (ch - 'a'); + else + return; + digit = digits[ch]; + + for (iy = 0; iy < 5; iy++) { + for (ix = 0; ix < 3; ix++) { + if (digit & 0x8000) { + // USBVISION_PUTPIXEL(frame, x + ix, y + iy, + // 0xFF, 0xFF, 0xFF); + } + digit = digit << 1; + } + } +} + + +void usbvision_osd_string(struct usb_usbvision *usbvision, + struct usbvision_frame *frame, + int x, int y, const char *str) +{ + while (*str) { + usbvision_osd_char(usbvision, frame, x, y, *str); + str++; + x += 4; /* 3 pixels character + 1 space */ + } +} + +/* + * usb_usbvision_osd_stats() + * + * On screen display of important debugging information. + * + */ +void usbvision_osd_stats(struct usb_usbvision *usbvision, + struct usbvision_frame *frame) +{ + const int y_diff = 8; + char tmp[16]; + int x = 10; + int y = 10; + + sprintf(tmp, "%8x", usbvision->frame_num); + usbvision_osd_string(usbvision, frame, x, y, tmp); + y += y_diff; + + sprintf(tmp, "%8lx", usbvision->isocUrbCount); + usbvision_osd_string(usbvision, frame, x, y, tmp); + y += y_diff; + + sprintf(tmp, "%8lx", usbvision->urb_length); + usbvision_osd_string(usbvision, frame, x, y, tmp); + y += y_diff; + + sprintf(tmp, "%8lx", usbvision->isocDataCount); + usbvision_osd_string(usbvision, frame, x, y, tmp); + y += y_diff; + + sprintf(tmp, "%8lx", usbvision->header_count); + usbvision_osd_string(usbvision, frame, x, y, tmp); + y += y_diff; + + sprintf(tmp, "%8lx", usbvision->scratch_ovf_count); + usbvision_osd_string(usbvision, frame, x, y, tmp); + y += y_diff; + + sprintf(tmp, "%8lx", usbvision->isocSkipCount); + usbvision_osd_string(usbvision, frame, x, y, tmp); + y += y_diff; + + sprintf(tmp, "%8lx", usbvision->isocErrCount); + usbvision_osd_string(usbvision, frame, x, y, tmp); + y += y_diff; + + sprintf(tmp, "%8x", usbvision->saturation); + usbvision_osd_string(usbvision, frame, x, y, tmp); + y += y_diff; + + sprintf(tmp, "%8x", usbvision->hue); + usbvision_osd_string(usbvision, frame, x, y, tmp); + y += y_diff; + + sprintf(tmp, "%8x", usbvision->brightness >> 8); + usbvision_osd_string(usbvision, frame, x, y, tmp); + y += y_diff; + + sprintf(tmp, "%8x", usbvision->contrast >> 12); + usbvision_osd_string(usbvision, frame, x, y, tmp); + y += y_diff; + +} + +/* + * usbvision_testpattern() + * + * Procedure forms a test pattern (yellow grid on blue background). + * + * Parameters: + * fullframe: if TRUE then entire frame is filled, otherwise the procedure + * continues from the current scanline. + * pmode 0: fill the frame with solid blue color (like on VCR or TV) + * 1: Draw a colored grid + * + */ +void usbvision_testpattern(struct usb_usbvision *usbvision, int fullframe, + int pmode) +{ + static const char proc[] = "usbvision_testpattern"; + struct usbvision_frame *frame; + unsigned char *f; + int num_cell = 0; + int scan_length = 0; + static int num_pass = 0; + + if (usbvision == NULL) { + printk(KERN_ERR "%s: usbvision == NULL\n", proc); + return; + } + if ((usbvision->curFrameNum < 0) + || (usbvision->curFrameNum >= USBVISION_NUMFRAMES)) { + printk(KERN_ERR "%s: usbvision->curFrameNum=%d.\n", proc, + usbvision->curFrameNum); + return; + } + + /* Grab the current frame */ + frame = &usbvision->frame[usbvision->curFrameNum]; + + /* Optionally start at the beginning */ + if (fullframe) { + frame->curline = 0; + frame->scanlength = 0; + } + + /* Form every scan line */ + for (; frame->curline < frame->frmheight; frame->curline++) { + int i; + + f = frame->data + (usbvision->curwidth * 3 * frame->curline); + for (i = 0; i < usbvision->curwidth; i++) { + unsigned char cb = 0x80; + unsigned char cg = 0; + unsigned char cr = 0; + + if (pmode == 1) { + if (frame->curline % 32 == 0) + cb = 0, cg = cr = 0xFF; + else if (i % 32 == 0) { + if (frame->curline % 32 == 1) + num_cell++; + cb = 0, cg = cr = 0xFF; + } else { + cb = + ((num_cell * 7) + + num_pass) & 0xFF; + cg = + ((num_cell * 5) + + num_pass * 2) & 0xFF; + cr = + ((num_cell * 3) + + num_pass * 3) & 0xFF; + } + } else { + /* Just the blue screen */ + } + + *f++ = cb; + *f++ = cg; + *f++ = cr; + scan_length += 3; + } + } + + frame->grabstate = FrameState_Done; + frame->scanlength += scan_length; + ++num_pass; + + /* We do this unconditionally, regardless of FLAGS_OSD_STATS */ + usbvision_osd_stats(usbvision, frame); +} + +/* + * Here comes the data parsing stuff that is run as interrupt + */ + +/* + * usbvision_find_header() + * + * Locate one of supported header markers in the scratch buffer. + */ +static enum ParseState usbvision_find_header(struct usb_usbvision *usbvision) +{ + struct usbvision_frame *frame; + int foundHeader = 0; + + if (usbvision->overlay) { + frame = &usbvision->overlay_frame; + } + else { + frame = &usbvision->frame[usbvision->curFrameNum]; + } + + while (scratch_get_header(usbvision, &frame->isocHeader) == USBVISION_HEADER_LENGTH) { + // found header in scratch + PDEBUG(DBG_HEADER, "found header: 0x%02x%02x %d %d %d %d %#x 0x%02x %u %u", + frame->isocHeader.magic_2, + frame->isocHeader.magic_1, + frame->isocHeader.headerLength, + frame->isocHeader.frameNum, + frame->isocHeader.framePhase, + frame->isocHeader.frameLatency, + frame->isocHeader.dataFormat, + frame->isocHeader.formatParam, + frame->isocHeader.frameWidth, + frame->isocHeader.frameHeight); + + if (usbvision->requestIntra) { + if (frame->isocHeader.formatParam & 0x80) { + foundHeader = 1; + usbvision->lastIsocFrameNum = -1; // do not check for lost frames this time + usbvision_unrequest_intra(usbvision); + break; + } + } + else { + foundHeader = 1; + break; + } + } + + if (foundHeader) { + frame->frmwidth = frame->isocHeader.frameWidth * usbvision->stretch_width; + frame->frmheight = frame->isocHeader.frameHeight * usbvision->stretch_height; + frame->v4l2_linesize = (frame->frmwidth * frame->v4l2_format.depth)>> 3; + usbvision->curFrame = frame; + } + else { // no header found + PDEBUG(DBG_HEADER, "skipping scratch data, no header"); + scratch_reset(usbvision); + return ParseState_EndParse; + } + + // found header + if (frame->isocHeader.dataFormat==ISOC_MODE_COMPRESS) { + //check isocHeader.frameNum for lost frames + if (usbvision->lastIsocFrameNum >= 0) { + if (((usbvision->lastIsocFrameNum + 1) % 32) != frame->isocHeader.frameNum) { + // unexpected frame drop: need to request new intra frame + PDEBUG(DBG_HEADER, "Lost frame before %d on USB", frame->isocHeader.frameNum); + usbvision_request_intra(usbvision); + return ParseState_NextFrame; + } + } + usbvision->lastIsocFrameNum = frame->isocHeader.frameNum; + } + usbvision->header_count++; + frame->scanstate = ScanState_Lines; + frame->curline = 0; + + if (flags & FLAGS_FORCE_TESTPATTERN) { + usbvision_testpattern(usbvision, 1, 1); + return ParseState_NextFrame; + } + return ParseState_Continue; +} + +static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision, + long *pcopylen) +{ + volatile struct usbvision_frame *frame; + unsigned char *f; + int len; + int i; + unsigned char yuyv[4]={180, 128, 10, 128}; // YUV components + unsigned char rv, gv, bv; // RGB components + int clipmask_index, bytes_per_pixel; + int overlay = usbvision->overlay; + int stretch_bytes, clipmask_add; + + if (overlay) { + frame = &usbvision->overlay_frame; + if (usbvision->overlay_base == NULL) { + //video_buffer is not set yet + return ParseState_NextFrame; + } + f = usbvision->overlay_win + frame->curline * + usbvision->vid_buf.fmt.bytesperline; + } + else { + frame = &usbvision->frame[usbvision->curFrameNum]; + f = frame->data + (frame->v4l2_linesize * frame->curline); + } + + /* Make sure there's enough data for the entire line */ + len = (frame->isocHeader.frameWidth * 2)+5; + if (scratch_len(usbvision) < len) { + PDEBUG(DBG_PARSE, "out of data in line %d, need %u.\n", frame->curline, len); + return ParseState_Out; + } + + if ((frame->curline + 1) >= frame->frmheight) { + return ParseState_NextFrame; + } + + bytes_per_pixel = frame->v4l2_format.bytes_per_pixel; + stretch_bytes = (usbvision->stretch_width - 1) * bytes_per_pixel; + clipmask_index = frame->curline * MAX_FRAME_WIDTH; + clipmask_add = usbvision->stretch_width; + + for (i = 0; i < frame->frmwidth; i+=(2 * usbvision->stretch_width)) { + + scratch_get(usbvision, &yuyv[0], 4); + + if((overlay) && (clipped_pixel(clipmask_index))) { + f += bytes_per_pixel; + } + else if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { + *f++ = yuyv[0]; // Y + *f++ = yuyv[3]; // U + } + else { + + YUV_TO_RGB_BY_THE_BOOK(yuyv[0], yuyv[1], yuyv[3], rv, gv, bv); + switch (frame->v4l2_format.format) { + case V4L2_PIX_FMT_RGB565: + *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3)); + *f++ = (0x07 & (gv >> 5)) | (0xF8 & rv); + break; + case V4L2_PIX_FMT_RGB24: + *f++ = bv; + *f++ = gv; + *f++ = rv; + break; + case V4L2_PIX_FMT_RGB32: + *f++ = bv; + *f++ = gv; + *f++ = rv; + f++; + break; + case V4L2_PIX_FMT_RGB555: + *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2)); + *f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1)); + break; + } + } + clipmask_index += clipmask_add; + f += stretch_bytes; + + if((overlay) && (clipped_pixel(clipmask_index))) { + f += bytes_per_pixel; + } + else if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { + *f++ = yuyv[2]; // Y + *f++ = yuyv[1]; // V + } + else { + + YUV_TO_RGB_BY_THE_BOOK(yuyv[2], yuyv[1], yuyv[3], rv, gv, bv); + switch (frame->v4l2_format.format) { + case V4L2_PIX_FMT_RGB565: + *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3)); + *f++ = (0x07 & (gv >> 5)) | (0xF8 & rv); + break; + case V4L2_PIX_FMT_RGB24: + *f++ = bv; + *f++ = gv; + *f++ = rv; + break; + case V4L2_PIX_FMT_RGB32: + *f++ = bv; + *f++ = gv; + *f++ = rv; + f++; + break; + case V4L2_PIX_FMT_RGB555: + *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2)); + *f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1)); + break; + } + } + clipmask_index += clipmask_add; + f += stretch_bytes; + } + + frame->curline += usbvision->stretch_height; + *pcopylen += frame->v4l2_linesize * usbvision->stretch_height; + + if (frame->curline >= frame->frmheight) { + return ParseState_NextFrame; + } + else { + return ParseState_Continue; + } +} + + +static int usbvision_decompress(struct usb_usbvision *usbvision,unsigned char *Compressed, + unsigned char *Decompressed, int *StartPos, + int *BlockTypeStartPos, int Len) +{ + int RestPixel, Idx, MaxPos, Pos, ExtraPos, BlockLen, BlockTypePos, BlockTypeLen; + unsigned char BlockByte, BlockCode, BlockType, BlockTypeByte, Integrator; + + Integrator = 0; + Pos = *StartPos; + BlockTypePos = *BlockTypeStartPos; + MaxPos = 396; //Pos + Len; + ExtraPos = Pos; + BlockLen = 0; + BlockByte = 0; + BlockCode = 0; + BlockType = 0; + BlockTypeByte = 0; + BlockTypeLen = 0; + RestPixel = Len; + + for (Idx = 0; Idx < Len; Idx++) { + + if (BlockLen == 0) { + if (BlockTypeLen==0) { + BlockTypeByte = Compressed[BlockTypePos]; + BlockTypePos++; + BlockTypeLen = 4; + } + BlockType = (BlockTypeByte & 0xC0) >> 6; + + //statistic: + usbvision->ComprBlockTypes[BlockType]++; + + Pos = ExtraPos; + if (BlockType == 0) { + if(RestPixel >= 24) { + Idx += 23; + RestPixel -= 24; + Integrator = Decompressed[Idx]; + } else { + Idx += RestPixel - 1; + RestPixel = 0; + } + } else { + BlockCode = Compressed[Pos]; + Pos++; + if (RestPixel >= 24) { + BlockLen = 24; + } else { + BlockLen = RestPixel; + } + RestPixel -= BlockLen; + ExtraPos = Pos + (BlockLen / 4); + } + BlockTypeByte <<= 2; + BlockTypeLen -= 1; + } + if (BlockLen > 0) { + if ((BlockLen%4) == 0) { + BlockByte = Compressed[Pos]; + Pos++; + } + if (BlockType == 1) { //inter Block + Integrator = Decompressed[Idx]; + } + switch (BlockByte & 0xC0) { + case 0x03<<6: + Integrator += Compressed[ExtraPos]; + ExtraPos++; + break; + case 0x02<<6: + Integrator += BlockCode; + break; + case 0x00: + Integrator -= BlockCode; + break; + } + Decompressed[Idx] = Integrator; + BlockByte <<= 2; + BlockLen -= 1; + } + } + *StartPos = ExtraPos; + *BlockTypeStartPos = BlockTypePos; + return Idx; +} + + +/* + * usbvision_parse_compress() + * + * Parse compressed frame from the scratch buffer, put + * decoded RGB value into the current frame buffer and add the written + * number of bytes (RGB) to the *pcopylen. + * + */ +static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision, + long *pcopylen) +{ +#define USBVISION_STRIP_MAGIC 0x5A +#define USBVISION_STRIP_LEN_MAX 400 +#define USBVISION_STRIP_HEADER_LEN 3 + + struct usbvision_frame *frame; + unsigned char *f,*u = NULL ,*v = NULL; + unsigned char StripData[USBVISION_STRIP_LEN_MAX]; + unsigned char StripHeader[USBVISION_STRIP_HEADER_LEN]; + int Idx, IdxEnd, StripLen, StripPtr, StartBlockPos, BlockPos, BlockTypePos; + int clipmask_index, bytes_per_pixel, rc; + int overlay = usbvision->overlay; + int imageSize; + unsigned char rv, gv, bv; + static unsigned char *Y, *U, *V; + + if (overlay) { + frame = &usbvision->overlay_frame; + imageSize = frame->frmwidth * frame->frmheight; + if (usbvision->overlay_base == NULL) { + //video_buffer is not set yet + return ParseState_NextFrame; + } + f = usbvision->overlay_win + frame->curline * + usbvision->vid_buf.fmt.bytesperline; + } + else { + frame = &usbvision->frame[usbvision->curFrameNum]; + imageSize = frame->frmwidth * frame->frmheight; + if ( (frame->v4l2_format.format == V4L2_PIX_FMT_YUV422P) || + (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420) ) + { // this is a planar format + //... v4l2_linesize not used here. + f = frame->data + (frame->width * frame->curline); + } else + f = frame->data + (frame->v4l2_linesize * frame->curline); + + if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV){ //initialise u and v pointers + // get base of u and b planes add halfoffset + + u = frame->data + + imageSize + + (frame->frmwidth >>1) * frame->curline ; + v = u + (imageSize >>1 ); + + } else if (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420){ + + v = frame->data + imageSize + ((frame->curline* (frame->width))>>2) ; + u = v + (imageSize >>2) ; + } + } + + if (frame->curline == 0) { + usbvision_adjust_compression(usbvision); + } + + if (scratch_len(usbvision) < USBVISION_STRIP_HEADER_LEN) { + return ParseState_Out; + } + + //get strip header without changing the scratch_read_ptr + scratch_set_extra_ptr(usbvision, &StripPtr, 0); + scratch_get_extra(usbvision, &StripHeader[0], &StripPtr, + USBVISION_STRIP_HEADER_LEN); + + if (StripHeader[0] != USBVISION_STRIP_MAGIC) { + // wrong strip magic + usbvision->stripMagicErrors++; + return ParseState_NextFrame; + } + + if (frame->curline != (int)StripHeader[2]) { + //line number missmatch error + usbvision->stripLineNumberErrors++; + } + + StripLen = 2 * (unsigned int)StripHeader[1]; + if (StripLen > USBVISION_STRIP_LEN_MAX) { + // strip overrun + // I think this never happens + usbvision_request_intra(usbvision); + } + + if (scratch_len(usbvision) < StripLen) { + //there is not enough data for the strip + return ParseState_Out; + } + + if (usbvision->IntraFrameBuffer) { + Y = usbvision->IntraFrameBuffer + frame->frmwidth * frame->curline; + U = usbvision->IntraFrameBuffer + imageSize + (frame->frmwidth / 2) * (frame->curline / 2); + V = usbvision->IntraFrameBuffer + imageSize / 4 * 5 + (frame->frmwidth / 2) * (frame->curline / 2); + } + else { + return ParseState_NextFrame; + } + + bytes_per_pixel = frame->v4l2_format.bytes_per_pixel; + clipmask_index = frame->curline * MAX_FRAME_WIDTH; + + scratch_get(usbvision, StripData, StripLen); + + IdxEnd = frame->frmwidth; + BlockTypePos = USBVISION_STRIP_HEADER_LEN; + StartBlockPos = BlockTypePos + (IdxEnd - 1) / 96 + (IdxEnd / 2 - 1) / 96 + 2; + BlockPos = StartBlockPos; + + usbvision->BlockPos = BlockPos; + + if ((rc = usbvision_decompress(usbvision, StripData, Y, &BlockPos, &BlockTypePos, IdxEnd)) != IdxEnd) { + //return ParseState_Continue; + } + if (StripLen > usbvision->maxStripLen) { + usbvision->maxStripLen = StripLen; + } + + if (frame->curline%2) { + if ((rc = usbvision_decompress(usbvision, StripData, V, &BlockPos, &BlockTypePos, IdxEnd/2)) != IdxEnd/2) { + //return ParseState_Continue; + } + } + else { + if ((rc = usbvision_decompress(usbvision, StripData, U, &BlockPos, &BlockTypePos, IdxEnd/2)) != IdxEnd/2) { + //return ParseState_Continue; + } + } + + if (BlockPos > usbvision->comprBlockPos) { + usbvision->comprBlockPos = BlockPos; + } + if (BlockPos > StripLen) { + usbvision->stripLenErrors++; + } + + for (Idx = 0; Idx < IdxEnd; Idx++) { + if((overlay) && (clipped_pixel(clipmask_index))) { + f += bytes_per_pixel; + } + else if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { + *f++ = Y[Idx]; + *f++ = Idx & 0x01 ? U[Idx/2] : V[Idx/2]; + } + else if(frame->v4l2_format.format == V4L2_PIX_FMT_YUV422P) { + *f++ = Y[Idx]; + if ( Idx & 0x01) + *u++ = U[Idx>>1] ; + else + *v++ = V[Idx>>1]; + } + else if (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420) { + *f++ = Y [Idx]; + if ( !(( Idx & 0x01 ) | ( frame->curline & 0x01 )) ){ + +/* only need do this for 1 in 4 pixels */ +/* intraframe buffer is YUV420 format */ + + *u++ = U[Idx >>1]; + *v++ = V[Idx >>1]; + } + + } + else { + YUV_TO_RGB_BY_THE_BOOK(Y[Idx], U[Idx/2], V[Idx/2], rv, gv, bv); + switch (frame->v4l2_format.format) { + case V4L2_PIX_FMT_GREY: + *f++ = Y[Idx]; + break; + case V4L2_PIX_FMT_RGB555: + *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2)); + *f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1)); + break; + case V4L2_PIX_FMT_RGB565: + *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3)); + *f++ = (0x07 & (gv >> 5)) | (0xF8 & rv); + break; + case V4L2_PIX_FMT_RGB24: + *f++ = bv; + *f++ = gv; + *f++ = rv; + break; + case V4L2_PIX_FMT_RGB32: + *f++ = bv; + *f++ = gv; + *f++ = rv; + f++; + break; + } + } + clipmask_index++; + } + /* Deal with non-integer no. of bytes for YUV420P */ + if (frame->v4l2_format.format != V4L2_PIX_FMT_YVU420 ) + *pcopylen += frame->v4l2_linesize; + else + *pcopylen += frame->curline & 0x01 ? frame->v4l2_linesize : frame->v4l2_linesize << 1; + + frame->curline += 1; + + if (frame->curline >= frame->frmheight) { + return ParseState_NextFrame; + } + else { + return ParseState_Continue; + } + +} + + +/* + * usbvision_parse_lines_420() + * + * Parse two lines from the scratch buffer, put + * decoded RGB value into the current frame buffer and add the written + * number of bytes (RGB) to the *pcopylen. + * + */ +static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision, + long *pcopylen) +{ + struct usbvision_frame *frame; + unsigned char *f_even = NULL, *f_odd = NULL; + unsigned int pixel_per_line, block; + int pixel, block_split; + int y_ptr, u_ptr, v_ptr, y_odd_offset; + const int y_block_size = 128; + const int uv_block_size = 64; + const int sub_block_size = 32; + const int y_step[] = { 0, 0, 0, 2 }, y_step_size = 4; + const int uv_step[]= { 0, 0, 0, 4 }, uv_step_size = 4; + unsigned char y[2], u, v; /* YUV components */ + int y_, u_, v_, vb, uvg, ur; + int r_, g_, b_; /* RGB components */ + unsigned char g; + int clipmask_even_index, clipmask_odd_index, bytes_per_pixel; + int clipmask_add, stretch_bytes; + int overlay = usbvision->overlay; + + if (overlay) { + frame = &usbvision->overlay_frame; + if (usbvision->overlay_base == NULL) { + //video_buffer is not set yet + return ParseState_NextFrame; + } + f_even = usbvision->overlay_win + frame->curline * + usbvision->vid_buf.fmt.bytesperline; + f_odd = f_even + usbvision->vid_buf.fmt.bytesperline * usbvision->stretch_height; + } + else { + frame = &usbvision->frame[usbvision->curFrameNum]; + f_even = frame->data + (frame->v4l2_linesize * frame->curline); + f_odd = f_even + frame->v4l2_linesize * usbvision->stretch_height; + } + + /* Make sure there's enough data for the entire line */ + /* In this mode usbvision transfer 3 bytes for every 2 pixels */ + /* I need two lines to decode the color */ + bytes_per_pixel = frame->v4l2_format.bytes_per_pixel; + stretch_bytes = (usbvision->stretch_width - 1) * bytes_per_pixel; + clipmask_even_index = frame->curline * MAX_FRAME_WIDTH; + clipmask_odd_index = clipmask_even_index + MAX_FRAME_WIDTH; + clipmask_add = usbvision->stretch_width; + pixel_per_line = frame->isocHeader.frameWidth; + + if (scratch_len(usbvision) < (int)pixel_per_line * 3) { + //printk(KERN_DEBUG "out of data, need %d\n", len); + return ParseState_Out; + } + + if ((frame->curline + 1) >= frame->frmheight) { + return ParseState_NextFrame; + } + + block_split = (pixel_per_line%y_block_size) ? 1 : 0; //are some blocks splitted into different lines? + + y_odd_offset = (pixel_per_line / y_block_size) * (y_block_size + uv_block_size) + + block_split * uv_block_size; + + scratch_set_extra_ptr(usbvision, &y_ptr, y_odd_offset); + scratch_set_extra_ptr(usbvision, &u_ptr, y_block_size); + scratch_set_extra_ptr(usbvision, &v_ptr, y_odd_offset + + (4 - block_split) * sub_block_size); + + for (block = 0; block < (pixel_per_line / sub_block_size); + block++) { + + + for (pixel = 0; pixel < sub_block_size; pixel +=2) { + scratch_get(usbvision, &y[0], 2); + scratch_get_extra(usbvision, &u, &u_ptr, 1); + scratch_get_extra(usbvision, &v, &v_ptr, 1); + + //I don't use the YUV_TO_RGB macro for better performance + v_ = v - 128; + u_ = u - 128; + vb = 132252 * v_; + uvg= -53281 * u_ - 25625 * v_; + ur = 104595 * u_; + + if((overlay) && (clipped_pixel(clipmask_even_index))) { + f_even += bytes_per_pixel; + } + else if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { + *f_even++ = y[0]; + *f_even++ = v; + } + else { + y_ = 76284 * (y[0] - 16); + + b_ = (y_ + vb) >> 16; + g_ = (y_ + uvg)>> 16; + r_ = (y_ + ur) >> 16; + + switch (frame->v4l2_format.format) { + case V4L2_PIX_FMT_RGB565: + g = LIMIT_RGB(g_); + *f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3)); + *f_even++ = (0x07 & ( g >> 5)) | (0xF8 & LIMIT_RGB(r_)); + break; + case V4L2_PIX_FMT_RGB24: + *f_even++ = LIMIT_RGB(b_); + *f_even++ = LIMIT_RGB(g_); + *f_even++ = LIMIT_RGB(r_); + break; + case V4L2_PIX_FMT_RGB32: + *f_even++ = LIMIT_RGB(b_); + *f_even++ = LIMIT_RGB(g_); + *f_even++ = LIMIT_RGB(r_); + f_even++; + break; + case V4L2_PIX_FMT_RGB555: + g = LIMIT_RGB(g_); + *f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2)); + *f_even++ = (0x03 & ( g >> 6)) | + (0x7C & (LIMIT_RGB(r_) >> 1)); + break; + } + } + clipmask_even_index += clipmask_add; + f_even += stretch_bytes; + + if((overlay) && (clipped_pixel(clipmask_even_index))) { + f_even += bytes_per_pixel; + } + else if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { + *f_even++ = y[1]; + *f_even++ = u; + } + else { + y_ = 76284 * (y[1] - 16); + + b_ = (y_ + vb) >> 16; + g_ = (y_ + uvg)>> 16; + r_ = (y_ + ur) >> 16; + + switch (frame->v4l2_format.format) { + case V4L2_PIX_FMT_RGB565: + g = LIMIT_RGB(g_); + *f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3)); + *f_even++ = (0x07 & ( g >> 5)) | (0xF8 & LIMIT_RGB(r_)); + break; + case V4L2_PIX_FMT_RGB24: + *f_even++ = LIMIT_RGB(b_); + *f_even++ = LIMIT_RGB(g_); + *f_even++ = LIMIT_RGB(r_); + break; + case V4L2_PIX_FMT_RGB32: + *f_even++ = LIMIT_RGB(b_); + *f_even++ = LIMIT_RGB(g_); + *f_even++ = LIMIT_RGB(r_); + f_even++; + break; + case V4L2_PIX_FMT_RGB555: + g = LIMIT_RGB(g_); + *f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2)); + *f_even++ = (0x03 & ( g >> 6)) | + (0x7C & (LIMIT_RGB(r_) >> 1)); + break; + } + } + clipmask_even_index += clipmask_add; + f_even += stretch_bytes; + + scratch_get_extra(usbvision, &y[0], &y_ptr, 2); + + if ((overlay) && (clipped_pixel(clipmask_odd_index))) { + f_odd += bytes_per_pixel; + } + else if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { + *f_odd++ = y[0]; + *f_odd++ = v; + } + else { + y_ = 76284 * (y[0] - 16); + + b_ = (y_ + vb) >> 16; + g_ = (y_ + uvg)>> 16; + r_ = (y_ + ur) >> 16; + + switch (frame->v4l2_format.format) { + case V4L2_PIX_FMT_RGB565: + g = LIMIT_RGB(g_); + *f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3)); + *f_odd++ = (0x07 & ( g >> 5)) | (0xF8 & LIMIT_RGB(r_)); + break; + case V4L2_PIX_FMT_RGB24: + *f_odd++ = LIMIT_RGB(b_); + *f_odd++ = LIMIT_RGB(g_); + *f_odd++ = LIMIT_RGB(r_); + break; + case V4L2_PIX_FMT_RGB32: + *f_odd++ = LIMIT_RGB(b_); + *f_odd++ = LIMIT_RGB(g_); + *f_odd++ = LIMIT_RGB(r_); + f_odd++; + break; + case V4L2_PIX_FMT_RGB555: + g = LIMIT_RGB(g_); + *f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2)); + *f_odd++ = (0x03 & ( g >> 6)) | + (0x7C & (LIMIT_RGB(r_) >> 1)); + break; + } + } + clipmask_odd_index += clipmask_add; + f_odd += stretch_bytes; + + if((overlay) && (clipped_pixel(clipmask_odd_index))) { + f_odd += bytes_per_pixel; + } + else if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { + *f_odd++ = y[1]; + *f_odd++ = u; + } + else { + y_ = 76284 * (y[1] - 16); + + b_ = (y_ + vb) >> 16; + g_ = (y_ + uvg)>> 16; + r_ = (y_ + ur) >> 16; + + switch (frame->v4l2_format.format) { + case V4L2_PIX_FMT_RGB565: + g = LIMIT_RGB(g_); + *f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3)); + *f_odd++ = (0x07 & ( g >> 5)) | (0xF8 & LIMIT_RGB(r_)); + break; + case V4L2_PIX_FMT_RGB24: + *f_odd++ = LIMIT_RGB(b_); + *f_odd++ = LIMIT_RGB(g_); + *f_odd++ = LIMIT_RGB(r_); + break; + case V4L2_PIX_FMT_RGB32: + *f_odd++ = LIMIT_RGB(b_); + *f_odd++ = LIMIT_RGB(g_); + *f_odd++ = LIMIT_RGB(r_); + f_odd++; + break; + case V4L2_PIX_FMT_RGB555: + g = LIMIT_RGB(g_); + *f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2)); + *f_odd++ = (0x03 & ( g >> 6)) | + (0x7C & (LIMIT_RGB(r_) >> 1)); + break; + } + } + clipmask_odd_index += clipmask_add; + f_odd += stretch_bytes; + } + + scratch_rm_old(usbvision,y_step[block % y_step_size] * sub_block_size); + scratch_inc_extra_ptr(&y_ptr, y_step[(block + 2 * block_split) % y_step_size] + * sub_block_size); + scratch_inc_extra_ptr(&u_ptr, uv_step[block % uv_step_size] + * sub_block_size); + scratch_inc_extra_ptr(&v_ptr, uv_step[(block + 2 * block_split) % uv_step_size] + * sub_block_size); + } + + scratch_rm_old(usbvision, pixel_per_line * 3 / 2 + + block_split * sub_block_size); + + frame->curline += 2 * usbvision->stretch_height; + *pcopylen += frame->v4l2_linesize * 2 * usbvision->stretch_height; + + if (frame->curline >= frame->frmheight) + return ParseState_NextFrame; + else + return ParseState_Continue; +} + +/* + * usbvision_parse_data() + * + * Generic routine to parse the scratch buffer. It employs either + * usbvision_find_header() or usbvision_parse_lines() to do most + * of work. + * + */ +static void usbvision_parse_data(struct usb_usbvision *usbvision) +{ + struct usbvision_frame *frame; + enum ParseState newstate; + long copylen = 0; + + if (usbvision->overlay) { + frame = &usbvision->overlay_frame; + } + else { + frame = &usbvision->frame[usbvision->curFrameNum]; + } + + PDEBUG(DBG_PARSE, "parsing len=%d\n", scratch_len(usbvision)); + + + while (1) { + + newstate = ParseState_Out; + if (scratch_len(usbvision)) { + if (frame->scanstate == ScanState_Scanning) { + newstate = usbvision_find_header(usbvision); + } + else if (frame->scanstate == ScanState_Lines) { + if (usbvision->isocMode == ISOC_MODE_YUV420) { + newstate = usbvision_parse_lines_420(usbvision, ©len); + } + else if (usbvision->isocMode == ISOC_MODE_YUV422) { + newstate = usbvision_parse_lines_422(usbvision, ©len); + } + else if (usbvision->isocMode == ISOC_MODE_COMPRESS) { + newstate = usbvision_parse_compress(usbvision, ©len); + } + + } + } + if (newstate == ParseState_Continue) { + continue; + } + else if ((newstate == ParseState_NextFrame) || (newstate == ParseState_Out)) { + break; + } + else { + return; /* ParseState_EndParse */ + } + } + + if (newstate == ParseState_NextFrame) { + frame->grabstate = FrameState_Done; + do_gettimeofday(&(frame->timestamp)); + frame->sequence = usbvision->frame_num; + if (usbvision->overlay) { + frame->grabstate = FrameState_Grabbing; + frame->scanstate = ScanState_Scanning; + frame->scanlength = 0; + copylen = 0; + } + else { + usbvision->curFrameNum = -1; + } + usbvision->frame_num++; + + /* Optionally display statistics on the screen */ + if (flags & FLAGS_OSD_STATS) + usbvision_osd_stats(usbvision, frame); + + /* This will cause the process to request another frame. */ + if (waitqueue_active(&frame->wq)) { + wake_up_interruptible(&frame->wq); + } + } + + /* Update the frame's uncompressed length. */ + frame->scanlength += copylen; +} + + +/* + * Make all of the blocks of data contiguous + */ +static int usbvision_compress_isochronous(struct usb_usbvision *usbvision, + struct urb *urb) +{ + unsigned char *packet_data; + int i, totlen = 0; + + for (i = 0; i < urb->number_of_packets; i++) { + int packet_len = urb->iso_frame_desc[i].actual_length; + int packet_stat = urb->iso_frame_desc[i].status; + + packet_data = urb->transfer_buffer + urb->iso_frame_desc[i].offset; + + /* Detect and ignore errored packets */ + if (packet_stat) { // packet_stat != 0 ????????????? + PDEBUG(DBG_ISOC, "data error: [%d] len=%d, status=%X", i, packet_len, packet_stat); + usbvision->isocErrCount++; + continue; + } + + /* Detect and ignore empty packets */ + if (packet_len < 0) { + PDEBUG(DBG_ISOC, "error packet [%d]", i); + usbvision->isocSkipCount++; + continue; + } + else if (packet_len == 0) { /* Frame end ????? */ + PDEBUG(DBG_ISOC, "null packet [%d]", i); + usbvision->isocstate=IsocState_NoFrame; + usbvision->isocSkipCount++; + continue; + } + else if (packet_len > usbvision->isocPacketSize) { + PDEBUG(DBG_ISOC, "packet[%d] > isocPacketSize", i); + usbvision->isocSkipCount++; + continue; + } + + PDEBUG(DBG_ISOC, "packet ok [%d] len=%d", i, packet_len); + + if (usbvision->isocstate==IsocState_NoFrame) { //new frame begins + usbvision->isocstate=IsocState_InFrame; + scratch_mark_header(usbvision); + usbvision_measure_bandwidth(usbvision); + PDEBUG(DBG_ISOC, "packet with header"); + } + + /* + * If usbvision continues to feed us with data but there is no + * consumption (if, for example, V4L client fell asleep) we + * may overflow the buffer. We have to move old data over to + * free room for new data. This is bad for old data. If we + * just drop new data then it's bad for new data... choose + * your favorite evil here. + */ + if (scratch_free(usbvision) < packet_len) { + + usbvision->scratch_ovf_count++; + PDEBUG(DBG_ISOC, "scratch buf overflow! scr_len: %d, n: %d", + scratch_len(usbvision), packet_len); + scratch_rm_old(usbvision, packet_len - scratch_free(usbvision)); + } + + /* Now we know that there is enough room in scratch buffer */ + scratch_put(usbvision, packet_data, packet_len); + totlen += packet_len; + usbvision->isocDataCount += packet_len; + usbvision->isocPacketCount++; + } +#if ENABLE_HEXDUMP + if (totlen > 0) { + static int foo = 0; + if (foo < 1) { + printk(KERN_DEBUG "+%d.\n", usbvision->scratchlen); + usbvision_hexdump(data0, (totlen > 64) ? 64 : totlen); + ++foo; + } + } +#endif + return totlen; +} + +static void usbvision_isocIrq(struct urb *urb, struct pt_regs *regs) +{ + int errCode = 0; + int len; + struct usb_usbvision *usbvision = urb->context; + int i; + unsigned long startTime = jiffies; + + /* We don't want to do anything if we are about to be removed! */ + if (!USBVISION_IS_OPERATIONAL(usbvision)) + return; + + if (!usbvision->streaming) { + PDEBUG(DBG_IRQ, "oops, not streaming, but interrupt"); + return; + } + + /* Copy the data received into our scratch buffer */ + len = usbvision_compress_isochronous(usbvision, urb); + + usbvision->isocUrbCount++; + usbvision->urb_length = len; + + for (i = 0; i < USBVISION_URB_FRAMES; i++) { + urb->iso_frame_desc[i].status = 0; + urb->iso_frame_desc[i].actual_length = 0; + } + urb->status = 0; + urb->dev = usbvision->dev; + errCode = usb_submit_urb (urb, GFP_ATOMIC); + +/* Disable this warning. By design of the driver. */ +// if(errCode) { +// err("%s: usb_submit_urb failed: error %d", __FUNCTION__, errCode); +// } + + /* If we collected enough data let's parse! */ + if (scratch_len(usbvision) > USBVISION_HEADER_LENGTH) { /* 12 == header_length */ + /*If we don't have a frame we're current working on, complain */ + if ((usbvision->curFrameNum >= 0) || (usbvision->overlay)) + usbvision_parse_data(usbvision); + else { + PDEBUG(DBG_IRQ, "received data, but no one needs it"); + scratch_reset(usbvision); + } + } + usbvision->timeInIrq += jiffies - startTime; + return; +} + +/*************************************/ +/* Low level usbvision access functions */ +/*************************************/ + +/* + * usbvision_read_reg() + * + * return < 0 -> Error + * >= 0 -> Data + */ + +static int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg) +{ + int errCode = 0; + unsigned char buffer[1]; + + if (!USBVISION_IS_OPERATIONAL(usbvision)) + return -1; + + errCode = usb_control_msg(usbvision->dev, usb_rcvctrlpipe(usbvision->dev, 1), + USBVISION_OP_CODE, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, + 0, (__u16) reg, buffer, 1, HZ); + + if (errCode < 0) { + err("%s: failed: error %d", __FUNCTION__, errCode); + return errCode; + } + return buffer[0]; +} + +/* + * usbvision_write_reg() + * + * return 1 -> Reg written + * 0 -> usbvision is not yet ready + * -1 -> Something went wrong + */ + +static int usbvision_write_reg(struct usb_usbvision *usbvision, unsigned char reg, + unsigned char value) +{ + int errCode = 0; + + if (!USBVISION_IS_OPERATIONAL(usbvision)) + return 0; + + errCode = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1), + USBVISION_OP_CODE, + USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_ENDPOINT, 0, (__u16) reg, &value, 1, HZ); + + if (errCode < 0) { + err("%s: failed: error %d", __FUNCTION__, errCode); + } + return errCode; +} + + +static void usbvision_ctrlUrb_complete(struct urb *urb, struct pt_regs *regs) +{ + struct usb_usbvision *usbvision = (struct usb_usbvision *)urb->context; + + PDEBUG(DBG_IRQ, ""); + usbvision->ctrlUrbBusy = 0; + if (waitqueue_active(&usbvision->ctrlUrb_wq)) { + wake_up_interruptible(&usbvision->ctrlUrb_wq); + } +} + + +static int usbvision_write_reg_irq(struct usb_usbvision *usbvision,int address, + unsigned char *data, int len) +{ + int errCode = 0; + + PDEBUG(DBG_IRQ, ""); + if (len > 8) { + return -EFAULT; + } +// down(&usbvision->ctrlUrbLock); + if (usbvision->ctrlUrbBusy) { +// up(&usbvision->ctrlUrbLock); + return -EBUSY; + } + usbvision->ctrlUrbBusy = 1; +// up(&usbvision->ctrlUrbLock); + + usbvision->ctrlUrbSetup.bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT; + usbvision->ctrlUrbSetup.bRequest = USBVISION_OP_CODE; + usbvision->ctrlUrbSetup.wValue = 0; + usbvision->ctrlUrbSetup.wIndex = cpu_to_le16(address); + usbvision->ctrlUrbSetup.wLength = cpu_to_le16(len); + usb_fill_control_urb (usbvision->ctrlUrb, usbvision->dev, + usb_sndctrlpipe(usbvision->dev, 1), + (unsigned char *)&usbvision->ctrlUrbSetup, + (void *)usbvision->ctrlUrbBuffer, len, + usbvision_ctrlUrb_complete, + (void *)usbvision); + + memcpy(usbvision->ctrlUrbBuffer, data, len); + + errCode = usb_submit_urb(usbvision->ctrlUrb, GFP_ATOMIC); + if (errCode < 0) { + // error in usb_submit_urb() + usbvision->ctrlUrbBusy = 0; + } + PDEBUG(DBG_IRQ, "submit %d byte: error %d", len, errCode); + return errCode; +} + + + + +static int usbvision_init_compression(struct usb_usbvision *usbvision) +{ + int errCode = 0; + + usbvision->lastIsocFrameNum = -1; + usbvision->isocDataCount = 0; + usbvision->isocPacketCount = 0; + usbvision->isocSkipCount = 0; + usbvision->comprLevel = 50; + usbvision->lastComprLevel = -1; + usbvision->isocUrbCount = 0; + usbvision->requestIntra = 1; + usbvision->isocMeasureBandwidthCount = 0; + + return errCode; +} + +/* this function measures the used bandwidth since last call + * return: 0 : no error + * sets usedBandwidth to 1-100 : 1-100% of full bandwidth resp. to isocPacketSize + */ +static int usbvision_measure_bandwidth (struct usb_usbvision *usbvision) +{ + int errCode = 0; + + if (usbvision->isocMeasureBandwidthCount < 2) { // this gives an average bandwidth of 3 frames + usbvision->isocMeasureBandwidthCount++; + return errCode; + } + if ((usbvision->isocPacketSize > 0) && (usbvision->isocPacketCount > 0)) { + usbvision->usedBandwidth = usbvision->isocDataCount / + (usbvision->isocPacketCount + usbvision->isocSkipCount) * + 100 / usbvision->isocPacketSize; + } + usbvision->isocMeasureBandwidthCount = 0; + usbvision->isocDataCount = 0; + usbvision->isocPacketCount = 0; + usbvision->isocSkipCount = 0; + return errCode; +} + +static int usbvision_adjust_compression (struct usb_usbvision *usbvision) +{ + int errCode = 0; + unsigned char buffer[6]; + + PDEBUG(DBG_IRQ, ""); + if ((adjustCompression) && (usbvision->usedBandwidth > 0)) { + usbvision->comprLevel += (usbvision->usedBandwidth - 90) / 2; + RESTRICT_TO_RANGE(usbvision->comprLevel, 0, 100); + if (usbvision->comprLevel != usbvision->lastComprLevel) { + int distorsion; + if (usbvision->bridgeType == BRIDGE_NT1004 || usbvision->bridgeType == BRIDGE_NT1005) { + buffer[0] = (unsigned char)(4 + 16 * usbvision->comprLevel / 100); // PCM Threshold 1 + buffer[1] = (unsigned char)(4 + 8 * usbvision->comprLevel / 100); // PCM Threshold 2 + distorsion = 7 + 248 * usbvision->comprLevel / 100; + buffer[2] = (unsigned char)(distorsion & 0xFF); // Average distorsion Threshold (inter) + buffer[3] = (unsigned char)(distorsion & 0xFF); // Average distorsion Threshold (intra) + distorsion = 1 + 42 * usbvision->comprLevel / 100; + buffer[4] = (unsigned char)(distorsion & 0xFF); // Maximum distorsion Threshold (inter) + buffer[5] = (unsigned char)(distorsion & 0xFF); // Maximum distorsion Threshold (intra) + } + else { //BRIDGE_NT1003 + buffer[0] = (unsigned char)(4 + 16 * usbvision->comprLevel / 100); // PCM threshold 1 + buffer[1] = (unsigned char)(4 + 8 * usbvision->comprLevel / 100); // PCM threshold 2 + distorsion = 2 + 253 * usbvision->comprLevel / 100; + buffer[2] = (unsigned char)(distorsion & 0xFF); // distorsion threshold bit0-7 + buffer[3] = 0; //(unsigned char)((distorsion >> 8) & 0x0F); // distorsion threshold bit 8-11 + distorsion = 0 + 43 * usbvision->comprLevel / 100; + buffer[4] = (unsigned char)(distorsion & 0xFF); // maximum distorsion bit0-7 + buffer[5] = 0; //(unsigned char)((distorsion >> 8) & 0x01); // maximum distorsion bit 8 + } + errCode = usbvision_write_reg_irq(usbvision, USBVISION_PCM_THR1, buffer, 6); + if (errCode == 0){ + PDEBUG(DBG_IRQ, "new compr params %#02x %#02x %#02x %#02x %#02x %#02x", buffer[0], + buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]); + usbvision->lastComprLevel = usbvision->comprLevel; + } + } + } + return errCode; +} + +static int usbvision_request_intra (struct usb_usbvision *usbvision) +{ + int errCode = 0; + unsigned char buffer[1]; + + PDEBUG(DBG_IRQ, ""); + usbvision->requestIntra = 1; + buffer[0] = 1; + usbvision_write_reg_irq(usbvision, USBVISION_FORCE_INTRA, buffer, 1); + return errCode; +} + +static int usbvision_unrequest_intra (struct usb_usbvision *usbvision) +{ + int errCode = 0; + unsigned char buffer[1]; + + PDEBUG(DBG_IRQ, ""); + usbvision->requestIntra = 0; + buffer[0] = 0; + usbvision_write_reg_irq(usbvision, USBVISION_FORCE_INTRA, buffer, 1); + return errCode; +} + +/* ----------------------------------------------------------------------- */ +/* I2C functions */ +/* ----------------------------------------------------------------------- */ + +static void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd, + void *arg) +{ + + int i; + + for (i = 0; i < USBVISION_I2C_CLIENTS_MAX; i++) { + if (NULL == usbvision->i2c_clients[i]) + continue; + if (NULL == usbvision->i2c_clients[i]->driver->command) + continue; + usbvision->i2c_clients[i]->driver->command(usbvision->i2c_clients[i], cmd, arg); + } +} + +static int attach_inform(struct i2c_client *client) +{ + struct usb_usbvision *usbvision; + struct tuner_setup tun_addr; + int i; + v4l2_std_id stdId; + + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + usbvision = (struct usb_usbvision *)client->adapter->data; + #else + usbvision = (struct usb_usbvision *)i2c_get_adapdata(client->adapter); + #endif + + for (i = 0; i < USBVISION_I2C_CLIENTS_MAX; i++) { + if (usbvision->i2c_clients[i] == NULL || + usbvision->i2c_clients[i]->driver->id == + client->driver->id) { + usbvision->i2c_clients[i] = client; + break; + } + } + if ((usbvision->have_tuner) && (usbvision->tuner_type != -1)) { + tun_addr.mode_mask = T_ANALOG_TV; + tun_addr.type = usbvision->tuner_type; + tun_addr.addr = ADDR_UNSET; + client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_addr); + + call_i2c_clients(usbvision, VIDIOC_S_INPUT, &usbvision->input.index); + } + // FIXME : need to add a call VIDIOC_S_CTRL for each control +/* call_i2c_clients(usbvision, DECODER_SET_PICTURE, &usbvision->vpic); */ + stdId = usbvision->input.std; + call_i2c_clients(usbvision, VIDIOC_S_STD, &stdId); + + PDEBUG(DBG_I2C, "usbvision[%d] attaches %s", usbvision->nr, client->name); + + return 0; +} + +static int detach_inform(struct i2c_client *client) +{ + struct usb_usbvision *usbvision; + int i; + + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + usbvision = (struct usb_usbvision *)client->adapter->data; + #else + usbvision = (struct usb_usbvision *)i2c_get_adapdata(client->adapter); + #endif + + PDEBUG(DBG_I2C, "usbvision[%d] detaches %s", usbvision->nr, client->name); + for (i = 0; i < USBVISION_I2C_CLIENTS_MAX; i++) { + if (NULL != usbvision->i2c_clients[i] && + usbvision->i2c_clients[i]->driver->id == + client->driver->id) { + usbvision->i2c_clients[i] = NULL; + break; + } + } + return 0; +} + +static int +usbvision_i2c_read_max4(struct usb_usbvision *usbvision, unsigned char addr, + char *buf, short len) +{ + int rc, retries; + + for (retries = 5;;) { + rc = usbvision_write_reg(usbvision, USBVISION_SER_ADRS, addr); + if (rc < 0) + return rc; + + /* Initiate byte read cycle */ + /* USBVISION_SER_CONT <- d0-d2 n. of bytes to r/w */ + /* d3 0=Wr 1=Rd */ + rc = usbvision_write_reg(usbvision, USBVISION_SER_CONT, + (len & 0x07) | 0x18); + if (rc < 0) + return rc; + + /* Test for Busy and ACK */ + do { + /* USBVISION_SER_CONT -> d4 == 0 busy */ + rc = usbvision_read_reg(usbvision, USBVISION_SER_CONT); + } while (rc > 0 && ((rc & 0x10) != 0)); /* Retry while busy */ + if (rc < 0) + return rc; + + /* USBVISION_SER_CONT -> d5 == 1 Not ack */ + if ((rc & 0x20) == 0) /* Ack? */ + break; + + /* I2C abort */ + rc = usbvision_write_reg(usbvision, USBVISION_SER_CONT, 0x00); + if (rc < 0) + return rc; + + if (--retries < 0) + return -1; + } + + switch (len) { + case 4: + buf[3] = usbvision_read_reg(usbvision, USBVISION_SER_DAT4); + case 3: + buf[2] = usbvision_read_reg(usbvision, USBVISION_SER_DAT3); + case 2: + buf[1] = usbvision_read_reg(usbvision, USBVISION_SER_DAT2); + case 1: + buf[0] = usbvision_read_reg(usbvision, USBVISION_SER_DAT1); + break; + default: + printk(KERN_ERR + "usbvision_i2c_read_max4: buffer length > 4\n"); + } + + if (debug & DBG_I2C) { + int idx; + for (idx = 0; idx < len; idx++) { + PDEBUG(DBG_I2C, "read %x from address %x", (unsigned char)buf[idx], addr); + } + } + return len; +} + + +static int usbvision_i2c_write_max4(struct usb_usbvision *usbvision, + unsigned char addr, const char *buf, + short len) +{ + int rc, retries; + int i; + unsigned char value[6]; + unsigned char ser_cont; + + ser_cont = (len & 0x07) | 0x10; + + value[0] = addr; + value[1] = ser_cont; + for (i = 0; i < len; i++) + value[i + 2] = buf[i]; + + for (retries = 5;;) { + rc = usb_control_msg(usbvision->dev, + usb_sndctrlpipe(usbvision->dev, 1), + USBVISION_OP_CODE, + USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_ENDPOINT, 0, + (__u16) USBVISION_SER_ADRS, value, + len + 2, HZ); + + if (rc < 0) + return rc; + + rc = usbvision_write_reg(usbvision, USBVISION_SER_CONT, + (len & 0x07) | 0x10); + if (rc < 0) + return rc; + + /* Test for Busy and ACK */ + do { + rc = usbvision_read_reg(usbvision, USBVISION_SER_CONT); + } while (rc > 0 && ((rc & 0x10) != 0)); /* Retry while busy */ + if (rc < 0) + return rc; + + if ((rc & 0x20) == 0) /* Ack? */ + break; + + /* I2C abort */ + usbvision_write_reg(usbvision, USBVISION_SER_CONT, 0x00); + + if (--retries < 0) + return -1; + + } + + if (debug & DBG_I2C) { + int idx; + for (idx = 0; idx < len; idx++) { + PDEBUG(DBG_I2C, "wrote %x at address %x", (unsigned char)buf[idx], addr); + } + } + return len; +} + +static int usbvision_i2c_write(void *data, unsigned char addr, char *buf, + short len) +{ + char *bufPtr = buf; + int retval; + int wrcount = 0; + int count; + int maxLen = 4; + struct usb_usbvision *usbvision = (struct usb_usbvision *) data; + + while (len > 0) { + count = (len > maxLen) ? maxLen : len; + retval = usbvision_i2c_write_max4(usbvision, addr, bufPtr, count); + if (retval > 0) { + len -= count; + bufPtr += count; + wrcount += count; + } else + return (retval < 0) ? retval : -EFAULT; + } + return wrcount; +} + +static int usbvision_i2c_read(void *data, unsigned char addr, char *buf, + short len) +{ + char temp[4]; + int retval, i; + int rdcount = 0; + int count; + struct usb_usbvision *usbvision = (struct usb_usbvision *) data; + + while (len > 0) { + count = (len > 3) ? 4 : len; + retval = usbvision_i2c_read_max4(usbvision, addr, temp, count); + if (retval > 0) { + for (i = 0; i < len; i++) + buf[rdcount + i] = temp[i]; + len -= count; + rdcount += count; + } else + return (retval < 0) ? retval : -EFAULT; + } + return rdcount; +} + +static struct i2c_algo_usb_data i2c_algo_template = { + .data = NULL, + .inb = usbvision_i2c_read, + .outb = usbvision_i2c_write, + .udelay = 10, + .mdelay = 10, + .timeout = 100, +}; + +static struct i2c_adapter i2c_adap_template = { + .owner = THIS_MODULE, + .name = "usbvision", + .id = I2C_HW_B_BT848, /* FIXME */ + .algo = NULL, + .algo_data = NULL, + .client_register = attach_inform, + .client_unregister = detach_inform, +#if defined (I2C_ADAP_CLASS_TV_ANALOG) + .class = I2C_ADAP_CLASS_TV_ANALOG, +#elif defined (I2C_CLASS_TV_ANALOG) + .class = I2C_CLASS_TV_ANALOG, +#endif +}; + +static struct i2c_client i2c_client_template = { + .name = "usbvision internal", + .flags = 0, + .addr = 0, + .adapter = NULL, + .driver = NULL, +}; + +static int usbvision_init_i2c(struct usb_usbvision *usbvision) +{ + memcpy(&usbvision->i2c_adap, &i2c_adap_template, + sizeof(struct i2c_adapter)); + memcpy(&usbvision->i2c_algo, &i2c_algo_template, + sizeof(struct i2c_algo_usb_data)); + memcpy(&usbvision->i2c_client, &i2c_client_template, + sizeof(struct i2c_client)); + + sprintf(usbvision->i2c_adap.name + strlen(usbvision->i2c_adap.name), + " #%d", usbvision->vdev->minor & 0x1f); + PDEBUG(DBG_I2C, "Adaptername: %s", usbvision->i2c_adap.name); + + i2c_set_adapdata(&usbvision->i2c_adap, usbvision); + i2c_set_clientdata(&usbvision->i2c_client, usbvision); + i2c_set_algo_usb_data(&usbvision->i2c_algo, usbvision); + + usbvision->i2c_adap.algo_data = &usbvision->i2c_algo; + usbvision->i2c_client.adapter = &usbvision->i2c_adap; + + if (usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_IIC_LRNACK) < 0) { + printk(KERN_ERR "usbvision_init_i2c: can't wirte reg\n"); + return -EBUSY; + } + +#ifdef CONFIG_KMOD + /* Request the load of the i2c modules we need */ + if (autoload) { + switch (usbvision_device_data[usbvision->DevModel].Codec) { + case CODEC_SAA7113: + request_module("saa7115"); + break; + case CODEC_SAA7111: + request_module("saa7115"); + break; + } + if (usbvision_device_data[usbvision->DevModel].Tuner == 1) { + request_module("tuner"); + } + } +#endif + + usbvision->i2c_ok = usbvision_i2c_usb_add_bus(&usbvision->i2c_adap); + + return usbvision->i2c_ok; + +} + + +/****************************/ +/* usbvision utility functions */ +/****************************/ + +static int usbvision_power_off(struct usb_usbvision *usbvision) +{ + int errCode = 0; + + PDEBUG(DBG_FUNC, ""); + + errCode = usbvision_write_reg(usbvision, USBVISION_PWR_REG, USBVISION_SSPND_EN); + if (errCode == 1) { + usbvision->power = 0; + } + PDEBUG(DBG_FUNC, "%s: errCode %d", (errCode!=1)?"ERROR":"power is off", errCode); + return errCode; +} + + +// to call usbvision_power_off from task queue +static void call_usbvision_power_off(void *_usbvision) +{ + struct usb_usbvision *usbvision = _usbvision; + + PDEBUG(DBG_FUNC, ""); + down_interruptible(&usbvision->lock); + if(usbvision->user == 0) { + usbvision_i2c_usb_del_bus(&usbvision->i2c_adap); + usbvision_power_off(usbvision); + usbvision->initialized = 0; + } + up(&usbvision->lock); +} + + +/* + * usbvision_set_video_format() + * + */ +static int usbvision_set_video_format(struct usb_usbvision *usbvision, int format) +{ + static const char proc[] = "usbvision_set_video_format"; + int rc; + unsigned char value[2]; + + if (!USBVISION_IS_OPERATIONAL(usbvision)) + return 0; + + PDEBUG(DBG_FUNC, "isocMode %#02x", format); + + if ((format != ISOC_MODE_YUV422) + && (format != ISOC_MODE_YUV420) + && (format != ISOC_MODE_COMPRESS)) { + printk(KERN_ERR "usbvision: unknown video format %02x, using default YUV420", + format); + format = ISOC_MODE_YUV420; + } + value[0] = 0x0A; //TODO: See the effect of the filter + value[1] = format; + rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1), + USBVISION_OP_CODE, + USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_ENDPOINT, 0, + (__u16) USBVISION_FILT_CONT, value, 2, HZ); + + if (rc < 0) { + printk(KERN_ERR "%s: ERROR=%d. USBVISION stopped - " + "reconnect or reload driver.\n", proc, rc); + } + usbvision->isocMode = format; + return rc; +} + +/* + * usbvision_set_output() + * + */ + +static int usbvision_set_output(struct usb_usbvision *usbvision, int width, + int height) +{ + int errCode = 0; + int UsbWidth, UsbHeight; + unsigned int frameRate=0, frameDrop=0; + unsigned char value[4]; + + if (!USBVISION_IS_OPERATIONAL(usbvision)) { + return 0; + } + + if (width > MAX_USB_WIDTH) { + UsbWidth = width / 2; + usbvision->stretch_width = 2; + } + else { + UsbWidth = width; + usbvision->stretch_width = 1; + } + + if (height > MAX_USB_HEIGHT) { + UsbHeight = height / 2; + usbvision->stretch_height = 2; + } + else { + UsbHeight = height; + usbvision->stretch_height = 1; + } + + RESTRICT_TO_RANGE(UsbWidth, MIN_FRAME_WIDTH, MAX_USB_WIDTH); + UsbWidth &= ~(MIN_FRAME_WIDTH-1); + RESTRICT_TO_RANGE(UsbHeight, MIN_FRAME_HEIGHT, MAX_USB_HEIGHT); + UsbHeight &= ~(1); + + PDEBUG(DBG_FUNC, "usb %dx%d; screen %dx%d; stretch %dx%d", + UsbWidth, UsbHeight, width, height, + usbvision->stretch_width, usbvision->stretch_height); + + /* I'll not rewrite the same values */ + if ((UsbWidth != usbvision->curwidth) || (UsbHeight != usbvision->curheight)) { + value[0] = UsbWidth & 0xff; //LSB + value[1] = (UsbWidth >> 8) & 0x03; //MSB + value[2] = UsbHeight & 0xff; //LSB + value[3] = (UsbHeight >> 8) & 0x03; //MSB + + errCode = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1), + USBVISION_OP_CODE, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, + 0, (__u16) USBVISION_LXSIZE_O, value, 4, HZ); + + if (errCode < 0) { + err("%s failed: error %d", __FUNCTION__, errCode); + return errCode; + } + usbvision->curwidth = usbvision->stretch_width * UsbWidth; + usbvision->curheight = usbvision->stretch_height * UsbHeight; + } + + if (usbvision->isocMode == ISOC_MODE_YUV422) { + frameRate = (usbvision->isocPacketSize * 1000) / (UsbWidth * UsbHeight * 2); + } + else if (usbvision->isocMode == ISOC_MODE_YUV420) { + frameRate = (usbvision->isocPacketSize * 1000) / ((UsbWidth * UsbHeight * 12) / 8); + } + else { + frameRate = FRAMERATE_MAX; + } + + if (usbvision->input.std & V4L2_STD_625_50) { + frameDrop = frameRate * 32 / 25 - 1; + } + else if (usbvision->input.std & V4L2_STD_525_60) { + frameDrop = frameRate * 32 / 30 - 1; + } + + RESTRICT_TO_RANGE(frameDrop, FRAMERATE_MIN, FRAMERATE_MAX); + + PDEBUG(DBG_FUNC, "frameRate %d fps, frameDrop %d", frameRate, frameDrop); + + frameDrop = FRAMERATE_MAX; // We can allow the maximum here, because dropping is controlled + + /* frameDrop = 7; => framePhase = 1, 5, 9, 13, 17, 21, 25, 0, 4, 8, ... + => frameSkip = 4; + => frameRate = (7 + 1) * 25 / 32 = 200 / 32 = 6.25; + + frameDrop = 9; => framePhase = 1, 5, 8, 11, 14, 17, 21, 24, 27, 1, 4, 8, ... + => frameSkip = 4, 3, 3, 3, 3, 4, 3, 3, 3, 3, 4, ... + => frameRate = (9 + 1) * 25 / 32 = 250 / 32 = 7.8125; + */ + errCode = usbvision_write_reg(usbvision, USBVISION_FRM_RATE, frameDrop); + return errCode; +} + + +/* + * usbvision_set_compress_params() + * + */ + +static int usbvision_set_compress_params(struct usb_usbvision *usbvision) +{ + static const char proc[] = "usbvision_set_compresion_params: "; + int rc; + unsigned char value[6]; + + value[0] = 0x0F; // Intra-Compression cycle + value[1] = 0x01; // Reg.45 one line per strip + value[2] = 0x00; // Reg.46 Force intra mode on all new frames + value[3] = 0x00; // Reg.47 FORCE_UP <- 0 normal operation (not force) + value[4] = 0xA2; // Reg.48 BUF_THR I'm not sure if this does something in not compressed mode. + value[5] = 0x00; // Reg.49 DVI_YUV This has nothing to do with compression + + //catched values for NT1004 + // value[0] = 0xFF; // Never apply intra mode automatically + // value[1] = 0xF1; // Use full frame height for virtual strip width; One line per strip + // value[2] = 0x01; // Force intra mode on all new frames + // value[3] = 0x00; // Strip size 400 Bytes; do not force up + // value[4] = 0xA2; // + if (!USBVISION_IS_OPERATIONAL(usbvision)) + return 0; + + rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1), + USBVISION_OP_CODE, + USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_ENDPOINT, 0, + (__u16) USBVISION_INTRA_CYC, value, 5, HZ); + + if (rc < 0) { + printk(KERN_ERR "%sERROR=%d. USBVISION stopped - " + "reconnect or reload driver.\n", proc, rc); + return rc; + } + + if (usbvision->bridgeType == BRIDGE_NT1004) { + value[0] = 20; // PCM Threshold 1 + value[1] = 12; // PCM Threshold 2 + value[2] = 255; // Distorsion Threshold inter + value[3] = 255; // Distorsion Threshold intra + value[4] = 43; // Max Distorsion inter + value[5] = 43; // Max Distorsion intra + } + else { + value[0] = 20; // PCM Threshold 1 + value[1] = 12; // PCM Threshold 2 + value[2] = 255; // Distorsion Threshold d7-d0 + value[3] = 0; // Distorsion Threshold d11-d8 + value[4] = 43; // Max Distorsion d7-d0 + value[5] = 0; // Max Distorsion d8 + } + + if (!USBVISION_IS_OPERATIONAL(usbvision)) + return 0; + + rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1), + USBVISION_OP_CODE, + USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_ENDPOINT, 0, + (__u16) USBVISION_PCM_THR1, value, 6, HZ); + + if (rc < 0) { + printk(KERN_ERR "%sERROR=%d. USBVISION stopped - " + "reconnect or reload driver.\n", proc, rc); + return rc; + } + + + return rc; +} + + +/* + * usbvision_set_input() + * + * Set the input (saa711x, ...) size x y and other misc input params + * I've no idea if this parameters are right + * + */ +static int usbvision_set_input(struct usb_usbvision *usbvision) +{ + static const char proc[] = "usbvision_set_input: "; + int rc; + unsigned char value[8]; + unsigned char dvi_yuv_value; + + if (!USBVISION_IS_OPERATIONAL(usbvision)) + return 0; + + /* Set input format expected from decoder*/ + if (usbvision_device_data[usbvision->DevModel].Vin_Reg1 >= 0) { + value[0] = usbvision_device_data[usbvision->DevModel].Vin_Reg1 & 0xff; + } else if(usbvision_device_data[usbvision->DevModel].Codec == CODEC_SAA7113) { + /* SAA7113 uses 8 bit output */ + value[0] = USBVISION_8_422_SYNC; + } else { + /* I'm sure only about d2-d0 [010] 16 bit 4:2:2 usin sync pulses + * as that is how saa7111 is configured */ + value[0] = USBVISION_16_422_SYNC; + /* | USBVISION_VSNC_POL | USBVISION_VCLK_POL);*/ + } + + rc = usbvision_write_reg(usbvision, USBVISION_VIN_REG1, value[0]); + if (rc < 0) { + printk(KERN_ERR "%sERROR=%d. USBVISION stopped - " + "reconnect or reload driver.\n", proc, rc); + return rc; + } + + + if (usbvision->input.std & V4L2_STD_PAL) { + value[0] = 0xC0; + value[1] = 0x02; //0x02C0 -> 704 Input video line length + value[2] = 0x20; + value[3] = 0x01; //0x0120 -> 288 Input video n. of lines + value[4] = 0x60; + value[5] = 0x00; //0x0060 -> 96 Input video h offset + value[6] = 0x16; + value[7] = 0x00; //0x0016 -> 22 Input video v offset + } else if (usbvision->input.std & V4L2_STD_SECAM) { + value[0] = 0xC0; + value[1] = 0x02; //0x02C0 -> 704 Input video line length + value[2] = 0x20; + value[3] = 0x01; //0x0120 -> 288 Input video n. of lines + value[4] = 0x01; + value[5] = 0x00; //0x0001 -> 01 Input video h offset + value[6] = 0x01; + value[7] = 0x00; //0x0001 -> 01 Input video v offset + } else { /* V4L2_STD_NTSC */ + value[0] = 0xD0; + value[1] = 0x02; //0x02D0 -> 720 Input video line length + value[2] = 0xF0; + value[3] = 0x00; //0x00F0 -> 240 Input video number of lines + value[4] = 0x50; + value[5] = 0x00; //0x0050 -> 80 Input video h offset + value[6] = 0x10; + value[7] = 0x00; //0x0010 -> 16 Input video v offset + } + + if (usbvision_device_data[usbvision->DevModel].X_Offset >= 0) { + value[4]=usbvision_device_data[usbvision->DevModel].X_Offset & 0xff; + value[5]=(usbvision_device_data[usbvision->DevModel].X_Offset & 0x0300) >> 8; + } + + if (usbvision_device_data[usbvision->DevModel].Y_Offset >= 0) { + value[6]=usbvision_device_data[usbvision->DevModel].Y_Offset & 0xff; + value[7]=(usbvision_device_data[usbvision->DevModel].Y_Offset & 0x0300) >> 8; + } + + rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1), + USBVISION_OP_CODE, /* USBVISION specific code */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0, + (__u16) USBVISION_LXSIZE_I, value, 8, HZ); + if (rc < 0) { + printk(KERN_ERR "%sERROR=%d. USBVISION stopped - " + "reconnect or reload driver.\n", proc, rc); + return rc; + } + + + dvi_yuv_value = 0x00; /* U comes after V, Ya comes after U/V, Yb comes after Yb */ + + if(usbvision_device_data[usbvision->DevModel].Dvi_yuv >= 0){ + dvi_yuv_value = usbvision_device_data[usbvision->DevModel].Dvi_yuv & 0xff; + } + else if(usbvision_device_data[usbvision->DevModel].Codec == CODEC_SAA7113) { + /* This changes as the fine sync control changes. Further investigation necessary */ + dvi_yuv_value = 0x06; + } + + return (usbvision_write_reg(usbvision, USBVISION_DVI_YUV, dvi_yuv_value)); +} + + +/* + * usbvision_set_dram_settings() + * + * Set the buffer address needed by the usbvision dram to operate + * This values has been taken with usbsnoop. + * + */ + +static int usbvision_set_dram_settings(struct usb_usbvision *usbvision) +{ + int rc; + unsigned char value[8]; + + if (usbvision->isocMode == ISOC_MODE_COMPRESS) { + value[0] = 0x42; + value[1] = 0x71; + value[2] = 0xff; + value[3] = 0x00; + value[4] = 0x98; + value[5] = 0xe0; + value[6] = 0x71; + value[7] = 0xff; + // UR: 0x0E200-0x3FFFF = 204288 Words (1 Word = 2 Byte) + // FDL: 0x00000-0x0E099 = 57498 Words + // VDW: 0x0E3FF-0x3FFFF + } + else { + value[0] = 0x42; + value[1] = 0x00; + value[2] = 0xff; + value[3] = 0x00; + value[4] = 0x00; + value[5] = 0x00; + value[6] = 0x00; + value[7] = 0xff; + } + /* These are the values of the address of the video buffer, + * they have to be loaded into the USBVISION_DRM_PRM1-8 + * + * Start address of video output buffer for read: drm_prm1-2 -> 0x00000 + * End address of video output buffer for read: drm_prm1-3 -> 0x1ffff + * Start address of video frame delay buffer: drm_prm1-4 -> 0x20000 + * Only used in compressed mode + * End address of video frame delay buffer: drm_prm1-5-6 -> 0x3ffff + * Only used in compressed mode + * Start address of video output buffer for write: drm_prm1-7 -> 0x00000 + * End address of video output buffer for write: drm_prm1-8 -> 0x1ffff + */ + + if (!USBVISION_IS_OPERATIONAL(usbvision)) + return 0; + + rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1), + USBVISION_OP_CODE, /* USBVISION specific code */ + USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_ENDPOINT, 0, + (__u16) USBVISION_DRM_PRM1, value, 8, HZ); + + if (rc < 0) { + err("%sERROR=%d", __FUNCTION__, rc); + return rc; + } + + /* Restart the video buffer logic */ + if ((rc = usbvision_write_reg(usbvision, USBVISION_DRM_CONT, USBVISION_RES_UR | + USBVISION_RES_FDL | USBVISION_RES_VDW)) < 0) + return rc; + rc = usbvision_write_reg(usbvision, USBVISION_DRM_CONT, 0x00); + + return rc; +} + +/* + * () + * + * Power on the device, enables suspend-resume logic + * & reset the isoc End-Point + * + */ + +static int usbvision_power_on(struct usb_usbvision *usbvision) +{ + int errCode = 0; + + PDEBUG(DBG_FUNC, ""); + + usbvision_write_reg(usbvision, USBVISION_PWR_REG, USBVISION_SSPND_EN); + usbvision_write_reg(usbvision, USBVISION_PWR_REG, + USBVISION_SSPND_EN | USBVISION_RES2); + usbvision_write_reg(usbvision, USBVISION_PWR_REG, + USBVISION_SSPND_EN | USBVISION_PWR_VID); + errCode = usbvision_write_reg(usbvision, USBVISION_PWR_REG, + USBVISION_SSPND_EN | USBVISION_PWR_VID | USBVISION_RES2); + if (errCode == 1) { + usbvision->power = 1; + } + PDEBUG(DBG_FUNC, "%s: errCode %d", (errCode<0)?"ERROR":"power is on", errCode); + return errCode; +} + + +static void usbvision_powerOffTimer(unsigned long data) +{ + struct usb_usbvision *usbvision = (void *) data; + + PDEBUG(DBG_FUNC, ""); + del_timer(&usbvision->powerOffTimer); + INIT_WORK(&usbvision->powerOffWork, call_usbvision_power_off, usbvision); + (void) schedule_work(&usbvision->powerOffWork); + +} + + +/* + * usbvision_begin_streaming() + * Sure you have to put bit 7 to 0, if not incoming frames are droped, but no + * idea about the rest + */ +static int usbvision_begin_streaming(struct usb_usbvision *usbvision) +{ + int errCode = 0; + + if (usbvision->isocMode == ISOC_MODE_COMPRESS) { + usbvision_init_compression(usbvision); + } + errCode = usbvision_write_reg(usbvision, USBVISION_VIN_REG2, USBVISION_NOHVALID | + usbvision->Vin_Reg2_Preset); + return errCode; +} + +/* + * usbvision_restart_isoc() + * Not sure yet if touching here PWR_REG make loose the config + */ + +static int usbvision_restart_isoc(struct usb_usbvision *usbvision) +{ + int ret; + + if ( + (ret = + usbvision_write_reg(usbvision, USBVISION_PWR_REG, + USBVISION_SSPND_EN | USBVISION_PWR_VID)) < 0) + return ret; + if ( + (ret = + usbvision_write_reg(usbvision, USBVISION_PWR_REG, + USBVISION_SSPND_EN | USBVISION_PWR_VID | + USBVISION_RES2)) < 0) + return ret; + if ( + (ret = + usbvision_write_reg(usbvision, USBVISION_VIN_REG2, + USBVISION_KEEP_BLANK | USBVISION_NOHVALID | + usbvision->Vin_Reg2_Preset)) < 0) return ret; + + /* TODO: schedule timeout */ + while ((usbvision_read_reg(usbvision, USBVISION_STATUS_REG) && 0x01) != 1); + + return 0; +} + +static int usbvision_audio_on(struct usb_usbvision *usbvision) +{ + if (usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, usbvision->AudioChannel) < 0) { + printk(KERN_ERR "usbvision_audio_on: can't wirte reg\n"); + return -1; + } + DEBUG(printk(KERN_DEBUG "usbvision_audio_on: channel %d\n", usbvision->AudioChannel)); + usbvision->AudioMute = 0; + return 0; +} + +static int usbvision_audio_mute(struct usb_usbvision *usbvision) +{ + if (usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, 0x03) < 0) { + printk(KERN_ERR "usbvision_audio_mute: can't wirte reg\n"); + return -1; + } + DEBUG(printk(KERN_DEBUG "usbvision_audio_mute: audio mute\n")); + usbvision->AudioMute = 1; + return 0; +} + +static int usbvision_audio_off(struct usb_usbvision *usbvision) +{ + if (usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, USBVISION_AUDIO_MUTE) < 0) { + printk(KERN_ERR "usbvision_audio_off: can't wirte reg\n"); + return -1; + } + DEBUG(printk(KERN_DEBUG "usbvision_audio_off: audio off\n")); + usbvision->AudioMute = 0; + usbvision->AudioChannel = USBVISION_AUDIO_MUTE; + return 0; +} + +static int usbvision_set_audio(struct usb_usbvision *usbvision, int AudioChannel) +{ + if (!usbvision->AudioMute) { + if (usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, AudioChannel) < 0) { + printk(KERN_ERR "usbvision_set_audio: can't write iopin register for audio switching\n"); + return -1; + } + } + DEBUG(printk(KERN_DEBUG "usbvision_set_audio: channel %d\n", AudioChannel)); + usbvision->AudioChannel = AudioChannel; + return 0; +} + +static int usbvision_setup(struct usb_usbvision *usbvision) +{ + usbvision_set_video_format(usbvision, isocMode); + usbvision_set_dram_settings(usbvision); + usbvision_set_compress_params(usbvision); + usbvision_set_input(usbvision); + usbvision_set_output(usbvision, MAX_USB_WIDTH, MAX_USB_HEIGHT); + usbvision_restart_isoc(usbvision); + + /* cosas del PCM */ + return USBVISION_IS_OPERATIONAL(usbvision); +} + + +/* + * usbvision_init_isoc() + * + */ +static int usbvision_init_isoc(struct usb_usbvision *usbvision) +{ + struct usb_device *dev = usbvision->dev; + int bufIdx, errCode, regValue; + + if (!USBVISION_IS_OPERATIONAL(usbvision)) + return -EFAULT; + + usbvision->curFrameNum = -1; + scratch_reset(usbvision); + + /* Alternate interface 1 is is the biggest frame size */ + errCode = usb_set_interface(dev, usbvision->iface, usbvision->ifaceAltActive); + if (errCode < 0) { + usbvision->last_error = errCode; + return -EBUSY; + } + + regValue = (16 - usbvision_read_reg(usbvision, USBVISION_ALTER_REG)) & 0x0F; + usbvision->isocPacketSize = (regValue == 0) ? 0 : (regValue * 64) - 1; + PDEBUG(DBG_ISOC, "ISO Packet Length:%d", usbvision->isocPacketSize); + + usbvision->usb_bandwidth = regValue >> 1; + PDEBUG(DBG_ISOC, "USB Bandwidth Usage: %dMbit/Sec", usbvision->usb_bandwidth); + + + + /* We double buffer the Iso lists */ + + for (bufIdx = 0; bufIdx < USBVISION_NUMSBUF; bufIdx++) { + int j, k; + struct urb *urb; + + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + urb = usb_alloc_urb(USBVISION_URB_FRAMES); + #else + urb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL); + #endif + if (urb == NULL) { + err("%s: usb_alloc_urb() failed", __FUNCTION__); + return -ENOMEM; + } + usbvision->sbuf[bufIdx].urb = urb; + urb->dev = dev; + urb->context = usbvision; + urb->pipe = usb_rcvisocpipe(dev, usbvision->video_endp); + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + urb->transfer_flags = USB_ISO_ASAP; + #else + urb->transfer_flags = URB_ISO_ASAP; + urb->interval = 1; + #endif + urb->transfer_buffer = usbvision->sbuf[bufIdx].data; + urb->complete = usbvision_isocIrq; + urb->number_of_packets = USBVISION_URB_FRAMES; + urb->transfer_buffer_length = + usbvision->isocPacketSize * USBVISION_URB_FRAMES; + for (j = k = 0; j < USBVISION_URB_FRAMES; j++, + k += usbvision->isocPacketSize) { + urb->iso_frame_desc[j].offset = k; + urb->iso_frame_desc[j].length = usbvision->isocPacketSize; + } + } + + + /* Submit all URBs */ + for (bufIdx = 0; bufIdx < USBVISION_NUMSBUF; bufIdx++) { + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + errCode = usb_submit_urb(usbvision->sbuf[bufIdx].urb); + #else + errCode = usb_submit_urb(usbvision->sbuf[bufIdx].urb, GFP_KERNEL); + #endif + if (errCode) { + err("%s: usb_submit_urb(%d) failed: error %d", __FUNCTION__, bufIdx, errCode); + } + } + + usbvision->streaming = 1; + PDEBUG(DBG_ISOC, "%s: streaming=1 usbvision->video_endp=$%02x", __FUNCTION__, usbvision->video_endp); + return 0; +} + +/* + * usbvision_stop_isoc() + * + * This procedure stops streaming and deallocates URBs. Then it + * activates zero-bandwidth alt. setting of the video interface. + * + */ +static void usbvision_stop_isoc(struct usb_usbvision *usbvision) +{ + int bufIdx, errCode, regValue; + + if (!usbvision->streaming || (usbvision->dev == NULL)) + return; + + /* Unschedule all of the iso td's */ + for (bufIdx = 0; bufIdx < USBVISION_NUMSBUF; bufIdx++) { + usb_kill_urb(usbvision->sbuf[bufIdx].urb); + usb_free_urb(usbvision->sbuf[bufIdx].urb); + usbvision->sbuf[bufIdx].urb = NULL; + } + + + PDEBUG(DBG_ISOC, "%s: streaming=0\n", __FUNCTION__); + usbvision->streaming = 0; + + + if (!usbvision->remove_pending) { + + /* Set packet size to 0 */ + errCode = usb_set_interface(usbvision->dev, usbvision->iface, + usbvision->ifaceAltInactive); + if (errCode < 0) { + err("%s: usb_set_interface() failed: error %d", __FUNCTION__, errCode); + usbvision->last_error = errCode; + } + regValue = (16 - usbvision_read_reg(usbvision, USBVISION_ALTER_REG)) & 0x0F; + usbvision->isocPacketSize = (regValue == 0) ? 0 : (regValue * 64) - 1; + PDEBUG(DBG_ISOC, "ISO Packet Length:%d", usbvision->isocPacketSize); + + usbvision->usb_bandwidth = regValue >> 1; + PDEBUG(DBG_ISOC, "USB Bandwidth Usage: %dMbit/Sec", usbvision->usb_bandwidth); + } +} + +/* + * usbvision_new_frame() + * + */ +static int usbvision_new_frame(struct usb_usbvision *usbvision, int framenum) +{ + struct usbvision_frame *frame; + int n; //byhec , width, height; + + /* If we're not grabbing a frame right now and the other frame is */ + /* ready to be grabbed into, then use it instead */ + if (usbvision->curFrameNum != -1) + return 0; + + n = (framenum - 1 + USBVISION_NUMFRAMES) % USBVISION_NUMFRAMES; + if (usbvision->frame[n].grabstate == FrameState_Ready) + framenum = n; + + frame = &usbvision->frame[framenum]; + + frame->grabstate = FrameState_Grabbing; + frame->scanstate = ScanState_Scanning; + frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */ + usbvision->curFrameNum = framenum; + + /* + * Normally we would want to copy previous frame into the current one + * before we even start filling it with data; this allows us to stop + * filling at any moment; top portion of the frame will be new and + * bottom portion will stay as it was in previous frame. If we don't + * do that then missing chunks of video stream will result in flickering + * portions of old data whatever it was before. + * + * If we choose not to copy previous frame (to, for example, save few + * bus cycles - the frame can be pretty large!) then we have an option + * to clear the frame before using. If we experience losses in this + * mode then missing picture will be black (flickering). + * + * Finally, if user chooses not to clean the current frame before + * filling it with data then the old data will be visible if we fail + * to refill entire frame with new data. + */ + if (!(flags & FLAGS_SEPARATE_FRAMES)) { + /* This copies previous frame into this one to mask losses */ + memmove(frame->data, usbvision->frame[1 - framenum].data, + MAX_FRAME_SIZE); + } else { + if (flags & FLAGS_CLEAN_FRAMES) { + /*This provides a "clean" frame but slows things down */ + memset(frame->data, 0, MAX_FRAME_SIZE); + } + } + return 0; +} + +static int usbvision_muxsel(struct usb_usbvision *usbvision, int channel, int norm) +{ + int mode[4]; + int audio[]= {1, 0, 0, 0}; + struct v4l2_routing route; + //channel 0 is TV with audiochannel 1 (tuner mono) + //channel 1 is Composite with audio channel 0 (line in) + //channel 2 is S-Video with audio channel 0 (line in) + //channel 3 is additional video inputs to the device with audio channel 0 (line in) + + RESTRICT_TO_RANGE(channel, 0, usbvision->video_inputs); + /* set the new video norm */ + if (usbvision->input.std != norm) { + v4l2_std_id video_command = norm; + + route.input = SAA7115_COMPOSITE1; + call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route); + call_i2c_clients(usbvision, VIDIOC_S_STD, &video_command); + usbvision->input.std = norm; + call_i2c_clients(usbvision, VIDIOC_S_INPUT, &usbvision->input.index); //set norm in tuner + } + + // set the new channel + // Regular USB TV Tuners -> channel: 0 = Television, 1 = Composite, 2 = S-Video + // Four video input devices -> channel: 0 = Chan White, 1 = Chan Green, 2 = Chan Yellow, 3 = Chan Red + + switch (usbvision_device_data[usbvision->DevModel].Codec) { + case CODEC_SAA7113: + if (SwitchSVideoInput) { // To handle problems with S-Video Input for some devices. Use SwitchSVideoInput parameter when loading the module. + mode[2] = 1; + } + else { + mode[2] = 7; + } + if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) { + mode[0] = 0; mode[1] = 2; mode[3] = 3; // Special for four input devices + } + else { + mode[0] = 0; mode[1] = 2; //modes for regular saa7113 devices + } + break; + case CODEC_SAA7111: + mode[0] = 0; mode[1] = 1; mode[2] = 7; //modes for saa7111 + break; + default: + mode[0] = 0; mode[1] = 1; mode[2] = 7; //default modes + } + route.input = mode[channel]; + call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route); + usbvision->channel = channel; + usbvision_set_audio(usbvision, audio[channel]); + return 0; +} + + +/* + * usbvision_open() + * + * This is part of Video 4 Linux API. The driver can be opened by one + * client only (checks internal counter 'usbvision->user'). The procedure + * then allocates buffers needed for video processing. + * + */ +static int usbvision_v4l2_open(struct inode *inode, struct file *file) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); + const int sb_size = USBVISION_URB_FRAMES * USBVISION_MAX_ISOC_PACKET_SIZE; + int i, errCode = 0; + + PDEBUG(DBG_IO, "open"); + + + if (timer_pending(&usbvision->powerOffTimer)) { + del_timer(&usbvision->powerOffTimer); + } + + if (usbvision->user) + errCode = -EBUSY; + else { + /* Clean pointers so we know if we allocated something */ + for (i = 0; i < USBVISION_NUMSBUF; i++) + usbvision->sbuf[i].data = NULL; + + /* Allocate memory for the frame buffers */ + usbvision->max_frame_size = MAX_FRAME_SIZE; + usbvision->fbuf_size = USBVISION_NUMFRAMES * usbvision->max_frame_size; + usbvision->fbuf = usbvision_rvmalloc(usbvision->fbuf_size); + usbvision->scratch = vmalloc(scratch_buf_size); + scratch_reset(usbvision); + if ((usbvision->fbuf == NULL) || (usbvision->scratch == NULL)) { + err("%s: unable to allocate %d bytes for fbuf and %d bytes for scratch", + __FUNCTION__, usbvision->fbuf_size, scratch_buf_size); + errCode = -ENOMEM; + } + else { + /* Allocate all buffers */ + for (i = 0; i < USBVISION_NUMFRAMES; i++) { + usbvision->frame[i].grabstate = FrameState_Unused; + usbvision->frame[i].data = usbvision->fbuf + + i * MAX_FRAME_SIZE; + /* + * Set default sizes in case IOCTL + * (VIDIOCMCAPTURE) + * is not used (using read() instead). + */ + usbvision->stretch_width = 1; + usbvision->stretch_height = 1; + usbvision->frame[i].width = usbvision->curwidth; + usbvision->frame[i].height = usbvision->curheight; + usbvision->frame[i].bytes_read = 0; + } + if (dga) { //set default for DGA + usbvision->overlay_frame.grabstate = FrameState_Unused; + usbvision->overlay_frame.scanstate = ScanState_Scanning; + usbvision->overlay_frame.data = NULL; + usbvision->overlay_frame.width = usbvision->curwidth; + usbvision->overlay_frame.height = usbvision->curheight; + usbvision->overlay_frame.bytes_read = 0; + } + for (i = 0; i < USBVISION_NUMSBUF; i++) { + usbvision->sbuf[i].data = kzalloc(sb_size, GFP_KERNEL); + if (usbvision->sbuf[i].data == NULL) { + err("%s: unable to allocate %d bytes for sbuf", __FUNCTION__, sb_size); + errCode = -ENOMEM; + break; + } + } + } + if ((!errCode) && (usbvision->isocMode==ISOC_MODE_COMPRESS)) { + int IFB_size = MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT * 3 / 2; + usbvision->IntraFrameBuffer = vmalloc(IFB_size); + if (usbvision->IntraFrameBuffer == NULL) { + err("%s: unable to allocate %d for compr. frame buffer", __FUNCTION__, IFB_size); + errCode = -ENOMEM; + } + + } + if (errCode) { + /* Have to free all that memory */ + if (usbvision->fbuf != NULL) { + usbvision_rvfree(usbvision->fbuf, usbvision->fbuf_size); + usbvision->fbuf = NULL; + } + if (usbvision->scratch != NULL) { + vfree(usbvision->scratch); + usbvision->scratch = NULL; + } + for (i = 0; i < USBVISION_NUMSBUF; i++) { + if (usbvision->sbuf[i].data != NULL) { + kfree(usbvision->sbuf[i].data); + usbvision->sbuf[i].data = NULL; + } + } + if (usbvision->IntraFrameBuffer != NULL) { + vfree(usbvision->IntraFrameBuffer); + usbvision->IntraFrameBuffer = NULL; + } + } + } + + /* If so far no errors then we shall start the camera */ + if (!errCode) { + down(&usbvision->lock); + if (usbvision->power == 0) { + usbvision_power_on(usbvision); + usbvision_init_i2c(usbvision); + } + + /* Send init sequence only once, it's large! */ + if (!usbvision->initialized) { + int setup_ok = 0; + setup_ok = usbvision_setup(usbvision); + if (setup_ok) + usbvision->initialized = 1; + else + errCode = -EBUSY; + } + + if (!errCode) { + usbvision_begin_streaming(usbvision); + errCode = usbvision_init_isoc(usbvision); + usbvision->user++; + } + else { + if (PowerOnAtOpen) { + usbvision_i2c_usb_del_bus(&usbvision->i2c_adap); + usbvision_power_off(usbvision); + usbvision->initialized = 0; + } + } + up(&usbvision->lock); + } + + if (errCode) { + } + + PDEBUG(DBG_IO, "success"); + return errCode; +} + +/* + * usbvision_v4l2_close() + * + * This is part of Video 4 Linux API. The procedure + * stops streaming and deallocates all buffers that were earlier + * allocated in usbvision_v4l2_open(). + * + */ +static int usbvision_v4l2_close(struct inode *inode, struct file *file) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); + int i; + + PDEBUG(DBG_IO, "close"); + down(&usbvision->lock); + + usbvision_audio_off(usbvision); + usbvision_restart_isoc(usbvision); + usbvision_stop_isoc(usbvision); + + if (usbvision->IntraFrameBuffer != NULL) { + vfree(usbvision->IntraFrameBuffer); + usbvision->IntraFrameBuffer = NULL; + } + + usbvision_rvfree(usbvision->fbuf, usbvision->fbuf_size); + vfree(usbvision->scratch); + for (i = 0; i < USBVISION_NUMSBUF; i++) + kfree(usbvision->sbuf[i].data); + + usbvision->user--; + + if (PowerOnAtOpen) { + mod_timer(&usbvision->powerOffTimer, jiffies + USBVISION_POWEROFF_TIME); + usbvision->initialized = 0; + } + + up(&usbvision->lock); + + if (usbvision->remove_pending) { + info("%s: Final disconnect", __FUNCTION__); + usbvision_release(usbvision); + } + + PDEBUG(DBG_IO, "success"); + + + return 0; +} + + +/* + * usbvision_ioctl() + * + * This is part of Video 4 Linux API. The procedure handles ioctl() calls. + * + */ +static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); + + if (!USBVISION_IS_OPERATIONAL(usbvision)) + return -EFAULT; + + switch (cmd) { + case UVIOCSREG: + { + struct usbvision_reg *usbvision_reg = arg; + int errCode; + + errCode = usbvision_write_reg(usbvision, usbvision_reg->addr, usbvision_reg->value); + + if (errCode < 0) { + err("%s: UVIOCSREG failed: error %d", __FUNCTION__, errCode); + } + else { + PDEBUG(DBG_IOCTL, "UVIOCSREG addr=0x%02X, value=0x%02X", + usbvision_reg->addr, usbvision_reg->value); + errCode = 0; + } + return errCode; + } + case UVIOCGREG: + { + struct usbvision_reg *usbvision_reg = arg; + int errCode; + + errCode = usbvision_read_reg(usbvision, usbvision_reg->addr); + + if (errCode < 0) { + err("%s: UVIOCGREG failed: error %d", __FUNCTION__, errCode); + } + else { + usbvision_reg->value=(unsigned char)errCode; + PDEBUG(DBG_IOCTL, "UVIOCGREG addr=0x%02X, value=0x%02X", + usbvision_reg->addr, usbvision_reg->value); + errCode = 0; // No error + } + return errCode; + } + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *vc=arg; + *vc = usbvision->vcap; + PDEBUG(DBG_IOCTL, "VIDIOC_QUERYCAP"); + return 0; + } + case VIDIOC_ENUMINPUT: + { + struct v4l2_input *vi = arg; + int chan; + + if ((vi->index >= usbvision->video_inputs) || (vi->index < 0) ) + return -EINVAL; + if (usbvision->have_tuner) { + chan = vi->index; + } + else { + chan = vi->index + 1; //skip Television string + } + switch(chan) { + case 0: + if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) { + strcpy(vi->name, "White Video Input"); + } + else { + strcpy(vi->name, "Television"); + vi->type = V4L2_INPUT_TYPE_TUNER; + vi->audioset = 1; + vi->tuner = chan; + vi->std = V4L2_STD_PAL | V4L2_STD_NTSC | V4L2_STD_SECAM; + } + break; + case 1: + vi->type = V4L2_INPUT_TYPE_CAMERA; + if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) { + strcpy(vi->name, "Green Video Input"); + } + else { + strcpy(vi->name, "Composite Video Input"); + } + vi->std = V4L2_STD_PAL; + break; + case 2: + vi->type = V4L2_INPUT_TYPE_CAMERA; + if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) { + strcpy(vi->name, "Yellow Video Input"); + } + else { + strcpy(vi->name, "S-Video Input"); + } + vi->std = V4L2_STD_PAL; + break; + case 3: + vi->type = V4L2_INPUT_TYPE_CAMERA; + strcpy(vi->name, "Red Video Input"); + vi->std = V4L2_STD_PAL; + break; + } + PDEBUG(DBG_IOCTL, "VIDIOC_ENUMINPUT name=%s:%d tuners=%d type=%d norm=%x", vi->name, vi->index, vi->tuner,vi->type,(int)vi->std); + return 0; + } + case VIDIOC_ENUMSTD: + { + struct v4l2_standard *vs = arg; + switch(vs->index) { + case 0: + vs->id = V4L2_STD_PAL; + strcpy(vs->name,"PAL"); + vs->frameperiod.numerator = 1; + vs->frameperiod.denominator = 25; + vs->framelines = 625; + break; + case 1: + vs->id = V4L2_STD_NTSC; + strcpy(vs->name,"NTSC"); + vs->frameperiod.numerator = 1001; + vs->frameperiod.denominator = 30000; + vs->framelines = 525; + break; + case 2: + vs->id = V4L2_STD_SECAM; + strcpy(vs->name,"SECAM"); + vs->frameperiod.numerator = 1; + vs->frameperiod.denominator = 25; + vs->framelines = 625; + break; + default: + return -EINVAL; + } + return 0; + } + case VIDIOC_G_INPUT: + { + int *input = arg; + *input = usbvision->input.index; + return 0; + } + case VIDIOC_S_INPUT: + { + int *input = arg; + if ((*input >= usbvision->video_inputs) || (*input < 0) ) + return -EINVAL; + usbvision->input.index = *input; + + down(&usbvision->lock); + usbvision_muxsel(usbvision, usbvision->input.index, usbvision->input.std); + usbvision_set_input(usbvision); + usbvision_set_output(usbvision, usbvision->curwidth, usbvision->curheight); + up(&usbvision->lock); + return 0; + } + case VIDIOC_G_STD: + { + v4l2_std_id *std = arg; + *std = usbvision->input.std; + PDEBUG(DBG_IOCTL, "VIDIOC_G_STD std_id=%x", (unsigned)*std); + return 0; + } + case VIDIOC_S_STD: + { + v4l2_std_id *std = arg; + + down(&usbvision->lock); + usbvision_muxsel(usbvision, usbvision->input.index, *std); + usbvision_set_input(usbvision); + usbvision_set_output(usbvision, usbvision->curwidth, usbvision->curheight); + up(&usbvision->lock); + + usbvision->input.std = *std; + PDEBUG(DBG_IOCTL, "VIDIOC_S_STD std_id=%x", (unsigned)*std); + return 0; + } + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *vt = arg; + struct v4l2_tuner status; + + if (!usbvision->have_tuner || vt->index) // Only tuner 0 + return -EINVAL; + strcpy(vt->name, "Television"); + vt->type = V4L2_TUNER_ANALOG_TV; + vt->capability = V4L2_TUNER_CAP_NORM; + vt->rangelow = 0; + vt->rangehigh = ~0; + vt->audmode = V4L2_TUNER_MODE_MONO; + vt->rxsubchans = V4L2_TUNER_SUB_MONO; + call_i2c_clients(usbvision,VIDIOC_G_TUNER,&status); + vt->signal = status.signal; + + PDEBUG(DBG_IOCTL, "VIDIOC_G_TUNER"); + return 0; + } + case VIDIOC_S_TUNER: + { + struct v4l2_tuner *vt = arg; + + // Only no or one tuner for now + if (!usbvision->have_tuner || vt->index) + return -EINVAL; + // FIXME vt->audmode Radio mode (STEREO/MONO/...) + // vt->reserved Radio freq + // usbvision_muxsel(usbvision, vt->index, vt->mode); + PDEBUG(DBG_IOCTL, "VIDIOC_S_TUNER"); + return 0; + } + case VIDIOC_G_FREQUENCY: + { + struct v4l2_frequency *freq = arg; + freq->tuner = 0; // Only one tuner + freq->type = V4L2_TUNER_ANALOG_TV; + freq->frequency = usbvision->freq; + PDEBUG(DBG_IOCTL, "VIDIOC_G_FREQUENCY freq=0x%X", (unsigned)freq->frequency); + return 0; + } + case VIDIOC_S_FREQUENCY: + { + struct v4l2_frequency *freq = arg; + usbvision->freq = freq->frequency; + call_i2c_clients(usbvision, cmd, freq); + PDEBUG(DBG_IOCTL, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)freq->frequency); + return 0; + } + case VIDIOC_G_AUDIO: + { + struct v4l2_audio *v = arg; + memset(v,0, sizeof(v)); + strcpy(v->name, "TV"); + PDEBUG(DBG_IOCTL, "VIDIOC_G_AUDIO"); + // FIXME: no more processings ??? + return 0; + } + case VIDIOC_S_AUDIO: + { + struct v4l2_audio *v = arg; + if(v->index) { + return -EINVAL; + } + PDEBUG(DBG_IOCTL, "VIDIOC_S_AUDIO"); + // FIXME: void function ??? + return 0; + } + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + switch(qc->id) { + case V4L2_CID_BRIGHTNESS: + case V4L2_CID_HUE: + case V4L2_CID_SATURATION: + case V4L2_CID_CONTRAST: + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill_std(qc); + break; + default: + return -EINVAL; + } + return 0; + } + case VIDIOC_G_CTRL: + { + struct v4l2_control *ctrl = arg; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + ctrl->value = usbvision->brightness; + break; + case V4L2_CID_CONTRAST: + ctrl->value = usbvision->contrast; + break; + case V4L2_CID_SATURATION: + ctrl->value = usbvision->saturation; + break; + case V4L2_CID_HUE: + ctrl->value = usbvision->hue; + break; + case V4L2_CID_AUDIO_VOLUME: + /* ctrl->value = usbvision->volume; */ + break; + case V4L2_CID_AUDIO_MUTE: + ctrl->value = usbvision->AudioMute; + break; + default: + return -EINVAL; + } + PDEBUG(DBG_IOCTL, "VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value); + return 0; + } + case VIDIOC_S_CTRL: + { + struct v4l2_control *ctrl = arg; + PDEBUG(DBG_IOCTL, "VIDIOC_S_CTRL id=%x value=%x",ctrl->id,ctrl->value); + call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl); + return 0; + } + case VIDIOC_REQBUFS: + { + struct v4l2_requestbuffers *vr = arg; + // FIXME : normally we allocate the requested number of buffers. + // this driver allocates statically the buffers. + vr->count = 2; + if(vr->memory != V4L2_MEMORY_MMAP) + return -EINVAL; + return 0; + } + case VIDIOC_QUERYBUF: + { + struct v4l2_buffer *vb = arg; + struct usbvision_frame *frame; + + // FIXME : works only on VIDEO_CAPTURE MODE, MMAP. + if(vb->type != V4L2_CAP_VIDEO_CAPTURE) { + return -EINVAL; + } + if(vb->index>1) { + return -EINVAL; + } + vb->flags = 0; + frame = &usbvision->frame[vb->index]; + if(frame->grabstate == FrameState_Grabbing) + vb->flags |= V4L2_BUF_FLAG_QUEUED; + if(frame->grabstate >= FrameState_Done) + vb->flags |= V4L2_BUF_FLAG_DONE; + if(frame->grabstate == FrameState_Unused) + vb->flags |= V4L2_BUF_FLAG_MAPPED; + vb->memory = V4L2_MEMORY_MMAP; + if(vb->index == 0) { + vb->m.offset = 0; + } + else { + vb->m.offset = MAX_FRAME_SIZE; + } + vb->length = MAX_FRAME_SIZE; + vb->timestamp = usbvision->frame[vb->index].timestamp; + vb->sequence = usbvision->frame_num; + return 0; + } + case VIDIOC_QBUF: // VIDIOCMCAPTURE + VIDIOCSYNC + { + struct v4l2_buffer *vb = arg; + struct usbvision_frame *frame; + + // FIXME : works only on VIDEO_CAPTURE MODE, MMAP. + if(vb->type != V4L2_CAP_VIDEO_CAPTURE) { + return -EINVAL; + } + if(vb->index>1) { + return -EINVAL; + } + + frame = &usbvision->frame[vb->index]; + + if (frame->grabstate == FrameState_Grabbing) { + return -EBUSY; + } + + usbvision_set_output(usbvision, usbvision->curwidth, usbvision->curheight); + + /* Mark it as ready */ + frame->grabstate = FrameState_Ready; + vb->flags &= ~V4L2_BUF_FLAG_DONE; + + /* set v4l2_format index */ + frame->v4l2_format = usbvision->palette; + + return usbvision_new_frame(usbvision, vb->index); + } + case VIDIOC_DQBUF: + { + struct v4l2_buffer *vb = arg; + int errCode = 0; + + DECLARE_WAITQUEUE(wait, current); + // FIXME : not the proper way to get the last filled frame + vb->index=-1; + if(usbvision->curFrameNum != -1) vb->index=usbvision->curFrameNum; + else { + if(usbvision->frame[1].grabstate >= FrameState_Done) + vb->index = 1; + else if(usbvision->frame[0].grabstate >= FrameState_Done) + vb->index = 0; + // If no FRAME_DONE, look for a FRAME_GRABBING state. + // See if a frame is in process (grabbing), then use it. + if (vb->index == -1) { + if (usbvision->frame[1].grabstate == FrameState_Grabbing) + vb->index = 1; + else if (usbvision->frame[0].grabstate == FrameState_Grabbing) + vb->index = 0; + } + } + if (vb->index == -1) + return -EINVAL; + + PDEBUG(DBG_IOCTL, "VIDIOC_DQBUF frame=%d, grabstate=%d", + vb->index, usbvision->frame[vb->index].grabstate); + + switch (usbvision->frame[vb->index].grabstate) { + case FrameState_Unused: + errCode = -EINVAL; + break; + case FrameState_Grabbing: + add_wait_queue(&usbvision->frame[vb->index].wq, &wait); + current->state = TASK_INTERRUPTIBLE; + while (usbvision->frame[vb->index].grabstate == FrameState_Grabbing) { + schedule(); + if (signal_pending(current)) { + remove_wait_queue(&usbvision->frame[vb->index].wq, &wait); + current->state = TASK_RUNNING; + return -EINTR; + } + } + remove_wait_queue(&usbvision->frame[vb->index].wq, &wait); + current->state = TASK_RUNNING; + case FrameState_Ready: + case FrameState_Error: + case FrameState_Done: + errCode = (usbvision->frame[vb->index].grabstate == FrameState_Error) ? -EIO : 0; + vb->memory = V4L2_MEMORY_MMAP; + vb->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE; + vb->sequence = usbvision->frame[vb->index].sequence; + usbvision->frame[vb->index].grabstate = FrameState_Unused; + break; + } + + usbvision->frame[vb->index].grabstate = FrameState_Unused; + return errCode; + } + case VIDIOC_STREAMON: + { + int b=V4L2_BUF_TYPE_VIDEO_CAPTURE; + call_i2c_clients(usbvision,VIDIOC_STREAMON , &b); + return 0; + } + case VIDIOC_STREAMOFF: + { + int b=V4L2_BUF_TYPE_VIDEO_CAPTURE; + down(&usbvision->lock); + // Stop all video streamings + call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b); + usbvision->frame_num = -1; + usbvision->frame[0].grabstate = FrameState_Unused; + usbvision->frame[1].grabstate = FrameState_Unused; + up(&usbvision->lock); + return 0; + } + case VIDIOC_G_FBUF: + { + struct v4l2_framebuffer *vb = arg; + + if (dga) { + *vb = usbvision->vid_buf; + } + else { + memset(vb, 0, sizeof(vb)); //dga not supported, not used + } + PDEBUG(DBG_IOCTL, "VIDIOC_G_FBUF base=%p, width=%d, height=%d, pixelformat=%d, bpl=%d", + vb->base, vb->fmt.width, vb->fmt.height, vb->fmt.pixelformat,vb->fmt.bytesperline); + return 0; + } + case VIDIOC_S_FBUF: + { + struct v4l2_framebuffer *vb = arg; + int formatIdx; + + if (dga == 0) { + return -EINVAL; + } + + if(!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_ADMIN)) { + return -EPERM; + } + + PDEBUG(DBG_IOCTL, "VIDIOC_S_FBUF base=%p, width=%d, height=%d, pixelformat=%d, bpl=%d", + vb->base, vb->fmt.width, vb->fmt.height, vb->fmt.pixelformat,vb->fmt.bytesperline); + + for (formatIdx=0; formatIdx <= USBVISION_SUPPORTED_PALETTES; formatIdx++) { + if (formatIdx == USBVISION_SUPPORTED_PALETTES) { + return -EINVAL; // no matching video_format + } + if ((vb->fmt.pixelformat == usbvision_v4l2_format[formatIdx].format) && + (usbvision_v4l2_format[formatIdx].supported)) { + break; //found matching video_format + } + } + + if (vb->fmt.bytesperline<1) { + return -EINVAL; + } + if (usbvision->overlay) { + return -EBUSY; + } + down(&usbvision->lock); + if (usbvision->overlay_base) { + iounmap(usbvision->overlay_base); + usbvision->vid_buf_valid = 0; + } + usbvision->overlay_base = ioremap((ulong)vb->base, vb->fmt.height * vb->fmt.bytesperline); + if (usbvision->overlay_base) { + usbvision->vid_buf_valid = 1; + } + usbvision->vid_buf = *vb; + usbvision->overlay_frame.v4l2_format = usbvision_v4l2_format[formatIdx]; + up(&usbvision->lock); + return 0; + } + case VIDIOC_ENUM_FMT: + { + struct v4l2_fmtdesc *vfd = arg; + if ( (dga == 0) && + (vfd->type == V4L2_BUF_TYPE_VIDEO_OVERLAY) && + (usbvision->palette.format != V4L2_PIX_FMT_YVU420) && + (usbvision->palette.format != V4L2_PIX_FMT_YUV422P) ) { + return -EINVAL; + } + if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) { + return -EINVAL; + } + vfd->flags = 0; + strcpy(vfd->description,usbvision_v4l2_format[vfd->index].desc); + vfd->pixelformat = usbvision_v4l2_format[vfd->index].format; + return 0; + } + case VIDIOC_G_FMT: + { + struct v4l2_format *vf = arg; + + if ( (dga == 0) && + (vf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY) && + (usbvision->palette.format != V4L2_PIX_FMT_YVU420) && + (usbvision->palette.format != V4L2_PIX_FMT_YUV422P) ) { + return -EINVAL; + } + down(&usbvision->lock); + *vf = usbvision->vid_win; + up(&usbvision->lock); + PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT x=%d, y=%d, w=%d, h=%d, chroma=%x, clips=%d", + vf->fmt.win.w.left, vf->fmt.win.w.top, vf->fmt.win.w.width, vf->fmt.win.w.height, vf->fmt.win.chromakey, vf->fmt.win.clipcount); + return 0; + } + case VIDIOC_S_FMT: + { + struct v4l2_format *vf = arg; + struct v4l2_clip *vc=NULL; + int on,formatIdx; + + if ( (dga == 0) && + (vf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY) && + (usbvision->palette.format != V4L2_PIX_FMT_YVU420) && + (usbvision->palette.format != V4L2_PIX_FMT_YUV422P) ) { + return -EINVAL; + } + if(vf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY) { + if (vf->fmt.win.clipcount>256) { + return -EDOM; /* Too many clips! */ + } + // Do every clips. + vc = vmalloc(sizeof(struct v4l2_clip)*(vf->fmt.win.clipcount+4)); + if (vc == NULL) { + return -ENOMEM; + } + if (vf->fmt.win.clipcount && copy_from_user(vc,vf->fmt.win.clips,sizeof(struct v4l2_clip)*vf->fmt.win.clipcount)) { + return -EFAULT; + } + on = usbvision->overlay; // Save overlay state + if (on) { + usbvision_cap(usbvision, 0); + } + + // strange, it seems xawtv sometimes calls us with 0 + // width and/or height. Ignore these values + if (vf->fmt.win.w.left == 0) { + vf->fmt.win.w.left = usbvision->vid_win.fmt.win.w.left; + } + if (vf->fmt.win.w.top == 0) { + vf->fmt.win.w.top = usbvision->vid_win.fmt.win.w.top; + } + + // by now we are committed to the new data... + down(&usbvision->lock); + RESTRICT_TO_RANGE(vf->fmt.win.w.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH); + RESTRICT_TO_RANGE(vf->fmt.win.w.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT); + usbvision->vid_win = *vf; + usbvision->overlay_frame.width = vf->fmt.win.w.width; + usbvision->overlay_frame.height = vf->fmt.win.w.height; + usbvision_set_output(usbvision, vf->fmt.win.w.width, vf->fmt.win.w.height); + up(&usbvision->lock); + + // Impose display clips + if (vf->fmt.win.w.left+vf->fmt.win.w.width > (unsigned int)usbvision->vid_buf.fmt.width) { + usbvision_new_clip(vf, vc, usbvision->vid_buf.fmt.width-vf->fmt.win.w.left, 0, vf->fmt.win.w.width-1, vf->fmt.win.w.height-1); + } + if (vf->fmt.win.w.top+vf->fmt.win.w.height > (unsigned int)usbvision->vid_buf.fmt.height) { + usbvision_new_clip(vf, vc, 0, usbvision->vid_buf.fmt.height-vf->fmt.win.w.top, vf->fmt.win.w.width-1, vf->fmt.win.w.height-1); + } + + // built the requested clipping zones + usbvision_built_overlay(usbvision, vf->fmt.win.clipcount, vc); + vfree(vc); + + // restore overlay state + if (on) { + usbvision_cap(usbvision, 1); + } + usbvision->vid_win_valid = 1; + PDEBUG(DBG_IOCTL, "VIDIOC_S_FMT overlay x=%d, y=%d, w=%d, h=%d, chroma=%x, clips=%d", + vf->fmt.win.w.left, vf->fmt.win.w.top, vf->fmt.win.w.width, vf->fmt.win.w.height, vf->fmt.win.chromakey, vf->fmt.win.clipcount); + } + else { + /* Find requested format in available ones */ + for(formatIdx=0;formatIdxfmt.pix.pixelformat == usbvision_v4l2_format[formatIdx].format) { + usbvision->palette = usbvision_v4l2_format[formatIdx]; + break; + } + } + /* robustness */ + if(formatIdx == USBVISION_SUPPORTED_PALETTES) { + return -EINVAL; + } + usbvision->vid_win.fmt.pix.pixelformat = vf->fmt.pix.pixelformat; + usbvision->vid_win.fmt.pix.width = vf->fmt.pix.width; //Image width in pixels. + usbvision->vid_win.fmt.pix.height = vf->fmt.pix.height; // Image height in pixels. + + // by now we are committed to the new data... + down(&usbvision->lock); + RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH); + RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT); + usbvision->vid_win = *vf; + usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height); + up(&usbvision->lock); + + usbvision->vid_win_valid = 1; + PDEBUG(DBG_IOCTL, "VIDIOC_S_FMT grabdisplay w=%d, h=%d, ", + vf->fmt.pix.width, vf->fmt.pix.height); + } + return 0; + } + case VIDIOC_OVERLAY: + { + int *v = arg; + + if ( (dga == 0) && + (usbvision->palette.format != V4L2_PIX_FMT_YVU420) && + (usbvision->palette.format != V4L2_PIX_FMT_YUV422P) ) { + PDEBUG(DBG_IOCTL, "VIDIOC_OVERLAY DGA disabled"); + return -EINVAL; + } + + if (*v == 0) { + usbvision_cap(usbvision, 0); + } + else { + // are VIDIOCSFBUF and VIDIOCSWIN done? + if ((usbvision->vid_buf_valid == 0) || (usbvision->vid_win_valid == 0)) { + PDEBUG(DBG_IOCTL, "VIDIOC_OVERLAY vid_buf_valid %d; vid_win_valid %d", + usbvision->vid_buf_valid, usbvision->vid_win_valid); + return -EINVAL; + } + usbvision_cap(usbvision, 1); + } + PDEBUG(DBG_IOCTL, "VIDIOC_OVERLAY %s", (*v)?"on":"off"); + return 0; + } + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static int usbvision_v4l2_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return video_usercopy(inode, file, cmd, arg, usbvision_v4l2_do_ioctl); +} + + +static ssize_t usbvision_v4l2_read(struct file *file, char *buf, + size_t count, loff_t *ppos) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); + int noblock = file->f_flags & O_NONBLOCK; + + int frmx = -1; + int rc = 0; + struct usbvision_frame *frame; + + PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __FUNCTION__, (unsigned long)count, noblock); + + if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL)) + return -EFAULT; + + down(&usbvision->lock); + //code for testing compression + if (usbvision->isocMode == ISOC_MODE_COMPRESS) { + usbvision->frame[0].v4l2_format = usbvision_v4l2_format[0]; //V4L2_PIX_FMT_GREY; + usbvision->frame[1].v4l2_format = usbvision_v4l2_format[0]; // V4L2_PIX_FMT_GREY; + } + + // See if a frame is completed, then use it. + if (usbvision->frame[0].grabstate >= FrameState_Done) // _Done or _Error + frmx = 0; + else if (usbvision->frame[1].grabstate >= FrameState_Done)// _Done or _Error + frmx = 1; + + if (noblock && (frmx == -1)) { + count = -EAGAIN; + goto usbvision_v4l2_read_done; + } + + // If no FRAME_DONE, look for a FRAME_GRABBING state. + // See if a frame is in process (grabbing), then use it. + if (frmx == -1) { + if (usbvision->frame[0].grabstate == FrameState_Grabbing) + frmx = 0; + else if (usbvision->frame[1].grabstate == FrameState_Grabbing) + frmx = 1; + } + + // If no frame is active, start one. + if (frmx == -1) + usbvision_new_frame(usbvision, frmx = 0); + + frame = &usbvision->frame[frmx]; + + restart: + if (!USBVISION_IS_OPERATIONAL(usbvision)) { + count = -EIO; + goto usbvision_v4l2_read_done; + } + PDEBUG(DBG_IO, "Waiting frame grabbing"); + rc = wait_event_interruptible(frame->wq, (frame->grabstate == FrameState_Done) || + (frame->grabstate == FrameState_Error)); + if (rc) { + goto usbvision_v4l2_read_done; + } + + if (frame->grabstate == FrameState_Error) { + frame->bytes_read = 0; + if (usbvision_new_frame(usbvision, frmx)) { + err("%s: usbvision_new_frame() failed", __FUNCTION__); + } + goto restart; + } + + PDEBUG(DBG_IO, "%s: frmx=%d, bytes_read=%ld, scanlength=%ld", __FUNCTION__, + frmx, frame->bytes_read, frame->scanlength); + + /* copy bytes to user space; we allow for partials reads */ + if ((count + frame->bytes_read) > (unsigned long)frame->scanlength) + count = frame->scanlength - frame->bytes_read; + + if (copy_to_user(buf, frame->data + frame->bytes_read, count)) { + count = -EFAULT; + goto usbvision_v4l2_read_done; + } + + frame->bytes_read += count; + PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld", __FUNCTION__, + (unsigned long)count, frame->bytes_read); + + if (frame->bytes_read >= frame->scanlength) {// All data has been read + frame->bytes_read = 0; + + /* Mark it as available to be used again. */ + usbvision->frame[frmx].grabstate = FrameState_Unused; + if (usbvision_new_frame(usbvision, frmx ? 0 : 1)) + err("%s: usbvision_new_frame() failed", __FUNCTION__); + } + +usbvision_v4l2_read_done: + up(&usbvision->lock); + return count; +} + +static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); + unsigned long start = vma->vm_start; + unsigned long size = vma->vm_end-vma->vm_start; + + unsigned long page, pos; + + if (!USBVISION_IS_OPERATIONAL(usbvision)) + return -EFAULT; + + if (size > (((USBVISION_NUMFRAMES * usbvision->max_frame_size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) + return -EINVAL; + + pos = (unsigned long) usbvision->fbuf; + while (size > 0) { + +// Really ugly.... + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10) //Compatibility for 2.6.10+ kernels + page = vmalloc_to_pfn((void *)pos); + if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { + return -EAGAIN; + } + #else //Compatibility for 2.6.0 - 2.6.9 kernels + page = usbvision_kvirt_to_pa(pos); + if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { + return -EAGAIN; + } + #endif + start += PAGE_SIZE; + pos += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + + return 0; +} + + +/* + * Here comes the stuff for radio on usbvision based devices + * + */ +static int usbvision_radio_open(struct inode *inode, struct file *file) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); + struct v4l2_frequency freq; + int errCode = 0; + + PDEBUG(DBG_RIO, "%s:", __FUNCTION__); + + down(&usbvision->lock); + + if (usbvision->user) { + err("%s: Someone tried to open an already opened USBVision Radio!", __FUNCTION__); + errCode = -EBUSY; + } + else { + if(PowerOnAtOpen) { + if (timer_pending(&usbvision->powerOffTimer)) { + del_timer(&usbvision->powerOffTimer); + } + if (usbvision->power == 0) { + usbvision_power_on(usbvision); + usbvision_init_i2c(usbvision); + } + } + + // If so far no errors then we shall start the radio + usbvision->radio = 1; + call_i2c_clients(usbvision,AUDC_SET_RADIO,&usbvision->tuner_type); + freq.frequency = 1517; //SWR3 @ 94.8MHz + call_i2c_clients(usbvision, VIDIOC_S_FREQUENCY, &freq); + usbvision_set_audio(usbvision, USBVISION_AUDIO_RADIO); + usbvision->user++; + } + + if (errCode) { + if (PowerOnAtOpen) { + usbvision_i2c_usb_del_bus(&usbvision->i2c_adap); + usbvision_power_off(usbvision); + usbvision->initialized = 0; + } + } + up(&usbvision->lock); + return errCode; +} + + +static int usbvision_radio_close(struct inode *inode, struct file *file) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); + int errCode = 0; + + PDEBUG(DBG_RIO, ""); + + down(&usbvision->lock); + + usbvision_audio_off(usbvision); + usbvision->radio=0; + usbvision->user--; + + if (PowerOnAtOpen) { + mod_timer(&usbvision->powerOffTimer, jiffies + USBVISION_POWEROFF_TIME); + usbvision->initialized = 0; + } + + up(&usbvision->lock); + + if (usbvision->remove_pending) { + info("%s: Final disconnect", __FUNCTION__); + usbvision_release(usbvision); + } + + + PDEBUG(DBG_RIO, "success"); + + return errCode; +} + +static int usbvision_do_radio_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); + + if (!USBVISION_IS_OPERATIONAL(usbvision)) + return -EIO; + + switch (cmd) { + /*************************** + * V4L2 IOCTLs * + ***************************/ + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *vc=arg; + memset(vc, 0, sizeof(struct v4l2_capability)); + strcpy(vc->driver,"usbvision radio"); + strcpy(vc->card,usbvision->vcap.card); + strcpy(vc->bus_info,"usb"); + vc->version = USBVISION_DRIVER_VERSION; /* version */ + vc->capabilities = V4L2_CAP_TUNER; /* capabilities */ + PDEBUG(DBG_RIO, "%s: VIDIOC_QUERYCAP", __FUNCTION__); + return 0; + } + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + switch(qc->id) + { + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill_std(qc); + break; + default: + return -EINVAL; + } + return 0; + } + case VIDIOC_G_CTRL: + { + struct v4l2_control *ctrl = arg; + PDEBUG(DBG_IOCTL, "VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value); + switch(ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: + /* ctrl->value = usbvision->volume; */ + break; + case V4L2_CID_AUDIO_MUTE: + ctrl->value = usbvision->AudioMute; + break; + default: + return -EINVAL; + } + return 0; + } + case VIDIOC_S_CTRL: + { + struct v4l2_control *ctrl = arg; + call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl); + + PDEBUG(DBG_RIO, "%s: VIDIOC_S_CTRL id=%x value=%x", __FUNCTION__,ctrl->id,ctrl->value); + return 0; + } + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *vt = arg; + + if (!usbvision->have_tuner || vt->index) // Only tuner 0 + return -EINVAL; + strcpy(vt->name, "Radio"); + vt->type = V4L2_TUNER_RADIO; + vt->capability = V4L2_TUNER_CAP_STEREO; + // japan: 76.0 MHz - 89.9 MHz + // western europe: 87.5 MHz - 108.0 MHz + // russia: 65.0 MHz - 108.0 MHz + vt->rangelow = (int)(65*16);; + vt->rangehigh = (int)(108*16); + vt->audmode = V4L2_TUNER_MODE_STEREO; + vt->rxsubchans = V4L2_TUNER_SUB_STEREO; + call_i2c_clients(usbvision,VIDIOC_G_TUNER,&vt); + + PDEBUG(DBG_RIO, "%s: VIDIOC_G_TUNER signal=%d", __FUNCTION__, vt->signal); + return 0; + } + case VIDIOC_S_TUNER: + { + struct v4l2_tuner *vt = arg; + + // Only channel 0 has a tuner + if((vt->index) || (usbvision->channel)) { + return -EINVAL; + } + PDEBUG(DBG_RIO, "%s: VIDIOC_S_TUNER", __FUNCTION__); + return 0; + } + case VIDIOC_G_AUDIO: + { + struct v4l2_audio *va = arg; + memset(va,0, sizeof(va)); + va->capability = V4L2_AUDCAP_STEREO; + strcpy(va->name, "Radio"); + PDEBUG(DBG_IOCTL, "VIDIOC_G_AUDIO"); + return 0; + } + case VIDIOC_S_AUDIO: + { + struct v4l2_audio *v = arg; + if(v->index) { + return -EINVAL; + } + PDEBUG(DBG_IOCTL, "VIDIOC_S_AUDIO"); + // FIXME: void function ??? + return 0; + } + case VIDIOC_G_FREQUENCY: + { + struct v4l2_frequency *freq = arg; + freq->tuner = 0; // Only one tuner + freq->type = V4L2_TUNER_RADIO; + freq->frequency = usbvision->freq; + PDEBUG(DBG_RIO, "VIDIOC_G_FREQUENCY freq=0x%X", (unsigned)freq->frequency); + return 0; + } + case VIDIOC_S_FREQUENCY: + { + struct v4l2_frequency *freq = arg; + usbvision->freq = freq->frequency; + call_i2c_clients(usbvision, cmd, freq); + PDEBUG(DBG_RIO, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)freq->frequency); + return 0; + } + + /*************************** + * V4L1 IOCTLs * + ***************************/ + case VIDIOCGCAP: + { + struct video_capability *vc = arg; + + memset(vc, 0, sizeof(struct video_capability)); + strcpy(vc->name,usbvision->vcap.card); + vc->type = VID_TYPE_TUNER; + vc->channels = 1; + vc->audios = 1; + PDEBUG(DBG_RIO, "%s: VIDIOCGCAP", __FUNCTION__); + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner *vt = arg; + + if((vt->tuner) || (usbvision->channel)) { /* Only tuner 0 */ + return -EINVAL; + } + strcpy(vt->name, "Radio"); + // japan: 76.0 MHz - 89.9 MHz + // western europe: 87.5 MHz - 108.0 MHz + // russia: 65.0 MHz - 108.0 MHz + vt->rangelow=(int)(65*16); + vt->rangehigh=(int)(108*16); + vt->flags= 0; + vt->mode = 0; + call_i2c_clients(usbvision,cmd,vt); + PDEBUG(DBG_RIO, "%s: VIDIOCGTUNER signal=%d", __FUNCTION__, vt->signal); + return 0; + } + case VIDIOCSTUNER: + { + struct video_tuner *vt = arg; + + // Only channel 0 has a tuner + if((vt->tuner) || (usbvision->channel)) { + return -EINVAL; + } + PDEBUG(DBG_RIO, "%s: VIDIOCSTUNER", __FUNCTION__); + return 0; + } + case VIDIOCGAUDIO: + { + struct video_audio *va = arg; + memset(va,0, sizeof(struct video_audio)); + call_i2c_clients(usbvision, cmd, va); + va->flags|=VIDEO_AUDIO_MUTABLE; + va->volume=1; + va->step=1; + strcpy(va->name, "Radio"); + PDEBUG(DBG_RIO, "%s: VIDIOCGAUDIO", __FUNCTION__); + return 0; + } + case VIDIOCSAUDIO: + { + struct video_audio *va = arg; + if(va->audio) { + return -EINVAL; + } + + if(va->flags & VIDEO_AUDIO_MUTE) { + if (usbvision_audio_mute(usbvision)) { + return -EFAULT; + } + } + else { + if (usbvision_audio_on(usbvision)) { + return -EFAULT; + } + } + PDEBUG(DBG_RIO, "%s: VIDIOCSAUDIO flags=0x%x)", __FUNCTION__, va->flags); + return 0; + } + case VIDIOCGFREQ: + { + unsigned long *freq = arg; + + *freq = usbvision->freq; + PDEBUG(DBG_RIO, "%s: VIDIOCGFREQ freq = %ld00 kHz", __FUNCTION__, (*freq * 10)>>4); + return 0; + } + case VIDIOCSFREQ: + { + unsigned long *freq = arg; + + usbvision->freq = *freq; + call_i2c_clients(usbvision, cmd, freq); + PDEBUG(DBG_RIO, "%s: VIDIOCSFREQ freq = %ld00 kHz", __FUNCTION__, (*freq * 10)>>4); + return 0; + } + default: + { + PDEBUG(DBG_RIO, "%s: Unknown command %x", __FUNCTION__, cmd); + return -ENOIOCTLCMD; + } + } + return 0; +} + + +static int usbvision_radio_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return video_usercopy(inode, file, cmd, arg, usbvision_do_radio_ioctl); +} + + +/* + * Here comes the stuff for vbi on usbvision based devices + * + */ +static int usbvision_vbi_open(struct inode *inode, struct file *file) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); + unsigned long freq; + int errCode = 0; + + PDEBUG(DBG_RIO, "%s:", __FUNCTION__); + + down(&usbvision->lock); + + if (usbvision->user) { + err("%s: Someone tried to open an already opened USBVision VBI!", __FUNCTION__); + errCode = -EBUSY; + } + else { + if(PowerOnAtOpen) { + if (timer_pending(&usbvision->powerOffTimer)) { + del_timer(&usbvision->powerOffTimer); + } + if (usbvision->power == 0) { + usbvision_power_on(usbvision); + usbvision_init_i2c(usbvision); + } + } + + // If so far no errors then we shall start the vbi device + //usbvision->vbi = 1; + call_i2c_clients(usbvision,AUDC_SET_RADIO,&usbvision->tuner_type); + freq = 1517; //SWR3 @ 94.8MHz + call_i2c_clients(usbvision, VIDIOCSFREQ, &freq); + usbvision_set_audio(usbvision, USBVISION_AUDIO_RADIO); + usbvision->user++; + } + + if (errCode) { + if (PowerOnAtOpen) { + usbvision_i2c_usb_del_bus(&usbvision->i2c_adap); + usbvision_power_off(usbvision); + usbvision->initialized = 0; + } + } + up(&usbvision->lock); + return errCode; +} + +static int usbvision_vbi_close(struct inode *inode, struct file *file) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); + int errCode = 0; + + PDEBUG(DBG_RIO, ""); + + down(&usbvision->lock); + + usbvision_audio_off(usbvision); + usbvision->vbi=0; + usbvision->user--; + + if (PowerOnAtOpen) { + mod_timer(&usbvision->powerOffTimer, jiffies + USBVISION_POWEROFF_TIME); + usbvision->initialized = 0; + } + + up(&usbvision->lock); + + if (usbvision->remove_pending) { + info("%s: Final disconnect", __FUNCTION__); + usbvision_release(usbvision); + } + + + PDEBUG(DBG_RIO, "success"); + + return errCode; +} + +static int usbvision_do_vbi_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); + + if (!USBVISION_IS_OPERATIONAL(usbvision)) + return -EIO; + + switch (cmd) { + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *vc=arg; + memset(vc, 0, sizeof(struct v4l2_capability)); + strcpy(vc->driver,"usbvision vbi"); + strcpy(vc->card,usbvision->vcap.card); + strcpy(vc->bus_info,"usb"); + vc->version = USBVISION_DRIVER_VERSION; /* version */ + vc->capabilities = V4L2_CAP_VBI_CAPTURE; /* capabilities */ + PDEBUG(DBG_RIO, "%s: VIDIOC_QUERYCAP", __FUNCTION__); + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner *vt = arg; + + if((vt->tuner) || (usbvision->channel)) { /* Only tuner 0 */ + return -EINVAL; + } + strcpy(vt->name, "vbi"); + // japan: 76.0 MHz - 89.9 MHz + // western europe: 87.5 MHz - 108.0 MHz + // russia: 65.0 MHz - 108.0 MHz + vt->rangelow=(int)(65*16); + vt->rangehigh=(int)(108*16); + vt->flags= 0; + vt->mode = 0; + call_i2c_clients(usbvision,cmd,vt); + PDEBUG(DBG_RIO, "%s: VIDIOCGTUNER signal=%d", __FUNCTION__, vt->signal); + return 0; + } + case VIDIOCSTUNER: + { + struct video_tuner *vt = arg; + + // Only channel 0 has a tuner + if((vt->tuner) || (usbvision->channel)) { + return -EINVAL; + } + PDEBUG(DBG_RIO, "%s: VIDIOCSTUNER", __FUNCTION__); + return 0; + } + case VIDIOCGAUDIO: + { + struct video_audio *va = arg; + memset(va,0, sizeof(struct video_audio)); + call_i2c_clients(usbvision, cmd, va); + va->flags|=VIDEO_AUDIO_MUTABLE; + va->volume=1; + va->step=1; + strcpy(va->name, "vbi"); + PDEBUG(DBG_RIO, "%s: VIDIOCGAUDIO", __FUNCTION__); + return 0; + } + case VIDIOCSAUDIO: + { + struct video_audio *va = arg; + if(va->audio) { + return -EINVAL; + } + + if(va->flags & VIDEO_AUDIO_MUTE) { + if (usbvision_audio_mute(usbvision)) { + return -EFAULT; + } + } + else { + if (usbvision_audio_on(usbvision)) { + return -EFAULT; + } + } + PDEBUG(DBG_RIO, "%s: VIDIOCSAUDIO flags=0x%x)", __FUNCTION__, va->flags); + return 0; + } + case VIDIOCGFREQ: + { + unsigned long *freq = arg; + + *freq = usbvision->freq; + PDEBUG(DBG_RIO, "%s: VIDIOCGFREQ freq = %ld00 kHz", __FUNCTION__, (*freq * 10)>>4); + return 0; + } + case VIDIOCSFREQ: + { + unsigned long *freq = arg; + + usbvision->freq = *freq; + call_i2c_clients(usbvision, cmd, freq); + PDEBUG(DBG_RIO, "%s: VIDIOCSFREQ freq = %ld00 kHz", __FUNCTION__, (*freq * 10)>>4); + return 0; + } + default: + { + PDEBUG(DBG_RIO, "%s: Unknown command %d", __FUNCTION__, cmd); + return -ENOIOCTLCMD; + } + } + return 0; +} + +static int usbvision_vbi_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return video_usercopy(inode, file, cmd, arg, usbvision_do_vbi_ioctl); +} + + + +static void usbvision_configure_video(struct usb_usbvision *usbvision) +{ + int model; + + if (usbvision == NULL) + return; + + model = usbvision->DevModel; + + RESTRICT_TO_RANGE(init_brightness, 0, 255); + RESTRICT_TO_RANGE(init_contrast, 0, 255); + RESTRICT_TO_RANGE(init_saturation, 0, 255); + RESTRICT_TO_RANGE(init_hue, 0, 255); + + usbvision->saturation = init_saturation << 8; + usbvision->hue = init_hue << 8; + usbvision->brightness = init_brightness << 8; + usbvision->contrast = init_contrast << 8; + usbvision->depth = 24; + usbvision->palette = usbvision_v4l2_format[2]; // V4L2_PIX_FMT_RGB24; + + if (usbvision_device_data[usbvision->DevModel].Vin_Reg2 >= 0) { + usbvision->Vin_Reg2_Preset = usbvision_device_data[usbvision->DevModel].Vin_Reg2 & 0xff; + } else { + usbvision->Vin_Reg2_Preset = 0; + } + + memset(&usbvision->vcap, 0, sizeof(usbvision->vcap)); + strcpy(usbvision->vcap.driver, "USBVision"); + usbvision->vcap.capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + (dga ? (V4L2_FBUF_CAP_LIST_CLIPPING | V4L2_CAP_VIDEO_OVERLAY) : 0) | + (usbvision->have_tuner ? V4L2_CAP_TUNER : 0); + usbvision->vcap.version = USBVISION_DRIVER_VERSION; /* version */ + + usbvision->video_inputs = usbvision_device_data[model].VideoChannels; + + memset(&usbvision->input, 0, sizeof(usbvision->input)); + usbvision->input.tuner = 0; + usbvision->input.type = V4L2_INPUT_TYPE_TUNER|VIDEO_TYPE_CAMERA; + usbvision->input.std = usbvision_device_data[model].VideoNorm; + + /* This should be here to make i2c clients to be able to register */ + usbvision_audio_off(usbvision); //first switch off audio + if (!PowerOnAtOpen) { + usbvision_power_on(usbvision); //and then power up the noisy tuner + usbvision_init_i2c(usbvision); + } +} + +// +// Video registration stuff +// + +// Video template +static struct file_operations usbvision_fops = { + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31) + .owner = THIS_MODULE, + #endif + .open = usbvision_v4l2_open, + .release = usbvision_v4l2_close, + .read = usbvision_v4l2_read, + .mmap = usbvision_v4l2_mmap, + .ioctl = usbvision_v4l2_ioctl, + .llseek = no_llseek, +}; +static struct video_device usbvision_video_template = { + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31) + .owner = THIS_MODULE, + #endif + .type = VID_TYPE_TUNER | VID_TYPE_CAPTURE, + .hardware = VID_HARDWARE_USBVISION, + .fops = &usbvision_fops, + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + .name = "usbvision-video", + .release = video_device_release, + #endif + .minor = -1, +}; + + +// Radio template +static struct file_operations usbvision_radio_fops = { + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31) + .owner = THIS_MODULE, + #endif + .open = usbvision_radio_open, + .release = usbvision_radio_close, + .ioctl = usbvision_radio_ioctl, + .llseek = no_llseek, +}; + +static struct video_device usbvision_radio_template= +{ + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31) + .owner = THIS_MODULE, + #endif + .type = VID_TYPE_TUNER, + .hardware = VID_HARDWARE_USBVISION, + .fops = &usbvision_radio_fops, + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + .release = video_device_release, + .name = "usbvision-radio", + #endif + .minor = -1, +}; + + +// vbi template +static struct file_operations usbvision_vbi_fops = { + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31) + .owner = THIS_MODULE, + #endif + .open = usbvision_vbi_open, + .release = usbvision_vbi_close, + .ioctl = usbvision_vbi_ioctl, + .llseek = no_llseek, +}; + +static struct video_device usbvision_vbi_template= +{ + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31) + .owner = THIS_MODULE, + #endif + .type = VID_TYPE_TUNER, + .hardware = VID_HARDWARE_USBVISION, + .fops = &usbvision_vbi_fops, + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + .release = video_device_release, + .name = "usbvision-vbi", + #endif + .minor = -1, +}; + + +static struct video_device *usbvision_vdev_init(struct usb_usbvision *usbvision, + struct video_device *vdev_template, + char *name) +{ + struct usb_device *usb_dev = usbvision->dev; + struct video_device *vdev; + + if (usb_dev == NULL) { + err("%s: usbvision->dev is not set", __FUNCTION__); + return NULL; + } + + vdev = video_device_alloc(); + if (NULL == vdev) { + return NULL; + } + *vdev = *vdev_template; +// vdev->minor = -1; + vdev->dev = &usb_dev->dev; + snprintf(vdev->name, sizeof(vdev->name), "%s", name); + video_set_drvdata(vdev, usbvision); + return vdev; +} + +// unregister video4linux devices +static void usbvision_unregister_video(struct usb_usbvision *usbvision) +{ + // vbi Device: + if (usbvision->vbi) { + PDEBUG(DBG_PROBE, "unregister /dev/vbi%d [v4l2]", usbvision->vbi->minor & 0x1f); + if (usbvision->vbi->minor != -1) { + video_unregister_device(usbvision->vbi); + } + else { + video_device_release(usbvision->vbi); + } + usbvision->vbi = NULL; + } + + // Radio Device: + if (usbvision->rdev) { + PDEBUG(DBG_PROBE, "unregister /dev/radio%d [v4l2]", usbvision->rdev->minor & 0x1f); + if (usbvision->rdev->minor != -1) { + video_unregister_device(usbvision->rdev); + } + else { + video_device_release(usbvision->rdev); + } + usbvision->rdev = NULL; + } + + // Video Device: + if (usbvision->vdev) { + PDEBUG(DBG_PROBE, "unregister /dev/video%d [v4l2]", usbvision->vdev->minor & 0x1f); + if (usbvision->vdev->minor != -1) { + video_unregister_device(usbvision->vdev); + } + else { + video_device_release(usbvision->vdev); + } + usbvision->vdev = NULL; + } +} + +// register video4linux devices +static int __devinit usbvision_register_video(struct usb_usbvision *usbvision) +{ + // Video Device: + usbvision->vdev = usbvision_vdev_init(usbvision, &usbvision_video_template, "USBVision Video"); + if (usbvision->vdev == NULL) { + goto err_exit; + } + if (video_register_device(usbvision->vdev, VFL_TYPE_GRABBER, video_nr)<0) { + goto err_exit; + } + info("USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]", usbvision->nr,usbvision->vdev->minor & 0x1f); + + // Radio Device: + if (usbvision_device_data[usbvision->DevModel].Radio) { + // usbvision has radio + usbvision->rdev = usbvision_vdev_init(usbvision, &usbvision_radio_template, "USBVision Radio"); + if (usbvision->rdev == NULL) { + goto err_exit; + } + if (video_register_device(usbvision->rdev, VFL_TYPE_RADIO, radio_nr)<0) { + goto err_exit; + } + info("USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]", usbvision->nr, usbvision->rdev->minor & 0x1f); + } + // vbi Device: + if (usbvision_device_data[usbvision->DevModel].vbi) { + usbvision->vbi = usbvision_vdev_init(usbvision, &usbvision_vbi_template, "USBVision VBI"); + if (usbvision->vdev == NULL) { + goto err_exit; + } + if (video_register_device(usbvision->vbi, VFL_TYPE_VBI, vbi_nr)<0) { + goto err_exit; + } + info("USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)", usbvision->nr,usbvision->vbi->minor & 0x1f); + } + // all done + return 0; + + err_exit: + err("USBVision[%d]: video_register_device() failed", usbvision->nr); + usbvision_unregister_video(usbvision); + return -1; +} + +/* + * usbvision_alloc() + * + * This code allocates the struct usb_usbvision. It is filled with default values. + * + * Returns NULL on error, a pointer to usb_usbvision else. + * + */ +static struct usb_usbvision *usbvision_alloc(struct usb_device *dev) +{ + struct usb_usbvision *usbvision; + int FrameIdx; + + if ((usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL)) == NULL) { + goto err_exit; + } + + usbvision->dev = dev; + + for (FrameIdx = 0; FrameIdx < USBVISION_NUMFRAMES; FrameIdx++) { + init_waitqueue_head(&usbvision->frame[FrameIdx].wq); + } + init_waitqueue_head(&usbvision->overlay_frame.wq); + init_MUTEX(&usbvision->lock); /* to 1 == available */ + + // prepare control urb for control messages during interrupts + usbvision->ctrlUrb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL); + if (usbvision->ctrlUrb == NULL) { + goto err_exit; + } + init_waitqueue_head(&usbvision->ctrlUrb_wq); + init_MUTEX(&usbvision->ctrlUrbLock); + + init_timer(&usbvision->powerOffTimer); + usbvision->powerOffTimer.data = (long) usbvision; + usbvision->powerOffTimer.function = usbvision_powerOffTimer; + + return usbvision; + +err_exit: + if (usbvision && usbvision->ctrlUrb) { + usb_free_urb(usbvision->ctrlUrb); + } + if (usbvision) { + kfree(usbvision); + } + return NULL; +} + +/* + * usbvision_release() + * + * This code does final release of struct usb_usbvision. This happens + * after the device is disconnected -and- all clients closed their files. + * + */ +static void usbvision_release(struct usb_usbvision *usbvision) +{ + PDEBUG(DBG_PROBE, ""); + + down(&usbvision->lock); + + if (timer_pending(&usbvision->powerOffTimer)) { + del_timer(&usbvision->powerOffTimer); + } + + usbvision->usbvision_used = 0; + usbvision->initialized = 0; + + up(&usbvision->lock); + + usbvision_remove_sysfs(usbvision->vdev); + usbvision_unregister_video(usbvision); + if(dga) { + if (usbvision->overlay_base) { + iounmap(usbvision->overlay_base); + } + } + + if (usbvision->ctrlUrb) { + usb_free_urb(usbvision->ctrlUrb); + } + + kfree(usbvision); + + PDEBUG(DBG_PROBE, "success"); +} + + +/* + * usbvision_probe() + * + * This procedure queries device descriptor and accepts the interface + * if it looks like USBVISION video device + * + */ +static int __devinit usbvision_probe(struct usb_interface *intf, const struct usb_device_id *devid) +{ + struct usb_device *dev = interface_to_usbdev(intf); + __u8 ifnum = intf->altsetting->desc.bInterfaceNumber; + const struct usb_host_interface *interface; + struct usb_usbvision *usbvision = NULL; + const struct usb_endpoint_descriptor *endpoint; + int model; + + PDEBUG(DBG_PROBE, "VID=%#04x, PID=%#04x, ifnum=%u", + dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum); + + /* Is it an USBVISION video dev? */ + model = 0; + for(model = 0; usbvision_device_data[model].idVendor; model++) { + if (le16_to_cpu(dev->descriptor.idVendor) != usbvision_device_data[model].idVendor) { + continue; + } + if (le16_to_cpu(dev->descriptor.idProduct) != usbvision_device_data[model].idProduct) { + continue; + } + + info("%s: %s found", __FUNCTION__, usbvision_device_data[model].ModelString); + break; + } + + if (usbvision_device_data[model].idVendor == 0) { + return -ENODEV; //no matching device + } + if (usbvision_device_data[model].Interface >= 0) { + interface = &dev->actconfig->interface[usbvision_device_data[model].Interface]->altsetting[0]; + } + else { + interface = &dev->actconfig->interface[ifnum]->altsetting[0]; + } + endpoint = &interface->endpoint[1].desc; + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC) { + err("%s: interface %d. has non-ISO endpoint!", __FUNCTION__, ifnum); + err("%s: Endpoint attribures %d", __FUNCTION__, endpoint->bmAttributes); + return -ENODEV; + } + if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) { + err("%s: interface %d. has ISO OUT endpoint!", __FUNCTION__, ifnum); + return -ENODEV; + } + + usb_get_dev(dev); + + if ((usbvision = usbvision_alloc(dev)) == NULL) { + err("%s: couldn't allocate USBVision struct", __FUNCTION__); + return -ENOMEM; + } + if (dev->descriptor.bNumConfigurations > 1) { + usbvision->bridgeType = BRIDGE_NT1004; + } + else if (usbvision_device_data[model].ModelString == "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)") { + usbvision->bridgeType = BRIDGE_NT1005; + } + else { + usbvision->bridgeType = BRIDGE_NT1003; + } + PDEBUG(DBG_PROBE, "bridgeType %d", usbvision->bridgeType); + + down(&usbvision->lock); + + usbvision->nr = usbvision_nr++; + + usbvision->have_tuner = usbvision_device_data[model].Tuner; + if (usbvision->have_tuner) { + usbvision->tuner_type = usbvision_device_data[model].TunerType; + } + + usbvision->DevModel = model; + usbvision->remove_pending = 0; + usbvision->last_error = 0; + usbvision->iface = ifnum; + usbvision->ifaceAltInactive = 0; + usbvision->ifaceAltActive = 1; + usbvision->video_endp = endpoint->bEndpointAddress; + usbvision->isocPacketSize = 0; + usbvision->usb_bandwidth = 0; + usbvision->user = 0; + + usbvision_register_video(usbvision); + usbvision_configure_video(usbvision); + up(&usbvision->lock); + + + usb_set_intfdata (intf, usbvision); + usbvision_create_sysfs(usbvision->vdev); + + PDEBUG(DBG_PROBE, "success"); + return 0; +} + + +/* + * usbvision_disconnect() + * + * This procedure stops all driver activity, deallocates interface-private + * structure (pointed by 'ptr') and after that driver should be removable + * with no ill consequences. + * + */ +static void __devexit usbvision_disconnect(struct usb_interface *intf) +{ + struct usb_usbvision *usbvision = usb_get_intfdata(intf); + + PDEBUG(DBG_PROBE, ""); + + if (usbvision == NULL) { + err("%s: usb_get_intfdata() failed", __FUNCTION__); + return; + } + usb_set_intfdata (intf, NULL); + + down(&usbvision->lock); + + // At this time we ask to cancel outstanding URBs + usbvision_stop_isoc(usbvision); + + if (usbvision->power) { + usbvision_i2c_usb_del_bus(&usbvision->i2c_adap); + usbvision_power_off(usbvision); + } + usbvision->remove_pending = 1; // Now all ISO data will be ignored + + usb_put_dev(usbvision->dev); + usbvision->dev = NULL; // USB device is no more + + up(&usbvision->lock); + + if (usbvision->user) { + info("%s: In use, disconnect pending", __FUNCTION__); + } + else { + usbvision_release(usbvision); + } + + PDEBUG(DBG_PROBE, "success"); + +} + +MODULE_DEVICE_TABLE (usb, usbvision_table); + +static struct usb_driver usbvision_driver = { + .name = "usbvision", + .id_table = usbvision_table, + .probe = usbvision_probe, + .disconnect = usbvision_disconnect +}; + +/* + * customdevice_process() + * + * This procedure preprocesses CustomDevice parameter if any + * + */ +void customdevice_process(void) +{ + usbvision_device_data[0]=usbvision_device_data[1]; + usbvision_table[0]=usbvision_table[1]; + + if(CustomDevice) + { + char *parse=CustomDevice; + + PDEBUG(DBG_PROBE, "CustomDevide=%s", CustomDevice); + + /*format is CustomDevice="0x0573 0x4D31 0 7113 3 PAL 1 1 1 5 -1 -1 -1 -1 -1" + usbvision_device_data[0].idVendor; + usbvision_device_data[0].idProduct; + usbvision_device_data[0].Interface; + usbvision_device_data[0].Codec; + usbvision_device_data[0].VideoChannels; + usbvision_device_data[0].VideoNorm; + usbvision_device_data[0].AudioChannels; + usbvision_device_data[0].Radio; + usbvision_device_data[0].Tuner; + usbvision_device_data[0].TunerType; + usbvision_device_data[0].Vin_Reg1; + usbvision_device_data[0].Vin_Reg2; + usbvision_device_data[0].X_Offset; + usbvision_device_data[0].Y_Offset; + usbvision_device_data[0].Dvi_yuv; + usbvision_device_data[0].ModelString; + */ + + rmspace(parse); + usbvision_device_data[0].ModelString="USBVISION Custom Device"; + + parse+=2; + sscanf(parse,"%x",&usbvision_device_data[0].idVendor); + goto2next(parse); + PDEBUG(DBG_PROBE, "idVendor=0x%.4X", usbvision_device_data[0].idVendor); + parse+=2; + sscanf(parse,"%x",&usbvision_device_data[0].idProduct); + goto2next(parse); + PDEBUG(DBG_PROBE, "idProduct=0x%.4X", usbvision_device_data[0].idProduct); + sscanf(parse,"%d",&usbvision_device_data[0].Interface); + goto2next(parse); + PDEBUG(DBG_PROBE, "Interface=%d", usbvision_device_data[0].Interface); + sscanf(parse,"%d",&usbvision_device_data[0].Codec); + goto2next(parse); + PDEBUG(DBG_PROBE, "Codec=%d", usbvision_device_data[0].Codec); + sscanf(parse,"%d",&usbvision_device_data[0].VideoChannels); + goto2next(parse); + PDEBUG(DBG_PROBE, "VideoChannels=%d", usbvision_device_data[0].VideoChannels); + + switch(*parse) + { + case 'P': + PDEBUG(DBG_PROBE, "VideoNorm=PAL"); + usbvision_device_data[0].VideoNorm=VIDEO_MODE_PAL; + break; + + case 'S': + PDEBUG(DBG_PROBE, "VideoNorm=SECAM"); + usbvision_device_data[0].VideoNorm=VIDEO_MODE_SECAM; + break; + + case 'N': + PDEBUG(DBG_PROBE, "VideoNorm=NTSC"); + usbvision_device_data[0].VideoNorm=VIDEO_MODE_NTSC; + break; + + default: + PDEBUG(DBG_PROBE, "VideoNorm=PAL (by default)"); + usbvision_device_data[0].VideoNorm=VIDEO_MODE_PAL; + break; + } + goto2next(parse); + + sscanf(parse,"%d",&usbvision_device_data[0].AudioChannels); + goto2next(parse); + PDEBUG(DBG_PROBE, "AudioChannels=%d", usbvision_device_data[0].AudioChannels); + sscanf(parse,"%d",&usbvision_device_data[0].Radio); + goto2next(parse); + PDEBUG(DBG_PROBE, "Radio=%d", usbvision_device_data[0].Radio); + sscanf(parse,"%d",&usbvision_device_data[0].Tuner); + goto2next(parse); + PDEBUG(DBG_PROBE, "Tuner=%d", usbvision_device_data[0].Tuner); + sscanf(parse,"%d",&usbvision_device_data[0].TunerType); + goto2next(parse); + PDEBUG(DBG_PROBE, "TunerType=%d", usbvision_device_data[0].TunerType); + sscanf(parse,"%d",&usbvision_device_data[0].Vin_Reg1); + goto2next(parse); + PDEBUG(DBG_PROBE, "Vin_Reg1=%d", usbvision_device_data[0].Vin_Reg1); + sscanf(parse,"%d",&usbvision_device_data[0].Vin_Reg2); + goto2next(parse); + PDEBUG(DBG_PROBE, "Vin_Reg2=%d", usbvision_device_data[0].Vin_Reg2); + sscanf(parse,"%d",&usbvision_device_data[0].X_Offset); + goto2next(parse); + PDEBUG(DBG_PROBE, "X_Offset=%d", usbvision_device_data[0].X_Offset); + sscanf(parse,"%d",&usbvision_device_data[0].Y_Offset); + goto2next(parse); + PDEBUG(DBG_PROBE, "Y_Offset=%d", usbvision_device_data[0].Y_Offset); + sscanf(parse,"%d",&usbvision_device_data[0].Dvi_yuv); + PDEBUG(DBG_PROBE, "Dvi_yuv=%d", usbvision_device_data[0].Dvi_yuv); + + //add to usbvision_table also + usbvision_table[0].match_flags=USB_DEVICE_ID_MATCH_DEVICE; + usbvision_table[0].idVendor=usbvision_device_data[0].idVendor; + usbvision_table[0].idProduct=usbvision_device_data[0].idProduct; + + } +} + + + +/* + * usbvision_init() + * + * This code is run to initialize the driver. + * + */ +static int __init usbvision_init(void) +{ + int errCode; + + PDEBUG(DBG_PROBE, ""); + + PDEBUG(DBG_IOCTL, "IOCTL debugging is enabled"); + PDEBUG(DBG_IO, "IO debugging is enabled"); + PDEBUG(DBG_RIO, "RIO debugging is enabled"); + PDEBUG(DBG_HEADER, "HEADER debugging is enabled"); + PDEBUG(DBG_PROBE, "PROBE debugging is enabled"); + PDEBUG(DBG_IRQ, "IRQ debugging is enabled"); + PDEBUG(DBG_ISOC, "ISOC debugging is enabled"); + PDEBUG(DBG_PARSE, "PARSE debugging is enabled"); + PDEBUG(DBG_SCRATCH, "SCRATCH debugging is enabled"); + PDEBUG(DBG_FUNC, "FUNC debugging is enabled"); + PDEBUG(DBG_I2C, "I2C debugging is enabled"); + + /* disable planar mode support unless compression enabled */ + if (isocMode != ISOC_MODE_COMPRESS ) { + // FIXME : not the right way to set supported flag + usbvision_v4l2_format[6].supported = 0; // V4L2_PIX_FMT_YVU420 + usbvision_v4l2_format[7].supported = 0; // V4L2_PIX_FMT_YUV422P + } + + customdevice_process(); + + errCode = usb_register(&usbvision_driver); + + if (errCode == 0) { + info(DRIVER_DESC " : " DRIVER_VERSION); + PDEBUG(DBG_PROBE, "success"); + } + return errCode; +} + +static void __exit usbvision_exit(void) +{ + PDEBUG(DBG_PROBE, ""); + + usb_deregister(&usbvision_driver); + PDEBUG(DBG_PROBE, "success"); +} + +module_init(usbvision_init); +module_exit(usbvision_exit); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c new file mode 100644 index 00000000000..e050e5559ac --- /dev/null +++ b/drivers/media/video/usbvision/usbvision-i2c.c @@ -0,0 +1,265 @@ +/* + * I2C_ALGO_USB.C + * i2c algorithm for USB-I2C Bridges + * + * Copyright (c) 1999-2005 Joerg Heckenbach + * Dwaine Garden + * + * This module is part of usbvision driver project. + * Updates to driver completed by Dwaine P. Garden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include +#include +#include +#include +#include + #include +#include +#include +#include +#include +#include +#include +#include +#include "usbvision-i2c.h" + +static int debug = 0; + +#if defined(module_param) // Showing parameters under SYSFS +module_param (debug, int, 0444); // debug mode of the device driver +#else +MODULE_PARM(debug, "i"); // debug mode of the device driver +#endif + +MODULE_AUTHOR("Joerg Heckenbach"); +MODULE_DESCRIPTION("I2C algorithm for USB-I2C-bridges"); +MODULE_LICENSE("GPL"); + + +static inline int try_write_address(struct i2c_adapter *i2c_adap, + unsigned char addr, int retries) +{ + struct i2c_algo_usb_data *adap = i2c_adap->algo_data; + void *data; + int i, ret = -1; + char buf[4]; + + data = i2c_get_adapdata(i2c_adap); + buf[0] = 0x00; + for (i = 0; i <= retries; i++) { + ret = (adap->outb(data, addr, buf, 1)); + if (ret == 1) + break; /* success! */ + udelay(5 /*adap->udelay */ ); + if (i == retries) /* no success */ + break; + udelay(adap->udelay); + } + if (debug) { + if (i) { + info("%s: Needed %d retries for address %#2x", __FUNCTION__, i, addr); + info("%s: Maybe there's no device at this address", __FUNCTION__); + } + } + return ret; +} + +static inline int try_read_address(struct i2c_adapter *i2c_adap, + unsigned char addr, int retries) +{ + struct i2c_algo_usb_data *adap = i2c_adap->algo_data; + void *data; + int i, ret = -1; + char buf[4]; + + data = i2c_get_adapdata(i2c_adap); + for (i = 0; i <= retries; i++) { + ret = (adap->inb(data, addr, buf, 1)); + if (ret == 1) + break; /* success! */ + udelay(5 /*adap->udelay */ ); + if (i == retries) /* no success */ + break; + udelay(adap->udelay); + } + if (debug) { + if (i) { + info("%s: Needed %d retries for address %#2x", __FUNCTION__, i, addr); + info("%s: Maybe there's no device at this address", __FUNCTION__); + } + } + return ret; +} + +static inline int usb_find_address(struct i2c_adapter *i2c_adap, + struct i2c_msg *msg, int retries, + unsigned char *add) +{ + unsigned short flags = msg->flags; + + unsigned char addr; + int ret; + if ((flags & I2C_M_TEN)) { + /* a ten bit address */ + addr = 0xf0 | ((msg->addr >> 7) & 0x03); + /* try extended address code... */ + ret = try_write_address(i2c_adap, addr, retries); + if (ret != 1) { + err("died at extended address code, while writing"); + return -EREMOTEIO; + } + add[0] = addr; + if (flags & I2C_M_RD) { + /* okay, now switch into reading mode */ + addr |= 0x01; + ret = try_read_address(i2c_adap, addr, retries); + if (ret != 1) { + err("died at extended address code, while reading"); + return -EREMOTEIO; + } + } + + } else { /* normal 7bit address */ + addr = (msg->addr << 1); + if (flags & I2C_M_RD) + addr |= 1; + if (flags & I2C_M_REV_DIR_ADDR) + addr ^= 1; + + add[0] = addr; + if (flags & I2C_M_RD) + ret = try_read_address(i2c_adap, addr, retries); + else + ret = try_write_address(i2c_adap, addr, retries); + + if (ret != 1) { + return -EREMOTEIO; + } + } + return 0; +} + +static int +usb_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) +{ + struct i2c_msg *pmsg; + struct i2c_algo_usb_data *adap = i2c_adap->algo_data; + void *data; + int i, ret; + unsigned char addr; + + data = i2c_get_adapdata(i2c_adap); + + for (i = 0; i < num; i++) { + pmsg = &msgs[i]; + ret = usb_find_address(i2c_adap, pmsg, i2c_adap->retries, &addr); + if (ret != 0) { + if (debug) { + info("%s: got NAK from device, message #%d\n", __FUNCTION__, i); + } + return (ret < 0) ? ret : -EREMOTEIO; + } + + if (pmsg->flags & I2C_M_RD) { + /* read bytes into buffer */ + ret = (adap->inb(data, addr, pmsg->buf, pmsg->len)); + if (ret < pmsg->len) { + return (ret < 0) ? ret : -EREMOTEIO; + } + } else { + /* write bytes from buffer */ + ret = (adap->outb(data, addr, pmsg->buf, pmsg->len)); + if (ret < pmsg->len) { + return (ret < 0) ? ret : -EREMOTEIO; + } + } + } + return num; +} + +static int algo_control(struct i2c_adapter *adapter, unsigned int cmd, unsigned long arg) +{ + return 0; +} + +static u32 usb_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; +} + + +/* -----exported algorithm data: ------------------------------------- */ + +static struct i2c_algorithm i2c_usb_algo = { + .master_xfer = usb_xfer, + .smbus_xfer = NULL, + .slave_send = NULL, + .slave_recv = NULL, + .algo_control = algo_control, + .functionality = usb_func, +}; + + +/* + * registering functions to load algorithms at runtime + */ +int usbvision_i2c_usb_add_bus(struct i2c_adapter *adap) +{ + /* register new adapter to i2c module... */ + + adap->algo = &i2c_usb_algo; + + adap->timeout = 100; /* default values, should */ + adap->retries = 3; /* be replaced by defines */ + +#ifdef MODULE + #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 21) + MOD_INC_USE_COUNT; + #endif +#endif + + i2c_add_adapter(adap); + + if (debug) { + info("i2c bus for %s registered", adap->name); + } + + return 0; +} + + +int usbvision_i2c_usb_del_bus(struct i2c_adapter *adap) +{ + + i2c_del_adapter(adap); + + if (debug) { + info("i2c bus for %s unregistered", adap->name); + } +#ifdef MODULE + #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 21) + MOD_DEC_USE_COUNT; + #endif +#endif + + return 0; +} + +EXPORT_SYMBOL(usbvision_i2c_usb_add_bus); +EXPORT_SYMBOL(usbvision_i2c_usb_del_bus); diff --git a/drivers/media/video/usbvision/usbvision-i2c.h b/drivers/media/video/usbvision/usbvision-i2c.h new file mode 100644 index 00000000000..a2df8dbdac5 --- /dev/null +++ b/drivers/media/video/usbvision/usbvision-i2c.h @@ -0,0 +1,58 @@ +/* + * I2C_ALGO_USB.H + * i2c algorithm for USB-I2C Bridges + * + * Copyright (c) 1999-2005 Joerg Heckenbach + * + * This module is part of usbvision driver project. + * Updates to driver completed by Dwaine P. Garden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#ifndef I2C_ALGO_USB_H +#define I2C_ALGO_USB_H 1 + +#include + +struct i2c_algo_usb_data { + void *data; /* private data for lowlevel routines */ + int (*inb) (void *data, unsigned char addr, char *buf, short len); + int (*outb) (void *data, unsigned char addr, char *buf, short len); + + /* local settings */ + int udelay; + int mdelay; + int timeout; +}; + +#define I2C_USB_ADAP_MAX 16 + +int usbvision_i2c_usb_add_bus(struct i2c_adapter *); +int usbvision_i2c_usb_del_bus(struct i2c_adapter *); + +static inline void *i2c_get_algo_usb_data (struct i2c_algo_usb_data *dev) +{ + return dev->data; +} + +static inline void i2c_set_algo_usb_data (struct i2c_algo_usb_data *dev, void *data) +{ + dev->data = data; +} + + +#endif //I2C_ALGO_USB_H diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h new file mode 100644 index 00000000000..b03e4eabfb0 --- /dev/null +++ b/drivers/media/video/usbvision/usbvision.h @@ -0,0 +1,594 @@ +/* + * USBVISION.H + * usbvision header file + * + * Copyright (c) 1999-2005 Joerg Heckenbach + * + * This module is part of usbvision driver project. + * Updates to driver completed by Dwaine P. Garden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#ifndef __LINUX_USBVISION_H +#define __LINUX_USBVISION_H + +#include + +#ifndef VID_HARDWARE_USBVISION + #define VID_HARDWARE_USBVISION 34 /* USBVision Video Grabber */ +#endif + +#define USBVISION_PWR_REG 0x00 + #define USBVISION_SSPND_EN (1 << 1) + #define USBVISION_RES2 (1 << 2) + #define USBVISION_PWR_VID (1 << 5) + #define USBVISION_E2_EN (1 << 7) +#define USBVISION_CONFIG_REG 0x01 +#define USBVISION_ADRS_REG 0x02 +#define USBVISION_ALTER_REG 0x03 +#define USBVISION_FORCE_ALTER_REG 0x04 +#define USBVISION_STATUS_REG 0x05 +#define USBVISION_IOPIN_REG 0x06 + #define USBVISION_IO_1 (1 << 0) + #define USBVISION_IO_2 (1 << 1) + #define USBVISION_AUDIO_IN 0 + #define USBVISION_AUDIO_TV 1 + #define USBVISION_AUDIO_RADIO 2 + #define USBVISION_AUDIO_MUTE 3 +#define USBVISION_SER_MODE 0x07 +#define USBVISION_SER_ADRS 0x08 +#define USBVISION_SER_CONT 0x09 +#define USBVISION_SER_DAT1 0x0A +#define USBVISION_SER_DAT2 0x0B +#define USBVISION_SER_DAT3 0x0C +#define USBVISION_SER_DAT4 0x0D +#define USBVISION_EE_DATA 0x0E +#define USBVISION_EE_LSBAD 0x0F +#define USBVISION_EE_CONT 0x10 +#define USBVISION_DRM_CONT 0x12 + #define USBVISION_REF (1 << 0) + #define USBVISION_RES_UR (1 << 2) + #define USBVISION_RES_FDL (1 << 3) + #define USBVISION_RES_VDW (1 << 4) +#define USBVISION_DRM_PRM1 0x13 +#define USBVISION_DRM_PRM2 0x14 +#define USBVISION_DRM_PRM3 0x15 +#define USBVISION_DRM_PRM4 0x16 +#define USBVISION_DRM_PRM5 0x17 +#define USBVISION_DRM_PRM6 0x18 +#define USBVISION_DRM_PRM7 0x19 +#define USBVISION_DRM_PRM8 0x1A +#define USBVISION_VIN_REG1 0x1B + #define USBVISION_8_422_SYNC 0x01 + #define USBVISION_16_422_SYNC 0x02 + #define USBVISION_VSNC_POL (1 << 3) + #define USBVISION_HSNC_POL (1 << 4) + #define USBVISION_FID_POL (1 << 5) + #define USBVISION_HVALID_PO (1 << 6) + #define USBVISION_VCLK_POL (1 << 7) +#define USBVISION_VIN_REG2 0x1C + #define USBVISION_AUTO_FID (1 << 0) + #define USBVISION_NONE_INTER (1 << 1) + #define USBVISION_NOHVALID (1 << 2) + #define USBVISION_UV_ID (1 << 3) + #define USBVISION_FIX_2C (1 << 4) + #define USBVISION_SEND_FID (1 << 5) + #define USBVISION_KEEP_BLANK (1 << 7) +#define USBVISION_LXSIZE_I 0x1D +#define USBVISION_MXSIZE_I 0x1E +#define USBVISION_LYSIZE_I 0x1F +#define USBVISION_MYSIZE_I 0x20 +#define USBVISION_LX_OFFST 0x21 +#define USBVISION_MX_OFFST 0x22 +#define USBVISION_LY_OFFST 0x23 +#define USBVISION_MY_OFFST 0x24 +#define USBVISION_FRM_RATE 0x25 +#define USBVISION_LXSIZE_O 0x26 +#define USBVISION_MXSIZE_O 0x27 +#define USBVISION_LYSIZE_O 0x28 +#define USBVISION_MYSIZE_O 0x29 +#define USBVISION_FILT_CONT 0x2A +#define USBVISION_VO_MODE 0x2B +#define USBVISION_INTRA_CYC 0x2C +#define USBVISION_STRIP_SZ 0x2D +#define USBVISION_FORCE_INTRA 0x2E +#define USBVISION_FORCE_UP 0x2F +#define USBVISION_BUF_THR 0x30 +#define USBVISION_DVI_YUV 0x31 +#define USBVISION_AUDIO_CONT 0x32 +#define USBVISION_AUD_PK_LEN 0x33 +#define USBVISION_BLK_PK_LEN 0x34 +#define USBVISION_PCM_THR1 0x38 +#define USBVISION_PCM_THR2 0x39 +#define USBVISION_DIST_THR_L 0x3A +#define USBVISION_DIST_THR_H 0x3B +#define USBVISION_MAX_DIST_L 0x3C +#define USBVISION_MAX_DIST_H 0x3D +#define USBVISION_OP_CODE 0x33 + +#define MAX_BYTES_PER_PIXEL 4 + +#define MIN_FRAME_WIDTH 64 +#define MAX_USB_WIDTH 320 //384 +#define MAX_FRAME_WIDTH 320 //384 /*streching sometimes causes crashes*/ + +#define MIN_FRAME_HEIGHT 48 +#define MAX_USB_HEIGHT 240 //288 +#define MAX_FRAME_HEIGHT 240 //288 /*Streching sometimes causes crashes*/ + +#define MAX_FRAME_SIZE (MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT * MAX_BYTES_PER_PIXEL) +#define USBVISION_CLIPMASK_SIZE (MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT / 8) //bytesize of clipmask + +#define USBVISION_URB_FRAMES 32 +#define USBVISION_MAX_ISOC_PACKET_SIZE 959 // NT1003 Specs Document says 1023 + +#define USBVISION_NUM_HEADERMARKER 20 +#define USBVISION_NUMFRAMES 2 +#define USBVISION_NUMSBUF 2 + +#define USBVISION_POWEROFF_TIME 3 * (HZ) // 3 seconds + +/* This macro restricts an int variable to an inclusive range */ +#define RESTRICT_TO_RANGE(v,mi,ma) { if ((v) < (mi)) (v) = (mi); else if ((v) > (ma)) (v) = (ma); } + +/* + * We use macros to do YUV -> RGB conversion because this is + * very important for speed and totally unimportant for size. + * + * YUV -> RGB Conversion + * --------------------- + * + * B = 1.164*(Y-16) + 2.018*(V-128) + * G = 1.164*(Y-16) - 0.813*(U-128) - 0.391*(V-128) + * R = 1.164*(Y-16) + 1.596*(U-128) + * + * If you fancy integer arithmetics (as you should), hear this: + * + * 65536*B = 76284*(Y-16) + 132252*(V-128) + * 65536*G = 76284*(Y-16) - 53281*(U-128) - 25625*(V-128) + * 65536*R = 76284*(Y-16) + 104595*(U-128) + * + * Make sure the output values are within [0..255] range. + */ +#define LIMIT_RGB(x) (((x) < 0) ? 0 : (((x) > 255) ? 255 : (x))) +#define YUV_TO_RGB_BY_THE_BOOK(my,mu,mv,mr,mg,mb) { \ + int mm_y, mm_yc, mm_u, mm_v, mm_r, mm_g, mm_b; \ + mm_y = (my) - 16; \ + mm_u = (mu) - 128; \ + mm_v = (mv) - 128; \ + mm_yc= mm_y * 76284; \ + mm_b = (mm_yc + 132252*mm_v ) >> 16; \ + mm_g = (mm_yc - 53281*mm_u - 25625*mm_v ) >> 16; \ + mm_r = (mm_yc + 104595*mm_u ) >> 16; \ + mb = LIMIT_RGB(mm_b); \ + mg = LIMIT_RGB(mm_g); \ + mr = LIMIT_RGB(mm_r); \ +} + + + +/* Debugging aid */ +#define USBVISION_SAY_AND_WAIT(what) { \ + wait_queue_head_t wq; \ + init_waitqueue_head(&wq); \ + printk(KERN_INFO "Say: %s\n", what); \ + interruptible_sleep_on_timeout (&wq, HZ*3); \ +} + +/* + * This macro checks if usbvision is still operational. The 'usbvision' + * pointer must be valid, usbvision->dev must be valid, we are not + * removing the device and the device has not erred on us. + */ +#define USBVISION_IS_OPERATIONAL(udevice) (\ + (udevice != NULL) && \ + ((udevice)->dev != NULL) && \ + ((udevice)->last_error == 0) && \ + (!(udevice)->remove_pending)) + + +enum ScanState { + ScanState_Scanning, /* Scanning for header */ + ScanState_Lines /* Parsing lines */ +}; + +/* Completion states of the data parser */ +enum ParseState { + ParseState_Continue, /* Just parse next item */ + ParseState_NextFrame, /* Frame done, send it to V4L */ + ParseState_Out, /* Not enough data for frame */ + ParseState_EndParse /* End parsing */ +}; + +enum FrameState { + FrameState_Unused, /* Unused (no MCAPTURE) */ + FrameState_Ready, /* Ready to start grabbing */ + FrameState_Grabbing, /* In the process of being grabbed into */ + FrameState_Done, /* Finished grabbing, but not been synced yet */ + FrameState_DoneHold, /* Are syncing or reading */ + FrameState_Error, /* Something bad happened while processing */ +}; + +enum IsocState { + IsocState_InFrame, /* Isoc packet is member of frame */ + IsocState_NoFrame, /* Isoc packet is not member of any frame */ +}; + +struct usb_device; + +struct usbvision_sbuf { + char *data; + struct urb *urb; +}; + +#define USBVISION_MAGIC_1 0x55 +#define USBVISION_MAGIC_2 0xAA +#define USBVISION_HEADER_LENGTH 0x0c +#define USBVISION_SAA7111_ADDR 0x48 +#define USBVISION_SAA7113_ADDR 0x4a +#define USBVISION_IIC_LRACK 0x20 +#define USBVISION_IIC_LRNACK 0x30 +#define USBVISION_FRAME_FORMAT_PARAM_INTRA (1<<7) + +static struct usbvision_v4l2_format_st { + int supported; + int bytes_per_pixel; + int depth; + int format; + char *desc; +} usbvision_v4l2_format[] = { + { 1, 1, 8, V4L2_PIX_FMT_GREY , "GREY" }, + { 1, 2, 16, V4L2_PIX_FMT_RGB565 , "RGB565" }, + { 1, 3, 24, V4L2_PIX_FMT_RGB24 , "RGB24" }, + { 1, 4, 32, V4L2_PIX_FMT_RGB32 , "RGB32" }, + { 1, 2, 16, V4L2_PIX_FMT_RGB555 , "RGB555" }, + { 1, 2, 16, V4L2_PIX_FMT_YUYV , "YUV422" }, + { 1, 2, 12, V4L2_PIX_FMT_YVU420 , "YUV420P" }, // 1.5 ! + { 1, 2, 16, V4L2_PIX_FMT_YUV422P , "YUV422P" } +}; +#define USBVISION_SUPPORTED_PALETTES ARRAY_SIZE(usbvision_v4l2_format) + +struct usbvision_frame_header { + unsigned char magic_1; /* 0 magic */ + unsigned char magic_2; /* 1 magic */ + unsigned char headerLength; /* 2 */ + unsigned char frameNum; /* 3 */ + unsigned char framePhase; /* 4 */ + unsigned char frameLatency; /* 5 */ + unsigned char dataFormat; /* 6 */ + unsigned char formatParam; /* 7 */ + unsigned char frameWidthLo; /* 8 */ + unsigned char frameWidthHi; /* 9 */ + unsigned char frameHeightLo; /* 10 */ + unsigned char frameHeightHi; /* 11 */ + __u16 frameWidth; /* 8 - 9 after endian correction*/ + __u16 frameHeight; /* 10 - 11 after endian correction*/ +}; + +struct usbvision_frame { + char *data; /* Frame buffer */ + struct usbvision_frame_header isocHeader; /* Header from stream */ + + int width; /* Width application is expecting */ + int height; /* Height */ + + int frmwidth; /* Width the frame actually is */ + int frmheight; /* Height */ + + volatile int grabstate; /* State of grabbing */ + int scanstate; /* State of scanning */ + + int curline; /* Line of frame we're working on */ + + long scanlength; /* uncompressed, raw data length of frame */ + long bytes_read; /* amount of scanlength that has been read from data */ + struct usbvision_v4l2_format_st v4l2_format; /* format the user needs*/ + int v4l2_linesize; /* bytes for one videoline*/ + struct timeval timestamp; + wait_queue_head_t wq; /* Processes waiting */ + int sequence; // How many video frames we send to user +}; + +#define CODEC_SAA7113 7113 +#define CODEC_SAA7111 7111 +#define BRIDGE_NT1003 1003 +#define BRIDGE_NT1004 1004 +#define BRIDGE_NT1005 1005 + +/* Supported Devices: A table for usbvision.c*/ + +static struct usbvision_device_data_st { + int idVendor; + int idProduct; + int Interface; /* to handle special interface number like BELKIN and Hauppauge WinTV-USB II */ + int Codec; + int VideoChannels; + __u64 VideoNorm; + int AudioChannels; + int Radio; + int vbi; + int Tuner; + int TunerType; + int Vin_Reg1; + int Vin_Reg2; + int X_Offset; + int Y_Offset; + int Dvi_yuv; + char *ModelString; +} usbvision_device_data[] = { + {0xFFF0, 0xFFF0, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Custom Dummy USBVision Device"}, + {0x0A6F, 0x0400, -1, CODEC_SAA7113, 4, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, -1, -1, -1, "Xanboo"}, + {0x050D, 0x0208, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 1, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Belkin USBView II"}, + {0x0571, 0x0002, 0, CODEC_SAA7111, 2, V4L2_STD_PAL, 0, 0, 1, 0, 0, -1, -1, -1, -1, 7, "echoFX InterView Lite"}, + {0x0573, 0x0003, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, -1, -1, -1, "USBGear USBG-V1 resp. HAMA USB"}, + {0x0573, 0x0400, -1, CODEC_SAA7113, 4, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "D-Link V100"}, + {0x0573, 0x2000, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, -1, -1, -1, "X10 USB Camera"}, + {0x0573, 0x2d00, -1, CODEC_SAA7111, 2, V4L2_STD_PAL, 1, 0, 1, 0, 0, -1, -1, -1, 3, 7, "Osprey 50"}, + {0x0573, 0x2d01, -1, CODEC_SAA7113, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Hauppauge USB-Live Model 600"}, + {0x0573, 0x2101, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 2, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Zoran Co. PMD (Nogatech) AV-grabber Manhattan"}, + {0x0573, 0x4100, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, 20, -1, "Nogatech USB-TV (NTSC) FM"}, + {0x0573, 0x4110, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, 20, -1, "PNY USB-TV (NTSC) FM"}, + {0x0573, 0x4450, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "PixelView PlayTv-USB PRO (PAL) FM"}, + {0x0573, 0x4550, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "ZTV ZT-721 2.4GHz USB A/V Receiver"}, + {0x0573, 0x4d00, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, 20, -1, "Hauppauge WinTv-USB USA"}, + {0x0573, 0x4d01, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB"}, + {0x0573, 0x4d02, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (NTSC)"}, + {0x0573, 0x4d03, -1, CODEC_SAA7111, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (SECAM) "}, + {0x0573, 0x4d10, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (NTSC) FM"}, + {0x0573, 0x4d11, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (PAL) FM"}, + {0x0573, 0x4d12, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (PAL) FM"}, + {0x0573, 0x4d2a, 0, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_MICROTUNE_4049FM5, -1, -1, 0, 3, 7, "Hauppauge WinTv USB (NTSC) FM Model 602 40201 Rev B285"}, + {0x0573, 0x4d2b, 0, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_MICROTUNE_4049FM5, -1, -1, 0, 3, 7, "Hauppauge WinTv USB (NTSC) FM Model 602 40201 Rev B282"}, + {0x0573, 0x4d2c, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_FM1216ME_MK3, -1, -1, 0, 3, 7, "Hauppauge WinTv USB (PAL/SECAM) 40209 Rev E1A5"}, + {0x0573, 0x4d20, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB II (PAL) FM Model 40201 Rev B226"}, + {0x0573, 0x4d21, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB II (PAL)"}, + {0x0573, 0x4d22, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB II (PAL) MODEL 566"}, + {0x0573, 0x4d23, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB (SECAM) 4D23"}, + {0x0573, 0x4d25, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB (SECAM) Model 40209 Rev B234"}, + {0x0573, 0x4d26, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB (SECAM) Model 40209 Rev B243"}, + {0x0573, 0x4d27, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_ALPS_TSBE1_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB Model 40204 Rev B281"}, + {0x0573, 0x4d28, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_ALPS_TSBE1_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB Model 40204 Rev B283"}, + {0x0573, 0x4d29, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB Model 40205 Rev B298"}, + {0x0573, 0x4d30, -1, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB FM Model 40211 Rev B123"}, + {0x0573, 0x4d31, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB III (PAL) FM Model 568"}, + {0x0573, 0x4d32, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB III (PAL) FM Model 573"}, + {0x0573, 0x4d35, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_MICROTUNE_4049FM5, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB III (PAL) FM Model 40219 Rev B252"}, + {0x0573, 0x4d37, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_FM1216ME_MK3, -1, -1, 0, 3, 7, "Hauppauge WinTV USB device Model 40219 Rev E189"}, + {0x0768, 0x0006, -1, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, 5, 5, -1, "Camtel Technology USB TV Genie Pro FM Model TVB330"}, + {0x07d0, 0x0001, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Digital Video Creator I"}, + {0x07d0, 0x0002, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 82, 20, 7, "Global Village GV-007 (NTSC)"}, + {0x07d0, 0x0003, 0, CODEC_SAA7113, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-50 Rev 1 (NTSC)"}, + {0x07d0, 0x0004, 0, CODEC_SAA7113, 2, V4L2_STD_PAL, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-80 Rev 1 (PAL)"}, + {0x07d0, 0x0005, 0, CODEC_SAA7113, 2, V4L2_STD_SECAM, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)"}, + {0x2304, 0x010d, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 0, 0, 1, TUNER_TEMIC_4066FY5_PAL_I, -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (PAL)"}, + {0x2304, 0x0109, -1, CODEC_SAA7111, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (SECAM)"}, + {0x2304, 0x0110, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1,128, 23, -1, "Pinnacle Studio PCTV USB (PAL) FM"}, + {0x2304, 0x0111, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, -1, -1, -1, "Miro PCTV USB"}, + {0x2304, 0x0112, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (NTSC) FM"}, + {0x2304, 0x0210, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL, -1, -1, 0, 3, 7, "Pinnacle Studio PCTV USB (PAL) FM"}, + {0x2304, 0x0212, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_TEMIC_4039FR5_NTSC, -1, -1, 0, 3, 7, "Pinnacle Studio PCTV USB (NTSC) FM"}, + {0x2304, 0x0214, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL, -1, -1, 0, 3, 7, "Pinnacle Studio PCTV USB (PAL) FM"}, + {0x2304, 0x0300, -1, CODEC_SAA7113, 2, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Pinnacle Studio Linx Video input cable (NTSC)"}, + {0x2304, 0x0301, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 1, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Pinnacle Studio Linx Video input cable (PAL)"}, + {0x2304, 0x0419, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL, -1, -1, 0, 3, 7, "Pinnacle PCTV Bungee USB (PAL) FM"}, + {0x2400, 0x4200, -1, CODEC_SAA7111, 3, VIDEO_MODE_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB"}, + {} /* Terminating entry */ +}; + + +/* Supported Devices: A table for the usb.c*/ + +static struct usb_device_id usbvision_table [] = { + { USB_DEVICE(0xFFF0, 0xFFF0) }, /* Custom Dummy USBVision Device */ + { USB_DEVICE(0x0A6F, 0x0400) }, /* Xanboo */ + { USB_DEVICE(0x050d, 0x0208) }, /* Belkin USBView II */ + { USB_DEVICE(0x0571, 0x0002) }, /* echoFX InterView Lite */ + { USB_DEVICE(0x0573, 0x0003) }, /* USBGear USBG-V1 */ + { USB_DEVICE(0x0573, 0x0400) }, /* D-Link V100 */ + { USB_DEVICE(0x0573, 0x2000) }, /* X10 USB Camera */ + { USB_DEVICE(0x0573, 0x2d00) }, /* Osprey 50 */ + { USB_DEVICE(0x0573, 0x2d01) }, /* Hauppauge USB-Live Model 600 */ + { USB_DEVICE(0x0573, 0x2101) }, /* Zoran Co. PMD (Nogatech) AV-grabber Manhattan */ + { USB_DEVICE(0x0573, 0x4100) }, /* Nogatech USB-TV FM (NTSC) */ + { USB_DEVICE(0x0573, 0x4110) }, /* PNY USB-TV (NTSC) FM */ + { USB_DEVICE(0x0573, 0x4450) }, /* PixelView PlayTv-USB PRO (PAL) FM */ + { USB_DEVICE(0x0573, 0x4550) }, /* ZTV ZT-721 2.4GHz USB A/V Receiver */ + { USB_DEVICE(0x0573, 0x4d00) }, /* Hauppauge WinTv-USB USA */ + { USB_DEVICE(0x0573, 0x4d01) }, /* Hauppauge WinTv-USB */ + { USB_DEVICE(0x0573, 0x4d02) }, /* Hauppauge WinTv-USB UK */ + { USB_DEVICE(0x0573, 0x4d03) }, /* Hauppauge WinTv-USB France */ + { USB_DEVICE(0x0573, 0x4d10) }, /* Hauppauge WinTv-USB with FM USA radio */ + { USB_DEVICE(0x0573, 0x4d11) }, /* Hauppauge WinTv-USB (PAL) with FM radio */ + { USB_DEVICE(0x0573, 0x4d12) }, /* Hauppauge WinTv-USB UK with FM Radio */ + { USB_DEVICE(0x0573, 0x4d2a) }, /* Hauppague WinTv USB Model 602 40201 Rev B285 */ + { USB_DEVICE(0x0573, 0x4d2b) }, /* Hauppague WinTv USB Model 602 40201 Rev B282 */ + { USB_DEVICE(0x0573, 0x4d2c) }, /* Hauppague WinTv USB Model 40209 Rev. E1A5 PAL*/ + { USB_DEVICE(0x0573, 0x4d20) }, /* Hauppauge WinTv-USB II (PAL) FM Model 40201 Rev B226 */ + { USB_DEVICE(0x0573, 0x4d21) }, /* Hauppauge WinTv-USB II (PAL) with FM radio*/ + { USB_DEVICE(0x0573, 0x4d22) }, /* Hauppauge WinTv-USB II (PAL) Model 566 */ + { USB_DEVICE(0x0573, 0x4d23) }, /* Hauppauge WinTv-USB France 4D23*/ + { USB_DEVICE(0x0573, 0x4d25) }, /* Hauppauge WinTv-USB Model 40209 rev B234 */ + { USB_DEVICE(0x0573, 0x4d26) }, /* Hauppauge WinTv-USB Model 40209 Rev B243 */ + { USB_DEVICE(0x0573, 0x4d27) }, /* Hauppauge WinTv-USB Model 40204 Rev B281 */ + { USB_DEVICE(0x0573, 0x4d28) }, /* Hauppauge WinTv-USB Model 40204 Rev B283 */ + { USB_DEVICE(0x0573, 0x4d29) }, /* Hauppauge WinTv-USB Model 40205 Rev B298 */ + { USB_DEVICE(0x0573, 0x4d30) }, /* Hauppauge WinTv-USB FM Model 40211 Rev B123 */ + { USB_DEVICE(0x0573, 0x4d31) }, /* Hauppauge WinTv-USB III (PAL) with FM radio Model 568 */ + { USB_DEVICE(0x0573, 0x4d32) }, /* Hauppauge WinTv-USB III (PAL) FM Model 573 */ + { USB_DEVICE(0x0573, 0x4d35) }, /* Hauppauge WinTv-USB III (SECAM) FM Model 40219 Rev B252 */ + { USB_DEVICE(0x0573, 0x4d37) }, /* Hauppauge WinTv-USB Model 40219 Rev E189 */ + { USB_DEVICE(0x0768, 0x0006) }, /* Camtel Technology USB TV Genie Pro FM Model TVB330 */ + { USB_DEVICE(0x07d0, 0x0001) }, /* Digital Video Creator I */ + { USB_DEVICE(0x07d0, 0x0002) }, /* Global Village GV-007 (NTSC) */ + { USB_DEVICE(0x07d0, 0x0003) }, /* Dazzle Fusion Model DVC-50 Rev 1 (NTSC) */ + { USB_DEVICE(0x07d0, 0x0004) }, /* Dazzle Fusion Model DVC-80 Rev 1 (PAL) */ + { USB_DEVICE(0x07d0, 0x0005) }, /* Dazzle Fusion Model DVC-90 Rev 1 (SECAM) */ + { USB_DEVICE(0x2304, 0x010d) }, /* Pinnacle Studio PCTV USB (PAL) */ + { USB_DEVICE(0x2304, 0x0109) }, /* Pinnacle Studio PCTV USB (SECAM) */ + { USB_DEVICE(0x2304, 0x0110) }, /* Pinnacle Studio PCTV USB (PAL) */ + { USB_DEVICE(0x2304, 0x0111) }, /* Miro PCTV USB */ + { USB_DEVICE(0x2304, 0x0112) }, /* Pinnacle Studio PCTV USB (NTSC) with FM radio */ + { USB_DEVICE(0x2304, 0x0210) }, /* Pinnacle Studio PCTV USB (PAL) with FM radio */ + { USB_DEVICE(0x2304, 0x0212) }, /* Pinnacle Studio PCTV USB (NTSC) with FM radio */ + { USB_DEVICE(0x2304, 0x0214) }, /* Pinnacle Studio PCTV USB (PAL) with FM radio */ + { USB_DEVICE(0x2304, 0x0300) }, /* Pinnacle Studio Linx Video input cable (NTSC) */ + { USB_DEVICE(0x2304, 0x0301) }, /* Pinnacle Studio Linx Video input cable (PAL) */ + { USB_DEVICE(0x2304, 0x0419) }, /* Pinnacle PCTV Bungee USB (PAL) FM */ + + { USB_DEVICE(0x2400, 0x4200) }, /* Hauppauge WinTv-USB2 Model 42012 */ + + { } /* Terminating entry */ +}; + + +#define USBVISION_I2C_CLIENTS_MAX 8 + +struct usb_usbvision { + struct video_device *vdev; /* Video Device */ + struct video_device *rdev; /* Radio Device */ + struct video_device *vbi; /* VBI Device */ + struct video_audio audio_dev; /* Current audio params */ + + /* i2c Declaration Section*/ + struct i2c_adapter i2c_adap; + struct i2c_algo_usb_data i2c_algo; + struct i2c_client i2c_client; + int i2c_state, i2c_ok; + struct i2c_client *i2c_clients[USBVISION_I2C_CLIENTS_MAX]; + + struct urb *ctrlUrb; + unsigned char ctrlUrbBuffer[8]; + int ctrlUrbBusy; + struct usb_ctrlrequest ctrlUrbSetup; + wait_queue_head_t ctrlUrb_wq; // Processes waiting + struct semaphore ctrlUrbLock; + + int have_tuner; + int tuner_type; + int bridgeType; // NT1003, NT1004, NT1005 + int channel; + int radio; + int video_inputs; // # of inputs + unsigned long freq; + int AudioMute; + int AudioChannel; + int isocMode; // format of video data for the usb isoc-transfer + unsigned int nr; // Number of the device < MAX_USBVISION + + /* Device structure */ + struct usb_device *dev; + unsigned char iface; /* Video interface number */ + unsigned char ifaceAltActive, ifaceAltInactive; /* Alt settings */ + unsigned char Vin_Reg2_Preset; + struct semaphore lock; + struct timer_list powerOffTimer; + struct work_struct powerOffWork; + int power; /* is the device powered on? */ + int user; /* user count for exclusive use */ + int usbvision_used; /* Is this structure in use? */ + int initialized; /* Had we already sent init sequence? */ + int DevModel; /* What type of USBVISION device we got? */ + int streaming; /* Are we streaming Isochronous? */ + int last_error; /* What calamity struck us? */ + int curwidth; /* width of the frame the device is currently set to*/ + int curheight; /* height of the frame the device is currently set to*/ + int stretch_width; /* stretch-factor for frame width (from usb to screen)*/ + int stretch_height; /* stretch-factor for frame height (from usb to screen)*/ + char *fbuf; /* Videodev buffer area for mmap*/ + int max_frame_size; /* Bytes in one video frame */ + int fbuf_size; /* Videodev buffer size */ + int curFrameNum; // number of current frame in frame buffer mode + struct usbvision_frame *curFrame; // pointer to current frame, set by usbvision_find_header + struct usbvision_frame frame[USBVISION_NUMFRAMES]; // frame buffer + int curSbufNum; // number of current receiving sbuf + struct usbvision_sbuf sbuf[USBVISION_NUMSBUF]; // S buffering + volatile int remove_pending; /* If set then about to exit */ + + /* Scratch space from the Isochronous Pipe.*/ + unsigned char *scratch; + int scratch_read_ptr; + int scratch_write_ptr; + int scratch_headermarker[USBVISION_NUM_HEADERMARKER]; + int scratch_headermarker_read_ptr; + int scratch_headermarker_write_ptr; + int isocstate; + /* color controls */ + int saturation; + int hue; + int brightness; + int contrast; + int depth; + struct usbvision_v4l2_format_st palette; + + struct v4l2_capability vcap; /* Video capabilities */ + struct v4l2_input input; /* May be used for tuner support */ + unsigned char video_endp; /* 0x82 for USBVISION devices based */ + + // Overlay stuff: + struct v4l2_framebuffer vid_buf; + struct v4l2_format vid_win; + int vid_buf_valid; // Status: video buffer is valid (set) + int vid_win_valid; // Status: video window is valid (set) + int overlay; /*Status: Are we overlaying? */ + unsigned int clipmask[USBVISION_CLIPMASK_SIZE / 4]; + unsigned char *overlay_base; /* Virtual base address of video buffer */ + unsigned char *overlay_win; /* virt start address of overlay window */ + struct usbvision_frame overlay_frame; + + // Decompression stuff: + unsigned char *IntraFrameBuffer; /* Buffer for reference frame */ + int BlockPos; //for test only + int requestIntra; // 0 = normal; 1 = intra frame is requested; + int lastIsocFrameNum; // check for lost isoc frames + int isocPacketSize; // need to calculate usedBandwidth + int usedBandwidth; // used bandwidth 0-100%, need to set comprLevel + int comprLevel; // How strong (100) or weak (0) is compression + int lastComprLevel; // How strong (100) or weak (0) was compression + int usb_bandwidth; /* Mbit/s */ + + /* /proc entries, relative to /proc/video/usbvision/ */ + struct proc_dir_entry *proc_devdir; /* Per-device proc directory */ + struct proc_dir_entry *proc_info; /* /info entry */ + struct proc_dir_entry *proc_register; /* /register entry */ + struct proc_dir_entry *proc_freq; /* /freq entry */ + struct proc_dir_entry *proc_input; /* /input entry */ + struct proc_dir_entry *proc_frame; /* /frame entry */ + struct proc_dir_entry *proc_button; /* /button entry */ + struct proc_dir_entry *proc_control; /* /control entry */ + + /* Statistics that can be overlayed on the screen */ + unsigned long isocUrbCount; // How many URBs we received so far + unsigned long urb_length; /* Length of last URB */ + unsigned long isocDataCount; /* How many bytes we received */ + unsigned long header_count; /* How many frame headers we found */ + unsigned long scratch_ovf_count; /* How many times we overflowed scratch */ + unsigned long isocSkipCount; /* How many empty ISO packets received */ + unsigned long isocErrCount; /* How many bad ISO packets received */ + unsigned long isocPacketCount; // How many packets we totally got + unsigned long timeInIrq; // How long do we need for interrupt + int isocMeasureBandwidthCount; + int frame_num; // How many video frames we send to user + int maxStripLen; // How big is the biggest strip + int comprBlockPos; + int stripLenErrors; // How many times was BlockPos greater than StripLen + int stripMagicErrors; + int stripLineNumberErrors; + int ComprBlockTypes[4]; +}; + +#endif /* __LINUX_USBVISION_H */ + diff --git a/drivers/media/video/usbvision/usbvision_ioctl.h b/drivers/media/video/usbvision/usbvision_ioctl.h new file mode 100644 index 00000000000..7204c5ceda4 --- /dev/null +++ b/drivers/media/video/usbvision/usbvision_ioctl.h @@ -0,0 +1,34 @@ +/* + * USBVISION_IOCTL.H + * IOCTL for usbvision + * + * Copyright (c) 1999-2005 Joerg Heckenbach + * + * This module is part of usbvision driver project. + * Updates to driver completed by Dwaine P. Garden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +struct usbvision_reg { + unsigned char addr; + unsigned char value; +}; + +#define UVIOCGREG _IOWR('u',240,struct usbvision_reg) // get register +#define UVIOCSREG _IOW('u',241,struct usbvision_reg) // set register +#define UVIOCSVINM _IOW('u',242,int) // set usbvision vin_mode + -- cgit v1.2.3 From 6714b01263b06b2e7d054625486451a9fd8e03f4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 4 Dec 2006 08:31:01 -0300 Subject: V4L/DVB (4923): Splitted usbvision cards from usbvison.h Having the cards description into a separated file makes easier to maintain and follows the same standard as other drivers. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/usbvision/Makefile | 2 +- drivers/media/video/usbvision/usbvision-cards.c | 158 +++++++++++++++++++++ drivers/media/video/usbvision/usbvision-core.c | 16 ++- drivers/media/video/usbvision/usbvision.h | 179 ++++-------------------- 4 files changed, 196 insertions(+), 159 deletions(-) create mode 100644 drivers/media/video/usbvision/usbvision-cards.c (limited to 'drivers/media/video') diff --git a/drivers/media/video/usbvision/Makefile b/drivers/media/video/usbvision/Makefile index bad2eee2dbb..ebdf78a1928 100644 --- a/drivers/media/video/usbvision/Makefile +++ b/drivers/media/video/usbvision/Makefile @@ -1,4 +1,4 @@ -usbvision-objs := usbvision-core.o usbvision-i2c.o +usbvision-objs := usbvision-core.o usbvision-i2c.o usbvision-cards.o obj-$(CONFIG_VIDEO_USBVISION) += usbvision.o diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c new file mode 100644 index 00000000000..16c8890bf9b --- /dev/null +++ b/drivers/media/video/usbvision/usbvision-cards.c @@ -0,0 +1,158 @@ +/* + * USBVISION.H + * usbvision header file + * + * Copyright (c) 1999-2005 Joerg Heckenbach + * + * This module is part of usbvision driver project. + * Updates to driver completed by Dwaine P. Garden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include +#include +#include +#include +#include "usbvision.h" + +/* Supported Devices: A table for usbvision.c*/ + +struct usbvision_device_data_st usbvision_device_data[] = { + {0xFFF0, 0xFFF0, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Custom Dummy USBVision Device"}, + {0x0A6F, 0x0400, -1, CODEC_SAA7113, 4, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, -1, -1, -1, "Xanboo"}, + {0x050D, 0x0208, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 1, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Belkin USBView II"}, + {0x0571, 0x0002, 0, CODEC_SAA7111, 2, V4L2_STD_PAL, 0, 0, 1, 0, 0, -1, -1, -1, -1, 7, "echoFX InterView Lite"}, + {0x0573, 0x0003, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, -1, -1, -1, "USBGear USBG-V1 resp. HAMA USB"}, + {0x0573, 0x0400, -1, CODEC_SAA7113, 4, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "D-Link V100"}, + {0x0573, 0x2000, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, -1, -1, -1, "X10 USB Camera"}, + {0x0573, 0x2d00, -1, CODEC_SAA7111, 2, V4L2_STD_PAL, 1, 0, 1, 0, 0, -1, -1, -1, 3, 7, "Osprey 50"}, + {0x0573, 0x2d01, -1, CODEC_SAA7113, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Hauppauge USB-Live Model 600"}, + {0x0573, 0x2101, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 2, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Zoran Co. PMD (Nogatech) AV-grabber Manhattan"}, + {0x0573, 0x4100, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, 20, -1, "Nogatech USB-TV (NTSC) FM"}, + {0x0573, 0x4110, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, 20, -1, "PNY USB-TV (NTSC) FM"}, + {0x0573, 0x4450, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "PixelView PlayTv-USB PRO (PAL) FM"}, + {0x0573, 0x4550, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "ZTV ZT-721 2.4GHz USB A/V Receiver"}, + {0x0573, 0x4d00, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, 20, -1, "Hauppauge WinTv-USB USA"}, + {0x0573, 0x4d01, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB"}, + {0x0573, 0x4d02, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (NTSC)"}, + {0x0573, 0x4d03, -1, CODEC_SAA7111, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (SECAM) "}, + {0x0573, 0x4d10, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (NTSC) FM"}, + {0x0573, 0x4d11, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (PAL) FM"}, + {0x0573, 0x4d12, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (PAL) FM"}, + {0x0573, 0x4d2a, 0, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_MICROTUNE_4049FM5, -1, -1, 0, 3, 7, "Hauppauge WinTv USB (NTSC) FM Model 602 40201 Rev B285"}, + {0x0573, 0x4d2b, 0, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_MICROTUNE_4049FM5, -1, -1, 0, 3, 7, "Hauppauge WinTv USB (NTSC) FM Model 602 40201 Rev B282"}, + {0x0573, 0x4d2c, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_FM1216ME_MK3, -1, -1, 0, 3, 7, "Hauppauge WinTv USB (PAL/SECAM) 40209 Rev E1A5"}, + {0x0573, 0x4d20, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB II (PAL) FM Model 40201 Rev B226"}, + {0x0573, 0x4d21, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB II (PAL)"}, + {0x0573, 0x4d22, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB II (PAL) MODEL 566"}, + {0x0573, 0x4d23, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB (SECAM) 4D23"}, + {0x0573, 0x4d25, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB (SECAM) Model 40209 Rev B234"}, + {0x0573, 0x4d26, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB (SECAM) Model 40209 Rev B243"}, + {0x0573, 0x4d27, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_ALPS_TSBE1_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB Model 40204 Rev B281"}, + {0x0573, 0x4d28, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_ALPS_TSBE1_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB Model 40204 Rev B283"}, + {0x0573, 0x4d29, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB Model 40205 Rev B298"}, + {0x0573, 0x4d30, -1, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB FM Model 40211 Rev B123"}, + {0x0573, 0x4d31, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB III (PAL) FM Model 568"}, + {0x0573, 0x4d32, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB III (PAL) FM Model 573"}, + {0x0573, 0x4d35, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_MICROTUNE_4049FM5, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB III (PAL) FM Model 40219 Rev B252"}, + {0x0573, 0x4d37, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_FM1216ME_MK3, -1, -1, 0, 3, 7, "Hauppauge WinTV USB device Model 40219 Rev E189"}, + {0x0768, 0x0006, -1, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, 5, 5, -1, "Camtel Technology USB TV Genie Pro FM Model TVB330"}, + {0x07d0, 0x0001, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Digital Video Creator I"}, + {0x07d0, 0x0002, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 82, 20, 7, "Global Village GV-007 (NTSC)"}, + {0x07d0, 0x0003, 0, CODEC_SAA7113, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-50 Rev 1 (NTSC)"}, + {0x07d0, 0x0004, 0, CODEC_SAA7113, 2, V4L2_STD_PAL, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-80 Rev 1 (PAL)"}, + {0x07d0, 0x0005, 0, CODEC_SAA7113, 2, V4L2_STD_SECAM, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)"}, + {0x2304, 0x010d, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 0, 0, 1, TUNER_TEMIC_4066FY5_PAL_I, -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (PAL)"}, + {0x2304, 0x0109, -1, CODEC_SAA7111, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (SECAM)"}, + {0x2304, 0x0110, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1,128, 23, -1, "Pinnacle Studio PCTV USB (PAL) FM"}, + {0x2304, 0x0111, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, -1, -1, -1, "Miro PCTV USB"}, + {0x2304, 0x0112, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (NTSC) FM"}, + {0x2304, 0x0210, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL, -1, -1, 0, 3, 7, "Pinnacle Studio PCTV USB (PAL) FM"}, + {0x2304, 0x0212, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_TEMIC_4039FR5_NTSC, -1, -1, 0, 3, 7, "Pinnacle Studio PCTV USB (NTSC) FM"}, + {0x2304, 0x0214, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL, -1, -1, 0, 3, 7, "Pinnacle Studio PCTV USB (PAL) FM"}, + {0x2304, 0x0300, -1, CODEC_SAA7113, 2, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Pinnacle Studio Linx Video input cable (NTSC)"}, + {0x2304, 0x0301, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 1, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Pinnacle Studio Linx Video input cable (PAL)"}, + {0x2304, 0x0419, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL, -1, -1, 0, 3, 7, "Pinnacle PCTV Bungee USB (PAL) FM"}, + {0x2400, 0x4200, -1, CODEC_SAA7111, 3, VIDEO_MODE_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB"}, + {} /* Terminating entry */ +}; + +/* Supported Devices */ + +struct usb_device_id usbvision_table [] = { + { USB_DEVICE(0xFFF0, 0xFFF0) }, /* Custom Dummy USBVision Device */ + { USB_DEVICE(0x0A6F, 0x0400) }, /* Xanboo */ + { USB_DEVICE(0x050d, 0x0208) }, /* Belkin USBView II */ + { USB_DEVICE(0x0571, 0x0002) }, /* echoFX InterView Lite */ + { USB_DEVICE(0x0573, 0x0003) }, /* USBGear USBG-V1 */ + { USB_DEVICE(0x0573, 0x0400) }, /* D-Link V100 */ + { USB_DEVICE(0x0573, 0x2000) }, /* X10 USB Camera */ + { USB_DEVICE(0x0573, 0x2d00) }, /* Osprey 50 */ + { USB_DEVICE(0x0573, 0x2d01) }, /* Hauppauge USB-Live Model 600 */ + { USB_DEVICE(0x0573, 0x2101) }, /* Zoran Co. PMD (Nogatech) AV-grabber Manhattan */ + { USB_DEVICE(0x0573, 0x4100) }, /* Nogatech USB-TV FM (NTSC) */ + { USB_DEVICE(0x0573, 0x4110) }, /* PNY USB-TV (NTSC) FM */ + { USB_DEVICE(0x0573, 0x4450) }, /* PixelView PlayTv-USB PRO (PAL) FM */ + { USB_DEVICE(0x0573, 0x4550) }, /* ZTV ZT-721 2.4GHz USB A/V Receiver */ + { USB_DEVICE(0x0573, 0x4d00) }, /* Hauppauge WinTv-USB USA */ + { USB_DEVICE(0x0573, 0x4d01) }, /* Hauppauge WinTv-USB */ + { USB_DEVICE(0x0573, 0x4d02) }, /* Hauppauge WinTv-USB UK */ + { USB_DEVICE(0x0573, 0x4d03) }, /* Hauppauge WinTv-USB France */ + { USB_DEVICE(0x0573, 0x4d10) }, /* Hauppauge WinTv-USB with FM USA radio */ + { USB_DEVICE(0x0573, 0x4d11) }, /* Hauppauge WinTv-USB (PAL) with FM radio */ + { USB_DEVICE(0x0573, 0x4d12) }, /* Hauppauge WinTv-USB UK with FM Radio */ + { USB_DEVICE(0x0573, 0x4d2a) }, /* Hauppague WinTv USB Model 602 40201 Rev B285 */ + { USB_DEVICE(0x0573, 0x4d2b) }, /* Hauppague WinTv USB Model 602 40201 Rev B282 */ + { USB_DEVICE(0x0573, 0x4d2c) }, /* Hauppague WinTv USB Model 40209 Rev. E1A5 PAL*/ + { USB_DEVICE(0x0573, 0x4d20) }, /* Hauppauge WinTv-USB II (PAL) FM Model 40201 Rev B226 */ + { USB_DEVICE(0x0573, 0x4d21) }, /* Hauppauge WinTv-USB II (PAL) with FM radio*/ + { USB_DEVICE(0x0573, 0x4d22) }, /* Hauppauge WinTv-USB II (PAL) Model 566 */ + { USB_DEVICE(0x0573, 0x4d23) }, /* Hauppauge WinTv-USB France 4D23*/ + { USB_DEVICE(0x0573, 0x4d25) }, /* Hauppauge WinTv-USB Model 40209 rev B234 */ + { USB_DEVICE(0x0573, 0x4d26) }, /* Hauppauge WinTv-USB Model 40209 Rev B243 */ + { USB_DEVICE(0x0573, 0x4d27) }, /* Hauppauge WinTv-USB Model 40204 Rev B281 */ + { USB_DEVICE(0x0573, 0x4d28) }, /* Hauppauge WinTv-USB Model 40204 Rev B283 */ + { USB_DEVICE(0x0573, 0x4d29) }, /* Hauppauge WinTv-USB Model 40205 Rev B298 */ + { USB_DEVICE(0x0573, 0x4d30) }, /* Hauppauge WinTv-USB FM Model 40211 Rev B123 */ + { USB_DEVICE(0x0573, 0x4d31) }, /* Hauppauge WinTv-USB III (PAL) with FM radio Model 568 */ + { USB_DEVICE(0x0573, 0x4d32) }, /* Hauppauge WinTv-USB III (PAL) FM Model 573 */ + { USB_DEVICE(0x0573, 0x4d35) }, /* Hauppauge WinTv-USB III (SECAM) FM Model 40219 Rev B252 */ + { USB_DEVICE(0x0573, 0x4d37) }, /* Hauppauge WinTv-USB Model 40219 Rev E189 */ + { USB_DEVICE(0x0768, 0x0006) }, /* Camtel Technology USB TV Genie Pro FM Model TVB330 */ + { USB_DEVICE(0x07d0, 0x0001) }, /* Digital Video Creator I */ + { USB_DEVICE(0x07d0, 0x0002) }, /* Global Village GV-007 (NTSC) */ + { USB_DEVICE(0x07d0, 0x0003) }, /* Dazzle Fusion Model DVC-50 Rev 1 (NTSC) */ + { USB_DEVICE(0x07d0, 0x0004) }, /* Dazzle Fusion Model DVC-80 Rev 1 (PAL) */ + { USB_DEVICE(0x07d0, 0x0005) }, /* Dazzle Fusion Model DVC-90 Rev 1 (SECAM) */ + { USB_DEVICE(0x2304, 0x010d) }, /* Pinnacle Studio PCTV USB (PAL) */ + { USB_DEVICE(0x2304, 0x0109) }, /* Pinnacle Studio PCTV USB (SECAM) */ + { USB_DEVICE(0x2304, 0x0110) }, /* Pinnacle Studio PCTV USB (PAL) */ + { USB_DEVICE(0x2304, 0x0111) }, /* Miro PCTV USB */ + { USB_DEVICE(0x2304, 0x0112) }, /* Pinnacle Studio PCTV USB (NTSC) with FM radio */ + { USB_DEVICE(0x2304, 0x0210) }, /* Pinnacle Studio PCTV USB (PAL) with FM radio */ + { USB_DEVICE(0x2304, 0x0212) }, /* Pinnacle Studio PCTV USB (NTSC) with FM radio */ + { USB_DEVICE(0x2304, 0x0214) }, /* Pinnacle Studio PCTV USB (PAL) with FM radio */ + { USB_DEVICE(0x2304, 0x0300) }, /* Pinnacle Studio Linx Video input cable (NTSC) */ + { USB_DEVICE(0x2304, 0x0301) }, /* Pinnacle Studio Linx Video input cable (PAL) */ + { USB_DEVICE(0x2304, 0x0419) }, /* Pinnacle PCTV Bungee USB (PAL) FM */ + + { USB_DEVICE(0x2400, 0x4200) }, /* Hauppauge WinTv-USB2 Model 42012 */ + + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE (usb, usbvision_table); diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index 62699ca020a..a23fcd15a1d 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -339,12 +339,10 @@ #include #include #include -#include #include #include #include #include -#include "usbvision-i2c.h" #define USBVISION_DRIVER_VERSION_MAJOR 0 #define USBVISION_DRIVER_VERSION_MINOR 8 @@ -428,6 +426,18 @@ enum { ISOC_MODE_COMPRESS = 0x60, }; +static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = { + { 1, 1, 8, V4L2_PIX_FMT_GREY , "GREY" }, + { 1, 2, 16, V4L2_PIX_FMT_RGB565 , "RGB565" }, + { 1, 3, 24, V4L2_PIX_FMT_RGB24 , "RGB24" }, + { 1, 4, 32, V4L2_PIX_FMT_RGB32 , "RGB32" }, + { 1, 2, 16, V4L2_PIX_FMT_RGB555 , "RGB555" }, + { 1, 2, 16, V4L2_PIX_FMT_YUYV , "YUV422" }, + { 1, 2, 12, V4L2_PIX_FMT_YVU420 , "YUV420P" }, // 1.5 ! + { 1, 2, 16, V4L2_PIX_FMT_YUV422P , "YUV422P" } +}; + + /* * The value of 'scratch_buf_size' affects quality of the picture * in many ways. Shorter buffers may cause loss of data when client @@ -5691,8 +5701,6 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf) } -MODULE_DEVICE_TABLE (usb, usbvision_table); - static struct usb_driver usbvision_driver = { .name = "usbvision", .id_table = usbvision_table, diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h index b03e4eabfb0..813b258f89c 100644 --- a/drivers/media/video/usbvision/usbvision.h +++ b/drivers/media/video/usbvision/usbvision.h @@ -27,6 +27,8 @@ #define __LINUX_USBVISION_H #include +#include +#include "usbvision-i2c.h" #ifndef VID_HARDWARE_USBVISION #define VID_HARDWARE_USBVISION 34 /* USBVision Video Grabber */ @@ -244,21 +246,12 @@ struct usbvision_sbuf { #define USBVISION_IIC_LRNACK 0x30 #define USBVISION_FRAME_FORMAT_PARAM_INTRA (1<<7) -static struct usbvision_v4l2_format_st { +struct usbvision_v4l2_format_st { int supported; int bytes_per_pixel; int depth; int format; char *desc; -} usbvision_v4l2_format[] = { - { 1, 1, 8, V4L2_PIX_FMT_GREY , "GREY" }, - { 1, 2, 16, V4L2_PIX_FMT_RGB565 , "RGB565" }, - { 1, 3, 24, V4L2_PIX_FMT_RGB24 , "RGB24" }, - { 1, 4, 32, V4L2_PIX_FMT_RGB32 , "RGB32" }, - { 1, 2, 16, V4L2_PIX_FMT_RGB555 , "RGB555" }, - { 1, 2, 16, V4L2_PIX_FMT_YUYV , "YUV422" }, - { 1, 2, 12, V4L2_PIX_FMT_YVU420 , "YUV420P" }, // 1.5 ! - { 1, 2, 16, V4L2_PIX_FMT_YUV422P , "YUV422P" } }; #define USBVISION_SUPPORTED_PALETTES ARRAY_SIZE(usbvision_v4l2_format) @@ -309,153 +302,31 @@ struct usbvision_frame { #define BRIDGE_NT1004 1004 #define BRIDGE_NT1005 1005 -/* Supported Devices: A table for usbvision.c*/ - -static struct usbvision_device_data_st { - int idVendor; - int idProduct; - int Interface; /* to handle special interface number like BELKIN and Hauppauge WinTV-USB II */ - int Codec; - int VideoChannels; - __u64 VideoNorm; - int AudioChannels; - int Radio; - int vbi; - int Tuner; - int TunerType; - int Vin_Reg1; - int Vin_Reg2; - int X_Offset; - int Y_Offset; - int Dvi_yuv; - char *ModelString; -} usbvision_device_data[] = { - {0xFFF0, 0xFFF0, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Custom Dummy USBVision Device"}, - {0x0A6F, 0x0400, -1, CODEC_SAA7113, 4, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, -1, -1, -1, "Xanboo"}, - {0x050D, 0x0208, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 1, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Belkin USBView II"}, - {0x0571, 0x0002, 0, CODEC_SAA7111, 2, V4L2_STD_PAL, 0, 0, 1, 0, 0, -1, -1, -1, -1, 7, "echoFX InterView Lite"}, - {0x0573, 0x0003, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, -1, -1, -1, "USBGear USBG-V1 resp. HAMA USB"}, - {0x0573, 0x0400, -1, CODEC_SAA7113, 4, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "D-Link V100"}, - {0x0573, 0x2000, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, -1, -1, -1, "X10 USB Camera"}, - {0x0573, 0x2d00, -1, CODEC_SAA7111, 2, V4L2_STD_PAL, 1, 0, 1, 0, 0, -1, -1, -1, 3, 7, "Osprey 50"}, - {0x0573, 0x2d01, -1, CODEC_SAA7113, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Hauppauge USB-Live Model 600"}, - {0x0573, 0x2101, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 2, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Zoran Co. PMD (Nogatech) AV-grabber Manhattan"}, - {0x0573, 0x4100, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, 20, -1, "Nogatech USB-TV (NTSC) FM"}, - {0x0573, 0x4110, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, 20, -1, "PNY USB-TV (NTSC) FM"}, - {0x0573, 0x4450, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "PixelView PlayTv-USB PRO (PAL) FM"}, - {0x0573, 0x4550, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "ZTV ZT-721 2.4GHz USB A/V Receiver"}, - {0x0573, 0x4d00, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, 20, -1, "Hauppauge WinTv-USB USA"}, - {0x0573, 0x4d01, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB"}, - {0x0573, 0x4d02, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (NTSC)"}, - {0x0573, 0x4d03, -1, CODEC_SAA7111, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (SECAM) "}, - {0x0573, 0x4d10, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (NTSC) FM"}, - {0x0573, 0x4d11, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (PAL) FM"}, - {0x0573, 0x4d12, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (PAL) FM"}, - {0x0573, 0x4d2a, 0, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_MICROTUNE_4049FM5, -1, -1, 0, 3, 7, "Hauppauge WinTv USB (NTSC) FM Model 602 40201 Rev B285"}, - {0x0573, 0x4d2b, 0, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_MICROTUNE_4049FM5, -1, -1, 0, 3, 7, "Hauppauge WinTv USB (NTSC) FM Model 602 40201 Rev B282"}, - {0x0573, 0x4d2c, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_FM1216ME_MK3, -1, -1, 0, 3, 7, "Hauppauge WinTv USB (PAL/SECAM) 40209 Rev E1A5"}, - {0x0573, 0x4d20, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB II (PAL) FM Model 40201 Rev B226"}, - {0x0573, 0x4d21, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB II (PAL)"}, - {0x0573, 0x4d22, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB II (PAL) MODEL 566"}, - {0x0573, 0x4d23, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB (SECAM) 4D23"}, - {0x0573, 0x4d25, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB (SECAM) Model 40209 Rev B234"}, - {0x0573, 0x4d26, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB (SECAM) Model 40209 Rev B243"}, - {0x0573, 0x4d27, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_ALPS_TSBE1_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB Model 40204 Rev B281"}, - {0x0573, 0x4d28, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_ALPS_TSBE1_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB Model 40204 Rev B283"}, - {0x0573, 0x4d29, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB Model 40205 Rev B298"}, - {0x0573, 0x4d30, -1, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB FM Model 40211 Rev B123"}, - {0x0573, 0x4d31, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB III (PAL) FM Model 568"}, - {0x0573, 0x4d32, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB III (PAL) FM Model 573"}, - {0x0573, 0x4d35, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_MICROTUNE_4049FM5, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB III (PAL) FM Model 40219 Rev B252"}, - {0x0573, 0x4d37, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_FM1216ME_MK3, -1, -1, 0, 3, 7, "Hauppauge WinTV USB device Model 40219 Rev E189"}, - {0x0768, 0x0006, -1, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, 5, 5, -1, "Camtel Technology USB TV Genie Pro FM Model TVB330"}, - {0x07d0, 0x0001, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Digital Video Creator I"}, - {0x07d0, 0x0002, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 82, 20, 7, "Global Village GV-007 (NTSC)"}, - {0x07d0, 0x0003, 0, CODEC_SAA7113, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-50 Rev 1 (NTSC)"}, - {0x07d0, 0x0004, 0, CODEC_SAA7113, 2, V4L2_STD_PAL, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-80 Rev 1 (PAL)"}, - {0x07d0, 0x0005, 0, CODEC_SAA7113, 2, V4L2_STD_SECAM, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)"}, - {0x2304, 0x010d, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 0, 0, 1, TUNER_TEMIC_4066FY5_PAL_I, -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (PAL)"}, - {0x2304, 0x0109, -1, CODEC_SAA7111, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (SECAM)"}, - {0x2304, 0x0110, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1,128, 23, -1, "Pinnacle Studio PCTV USB (PAL) FM"}, - {0x2304, 0x0111, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, -1, -1, -1, "Miro PCTV USB"}, - {0x2304, 0x0112, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (NTSC) FM"}, - {0x2304, 0x0210, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL, -1, -1, 0, 3, 7, "Pinnacle Studio PCTV USB (PAL) FM"}, - {0x2304, 0x0212, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_TEMIC_4039FR5_NTSC, -1, -1, 0, 3, 7, "Pinnacle Studio PCTV USB (NTSC) FM"}, - {0x2304, 0x0214, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL, -1, -1, 0, 3, 7, "Pinnacle Studio PCTV USB (PAL) FM"}, - {0x2304, 0x0300, -1, CODEC_SAA7113, 2, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Pinnacle Studio Linx Video input cable (NTSC)"}, - {0x2304, 0x0301, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 1, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Pinnacle Studio Linx Video input cable (PAL)"}, - {0x2304, 0x0419, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL, -1, -1, 0, 3, 7, "Pinnacle PCTV Bungee USB (PAL) FM"}, - {0x2400, 0x4200, -1, CODEC_SAA7111, 3, VIDEO_MODE_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB"}, - {} /* Terminating entry */ -}; - +#define USBVISION_I2C_CLIENTS_MAX 8 -/* Supported Devices: A table for the usb.c*/ - -static struct usb_device_id usbvision_table [] = { - { USB_DEVICE(0xFFF0, 0xFFF0) }, /* Custom Dummy USBVision Device */ - { USB_DEVICE(0x0A6F, 0x0400) }, /* Xanboo */ - { USB_DEVICE(0x050d, 0x0208) }, /* Belkin USBView II */ - { USB_DEVICE(0x0571, 0x0002) }, /* echoFX InterView Lite */ - { USB_DEVICE(0x0573, 0x0003) }, /* USBGear USBG-V1 */ - { USB_DEVICE(0x0573, 0x0400) }, /* D-Link V100 */ - { USB_DEVICE(0x0573, 0x2000) }, /* X10 USB Camera */ - { USB_DEVICE(0x0573, 0x2d00) }, /* Osprey 50 */ - { USB_DEVICE(0x0573, 0x2d01) }, /* Hauppauge USB-Live Model 600 */ - { USB_DEVICE(0x0573, 0x2101) }, /* Zoran Co. PMD (Nogatech) AV-grabber Manhattan */ - { USB_DEVICE(0x0573, 0x4100) }, /* Nogatech USB-TV FM (NTSC) */ - { USB_DEVICE(0x0573, 0x4110) }, /* PNY USB-TV (NTSC) FM */ - { USB_DEVICE(0x0573, 0x4450) }, /* PixelView PlayTv-USB PRO (PAL) FM */ - { USB_DEVICE(0x0573, 0x4550) }, /* ZTV ZT-721 2.4GHz USB A/V Receiver */ - { USB_DEVICE(0x0573, 0x4d00) }, /* Hauppauge WinTv-USB USA */ - { USB_DEVICE(0x0573, 0x4d01) }, /* Hauppauge WinTv-USB */ - { USB_DEVICE(0x0573, 0x4d02) }, /* Hauppauge WinTv-USB UK */ - { USB_DEVICE(0x0573, 0x4d03) }, /* Hauppauge WinTv-USB France */ - { USB_DEVICE(0x0573, 0x4d10) }, /* Hauppauge WinTv-USB with FM USA radio */ - { USB_DEVICE(0x0573, 0x4d11) }, /* Hauppauge WinTv-USB (PAL) with FM radio */ - { USB_DEVICE(0x0573, 0x4d12) }, /* Hauppauge WinTv-USB UK with FM Radio */ - { USB_DEVICE(0x0573, 0x4d2a) }, /* Hauppague WinTv USB Model 602 40201 Rev B285 */ - { USB_DEVICE(0x0573, 0x4d2b) }, /* Hauppague WinTv USB Model 602 40201 Rev B282 */ - { USB_DEVICE(0x0573, 0x4d2c) }, /* Hauppague WinTv USB Model 40209 Rev. E1A5 PAL*/ - { USB_DEVICE(0x0573, 0x4d20) }, /* Hauppauge WinTv-USB II (PAL) FM Model 40201 Rev B226 */ - { USB_DEVICE(0x0573, 0x4d21) }, /* Hauppauge WinTv-USB II (PAL) with FM radio*/ - { USB_DEVICE(0x0573, 0x4d22) }, /* Hauppauge WinTv-USB II (PAL) Model 566 */ - { USB_DEVICE(0x0573, 0x4d23) }, /* Hauppauge WinTv-USB France 4D23*/ - { USB_DEVICE(0x0573, 0x4d25) }, /* Hauppauge WinTv-USB Model 40209 rev B234 */ - { USB_DEVICE(0x0573, 0x4d26) }, /* Hauppauge WinTv-USB Model 40209 Rev B243 */ - { USB_DEVICE(0x0573, 0x4d27) }, /* Hauppauge WinTv-USB Model 40204 Rev B281 */ - { USB_DEVICE(0x0573, 0x4d28) }, /* Hauppauge WinTv-USB Model 40204 Rev B283 */ - { USB_DEVICE(0x0573, 0x4d29) }, /* Hauppauge WinTv-USB Model 40205 Rev B298 */ - { USB_DEVICE(0x0573, 0x4d30) }, /* Hauppauge WinTv-USB FM Model 40211 Rev B123 */ - { USB_DEVICE(0x0573, 0x4d31) }, /* Hauppauge WinTv-USB III (PAL) with FM radio Model 568 */ - { USB_DEVICE(0x0573, 0x4d32) }, /* Hauppauge WinTv-USB III (PAL) FM Model 573 */ - { USB_DEVICE(0x0573, 0x4d35) }, /* Hauppauge WinTv-USB III (SECAM) FM Model 40219 Rev B252 */ - { USB_DEVICE(0x0573, 0x4d37) }, /* Hauppauge WinTv-USB Model 40219 Rev E189 */ - { USB_DEVICE(0x0768, 0x0006) }, /* Camtel Technology USB TV Genie Pro FM Model TVB330 */ - { USB_DEVICE(0x07d0, 0x0001) }, /* Digital Video Creator I */ - { USB_DEVICE(0x07d0, 0x0002) }, /* Global Village GV-007 (NTSC) */ - { USB_DEVICE(0x07d0, 0x0003) }, /* Dazzle Fusion Model DVC-50 Rev 1 (NTSC) */ - { USB_DEVICE(0x07d0, 0x0004) }, /* Dazzle Fusion Model DVC-80 Rev 1 (PAL) */ - { USB_DEVICE(0x07d0, 0x0005) }, /* Dazzle Fusion Model DVC-90 Rev 1 (SECAM) */ - { USB_DEVICE(0x2304, 0x010d) }, /* Pinnacle Studio PCTV USB (PAL) */ - { USB_DEVICE(0x2304, 0x0109) }, /* Pinnacle Studio PCTV USB (SECAM) */ - { USB_DEVICE(0x2304, 0x0110) }, /* Pinnacle Studio PCTV USB (PAL) */ - { USB_DEVICE(0x2304, 0x0111) }, /* Miro PCTV USB */ - { USB_DEVICE(0x2304, 0x0112) }, /* Pinnacle Studio PCTV USB (NTSC) with FM radio */ - { USB_DEVICE(0x2304, 0x0210) }, /* Pinnacle Studio PCTV USB (PAL) with FM radio */ - { USB_DEVICE(0x2304, 0x0212) }, /* Pinnacle Studio PCTV USB (NTSC) with FM radio */ - { USB_DEVICE(0x2304, 0x0214) }, /* Pinnacle Studio PCTV USB (PAL) with FM radio */ - { USB_DEVICE(0x2304, 0x0300) }, /* Pinnacle Studio Linx Video input cable (NTSC) */ - { USB_DEVICE(0x2304, 0x0301) }, /* Pinnacle Studio Linx Video input cable (PAL) */ - { USB_DEVICE(0x2304, 0x0419) }, /* Pinnacle PCTV Bungee USB (PAL) FM */ - - { USB_DEVICE(0x2400, 0x4200) }, /* Hauppauge WinTv-USB2 Model 42012 */ - - { } /* Terminating entry */ +struct usbvision_device_data_st { + int idVendor; + int idProduct; + int Interface; /* to handle special interface number like BELKIN and Hauppauge WinTV-USB II */ + int Codec; + int VideoChannels; + __u64 VideoNorm; + int AudioChannels; + int Radio; + int vbi; + int Tuner; + int TunerType; + int Vin_Reg1; + int Vin_Reg2; + int X_Offset; + int Y_Offset; + int Dvi_yuv; + char *ModelString; }; - -#define USBVISION_I2C_CLIENTS_MAX 8 +/* Declared on usbvision-cards.c */ +extern struct usbvision_device_data_st usbvision_device_data[]; +extern struct usb_device_id usbvision_table[]; struct usb_usbvision { struct video_device *vdev; /* Video Device */ -- cgit v1.2.3 From c8400c700723936d9333c977e51fa77062d26dd4 Mon Sep 17 00:00:00 2001 From: Thierry MERLE Date: Mon, 4 Dec 2006 08:31:04 -0300 Subject: V4L/DVB (4924): Fix some bugs on usbvision due to the merge into one module Found the bug that prevented the driver from loading : a module param conflict between usbvision-i2c and usbvision-core (debug parameter). - correct the module param "debug" conflics in usbvision-i2c.c and usbvision-core.c - add some debug printouts in usbvision-core.c VDIOC_QBUF/VIDIOC_DQBUF - usbvision-core.c : add vb->field = V4L2_FIELD_NONE in VIDIOC_DQBUF Signed-off-by: Thierry MERLE Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/usbvision/usbvision-core.c | 6 ++++-- drivers/media/video/usbvision/usbvision-i2c.c | 20 ++++++++------------ 2 files changed, 12 insertions(+), 14 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index a23fcd15a1d..da422e7793a 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -4240,6 +4240,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, /* set v4l2_format index */ frame->v4l2_format = usbvision->palette; + PDEBUG(DBG_IOCTL, "VIDIOC_QBUF frame=%d",vb->index); return usbvision_new_frame(usbvision, vb->index); } @@ -4269,8 +4270,8 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, if (vb->index == -1) return -EINVAL; - PDEBUG(DBG_IOCTL, "VIDIOC_DQBUF frame=%d, grabstate=%d", - vb->index, usbvision->frame[vb->index].grabstate); + PDEBUG(DBG_IOCTL, "VIDIOC_DQBUF frame=%d, grabstate=%d, curframeNum=%d", + vb->index, usbvision->frame[vb->index].grabstate,usbvision->curFrameNum); switch (usbvision->frame[vb->index].grabstate) { case FrameState_Unused: @@ -4295,6 +4296,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, errCode = (usbvision->frame[vb->index].grabstate == FrameState_Error) ? -EIO : 0; vb->memory = V4L2_MEMORY_MMAP; vb->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE; + vb->field = V4L2_FIELD_NONE; vb->sequence = usbvision->frame[vb->index].sequence; usbvision->frame[vb->index].grabstate = FrameState_Unused; break; diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c index e050e5559ac..466e11f4584 100644 --- a/drivers/media/video/usbvision/usbvision-i2c.c +++ b/drivers/media/video/usbvision/usbvision-i2c.c @@ -39,18 +39,14 @@ #include #include "usbvision-i2c.h" -static int debug = 0; +static int debug_i2c_usb = 0; #if defined(module_param) // Showing parameters under SYSFS -module_param (debug, int, 0444); // debug mode of the device driver +module_param (debug_i2c_usb, int, 0444); // debug_i2c_usb mode of the device driver #else -MODULE_PARM(debug, "i"); // debug mode of the device driver +MODULE_PARM(debug_i2c_usb, "i"); // debug_i2c_usb mode of the device driver #endif -MODULE_AUTHOR("Joerg Heckenbach"); -MODULE_DESCRIPTION("I2C algorithm for USB-I2C-bridges"); -MODULE_LICENSE("GPL"); - static inline int try_write_address(struct i2c_adapter *i2c_adap, unsigned char addr, int retries) @@ -71,7 +67,7 @@ static inline int try_write_address(struct i2c_adapter *i2c_adap, break; udelay(adap->udelay); } - if (debug) { + if (debug_i2c_usb) { if (i) { info("%s: Needed %d retries for address %#2x", __FUNCTION__, i, addr); info("%s: Maybe there's no device at this address", __FUNCTION__); @@ -98,7 +94,7 @@ static inline int try_read_address(struct i2c_adapter *i2c_adap, break; udelay(adap->udelay); } - if (debug) { + if (debug_i2c_usb) { if (i) { info("%s: Needed %d retries for address %#2x", __FUNCTION__, i, addr); info("%s: Maybe there's no device at this address", __FUNCTION__); @@ -170,7 +166,7 @@ usb_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) pmsg = &msgs[i]; ret = usb_find_address(i2c_adap, pmsg, i2c_adap->retries, &addr); if (ret != 0) { - if (debug) { + if (debug_i2c_usb) { info("%s: got NAK from device, message #%d\n", __FUNCTION__, i); } return (ret < 0) ? ret : -EREMOTEIO; @@ -236,7 +232,7 @@ int usbvision_i2c_usb_add_bus(struct i2c_adapter *adap) i2c_add_adapter(adap); - if (debug) { + if (debug_i2c_usb) { info("i2c bus for %s registered", adap->name); } @@ -249,7 +245,7 @@ int usbvision_i2c_usb_del_bus(struct i2c_adapter *adap) i2c_del_adapter(adap); - if (debug) { + if (debug_i2c_usb) { info("i2c bus for %s unregistered", adap->name); } #ifdef MODULE -- cgit v1.2.3 From cc9e595a585a4f067dcfdc67e7c4432702ea28ac Mon Sep 17 00:00:00 2001 From: Thierry MERLE Date: Mon, 4 Dec 2006 08:31:07 -0300 Subject: V4L/DVB (4925): Corrected and separated the Kconfig for usbvision Signed-off-by: Thierry MERLE Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 12 +----------- drivers/media/video/usbvision/Kconfig | 12 ++++++++++++ 2 files changed, 13 insertions(+), 11 deletions(-) create mode 100644 drivers/media/video/usbvision/Kconfig (limited to 'drivers/media/video') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 9365a8dd44e..29a11c1db1b 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -686,17 +686,7 @@ source "drivers/media/video/pvrusb2/Kconfig" source "drivers/media/video/em28xx/Kconfig" -config VIDEO_USBVISION - tristate "USB video devices based on NT1003/1005/1005" - depends on I2C && VIDEO_V4L2 - select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO - ---help--- - There are more than 50 different USB video devices based on - NT1003/1004/1005 USB Bridges. This driver enables using those - devices. - - To compile this driver as a module, choose M here: the - module will be called ovcamchip. +source "drivers/media/video/usbvision/Kconfig" source "drivers/media/video/usbvideo/Kconfig" diff --git a/drivers/media/video/usbvision/Kconfig b/drivers/media/video/usbvision/Kconfig new file mode 100644 index 00000000000..fc24ef05b3f --- /dev/null +++ b/drivers/media/video/usbvision/Kconfig @@ -0,0 +1,12 @@ +config VIDEO_USBVISION + tristate "USB video devices based on Nogatech NT1003/1004/1005" + depends on I2C && VIDEO_V4L2 + select VIDEO_TUNER + select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO + ---help--- + There are more than 50 different USB video devices based on + NT1003/1004/1005 USB Bridges. This driver enables using those + devices. + + To compile this driver as a module, choose M here: the + module will be called usbvision. -- cgit v1.2.3 From 18d8a4540caddaa9a42fb4dbc04c75c4b806278b Mon Sep 17 00:00:00 2001 From: Dwaine Garden Date: Mon, 4 Dec 2006 08:31:11 -0300 Subject: V4L/DVB (4926): Fix USBVision handling of VIDIOC_QUERYCTRL There's a better (and recommended) way for handling VIDIOC_QUERYCTRL. This patch will fix the issue where the hardware control values were invalid and stops the SAA7115 module from complaining about invalid values. saa7115 4-0024: invalid brightness setting 32768 saa7115 4-0024: invalid contrast setting 49152 saa7115 4-0024: invalid hue setting 32768 saa7115 4-0024: invalid saturation setting 32768 Signed-off-by: Dwaine Garden Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/usbvision/usbvision-core.c | 399 +++++++++++-------------- 1 file changed, 182 insertions(+), 217 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index da422e7793a..f225701f16f 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -1,7 +1,7 @@ /* * USB USBVISION Video device driver 0.9.8.3cvs (For Kernel 2.4.19-2.4.32 + 2.6.0-2.6.16) * - * + * * * Copyright (c) 1999-2005 Joerg Heckenbach * @@ -181,7 +181,7 @@ * June 2, 2004 - 0.9.6 Dwaine Garden * - Fixed sourceforge.net cvs repository. * - Added #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,26) for .owner to help compiling under kernels 2.4.x which do not have the i2c v2.8.x updates. - * - Added device Hauppauge WinTv-USB III (PAL) FM Model 597 to usbvision.h + * - Added device Hauppauge WinTv-USB III (PAL) FM Model 597 to usbvision.h * * July 1, 2004 -0.9.6 Dwaine Garden * - Patch was submitted by Hal Finkel to fix the problem with the tuner not working under kernel 2.6.7. @@ -206,7 +206,7 @@ * - Changed usbvision_muxsel to address the problem with black & white s-video output for NT1004 devices with saa7114 video decoder. Thanks to Emmanuel for the patch and testing. * - Fixed up SECAM devices which could not properly output video. Changes to usbmuxsel. Thanks to Emmanuel for the patch and everyone with a SECAM device which help test. * - Removed some commented out code. Clean up. - * - Tried to fix up the annoying empty directories in the sourceforge.net cvs. Fuck it up again. 8*( + * - Tried to fix up the annoying empty directories in the sourceforge.net cvs. Fuck it up again. 8*( * * November 15, 2004 - 0.9.8 Dwaine Garden * - Release new tar - 0.9.8 on sourceforge.net @@ -228,7 +228,7 @@ * - Better support for mythtv. * * January 2, 2005 - 0.9.8.1cvs Dwaine Garden - * - Setup that you can specify which device is used for video. Default is auto detect next available device number eg. /dev/videoX + * - Setup that you can specify which device is used for video. Default is auto detect next available device number eg. /dev/videoX * - Setup that you can specify which device is used for radio. Default is auto detect next available device number eg. /dev/radioX * - usb_unlink_urb() is deprecated for synchronous unlinks. Using usb_kill_urb instead. * - usbvision_kvirt_to_pa is deprecated. Removed. @@ -251,39 +251,39 @@ * April 20, 2005 - 0.9.8.2cvs Dwaine Garden * - Release lock in usbvision_v4l_read_done. -Thanks to nplanel for the patch. * - Additional comments to the driver. - * - Fixed some spelling mistakes. 8*) + * - Fixed some spelling mistakes. 8*) * * April 23, 2005 - 0.9.8.2cvs Joerg Heckenbach * - Found bug in usbvision line counting. Now there should be no spurious lines in the image any longer. - * - Swapped usbvision_register_video and usbvision_configure_video to fix problem with PowerOnAtOpen=0. + * - Swapped usbvision_register_video and usbvision_configure_video to fix problem with PowerOnAtOpen=0. * Thanks to Erwan Velu * * April 26, 2005 - 0.9.8.2cvs Joerg Heckenbach * - Fixed problem with rmmod module and oppses. Replaced vfree(usbvision->overlay_base) with iounmap(usbvision->overlay_base). - * - Added function usb_get_dev(dev) and ; To help with unloading the module multiple times without crashing. + * - Added function usb_get_dev(dev) and ; To help with unloading the module multiple times without crashing. * (Keep the reference count in kobjects correct) * * June 14, 2005 - 0.9.8.2cvs Dwaine - * - Missed a change in saa7113.c for checking kernel version. Added conditional if's. + * - Missed a change in saa7113.c for checking kernel version. Added conditional if's. * * June 15, 2005 - 0.9.8.2cvs Dwaine - * - Added new device WinTV device VendorId 0573 and ProductId 4d29. + * - Added new device WinTV device VendorId 0573 and ProductId 4d29. * - Hacked some support for newer NT1005 devices. This devices only seem to have one configuration, not multiple configurations like the NT1004. * * June 29, 2005 - 0.9.8.2cvs Dwaine - * - Added new device WinTV device VendorId 0573 and ProductId 4d37. - * - Because of the first empty entry in usbvision_table, modutils failed to create the necessary entries for modules.usbmap. - * This means hotplug won't work for usbvision. Thanks to Gary Ng. + * - Added new device WinTV device VendorId 0573 and ProductId 4d37. + * - Because of the first empty entry in usbvision_table, modutils failed to create the necessary entries for modules.usbmap. + * This means hotplug won't work for usbvision. Thanks to Gary Ng. * - Sent an e-mail to the maintainer of usb.ids. New devices identified need to be added. - * - Fixed compile error with saa7113 under kernel 2.6.12. + * - Fixed compile error with saa7113 under kernel 2.6.12. * * July 6, 2005 - 0.9.8.2cvs Dwaine - * - Patch submitted by Gary Ng for two additional procfs entries. Device Input and Frequency setting. + * - Patch submitted by Gary Ng for two additional procfs entries. Device Input and Frequency setting. * * July 12, 2005 - 0.9.8.2cvs Dwaine * - New tuner identified for some devices it's called TCL_MFPE05. This tuner uses the same API as tuner 38 in tuner.c. * - Thanks to lynx31 for contacting Hauppage and asking them. - * - I have no clue as to which devices use this new tuner, so people will have to contact me and tell me. + * - I have no clue as to which devices use this new tuner, so people will have to contact me and tell me. * * July 21, 2005 - 0.9.8.2cvs Dwaine * - Patched usbvision.c with missing ifdef kernversion statement so the module will compile with older kernels and v4l. @@ -305,11 +305,11 @@ * -Changed number of bytes for i2c write to 4 as per the NT100X spec sheet. Thanks to Merlum for finding it. * -Remove the radio option for device Hauppauge WinTV USB device Model 40219 Rev E189. This device does not have a FM radio. Thanks to Shadwell. * -Added radio option for device Hauppauge WinTV USB device Model 40219 Rev E189 again. Just got an e-mail indicating their device has one. 8*) - * + * * Aug 27, 2006 - 0.9.8.3cvs Dwaine * -Changed ifdef statement so the usbvision driver will compile with kernels at 2.6.12. * -Updated readme files for new updated tuner list for v4l devices. - * + * * * * TODO: @@ -351,8 +351,8 @@ #define USBVISION_VERSION __stringify(USBVISION_DRIVER_VERSION_MAJOR) "." __stringify(USBVISION_DRIVER_VERSION_MINOR) "." __stringify(USBVISION_DRIVER_VERSION_PATCHLEVEL) " " USBVISION_DRIVER_VERSION_COMMENT #define USBVISION_DRIVER_VERSION KERNEL_VERSION(USBVISION_DRIVER_VERSION_MAJOR,USBVISION_DRIVER_VERSION_MINOR,USBVISION_DRIVER_VERSION_PATCHLEVEL) -#include -#include +#include +#include #include #include @@ -427,14 +427,14 @@ enum { }; static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = { - { 1, 1, 8, V4L2_PIX_FMT_GREY , "GREY" }, - { 1, 2, 16, V4L2_PIX_FMT_RGB565 , "RGB565" }, - { 1, 3, 24, V4L2_PIX_FMT_RGB24 , "RGB24" }, - { 1, 4, 32, V4L2_PIX_FMT_RGB32 , "RGB32" }, - { 1, 2, 16, V4L2_PIX_FMT_RGB555 , "RGB555" }, - { 1, 2, 16, V4L2_PIX_FMT_YUYV , "YUV422" }, - { 1, 2, 12, V4L2_PIX_FMT_YVU420 , "YUV420P" }, // 1.5 ! - { 1, 2, 16, V4L2_PIX_FMT_YUV422P , "YUV422P" } + { 1, 1, 8, V4L2_PIX_FMT_GREY , "GREY" }, + { 1, 2, 16, V4L2_PIX_FMT_RGB565 , "RGB565" }, + { 1, 3, 24, V4L2_PIX_FMT_RGB24 , "RGB24" }, + { 1, 4, 32, V4L2_PIX_FMT_RGB32 , "RGB32" }, + { 1, 2, 16, V4L2_PIX_FMT_RGB555 , "RGB555" }, + { 1, 2, 16, V4L2_PIX_FMT_YUYV , "YUV422" }, + { 1, 2, 12, V4L2_PIX_FMT_YVU420 , "YUV420P" }, // 1.5 ! + { 1, 2, 16, V4L2_PIX_FMT_YUV422P , "YUV422P" } }; @@ -448,11 +448,6 @@ static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = { #define DEFAULT_SCRATCH_BUF_SIZE (0x20000) // 128kB memory scratch buffer static const int scratch_buf_size = DEFAULT_SCRATCH_BUF_SIZE; -static int init_brightness = 128; // Initalize the brightness of the video device -static int init_contrast = 192; // Initalize the contrast of the video device -static int init_saturation = 128; // Initalize the staturation mode of the video device -static int init_hue = 128; // Initalize the Hue settings of the video device - // Function prototypes static int usbvision_restart_isoc(struct usb_usbvision *usbvision); static int usbvision_begin_streaming(struct usb_usbvision *usbvision); @@ -466,9 +461,9 @@ static int usbvision_unrequest_intra (struct usb_usbvision *usbvision); static int usbvision_adjust_compression (struct usb_usbvision *usbvision); static int usbvision_measure_bandwidth (struct usb_usbvision *usbvision); static void usbvision_release(struct usb_usbvision *usbvision); -static int usbvision_set_input(struct usb_usbvision *usbvision); -static int usbvision_set_output(struct usb_usbvision *usbvision, int width, int height); -static void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd, void *arg); +static int usbvision_set_input(struct usb_usbvision *usbvision); +static int usbvision_set_output(struct usb_usbvision *usbvision, int width, int height); +static void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd, void *arg); // Bit flags (options) @@ -488,8 +483,8 @@ static int adjustCompression = 1; // Set the compression to be adaptive static int dga = 1; // Set the default Direct Graphic Access static int PowerOnAtOpen = 1; // Set the default device to power on at startup static int SwitchSVideoInput = 0; // To help people with Black and White output with using s-video input. Some cables and input device are wired differently. -static int video_nr = -1; // Sequential Number of Video Device -static int radio_nr = -1; // Sequential Number of Radio Device +static int video_nr = -1; // Sequential Number of Video Device +static int radio_nr = -1; // Sequential Number of Radio Device static int vbi_nr = -1; // Sequential Number of VBI Device static char *CustomDevice=NULL; // Set as nothing.... @@ -515,10 +510,10 @@ MODULE_PARM(adjustCompression, "i"); // Grab the compression to be adaptive MODULE_PARM(dga, "i"); // Grab the Direct Graphic Access MODULE_PARM(PowerOnAtOpen, "i"); // Grab the device to power on at startup MODULE_PARM(SwitchSVideoInput, "i"); // To help people with Black and White output with using s-video input. Some cables and input device are wired differently. -MODULE_PARM(video_nr, "i"); // video_nr option allows to specify a certain /dev/videoX device (like /dev/video0 or /dev/video1 ...) +MODULE_PARM(video_nr, "i"); // video_nr option allows to specify a certain /dev/videoX device (like /dev/video0 or /dev/video1 ...) MODULE_PARM(radio_nr, "i"); // radio_nr option allows to specify a certain /dev/radioX device (like /dev/radio0 or /dev/radio1 ...) MODULE_PARM(vbi_nr, "i"); // vbi_nr option allows to specify a certain /dev/vbiX device (like /dev/vbi0 or /dev/vbi1 ...) -MODULE_PARM(CustomDevice, "s"); // .... CustomDevice +MODULE_PARM(CustomDevice, "s"); // .... CustomDevice #endif MODULE_PARM_DESC(flags, " Set the default Overlay Display mode of the device driver. Default: 0 (Off)"); @@ -539,7 +534,7 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE(DRIVER_LICENSE); MODULE_VERSION(DRIVER_VERSION); - MODULE_ALIAS(DRIVER_ALIAS); + MODULE_ALIAS(DRIVER_ALIAS); #ifdef MODULE static unsigned int autoload = 1; @@ -549,8 +544,8 @@ static unsigned int autoload = 0; /****************************************************************************************/ -/* SYSFS Code - Copied from the stv680.c usb module. */ -/* Device information is located at /sys/class/video4linux/video0 */ +/* SYSFS Code - Copied from the stv680.c usb module. */ +/* Device information is located at /sys/class/video4linux/video0 */ /* Device parameters information is located at /sys/module/usbvision */ /* Device USB Information is located at /sys/bus/usb/drivers/USBVision Video Grabber */ /****************************************************************************************/ @@ -567,79 +562,79 @@ static inline struct usb_usbvision *cd_to_usbvision(struct class_device *cd) static ssize_t show_version(struct class_device *cd, char *buf) { return sprintf(buf, "%s\n", DRIVER_VERSION); -} +} static CLASS_DEVICE_ATTR(version, S_IRUGO, show_version, NULL); static ssize_t show_model(struct class_device *class_dev, char *buf) { - struct video_device *vdev = to_video_device(class_dev); - struct usb_usbvision *usbvision = video_get_drvdata(vdev); + struct video_device *vdev = to_video_device(class_dev); + struct usb_usbvision *usbvision = video_get_drvdata(vdev); return sprintf(buf, "%s\n", usbvision_device_data[usbvision->DevModel].ModelString); -} +} static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL); static ssize_t show_hue(struct class_device *class_dev, char *buf) { - struct video_device *vdev = to_video_device(class_dev); - struct usb_usbvision *usbvision = video_get_drvdata(vdev); + struct video_device *vdev = to_video_device(class_dev); + struct usb_usbvision *usbvision = video_get_drvdata(vdev); return sprintf(buf, "%d\n", usbvision->hue >> 8); -} +} static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); static ssize_t show_contrast(struct class_device *class_dev, char *buf) { - struct video_device *vdev = to_video_device(class_dev); - struct usb_usbvision *usbvision = video_get_drvdata(vdev); + struct video_device *vdev = to_video_device(class_dev); + struct usb_usbvision *usbvision = video_get_drvdata(vdev); return sprintf(buf, "%d\n", usbvision->contrast >> 8); -} +} static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); static ssize_t show_brightness(struct class_device *class_dev, char *buf) { - struct video_device *vdev = to_video_device(class_dev); - struct usb_usbvision *usbvision = video_get_drvdata(vdev); + struct video_device *vdev = to_video_device(class_dev); + struct usb_usbvision *usbvision = video_get_drvdata(vdev); return sprintf(buf, "%d\n", usbvision->brightness >> 8); -} +} static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); static ssize_t show_saturation(struct class_device *class_dev, char *buf) { - struct video_device *vdev = to_video_device(class_dev); - struct usb_usbvision *usbvision = video_get_drvdata(vdev); + struct video_device *vdev = to_video_device(class_dev); + struct usb_usbvision *usbvision = video_get_drvdata(vdev); return sprintf(buf, "%d\n", usbvision->saturation >> 8); -} +} static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); static ssize_t show_streaming(struct class_device *class_dev, char *buf) { - struct video_device *vdev = to_video_device(class_dev); - struct usb_usbvision *usbvision = video_get_drvdata(vdev); + struct video_device *vdev = to_video_device(class_dev); + struct usb_usbvision *usbvision = video_get_drvdata(vdev); return sprintf(buf, "%s\n", YES_NO(usbvision->streaming)); -} +} static CLASS_DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL); static ssize_t show_overlay(struct class_device *class_dev, char *buf) { - struct video_device *vdev = to_video_device(class_dev); - struct usb_usbvision *usbvision = video_get_drvdata(vdev); + struct video_device *vdev = to_video_device(class_dev); + struct usb_usbvision *usbvision = video_get_drvdata(vdev); return sprintf(buf, "%s\n", YES_NO(usbvision->overlay)); -} +} static CLASS_DEVICE_ATTR(overlay, S_IRUGO, show_overlay, NULL); static ssize_t show_compression(struct class_device *class_dev, char *buf) { - struct video_device *vdev = to_video_device(class_dev); - struct usb_usbvision *usbvision = video_get_drvdata(vdev); + struct video_device *vdev = to_video_device(class_dev); + struct usb_usbvision *usbvision = video_get_drvdata(vdev); return sprintf(buf, "%s\n", YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS)); -} +} static CLASS_DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL); static ssize_t show_device_bridge(struct class_device *class_dev, char *buf) { - struct video_device *vdev = to_video_device(class_dev); - struct usb_usbvision *usbvision = video_get_drvdata(vdev); + struct video_device *vdev = to_video_device(class_dev); + struct usb_usbvision *usbvision = video_get_drvdata(vdev); return sprintf(buf, "%d\n", usbvision->bridgeType); -} +} static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL); static void usbvision_create_sysfs(struct video_device *vdev) @@ -1195,9 +1190,9 @@ void usbvision_osd_stats(struct usb_usbvision *usbvision, * * Parameters: * fullframe: if TRUE then entire frame is filled, otherwise the procedure - * continues from the current scanline. + * continues from the current scanline. * pmode 0: fill the frame with solid blue color (like on VCR or TV) - * 1: Draw a colored grid + * 1: Draw a colored grid * */ void usbvision_testpattern(struct usb_usbvision *usbvision, int fullframe, @@ -1608,7 +1603,7 @@ static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision, if (overlay) { frame = &usbvision->overlay_frame; - imageSize = frame->frmwidth * frame->frmheight; + imageSize = frame->frmwidth * frame->frmheight; if (usbvision->overlay_base == NULL) { //video_buffer is not set yet return ParseState_NextFrame; @@ -1618,26 +1613,26 @@ static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision, } else { frame = &usbvision->frame[usbvision->curFrameNum]; - imageSize = frame->frmwidth * frame->frmheight; + imageSize = frame->frmwidth * frame->frmheight; if ( (frame->v4l2_format.format == V4L2_PIX_FMT_YUV422P) || (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420) ) - { // this is a planar format - //... v4l2_linesize not used here. + { // this is a planar format + //... v4l2_linesize not used here. f = frame->data + (frame->width * frame->curline); - } else + } else f = frame->data + (frame->v4l2_linesize * frame->curline); - + if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV){ //initialise u and v pointers - // get base of u and b planes add halfoffset - - u = frame->data - + imageSize + // get base of u and b planes add halfoffset + + u = frame->data + + imageSize + (frame->frmwidth >>1) * frame->curline ; v = u + (imageSize >>1 ); - + } else if (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420){ - - v = frame->data + imageSize + ((frame->curline* (frame->width))>>2) ; + + v = frame->data + imageSize + ((frame->curline* (frame->width))>>2) ; u = v + (imageSize >>2) ; } } @@ -1687,7 +1682,7 @@ static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision, return ParseState_NextFrame; } - bytes_per_pixel = frame->v4l2_format.bytes_per_pixel; + bytes_per_pixel = frame->v4l2_format.bytes_per_pixel; clipmask_index = frame->curline * MAX_FRAME_WIDTH; scratch_get(usbvision, StripData, StripLen); @@ -1723,7 +1718,7 @@ static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision, if (BlockPos > StripLen) { usbvision->stripLenErrors++; } - + for (Idx = 0; Idx < IdxEnd; Idx++) { if((overlay) && (clipped_pixel(clipmask_index))) { f += bytes_per_pixel; @@ -1741,15 +1736,15 @@ static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision, } else if (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420) { *f++ = Y [Idx]; - if ( !(( Idx & 0x01 ) | ( frame->curline & 0x01 )) ){ - + if ( !(( Idx & 0x01 ) | ( frame->curline & 0x01 )) ){ + /* only need do this for 1 in 4 pixels */ /* intraframe buffer is YUV420 format */ *u++ = U[Idx >>1]; *v++ = V[Idx >>1]; } - + } else { YUV_TO_RGB_BY_THE_BOOK(Y[Idx], U[Idx/2], V[Idx/2], rv, gv, bv); @@ -1780,12 +1775,12 @@ static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision, } clipmask_index++; } - /* Deal with non-integer no. of bytes for YUV420P */ - if (frame->v4l2_format.format != V4L2_PIX_FMT_YVU420 ) - *pcopylen += frame->v4l2_linesize; - else - *pcopylen += frame->curline & 0x01 ? frame->v4l2_linesize : frame->v4l2_linesize << 1; - + /* Deal with non-integer no. of bytes for YUV420P */ + if (frame->v4l2_format.format != V4L2_PIX_FMT_YVU420 ) + *pcopylen += frame->v4l2_linesize; + else + *pcopylen += frame->curline & 0x01 ? frame->v4l2_linesize : frame->v4l2_linesize << 1; + frame->curline += 1; if (frame->curline >= frame->frmheight) { @@ -1846,7 +1841,7 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision /* Make sure there's enough data for the entire line */ /* In this mode usbvision transfer 3 bytes for every 2 pixels */ /* I need two lines to decode the color */ - bytes_per_pixel = frame->v4l2_format.bytes_per_pixel; + bytes_per_pixel = frame->v4l2_format.bytes_per_pixel; stretch_bytes = (usbvision->stretch_width - 1) * bytes_per_pixel; clipmask_even_index = frame->curline * MAX_FRAME_WIDTH; clipmask_odd_index = clipmask_even_index + MAX_FRAME_WIDTH; @@ -2276,7 +2271,7 @@ static void usbvision_isocIrq(struct urb *urb, struct pt_regs *regs) urb->iso_frame_desc[i].status = 0; urb->iso_frame_desc[i].actual_length = 0; } - urb->status = 0; + urb->status = 0; urb->dev = usbvision->dev; errCode = usb_submit_urb (urb, GFP_ATOMIC); @@ -2562,10 +2557,10 @@ static int attach_inform(struct i2c_client *client) } if ((usbvision->have_tuner) && (usbvision->tuner_type != -1)) { tun_addr.mode_mask = T_ANALOG_TV; - tun_addr.type = usbvision->tuner_type; - tun_addr.addr = ADDR_UNSET; - client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_addr); - + tun_addr.type = usbvision->tuner_type; + tun_addr.addr = ADDR_UNSET; + client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_addr); + call_i2c_clients(usbvision, VIDIOC_S_INPUT, &usbvision->input.index); } // FIXME : need to add a call VIDIOC_S_CTRL for each control @@ -2733,7 +2728,7 @@ static int usbvision_i2c_write(void *data, unsigned char addr, char *buf, int retval; int wrcount = 0; int count; - int maxLen = 4; + int maxLen = 4; struct usb_usbvision *usbvision = (struct usb_usbvision *) data; while (len > 0) { @@ -2841,7 +2836,7 @@ static int usbvision_init_i2c(struct usb_usbvision *usbvision) break; } if (usbvision_device_data[usbvision->DevModel].Tuner == 1) { - request_module("tuner"); + request_module("tuner"); } } #endif @@ -3001,7 +2996,7 @@ static int usbvision_set_output(struct usb_usbvision *usbvision, int width, } if (usbvision->input.std & V4L2_STD_625_50) { - frameDrop = frameRate * 32 / 25 - 1; + frameDrop = frameRate * 32 / 25 - 1; } else if (usbvision->input.std & V4L2_STD_525_60) { frameDrop = frameRate * 32 / 30 - 1; @@ -3042,7 +3037,7 @@ static int usbvision_set_compress_params(struct usb_usbvision *usbvision) value[2] = 0x00; // Reg.46 Force intra mode on all new frames value[3] = 0x00; // Reg.47 FORCE_UP <- 0 normal operation (not force) value[4] = 0xA2; // Reg.48 BUF_THR I'm not sure if this does something in not compressed mode. - value[5] = 0x00; // Reg.49 DVI_YUV This has nothing to do with compression + value[5] = 0x00; // Reg.49 DVI_YUV This has nothing to do with compression //catched values for NT1004 // value[0] = 0xFF; // Never apply intra mode automatically @@ -3196,7 +3191,7 @@ static int usbvision_set_input(struct usb_usbvision *usbvision) dvi_yuv_value = usbvision_device_data[usbvision->DevModel].Dvi_yuv & 0xff; } else if(usbvision_device_data[usbvision->DevModel].Codec == CODEC_SAA7113) { - /* This changes as the fine sync control changes. Further investigation necessary */ + /* This changes as the fine sync control changes. Further investigation necessary */ dvi_yuv_value = 0x06; } @@ -3313,7 +3308,7 @@ static void usbvision_powerOffTimer(unsigned long data) del_timer(&usbvision->powerOffTimer); INIT_WORK(&usbvision->powerOffWork, call_usbvision_power_off, usbvision); (void) schedule_work(&usbvision->powerOffWork); - + } @@ -3421,7 +3416,7 @@ static int usbvision_setup(struct usb_usbvision *usbvision) usbvision_set_input(usbvision); usbvision_set_output(usbvision, MAX_USB_WIDTH, MAX_USB_HEIGHT); usbvision_restart_isoc(usbvision); - + /* cosas del PCM */ return USBVISION_IS_OPERATIONAL(usbvision); } @@ -3532,12 +3527,12 @@ static void usbvision_stop_isoc(struct usb_usbvision *usbvision) usb_kill_urb(usbvision->sbuf[bufIdx].urb); usb_free_urb(usbvision->sbuf[bufIdx].urb); usbvision->sbuf[bufIdx].urb = NULL; - } + } PDEBUG(DBG_ISOC, "%s: streaming=0\n", __FUNCTION__); usbvision->streaming = 0; - + if (!usbvision->remove_pending) { @@ -3615,7 +3610,7 @@ static int usbvision_new_frame(struct usb_usbvision *usbvision, int framenum) static int usbvision_muxsel(struct usb_usbvision *usbvision, int channel, int norm) { int mode[4]; - int audio[]= {1, 0, 0, 0}; + int audio[]= {1, 0, 0, 0}; struct v4l2_routing route; //channel 0 is TV with audiochannel 1 (tuner mono) //channel 1 is Composite with audio channel 0 (line in) @@ -3636,7 +3631,7 @@ static int usbvision_muxsel(struct usb_usbvision *usbvision, int channel, int no // set the new channel // Regular USB TV Tuners -> channel: 0 = Television, 1 = Composite, 2 = S-Video - // Four video input devices -> channel: 0 = Chan White, 1 = Chan Green, 2 = Chan Yellow, 3 = Chan Red + // Four video input devices -> channel: 0 = Chan White, 1 = Chan Green, 2 = Chan Yellow, 3 = Chan Red switch (usbvision_device_data[usbvision->DevModel].Codec) { case CODEC_SAA7113: @@ -3646,10 +3641,10 @@ static int usbvision_muxsel(struct usb_usbvision *usbvision, int channel, int no else { mode[2] = 7; } - if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) { + if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) { mode[0] = 0; mode[1] = 2; mode[3] = 3; // Special for four input devices } - else { + else { mode[0] = 0; mode[1] = 2; //modes for regular saa7113 devices } break; @@ -3748,7 +3743,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) err("%s: unable to allocate %d for compr. frame buffer", __FUNCTION__, IFB_size); errCode = -ENOMEM; } - + } if (errCode) { /* Have to free all that memory */ @@ -3940,8 +3935,8 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, case 0: if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) { strcpy(vi->name, "White Video Input"); - } - else { + } + else { strcpy(vi->name, "Television"); vi->type = V4L2_INPUT_TYPE_TUNER; vi->audioset = 1; @@ -3950,30 +3945,30 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, } break; case 1: - vi->type = V4L2_INPUT_TYPE_CAMERA; + vi->type = V4L2_INPUT_TYPE_CAMERA; if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) { strcpy(vi->name, "Green Video Input"); - } - else { + } + else { strcpy(vi->name, "Composite Video Input"); } vi->std = V4L2_STD_PAL; break; case 2: - vi->type = V4L2_INPUT_TYPE_CAMERA; + vi->type = V4L2_INPUT_TYPE_CAMERA; if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) { strcpy(vi->name, "Yellow Video Input"); - } - else { + } + else { strcpy(vi->name, "S-Video Input"); } vi->std = V4L2_STD_PAL; break; case 3: - vi->type = V4L2_INPUT_TYPE_CAMERA; + vi->type = V4L2_INPUT_TYPE_CAMERA; strcpy(vi->name, "Red Video Input"); vi->std = V4L2_STD_PAL; - break; + break; } PDEBUG(DBG_IOCTL, "VIDIOC_ENUMINPUT name=%s:%d tuners=%d type=%d norm=%x", vi->name, vi->index, vi->tuner,vi->type,(int)vi->std); return 0; @@ -4008,13 +4003,13 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, } return 0; } - case VIDIOC_G_INPUT: + case VIDIOC_G_INPUT: { int *input = arg; *input = usbvision->input.index; return 0; } - case VIDIOC_S_INPUT: + case VIDIOC_S_INPUT: { int *input = arg; if ((*input >= usbvision->video_inputs) || (*input < 0) ) @@ -4028,14 +4023,14 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, up(&usbvision->lock); return 0; } - case VIDIOC_G_STD: + case VIDIOC_G_STD: { v4l2_std_id *std = arg; *std = usbvision->input.std; PDEBUG(DBG_IOCTL, "VIDIOC_G_STD std_id=%x", (unsigned)*std); return 0; } - case VIDIOC_S_STD: + case VIDIOC_S_STD: { v4l2_std_id *std = arg; @@ -4049,7 +4044,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, PDEBUG(DBG_IOCTL, "VIDIOC_S_STD std_id=%x", (unsigned)*std); return 0; } - case VIDIOC_G_TUNER: + case VIDIOC_G_TUNER: { struct v4l2_tuner *vt = arg; struct v4l2_tuner status; @@ -4118,55 +4113,35 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, // FIXME: void function ??? return 0; } - case VIDIOC_QUERYCTRL: + case VIDIOC_QUERYCTRL: { - struct v4l2_queryctrl *qc = arg; - switch(qc->id) { - case V4L2_CID_BRIGHTNESS: - case V4L2_CID_HUE: - case V4L2_CID_SATURATION: - case V4L2_CID_CONTRAST: - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill_std(qc); - break; - default: + struct v4l2_queryctrl *ctrl = arg; + int id=ctrl->id; + + memset(ctrl,0,sizeof(*ctrl)); + ctrl->id=id; + + i2c_clients_command(&usbvision->i2c_adap, cmd, arg); + + if (ctrl->type) + return 0; + else return -EINVAL; - } - return 0; + + PDEBUG(DBG_IOCTL,"VIDIOC_QUERYCTRL id=%x value=%x",ctrl->id,ctrl->type); } case VIDIOC_G_CTRL: { struct v4l2_control *ctrl = arg; - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->value = usbvision->brightness; - break; - case V4L2_CID_CONTRAST: - ctrl->value = usbvision->contrast; - break; - case V4L2_CID_SATURATION: - ctrl->value = usbvision->saturation; - break; - case V4L2_CID_HUE: - ctrl->value = usbvision->hue; - break; - case V4L2_CID_AUDIO_VOLUME: - /* ctrl->value = usbvision->volume; */ - break; - case V4L2_CID_AUDIO_MUTE: - ctrl->value = usbvision->AudioMute; - break; - default: - return -EINVAL; - } - PDEBUG(DBG_IOCTL, "VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value); + PDEBUG(DBG_IOCTL,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value); + call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl); return 0; } case VIDIOC_S_CTRL: { struct v4l2_control *ctrl = arg; + PDEBUG(DBG_IOCTL, "VIDIOC_S_CTRL id=%x value=%x",ctrl->id,ctrl->value); call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl); return 0; @@ -4213,7 +4188,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, vb->sequence = usbvision->frame_num; return 0; } - case VIDIOC_QBUF: // VIDIOCMCAPTURE + VIDIOCSYNC + case VIDIOC_QBUF: // VIDIOCMCAPTURE + VIDIOCSYNC { struct v4l2_buffer *vb = arg; struct usbvision_frame *frame; @@ -4308,7 +4283,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_STREAMON: { int b=V4L2_BUF_TYPE_VIDEO_CAPTURE; - call_i2c_clients(usbvision,VIDIOC_STREAMON , &b); + call_i2c_clients(usbvision,VIDIOC_STREAMON , &b); return 0; } case VIDIOC_STREAMOFF: @@ -4323,7 +4298,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, up(&usbvision->lock); return 0; } - case VIDIOC_G_FBUF: + case VIDIOC_G_FBUF: { struct v4l2_framebuffer *vb = arg; @@ -4389,7 +4364,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, if ( (dga == 0) && (vfd->type == V4L2_BUF_TYPE_VIDEO_OVERLAY) && (usbvision->palette.format != V4L2_PIX_FMT_YVU420) && - (usbvision->palette.format != V4L2_PIX_FMT_YUV422P) ) { + (usbvision->palette.format != V4L2_PIX_FMT_YUV422P) ) { return -EINVAL; } if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) { @@ -4403,11 +4378,11 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_G_FMT: { struct v4l2_format *vf = arg; - + if ( (dga == 0) && (vf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY) && (usbvision->palette.format != V4L2_PIX_FMT_YVU420) && - (usbvision->palette.format != V4L2_PIX_FMT_YUV422P) ) { + (usbvision->palette.format != V4L2_PIX_FMT_YUV422P) ) { return -EINVAL; } down(&usbvision->lock); @@ -4417,7 +4392,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, vf->fmt.win.w.left, vf->fmt.win.w.top, vf->fmt.win.w.width, vf->fmt.win.w.height, vf->fmt.win.chromakey, vf->fmt.win.clipcount); return 0; } - case VIDIOC_S_FMT: + case VIDIOC_S_FMT: { struct v4l2_format *vf = arg; struct v4l2_clip *vc=NULL; @@ -4426,7 +4401,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, if ( (dga == 0) && (vf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY) && (usbvision->palette.format != V4L2_PIX_FMT_YVU420) && - (usbvision->palette.format != V4L2_PIX_FMT_YUV422P) ) { + (usbvision->palette.format != V4L2_PIX_FMT_YUV422P) ) { return -EINVAL; } if(vf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY) { @@ -4518,10 +4493,10 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_OVERLAY: { int *v = arg; - + if ( (dga == 0) && (usbvision->palette.format != V4L2_PIX_FMT_YVU420) && - (usbvision->palette.format != V4L2_PIX_FMT_YUV422P) ) { + (usbvision->palette.format != V4L2_PIX_FMT_YUV422P) ) { PDEBUG(DBG_IOCTL, "VIDIOC_OVERLAY DGA disabled"); return -EINVAL; } @@ -4609,7 +4584,7 @@ static ssize_t usbvision_v4l2_read(struct file *file, char *buf, goto usbvision_v4l2_read_done; } PDEBUG(DBG_IO, "Waiting frame grabbing"); - rc = wait_event_interruptible(frame->wq, (frame->grabstate == FrameState_Done) || + rc = wait_event_interruptible(frame->wq, (frame->grabstate == FrameState_Done) || (frame->grabstate == FrameState_Error)); if (rc) { goto usbvision_v4l2_read_done; @@ -4670,11 +4645,11 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) pos = (unsigned long) usbvision->fbuf; while (size > 0) { - + // Really ugly.... - #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10) //Compatibility for 2.6.10+ kernels + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10) //Compatibility for 2.6.10+ kernels page = vmalloc_to_pfn((void *)pos); - if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { + if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { return -EAGAIN; } #else //Compatibility for 2.6.0 - 2.6.9 kernels @@ -4791,7 +4766,7 @@ static int usbvision_do_radio_ioctl(struct inode *inode, struct file *file, /*************************** * V4L2 IOCTLs * ***************************/ - case VIDIOC_QUERYCAP: + case VIDIOC_QUERYCAP: { struct v4l2_capability *vc=arg; memset(vc, 0, sizeof(struct v4l2_capability)); @@ -4803,7 +4778,7 @@ static int usbvision_do_radio_ioctl(struct inode *inode, struct file *file, PDEBUG(DBG_RIO, "%s: VIDIOC_QUERYCAP", __FUNCTION__); return 0; } - case VIDIOC_QUERYCTRL: + case VIDIOC_QUERYCTRL: { struct v4l2_queryctrl *qc = arg; switch(qc->id) @@ -4817,7 +4792,7 @@ static int usbvision_do_radio_ioctl(struct inode *inode, struct file *file, } return 0; } - case VIDIOC_G_CTRL: + case VIDIOC_G_CTRL: { struct v4l2_control *ctrl = arg; PDEBUG(DBG_IOCTL, "VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value); @@ -4833,7 +4808,7 @@ static int usbvision_do_radio_ioctl(struct inode *inode, struct file *file, } return 0; } - case VIDIOC_S_CTRL: + case VIDIOC_S_CTRL: { struct v4l2_control *ctrl = arg; call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl); @@ -4841,7 +4816,7 @@ static int usbvision_do_radio_ioctl(struct inode *inode, struct file *file, PDEBUG(DBG_RIO, "%s: VIDIOC_S_CTRL id=%x value=%x", __FUNCTION__,ctrl->id,ctrl->value); return 0; } - case VIDIOC_G_TUNER: + case VIDIOC_G_TUNER: { struct v4l2_tuner *vt = arg; @@ -4862,7 +4837,7 @@ static int usbvision_do_radio_ioctl(struct inode *inode, struct file *file, PDEBUG(DBG_RIO, "%s: VIDIOC_G_TUNER signal=%d", __FUNCTION__, vt->signal); return 0; } - case VIDIOC_S_TUNER: + case VIDIOC_S_TUNER: { struct v4l2_tuner *vt = arg; @@ -4873,7 +4848,7 @@ static int usbvision_do_radio_ioctl(struct inode *inode, struct file *file, PDEBUG(DBG_RIO, "%s: VIDIOC_S_TUNER", __FUNCTION__); return 0; } - case VIDIOC_G_AUDIO: + case VIDIOC_G_AUDIO: { struct v4l2_audio *va = arg; memset(va,0, sizeof(va)); @@ -4882,7 +4857,7 @@ static int usbvision_do_radio_ioctl(struct inode *inode, struct file *file, PDEBUG(DBG_IOCTL, "VIDIOC_G_AUDIO"); return 0; } - case VIDIOC_S_AUDIO: + case VIDIOC_S_AUDIO: { struct v4l2_audio *v = arg; if(v->index) { @@ -4892,7 +4867,7 @@ static int usbvision_do_radio_ioctl(struct inode *inode, struct file *file, // FIXME: void function ??? return 0; } - case VIDIOC_G_FREQUENCY: + case VIDIOC_G_FREQUENCY: { struct v4l2_frequency *freq = arg; freq->tuner = 0; // Only one tuner @@ -4901,7 +4876,7 @@ static int usbvision_do_radio_ioctl(struct inode *inode, struct file *file, PDEBUG(DBG_RIO, "VIDIOC_G_FREQUENCY freq=0x%X", (unsigned)freq->frequency); return 0; } - case VIDIOC_S_FREQUENCY: + case VIDIOC_S_FREQUENCY: { struct v4l2_frequency *freq = arg; usbvision->freq = freq->frequency; @@ -4913,7 +4888,7 @@ static int usbvision_do_radio_ioctl(struct inode *inode, struct file *file, /*************************** * V4L1 IOCTLs * ***************************/ - case VIDIOCGCAP: + case VIDIOCGCAP: { struct video_capability *vc = arg; @@ -5227,18 +5202,8 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision) if (usbvision == NULL) return; - - model = usbvision->DevModel; - RESTRICT_TO_RANGE(init_brightness, 0, 255); - RESTRICT_TO_RANGE(init_contrast, 0, 255); - RESTRICT_TO_RANGE(init_saturation, 0, 255); - RESTRICT_TO_RANGE(init_hue, 0, 255); - - usbvision->saturation = init_saturation << 8; - usbvision->hue = init_hue << 8; - usbvision->brightness = init_brightness << 8; - usbvision->contrast = init_contrast << 8; + model = usbvision->DevModel; usbvision->depth = 24; usbvision->palette = usbvision_v4l2_format[2]; // V4L2_PIX_FMT_RGB24; @@ -5393,7 +5358,7 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision) } usbvision->vbi = NULL; } - + // Radio Device: if (usbvision->rdev) { PDEBUG(DBG_PROBE, "unregister /dev/radio%d [v4l2]", usbvision->rdev->minor & 0x1f); @@ -5444,7 +5409,7 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision) } info("USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]", usbvision->nr, usbvision->rdev->minor & 0x1f); } - // vbi Device: + // vbi Device: if (usbvision_device_data[usbvision->DevModel].vbi) { usbvision->vbi = usbvision_vdev_init(usbvision, &usbvision_vbi_template, "USBVision VBI"); if (usbvision->vdev == NULL) { @@ -5575,10 +5540,10 @@ static int __devinit usbvision_probe(struct usb_interface *intf, const struct us /* Is it an USBVISION video dev? */ model = 0; for(model = 0; usbvision_device_data[model].idVendor; model++) { - if (le16_to_cpu(dev->descriptor.idVendor) != usbvision_device_data[model].idVendor) { + if (le16_to_cpu(dev->descriptor.idVendor) != usbvision_device_data[model].idVendor) { continue; } - if (le16_to_cpu(dev->descriptor.idProduct) != usbvision_device_data[model].idProduct) { + if (le16_to_cpu(dev->descriptor.idProduct) != usbvision_device_data[model].idProduct) { continue; } @@ -5607,7 +5572,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf, const struct us } usb_get_dev(dev); - + if ((usbvision = usbvision_alloc(dev)) == NULL) { err("%s: couldn't allocate USBVision struct", __FUNCTION__); return -ENOMEM; @@ -5617,7 +5582,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf, const struct us } else if (usbvision_device_data[model].ModelString == "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)") { usbvision->bridgeType = BRIDGE_NT1005; - } + } else { usbvision->bridgeType = BRIDGE_NT1003; } @@ -5649,7 +5614,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf, const struct us usb_set_intfdata (intf, usbvision); - usbvision_create_sysfs(usbvision->vdev); + usbvision_create_sysfs(usbvision->vdev); PDEBUG(DBG_PROBE, "success"); return 0; @@ -5724,7 +5689,7 @@ void customdevice_process(void) if(CustomDevice) { char *parse=CustomDevice; - + PDEBUG(DBG_PROBE, "CustomDevide=%s", CustomDevice); /*format is CustomDevice="0x0573 0x4D31 0 7113 3 PAL 1 1 1 5 -1 -1 -1 -1 -1" @@ -5743,9 +5708,9 @@ void customdevice_process(void) usbvision_device_data[0].X_Offset; usbvision_device_data[0].Y_Offset; usbvision_device_data[0].Dvi_yuv; - usbvision_device_data[0].ModelString; + usbvision_device_data[0].ModelString; */ - + rmspace(parse); usbvision_device_data[0].ModelString="USBVISION Custom Device"; @@ -5852,12 +5817,12 @@ static int __init usbvision_init(void) PDEBUG(DBG_FUNC, "FUNC debugging is enabled"); PDEBUG(DBG_I2C, "I2C debugging is enabled"); - /* disable planar mode support unless compression enabled */ - if (isocMode != ISOC_MODE_COMPRESS ) { + /* disable planar mode support unless compression enabled */ + if (isocMode != ISOC_MODE_COMPRESS ) { // FIXME : not the right way to set supported flag usbvision_v4l2_format[6].supported = 0; // V4L2_PIX_FMT_YVU420 usbvision_v4l2_format[7].supported = 0; // V4L2_PIX_FMT_YUV422P - } + } customdevice_process(); -- cgit v1.2.3 From f2242ee5474f46d87a45cd4e214b5c3aa02ff293 Mon Sep 17 00:00:00 2001 From: Thierry MERLE Date: Mon, 4 Dec 2006 08:31:14 -0300 Subject: V4L/DVB (4927): Enhancements on usbvision driver Enhance the buffer management of this driver + some corrections - linux list.h usage for buffer management - VIDIOC_ENUMSTD/VIDIOC_G_STD/VIDIOC_S_STD simplification (use of v4l2_video_std_construct) - create_sysfs : remove of warnings for video_device_create_file return code - make the driver compatible with 2.6.19 kernel version (remove slave_send and slave_recv in usbvision-i2c, change ctrlUrb_complete function prototype) - deactivated v4l2_read because this code was not the priority but working on it :) Signed-off-by: Thierry MERLE Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/usbvision/usbvision-core.c | 651 ++++++++++++++----------- drivers/media/video/usbvision/usbvision-i2c.c | 8 +- drivers/media/video/usbvision/usbvision.h | 91 ++-- 3 files changed, 418 insertions(+), 332 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index f225701f16f..06e8e67da36 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -437,6 +437,25 @@ static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = { { 1, 2, 16, V4L2_PIX_FMT_YUV422P , "YUV422P" } }; +/* supported tv norms */ +static struct usbvision_tvnorm tvnorms[] = { + { + .name = "PAL", + .id = V4L2_STD_PAL, + }, { + .name = "NTSC", + .id = V4L2_STD_NTSC, + }, { + .name = "SECAM", + .id = V4L2_STD_SECAM, + }, { + .name = "PAL-M", + .id = V4L2_STD_PAL_M, + } +}; + +#define TVNORMS ARRAY_SIZE(tvnorms) + /* * The value of 'scratch_buf_size' affects quality of the picture @@ -451,7 +470,7 @@ static const int scratch_buf_size = DEFAULT_SCRATCH_BUF_SIZE; // Function prototypes static int usbvision_restart_isoc(struct usb_usbvision *usbvision); static int usbvision_begin_streaming(struct usb_usbvision *usbvision); -static int usbvision_muxsel(struct usb_usbvision *usbvision, int channel, int norm); +static int usbvision_muxsel(struct usb_usbvision *usbvision, int channel); static int usbvision_i2c_write(void *data, unsigned char addr, char *buf, short len); static int usbvision_i2c_read(void *data, unsigned char addr, char *buf, short len); static int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg); @@ -463,6 +482,8 @@ static int usbvision_measure_bandwidth (struct usb_usbvision *usbvision); static void usbvision_release(struct usb_usbvision *usbvision); static int usbvision_set_input(struct usb_usbvision *usbvision); static int usbvision_set_output(struct usb_usbvision *usbvision, int width, int height); +static void usbvision_empty_framequeues(struct usb_usbvision *dev); +static int usbvision_stream_interrupt(struct usb_usbvision *dev); static void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd, void *arg); @@ -609,7 +630,7 @@ static ssize_t show_streaming(struct class_device *class_dev, char *buf) { struct video_device *vdev = to_video_device(class_dev); struct usb_usbvision *usbvision = video_get_drvdata(vdev); - return sprintf(buf, "%s\n", YES_NO(usbvision->streaming)); + return sprintf(buf, "%s\n", YES_NO(usbvision->streaming==Stream_On?1:0)); } static CLASS_DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL); @@ -639,17 +660,18 @@ static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL); static void usbvision_create_sysfs(struct video_device *vdev) { + int res; if (vdev) { - video_device_create_file(vdev, &class_device_attr_version); - video_device_create_file(vdev, &class_device_attr_model); - video_device_create_file(vdev, &class_device_attr_hue); - video_device_create_file(vdev, &class_device_attr_contrast); - video_device_create_file(vdev, &class_device_attr_brightness); - video_device_create_file(vdev, &class_device_attr_saturation); - video_device_create_file(vdev, &class_device_attr_streaming); - video_device_create_file(vdev, &class_device_attr_overlay); - video_device_create_file(vdev, &class_device_attr_compression); - video_device_create_file(vdev, &class_device_attr_bridge); + res=video_device_create_file(vdev, &class_device_attr_version); + res=video_device_create_file(vdev, &class_device_attr_model); + res=video_device_create_file(vdev, &class_device_attr_hue); + res=video_device_create_file(vdev, &class_device_attr_contrast); + res=video_device_create_file(vdev, &class_device_attr_brightness); + res=video_device_create_file(vdev, &class_device_attr_saturation); + res=video_device_create_file(vdev, &class_device_attr_streaming); + res=video_device_create_file(vdev, &class_device_attr_overlay); + res=video_device_create_file(vdev, &class_device_attr_compression); + res=video_device_create_file(vdev, &class_device_attr_bridge); } } @@ -1209,15 +1231,13 @@ void usbvision_testpattern(struct usb_usbvision *usbvision, int fullframe, printk(KERN_ERR "%s: usbvision == NULL\n", proc); return; } - if ((usbvision->curFrameNum < 0) - || (usbvision->curFrameNum >= USBVISION_NUMFRAMES)) { - printk(KERN_ERR "%s: usbvision->curFrameNum=%d.\n", proc, - usbvision->curFrameNum); + if (usbvision->curFrame == NULL) { + printk(KERN_ERR "%s: usbvision->curFrame is NULL.\n", proc); return; } /* Grab the current frame */ - frame = &usbvision->frame[usbvision->curFrameNum]; + frame = usbvision->curFrame; /* Optionally start at the beginning */ if (fullframe) { @@ -1290,7 +1310,7 @@ static enum ParseState usbvision_find_header(struct usb_usbvision *usbvision) frame = &usbvision->overlay_frame; } else { - frame = &usbvision->frame[usbvision->curFrameNum]; + frame = usbvision->curFrame; } while (scratch_get_header(usbvision, &frame->isocHeader) == USBVISION_HEADER_LENGTH) { @@ -1325,7 +1345,6 @@ static enum ParseState usbvision_find_header(struct usb_usbvision *usbvision) frame->frmwidth = frame->isocHeader.frameWidth * usbvision->stretch_width; frame->frmheight = frame->isocHeader.frameHeight * usbvision->stretch_height; frame->v4l2_linesize = (frame->frmwidth * frame->v4l2_format.depth)>> 3; - usbvision->curFrame = frame; } else { // no header found PDEBUG(DBG_HEADER, "skipping scratch data, no header"); @@ -1380,7 +1399,7 @@ static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision usbvision->vid_buf.fmt.bytesperline; } else { - frame = &usbvision->frame[usbvision->curFrameNum]; + frame = usbvision->curFrame; f = frame->data + (frame->v4l2_linesize * frame->curline); } @@ -1612,7 +1631,7 @@ static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision, usbvision->vid_buf.fmt.bytesperline; } else { - frame = &usbvision->frame[usbvision->curFrameNum]; + frame = usbvision->curFrame; imageSize = frame->frmwidth * frame->frmheight; if ( (frame->v4l2_format.format == V4L2_PIX_FMT_YUV422P) || (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420) ) @@ -1833,7 +1852,7 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision f_odd = f_even + usbvision->vid_buf.fmt.bytesperline * usbvision->stretch_height; } else { - frame = &usbvision->frame[usbvision->curFrameNum]; + frame = usbvision->curFrame; f_even = frame->data + (frame->v4l2_linesize * frame->curline); f_odd = f_even + frame->v4l2_linesize * usbvision->stretch_height; } @@ -2088,17 +2107,17 @@ static void usbvision_parse_data(struct usb_usbvision *usbvision) struct usbvision_frame *frame; enum ParseState newstate; long copylen = 0; + unsigned long lock_flags; if (usbvision->overlay) { frame = &usbvision->overlay_frame; } else { - frame = &usbvision->frame[usbvision->curFrameNum]; + frame = usbvision->curFrame; } PDEBUG(DBG_PARSE, "parsing len=%d\n", scratch_len(usbvision)); - while (1) { newstate = ParseState_Out; @@ -2141,7 +2160,10 @@ static void usbvision_parse_data(struct usb_usbvision *usbvision) copylen = 0; } else { - usbvision->curFrameNum = -1; + spin_lock_irqsave(&usbvision->queue_lock, lock_flags); + list_move_tail(&(frame->frame), &usbvision->outqueue); + usbvision->curFrame = NULL; + spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); } usbvision->frame_num++; @@ -2150,10 +2172,14 @@ static void usbvision_parse_data(struct usb_usbvision *usbvision) usbvision_osd_stats(usbvision, frame); /* This will cause the process to request another frame. */ - if (waitqueue_active(&frame->wq)) { - wake_up_interruptible(&frame->wq); + if (waitqueue_active(&usbvision->wait_frame)) { + PDEBUG(DBG_PARSE, "Wake up !"); + wake_up_interruptible(&usbvision->wait_frame); } } + else + frame->grabstate = FrameState_Grabbing; + /* Update the frame's uncompressed length. */ frame->scanlength += copylen; @@ -2164,7 +2190,7 @@ static void usbvision_parse_data(struct usb_usbvision *usbvision) * Make all of the blocks of data contiguous */ static int usbvision_compress_isochronous(struct usb_usbvision *usbvision, - struct urb *urb) + struct urb *urb) { unsigned char *packet_data; int i, totlen = 0; @@ -2246,51 +2272,70 @@ static int usbvision_compress_isochronous(struct usb_usbvision *usbvision, static void usbvision_isocIrq(struct urb *urb, struct pt_regs *regs) { - int errCode = 0; - int len; - struct usb_usbvision *usbvision = urb->context; - int i; - unsigned long startTime = jiffies; - - /* We don't want to do anything if we are about to be removed! */ - if (!USBVISION_IS_OPERATIONAL(usbvision)) - return; + int errCode = 0; + int len; + struct usb_usbvision *usbvision = urb->context; + int i; + unsigned long startTime = jiffies; + struct usbvision_frame **f; - if (!usbvision->streaming) { - PDEBUG(DBG_IRQ, "oops, not streaming, but interrupt"); - return; - } + /* We don't want to do anything if we are about to be removed! */ + if (!USBVISION_IS_OPERATIONAL(usbvision)) + return; - /* Copy the data received into our scratch buffer */ - len = usbvision_compress_isochronous(usbvision, urb); + f = &usbvision->curFrame; - usbvision->isocUrbCount++; - usbvision->urb_length = len; + /* Manage streaming interruption */ + if (usbvision->streaming == Stream_Interrupt) { + usbvision->streaming = Stream_Off; + if ((*f)) { + (*f)->grabstate = FrameState_Ready; + (*f)->scanstate = ScanState_Scanning; + } + PDEBUG(DBG_IRQ, "stream interrupted"); + wake_up_interruptible(&usbvision->wait_stream); + } - for (i = 0; i < USBVISION_URB_FRAMES; i++) { - urb->iso_frame_desc[i].status = 0; - urb->iso_frame_desc[i].actual_length = 0; - } - urb->status = 0; - urb->dev = usbvision->dev; - errCode = usb_submit_urb (urb, GFP_ATOMIC); + /* Copy the data received into our scratch buffer */ + len = usbvision_compress_isochronous(usbvision, urb); -/* Disable this warning. By design of the driver. */ -// if(errCode) { -// err("%s: usb_submit_urb failed: error %d", __FUNCTION__, errCode); -// } + usbvision->isocUrbCount++; + usbvision->urb_length = len; - /* If we collected enough data let's parse! */ - if (scratch_len(usbvision) > USBVISION_HEADER_LENGTH) { /* 12 == header_length */ - /*If we don't have a frame we're current working on, complain */ - if ((usbvision->curFrameNum >= 0) || (usbvision->overlay)) - usbvision_parse_data(usbvision); - else { - PDEBUG(DBG_IRQ, "received data, but no one needs it"); - scratch_reset(usbvision); + if (usbvision->streaming == Stream_On) { + + /* If we collected enough data let's parse! */ + if (scratch_len(usbvision) > USBVISION_HEADER_LENGTH) { /* 12 == header_length */ + /*If we don't have a frame we're current working on, complain */ + if((!list_empty(&(usbvision->inqueue))) || (usbvision->overlay)) { + if (!(*f)) { + (*f) = list_entry(usbvision->inqueue.next,struct usbvision_frame, frame); + } + usbvision_parse_data(usbvision); + } + else { + PDEBUG(DBG_IRQ, "received data, but no one needs it"); + scratch_reset(usbvision); + } } } + usbvision->timeInIrq += jiffies - startTime; + + for (i = 0; i < USBVISION_URB_FRAMES; i++) { + urb->iso_frame_desc[i].status = 0; + urb->iso_frame_desc[i].actual_length = 0; + } + + urb->status = 0; + urb->dev = usbvision->dev; + errCode = usb_submit_urb (urb, GFP_ATOMIC); + + /* Disable this warning. By design of the driver. */ + // if(errCode) { + // err("%s: usb_submit_urb failed: error %d", __FUNCTION__, errCode); + // } + return; } @@ -2539,7 +2584,6 @@ static int attach_inform(struct i2c_client *client) struct usb_usbvision *usbvision; struct tuner_setup tun_addr; int i; - v4l2_std_id stdId; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) usbvision = (struct usb_usbvision *)client->adapter->data; @@ -2560,13 +2604,11 @@ static int attach_inform(struct i2c_client *client) tun_addr.type = usbvision->tuner_type; tun_addr.addr = ADDR_UNSET; client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_addr); - - call_i2c_clients(usbvision, VIDIOC_S_INPUT, &usbvision->input.index); + call_i2c_clients(usbvision, VIDIOC_INT_RESET, NULL); + call_i2c_clients(usbvision, VIDIOC_S_INPUT, &usbvision->ctl_input); + call_i2c_clients(usbvision, VIDIOC_STREAMON, NULL); } - // FIXME : need to add a call VIDIOC_S_CTRL for each control -/* call_i2c_clients(usbvision, DECODER_SET_PICTURE, &usbvision->vpic); */ - stdId = usbvision->input.std; - call_i2c_clients(usbvision, VIDIOC_S_STD, &stdId); + call_i2c_clients(usbvision, VIDIOC_S_STD, &usbvision->tvnorm->id); PDEBUG(DBG_I2C, "usbvision[%d] attaches %s", usbvision->nr, client->name); @@ -2995,10 +3037,10 @@ static int usbvision_set_output(struct usb_usbvision *usbvision, int width, frameRate = FRAMERATE_MAX; } - if (usbvision->input.std & V4L2_STD_625_50) { + if (usbvision->tvnorm->id & V4L2_STD_625_50) { frameDrop = frameRate * 32 / 25 - 1; } - else if (usbvision->input.std & V4L2_STD_525_60) { + else if (usbvision->tvnorm->id & V4L2_STD_525_60) { frameDrop = frameRate * 32 / 30 - 1; } @@ -3021,6 +3063,40 @@ static int usbvision_set_output(struct usb_usbvision *usbvision, int width, } +/* + * usbvision_empty_framequeues() + * prepare queues for incoming and outgoing frames + */ +static void usbvision_empty_framequeues(struct usb_usbvision *usbvision) +{ + u32 i; + + INIT_LIST_HEAD(&(usbvision->inqueue)); + INIT_LIST_HEAD(&(usbvision->outqueue)); + + for (i = 0; i < USBVISION_NUMFRAMES; i++) { + usbvision->frame[i].grabstate = FrameState_Unused; + usbvision->frame[i].bytes_read = 0; + } +} + +/* + * usbvision_stream_interrupt() + * stops streaming + */ +static int usbvision_stream_interrupt(struct usb_usbvision *usbvision) +{ + int ret = 0; + + /* stop reading from the device */ + + usbvision->streaming = Stream_Interrupt; + ret = wait_event_timeout(usbvision->wait_stream, + (usbvision->streaming == Stream_Off), + msecs_to_jiffies(USBVISION_NUMSBUF*USBVISION_URB_FRAMES)); + return ret; +} + /* * usbvision_set_compress_params() * @@ -3135,7 +3211,7 @@ static int usbvision_set_input(struct usb_usbvision *usbvision) } - if (usbvision->input.std & V4L2_STD_PAL) { + if (usbvision->tvnorm->id & V4L2_STD_PAL) { value[0] = 0xC0; value[1] = 0x02; //0x02C0 -> 704 Input video line length value[2] = 0x20; @@ -3144,7 +3220,7 @@ static int usbvision_set_input(struct usb_usbvision *usbvision) value[5] = 0x00; //0x0060 -> 96 Input video h offset value[6] = 0x16; value[7] = 0x00; //0x0016 -> 22 Input video v offset - } else if (usbvision->input.std & V4L2_STD_SECAM) { + } else if (usbvision->tvnorm->id & V4L2_STD_SECAM) { value[0] = 0xC0; value[1] = 0x02; //0x02C0 -> 704 Input video line length value[2] = 0x20; @@ -3434,7 +3510,7 @@ static int usbvision_init_isoc(struct usb_usbvision *usbvision) if (!USBVISION_IS_OPERATIONAL(usbvision)) return -EFAULT; - usbvision->curFrameNum = -1; + usbvision->curFrame = NULL; scratch_reset(usbvision); /* Alternate interface 1 is is the biggest frame size */ @@ -3503,7 +3579,7 @@ static int usbvision_init_isoc(struct usb_usbvision *usbvision) } } - usbvision->streaming = 1; + usbvision->streaming = Stream_On; PDEBUG(DBG_ISOC, "%s: streaming=1 usbvision->video_endp=$%02x", __FUNCTION__, usbvision->video_endp); return 0; } @@ -3519,7 +3595,8 @@ static void usbvision_stop_isoc(struct usb_usbvision *usbvision) { int bufIdx, errCode, regValue; - if (!usbvision->streaming || (usbvision->dev == NULL)) + // FIXME : removed the streaming==Stream_Off. This field has not the same signification than before ! + if (usbvision->dev == NULL) return; /* Unschedule all of the iso td's */ @@ -3530,9 +3607,8 @@ static void usbvision_stop_isoc(struct usb_usbvision *usbvision) } - PDEBUG(DBG_ISOC, "%s: streaming=0\n", __FUNCTION__); - usbvision->streaming = 0; - + PDEBUG(DBG_ISOC, "%s: streaming=Stream_Off\n", __FUNCTION__); + usbvision->streaming = Stream_Off; if (!usbvision->remove_pending) { @@ -3552,62 +3628,7 @@ static void usbvision_stop_isoc(struct usb_usbvision *usbvision) } } -/* - * usbvision_new_frame() - * - */ -static int usbvision_new_frame(struct usb_usbvision *usbvision, int framenum) -{ - struct usbvision_frame *frame; - int n; //byhec , width, height; - - /* If we're not grabbing a frame right now and the other frame is */ - /* ready to be grabbed into, then use it instead */ - if (usbvision->curFrameNum != -1) - return 0; - - n = (framenum - 1 + USBVISION_NUMFRAMES) % USBVISION_NUMFRAMES; - if (usbvision->frame[n].grabstate == FrameState_Ready) - framenum = n; - - frame = &usbvision->frame[framenum]; - - frame->grabstate = FrameState_Grabbing; - frame->scanstate = ScanState_Scanning; - frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */ - usbvision->curFrameNum = framenum; - - /* - * Normally we would want to copy previous frame into the current one - * before we even start filling it with data; this allows us to stop - * filling at any moment; top portion of the frame will be new and - * bottom portion will stay as it was in previous frame. If we don't - * do that then missing chunks of video stream will result in flickering - * portions of old data whatever it was before. - * - * If we choose not to copy previous frame (to, for example, save few - * bus cycles - the frame can be pretty large!) then we have an option - * to clear the frame before using. If we experience losses in this - * mode then missing picture will be black (flickering). - * - * Finally, if user chooses not to clean the current frame before - * filling it with data then the old data will be visible if we fail - * to refill entire frame with new data. - */ - if (!(flags & FLAGS_SEPARATE_FRAMES)) { - /* This copies previous frame into this one to mask losses */ - memmove(frame->data, usbvision->frame[1 - framenum].data, - MAX_FRAME_SIZE); - } else { - if (flags & FLAGS_CLEAN_FRAMES) { - /*This provides a "clean" frame but slows things down */ - memset(frame->data, 0, MAX_FRAME_SIZE); - } - } - return 0; -} - -static int usbvision_muxsel(struct usb_usbvision *usbvision, int channel, int norm) +static int usbvision_muxsel(struct usb_usbvision *usbvision, int channel) { int mode[4]; int audio[]= {1, 0, 0, 0}; @@ -3618,16 +3639,10 @@ static int usbvision_muxsel(struct usb_usbvision *usbvision, int channel, int no //channel 3 is additional video inputs to the device with audio channel 0 (line in) RESTRICT_TO_RANGE(channel, 0, usbvision->video_inputs); - /* set the new video norm */ - if (usbvision->input.std != norm) { - v4l2_std_id video_command = norm; - + usbvision->ctl_input = channel; route.input = SAA7115_COMPOSITE1; call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route); - call_i2c_clients(usbvision, VIDIOC_S_STD, &video_command); - usbvision->input.std = norm; - call_i2c_clients(usbvision, VIDIOC_S_INPUT, &usbvision->input.index); //set norm in tuner - } + call_i2c_clients(usbvision, VIDIOC_S_INPUT, &usbvision->ctl_input); // set the new channel // Regular USB TV Tuners -> channel: 0 = Television, 1 = Composite, 2 = S-Video @@ -3703,8 +3718,13 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) errCode = -ENOMEM; } else { + spin_lock_init(&usbvision->queue_lock); + init_waitqueue_head(&usbvision->wait_frame); + init_waitqueue_head(&usbvision->wait_stream); + /* Allocate all buffers */ for (i = 0; i < USBVISION_NUMFRAMES; i++) { + usbvision->frame[i].index = i; usbvision->frame[i].grabstate = FrameState_Unused; usbvision->frame[i].data = usbvision->fbuf + i * MAX_FRAME_SIZE; @@ -3804,6 +3824,9 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) if (errCode) { } + /* prepare queues */ + usbvision_empty_framequeues(usbvision); + PDEBUG(DBG_IO, "success"); return errCode; } @@ -3875,6 +3898,8 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, if (!USBVISION_IS_OPERATIONAL(usbvision)) return -EFAULT; + // if (debug & DBG_IOCTL) v4l_printk_ioctl(cmd); + switch (cmd) { case UVIOCSREG: { @@ -3914,7 +3939,20 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_QUERYCAP: { struct v4l2_capability *vc=arg; - *vc = usbvision->vcap; + + memset(vc, 0, sizeof(*vc)); + strlcpy(vc->driver, "USBVision", sizeof(vc->driver)); + strlcpy(vc->card, usbvision_device_data[usbvision->DevModel].ModelString, + sizeof(vc->card)); + strlcpy(vc->bus_info, usbvision->dev->dev.bus_id, + sizeof(vc->bus_info)); + vc->version = USBVISION_DRIVER_VERSION; + vc->capabilities = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_AUDIO | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | + (dga ? (V4L2_FBUF_CAP_LIST_CLIPPING | V4L2_CAP_VIDEO_OVERLAY) : 0) | + (usbvision->have_tuner ? V4L2_CAP_TUNER : 0); PDEBUG(DBG_IOCTL, "VIDIOC_QUERYCAP"); return 0; } @@ -3975,38 +4013,24 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, } case VIDIOC_ENUMSTD: { - struct v4l2_standard *vs = arg; - switch(vs->index) { - case 0: - vs->id = V4L2_STD_PAL; - strcpy(vs->name,"PAL"); - vs->frameperiod.numerator = 1; - vs->frameperiod.denominator = 25; - vs->framelines = 625; - break; - case 1: - vs->id = V4L2_STD_NTSC; - strcpy(vs->name,"NTSC"); - vs->frameperiod.numerator = 1001; - vs->frameperiod.denominator = 30000; - vs->framelines = 525; - break; - case 2: - vs->id = V4L2_STD_SECAM; - strcpy(vs->name,"SECAM"); - vs->frameperiod.numerator = 1; - vs->frameperiod.denominator = 25; - vs->framelines = 625; - break; - default: + struct v4l2_standard *e = arg; + unsigned int i; + int ret; + + i = e->index; + if (i >= TVNORMS) return -EINVAL; - } + ret = v4l2_video_std_construct(e, tvnorms[e->index].id, + tvnorms[e->index].name); + e->index = i; + if (ret < 0) + return ret; return 0; } case VIDIOC_G_INPUT: { int *input = arg; - *input = usbvision->input.index; + *input = usbvision->ctl_input; return 0; } case VIDIOC_S_INPUT: @@ -4014,10 +4038,10 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, int *input = arg; if ((*input >= usbvision->video_inputs) || (*input < 0) ) return -EINVAL; - usbvision->input.index = *input; + usbvision->ctl_input = *input; down(&usbvision->lock); - usbvision_muxsel(usbvision, usbvision->input.index, usbvision->input.std); + usbvision_muxsel(usbvision, usbvision->ctl_input); usbvision_set_input(usbvision); usbvision_set_output(usbvision, usbvision->curwidth, usbvision->curheight); up(&usbvision->lock); @@ -4025,43 +4049,50 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, } case VIDIOC_G_STD: { - v4l2_std_id *std = arg; - *std = usbvision->input.std; - PDEBUG(DBG_IOCTL, "VIDIOC_G_STD std_id=%x", (unsigned)*std); + v4l2_std_id *id = arg; + + *id = usbvision->tvnorm->id; + + PDEBUG(DBG_IOCTL, "VIDIOC_G_STD std_id=%s", usbvision->tvnorm->name); return 0; } case VIDIOC_S_STD: { - v4l2_std_id *std = arg; + v4l2_std_id *id = arg; + unsigned int i; + + for (i = 0; i < TVNORMS; i++) + if (*id == tvnorms[i].id) + break; + if (i == TVNORMS) + for (i = 0; i < TVNORMS; i++) + if (*id & tvnorms[i].id) + break; + if (i == TVNORMS) + return -EINVAL; down(&usbvision->lock); - usbvision_muxsel(usbvision, usbvision->input.index, *std); - usbvision_set_input(usbvision); - usbvision_set_output(usbvision, usbvision->curwidth, usbvision->curheight); + usbvision->tvnorm = &tvnorms[i]; + + call_i2c_clients(usbvision, VIDIOC_S_STD, + &usbvision->tvnorm->id); + up(&usbvision->lock); - usbvision->input.std = *std; - PDEBUG(DBG_IOCTL, "VIDIOC_S_STD std_id=%x", (unsigned)*std); + PDEBUG(DBG_IOCTL, "VIDIOC_S_STD std_id=%s", usbvision->tvnorm->name); return 0; } case VIDIOC_G_TUNER: { struct v4l2_tuner *vt = arg; - struct v4l2_tuner status; if (!usbvision->have_tuner || vt->index) // Only tuner 0 return -EINVAL; strcpy(vt->name, "Television"); - vt->type = V4L2_TUNER_ANALOG_TV; - vt->capability = V4L2_TUNER_CAP_NORM; - vt->rangelow = 0; - vt->rangehigh = ~0; - vt->audmode = V4L2_TUNER_MODE_MONO; - vt->rxsubchans = V4L2_TUNER_SUB_MONO; - call_i2c_clients(usbvision,VIDIOC_G_TUNER,&status); - vt->signal = status.signal; - - PDEBUG(DBG_IOCTL, "VIDIOC_G_TUNER"); + /* Let clients fill in the remainder of this struct */ + call_i2c_clients(usbvision,VIDIOC_G_TUNER,vt); + + PDEBUG(DBG_IOCTL, "VIDIOC_G_TUNER signal=%x, afc=%x",vt->signal,vt->afc); return 0; } case VIDIOC_S_TUNER: @@ -4071,15 +4102,16 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, // Only no or one tuner for now if (!usbvision->have_tuner || vt->index) return -EINVAL; - // FIXME vt->audmode Radio mode (STEREO/MONO/...) - // vt->reserved Radio freq - // usbvision_muxsel(usbvision, vt->index, vt->mode); + /* let clients handle this */ + call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt); + PDEBUG(DBG_IOCTL, "VIDIOC_S_TUNER"); return 0; } case VIDIOC_G_FREQUENCY: { struct v4l2_frequency *freq = arg; + freq->tuner = 0; // Only one tuner freq->type = V4L2_TUNER_ANALOG_TV; freq->frequency = usbvision->freq; @@ -4089,6 +4121,11 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_S_FREQUENCY: { struct v4l2_frequency *freq = arg; + + // Only no or one tuner for now + if (!usbvision->have_tuner || freq->tuner) + return -EINVAL; + usbvision->freq = freq->frequency; call_i2c_clients(usbvision, cmd, freq); PDEBUG(DBG_IOCTL, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)freq->frequency); @@ -4149,11 +4186,27 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_REQBUFS: { struct v4l2_requestbuffers *vr = arg; - // FIXME : normally we allocate the requested number of buffers. - // this driver allocates statically the buffers. - vr->count = 2; - if(vr->memory != V4L2_MEMORY_MMAP) + int ret; + + RESTRICT_TO_RANGE(vr->count,1,USBVISION_NUMFRAMES); + + // Check input validity : the user must do a VIDEO CAPTURE and MMAP method. + if((vr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) || + (vr->memory != V4L2_MEMORY_MMAP)) return -EINVAL; + + // FIXME : before this, we must control if buffers are still mapped. + // Then interrupt streaming if so... + if(usbvision->streaming == Stream_On) { + if ((ret = usbvision_stream_interrupt(usbvision))) + return ret; + } + + usbvision_empty_framequeues(usbvision); + + usbvision->curFrame = NULL; + + PDEBUG(DBG_IOCTL, "VIDIOC_REQBUFS count=%d",vr->count); return 0; } case VIDIOC_QUERYBUF: @@ -4161,16 +4214,18 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, struct v4l2_buffer *vb = arg; struct usbvision_frame *frame; - // FIXME : works only on VIDEO_CAPTURE MODE, MMAP. + // FIXME : must control that buffers are mapped (VIDIOC_REQBUFS has been called) + if(vb->type != V4L2_CAP_VIDEO_CAPTURE) { return -EINVAL; } - if(vb->index>1) { + if(vb->index>=USBVISION_NUMFRAMES) { return -EINVAL; } + // Updating the corresponding frame state vb->flags = 0; frame = &usbvision->frame[vb->index]; - if(frame->grabstate == FrameState_Grabbing) + if(frame->grabstate >= FrameState_Ready) vb->flags |= V4L2_BUF_FLAG_QUEUED; if(frame->grabstate >= FrameState_Done) vb->flags |= V4L2_BUF_FLAG_DONE; @@ -4183,119 +4238,115 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, else { vb->m.offset = MAX_FRAME_SIZE; } + vb->memory = V4L2_MEMORY_MMAP; + vb->field = V4L2_FIELD_NONE; vb->length = MAX_FRAME_SIZE; vb->timestamp = usbvision->frame[vb->index].timestamp; - vb->sequence = usbvision->frame_num; + vb->sequence = usbvision->frame[vb->index].sequence; return 0; } - case VIDIOC_QBUF: // VIDIOCMCAPTURE + VIDIOCSYNC + case VIDIOC_QBUF: { struct v4l2_buffer *vb = arg; struct usbvision_frame *frame; + unsigned long lock_flags; // FIXME : works only on VIDEO_CAPTURE MODE, MMAP. if(vb->type != V4L2_CAP_VIDEO_CAPTURE) { return -EINVAL; } - if(vb->index>1) { + if(vb->index>=USBVISION_NUMFRAMES) { return -EINVAL; } frame = &usbvision->frame[vb->index]; - if (frame->grabstate == FrameState_Grabbing) { - return -EBUSY; + if (frame->grabstate != FrameState_Unused) { + return -EAGAIN; } - usbvision_set_output(usbvision, usbvision->curwidth, usbvision->curheight); - - /* Mark it as ready */ + /* Mark it as ready and enqueue frame */ frame->grabstate = FrameState_Ready; + frame->scanstate = ScanState_Scanning; + frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */ + vb->flags &= ~V4L2_BUF_FLAG_DONE; /* set v4l2_format index */ frame->v4l2_format = usbvision->palette; - PDEBUG(DBG_IOCTL, "VIDIOC_QBUF frame=%d",vb->index); - return usbvision_new_frame(usbvision, vb->index); + spin_lock_irqsave(&usbvision->queue_lock, lock_flags); + list_add_tail(&usbvision->frame[vb->index].frame, &usbvision->inqueue); + spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); + + return 0; } case VIDIOC_DQBUF: { struct v4l2_buffer *vb = arg; - int errCode = 0; + int ret; + struct usbvision_frame *f; + unsigned long lock_flags; - DECLARE_WAITQUEUE(wait, current); - // FIXME : not the proper way to get the last filled frame - vb->index=-1; - if(usbvision->curFrameNum != -1) vb->index=usbvision->curFrameNum; - else { - if(usbvision->frame[1].grabstate >= FrameState_Done) - vb->index = 1; - else if(usbvision->frame[0].grabstate >= FrameState_Done) - vb->index = 0; - // If no FRAME_DONE, look for a FRAME_GRABBING state. - // See if a frame is in process (grabbing), then use it. - if (vb->index == -1) { - if (usbvision->frame[1].grabstate == FrameState_Grabbing) - vb->index = 1; - else if (usbvision->frame[0].grabstate == FrameState_Grabbing) - vb->index = 0; - } - } - if (vb->index == -1) + if (vb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - PDEBUG(DBG_IOCTL, "VIDIOC_DQBUF frame=%d, grabstate=%d, curframeNum=%d", - vb->index, usbvision->frame[vb->index].grabstate,usbvision->curFrameNum); - - switch (usbvision->frame[vb->index].grabstate) { - case FrameState_Unused: - errCode = -EINVAL; - break; - case FrameState_Grabbing: - add_wait_queue(&usbvision->frame[vb->index].wq, &wait); - current->state = TASK_INTERRUPTIBLE; - while (usbvision->frame[vb->index].grabstate == FrameState_Grabbing) { - schedule(); - if (signal_pending(current)) { - remove_wait_queue(&usbvision->frame[vb->index].wq, &wait); - current->state = TASK_RUNNING; - return -EINTR; - } - } - remove_wait_queue(&usbvision->frame[vb->index].wq, &wait); - current->state = TASK_RUNNING; - case FrameState_Ready: - case FrameState_Error: - case FrameState_Done: - errCode = (usbvision->frame[vb->index].grabstate == FrameState_Error) ? -EIO : 0; - vb->memory = V4L2_MEMORY_MMAP; - vb->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE; - vb->field = V4L2_FIELD_NONE; - vb->sequence = usbvision->frame[vb->index].sequence; - usbvision->frame[vb->index].grabstate = FrameState_Unused; - break; + if (list_empty(&(usbvision->outqueue))) { + if (usbvision->streaming == Stream_Off) + return -EINVAL; + ret = wait_event_interruptible + (usbvision->wait_frame, + !list_empty(&(usbvision->outqueue))); + if (ret) + return ret; } - usbvision->frame[vb->index].grabstate = FrameState_Unused; - return errCode; + spin_lock_irqsave(&usbvision->queue_lock, lock_flags); + f = list_entry(usbvision->outqueue.next, + struct usbvision_frame, frame); + list_del(usbvision->outqueue.next); + spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); + + f->grabstate = FrameState_Unused; + + vb->memory = V4L2_MEMORY_MMAP; + vb->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE; + vb->index = f->index; + vb->sequence = f->sequence; + + return 0; } case VIDIOC_STREAMON: { int b=V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (list_empty(&usbvision->inqueue)) + return -EINVAL; + + usbvision->streaming = Stream_On; + call_i2c_clients(usbvision,VIDIOC_STREAMON , &b); + + PDEBUG(DBG_IOCTL, "VIDIOC_STREAMON"); + return 0; } case VIDIOC_STREAMOFF: { + int *type = arg; int b=V4L2_BUF_TYPE_VIDEO_CAPTURE; - down(&usbvision->lock); - // Stop all video streamings - call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b); - usbvision->frame_num = -1; - usbvision->frame[0].grabstate = FrameState_Unused; - usbvision->frame[1].grabstate = FrameState_Unused; - up(&usbvision->lock); + + if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if(usbvision->streaming == Stream_On) { + usbvision_stream_interrupt(usbvision); + // Stop all video streamings + call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b); + } + usbvision_empty_framequeues(usbvision); + + PDEBUG(DBG_IOCTL, "VIDIOC_STREAMOFF"); return 0; } case VIDIOC_G_FBUF: @@ -4361,6 +4412,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_ENUM_FMT: { struct v4l2_fmtdesc *vfd = arg; + if ( (dga == 0) && (vfd->type == V4L2_BUF_TYPE_VIDEO_OVERLAY) && (usbvision->palette.format != V4L2_PIX_FMT_YVU420) && @@ -4539,7 +4591,7 @@ static ssize_t usbvision_v4l2_read(struct file *file, char *buf, int frmx = -1; int rc = 0; struct usbvision_frame *frame; - +return -EINVAL; PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __FUNCTION__, (unsigned long)count, noblock); if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL)) @@ -4574,7 +4626,8 @@ static ssize_t usbvision_v4l2_read(struct file *file, char *buf, // If no frame is active, start one. if (frmx == -1) - usbvision_new_frame(usbvision, frmx = 0); + // FIXME: enqueue all inqueue... + /* usbvision_new_frame(usbvision, frmx = 0); */ frame = &usbvision->frame[frmx]; @@ -4584,7 +4637,7 @@ static ssize_t usbvision_v4l2_read(struct file *file, char *buf, goto usbvision_v4l2_read_done; } PDEBUG(DBG_IO, "Waiting frame grabbing"); - rc = wait_event_interruptible(frame->wq, (frame->grabstate == FrameState_Done) || + rc = wait_event_interruptible(usbvision->wait_frame, (frame->grabstate == FrameState_Done) || (frame->grabstate == FrameState_Error)); if (rc) { goto usbvision_v4l2_read_done; @@ -4592,9 +4645,10 @@ static ssize_t usbvision_v4l2_read(struct file *file, char *buf, if (frame->grabstate == FrameState_Error) { frame->bytes_read = 0; - if (usbvision_new_frame(usbvision, frmx)) { - err("%s: usbvision_new_frame() failed", __FUNCTION__); - } + // FIXME: enqueue all inqueue... +/* if (usbvision_new_frame(usbvision, frmx)) { */ +/* err("%s: usbvision_new_frame() failed", __FUNCTION__); */ +/* } */ goto restart; } @@ -4619,8 +4673,9 @@ static ssize_t usbvision_v4l2_read(struct file *file, char *buf, /* Mark it as available to be used again. */ usbvision->frame[frmx].grabstate = FrameState_Unused; - if (usbvision_new_frame(usbvision, frmx ? 0 : 1)) - err("%s: usbvision_new_frame() failed", __FUNCTION__); + // FIXME enqueue another frame +/* if (usbvision_new_frame(usbvision, frmx ? 0 : 1)) */ +/* err("%s: usbvision_new_frame() failed", __FUNCTION__); */ } usbvision_v4l2_read_done: @@ -5198,7 +5253,7 @@ static int usbvision_vbi_ioctl(struct inode *inode, struct file *file, static void usbvision_configure_video(struct usb_usbvision *usbvision) { - int model; + int model,i; if (usbvision == NULL) return; @@ -5215,17 +5270,26 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision) memset(&usbvision->vcap, 0, sizeof(usbvision->vcap)); strcpy(usbvision->vcap.driver, "USBVision"); - usbvision->vcap.capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + strlcpy(usbvision->vcap.bus_info, usbvision->dev->dev.bus_id, + sizeof(usbvision->vcap.bus_info)); + usbvision->vcap.capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | (dga ? (V4L2_FBUF_CAP_LIST_CLIPPING | V4L2_CAP_VIDEO_OVERLAY) : 0) | (usbvision->have_tuner ? V4L2_CAP_TUNER : 0); usbvision->vcap.version = USBVISION_DRIVER_VERSION; /* version */ - usbvision->video_inputs = usbvision_device_data[model].VideoChannels; - memset(&usbvision->input, 0, sizeof(usbvision->input)); - usbvision->input.tuner = 0; - usbvision->input.type = V4L2_INPUT_TYPE_TUNER|VIDEO_TYPE_CAMERA; - usbvision->input.std = usbvision_device_data[model].VideoNorm; + for (i = 0; i < TVNORMS; i++) + if (usbvision_device_data[model].VideoNorm == tvnorms[i].mode) + break; + if (i == TVNORMS) + i = 0; + usbvision->tvnorm = &tvnorms[i]; /* set default norm */ + call_i2c_clients(usbvision, VIDIOC_S_STD, + &usbvision->tvnorm->id); + + usbvision->video_inputs = usbvision_device_data[model].VideoChannels; + usbvision->ctl_input = 0; +/* usbvision_muxsel(usbvision, usbvision->ctl_input); */ /* This should be here to make i2c clients to be able to register */ usbvision_audio_off(usbvision); //first switch off audio @@ -5440,7 +5504,6 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision) static struct usb_usbvision *usbvision_alloc(struct usb_device *dev) { struct usb_usbvision *usbvision; - int FrameIdx; if ((usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL)) == NULL) { goto err_exit; @@ -5448,10 +5511,6 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev) usbvision->dev = dev; - for (FrameIdx = 0; FrameIdx < USBVISION_NUMFRAMES; FrameIdx++) { - init_waitqueue_head(&usbvision->frame[FrameIdx].wq); - } - init_waitqueue_head(&usbvision->overlay_frame.wq); init_MUTEX(&usbvision->lock); /* to 1 == available */ // prepare control urb for control messages during interrupts @@ -5460,7 +5519,7 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev) goto err_exit; } init_waitqueue_head(&usbvision->ctrlUrb_wq); - init_MUTEX(&usbvision->ctrlUrbLock); + init_MUTEX(&usbvision->ctrlUrbLock); /* to 1 == available */ init_timer(&usbvision->powerOffTimer); usbvision->powerOffTimer.data = (long) usbvision; @@ -5536,7 +5595,6 @@ static int __devinit usbvision_probe(struct usb_interface *intf, const struct us PDEBUG(DBG_PROBE, "VID=%#04x, PID=%#04x, ifnum=%u", dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum); - /* Is it an USBVISION video dev? */ model = 0; for(model = 0; usbvision_device_data[model].idVendor; model++) { @@ -5655,6 +5713,9 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf) usb_put_dev(usbvision->dev); usbvision->dev = NULL; // USB device is no more + wake_up_interruptible(&usbvision->wait_frame); + wake_up_interruptible(&usbvision->wait_stream); + up(&usbvision->lock); if (usbvision->user) { diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c index 466e11f4584..48afcd2aca3 100644 --- a/drivers/media/video/usbvision/usbvision-i2c.c +++ b/drivers/media/video/usbvision/usbvision-i2c.c @@ -1,4 +1,4 @@ -/* +/* * I2C_ALGO_USB.C * i2c algorithm for USB-I2C Bridges * @@ -39,7 +39,7 @@ #include #include "usbvision-i2c.h" -static int debug_i2c_usb = 0; +static int debug_i2c_usb = 0; #if defined(module_param) // Showing parameters under SYSFS module_param (debug_i2c_usb, int, 0444); // debug_i2c_usb mode of the device driver @@ -108,7 +108,7 @@ static inline int usb_find_address(struct i2c_adapter *i2c_adap, unsigned char *add) { unsigned short flags = msg->flags; - + unsigned char addr; int ret; if ((flags & I2C_M_TEN)) { @@ -205,8 +205,6 @@ static u32 usb_func(struct i2c_adapter *adap) static struct i2c_algorithm i2c_usb_algo = { .master_xfer = usb_xfer, .smbus_xfer = NULL, - .slave_send = NULL, - .slave_recv = NULL, .algo_control = algo_control, .functionality = usb_func, }; diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h index 813b258f89c..870c0cc81d8 100644 --- a/drivers/media/video/usbvision/usbvision.h +++ b/drivers/media/video/usbvision/usbvision.h @@ -1,4 +1,4 @@ -/* +/* * USBVISION.H * usbvision header file * @@ -38,7 +38,7 @@ #define USBVISION_SSPND_EN (1 << 1) #define USBVISION_RES2 (1 << 2) #define USBVISION_PWR_VID (1 << 5) - #define USBVISION_E2_EN (1 << 7) + #define USBVISION_E2_EN (1 << 7) #define USBVISION_CONFIG_REG 0x01 #define USBVISION_ADRS_REG 0x02 #define USBVISION_ALTER_REG 0x03 @@ -139,7 +139,7 @@ #define USBVISION_MAX_ISOC_PACKET_SIZE 959 // NT1003 Specs Document says 1023 #define USBVISION_NUM_HEADERMARKER 20 -#define USBVISION_NUMFRAMES 2 +#define USBVISION_NUMFRAMES 3 #define USBVISION_NUMSBUF 2 #define USBVISION_POWEROFF_TIME 3 * (HZ) // 3 seconds @@ -225,6 +225,13 @@ enum FrameState { FrameState_Error, /* Something bad happened while processing */ }; +/* stream states */ +enum StreamState { + Stream_Off, + Stream_Interrupt, + Stream_On, +}; + enum IsocState { IsocState_InFrame, /* Isoc packet is member of frame */ IsocState_NoFrame, /* Isoc packet is not member of any frame */ @@ -272,27 +279,36 @@ struct usbvision_frame_header { __u16 frameHeight; /* 10 - 11 after endian correction*/ }; +/* tvnorms */ +struct usbvision_tvnorm { + char *name; + v4l2_std_id id; + /* mode for saa7113h */ + int mode; +}; + struct usbvision_frame { char *data; /* Frame buffer */ struct usbvision_frame_header isocHeader; /* Header from stream */ int width; /* Width application is expecting */ int height; /* Height */ - + int index; /* Frame index */ int frmwidth; /* Width the frame actually is */ int frmheight; /* Height */ volatile int grabstate; /* State of grabbing */ int scanstate; /* State of scanning */ + struct list_head frame; + int curline; /* Line of frame we're working on */ long scanlength; /* uncompressed, raw data length of frame */ long bytes_read; /* amount of scanlength that has been read from data */ struct usbvision_v4l2_format_st v4l2_format; /* format the user needs*/ int v4l2_linesize; /* bytes for one videoline*/ - struct timeval timestamp; - wait_queue_head_t wq; /* Processes waiting */ + struct timeval timestamp; int sequence; // How many video frames we send to user }; @@ -305,23 +321,23 @@ struct usbvision_frame { #define USBVISION_I2C_CLIENTS_MAX 8 struct usbvision_device_data_st { - int idVendor; - int idProduct; - int Interface; /* to handle special interface number like BELKIN and Hauppauge WinTV-USB II */ - int Codec; - int VideoChannels; - __u64 VideoNorm; - int AudioChannels; - int Radio; - int vbi; - int Tuner; - int TunerType; - int Vin_Reg1; - int Vin_Reg2; - int X_Offset; - int Y_Offset; - int Dvi_yuv; - char *ModelString; + int idVendor; + int idProduct; + int Interface; /* to handle special interface number like BELKIN and Hauppauge WinTV-USB II */ + int Codec; + int VideoChannels; + __u64 VideoNorm; + int AudioChannels; + int Radio; + int vbi; + int Tuner; + int TunerType; + int Vin_Reg1; + int Vin_Reg2; + int X_Offset; + int Y_Offset; + int Dvi_yuv; + char *ModelString; }; /* Declared on usbvision-cards.c */ @@ -332,7 +348,7 @@ struct usb_usbvision { struct video_device *vdev; /* Video Device */ struct video_device *rdev; /* Radio Device */ struct video_device *vbi; /* VBI Device */ - struct video_audio audio_dev; /* Current audio params */ + struct video_audio audio_dev; /* Current audio params */ /* i2c Declaration Section*/ struct i2c_adapter i2c_adap; @@ -373,7 +389,7 @@ struct usb_usbvision { int usbvision_used; /* Is this structure in use? */ int initialized; /* Had we already sent init sequence? */ int DevModel; /* What type of USBVISION device we got? */ - int streaming; /* Are we streaming Isochronous? */ + enum StreamState streaming; /* Are we streaming Isochronous? */ int last_error; /* What calamity struck us? */ int curwidth; /* width of the frame the device is currently set to*/ int curheight; /* height of the frame the device is currently set to*/ @@ -382,7 +398,10 @@ struct usb_usbvision { char *fbuf; /* Videodev buffer area for mmap*/ int max_frame_size; /* Bytes in one video frame */ int fbuf_size; /* Videodev buffer size */ - int curFrameNum; // number of current frame in frame buffer mode + spinlock_t queue_lock; /* spinlock for protecting mods on inqueue and outqueue */ + struct list_head inqueue, outqueue; /* queued frame list and ready to dequeue frame list */ + wait_queue_head_t wait_frame; /* Processes waiting */ + wait_queue_head_t wait_stream; /* Processes waiting */ struct usbvision_frame *curFrame; // pointer to current frame, set by usbvision_find_header struct usbvision_frame frame[USBVISION_NUMFRAMES]; // frame buffer int curSbufNum; // number of current receiving sbuf @@ -397,20 +416,21 @@ struct usb_usbvision { int scratch_headermarker_read_ptr; int scratch_headermarker_write_ptr; int isocstate; - /* color controls */ + /* color controls */ int saturation; int hue; int brightness; - int contrast; + int contrast; int depth; struct usbvision_v4l2_format_st palette; struct v4l2_capability vcap; /* Video capabilities */ - struct v4l2_input input; /* May be used for tuner support */ + unsigned int ctl_input; /* selected input */ + struct usbvision_tvnorm *tvnorm; /* selected tv norm */ unsigned char video_endp; /* 0x82 for USBVISION devices based */ // Overlay stuff: - struct v4l2_framebuffer vid_buf; + struct v4l2_framebuffer vid_buf; struct v4l2_format vid_win; int vid_buf_valid; // Status: video buffer is valid (set) int vid_win_valid; // Status: video window is valid (set) @@ -435,8 +455,8 @@ struct usb_usbvision { struct proc_dir_entry *proc_devdir; /* Per-device proc directory */ struct proc_dir_entry *proc_info; /* /info entry */ struct proc_dir_entry *proc_register; /* /register entry */ - struct proc_dir_entry *proc_freq; /* /freq entry */ - struct proc_dir_entry *proc_input; /* /input entry */ + struct proc_dir_entry *proc_freq; /* /freq entry */ + struct proc_dir_entry *proc_input; /* /input entry */ struct proc_dir_entry *proc_frame; /* /frame entry */ struct proc_dir_entry *proc_button; /* /button entry */ struct proc_dir_entry *proc_control; /* /control entry */ @@ -463,3 +483,10 @@ struct usb_usbvision { #endif /* __LINUX_USBVISION_H */ +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ -- cgit v1.2.3 From 5f7fb877be14da92803f0b5b60955e071ebe2d58 Mon Sep 17 00:00:00 2001 From: Thierry Date: Mon, 4 Dec 2006 08:31:17 -0300 Subject: V4L/DVB (4928): Usbvision_v4l2 robustness on disconnect This patch corrects 2 bugs (causes kernel oops) that occur when unplugging the peripheral whereas nobody has opened it yet : - do not call usbvision_stop_isoc if usbvision_init_isoc has not been called - do not call wakeup_interruptible on waitqueues that did not have been initialized with init_waitqueue_head Signed-off-by: Thierry MERLE Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/usbvision/usbvision-core.c | 17 ++++++++--------- drivers/media/video/usbvision/usbvision.h | 7 ++++--- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index 06e8e67da36..5a61ed728b3 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -2287,7 +2287,7 @@ static void usbvision_isocIrq(struct urb *urb, struct pt_regs *regs) /* Manage streaming interruption */ if (usbvision->streaming == Stream_Interrupt) { - usbvision->streaming = Stream_Off; + usbvision->streaming = Stream_Idle; if ((*f)) { (*f)->grabstate = FrameState_Ready; (*f)->scanstate = ScanState_Scanning; @@ -3092,7 +3092,7 @@ static int usbvision_stream_interrupt(struct usb_usbvision *usbvision) usbvision->streaming = Stream_Interrupt; ret = wait_event_timeout(usbvision->wait_stream, - (usbvision->streaming == Stream_Off), + (usbvision->streaming == Stream_Idle), msecs_to_jiffies(USBVISION_NUMSBUF*USBVISION_URB_FRAMES)); return ret; } @@ -3579,7 +3579,7 @@ static int usbvision_init_isoc(struct usb_usbvision *usbvision) } } - usbvision->streaming = Stream_On; + usbvision->streaming = Stream_Idle; PDEBUG(DBG_ISOC, "%s: streaming=1 usbvision->video_endp=$%02x", __FUNCTION__, usbvision->video_endp); return 0; } @@ -3595,8 +3595,7 @@ static void usbvision_stop_isoc(struct usb_usbvision *usbvision) { int bufIdx, errCode, regValue; - // FIXME : removed the streaming==Stream_Off. This field has not the same signification than before ! - if (usbvision->dev == NULL) + if ((usbvision->streaming == Stream_Off) || (usbvision->dev == NULL)) return; /* Unschedule all of the iso td's */ @@ -4292,7 +4291,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, return -EINVAL; if (list_empty(&(usbvision->outqueue))) { - if (usbvision->streaming == Stream_Off) + if (usbvision->streaming == Stream_Idle) return -EINVAL; ret = wait_event_interruptible (usbvision->wait_frame, @@ -5665,6 +5664,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf, const struct us usbvision->isocPacketSize = 0; usbvision->usb_bandwidth = 0; usbvision->user = 0; + usbvision->streaming = Stream_Off; usbvision_register_video(usbvision); usbvision_configure_video(usbvision); @@ -5713,13 +5713,12 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf) usb_put_dev(usbvision->dev); usbvision->dev = NULL; // USB device is no more - wake_up_interruptible(&usbvision->wait_frame); - wake_up_interruptible(&usbvision->wait_stream); - up(&usbvision->lock); if (usbvision->user) { info("%s: In use, disconnect pending", __FUNCTION__); + wake_up_interruptible(&usbvision->wait_frame); + wake_up_interruptible(&usbvision->wait_stream); } else { usbvision_release(usbvision); diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h index 870c0cc81d8..ef83a5c4d2f 100644 --- a/drivers/media/video/usbvision/usbvision.h +++ b/drivers/media/video/usbvision/usbvision.h @@ -227,9 +227,10 @@ enum FrameState { /* stream states */ enum StreamState { - Stream_Off, - Stream_Interrupt, - Stream_On, + Stream_Off, /* Driver streaming is completely OFF */ + Stream_Idle, /* Driver streaming is ready to be put ON by the application */ + Stream_Interrupt, /* Driver streaming must be interrupted */ + Stream_On, /* Driver streaming is put ON by the application */ }; enum IsocState { -- cgit v1.2.3 From 3084920b555b3ba73590430b2e03d9167db23e8e Mon Sep 17 00:00:00 2001 From: Thierry MERLE Date: Mon, 4 Dec 2006 08:31:21 -0300 Subject: V4L/DVB (4929): Read() implementation + format set/get simplifications - implement read() entry point that works with linux list.h - rework of VIDIOC_ENUM_FMT/VIDIOC_S_FMT/VIDIOC_G_FMT - VIDIOC_STREAMON : allows streaming whereas there is no queued buffer (xdtv does VIDIOC_STREAMON before VIDIOC_QBUFs) Signed-off-by: Thierry MERLE Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/usbvision/usbvision-core.c | 323 +++++++++++++------------ 1 file changed, 167 insertions(+), 156 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index 5a61ed728b3..3833f3fbbdf 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -409,7 +409,8 @@ static int usbvision_nr = 0; // sequential number of usbvision device - +static unsigned long usbvision_timestamp = 0; // timestamp in jiffies of a hundred frame +static unsigned long usbvision_counter = 0; // frame counter static const int max_imgwidth = MAX_FRAME_WIDTH; static const int max_imgheight = MAX_FRAME_HEIGHT; @@ -4278,6 +4279,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, list_add_tail(&usbvision->frame[vb->index].frame, &usbvision->inqueue); spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); + PDEBUG(DBG_IOCTL, "VIDIOC_QBUF frame #%d",vb->index); return 0; } case VIDIOC_DQBUF: @@ -4312,18 +4314,31 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, vb->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE; vb->index = f->index; vb->sequence = f->sequence; + vb->timestamp = f->timestamp; + vb->field = V4L2_FIELD_NONE; + vb->bytesused = f->scanlength; + if(debug & DBG_IOCTL) { // do not spend computing time for debug stuff if not needed ! + if(usbvision_counter == 100) { + PDEBUG(DBG_IOCTL, "VIDIOC_DQBUF delta=%d",(unsigned)(jiffies-usbvision_timestamp)); + usbvision_counter = 0; + usbvision_timestamp = jiffies; + } + else { + usbvision_counter++; + } + PDEBUG(DBG_IOCTL, "VIDIOC_DQBUF frame #%d",vb->index); + } return 0; } case VIDIOC_STREAMON: { int b=V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (list_empty(&usbvision->inqueue)) - return -EINVAL; - usbvision->streaming = Stream_On; + if(debug & DBG_IOCTL) usbvision_timestamp = jiffies; + call_i2c_clients(usbvision,VIDIOC_STREAMON , &b); PDEBUG(DBG_IOCTL, "VIDIOC_STREAMON"); @@ -4412,134 +4427,132 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_fmtdesc *vfd = arg; - if ( (dga == 0) && - (vfd->type == V4L2_BUF_TYPE_VIDEO_OVERLAY) && - (usbvision->palette.format != V4L2_PIX_FMT_YVU420) && - (usbvision->palette.format != V4L2_PIX_FMT_YUV422P) ) { - return -EINVAL; - } if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) { return -EINVAL; } vfd->flags = 0; + vfd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; strcpy(vfd->description,usbvision_v4l2_format[vfd->index].desc); vfd->pixelformat = usbvision_v4l2_format[vfd->index].format; + memset(vfd->reserved, 0, sizeof(vfd->reserved)); return 0; } case VIDIOC_G_FMT: { struct v4l2_format *vf = arg; - if ( (dga == 0) && - (vf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY) && - (usbvision->palette.format != V4L2_PIX_FMT_YVU420) && - (usbvision->palette.format != V4L2_PIX_FMT_YUV422P) ) { - return -EINVAL; + switch (vf->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + { + vf->fmt.pix.width = usbvision->curwidth; + vf->fmt.pix.height = usbvision->curheight; + vf->fmt.pix.pixelformat = usbvision->palette.format; + vf->fmt.pix.bytesperline = usbvision->curwidth*usbvision->palette.bytes_per_pixel; + vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*usbvision->curheight; + vf->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + vf->fmt.pix.field = V4L2_FIELD_NONE; /* Always progressive image */ + } + return 0; + default: + PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT invalid type %d",vf->type); + return -EINVAL; } - down(&usbvision->lock); - *vf = usbvision->vid_win; - up(&usbvision->lock); - PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT x=%d, y=%d, w=%d, h=%d, chroma=%x, clips=%d", - vf->fmt.win.w.left, vf->fmt.win.w.top, vf->fmt.win.w.width, vf->fmt.win.w.height, vf->fmt.win.chromakey, vf->fmt.win.clipcount); + PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT w=%d, h=%d",vf->fmt.win.w.width, vf->fmt.win.w.height); return 0; } + case VIDIOC_TRY_FMT: case VIDIOC_S_FMT: { struct v4l2_format *vf = arg; struct v4l2_clip *vc=NULL; int on,formatIdx; - if ( (dga == 0) && - (vf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY) && - (usbvision->palette.format != V4L2_PIX_FMT_YVU420) && - (usbvision->palette.format != V4L2_PIX_FMT_YUV422P) ) { - return -EINVAL; - } - if(vf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY) { - if (vf->fmt.win.clipcount>256) { - return -EDOM; /* Too many clips! */ - } - // Do every clips. - vc = vmalloc(sizeof(struct v4l2_clip)*(vf->fmt.win.clipcount+4)); - if (vc == NULL) { - return -ENOMEM; - } - if (vf->fmt.win.clipcount && copy_from_user(vc,vf->fmt.win.clips,sizeof(struct v4l2_clip)*vf->fmt.win.clipcount)) { - return -EFAULT; - } - on = usbvision->overlay; // Save overlay state - if (on) { - usbvision_cap(usbvision, 0); - } + switch(vf->type) { + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + { + if (vf->fmt.win.clipcount>256) { + return -EDOM; /* Too many clips! */ + } + // Do every clips. + vc = vmalloc(sizeof(struct v4l2_clip)*(vf->fmt.win.clipcount+4)); + if (vc == NULL) { + return -ENOMEM; + } + if (vf->fmt.win.clipcount && copy_from_user(vc,vf->fmt.win.clips,sizeof(struct v4l2_clip)*vf->fmt.win.clipcount)) { + return -EFAULT; + } + on = usbvision->overlay; // Save overlay state + if (on) { + usbvision_cap(usbvision, 0); + } - // strange, it seems xawtv sometimes calls us with 0 - // width and/or height. Ignore these values - if (vf->fmt.win.w.left == 0) { - vf->fmt.win.w.left = usbvision->vid_win.fmt.win.w.left; - } - if (vf->fmt.win.w.top == 0) { - vf->fmt.win.w.top = usbvision->vid_win.fmt.win.w.top; - } + // strange, it seems xawtv sometimes calls us with 0 + // width and/or height. Ignore these values + if (vf->fmt.win.w.left == 0) { + vf->fmt.win.w.left = usbvision->vid_win.fmt.win.w.left; + } + if (vf->fmt.win.w.top == 0) { + vf->fmt.win.w.top = usbvision->vid_win.fmt.win.w.top; + } - // by now we are committed to the new data... - down(&usbvision->lock); - RESTRICT_TO_RANGE(vf->fmt.win.w.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH); - RESTRICT_TO_RANGE(vf->fmt.win.w.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT); - usbvision->vid_win = *vf; - usbvision->overlay_frame.width = vf->fmt.win.w.width; - usbvision->overlay_frame.height = vf->fmt.win.w.height; - usbvision_set_output(usbvision, vf->fmt.win.w.width, vf->fmt.win.w.height); - up(&usbvision->lock); - - // Impose display clips - if (vf->fmt.win.w.left+vf->fmt.win.w.width > (unsigned int)usbvision->vid_buf.fmt.width) { - usbvision_new_clip(vf, vc, usbvision->vid_buf.fmt.width-vf->fmt.win.w.left, 0, vf->fmt.win.w.width-1, vf->fmt.win.w.height-1); - } - if (vf->fmt.win.w.top+vf->fmt.win.w.height > (unsigned int)usbvision->vid_buf.fmt.height) { - usbvision_new_clip(vf, vc, 0, usbvision->vid_buf.fmt.height-vf->fmt.win.w.top, vf->fmt.win.w.width-1, vf->fmt.win.w.height-1); - } + // by now we are committed to the new data... + down(&usbvision->lock); + RESTRICT_TO_RANGE(vf->fmt.win.w.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH); + RESTRICT_TO_RANGE(vf->fmt.win.w.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT); + usbvision->vid_win = *vf; + usbvision->overlay_frame.width = vf->fmt.win.w.width; + usbvision->overlay_frame.height = vf->fmt.win.w.height; + usbvision_set_output(usbvision, vf->fmt.win.w.width, vf->fmt.win.w.height); + up(&usbvision->lock); + + // Impose display clips + if (vf->fmt.win.w.left+vf->fmt.win.w.width > (unsigned int)usbvision->vid_buf.fmt.width) { + usbvision_new_clip(vf, vc, usbvision->vid_buf.fmt.width-vf->fmt.win.w.left, 0, vf->fmt.win.w.width-1, vf->fmt.win.w.height-1); + } + if (vf->fmt.win.w.top+vf->fmt.win.w.height > (unsigned int)usbvision->vid_buf.fmt.height) { + usbvision_new_clip(vf, vc, 0, usbvision->vid_buf.fmt.height-vf->fmt.win.w.top, vf->fmt.win.w.width-1, vf->fmt.win.w.height-1); + } - // built the requested clipping zones - usbvision_built_overlay(usbvision, vf->fmt.win.clipcount, vc); - vfree(vc); + // built the requested clipping zones + usbvision_built_overlay(usbvision, vf->fmt.win.clipcount, vc); + vfree(vc); - // restore overlay state - if (on) { - usbvision_cap(usbvision, 1); + // restore overlay state + if (on) { + usbvision_cap(usbvision, 1); + } + usbvision->vid_win_valid = 1; + PDEBUG(DBG_IOCTL, "VIDIOC_S_FMT overlay x=%d, y=%d, w=%d, h=%d, chroma=%x, clips=%d", + vf->fmt.win.w.left, vf->fmt.win.w.top, vf->fmt.win.w.width, vf->fmt.win.w.height, vf->fmt.win.chromakey, vf->fmt.win.clipcount); + return 0; } - usbvision->vid_win_valid = 1; - PDEBUG(DBG_IOCTL, "VIDIOC_S_FMT overlay x=%d, y=%d, w=%d, h=%d, chroma=%x, clips=%d", - vf->fmt.win.w.left, vf->fmt.win.w.top, vf->fmt.win.w.width, vf->fmt.win.w.height, vf->fmt.win.chromakey, vf->fmt.win.clipcount); - } - else { - /* Find requested format in available ones */ - for(formatIdx=0;formatIdxfmt.pix.pixelformat == usbvision_v4l2_format[formatIdx].format) { - usbvision->palette = usbvision_v4l2_format[formatIdx]; - break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + { + /* Find requested format in available ones */ + for(formatIdx=0;formatIdxfmt.pix.pixelformat == usbvision_v4l2_format[formatIdx].format) { + usbvision->palette = usbvision_v4l2_format[formatIdx]; + break; + } + } + /* robustness */ + if(formatIdx == USBVISION_SUPPORTED_PALETTES) { + return -EINVAL; } + RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH); + RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT); + // by now we are committed to the new data... + down(&usbvision->lock); + usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height); + up(&usbvision->lock); + + PDEBUG(DBG_IOCTL, "VIDIOC_S_FMT grabdisplay w=%d, h=%d, format=%s", + vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc); + return 0; } - /* robustness */ - if(formatIdx == USBVISION_SUPPORTED_PALETTES) { + default: return -EINVAL; - } - usbvision->vid_win.fmt.pix.pixelformat = vf->fmt.pix.pixelformat; - usbvision->vid_win.fmt.pix.width = vf->fmt.pix.width; //Image width in pixels. - usbvision->vid_win.fmt.pix.height = vf->fmt.pix.height; // Image height in pixels. - - // by now we are committed to the new data... - down(&usbvision->lock); - RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH); - RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT); - usbvision->vid_win = *vf; - usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height); - up(&usbvision->lock); - - usbvision->vid_win_valid = 1; - PDEBUG(DBG_IOCTL, "VIDIOC_S_FMT grabdisplay w=%d, h=%d, ", - vf->fmt.pix.width, vf->fmt.pix.height); } - return 0; } case VIDIOC_OVERLAY: { @@ -4586,99 +4599,97 @@ static ssize_t usbvision_v4l2_read(struct file *file, char *buf, struct video_device *dev = video_devdata(file); struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); int noblock = file->f_flags & O_NONBLOCK; + unsigned long lock_flags; int frmx = -1; - int rc = 0; + int ret,i; struct usbvision_frame *frame; -return -EINVAL; + PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __FUNCTION__, (unsigned long)count, noblock); if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL)) return -EFAULT; - down(&usbvision->lock); - //code for testing compression - if (usbvision->isocMode == ISOC_MODE_COMPRESS) { - usbvision->frame[0].v4l2_format = usbvision_v4l2_format[0]; //V4L2_PIX_FMT_GREY; - usbvision->frame[1].v4l2_format = usbvision_v4l2_format[0]; // V4L2_PIX_FMT_GREY; - } + /* no stream is running, make it running ! */ + usbvision->streaming = Stream_On; + call_i2c_clients(usbvision,VIDIOC_STREAMON , NULL); - // See if a frame is completed, then use it. - if (usbvision->frame[0].grabstate >= FrameState_Done) // _Done or _Error - frmx = 0; - else if (usbvision->frame[1].grabstate >= FrameState_Done)// _Done or _Error - frmx = 1; + /* First, enqueue as many frames as possible (like a user of VIDIOC_QBUF would do) */ + for(i=0;iframe[i]; + if(frame->grabstate == FrameState_Unused) { + /* Mark it as ready and enqueue frame */ + frame->grabstate = FrameState_Ready; + frame->scanstate = ScanState_Scanning; + frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */ - if (noblock && (frmx == -1)) { - count = -EAGAIN; - goto usbvision_v4l2_read_done; - } + /* set v4l2_format index */ + frame->v4l2_format = usbvision->palette; - // If no FRAME_DONE, look for a FRAME_GRABBING state. - // See if a frame is in process (grabbing), then use it. - if (frmx == -1) { - if (usbvision->frame[0].grabstate == FrameState_Grabbing) - frmx = 0; - else if (usbvision->frame[1].grabstate == FrameState_Grabbing) - frmx = 1; + spin_lock_irqsave(&usbvision->queue_lock, lock_flags); + list_add_tail(&frame->frame, &usbvision->inqueue); + spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); + } } - // If no frame is active, start one. - if (frmx == -1) - // FIXME: enqueue all inqueue... - /* usbvision_new_frame(usbvision, frmx = 0); */ - - frame = &usbvision->frame[frmx]; + /* Then try to steal a frame (like a VIDIOC_DQBUF would do) */ + if (list_empty(&(usbvision->outqueue))) { + if(noblock) + return -EAGAIN; - restart: - if (!USBVISION_IS_OPERATIONAL(usbvision)) { - count = -EIO; - goto usbvision_v4l2_read_done; + ret = wait_event_interruptible + (usbvision->wait_frame, + !list_empty(&(usbvision->outqueue))); + if (ret) + return ret; } - PDEBUG(DBG_IO, "Waiting frame grabbing"); - rc = wait_event_interruptible(usbvision->wait_frame, (frame->grabstate == FrameState_Done) || - (frame->grabstate == FrameState_Error)); - if (rc) { - goto usbvision_v4l2_read_done; + + spin_lock_irqsave(&usbvision->queue_lock, lock_flags); + frame = list_entry(usbvision->outqueue.next, + struct usbvision_frame, frame); + list_del(usbvision->outqueue.next); + spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); + + if(debug & DBG_IOCTL) { // do not spend computing time for debug stuff if not needed ! + if(usbvision_counter == 100) { + PDEBUG(DBG_IOCTL, "VIDIOC_DQBUF delta=%d",(unsigned)(jiffies-usbvision_timestamp)); + usbvision_counter = 0; + usbvision_timestamp = jiffies; + } + else { + usbvision_counter++; + } } + /* An error returns an empty frame */ if (frame->grabstate == FrameState_Error) { frame->bytes_read = 0; - // FIXME: enqueue all inqueue... -/* if (usbvision_new_frame(usbvision, frmx)) { */ -/* err("%s: usbvision_new_frame() failed", __FUNCTION__); */ -/* } */ - goto restart; + return 0; } PDEBUG(DBG_IO, "%s: frmx=%d, bytes_read=%ld, scanlength=%ld", __FUNCTION__, - frmx, frame->bytes_read, frame->scanlength); + frame->index, frame->bytes_read, frame->scanlength); /* copy bytes to user space; we allow for partials reads */ if ((count + frame->bytes_read) > (unsigned long)frame->scanlength) count = frame->scanlength - frame->bytes_read; if (copy_to_user(buf, frame->data + frame->bytes_read, count)) { - count = -EFAULT; - goto usbvision_v4l2_read_done; + return -EFAULT; } frame->bytes_read += count; PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld", __FUNCTION__, (unsigned long)count, frame->bytes_read); - if (frame->bytes_read >= frame->scanlength) {// All data has been read + // For now, forget the frame if it has not been read in one shot. +/* if (frame->bytes_read >= frame->scanlength) {// All data has been read */ frame->bytes_read = 0; /* Mark it as available to be used again. */ usbvision->frame[frmx].grabstate = FrameState_Unused; - // FIXME enqueue another frame -/* if (usbvision_new_frame(usbvision, frmx ? 0 : 1)) */ -/* err("%s: usbvision_new_frame() failed", __FUNCTION__); */ - } +/* } */ -usbvision_v4l2_read_done: - up(&usbvision->lock); return count; } -- cgit v1.2.3 From 40bad67840aa6856cb39a431510a57d940017898 Mon Sep 17 00:00:00 2001 From: Thierry MERLE Date: Mon, 4 Dec 2006 08:31:24 -0300 Subject: V4L/DVB (4930): Usbvision_v4l2 : mmap corrected to get all frames - private ioctls UVIOCSREG/UVIOCGREG translated to the VIDIOC_INT_G_REGISTER/VIDIOC_INT_S_REGISTER - lost frame bug corrected (mmap rework) - reset scratch buffer is no buffer is queued (prevents useless scratch overflow management) Signed-off-by: Thierry MERLE Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/usbvision/usbvision-core.c | 105 ++++++++++++++----------- 1 file changed, 59 insertions(+), 46 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index 3833f3fbbdf..eb8f4ca3a15 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -364,8 +364,6 @@ #endif #include "usbvision.h" -#include "usbvision_ioctl.h" - #define DRIVER_VERSION "0.9.8.3cvs for Linux kernels 2.4.19-2.4.32 + 2.6.0-2.6.17, compiled at "__DATE__", "__TIME__ #define EMAIL "joerg@heckenbach-aw.de" @@ -2320,6 +2318,10 @@ static void usbvision_isocIrq(struct urb *urb, struct pt_regs *regs) } } } + else { + PDEBUG(DBG_IRQ, "received data, but no one needs it"); + scratch_reset(usbvision); + } usbvision->timeInIrq += jiffies - startTime; @@ -3901,41 +3903,50 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, // if (debug & DBG_IOCTL) v4l_printk_ioctl(cmd); switch (cmd) { - case UVIOCSREG: + +#ifdef CONFIG_VIDEO_ADV_DEBUG + /* ioctls to allow direct acces to the NT100x registers */ + case VIDIOC_INT_G_REGISTER: { - struct usbvision_reg *usbvision_reg = arg; + struct v4l2_register *reg = arg; int errCode; - errCode = usbvision_write_reg(usbvision, usbvision_reg->addr, usbvision_reg->value); - + if (reg->i2c_id != 0) + return -EINVAL; + /* NT100x has a 8-bit register space */ + errCode = usbvision_read_reg(usbvision, reg->reg&0xff); if (errCode < 0) { - err("%s: UVIOCSREG failed: error %d", __FUNCTION__, errCode); + err("%s: VIDIOC_INT_G_REGISTER failed: error %d", __FUNCTION__, errCode); } else { - PDEBUG(DBG_IOCTL, "UVIOCSREG addr=0x%02X, value=0x%02X", - usbvision_reg->addr, usbvision_reg->value); - errCode = 0; + reg->val=(unsigned char)errCode; + PDEBUG(DBG_IOCTL, "VIDIOC_INT_G_REGISTER reg=0x%02X, value=0x%02X", + (unsigned int)reg->reg, reg->val); + errCode = 0; // No error } return errCode; } - case UVIOCGREG: + case VIDIOC_INT_S_REGISTER: { - struct usbvision_reg *usbvision_reg = arg; + struct v4l2_register *reg = arg; int errCode; - errCode = usbvision_read_reg(usbvision, usbvision_reg->addr); - + if (reg->i2c_id != 0) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val); if (errCode < 0) { - err("%s: UVIOCGREG failed: error %d", __FUNCTION__, errCode); + err("%s: VIDIOC_INT_S_REGISTER failed: error %d", __FUNCTION__, errCode); } else { - usbvision_reg->value=(unsigned char)errCode; - PDEBUG(DBG_IOCTL, "UVIOCGREG addr=0x%02X, value=0x%02X", - usbvision_reg->addr, usbvision_reg->value); - errCode = 0; // No error + PDEBUG(DBG_IOCTL, "VIDIOC_INT_S_REGISTER reg=0x%02X, value=0x%02X", + (unsigned int)reg->reg, reg->val); + errCode = 0; } - return errCode; + return 0; } +#endif case VIDIOC_QUERYCAP: { struct v4l2_capability *vc=arg; @@ -4232,12 +4243,9 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, if(frame->grabstate == FrameState_Unused) vb->flags |= V4L2_BUF_FLAG_MAPPED; vb->memory = V4L2_MEMORY_MMAP; - if(vb->index == 0) { - vb->m.offset = 0; - } - else { - vb->m.offset = MAX_FRAME_SIZE; - } + + vb->m.offset = vb->index*MAX_FRAME_SIZE; + vb->memory = V4L2_MEMORY_MMAP; vb->field = V4L2_FIELD_NONE; vb->length = MAX_FRAME_SIZE; @@ -4695,40 +4703,45 @@ static ssize_t usbvision_v4l2_read(struct file *file, char *buf, static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) { + unsigned long size = vma->vm_end - vma->vm_start, + start = vma->vm_start; + void *pos; + u32 i; + struct video_device *dev = video_devdata(file); struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); - unsigned long start = vma->vm_start; - unsigned long size = vma->vm_end-vma->vm_start; - - unsigned long page, pos; if (!USBVISION_IS_OPERATIONAL(usbvision)) return -EFAULT; - if (size > (((USBVISION_NUMFRAMES * usbvision->max_frame_size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) + if (!(vma->vm_flags & VM_WRITE) || + size != PAGE_ALIGN(usbvision->max_frame_size)) { + return -EINVAL; + } + + for (i = 0; i < USBVISION_NUMFRAMES; i++) { + if (((usbvision->max_frame_size*i) >> PAGE_SHIFT) == vma->vm_pgoff) + break; + } + if (i == USBVISION_NUMFRAMES) { + PDEBUG(DBG_FUNC, "mmap: user supplied mapping address is out of range"); return -EINVAL; + } - pos = (unsigned long) usbvision->fbuf; + /* VM_IO is eventually going to replace PageReserved altogether */ + vma->vm_flags |= VM_IO; + vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */ + + pos = usbvision->frame[i].data; while (size > 0) { -// Really ugly.... - #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10) //Compatibility for 2.6.10+ kernels - page = vmalloc_to_pfn((void *)pos); - if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { - return -EAGAIN; - } - #else //Compatibility for 2.6.0 - 2.6.9 kernels - page = usbvision_kvirt_to_pa(pos); - if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { + if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { + PDEBUG(DBG_FUNC, "mmap: vm_insert_page failed"); return -EAGAIN; } - #endif start += PAGE_SIZE; pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + size -= PAGE_SIZE; } return 0; -- cgit v1.2.3 From ee5407c5019eb720872abea2e0a1376c35e2304a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 4 Dec 2006 08:31:27 -0300 Subject: V4L/DVB (4931): Removed usbvision_ioctl.h, since it isn't required anymore Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/usbvision/usbvision_ioctl.h | 34 ------------------------- 1 file changed, 34 deletions(-) delete mode 100644 drivers/media/video/usbvision/usbvision_ioctl.h (limited to 'drivers/media/video') diff --git a/drivers/media/video/usbvision/usbvision_ioctl.h b/drivers/media/video/usbvision/usbvision_ioctl.h deleted file mode 100644 index 7204c5ceda4..00000000000 --- a/drivers/media/video/usbvision/usbvision_ioctl.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * USBVISION_IOCTL.H - * IOCTL for usbvision - * - * Copyright (c) 1999-2005 Joerg Heckenbach - * - * This module is part of usbvision driver project. - * Updates to driver completed by Dwaine P. Garden - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -struct usbvision_reg { - unsigned char addr; - unsigned char value; -}; - -#define UVIOCGREG _IOWR('u',240,struct usbvision_reg) // get register -#define UVIOCSREG _IOW('u',241,struct usbvision_reg) // set register -#define UVIOCSVINM _IOW('u',242,int) // set usbvision vin_mode - -- cgit v1.2.3 From 957883d0b56a649389d0652a727324dd8ba2e83c Mon Sep 17 00:00:00 2001 From: Thierry MERLE Date: Mon, 4 Dec 2006 08:31:30 -0300 Subject: V4L/DVB (4932): Usbvision_v4l2: fix norm setting problems Patch contents: - fix i2c command broadcast (caused problems for SECAM norm setting) - default input selection at driver open Signed-off-by: Thierry MERLE Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/usbvision/usbvision-core.c | 99 ++++++++++++-------------- drivers/media/video/usbvision/usbvision.h | 5 +- 2 files changed, 46 insertions(+), 58 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index eb8f4ca3a15..f87bd0afbbf 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -2570,58 +2570,61 @@ static int usbvision_unrequest_intra (struct usb_usbvision *usbvision) static void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd, void *arg) { - - int i; - - for (i = 0; i < USBVISION_I2C_CLIENTS_MAX; i++) { - if (NULL == usbvision->i2c_clients[i]) - continue; - if (NULL == usbvision->i2c_clients[i]->driver->command) - continue; - usbvision->i2c_clients[i]->driver->command(usbvision->i2c_clients[i], cmd, arg); - } + BUG_ON(NULL == usbvision->i2c_adap.algo_data); + i2c_clients_command(&usbvision->i2c_adap, cmd, arg); } static int attach_inform(struct i2c_client *client) { struct usb_usbvision *usbvision; - struct tuner_setup tun_addr; - int i; - #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - usbvision = (struct usb_usbvision *)client->adapter->data; - #else - usbvision = (struct usb_usbvision *)i2c_get_adapdata(client->adapter); - #endif + usbvision = (struct usb_usbvision *)i2c_get_adapdata(client->adapter); + + switch (client->addr << 1) { + case 0x43: + case 0x4b: + { + struct tuner_setup tun_setup; - for (i = 0; i < USBVISION_I2C_CLIENTS_MAX; i++) { - if (usbvision->i2c_clients[i] == NULL || - usbvision->i2c_clients[i]->driver->id == - client->driver->id) { - usbvision->i2c_clients[i] = client; + tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; + tun_setup.type = TUNER_TDA9887; + tun_setup.addr = client->addr; + + call_i2c_clients(usbvision, TUNER_SET_TYPE_ADDR, &tun_setup); break; } - } - if ((usbvision->have_tuner) && (usbvision->tuner_type != -1)) { - tun_addr.mode_mask = T_ANALOG_TV; - tun_addr.type = usbvision->tuner_type; - tun_addr.addr = ADDR_UNSET; - client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_addr); - call_i2c_clients(usbvision, VIDIOC_INT_RESET, NULL); - call_i2c_clients(usbvision, VIDIOC_S_INPUT, &usbvision->ctl_input); - call_i2c_clients(usbvision, VIDIOC_STREAMON, NULL); - } - call_i2c_clients(usbvision, VIDIOC_S_STD, &usbvision->tvnorm->id); + case 0x42: + PDEBUG(DBG_I2C,"attach_inform: saa7114 detected.\n"); + break; + case 0x4a: + PDEBUG(DBG_I2C,"attach_inform: saa7113 detected.\n"); + break; + case 0xa0: + PDEBUG(DBG_I2C,"attach_inform: eeprom detected.\n"); + break; - PDEBUG(DBG_I2C, "usbvision[%d] attaches %s", usbvision->nr, client->name); + default: + PDEBUG(DBG_I2C,"attach inform: detected I2C address %x\n", client->addr << 1); + { + struct tuner_setup tun_setup; + usbvision->tuner_addr = client->addr; + + if ((usbvision->have_tuner) && (usbvision->tuner_type != -1)) { + tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; + tun_setup.type = usbvision->tuner_type; + tun_setup.addr = usbvision->tuner_addr; + call_i2c_clients(usbvision, TUNER_SET_TYPE_ADDR, &tun_setup); + } + } + break; + } return 0; } static int detach_inform(struct i2c_client *client) { struct usb_usbvision *usbvision; - int i; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) usbvision = (struct usb_usbvision *)client->adapter->data; @@ -2630,14 +2633,6 @@ static int detach_inform(struct i2c_client *client) #endif PDEBUG(DBG_I2C, "usbvision[%d] detaches %s", usbvision->nr, client->name); - for (i = 0; i < USBVISION_I2C_CLIENTS_MAX; i++) { - if (NULL != usbvision->i2c_clients[i] && - usbvision->i2c_clients[i]->driver->id == - client->driver->id) { - usbvision->i2c_clients[i] = NULL; - break; - } - } return 0; } @@ -2886,10 +2881,7 @@ static int usbvision_init_i2c(struct usb_usbvision *usbvision) } #endif - usbvision->i2c_ok = usbvision_i2c_usb_add_bus(&usbvision->i2c_adap); - - return usbvision->i2c_ok; - + return usbvision_i2c_usb_add_bus(&usbvision->i2c_adap); } @@ -3811,6 +3803,8 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) if (!errCode) { usbvision_begin_streaming(usbvision); errCode = usbvision_init_isoc(usbvision); + /* device needs to be initialized before isoc transfer */ + usbvision_muxsel(usbvision,0); usbvision->user++; } else { @@ -4169,7 +4163,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, memset(ctrl,0,sizeof(*ctrl)); ctrl->id=id; - i2c_clients_command(&usbvision->i2c_adap, cmd, arg); + call_i2c_clients(usbvision, cmd, arg); if (ctrl->type) return 0; @@ -5300,19 +5294,15 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision) (usbvision->have_tuner ? V4L2_CAP_TUNER : 0); usbvision->vcap.version = USBVISION_DRIVER_VERSION; /* version */ - for (i = 0; i < TVNORMS; i++) if (usbvision_device_data[model].VideoNorm == tvnorms[i].mode) break; if (i == TVNORMS) i = 0; - usbvision->tvnorm = &tvnorms[i]; /* set default norm */ - call_i2c_clients(usbvision, VIDIOC_S_STD, - &usbvision->tvnorm->id); + usbvision->tvnorm = &tvnorms[i]; /* set default norm */ usbvision->video_inputs = usbvision_device_data[model].VideoChannels; usbvision->ctl_input = 0; -/* usbvision_muxsel(usbvision, usbvision->ctl_input); */ /* This should be here to make i2c clients to be able to register */ usbvision_audio_off(usbvision); //first switch off audio @@ -5678,6 +5668,8 @@ static int __devinit usbvision_probe(struct usb_interface *intf, const struct us usbvision->tuner_type = usbvision_device_data[model].TunerType; } + usbvision->tuner_addr = ADDR_UNSET; + usbvision->DevModel = model; usbvision->remove_pending = 0; usbvision->last_error = 0; @@ -5689,7 +5681,6 @@ static int __devinit usbvision_probe(struct usb_interface *intf, const struct us usbvision->usb_bandwidth = 0; usbvision->user = 0; usbvision->streaming = Stream_Off; - usbvision_register_video(usbvision); usbvision_configure_video(usbvision); up(&usbvision->lock); diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h index ef83a5c4d2f..f304e66b03a 100644 --- a/drivers/media/video/usbvision/usbvision.h +++ b/drivers/media/video/usbvision/usbvision.h @@ -319,8 +319,6 @@ struct usbvision_frame { #define BRIDGE_NT1004 1004 #define BRIDGE_NT1005 1005 -#define USBVISION_I2C_CLIENTS_MAX 8 - struct usbvision_device_data_st { int idVendor; int idProduct; @@ -355,8 +353,6 @@ struct usb_usbvision { struct i2c_adapter i2c_adap; struct i2c_algo_usb_data i2c_algo; struct i2c_client i2c_client; - int i2c_state, i2c_ok; - struct i2c_client *i2c_clients[USBVISION_I2C_CLIENTS_MAX]; struct urb *ctrlUrb; unsigned char ctrlUrbBuffer[8]; @@ -367,6 +363,7 @@ struct usb_usbvision { int have_tuner; int tuner_type; + int tuner_addr; int bridgeType; // NT1003, NT1004, NT1005 int channel; int radio; -- cgit v1.2.3 From 3086d6cb0a2ec93f17bc215af3113c54af6080c1 Mon Sep 17 00:00:00 2001 From: Thierry MERLE Date: Mon, 4 Dec 2006 08:31:32 -0300 Subject: V4L/DVB (4933): Usbvision_v4l2: radio interface / tda9887 problem ? - implement the v4l2 radio interface Signed-off-by: Thierry MERLE Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/usbvision/usbvision-core.c | 234 +++++++------------------ 1 file changed, 67 insertions(+), 167 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index f87bd0afbbf..0365c7f9397 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -4835,220 +4835,120 @@ static int usbvision_do_radio_ioctl(struct inode *inode, struct file *file, return -EIO; switch (cmd) { - /*************************** - * V4L2 IOCTLs * - ***************************/ case VIDIOC_QUERYCAP: { struct v4l2_capability *vc=arg; - memset(vc, 0, sizeof(struct v4l2_capability)); - strcpy(vc->driver,"usbvision radio"); - strcpy(vc->card,usbvision->vcap.card); - strcpy(vc->bus_info,"usb"); - vc->version = USBVISION_DRIVER_VERSION; /* version */ - vc->capabilities = V4L2_CAP_TUNER; /* capabilities */ - PDEBUG(DBG_RIO, "%s: VIDIOC_QUERYCAP", __FUNCTION__); + + memset(vc, 0, sizeof(*vc)); + strlcpy(vc->driver, "USBVision", sizeof(vc->driver)); + strlcpy(vc->card, usbvision_device_data[usbvision->DevModel].ModelString, + sizeof(vc->card)); + strlcpy(vc->bus_info, usbvision->dev->dev.bus_id, + sizeof(vc->bus_info)); + vc->version = USBVISION_DRIVER_VERSION; + vc->capabilities = (usbvision->have_tuner ? V4L2_CAP_TUNER : 0); + PDEBUG(DBG_RIO, "VIDIOC_QUERYCAP"); return 0; } case VIDIOC_QUERYCTRL: { - struct v4l2_queryctrl *qc = arg; - switch(qc->id) - { - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill_std(qc); - break; - default: - return -EINVAL; - } - return 0; + struct v4l2_queryctrl *ctrl = arg; + int id=ctrl->id; + + memset(ctrl,0,sizeof(*ctrl)); + ctrl->id=id; + + call_i2c_clients(usbvision, cmd, arg); + PDEBUG(DBG_RIO,"VIDIOC_QUERYCTRL id=%x value=%x",ctrl->id,ctrl->type); + + if (ctrl->type) + return 0; + else + return -EINVAL; + } case VIDIOC_G_CTRL: { struct v4l2_control *ctrl = arg; - PDEBUG(DBG_IOCTL, "VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value); - switch(ctrl->id) { - case V4L2_CID_AUDIO_VOLUME: - /* ctrl->value = usbvision->volume; */ - break; - case V4L2_CID_AUDIO_MUTE: - ctrl->value = usbvision->AudioMute; - break; - default: - return -EINVAL; - } + + call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl); + PDEBUG(DBG_RIO,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value); return 0; } case VIDIOC_S_CTRL: { struct v4l2_control *ctrl = arg; - call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl); - PDEBUG(DBG_RIO, "%s: VIDIOC_S_CTRL id=%x value=%x", __FUNCTION__,ctrl->id,ctrl->value); + call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl); + PDEBUG(DBG_RIO, "VIDIOC_S_CTRL id=%x value=%x",ctrl->id,ctrl->value); return 0; } case VIDIOC_G_TUNER: { - struct v4l2_tuner *vt = arg; + struct v4l2_tuner *t = arg; - if (!usbvision->have_tuner || vt->index) // Only tuner 0 + if (t->index > 0) return -EINVAL; - strcpy(vt->name, "Radio"); - vt->type = V4L2_TUNER_RADIO; - vt->capability = V4L2_TUNER_CAP_STEREO; - // japan: 76.0 MHz - 89.9 MHz - // western europe: 87.5 MHz - 108.0 MHz - // russia: 65.0 MHz - 108.0 MHz - vt->rangelow = (int)(65*16);; - vt->rangehigh = (int)(108*16); - vt->audmode = V4L2_TUNER_MODE_STEREO; - vt->rxsubchans = V4L2_TUNER_SUB_STEREO; - call_i2c_clients(usbvision,VIDIOC_G_TUNER,&vt); - PDEBUG(DBG_RIO, "%s: VIDIOC_G_TUNER signal=%d", __FUNCTION__, vt->signal); + memset(t,0,sizeof(*t)); + strcpy(t->name, "Radio"); + t->type = V4L2_TUNER_RADIO; + + /* Let clients fill in the remainder of this struct */ + call_i2c_clients(usbvision,VIDIOC_G_TUNER,t); + PDEBUG(DBG_RIO, "VIDIOC_G_TUNER signal=%x, afc=%x",t->signal,t->afc); return 0; } case VIDIOC_S_TUNER: { struct v4l2_tuner *vt = arg; - // Only channel 0 has a tuner - if((vt->index) || (usbvision->channel)) { + // Only no or one tuner for now + if (!usbvision->have_tuner || vt->index) return -EINVAL; - } - PDEBUG(DBG_RIO, "%s: VIDIOC_S_TUNER", __FUNCTION__); + /* let clients handle this */ + call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt); + + PDEBUG(DBG_RIO, "VIDIOC_S_TUNER"); return 0; } case VIDIOC_G_AUDIO: { - struct v4l2_audio *va = arg; - memset(va,0, sizeof(va)); - va->capability = V4L2_AUDCAP_STEREO; - strcpy(va->name, "Radio"); - PDEBUG(DBG_IOCTL, "VIDIOC_G_AUDIO"); + struct v4l2_audio *a = arg; + + memset(a,0,sizeof(*a)); + strcpy(a->name,"Radio"); + PDEBUG(DBG_RIO, "VIDIOC_G_AUDIO"); return 0; } case VIDIOC_S_AUDIO: - { - struct v4l2_audio *v = arg; - if(v->index) { - return -EINVAL; - } - PDEBUG(DBG_IOCTL, "VIDIOC_S_AUDIO"); - // FIXME: void function ??? - return 0; - } - case VIDIOC_G_FREQUENCY: - { - struct v4l2_frequency *freq = arg; - freq->tuner = 0; // Only one tuner - freq->type = V4L2_TUNER_RADIO; - freq->frequency = usbvision->freq; - PDEBUG(DBG_RIO, "VIDIOC_G_FREQUENCY freq=0x%X", (unsigned)freq->frequency); - return 0; - } - case VIDIOC_S_FREQUENCY: - { - struct v4l2_frequency *freq = arg; - usbvision->freq = freq->frequency; - call_i2c_clients(usbvision, cmd, freq); - PDEBUG(DBG_RIO, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)freq->frequency); - return 0; - } + case VIDIOC_S_INPUT: + case VIDIOC_S_STD: + return 0; - /*************************** - * V4L1 IOCTLs * - ***************************/ - case VIDIOCGCAP: - { - struct video_capability *vc = arg; - - memset(vc, 0, sizeof(struct video_capability)); - strcpy(vc->name,usbvision->vcap.card); - vc->type = VID_TYPE_TUNER; - vc->channels = 1; - vc->audios = 1; - PDEBUG(DBG_RIO, "%s: VIDIOCGCAP", __FUNCTION__); - return 0; - } - case VIDIOCGTUNER: + case VIDIOC_G_FREQUENCY: { - struct video_tuner *vt = arg; + struct v4l2_frequency *f = arg; - if((vt->tuner) || (usbvision->channel)) { /* Only tuner 0 */ - return -EINVAL; - } - strcpy(vt->name, "Radio"); - // japan: 76.0 MHz - 89.9 MHz - // western europe: 87.5 MHz - 108.0 MHz - // russia: 65.0 MHz - 108.0 MHz - vt->rangelow=(int)(65*16); - vt->rangehigh=(int)(108*16); - vt->flags= 0; - vt->mode = 0; - call_i2c_clients(usbvision,cmd,vt); - PDEBUG(DBG_RIO, "%s: VIDIOCGTUNER signal=%d", __FUNCTION__, vt->signal); - return 0; - } - case VIDIOCSTUNER: - { - struct video_tuner *vt = arg; + memset(f,0,sizeof(*f)); - // Only channel 0 has a tuner - if((vt->tuner) || (usbvision->channel)) { - return -EINVAL; - } - PDEBUG(DBG_RIO, "%s: VIDIOCSTUNER", __FUNCTION__); - return 0; - } - case VIDIOCGAUDIO: - { - struct video_audio *va = arg; - memset(va,0, sizeof(struct video_audio)); - call_i2c_clients(usbvision, cmd, va); - va->flags|=VIDEO_AUDIO_MUTABLE; - va->volume=1; - va->step=1; - strcpy(va->name, "Radio"); - PDEBUG(DBG_RIO, "%s: VIDIOCGAUDIO", __FUNCTION__); - return 0; - } - case VIDIOCSAUDIO: - { - struct video_audio *va = arg; - if(va->audio) { - return -EINVAL; - } + f->type = V4L2_TUNER_RADIO; + f->frequency = usbvision->freq; + call_i2c_clients(usbvision, cmd, f); + PDEBUG(DBG_RIO, "VIDIOC_G_FREQUENCY freq=0x%X", (unsigned)f->frequency); - if(va->flags & VIDEO_AUDIO_MUTE) { - if (usbvision_audio_mute(usbvision)) { - return -EFAULT; - } - } - else { - if (usbvision_audio_on(usbvision)) { - return -EFAULT; - } - } - PDEBUG(DBG_RIO, "%s: VIDIOCSAUDIO flags=0x%x)", __FUNCTION__, va->flags); return 0; } - case VIDIOCGFREQ: + case VIDIOC_S_FREQUENCY: { - unsigned long *freq = arg; + struct v4l2_frequency *f = arg; - *freq = usbvision->freq; - PDEBUG(DBG_RIO, "%s: VIDIOCGFREQ freq = %ld00 kHz", __FUNCTION__, (*freq * 10)>>4); - return 0; - } - case VIDIOCSFREQ: - { - unsigned long *freq = arg; + if (f->tuner != 0) + return -EINVAL; + usbvision->freq = f->frequency; + call_i2c_clients(usbvision, cmd, f); + PDEBUG(DBG_RIO, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)f->frequency); - usbvision->freq = *freq; - call_i2c_clients(usbvision, cmd, freq); - PDEBUG(DBG_RIO, "%s: VIDIOCSFREQ freq = %ld00 kHz", __FUNCTION__, (*freq * 10)>>4); return 0; } default: @@ -5102,7 +5002,7 @@ static int usbvision_vbi_open(struct inode *inode, struct file *file) //usbvision->vbi = 1; call_i2c_clients(usbvision,AUDC_SET_RADIO,&usbvision->tuner_type); freq = 1517; //SWR3 @ 94.8MHz - call_i2c_clients(usbvision, VIDIOCSFREQ, &freq); + call_i2c_clients(usbvision, VIDIOC_S_FREQUENCY, &freq); usbvision_set_audio(usbvision, USBVISION_AUDIO_RADIO); usbvision->user++; } -- cgit v1.2.3 From cefccc8011c58b559498396f0ccefa0a0ffa3f53 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 4 Dec 2006 08:31:35 -0300 Subject: V4L/DVB (4934): Usbvision radio requires GainNormal at e register Adds an option to select GainNormal at tda9887 and make usbvision to use it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tda9887.c | 6 ++++++ drivers/media/video/usbvision/usbvision-core.c | 3 +++ 2 files changed, 9 insertions(+) (limited to 'drivers/media/video') diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index 87ffb0e84a7..fde576f1101 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -482,6 +482,12 @@ static int tda9887_set_config(struct tuner *t, char *buf) buf[1] &= ~cQSS; if (t->tda9887_config & TDA9887_GATING_18) buf[3] &= ~cGating_36; + + if (t->tda9887_config & TDA9887_GAIN_NORMAL) { + radio_stereo.e &= ~cTunerGainLow; + radio_mono.e &= ~cTunerGainLow; + } + return 0; } diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index 0365c7f9397..b5aa3185402 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -2585,12 +2585,15 @@ static int attach_inform(struct i2c_client *client) case 0x4b: { struct tuner_setup tun_setup; + unsigned int tda9887_conf = TDA9887_GAIN_NORMAL; tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; tun_setup.type = TUNER_TDA9887; tun_setup.addr = client->addr; call_i2c_clients(usbvision, TUNER_SET_TYPE_ADDR, &tun_setup); + call_i2c_clients(usbvision,TDA9887_SET_CONFIG, &tda9887_conf); + break; } case 0x42: -- cgit v1.2.3 From 483deb0f2b38060c1f2de216c09f05b1869b0d52 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 4 Dec 2006 08:31:38 -0300 Subject: V4L/DVB (4935): Added the capability of selecting fm gain by tuner Some tuners require using cGainNormal instead of cGainLow for high sensibility on FM reception. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-simple.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media/video') diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index fcf8693e4d5..1b9b0742f75 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -467,6 +467,8 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) config |= TDA9887_INTERCARRIER; /* if (params->port1_set_for_fm_mono) config &= ~TDA9887_PORT1_ACTIVE;*/ + if (params->fm_gain_normal) + config |= TDA9887_GAIN_NORMAL; i2c_clients_command(c->adapter, TDA9887_SET_CONFIG, &config); } if (4 != (rc = i2c_master_send(c,buffer,4))) -- cgit v1.2.3 From d8159a3684007e0ded915cb7465c9534a2650c53 Mon Sep 17 00:00:00 2001 From: Thierry MERLE Date: Mon, 4 Dec 2006 08:31:42 -0300 Subject: V4L/DVB (4936): Make MT4049FM5 tuner to set FM Gain to Normal - remove any specific TDA9887_SET_CONFIG of usbvision driver - add fm_gain_normal=1 to the MT4049FM5 tuner for radio functionality Signed-off-by: Thierry MERLE Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-types.c | 1 + drivers/media/video/usbvision/usbvision-core.c | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c index 1256c64af4d..74c3e6f96f1 100644 --- a/drivers/media/video/tuner-types.c +++ b/drivers/media/video/tuner-types.c @@ -651,6 +651,7 @@ static struct tuner_params tuner_microtune_4049_fm5_params[] = { .has_tda9887 = 1, .port1_invert_for_secam_lc = 1, .default_pll_gating_18 = 1, + .fm_gain_normal=1, }, }; diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index b5aa3185402..0eb3ddcd0f3 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -2585,14 +2585,12 @@ static int attach_inform(struct i2c_client *client) case 0x4b: { struct tuner_setup tun_setup; - unsigned int tda9887_conf = TDA9887_GAIN_NORMAL; tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; tun_setup.type = TUNER_TDA9887; tun_setup.addr = client->addr; call_i2c_clients(usbvision, TUNER_SET_TYPE_ADDR, &tun_setup); - call_i2c_clients(usbvision,TDA9887_SET_CONFIG, &tda9887_conf); break; } -- cgit v1.2.3 From 483dfdb64fd4a9f240c84e0e225a90c044d65402 Mon Sep 17 00:00:00 2001 From: Thierry MERLE Date: Mon, 4 Dec 2006 08:31:45 -0300 Subject: V4L/DVB (4937): Usbvision cleanup and code reorganization - removal of overlay stuff - reorganization of functions in 3 files: * usbvision-i2c for I2C-related stuff * usbvision-video for v4l2 entry points * usbvision-core for all peripheral controls and utilities Signed-off-by: Thierry MERLE Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/usbvision/Makefile | 2 +- drivers/media/video/usbvision/usbvision-cards.c | 1 - drivers/media/video/usbvision/usbvision-core.c | 3870 ++--------------------- drivers/media/video/usbvision/usbvision-i2c.c | 382 ++- drivers/media/video/usbvision/usbvision-i2c.h | 58 - drivers/media/video/usbvision/usbvision-video.c | 2060 ++++++++++++ drivers/media/video/usbvision/usbvision.h | 135 +- 7 files changed, 2808 insertions(+), 3700 deletions(-) delete mode 100644 drivers/media/video/usbvision/usbvision-i2c.h create mode 100644 drivers/media/video/usbvision/usbvision-video.c (limited to 'drivers/media/video') diff --git a/drivers/media/video/usbvision/Makefile b/drivers/media/video/usbvision/Makefile index ebdf78a1928..9ac92a80c64 100644 --- a/drivers/media/video/usbvision/Makefile +++ b/drivers/media/video/usbvision/Makefile @@ -1,4 +1,4 @@ -usbvision-objs := usbvision-core.o usbvision-i2c.o usbvision-cards.o +usbvision-objs := usbvision-core.o usbvision-video.o usbvision-i2c.o usbvision-cards.o obj-$(CONFIG_VIDEO_USBVISION) += usbvision.o diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c index 16c8890bf9b..f1fb9e752b5 100644 --- a/drivers/media/video/usbvision/usbvision-cards.c +++ b/drivers/media/video/usbvision/usbvision-cards.c @@ -30,7 +30,6 @@ #include "usbvision.h" /* Supported Devices: A table for usbvision.c*/ - struct usbvision_device_data_st usbvision_device_data[] = { {0xFFF0, 0xFFF0, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Custom Dummy USBVision Device"}, {0x0A6F, 0x0400, -1, CODEC_SAA7113, 4, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, -1, -1, -1, "Xanboo"}, diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index 0eb3ddcd0f3..cf787d8ab6d 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -1,11 +1,12 @@ /* - * USB USBVISION Video device driver 0.9.8.3cvs (For Kernel 2.4.19-2.4.32 + 2.6.0-2.6.16) - * - * + * usbvision-core.c - driver for NT100x USB video capture devices + * * * Copyright (c) 1999-2005 Joerg Heckenbach + * Dwaine Garden * * This module is part of usbvision driver project. + * Updates to driver completed by Dwaine P. Garden * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,309 +21,6 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Let's call the version 0.... until compression decoding is completely - * implemented. - * - * This driver is written by Jose Ignacio Gijon and Joerg Heckenbach. - * It was based on USB CPiA driver written by Peter Pregler, - * Scott J. Bertin and Johannes Erdfelt - * Ideas are taken from bttv driver by Ralph Metzler, Marcus Metzler & - * Gerd Knorr and zoran 36120/36125 driver by Pauline Middelink - * Updates to driver completed by Dwaine P. Garden - * - * History: - * - * Mar. 2000 - 15.12.2000: (0.0.0 - 0.2.0) - * Several alpha drivers and the first beta. - * - * Since Dec. 2000: (0.2.1) or (v2.1) - * Code changes or updates by Dwaine Garden and every other person. - * - * Added: New Hauppauge TV device Vendor ID: 0x0573 - * Product ID: 0x4D01 - * (Thanks to Giovanni Garberoglio) - * - * Added: UK Hauppauge WinTV-USB Vendor ID: 0x0573 - * Product ID: 0x4D02 - * (Thanks to Derek Freeman-Jones) - * - * Feb, 2001 - Apr 08, 2001: (0.3.0) - * - Some fixes. Driver is now more stable. - * - Scratch is organized as ring-buffer now for better performance - * - DGA (overlay) is now supported. - * !!!!Danger!!!! Clipping is not yet implemented. Your system will - * crash if your video window leaves the screen!!! - * - Max. Framesize is set to 320x240. There isn't more memory on the - * nt1003 video device for the FIFO. - * - Supported video palettes: RGB565, RGB555, RGB24, RGB32 - * - * - * Apr 15, 2001: (0.3.1-test...) - * - Clipping is implemented - * - NTSC is now coloured (Thanks to Dwaine Garden) - * - Added SECAM colour detection in saa7111-new - * - Added: French Hauppauge WinTV USB Vendor ID: 0x0573 - * Product ID: 0x4D03 - * (Thanks to Julius Hrivnac) - * - Added: US Hauppauge WINTV USB Vendor ID: 0x0573 - * Product ID: 0x4D00 - * (Thanks to Derrick J Brashear) - * - Changes for adding new devices. There's now a table in usbvision.h. - * Adding your devices data to the usbvision_device_data table is all - * you need to add a new device. - * - * May 11, 2001: (0.3.2-test...) (Thanks to Derek Freeman-Jones) - * - Support YUV422 raw format for people with hardware scaling. - * - Only power on the device when opened (use option PowerOnAtOpen=0 to disable it). - * - Turn off audio so we can listen to Line In. - * - * July 5, 2001 - (Patch the driver to run with Kernel 2.4.6) - * - Fixed a problem with the number of parameters passed to video_register_device. - * - * July 6, 2001 - Added: HAUPPAUGE WINTV-USB FM USA Vendor ID: 0x0573 - * Product ID: 0x4D10 - * (Thanks to Braddock Gaskill) - * Added: USBGear USBG-V1 resp. HAMA USB - * Vendor ID: 0x0573 - * Product ID: 0x0003 - * (Thanks to Bradley A. Singletary and Juergen Weigert) - * - * Jan 24, 2002 - (0.3.3-test...) - * - Moved all global variables that are device specific the usb_usbvision struct - * - Fixed the 64x48 unchangable image in xawtv when starting it with overlay - * - Add VideoNorm and TunerType to the usb_device_data table - * - Checked the audio channels and mute for HAUPPAUGE WinTV USB FM - * - Implemented the power on when opening the device. But some software opens - * the device several times when starting. So the i2c parts are just registered - * by an open, when they become deregistered by the next close. You can speed - * up tuner detection, when adding "options tuner addr=your_addr" to /etc/modules.conf - * - Begin to resize the frame in width and height. So it will be possible to watch i.e. - * 384x288 pixels at 23 fps. - * - * Feb 10, 2002 - * - Added radio device - * - * - * Jul 30, 2002 - (Thanks Cameron Maxwell) - * - Changes to usbvision.h --fixed usbvision device data structure, incorrectly had (0x0573, 0x4d21) for WinTV-USB II, should be 0x4d20. - * - Changes for device WinTV-USB II (0x0573. 0x4D21). It does not have a FM tuner. - * - Added the real device HAUPPAUGE WINTV-USB II (PAL) to the device structure in usbvision.h. - * - Changes to saa7113-new, the video is 8 bit data for the Phillips SAA7113 not 16bit like SAA7111. - * - Tuned lots of setup registers for the Phillips SAA7113 video chipset. - * - Changes to the supplied makefile. (Dwaine Garden) Still needs to be fixed so it will compile modules on different distrubutions. - * - * - * Aug 10, 2002 - (Thanks Mike Klinke) - * - Changes to usbvision.txt -- Fixed instructions on the location to copy the contents of the tgz file. - * - Added device WinTV-USB FM Model 621 (0x0573. 0x4D30). There is another device which carries the same name. Kept that device in the device structure. - * - * Aug 12, 2002 - Dwaine Garden - * - Added the ability to read the NT100x chip for the MaxISOPacketLength and USB Bandwidth - * Setting of the video device. - * - Adjustments to the SAA7113H code for proper video output. - * - Changes to usbvision.h, so all the devices with FM tuners are working. - * - * Feb 10, 2003 - Joerg Heckenbach - * - fixed endian bug for Motorola PPC - * - * Feb 13, 2003 - Joerg Heckenbach - * - fixed Vin_Reg setting and presetting from usbvision_device_data() - * - * Apr 19, 2003 - Dwaine Garden - * - Fixed compiling errors under RedHat v9.0. from uvirt_to_kva and usbvision_mmap. (Thanks Cameron Maxwell) - * - Changed pte_offset to pte_offset_kernel. - * - Changed remap_page_range and added additional parameter to function. - * - Change setup parameters for the D-Link V100 USB device - * - Added a new device to the usbvision driver. Pinnacle Studio PCTV USB (PAL) 0x2304 0x0110 - * - Screwed up the sourceforge.net cvs respository! 8*) - * - * Apr 22, 2002 - Dwaine Garden - * - Added a new device to the usbvision driver. Dazzle DVC-80 (PAL) 0x07d0 0x0004. (Thanks Carl Anderson) - * - Changes to some of the comments. - * - * June 06, 2002 - Ivan, Dwaine Garden - * - Ivan updates for fine tuning device parameters without driver recompiling. (Ivan) - * - Changes to some of the comments. (Dwaine Garden) - * - Changes to the makefile - Better CPU settings. (Ivan) - * - Changes to device Hauppauge WinTv-USB III (PAL) FM Model 568 - Fine tuning parameters (Ivan) - * - * - * Oct 16, 2003 - 0.9.0 - Joerg Heckenbach - * - Implementation of the first part of the decompression algorithm for intra frames. - * The resolution has to be 320x240. A dynamic adaption of compression deepth is - * missing yet. - * - * Oct 22, 2003 - 0.9.1 - Joerg Heckenbach - * - Implementation of the decompression algorithm for inter frames. - * The resolution still has to be 320x240. - * - * Nov 2003 - Feb 2004 - 0.9.2 to 0.9.3 - Joerg Heckenbach - * - Implement last unknown compressed block type. But color is still noisy. - * - Finding criteria for adaptive compression adjustment. - * - Porting to 2.6 kernels, but still working under 2.4 - * - * Feb 04, 2004 - 0.9.4 Joerg Heckenbach - * - Found bug in color decompression. Color is OK now. - * - * Feb 09, 2004 - 0.9.5 Joerg Heckenbach - * - Add auto-recognition of chip type NT1003 or NT1004. - * - Add adaptive compression adjustment. - * - Patched saa7113 multiplexer switching (Thanks to Orlando F.S. Bordoni) - * - * Feb 24, 2004 - 0.9.6 Joerg Heckenbach - * - Add a timer to wait before poweroff at close, to save start time in - * some video applications - * - * Mar 4, 2004 - 0.9.6 Dwaine Garden - * - Added device Global Village GV-007 (NTSC) to usbvision.h (Thanks to Abe Skolnik) - * - Forgot to add this device to the driver. 8*) - * - * June 2, 2004 - 0.9.6 Dwaine Garden - * - Fixed sourceforge.net cvs repository. - * - Added #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,26) for .owner to help compiling under kernels 2.4.x which do not have the i2c v2.8.x updates. - * - Added device Hauppauge WinTv-USB III (PAL) FM Model 597 to usbvision.h - * - * July 1, 2004 -0.9.6 Dwaine Garden - * - Patch was submitted by Hal Finkel to fix the problem with the tuner not working under kernel 2.6.7. - * - Thanks Hal..... - * - * July 30, 2004 - 0.9.6 Dwaine Garden - * - Patch was submitted by Tobias Diaz to fix Model ID mismatch in usbvision.h. - * - Thanks..... - * - * August 12, 2004 - 0.9.6 Dwaine Garden - * - Updated the readme file so people could install the driver under the configuration file for kernel 2.6.x recompiles. Now people can use make xconfig! - * - Added new device "Camtel Technology Corp TVB330-USB FM". - * - Sourceforge.net CVS has been updated with all the changes. - * - * August 20, 2004 - 0.9.7 Dwaine Garden - * - Added Device "Hauppauge USB Live Model 600" - * - Fixed up all the devices which did not have a default tuner type in usbvision.h. It's best guess, at least until someone with the device tells me otherwise. - * - Sourceforge.net CVS has been updated with all the changes. - * - Clean up the driver. - * - * September 13, 2004 - 0.9.8 Dwaine Garden - * - Changed usbvision_muxsel to address the problem with black & white s-video output for NT1004 devices with saa7114 video decoder. Thanks to Emmanuel for the patch and testing. - * - Fixed up SECAM devices which could not properly output video. Changes to usbmuxsel. Thanks to Emmanuel for the patch and everyone with a SECAM device which help test. - * - Removed some commented out code. Clean up. - * - Tried to fix up the annoying empty directories in the sourceforge.net cvs. Fuck it up again. 8*( - * - * November 15, 2004 - 0.9.8 Dwaine Garden - * - Release new tar - 0.9.8 on sourceforge.net - * - Added some new devices to usbvision.h WinTV USB Model 602 40201 Rev B282, Hauppague WinTV USB Model 602 40201 Rev B285 - * - Added better compatibility for 2.6.x kernels. - * - Hardware full screen scaling in grabdisplay mode. - * - Better support for sysfs. More code to follow for both video device and radio device. Device information is located at /sys/class/video4linux/video0 - * - Added module_param so loaded module parameters are displayed in sysfs. Driver parameters should show up in /sys/module/usbvision - * - Adjusted the SAA7111 registers to match the 2.6.x kernel SAA7111 code. Thanks to the person which helped test. - * - Changed to wait_event_interruptible. For all the people running Fedora 2. - * - Added some screenshots of actual video captures on sourceforge.net. - * - * November 24, 2004 - 0.9.8.1cvs Dwaine Garden - * - Added patch to check for palette and format in VIDIOCSPICT. Helix Producer should work fine with the driver now. Thanks Jason Simpson - * - Two device description changes and two additions for the maintainer of usb.ids. - * - * December 2, 2004 - 0.9.8.1cvs Dwaine Garden - * - Added patch for YUV420P and YUV422P video output. Thanks to Alex Smith. - * - Better support for mythtv. - * - * January 2, 2005 - 0.9.8.1cvs Dwaine Garden - * - Setup that you can specify which device is used for video. Default is auto detect next available device number eg. /dev/videoX - * - Setup that you can specify which device is used for radio. Default is auto detect next available device number eg. /dev/radioX - * - usb_unlink_urb() is deprecated for synchronous unlinks. Using usb_kill_urb instead. - * - usbvision_kvirt_to_pa is deprecated. Removed. - * - Changes are related to kernel changes for 2.6.10. (Fedora 4) - * - * February 2, 2005 - 0.9.8.1cvs Dwaine Garden - * - Added a new device to usbvision.h Dazzle DVC 50. Thanks to Luiz S. - * - * March 29, 2005 - 0.9.8.1cvs Dwaine Garden - * - Fixed compile error with saa7113 under kernels 2.6.11+ - * - Added module parameter to help people with Black and White output with using s-video input. Some cables and input device are wired differently. - * - Removed the .id from the i2c usbvision template. There was a change to the i2c with kernels 2.6.11+. - * - * April 9, 2005 - 0.9.8.1cvs Dwaine Garden - * - Added in the 2.4 and 2.6 readme files the SwitchSVideoInput parameter information. This will help people setup the right values for the parameter. - * If your device experiences Black and White images with the S-Video Input. Set this parameter to 1 when loading the module. - * - Replaced the wrong 2.6 readme file. I lost the right version. Someone sent me the right version by e-mail. Thanks. - * - Released new module version on sourceforge.net. So everyone can enjoy all the fixes and additional device support. - * - * April 20, 2005 - 0.9.8.2cvs Dwaine Garden - * - Release lock in usbvision_v4l_read_done. -Thanks to nplanel for the patch. - * - Additional comments to the driver. - * - Fixed some spelling mistakes. 8*) - * - * April 23, 2005 - 0.9.8.2cvs Joerg Heckenbach - * - Found bug in usbvision line counting. Now there should be no spurious lines in the image any longer. - * - Swapped usbvision_register_video and usbvision_configure_video to fix problem with PowerOnAtOpen=0. - * Thanks to Erwan Velu - * - * April 26, 2005 - 0.9.8.2cvs Joerg Heckenbach - * - Fixed problem with rmmod module and oppses. Replaced vfree(usbvision->overlay_base) with iounmap(usbvision->overlay_base). - * - Added function usb_get_dev(dev) and ; To help with unloading the module multiple times without crashing. - * (Keep the reference count in kobjects correct) - * - * June 14, 2005 - 0.9.8.2cvs Dwaine - * - Missed a change in saa7113.c for checking kernel version. Added conditional if's. - * - * June 15, 2005 - 0.9.8.2cvs Dwaine - * - Added new device WinTV device VendorId 0573 and ProductId 4d29. - * - Hacked some support for newer NT1005 devices. This devices only seem to have one configuration, not multiple configurations like the NT1004. - * - * June 29, 2005 - 0.9.8.2cvs Dwaine - * - Added new device WinTV device VendorId 0573 and ProductId 4d37. - * - Because of the first empty entry in usbvision_table, modutils failed to create the necessary entries for modules.usbmap. - * This means hotplug won't work for usbvision. Thanks to Gary Ng. - * - Sent an e-mail to the maintainer of usb.ids. New devices identified need to be added. - * - Fixed compile error with saa7113 under kernel 2.6.12. - * - * July 6, 2005 - 0.9.8.2cvs Dwaine - * - Patch submitted by Gary Ng for two additional procfs entries. Device Input and Frequency setting. - * - * July 12, 2005 - 0.9.8.2cvs Dwaine - * - New tuner identified for some devices it's called TCL_MFPE05. This tuner uses the same API as tuner 38 in tuner.c. - * - Thanks to lynx31 for contacting Hauppage and asking them. - * - I have no clue as to which devices use this new tuner, so people will have to contact me and tell me. - * - * July 21, 2005 - 0.9.8.2cvs Dwaine - * - Patched usbvision.c with missing ifdef kernversion statement so the module will compile with older kernels and v4l. - * - Thanks to cipe007...... - * - * May 19, 2006 - 0.9.8.3cvs Dwaine - * - Patched usbvision.c and i2c-algo.c so they will compile with kernel 2.6.16 - * - Adjust device "Pinnacle Studio PCTV USB (PAL) FM" values in usbvision.h - * - * May 24, 2006 - 0.9.8.3cvs Dwaine - * -Pinnacle Studio PCTV USB (NTSC) FM uses saa7111, not saa7113 like first thought. - * -Updated usbvision.h - * - * Aug 15, 2006 - 0.9.8.3cvs Dwaine - * -Added saa711x module into cvs, since the newer saa7115 module in newer kernels is v4l2. The usbvision driver is only v4l. - * -Updated makefile to put compiled modules into correct location. - * - * Aug 21, 2006 - 0.9.8.3cvs Dwaine - * -Changed number of bytes for i2c write to 4 as per the NT100X spec sheet. Thanks to Merlum for finding it. - * -Remove the radio option for device Hauppauge WinTV USB device Model 40219 Rev E189. This device does not have a FM radio. Thanks to Shadwell. - * -Added radio option for device Hauppauge WinTV USB device Model 40219 Rev E189 again. Just got an e-mail indicating their device has one. 8*) - * - * Aug 27, 2006 - 0.9.8.3cvs Dwaine - * -Changed ifdef statement so the usbvision driver will compile with kernels at 2.6.12. - * -Updated readme files for new updated tuner list for v4l devices. - * - * - * - * TODO: - * - use submit_urb for all setup packets - * - Fix memory settings for nt1004. It is 4 times as big as the - * nt1003 memory. - * - Add audio on endpoint 3 for nt1004 chip. Seems impossible, needs a codec interface. Which one? - * - Clean up the driver. - * - optimization for performance. - * - Add Videotext capability (VBI). Working on it..... - * - Check audio for other devices - * - Add v4l2 interface - * */ #include @@ -344,13 +42,6 @@ #include #include -#define USBVISION_DRIVER_VERSION_MAJOR 0 -#define USBVISION_DRIVER_VERSION_MINOR 8 -#define USBVISION_DRIVER_VERSION_PATCHLEVEL 0 - -#define USBVISION_VERSION __stringify(USBVISION_DRIVER_VERSION_MAJOR) "." __stringify(USBVISION_DRIVER_VERSION_MINOR) "." __stringify(USBVISION_DRIVER_VERSION_PATCHLEVEL) " " USBVISION_DRIVER_VERSION_COMMENT -#define USBVISION_DRIVER_VERSION KERNEL_VERSION(USBVISION_DRIVER_VERSION_MAJOR,USBVISION_DRIVER_VERSION_MINOR,USBVISION_DRIVER_VERSION_PATCHLEVEL) - #include #include #include @@ -365,99 +56,44 @@ #include "usbvision.h" -#define DRIVER_VERSION "0.9.8.3cvs for Linux kernels 2.4.19-2.4.32 + 2.6.0-2.6.17, compiled at "__DATE__", "__TIME__ -#define EMAIL "joerg@heckenbach-aw.de" -#define DRIVER_AUTHOR "Joerg Heckenbach , Dwaine Garden " -#define DRIVER_DESC "USBVision USB Video Device Driver for Linux" -#define DRIVER_LICENSE "GPL" -#define DRIVER_ALIAS "USBVision" +static unsigned int core_debug = 0; +module_param(core_debug,int,0644); +MODULE_PARM_DESC(core_debug,"enable debug messages [core]"); -#define ENABLE_HEXDUMP 0 /* Enable if you need it */ +static unsigned int force_testpattern = 0; +module_param(force_testpattern,int,0644); +MODULE_PARM_DESC(force_testpattern,"enable test pattern display [core]"); + +static int adjustCompression = 1; // Set the compression to be adaptive +module_param(adjustCompression, int, 0444); +MODULE_PARM_DESC(adjustCompression, " Set the ADPCM compression for the device. Default: 1 (On)"); + +static int SwitchSVideoInput = 0; // To help people with Black and White output with using s-video input. Some cables and input device are wired differently. +module_param(SwitchSVideoInput, int, 0444); +MODULE_PARM_DESC(SwitchSVideoInput, " Set the S-Video input. Some cables and input device are wired differently. Default: 0 (Off)"); +#define ENABLE_HEXDUMP 0 /* Enable if you need it */ -#define USBVISION_DEBUG /* Turn on debug messages */ #ifdef USBVISION_DEBUG #define PDEBUG(level, fmt, args...) \ - if (debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args) + if (core_debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args) #else #define PDEBUG(level, fmt, args...) do {} while(0) #endif -#define DBG_IOCTL 1<<3 -#define DBG_IO 1<<4 -#define DBG_RIO 1<<5 -#define DBG_HEADER 1<<7 -#define DBG_PROBE 1<<8 -#define DBG_IRQ 1<<9 -#define DBG_ISOC 1<<10 -#define DBG_PARSE 1<<11 -#define DBG_SCRATCH 1<<12 -#define DBG_FUNC 1<<13 -#define DBG_I2C 1<<14 - -#define DEBUG(x...) /* General Debug */ -#define IODEBUG(x...) /* Debug IO */ -#define OVDEBUG(x...) /* Debug overlay */ -#define MDEBUG(x...) /* Debug memory management */ - -//String operations -#define rmspace(str) while(*str==' ') str++; -#define goto2next(str) while(*str!=' ') str++; while(*str==' ') str++; - - -static int usbvision_nr = 0; // sequential number of usbvision device -static unsigned long usbvision_timestamp = 0; // timestamp in jiffies of a hundred frame -static unsigned long usbvision_counter = 0; // frame counter +#define DBG_HEADER 1<<0 +#define DBG_IRQ 1<<1 +#define DBG_ISOC 1<<2 +#define DBG_PARSE 1<<3 +#define DBG_SCRATCH 1<<4 static const int max_imgwidth = MAX_FRAME_WIDTH; static const int max_imgheight = MAX_FRAME_HEIGHT; static const int min_imgwidth = MIN_FRAME_WIDTH; static const int min_imgheight = MIN_FRAME_HEIGHT; -#define FRAMERATE_MIN 0 -#define FRAMERATE_MAX 31 - - -enum { - ISOC_MODE_YUV422 = 0x03, - ISOC_MODE_YUV420 = 0x14, - ISOC_MODE_COMPRESS = 0x60, -}; - -static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = { - { 1, 1, 8, V4L2_PIX_FMT_GREY , "GREY" }, - { 1, 2, 16, V4L2_PIX_FMT_RGB565 , "RGB565" }, - { 1, 3, 24, V4L2_PIX_FMT_RGB24 , "RGB24" }, - { 1, 4, 32, V4L2_PIX_FMT_RGB32 , "RGB32" }, - { 1, 2, 16, V4L2_PIX_FMT_RGB555 , "RGB555" }, - { 1, 2, 16, V4L2_PIX_FMT_YUYV , "YUV422" }, - { 1, 2, 12, V4L2_PIX_FMT_YVU420 , "YUV420P" }, // 1.5 ! - { 1, 2, 16, V4L2_PIX_FMT_YUV422P , "YUV422P" } -}; - -/* supported tv norms */ -static struct usbvision_tvnorm tvnorms[] = { - { - .name = "PAL", - .id = V4L2_STD_PAL, - }, { - .name = "NTSC", - .id = V4L2_STD_NTSC, - }, { - .name = "SECAM", - .id = V4L2_STD_SECAM, - }, { - .name = "PAL-M", - .id = V4L2_STD_PAL_M, - } -}; - -#define TVNORMS ARRAY_SIZE(tvnorms) - - -/* - * The value of 'scratch_buf_size' affects quality of the picture +/* The value of 'scratch_buf_size' affects quality of the picture * in many ways. Shorter buffers may cause loss of data when client * is too slow. Larger buffers are memory-consuming and take longer * to work with. This setting can be adjusted, but the default value @@ -467,229 +103,10 @@ static struct usbvision_tvnorm tvnorms[] = { static const int scratch_buf_size = DEFAULT_SCRATCH_BUF_SIZE; // Function prototypes -static int usbvision_restart_isoc(struct usb_usbvision *usbvision); -static int usbvision_begin_streaming(struct usb_usbvision *usbvision); -static int usbvision_muxsel(struct usb_usbvision *usbvision, int channel); -static int usbvision_i2c_write(void *data, unsigned char addr, char *buf, short len); -static int usbvision_i2c_read(void *data, unsigned char addr, char *buf, short len); -static int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg); -static int usbvision_write_reg(struct usb_usbvision *usbvision, unsigned char reg, unsigned char value); static int usbvision_request_intra (struct usb_usbvision *usbvision); static int usbvision_unrequest_intra (struct usb_usbvision *usbvision); static int usbvision_adjust_compression (struct usb_usbvision *usbvision); static int usbvision_measure_bandwidth (struct usb_usbvision *usbvision); -static void usbvision_release(struct usb_usbvision *usbvision); -static int usbvision_set_input(struct usb_usbvision *usbvision); -static int usbvision_set_output(struct usb_usbvision *usbvision, int width, int height); -static void usbvision_empty_framequeues(struct usb_usbvision *dev); -static int usbvision_stream_interrupt(struct usb_usbvision *dev); -static void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd, void *arg); - - -// Bit flags (options) -#define FLAGS_RETRY_VIDIOCSYNC (1 << 0) -#define FLAGS_MONOCHROME (1 << 1) -#define FLAGS_DISPLAY_HINTS (1 << 2) -#define FLAGS_OSD_STATS (1 << 3) -#define FLAGS_FORCE_TESTPATTERN (1 << 4) -#define FLAGS_SEPARATE_FRAMES (1 << 5) -#define FLAGS_CLEAN_FRAMES (1 << 6) - -// Default initalization of device driver parameters -static int flags = 0; // Set the default Overlay Display mode of the device driver -static int debug = 0; // Set the default Debug Mode of the device driver -static int isocMode = ISOC_MODE_COMPRESS; // Set the default format for ISOC endpoint -static int adjustCompression = 1; // Set the compression to be adaptive -static int dga = 1; // Set the default Direct Graphic Access -static int PowerOnAtOpen = 1; // Set the default device to power on at startup -static int SwitchSVideoInput = 0; // To help people with Black and White output with using s-video input. Some cables and input device are wired differently. -static int video_nr = -1; // Sequential Number of Video Device -static int radio_nr = -1; // Sequential Number of Radio Device -static int vbi_nr = -1; // Sequential Number of VBI Device -static char *CustomDevice=NULL; // Set as nothing.... - -// Grab parameters for the device driver - -#if defined(module_param) // Showing parameters under SYSFS -module_param(flags, int, 0444); -module_param(debug, int, 0444); -module_param(isocMode, int, 0444); -module_param(adjustCompression, int, 0444); -module_param(dga, int, 0444); -module_param(PowerOnAtOpen, int, 0444); -module_param(SwitchSVideoInput, int, 0444); -module_param(video_nr, int, 0444); -module_param(radio_nr, int, 0444); -module_param(vbi_nr, int, 0444); -module_param(CustomDevice, charp, 0444); -#else // Old Style -MODULE_PARM(flags, "i"); // Grab the Overlay Display mode of the device driver -MODULE_PARM(debug, "i"); // Grab the Debug Mode of the device driver -MODULE_PARM(isocMode, "i"); // Grab the video format of the video device -MODULE_PARM(adjustCompression, "i"); // Grab the compression to be adaptive -MODULE_PARM(dga, "i"); // Grab the Direct Graphic Access -MODULE_PARM(PowerOnAtOpen, "i"); // Grab the device to power on at startup -MODULE_PARM(SwitchSVideoInput, "i"); // To help people with Black and White output with using s-video input. Some cables and input device are wired differently. -MODULE_PARM(video_nr, "i"); // video_nr option allows to specify a certain /dev/videoX device (like /dev/video0 or /dev/video1 ...) -MODULE_PARM(radio_nr, "i"); // radio_nr option allows to specify a certain /dev/radioX device (like /dev/radio0 or /dev/radio1 ...) -MODULE_PARM(vbi_nr, "i"); // vbi_nr option allows to specify a certain /dev/vbiX device (like /dev/vbi0 or /dev/vbi1 ...) -MODULE_PARM(CustomDevice, "s"); // .... CustomDevice -#endif - -MODULE_PARM_DESC(flags, " Set the default Overlay Display mode of the device driver. Default: 0 (Off)"); -MODULE_PARM_DESC(debug, " Set the default Debug Mode of the device driver. Default: 0 (Off)"); -MODULE_PARM_DESC(isocMode, " Set the default format for ISOC endpoint. Default: 0x60 (Compression On)"); -MODULE_PARM_DESC(adjustCompression, " Set the ADPCM compression for the device. Default: 1 (On)"); -MODULE_PARM_DESC(dga, " Set the Direct Graphic Access for the device. Default: 1 (On)"); -MODULE_PARM_DESC(PowerOnAtOpen, " Set the default device to power on when device is opened. Default: 1 (On)"); -MODULE_PARM_DESC(SwitchSVideoInput, " Set the S-Video input. Some cables and input device are wired differently. Default: 0 (Off)"); -MODULE_PARM_DESC(video_nr, "Set video device number (/dev/videoX). Default: -1 (autodetect)"); -MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)"); -MODULE_PARM_DESC(vbi_nr, "Set vbi device number (/dev/vbiX). Default: -1 (autodetect)"); -MODULE_PARM_DESC(CustomDevice, " Define the fine tuning parameters for the device. Default: null"); - - -// Misc stuff -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE(DRIVER_LICENSE); - MODULE_VERSION(DRIVER_VERSION); - MODULE_ALIAS(DRIVER_ALIAS); - -#ifdef MODULE -static unsigned int autoload = 1; -#else -static unsigned int autoload = 0; -#endif - - -/****************************************************************************************/ -/* SYSFS Code - Copied from the stv680.c usb module. */ -/* Device information is located at /sys/class/video4linux/video0 */ -/* Device parameters information is located at /sys/module/usbvision */ -/* Device USB Information is located at /sys/bus/usb/drivers/USBVision Video Grabber */ -/****************************************************************************************/ - - -#define YES_NO(x) ((x) ? "Yes" : "No") - -static inline struct usb_usbvision *cd_to_usbvision(struct class_device *cd) -{ - struct video_device *vdev = to_video_device(cd); - return video_get_drvdata(vdev); -} - -static ssize_t show_version(struct class_device *cd, char *buf) -{ - return sprintf(buf, "%s\n", DRIVER_VERSION); -} -static CLASS_DEVICE_ATTR(version, S_IRUGO, show_version, NULL); - -static ssize_t show_model(struct class_device *class_dev, char *buf) -{ - struct video_device *vdev = to_video_device(class_dev); - struct usb_usbvision *usbvision = video_get_drvdata(vdev); - return sprintf(buf, "%s\n", usbvision_device_data[usbvision->DevModel].ModelString); -} -static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL); - -static ssize_t show_hue(struct class_device *class_dev, char *buf) -{ - struct video_device *vdev = to_video_device(class_dev); - struct usb_usbvision *usbvision = video_get_drvdata(vdev); - return sprintf(buf, "%d\n", usbvision->hue >> 8); -} -static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); - -static ssize_t show_contrast(struct class_device *class_dev, char *buf) -{ - struct video_device *vdev = to_video_device(class_dev); - struct usb_usbvision *usbvision = video_get_drvdata(vdev); - return sprintf(buf, "%d\n", usbvision->contrast >> 8); -} -static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); - -static ssize_t show_brightness(struct class_device *class_dev, char *buf) -{ - struct video_device *vdev = to_video_device(class_dev); - struct usb_usbvision *usbvision = video_get_drvdata(vdev); - return sprintf(buf, "%d\n", usbvision->brightness >> 8); -} -static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); - -static ssize_t show_saturation(struct class_device *class_dev, char *buf) -{ - struct video_device *vdev = to_video_device(class_dev); - struct usb_usbvision *usbvision = video_get_drvdata(vdev); - return sprintf(buf, "%d\n", usbvision->saturation >> 8); -} -static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); - -static ssize_t show_streaming(struct class_device *class_dev, char *buf) -{ - struct video_device *vdev = to_video_device(class_dev); - struct usb_usbvision *usbvision = video_get_drvdata(vdev); - return sprintf(buf, "%s\n", YES_NO(usbvision->streaming==Stream_On?1:0)); -} -static CLASS_DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL); - -static ssize_t show_overlay(struct class_device *class_dev, char *buf) -{ - struct video_device *vdev = to_video_device(class_dev); - struct usb_usbvision *usbvision = video_get_drvdata(vdev); - return sprintf(buf, "%s\n", YES_NO(usbvision->overlay)); -} -static CLASS_DEVICE_ATTR(overlay, S_IRUGO, show_overlay, NULL); - -static ssize_t show_compression(struct class_device *class_dev, char *buf) -{ - struct video_device *vdev = to_video_device(class_dev); - struct usb_usbvision *usbvision = video_get_drvdata(vdev); - return sprintf(buf, "%s\n", YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS)); -} -static CLASS_DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL); - -static ssize_t show_device_bridge(struct class_device *class_dev, char *buf) -{ - struct video_device *vdev = to_video_device(class_dev); - struct usb_usbvision *usbvision = video_get_drvdata(vdev); - return sprintf(buf, "%d\n", usbvision->bridgeType); -} -static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL); - -static void usbvision_create_sysfs(struct video_device *vdev) -{ - int res; - if (vdev) { - res=video_device_create_file(vdev, &class_device_attr_version); - res=video_device_create_file(vdev, &class_device_attr_model); - res=video_device_create_file(vdev, &class_device_attr_hue); - res=video_device_create_file(vdev, &class_device_attr_contrast); - res=video_device_create_file(vdev, &class_device_attr_brightness); - res=video_device_create_file(vdev, &class_device_attr_saturation); - res=video_device_create_file(vdev, &class_device_attr_streaming); - res=video_device_create_file(vdev, &class_device_attr_overlay); - res=video_device_create_file(vdev, &class_device_attr_compression); - res=video_device_create_file(vdev, &class_device_attr_bridge); - } -} - -static void usbvision_remove_sysfs(struct video_device *vdev) -{ - if (vdev) { - video_device_remove_file(vdev, &class_device_attr_version); - video_device_remove_file(vdev, &class_device_attr_model); - video_device_remove_file(vdev, &class_device_attr_hue); - video_device_remove_file(vdev, &class_device_attr_contrast); - video_device_remove_file(vdev, &class_device_attr_brightness); - video_device_remove_file(vdev, &class_device_attr_saturation); - video_device_remove_file(vdev, &class_device_attr_streaming); - video_device_remove_file(vdev, &class_device_attr_overlay); - video_device_remove_file(vdev, &class_device_attr_compression); - video_device_remove_file(vdev, &class_device_attr_bridge); - } -} - /*******************************/ /* Memory management functions */ @@ -700,7 +117,6 @@ static void usbvision_remove_sysfs(struct video_device *vdev) * This is used when initializing the contents of the area. */ - void *usbvision_rvmalloc(unsigned long size) { void *mem; @@ -712,65 +128,58 @@ void *usbvision_rvmalloc(unsigned long size) return NULL; memset(mem, 0, size); /* Clear the ram out, no junk to the user */ - adr = (unsigned long) mem; - while (size > 0) { - #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - mem_map_reserve(vmalloc_to_page((void *)adr)); - #else - SetPageReserved(vmalloc_to_page((void *)adr)); - #endif - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - - return mem; + adr = (unsigned long) mem; + while (size > 0) { + SetPageReserved(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + + return mem; } void usbvision_rvfree(void *mem, unsigned long size) { - unsigned long adr; - - if (!mem) - return; - - adr = (unsigned long) mem; - while ((long) size > 0) { - #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - mem_map_unreserve(vmalloc_to_page((void *)adr)); - #else - ClearPageReserved(vmalloc_to_page((void *)adr)); - #endif - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - vfree(mem); -} + unsigned long adr; + + if (!mem) + return; + size = PAGE_ALIGN(size); + adr = (unsigned long) mem; + while ((long) size > 0) { + ClearPageReserved(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + vfree(mem); +} #if ENABLE_HEXDUMP static void usbvision_hexdump(const unsigned char *data, int len) { - char tmp[80]; - int i, k; - - for (i = k = 0; len > 0; i++, len--) { - if (i > 0 && (i % 16 == 0)) { - printk("%s\n", tmp); - k = 0; - } - k += sprintf(&tmp[k], "%02x ", data[i]); - } - if (k > 0) - printk("%s\n", tmp); + char tmp[80]; + int i, k; + + for (i = k = 0; len > 0; i++, len--) { + if (i > 0 && (i % 16 == 0)) { + printk("%s\n", tmp); + k = 0; + } + k += sprintf(&tmp[k], "%02x ", data[i]); + } + if (k > 0) + printk("%s\n", tmp); } #endif - -/* These procedures handle the scratch ring buffer */ +/******************************** + * scratch ring buffer handling + ********************************/ int scratch_len(struct usb_usbvision *usbvision) /*This returns the amount of data actually in the buffer */ { int len = usbvision->scratch_write_ptr - usbvision->scratch_read_ptr; @@ -800,13 +209,6 @@ int scratch_free(struct usb_usbvision *usbvision) } -void *debug_memcpy(void *dest, void *src, size_t len) -{ - printk(KERN_DEBUG "memcpy(%p, %p, %d);\n", dest, src, len); - return memcpy(dest, src, len); -} - - /* This puts data into the buffer */ int scratch_put(struct usb_usbvision *usbvision, unsigned char *data, int len) { @@ -964,246 +366,26 @@ void scratch_reset(struct usb_usbvision *usbvision) usbvision->isocstate = IsocState_NoFrame; } - - -/* Here comes the OVERLAY stuff */ - -/* Tell the interrupt handler what to to. */ -static -void usbvision_cap(struct usb_usbvision* usbvision, int on) -{ - DEBUG(printk(KERN_DEBUG "usbvision_cap: overlay was %d, set it to %d\n", usbvision->overlay, on);) - - if (on) { - usbvision->overlay = 1; - } - else { - usbvision->overlay = 0; - } -} - - - - -/* append a new clipregion to the vector of video_clips */ -static -void usbvision_new_clip(struct v4l2_format* vf, struct v4l2_clip* vcp, int x, int y, int w, int h) -{ - vcp[vf->fmt.win.clipcount].c.left = x; - vcp[vf->fmt.win.clipcount].c.top = y; - vcp[vf->fmt.win.clipcount].c.width = w; - vcp[vf->fmt.win.clipcount].c.height = h; - vf->fmt.win.clipcount++; -} - - -#define mark_pixel(x,y) usbvision->clipmask[((x) + (y) * MAX_FRAME_WIDTH)/32] |= 0x00000001<<((x)%32) -#define clipped_pixel(index) usbvision->clipmask[(index)/32] & (0x00000001<<((index)%32)) - -static -void usbvision_built_overlay(struct usb_usbvision* usbvision, int count, struct v4l2_clip *vcp) -{ - usbvision->overlay_win = usbvision->overlay_base + - (signed int)usbvision->vid_win.fmt.win.w.left * usbvision->depth / 8 + - (signed int)usbvision->vid_win.fmt.win.w.top * usbvision->vid_buf.fmt.bytesperline; - - IODEBUG(printk(KERN_DEBUG "built_overlay base=%p, win=%p, bpl=%d, clips=%d, size=%dx%d\n", - usbvision->overlay_base, usbvision->overlay_win, - usbvision->vid_buf.fmt.bytesperline, count, - usbvision->vid_win.fmt.win.w.width, usbvision->vid_win.fmt.win.w.height);) - - - /* Add here generation of clipping mask */ -{ - int x_start, x_end, y_start, y_end; - int clip_index, x, y; - - memset(usbvision->clipmask, 0, USBVISION_CLIPMASK_SIZE); - - OVDEBUG(printk(KERN_DEBUG "clips = %d\n", count);) - - for(clip_index = 0; clip_index < count; clip_index++) { - OVDEBUG(printk(KERN_DEBUG "clip: %d,%d,%d,%d\n", vcp[clip_index].x, - vcp[clip_index].y, - vcp[clip_index].width, - vcp[clip_index].height);) - - x_start = vcp[clip_index].c.left; - if(x_start >= (int)usbvision->vid_win.fmt.win.w.width) { - OVDEBUG(printk(KERN_DEBUG "x_start=%d\n", x_start);) - continue; //clipping window is right of overlay window - } - x_end = x_start + vcp[clip_index].c.width; - if(x_end <= 0) { - OVDEBUG(printk(KERN_DEBUG "x_end=%d\n", x_end);) - continue; //clipping window is left of overlay window - } - - y_start = vcp[clip_index].c.top; - if(y_start >= (int)usbvision->vid_win.fmt.win.w.height) { - OVDEBUG(printk(KERN_DEBUG "y_start=%d\n", y_start);) - continue; //clipping window is below overlay window - } - y_end = y_start + vcp[clip_index].c.height; - if(y_end <= 0) { - OVDEBUG(printk(KERN_DEBUG "y_end=%d\n", y_end);) - continue; //clipping window is above overlay window - } - - //clip the clipping window - if (x_start < 0) { - x_start = 0; - } - if (x_end > (int)usbvision->vid_win.fmt.win.w.width) { - x_end = (int)usbvision->vid_win.fmt.win.w.width; - } - if (y_start < 0) { - y_start = 0; - } - if (y_end > (int)usbvision->vid_win.fmt.win.w.height) { - y_end = (int)usbvision->vid_win.fmt.win.w.height; - } - - OVDEBUG(printk(KERN_DEBUG "clip_o: %d,%d,%d,%d\n", x_start, y_start, x_end, y_end);) - - - - for(y = y_start; y < y_end; y++) { - for(x = x_start; x < x_end; x++) { - mark_pixel(x,y); - } - } - } -} - -} - - - -void usbvision_osd_char(struct usb_usbvision *usbvision, - struct usbvision_frame *frame, int x, int y, int ch) +int usbvision_scratch_alloc(struct usb_usbvision *usbvision) { - static const unsigned short digits[16] = { - 0xF6DE, /* 0 */ - 0x2492, /* 1 */ - 0xE7CE, /* 2 */ - 0xE79E, /* 3 */ - 0xB792, /* 4 */ - 0xF39E, /* 5 */ - 0xF3DE, /* 6 */ - 0xF492, /* 7 */ - 0xF7DE, /* 8 */ - 0xF79E, /* 9 */ - 0x77DA, /* a */ - 0xD75C, /* b */ - 0xF24E, /* c */ - 0xD6DC, /* d */ - 0xF34E, /* e */ - 0xF348 /* f */ - }; - unsigned short digit; - int ix, iy; - - if ((usbvision == NULL) || (frame == NULL)) - return; - - if (ch >= '0' && ch <= '9') - ch -= '0'; - else if (ch >= 'A' && ch <= 'F') - ch = 10 + (ch - 'A'); - else if (ch >= 'a' && ch <= 'f') - ch = 10 + (ch - 'a'); - else - return; - digit = digits[ch]; - - for (iy = 0; iy < 5; iy++) { - for (ix = 0; ix < 3; ix++) { - if (digit & 0x8000) { - // USBVISION_PUTPIXEL(frame, x + ix, y + iy, - // 0xFF, 0xFF, 0xFF); - } - digit = digit << 1; - } + usbvision->scratch = vmalloc(scratch_buf_size); + scratch_reset(usbvision); + if(usbvision->scratch == NULL) { + err("%s: unable to allocate %d bytes for scratch", + __FUNCTION__, scratch_buf_size); + return -ENOMEM; } + return 0; } - -void usbvision_osd_string(struct usb_usbvision *usbvision, - struct usbvision_frame *frame, - int x, int y, const char *str) +void usbvision_scratch_free(struct usb_usbvision *usbvision) { - while (*str) { - usbvision_osd_char(usbvision, frame, x, y, *str); - str++; - x += 4; /* 3 pixels character + 1 space */ + if (usbvision->scratch != NULL) { + vfree(usbvision->scratch); + usbvision->scratch = NULL; } } -/* - * usb_usbvision_osd_stats() - * - * On screen display of important debugging information. - * - */ -void usbvision_osd_stats(struct usb_usbvision *usbvision, - struct usbvision_frame *frame) -{ - const int y_diff = 8; - char tmp[16]; - int x = 10; - int y = 10; - - sprintf(tmp, "%8x", usbvision->frame_num); - usbvision_osd_string(usbvision, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8lx", usbvision->isocUrbCount); - usbvision_osd_string(usbvision, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8lx", usbvision->urb_length); - usbvision_osd_string(usbvision, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8lx", usbvision->isocDataCount); - usbvision_osd_string(usbvision, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8lx", usbvision->header_count); - usbvision_osd_string(usbvision, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8lx", usbvision->scratch_ovf_count); - usbvision_osd_string(usbvision, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8lx", usbvision->isocSkipCount); - usbvision_osd_string(usbvision, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8lx", usbvision->isocErrCount); - usbvision_osd_string(usbvision, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8x", usbvision->saturation); - usbvision_osd_string(usbvision, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8x", usbvision->hue); - usbvision_osd_string(usbvision, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8x", usbvision->brightness >> 8); - usbvision_osd_string(usbvision, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8x", usbvision->contrast >> 12); - usbvision_osd_string(usbvision, frame, x, y, tmp); - y += y_diff; - -} - /* * usbvision_testpattern() * @@ -1287,14 +469,40 @@ void usbvision_testpattern(struct usb_usbvision *usbvision, int fullframe, frame->scanlength += scan_length; ++num_pass; - /* We do this unconditionally, regardless of FLAGS_OSD_STATS */ - usbvision_osd_stats(usbvision, frame); } /* - * Here comes the data parsing stuff that is run as interrupt + * usbvision_decompress_alloc() + * + * allocates intermediate buffer for decompression */ - +int usbvision_decompress_alloc(struct usb_usbvision *usbvision) +{ + int IFB_size = MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT * 3 / 2; + usbvision->IntraFrameBuffer = vmalloc(IFB_size); + if (usbvision->IntraFrameBuffer == NULL) { + err("%s: unable to allocate %d for compr. frame buffer", __FUNCTION__, IFB_size); + return -ENOMEM; + } + return 0; +} + +/* + * usbvision_decompress_free() + * + * frees intermediate buffer for decompression + */ +void usbvision_decompress_free(struct usb_usbvision *usbvision) +{ + if (usbvision->IntraFrameBuffer != NULL) { + vfree(usbvision->IntraFrameBuffer); + usbvision->IntraFrameBuffer = NULL; + } +} + +/************************************************************ + * Here comes the data parsing stuff that is run as interrupt + ************************************************************/ /* * usbvision_find_header() * @@ -1305,12 +513,7 @@ static enum ParseState usbvision_find_header(struct usb_usbvision *usbvision) struct usbvision_frame *frame; int foundHeader = 0; - if (usbvision->overlay) { - frame = &usbvision->overlay_frame; - } - else { - frame = usbvision->curFrame; - } + frame = usbvision->curFrame; while (scratch_get_header(usbvision, &frame->isocHeader) == USBVISION_HEADER_LENGTH) { // found header in scratch @@ -1368,7 +571,7 @@ static enum ParseState usbvision_find_header(struct usb_usbvision *usbvision) frame->scanstate = ScanState_Lines; frame->curline = 0; - if (flags & FLAGS_FORCE_TESTPATTERN) { + if (force_testpattern) { usbvision_testpattern(usbvision, 1, 1); return ParseState_NextFrame; } @@ -1385,22 +588,10 @@ static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision unsigned char yuyv[4]={180, 128, 10, 128}; // YUV components unsigned char rv, gv, bv; // RGB components int clipmask_index, bytes_per_pixel; - int overlay = usbvision->overlay; int stretch_bytes, clipmask_add; - if (overlay) { - frame = &usbvision->overlay_frame; - if (usbvision->overlay_base == NULL) { - //video_buffer is not set yet - return ParseState_NextFrame; - } - f = usbvision->overlay_win + frame->curline * - usbvision->vid_buf.fmt.bytesperline; - } - else { - frame = usbvision->curFrame; - f = frame->data + (frame->v4l2_linesize * frame->curline); - } + frame = usbvision->curFrame; + f = frame->data + (frame->v4l2_linesize * frame->curline); /* Make sure there's enough data for the entire line */ len = (frame->isocHeader.frameWidth * 2)+5; @@ -1422,10 +613,7 @@ static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision scratch_get(usbvision, &yuyv[0], 4); - if((overlay) && (clipped_pixel(clipmask_index))) { - f += bytes_per_pixel; - } - else if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { + if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { *f++ = yuyv[0]; // Y *f++ = yuyv[3]; // U } @@ -1457,10 +645,7 @@ static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision clipmask_index += clipmask_add; f += stretch_bytes; - if((overlay) && (clipped_pixel(clipmask_index))) { - f += bytes_per_pixel; - } - else if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { + if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { *f++ = yuyv[2]; // Y *f++ = yuyv[1]; // V } @@ -1504,7 +689,7 @@ static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision } } - +/* The decompression routine */ static int usbvision_decompress(struct usb_usbvision *usbvision,unsigned char *Compressed, unsigned char *Decompressed, int *StartPos, int *BlockTypeStartPos, int Len) @@ -1614,45 +799,31 @@ static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision, unsigned char StripHeader[USBVISION_STRIP_HEADER_LEN]; int Idx, IdxEnd, StripLen, StripPtr, StartBlockPos, BlockPos, BlockTypePos; int clipmask_index, bytes_per_pixel, rc; - int overlay = usbvision->overlay; int imageSize; unsigned char rv, gv, bv; static unsigned char *Y, *U, *V; - if (overlay) { - frame = &usbvision->overlay_frame; - imageSize = frame->frmwidth * frame->frmheight; - if (usbvision->overlay_base == NULL) { - //video_buffer is not set yet - return ParseState_NextFrame; - } - f = usbvision->overlay_win + frame->curline * - usbvision->vid_buf.fmt.bytesperline; - } - else { - frame = usbvision->curFrame; - imageSize = frame->frmwidth * frame->frmheight; - if ( (frame->v4l2_format.format == V4L2_PIX_FMT_YUV422P) || - (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420) ) - { // this is a planar format - //... v4l2_linesize not used here. - f = frame->data + (frame->width * frame->curline); - } else - f = frame->data + (frame->v4l2_linesize * frame->curline); - - if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV){ //initialise u and v pointers - // get base of u and b planes add halfoffset - - u = frame->data - + imageSize - + (frame->frmwidth >>1) * frame->curline ; - v = u + (imageSize >>1 ); - - } else if (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420){ - - v = frame->data + imageSize + ((frame->curline* (frame->width))>>2) ; - u = v + (imageSize >>2) ; - } + frame = usbvision->curFrame; + imageSize = frame->frmwidth * frame->frmheight; + if ( (frame->v4l2_format.format == V4L2_PIX_FMT_YUV422P) || + (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420) ) { // this is a planar format + //... v4l2_linesize not used here. + f = frame->data + (frame->width * frame->curline); + } else + f = frame->data + (frame->v4l2_linesize * frame->curline); + + if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV){ //initialise u and v pointers + // get base of u and b planes add halfoffset + + u = frame->data + + imageSize + + (frame->frmwidth >>1) * frame->curline ; + v = u + (imageSize >>1 ); + + } else if (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420){ + + v = frame->data + imageSize + ((frame->curline* (frame->width))>>2) ; + u = v + (imageSize >>2) ; } if (frame->curline == 0) { @@ -1738,10 +909,7 @@ static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision, } for (Idx = 0; Idx < IdxEnd; Idx++) { - if((overlay) && (clipped_pixel(clipmask_index))) { - f += bytes_per_pixel; - } - else if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { + if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { *f++ = Y[Idx]; *f++ = Idx & 0x01 ? U[Idx/2] : V[Idx/2]; } @@ -1838,23 +1006,10 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision unsigned char g; int clipmask_even_index, clipmask_odd_index, bytes_per_pixel; int clipmask_add, stretch_bytes; - int overlay = usbvision->overlay; - if (overlay) { - frame = &usbvision->overlay_frame; - if (usbvision->overlay_base == NULL) { - //video_buffer is not set yet - return ParseState_NextFrame; - } - f_even = usbvision->overlay_win + frame->curline * - usbvision->vid_buf.fmt.bytesperline; - f_odd = f_even + usbvision->vid_buf.fmt.bytesperline * usbvision->stretch_height; - } - else { - frame = usbvision->curFrame; - f_even = frame->data + (frame->v4l2_linesize * frame->curline); - f_odd = f_even + frame->v4l2_linesize * usbvision->stretch_height; - } + frame = usbvision->curFrame; + f_even = frame->data + (frame->v4l2_linesize * frame->curline); + f_odd = f_even + frame->v4l2_linesize * usbvision->stretch_height; /* Make sure there's enough data for the entire line */ /* In this mode usbvision transfer 3 bytes for every 2 pixels */ @@ -1901,10 +1056,7 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision uvg= -53281 * u_ - 25625 * v_; ur = 104595 * u_; - if((overlay) && (clipped_pixel(clipmask_even_index))) { - f_even += bytes_per_pixel; - } - else if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { + if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { *f_even++ = y[0]; *f_even++ = v; } @@ -1943,10 +1095,7 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision clipmask_even_index += clipmask_add; f_even += stretch_bytes; - if((overlay) && (clipped_pixel(clipmask_even_index))) { - f_even += bytes_per_pixel; - } - else if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { + if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { *f_even++ = y[1]; *f_even++ = u; } @@ -1987,10 +1136,7 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision scratch_get_extra(usbvision, &y[0], &y_ptr, 2); - if ((overlay) && (clipped_pixel(clipmask_odd_index))) { - f_odd += bytes_per_pixel; - } - else if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { + if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { *f_odd++ = y[0]; *f_odd++ = v; } @@ -2029,10 +1175,7 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision clipmask_odd_index += clipmask_add; f_odd += stretch_bytes; - if((overlay) && (clipped_pixel(clipmask_odd_index))) { - f_odd += bytes_per_pixel; - } - else if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { + if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { *f_odd++ = y[1]; *f_odd++ = u; } @@ -2108,12 +1251,7 @@ static void usbvision_parse_data(struct usb_usbvision *usbvision) long copylen = 0; unsigned long lock_flags; - if (usbvision->overlay) { - frame = &usbvision->overlay_frame; - } - else { - frame = usbvision->curFrame; - } + frame = usbvision->curFrame; PDEBUG(DBG_PARSE, "parsing len=%d\n", scratch_len(usbvision)); @@ -2152,23 +1290,13 @@ static void usbvision_parse_data(struct usb_usbvision *usbvision) frame->grabstate = FrameState_Done; do_gettimeofday(&(frame->timestamp)); frame->sequence = usbvision->frame_num; - if (usbvision->overlay) { - frame->grabstate = FrameState_Grabbing; - frame->scanstate = ScanState_Scanning; - frame->scanlength = 0; - copylen = 0; - } - else { - spin_lock_irqsave(&usbvision->queue_lock, lock_flags); - list_move_tail(&(frame->frame), &usbvision->outqueue); - usbvision->curFrame = NULL; - spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); - } - usbvision->frame_num++; - /* Optionally display statistics on the screen */ - if (flags & FLAGS_OSD_STATS) - usbvision_osd_stats(usbvision, frame); + spin_lock_irqsave(&usbvision->queue_lock, lock_flags); + list_move_tail(&(frame->frame), &usbvision->outqueue); + usbvision->curFrame = NULL; + spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); + + usbvision->frame_num++; /* This will cause the process to request another frame. */ if (waitqueue_active(&usbvision->wait_frame)) { @@ -2306,7 +1434,7 @@ static void usbvision_isocIrq(struct urb *urb, struct pt_regs *regs) /* If we collected enough data let's parse! */ if (scratch_len(usbvision) > USBVISION_HEADER_LENGTH) { /* 12 == header_length */ /*If we don't have a frame we're current working on, complain */ - if((!list_empty(&(usbvision->inqueue))) || (usbvision->overlay)) { + if(!list_empty(&(usbvision->inqueue))) { if (!(*f)) { (*f) = list_entry(usbvision->inqueue.next,struct usbvision_frame, frame); } @@ -2353,7 +1481,7 @@ static void usbvision_isocIrq(struct urb *urb, struct pt_regs *regs) * >= 0 -> Data */ -static int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg) +int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg) { int errCode = 0; unsigned char buffer[1]; @@ -2381,7 +1509,7 @@ static int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg * -1 -> Something went wrong */ -static int usbvision_write_reg(struct usb_usbvision *usbvision, unsigned char reg, +int usbvision_write_reg(struct usb_usbvision *usbvision, unsigned char reg, unsigned char value) { int errCode = 0; @@ -2454,8 +1582,6 @@ static int usbvision_write_reg_irq(struct usb_usbvision *usbvision,int address, } - - static int usbvision_init_compression(struct usb_usbvision *usbvision) { int errCode = 0; @@ -2563,334 +1689,11 @@ static int usbvision_unrequest_intra (struct usb_usbvision *usbvision) return errCode; } -/* ----------------------------------------------------------------------- */ -/* I2C functions */ -/* ----------------------------------------------------------------------- */ - -static void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd, - void *arg) -{ - BUG_ON(NULL == usbvision->i2c_adap.algo_data); - i2c_clients_command(&usbvision->i2c_adap, cmd, arg); -} - -static int attach_inform(struct i2c_client *client) -{ - struct usb_usbvision *usbvision; - - usbvision = (struct usb_usbvision *)i2c_get_adapdata(client->adapter); - - switch (client->addr << 1) { - case 0x43: - case 0x4b: - { - struct tuner_setup tun_setup; - - tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; - tun_setup.type = TUNER_TDA9887; - tun_setup.addr = client->addr; - - call_i2c_clients(usbvision, TUNER_SET_TYPE_ADDR, &tun_setup); - - break; - } - case 0x42: - PDEBUG(DBG_I2C,"attach_inform: saa7114 detected.\n"); - break; - case 0x4a: - PDEBUG(DBG_I2C,"attach_inform: saa7113 detected.\n"); - break; - case 0xa0: - PDEBUG(DBG_I2C,"attach_inform: eeprom detected.\n"); - break; - - default: - PDEBUG(DBG_I2C,"attach inform: detected I2C address %x\n", client->addr << 1); - { - struct tuner_setup tun_setup; - - usbvision->tuner_addr = client->addr; - - if ((usbvision->have_tuner) && (usbvision->tuner_type != -1)) { - tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; - tun_setup.type = usbvision->tuner_type; - tun_setup.addr = usbvision->tuner_addr; - call_i2c_clients(usbvision, TUNER_SET_TYPE_ADDR, &tun_setup); - } - } - break; - } - return 0; -} - -static int detach_inform(struct i2c_client *client) -{ - struct usb_usbvision *usbvision; - - #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - usbvision = (struct usb_usbvision *)client->adapter->data; - #else - usbvision = (struct usb_usbvision *)i2c_get_adapdata(client->adapter); - #endif - - PDEBUG(DBG_I2C, "usbvision[%d] detaches %s", usbvision->nr, client->name); - return 0; -} - -static int -usbvision_i2c_read_max4(struct usb_usbvision *usbvision, unsigned char addr, - char *buf, short len) -{ - int rc, retries; - - for (retries = 5;;) { - rc = usbvision_write_reg(usbvision, USBVISION_SER_ADRS, addr); - if (rc < 0) - return rc; - - /* Initiate byte read cycle */ - /* USBVISION_SER_CONT <- d0-d2 n. of bytes to r/w */ - /* d3 0=Wr 1=Rd */ - rc = usbvision_write_reg(usbvision, USBVISION_SER_CONT, - (len & 0x07) | 0x18); - if (rc < 0) - return rc; - - /* Test for Busy and ACK */ - do { - /* USBVISION_SER_CONT -> d4 == 0 busy */ - rc = usbvision_read_reg(usbvision, USBVISION_SER_CONT); - } while (rc > 0 && ((rc & 0x10) != 0)); /* Retry while busy */ - if (rc < 0) - return rc; - - /* USBVISION_SER_CONT -> d5 == 1 Not ack */ - if ((rc & 0x20) == 0) /* Ack? */ - break; - - /* I2C abort */ - rc = usbvision_write_reg(usbvision, USBVISION_SER_CONT, 0x00); - if (rc < 0) - return rc; - - if (--retries < 0) - return -1; - } - - switch (len) { - case 4: - buf[3] = usbvision_read_reg(usbvision, USBVISION_SER_DAT4); - case 3: - buf[2] = usbvision_read_reg(usbvision, USBVISION_SER_DAT3); - case 2: - buf[1] = usbvision_read_reg(usbvision, USBVISION_SER_DAT2); - case 1: - buf[0] = usbvision_read_reg(usbvision, USBVISION_SER_DAT1); - break; - default: - printk(KERN_ERR - "usbvision_i2c_read_max4: buffer length > 4\n"); - } - - if (debug & DBG_I2C) { - int idx; - for (idx = 0; idx < len; idx++) { - PDEBUG(DBG_I2C, "read %x from address %x", (unsigned char)buf[idx], addr); - } - } - return len; -} - - -static int usbvision_i2c_write_max4(struct usb_usbvision *usbvision, - unsigned char addr, const char *buf, - short len) -{ - int rc, retries; - int i; - unsigned char value[6]; - unsigned char ser_cont; - - ser_cont = (len & 0x07) | 0x10; - - value[0] = addr; - value[1] = ser_cont; - for (i = 0; i < len; i++) - value[i + 2] = buf[i]; - - for (retries = 5;;) { - rc = usb_control_msg(usbvision->dev, - usb_sndctrlpipe(usbvision->dev, 1), - USBVISION_OP_CODE, - USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_ENDPOINT, 0, - (__u16) USBVISION_SER_ADRS, value, - len + 2, HZ); - - if (rc < 0) - return rc; - - rc = usbvision_write_reg(usbvision, USBVISION_SER_CONT, - (len & 0x07) | 0x10); - if (rc < 0) - return rc; - - /* Test for Busy and ACK */ - do { - rc = usbvision_read_reg(usbvision, USBVISION_SER_CONT); - } while (rc > 0 && ((rc & 0x10) != 0)); /* Retry while busy */ - if (rc < 0) - return rc; - - if ((rc & 0x20) == 0) /* Ack? */ - break; - - /* I2C abort */ - usbvision_write_reg(usbvision, USBVISION_SER_CONT, 0x00); - - if (--retries < 0) - return -1; - - } - - if (debug & DBG_I2C) { - int idx; - for (idx = 0; idx < len; idx++) { - PDEBUG(DBG_I2C, "wrote %x at address %x", (unsigned char)buf[idx], addr); - } - } - return len; -} - -static int usbvision_i2c_write(void *data, unsigned char addr, char *buf, - short len) -{ - char *bufPtr = buf; - int retval; - int wrcount = 0; - int count; - int maxLen = 4; - struct usb_usbvision *usbvision = (struct usb_usbvision *) data; - - while (len > 0) { - count = (len > maxLen) ? maxLen : len; - retval = usbvision_i2c_write_max4(usbvision, addr, bufPtr, count); - if (retval > 0) { - len -= count; - bufPtr += count; - wrcount += count; - } else - return (retval < 0) ? retval : -EFAULT; - } - return wrcount; -} - -static int usbvision_i2c_read(void *data, unsigned char addr, char *buf, - short len) -{ - char temp[4]; - int retval, i; - int rdcount = 0; - int count; - struct usb_usbvision *usbvision = (struct usb_usbvision *) data; - - while (len > 0) { - count = (len > 3) ? 4 : len; - retval = usbvision_i2c_read_max4(usbvision, addr, temp, count); - if (retval > 0) { - for (i = 0; i < len; i++) - buf[rdcount + i] = temp[i]; - len -= count; - rdcount += count; - } else - return (retval < 0) ? retval : -EFAULT; - } - return rdcount; -} - -static struct i2c_algo_usb_data i2c_algo_template = { - .data = NULL, - .inb = usbvision_i2c_read, - .outb = usbvision_i2c_write, - .udelay = 10, - .mdelay = 10, - .timeout = 100, -}; - -static struct i2c_adapter i2c_adap_template = { - .owner = THIS_MODULE, - .name = "usbvision", - .id = I2C_HW_B_BT848, /* FIXME */ - .algo = NULL, - .algo_data = NULL, - .client_register = attach_inform, - .client_unregister = detach_inform, -#if defined (I2C_ADAP_CLASS_TV_ANALOG) - .class = I2C_ADAP_CLASS_TV_ANALOG, -#elif defined (I2C_CLASS_TV_ANALOG) - .class = I2C_CLASS_TV_ANALOG, -#endif -}; - -static struct i2c_client i2c_client_template = { - .name = "usbvision internal", - .flags = 0, - .addr = 0, - .adapter = NULL, - .driver = NULL, -}; - -static int usbvision_init_i2c(struct usb_usbvision *usbvision) -{ - memcpy(&usbvision->i2c_adap, &i2c_adap_template, - sizeof(struct i2c_adapter)); - memcpy(&usbvision->i2c_algo, &i2c_algo_template, - sizeof(struct i2c_algo_usb_data)); - memcpy(&usbvision->i2c_client, &i2c_client_template, - sizeof(struct i2c_client)); - - sprintf(usbvision->i2c_adap.name + strlen(usbvision->i2c_adap.name), - " #%d", usbvision->vdev->minor & 0x1f); - PDEBUG(DBG_I2C, "Adaptername: %s", usbvision->i2c_adap.name); - - i2c_set_adapdata(&usbvision->i2c_adap, usbvision); - i2c_set_clientdata(&usbvision->i2c_client, usbvision); - i2c_set_algo_usb_data(&usbvision->i2c_algo, usbvision); - - usbvision->i2c_adap.algo_data = &usbvision->i2c_algo; - usbvision->i2c_client.adapter = &usbvision->i2c_adap; - - if (usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_IIC_LRNACK) < 0) { - printk(KERN_ERR "usbvision_init_i2c: can't wirte reg\n"); - return -EBUSY; - } - -#ifdef CONFIG_KMOD - /* Request the load of the i2c modules we need */ - if (autoload) { - switch (usbvision_device_data[usbvision->DevModel].Codec) { - case CODEC_SAA7113: - request_module("saa7115"); - break; - case CODEC_SAA7111: - request_module("saa7115"); - break; - } - if (usbvision_device_data[usbvision->DevModel].Tuner == 1) { - request_module("tuner"); - } - } -#endif - - return usbvision_i2c_usb_add_bus(&usbvision->i2c_adap); -} +/******************************* + * usbvision utility functions + *******************************/ - -/****************************/ -/* usbvision utility functions */ -/****************************/ - -static int usbvision_power_off(struct usb_usbvision *usbvision) +int usbvision_power_off(struct usb_usbvision *usbvision) { int errCode = 0; @@ -2905,22 +1708,6 @@ static int usbvision_power_off(struct usb_usbvision *usbvision) } -// to call usbvision_power_off from task queue -static void call_usbvision_power_off(void *_usbvision) -{ - struct usb_usbvision *usbvision = _usbvision; - - PDEBUG(DBG_FUNC, ""); - down_interruptible(&usbvision->lock); - if(usbvision->user == 0) { - usbvision_i2c_usb_del_bus(&usbvision->i2c_adap); - usbvision_power_off(usbvision); - usbvision->initialized = 0; - } - up(&usbvision->lock); -} - - /* * usbvision_set_video_format() * @@ -2964,8 +1751,8 @@ static int usbvision_set_video_format(struct usb_usbvision *usbvision, int forma * */ -static int usbvision_set_output(struct usb_usbvision *usbvision, int width, - int height) +int usbvision_set_output(struct usb_usbvision *usbvision, int width, + int height) { int errCode = 0; int UsbWidth, UsbHeight; @@ -3059,11 +1846,63 @@ static int usbvision_set_output(struct usb_usbvision *usbvision, int width, } +/* + * usbvision_frames_alloc + * allocate the maximum frames this driver can manage + */ +int usbvision_frames_alloc(struct usb_usbvision *usbvision) +{ + int i; + + /* Allocate memory for the frame buffers */ + usbvision->max_frame_size = MAX_FRAME_SIZE; + usbvision->fbuf_size = USBVISION_NUMFRAMES * usbvision->max_frame_size; + usbvision->fbuf = usbvision_rvmalloc(usbvision->fbuf_size); + + if(usbvision->fbuf == NULL) { + err("%s: unable to allocate %d bytes for fbuf ", + __FUNCTION__, usbvision->fbuf_size); + return -ENOMEM; + } + spin_lock_init(&usbvision->queue_lock); + init_waitqueue_head(&usbvision->wait_frame); + init_waitqueue_head(&usbvision->wait_stream); + + /* Allocate all buffers */ + for (i = 0; i < USBVISION_NUMFRAMES; i++) { + usbvision->frame[i].index = i; + usbvision->frame[i].grabstate = FrameState_Unused; + usbvision->frame[i].data = usbvision->fbuf + + i * usbvision->max_frame_size; + /* + * Set default sizes for read operation. + */ + usbvision->stretch_width = 1; + usbvision->stretch_height = 1; + usbvision->frame[i].width = usbvision->curwidth; + usbvision->frame[i].height = usbvision->curheight; + usbvision->frame[i].bytes_read = 0; + } + return 0; +} + +/* + * usbvision_frames_free + * frees memory allocated for the frames + */ +void usbvision_frames_free(struct usb_usbvision *usbvision) +{ + /* Have to free all that memory */ + if (usbvision->fbuf != NULL) { + usbvision_rvfree(usbvision->fbuf, usbvision->fbuf_size); + usbvision->fbuf = NULL; + } +} /* * usbvision_empty_framequeues() * prepare queues for incoming and outgoing frames */ -static void usbvision_empty_framequeues(struct usb_usbvision *usbvision) +void usbvision_empty_framequeues(struct usb_usbvision *usbvision) { u32 i; @@ -3080,7 +1919,7 @@ static void usbvision_empty_framequeues(struct usb_usbvision *usbvision) * usbvision_stream_interrupt() * stops streaming */ -static int usbvision_stream_interrupt(struct usb_usbvision *usbvision) +int usbvision_stream_interrupt(struct usb_usbvision *usbvision) { int ret = 0; @@ -3176,7 +2015,7 @@ static int usbvision_set_compress_params(struct usb_usbvision *usbvision) * I've no idea if this parameters are right * */ -static int usbvision_set_input(struct usb_usbvision *usbvision) +int usbvision_set_input(struct usb_usbvision *usbvision) { static const char proc[] = "usbvision_set_input: "; int rc; @@ -3351,7 +2190,7 @@ static int usbvision_set_dram_settings(struct usb_usbvision *usbvision) * */ -static int usbvision_power_on(struct usb_usbvision *usbvision) +int usbvision_power_on(struct usb_usbvision *usbvision) { int errCode = 0; @@ -3372,6 +2211,25 @@ static int usbvision_power_on(struct usb_usbvision *usbvision) } +/* + * usbvision timer stuff + */ + +// to call usbvision_power_off from task queue +static void call_usbvision_power_off(void *_usbvision) +{ + struct usb_usbvision *usbvision = _usbvision; + + PDEBUG(DBG_FUNC, ""); + down_interruptible(&usbvision->lock); + if(usbvision->user == 0) { + usbvision_i2c_usb_del_bus(&usbvision->i2c_adap); + usbvision_power_off(usbvision); + usbvision->initialized = 0; + } + up(&usbvision->lock); +} + static void usbvision_powerOffTimer(unsigned long data) { struct usb_usbvision *usbvision = (void *) data; @@ -3383,13 +2241,31 @@ static void usbvision_powerOffTimer(unsigned long data) } +void usbvision_init_powerOffTimer(struct usb_usbvision *usbvision) +{ + init_timer(&usbvision->powerOffTimer); + usbvision->powerOffTimer.data = (long) usbvision; + usbvision->powerOffTimer.function = usbvision_powerOffTimer; +} + +void usbvision_set_powerOffTimer(struct usb_usbvision *usbvision) +{ + mod_timer(&usbvision->powerOffTimer, jiffies + USBVISION_POWEROFF_TIME); +} + +void usbvision_reset_powerOffTimer(struct usb_usbvision *usbvision) +{ + if (timer_pending(&usbvision->powerOffTimer)) { + del_timer(&usbvision->powerOffTimer); + } +} /* * usbvision_begin_streaming() * Sure you have to put bit 7 to 0, if not incoming frames are droped, but no * idea about the rest */ -static int usbvision_begin_streaming(struct usb_usbvision *usbvision) +int usbvision_begin_streaming(struct usb_usbvision *usbvision) { int errCode = 0; @@ -3406,7 +2282,7 @@ static int usbvision_begin_streaming(struct usb_usbvision *usbvision) * Not sure yet if touching here PWR_REG make loose the config */ -static int usbvision_restart_isoc(struct usb_usbvision *usbvision) +int usbvision_restart_isoc(struct usb_usbvision *usbvision) { int ret; @@ -3433,41 +2309,18 @@ static int usbvision_restart_isoc(struct usb_usbvision *usbvision) return 0; } -static int usbvision_audio_on(struct usb_usbvision *usbvision) -{ - if (usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, usbvision->AudioChannel) < 0) { - printk(KERN_ERR "usbvision_audio_on: can't wirte reg\n"); - return -1; - } - DEBUG(printk(KERN_DEBUG "usbvision_audio_on: channel %d\n", usbvision->AudioChannel)); - usbvision->AudioMute = 0; - return 0; -} - -static int usbvision_audio_mute(struct usb_usbvision *usbvision) -{ - if (usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, 0x03) < 0) { - printk(KERN_ERR "usbvision_audio_mute: can't wirte reg\n"); - return -1; - } - DEBUG(printk(KERN_DEBUG "usbvision_audio_mute: audio mute\n")); - usbvision->AudioMute = 1; - return 0; -} - -static int usbvision_audio_off(struct usb_usbvision *usbvision) +int usbvision_audio_off(struct usb_usbvision *usbvision) { if (usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, USBVISION_AUDIO_MUTE) < 0) { printk(KERN_ERR "usbvision_audio_off: can't wirte reg\n"); return -1; } - DEBUG(printk(KERN_DEBUG "usbvision_audio_off: audio off\n")); usbvision->AudioMute = 0; usbvision->AudioChannel = USBVISION_AUDIO_MUTE; return 0; } -static int usbvision_set_audio(struct usb_usbvision *usbvision, int AudioChannel) +int usbvision_set_audio(struct usb_usbvision *usbvision, int AudioChannel) { if (!usbvision->AudioMute) { if (usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, AudioChannel) < 0) { @@ -3475,14 +2328,13 @@ static int usbvision_set_audio(struct usb_usbvision *usbvision, int AudioChannel return -1; } } - DEBUG(printk(KERN_DEBUG "usbvision_set_audio: channel %d\n", AudioChannel)); usbvision->AudioChannel = AudioChannel; return 0; } -static int usbvision_setup(struct usb_usbvision *usbvision) +int usbvision_setup(struct usb_usbvision *usbvision,int format) { - usbvision_set_video_format(usbvision, isocMode); + usbvision_set_video_format(usbvision, format); usbvision_set_dram_settings(usbvision); usbvision_set_compress_params(usbvision); usbvision_set_input(usbvision); @@ -3494,22 +2346,55 @@ static int usbvision_setup(struct usb_usbvision *usbvision) } -/* - * usbvision_init_isoc() - * - */ -static int usbvision_init_isoc(struct usb_usbvision *usbvision) +int usbvision_sbuf_alloc(struct usb_usbvision *usbvision) { - struct usb_device *dev = usbvision->dev; - int bufIdx, errCode, regValue; + int i, errCode = 0; + const int sb_size = USBVISION_URB_FRAMES * USBVISION_MAX_ISOC_PACKET_SIZE; - if (!USBVISION_IS_OPERATIONAL(usbvision)) - return -EFAULT; + /* Clean pointers so we know if we allocated something */ + for (i = 0; i < USBVISION_NUMSBUF; i++) + usbvision->sbuf[i].data = NULL; - usbvision->curFrame = NULL; - scratch_reset(usbvision); + for (i = 0; i < USBVISION_NUMSBUF; i++) { + usbvision->sbuf[i].data = kzalloc(sb_size, GFP_KERNEL); + if (usbvision->sbuf[i].data == NULL) { + err("%s: unable to allocate %d bytes for sbuf", __FUNCTION__, sb_size); + errCode = -ENOMEM; + break; + } + } + return errCode; +} - /* Alternate interface 1 is is the biggest frame size */ + +void usbvision_sbuf_free(struct usb_usbvision *usbvision) +{ + int i; + + for (i = 0; i < USBVISION_NUMSBUF; i++) { + if (usbvision->sbuf[i].data != NULL) { + kfree(usbvision->sbuf[i].data); + usbvision->sbuf[i].data = NULL; + } + } +} + +/* + * usbvision_init_isoc() + * + */ +int usbvision_init_isoc(struct usb_usbvision *usbvision) +{ + struct usb_device *dev = usbvision->dev; + int bufIdx, errCode, regValue; + + if (!USBVISION_IS_OPERATIONAL(usbvision)) + return -EFAULT; + + usbvision->curFrame = NULL; + scratch_reset(usbvision); + + /* Alternate interface 1 is is the biggest frame size */ errCode = usb_set_interface(dev, usbvision->iface, usbvision->ifaceAltActive); if (errCode < 0) { usbvision->last_error = errCode; @@ -3587,7 +2472,7 @@ static int usbvision_init_isoc(struct usb_usbvision *usbvision) * activates zero-bandwidth alt. setting of the video interface. * */ -static void usbvision_stop_isoc(struct usb_usbvision *usbvision) +void usbvision_stop_isoc(struct usb_usbvision *usbvision) { int bufIdx, errCode, regValue; @@ -3623,7 +2508,7 @@ static void usbvision_stop_isoc(struct usb_usbvision *usbvision) } } -static int usbvision_muxsel(struct usb_usbvision *usbvision, int channel) +int usbvision_muxsel(struct usb_usbvision *usbvision, int channel) { int mode[4]; int audio[]= {1, 0, 0, 0}; @@ -3671,2157 +2556,6 @@ static int usbvision_muxsel(struct usb_usbvision *usbvision, int channel) return 0; } - -/* - * usbvision_open() - * - * This is part of Video 4 Linux API. The driver can be opened by one - * client only (checks internal counter 'usbvision->user'). The procedure - * then allocates buffers needed for video processing. - * - */ -static int usbvision_v4l2_open(struct inode *inode, struct file *file) -{ - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); - const int sb_size = USBVISION_URB_FRAMES * USBVISION_MAX_ISOC_PACKET_SIZE; - int i, errCode = 0; - - PDEBUG(DBG_IO, "open"); - - - if (timer_pending(&usbvision->powerOffTimer)) { - del_timer(&usbvision->powerOffTimer); - } - - if (usbvision->user) - errCode = -EBUSY; - else { - /* Clean pointers so we know if we allocated something */ - for (i = 0; i < USBVISION_NUMSBUF; i++) - usbvision->sbuf[i].data = NULL; - - /* Allocate memory for the frame buffers */ - usbvision->max_frame_size = MAX_FRAME_SIZE; - usbvision->fbuf_size = USBVISION_NUMFRAMES * usbvision->max_frame_size; - usbvision->fbuf = usbvision_rvmalloc(usbvision->fbuf_size); - usbvision->scratch = vmalloc(scratch_buf_size); - scratch_reset(usbvision); - if ((usbvision->fbuf == NULL) || (usbvision->scratch == NULL)) { - err("%s: unable to allocate %d bytes for fbuf and %d bytes for scratch", - __FUNCTION__, usbvision->fbuf_size, scratch_buf_size); - errCode = -ENOMEM; - } - else { - spin_lock_init(&usbvision->queue_lock); - init_waitqueue_head(&usbvision->wait_frame); - init_waitqueue_head(&usbvision->wait_stream); - - /* Allocate all buffers */ - for (i = 0; i < USBVISION_NUMFRAMES; i++) { - usbvision->frame[i].index = i; - usbvision->frame[i].grabstate = FrameState_Unused; - usbvision->frame[i].data = usbvision->fbuf + - i * MAX_FRAME_SIZE; - /* - * Set default sizes in case IOCTL - * (VIDIOCMCAPTURE) - * is not used (using read() instead). - */ - usbvision->stretch_width = 1; - usbvision->stretch_height = 1; - usbvision->frame[i].width = usbvision->curwidth; - usbvision->frame[i].height = usbvision->curheight; - usbvision->frame[i].bytes_read = 0; - } - if (dga) { //set default for DGA - usbvision->overlay_frame.grabstate = FrameState_Unused; - usbvision->overlay_frame.scanstate = ScanState_Scanning; - usbvision->overlay_frame.data = NULL; - usbvision->overlay_frame.width = usbvision->curwidth; - usbvision->overlay_frame.height = usbvision->curheight; - usbvision->overlay_frame.bytes_read = 0; - } - for (i = 0; i < USBVISION_NUMSBUF; i++) { - usbvision->sbuf[i].data = kzalloc(sb_size, GFP_KERNEL); - if (usbvision->sbuf[i].data == NULL) { - err("%s: unable to allocate %d bytes for sbuf", __FUNCTION__, sb_size); - errCode = -ENOMEM; - break; - } - } - } - if ((!errCode) && (usbvision->isocMode==ISOC_MODE_COMPRESS)) { - int IFB_size = MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT * 3 / 2; - usbvision->IntraFrameBuffer = vmalloc(IFB_size); - if (usbvision->IntraFrameBuffer == NULL) { - err("%s: unable to allocate %d for compr. frame buffer", __FUNCTION__, IFB_size); - errCode = -ENOMEM; - } - - } - if (errCode) { - /* Have to free all that memory */ - if (usbvision->fbuf != NULL) { - usbvision_rvfree(usbvision->fbuf, usbvision->fbuf_size); - usbvision->fbuf = NULL; - } - if (usbvision->scratch != NULL) { - vfree(usbvision->scratch); - usbvision->scratch = NULL; - } - for (i = 0; i < USBVISION_NUMSBUF; i++) { - if (usbvision->sbuf[i].data != NULL) { - kfree(usbvision->sbuf[i].data); - usbvision->sbuf[i].data = NULL; - } - } - if (usbvision->IntraFrameBuffer != NULL) { - vfree(usbvision->IntraFrameBuffer); - usbvision->IntraFrameBuffer = NULL; - } - } - } - - /* If so far no errors then we shall start the camera */ - if (!errCode) { - down(&usbvision->lock); - if (usbvision->power == 0) { - usbvision_power_on(usbvision); - usbvision_init_i2c(usbvision); - } - - /* Send init sequence only once, it's large! */ - if (!usbvision->initialized) { - int setup_ok = 0; - setup_ok = usbvision_setup(usbvision); - if (setup_ok) - usbvision->initialized = 1; - else - errCode = -EBUSY; - } - - if (!errCode) { - usbvision_begin_streaming(usbvision); - errCode = usbvision_init_isoc(usbvision); - /* device needs to be initialized before isoc transfer */ - usbvision_muxsel(usbvision,0); - usbvision->user++; - } - else { - if (PowerOnAtOpen) { - usbvision_i2c_usb_del_bus(&usbvision->i2c_adap); - usbvision_power_off(usbvision); - usbvision->initialized = 0; - } - } - up(&usbvision->lock); - } - - if (errCode) { - } - - /* prepare queues */ - usbvision_empty_framequeues(usbvision); - - PDEBUG(DBG_IO, "success"); - return errCode; -} - -/* - * usbvision_v4l2_close() - * - * This is part of Video 4 Linux API. The procedure - * stops streaming and deallocates all buffers that were earlier - * allocated in usbvision_v4l2_open(). - * - */ -static int usbvision_v4l2_close(struct inode *inode, struct file *file) -{ - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); - int i; - - PDEBUG(DBG_IO, "close"); - down(&usbvision->lock); - - usbvision_audio_off(usbvision); - usbvision_restart_isoc(usbvision); - usbvision_stop_isoc(usbvision); - - if (usbvision->IntraFrameBuffer != NULL) { - vfree(usbvision->IntraFrameBuffer); - usbvision->IntraFrameBuffer = NULL; - } - - usbvision_rvfree(usbvision->fbuf, usbvision->fbuf_size); - vfree(usbvision->scratch); - for (i = 0; i < USBVISION_NUMSBUF; i++) - kfree(usbvision->sbuf[i].data); - - usbvision->user--; - - if (PowerOnAtOpen) { - mod_timer(&usbvision->powerOffTimer, jiffies + USBVISION_POWEROFF_TIME); - usbvision->initialized = 0; - } - - up(&usbvision->lock); - - if (usbvision->remove_pending) { - info("%s: Final disconnect", __FUNCTION__); - usbvision_release(usbvision); - } - - PDEBUG(DBG_IO, "success"); - - - return 0; -} - - -/* - * usbvision_ioctl() - * - * This is part of Video 4 Linux API. The procedure handles ioctl() calls. - * - */ -static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) -{ - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); - - if (!USBVISION_IS_OPERATIONAL(usbvision)) - return -EFAULT; - - // if (debug & DBG_IOCTL) v4l_printk_ioctl(cmd); - - switch (cmd) { - -#ifdef CONFIG_VIDEO_ADV_DEBUG - /* ioctls to allow direct acces to the NT100x registers */ - case VIDIOC_INT_G_REGISTER: - { - struct v4l2_register *reg = arg; - int errCode; - - if (reg->i2c_id != 0) - return -EINVAL; - /* NT100x has a 8-bit register space */ - errCode = usbvision_read_reg(usbvision, reg->reg&0xff); - if (errCode < 0) { - err("%s: VIDIOC_INT_G_REGISTER failed: error %d", __FUNCTION__, errCode); - } - else { - reg->val=(unsigned char)errCode; - PDEBUG(DBG_IOCTL, "VIDIOC_INT_G_REGISTER reg=0x%02X, value=0x%02X", - (unsigned int)reg->reg, reg->val); - errCode = 0; // No error - } - return errCode; - } - case VIDIOC_INT_S_REGISTER: - { - struct v4l2_register *reg = arg; - int errCode; - - if (reg->i2c_id != 0) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val); - if (errCode < 0) { - err("%s: VIDIOC_INT_S_REGISTER failed: error %d", __FUNCTION__, errCode); - } - else { - PDEBUG(DBG_IOCTL, "VIDIOC_INT_S_REGISTER reg=0x%02X, value=0x%02X", - (unsigned int)reg->reg, reg->val); - errCode = 0; - } - return 0; - } -#endif - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *vc=arg; - - memset(vc, 0, sizeof(*vc)); - strlcpy(vc->driver, "USBVision", sizeof(vc->driver)); - strlcpy(vc->card, usbvision_device_data[usbvision->DevModel].ModelString, - sizeof(vc->card)); - strlcpy(vc->bus_info, usbvision->dev->dev.bus_id, - sizeof(vc->bus_info)); - vc->version = USBVISION_DRIVER_VERSION; - vc->capabilities = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_AUDIO | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - (dga ? (V4L2_FBUF_CAP_LIST_CLIPPING | V4L2_CAP_VIDEO_OVERLAY) : 0) | - (usbvision->have_tuner ? V4L2_CAP_TUNER : 0); - PDEBUG(DBG_IOCTL, "VIDIOC_QUERYCAP"); - return 0; - } - case VIDIOC_ENUMINPUT: - { - struct v4l2_input *vi = arg; - int chan; - - if ((vi->index >= usbvision->video_inputs) || (vi->index < 0) ) - return -EINVAL; - if (usbvision->have_tuner) { - chan = vi->index; - } - else { - chan = vi->index + 1; //skip Television string - } - switch(chan) { - case 0: - if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) { - strcpy(vi->name, "White Video Input"); - } - else { - strcpy(vi->name, "Television"); - vi->type = V4L2_INPUT_TYPE_TUNER; - vi->audioset = 1; - vi->tuner = chan; - vi->std = V4L2_STD_PAL | V4L2_STD_NTSC | V4L2_STD_SECAM; - } - break; - case 1: - vi->type = V4L2_INPUT_TYPE_CAMERA; - if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) { - strcpy(vi->name, "Green Video Input"); - } - else { - strcpy(vi->name, "Composite Video Input"); - } - vi->std = V4L2_STD_PAL; - break; - case 2: - vi->type = V4L2_INPUT_TYPE_CAMERA; - if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) { - strcpy(vi->name, "Yellow Video Input"); - } - else { - strcpy(vi->name, "S-Video Input"); - } - vi->std = V4L2_STD_PAL; - break; - case 3: - vi->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(vi->name, "Red Video Input"); - vi->std = V4L2_STD_PAL; - break; - } - PDEBUG(DBG_IOCTL, "VIDIOC_ENUMINPUT name=%s:%d tuners=%d type=%d norm=%x", vi->name, vi->index, vi->tuner,vi->type,(int)vi->std); - return 0; - } - case VIDIOC_ENUMSTD: - { - struct v4l2_standard *e = arg; - unsigned int i; - int ret; - - i = e->index; - if (i >= TVNORMS) - return -EINVAL; - ret = v4l2_video_std_construct(e, tvnorms[e->index].id, - tvnorms[e->index].name); - e->index = i; - if (ret < 0) - return ret; - return 0; - } - case VIDIOC_G_INPUT: - { - int *input = arg; - *input = usbvision->ctl_input; - return 0; - } - case VIDIOC_S_INPUT: - { - int *input = arg; - if ((*input >= usbvision->video_inputs) || (*input < 0) ) - return -EINVAL; - usbvision->ctl_input = *input; - - down(&usbvision->lock); - usbvision_muxsel(usbvision, usbvision->ctl_input); - usbvision_set_input(usbvision); - usbvision_set_output(usbvision, usbvision->curwidth, usbvision->curheight); - up(&usbvision->lock); - return 0; - } - case VIDIOC_G_STD: - { - v4l2_std_id *id = arg; - - *id = usbvision->tvnorm->id; - - PDEBUG(DBG_IOCTL, "VIDIOC_G_STD std_id=%s", usbvision->tvnorm->name); - return 0; - } - case VIDIOC_S_STD: - { - v4l2_std_id *id = arg; - unsigned int i; - - for (i = 0; i < TVNORMS; i++) - if (*id == tvnorms[i].id) - break; - if (i == TVNORMS) - for (i = 0; i < TVNORMS; i++) - if (*id & tvnorms[i].id) - break; - if (i == TVNORMS) - return -EINVAL; - - down(&usbvision->lock); - usbvision->tvnorm = &tvnorms[i]; - - call_i2c_clients(usbvision, VIDIOC_S_STD, - &usbvision->tvnorm->id); - - up(&usbvision->lock); - - PDEBUG(DBG_IOCTL, "VIDIOC_S_STD std_id=%s", usbvision->tvnorm->name); - return 0; - } - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *vt = arg; - - if (!usbvision->have_tuner || vt->index) // Only tuner 0 - return -EINVAL; - strcpy(vt->name, "Television"); - /* Let clients fill in the remainder of this struct */ - call_i2c_clients(usbvision,VIDIOC_G_TUNER,vt); - - PDEBUG(DBG_IOCTL, "VIDIOC_G_TUNER signal=%x, afc=%x",vt->signal,vt->afc); - return 0; - } - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *vt = arg; - - // Only no or one tuner for now - if (!usbvision->have_tuner || vt->index) - return -EINVAL; - /* let clients handle this */ - call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt); - - PDEBUG(DBG_IOCTL, "VIDIOC_S_TUNER"); - return 0; - } - case VIDIOC_G_FREQUENCY: - { - struct v4l2_frequency *freq = arg; - - freq->tuner = 0; // Only one tuner - freq->type = V4L2_TUNER_ANALOG_TV; - freq->frequency = usbvision->freq; - PDEBUG(DBG_IOCTL, "VIDIOC_G_FREQUENCY freq=0x%X", (unsigned)freq->frequency); - return 0; - } - case VIDIOC_S_FREQUENCY: - { - struct v4l2_frequency *freq = arg; - - // Only no or one tuner for now - if (!usbvision->have_tuner || freq->tuner) - return -EINVAL; - - usbvision->freq = freq->frequency; - call_i2c_clients(usbvision, cmd, freq); - PDEBUG(DBG_IOCTL, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)freq->frequency); - return 0; - } - case VIDIOC_G_AUDIO: - { - struct v4l2_audio *v = arg; - memset(v,0, sizeof(v)); - strcpy(v->name, "TV"); - PDEBUG(DBG_IOCTL, "VIDIOC_G_AUDIO"); - // FIXME: no more processings ??? - return 0; - } - case VIDIOC_S_AUDIO: - { - struct v4l2_audio *v = arg; - if(v->index) { - return -EINVAL; - } - PDEBUG(DBG_IOCTL, "VIDIOC_S_AUDIO"); - // FIXME: void function ??? - return 0; - } - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *ctrl = arg; - int id=ctrl->id; - - memset(ctrl,0,sizeof(*ctrl)); - ctrl->id=id; - - call_i2c_clients(usbvision, cmd, arg); - - if (ctrl->type) - return 0; - else - return -EINVAL; - - PDEBUG(DBG_IOCTL,"VIDIOC_QUERYCTRL id=%x value=%x",ctrl->id,ctrl->type); - } - case VIDIOC_G_CTRL: - { - struct v4l2_control *ctrl = arg; - - PDEBUG(DBG_IOCTL,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value); - call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl); - return 0; - } - case VIDIOC_S_CTRL: - { - struct v4l2_control *ctrl = arg; - - PDEBUG(DBG_IOCTL, "VIDIOC_S_CTRL id=%x value=%x",ctrl->id,ctrl->value); - call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl); - return 0; - } - case VIDIOC_REQBUFS: - { - struct v4l2_requestbuffers *vr = arg; - int ret; - - RESTRICT_TO_RANGE(vr->count,1,USBVISION_NUMFRAMES); - - // Check input validity : the user must do a VIDEO CAPTURE and MMAP method. - if((vr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) || - (vr->memory != V4L2_MEMORY_MMAP)) - return -EINVAL; - - // FIXME : before this, we must control if buffers are still mapped. - // Then interrupt streaming if so... - if(usbvision->streaming == Stream_On) { - if ((ret = usbvision_stream_interrupt(usbvision))) - return ret; - } - - usbvision_empty_framequeues(usbvision); - - usbvision->curFrame = NULL; - - PDEBUG(DBG_IOCTL, "VIDIOC_REQBUFS count=%d",vr->count); - return 0; - } - case VIDIOC_QUERYBUF: - { - struct v4l2_buffer *vb = arg; - struct usbvision_frame *frame; - - // FIXME : must control that buffers are mapped (VIDIOC_REQBUFS has been called) - - if(vb->type != V4L2_CAP_VIDEO_CAPTURE) { - return -EINVAL; - } - if(vb->index>=USBVISION_NUMFRAMES) { - return -EINVAL; - } - // Updating the corresponding frame state - vb->flags = 0; - frame = &usbvision->frame[vb->index]; - if(frame->grabstate >= FrameState_Ready) - vb->flags |= V4L2_BUF_FLAG_QUEUED; - if(frame->grabstate >= FrameState_Done) - vb->flags |= V4L2_BUF_FLAG_DONE; - if(frame->grabstate == FrameState_Unused) - vb->flags |= V4L2_BUF_FLAG_MAPPED; - vb->memory = V4L2_MEMORY_MMAP; - - vb->m.offset = vb->index*MAX_FRAME_SIZE; - - vb->memory = V4L2_MEMORY_MMAP; - vb->field = V4L2_FIELD_NONE; - vb->length = MAX_FRAME_SIZE; - vb->timestamp = usbvision->frame[vb->index].timestamp; - vb->sequence = usbvision->frame[vb->index].sequence; - return 0; - } - case VIDIOC_QBUF: - { - struct v4l2_buffer *vb = arg; - struct usbvision_frame *frame; - unsigned long lock_flags; - - // FIXME : works only on VIDEO_CAPTURE MODE, MMAP. - if(vb->type != V4L2_CAP_VIDEO_CAPTURE) { - return -EINVAL; - } - if(vb->index>=USBVISION_NUMFRAMES) { - return -EINVAL; - } - - frame = &usbvision->frame[vb->index]; - - if (frame->grabstate != FrameState_Unused) { - return -EAGAIN; - } - - /* Mark it as ready and enqueue frame */ - frame->grabstate = FrameState_Ready; - frame->scanstate = ScanState_Scanning; - frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */ - - vb->flags &= ~V4L2_BUF_FLAG_DONE; - - /* set v4l2_format index */ - frame->v4l2_format = usbvision->palette; - - spin_lock_irqsave(&usbvision->queue_lock, lock_flags); - list_add_tail(&usbvision->frame[vb->index].frame, &usbvision->inqueue); - spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); - - PDEBUG(DBG_IOCTL, "VIDIOC_QBUF frame #%d",vb->index); - return 0; - } - case VIDIOC_DQBUF: - { - struct v4l2_buffer *vb = arg; - int ret; - struct usbvision_frame *f; - unsigned long lock_flags; - - if (vb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (list_empty(&(usbvision->outqueue))) { - if (usbvision->streaming == Stream_Idle) - return -EINVAL; - ret = wait_event_interruptible - (usbvision->wait_frame, - !list_empty(&(usbvision->outqueue))); - if (ret) - return ret; - } - - spin_lock_irqsave(&usbvision->queue_lock, lock_flags); - f = list_entry(usbvision->outqueue.next, - struct usbvision_frame, frame); - list_del(usbvision->outqueue.next); - spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); - - f->grabstate = FrameState_Unused; - - vb->memory = V4L2_MEMORY_MMAP; - vb->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE; - vb->index = f->index; - vb->sequence = f->sequence; - vb->timestamp = f->timestamp; - vb->field = V4L2_FIELD_NONE; - vb->bytesused = f->scanlength; - - if(debug & DBG_IOCTL) { // do not spend computing time for debug stuff if not needed ! - if(usbvision_counter == 100) { - PDEBUG(DBG_IOCTL, "VIDIOC_DQBUF delta=%d",(unsigned)(jiffies-usbvision_timestamp)); - usbvision_counter = 0; - usbvision_timestamp = jiffies; - } - else { - usbvision_counter++; - } - PDEBUG(DBG_IOCTL, "VIDIOC_DQBUF frame #%d",vb->index); - } - return 0; - } - case VIDIOC_STREAMON: - { - int b=V4L2_BUF_TYPE_VIDEO_CAPTURE; - - usbvision->streaming = Stream_On; - - if(debug & DBG_IOCTL) usbvision_timestamp = jiffies; - - call_i2c_clients(usbvision,VIDIOC_STREAMON , &b); - - PDEBUG(DBG_IOCTL, "VIDIOC_STREAMON"); - - return 0; - } - case VIDIOC_STREAMOFF: - { - int *type = arg; - int b=V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if(usbvision->streaming == Stream_On) { - usbvision_stream_interrupt(usbvision); - // Stop all video streamings - call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b); - } - usbvision_empty_framequeues(usbvision); - - PDEBUG(DBG_IOCTL, "VIDIOC_STREAMOFF"); - return 0; - } - case VIDIOC_G_FBUF: - { - struct v4l2_framebuffer *vb = arg; - - if (dga) { - *vb = usbvision->vid_buf; - } - else { - memset(vb, 0, sizeof(vb)); //dga not supported, not used - } - PDEBUG(DBG_IOCTL, "VIDIOC_G_FBUF base=%p, width=%d, height=%d, pixelformat=%d, bpl=%d", - vb->base, vb->fmt.width, vb->fmt.height, vb->fmt.pixelformat,vb->fmt.bytesperline); - return 0; - } - case VIDIOC_S_FBUF: - { - struct v4l2_framebuffer *vb = arg; - int formatIdx; - - if (dga == 0) { - return -EINVAL; - } - - if(!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_ADMIN)) { - return -EPERM; - } - - PDEBUG(DBG_IOCTL, "VIDIOC_S_FBUF base=%p, width=%d, height=%d, pixelformat=%d, bpl=%d", - vb->base, vb->fmt.width, vb->fmt.height, vb->fmt.pixelformat,vb->fmt.bytesperline); - - for (formatIdx=0; formatIdx <= USBVISION_SUPPORTED_PALETTES; formatIdx++) { - if (formatIdx == USBVISION_SUPPORTED_PALETTES) { - return -EINVAL; // no matching video_format - } - if ((vb->fmt.pixelformat == usbvision_v4l2_format[formatIdx].format) && - (usbvision_v4l2_format[formatIdx].supported)) { - break; //found matching video_format - } - } - - if (vb->fmt.bytesperline<1) { - return -EINVAL; - } - if (usbvision->overlay) { - return -EBUSY; - } - down(&usbvision->lock); - if (usbvision->overlay_base) { - iounmap(usbvision->overlay_base); - usbvision->vid_buf_valid = 0; - } - usbvision->overlay_base = ioremap((ulong)vb->base, vb->fmt.height * vb->fmt.bytesperline); - if (usbvision->overlay_base) { - usbvision->vid_buf_valid = 1; - } - usbvision->vid_buf = *vb; - usbvision->overlay_frame.v4l2_format = usbvision_v4l2_format[formatIdx]; - up(&usbvision->lock); - return 0; - } - case VIDIOC_ENUM_FMT: - { - struct v4l2_fmtdesc *vfd = arg; - - if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) { - return -EINVAL; - } - vfd->flags = 0; - vfd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - strcpy(vfd->description,usbvision_v4l2_format[vfd->index].desc); - vfd->pixelformat = usbvision_v4l2_format[vfd->index].format; - memset(vfd->reserved, 0, sizeof(vfd->reserved)); - return 0; - } - case VIDIOC_G_FMT: - { - struct v4l2_format *vf = arg; - - switch (vf->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - { - vf->fmt.pix.width = usbvision->curwidth; - vf->fmt.pix.height = usbvision->curheight; - vf->fmt.pix.pixelformat = usbvision->palette.format; - vf->fmt.pix.bytesperline = usbvision->curwidth*usbvision->palette.bytes_per_pixel; - vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*usbvision->curheight; - vf->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - vf->fmt.pix.field = V4L2_FIELD_NONE; /* Always progressive image */ - } - return 0; - default: - PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT invalid type %d",vf->type); - return -EINVAL; - } - PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT w=%d, h=%d",vf->fmt.win.w.width, vf->fmt.win.w.height); - return 0; - } - case VIDIOC_TRY_FMT: - case VIDIOC_S_FMT: - { - struct v4l2_format *vf = arg; - struct v4l2_clip *vc=NULL; - int on,formatIdx; - - switch(vf->type) { - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - { - if (vf->fmt.win.clipcount>256) { - return -EDOM; /* Too many clips! */ - } - // Do every clips. - vc = vmalloc(sizeof(struct v4l2_clip)*(vf->fmt.win.clipcount+4)); - if (vc == NULL) { - return -ENOMEM; - } - if (vf->fmt.win.clipcount && copy_from_user(vc,vf->fmt.win.clips,sizeof(struct v4l2_clip)*vf->fmt.win.clipcount)) { - return -EFAULT; - } - on = usbvision->overlay; // Save overlay state - if (on) { - usbvision_cap(usbvision, 0); - } - - // strange, it seems xawtv sometimes calls us with 0 - // width and/or height. Ignore these values - if (vf->fmt.win.w.left == 0) { - vf->fmt.win.w.left = usbvision->vid_win.fmt.win.w.left; - } - if (vf->fmt.win.w.top == 0) { - vf->fmt.win.w.top = usbvision->vid_win.fmt.win.w.top; - } - - // by now we are committed to the new data... - down(&usbvision->lock); - RESTRICT_TO_RANGE(vf->fmt.win.w.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH); - RESTRICT_TO_RANGE(vf->fmt.win.w.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT); - usbvision->vid_win = *vf; - usbvision->overlay_frame.width = vf->fmt.win.w.width; - usbvision->overlay_frame.height = vf->fmt.win.w.height; - usbvision_set_output(usbvision, vf->fmt.win.w.width, vf->fmt.win.w.height); - up(&usbvision->lock); - - // Impose display clips - if (vf->fmt.win.w.left+vf->fmt.win.w.width > (unsigned int)usbvision->vid_buf.fmt.width) { - usbvision_new_clip(vf, vc, usbvision->vid_buf.fmt.width-vf->fmt.win.w.left, 0, vf->fmt.win.w.width-1, vf->fmt.win.w.height-1); - } - if (vf->fmt.win.w.top+vf->fmt.win.w.height > (unsigned int)usbvision->vid_buf.fmt.height) { - usbvision_new_clip(vf, vc, 0, usbvision->vid_buf.fmt.height-vf->fmt.win.w.top, vf->fmt.win.w.width-1, vf->fmt.win.w.height-1); - } - - // built the requested clipping zones - usbvision_built_overlay(usbvision, vf->fmt.win.clipcount, vc); - vfree(vc); - - // restore overlay state - if (on) { - usbvision_cap(usbvision, 1); - } - usbvision->vid_win_valid = 1; - PDEBUG(DBG_IOCTL, "VIDIOC_S_FMT overlay x=%d, y=%d, w=%d, h=%d, chroma=%x, clips=%d", - vf->fmt.win.w.left, vf->fmt.win.w.top, vf->fmt.win.w.width, vf->fmt.win.w.height, vf->fmt.win.chromakey, vf->fmt.win.clipcount); - return 0; - } - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - { - /* Find requested format in available ones */ - for(formatIdx=0;formatIdxfmt.pix.pixelformat == usbvision_v4l2_format[formatIdx].format) { - usbvision->palette = usbvision_v4l2_format[formatIdx]; - break; - } - } - /* robustness */ - if(formatIdx == USBVISION_SUPPORTED_PALETTES) { - return -EINVAL; - } - RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH); - RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT); - // by now we are committed to the new data... - down(&usbvision->lock); - usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height); - up(&usbvision->lock); - - PDEBUG(DBG_IOCTL, "VIDIOC_S_FMT grabdisplay w=%d, h=%d, format=%s", - vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc); - return 0; - } - default: - return -EINVAL; - } - } - case VIDIOC_OVERLAY: - { - int *v = arg; - - if ( (dga == 0) && - (usbvision->palette.format != V4L2_PIX_FMT_YVU420) && - (usbvision->palette.format != V4L2_PIX_FMT_YUV422P) ) { - PDEBUG(DBG_IOCTL, "VIDIOC_OVERLAY DGA disabled"); - return -EINVAL; - } - - if (*v == 0) { - usbvision_cap(usbvision, 0); - } - else { - // are VIDIOCSFBUF and VIDIOCSWIN done? - if ((usbvision->vid_buf_valid == 0) || (usbvision->vid_win_valid == 0)) { - PDEBUG(DBG_IOCTL, "VIDIOC_OVERLAY vid_buf_valid %d; vid_win_valid %d", - usbvision->vid_buf_valid, usbvision->vid_win_valid); - return -EINVAL; - } - usbvision_cap(usbvision, 1); - } - PDEBUG(DBG_IOCTL, "VIDIOC_OVERLAY %s", (*v)?"on":"off"); - return 0; - } - default: - return -ENOIOCTLCMD; - } - return 0; -} - -static int usbvision_v4l2_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return video_usercopy(inode, file, cmd, arg, usbvision_v4l2_do_ioctl); -} - - -static ssize_t usbvision_v4l2_read(struct file *file, char *buf, - size_t count, loff_t *ppos) -{ - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); - int noblock = file->f_flags & O_NONBLOCK; - unsigned long lock_flags; - - int frmx = -1; - int ret,i; - struct usbvision_frame *frame; - - PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __FUNCTION__, (unsigned long)count, noblock); - - if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL)) - return -EFAULT; - - /* no stream is running, make it running ! */ - usbvision->streaming = Stream_On; - call_i2c_clients(usbvision,VIDIOC_STREAMON , NULL); - - /* First, enqueue as many frames as possible (like a user of VIDIOC_QBUF would do) */ - for(i=0;iframe[i]; - if(frame->grabstate == FrameState_Unused) { - /* Mark it as ready and enqueue frame */ - frame->grabstate = FrameState_Ready; - frame->scanstate = ScanState_Scanning; - frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */ - - /* set v4l2_format index */ - frame->v4l2_format = usbvision->palette; - - spin_lock_irqsave(&usbvision->queue_lock, lock_flags); - list_add_tail(&frame->frame, &usbvision->inqueue); - spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); - } - } - - /* Then try to steal a frame (like a VIDIOC_DQBUF would do) */ - if (list_empty(&(usbvision->outqueue))) { - if(noblock) - return -EAGAIN; - - ret = wait_event_interruptible - (usbvision->wait_frame, - !list_empty(&(usbvision->outqueue))); - if (ret) - return ret; - } - - spin_lock_irqsave(&usbvision->queue_lock, lock_flags); - frame = list_entry(usbvision->outqueue.next, - struct usbvision_frame, frame); - list_del(usbvision->outqueue.next); - spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); - - if(debug & DBG_IOCTL) { // do not spend computing time for debug stuff if not needed ! - if(usbvision_counter == 100) { - PDEBUG(DBG_IOCTL, "VIDIOC_DQBUF delta=%d",(unsigned)(jiffies-usbvision_timestamp)); - usbvision_counter = 0; - usbvision_timestamp = jiffies; - } - else { - usbvision_counter++; - } - } - - /* An error returns an empty frame */ - if (frame->grabstate == FrameState_Error) { - frame->bytes_read = 0; - return 0; - } - - PDEBUG(DBG_IO, "%s: frmx=%d, bytes_read=%ld, scanlength=%ld", __FUNCTION__, - frame->index, frame->bytes_read, frame->scanlength); - - /* copy bytes to user space; we allow for partials reads */ - if ((count + frame->bytes_read) > (unsigned long)frame->scanlength) - count = frame->scanlength - frame->bytes_read; - - if (copy_to_user(buf, frame->data + frame->bytes_read, count)) { - return -EFAULT; - } - - frame->bytes_read += count; - PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld", __FUNCTION__, - (unsigned long)count, frame->bytes_read); - - // For now, forget the frame if it has not been read in one shot. -/* if (frame->bytes_read >= frame->scanlength) {// All data has been read */ - frame->bytes_read = 0; - - /* Mark it as available to be used again. */ - usbvision->frame[frmx].grabstate = FrameState_Unused; -/* } */ - - return count; -} - -static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) -{ - unsigned long size = vma->vm_end - vma->vm_start, - start = vma->vm_start; - void *pos; - u32 i; - - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); - - if (!USBVISION_IS_OPERATIONAL(usbvision)) - return -EFAULT; - - if (!(vma->vm_flags & VM_WRITE) || - size != PAGE_ALIGN(usbvision->max_frame_size)) { - return -EINVAL; - } - - for (i = 0; i < USBVISION_NUMFRAMES; i++) { - if (((usbvision->max_frame_size*i) >> PAGE_SHIFT) == vma->vm_pgoff) - break; - } - if (i == USBVISION_NUMFRAMES) { - PDEBUG(DBG_FUNC, "mmap: user supplied mapping address is out of range"); - return -EINVAL; - } - - /* VM_IO is eventually going to replace PageReserved altogether */ - vma->vm_flags |= VM_IO; - vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */ - - pos = usbvision->frame[i].data; - while (size > 0) { - - if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { - PDEBUG(DBG_FUNC, "mmap: vm_insert_page failed"); - return -EAGAIN; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - size -= PAGE_SIZE; - } - - return 0; -} - - -/* - * Here comes the stuff for radio on usbvision based devices - * - */ -static int usbvision_radio_open(struct inode *inode, struct file *file) -{ - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); - struct v4l2_frequency freq; - int errCode = 0; - - PDEBUG(DBG_RIO, "%s:", __FUNCTION__); - - down(&usbvision->lock); - - if (usbvision->user) { - err("%s: Someone tried to open an already opened USBVision Radio!", __FUNCTION__); - errCode = -EBUSY; - } - else { - if(PowerOnAtOpen) { - if (timer_pending(&usbvision->powerOffTimer)) { - del_timer(&usbvision->powerOffTimer); - } - if (usbvision->power == 0) { - usbvision_power_on(usbvision); - usbvision_init_i2c(usbvision); - } - } - - // If so far no errors then we shall start the radio - usbvision->radio = 1; - call_i2c_clients(usbvision,AUDC_SET_RADIO,&usbvision->tuner_type); - freq.frequency = 1517; //SWR3 @ 94.8MHz - call_i2c_clients(usbvision, VIDIOC_S_FREQUENCY, &freq); - usbvision_set_audio(usbvision, USBVISION_AUDIO_RADIO); - usbvision->user++; - } - - if (errCode) { - if (PowerOnAtOpen) { - usbvision_i2c_usb_del_bus(&usbvision->i2c_adap); - usbvision_power_off(usbvision); - usbvision->initialized = 0; - } - } - up(&usbvision->lock); - return errCode; -} - - -static int usbvision_radio_close(struct inode *inode, struct file *file) -{ - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); - int errCode = 0; - - PDEBUG(DBG_RIO, ""); - - down(&usbvision->lock); - - usbvision_audio_off(usbvision); - usbvision->radio=0; - usbvision->user--; - - if (PowerOnAtOpen) { - mod_timer(&usbvision->powerOffTimer, jiffies + USBVISION_POWEROFF_TIME); - usbvision->initialized = 0; - } - - up(&usbvision->lock); - - if (usbvision->remove_pending) { - info("%s: Final disconnect", __FUNCTION__); - usbvision_release(usbvision); - } - - - PDEBUG(DBG_RIO, "success"); - - return errCode; -} - -static int usbvision_do_radio_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) -{ - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); - - if (!USBVISION_IS_OPERATIONAL(usbvision)) - return -EIO; - - switch (cmd) { - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *vc=arg; - - memset(vc, 0, sizeof(*vc)); - strlcpy(vc->driver, "USBVision", sizeof(vc->driver)); - strlcpy(vc->card, usbvision_device_data[usbvision->DevModel].ModelString, - sizeof(vc->card)); - strlcpy(vc->bus_info, usbvision->dev->dev.bus_id, - sizeof(vc->bus_info)); - vc->version = USBVISION_DRIVER_VERSION; - vc->capabilities = (usbvision->have_tuner ? V4L2_CAP_TUNER : 0); - PDEBUG(DBG_RIO, "VIDIOC_QUERYCAP"); - return 0; - } - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *ctrl = arg; - int id=ctrl->id; - - memset(ctrl,0,sizeof(*ctrl)); - ctrl->id=id; - - call_i2c_clients(usbvision, cmd, arg); - PDEBUG(DBG_RIO,"VIDIOC_QUERYCTRL id=%x value=%x",ctrl->id,ctrl->type); - - if (ctrl->type) - return 0; - else - return -EINVAL; - - } - case VIDIOC_G_CTRL: - { - struct v4l2_control *ctrl = arg; - - call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl); - PDEBUG(DBG_RIO,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value); - return 0; - } - case VIDIOC_S_CTRL: - { - struct v4l2_control *ctrl = arg; - - call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl); - PDEBUG(DBG_RIO, "VIDIOC_S_CTRL id=%x value=%x",ctrl->id,ctrl->value); - return 0; - } - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *t = arg; - - if (t->index > 0) - return -EINVAL; - - memset(t,0,sizeof(*t)); - strcpy(t->name, "Radio"); - t->type = V4L2_TUNER_RADIO; - - /* Let clients fill in the remainder of this struct */ - call_i2c_clients(usbvision,VIDIOC_G_TUNER,t); - PDEBUG(DBG_RIO, "VIDIOC_G_TUNER signal=%x, afc=%x",t->signal,t->afc); - return 0; - } - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *vt = arg; - - // Only no or one tuner for now - if (!usbvision->have_tuner || vt->index) - return -EINVAL; - /* let clients handle this */ - call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt); - - PDEBUG(DBG_RIO, "VIDIOC_S_TUNER"); - return 0; - } - case VIDIOC_G_AUDIO: - { - struct v4l2_audio *a = arg; - - memset(a,0,sizeof(*a)); - strcpy(a->name,"Radio"); - PDEBUG(DBG_RIO, "VIDIOC_G_AUDIO"); - return 0; - } - case VIDIOC_S_AUDIO: - case VIDIOC_S_INPUT: - case VIDIOC_S_STD: - return 0; - - case VIDIOC_G_FREQUENCY: - { - struct v4l2_frequency *f = arg; - - memset(f,0,sizeof(*f)); - - f->type = V4L2_TUNER_RADIO; - f->frequency = usbvision->freq; - call_i2c_clients(usbvision, cmd, f); - PDEBUG(DBG_RIO, "VIDIOC_G_FREQUENCY freq=0x%X", (unsigned)f->frequency); - - return 0; - } - case VIDIOC_S_FREQUENCY: - { - struct v4l2_frequency *f = arg; - - if (f->tuner != 0) - return -EINVAL; - usbvision->freq = f->frequency; - call_i2c_clients(usbvision, cmd, f); - PDEBUG(DBG_RIO, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)f->frequency); - - return 0; - } - default: - { - PDEBUG(DBG_RIO, "%s: Unknown command %x", __FUNCTION__, cmd); - return -ENOIOCTLCMD; - } - } - return 0; -} - - -static int usbvision_radio_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return video_usercopy(inode, file, cmd, arg, usbvision_do_radio_ioctl); -} - - -/* - * Here comes the stuff for vbi on usbvision based devices - * - */ -static int usbvision_vbi_open(struct inode *inode, struct file *file) -{ - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); - unsigned long freq; - int errCode = 0; - - PDEBUG(DBG_RIO, "%s:", __FUNCTION__); - - down(&usbvision->lock); - - if (usbvision->user) { - err("%s: Someone tried to open an already opened USBVision VBI!", __FUNCTION__); - errCode = -EBUSY; - } - else { - if(PowerOnAtOpen) { - if (timer_pending(&usbvision->powerOffTimer)) { - del_timer(&usbvision->powerOffTimer); - } - if (usbvision->power == 0) { - usbvision_power_on(usbvision); - usbvision_init_i2c(usbvision); - } - } - - // If so far no errors then we shall start the vbi device - //usbvision->vbi = 1; - call_i2c_clients(usbvision,AUDC_SET_RADIO,&usbvision->tuner_type); - freq = 1517; //SWR3 @ 94.8MHz - call_i2c_clients(usbvision, VIDIOC_S_FREQUENCY, &freq); - usbvision_set_audio(usbvision, USBVISION_AUDIO_RADIO); - usbvision->user++; - } - - if (errCode) { - if (PowerOnAtOpen) { - usbvision_i2c_usb_del_bus(&usbvision->i2c_adap); - usbvision_power_off(usbvision); - usbvision->initialized = 0; - } - } - up(&usbvision->lock); - return errCode; -} - -static int usbvision_vbi_close(struct inode *inode, struct file *file) -{ - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); - int errCode = 0; - - PDEBUG(DBG_RIO, ""); - - down(&usbvision->lock); - - usbvision_audio_off(usbvision); - usbvision->vbi=0; - usbvision->user--; - - if (PowerOnAtOpen) { - mod_timer(&usbvision->powerOffTimer, jiffies + USBVISION_POWEROFF_TIME); - usbvision->initialized = 0; - } - - up(&usbvision->lock); - - if (usbvision->remove_pending) { - info("%s: Final disconnect", __FUNCTION__); - usbvision_release(usbvision); - } - - - PDEBUG(DBG_RIO, "success"); - - return errCode; -} - -static int usbvision_do_vbi_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) -{ - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); - - if (!USBVISION_IS_OPERATIONAL(usbvision)) - return -EIO; - - switch (cmd) { - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *vc=arg; - memset(vc, 0, sizeof(struct v4l2_capability)); - strcpy(vc->driver,"usbvision vbi"); - strcpy(vc->card,usbvision->vcap.card); - strcpy(vc->bus_info,"usb"); - vc->version = USBVISION_DRIVER_VERSION; /* version */ - vc->capabilities = V4L2_CAP_VBI_CAPTURE; /* capabilities */ - PDEBUG(DBG_RIO, "%s: VIDIOC_QUERYCAP", __FUNCTION__); - return 0; - } - case VIDIOCGTUNER: - { - struct video_tuner *vt = arg; - - if((vt->tuner) || (usbvision->channel)) { /* Only tuner 0 */ - return -EINVAL; - } - strcpy(vt->name, "vbi"); - // japan: 76.0 MHz - 89.9 MHz - // western europe: 87.5 MHz - 108.0 MHz - // russia: 65.0 MHz - 108.0 MHz - vt->rangelow=(int)(65*16); - vt->rangehigh=(int)(108*16); - vt->flags= 0; - vt->mode = 0; - call_i2c_clients(usbvision,cmd,vt); - PDEBUG(DBG_RIO, "%s: VIDIOCGTUNER signal=%d", __FUNCTION__, vt->signal); - return 0; - } - case VIDIOCSTUNER: - { - struct video_tuner *vt = arg; - - // Only channel 0 has a tuner - if((vt->tuner) || (usbvision->channel)) { - return -EINVAL; - } - PDEBUG(DBG_RIO, "%s: VIDIOCSTUNER", __FUNCTION__); - return 0; - } - case VIDIOCGAUDIO: - { - struct video_audio *va = arg; - memset(va,0, sizeof(struct video_audio)); - call_i2c_clients(usbvision, cmd, va); - va->flags|=VIDEO_AUDIO_MUTABLE; - va->volume=1; - va->step=1; - strcpy(va->name, "vbi"); - PDEBUG(DBG_RIO, "%s: VIDIOCGAUDIO", __FUNCTION__); - return 0; - } - case VIDIOCSAUDIO: - { - struct video_audio *va = arg; - if(va->audio) { - return -EINVAL; - } - - if(va->flags & VIDEO_AUDIO_MUTE) { - if (usbvision_audio_mute(usbvision)) { - return -EFAULT; - } - } - else { - if (usbvision_audio_on(usbvision)) { - return -EFAULT; - } - } - PDEBUG(DBG_RIO, "%s: VIDIOCSAUDIO flags=0x%x)", __FUNCTION__, va->flags); - return 0; - } - case VIDIOCGFREQ: - { - unsigned long *freq = arg; - - *freq = usbvision->freq; - PDEBUG(DBG_RIO, "%s: VIDIOCGFREQ freq = %ld00 kHz", __FUNCTION__, (*freq * 10)>>4); - return 0; - } - case VIDIOCSFREQ: - { - unsigned long *freq = arg; - - usbvision->freq = *freq; - call_i2c_clients(usbvision, cmd, freq); - PDEBUG(DBG_RIO, "%s: VIDIOCSFREQ freq = %ld00 kHz", __FUNCTION__, (*freq * 10)>>4); - return 0; - } - default: - { - PDEBUG(DBG_RIO, "%s: Unknown command %d", __FUNCTION__, cmd); - return -ENOIOCTLCMD; - } - } - return 0; -} - -static int usbvision_vbi_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return video_usercopy(inode, file, cmd, arg, usbvision_do_vbi_ioctl); -} - - - -static void usbvision_configure_video(struct usb_usbvision *usbvision) -{ - int model,i; - - if (usbvision == NULL) - return; - - model = usbvision->DevModel; - usbvision->depth = 24; - usbvision->palette = usbvision_v4l2_format[2]; // V4L2_PIX_FMT_RGB24; - - if (usbvision_device_data[usbvision->DevModel].Vin_Reg2 >= 0) { - usbvision->Vin_Reg2_Preset = usbvision_device_data[usbvision->DevModel].Vin_Reg2 & 0xff; - } else { - usbvision->Vin_Reg2_Preset = 0; - } - - memset(&usbvision->vcap, 0, sizeof(usbvision->vcap)); - strcpy(usbvision->vcap.driver, "USBVision"); - strlcpy(usbvision->vcap.bus_info, usbvision->dev->dev.bus_id, - sizeof(usbvision->vcap.bus_info)); - usbvision->vcap.capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | - (dga ? (V4L2_FBUF_CAP_LIST_CLIPPING | V4L2_CAP_VIDEO_OVERLAY) : 0) | - (usbvision->have_tuner ? V4L2_CAP_TUNER : 0); - usbvision->vcap.version = USBVISION_DRIVER_VERSION; /* version */ - - for (i = 0; i < TVNORMS; i++) - if (usbvision_device_data[model].VideoNorm == tvnorms[i].mode) - break; - if (i == TVNORMS) - i = 0; - usbvision->tvnorm = &tvnorms[i]; /* set default norm */ - - usbvision->video_inputs = usbvision_device_data[model].VideoChannels; - usbvision->ctl_input = 0; - - /* This should be here to make i2c clients to be able to register */ - usbvision_audio_off(usbvision); //first switch off audio - if (!PowerOnAtOpen) { - usbvision_power_on(usbvision); //and then power up the noisy tuner - usbvision_init_i2c(usbvision); - } -} - -// -// Video registration stuff -// - -// Video template -static struct file_operations usbvision_fops = { - #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31) - .owner = THIS_MODULE, - #endif - .open = usbvision_v4l2_open, - .release = usbvision_v4l2_close, - .read = usbvision_v4l2_read, - .mmap = usbvision_v4l2_mmap, - .ioctl = usbvision_v4l2_ioctl, - .llseek = no_llseek, -}; -static struct video_device usbvision_video_template = { - #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31) - .owner = THIS_MODULE, - #endif - .type = VID_TYPE_TUNER | VID_TYPE_CAPTURE, - .hardware = VID_HARDWARE_USBVISION, - .fops = &usbvision_fops, - #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) - .name = "usbvision-video", - .release = video_device_release, - #endif - .minor = -1, -}; - - -// Radio template -static struct file_operations usbvision_radio_fops = { - #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31) - .owner = THIS_MODULE, - #endif - .open = usbvision_radio_open, - .release = usbvision_radio_close, - .ioctl = usbvision_radio_ioctl, - .llseek = no_llseek, -}; - -static struct video_device usbvision_radio_template= -{ - #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31) - .owner = THIS_MODULE, - #endif - .type = VID_TYPE_TUNER, - .hardware = VID_HARDWARE_USBVISION, - .fops = &usbvision_radio_fops, - #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) - .release = video_device_release, - .name = "usbvision-radio", - #endif - .minor = -1, -}; - - -// vbi template -static struct file_operations usbvision_vbi_fops = { - #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31) - .owner = THIS_MODULE, - #endif - .open = usbvision_vbi_open, - .release = usbvision_vbi_close, - .ioctl = usbvision_vbi_ioctl, - .llseek = no_llseek, -}; - -static struct video_device usbvision_vbi_template= -{ - #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31) - .owner = THIS_MODULE, - #endif - .type = VID_TYPE_TUNER, - .hardware = VID_HARDWARE_USBVISION, - .fops = &usbvision_vbi_fops, - #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) - .release = video_device_release, - .name = "usbvision-vbi", - #endif - .minor = -1, -}; - - -static struct video_device *usbvision_vdev_init(struct usb_usbvision *usbvision, - struct video_device *vdev_template, - char *name) -{ - struct usb_device *usb_dev = usbvision->dev; - struct video_device *vdev; - - if (usb_dev == NULL) { - err("%s: usbvision->dev is not set", __FUNCTION__); - return NULL; - } - - vdev = video_device_alloc(); - if (NULL == vdev) { - return NULL; - } - *vdev = *vdev_template; -// vdev->minor = -1; - vdev->dev = &usb_dev->dev; - snprintf(vdev->name, sizeof(vdev->name), "%s", name); - video_set_drvdata(vdev, usbvision); - return vdev; -} - -// unregister video4linux devices -static void usbvision_unregister_video(struct usb_usbvision *usbvision) -{ - // vbi Device: - if (usbvision->vbi) { - PDEBUG(DBG_PROBE, "unregister /dev/vbi%d [v4l2]", usbvision->vbi->minor & 0x1f); - if (usbvision->vbi->minor != -1) { - video_unregister_device(usbvision->vbi); - } - else { - video_device_release(usbvision->vbi); - } - usbvision->vbi = NULL; - } - - // Radio Device: - if (usbvision->rdev) { - PDEBUG(DBG_PROBE, "unregister /dev/radio%d [v4l2]", usbvision->rdev->minor & 0x1f); - if (usbvision->rdev->minor != -1) { - video_unregister_device(usbvision->rdev); - } - else { - video_device_release(usbvision->rdev); - } - usbvision->rdev = NULL; - } - - // Video Device: - if (usbvision->vdev) { - PDEBUG(DBG_PROBE, "unregister /dev/video%d [v4l2]", usbvision->vdev->minor & 0x1f); - if (usbvision->vdev->minor != -1) { - video_unregister_device(usbvision->vdev); - } - else { - video_device_release(usbvision->vdev); - } - usbvision->vdev = NULL; - } -} - -// register video4linux devices -static int __devinit usbvision_register_video(struct usb_usbvision *usbvision) -{ - // Video Device: - usbvision->vdev = usbvision_vdev_init(usbvision, &usbvision_video_template, "USBVision Video"); - if (usbvision->vdev == NULL) { - goto err_exit; - } - if (video_register_device(usbvision->vdev, VFL_TYPE_GRABBER, video_nr)<0) { - goto err_exit; - } - info("USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]", usbvision->nr,usbvision->vdev->minor & 0x1f); - - // Radio Device: - if (usbvision_device_data[usbvision->DevModel].Radio) { - // usbvision has radio - usbvision->rdev = usbvision_vdev_init(usbvision, &usbvision_radio_template, "USBVision Radio"); - if (usbvision->rdev == NULL) { - goto err_exit; - } - if (video_register_device(usbvision->rdev, VFL_TYPE_RADIO, radio_nr)<0) { - goto err_exit; - } - info("USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]", usbvision->nr, usbvision->rdev->minor & 0x1f); - } - // vbi Device: - if (usbvision_device_data[usbvision->DevModel].vbi) { - usbvision->vbi = usbvision_vdev_init(usbvision, &usbvision_vbi_template, "USBVision VBI"); - if (usbvision->vdev == NULL) { - goto err_exit; - } - if (video_register_device(usbvision->vbi, VFL_TYPE_VBI, vbi_nr)<0) { - goto err_exit; - } - info("USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)", usbvision->nr,usbvision->vbi->minor & 0x1f); - } - // all done - return 0; - - err_exit: - err("USBVision[%d]: video_register_device() failed", usbvision->nr); - usbvision_unregister_video(usbvision); - return -1; -} - -/* - * usbvision_alloc() - * - * This code allocates the struct usb_usbvision. It is filled with default values. - * - * Returns NULL on error, a pointer to usb_usbvision else. - * - */ -static struct usb_usbvision *usbvision_alloc(struct usb_device *dev) -{ - struct usb_usbvision *usbvision; - - if ((usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL)) == NULL) { - goto err_exit; - } - - usbvision->dev = dev; - - init_MUTEX(&usbvision->lock); /* to 1 == available */ - - // prepare control urb for control messages during interrupts - usbvision->ctrlUrb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL); - if (usbvision->ctrlUrb == NULL) { - goto err_exit; - } - init_waitqueue_head(&usbvision->ctrlUrb_wq); - init_MUTEX(&usbvision->ctrlUrbLock); /* to 1 == available */ - - init_timer(&usbvision->powerOffTimer); - usbvision->powerOffTimer.data = (long) usbvision; - usbvision->powerOffTimer.function = usbvision_powerOffTimer; - - return usbvision; - -err_exit: - if (usbvision && usbvision->ctrlUrb) { - usb_free_urb(usbvision->ctrlUrb); - } - if (usbvision) { - kfree(usbvision); - } - return NULL; -} - -/* - * usbvision_release() - * - * This code does final release of struct usb_usbvision. This happens - * after the device is disconnected -and- all clients closed their files. - * - */ -static void usbvision_release(struct usb_usbvision *usbvision) -{ - PDEBUG(DBG_PROBE, ""); - - down(&usbvision->lock); - - if (timer_pending(&usbvision->powerOffTimer)) { - del_timer(&usbvision->powerOffTimer); - } - - usbvision->usbvision_used = 0; - usbvision->initialized = 0; - - up(&usbvision->lock); - - usbvision_remove_sysfs(usbvision->vdev); - usbvision_unregister_video(usbvision); - if(dga) { - if (usbvision->overlay_base) { - iounmap(usbvision->overlay_base); - } - } - - if (usbvision->ctrlUrb) { - usb_free_urb(usbvision->ctrlUrb); - } - - kfree(usbvision); - - PDEBUG(DBG_PROBE, "success"); -} - - -/* - * usbvision_probe() - * - * This procedure queries device descriptor and accepts the interface - * if it looks like USBVISION video device - * - */ -static int __devinit usbvision_probe(struct usb_interface *intf, const struct usb_device_id *devid) -{ - struct usb_device *dev = interface_to_usbdev(intf); - __u8 ifnum = intf->altsetting->desc.bInterfaceNumber; - const struct usb_host_interface *interface; - struct usb_usbvision *usbvision = NULL; - const struct usb_endpoint_descriptor *endpoint; - int model; - - PDEBUG(DBG_PROBE, "VID=%#04x, PID=%#04x, ifnum=%u", - dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum); - /* Is it an USBVISION video dev? */ - model = 0; - for(model = 0; usbvision_device_data[model].idVendor; model++) { - if (le16_to_cpu(dev->descriptor.idVendor) != usbvision_device_data[model].idVendor) { - continue; - } - if (le16_to_cpu(dev->descriptor.idProduct) != usbvision_device_data[model].idProduct) { - continue; - } - - info("%s: %s found", __FUNCTION__, usbvision_device_data[model].ModelString); - break; - } - - if (usbvision_device_data[model].idVendor == 0) { - return -ENODEV; //no matching device - } - if (usbvision_device_data[model].Interface >= 0) { - interface = &dev->actconfig->interface[usbvision_device_data[model].Interface]->altsetting[0]; - } - else { - interface = &dev->actconfig->interface[ifnum]->altsetting[0]; - } - endpoint = &interface->endpoint[1].desc; - if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC) { - err("%s: interface %d. has non-ISO endpoint!", __FUNCTION__, ifnum); - err("%s: Endpoint attribures %d", __FUNCTION__, endpoint->bmAttributes); - return -ENODEV; - } - if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) { - err("%s: interface %d. has ISO OUT endpoint!", __FUNCTION__, ifnum); - return -ENODEV; - } - - usb_get_dev(dev); - - if ((usbvision = usbvision_alloc(dev)) == NULL) { - err("%s: couldn't allocate USBVision struct", __FUNCTION__); - return -ENOMEM; - } - if (dev->descriptor.bNumConfigurations > 1) { - usbvision->bridgeType = BRIDGE_NT1004; - } - else if (usbvision_device_data[model].ModelString == "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)") { - usbvision->bridgeType = BRIDGE_NT1005; - } - else { - usbvision->bridgeType = BRIDGE_NT1003; - } - PDEBUG(DBG_PROBE, "bridgeType %d", usbvision->bridgeType); - - down(&usbvision->lock); - - usbvision->nr = usbvision_nr++; - - usbvision->have_tuner = usbvision_device_data[model].Tuner; - if (usbvision->have_tuner) { - usbvision->tuner_type = usbvision_device_data[model].TunerType; - } - - usbvision->tuner_addr = ADDR_UNSET; - - usbvision->DevModel = model; - usbvision->remove_pending = 0; - usbvision->last_error = 0; - usbvision->iface = ifnum; - usbvision->ifaceAltInactive = 0; - usbvision->ifaceAltActive = 1; - usbvision->video_endp = endpoint->bEndpointAddress; - usbvision->isocPacketSize = 0; - usbvision->usb_bandwidth = 0; - usbvision->user = 0; - usbvision->streaming = Stream_Off; - usbvision_register_video(usbvision); - usbvision_configure_video(usbvision); - up(&usbvision->lock); - - - usb_set_intfdata (intf, usbvision); - usbvision_create_sysfs(usbvision->vdev); - - PDEBUG(DBG_PROBE, "success"); - return 0; -} - - -/* - * usbvision_disconnect() - * - * This procedure stops all driver activity, deallocates interface-private - * structure (pointed by 'ptr') and after that driver should be removable - * with no ill consequences. - * - */ -static void __devexit usbvision_disconnect(struct usb_interface *intf) -{ - struct usb_usbvision *usbvision = usb_get_intfdata(intf); - - PDEBUG(DBG_PROBE, ""); - - if (usbvision == NULL) { - err("%s: usb_get_intfdata() failed", __FUNCTION__); - return; - } - usb_set_intfdata (intf, NULL); - - down(&usbvision->lock); - - // At this time we ask to cancel outstanding URBs - usbvision_stop_isoc(usbvision); - - if (usbvision->power) { - usbvision_i2c_usb_del_bus(&usbvision->i2c_adap); - usbvision_power_off(usbvision); - } - usbvision->remove_pending = 1; // Now all ISO data will be ignored - - usb_put_dev(usbvision->dev); - usbvision->dev = NULL; // USB device is no more - - up(&usbvision->lock); - - if (usbvision->user) { - info("%s: In use, disconnect pending", __FUNCTION__); - wake_up_interruptible(&usbvision->wait_frame); - wake_up_interruptible(&usbvision->wait_stream); - } - else { - usbvision_release(usbvision); - } - - PDEBUG(DBG_PROBE, "success"); - -} - -static struct usb_driver usbvision_driver = { - .name = "usbvision", - .id_table = usbvision_table, - .probe = usbvision_probe, - .disconnect = usbvision_disconnect -}; - -/* - * customdevice_process() - * - * This procedure preprocesses CustomDevice parameter if any - * - */ -void customdevice_process(void) -{ - usbvision_device_data[0]=usbvision_device_data[1]; - usbvision_table[0]=usbvision_table[1]; - - if(CustomDevice) - { - char *parse=CustomDevice; - - PDEBUG(DBG_PROBE, "CustomDevide=%s", CustomDevice); - - /*format is CustomDevice="0x0573 0x4D31 0 7113 3 PAL 1 1 1 5 -1 -1 -1 -1 -1" - usbvision_device_data[0].idVendor; - usbvision_device_data[0].idProduct; - usbvision_device_data[0].Interface; - usbvision_device_data[0].Codec; - usbvision_device_data[0].VideoChannels; - usbvision_device_data[0].VideoNorm; - usbvision_device_data[0].AudioChannels; - usbvision_device_data[0].Radio; - usbvision_device_data[0].Tuner; - usbvision_device_data[0].TunerType; - usbvision_device_data[0].Vin_Reg1; - usbvision_device_data[0].Vin_Reg2; - usbvision_device_data[0].X_Offset; - usbvision_device_data[0].Y_Offset; - usbvision_device_data[0].Dvi_yuv; - usbvision_device_data[0].ModelString; - */ - - rmspace(parse); - usbvision_device_data[0].ModelString="USBVISION Custom Device"; - - parse+=2; - sscanf(parse,"%x",&usbvision_device_data[0].idVendor); - goto2next(parse); - PDEBUG(DBG_PROBE, "idVendor=0x%.4X", usbvision_device_data[0].idVendor); - parse+=2; - sscanf(parse,"%x",&usbvision_device_data[0].idProduct); - goto2next(parse); - PDEBUG(DBG_PROBE, "idProduct=0x%.4X", usbvision_device_data[0].idProduct); - sscanf(parse,"%d",&usbvision_device_data[0].Interface); - goto2next(parse); - PDEBUG(DBG_PROBE, "Interface=%d", usbvision_device_data[0].Interface); - sscanf(parse,"%d",&usbvision_device_data[0].Codec); - goto2next(parse); - PDEBUG(DBG_PROBE, "Codec=%d", usbvision_device_data[0].Codec); - sscanf(parse,"%d",&usbvision_device_data[0].VideoChannels); - goto2next(parse); - PDEBUG(DBG_PROBE, "VideoChannels=%d", usbvision_device_data[0].VideoChannels); - - switch(*parse) - { - case 'P': - PDEBUG(DBG_PROBE, "VideoNorm=PAL"); - usbvision_device_data[0].VideoNorm=VIDEO_MODE_PAL; - break; - - case 'S': - PDEBUG(DBG_PROBE, "VideoNorm=SECAM"); - usbvision_device_data[0].VideoNorm=VIDEO_MODE_SECAM; - break; - - case 'N': - PDEBUG(DBG_PROBE, "VideoNorm=NTSC"); - usbvision_device_data[0].VideoNorm=VIDEO_MODE_NTSC; - break; - - default: - PDEBUG(DBG_PROBE, "VideoNorm=PAL (by default)"); - usbvision_device_data[0].VideoNorm=VIDEO_MODE_PAL; - break; - } - goto2next(parse); - - sscanf(parse,"%d",&usbvision_device_data[0].AudioChannels); - goto2next(parse); - PDEBUG(DBG_PROBE, "AudioChannels=%d", usbvision_device_data[0].AudioChannels); - sscanf(parse,"%d",&usbvision_device_data[0].Radio); - goto2next(parse); - PDEBUG(DBG_PROBE, "Radio=%d", usbvision_device_data[0].Radio); - sscanf(parse,"%d",&usbvision_device_data[0].Tuner); - goto2next(parse); - PDEBUG(DBG_PROBE, "Tuner=%d", usbvision_device_data[0].Tuner); - sscanf(parse,"%d",&usbvision_device_data[0].TunerType); - goto2next(parse); - PDEBUG(DBG_PROBE, "TunerType=%d", usbvision_device_data[0].TunerType); - sscanf(parse,"%d",&usbvision_device_data[0].Vin_Reg1); - goto2next(parse); - PDEBUG(DBG_PROBE, "Vin_Reg1=%d", usbvision_device_data[0].Vin_Reg1); - sscanf(parse,"%d",&usbvision_device_data[0].Vin_Reg2); - goto2next(parse); - PDEBUG(DBG_PROBE, "Vin_Reg2=%d", usbvision_device_data[0].Vin_Reg2); - sscanf(parse,"%d",&usbvision_device_data[0].X_Offset); - goto2next(parse); - PDEBUG(DBG_PROBE, "X_Offset=%d", usbvision_device_data[0].X_Offset); - sscanf(parse,"%d",&usbvision_device_data[0].Y_Offset); - goto2next(parse); - PDEBUG(DBG_PROBE, "Y_Offset=%d", usbvision_device_data[0].Y_Offset); - sscanf(parse,"%d",&usbvision_device_data[0].Dvi_yuv); - PDEBUG(DBG_PROBE, "Dvi_yuv=%d", usbvision_device_data[0].Dvi_yuv); - - //add to usbvision_table also - usbvision_table[0].match_flags=USB_DEVICE_ID_MATCH_DEVICE; - usbvision_table[0].idVendor=usbvision_device_data[0].idVendor; - usbvision_table[0].idProduct=usbvision_device_data[0].idProduct; - - } -} - - - -/* - * usbvision_init() - * - * This code is run to initialize the driver. - * - */ -static int __init usbvision_init(void) -{ - int errCode; - - PDEBUG(DBG_PROBE, ""); - - PDEBUG(DBG_IOCTL, "IOCTL debugging is enabled"); - PDEBUG(DBG_IO, "IO debugging is enabled"); - PDEBUG(DBG_RIO, "RIO debugging is enabled"); - PDEBUG(DBG_HEADER, "HEADER debugging is enabled"); - PDEBUG(DBG_PROBE, "PROBE debugging is enabled"); - PDEBUG(DBG_IRQ, "IRQ debugging is enabled"); - PDEBUG(DBG_ISOC, "ISOC debugging is enabled"); - PDEBUG(DBG_PARSE, "PARSE debugging is enabled"); - PDEBUG(DBG_SCRATCH, "SCRATCH debugging is enabled"); - PDEBUG(DBG_FUNC, "FUNC debugging is enabled"); - PDEBUG(DBG_I2C, "I2C debugging is enabled"); - - /* disable planar mode support unless compression enabled */ - if (isocMode != ISOC_MODE_COMPRESS ) { - // FIXME : not the right way to set supported flag - usbvision_v4l2_format[6].supported = 0; // V4L2_PIX_FMT_YVU420 - usbvision_v4l2_format[7].supported = 0; // V4L2_PIX_FMT_YUV422P - } - - customdevice_process(); - - errCode = usb_register(&usbvision_driver); - - if (errCode == 0) { - info(DRIVER_DESC " : " DRIVER_VERSION); - PDEBUG(DBG_PROBE, "success"); - } - return errCode; -} - -static void __exit usbvision_exit(void) -{ - PDEBUG(DBG_PROBE, ""); - - usb_deregister(&usbvision_driver); - PDEBUG(DBG_PROBE, "success"); -} - -module_init(usbvision_init); -module_exit(usbvision_exit); - /* * Overrides for Emacs so that we follow Linus's tabbing style. * --------------------------------------------------------------------------- diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c index 48afcd2aca3..2de74e48cbe 100644 --- a/drivers/media/video/usbvision/usbvision-i2c.c +++ b/drivers/media/video/usbvision/usbvision-i2c.c @@ -37,16 +37,18 @@ #include #include #include -#include "usbvision-i2c.h" +#include "usbvision.h" -static int debug_i2c_usb = 0; +#define DBG_I2C 1<<0 +#define DBG_ALGO 1<<1 -#if defined(module_param) // Showing parameters under SYSFS -module_param (debug_i2c_usb, int, 0444); // debug_i2c_usb mode of the device driver -#else -MODULE_PARM(debug_i2c_usb, "i"); // debug_i2c_usb mode of the device driver -#endif +static int i2c_debug = 0; + +module_param (i2c_debug, int, 0644); // debug_i2c_usb mode of the device driver +MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); +#define PDEBUG(level, fmt, args...) \ + if (i2c_debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args) static inline int try_write_address(struct i2c_adapter *i2c_adap, unsigned char addr, int retries) @@ -67,11 +69,9 @@ static inline int try_write_address(struct i2c_adapter *i2c_adap, break; udelay(adap->udelay); } - if (debug_i2c_usb) { - if (i) { - info("%s: Needed %d retries for address %#2x", __FUNCTION__, i, addr); - info("%s: Maybe there's no device at this address", __FUNCTION__); - } + if (i) { + PDEBUG(DBG_ALGO,"Needed %d retries for address %#2x", i, addr); + PDEBUG(DBG_ALGO,"Maybe there's no device at this address"); } return ret; } @@ -94,11 +94,9 @@ static inline int try_read_address(struct i2c_adapter *i2c_adap, break; udelay(adap->udelay); } - if (debug_i2c_usb) { - if (i) { - info("%s: Needed %d retries for address %#2x", __FUNCTION__, i, addr); - info("%s: Maybe there's no device at this address", __FUNCTION__); - } + if (i) { + PDEBUG(DBG_ALGO,"Needed %d retries for address %#2x", i, addr); + PDEBUG(DBG_ALGO,"Maybe there's no device at this address"); } return ret; } @@ -166,9 +164,7 @@ usb_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) pmsg = &msgs[i]; ret = usb_find_address(i2c_adap, pmsg, i2c_adap->retries, &addr); if (ret != 0) { - if (debug_i2c_usb) { - info("%s: got NAK from device, message #%d\n", __FUNCTION__, i); - } + PDEBUG(DBG_ALGO,"got NAK from device, message #%d", i); return (ret < 0) ? ret : -EREMOTEIO; } @@ -215,6 +211,9 @@ static struct i2c_algorithm i2c_usb_algo = { */ int usbvision_i2c_usb_add_bus(struct i2c_adapter *adap) { + PDEBUG(DBG_I2C, "I2C debugging is enabled [i2c]"); + PDEBUG(DBG_ALGO, "ALGO debugging is enabled [i2c]"); + /* register new adapter to i2c module... */ adap->algo = &i2c_usb_algo; @@ -222,17 +221,9 @@ int usbvision_i2c_usb_add_bus(struct i2c_adapter *adap) adap->timeout = 100; /* default values, should */ adap->retries = 3; /* be replaced by defines */ -#ifdef MODULE - #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 21) - MOD_INC_USE_COUNT; - #endif -#endif - i2c_add_adapter(adap); - if (debug_i2c_usb) { - info("i2c bus for %s registered", adap->name); - } + PDEBUG(DBG_ALGO,"i2c bus for %s registered", adap->name); return 0; } @@ -243,17 +234,338 @@ int usbvision_i2c_usb_del_bus(struct i2c_adapter *adap) i2c_del_adapter(adap); - if (debug_i2c_usb) { - info("i2c bus for %s unregistered", adap->name); + PDEBUG(DBG_ALGO,"i2c bus for %s unregistered", adap->name); + + return 0; +} + + +/* ----------------------------------------------------------------------- */ +/* usbvision specific I2C functions */ +/* ----------------------------------------------------------------------- */ +static struct i2c_adapter i2c_adap_template; +static struct i2c_algo_usb_data i2c_algo_template; +static struct i2c_client i2c_client_template; + +int usbvision_init_i2c(struct usb_usbvision *usbvision) +{ + memcpy(&usbvision->i2c_adap, &i2c_adap_template, + sizeof(struct i2c_adapter)); + memcpy(&usbvision->i2c_algo, &i2c_algo_template, + sizeof(struct i2c_algo_usb_data)); + memcpy(&usbvision->i2c_client, &i2c_client_template, + sizeof(struct i2c_client)); + + sprintf(usbvision->i2c_adap.name + strlen(usbvision->i2c_adap.name), + " #%d", usbvision->vdev->minor & 0x1f); + PDEBUG(DBG_I2C,"Adaptername: %s", usbvision->i2c_adap.name); + + i2c_set_adapdata(&usbvision->i2c_adap, usbvision); + i2c_set_clientdata(&usbvision->i2c_client, usbvision); + i2c_set_algo_usb_data(&usbvision->i2c_algo, usbvision); + + usbvision->i2c_adap.algo_data = &usbvision->i2c_algo; + usbvision->i2c_client.adapter = &usbvision->i2c_adap; + + if (usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_IIC_LRNACK) < 0) { + printk(KERN_ERR "usbvision_init_i2c: can't write reg\n"); + return -EBUSY; + } + +#ifdef CONFIG_MODULES + /* Request the load of the i2c modules we need */ + switch (usbvision_device_data[usbvision->DevModel].Codec) { + case CODEC_SAA7113: + request_module("saa7115"); + break; + case CODEC_SAA7111: + request_module("saa7115"); + break; + } + if (usbvision_device_data[usbvision->DevModel].Tuner == 1) { + request_module("tuner"); } -#ifdef MODULE - #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 21) - MOD_DEC_USE_COUNT; - #endif #endif + return usbvision_i2c_usb_add_bus(&usbvision->i2c_adap); +} + +void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd, + void *arg) +{ + BUG_ON(NULL == usbvision->i2c_adap.algo_data); + i2c_clients_command(&usbvision->i2c_adap, cmd, arg); +} + +static int attach_inform(struct i2c_client *client) +{ + struct usb_usbvision *usbvision; + + usbvision = (struct usb_usbvision *)i2c_get_adapdata(client->adapter); + + switch (client->addr << 1) { + case 0x43: + case 0x4b: + { + struct tuner_setup tun_setup; + + tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; + tun_setup.type = TUNER_TDA9887; + tun_setup.addr = client->addr; + + call_i2c_clients(usbvision, TUNER_SET_TYPE_ADDR, &tun_setup); + + break; + } + case 0x42: + PDEBUG(DBG_I2C,"attach_inform: saa7114 detected."); + break; + case 0x4a: + PDEBUG(DBG_I2C,"attach_inform: saa7113 detected."); + break; + case 0xa0: + PDEBUG(DBG_I2C,"attach_inform: eeprom detected."); + break; + + default: + { + struct tuner_setup tun_setup; + + PDEBUG(DBG_I2C,"attach inform: detected I2C address %x", client->addr << 1); + usbvision->tuner_addr = client->addr; + + if ((usbvision->have_tuner) && (usbvision->tuner_type != -1)) { + tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; + tun_setup.type = usbvision->tuner_type; + tun_setup.addr = usbvision->tuner_addr; + call_i2c_clients(usbvision, TUNER_SET_TYPE_ADDR, &tun_setup); + } + } + break; + } return 0; } +static int detach_inform(struct i2c_client *client) +{ + struct usb_usbvision *usbvision; + + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + usbvision = (struct usb_usbvision *)client->adapter->data; + #else + usbvision = (struct usb_usbvision *)i2c_get_adapdata(client->adapter); + #endif + + PDEBUG(DBG_I2C,"usbvision[%d] detaches %s", usbvision->nr, client->name); + return 0; +} + +static int +usbvision_i2c_read_max4(struct usb_usbvision *usbvision, unsigned char addr, + char *buf, short len) +{ + int rc, retries; + + for (retries = 5;;) { + rc = usbvision_write_reg(usbvision, USBVISION_SER_ADRS, addr); + if (rc < 0) + return rc; + + /* Initiate byte read cycle */ + /* USBVISION_SER_CONT <- d0-d2 n. of bytes to r/w */ + /* d3 0=Wr 1=Rd */ + rc = usbvision_write_reg(usbvision, USBVISION_SER_CONT, + (len & 0x07) | 0x18); + if (rc < 0) + return rc; + + /* Test for Busy and ACK */ + do { + /* USBVISION_SER_CONT -> d4 == 0 busy */ + rc = usbvision_read_reg(usbvision, USBVISION_SER_CONT); + } while (rc > 0 && ((rc & 0x10) != 0)); /* Retry while busy */ + if (rc < 0) + return rc; + + /* USBVISION_SER_CONT -> d5 == 1 Not ack */ + if ((rc & 0x20) == 0) /* Ack? */ + break; + + /* I2C abort */ + rc = usbvision_write_reg(usbvision, USBVISION_SER_CONT, 0x00); + if (rc < 0) + return rc; + + if (--retries < 0) + return -1; + } + + switch (len) { + case 4: + buf[3] = usbvision_read_reg(usbvision, USBVISION_SER_DAT4); + case 3: + buf[2] = usbvision_read_reg(usbvision, USBVISION_SER_DAT3); + case 2: + buf[1] = usbvision_read_reg(usbvision, USBVISION_SER_DAT2); + case 1: + buf[0] = usbvision_read_reg(usbvision, USBVISION_SER_DAT1); + break; + default: + printk(KERN_ERR + "usbvision_i2c_read_max4: buffer length > 4\n"); + } + + if (i2c_debug & DBG_I2C) { + int idx; + for (idx = 0; idx < len; idx++) { + PDEBUG(DBG_I2C,"read %x from address %x", (unsigned char)buf[idx], addr); + } + } + return len; +} + + +static int usbvision_i2c_write_max4(struct usb_usbvision *usbvision, + unsigned char addr, const char *buf, + short len) +{ + int rc, retries; + int i; + unsigned char value[6]; + unsigned char ser_cont; + + ser_cont = (len & 0x07) | 0x10; + + value[0] = addr; + value[1] = ser_cont; + for (i = 0; i < len; i++) + value[i + 2] = buf[i]; + + for (retries = 5;;) { + rc = usb_control_msg(usbvision->dev, + usb_sndctrlpipe(usbvision->dev, 1), + USBVISION_OP_CODE, + USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_ENDPOINT, 0, + (__u16) USBVISION_SER_ADRS, value, + len + 2, HZ); + + if (rc < 0) + return rc; + + rc = usbvision_write_reg(usbvision, USBVISION_SER_CONT, + (len & 0x07) | 0x10); + if (rc < 0) + return rc; + + /* Test for Busy and ACK */ + do { + rc = usbvision_read_reg(usbvision, USBVISION_SER_CONT); + } while (rc > 0 && ((rc & 0x10) != 0)); /* Retry while busy */ + if (rc < 0) + return rc; + + if ((rc & 0x20) == 0) /* Ack? */ + break; + + /* I2C abort */ + usbvision_write_reg(usbvision, USBVISION_SER_CONT, 0x00); + + if (--retries < 0) + return -1; + + } + + if (i2c_debug & DBG_I2C) { + int idx; + for (idx = 0; idx < len; idx++) { + PDEBUG(DBG_I2C,"wrote %x at address %x", (unsigned char)buf[idx], addr); + } + } + return len; +} + +static int usbvision_i2c_write(void *data, unsigned char addr, char *buf, + short len) +{ + char *bufPtr = buf; + int retval; + int wrcount = 0; + int count; + int maxLen = 4; + struct usb_usbvision *usbvision = (struct usb_usbvision *) data; + + while (len > 0) { + count = (len > maxLen) ? maxLen : len; + retval = usbvision_i2c_write_max4(usbvision, addr, bufPtr, count); + if (retval > 0) { + len -= count; + bufPtr += count; + wrcount += count; + } else + return (retval < 0) ? retval : -EFAULT; + } + return wrcount; +} + +static int usbvision_i2c_read(void *data, unsigned char addr, char *buf, + short len) +{ + char temp[4]; + int retval, i; + int rdcount = 0; + int count; + struct usb_usbvision *usbvision = (struct usb_usbvision *) data; + + while (len > 0) { + count = (len > 3) ? 4 : len; + retval = usbvision_i2c_read_max4(usbvision, addr, temp, count); + if (retval > 0) { + for (i = 0; i < len; i++) + buf[rdcount + i] = temp[i]; + len -= count; + rdcount += count; + } else + return (retval < 0) ? retval : -EFAULT; + } + return rdcount; +} + +static struct i2c_algo_usb_data i2c_algo_template = { + .data = NULL, + .inb = usbvision_i2c_read, + .outb = usbvision_i2c_write, + .udelay = 10, + .mdelay = 10, + .timeout = 100, +}; + +static struct i2c_adapter i2c_adap_template = { + .owner = THIS_MODULE, + .name = "usbvision", + .id = I2C_HW_B_BT848, /* FIXME */ + .algo = NULL, + .algo_data = NULL, + .client_register = attach_inform, + .client_unregister = detach_inform, +#if defined (I2C_ADAP_CLASS_TV_ANALOG) + .class = I2C_ADAP_CLASS_TV_ANALOG, +#elif defined (I2C_CLASS_TV_ANALOG) + .class = I2C_CLASS_TV_ANALOG, +#endif +}; + +static struct i2c_client i2c_client_template = { + .name = "usbvision internal", +}; + EXPORT_SYMBOL(usbvision_i2c_usb_add_bus); EXPORT_SYMBOL(usbvision_i2c_usb_del_bus); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/video/usbvision/usbvision-i2c.h b/drivers/media/video/usbvision/usbvision-i2c.h deleted file mode 100644 index a2df8dbdac5..00000000000 --- a/drivers/media/video/usbvision/usbvision-i2c.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * I2C_ALGO_USB.H - * i2c algorithm for USB-I2C Bridges - * - * Copyright (c) 1999-2005 Joerg Heckenbach - * - * This module is part of usbvision driver project. - * Updates to driver completed by Dwaine P. Garden - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -#ifndef I2C_ALGO_USB_H -#define I2C_ALGO_USB_H 1 - -#include - -struct i2c_algo_usb_data { - void *data; /* private data for lowlevel routines */ - int (*inb) (void *data, unsigned char addr, char *buf, short len); - int (*outb) (void *data, unsigned char addr, char *buf, short len); - - /* local settings */ - int udelay; - int mdelay; - int timeout; -}; - -#define I2C_USB_ADAP_MAX 16 - -int usbvision_i2c_usb_add_bus(struct i2c_adapter *); -int usbvision_i2c_usb_del_bus(struct i2c_adapter *); - -static inline void *i2c_get_algo_usb_data (struct i2c_algo_usb_data *dev) -{ - return dev->data; -} - -static inline void i2c_set_algo_usb_data (struct i2c_algo_usb_data *dev, void *data) -{ - dev->data = data; -} - - -#endif //I2C_ALGO_USB_H diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c new file mode 100644 index 00000000000..7e26d833688 --- /dev/null +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -0,0 +1,2060 @@ +/* + * USB USBVISION Video device driver 0.9.9 + * + * + * + * Copyright (c) 1999-2005 Joerg Heckenbach + * + * This module is part of usbvision driver project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Let's call the version 0.... until compression decoding is completely + * implemented. + * + * This driver is written by Jose Ignacio Gijon and Joerg Heckenbach. + * It was based on USB CPiA driver written by Peter Pregler, + * Scott J. Bertin and Johannes Erdfelt + * Ideas are taken from bttv driver by Ralph Metzler, Marcus Metzler & + * Gerd Knorr and zoran 36120/36125 driver by Pauline Middelink + * Updates to driver completed by Dwaine P. Garden + * + * + * TODO: + * - use submit_urb for all setup packets + * - Fix memory settings for nt1004. It is 4 times as big as the + * nt1003 memory. + * - Add audio on endpoint 3 for nt1004 chip. Seems impossible, needs a codec interface. Which one? + * - Clean up the driver. + * - optimization for performance. + * - Add Videotext capability (VBI). Working on it..... + * - Check audio for other devices + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + #include + #include + +#ifdef CONFIG_KMOD +#include +#endif + +#include "usbvision.h" + +#define DRIVER_AUTHOR "Joerg Heckenbach , Dwaine Garden " +#define DRIVER_NAME "usbvision" +#define DRIVER_ALIAS "USBVision" +#define DRIVER_DESC "USBVision USB Video Device Driver for Linux" +#define DRIVER_LICENSE "GPL" +#define USBVISION_DRIVER_VERSION_MAJOR 0 +#define USBVISION_DRIVER_VERSION_MINOR 9 +#define USBVISION_DRIVER_VERSION_PATCHLEVEL 9 +#define USBVISION_DRIVER_VERSION KERNEL_VERSION(USBVISION_DRIVER_VERSION_MAJOR,USBVISION_DRIVER_VERSION_MINOR,USBVISION_DRIVER_VERSION_PATCHLEVEL) +#define USBVISION_VERSION_STRING __stringify(USBVISION_DRIVER_VERSION_MAJOR) "." __stringify(USBVISION_DRIVER_VERSION_MINOR) "." __stringify(USBVISION_DRIVER_VERSION_PATCHLEVEL) + +#define ENABLE_HEXDUMP 0 /* Enable if you need it */ + + +#define USBVISION_DEBUG /* Turn on debug messages */ + +#ifdef USBVISION_DEBUG + #define PDEBUG(level, fmt, args...) \ + if (video_debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args) +#else + #define PDEBUG(level, fmt, args...) do {} while(0) +#endif + +#define DBG_IOCTL 1<<0 +#define DBG_IO 1<<1 +#define DBG_PROBE 1<<2 +#define DBG_FUNC 1<<3 + +//String operations +#define rmspace(str) while(*str==' ') str++; +#define goto2next(str) while(*str!=' ') str++; while(*str==' ') str++; + + +static int usbvision_nr = 0; // sequential number of usbvision device + +static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = { + { 1, 1, 8, V4L2_PIX_FMT_GREY , "GREY" }, + { 1, 2, 16, V4L2_PIX_FMT_RGB565 , "RGB565" }, + { 1, 3, 24, V4L2_PIX_FMT_RGB24 , "RGB24" }, + { 1, 4, 32, V4L2_PIX_FMT_RGB32 , "RGB32" }, + { 1, 2, 16, V4L2_PIX_FMT_RGB555 , "RGB555" }, + { 1, 2, 16, V4L2_PIX_FMT_YUYV , "YUV422" }, + { 1, 2, 12, V4L2_PIX_FMT_YVU420 , "YUV420P" }, // 1.5 ! + { 1, 2, 16, V4L2_PIX_FMT_YUV422P , "YUV422P" } +}; + +/* supported tv norms */ +static struct usbvision_tvnorm tvnorms[] = { + { + .name = "PAL", + .id = V4L2_STD_PAL, + }, { + .name = "NTSC", + .id = V4L2_STD_NTSC, + }, { + .name = "SECAM", + .id = V4L2_STD_SECAM, + }, { + .name = "PAL-M", + .id = V4L2_STD_PAL_M, + } +}; + +#define TVNORMS ARRAY_SIZE(tvnorms) + +// Function prototypes +static void usbvision_release(struct usb_usbvision *usbvision); + +// Default initalization of device driver parameters +static int isocMode = ISOC_MODE_COMPRESS; // Set the default format for ISOC endpoint +static int video_debug = 0; // Set the default Debug Mode of the device driver +static int PowerOnAtOpen = 1; // Set the default device to power on at startup +static int video_nr = -1; // Sequential Number of Video Device +static int radio_nr = -1; // Sequential Number of Radio Device +static int vbi_nr = -1; // Sequential Number of VBI Device +static char *CustomDevice=NULL; // Set as nothing.... + +// Grab parameters for the device driver + +#if defined(module_param) // Showing parameters under SYSFS +module_param(isocMode, int, 0444); +module_param(video_debug, int, 0444); +module_param(PowerOnAtOpen, int, 0444); +module_param(video_nr, int, 0444); +module_param(radio_nr, int, 0444); +module_param(vbi_nr, int, 0444); +module_param(CustomDevice, charp, 0444); +#else // Old Style +MODULE_PARAM(isocMode, "i"); +MODULE_PARM(video_debug, "i"); // Grab the Debug Mode of the device driver +MODULE_PARM(adjustCompression, "i"); // Grab the compression to be adaptive +MODULE_PARM(PowerOnAtOpen, "i"); // Grab the device to power on at startup +MODULE_PARM(SwitchSVideoInput, "i"); // To help people with Black and White output with using s-video input. Some cables and input device are wired differently. +MODULE_PARM(video_nr, "i"); // video_nr option allows to specify a certain /dev/videoX device (like /dev/video0 or /dev/video1 ...) +MODULE_PARM(radio_nr, "i"); // radio_nr option allows to specify a certain /dev/radioX device (like /dev/radio0 or /dev/radio1 ...) +MODULE_PARM(vbi_nr, "i"); // vbi_nr option allows to specify a certain /dev/vbiX device (like /dev/vbi0 or /dev/vbi1 ...) +MODULE_PARM(CustomDevice, "s"); // .... CustomDevice +#endif + +MODULE_PARM_DESC(isocMode, " Set the default format for ISOC endpoint. Default: 0x60 (Compression On)"); +MODULE_PARM_DESC(video_debug, " Set the default Debug Mode of the device driver. Default: 0 (Off)"); +MODULE_PARM_DESC(PowerOnAtOpen, " Set the default device to power on when device is opened. Default: 1 (On)"); +MODULE_PARM_DESC(video_nr, "Set video device number (/dev/videoX). Default: -1 (autodetect)"); +MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)"); +MODULE_PARM_DESC(vbi_nr, "Set vbi device number (/dev/vbiX). Default: -1 (autodetect)"); +MODULE_PARM_DESC(CustomDevice, " Define the fine tuning parameters for the device. Default: null"); + + +// Misc stuff +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE(DRIVER_LICENSE); + MODULE_VERSION(USBVISION_VERSION_STRING); + MODULE_ALIAS(DRIVER_ALIAS); + + +/****************************************************************************************/ +/* SYSFS Code - Copied from the stv680.c usb module. */ +/* Device information is located at /sys/class/video4linux/video0 */ +/* Device parameters information is located at /sys/module/usbvision */ +/* Device USB Information is located at /sys/bus/usb/drivers/USBVision Video Grabber */ +/****************************************************************************************/ + + +#define YES_NO(x) ((x) ? "Yes" : "No") + +static inline struct usb_usbvision *cd_to_usbvision(struct class_device *cd) +{ + struct video_device *vdev = to_video_device(cd); + return video_get_drvdata(vdev); +} + +static ssize_t show_version(struct class_device *cd, char *buf) +{ + return sprintf(buf, "%s\n", USBVISION_VERSION_STRING); +} +static CLASS_DEVICE_ATTR(version, S_IRUGO, show_version, NULL); + +static ssize_t show_model(struct class_device *class_dev, char *buf) +{ + struct video_device *vdev = to_video_device(class_dev); + struct usb_usbvision *usbvision = video_get_drvdata(vdev); + return sprintf(buf, "%s\n", usbvision_device_data[usbvision->DevModel].ModelString); +} +static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL); + +static ssize_t show_hue(struct class_device *class_dev, char *buf) +{ + struct video_device *vdev = to_video_device(class_dev); + struct usb_usbvision *usbvision = video_get_drvdata(vdev); + struct v4l2_control ctrl; + ctrl.id = V4L2_CID_HUE; + ctrl.value = 0; + call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); + return sprintf(buf, "%d\n", ctrl.value >> 8); +} +static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL); + +static ssize_t show_contrast(struct class_device *class_dev, char *buf) +{ + struct video_device *vdev = to_video_device(class_dev); + struct usb_usbvision *usbvision = video_get_drvdata(vdev); + struct v4l2_control ctrl; + ctrl.id = V4L2_CID_CONTRAST; + ctrl.value = 0; + call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); + return sprintf(buf, "%d\n", ctrl.value >> 8); +} +static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL); + +static ssize_t show_brightness(struct class_device *class_dev, char *buf) +{ + struct video_device *vdev = to_video_device(class_dev); + struct usb_usbvision *usbvision = video_get_drvdata(vdev); + struct v4l2_control ctrl; + ctrl.id = V4L2_CID_BRIGHTNESS; + ctrl.value = 0; + call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); + return sprintf(buf, "%d\n", ctrl.value >> 8); +} +static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL); + +static ssize_t show_saturation(struct class_device *class_dev, char *buf) +{ + struct video_device *vdev = to_video_device(class_dev); + struct usb_usbvision *usbvision = video_get_drvdata(vdev); + struct v4l2_control ctrl; + ctrl.id = V4L2_CID_SATURATION; + ctrl.value = 0; + call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl); + return sprintf(buf, "%d\n", ctrl.value >> 8); +} +static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL); + +static ssize_t show_streaming(struct class_device *class_dev, char *buf) +{ + struct video_device *vdev = to_video_device(class_dev); + struct usb_usbvision *usbvision = video_get_drvdata(vdev); + return sprintf(buf, "%s\n", YES_NO(usbvision->streaming==Stream_On?1:0)); +} +static CLASS_DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL); + +static ssize_t show_compression(struct class_device *class_dev, char *buf) +{ + struct video_device *vdev = to_video_device(class_dev); + struct usb_usbvision *usbvision = video_get_drvdata(vdev); + return sprintf(buf, "%s\n", YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS)); +} +static CLASS_DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL); + +static ssize_t show_device_bridge(struct class_device *class_dev, char *buf) +{ + struct video_device *vdev = to_video_device(class_dev); + struct usb_usbvision *usbvision = video_get_drvdata(vdev); + return sprintf(buf, "%d\n", usbvision->bridgeType); +} +static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL); + +static void usbvision_create_sysfs(struct video_device *vdev) +{ + int res; + if (vdev) { + res=video_device_create_file(vdev, &class_device_attr_version); + res=video_device_create_file(vdev, &class_device_attr_model); + res=video_device_create_file(vdev, &class_device_attr_hue); + res=video_device_create_file(vdev, &class_device_attr_contrast); + res=video_device_create_file(vdev, &class_device_attr_brightness); + res=video_device_create_file(vdev, &class_device_attr_saturation); + res=video_device_create_file(vdev, &class_device_attr_streaming); + res=video_device_create_file(vdev, &class_device_attr_compression); + res=video_device_create_file(vdev, &class_device_attr_bridge); + } +} + +static void usbvision_remove_sysfs(struct video_device *vdev) +{ + if (vdev) { + video_device_remove_file(vdev, &class_device_attr_version); + video_device_remove_file(vdev, &class_device_attr_model); + video_device_remove_file(vdev, &class_device_attr_hue); + video_device_remove_file(vdev, &class_device_attr_contrast); + video_device_remove_file(vdev, &class_device_attr_brightness); + video_device_remove_file(vdev, &class_device_attr_saturation); + video_device_remove_file(vdev, &class_device_attr_streaming); + video_device_remove_file(vdev, &class_device_attr_compression); + video_device_remove_file(vdev, &class_device_attr_bridge); + } +} + + +/* + * usbvision_open() + * + * This is part of Video 4 Linux API. The driver can be opened by one + * client only (checks internal counter 'usbvision->user'). The procedure + * then allocates buffers needed for video processing. + * + */ +static int usbvision_v4l2_open(struct inode *inode, struct file *file) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); + int errCode = 0; + + PDEBUG(DBG_IO, "open"); + + + usbvision_reset_powerOffTimer(usbvision); + + if (usbvision->user) + errCode = -EBUSY; + else { + /* Allocate memory for the frame buffers */ + errCode = usbvision_frames_alloc(usbvision); + if(!errCode) { + /* Allocate memory for the scratch ring buffer */ + errCode = usbvision_scratch_alloc(usbvision); + if(!errCode) { + /* Allocate memory for the USB S buffers */ + errCode = usbvision_sbuf_alloc(usbvision); + if ((!errCode) && (usbvision->isocMode==ISOC_MODE_COMPRESS)) { + /* Allocate intermediate decompression buffers only if needed */ + errCode = usbvision_decompress_alloc(usbvision); + } + } + } + if (errCode) { + /* Deallocate all buffers if trouble */ + usbvision_frames_free(usbvision); + usbvision_scratch_free(usbvision); + usbvision_sbuf_free(usbvision); + usbvision_decompress_free(usbvision); + } + } + + /* If so far no errors then we shall start the camera */ + if (!errCode) { + down(&usbvision->lock); + if (usbvision->power == 0) { + usbvision_power_on(usbvision); + usbvision_init_i2c(usbvision); + } + + /* Send init sequence only once, it's large! */ + if (!usbvision->initialized) { + int setup_ok = 0; + setup_ok = usbvision_setup(usbvision,isocMode); + if (setup_ok) + usbvision->initialized = 1; + else + errCode = -EBUSY; + } + + if (!errCode) { + usbvision_begin_streaming(usbvision); + errCode = usbvision_init_isoc(usbvision); + /* device needs to be initialized before isoc transfer */ + usbvision_muxsel(usbvision,0); + usbvision->user++; + } + else { + if (PowerOnAtOpen) { + usbvision_i2c_usb_del_bus(&usbvision->i2c_adap); + usbvision_power_off(usbvision); + usbvision->initialized = 0; + } + } + up(&usbvision->lock); + } + + if (errCode) { + } + + /* prepare queues */ + usbvision_empty_framequeues(usbvision); + + PDEBUG(DBG_IO, "success"); + return errCode; +} + +/* + * usbvision_v4l2_close() + * + * This is part of Video 4 Linux API. The procedure + * stops streaming and deallocates all buffers that were earlier + * allocated in usbvision_v4l2_open(). + * + */ +static int usbvision_v4l2_close(struct inode *inode, struct file *file) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); + + PDEBUG(DBG_IO, "close"); + down(&usbvision->lock); + + usbvision_audio_off(usbvision); + usbvision_restart_isoc(usbvision); + usbvision_stop_isoc(usbvision); + + usbvision_decompress_free(usbvision); + usbvision_rvfree(usbvision->fbuf, usbvision->fbuf_size); + usbvision_scratch_free(usbvision); + usbvision_sbuf_free(usbvision); + + usbvision->user--; + + if (PowerOnAtOpen) { + /* power off in a little while to avoid off/on every close/open short sequences */ + usbvision_set_powerOffTimer(usbvision); + usbvision->initialized = 0; + } + + up(&usbvision->lock); + + if (usbvision->remove_pending) { + info("%s: Final disconnect", __FUNCTION__); + usbvision_release(usbvision); + } + + PDEBUG(DBG_IO, "success"); + + + return 0; +} + + +/* + * usbvision_ioctl() + * + * This is part of Video 4 Linux API. The procedure handles ioctl() calls. + * + */ +static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); + + if (!USBVISION_IS_OPERATIONAL(usbvision)) + return -EFAULT; + + switch (cmd) { + +#ifdef CONFIG_VIDEO_ADV_DEBUG + /* ioctls to allow direct acces to the NT100x registers */ + case VIDIOC_INT_G_REGISTER: + { + struct v4l2_register *reg = arg; + int errCode; + + if (reg->i2c_id != 0) + return -EINVAL; + /* NT100x has a 8-bit register space */ + errCode = usbvision_read_reg(usbvision, reg->reg&0xff); + if (errCode < 0) { + err("%s: VIDIOC_INT_G_REGISTER failed: error %d", __FUNCTION__, errCode); + } + else { + reg->val=(unsigned char)errCode; + PDEBUG(DBG_IOCTL, "VIDIOC_INT_G_REGISTER reg=0x%02X, value=0x%02X", + (unsigned int)reg->reg, reg->val); + errCode = 0; // No error + } + return errCode; + } + case VIDIOC_INT_S_REGISTER: + { + struct v4l2_register *reg = arg; + int errCode; + + if (reg->i2c_id != 0) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val); + if (errCode < 0) { + err("%s: VIDIOC_INT_S_REGISTER failed: error %d", __FUNCTION__, errCode); + } + else { + PDEBUG(DBG_IOCTL, "VIDIOC_INT_S_REGISTER reg=0x%02X, value=0x%02X", + (unsigned int)reg->reg, reg->val); + errCode = 0; + } + return 0; + } +#endif + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *vc=arg; + + memset(vc, 0, sizeof(*vc)); + strlcpy(vc->driver, "USBVision", sizeof(vc->driver)); + strlcpy(vc->card, usbvision_device_data[usbvision->DevModel].ModelString, + sizeof(vc->card)); + strlcpy(vc->bus_info, usbvision->dev->dev.bus_id, + sizeof(vc->bus_info)); + vc->version = USBVISION_DRIVER_VERSION; + vc->capabilities = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_AUDIO | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | + (usbvision->have_tuner ? V4L2_CAP_TUNER : 0); + PDEBUG(DBG_IOCTL, "VIDIOC_QUERYCAP"); + return 0; + } + case VIDIOC_ENUMINPUT: + { + struct v4l2_input *vi = arg; + int chan; + + if ((vi->index >= usbvision->video_inputs) || (vi->index < 0) ) + return -EINVAL; + if (usbvision->have_tuner) { + chan = vi->index; + } + else { + chan = vi->index + 1; //skip Television string + } + switch(chan) { + case 0: + if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) { + strcpy(vi->name, "White Video Input"); + } + else { + strcpy(vi->name, "Television"); + vi->type = V4L2_INPUT_TYPE_TUNER; + vi->audioset = 1; + vi->tuner = chan; + vi->std = V4L2_STD_PAL | V4L2_STD_NTSC | V4L2_STD_SECAM; + } + break; + case 1: + vi->type = V4L2_INPUT_TYPE_CAMERA; + if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) { + strcpy(vi->name, "Green Video Input"); + } + else { + strcpy(vi->name, "Composite Video Input"); + } + vi->std = V4L2_STD_PAL; + break; + case 2: + vi->type = V4L2_INPUT_TYPE_CAMERA; + if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) { + strcpy(vi->name, "Yellow Video Input"); + } + else { + strcpy(vi->name, "S-Video Input"); + } + vi->std = V4L2_STD_PAL; + break; + case 3: + vi->type = V4L2_INPUT_TYPE_CAMERA; + strcpy(vi->name, "Red Video Input"); + vi->std = V4L2_STD_PAL; + break; + } + PDEBUG(DBG_IOCTL, "VIDIOC_ENUMINPUT name=%s:%d tuners=%d type=%d norm=%x", + vi->name, vi->index, vi->tuner,vi->type,(int)vi->std); + return 0; + } + case VIDIOC_ENUMSTD: + { + struct v4l2_standard *e = arg; + unsigned int i; + int ret; + + i = e->index; + if (i >= TVNORMS) + return -EINVAL; + ret = v4l2_video_std_construct(e, tvnorms[e->index].id, + tvnorms[e->index].name); + e->index = i; + if (ret < 0) + return ret; + return 0; + } + case VIDIOC_G_INPUT: + { + int *input = arg; + *input = usbvision->ctl_input; + return 0; + } + case VIDIOC_S_INPUT: + { + int *input = arg; + if ((*input >= usbvision->video_inputs) || (*input < 0) ) + return -EINVAL; + usbvision->ctl_input = *input; + + down(&usbvision->lock); + usbvision_muxsel(usbvision, usbvision->ctl_input); + usbvision_set_input(usbvision); + usbvision_set_output(usbvision, usbvision->curwidth, usbvision->curheight); + up(&usbvision->lock); + return 0; + } + case VIDIOC_G_STD: + { + v4l2_std_id *id = arg; + + *id = usbvision->tvnorm->id; + + PDEBUG(DBG_IOCTL, "VIDIOC_G_STD std_id=%s", usbvision->tvnorm->name); + return 0; + } + case VIDIOC_S_STD: + { + v4l2_std_id *id = arg; + unsigned int i; + + for (i = 0; i < TVNORMS; i++) + if (*id == tvnorms[i].id) + break; + if (i == TVNORMS) + for (i = 0; i < TVNORMS; i++) + if (*id & tvnorms[i].id) + break; + if (i == TVNORMS) + return -EINVAL; + + down(&usbvision->lock); + usbvision->tvnorm = &tvnorms[i]; + + call_i2c_clients(usbvision, VIDIOC_S_STD, + &usbvision->tvnorm->id); + + up(&usbvision->lock); + + PDEBUG(DBG_IOCTL, "VIDIOC_S_STD std_id=%s", usbvision->tvnorm->name); + return 0; + } + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *vt = arg; + + if (!usbvision->have_tuner || vt->index) // Only tuner 0 + return -EINVAL; + strcpy(vt->name, "Television"); + /* Let clients fill in the remainder of this struct */ + call_i2c_clients(usbvision,VIDIOC_G_TUNER,vt); + + PDEBUG(DBG_IOCTL, "VIDIOC_G_TUNER signal=%x, afc=%x",vt->signal,vt->afc); + return 0; + } + case VIDIOC_S_TUNER: + { + struct v4l2_tuner *vt = arg; + + // Only no or one tuner for now + if (!usbvision->have_tuner || vt->index) + return -EINVAL; + /* let clients handle this */ + call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt); + + PDEBUG(DBG_IOCTL, "VIDIOC_S_TUNER"); + return 0; + } + case VIDIOC_G_FREQUENCY: + { + struct v4l2_frequency *freq = arg; + + freq->tuner = 0; // Only one tuner + freq->type = V4L2_TUNER_ANALOG_TV; + freq->frequency = usbvision->freq; + PDEBUG(DBG_IOCTL, "VIDIOC_G_FREQUENCY freq=0x%X", (unsigned)freq->frequency); + return 0; + } + case VIDIOC_S_FREQUENCY: + { + struct v4l2_frequency *freq = arg; + + // Only no or one tuner for now + if (!usbvision->have_tuner || freq->tuner) + return -EINVAL; + + usbvision->freq = freq->frequency; + call_i2c_clients(usbvision, cmd, freq); + PDEBUG(DBG_IOCTL, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)freq->frequency); + return 0; + } + case VIDIOC_G_AUDIO: + { + struct v4l2_audio *v = arg; + memset(v,0, sizeof(v)); + strcpy(v->name, "TV"); + PDEBUG(DBG_IOCTL, "VIDIOC_G_AUDIO"); + return 0; + } + case VIDIOC_S_AUDIO: + { + struct v4l2_audio *v = arg; + if(v->index) { + return -EINVAL; + } + PDEBUG(DBG_IOCTL, "VIDIOC_S_AUDIO"); + return 0; + } + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *ctrl = arg; + int id=ctrl->id; + + memset(ctrl,0,sizeof(*ctrl)); + ctrl->id=id; + + call_i2c_clients(usbvision, cmd, arg); + + if (ctrl->type) + return 0; + else + return -EINVAL; + + PDEBUG(DBG_IOCTL,"VIDIOC_QUERYCTRL id=%x value=%x",ctrl->id,ctrl->type); + } + case VIDIOC_G_CTRL: + { + struct v4l2_control *ctrl = arg; + PDEBUG(DBG_IOCTL,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value); + call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl); + return 0; + } + case VIDIOC_S_CTRL: + { + struct v4l2_control *ctrl = arg; + + PDEBUG(DBG_IOCTL, "VIDIOC_S_CTRL id=%x value=%x",ctrl->id,ctrl->value); + call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl); + return 0; + } + case VIDIOC_REQBUFS: + { + struct v4l2_requestbuffers *vr = arg; + int ret; + + RESTRICT_TO_RANGE(vr->count,1,USBVISION_NUMFRAMES); + + // Check input validity : the user must do a VIDEO CAPTURE and MMAP method. + if((vr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) || + (vr->memory != V4L2_MEMORY_MMAP)) + return -EINVAL; + + if(usbvision->streaming == Stream_On) { + if ((ret = usbvision_stream_interrupt(usbvision))) + return ret; + } + + usbvision_empty_framequeues(usbvision); + + usbvision->curFrame = NULL; + + PDEBUG(DBG_IOCTL, "VIDIOC_REQBUFS count=%d",vr->count); + return 0; + } + case VIDIOC_QUERYBUF: + { + struct v4l2_buffer *vb = arg; + struct usbvision_frame *frame; + + // FIXME : must control that buffers are mapped (VIDIOC_REQBUFS has been called) + + if(vb->type != V4L2_CAP_VIDEO_CAPTURE) { + return -EINVAL; + } + if(vb->index>=USBVISION_NUMFRAMES) { + return -EINVAL; + } + // Updating the corresponding frame state + vb->flags = 0; + frame = &usbvision->frame[vb->index]; + if(frame->grabstate >= FrameState_Ready) + vb->flags |= V4L2_BUF_FLAG_QUEUED; + if(frame->grabstate >= FrameState_Done) + vb->flags |= V4L2_BUF_FLAG_DONE; + if(frame->grabstate == FrameState_Unused) + vb->flags |= V4L2_BUF_FLAG_MAPPED; + vb->memory = V4L2_MEMORY_MMAP; + + vb->m.offset = vb->index*usbvision->max_frame_size; + + vb->memory = V4L2_MEMORY_MMAP; + vb->field = V4L2_FIELD_NONE; + vb->length = usbvision->max_frame_size; + vb->timestamp = usbvision->frame[vb->index].timestamp; + vb->sequence = usbvision->frame[vb->index].sequence; + return 0; + } + case VIDIOC_QBUF: + { + struct v4l2_buffer *vb = arg; + struct usbvision_frame *frame; + unsigned long lock_flags; + + // FIXME : works only on VIDEO_CAPTURE MODE, MMAP. + if(vb->type != V4L2_CAP_VIDEO_CAPTURE) { + return -EINVAL; + } + if(vb->index>=USBVISION_NUMFRAMES) { + return -EINVAL; + } + + frame = &usbvision->frame[vb->index]; + + if (frame->grabstate != FrameState_Unused) { + return -EAGAIN; + } + + /* Mark it as ready and enqueue frame */ + frame->grabstate = FrameState_Ready; + frame->scanstate = ScanState_Scanning; + frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */ + + vb->flags &= ~V4L2_BUF_FLAG_DONE; + + /* set v4l2_format index */ + frame->v4l2_format = usbvision->palette; + + spin_lock_irqsave(&usbvision->queue_lock, lock_flags); + list_add_tail(&usbvision->frame[vb->index].frame, &usbvision->inqueue); + spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); + + PDEBUG(DBG_IOCTL, "VIDIOC_QBUF frame #%d",vb->index); + return 0; + } + case VIDIOC_DQBUF: + { + struct v4l2_buffer *vb = arg; + int ret; + struct usbvision_frame *f; + unsigned long lock_flags; + + if (vb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (list_empty(&(usbvision->outqueue))) { + if (usbvision->streaming == Stream_Idle) + return -EINVAL; + ret = wait_event_interruptible + (usbvision->wait_frame, + !list_empty(&(usbvision->outqueue))); + if (ret) + return ret; + } + + spin_lock_irqsave(&usbvision->queue_lock, lock_flags); + f = list_entry(usbvision->outqueue.next, + struct usbvision_frame, frame); + list_del(usbvision->outqueue.next); + spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); + + f->grabstate = FrameState_Unused; + + vb->memory = V4L2_MEMORY_MMAP; + vb->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE; + vb->index = f->index; + vb->sequence = f->sequence; + vb->timestamp = f->timestamp; + vb->field = V4L2_FIELD_NONE; + vb->bytesused = f->scanlength; + + return 0; + } + case VIDIOC_STREAMON: + { + int b=V4L2_BUF_TYPE_VIDEO_CAPTURE; + + usbvision->streaming = Stream_On; + + call_i2c_clients(usbvision,VIDIOC_STREAMON , &b); + + PDEBUG(DBG_IOCTL, "VIDIOC_STREAMON"); + + return 0; + } + case VIDIOC_STREAMOFF: + { + int *type = arg; + int b=V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if(usbvision->streaming == Stream_On) { + usbvision_stream_interrupt(usbvision); + // Stop all video streamings + call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b); + } + usbvision_empty_framequeues(usbvision); + + PDEBUG(DBG_IOCTL, "VIDIOC_STREAMOFF"); + return 0; + } + case VIDIOC_ENUM_FMT: + { + struct v4l2_fmtdesc *vfd = arg; + + if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) { + return -EINVAL; + } + vfd->flags = 0; + vfd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + strcpy(vfd->description,usbvision_v4l2_format[vfd->index].desc); + vfd->pixelformat = usbvision_v4l2_format[vfd->index].format; + memset(vfd->reserved, 0, sizeof(vfd->reserved)); + return 0; + } + case VIDIOC_G_FMT: + { + struct v4l2_format *vf = arg; + + switch (vf->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + { + vf->fmt.pix.width = usbvision->curwidth; + vf->fmt.pix.height = usbvision->curheight; + vf->fmt.pix.pixelformat = usbvision->palette.format; + vf->fmt.pix.bytesperline = usbvision->curwidth*usbvision->palette.bytes_per_pixel; + vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*usbvision->curheight; + vf->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + vf->fmt.pix.field = V4L2_FIELD_NONE; /* Always progressive image */ + } + return 0; + default: + PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT invalid type %d",vf->type); + return -EINVAL; + } + PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT w=%d, h=%d",vf->fmt.win.w.width, vf->fmt.win.w.height); + return 0; + } + case VIDIOC_TRY_FMT: + case VIDIOC_S_FMT: + { + struct v4l2_format *vf = arg; + int formatIdx,ret; + + switch(vf->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + { + /* Find requested format in available ones */ + for(formatIdx=0;formatIdxfmt.pix.pixelformat == usbvision_v4l2_format[formatIdx].format) { + usbvision->palette = usbvision_v4l2_format[formatIdx]; + break; + } + } + /* robustness */ + if(formatIdx == USBVISION_SUPPORTED_PALETTES) { + return -EINVAL; + } + RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH); + RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT); + + /* stop io in case it is already in progress */ + if(usbvision->streaming == Stream_On) { + if ((ret = usbvision_stream_interrupt(usbvision))) + return ret; + } + usbvision_empty_framequeues(usbvision); + + usbvision->curFrame = NULL; + + // by now we are committed to the new data... + down(&usbvision->lock); + usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height); + up(&usbvision->lock); + + PDEBUG(DBG_IOCTL, "VIDIOC_S_FMT grabdisplay w=%d, h=%d, format=%s", + vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc); + return 0; + } + default: + return -EINVAL; + } + } + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static int usbvision_v4l2_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return video_usercopy(inode, file, cmd, arg, usbvision_v4l2_do_ioctl); +} + + +static ssize_t usbvision_v4l2_read(struct file *file, char *buf, + size_t count, loff_t *ppos) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); + int noblock = file->f_flags & O_NONBLOCK; + unsigned long lock_flags; + + int frmx = -1; + int ret,i; + struct usbvision_frame *frame; + + PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __FUNCTION__, (unsigned long)count, noblock); + + if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL)) + return -EFAULT; + + /* no stream is running, make it running ! */ + usbvision->streaming = Stream_On; + call_i2c_clients(usbvision,VIDIOC_STREAMON , NULL); + + /* First, enqueue as many frames as possible (like a user of VIDIOC_QBUF would do) */ + for(i=0;iframe[i]; + if(frame->grabstate == FrameState_Unused) { + /* Mark it as ready and enqueue frame */ + frame->grabstate = FrameState_Ready; + frame->scanstate = ScanState_Scanning; + frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */ + + /* set v4l2_format index */ + frame->v4l2_format = usbvision->palette; + + spin_lock_irqsave(&usbvision->queue_lock, lock_flags); + list_add_tail(&frame->frame, &usbvision->inqueue); + spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); + } + } + + /* Then try to steal a frame (like a VIDIOC_DQBUF would do) */ + if (list_empty(&(usbvision->outqueue))) { + if(noblock) + return -EAGAIN; + + ret = wait_event_interruptible + (usbvision->wait_frame, + !list_empty(&(usbvision->outqueue))); + if (ret) + return ret; + } + + spin_lock_irqsave(&usbvision->queue_lock, lock_flags); + frame = list_entry(usbvision->outqueue.next, + struct usbvision_frame, frame); + list_del(usbvision->outqueue.next); + spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); + + /* An error returns an empty frame */ + if (frame->grabstate == FrameState_Error) { + frame->bytes_read = 0; + return 0; + } + + PDEBUG(DBG_IO, "%s: frmx=%d, bytes_read=%ld, scanlength=%ld", __FUNCTION__, + frame->index, frame->bytes_read, frame->scanlength); + + /* copy bytes to user space; we allow for partials reads */ + if ((count + frame->bytes_read) > (unsigned long)frame->scanlength) + count = frame->scanlength - frame->bytes_read; + + if (copy_to_user(buf, frame->data + frame->bytes_read, count)) { + return -EFAULT; + } + + frame->bytes_read += count; + PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld", __FUNCTION__, + (unsigned long)count, frame->bytes_read); + + // For now, forget the frame if it has not been read in one shot. +/* if (frame->bytes_read >= frame->scanlength) {// All data has been read */ + frame->bytes_read = 0; + + /* Mark it as available to be used again. */ + usbvision->frame[frmx].grabstate = FrameState_Unused; +/* } */ + + return count; +} + +static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) +{ + unsigned long size = vma->vm_end - vma->vm_start, + start = vma->vm_start; + void *pos; + u32 i; + + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); + + down(&usbvision->lock); + + if (!USBVISION_IS_OPERATIONAL(usbvision)) { + up(&usbvision->lock); + return -EFAULT; + } + + if (!(vma->vm_flags & VM_WRITE) || + size != PAGE_ALIGN(usbvision->max_frame_size)) { + up(&usbvision->lock); + return -EINVAL; + } + + for (i = 0; i < USBVISION_NUMFRAMES; i++) { + if (((usbvision->max_frame_size*i) >> PAGE_SHIFT) == vma->vm_pgoff) + break; + } + if (i == USBVISION_NUMFRAMES) { + PDEBUG(DBG_FUNC, "mmap: user supplied mapping address is out of range"); + up(&usbvision->lock); + return -EINVAL; + } + + /* VM_IO is eventually going to replace PageReserved altogether */ + vma->vm_flags |= VM_IO; + vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */ + + pos = usbvision->frame[i].data; + while (size > 0) { + + if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { + PDEBUG(DBG_FUNC, "mmap: vm_insert_page failed"); + up(&usbvision->lock); + return -EAGAIN; + } + start += PAGE_SIZE; + pos += PAGE_SIZE; + size -= PAGE_SIZE; + } + + up(&usbvision->lock); + return 0; +} + + +/* + * Here comes the stuff for radio on usbvision based devices + * + */ +static int usbvision_radio_open(struct inode *inode, struct file *file) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); + struct v4l2_frequency freq; + int errCode = 0; + + PDEBUG(DBG_IO, "%s:", __FUNCTION__); + + down(&usbvision->lock); + + if (usbvision->user) { + err("%s: Someone tried to open an already opened USBVision Radio!", __FUNCTION__); + errCode = -EBUSY; + } + else { + if(PowerOnAtOpen) { + usbvision_reset_powerOffTimer(usbvision); + if (usbvision->power == 0) { + usbvision_power_on(usbvision); + usbvision_init_i2c(usbvision); + } + } + + // If so far no errors then we shall start the radio + usbvision->radio = 1; + call_i2c_clients(usbvision,AUDC_SET_RADIO,&usbvision->tuner_type); + freq.frequency = 1517; //SWR3 @ 94.8MHz + call_i2c_clients(usbvision, VIDIOC_S_FREQUENCY, &freq); + usbvision_set_audio(usbvision, USBVISION_AUDIO_RADIO); + usbvision->user++; + } + + if (errCode) { + if (PowerOnAtOpen) { + usbvision_i2c_usb_del_bus(&usbvision->i2c_adap); + usbvision_power_off(usbvision); + usbvision->initialized = 0; + } + } + up(&usbvision->lock); + return errCode; +} + + +static int usbvision_radio_close(struct inode *inode, struct file *file) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); + int errCode = 0; + + PDEBUG(DBG_IO, ""); + + down(&usbvision->lock); + + usbvision_audio_off(usbvision); + usbvision->radio=0; + usbvision->user--; + + if (PowerOnAtOpen) { + usbvision_set_powerOffTimer(usbvision); + usbvision->initialized = 0; + } + + up(&usbvision->lock); + + if (usbvision->remove_pending) { + info("%s: Final disconnect", __FUNCTION__); + usbvision_release(usbvision); + } + + + PDEBUG(DBG_IO, "success"); + + return errCode; +} + +static int usbvision_do_radio_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) +{ + struct video_device *dev = video_devdata(file); + struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev); + + if (!USBVISION_IS_OPERATIONAL(usbvision)) + return -EIO; + + switch (cmd) { + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *vc=arg; + + memset(vc, 0, sizeof(*vc)); + strlcpy(vc->driver, "USBVision", sizeof(vc->driver)); + strlcpy(vc->card, usbvision_device_data[usbvision->DevModel].ModelString, + sizeof(vc->card)); + strlcpy(vc->bus_info, usbvision->dev->dev.bus_id, + sizeof(vc->bus_info)); + vc->version = USBVISION_DRIVER_VERSION; + vc->capabilities = (usbvision->have_tuner ? V4L2_CAP_TUNER : 0); + PDEBUG(DBG_IO, "VIDIOC_QUERYCAP"); + return 0; + } + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *ctrl = arg; + int id=ctrl->id; + + memset(ctrl,0,sizeof(*ctrl)); + ctrl->id=id; + + call_i2c_clients(usbvision, cmd, arg); + PDEBUG(DBG_IO,"VIDIOC_QUERYCTRL id=%x value=%x",ctrl->id,ctrl->type); + + if (ctrl->type) + return 0; + else + return -EINVAL; + + } + case VIDIOC_G_CTRL: + { + struct v4l2_control *ctrl = arg; + + call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl); + PDEBUG(DBG_IO,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value); + return 0; + } + case VIDIOC_S_CTRL: + { + struct v4l2_control *ctrl = arg; + + call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl); + PDEBUG(DBG_IO, "VIDIOC_S_CTRL id=%x value=%x",ctrl->id,ctrl->value); + return 0; + } + case VIDIOC_G_TUNER: + { + struct v4l2_tuner *t = arg; + + if (t->index > 0) + return -EINVAL; + + memset(t,0,sizeof(*t)); + strcpy(t->name, "Radio"); + t->type = V4L2_TUNER_RADIO; + + /* Let clients fill in the remainder of this struct */ + call_i2c_clients(usbvision,VIDIOC_G_TUNER,t); + PDEBUG(DBG_IO, "VIDIOC_G_TUNER signal=%x, afc=%x",t->signal,t->afc); + return 0; + } + case VIDIOC_S_TUNER: + { + struct v4l2_tuner *vt = arg; + + // Only no or one tuner for now + if (!usbvision->have_tuner || vt->index) + return -EINVAL; + /* let clients handle this */ + call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt); + + PDEBUG(DBG_IO, "VIDIOC_S_TUNER"); + return 0; + } + case VIDIOC_G_AUDIO: + { + struct v4l2_audio *a = arg; + + memset(a,0,sizeof(*a)); + strcpy(a->name,"Radio"); + PDEBUG(DBG_IO, "VIDIOC_G_AUDIO"); + return 0; + } + case VIDIOC_S_AUDIO: + case VIDIOC_S_INPUT: + case VIDIOC_S_STD: + return 0; + + case VIDIOC_G_FREQUENCY: + { + struct v4l2_frequency *f = arg; + + memset(f,0,sizeof(*f)); + + f->type = V4L2_TUNER_RADIO; + f->frequency = usbvision->freq; + call_i2c_clients(usbvision, cmd, f); + PDEBUG(DBG_IO, "VIDIOC_G_FREQUENCY freq=0x%X", (unsigned)f->frequency); + + return 0; + } + case VIDIOC_S_FREQUENCY: + { + struct v4l2_frequency *f = arg; + + if (f->tuner != 0) + return -EINVAL; + usbvision->freq = f->frequency; + call_i2c_clients(usbvision, cmd, f); + PDEBUG(DBG_IO, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)f->frequency); + + return 0; + } + default: + { + PDEBUG(DBG_IO, "%s: Unknown command %x", __FUNCTION__, cmd); + return -ENOIOCTLCMD; + } + } + return 0; +} + + +static int usbvision_radio_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return video_usercopy(inode, file, cmd, arg, usbvision_do_radio_ioctl); +} + + +/* + * Here comes the stuff for vbi on usbvision based devices + * + */ +static int usbvision_vbi_open(struct inode *inode, struct file *file) +{ + /* TODO */ + return -EINVAL; + +} + +static int usbvision_vbi_close(struct inode *inode, struct file *file) +{ + /* TODO */ + return -EINVAL; +} + +static int usbvision_do_vbi_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) +{ + /* TODO */ + return -EINVAL; +} + +static int usbvision_vbi_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return video_usercopy(inode, file, cmd, arg, usbvision_do_vbi_ioctl); +} + + +// +// Video registration stuff +// + +// Video template +static struct file_operations usbvision_fops = { + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31) + .owner = THIS_MODULE, + #endif + .open = usbvision_v4l2_open, + .release = usbvision_v4l2_close, + .read = usbvision_v4l2_read, + .mmap = usbvision_v4l2_mmap, + .ioctl = usbvision_v4l2_ioctl, + .llseek = no_llseek, +}; +static struct video_device usbvision_video_template = { + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31) + .owner = THIS_MODULE, + #endif + .type = VID_TYPE_TUNER | VID_TYPE_CAPTURE, + .hardware = VID_HARDWARE_USBVISION, + .fops = &usbvision_fops, + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + .name = "usbvision-video", + .release = video_device_release, + #endif + .minor = -1, +}; + + +// Radio template +static struct file_operations usbvision_radio_fops = { + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31) + .owner = THIS_MODULE, + #endif + .open = usbvision_radio_open, + .release = usbvision_radio_close, + .ioctl = usbvision_radio_ioctl, + .llseek = no_llseek, +}; + +static struct video_device usbvision_radio_template= +{ + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31) + .owner = THIS_MODULE, + #endif + .type = VID_TYPE_TUNER, + .hardware = VID_HARDWARE_USBVISION, + .fops = &usbvision_radio_fops, + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + .release = video_device_release, + .name = "usbvision-radio", + #endif + .minor = -1, +}; + + +// vbi template +static struct file_operations usbvision_vbi_fops = { + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31) + .owner = THIS_MODULE, + #endif + .open = usbvision_vbi_open, + .release = usbvision_vbi_close, + .ioctl = usbvision_vbi_ioctl, + .llseek = no_llseek, +}; + +static struct video_device usbvision_vbi_template= +{ + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31) + .owner = THIS_MODULE, + #endif + .type = VID_TYPE_TUNER, + .hardware = VID_HARDWARE_USBVISION, + .fops = &usbvision_vbi_fops, + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + .release = video_device_release, + .name = "usbvision-vbi", + #endif + .minor = -1, +}; + + +static struct video_device *usbvision_vdev_init(struct usb_usbvision *usbvision, + struct video_device *vdev_template, + char *name) +{ + struct usb_device *usb_dev = usbvision->dev; + struct video_device *vdev; + + if (usb_dev == NULL) { + err("%s: usbvision->dev is not set", __FUNCTION__); + return NULL; + } + + vdev = video_device_alloc(); + if (NULL == vdev) { + return NULL; + } + *vdev = *vdev_template; +// vdev->minor = -1; + vdev->dev = &usb_dev->dev; + snprintf(vdev->name, sizeof(vdev->name), "%s", name); + video_set_drvdata(vdev, usbvision); + return vdev; +} + +// unregister video4linux devices +static void usbvision_unregister_video(struct usb_usbvision *usbvision) +{ + // vbi Device: + if (usbvision->vbi) { + PDEBUG(DBG_PROBE, "unregister /dev/vbi%d [v4l2]", usbvision->vbi->minor & 0x1f); + if (usbvision->vbi->minor != -1) { + video_unregister_device(usbvision->vbi); + } + else { + video_device_release(usbvision->vbi); + } + usbvision->vbi = NULL; + } + + // Radio Device: + if (usbvision->rdev) { + PDEBUG(DBG_PROBE, "unregister /dev/radio%d [v4l2]", usbvision->rdev->minor & 0x1f); + if (usbvision->rdev->minor != -1) { + video_unregister_device(usbvision->rdev); + } + else { + video_device_release(usbvision->rdev); + } + usbvision->rdev = NULL; + } + + // Video Device: + if (usbvision->vdev) { + PDEBUG(DBG_PROBE, "unregister /dev/video%d [v4l2]", usbvision->vdev->minor & 0x1f); + if (usbvision->vdev->minor != -1) { + video_unregister_device(usbvision->vdev); + } + else { + video_device_release(usbvision->vdev); + } + usbvision->vdev = NULL; + } +} + +// register video4linux devices +static int __devinit usbvision_register_video(struct usb_usbvision *usbvision) +{ + // Video Device: + usbvision->vdev = usbvision_vdev_init(usbvision, &usbvision_video_template, "USBVision Video"); + if (usbvision->vdev == NULL) { + goto err_exit; + } + if (video_register_device(usbvision->vdev, VFL_TYPE_GRABBER, video_nr)<0) { + goto err_exit; + } + info("USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]", usbvision->nr,usbvision->vdev->minor & 0x1f); + + // Radio Device: + if (usbvision_device_data[usbvision->DevModel].Radio) { + // usbvision has radio + usbvision->rdev = usbvision_vdev_init(usbvision, &usbvision_radio_template, "USBVision Radio"); + if (usbvision->rdev == NULL) { + goto err_exit; + } + if (video_register_device(usbvision->rdev, VFL_TYPE_RADIO, radio_nr)<0) { + goto err_exit; + } + info("USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]", usbvision->nr, usbvision->rdev->minor & 0x1f); + } + // vbi Device: + if (usbvision_device_data[usbvision->DevModel].vbi) { + usbvision->vbi = usbvision_vdev_init(usbvision, &usbvision_vbi_template, "USBVision VBI"); + if (usbvision->vdev == NULL) { + goto err_exit; + } + if (video_register_device(usbvision->vbi, VFL_TYPE_VBI, vbi_nr)<0) { + goto err_exit; + } + info("USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)", usbvision->nr,usbvision->vbi->minor & 0x1f); + } + // all done + return 0; + + err_exit: + err("USBVision[%d]: video_register_device() failed", usbvision->nr); + usbvision_unregister_video(usbvision); + return -1; +} + +/* + * usbvision_alloc() + * + * This code allocates the struct usb_usbvision. It is filled with default values. + * + * Returns NULL on error, a pointer to usb_usbvision else. + * + */ +static struct usb_usbvision *usbvision_alloc(struct usb_device *dev) +{ + struct usb_usbvision *usbvision; + + if ((usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL)) == NULL) { + goto err_exit; + } + + usbvision->dev = dev; + + init_MUTEX(&usbvision->lock); /* to 1 == available */ + + // prepare control urb for control messages during interrupts + usbvision->ctrlUrb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL); + if (usbvision->ctrlUrb == NULL) { + goto err_exit; + } + init_waitqueue_head(&usbvision->ctrlUrb_wq); + init_MUTEX(&usbvision->ctrlUrbLock); /* to 1 == available */ + + usbvision_init_powerOffTimer(usbvision); + + return usbvision; + +err_exit: + if (usbvision && usbvision->ctrlUrb) { + usb_free_urb(usbvision->ctrlUrb); + } + if (usbvision) { + kfree(usbvision); + } + return NULL; +} + +/* + * usbvision_release() + * + * This code does final release of struct usb_usbvision. This happens + * after the device is disconnected -and- all clients closed their files. + * + */ +static void usbvision_release(struct usb_usbvision *usbvision) +{ + PDEBUG(DBG_PROBE, ""); + + down(&usbvision->lock); + + usbvision_reset_powerOffTimer(usbvision); + + usbvision->initialized = 0; + + up(&usbvision->lock); + + usbvision_remove_sysfs(usbvision->vdev); + usbvision_unregister_video(usbvision); + + if (usbvision->ctrlUrb) { + usb_free_urb(usbvision->ctrlUrb); + } + + kfree(usbvision); + + PDEBUG(DBG_PROBE, "success"); +} + + +/******************************** usb interface *****************************************/ + +static void usbvision_configure_video(struct usb_usbvision *usbvision) +{ + int model,i; + + if (usbvision == NULL) + return; + + model = usbvision->DevModel; + usbvision->palette = usbvision_v4l2_format[2]; // V4L2_PIX_FMT_RGB24; + + if (usbvision_device_data[usbvision->DevModel].Vin_Reg2 >= 0) { + usbvision->Vin_Reg2_Preset = usbvision_device_data[usbvision->DevModel].Vin_Reg2 & 0xff; + } else { + usbvision->Vin_Reg2_Preset = 0; + } + + for (i = 0; i < TVNORMS; i++) + if (usbvision_device_data[model].VideoNorm == tvnorms[i].mode) + break; + if (i == TVNORMS) + i = 0; + usbvision->tvnorm = &tvnorms[i]; /* set default norm */ + + usbvision->video_inputs = usbvision_device_data[model].VideoChannels; + usbvision->ctl_input = 0; + + /* This should be here to make i2c clients to be able to register */ + usbvision_audio_off(usbvision); //first switch off audio + if (!PowerOnAtOpen) { + usbvision_power_on(usbvision); //and then power up the noisy tuner + usbvision_init_i2c(usbvision); + } +} + +/* + * usbvision_probe() + * + * This procedure queries device descriptor and accepts the interface + * if it looks like USBVISION video device + * + */ +static int __devinit usbvision_probe(struct usb_interface *intf, const struct usb_device_id *devid) +{ + struct usb_device *dev = interface_to_usbdev(intf); + __u8 ifnum = intf->altsetting->desc.bInterfaceNumber; + const struct usb_host_interface *interface; + struct usb_usbvision *usbvision = NULL; + const struct usb_endpoint_descriptor *endpoint; + int model; + + PDEBUG(DBG_PROBE, "VID=%#04x, PID=%#04x, ifnum=%u", + dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum); + /* Is it an USBVISION video dev? */ + model = 0; + for(model = 0; usbvision_device_data[model].idVendor; model++) { + if (le16_to_cpu(dev->descriptor.idVendor) != usbvision_device_data[model].idVendor) { + continue; + } + if (le16_to_cpu(dev->descriptor.idProduct) != usbvision_device_data[model].idProduct) { + continue; + } + + info("%s: %s found", __FUNCTION__, usbvision_device_data[model].ModelString); + break; + } + + if (usbvision_device_data[model].idVendor == 0) { + return -ENODEV; //no matching device + } + if (usbvision_device_data[model].Interface >= 0) { + interface = &dev->actconfig->interface[usbvision_device_data[model].Interface]->altsetting[0]; + } + else { + interface = &dev->actconfig->interface[ifnum]->altsetting[0]; + } + endpoint = &interface->endpoint[1].desc; + if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC) { + err("%s: interface %d. has non-ISO endpoint!", __FUNCTION__, ifnum); + err("%s: Endpoint attribures %d", __FUNCTION__, endpoint->bmAttributes); + return -ENODEV; + } + if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) { + err("%s: interface %d. has ISO OUT endpoint!", __FUNCTION__, ifnum); + return -ENODEV; + } + + usb_get_dev(dev); + + if ((usbvision = usbvision_alloc(dev)) == NULL) { + err("%s: couldn't allocate USBVision struct", __FUNCTION__); + return -ENOMEM; + } + if (dev->descriptor.bNumConfigurations > 1) { + usbvision->bridgeType = BRIDGE_NT1004; + } + else if (usbvision_device_data[model].ModelString == "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)") { + usbvision->bridgeType = BRIDGE_NT1005; + } + else { + usbvision->bridgeType = BRIDGE_NT1003; + } + PDEBUG(DBG_PROBE, "bridgeType %d", usbvision->bridgeType); + + down(&usbvision->lock); + + usbvision->nr = usbvision_nr++; + + usbvision->have_tuner = usbvision_device_data[model].Tuner; + if (usbvision->have_tuner) { + usbvision->tuner_type = usbvision_device_data[model].TunerType; + } + + usbvision->tuner_addr = ADDR_UNSET; + + usbvision->DevModel = model; + usbvision->remove_pending = 0; + usbvision->iface = ifnum; + usbvision->ifaceAltInactive = 0; + usbvision->ifaceAltActive = 1; + usbvision->video_endp = endpoint->bEndpointAddress; + usbvision->isocPacketSize = 0; + usbvision->usb_bandwidth = 0; + usbvision->user = 0; + usbvision->streaming = Stream_Off; + usbvision_register_video(usbvision); + usbvision_configure_video(usbvision); + up(&usbvision->lock); + + + usb_set_intfdata (intf, usbvision); + usbvision_create_sysfs(usbvision->vdev); + + PDEBUG(DBG_PROBE, "success"); + return 0; +} + + +/* + * usbvision_disconnect() + * + * This procedure stops all driver activity, deallocates interface-private + * structure (pointed by 'ptr') and after that driver should be removable + * with no ill consequences. + * + */ +static void __devexit usbvision_disconnect(struct usb_interface *intf) +{ + struct usb_usbvision *usbvision = usb_get_intfdata(intf); + + PDEBUG(DBG_PROBE, ""); + + if (usbvision == NULL) { + err("%s: usb_get_intfdata() failed", __FUNCTION__); + return; + } + usb_set_intfdata (intf, NULL); + + down(&usbvision->lock); + + // At this time we ask to cancel outstanding URBs + usbvision_stop_isoc(usbvision); + + if (usbvision->power) { + usbvision_i2c_usb_del_bus(&usbvision->i2c_adap); + usbvision_power_off(usbvision); + } + usbvision->remove_pending = 1; // Now all ISO data will be ignored + + usb_put_dev(usbvision->dev); + usbvision->dev = NULL; // USB device is no more + + up(&usbvision->lock); + + if (usbvision->user) { + info("%s: In use, disconnect pending", __FUNCTION__); + wake_up_interruptible(&usbvision->wait_frame); + wake_up_interruptible(&usbvision->wait_stream); + } + else { + usbvision_release(usbvision); + } + + PDEBUG(DBG_PROBE, "success"); + +} + +static struct usb_driver usbvision_driver = { + .name = "usbvision", + .id_table = usbvision_table, + .probe = usbvision_probe, + .disconnect = usbvision_disconnect +}; + +/* + * customdevice_process() + * + * This procedure preprocesses CustomDevice parameter if any + * + */ +void customdevice_process(void) +{ + usbvision_device_data[0]=usbvision_device_data[1]; + usbvision_table[0]=usbvision_table[1]; + + if(CustomDevice) + { + char *parse=CustomDevice; + + PDEBUG(DBG_PROBE, "CustomDevide=%s", CustomDevice); + + /*format is CustomDevice="0x0573 0x4D31 0 7113 3 PAL 1 1 1 5 -1 -1 -1 -1 -1" + usbvision_device_data[0].idVendor; + usbvision_device_data[0].idProduct; + usbvision_device_data[0].Interface; + usbvision_device_data[0].Codec; + usbvision_device_data[0].VideoChannels; + usbvision_device_data[0].VideoNorm; + usbvision_device_data[0].AudioChannels; + usbvision_device_data[0].Radio; + usbvision_device_data[0].Tuner; + usbvision_device_data[0].TunerType; + usbvision_device_data[0].Vin_Reg1; + usbvision_device_data[0].Vin_Reg2; + usbvision_device_data[0].X_Offset; + usbvision_device_data[0].Y_Offset; + usbvision_device_data[0].Dvi_yuv; + usbvision_device_data[0].ModelString; + */ + + rmspace(parse); + usbvision_device_data[0].ModelString="USBVISION Custom Device"; + + parse+=2; + sscanf(parse,"%x",&usbvision_device_data[0].idVendor); + goto2next(parse); + PDEBUG(DBG_PROBE, "idVendor=0x%.4X", usbvision_device_data[0].idVendor); + parse+=2; + sscanf(parse,"%x",&usbvision_device_data[0].idProduct); + goto2next(parse); + PDEBUG(DBG_PROBE, "idProduct=0x%.4X", usbvision_device_data[0].idProduct); + sscanf(parse,"%d",&usbvision_device_data[0].Interface); + goto2next(parse); + PDEBUG(DBG_PROBE, "Interface=%d", usbvision_device_data[0].Interface); + sscanf(parse,"%d",&usbvision_device_data[0].Codec); + goto2next(parse); + PDEBUG(DBG_PROBE, "Codec=%d", usbvision_device_data[0].Codec); + sscanf(parse,"%d",&usbvision_device_data[0].VideoChannels); + goto2next(parse); + PDEBUG(DBG_PROBE, "VideoChannels=%d", usbvision_device_data[0].VideoChannels); + + switch(*parse) + { + case 'P': + PDEBUG(DBG_PROBE, "VideoNorm=PAL"); + usbvision_device_data[0].VideoNorm=VIDEO_MODE_PAL; + break; + + case 'S': + PDEBUG(DBG_PROBE, "VideoNorm=SECAM"); + usbvision_device_data[0].VideoNorm=VIDEO_MODE_SECAM; + break; + + case 'N': + PDEBUG(DBG_PROBE, "VideoNorm=NTSC"); + usbvision_device_data[0].VideoNorm=VIDEO_MODE_NTSC; + break; + + default: + PDEBUG(DBG_PROBE, "VideoNorm=PAL (by default)"); + usbvision_device_data[0].VideoNorm=VIDEO_MODE_PAL; + break; + } + goto2next(parse); + + sscanf(parse,"%d",&usbvision_device_data[0].AudioChannels); + goto2next(parse); + PDEBUG(DBG_PROBE, "AudioChannels=%d", usbvision_device_data[0].AudioChannels); + sscanf(parse,"%d",&usbvision_device_data[0].Radio); + goto2next(parse); + PDEBUG(DBG_PROBE, "Radio=%d", usbvision_device_data[0].Radio); + sscanf(parse,"%d",&usbvision_device_data[0].Tuner); + goto2next(parse); + PDEBUG(DBG_PROBE, "Tuner=%d", usbvision_device_data[0].Tuner); + sscanf(parse,"%d",&usbvision_device_data[0].TunerType); + goto2next(parse); + PDEBUG(DBG_PROBE, "TunerType=%d", usbvision_device_data[0].TunerType); + sscanf(parse,"%d",&usbvision_device_data[0].Vin_Reg1); + goto2next(parse); + PDEBUG(DBG_PROBE, "Vin_Reg1=%d", usbvision_device_data[0].Vin_Reg1); + sscanf(parse,"%d",&usbvision_device_data[0].Vin_Reg2); + goto2next(parse); + PDEBUG(DBG_PROBE, "Vin_Reg2=%d", usbvision_device_data[0].Vin_Reg2); + sscanf(parse,"%d",&usbvision_device_data[0].X_Offset); + goto2next(parse); + PDEBUG(DBG_PROBE, "X_Offset=%d", usbvision_device_data[0].X_Offset); + sscanf(parse,"%d",&usbvision_device_data[0].Y_Offset); + goto2next(parse); + PDEBUG(DBG_PROBE, "Y_Offset=%d", usbvision_device_data[0].Y_Offset); + sscanf(parse,"%d",&usbvision_device_data[0].Dvi_yuv); + PDEBUG(DBG_PROBE, "Dvi_yuv=%d", usbvision_device_data[0].Dvi_yuv); + + //add to usbvision_table also + usbvision_table[0].match_flags=USB_DEVICE_ID_MATCH_DEVICE; + usbvision_table[0].idVendor=usbvision_device_data[0].idVendor; + usbvision_table[0].idProduct=usbvision_device_data[0].idProduct; + + } +} + + + +/* + * usbvision_init() + * + * This code is run to initialize the driver. + * + */ +static int __init usbvision_init(void) +{ + int errCode; + + PDEBUG(DBG_PROBE, ""); + + PDEBUG(DBG_IOCTL, "IOCTL debugging is enabled [video]"); + PDEBUG(DBG_IO, "IO debugging is enabled [video]"); + PDEBUG(DBG_PROBE, "PROBE debugging is enabled [video]"); + PDEBUG(DBG_FUNC, "FUNC debugging is enabled [video]"); + + /* disable planar mode support unless compression enabled */ + if (isocMode != ISOC_MODE_COMPRESS ) { + // FIXME : not the right way to set supported flag + usbvision_v4l2_format[6].supported = 0; // V4L2_PIX_FMT_YVU420 + usbvision_v4l2_format[7].supported = 0; // V4L2_PIX_FMT_YUV422P + } + + customdevice_process(); + + errCode = usb_register(&usbvision_driver); + + if (errCode == 0) { + info(DRIVER_DESC " : " USBVISION_VERSION_STRING); + PDEBUG(DBG_PROBE, "success"); + } + return errCode; +} + +static void __exit usbvision_exit(void) +{ + PDEBUG(DBG_PROBE, ""); + + usb_deregister(&usbvision_driver); + PDEBUG(DBG_PROBE, "success"); +} + +module_init(usbvision_init); +module_exit(usbvision_exit); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h index f304e66b03a..f2eeda8326f 100644 --- a/drivers/media/video/usbvision/usbvision.h +++ b/drivers/media/video/usbvision/usbvision.h @@ -28,7 +28,9 @@ #include #include -#include "usbvision-i2c.h" +#include +#include +#include #ifndef VID_HARDWARE_USBVISION #define VID_HARDWARE_USBVISION 34 /* USBVision Video Grabber */ @@ -139,11 +141,21 @@ #define USBVISION_MAX_ISOC_PACKET_SIZE 959 // NT1003 Specs Document says 1023 #define USBVISION_NUM_HEADERMARKER 20 -#define USBVISION_NUMFRAMES 3 -#define USBVISION_NUMSBUF 2 +#define USBVISION_NUMFRAMES 3 /* Maximum number of frames an application can get */ +#define USBVISION_NUMSBUF 2 /* Dimensioning the USB S buffering */ #define USBVISION_POWEROFF_TIME 3 * (HZ) // 3 seconds + +#define FRAMERATE_MIN 0 +#define FRAMERATE_MAX 31 + +enum { + ISOC_MODE_YUV422 = 0x03, + ISOC_MODE_YUV420 = 0x14, + ISOC_MODE_COMPRESS = 0x60, +}; + /* This macro restricts an int variable to an inclusive range */ #define RESTRICT_TO_RANGE(v,mi,ma) { if ((v) < (mi)) (v) = (mi); else if ((v) > (ma)) (v) = (ma); } @@ -181,8 +193,6 @@ mr = LIMIT_RGB(mm_r); \ } - - /* Debugging aid */ #define USBVISION_SAY_AND_WAIT(what) { \ wait_queue_head_t wq; \ @@ -202,7 +212,23 @@ ((udevice)->last_error == 0) && \ (!(udevice)->remove_pending)) +/* I2C structures */ +struct i2c_algo_usb_data { + void *data; /* private data for lowlevel routines */ + int (*inb) (void *data, unsigned char addr, char *buf, short len); + int (*outb) (void *data, unsigned char addr, char *buf, short len); + + /* local settings */ + int udelay; + int mdelay; + int timeout; +}; +#define I2C_USB_ADAP_MAX 16 + +/* ----------------------------------------------------------------- */ +/* usbvision video structures */ +/* ----------------------------------------------------------------- */ enum ScanState { ScanState_Scanning, /* Scanning for header */ ScanState_Lines /* Parsing lines */ @@ -347,7 +373,6 @@ struct usb_usbvision { struct video_device *vdev; /* Video Device */ struct video_device *rdev; /* Radio Device */ struct video_device *vbi; /* VBI Device */ - struct video_audio audio_dev; /* Current audio params */ /* i2c Declaration Section*/ struct i2c_adapter i2c_adap; @@ -361,6 +386,7 @@ struct usb_usbvision { wait_queue_head_t ctrlUrb_wq; // Processes waiting struct semaphore ctrlUrbLock; + /* configuration part */ int have_tuner; int tuner_type; int tuner_addr; @@ -372,7 +398,7 @@ struct usb_usbvision { int AudioMute; int AudioChannel; int isocMode; // format of video data for the usb isoc-transfer - unsigned int nr; // Number of the device < MAX_USBVISION + unsigned int nr; // Number of the device /* Device structure */ struct usb_device *dev; @@ -384,7 +410,6 @@ struct usb_usbvision { struct work_struct powerOffWork; int power; /* is the device powered on? */ int user; /* user count for exclusive use */ - int usbvision_used; /* Is this structure in use? */ int initialized; /* Had we already sent init sequence? */ int DevModel; /* What type of USBVISION device we got? */ enum StreamState streaming; /* Are we streaming Isochronous? */ @@ -402,7 +427,6 @@ struct usb_usbvision { wait_queue_head_t wait_stream; /* Processes waiting */ struct usbvision_frame *curFrame; // pointer to current frame, set by usbvision_find_header struct usbvision_frame frame[USBVISION_NUMFRAMES]; // frame buffer - int curSbufNum; // number of current receiving sbuf struct usbvision_sbuf sbuf[USBVISION_NUMSBUF]; // S buffering volatile int remove_pending; /* If set then about to exit */ @@ -413,13 +437,7 @@ struct usb_usbvision { int scratch_headermarker[USBVISION_NUM_HEADERMARKER]; int scratch_headermarker_read_ptr; int scratch_headermarker_write_ptr; - int isocstate; - /* color controls */ - int saturation; - int hue; - int brightness; - int contrast; - int depth; + enum IsocState isocstate; struct usbvision_v4l2_format_st palette; struct v4l2_capability vcap; /* Video capabilities */ @@ -427,17 +445,6 @@ struct usb_usbvision { struct usbvision_tvnorm *tvnorm; /* selected tv norm */ unsigned char video_endp; /* 0x82 for USBVISION devices based */ - // Overlay stuff: - struct v4l2_framebuffer vid_buf; - struct v4l2_format vid_win; - int vid_buf_valid; // Status: video buffer is valid (set) - int vid_win_valid; // Status: video window is valid (set) - int overlay; /*Status: Are we overlaying? */ - unsigned int clipmask[USBVISION_CLIPMASK_SIZE / 4]; - unsigned char *overlay_base; /* Virtual base address of video buffer */ - unsigned char *overlay_win; /* virt start address of overlay window */ - struct usbvision_frame overlay_frame; - // Decompression stuff: unsigned char *IntraFrameBuffer; /* Buffer for reference frame */ int BlockPos; //for test only @@ -449,16 +456,6 @@ struct usb_usbvision { int lastComprLevel; // How strong (100) or weak (0) was compression int usb_bandwidth; /* Mbit/s */ - /* /proc entries, relative to /proc/video/usbvision/ */ - struct proc_dir_entry *proc_devdir; /* Per-device proc directory */ - struct proc_dir_entry *proc_info; /* /info entry */ - struct proc_dir_entry *proc_register; /* /register entry */ - struct proc_dir_entry *proc_freq; /* /freq entry */ - struct proc_dir_entry *proc_input; /* /input entry */ - struct proc_dir_entry *proc_frame; /* /frame entry */ - struct proc_dir_entry *proc_button; /* /button entry */ - struct proc_dir_entry *proc_control; /* /control entry */ - /* Statistics that can be overlayed on the screen */ unsigned long isocUrbCount; // How many URBs we received so far unsigned long urb_length; /* Length of last URB */ @@ -479,6 +476,70 @@ struct usb_usbvision { int ComprBlockTypes[4]; }; + +/* --------------------------------------------------------------- */ +/* defined in usbvision-i2c.c */ +/* i2c-algo-usb declaration */ +/* --------------------------------------------------------------- */ + +int usbvision_i2c_usb_add_bus(struct i2c_adapter *); +int usbvision_i2c_usb_del_bus(struct i2c_adapter *); + +static inline void *i2c_get_algo_usb_data (struct i2c_algo_usb_data *dev) +{ + return dev->data; +} + +static inline void i2c_set_algo_usb_data (struct i2c_algo_usb_data *dev, void *data) +{ + dev->data = data; +} + + +/* ----------------------------------------------------------------------- */ +/* usbvision specific I2C functions */ +/* ----------------------------------------------------------------------- */ +int usbvision_init_i2c(struct usb_usbvision *usbvision); +void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd,void *arg); + +/* defined in usbvision-core.c */ +void *usbvision_rvmalloc(unsigned long size); +void usbvision_rvfree(void *mem, unsigned long size); +int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg); +int usbvision_write_reg(struct usb_usbvision *usbvision, unsigned char reg, + unsigned char value); + +int usbvision_frames_alloc(struct usb_usbvision *usbvision); +void usbvision_frames_free(struct usb_usbvision *usbvision); +int usbvision_scratch_alloc(struct usb_usbvision *usbvision); +void usbvision_scratch_free(struct usb_usbvision *usbvision); +int usbvision_sbuf_alloc(struct usb_usbvision *usbvision); +void usbvision_sbuf_free(struct usb_usbvision *usbvision); +int usbvision_decompress_alloc(struct usb_usbvision *usbvision); +void usbvision_decompress_free(struct usb_usbvision *usbvision); + +int usbvision_setup(struct usb_usbvision *usbvision,int format); +int usbvision_init_isoc(struct usb_usbvision *usbvision); +int usbvision_restart_isoc(struct usb_usbvision *usbvision); +void usbvision_stop_isoc(struct usb_usbvision *usbvision); + +int usbvision_set_audio(struct usb_usbvision *usbvision, int AudioChannel); +int usbvision_audio_off(struct usb_usbvision *usbvision); + +int usbvision_begin_streaming(struct usb_usbvision *usbvision); +void usbvision_empty_framequeues(struct usb_usbvision *dev); +int usbvision_stream_interrupt(struct usb_usbvision *dev); + +int usbvision_muxsel(struct usb_usbvision *usbvision, int channel); +int usbvision_set_input(struct usb_usbvision *usbvision); +int usbvision_set_output(struct usb_usbvision *usbvision, int width, int height); + +void usbvision_init_powerOffTimer(struct usb_usbvision *usbvision); +void usbvision_set_powerOffTimer(struct usb_usbvision *usbvision); +void usbvision_reset_powerOffTimer(struct usb_usbvision *usbvision); +int usbvision_power_off(struct usb_usbvision *usbvision); +int usbvision_power_on(struct usb_usbvision *usbvision); + #endif /* __LINUX_USBVISION_H */ /* -- cgit v1.2.3 From 7ca659e3c1c3dd67073751385ae3bd25b27526bb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Dec 2006 11:43:31 -0300 Subject: V4L/DVB (4942): Whitespace cleanups Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/usbvision/usbvision-cards.c | 46 ++++++++++++------------- drivers/media/video/usbvision/usbvision-core.c | 2 +- drivers/media/video/usbvision/usbvision-video.c | 2 +- 3 files changed, 25 insertions(+), 25 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c index f1fb9e752b5..134eb9865df 100644 --- a/drivers/media/video/usbvision/usbvision-cards.c +++ b/drivers/media/video/usbvision/usbvision-cards.c @@ -1,4 +1,4 @@ -/* +/* * USBVISION.H * usbvision header file * @@ -31,18 +31,18 @@ /* Supported Devices: A table for usbvision.c*/ struct usbvision_device_data_st usbvision_device_data[] = { - {0xFFF0, 0xFFF0, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Custom Dummy USBVision Device"}, - {0x0A6F, 0x0400, -1, CODEC_SAA7113, 4, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, -1, -1, -1, "Xanboo"}, + {0xFFF0, 0xFFF0, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Custom Dummy USBVision Device"}, + {0x0A6F, 0x0400, -1, CODEC_SAA7113, 4, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, -1, -1, -1, "Xanboo"}, {0x050D, 0x0208, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 1, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Belkin USBView II"}, - {0x0571, 0x0002, 0, CODEC_SAA7111, 2, V4L2_STD_PAL, 0, 0, 1, 0, 0, -1, -1, -1, -1, 7, "echoFX InterView Lite"}, + {0x0571, 0x0002, 0, CODEC_SAA7111, 2, V4L2_STD_PAL, 0, 0, 1, 0, 0, -1, -1, -1, -1, 7, "echoFX InterView Lite"}, {0x0573, 0x0003, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, -1, -1, -1, "USBGear USBG-V1 resp. HAMA USB"}, {0x0573, 0x0400, -1, CODEC_SAA7113, 4, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "D-Link V100"}, {0x0573, 0x2000, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, -1, -1, -1, "X10 USB Camera"}, - {0x0573, 0x2d00, -1, CODEC_SAA7111, 2, V4L2_STD_PAL, 1, 0, 1, 0, 0, -1, -1, -1, 3, 7, "Osprey 50"}, - {0x0573, 0x2d01, -1, CODEC_SAA7113, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Hauppauge USB-Live Model 600"}, + {0x0573, 0x2d00, -1, CODEC_SAA7111, 2, V4L2_STD_PAL, 1, 0, 1, 0, 0, -1, -1, -1, 3, 7, "Osprey 50"}, + {0x0573, 0x2d01, -1, CODEC_SAA7113, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Hauppauge USB-Live Model 600"}, {0x0573, 0x2101, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 2, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Zoran Co. PMD (Nogatech) AV-grabber Manhattan"}, {0x0573, 0x4100, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, 20, -1, "Nogatech USB-TV (NTSC) FM"}, - {0x0573, 0x4110, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, 20, -1, "PNY USB-TV (NTSC) FM"}, + {0x0573, 0x4110, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, 20, -1, "PNY USB-TV (NTSC) FM"}, {0x0573, 0x4450, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "PixelView PlayTv-USB PRO (PAL) FM"}, {0x0573, 0x4550, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "ZTV ZT-721 2.4GHz USB A/V Receiver"}, {0x0573, 0x4d00, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, 20, -1, "Hauppauge WinTv-USB USA"}, @@ -52,9 +52,9 @@ struct usbvision_device_data_st usbvision_device_data[] = { {0x0573, 0x4d10, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (NTSC) FM"}, {0x0573, 0x4d11, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (PAL) FM"}, {0x0573, 0x4d12, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB (PAL) FM"}, - {0x0573, 0x4d2a, 0, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_MICROTUNE_4049FM5, -1, -1, 0, 3, 7, "Hauppauge WinTv USB (NTSC) FM Model 602 40201 Rev B285"}, + {0x0573, 0x4d2a, 0, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_MICROTUNE_4049FM5, -1, -1, 0, 3, 7, "Hauppauge WinTv USB (NTSC) FM Model 602 40201 Rev B285"}, {0x0573, 0x4d2b, 0, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_MICROTUNE_4049FM5, -1, -1, 0, 3, 7, "Hauppauge WinTv USB (NTSC) FM Model 602 40201 Rev B282"}, - {0x0573, 0x4d2c, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_FM1216ME_MK3, -1, -1, 0, 3, 7, "Hauppauge WinTv USB (PAL/SECAM) 40209 Rev E1A5"}, + {0x0573, 0x4d2c, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_FM1216ME_MK3, -1, -1, 0, 3, 7, "Hauppauge WinTv USB (PAL/SECAM) 40209 Rev E1A5"}, {0x0573, 0x4d20, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB II (PAL) FM Model 40201 Rev B226"}, {0x0573, 0x4d21, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB II (PAL)"}, {0x0573, 0x4d22, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB II (PAL) MODEL 566"}, @@ -62,20 +62,20 @@ struct usbvision_device_data_st usbvision_device_data[] = { {0x0573, 0x4d25, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB (SECAM) Model 40209 Rev B234"}, {0x0573, 0x4d26, -1, CODEC_SAA7113, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB (SECAM) Model 40209 Rev B243"}, {0x0573, 0x4d27, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_ALPS_TSBE1_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB Model 40204 Rev B281"}, - {0x0573, 0x4d28, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_ALPS_TSBE1_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB Model 40204 Rev B283"}, - {0x0573, 0x4d29, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB Model 40205 Rev B298"}, + {0x0573, 0x4d28, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_ALPS_TSBE1_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB Model 40204 Rev B283"}, + {0x0573, 0x4d29, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB Model 40205 Rev B298"}, {0x0573, 0x4d30, -1, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB FM Model 40211 Rev B123"}, {0x0573, 0x4d31, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB III (PAL) FM Model 568"}, - {0x0573, 0x4d32, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB III (PAL) FM Model 573"}, + {0x0573, 0x4d32, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB III (PAL) FM Model 573"}, {0x0573, 0x4d35, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_MICROTUNE_4049FM5, -1, -1, 0, 3, 7, "Hauppauge WinTv-USB III (PAL) FM Model 40219 Rev B252"}, {0x0573, 0x4d37, 0, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_FM1216ME_MK3, -1, -1, 0, 3, 7, "Hauppauge WinTV USB device Model 40219 Rev E189"}, {0x0768, 0x0006, -1, CODEC_SAA7113, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, 5, 5, -1, "Camtel Technology USB TV Genie Pro FM Model TVB330"}, {0x07d0, 0x0001, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Digital Video Creator I"}, - {0x07d0, 0x0002, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 82, 20, 7, "Global Village GV-007 (NTSC)"}, + {0x07d0, 0x0002, -1, CODEC_SAA7111, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 82, 20, 7, "Global Village GV-007 (NTSC)"}, {0x07d0, 0x0003, 0, CODEC_SAA7113, 2, V4L2_STD_NTSC, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-50 Rev 1 (NTSC)"}, {0x07d0, 0x0004, 0, CODEC_SAA7113, 2, V4L2_STD_PAL, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-80 Rev 1 (PAL)"}, - {0x07d0, 0x0005, 0, CODEC_SAA7113, 2, V4L2_STD_SECAM, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)"}, - {0x2304, 0x010d, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 0, 0, 1, TUNER_TEMIC_4066FY5_PAL_I, -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (PAL)"}, + {0x07d0, 0x0005, 0, CODEC_SAA7113, 2, V4L2_STD_SECAM, 0, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)"}, + {0x2304, 0x010d, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 0, 0, 1, TUNER_TEMIC_4066FY5_PAL_I, -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (PAL)"}, {0x2304, 0x0109, -1, CODEC_SAA7111, 3, V4L2_STD_SECAM, 1, 0, 1, 1, TUNER_PHILIPS_SECAM, -1, -1, -1, -1, -1, "Pinnacle Studio PCTV USB (SECAM)"}, {0x2304, 0x0110, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_PHILIPS_PAL, -1, -1,128, 23, -1, "Pinnacle Studio PCTV USB (PAL) FM"}, {0x2304, 0x0111, -1, CODEC_SAA7111, 3, V4L2_STD_PAL, 1, 0, 1, 1, TUNER_PHILIPS_PAL, -1, -1, -1, -1, -1, "Miro PCTV USB"}, @@ -84,7 +84,7 @@ struct usbvision_device_data_st usbvision_device_data[] = { {0x2304, 0x0212, -1, CODEC_SAA7111, 3, V4L2_STD_NTSC, 1, 1, 1, 1, TUNER_TEMIC_4039FR5_NTSC, -1, -1, 0, 3, 7, "Pinnacle Studio PCTV USB (NTSC) FM"}, {0x2304, 0x0214, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL, -1, -1, 0, 3, 7, "Pinnacle Studio PCTV USB (PAL) FM"}, {0x2304, 0x0300, -1, CODEC_SAA7113, 2, V4L2_STD_NTSC, 1, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Pinnacle Studio Linx Video input cable (NTSC)"}, - {0x2304, 0x0301, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 1, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Pinnacle Studio Linx Video input cable (PAL)"}, + {0x2304, 0x0301, -1, CODEC_SAA7113, 2, V4L2_STD_PAL, 1, 0, 1, 0, 0, -1, -1, 0, 3, 7, "Pinnacle Studio Linx Video input cable (PAL)"}, {0x2304, 0x0419, -1, CODEC_SAA7113, 3, V4L2_STD_PAL, 1, 1, 1, 1, TUNER_TEMIC_4009FR5_PAL, -1, -1, 0, 3, 7, "Pinnacle PCTV Bungee USB (PAL) FM"}, {0x2400, 0x4200, -1, CODEC_SAA7111, 3, VIDEO_MODE_NTSC, 1, 0, 1, 1, TUNER_PHILIPS_NTSC_M, -1, -1, -1, -1, -1, "Hauppauge WinTv-USB"}, {} /* Terminating entry */ @@ -94,13 +94,13 @@ struct usbvision_device_data_st usbvision_device_data[] = { struct usb_device_id usbvision_table [] = { { USB_DEVICE(0xFFF0, 0xFFF0) }, /* Custom Dummy USBVision Device */ - { USB_DEVICE(0x0A6F, 0x0400) }, /* Xanboo */ + { USB_DEVICE(0x0A6F, 0x0400) }, /* Xanboo */ { USB_DEVICE(0x050d, 0x0208) }, /* Belkin USBView II */ { USB_DEVICE(0x0571, 0x0002) }, /* echoFX InterView Lite */ { USB_DEVICE(0x0573, 0x0003) }, /* USBGear USBG-V1 */ { USB_DEVICE(0x0573, 0x0400) }, /* D-Link V100 */ { USB_DEVICE(0x0573, 0x2000) }, /* X10 USB Camera */ - { USB_DEVICE(0x0573, 0x2d00) }, /* Osprey 50 */ + { USB_DEVICE(0x0573, 0x2d00) }, /* Osprey 50 */ { USB_DEVICE(0x0573, 0x2d01) }, /* Hauppauge USB-Live Model 600 */ { USB_DEVICE(0x0573, 0x2101) }, /* Zoran Co. PMD (Nogatech) AV-grabber Manhattan */ { USB_DEVICE(0x0573, 0x4100) }, /* Nogatech USB-TV FM (NTSC) */ @@ -114,9 +114,9 @@ struct usb_device_id usbvision_table [] = { { USB_DEVICE(0x0573, 0x4d10) }, /* Hauppauge WinTv-USB with FM USA radio */ { USB_DEVICE(0x0573, 0x4d11) }, /* Hauppauge WinTv-USB (PAL) with FM radio */ { USB_DEVICE(0x0573, 0x4d12) }, /* Hauppauge WinTv-USB UK with FM Radio */ - { USB_DEVICE(0x0573, 0x4d2a) }, /* Hauppague WinTv USB Model 602 40201 Rev B285 */ + { USB_DEVICE(0x0573, 0x4d2a) }, /* Hauppague WinTv USB Model 602 40201 Rev B285 */ { USB_DEVICE(0x0573, 0x4d2b) }, /* Hauppague WinTv USB Model 602 40201 Rev B282 */ - { USB_DEVICE(0x0573, 0x4d2c) }, /* Hauppague WinTv USB Model 40209 Rev. E1A5 PAL*/ + { USB_DEVICE(0x0573, 0x4d2c) }, /* Hauppague WinTv USB Model 40209 Rev. E1A5 PAL*/ { USB_DEVICE(0x0573, 0x4d20) }, /* Hauppauge WinTv-USB II (PAL) FM Model 40201 Rev B226 */ { USB_DEVICE(0x0573, 0x4d21) }, /* Hauppauge WinTv-USB II (PAL) with FM radio*/ { USB_DEVICE(0x0573, 0x4d22) }, /* Hauppauge WinTv-USB II (PAL) Model 566 */ @@ -125,7 +125,7 @@ struct usb_device_id usbvision_table [] = { { USB_DEVICE(0x0573, 0x4d26) }, /* Hauppauge WinTv-USB Model 40209 Rev B243 */ { USB_DEVICE(0x0573, 0x4d27) }, /* Hauppauge WinTv-USB Model 40204 Rev B281 */ { USB_DEVICE(0x0573, 0x4d28) }, /* Hauppauge WinTv-USB Model 40204 Rev B283 */ - { USB_DEVICE(0x0573, 0x4d29) }, /* Hauppauge WinTv-USB Model 40205 Rev B298 */ + { USB_DEVICE(0x0573, 0x4d29) }, /* Hauppauge WinTv-USB Model 40205 Rev B298 */ { USB_DEVICE(0x0573, 0x4d30) }, /* Hauppauge WinTv-USB FM Model 40211 Rev B123 */ { USB_DEVICE(0x0573, 0x4d31) }, /* Hauppauge WinTv-USB III (PAL) with FM radio Model 568 */ { USB_DEVICE(0x0573, 0x4d32) }, /* Hauppauge WinTv-USB III (PAL) FM Model 573 */ @@ -136,7 +136,7 @@ struct usb_device_id usbvision_table [] = { { USB_DEVICE(0x07d0, 0x0002) }, /* Global Village GV-007 (NTSC) */ { USB_DEVICE(0x07d0, 0x0003) }, /* Dazzle Fusion Model DVC-50 Rev 1 (NTSC) */ { USB_DEVICE(0x07d0, 0x0004) }, /* Dazzle Fusion Model DVC-80 Rev 1 (PAL) */ - { USB_DEVICE(0x07d0, 0x0005) }, /* Dazzle Fusion Model DVC-90 Rev 1 (SECAM) */ + { USB_DEVICE(0x07d0, 0x0005) }, /* Dazzle Fusion Model DVC-90 Rev 1 (SECAM) */ { USB_DEVICE(0x2304, 0x010d) }, /* Pinnacle Studio PCTV USB (PAL) */ { USB_DEVICE(0x2304, 0x0109) }, /* Pinnacle Studio PCTV USB (SECAM) */ { USB_DEVICE(0x2304, 0x0110) }, /* Pinnacle Studio PCTV USB (PAL) */ @@ -146,7 +146,7 @@ struct usb_device_id usbvision_table [] = { { USB_DEVICE(0x2304, 0x0212) }, /* Pinnacle Studio PCTV USB (NTSC) with FM radio */ { USB_DEVICE(0x2304, 0x0214) }, /* Pinnacle Studio PCTV USB (PAL) with FM radio */ { USB_DEVICE(0x2304, 0x0300) }, /* Pinnacle Studio Linx Video input cable (NTSC) */ - { USB_DEVICE(0x2304, 0x0301) }, /* Pinnacle Studio Linx Video input cable (PAL) */ + { USB_DEVICE(0x2304, 0x0301) }, /* Pinnacle Studio Linx Video input cable (PAL) */ { USB_DEVICE(0x2304, 0x0419) }, /* Pinnacle PCTV Bungee USB (PAL) FM */ { USB_DEVICE(0x2400, 0x4200) }, /* Hauppauge WinTv-USB2 Model 42012 */ diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index cf787d8ab6d..cf5d4771312 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -1,6 +1,6 @@ /* * usbvision-core.c - driver for NT100x USB video capture devices - * + * * * Copyright (c) 1999-2005 Joerg Heckenbach * Dwaine Garden diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index 7e26d833688..ab29ddb6826 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -1,5 +1,5 @@ /* - * USB USBVISION Video device driver 0.9.9 + * USB USBVISION Video device driver 0.9.9 * * * -- cgit v1.2.3 From a1ed551cdb4f29157466340760fde68bcda704a9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Dec 2006 11:41:59 -0300 Subject: V4L/DVB (4941): Remove LINUX_VERSION_CODE and fix identations Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/usbvision/usbvision-core.c | 22 +++++---------------- drivers/media/video/usbvision/usbvision-i2c.c | 14 +++++-------- drivers/media/video/usbvision/usbvision-video.c | 26 ++++--------------------- 3 files changed, 14 insertions(+), 48 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index cf5d4771312..e660a91d825 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -47,8 +47,8 @@ #include #include - #include - #include +#include +#include #ifdef CONFIG_KMOD #include @@ -1397,7 +1397,7 @@ static int usbvision_compress_isochronous(struct usb_usbvision *usbvision, return totlen; } -static void usbvision_isocIrq(struct urb *urb, struct pt_regs *regs) +static void usbvision_isocIrq(struct urb *urb) { int errCode = 0; int len; @@ -1529,7 +1529,7 @@ int usbvision_write_reg(struct usb_usbvision *usbvision, unsigned char reg, } -static void usbvision_ctrlUrb_complete(struct urb *urb, struct pt_regs *regs) +static void usbvision_ctrlUrb_complete(struct urb *urb) { struct usb_usbvision *usbvision = (struct usb_usbvision *)urb->context; @@ -2416,11 +2416,7 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision) int j, k; struct urb *urb; - #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - urb = usb_alloc_urb(USBVISION_URB_FRAMES); - #else - urb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL); - #endif + urb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL); if (urb == NULL) { err("%s: usb_alloc_urb() failed", __FUNCTION__); return -ENOMEM; @@ -2429,12 +2425,8 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision) urb->dev = dev; urb->context = usbvision; urb->pipe = usb_rcvisocpipe(dev, usbvision->video_endp); - #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - urb->transfer_flags = USB_ISO_ASAP; - #else urb->transfer_flags = URB_ISO_ASAP; urb->interval = 1; - #endif urb->transfer_buffer = usbvision->sbuf[bufIdx].data; urb->complete = usbvision_isocIrq; urb->number_of_packets = USBVISION_URB_FRAMES; @@ -2450,11 +2442,7 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision) /* Submit all URBs */ for (bufIdx = 0; bufIdx < USBVISION_NUMSBUF; bufIdx++) { - #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - errCode = usb_submit_urb(usbvision->sbuf[bufIdx].urb); - #else errCode = usb_submit_urb(usbvision->sbuf[bufIdx].urb, GFP_KERNEL); - #endif if (errCode) { err("%s: usb_submit_urb(%d) failed: error %d", __FUNCTION__, bufIdx, errCode); } diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c index 2de74e48cbe..92bf9a1f1e2 100644 --- a/drivers/media/video/usbvision/usbvision-i2c.c +++ b/drivers/media/video/usbvision/usbvision-i2c.c @@ -29,7 +29,7 @@ #include #include #include - #include +#include #include #include #include @@ -350,13 +350,9 @@ static int detach_inform(struct i2c_client *client) { struct usb_usbvision *usbvision; - #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - usbvision = (struct usb_usbvision *)client->adapter->data; - #else - usbvision = (struct usb_usbvision *)i2c_get_adapdata(client->adapter); - #endif + usbvision = (struct usb_usbvision *)i2c_get_adapdata(client->adapter); - PDEBUG(DBG_I2C,"usbvision[%d] detaches %s", usbvision->nr, client->name); + PDEBUG(DBG_I2C,"usbvision[%d] detaches %s", usbvision->nr, client->name); return 0; } @@ -548,9 +544,9 @@ static struct i2c_adapter i2c_adap_template = { .algo_data = NULL, .client_register = attach_inform, .client_unregister = detach_inform, -#if defined (I2C_ADAP_CLASS_TV_ANALOG) +#ifdef I2C_ADAP_CLASS_TV_ANALOG .class = I2C_ADAP_CLASS_TV_ANALOG, -#elif defined (I2C_CLASS_TV_ANALOG) +#else .class = I2C_CLASS_TV_ANALOG, #endif }; diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index ab29ddb6826..1285b93d0eb 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -68,8 +68,8 @@ #include #include - #include - #include +#include +#include #ifdef CONFIG_KMOD #include @@ -189,8 +189,8 @@ MODULE_PARM_DESC(CustomDevice, " Define the fine tuning parameters for the devic MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE(DRIVER_LICENSE); - MODULE_VERSION(USBVISION_VERSION_STRING); - MODULE_ALIAS(DRIVER_ALIAS); +MODULE_VERSION(USBVISION_VERSION_STRING); +MODULE_ALIAS(DRIVER_ALIAS); /****************************************************************************************/ @@ -1430,9 +1430,7 @@ static int usbvision_vbi_ioctl(struct inode *inode, struct file *file, // Video template static struct file_operations usbvision_fops = { - #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31) .owner = THIS_MODULE, - #endif .open = usbvision_v4l2_open, .release = usbvision_v4l2_close, .read = usbvision_v4l2_read, @@ -1441,25 +1439,19 @@ static struct file_operations usbvision_fops = { .llseek = no_llseek, }; static struct video_device usbvision_video_template = { - #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31) .owner = THIS_MODULE, - #endif .type = VID_TYPE_TUNER | VID_TYPE_CAPTURE, .hardware = VID_HARDWARE_USBVISION, .fops = &usbvision_fops, - #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) .name = "usbvision-video", .release = video_device_release, - #endif .minor = -1, }; // Radio template static struct file_operations usbvision_radio_fops = { - #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31) .owner = THIS_MODULE, - #endif .open = usbvision_radio_open, .release = usbvision_radio_close, .ioctl = usbvision_radio_ioctl, @@ -1468,25 +1460,19 @@ static struct file_operations usbvision_radio_fops = { static struct video_device usbvision_radio_template= { - #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31) .owner = THIS_MODULE, - #endif .type = VID_TYPE_TUNER, .hardware = VID_HARDWARE_USBVISION, .fops = &usbvision_radio_fops, - #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) .release = video_device_release, .name = "usbvision-radio", - #endif .minor = -1, }; // vbi template static struct file_operations usbvision_vbi_fops = { - #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31) .owner = THIS_MODULE, - #endif .open = usbvision_vbi_open, .release = usbvision_vbi_close, .ioctl = usbvision_vbi_ioctl, @@ -1495,16 +1481,12 @@ static struct file_operations usbvision_vbi_fops = { static struct video_device usbvision_vbi_template= { - #if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,31) .owner = THIS_MODULE, - #endif .type = VID_TYPE_TUNER, .hardware = VID_HARDWARE_USBVISION, .fops = &usbvision_vbi_fops, - #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) .release = video_device_release, .name = "usbvision-vbi", - #endif .minor = -1, }; -- cgit v1.2.3 From 1c5ee876d697a9d1b70117e4277eaa445d14a728 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Mon, 4 Dec 2006 18:04:11 -0300 Subject: V4L/DVB (4938): Cx88: Convert lgdt3302 tuning function to use dvb_pll_attach There was a still a pre-dvb-pll set_params function for the lgdt3302 in the cx88-dvb driver. This patch removes that function and uses dvb_pll_attach() for the cards that were using it (Dvico FusionHDTV 3 GOLD {Q,T}). This way the set_params function from dvb-pll is used. dvb_attach() is in turn used on dvb_pll_attach(), eliminating some static dependencies on dvb-pll. There are still a couple static dependencies on dvb-pll remaining. Signed-off-by: Trent Piepho Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-dvb.c | 38 ++++--------------------------------- 1 file changed, 4 insertions(+), 34 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 0266a3616ce..95db017badd 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -360,38 +360,6 @@ static struct or51132_config pchdtv_hd3000 = { .set_ts_params = or51132_set_ts_param, }; -static int lgdt3302_tuner_set_params(struct dvb_frontend* fe, - struct dvb_frontend_parameters* params) -{ - /* FIXME make this routine use the tuner-simple code. - * It could probably be shared with a number of ATSC - * frontends. Many share the same tuner with analog TV. */ - - struct cx8802_dev *dev= fe->dvb->priv; - struct cx88_core *core = dev->core; - u8 buf[4]; - struct i2c_msg msg = - { .addr = dev->core->pll_addr, .flags = 0, .buf = buf, .len = 4 }; - int err; - - dvb_pll_configure(core->pll_desc, buf, params->frequency, 0); - dprintk(1, "%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n", - __FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if ((err = i2c_transfer(&core->i2c_adap, &msg, 1)) != 1) { - printk(KERN_WARNING "cx88-dvb: %s error " - "(addr %02x <- %02x, err = %i)\n", - __FUNCTION__, buf[0], buf[1], err); - if (err < 0) - return err; - else - return -EREMOTEIO; - } - return 0; -} - static int lgdt330x_pll_rf_set(struct dvb_frontend* fe, int index) { struct cx8802_dev *dev= fe->dvb->priv; @@ -669,7 +637,8 @@ static int dvb_register(struct cx8802_dev *dev) &fusionhdtv_3_gold, &dev->core->i2c_adap); if (dev->dvb.frontend != NULL) { - dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3302_tuner_set_params; + dvb_attach(dvb_pll_attach, dev->dvb.frontend, dev->core->pll_addr, + &dev->core->i2c_adap, dev->core->pll_desc); } } break; @@ -689,7 +658,8 @@ static int dvb_register(struct cx8802_dev *dev) &fusionhdtv_3_gold, &dev->core->i2c_adap); if (dev->dvb.frontend != NULL) { - dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3302_tuner_set_params; + dvb_attach(dvb_pll_attach, dev->dvb.frontend, dev->core->pll_addr, + &dev->core->i2c_adap, dev->core->pll_desc); } } break; -- cgit v1.2.3 From f30ebd43597e9b2bbbc8b0eb650f5aad545e255b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Dec 2006 12:32:18 -0300 Subject: V4L/DVB (4951): Add version.h, since it is required for VIDIOC_QUERYCAP Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/usbvision/usbvision-video.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media/video') diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index 1285b93d0eb..3f3839be561 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -44,6 +44,7 @@ * */ +#include #include #include #include -- cgit v1.2.3 From c876a3468d0f136710af81595177889953d1ff71 Mon Sep 17 00:00:00 2001 From: Thierry MERLE Date: Sat, 9 Dec 2006 16:42:54 -0300 Subject: V4L/DVB (4953): Usbvision minor fixes - fix debug outputs - fix returned parameters on VIDIOC_G_FMT, VIDIOC_S_FMT and VIDIOC_TRY_FMT and mmap size setting Signed-off-by: Thierry MERLE Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/usbvision/usbvision-core.c | 1 + drivers/media/video/usbvision/usbvision-video.c | 28 ++++++++++++++++--------- drivers/media/video/usbvision/usbvision.h | 7 +++++++ 3 files changed, 26 insertions(+), 10 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index e660a91d825..9163b60c7f9 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -87,6 +87,7 @@ MODULE_PARM_DESC(SwitchSVideoInput, " Set the S-Video input. Some cables and in #define DBG_ISOC 1<<2 #define DBG_PARSE 1<<3 #define DBG_SCRATCH 1<<4 +#define DBG_FUNC 1<<5 static const int max_imgwidth = MAX_FRAME_WIDTH; static const int max_imgheight = MAX_FRAME_HEIGHT; diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index 3f3839be561..864446c012e 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -92,8 +92,6 @@ #define ENABLE_HEXDUMP 0 /* Enable if you need it */ -#define USBVISION_DEBUG /* Turn on debug messages */ - #ifdef USBVISION_DEBUG #define PDEBUG(level, fmt, args...) \ if (video_debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args) @@ -104,7 +102,7 @@ #define DBG_IOCTL 1<<0 #define DBG_IO 1<<1 #define DBG_PROBE 1<<2 -#define DBG_FUNC 1<<3 +#define DBG_MMAP 1<<3 //String operations #define rmspace(str) while(*str==' ') str++; @@ -821,7 +819,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, vb->memory = V4L2_MEMORY_MMAP; vb->field = V4L2_FIELD_NONE; - vb->length = usbvision->max_frame_size; + vb->length = usbvision->curwidth*usbvision->curheight*usbvision->palette.bytes_per_pixel; vb->timestamp = usbvision->frame[vb->index].timestamp; vb->sequence = usbvision->frame[vb->index].sequence; return 0; @@ -959,13 +957,14 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*usbvision->curheight; vf->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; vf->fmt.pix.field = V4L2_FIELD_NONE; /* Always progressive image */ + PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT w=%d, h=%d, format=%s", + vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc); + return 0; } - return 0; default: PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT invalid type %d",vf->type); return -EINVAL; } - PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT w=%d, h=%d",vf->fmt.win.w.width, vf->fmt.win.w.height); return 0; } case VIDIOC_TRY_FMT: @@ -991,6 +990,15 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH); RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT); + vf->fmt.pix.bytesperline = vf->fmt.pix.width*usbvision->palette.bytes_per_pixel; + vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*vf->fmt.pix.height; + + if(cmd == VIDIOC_TRY_FMT) { + PDEBUG(DBG_IOCTL, "VIDIOC_TRY_FMT grabdisplay w=%d, h=%d, format=%s", + vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc); + return 0; + } + /* stop io in case it is already in progress */ if(usbvision->streaming == Stream_On) { if ((ret = usbvision_stream_interrupt(usbvision))) @@ -1133,7 +1141,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) } if (!(vma->vm_flags & VM_WRITE) || - size != PAGE_ALIGN(usbvision->max_frame_size)) { + size != PAGE_ALIGN(usbvision->curwidth*usbvision->curheight*usbvision->palette.bytes_per_pixel)) { up(&usbvision->lock); return -EINVAL; } @@ -1143,7 +1151,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) break; } if (i == USBVISION_NUMFRAMES) { - PDEBUG(DBG_FUNC, "mmap: user supplied mapping address is out of range"); + PDEBUG(DBG_MMAP, "mmap: user supplied mapping address is out of range"); up(&usbvision->lock); return -EINVAL; } @@ -1156,7 +1164,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) while (size > 0) { if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { - PDEBUG(DBG_FUNC, "mmap: vm_insert_page failed"); + PDEBUG(DBG_MMAP, "mmap: vm_insert_page failed"); up(&usbvision->lock); return -EAGAIN; } @@ -2003,7 +2011,7 @@ static int __init usbvision_init(void) PDEBUG(DBG_IOCTL, "IOCTL debugging is enabled [video]"); PDEBUG(DBG_IO, "IO debugging is enabled [video]"); PDEBUG(DBG_PROBE, "PROBE debugging is enabled [video]"); - PDEBUG(DBG_FUNC, "FUNC debugging is enabled [video]"); + PDEBUG(DBG_MMAP, "MMAP debugging is enabled [video]"); /* disable planar mode support unless compression enabled */ if (isocMode != ISOC_MODE_COMPRESS ) { diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h index f2eeda8326f..0e7e3d653ca 100644 --- a/drivers/media/video/usbvision/usbvision.h +++ b/drivers/media/video/usbvision/usbvision.h @@ -3,9 +3,14 @@ * usbvision header file * * Copyright (c) 1999-2005 Joerg Heckenbach + * Dwaine Garden + * + * + * Report problems to v4l MailingList : http://www.redhat.com/mailman/listinfo/video4linux-list * * This module is part of usbvision driver project. * Updates to driver completed by Dwaine P. Garden + * v4l2 conversion by Thierry Merle * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,6 +37,8 @@ #include #include +#define USBVISION_DEBUG /* Turn on debug messages */ + #ifndef VID_HARDWARE_USBVISION #define VID_HARDWARE_USBVISION 34 /* USBVision Video Grabber */ #endif -- cgit v1.2.3 From 1d4bb7d3c154167c8f0b80cfd72914d8732d3d01 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 5 Dec 2006 01:01:39 -0300 Subject: V4L/DVB (4943): Cx88: cleanup dvb_pll_attach for lgdt3302 tuners Since we're using dvb_pll_attach now, we dont have to populate dev->core->pll_addr or dev->core->pll_desc anymore. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-dvb.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 95db017badd..5f6d5491f5d 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -631,14 +631,13 @@ static int dvb_register(struct cx8802_dev *dev) /* Select RF connector callback */ fusionhdtv_3_gold.pll_rf_set = lgdt330x_pll_rf_set; - dev->core->pll_addr = 0x61; - dev->core->pll_desc = &dvb_pll_microtune_4042; dev->dvb.frontend = dvb_attach(lgdt330x_attach, &fusionhdtv_3_gold, &dev->core->i2c_adap); if (dev->dvb.frontend != NULL) { - dvb_attach(dvb_pll_attach, dev->dvb.frontend, dev->core->pll_addr, - &dev->core->i2c_adap, dev->core->pll_desc); + dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, + &dev->core->i2c_adap, + &dvb_pll_microtune_4042); } } break; @@ -652,14 +651,13 @@ static int dvb_register(struct cx8802_dev *dev) mdelay(100); cx_set(MO_GP0_IO, 9); mdelay(200); - dev->core->pll_addr = 0x61; - dev->core->pll_desc = &dvb_pll_thomson_dtt761x; dev->dvb.frontend = dvb_attach(lgdt330x_attach, &fusionhdtv_3_gold, &dev->core->i2c_adap); if (dev->dvb.frontend != NULL) { - dvb_attach(dvb_pll_attach, dev->dvb.frontend, dev->core->pll_addr, - &dev->core->i2c_adap, dev->core->pll_desc); + dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, + &dev->core->i2c_adap, + &dvb_pll_thomson_dtt761x); } } break; -- cgit v1.2.3 From 5786a34b439b660256e236f870c0418e39dd16d0 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 5 Dec 2006 01:21:19 -0300 Subject: V4L/DVB (4944): Cx88: Convert DViCO FusionHDTV Hybrid to use dvb_pll_attach Converted DViCO FusionHDTV Hybrid to use dvb_pll_attach, removing another static dependency of cx88-dvb on dvb-pll. Acked-by: Chris Pascoe Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-dvb.c | 35 +++-------------------------------- 1 file changed, 3 insertions(+), 32 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 5f6d5491f5d..60dd80f595e 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -268,35 +268,6 @@ static struct mt352_config dntv_live_dvbt_pro_config = { }; #endif -static int dvico_hybrid_tuner_set_params(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params) -{ - u8 pllbuf[4]; - struct cx8802_dev *dev= fe->dvb->priv; - struct i2c_msg msg = - { .addr = dev->core->pll_addr, .flags = 0, - .buf = pllbuf, .len = 4 }; - int err; - - dvb_pll_configure(dev->core->pll_desc, pllbuf, - params->frequency, - params->u.ofdm.bandwidth); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); - if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) { - printk(KERN_WARNING "cx88-dvb: %s error " - "(addr %02x <- %02x, err = %i)\n", - __FUNCTION__, pllbuf[0], pllbuf[1], err); - if (err < 0) - return err; - else - return -EREMOTEIO; - } - - return 0; -} - static struct zl10353_config dvico_fusionhdtv_hybrid = { .demod_address = 0x0f, .no_tuner = 1, @@ -599,13 +570,13 @@ static int dvb_register(struct cx8802_dev *dev) #endif break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID: - dev->core->pll_addr = 0x61; - dev->core->pll_desc = &dvb_pll_thomson_fe6600; dev->dvb.frontend = dvb_attach(zl10353_attach, &dvico_fusionhdtv_hybrid, &dev->core->i2c_adap); if (dev->dvb.frontend != NULL) { - dev->dvb.frontend->ops.tuner_ops.set_params = dvico_hybrid_tuner_set_params; + dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, + &dev->core->i2c_adap, + &dvb_pll_thomson_fe6600); } break; case CX88_BOARD_PCHDTV_HD3000: -- cgit v1.2.3 From ed35526027f3b45a7c799f73916166b1161bf082 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 5 Dec 2006 01:34:56 -0300 Subject: V4L/DVB (4945): Cx88: consolidate cx22702_config structs There are five cx22702_config structs used by cx88-dvb, only two of which are unique. This patch removes the duplicates and sets each card to use one of the two remaining config structs. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-dvb.c | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 60dd80f595e..d9907ce8ad4 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -282,15 +282,7 @@ static struct cx22702_config connexant_refboard_config = { .output_mode = CX22702_SERIAL_OUTPUT, }; -static struct cx22702_config hauppauge_novat_config = { - .demod_address = 0x43, - .output_mode = CX22702_SERIAL_OUTPUT, -}; -static struct cx22702_config hauppauge_hvr1100_config = { - .demod_address = 0x63, - .output_mode = CX22702_SERIAL_OUTPUT, -}; -static struct cx22702_config hauppauge_hvr3000_config = { +static struct cx22702_config hauppauge_hvr_config = { .demod_address = 0x63, .output_mode = CX22702_SERIAL_OUTPUT, }; @@ -313,11 +305,6 @@ static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, return ret; } -static struct cx22702_config hauppauge_hvr1300_config = { - .demod_address = 0x63, - .output_mode = CX22702_SERIAL_OUTPUT, -}; - static int or51132_set_ts_param(struct dvb_frontend* fe, int is_punctured) { @@ -465,7 +452,7 @@ static int dvb_register(struct cx8802_dev *dev) switch (dev->core->board) { case CX88_BOARD_HAUPPAUGE_DVB_T1: dev->dvb.frontend = dvb_attach(cx22702_attach, - &hauppauge_novat_config, + &connexant_refboard_config, &dev->core->i2c_adap); if (dev->dvb.frontend != NULL) { dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, @@ -490,7 +477,7 @@ static int dvb_register(struct cx8802_dev *dev) case CX88_BOARD_HAUPPAUGE_HVR1100: case CX88_BOARD_HAUPPAUGE_HVR1100LP: dev->dvb.frontend = dvb_attach(cx22702_attach, - &hauppauge_hvr1100_config, + &hauppauge_hvr_config, &dev->core->i2c_adap); if (dev->dvb.frontend != NULL) { dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, @@ -709,7 +696,7 @@ static int dvb_register(struct cx8802_dev *dev) break; case CX88_BOARD_HAUPPAUGE_HVR1300: dev->dvb.frontend = dvb_attach(cx22702_attach, - &hauppauge_hvr1300_config, + &hauppauge_hvr_config, &dev->core->i2c_adap); if (dev->dvb.frontend != NULL) { dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, @@ -719,7 +706,7 @@ static int dvb_register(struct cx8802_dev *dev) break; case CX88_BOARD_HAUPPAUGE_HVR3000: dev->dvb.frontend = dvb_attach(cx22702_attach, - &hauppauge_hvr3000_config, + &hauppauge_hvr_config, &dev->core->i2c_adap); if (dev->dvb.frontend != NULL) { dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, -- cgit v1.2.3 From 22f3f17dd705c476d2c8a2d879ddacaa8f9237e3 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 5 Dec 2006 01:38:58 -0300 Subject: V4L/DVB (4946): Cx88: Move cx88_dvb_bus_ctrl out of the card-specific area This function should not be in the card-specific area of the file. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-dvb.c | 38 +++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index d9907ce8ad4..694002a7dfc 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -100,6 +100,26 @@ static struct videobuf_queue_ops dvb_qops = { }; /* ------------------------------------------------------------------ */ + +static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire) +{ + struct cx8802_dev *dev= fe->dvb->priv; + struct cx8802_driver *drv = NULL; + int ret = 0; + + drv = cx8802_get_driver(dev, CX88_MPEG_DVB); + if (drv) { + if(acquire) + ret = drv->request_acquire(drv); + else + ret = drv->request_release(drv); + } + + return ret; +} + +/* ------------------------------------------------------------------ */ + static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe) { static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x39 }; @@ -287,24 +307,6 @@ static struct cx22702_config hauppauge_hvr_config = { .output_mode = CX22702_SERIAL_OUTPUT, }; -static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, - int acquire) -{ - struct cx8802_dev *dev= fe->dvb->priv; - struct cx8802_driver *drv = NULL; - int ret = 0; - - drv = cx8802_get_driver(dev, CX88_MPEG_DVB); - if (drv) { - if(acquire) - ret = drv->request_acquire(drv); - else - ret = drv->request_release(drv); - } - - return ret; -} - static int or51132_set_ts_param(struct dvb_frontend* fe, int is_punctured) { -- cgit v1.2.3 From 4a390558a691445e3d710998b850570fe8a20d31 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Tue, 5 Dec 2006 02:00:53 -0300 Subject: V4L/DVB (4947): Cx88: trivial cleanups - small whitespace cleanups - 80-column whitespace cleanups - remove unneeded brackets Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-dvb.c | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 694002a7dfc..8b203354fcc 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -74,8 +74,8 @@ static int dvb_buf_setup(struct videobuf_queue *q, return 0; } -static int dvb_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) +static int dvb_buf_prepare(struct videobuf_queue *q, + struct videobuf_buffer *vb, enum v4l2_field field) { struct cx8802_dev *dev = q->priv_data; return cx8802_buf_prepare(q, dev, (struct cx88_buffer*)vb,field); @@ -87,7 +87,8 @@ static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) cx8802_buf_queue(dev, (struct cx88_buffer*)vb); } -static void dvb_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb) +static void dvb_buf_release(struct videobuf_queue *q, + struct videobuf_buffer *vb) { cx88_free_buffer(q, (struct cx88_buffer*)vb); } @@ -109,7 +110,7 @@ static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire) drv = cx8802_get_driver(dev, CX88_MPEG_DVB); if (drv) { - if(acquire) + if (acquire) ret = drv->request_acquire(drv); else ret = drv->request_release(drv); @@ -307,8 +308,7 @@ static struct cx22702_config hauppauge_hvr_config = { .output_mode = CX22702_SERIAL_OUTPUT, }; -static int or51132_set_ts_param(struct dvb_frontend* fe, - int is_punctured) +static int or51132_set_ts_param(struct dvb_frontend* fe, int is_punctured) { struct cx8802_dev *dev= fe->dvb->priv; dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00; @@ -364,8 +364,7 @@ static struct lgdt330x_config pchdtv_hd5500 = { .set_ts_params = lgdt330x_set_ts_param, }; -static int nxt200x_set_ts_param(struct dvb_frontend* fe, - int is_punctured) +static int nxt200x_set_ts_param(struct dvb_frontend* fe, int is_punctured) { struct cx8802_dev *dev= fe->dvb->priv; dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00; @@ -401,11 +400,10 @@ static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe, struct cx8802_dev *dev= fe->dvb->priv; struct cx88_core *core = dev->core; - if (voltage == SEC_VOLTAGE_OFF) { + if (voltage == SEC_VOLTAGE_OFF) cx_write(MO_GP0_IO, 0x000006fb); - } else { + else cx_write(MO_GP0_IO, 0x000006f9); - } if (core->prev_set_voltage) return core->prev_set_voltage(fe, voltage); @@ -483,8 +481,7 @@ static int dvb_register(struct cx8802_dev *dev) &dev->core->i2c_adap); if (dev->dvb.frontend != NULL) { dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, - &dev->core->i2c_adap, - &dvb_pll_fmd1216me); + &dev->core->i2c_adap, &dvb_pll_fmd1216me); } break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS: @@ -569,8 +566,7 @@ static int dvb_register(struct cx8802_dev *dev) } break; case CX88_BOARD_PCHDTV_HD3000: - dev->dvb.frontend = dvb_attach(or51132_attach, - &pchdtv_hd3000, + dev->dvb.frontend = dvb_attach(or51132_attach, &pchdtv_hd3000, &dev->core->i2c_adap); if (dev->dvb.frontend != NULL) { dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, @@ -702,8 +698,7 @@ static int dvb_register(struct cx8802_dev *dev) &dev->core->i2c_adap); if (dev->dvb.frontend != NULL) { dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, - &dev->core->i2c_adap, - &dvb_pll_fmd1216me); + &dev->core->i2c_adap, &dvb_pll_fmd1216me); } break; case CX88_BOARD_HAUPPAUGE_HVR3000: @@ -712,8 +707,7 @@ static int dvb_register(struct cx8802_dev *dev) &dev->core->i2c_adap); if (dev->dvb.frontend != NULL) { dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61, - &dev->core->i2c_adap, - &dvb_pll_fmd1216me); + &dev->core->i2c_adap, &dvb_pll_fmd1216me); } break; default: -- cgit v1.2.3 From 67952e8cb111c5b2f9e675dba1bbde4876f9fcf3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 10 Dec 2006 00:14:21 -0200 Subject: V4L/DVB (4949a): Fix INIT_WORK INIT_WORK syntax changed on kernel 2.6.19. Fixing it on usbvision and cx88-input. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-input.c | 2 +- drivers/media/video/usbvision/usbvision-core.c | 8 ++++---- drivers/media/video/usbvision/usbvision.h | 2 ++ 3 files changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index c6d412b1f21..8136673fe9e 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -158,7 +158,7 @@ static void cx88_ir_work(struct work_struct *work) static void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir) { if (ir->polling) { - INIT_WORK(&ir->work, cx88_ir_work, ir); + INIT_WORK(&ir->work, cx88_ir_work); init_timer(&ir->timer); ir->timer.function = ir_timer; ir->timer.data = (unsigned long)ir; diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index 9163b60c7f9..9ff93e7346a 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -1708,7 +1708,6 @@ int usbvision_power_off(struct usb_usbvision *usbvision) return errCode; } - /* * usbvision_set_video_format() * @@ -2217,14 +2216,15 @@ int usbvision_power_on(struct usb_usbvision *usbvision) */ // to call usbvision_power_off from task queue -static void call_usbvision_power_off(void *_usbvision) +static void call_usbvision_power_off(struct work_struct *work) { - struct usb_usbvision *usbvision = _usbvision; + struct usb_usbvision *usbvision = container_of(work, struct usb_usbvision, work); PDEBUG(DBG_FUNC, ""); down_interruptible(&usbvision->lock); if(usbvision->user == 0) { usbvision_i2c_usb_del_bus(&usbvision->i2c_adap); + usbvision_power_off(usbvision); usbvision->initialized = 0; } @@ -2237,7 +2237,7 @@ static void usbvision_powerOffTimer(unsigned long data) PDEBUG(DBG_FUNC, ""); del_timer(&usbvision->powerOffTimer); - INIT_WORK(&usbvision->powerOffWork, call_usbvision_power_off, usbvision); + INIT_WORK(&usbvision->powerOffWork, call_usbvision_power_off); (void) schedule_work(&usbvision->powerOffWork); } diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h index 0e7e3d653ca..782abf4ffaa 100644 --- a/drivers/media/video/usbvision/usbvision.h +++ b/drivers/media/video/usbvision/usbvision.h @@ -381,6 +381,8 @@ struct usb_usbvision { struct video_device *rdev; /* Radio Device */ struct video_device *vbi; /* VBI Device */ + struct work_struct work; + /* i2c Declaration Section*/ struct i2c_adapter i2c_adap; struct i2c_algo_usb_data i2c_algo; -- cgit v1.2.3 From 1de1bf06330920802d3b7646a088965bdd918356 Mon Sep 17 00:00:00 2001 From: Thierry MERLE Date: Sun, 10 Dec 2006 13:31:04 -0300 Subject: V4L/DVB 4949b: Fix container_of pointer retreival Signed-off-by: Thierry MERLE Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/usbvision/usbvision-core.c | 2 +- drivers/media/video/usbvision/usbvision.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index 9ff93e7346a..797b97baf9e 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -2218,7 +2218,7 @@ int usbvision_power_on(struct usb_usbvision *usbvision) // to call usbvision_power_off from task queue static void call_usbvision_power_off(struct work_struct *work) { - struct usb_usbvision *usbvision = container_of(work, struct usb_usbvision, work); + struct usb_usbvision *usbvision = container_of(work, struct usb_usbvision, powerOffWork); PDEBUG(DBG_FUNC, ""); down_interruptible(&usbvision->lock); diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h index 782abf4ffaa..0e7e3d653ca 100644 --- a/drivers/media/video/usbvision/usbvision.h +++ b/drivers/media/video/usbvision/usbvision.h @@ -381,8 +381,6 @@ struct usb_usbvision { struct video_device *rdev; /* Radio Device */ struct video_device *vbi; /* VBI Device */ - struct work_struct work; - /* i2c Declaration Section*/ struct i2c_adapter i2c_adap; struct i2c_algo_usb_data i2c_algo; -- cgit v1.2.3 From 3269711b76ba27b78862c48398b0d313ccaa99c2 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 10 Dec 2006 21:21:33 +0100 Subject: i2c: Discard the i2c algo del_bus wrappers They are all only calling i2c_del_adapter, so we may as well do it directly. Signed-off-by: Jean Delvare --- drivers/media/video/bt8xx/bttv-i2c.c | 6 +----- drivers/media/video/cx88/cx88-core.c | 2 +- drivers/media/video/cx88/cx88-vp3054-i2c.c | 2 +- drivers/media/video/vino.c | 2 +- drivers/media/video/zoran_card.c | 2 +- 5 files changed, 5 insertions(+), 9 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c index 70de6c96e20..62b873076e0 100644 --- a/drivers/media/video/bt8xx/bttv-i2c.c +++ b/drivers/media/video/bt8xx/bttv-i2c.c @@ -479,11 +479,7 @@ int __devexit fini_bttv_i2c(struct bttv *btv) if (0 != btv->i2c_rc) return 0; - if (btv->use_i2c_hw) { - return i2c_del_adapter(&btv->c.i2c_adap); - } else { - return i2c_bit_del_bus(&btv->c.i2c_adap); - } + return i2c_del_adapter(&btv->c.i2c_adap); } /* diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 4b655f2ef27..453af5e943f 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -1153,7 +1153,7 @@ void cx88_core_put(struct cx88_core *core, struct pci_dev *pci) mutex_lock(&devlist); cx88_ir_fini(core); if (0 == core->i2c_rc) - i2c_bit_del_bus(&core->i2c_adap); + i2c_del_adapter(&core->i2c_adap); list_del(&core->devlist); iounmap(core->lmmio); cx88_devcount--; diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.c b/drivers/media/video/cx88/cx88-vp3054-i2c.c index 2b4f1970c7d..6068c9bf82c 100644 --- a/drivers/media/video/cx88/cx88-vp3054-i2c.c +++ b/drivers/media/video/cx88/cx88-vp3054-i2c.c @@ -168,7 +168,7 @@ void vp3054_i2c_remove(struct cx8802_dev *dev) dev->core->board != CX88_BOARD_DNTV_LIVE_DVB_T_PRO) return; - i2c_bit_del_bus(&vp3054_i2c->adap); + i2c_del_adapter(&vp3054_i2c->adap); kfree(vp3054_i2c); } diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c index 6b6dff4d236..a373c142e74 100644 --- a/drivers/media/video/vino.c +++ b/drivers/media/video/vino.c @@ -782,7 +782,7 @@ static int vino_i2c_add_bus(void) static int vino_i2c_del_bus(void) { - return i2c_sgi_del_bus(&vino_i2c_adapter); + return i2c_del_adapter(&vino_i2c_adapter); } static int i2c_camera_command(unsigned int cmd, void *arg) diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c index 653822ce391..4d1eb2fba34 100644 --- a/drivers/media/video/zoran_card.c +++ b/drivers/media/video/zoran_card.c @@ -849,7 +849,7 @@ zoran_register_i2c (struct zoran *zr) static void zoran_unregister_i2c (struct zoran *zr) { - i2c_bit_del_bus((&zr->i2c_adapter)); + i2c_del_adapter(&zr->i2c_adapter); } /* Check a zoran_params struct for correctness, insert default params */ -- cgit v1.2.3 From 2a7e9a260ede3b17b5bc25c540a033a45bbf0461 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 11 Dec 2006 05:37:14 -0300 Subject: V4L/DVB (4954): Fix: On ia64, i2c adap->inb/adap->outb are wrongly evaluated i2c defines two callbacks (inb/outb). On ia64, since it defines also two macros with those names, it causes the following errors: drivers/media/video/usbvision/usbvision-i2c.c:64:39: macro "outb" passed 4 arguments, but takes just 2 drivers/media/video/usbvision/usbvision-i2c.c: In function `try_write_address': drivers/media/video/usbvision/usbvision-i2c.c:64: warning: assignment makes integer from pointer without a cast drivers/media/video/usbvision/usbvision-i2c.c:89:38: macro "inb" passed 4 arguments, but takes just 1 drivers/media/video/usbvision/usbvision-i2c.c: In function `try_read_address': drivers/media/video/usbvision/usbvision-i2c.c:89: warning: assignment makes integer from pointer without a cast drivers/media/video/usbvision/usbvision-i2c.c:85: warning: unused variable `buf' drivers/media/video/usbvision/usbvision-i2c.c:173:53: macro "inb" passed 4 arguments, but takes just 1 drivers/media/video/usbvision/usbvision-i2c.c: In function `usb_xfer': drivers/media/video/usbvision/usbvision-i2c.c:173: warning: assignment makes integer from pointer without a cast drivers/media/video/usbvision/usbvision-i2c.c:179:54: macro "outb" passed 4 arguments, but takes just 2 drivers/media/video/usbvision/usbvision-i2c.c:179: warning: assignment makes integer from pointer without a cast thanks to Andrew Morton for pointing this. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/usbvision/usbvision-i2c.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers/media/video') diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c index 92bf9a1f1e2..0f3fba7ea6f 100644 --- a/drivers/media/video/usbvision/usbvision-i2c.c +++ b/drivers/media/video/usbvision/usbvision-i2c.c @@ -50,6 +50,11 @@ MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); #define PDEBUG(level, fmt, args...) \ if (i2c_debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args) +static int usbvision_i2c_write(void *data, unsigned char addr, char *buf, + short len); +static int usbvision_i2c_read(void *data, unsigned char addr, char *buf, + short len); + static inline int try_write_address(struct i2c_adapter *i2c_adap, unsigned char addr, int retries) { @@ -61,7 +66,7 @@ static inline int try_write_address(struct i2c_adapter *i2c_adap, data = i2c_get_adapdata(i2c_adap); buf[0] = 0x00; for (i = 0; i <= retries; i++) { - ret = (adap->outb(data, addr, buf, 1)); + ret = (usbvision_i2c_write(data, addr, buf, 1)); if (ret == 1) break; /* success! */ udelay(5 /*adap->udelay */ ); @@ -86,7 +91,7 @@ static inline int try_read_address(struct i2c_adapter *i2c_adap, data = i2c_get_adapdata(i2c_adap); for (i = 0; i <= retries; i++) { - ret = (adap->inb(data, addr, buf, 1)); + ret = (usbvision_i2c_read(data, addr, buf, 1)); if (ret == 1) break; /* success! */ udelay(5 /*adap->udelay */ ); @@ -153,7 +158,6 @@ static int usb_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) { struct i2c_msg *pmsg; - struct i2c_algo_usb_data *adap = i2c_adap->algo_data; void *data; int i, ret; unsigned char addr; @@ -170,13 +174,13 @@ usb_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) if (pmsg->flags & I2C_M_RD) { /* read bytes into buffer */ - ret = (adap->inb(data, addr, pmsg->buf, pmsg->len)); + ret = (usbvision_i2c_read(data, addr, pmsg->buf, pmsg->len)); if (ret < pmsg->len) { return (ret < 0) ? ret : -EREMOTEIO; } } else { /* write bytes from buffer */ - ret = (adap->outb(data, addr, pmsg->buf, pmsg->len)); + ret = (usbvision_i2c_write(data, addr, pmsg->buf, pmsg->len)); if (ret < pmsg->len) { return (ret < 0) ? ret : -EREMOTEIO; } -- cgit v1.2.3