Commit 6176fadc authored by Takashi Iwai's avatar Takashi Iwai

Merge branch 'topic/seq-cleanup' into for-next

parents 66c21c5a 54a721ab
...@@ -25,29 +25,26 @@ ...@@ -25,29 +25,26 @@
* registered device information * registered device information
*/ */
#define ID_LEN 32
/* status flag */
#define SNDRV_SEQ_DEVICE_FREE 0
#define SNDRV_SEQ_DEVICE_REGISTERED 1
struct snd_seq_device { struct snd_seq_device {
/* device info */ /* device info */
struct snd_card *card; /* sound card */ struct snd_card *card; /* sound card */
int device; /* device number */ int device; /* device number */
char id[ID_LEN]; /* driver id */ const char *id; /* driver id */
char name[80]; /* device name */ char name[80]; /* device name */
int argsize; /* size of the argument */ int argsize; /* size of the argument */
void *driver_data; /* private data for driver */ void *driver_data; /* private data for driver */
int status; /* flag - read only */
void *private_data; /* private data for the caller */ void *private_data; /* private data for the caller */
void (*private_free)(struct snd_seq_device *device); void (*private_free)(struct snd_seq_device *device);
struct list_head list; /* link to next device */ struct device dev;
}; };
#define to_seq_dev(_dev) \
container_of(_dev, struct snd_seq_device, dev)
/* sequencer driver */
/* driver operators /* driver operators
* init_device: * probe:
* Initialize the device with given parameters. * Initialize the device with given parameters.
* Typically, * Typically,
* 1. call snd_hwdep_new * 1. call snd_hwdep_new
...@@ -55,25 +52,40 @@ struct snd_seq_device { ...@@ -55,25 +52,40 @@ struct snd_seq_device {
* 3. call snd_hwdep_register * 3. call snd_hwdep_register
* 4. store the instance to dev->driver_data pointer. * 4. store the instance to dev->driver_data pointer.
* *
* free_device: * remove:
* Release the private data. * Release the private data.
* Typically, call snd_device_free(dev->card, dev->driver_data) * Typically, call snd_device_free(dev->card, dev->driver_data)
*/ */
struct snd_seq_dev_ops { struct snd_seq_driver {
int (*init_device)(struct snd_seq_device *dev); struct device_driver driver;
int (*free_device)(struct snd_seq_device *dev); char *id;
int argsize;
}; };
#define to_seq_drv(_drv) \
container_of(_drv, struct snd_seq_driver, driver)
/* /*
* prototypes * prototypes
*/ */
#ifdef CONFIG_MODULES
void snd_seq_device_load_drivers(void); void snd_seq_device_load_drivers(void);
int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, struct snd_seq_device **result); #else
int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, int argsize); #define snd_seq_device_load_drivers()
int snd_seq_device_unregister_driver(char *id); #endif
int snd_seq_device_new(struct snd_card *card, int device, const char *id,
int argsize, struct snd_seq_device **result);
#define SNDRV_SEQ_DEVICE_ARGPTR(dev) (void *)((char *)(dev) + sizeof(struct snd_seq_device)) #define SNDRV_SEQ_DEVICE_ARGPTR(dev) (void *)((char *)(dev) + sizeof(struct snd_seq_device))
int __must_check __snd_seq_driver_register(struct snd_seq_driver *drv,
struct module *mod);
#define snd_seq_driver_register(drv) \
__snd_seq_driver_register(drv, THIS_MODULE)
void snd_seq_driver_unregister(struct snd_seq_driver *drv);
#define module_snd_seq_driver(drv) \
module_driver(drv, snd_seq_driver_register, snd_seq_driver_unregister)
/* /*
* id strings for generic devices * id strings for generic devices
......
...@@ -99,13 +99,9 @@ int snd_seq_event_port_attach(int client, struct snd_seq_port_callback *pcbp, ...@@ -99,13 +99,9 @@ int snd_seq_event_port_attach(int client, struct snd_seq_port_callback *pcbp,
int snd_seq_event_port_detach(int client, int port); int snd_seq_event_port_detach(int client, int port);
#ifdef CONFIG_MODULES #ifdef CONFIG_MODULES
void snd_seq_autoload_lock(void);
void snd_seq_autoload_unlock(void);
void snd_seq_autoload_init(void); void snd_seq_autoload_init(void);
#define snd_seq_autoload_exit() snd_seq_autoload_lock() void snd_seq_autoload_exit(void);
#else #else
#define snd_seq_autoload_lock()
#define snd_seq_autoload_unlock()
#define snd_seq_autoload_init() #define snd_seq_autoload_init()
#define snd_seq_autoload_exit() #define snd_seq_autoload_exit()
#endif #endif
......
...@@ -65,15 +65,20 @@ static unsigned int odev_poll(struct file *file, poll_table * wait); ...@@ -65,15 +65,20 @@ static unsigned int odev_poll(struct file *file, poll_table * wait);
* module interface * module interface
*/ */
static struct snd_seq_driver seq_oss_synth_driver = {
.driver = {
.name = KBUILD_MODNAME,
.probe = snd_seq_oss_synth_probe,
.remove = snd_seq_oss_synth_remove,
},
.id = SNDRV_SEQ_DEV_ID_OSS,
.argsize = sizeof(struct snd_seq_oss_reg),
};
static int __init alsa_seq_oss_init(void) static int __init alsa_seq_oss_init(void)
{ {
int rc; int rc;
static struct snd_seq_dev_ops ops = {
snd_seq_oss_synth_register,
snd_seq_oss_synth_unregister,
};
snd_seq_autoload_lock();
if ((rc = register_device()) < 0) if ((rc = register_device()) < 0)
goto error; goto error;
if ((rc = register_proc()) < 0) { if ((rc = register_proc()) < 0) {
...@@ -86,8 +91,8 @@ static int __init alsa_seq_oss_init(void) ...@@ -86,8 +91,8 @@ static int __init alsa_seq_oss_init(void)
goto error; goto error;
} }
if ((rc = snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_OSS, &ops, rc = snd_seq_driver_register(&seq_oss_synth_driver);
sizeof(struct snd_seq_oss_reg))) < 0) { if (rc < 0) {
snd_seq_oss_delete_client(); snd_seq_oss_delete_client();
unregister_proc(); unregister_proc();
unregister_device(); unregister_device();
...@@ -98,13 +103,12 @@ static int __init alsa_seq_oss_init(void) ...@@ -98,13 +103,12 @@ static int __init alsa_seq_oss_init(void)
snd_seq_oss_synth_init(); snd_seq_oss_synth_init();
error: error:
snd_seq_autoload_unlock();
return rc; return rc;
} }
static void __exit alsa_seq_oss_exit(void) static void __exit alsa_seq_oss_exit(void)
{ {
snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_OSS); snd_seq_driver_unregister(&seq_oss_synth_driver);
snd_seq_oss_delete_client(); snd_seq_oss_delete_client();
unregister_proc(); unregister_proc();
unregister_device(); unregister_device();
......
...@@ -98,8 +98,9 @@ snd_seq_oss_synth_init(void) ...@@ -98,8 +98,9 @@ snd_seq_oss_synth_init(void)
* registration of the synth device * registration of the synth device
*/ */
int int
snd_seq_oss_synth_register(struct snd_seq_device *dev) snd_seq_oss_synth_probe(struct device *_dev)
{ {
struct snd_seq_device *dev = to_seq_dev(_dev);
int i; int i;
struct seq_oss_synth *rec; struct seq_oss_synth *rec;
struct snd_seq_oss_reg *reg = SNDRV_SEQ_DEVICE_ARGPTR(dev); struct snd_seq_oss_reg *reg = SNDRV_SEQ_DEVICE_ARGPTR(dev);
...@@ -149,8 +150,9 @@ snd_seq_oss_synth_register(struct snd_seq_device *dev) ...@@ -149,8 +150,9 @@ snd_seq_oss_synth_register(struct snd_seq_device *dev)
int int
snd_seq_oss_synth_unregister(struct snd_seq_device *dev) snd_seq_oss_synth_remove(struct device *_dev)
{ {
struct snd_seq_device *dev = to_seq_dev(_dev);
int index; int index;
struct seq_oss_synth *rec = dev->driver_data; struct seq_oss_synth *rec = dev->driver_data;
unsigned long flags; unsigned long flags;
......
...@@ -28,8 +28,8 @@ ...@@ -28,8 +28,8 @@
#include <sound/seq_device.h> #include <sound/seq_device.h>
void snd_seq_oss_synth_init(void); void snd_seq_oss_synth_init(void);
int snd_seq_oss_synth_register(struct snd_seq_device *dev); int snd_seq_oss_synth_probe(struct device *dev);
int snd_seq_oss_synth_unregister(struct snd_seq_device *dev); int snd_seq_oss_synth_remove(struct device *dev);
void snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp); void snd_seq_oss_synth_setup(struct seq_oss_devinfo *dp);
void snd_seq_oss_synth_setup_midi(struct seq_oss_devinfo *dp); void snd_seq_oss_synth_setup_midi(struct seq_oss_devinfo *dp);
void snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp); void snd_seq_oss_synth_cleanup(struct seq_oss_devinfo *dp);
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
* *
*/ */
#include <linux/device.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <sound/core.h> #include <sound/core.h>
...@@ -51,140 +52,78 @@ MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); ...@@ -51,140 +52,78 @@ MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
MODULE_DESCRIPTION("ALSA sequencer device management"); MODULE_DESCRIPTION("ALSA sequencer device management");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/* driver state */ /*
#define DRIVER_EMPTY 0 * bus definition
#define DRIVER_LOADED (1<<0) */
#define DRIVER_REQUESTED (1<<1) static int snd_seq_bus_match(struct device *dev, struct device_driver *drv)
#define DRIVER_LOCKED (1<<2) {
#define DRIVER_REQUESTING (1<<3) struct snd_seq_device *sdev = to_seq_dev(dev);
struct snd_seq_driver *sdrv = to_seq_drv(drv);
struct ops_list {
char id[ID_LEN]; /* driver id */
int driver; /* driver state */
int used; /* reference counter */
int argsize; /* argument size */
/* operators */
struct snd_seq_dev_ops ops;
/* registered devices */
struct list_head dev_list; /* list of devices */
int num_devices; /* number of associated devices */
int num_init_devices; /* number of initialized devices */
struct mutex reg_mutex;
struct list_head list; /* next driver */
};
return strcmp(sdrv->id, sdev->id) == 0 &&
sdrv->argsize == sdev->argsize;
}
static LIST_HEAD(opslist); static struct bus_type snd_seq_bus_type = {
static int num_ops; .name = "snd_seq",
static DEFINE_MUTEX(ops_mutex); .match = snd_seq_bus_match,
#ifdef CONFIG_PROC_FS };
static struct snd_info_entry *info_entry;
#endif
/* /*
* prototypes * proc interface -- just for compatibility
*/ */
static int snd_seq_device_free(struct snd_seq_device *dev); #ifdef CONFIG_PROC_FS
static int snd_seq_device_dev_free(struct snd_device *device); static struct snd_info_entry *info_entry;
static int snd_seq_device_dev_register(struct snd_device *device);
static int snd_seq_device_dev_disconnect(struct snd_device *device);
static int init_device(struct snd_seq_device *dev, struct ops_list *ops);
static int free_device(struct snd_seq_device *dev, struct ops_list *ops);
static struct ops_list *find_driver(char *id, int create_if_empty);
static struct ops_list *create_driver(char *id);
static void unlock_driver(struct ops_list *ops);
static void remove_drivers(void);
/* static int print_dev_info(struct device *dev, void *data)
* show all drivers and their status {
*/ struct snd_seq_device *sdev = to_seq_dev(dev);
struct snd_info_buffer *buffer = data;
snd_iprintf(buffer, "snd-%s,%s,%d\n", sdev->id,
dev->driver ? "loaded" : "empty",
dev->driver ? 1 : 0);
return 0;
}
#ifdef CONFIG_PROC_FS
static void snd_seq_device_info(struct snd_info_entry *entry, static void snd_seq_device_info(struct snd_info_entry *entry,
struct snd_info_buffer *buffer) struct snd_info_buffer *buffer)
{ {
struct ops_list *ops; bus_for_each_dev(&snd_seq_bus_type, NULL, buffer, print_dev_info);
mutex_lock(&ops_mutex);
list_for_each_entry(ops, &opslist, list) {
snd_iprintf(buffer, "snd-%s%s%s%s,%d\n",
ops->id,
ops->driver & DRIVER_LOADED ? ",loaded" : (ops->driver == DRIVER_EMPTY ? ",empty" : ""),
ops->driver & DRIVER_REQUESTED ? ",requested" : "",
ops->driver & DRIVER_LOCKED ? ",locked" : "",
ops->num_devices);
}
mutex_unlock(&ops_mutex);
} }
#endif #endif
/* /*
* load all registered drivers (called from seq_clientmgr.c) * load all registered drivers (called from seq_clientmgr.c)
*/ */
#ifdef CONFIG_MODULES #ifdef CONFIG_MODULES
/* avoid auto-loading during module_init() */ /* flag to block auto-loading */
static atomic_t snd_seq_in_init = ATOMIC_INIT(1); /* blocked as default */ static atomic_t snd_seq_in_init = ATOMIC_INIT(1); /* blocked as default */
void snd_seq_autoload_lock(void)
{
atomic_inc(&snd_seq_in_init);
}
void snd_seq_autoload_unlock(void) static int request_seq_drv(struct device *dev, void *data)
{ {
atomic_dec(&snd_seq_in_init); struct snd_seq_device *sdev = to_seq_dev(dev);
if (!dev->driver)
request_module("snd-%s", sdev->id);
return 0;
} }
static void autoload_drivers(void) static void autoload_drivers(struct work_struct *work)
{ {
/* avoid reentrance */ /* avoid reentrance */
if (atomic_inc_return(&snd_seq_in_init) == 1) { if (atomic_inc_return(&snd_seq_in_init) == 1)
struct ops_list *ops; bus_for_each_dev(&snd_seq_bus_type, NULL, NULL,
request_seq_drv);
mutex_lock(&ops_mutex);
list_for_each_entry(ops, &opslist, list) {
if ((ops->driver & DRIVER_REQUESTING) &&
!(ops->driver & DRIVER_REQUESTED)) {
ops->used++;
mutex_unlock(&ops_mutex);
ops->driver |= DRIVER_REQUESTED;
request_module("snd-%s", ops->id);
mutex_lock(&ops_mutex);
ops->used--;
}
}
mutex_unlock(&ops_mutex);
}
atomic_dec(&snd_seq_in_init); atomic_dec(&snd_seq_in_init);
} }
static void call_autoload(struct work_struct *work) static DECLARE_WORK(autoload_work, autoload_drivers);
{
autoload_drivers();
}
static DECLARE_WORK(autoload_work, call_autoload);
static void try_autoload(struct ops_list *ops)
{
if (!ops->driver) {
ops->driver |= DRIVER_REQUESTING;
schedule_work(&autoload_work);
}
}
static void queue_autoload_drivers(void) static void queue_autoload_drivers(void)
{ {
struct ops_list *ops; schedule_work(&autoload_work);
mutex_lock(&ops_mutex);
list_for_each_entry(ops, &opslist, list)
try_autoload(ops);
mutex_unlock(&ops_mutex);
} }
void snd_seq_autoload_init(void) void snd_seq_autoload_init(void)
...@@ -195,384 +134,143 @@ void snd_seq_autoload_init(void) ...@@ -195,384 +134,143 @@ void snd_seq_autoload_init(void)
queue_autoload_drivers(); queue_autoload_drivers();
#endif #endif
} }
#else EXPORT_SYMBOL(snd_seq_autoload_init);
#define try_autoload(ops) /* NOP */
#endif
void snd_seq_device_load_drivers(void) void snd_seq_autoload_exit(void)
{ {
#ifdef CONFIG_MODULES atomic_inc(&snd_seq_in_init);
queue_autoload_drivers();
flush_work(&autoload_work);
#endif
} }
EXPORT_SYMBOL(snd_seq_autoload_exit);
/* void snd_seq_device_load_drivers(void)
* register a sequencer device
* card = card info
* device = device number (if any)
* id = id of driver
* result = return pointer (NULL allowed if unnecessary)
*/
int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize,
struct snd_seq_device **result)
{ {
struct snd_seq_device *dev; queue_autoload_drivers();
struct ops_list *ops; flush_work(&autoload_work);
int err;
static struct snd_device_ops dops = {
.dev_free = snd_seq_device_dev_free,
.dev_register = snd_seq_device_dev_register,
.dev_disconnect = snd_seq_device_dev_disconnect,
};
if (result)
*result = NULL;
if (snd_BUG_ON(!id))
return -EINVAL;
ops = find_driver(id, 1);
if (ops == NULL)
return -ENOMEM;
dev = kzalloc(sizeof(*dev)*2 + argsize, GFP_KERNEL);
if (dev == NULL) {
unlock_driver(ops);
return -ENOMEM;
}
/* set up device info */
dev->card = card;
dev->device = device;
strlcpy(dev->id, id, sizeof(dev->id));
dev->argsize = argsize;
dev->status = SNDRV_SEQ_DEVICE_FREE;
/* add this device to the list */
mutex_lock(&ops->reg_mutex);
list_add_tail(&dev->list, &ops->dev_list);
ops->num_devices++;
mutex_unlock(&ops->reg_mutex);
if ((err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops)) < 0) {
snd_seq_device_free(dev);
return err;
}
try_autoload(ops);
unlock_driver(ops);
if (result)
*result = dev;
return 0;
} }
EXPORT_SYMBOL(snd_seq_device_load_drivers);
#else
#define queue_autoload_drivers() /* NOP */
#endif
/* /*
* free the existing device * device management
*/ */
static int snd_seq_device_free(struct snd_seq_device *dev)
{
struct ops_list *ops;
if (snd_BUG_ON(!dev))
return -EINVAL;
ops = find_driver(dev->id, 0);
if (ops == NULL)
return -ENXIO;
/* remove the device from the list */
mutex_lock(&ops->reg_mutex);
list_del(&dev->list);
ops->num_devices--;
mutex_unlock(&ops->reg_mutex);
free_device(dev, ops);
if (dev->private_free)
dev->private_free(dev);
kfree(dev);
unlock_driver(ops);
return 0;
}
static int snd_seq_device_dev_free(struct snd_device *device) static int snd_seq_device_dev_free(struct snd_device *device)
{ {
struct snd_seq_device *dev = device->device_data; struct snd_seq_device *dev = device->device_data;
return snd_seq_device_free(dev);
put_device(&dev->dev);
return 0;
} }
/*
* register the device
*/
static int snd_seq_device_dev_register(struct snd_device *device) static int snd_seq_device_dev_register(struct snd_device *device)
{ {
struct snd_seq_device *dev = device->device_data; struct snd_seq_device *dev = device->device_data;
struct ops_list *ops; int err;
ops = find_driver(dev->id, 0);
if (ops == NULL)
return -ENOENT;
/* initialize this device if the corresponding driver was
* already loaded
*/
if (ops->driver & DRIVER_LOADED)
init_device(dev, ops);
unlock_driver(ops); err = device_add(&dev->dev);
if (err < 0)
return err;
if (!dev->dev.driver)
queue_autoload_drivers();
return 0; return 0;
} }
/*
* disconnect the device
*/
static int snd_seq_device_dev_disconnect(struct snd_device *device) static int snd_seq_device_dev_disconnect(struct snd_device *device)
{ {
struct snd_seq_device *dev = device->device_data; struct snd_seq_device *dev = device->device_data;
struct ops_list *ops;
ops = find_driver(dev->id, 0);
if (ops == NULL)
return -ENOENT;
free_device(dev, ops);
unlock_driver(ops); device_del(&dev->dev);
return 0; return 0;
} }
/* static void snd_seq_dev_release(struct device *dev)
* register device driver
* id = driver id
* entry = driver operators - duplicated to each instance
*/
int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry,
int argsize)
{ {
struct ops_list *ops; struct snd_seq_device *sdev = to_seq_dev(dev);
struct snd_seq_device *dev;
if (id == NULL || entry == NULL || if (sdev->private_free)
entry->init_device == NULL || entry->free_device == NULL) sdev->private_free(sdev);
return -EINVAL; kfree(sdev);
ops = find_driver(id, 1);
if (ops == NULL)
return -ENOMEM;
if (ops->driver & DRIVER_LOADED) {
pr_warn("ALSA: seq: driver_register: driver '%s' already exists\n", id);
unlock_driver(ops);
return -EBUSY;
}
mutex_lock(&ops->reg_mutex);
/* copy driver operators */
ops->ops = *entry;
ops->driver |= DRIVER_LOADED;
ops->argsize = argsize;
/* initialize existing devices if necessary */
list_for_each_entry(dev, &ops->dev_list, list) {
init_device(dev, ops);
}
mutex_unlock(&ops->reg_mutex);
unlock_driver(ops);
return 0;
} }
/*
* create driver record
*/
static struct ops_list * create_driver(char *id)
{
struct ops_list *ops;
ops = kzalloc(sizeof(*ops), GFP_KERNEL);
if (ops == NULL)
return ops;
/* set up driver entry */
strlcpy(ops->id, id, sizeof(ops->id));
mutex_init(&ops->reg_mutex);
/*
* The ->reg_mutex locking rules are per-driver, so we create
* separate per-driver lock classes:
*/
lockdep_set_class(&ops->reg_mutex, (struct lock_class_key *)id);
ops->driver = DRIVER_EMPTY;
INIT_LIST_HEAD(&ops->dev_list);
/* lock this instance */
ops->used = 1;
/* register driver entry */
mutex_lock(&ops_mutex);
list_add_tail(&ops->list, &opslist);
num_ops++;
mutex_unlock(&ops_mutex);
return ops;
}
/* /*
* unregister the specified driver * register a sequencer device
* card = card info
* device = device number (if any)
* id = id of driver
* result = return pointer (NULL allowed if unnecessary)
*/ */
int snd_seq_device_unregister_driver(char *id) int snd_seq_device_new(struct snd_card *card, int device, const char *id,
int argsize, struct snd_seq_device **result)
{ {
struct ops_list *ops;
struct snd_seq_device *dev; struct snd_seq_device *dev;
int err;
static struct snd_device_ops dops = {
.dev_free = snd_seq_device_dev_free,
.dev_register = snd_seq_device_dev_register,
.dev_disconnect = snd_seq_device_dev_disconnect,
};
ops = find_driver(id, 0); if (result)
if (ops == NULL) *result = NULL;
return -ENXIO;
if (! (ops->driver & DRIVER_LOADED) ||
(ops->driver & DRIVER_LOCKED)) {
pr_err("ALSA: seq: driver_unregister: cannot unload driver '%s': status=%x\n",
id, ops->driver);
unlock_driver(ops);
return -EBUSY;
}
/* close and release all devices associated with this driver */
mutex_lock(&ops->reg_mutex);
ops->driver |= DRIVER_LOCKED; /* do not remove this driver recursively */
list_for_each_entry(dev, &ops->dev_list, list) {
free_device(dev, ops);
}
ops->driver = 0;
if (ops->num_init_devices > 0)
pr_err("ALSA: seq: free_driver: init_devices > 0!! (%d)\n",
ops->num_init_devices);
mutex_unlock(&ops->reg_mutex);
unlock_driver(ops);
/* remove empty driver entries */ if (snd_BUG_ON(!id))
remove_drivers(); return -EINVAL;
return 0; dev = kzalloc(sizeof(*dev) + argsize, GFP_KERNEL);
} if (!dev)
return -ENOMEM;
/* set up device info */
dev->card = card;
dev->device = device;
dev->id = id;
dev->argsize = argsize;
/* device_initialize(&dev->dev);
* remove empty driver entries dev->dev.parent = &card->card_dev;
*/ dev->dev.bus = &snd_seq_bus_type;
static void remove_drivers(void) dev->dev.release = snd_seq_dev_release;
{ dev_set_name(&dev->dev, "%s-%d-%d", dev->id, card->number, device);
struct list_head *head;
mutex_lock(&ops_mutex);
head = opslist.next;
while (head != &opslist) {
struct ops_list *ops = list_entry(head, struct ops_list, list);
if (! (ops->driver & DRIVER_LOADED) &&
ops->used == 0 && ops->num_devices == 0) {
head = head->next;
list_del(&ops->list);
kfree(ops);
num_ops--;
} else
head = head->next;
}
mutex_unlock(&ops_mutex);
}
/* /* add this device to the list */
* initialize the device - call init_device operator err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops);
*/ if (err < 0) {
static int init_device(struct snd_seq_device *dev, struct ops_list *ops) put_device(&dev->dev);
{ return err;
if (! (ops->driver & DRIVER_LOADED))
return 0; /* driver is not loaded yet */
if (dev->status != SNDRV_SEQ_DEVICE_FREE)
return 0; /* already initialized */
if (ops->argsize != dev->argsize) {
pr_err("ALSA: seq: incompatible device '%s' for plug-in '%s' (%d %d)\n",
dev->name, ops->id, ops->argsize, dev->argsize);
return -EINVAL;
}
if (ops->ops.init_device(dev) >= 0) {
dev->status = SNDRV_SEQ_DEVICE_REGISTERED;
ops->num_init_devices++;
} else {
pr_err("ALSA: seq: init_device failed: %s: %s\n",
dev->name, dev->id);
} }
if (result)
*result = dev;
return 0; return 0;
} }
EXPORT_SYMBOL(snd_seq_device_new);
/* /*
* release the device - call free_device operator * driver registration
*/ */
static int free_device(struct snd_seq_device *dev, struct ops_list *ops) int __snd_seq_driver_register(struct snd_seq_driver *drv, struct module *mod)
{ {
int result; if (WARN_ON(!drv->driver.name || !drv->id))
if (! (ops->driver & DRIVER_LOADED))
return 0; /* driver is not loaded yet */
if (dev->status != SNDRV_SEQ_DEVICE_REGISTERED)
return 0; /* not registered */
if (ops->argsize != dev->argsize) {
pr_err("ALSA: seq: incompatible device '%s' for plug-in '%s' (%d %d)\n",
dev->name, ops->id, ops->argsize, dev->argsize);
return -EINVAL; return -EINVAL;
} drv->driver.bus = &snd_seq_bus_type;
if ((result = ops->ops.free_device(dev)) >= 0 || result == -ENXIO) { drv->driver.owner = mod;
dev->status = SNDRV_SEQ_DEVICE_FREE; return driver_register(&drv->driver);
dev->driver_data = NULL;
ops->num_init_devices--;
} else {
pr_err("ALSA: seq: free_device failed: %s: %s\n",
dev->name, dev->id);
}
return 0;
} }
EXPORT_SYMBOL_GPL(__snd_seq_driver_register);
/* void snd_seq_driver_unregister(struct snd_seq_driver *drv)
* find the matching driver with given id
*/
static struct ops_list * find_driver(char *id, int create_if_empty)
{ {
struct ops_list *ops; driver_unregister(&drv->driver);
mutex_lock(&ops_mutex);
list_for_each_entry(ops, &opslist, list) {
if (strcmp(ops->id, id) == 0) {
ops->used++;
mutex_unlock(&ops_mutex);
return ops;
}
}
mutex_unlock(&ops_mutex);
if (create_if_empty)
return create_driver(id);
return NULL;
} }
EXPORT_SYMBOL_GPL(snd_seq_driver_unregister);
static void unlock_driver(struct ops_list *ops)
{
mutex_lock(&ops_mutex);
ops->used--;
mutex_unlock(&ops_mutex);
}
/* /*
* module part * module part
*/ */
static int __init alsa_seq_device_init(void) static int __init seq_dev_proc_init(void)
{ {
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
info_entry = snd_info_create_module_entry(THIS_MODULE, "drivers", info_entry = snd_info_create_module_entry(THIS_MODULE, "drivers",
...@@ -589,28 +287,29 @@ static int __init alsa_seq_device_init(void) ...@@ -589,28 +287,29 @@ static int __init alsa_seq_device_init(void)
return 0; return 0;
} }
static int __init alsa_seq_device_init(void)
{
int err;
err = bus_register(&snd_seq_bus_type);
if (err < 0)
return err;
err = seq_dev_proc_init();
if (err < 0)
bus_unregister(&snd_seq_bus_type);
return err;
}
static void __exit alsa_seq_device_exit(void) static void __exit alsa_seq_device_exit(void)
{ {
#ifdef CONFIG_MODULES #ifdef CONFIG_MODULES
cancel_work_sync(&autoload_work); cancel_work_sync(&autoload_work);
#endif #endif
remove_drivers();
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
snd_info_free_entry(info_entry); snd_info_free_entry(info_entry);
#endif #endif
if (num_ops) bus_unregister(&snd_seq_bus_type);
pr_err("ALSA: seq: drivers not released (%d)\n", num_ops);
} }
module_init(alsa_seq_device_init) module_init(alsa_seq_device_init)
module_exit(alsa_seq_device_exit) module_exit(alsa_seq_device_exit)
EXPORT_SYMBOL(snd_seq_device_load_drivers);
EXPORT_SYMBOL(snd_seq_device_new);
EXPORT_SYMBOL(snd_seq_device_register_driver);
EXPORT_SYMBOL(snd_seq_device_unregister_driver);
#ifdef CONFIG_MODULES
EXPORT_SYMBOL(snd_seq_autoload_init);
EXPORT_SYMBOL(snd_seq_autoload_lock);
EXPORT_SYMBOL(snd_seq_autoload_unlock);
#endif
...@@ -214,11 +214,7 @@ delete_client(void) ...@@ -214,11 +214,7 @@ delete_client(void)
static int __init alsa_seq_dummy_init(void) static int __init alsa_seq_dummy_init(void)
{ {
int err; return register_client();
snd_seq_autoload_lock();
err = register_client();
snd_seq_autoload_unlock();
return err;
} }
static void __exit alsa_seq_dummy_exit(void) static void __exit alsa_seq_dummy_exit(void)
......
...@@ -273,8 +273,9 @@ static void snd_seq_midisynth_delete(struct seq_midisynth *msynth) ...@@ -273,8 +273,9 @@ static void snd_seq_midisynth_delete(struct seq_midisynth *msynth)
/* register new midi synth port */ /* register new midi synth port */
static int static int
snd_seq_midisynth_register_port(struct snd_seq_device *dev) snd_seq_midisynth_probe(struct device *_dev)
{ {
struct snd_seq_device *dev = to_seq_dev(_dev);
struct seq_midisynth_client *client; struct seq_midisynth_client *client;
struct seq_midisynth *msynth, *ms; struct seq_midisynth *msynth, *ms;
struct snd_seq_port_info *port; struct snd_seq_port_info *port;
...@@ -427,8 +428,9 @@ snd_seq_midisynth_register_port(struct snd_seq_device *dev) ...@@ -427,8 +428,9 @@ snd_seq_midisynth_register_port(struct snd_seq_device *dev)
/* release midi synth port */ /* release midi synth port */
static int static int
snd_seq_midisynth_unregister_port(struct snd_seq_device *dev) snd_seq_midisynth_remove(struct device *_dev)
{ {
struct snd_seq_device *dev = to_seq_dev(_dev);
struct seq_midisynth_client *client; struct seq_midisynth_client *client;
struct seq_midisynth *msynth; struct seq_midisynth *msynth;
struct snd_card *card = dev->card; struct snd_card *card = dev->card;
...@@ -457,24 +459,14 @@ snd_seq_midisynth_unregister_port(struct snd_seq_device *dev) ...@@ -457,24 +459,14 @@ snd_seq_midisynth_unregister_port(struct snd_seq_device *dev)
return 0; return 0;
} }
static struct snd_seq_driver seq_midisynth_driver = {
.driver = {
.name = KBUILD_MODNAME,
.probe = snd_seq_midisynth_probe,
.remove = snd_seq_midisynth_remove,
},
.id = SNDRV_SEQ_DEV_ID_MIDISYNTH,
.argsize = 0,
};
static int __init alsa_seq_midi_init(void) module_snd_seq_driver(seq_midisynth_driver);
{
static struct snd_seq_dev_ops ops = {
snd_seq_midisynth_register_port,
snd_seq_midisynth_unregister_port,
};
memset(&synths, 0, sizeof(synths));
snd_seq_autoload_lock();
snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_MIDISYNTH, &ops, 0);
snd_seq_autoload_unlock();
return 0;
}
static void __exit alsa_seq_midi_exit(void)
{
snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_MIDISYNTH);
}
module_init(alsa_seq_midi_init)
module_exit(alsa_seq_midi_exit)
...@@ -216,8 +216,9 @@ static int snd_opl3_synth_create_port(struct snd_opl3 * opl3) ...@@ -216,8 +216,9 @@ static int snd_opl3_synth_create_port(struct snd_opl3 * opl3)
/* ------------------------------ */ /* ------------------------------ */
static int snd_opl3_seq_new_device(struct snd_seq_device *dev) static int snd_opl3_seq_probe(struct device *_dev)
{ {
struct snd_seq_device *dev = to_seq_dev(_dev);
struct snd_opl3 *opl3; struct snd_opl3 *opl3;
int client, err; int client, err;
char name[32]; char name[32];
...@@ -257,8 +258,9 @@ static int snd_opl3_seq_new_device(struct snd_seq_device *dev) ...@@ -257,8 +258,9 @@ static int snd_opl3_seq_new_device(struct snd_seq_device *dev)
return 0; return 0;
} }
static int snd_opl3_seq_delete_device(struct snd_seq_device *dev) static int snd_opl3_seq_remove(struct device *_dev)
{ {
struct snd_seq_device *dev = to_seq_dev(_dev);
struct snd_opl3 *opl3; struct snd_opl3 *opl3;
opl3 = *(struct snd_opl3 **)SNDRV_SEQ_DEVICE_ARGPTR(dev); opl3 = *(struct snd_opl3 **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
...@@ -275,22 +277,14 @@ static int snd_opl3_seq_delete_device(struct snd_seq_device *dev) ...@@ -275,22 +277,14 @@ static int snd_opl3_seq_delete_device(struct snd_seq_device *dev)
return 0; return 0;
} }
static int __init alsa_opl3_seq_init(void) static struct snd_seq_driver opl3_seq_driver = {
{ .driver = {
static struct snd_seq_dev_ops ops = .name = KBUILD_MODNAME,
{ .probe = snd_opl3_seq_probe,
snd_opl3_seq_new_device, .remove = snd_opl3_seq_remove,
snd_opl3_seq_delete_device },
}; .id = SNDRV_SEQ_DEV_ID_OPL3,
.argsize = sizeof(struct snd_opl3 *),
return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_OPL3, &ops, };
sizeof(struct snd_opl3 *));
}
static void __exit alsa_opl3_seq_exit(void)
{
snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_OPL3);
}
module_init(alsa_opl3_seq_init) module_snd_seq_driver(opl3_seq_driver);
module_exit(alsa_opl3_seq_exit)
...@@ -124,8 +124,9 @@ static void snd_opl4_seq_free_port(void *private_data) ...@@ -124,8 +124,9 @@ static void snd_opl4_seq_free_port(void *private_data)
snd_midi_channel_free_set(opl4->chset); snd_midi_channel_free_set(opl4->chset);
} }
static int snd_opl4_seq_new_device(struct snd_seq_device *dev) static int snd_opl4_seq_probe(struct device *_dev)
{ {
struct snd_seq_device *dev = to_seq_dev(_dev);
struct snd_opl4 *opl4; struct snd_opl4 *opl4;
int client; int client;
struct snd_seq_port_callback pcallbacks; struct snd_seq_port_callback pcallbacks;
...@@ -180,8 +181,9 @@ static int snd_opl4_seq_new_device(struct snd_seq_device *dev) ...@@ -180,8 +181,9 @@ static int snd_opl4_seq_new_device(struct snd_seq_device *dev)
return 0; return 0;
} }
static int snd_opl4_seq_delete_device(struct snd_seq_device *dev) static int snd_opl4_seq_remove(struct device *_dev)
{ {
struct snd_seq_device *dev = to_seq_dev(_dev);
struct snd_opl4 *opl4; struct snd_opl4 *opl4;
opl4 = *(struct snd_opl4 **)SNDRV_SEQ_DEVICE_ARGPTR(dev); opl4 = *(struct snd_opl4 **)SNDRV_SEQ_DEVICE_ARGPTR(dev);
...@@ -195,21 +197,14 @@ static int snd_opl4_seq_delete_device(struct snd_seq_device *dev) ...@@ -195,21 +197,14 @@ static int snd_opl4_seq_delete_device(struct snd_seq_device *dev)
return 0; return 0;
} }
static int __init alsa_opl4_synth_init(void) static struct snd_seq_driver opl4_seq_driver = {
{ .driver = {
static struct snd_seq_dev_ops ops = { .name = KBUILD_MODNAME,
snd_opl4_seq_new_device, .probe = snd_opl4_seq_probe,
snd_opl4_seq_delete_device .remove = snd_opl4_seq_remove,
}; },
.id = SNDRV_SEQ_DEV_ID_OPL4,
return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_OPL4, &ops, .argsize = sizeof(struct snd_opl4 *),
sizeof(struct snd_opl4 *)); };
}
static void __exit alsa_opl4_synth_exit(void)
{
snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_OPL4);
}
module_init(alsa_opl4_synth_init) module_snd_seq_driver(opl4_seq_driver);
module_exit(alsa_opl4_synth_exit)
...@@ -34,8 +34,9 @@ MODULE_LICENSE("GPL"); ...@@ -34,8 +34,9 @@ MODULE_LICENSE("GPL");
/* /*
* create a new hardware dependent device for Emu8000 * create a new hardware dependent device for Emu8000
*/ */
static int snd_emu8000_new_device(struct snd_seq_device *dev) static int snd_emu8000_probe(struct device *_dev)
{ {
struct snd_seq_device *dev = to_seq_dev(_dev);
struct snd_emu8000 *hw; struct snd_emu8000 *hw;
struct snd_emux *emu; struct snd_emux *emu;
...@@ -93,8 +94,9 @@ static int snd_emu8000_new_device(struct snd_seq_device *dev) ...@@ -93,8 +94,9 @@ static int snd_emu8000_new_device(struct snd_seq_device *dev)
/* /*
* free all resources * free all resources
*/ */
static int snd_emu8000_delete_device(struct snd_seq_device *dev) static int snd_emu8000_remove(struct device *_dev)
{ {
struct snd_seq_device *dev = to_seq_dev(_dev);
struct snd_emu8000 *hw; struct snd_emu8000 *hw;
if (dev->driver_data == NULL) if (dev->driver_data == NULL)
...@@ -114,21 +116,14 @@ static int snd_emu8000_delete_device(struct snd_seq_device *dev) ...@@ -114,21 +116,14 @@ static int snd_emu8000_delete_device(struct snd_seq_device *dev)
* INIT part * INIT part
*/ */
static int __init alsa_emu8000_init(void) static struct snd_seq_driver emu8000_driver = {
{ .driver = {
.name = KBUILD_MODNAME,
static struct snd_seq_dev_ops ops = { .probe = snd_emu8000_probe,
snd_emu8000_new_device, .remove = snd_emu8000_remove,
snd_emu8000_delete_device, },
}; .id = SNDRV_SEQ_DEV_ID_EMU8000,
return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_EMU8000, &ops, .argsize = sizeof(struct snd_emu8000 *),
sizeof(struct snd_emu8000*)); };
}
module_snd_seq_driver(emu8000_driver);
static void __exit alsa_emu8000_exit(void)
{
snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_EMU8000);
}
module_init(alsa_emu8000_init)
module_exit(alsa_emu8000_exit)
...@@ -29,8 +29,9 @@ MODULE_LICENSE("GPL"); ...@@ -29,8 +29,9 @@ MODULE_LICENSE("GPL");
/* /*
* create a new hardware dependent device for Emu10k1 * create a new hardware dependent device for Emu10k1
*/ */
static int snd_emu10k1_synth_new_device(struct snd_seq_device *dev) static int snd_emu10k1_synth_probe(struct device *_dev)
{ {
struct snd_seq_device *dev = to_seq_dev(_dev);
struct snd_emux *emux; struct snd_emux *emux;
struct snd_emu10k1 *hw; struct snd_emu10k1 *hw;
struct snd_emu10k1_synth_arg *arg; struct snd_emu10k1_synth_arg *arg;
...@@ -79,8 +80,9 @@ static int snd_emu10k1_synth_new_device(struct snd_seq_device *dev) ...@@ -79,8 +80,9 @@ static int snd_emu10k1_synth_new_device(struct snd_seq_device *dev)
return 0; return 0;
} }
static int snd_emu10k1_synth_delete_device(struct snd_seq_device *dev) static int snd_emu10k1_synth_remove(struct device *_dev)
{ {
struct snd_seq_device *dev = to_seq_dev(_dev);
struct snd_emux *emux; struct snd_emux *emux;
struct snd_emu10k1 *hw; struct snd_emu10k1 *hw;
unsigned long flags; unsigned long flags;
...@@ -104,21 +106,14 @@ static int snd_emu10k1_synth_delete_device(struct snd_seq_device *dev) ...@@ -104,21 +106,14 @@ static int snd_emu10k1_synth_delete_device(struct snd_seq_device *dev)
* INIT part * INIT part
*/ */
static int __init alsa_emu10k1_synth_init(void) static struct snd_seq_driver emu10k1_synth_driver = {
{ .driver = {
.name = KBUILD_MODNAME,
static struct snd_seq_dev_ops ops = { .probe = snd_emu10k1_synth_probe,
snd_emu10k1_synth_new_device, .remove = snd_emu10k1_synth_remove,
snd_emu10k1_synth_delete_device, },
}; .id = SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH,
return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH, &ops, .argsize = sizeof(struct snd_emu10k1_synth_arg),
sizeof(struct snd_emu10k1_synth_arg)); };
}
module_snd_seq_driver(emu10k1_synth_driver);
static void __exit alsa_emu10k1_synth_exit(void)
{
snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH);
}
module_init(alsa_emu10k1_synth_init)
module_exit(alsa_emu10k1_synth_exit)
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