From fcfcc128910473bdf3411a074894ae36c808106a Mon Sep 17 00:00:00 2001 From: "darron@kewl.org" Date: Sat, 11 Oct 2008 15:05:50 +0100 Subject: S2API: Add Multiple-frontend on a single adapter support. From: Steven Toth A detailed description from the original patches 2 years ago: "The WinTV-HVR3000 has a single transport bus which is shared between a DVB-T and DVB-S modulator. These patches build on the bus acquisition cx88 work from a few weeks ago to add support for this. So to applications the HVR3000 looks like this: /dev/dvb/adapter0/fe0 (cx24123 DVB-S demod) /dev/dvb/adapter0/fe1 (cx22702 DVB-T demod) Additional boards continue as before, eg: /dev/dvb/adapter1/fe0 (lgdt3302 ATSC demod) The basic change is removing the single instance of the videobuf_dvb in cx8802_dev and saa7134_dev(?) and replacing it with a list and some supporting functions. *NOTE* This branch was taken before v4l-dvb was closed for 2.6.19 so two or three current cx88 patches appear to be reversed by this tree, this will be cleaned up in the near future. The patches missing change the mutex handing to core->lock, fix an enumeration problem." It should be recognised that a number of people have been maintaining this patchset. Significant levels of Kudos to everyone one involved, including but not limited to: Darron Broad Fabio M. Di Nitto Carlo Scarfoglio Hans Werner Without the work of these people, and countless others, my two year old patches would of died on the Mercurial linuxtv.org vine a long time ago. TODO: Revise these patches a little further so that the need for demux1 and dvr0 is optional, not mandatory on the HVR3000. HISTORY (darron): This is the last update to MFE prepared by Hans which is based upon the `scratchpad' diff created by Carlo. All MFE work prior to that point must be attributed to Fabio who ported and maintained Steve's original patch up to that time. Priority: normal Signed-off-by: Steven Toth Signed-off-by: Darron Broad --- linux/drivers/media/video/videobuf-dvb.c | 171 ++++++++++++++++++++++++++----- 1 file changed, 148 insertions(+), 23 deletions(-) (limited to 'linux/drivers/media/video/videobuf-dvb.c') diff --git a/linux/drivers/media/video/videobuf-dvb.c b/linux/drivers/media/video/videobuf-dvb.c index d9979ab26..9f1b91fc7 100644 --- a/linux/drivers/media/video/videobuf-dvb.c +++ b/linux/drivers/media/video/videobuf-dvb.c @@ -140,29 +140,75 @@ static int videobuf_dvb_stop_feed(struct dvb_demux_feed *feed) } /* ------------------------------------------------------------------ */ +/* Register a single adapter and one or more frontends */ +int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f, + struct module *module, + void *adapter_priv, + struct device *device, + short *adapter_nr) //NEW +{ + struct list_head *list, *q; + struct videobuf_dvb_frontend *fe; + int res = -EINVAL; + + fe = videobuf_dvb_get_frontend(f, 1); + if (!fe) { + printk(KERN_WARNING "Unable to register the adapter which has no frontends\n"); + goto err; + } + + /* Bring up the adapter */ + res = videobuf_dvb_register_adapter(f, module, adapter_priv, device, fe->dvb.name, adapter_nr); //NEW + if (res < 0) { + printk(KERN_WARNING "videobuf_dvb_register_adapter failed (errno = %d)\n", res); + goto err; + } -int videobuf_dvb_register(struct videobuf_dvb *dvb, + /* Attach all of the frontends to the adapter */ + mutex_lock(&f->lock); + list_for_each_safe(list, q, &f->frontend.felist) { + fe = list_entry(list, struct videobuf_dvb_frontend, felist); + + res = videobuf_dvb_register_frontend(&f->adapter, &fe->dvb); + if (res < 0) { + printk(KERN_WARNING "%s: videobuf_dvb_register_frontend failed (errno = %d)\n", + fe->dvb.name, res); + } + } + mutex_unlock(&f->lock); + +err: + return res; +} + +int videobuf_dvb_register_adapter(struct videobuf_dvb_frontends *fe, struct module *module, void *adapter_priv, struct device *device, - short *adapter_nr) + char *adapter_name, + short *adapter_nr) //NEW { int result; - mutex_init(&dvb->lock); + mutex_init(&fe->lock); /* register adapter */ - result = dvb_register_adapter(&dvb->adapter, dvb->name, module, device, - adapter_nr); + result = dvb_register_adapter(&fe->adapter, adapter_name, module, device, adapter_nr); if (result < 0) { printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n", - dvb->name, result); - goto fail_adapter; + adapter_name, result); } - dvb->adapter.priv = adapter_priv; + fe->adapter.priv = adapter_priv; + + return result; +} + +int videobuf_dvb_register_frontend(struct dvb_adapter *adapter, struct videobuf_dvb *dvb) +{ + int result; /* register frontend */ - result = dvb_register_frontend(&dvb->adapter, dvb->frontend); + result = dvb_register_frontend(adapter, dvb->frontend); if (result < 0) { printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n", dvb->name, result); @@ -188,7 +234,9 @@ int videobuf_dvb_register(struct videobuf_dvb *dvb, dvb->dmxdev.filternum = 256; dvb->dmxdev.demux = &dvb->demux.dmx; dvb->dmxdev.capabilities = 0; - result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); + //result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); + result = dvb_dmxdev_init(&dvb->dmxdev, adapter); + if (result < 0) { printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n", dvb->name, result); @@ -219,7 +267,7 @@ int videobuf_dvb_register(struct videobuf_dvb *dvb, } /* register network adapter */ - dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); + dvb_net_init(adapter, &dvb->net, &dvb->demux.dmx); return 0; fail_fe_conn: @@ -235,24 +283,101 @@ fail_dmx: fail_frontend: dvb_frontend_detach(dvb->frontend); dvb_unregister_adapter(&dvb->adapter); -fail_adapter: + return result; } -void videobuf_dvb_unregister(struct videobuf_dvb *dvb) +void videobuf_dvb_unregister_bus(struct videobuf_dvb_frontends *f) { - dvb_net_release(&dvb->net); - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); - dvb_dmxdev_release(&dvb->dmxdev); - dvb_dmx_release(&dvb->demux); - dvb_unregister_frontend(dvb->frontend); - dvb_frontend_detach(dvb->frontend); - dvb_unregister_adapter(&dvb->adapter); + struct list_head *list, *q; + struct videobuf_dvb_frontend *fe; + + mutex_lock(&f->lock); + list_for_each_safe(list, q, &f->frontend.felist) { + fe = list_entry(list, struct videobuf_dvb_frontend, felist); + + dvb_net_release(&fe->dvb.net); + fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx, &fe->dvb.fe_mem); + fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx, &fe->dvb.fe_hw); + dvb_dmxdev_release(&fe->dvb.dmxdev); + dvb_dmx_release(&fe->dvb.demux); + dvb_unregister_frontend(fe->dvb.frontend); + dvb_frontend_detach(fe->dvb.frontend); + + list_del(list); + kfree(fe); + } + mutex_unlock(&f->lock); + + dvb_unregister_adapter(&f->adapter); +} + +struct videobuf_dvb_frontend * videobuf_dvb_get_frontend(struct videobuf_dvb_frontends *f, int id) +{ + struct list_head *list, *q; + struct videobuf_dvb_frontend *fe, *ret = NULL; + + mutex_lock(&f->lock); + + list_for_each_safe(list, q, &f->frontend.felist) { + fe = list_entry(list, struct videobuf_dvb_frontend, felist); + if (fe->id == id) { + ret = fe; + break; + } + } + + mutex_unlock(&f->lock); + + return ret; +} + +int videobuf_dvb_find_frontend(struct videobuf_dvb_frontends *f, struct dvb_frontend *p) +{ + struct list_head *list, *q; + struct videobuf_dvb_frontend *fe = NULL; + int ret = 0; + + mutex_lock(&f->lock); + + list_for_each_safe(list, q, &f->frontend.felist) { + fe = list_entry(list, struct videobuf_dvb_frontend, felist); + if (fe->dvb.frontend == p) { + ret = fe->id; + break; + } + } + + mutex_unlock(&f->lock); + + return ret; +} + +struct videobuf_dvb_frontend * videobuf_dvb_alloc_frontend(void *private, struct videobuf_dvb_frontends *f, int id) +{ + struct videobuf_dvb_frontend *fe; + + fe = kzalloc(sizeof(struct videobuf_dvb_frontend),GFP_KERNEL); + if (fe == NULL) + goto fail_alloc; + + fe->dev = private; + fe->id = id; + mutex_init(&fe->dvb.lock); + + mutex_lock(&f->lock); + list_add_tail(&fe->felist,&f->frontend.felist); + mutex_unlock(&f->lock); + +fail_alloc: + return fe; } -EXPORT_SYMBOL(videobuf_dvb_register); -EXPORT_SYMBOL(videobuf_dvb_unregister); +EXPORT_SYMBOL(videobuf_dvb_register_bus); +EXPORT_SYMBOL(videobuf_dvb_unregister_bus); +EXPORT_SYMBOL(videobuf_dvb_alloc_frontend); +EXPORT_SYMBOL(videobuf_dvb_get_frontend); +EXPORT_SYMBOL(videobuf_dvb_find_frontend); /* ------------------------------------------------------------------ */ /* -- cgit v1.2.3 From 270e299bd7d5775be3af60217fb512a480a75a33 Mon Sep 17 00:00:00 2001 From: "darron@kewl.org" Date: Sat, 11 Oct 2008 15:18:53 +0100 Subject: MFE: Fix a number of bugs and some tidying up From: Darron Broad A number of reference to videobuf_dvb_get_frontend used an invalid index. This has been fixed. The section for the HVR3000 in advise_acquire was redundant as the same logic is used on the HVR4000. This has been removed and both cards now use the same function. A number of small errors and whitespace errors are also fixed. Priority: normal Signed-off-by: Darron Broad --- linux/drivers/media/video/videobuf-dvb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'linux/drivers/media/video/videobuf-dvb.c') diff --git a/linux/drivers/media/video/videobuf-dvb.c b/linux/drivers/media/video/videobuf-dvb.c index 9f1b91fc7..cf699a8ca 100644 --- a/linux/drivers/media/video/videobuf-dvb.c +++ b/linux/drivers/media/video/videobuf-dvb.c @@ -234,7 +234,6 @@ int videobuf_dvb_register_frontend(struct dvb_adapter *adapter, struct videobuf_ dvb->dmxdev.filternum = 256; dvb->dmxdev.demux = &dvb->demux.dmx; dvb->dmxdev.capabilities = 0; - //result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); result = dvb_dmxdev_init(&dvb->dmxdev, adapter); if (result < 0) { @@ -282,7 +281,7 @@ fail_dmx: dvb_unregister_frontend(dvb->frontend); fail_frontend: dvb_frontend_detach(dvb->frontend); - dvb_unregister_adapter(&dvb->adapter); + dvb_unregister_adapter(adapter); return result; } -- cgit v1.2.3 From e792b162282b2a6897d82cb48a3ee6222bc01686 Mon Sep 17 00:00:00 2001 From: "darron@kewl.org" Date: Sat, 11 Oct 2008 15:44:05 +0100 Subject: MFE: Add multi-frontend mutual exclusion From: Darron Broad This add frontend R/W mutual exclusion. Prior to this point in time it was possible to open both frontends simultaneously which an MFE card cannot support. In order to stop this, a delayed open is performed which has the following function: Return EBUSY after a configurable amount of time if a frontend is unavailable due to the other being in use. Only allow opening of a frontend if the kernel thread of the other has stopped. This solution was chosen to allow switching between frontends to work as seamlessly as possible. When both frontends are actually opened simultaneously then one will only open, but if quick switching is performed between one of many then the new open will succeed in a clean fashion rather than interrupting a kernel thread. Priority: normal Signed-off-by: Darron Broad --- linux/drivers/media/video/videobuf-dvb.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'linux/drivers/media/video/videobuf-dvb.c') diff --git a/linux/drivers/media/video/videobuf-dvb.c b/linux/drivers/media/video/videobuf-dvb.c index cf699a8ca..33e2f2b2b 100644 --- a/linux/drivers/media/video/videobuf-dvb.c +++ b/linux/drivers/media/video/videobuf-dvb.c @@ -145,7 +145,8 @@ int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f, struct module *module, void *adapter_priv, struct device *device, - short *adapter_nr) //NEW + short *adapter_nr, + int mfe_shared) { struct list_head *list, *q; struct videobuf_dvb_frontend *fe; @@ -158,7 +159,7 @@ int videobuf_dvb_register_bus(struct videobuf_dvb_frontends *f, } /* Bring up the adapter */ - res = videobuf_dvb_register_adapter(f, module, adapter_priv, device, fe->dvb.name, adapter_nr); //NEW + res = videobuf_dvb_register_adapter(f, module, adapter_priv, device, fe->dvb.name, adapter_nr, mfe_shared); if (res < 0) { printk(KERN_WARNING "videobuf_dvb_register_adapter failed (errno = %d)\n", res); goto err; @@ -186,7 +187,8 @@ int videobuf_dvb_register_adapter(struct videobuf_dvb_frontends *fe, void *adapter_priv, struct device *device, char *adapter_name, - short *adapter_nr) //NEW + short *adapter_nr, + int mfe_shared) { int result; @@ -199,6 +201,7 @@ int videobuf_dvb_register_adapter(struct videobuf_dvb_frontends *fe, adapter_name, result); } fe->adapter.priv = adapter_priv; + fe->adapter.mfe_shared = mfe_shared; return result; } -- cgit v1.2.3