Commit d68b687b authored by Devin Heitmueller's avatar Devin Heitmueller Committed by Mauro Carvalho Chehab

V4L/DVB: cx18: rework cx18-alsa module loading to support automatic loading

Restructure the way the module gets loaded so that it gets loaded automatically
when cx18 is loaded, and make it work properly if there are multiple cards
present (since the old code would only take one opportunity to connect to cx18
instances when the module first loaded).

This work was sponsored by ONELAN Limited.
Signed-off-by: default avatarDevin Heitmueller <dheitmueller@kernellabs.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 4a8cfe6a
...@@ -190,11 +190,9 @@ static int __init snd_cx18_init(struct v4l2_device *v4l2_dev) ...@@ -190,11 +190,9 @@ static int __init snd_cx18_init(struct v4l2_device *v4l2_dev)
return ret; return ret;
} }
static int __init cx18_alsa_init_callback(struct device *dev, void *data) int cx18_alsa_load(struct cx18 *cx)
{ {
struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); struct v4l2_device *v4l2_dev = &cx->v4l2_dev;
int *count = data;
struct cx18 *cx;
struct cx18_stream *s; struct cx18_stream *s;
if (v4l2_dev == NULL) { if (v4l2_dev == NULL) {
...@@ -227,41 +225,16 @@ static int __init cx18_alsa_init_callback(struct device *dev, void *data) ...@@ -227,41 +225,16 @@ static int __init cx18_alsa_init_callback(struct device *dev, void *data)
__func__); __func__);
} else { } else {
CX18_DEBUG_ALSA_INFO("%s: created cx18 ALSA interface instance " CX18_DEBUG_ALSA_INFO("%s: created cx18 ALSA interface instance "
"%d\n", __func__, *count); "\n", __func__);
(*count)++;
} }
return 0; return 0;
} }
static int __init cx18_alsa_init(void) static int __init cx18_alsa_init(void)
{ {
struct device_driver *drv;
int count = 0;
int ret;
printk(KERN_INFO "cx18-alsa: module loading...\n"); printk(KERN_INFO "cx18-alsa: module loading...\n");
cx18_ext_init = &cx18_alsa_load;
drv = driver_find("cx18", &pci_bus_type); return 0;
if (drv == NULL) {
printk("cx18-alsa: drv was null\n");
return -ENODEV;
}
ret = driver_for_each_device(drv, NULL, &count,
cx18_alsa_init_callback);
put_driver(drv);
if (count == 0) {
printk(KERN_ERR "cx18-alsa: no cx18 cards found with a PCM "
"capture stream allocated\n");
ret = -ENODEV;
} else {
printk(KERN_INFO "cx18-alsa: ALSA interface(s) created for %d "
"cx18 card(s)\n", count);
ret = 0;
}
printk(KERN_INFO "cx18-alsa: module load complete\n");
return ret;
} }
static void snd_cx18_exit(struct snd_cx18_card *cxsc) static void snd_cx18_exit(struct snd_cx18_card *cxsc)
...@@ -308,6 +281,7 @@ static void cx18_alsa_exit(void) ...@@ -308,6 +281,7 @@ static void cx18_alsa_exit(void)
ret = driver_for_each_device(drv, NULL, NULL, cx18_alsa_exit_callback); ret = driver_for_each_device(drv, NULL, NULL, cx18_alsa_exit_callback);
put_driver(drv); put_driver(drv);
cx18_ext_init = NULL;
printk(KERN_INFO "cx18-alsa: module unload complete\n"); printk(KERN_INFO "cx18-alsa: module unload complete\n");
} }
......
...@@ -47,6 +47,10 @@ ...@@ -47,6 +47,10 @@
setting this to 1 you ensure that radio0 is now also radio1. */ setting this to 1 you ensure that radio0 is now also radio1. */
int cx18_first_minor; int cx18_first_minor;
/* Callback for registering extensions */
int (*cx18_ext_init)(struct cx18 *);
EXPORT_SYMBOL(cx18_ext_init);
/* add your revision and whatnot here */ /* add your revision and whatnot here */
static struct pci_device_id cx18_pci_tbl[] __devinitdata = { static struct pci_device_id cx18_pci_tbl[] __devinitdata = {
{PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418, {PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418,
...@@ -243,6 +247,9 @@ MODULE_LICENSE("GPL"); ...@@ -243,6 +247,9 @@ MODULE_LICENSE("GPL");
MODULE_VERSION(CX18_VERSION); MODULE_VERSION(CX18_VERSION);
/* Forward Declaration */
static void request_modules(struct cx18 *dev);
/* Generic utility functions */ /* Generic utility functions */
int cx18_msleep_timeout(unsigned int msecs, int intr) int cx18_msleep_timeout(unsigned int msecs, int intr)
{ {
...@@ -1049,6 +1056,10 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev, ...@@ -1049,6 +1056,10 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
} }
CX18_INFO("Initialized card: %s\n", cx->card_name); CX18_INFO("Initialized card: %s\n", cx->card_name);
/* Load cx18 submodules (cx18-alsa) */
request_modules(cx);
return 0; return 0;
free_streams: free_streams:
...@@ -1237,6 +1248,29 @@ static void cx18_remove(struct pci_dev *pci_dev) ...@@ -1237,6 +1248,29 @@ static void cx18_remove(struct pci_dev *pci_dev)
kfree(cx); kfree(cx);
} }
#if defined(CONFIG_MODULES) && defined(MODULE)
static void request_module_async(struct work_struct *work)
{
struct cx18 *dev=container_of(work, struct cx18, request_module_wk);
/* Make sure cx18-alsa module is loaded */
request_module("cx18-alsa");
/* Initialize cx18-alsa for this instance of the cx18 device */
if (cx18_ext_init != NULL)
cx18_ext_init(dev);
}
static void request_modules(struct cx18 *dev)
{
INIT_WORK(&dev->request_module_wk, request_module_async);
schedule_work(&dev->request_module_wk);
}
#else
#define request_modules(dev)
#endif /* CONFIG_MODULES */
/* define a pci_driver for card detection */ /* define a pci_driver for card detection */
static struct pci_driver cx18_pci_driver = { static struct pci_driver cx18_pci_driver = {
.name = "cx18", .name = "cx18",
......
...@@ -637,6 +637,9 @@ struct cx18 { ...@@ -637,6 +637,9 @@ struct cx18 {
u32 active_input; u32 active_input;
v4l2_std_id std; v4l2_std_id std;
v4l2_std_id tuner_std; /* The norm of the tuner (fixed) */ v4l2_std_id tuner_std; /* The norm of the tuner (fixed) */
/* Used for cx18-alsa module loading */
struct work_struct request_module_wk;
}; };
static inline struct cx18 *to_cx18(struct v4l2_device *v4l2_dev) static inline struct cx18 *to_cx18(struct v4l2_device *v4l2_dev)
...@@ -644,6 +647,9 @@ static inline struct cx18 *to_cx18(struct v4l2_device *v4l2_dev) ...@@ -644,6 +647,9 @@ static inline struct cx18 *to_cx18(struct v4l2_device *v4l2_dev)
return container_of(v4l2_dev, struct cx18, v4l2_dev); return container_of(v4l2_dev, struct cx18, v4l2_dev);
} }
/* cx18 extensions to be loaded */
extern int (*cx18_ext_init)(struct cx18 *);
/* Globals */ /* Globals */
extern int cx18_first_minor; extern int cx18_first_minor;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment