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);
- int *count = data;
- struct cx18 *cx;
+ struct v4l2_device *v4l2_dev = &cx->v4l2_dev;
struct cx18_stream *s;
if (v4l2_dev == NULL) {
__func__);
} else {
CX18_DEBUG_ALSA_INFO("%s: created cx18 ALSA interface instance "
- "%d\n", __func__, *count);
- (*count)++;
+ "\n", __func__);
}
return 0;
}
static int __init cx18_alsa_init(void)
{
- struct device_driver *drv;
- int count = 0;
- int ret;
-
printk(KERN_INFO "cx18-alsa: module loading...\n");
-
- drv = driver_find("cx18", &pci_bus_type);
- 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;
+ cx18_ext_init = &cx18_alsa_load;
+ return 0;
}
static void snd_cx18_exit(struct snd_cx18_card *cxsc)
ret = driver_for_each_device(drv, NULL, NULL, cx18_alsa_exit_callback);
put_driver(drv);
+ cx18_ext_init = NULL;
printk(KERN_INFO "cx18-alsa: module unload complete\n");
}
setting this to 1 you ensure that radio0 is now also radio1. */
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 */
static struct pci_device_id cx18_pci_tbl[] __devinitdata = {
{PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418,
MODULE_VERSION(CX18_VERSION);
+/* Forward Declaration */
+static void request_modules(struct cx18 *dev);
+
/* Generic utility functions */
int cx18_msleep_timeout(unsigned int msecs, int intr)
{
}
CX18_INFO("Initialized card: %s\n", cx->card_name);
+
+ /* Load cx18 submodules (cx18-alsa) */
+ request_modules(cx);
+
return 0;
free_streams:
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 */
static struct pci_driver cx18_pci_driver = {
.name = "cx18",
u32 active_input;
v4l2_std_id std;
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)
return container_of(v4l2_dev, struct cx18, v4l2_dev);
}
+/* cx18 extensions to be loaded */
+extern int (*cx18_ext_init)(struct cx18 *);
+
/* Globals */
extern int cx18_first_minor;