On Tue, Apr 1, 2008 at 11:41 AM, Ben Caldwell <benny.caldwell@xxxxxxxxx> wrote: > On Tue, Apr 1, 2008 at 10:31 AM, Nicholas Magers < > After much plodding through changesets I have something to report. It seems > that the the dvico dual digital 4 card is broken in changesets after > d4df22377e83 (11 days ago). > It is interesting to note that the next change (the one that breaks it) is > "Removes video_dev from tuner-xc3028 config struct" - the dvico dual digital > 4 has an xc3028. > > So to get it working: > *hg update -r d4df22377e83 > make clean > make rminstall > make release > make > make install* > > Then reboot. One other interesting thing I have found is that sometimes > after compiling new modules I actually have to turn the PC off then on again > (rather than just a reboot) to get everything working properly. > > - Ben Can you try using the v4l-dvb master branch hg repository on linuxtv.org again, after applying the attached patch (see below) It is clear what went wrong on the Dual Digital 4 -- Mauro did some changes recently that use a "magic number" (yuck) to differentiate between devices and manage multiple instances of the xc2028 driver on a hybrid design. He used i2c_adapter->algo_data to generate this "magic number" , which, IMHO is a very bad idea, especially since some digital-only devices do not even define algo_data. On the other hand, i2c_adap->algo_data is a reasonable structure to use for the "video_dev" pointer in the tuner_callback function, *if* it is defined. The patch in the link above uses the 'hybrid_tuner_request_state" method to manage multiple instances of the device driver on a hybrid design. This uses a *much* safer method, using the i2c_adapter ID along with the device i2c address to identify unique instances. For the "video_dev" pointer, the patch also uses a safer method: If the dvb_adapter device is defined, use fe->dvb->priv, otherwise, fall back to Mauro's previous method of using i2c_adap->algo_data. Please note: This patch is intended for testing purposes only -- there is a remaining issue in this patch, where it doesn't destroy some memory properly when tuner instances are destroyed. I'll be happy to fix that remaining issue after I receive some reports that the larger issue is actually remedied by this patch. Please let me know if this fixes the problem, and I'll produce a new patch afterwards. Regards, Mike Krufky
diff -r 0776e4801991 linux/drivers/media/video/tuner-xc2028.c --- a/linux/drivers/media/video/tuner-xc2028.c Fri Mar 28 14:52:44 2008 -0300 +++ b/linux/drivers/media/video/tuner-xc2028.c Tue Apr 01 15:57:38 2008 -0400 @@ -57,7 +57,7 @@ MODULE_PARM_DESC(firmware_name, "Firmwar MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the " "default firmware name\n"); -static LIST_HEAD(xc2028_list); +static LIST_HEAD(hybrid_tuner_instance_list); static DEFINE_MUTEX(xc2028_list_mutex); /* struct for storing firmware table */ @@ -79,12 +79,11 @@ struct firmware_properties { }; struct xc2028_data { - struct list_head xc2028_list; + struct list_head hybrid_tuner_instance_list; struct tuner_i2c_props i2c_props; int (*tuner_callback) (void *dev, int command, int arg); void *video_dev; - int count; __u32 frequency; struct firmware_description *firm; @@ -1095,19 +1094,12 @@ static int xc2028_dvb_release(struct dvb mutex_lock(&xc2028_list_mutex); - priv->count--; - - if (!priv->count) { - list_del(&priv->xc2028_list); - - kfree(priv->ctrl.fname); - - free_firmware(priv); - kfree(priv); - fe->tuner_priv = NULL; - } + if (priv) + hybrid_tuner_release_state(priv); mutex_unlock(&xc2028_list_mutex); + + fe->tuner_priv = NULL; return 0; } @@ -1179,7 +1171,7 @@ struct dvb_frontend *xc2028_attach(struc struct xc2028_config *cfg) { struct xc2028_data *priv; - void *video_dev; + int instance; if (debug) printk(KERN_DEBUG "xc2028: Xcv2028/3028 init called!\n"); @@ -1192,48 +1184,40 @@ struct dvb_frontend *xc2028_attach(struc return NULL; } - video_dev = cfg->i2c_adap->algo_data; - - if (debug) - printk(KERN_DEBUG "xc2028: video_dev =%p\n", video_dev); - mutex_lock(&xc2028_list_mutex); - list_for_each_entry(priv, &xc2028_list, xc2028_list) { - if (&priv->i2c_props.adap->dev == &cfg->i2c_adap->dev) { - video_dev = NULL; - if (debug) - printk(KERN_DEBUG "xc2028: reusing device\n"); - - break; - } - } - - if (video_dev) { - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (priv == NULL) { - mutex_unlock(&xc2028_list_mutex); - return NULL; - } - - priv->i2c_props.addr = cfg->i2c_addr; - priv->i2c_props.adap = cfg->i2c_adap; - priv->i2c_props.name = "xc2028"; - - priv->video_dev = video_dev; + instance = hybrid_tuner_request_state(struct xc2028_data, priv, + hybrid_tuner_instance_list, + cfg->i2c_adap, cfg->i2c_addr, + "xc2028"); + switch (instance) { + case 0: + /* memory allocation failure */ + goto fail; + break; + case 1: + /* new tuner instance */ priv->tuner_callback = cfg->callback; priv->ctrl.max_len = 13; mutex_init(&priv->lock); - list_add_tail(&priv->xc2028_list, &xc2028_list); - } - - fe->tuner_priv = priv; - priv->count++; - - if (debug) - printk(KERN_DEBUG "xc2028: usage count is %i\n", priv->count); + /* analog side (tuner-core) uses i2c_adap->algo_data. + * digital side is not guaranteed to have algo_data defined. + * + * digital side will always have fe->dvb defined. + * analog side (tuner-core) doesn't (yet) define fe->dvb. + */ + priv->video_dev = ((fe->dvb) && (fe->dvb->priv)) ? + fe->dvb->priv : cfg->i2c_adap->algo_data; + + fe->tuner_priv = priv; + break; + case 2: + /* existing tuner instance */ + fe->tuner_priv = priv; + break; + } memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops, sizeof(xc2028_dvb_tuner_ops)); @@ -1246,6 +1230,11 @@ struct dvb_frontend *xc2028_attach(struc mutex_unlock(&xc2028_list_mutex); return fe; +fail: + mutex_unlock(&xc2028_list_mutex); + + xc2028_dvb_release(fe); + return NULL; } EXPORT_SYMBOL(xc2028_attach);
_______________________________________________ linux-dvb mailing list linux-dvb@xxxxxxxxxxx http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb