From 974598b3e1d92694dec31bb072cd65be34fa012d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 5 Mar 2009 09:38:24 +0000 Subject: cx88: Prevent general protection fault on rmmod From: Jean Delvare When unloading the cx8800 driver I sometimes get a general protection fault. Analysis revealed a race in cx88_ir_stop(). It can be solved by using a delayed work instead of a timer for infrared input polling. This fixes kernel.org bug #12802. Signed-off-by: Jean Delvare Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/cx88/cx88-input.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'linux/drivers/media/video/cx88') diff --git a/linux/drivers/media/video/cx88/cx88-input.c b/linux/drivers/media/video/cx88/cx88-input.c index dbb6ee2d9..f247e5f45 100644 --- a/linux/drivers/media/video/cx88/cx88-input.c +++ b/linux/drivers/media/video/cx88/cx88-input.c @@ -49,8 +49,12 @@ struct cx88_IR { /* poll external decoder */ int polling; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) struct work_struct work; struct timer_list timer; +#else + struct delayed_work work; +#endif u32 gpio_addr; u32 last_gpio; u32 mask_keycode; @@ -144,6 +148,7 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) } } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) static void ir_timer(unsigned long data) { struct cx88_IR *ir = (struct cx88_IR *)data; @@ -151,7 +156,6 @@ static void ir_timer(unsigned long data) schedule_work(&ir->work); } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) static void cx88_ir_work(void *data) #else static void cx88_ir_work(struct work_struct *work) @@ -160,23 +164,30 @@ static void cx88_ir_work(struct work_struct *work) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) struct cx88_IR *ir = data; #else - struct cx88_IR *ir = container_of(work, struct cx88_IR, work); + struct delayed_work *dwork = container_of(work, struct delayed_work, + work); + struct cx88_IR *ir = container_of(dwork, struct cx88_IR, work); #endif cx88_ir_handle_key(ir); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling)); +#else + schedule_delayed_work(dwork, msecs_to_jiffies(ir->polling)); +#endif } void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir) { if (ir->polling) { - setup_timer(&ir->timer, ir_timer, (unsigned long)ir); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + setup_timer(&ir->timer, ir_timer, (unsigned long)ir); INIT_WORK(&ir->work, cx88_ir_work, ir); + schedule_work(&ir->work); #else - INIT_WORK(&ir->work, cx88_ir_work); + INIT_DELAYED_WORK(&ir->work, cx88_ir_work); + schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling)); #endif - schedule_work(&ir->work); } if (ir->sampling) { core->pci_irqmask |= PCI_INT_IR_SMPINT; @@ -193,8 +204,12 @@ void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir) } if (ir->polling) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) del_timer_sync(&ir->timer); flush_scheduled_work(); +#else + cancel_delayed_work_sync(&ir->work); +#endif } } -- cgit v1.2.3 From f1ecc598eb4d5dcf96c771908ff51c48e734dde8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 11 Mar 2009 07:57:43 -0300 Subject: Backout changeset, in favor of rev2 of the patch From: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/cx88/cx88-input.c | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) (limited to 'linux/drivers/media/video/cx88') diff --git a/linux/drivers/media/video/cx88/cx88-input.c b/linux/drivers/media/video/cx88/cx88-input.c index f247e5f45..dbb6ee2d9 100644 --- a/linux/drivers/media/video/cx88/cx88-input.c +++ b/linux/drivers/media/video/cx88/cx88-input.c @@ -49,12 +49,8 @@ struct cx88_IR { /* poll external decoder */ int polling; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) struct work_struct work; struct timer_list timer; -#else - struct delayed_work work; -#endif u32 gpio_addr; u32 last_gpio; u32 mask_keycode; @@ -148,7 +144,6 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) } } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) static void ir_timer(unsigned long data) { struct cx88_IR *ir = (struct cx88_IR *)data; @@ -156,6 +151,7 @@ static void ir_timer(unsigned long data) schedule_work(&ir->work); } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) static void cx88_ir_work(void *data) #else static void cx88_ir_work(struct work_struct *work) @@ -164,30 +160,23 @@ static void cx88_ir_work(struct work_struct *work) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) struct cx88_IR *ir = data; #else - struct delayed_work *dwork = container_of(work, struct delayed_work, - work); - struct cx88_IR *ir = container_of(dwork, struct cx88_IR, work); + struct cx88_IR *ir = container_of(work, struct cx88_IR, work); #endif cx88_ir_handle_key(ir); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling)); -#else - schedule_delayed_work(dwork, msecs_to_jiffies(ir->polling)); -#endif } void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir) { if (ir->polling) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) setup_timer(&ir->timer, ir_timer, (unsigned long)ir); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) INIT_WORK(&ir->work, cx88_ir_work, ir); - schedule_work(&ir->work); #else - INIT_DELAYED_WORK(&ir->work, cx88_ir_work); - schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling)); + INIT_WORK(&ir->work, cx88_ir_work); #endif + schedule_work(&ir->work); } if (ir->sampling) { core->pci_irqmask |= PCI_INT_IR_SMPINT; @@ -204,12 +193,8 @@ void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir) } if (ir->polling) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) del_timer_sync(&ir->timer); flush_scheduled_work(); -#else - cancel_delayed_work_sync(&ir->work); -#endif } } -- cgit v1.2.3 From cc038d948545b0b6de0bb031f28afdf7968813b3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 7 Mar 2009 10:42:12 +0000 Subject: cx88: Prevent general protection fault on rmmod From: Jean Delvare When unloading the cx8800 driver I sometimes get a general protection fault. Analysis revealed a race in cx88_ir_stop(). It can be solved by using a delayed work instead of a timer for infrared input polling. Signed-off-by: Jean Delvare Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/cx88/cx88-input.c | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) (limited to 'linux/drivers/media/video/cx88') diff --git a/linux/drivers/media/video/cx88/cx88-input.c b/linux/drivers/media/video/cx88/cx88-input.c index dbb6ee2d9..8a2e631b7 100644 --- a/linux/drivers/media/video/cx88/cx88-input.c +++ b/linux/drivers/media/video/cx88/cx88-input.c @@ -49,8 +49,7 @@ struct cx88_IR { /* poll external decoder */ int polling; - struct work_struct work; - struct timer_list timer; + struct delayed_work work; u32 gpio_addr; u32 last_gpio; u32 mask_keycode; @@ -144,13 +143,6 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) } } -static void ir_timer(unsigned long data) -{ - struct cx88_IR *ir = (struct cx88_IR *)data; - - schedule_work(&ir->work); -} - #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) static void cx88_ir_work(void *data) #else @@ -160,23 +152,22 @@ static void cx88_ir_work(struct work_struct *work) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) struct cx88_IR *ir = data; #else - struct cx88_IR *ir = container_of(work, struct cx88_IR, work); + struct cx88_IR *ir = container_of(work, struct cx88_IR, work.work); #endif cx88_ir_handle_key(ir); - mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling)); + schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling)); } void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir) { if (ir->polling) { - setup_timer(&ir->timer, ir_timer, (unsigned long)ir); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) - INIT_WORK(&ir->work, cx88_ir_work, ir); + INIT_DELAYED_WORK(&ir->work, cx88_ir_work, ir); #else - INIT_WORK(&ir->work, cx88_ir_work); + INIT_DELAYED_WORK(&ir->work, cx88_ir_work); #endif - schedule_work(&ir->work); + schedule_delayed_work(&ir->work, 0); } if (ir->sampling) { core->pci_irqmask |= PCI_INT_IR_SMPINT; @@ -192,10 +183,8 @@ void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir) core->pci_irqmask &= ~PCI_INT_IR_SMPINT; } - if (ir->polling) { - del_timer_sync(&ir->timer); - flush_scheduled_work(); - } + if (ir->polling) + cancel_delayed_work_sync(&ir->work); } /* ---------------------------------------------------------------------- */ -- cgit v1.2.3 From 47b7123665629b4f3d24173609a0d3b398c7132c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 10 Mar 2009 22:08:06 +0000 Subject: Add support for Terratec Cinergy HT PCI MKII From: Stephan Wienczny This patch adds support for Terratec Cinergy HT PCI MKII with card id 79. Its more or less a copy of Pinnacle Hybrid PCTV. Thanks to k1ngf1sher on forum.ubuntuusers.de for the idea to copy that card. Priority: normal Signed-off-by: Stephan Wienczny Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/cx88/cx88-cards.c | 38 +++++++++++++++++++++++++++++ linux/drivers/media/video/cx88/cx88-dvb.c | 16 ++++++++++++ linux/drivers/media/video/cx88/cx88.h | 1 + 3 files changed, 55 insertions(+) (limited to 'linux/drivers/media/video/cx88') diff --git a/linux/drivers/media/video/cx88/cx88-cards.c b/linux/drivers/media/video/cx88/cx88-cards.c index f9b5a9c09..b3d966ad5 100644 --- a/linux/drivers/media/video/cx88/cx88-cards.c +++ b/linux/drivers/media/video/cx88/cx88-cards.c @@ -1967,6 +1967,39 @@ static const struct cx88_board cx88_boards[] = { } }, .mpeg = CX88_MPEG_DVB, }, + [CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII] = { + .name = "Terratec Cinergy HT PCI MKII", + .tuner_type = TUNER_XC2028, + .tuner_addr = 0x61, + .radio_type = TUNER_XC2028, + .radio_addr = 0x61, + .input = { { + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x004ff, + .gpio1 = 0x010ff, + .gpio2 = 0x00001, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x004fb, + .gpio1 = 0x010ef, + .audioroute = 1, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x004fb, + .gpio1 = 0x010ef, + .audioroute = 1, + } }, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x004ff, + .gpio1 = 0x010ff, + .gpio2 = 0x0ff, + }, + .mpeg = CX88_MPEG_DVB, + }, }; /* ------------------------------------------------------------------ */ @@ -2376,6 +2409,10 @@ static const struct cx88_subid cx88_subids[] = { .subvendor = 0xb200, .subdevice = 0x4200, .card = CX88_BOARD_SATTRADE_ST4200, + }, { + .subvendor = 0x153b, + .subdevice = 0x1177, + .card = CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII, }, }; @@ -2852,6 +2889,7 @@ void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl) */ break; case CX88_BOARD_PINNACLE_HYBRID_PCTV: + case CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII: ctl->demod = XC3028_FE_ZARLINK456; ctl->mts = 1; break; diff --git a/linux/drivers/media/video/cx88/cx88-dvb.c b/linux/drivers/media/video/cx88/cx88-dvb.c index 488126ad6..10cf470ce 100644 --- a/linux/drivers/media/video/cx88/cx88-dvb.c +++ b/linux/drivers/media/video/cx88/cx88-dvb.c @@ -242,6 +242,12 @@ static struct mt352_config dvico_fusionhdtv_dual = { .demod_init = dvico_dual_demod_init, }; +static struct zl10353_config cx88_terratec_cinergy_ht_pci_mkii_config = { + .demod_address = (0x1e >> 1), + .no_tuner = 1, + .if2 = 45600, +}; + #if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE)) static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe) { @@ -1138,6 +1144,16 @@ static int dvb_register(struct cx8802_dev *dev) if (fe0->dvb.frontend != NULL) fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage; break; + case CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII: + fe0->dvb.frontend = dvb_attach(zl10353_attach, + &cx88_terratec_cinergy_ht_pci_mkii_config, + &core->i2c_adap); + if (fe0->dvb.frontend) { + fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL; + if (attach_xc3028(0x61, dev) < 0) + goto frontend_detach; + } + break; default: printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n", core->name); diff --git a/linux/drivers/media/video/cx88/cx88.h b/linux/drivers/media/video/cx88/cx88.h index 2227d93c7..1372d2b7b 100644 --- a/linux/drivers/media/video/cx88/cx88.h +++ b/linux/drivers/media/video/cx88/cx88.h @@ -232,6 +232,7 @@ extern struct sram_channel cx88_sram_channels[]; #define CX88_BOARD_SATTRADE_ST4200 76 #define CX88_BOARD_TBS_8910 77 #define CX88_BOARD_PROF_6200 78 +#define CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII 79 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, -- cgit v1.2.3 From 98067ab29acca0eafb57f28d72ae299eb41d6642 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 14 Mar 2009 16:40:51 +0100 Subject: cx88: convert to v4l2_device. From: Hans Verkuil Priority: normal Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/video/cx88/cx88-cards.c | 8 ++++++++ linux/drivers/media/video/cx88/cx88-core.c | 4 +++- linux/drivers/media/video/cx88/cx88-i2c.c | 8 +++++--- linux/drivers/media/video/cx88/cx88.h | 8 +++++++- 4 files changed, 23 insertions(+), 5 deletions(-) (limited to 'linux/drivers/media/video/cx88') diff --git a/linux/drivers/media/video/cx88/cx88-cards.c b/linux/drivers/media/video/cx88/cx88-cards.c index b3d966ad5..719315d02 100644 --- a/linux/drivers/media/video/cx88/cx88-cards.c +++ b/linux/drivers/media/video/cx88/cx88-cards.c @@ -3171,7 +3171,15 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) core->nr = nr; sprintf(core->name, "cx88[%d]", core->nr); + + strcpy(core->v4l2_dev.name, core->name); + if (v4l2_device_register(NULL, &core->v4l2_dev)) { + kfree(core); + return NULL; + } + if (0 != cx88_get_resources(core, pci)) { + v4l2_device_unregister(&core->v4l2_dev); kfree(core); return NULL; } diff --git a/linux/drivers/media/video/cx88/cx88-core.c b/linux/drivers/media/video/cx88/cx88-core.c index c9de13b56..ca36a48fa 100644 --- a/linux/drivers/media/video/cx88/cx88-core.c +++ b/linux/drivers/media/video/cx88/cx88-core.c @@ -1040,7 +1040,8 @@ struct video_device *cx88_vdev_init(struct cx88_core *core, return NULL; *vfd = *template; vfd->minor = -1; - vfd->parent = &pci->dev; + vfd->v4l2_dev = &core->v4l2_dev; + vfd->parent = &pci->dev; vfd->release = video_device_release; snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", core->name, type, core->board.name); @@ -1093,6 +1094,7 @@ void cx88_core_put(struct cx88_core *core, struct pci_dev *pci) iounmap(core->lmmio); cx88_devcount--; mutex_unlock(&devlist); + v4l2_device_unregister(&core->v4l2_dev); kfree(core); } diff --git a/linux/drivers/media/video/cx88/cx88-i2c.c b/linux/drivers/media/video/cx88/cx88-i2c.c index c0ff2305d..4a17a7579 100644 --- a/linux/drivers/media/video/cx88/cx88-i2c.c +++ b/linux/drivers/media/video/cx88/cx88-i2c.c @@ -99,7 +99,8 @@ static int cx8800_bit_getsda(void *data) static int attach_inform(struct i2c_client *client) { - struct cx88_core *core = i2c_get_adapdata(client->adapter); + struct v4l2_device *v4l2_dev = i2c_get_adapdata(client->adapter); + struct cx88_core *core = to_core(v4l2_dev); dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n", client->driver->driver.name, client->addr, client->name); @@ -108,7 +109,8 @@ static int attach_inform(struct i2c_client *client) static int detach_inform(struct i2c_client *client) { - struct cx88_core *core = i2c_get_adapdata(client->adapter); + struct v4l2_device *v4l2_dev = i2c_get_adapdata(client->adapter); + struct cx88_core *core = to_core(v4l2_dev); dprintk(1, "i2c detach [client=%s]\n", client->name); return 0; @@ -186,7 +188,7 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) core->i2c_adap.client_unregister = detach_inform; core->i2c_algo.udelay = i2c_udelay; core->i2c_algo.data = core; - i2c_set_adapdata(&core->i2c_adap,core); + i2c_set_adapdata(&core->i2c_adap, &core->v4l2_dev); core->i2c_adap.algo_data = &core->i2c_algo; core->i2c_client.adapter = &core->i2c_adap; strlcpy(core->i2c_client.name, "cx88xx internal", I2C_NAME_SIZE); diff --git a/linux/drivers/media/video/cx88/cx88.h b/linux/drivers/media/video/cx88/cx88.h index 1372d2b7b..d70e26000 100644 --- a/linux/drivers/media/video/cx88/cx88.h +++ b/linux/drivers/media/video/cx88/cx88.h @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include #include @@ -331,6 +331,7 @@ struct cx88_core { u32 i2c_state, i2c_rc; /* config info -- analog */ + struct v4l2_device v4l2_dev; unsigned int boardnr; struct cx88_board board; @@ -369,6 +370,11 @@ struct cx88_core { int active_fe_id; }; +static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev) +{ + return container_of(v4l2_dev, struct cx88_core, v4l2_dev); +} + struct cx8800_dev; struct cx8802_dev; -- cgit v1.2.3