Commit f90c06a2b613eea24a77d56f24b084745c43713d

Authored by Pawel MOLL
Committed by Jaroslav Kysela
1 parent 030a07e441

ALSA: Fix limit of 8 PCM devices in SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE

When compiled with CONFIG_SND_DYNAMIC_MINORS the ALSA core is fine
to have more than 8 PCM devices per card, except one place - the
SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE ioctl, which will not enumerate
devices > 7. This patch fixes the issue, changing the devices list
organisation.

Instead of adding new device to the tail, the list is now kept always
ordered (by card number, then device number). Thus, during enumeration,
it is easy to discover the fact that there is no more given card's
devices.

Additionally the device field of struct snd_pcm had to be changed to int,
as its "unsignednity" caused a lot of problems when comparing it to
potentially negative signed values. (-1 is 0xffffffff or even more then ;-)

Signed-off-by: Pawel Moll <pawel.moll@st.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>

Showing 4 changed files with 46 additions and 17 deletions Side-by-side Diff

include/sound/minors.h
... ... @@ -21,6 +21,8 @@
21 21 *
22 22 */
23 23  
  24 +#define SNDRV_OS_MINORS 256
  25 +
24 26 #define SNDRV_MINOR_DEVICES 32
25 27 #define SNDRV_MINOR_CARD(minor) ((minor) >> 5)
26 28 #define SNDRV_MINOR_DEVICE(minor) ((minor) & 0x001f)
... ... @@ -25,6 +25,7 @@
25 25  
26 26 #include <sound/asound.h>
27 27 #include <sound/memalloc.h>
  28 +#include <sound/minors.h>
28 29 #include <linux/poll.h>
29 30 #include <linux/mm.h>
30 31 #include <linux/bitops.h>
... ... @@ -84,7 +85,11 @@
84 85 *
85 86 */
86 87  
87   -#define SNDRV_PCM_DEVICES 8
  88 +#if defined(CONFIG_SND_DYNAMIC_MINORS)
  89 +#define SNDRV_PCM_DEVICES (SNDRV_OS_MINORS-2)
  90 +#else
  91 +#define SNDRV_PCM_DEVICES 8
  92 +#endif
88 93  
89 94 #define SNDRV_PCM_IOCTL1_FALSE ((void *)0)
90 95 #define SNDRV_PCM_IOCTL1_TRUE ((void *)1)
... ... @@ -416,7 +421,7 @@
416 421 struct snd_pcm {
417 422 struct snd_card *card;
418 423 struct list_head list;
419   - unsigned int device; /* device number */
  424 + int device; /* device number */
420 425 unsigned int info_flags;
421 426 unsigned short dev_class;
422 427 unsigned short dev_subclass;
... ... @@ -42,7 +42,7 @@
42 42 static int snd_pcm_dev_register(struct snd_device *device);
43 43 static int snd_pcm_dev_disconnect(struct snd_device *device);
44 44  
45   -static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device)
  45 +static struct snd_pcm *snd_pcm_get(struct snd_card *card, int device)
46 46 {
47 47 struct snd_pcm *pcm;
48 48  
... ... @@ -53,6 +53,37 @@
53 53 return NULL;
54 54 }
55 55  
  56 +static int snd_pcm_next(struct snd_card *card, int device)
  57 +{
  58 + struct snd_pcm *pcm;
  59 +
  60 + list_for_each_entry(pcm, &snd_pcm_devices, list) {
  61 + if (pcm->card == card && pcm->device > device)
  62 + return pcm->device;
  63 + else if (pcm->card->number > card->number)
  64 + return -1;
  65 + }
  66 + return -1;
  67 +}
  68 +
  69 +static int snd_pcm_add(struct snd_pcm *newpcm)
  70 +{
  71 + struct snd_pcm *pcm;
  72 +
  73 + list_for_each_entry(pcm, &snd_pcm_devices, list) {
  74 + if (pcm->card == newpcm->card && pcm->device == newpcm->device)
  75 + return -EBUSY;
  76 + if (pcm->card->number > newpcm->card->number ||
  77 + (pcm->card == newpcm->card &&
  78 + pcm->device > newpcm->device)) {
  79 + list_add(&newpcm->list, pcm->list.prev);
  80 + return 0;
  81 + }
  82 + }
  83 + list_add_tail(&newpcm->list, &snd_pcm_devices);
  84 + return 0;
  85 +}
  86 +
56 87 static int snd_pcm_control_ioctl(struct snd_card *card,
57 88 struct snd_ctl_file *control,
58 89 unsigned int cmd, unsigned long arg)
... ... @@ -65,14 +96,7 @@
65 96 if (get_user(device, (int __user *)arg))
66 97 return -EFAULT;
67 98 mutex_lock(&register_mutex);
68   - device = device < 0 ? 0 : device + 1;
69   - while (device < SNDRV_PCM_DEVICES) {
70   - if (snd_pcm_search(card, device))
71   - break;
72   - device++;
73   - }
74   - if (device == SNDRV_PCM_DEVICES)
75   - device = -1;
  99 + device = snd_pcm_next(card, device);
76 100 mutex_unlock(&register_mutex);
77 101 if (put_user(device, (int __user *)arg))
78 102 return -EFAULT;
... ... @@ -98,7 +122,7 @@
98 122 if (get_user(subdevice, &info->subdevice))
99 123 return -EFAULT;
100 124 mutex_lock(&register_mutex);
101   - pcm = snd_pcm_search(card, device);
  125 + pcm = snd_pcm_get(card, device);
102 126 if (pcm == NULL) {
103 127 err = -ENXIO;
104 128 goto _error;
105 129  
106 130  
... ... @@ -931,11 +955,11 @@
931 955  
932 956 snd_assert(pcm != NULL && device != NULL, return -ENXIO);
933 957 mutex_lock(&register_mutex);
934   - if (snd_pcm_search(pcm->card, pcm->device)) {
  958 + err = snd_pcm_add(pcm);
  959 + if (err) {
935 960 mutex_unlock(&register_mutex);
936   - return -EBUSY;
  961 + return err;
937 962 }
938   - list_add_tail(&pcm->list, &snd_pcm_devices);
939 963 for (cidx = 0; cidx < 2; cidx++) {
940 964 int devtype = -1;
941 965 if (pcm->streams[cidx].substream == NULL)
... ... @@ -34,8 +34,6 @@
34 34 #include <linux/kmod.h>
35 35 #include <linux/mutex.h>
36 36  
37   -#define SNDRV_OS_MINORS 256
38   -
39 37 static int major = CONFIG_SND_MAJOR;
40 38 int snd_major;
41 39 EXPORT_SYMBOL(snd_major);