[ALSA] dynamic minors (3/6): store device-specific object pointers dynamically
Instead of storing the pointers to the device-specific structures in an
array, put them into the struct snd_minor, and look them up dynamically.
This makes the device type modules independent of the minor number
encoding.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 2bc5f69..95036c8 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -33,7 +33,7 @@
MODULE_DESCRIPTION("Midlevel PCM code for ALSA.");
MODULE_LICENSE("GPL");
-struct snd_pcm *snd_pcm_devices[SNDRV_CARDS * SNDRV_PCM_DEVICES];
+static LIST_HEAD(snd_pcm_devices);
static LIST_HEAD(snd_pcm_notify_list);
static DECLARE_MUTEX(register_mutex);
@@ -43,13 +43,23 @@
static int snd_pcm_dev_disconnect(struct snd_device *device);
static int snd_pcm_dev_unregister(struct snd_device *device);
+static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device)
+{
+ struct list_head *p;
+ struct snd_pcm *pcm;
+
+ list_for_each(p, &snd_pcm_devices) {
+ pcm = list_entry(p, struct snd_pcm, list);
+ if (pcm->card == card && pcm->device == device)
+ return pcm;
+ }
+ return NULL;
+}
+
static int snd_pcm_control_ioctl(struct snd_card *card,
struct snd_ctl_file *control,
unsigned int cmd, unsigned long arg)
{
- unsigned int tmp;
-
- tmp = card->number * SNDRV_PCM_DEVICES;
switch (cmd) {
case SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE:
{
@@ -57,14 +67,16 @@
if (get_user(device, (int __user *)arg))
return -EFAULT;
+ down(®ister_mutex);
device = device < 0 ? 0 : device + 1;
while (device < SNDRV_PCM_DEVICES) {
- if (snd_pcm_devices[tmp + device])
+ if (snd_pcm_search(card, device))
break;
device++;
}
if (device == SNDRV_PCM_DEVICES)
device = -1;
+ up(®ister_mutex);
if (put_user(device, (int __user *)arg))
return -EFAULT;
return 0;
@@ -77,31 +89,44 @@
struct snd_pcm *pcm;
struct snd_pcm_str *pstr;
struct snd_pcm_substream *substream;
+ int err;
+
info = (struct snd_pcm_info __user *)arg;
if (get_user(device, &info->device))
return -EFAULT;
- if (device >= SNDRV_PCM_DEVICES)
- return -ENXIO;
- pcm = snd_pcm_devices[tmp + device];
- if (pcm == NULL)
- return -ENXIO;
if (get_user(stream, &info->stream))
return -EFAULT;
if (stream < 0 || stream > 1)
return -EINVAL;
- pstr = &pcm->streams[stream];
- if (pstr->substream_count == 0)
- return -ENOENT;
if (get_user(subdevice, &info->subdevice))
return -EFAULT;
- if (subdevice >= pstr->substream_count)
- return -ENXIO;
- for (substream = pstr->substream; substream; substream = substream->next)
+ down(®ister_mutex);
+ pcm = snd_pcm_search(card, device);
+ if (pcm == NULL) {
+ err = -ENXIO;
+ goto _error;
+ }
+ pstr = &pcm->streams[stream];
+ if (pstr->substream_count == 0) {
+ err = -ENOENT;
+ goto _error;
+ }
+ if (subdevice >= pstr->substream_count) {
+ err = -ENXIO;
+ goto _error;
+ }
+ for (substream = pstr->substream; substream;
+ substream = substream->next)
if (substream->number == (int)subdevice)
break;
- if (substream == NULL)
- return -ENXIO;
- return snd_pcm_info_user(substream, info);
+ if (substream == NULL) {
+ err = -ENXIO;
+ goto _error;
+ }
+ err = snd_pcm_info_user(substream, info);
+ _error:
+ up(®ister_mutex);
+ return err;
}
case SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE:
{
@@ -865,8 +890,7 @@
static int snd_pcm_dev_register(struct snd_device *device)
{
- int idx, cidx, err;
- unsigned short minor;
+ int cidx, err;
struct snd_pcm_substream *substream;
struct list_head *list;
char str[16];
@@ -874,12 +898,11 @@
snd_assert(pcm != NULL && device != NULL, return -ENXIO);
down(®ister_mutex);
- idx = (pcm->card->number * SNDRV_PCM_DEVICES) + pcm->device;
- if (snd_pcm_devices[idx]) {
+ if (snd_pcm_search(pcm->card, pcm->device)) {
up(®ister_mutex);
return -EBUSY;
}
- snd_pcm_devices[idx] = pcm;
+ list_add_tail(&pcm->list, &snd_pcm_devices);
for (cidx = 0; cidx < 2; cidx++) {
int devtype = -1;
if (pcm->streams[cidx].substream == NULL)
@@ -887,20 +910,19 @@
switch (cidx) {
case SNDRV_PCM_STREAM_PLAYBACK:
sprintf(str, "pcmC%iD%ip", pcm->card->number, pcm->device);
- minor = SNDRV_MINOR_PCM_PLAYBACK + idx;
devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;
break;
case SNDRV_PCM_STREAM_CAPTURE:
sprintf(str, "pcmC%iD%ic", pcm->card->number, pcm->device);
- minor = SNDRV_MINOR_PCM_CAPTURE + idx;
devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;
break;
}
if ((err = snd_register_device(devtype, pcm->card,
pcm->device,
- &snd_pcm_f_ops[cidx], str)) < 0)
+ &snd_pcm_f_ops[cidx],
+ pcm, str)) < 0)
{
- snd_pcm_devices[idx] = NULL;
+ list_del(&pcm->list);
up(®ister_mutex);
return err;
}
@@ -921,11 +943,10 @@
struct snd_pcm *pcm = device->device_data;
struct list_head *list;
struct snd_pcm_substream *substream;
- int idx, cidx;
+ int cidx;
down(®ister_mutex);
- idx = (pcm->card->number * SNDRV_PCM_DEVICES) + pcm->device;
- snd_pcm_devices[idx] = NULL;
+ list_del_init(&pcm->list);
for (cidx = 0; cidx < 2; cidx++)
for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
if (substream->runtime)
@@ -941,15 +962,14 @@
static int snd_pcm_dev_unregister(struct snd_device *device)
{
- int idx, cidx, devtype;
+ int cidx, devtype;
struct snd_pcm_substream *substream;
struct list_head *list;
struct snd_pcm *pcm = device->device_data;
snd_assert(pcm != NULL, return -ENXIO);
down(®ister_mutex);
- idx = (pcm->card->number * SNDRV_PCM_DEVICES) + pcm->device;
- snd_pcm_devices[idx] = NULL;
+ list_del(&pcm->list);
for (cidx = 0; cidx < 2; cidx++) {
devtype = -1;
switch (cidx) {
@@ -975,24 +995,19 @@
int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
{
- int idx;
+ struct list_head *p;
snd_assert(notify != NULL && notify->n_register != NULL && notify->n_unregister != NULL, return -EINVAL);
down(®ister_mutex);
if (nfree) {
list_del(¬ify->list);
- for (idx = 0; idx < SNDRV_CARDS * SNDRV_PCM_DEVICES; idx++) {
- if (snd_pcm_devices[idx] == NULL)
- continue;
- notify->n_unregister(snd_pcm_devices[idx]);
- }
+ list_for_each(p, &snd_pcm_devices)
+ notify->n_unregister(list_entry(p,
+ struct snd_pcm, list));
} else {
list_add_tail(¬ify->list, &snd_pcm_notify_list);
- for (idx = 0; idx < SNDRV_CARDS * SNDRV_PCM_DEVICES; idx++) {
- if (snd_pcm_devices[idx] == NULL)
- continue;
- notify->n_register(snd_pcm_devices[idx]);
- }
+ list_for_each(p, &snd_pcm_devices)
+ notify->n_register(list_entry(p, struct snd_pcm, list));
}
up(®ister_mutex);
return 0;
@@ -1005,16 +1020,14 @@
static void snd_pcm_proc_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
- int idx;
+ struct list_head *p;
struct snd_pcm *pcm;
down(®ister_mutex);
- for (idx = 0; idx < SNDRV_CARDS * SNDRV_PCM_DEVICES; idx++) {
- pcm = snd_pcm_devices[idx];
- if (pcm == NULL)
- continue;
- snd_iprintf(buffer, "%02i-%02i: %s : %s", idx / SNDRV_PCM_DEVICES,
- idx % SNDRV_PCM_DEVICES, pcm->id, pcm->name);
+ list_for_each(p, &snd_pcm_devices) {
+ pcm = list_entry(p, struct snd_pcm, list);
+ snd_iprintf(buffer, "%02i-%02i: %s : %s",
+ pcm->card->number, pcm->device, pcm->id, pcm->name);
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)
snd_iprintf(buffer, " : playback %i",
pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count);
@@ -1063,7 +1076,6 @@
module_init(alsa_pcm_init)
module_exit(alsa_pcm_exit)
-EXPORT_SYMBOL(snd_pcm_devices);
EXPORT_SYMBOL(snd_pcm_new);
EXPORT_SYMBOL(snd_pcm_new_stream);
EXPORT_SYMBOL(snd_pcm_notify);