1 /* 2 * ALSA sequencer device management 3 * Copyright (c) 1999 by Takashi Iwai <tiwai@suse.de> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * 19 * 20 *---------------------------------------------------------------- 21 * 22 * This device handler separates the card driver module from sequencer 23 * stuff (sequencer core, synth drivers, etc), so that user can avoid 24 * to spend unnecessary resources e.g. if he needs only listening to 25 * MP3s. 26 * 27 * The card (or lowlevel) driver creates a sequencer device entry 28 * via snd_seq_device_new(). This is an entry pointer to communicate 29 * with the sequencer device "driver", which is involved with the 30 * actual part to communicate with the sequencer core. 31 * Each sequencer device entry has an id string and the corresponding 32 * driver with the same id is loaded when required. For example, 33 * lowlevel codes to access emu8000 chip on sbawe card are included in 34 * emu8000-synth module. To activate this module, the hardware 35 * resources like i/o port are passed via snd_seq_device argument. 36 * 37 */ 38 39 #include <linux/device.h> 40 #include <linux/init.h> 41 #include <linux/module.h> 42 #include <sound/core.h> 43 #include <sound/info.h> 44 #include <sound/seq_device.h> 45 #include <sound/seq_kernel.h> 46 #include <sound/initval.h> 47 #include <linux/kmod.h> 48 #include <linux/slab.h> 49 #include <linux/mutex.h> 50 51 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); 52 MODULE_DESCRIPTION("ALSA sequencer device management"); 53 MODULE_LICENSE("GPL"); 54 55 /* 56 * bus definition 57 */ 58 static int snd_seq_bus_match(struct device *dev, struct device_driver *drv) 59 { 60 struct snd_seq_device *sdev = to_seq_dev(dev); 61 struct snd_seq_driver *sdrv = to_seq_drv(drv); 62 63 return strcmp(sdrv->id, sdev->id) == 0 && 64 sdrv->argsize == sdev->argsize; 65 } 66 67 static struct bus_type snd_seq_bus_type = { 68 .name = "snd_seq", 69 .match = snd_seq_bus_match, 70 }; 71 72 /* 73 * proc interface -- just for compatibility 74 */ 75 #ifdef CONFIG_SND_PROC_FS 76 static struct snd_info_entry *info_entry; 77 78 static int print_dev_info(struct device *dev, void *data) 79 { 80 struct snd_seq_device *sdev = to_seq_dev(dev); 81 struct snd_info_buffer *buffer = data; 82 83 snd_iprintf(buffer, "snd-%s,%s,%d\n", sdev->id, 84 dev->driver ? "loaded" : "empty", 85 dev->driver ? 1 : 0); 86 return 0; 87 } 88 89 static void snd_seq_device_info(struct snd_info_entry *entry, 90 struct snd_info_buffer *buffer) 91 { 92 bus_for_each_dev(&snd_seq_bus_type, NULL, buffer, print_dev_info); 93 } 94 #endif 95 96 /* 97 * load all registered drivers (called from seq_clientmgr.c) 98 */ 99 100 #ifdef CONFIG_MODULES 101 /* flag to block auto-loading */ 102 static atomic_t snd_seq_in_init = ATOMIC_INIT(1); /* blocked as default */ 103 104 static int request_seq_drv(struct device *dev, void *data) 105 { 106 struct snd_seq_device *sdev = to_seq_dev(dev); 107 108 if (!dev->driver) 109 request_module("snd-%s", sdev->id); 110 return 0; 111 } 112 113 static void autoload_drivers(struct work_struct *work) 114 { 115 /* avoid reentrance */ 116 if (atomic_inc_return(&snd_seq_in_init) == 1) 117 bus_for_each_dev(&snd_seq_bus_type, NULL, NULL, 118 request_seq_drv); 119 atomic_dec(&snd_seq_in_init); 120 } 121 122 static DECLARE_WORK(autoload_work, autoload_drivers); 123 124 static void queue_autoload_drivers(void) 125 { 126 schedule_work(&autoload_work); 127 } 128 129 void snd_seq_autoload_init(void) 130 { 131 atomic_dec(&snd_seq_in_init); 132 #ifdef CONFIG_SND_SEQUENCER_MODULE 133 /* initial autoload only when snd-seq is a module */ 134 queue_autoload_drivers(); 135 #endif 136 } 137 EXPORT_SYMBOL(snd_seq_autoload_init); 138 139 void snd_seq_autoload_exit(void) 140 { 141 atomic_inc(&snd_seq_in_init); 142 } 143 EXPORT_SYMBOL(snd_seq_autoload_exit); 144 145 void snd_seq_device_load_drivers(void) 146 { 147 queue_autoload_drivers(); 148 flush_work(&autoload_work); 149 } 150 EXPORT_SYMBOL(snd_seq_device_load_drivers); 151 #define cancel_autoload_drivers() cancel_work_sync(&autoload_work) 152 #else 153 #define queue_autoload_drivers() /* NOP */ 154 #define cancel_autoload_drivers() /* NOP */ 155 #endif 156 157 /* 158 * device management 159 */ 160 static int snd_seq_device_dev_free(struct snd_device *device) 161 { 162 struct snd_seq_device *dev = device->device_data; 163 164 cancel_autoload_drivers(); 165 put_device(&dev->dev); 166 return 0; 167 } 168 169 static int snd_seq_device_dev_register(struct snd_device *device) 170 { 171 struct snd_seq_device *dev = device->device_data; 172 int err; 173 174 err = device_add(&dev->dev); 175 if (err < 0) 176 return err; 177 if (!dev->dev.driver) 178 queue_autoload_drivers(); 179 return 0; 180 } 181 182 static int snd_seq_device_dev_disconnect(struct snd_device *device) 183 { 184 struct snd_seq_device *dev = device->device_data; 185 186 device_del(&dev->dev); 187 return 0; 188 } 189 190 static void snd_seq_dev_release(struct device *dev) 191 { 192 struct snd_seq_device *sdev = to_seq_dev(dev); 193 194 if (sdev->private_free) 195 sdev->private_free(sdev); 196 kfree(sdev); 197 } 198 199 /* 200 * register a sequencer device 201 * card = card info 202 * device = device number (if any) 203 * id = id of driver 204 * result = return pointer (NULL allowed if unnecessary) 205 */ 206 int snd_seq_device_new(struct snd_card *card, int device, const char *id, 207 int argsize, struct snd_seq_device **result) 208 { 209 struct snd_seq_device *dev; 210 int err; 211 static struct snd_device_ops dops = { 212 .dev_free = snd_seq_device_dev_free, 213 .dev_register = snd_seq_device_dev_register, 214 .dev_disconnect = snd_seq_device_dev_disconnect, 215 }; 216 217 if (result) 218 *result = NULL; 219 220 if (snd_BUG_ON(!id)) 221 return -EINVAL; 222 223 dev = kzalloc(sizeof(*dev) + argsize, GFP_KERNEL); 224 if (!dev) 225 return -ENOMEM; 226 227 /* set up device info */ 228 dev->card = card; 229 dev->device = device; 230 dev->id = id; 231 dev->argsize = argsize; 232 233 device_initialize(&dev->dev); 234 dev->dev.parent = &card->card_dev; 235 dev->dev.bus = &snd_seq_bus_type; 236 dev->dev.release = snd_seq_dev_release; 237 dev_set_name(&dev->dev, "%s-%d-%d", dev->id, card->number, device); 238 239 /* add this device to the list */ 240 err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops); 241 if (err < 0) { 242 put_device(&dev->dev); 243 return err; 244 } 245 246 if (result) 247 *result = dev; 248 249 return 0; 250 } 251 EXPORT_SYMBOL(snd_seq_device_new); 252 253 /* 254 * driver registration 255 */ 256 int __snd_seq_driver_register(struct snd_seq_driver *drv, struct module *mod) 257 { 258 if (WARN_ON(!drv->driver.name || !drv->id)) 259 return -EINVAL; 260 drv->driver.bus = &snd_seq_bus_type; 261 drv->driver.owner = mod; 262 return driver_register(&drv->driver); 263 } 264 EXPORT_SYMBOL_GPL(__snd_seq_driver_register); 265 266 void snd_seq_driver_unregister(struct snd_seq_driver *drv) 267 { 268 driver_unregister(&drv->driver); 269 } 270 EXPORT_SYMBOL_GPL(snd_seq_driver_unregister); 271 272 /* 273 * module part 274 */ 275 276 static int __init seq_dev_proc_init(void) 277 { 278 #ifdef CONFIG_SND_PROC_FS 279 info_entry = snd_info_create_module_entry(THIS_MODULE, "drivers", 280 snd_seq_root); 281 if (info_entry == NULL) 282 return -ENOMEM; 283 info_entry->content = SNDRV_INFO_CONTENT_TEXT; 284 info_entry->c.text.read = snd_seq_device_info; 285 if (snd_info_register(info_entry) < 0) { 286 snd_info_free_entry(info_entry); 287 return -ENOMEM; 288 } 289 #endif 290 return 0; 291 } 292 293 static int __init alsa_seq_device_init(void) 294 { 295 int err; 296 297 err = bus_register(&snd_seq_bus_type); 298 if (err < 0) 299 return err; 300 err = seq_dev_proc_init(); 301 if (err < 0) 302 bus_unregister(&snd_seq_bus_type); 303 return err; 304 } 305 306 static void __exit alsa_seq_device_exit(void) 307 { 308 #ifdef CONFIG_MODULES 309 cancel_work_sync(&autoload_work); 310 #endif 311 #ifdef CONFIG_SND_PROC_FS 312 snd_info_free_entry(info_entry); 313 #endif 314 bus_unregister(&snd_seq_bus_type); 315 } 316 317 subsys_initcall(alsa_seq_device_init) 318 module_exit(alsa_seq_device_exit) 319