Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  ALSA sequencer device management
0004  *  Copyright (c) 1999 by Takashi Iwai <tiwai@suse.de>
0005  *
0006  *----------------------------------------------------------------
0007  *
0008  * This device handler separates the card driver module from sequencer
0009  * stuff (sequencer core, synth drivers, etc), so that user can avoid
0010  * to spend unnecessary resources e.g. if he needs only listening to
0011  * MP3s.
0012  *
0013  * The card (or lowlevel) driver creates a sequencer device entry
0014  * via snd_seq_device_new().  This is an entry pointer to communicate
0015  * with the sequencer device "driver", which is involved with the
0016  * actual part to communicate with the sequencer core.
0017  * Each sequencer device entry has an id string and the corresponding
0018  * driver with the same id is loaded when required.  For example,
0019  * lowlevel codes to access emu8000 chip on sbawe card are included in
0020  * emu8000-synth module.  To activate this module, the hardware
0021  * resources like i/o port are passed via snd_seq_device argument.
0022  */
0023 
0024 #include <linux/device.h>
0025 #include <linux/init.h>
0026 #include <linux/module.h>
0027 #include <sound/core.h>
0028 #include <sound/info.h>
0029 #include <sound/seq_device.h>
0030 #include <sound/seq_kernel.h>
0031 #include <sound/initval.h>
0032 #include <linux/kmod.h>
0033 #include <linux/slab.h>
0034 #include <linux/mutex.h>
0035 
0036 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
0037 MODULE_DESCRIPTION("ALSA sequencer device management");
0038 MODULE_LICENSE("GPL");
0039 
0040 /*
0041  * bus definition
0042  */
0043 static int snd_seq_bus_match(struct device *dev, struct device_driver *drv)
0044 {
0045     struct snd_seq_device *sdev = to_seq_dev(dev);
0046     struct snd_seq_driver *sdrv = to_seq_drv(drv);
0047 
0048     return strcmp(sdrv->id, sdev->id) == 0 &&
0049         sdrv->argsize == sdev->argsize;
0050 }
0051 
0052 static struct bus_type snd_seq_bus_type = {
0053     .name = "snd_seq",
0054     .match = snd_seq_bus_match,
0055 };
0056 
0057 /*
0058  * proc interface -- just for compatibility
0059  */
0060 #ifdef CONFIG_SND_PROC_FS
0061 static struct snd_info_entry *info_entry;
0062 
0063 static int print_dev_info(struct device *dev, void *data)
0064 {
0065     struct snd_seq_device *sdev = to_seq_dev(dev);
0066     struct snd_info_buffer *buffer = data;
0067 
0068     snd_iprintf(buffer, "snd-%s,%s,%d\n", sdev->id,
0069             dev->driver ? "loaded" : "empty",
0070             dev->driver ? 1 : 0);
0071     return 0;
0072 }
0073 
0074 static void snd_seq_device_info(struct snd_info_entry *entry,
0075                 struct snd_info_buffer *buffer)
0076 {
0077     bus_for_each_dev(&snd_seq_bus_type, NULL, buffer, print_dev_info);
0078 }
0079 #endif
0080 
0081 /*
0082  * load all registered drivers (called from seq_clientmgr.c)
0083  */
0084 
0085 #ifdef CONFIG_MODULES
0086 /* flag to block auto-loading */
0087 static atomic_t snd_seq_in_init = ATOMIC_INIT(1); /* blocked as default */
0088 
0089 static int request_seq_drv(struct device *dev, void *data)
0090 {
0091     struct snd_seq_device *sdev = to_seq_dev(dev);
0092 
0093     if (!dev->driver)
0094         request_module("snd-%s", sdev->id);
0095     return 0;
0096 }
0097 
0098 static void autoload_drivers(struct work_struct *work)
0099 {
0100     /* avoid reentrance */
0101     if (atomic_inc_return(&snd_seq_in_init) == 1)
0102         bus_for_each_dev(&snd_seq_bus_type, NULL, NULL,
0103                  request_seq_drv);
0104     atomic_dec(&snd_seq_in_init);
0105 }
0106 
0107 static DECLARE_WORK(autoload_work, autoload_drivers);
0108 
0109 static void queue_autoload_drivers(void)
0110 {
0111     schedule_work(&autoload_work);
0112 }
0113 
0114 void snd_seq_autoload_init(void)
0115 {
0116     atomic_dec(&snd_seq_in_init);
0117 #ifdef CONFIG_SND_SEQUENCER_MODULE
0118     /* initial autoload only when snd-seq is a module */
0119     queue_autoload_drivers();
0120 #endif
0121 }
0122 EXPORT_SYMBOL(snd_seq_autoload_init);
0123 
0124 void snd_seq_autoload_exit(void)
0125 {
0126     atomic_inc(&snd_seq_in_init);
0127 }
0128 EXPORT_SYMBOL(snd_seq_autoload_exit);
0129 
0130 void snd_seq_device_load_drivers(void)
0131 {
0132     queue_autoload_drivers();
0133     flush_work(&autoload_work);
0134 }
0135 EXPORT_SYMBOL(snd_seq_device_load_drivers);
0136 
0137 static inline void cancel_autoload_drivers(void)
0138 {
0139     cancel_work_sync(&autoload_work);
0140 }
0141 #else
0142 static inline void queue_autoload_drivers(void)
0143 {
0144 }
0145 
0146 static inline void cancel_autoload_drivers(void)
0147 {
0148 }
0149 #endif
0150 
0151 /*
0152  * device management
0153  */
0154 static int snd_seq_device_dev_free(struct snd_device *device)
0155 {
0156     struct snd_seq_device *dev = device->device_data;
0157 
0158     cancel_autoload_drivers();
0159     if (dev->private_free)
0160         dev->private_free(dev);
0161     put_device(&dev->dev);
0162     return 0;
0163 }
0164 
0165 static int snd_seq_device_dev_register(struct snd_device *device)
0166 {
0167     struct snd_seq_device *dev = device->device_data;
0168     int err;
0169 
0170     err = device_add(&dev->dev);
0171     if (err < 0)
0172         return err;
0173     if (!dev->dev.driver)
0174         queue_autoload_drivers();
0175     return 0;
0176 }
0177 
0178 static int snd_seq_device_dev_disconnect(struct snd_device *device)
0179 {
0180     struct snd_seq_device *dev = device->device_data;
0181 
0182     device_del(&dev->dev);
0183     return 0;
0184 }
0185 
0186 static void snd_seq_dev_release(struct device *dev)
0187 {
0188     kfree(to_seq_dev(dev));
0189 }
0190 
0191 /*
0192  * register a sequencer device
0193  * card = card info
0194  * device = device number (if any)
0195  * id = id of driver
0196  * result = return pointer (NULL allowed if unnecessary)
0197  */
0198 int snd_seq_device_new(struct snd_card *card, int device, const char *id,
0199                int argsize, struct snd_seq_device **result)
0200 {
0201     struct snd_seq_device *dev;
0202     int err;
0203     static const struct snd_device_ops dops = {
0204         .dev_free = snd_seq_device_dev_free,
0205         .dev_register = snd_seq_device_dev_register,
0206         .dev_disconnect = snd_seq_device_dev_disconnect,
0207     };
0208 
0209     if (result)
0210         *result = NULL;
0211 
0212     if (snd_BUG_ON(!id))
0213         return -EINVAL;
0214 
0215     dev = kzalloc(sizeof(*dev) + argsize, GFP_KERNEL);
0216     if (!dev)
0217         return -ENOMEM;
0218 
0219     /* set up device info */
0220     dev->card = card;
0221     dev->device = device;
0222     dev->id = id;
0223     dev->argsize = argsize;
0224 
0225     device_initialize(&dev->dev);
0226     dev->dev.parent = &card->card_dev;
0227     dev->dev.bus = &snd_seq_bus_type;
0228     dev->dev.release = snd_seq_dev_release;
0229     dev_set_name(&dev->dev, "%s-%d-%d", dev->id, card->number, device);
0230 
0231     /* add this device to the list */
0232     err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops);
0233     if (err < 0) {
0234         put_device(&dev->dev);
0235         return err;
0236     }
0237     
0238     if (result)
0239         *result = dev;
0240 
0241     return 0;
0242 }
0243 EXPORT_SYMBOL(snd_seq_device_new);
0244 
0245 /*
0246  * driver registration
0247  */
0248 int __snd_seq_driver_register(struct snd_seq_driver *drv, struct module *mod)
0249 {
0250     if (WARN_ON(!drv->driver.name || !drv->id))
0251         return -EINVAL;
0252     drv->driver.bus = &snd_seq_bus_type;
0253     drv->driver.owner = mod;
0254     return driver_register(&drv->driver);
0255 }
0256 EXPORT_SYMBOL_GPL(__snd_seq_driver_register);
0257 
0258 void snd_seq_driver_unregister(struct snd_seq_driver *drv)
0259 {
0260     driver_unregister(&drv->driver);
0261 }
0262 EXPORT_SYMBOL_GPL(snd_seq_driver_unregister);
0263 
0264 /*
0265  * module part
0266  */
0267 
0268 static int __init seq_dev_proc_init(void)
0269 {
0270 #ifdef CONFIG_SND_PROC_FS
0271     info_entry = snd_info_create_module_entry(THIS_MODULE, "drivers",
0272                           snd_seq_root);
0273     if (info_entry == NULL)
0274         return -ENOMEM;
0275     info_entry->content = SNDRV_INFO_CONTENT_TEXT;
0276     info_entry->c.text.read = snd_seq_device_info;
0277     if (snd_info_register(info_entry) < 0) {
0278         snd_info_free_entry(info_entry);
0279         return -ENOMEM;
0280     }
0281 #endif
0282     return 0;
0283 }
0284 
0285 static int __init alsa_seq_device_init(void)
0286 {
0287     int err;
0288 
0289     err = bus_register(&snd_seq_bus_type);
0290     if (err < 0)
0291         return err;
0292     err = seq_dev_proc_init();
0293     if (err < 0)
0294         bus_unregister(&snd_seq_bus_type);
0295     return err;
0296 }
0297 
0298 static void __exit alsa_seq_device_exit(void)
0299 {
0300 #ifdef CONFIG_MODULES
0301     cancel_work_sync(&autoload_work);
0302 #endif
0303 #ifdef CONFIG_SND_PROC_FS
0304     snd_info_free_entry(info_entry);
0305 #endif
0306     bus_unregister(&snd_seq_bus_type);
0307 }
0308 
0309 subsys_initcall(alsa_seq_device_init)
0310 module_exit(alsa_seq_device_exit)