Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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. The same limit was present in OSS emulation code. It has
been fixed as well.

Additionally the device field of struct snd_pcm is now int, instead of
unsigned int, as there is no obvious reason for keeping it unsigned.
This caused a lot of problems with comparing this value with other
(almost always signed) variables. There is just one more place where
device number is unsigned - in struct snd_pcm_info, which should be
also sorted out in future.

Signed-off-by: Pawel MOLL <pawel.moll@st.com>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>

authored by

Pawel MOLL and committed by
Jaroslav Kysela
94239690 815ecf8d

+45 -23
+2
include/sound/minors.h
··· 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)
+1 -3
include/sound/pcm.h
··· 84 84 * 85 85 */ 86 86 87 - #define SNDRV_PCM_DEVICES 8 88 - 89 87 #define SNDRV_PCM_IOCTL1_FALSE ((void *)0) 90 88 #define SNDRV_PCM_IOCTL1_TRUE ((void *)1) 91 89 ··· 414 416 struct snd_pcm { 415 417 struct snd_card *card; 416 418 struct list_head list; 417 - unsigned int device; /* device number */ 419 + int device; /* device number */ 418 420 unsigned int info_flags; 419 421 unsigned short dev_class; 420 422 unsigned short dev_subclass;
+5 -5
sound/core/oss/pcm_oss.c
··· 2947 2947 static int snd_pcm_oss_register_minor(struct snd_pcm *pcm) 2948 2948 { 2949 2949 pcm->oss.reg = 0; 2950 - if (dsp_map[pcm->card->number] == (int)pcm->device) { 2950 + if (dsp_map[pcm->card->number] == pcm->device) { 2951 2951 char name[128]; 2952 2952 int duplex; 2953 2953 register_oss_dsp(pcm, 0); ··· 2963 2963 pcm->oss.reg++; 2964 2964 pcm->oss.reg_mask |= 1; 2965 2965 } 2966 - if (adsp_map[pcm->card->number] == (int)pcm->device) { 2966 + if (adsp_map[pcm->card->number] == pcm->device) { 2967 2967 register_oss_dsp(pcm, 1); 2968 2968 pcm->oss.reg++; 2969 2969 pcm->oss.reg_mask |= 2; ··· 2988 2988 snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM, 2989 2989 pcm->card, 1); 2990 2990 } 2991 - if (dsp_map[pcm->card->number] == (int)pcm->device) { 2991 + if (dsp_map[pcm->card->number] == pcm->device) { 2992 2992 #ifdef SNDRV_OSS_INFO_DEV_AUDIO 2993 2993 snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_AUDIO, pcm->card->number); 2994 2994 #endif ··· 3019 3019 3020 3020 /* check device map table */ 3021 3021 for (i = 0; i < SNDRV_CARDS; i++) { 3022 - if (dsp_map[i] < 0 || dsp_map[i] >= SNDRV_PCM_DEVICES) { 3022 + if (dsp_map[i] < 0 || dsp_map[i] >= SNDRV_OS_MINORS) { 3023 3023 snd_printk(KERN_ERR "invalid dsp_map[%d] = %d\n", 3024 3024 i, dsp_map[i]); 3025 3025 dsp_map[i] = 0; 3026 3026 } 3027 - if (adsp_map[i] < 0 || adsp_map[i] >= SNDRV_PCM_DEVICES) { 3027 + if (adsp_map[i] < 0 || adsp_map[i] >= SNDRV_OS_MINORS) { 3028 3028 snd_printk(KERN_ERR "invalid adsp_map[%d] = %d\n", 3029 3029 i, adsp_map[i]); 3030 3030 adsp_map[i] = 1;
+37 -13
sound/core/pcm.c
··· 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 inline struct snd_pcm *snd_pcm_get(struct snd_card *card, int device) 46 46 { 47 47 struct snd_pcm *pcm; 48 48 ··· 51 51 return pcm; 52 52 } 53 53 return NULL; 54 + } 55 + 56 + static inline 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 inline 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; 54 85 } 55 86 56 87 static int snd_pcm_control_ioctl(struct snd_card *card, ··· 96 65 if (get_user(device, (int __user *)arg)) 97 66 return -EFAULT; 98 67 mutex_lock(&register_mutex); 99 - device = device < 0 ? 0 : device + 1; 100 - while (device < SNDRV_PCM_DEVICES) { 101 - if (snd_pcm_search(card, device)) 102 - break; 103 - device++; 104 - } 105 - if (device == SNDRV_PCM_DEVICES) 106 - device = -1; 68 + device = snd_pcm_next(card, device); 107 69 mutex_unlock(&register_mutex); 108 70 if (put_user(device, (int __user *)arg)) 109 71 return -EFAULT; ··· 122 98 if (get_user(subdevice, &info->subdevice)) 123 99 return -EFAULT; 124 100 mutex_lock(&register_mutex); 125 - pcm = snd_pcm_search(card, device); 101 + pcm = snd_pcm_get(card, device); 126 102 if (pcm == NULL) { 127 103 err = -ENXIO; 128 104 goto _error; ··· 955 931 956 932 snd_assert(pcm != NULL && device != NULL, return -ENXIO); 957 933 mutex_lock(&register_mutex); 958 - if (snd_pcm_search(pcm->card, pcm->device)) { 934 + err = snd_pcm_add(pcm); 935 + if (err) { 959 936 mutex_unlock(&register_mutex); 960 - return -EBUSY; 937 + return err; 961 938 } 962 - list_add_tail(&pcm->list, &snd_pcm_devices); 963 939 for (cidx = 0; cidx < 2; cidx++) { 964 940 int devtype = -1; 965 941 if (pcm->streams[cidx].substream == NULL)
-2
sound/core/sound.c
··· 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);