At Tue, 29 Jul 2008 17:34:26 +0100, Pawel MOLL wrote:
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.
Well, the comparison isn't so problematic usually. The unneeded casts are found in many places simply to shut crap warnings by old buggy gcc. But, it's fine to make it int again.
There is just one more place where device number is unsigned - in struct snd_pcm_info, which should be also sorted out in future.
Could you split this as a separate patch? This unsigned int -> int change is irrelevant with the fix for 8 PCM devices limit.
Other review comments below.
Signed-off-by: Pawel MOLL pawel.moll@st.com
diff --git a/include/sound/minors.h b/include/sound/minors.h index 46bcd20..a81798a 100644 --- a/include/sound/minors.h +++ b/include/sound/minors.h @@ -21,6 +21,8 @@
*/
+#define SNDRV_OS_MINORS 256
#define SNDRV_MINOR_DEVICES 32 #define SNDRV_MINOR_CARD(minor) ((minor) >> 5) #define SNDRV_MINOR_DEVICE(minor) ((minor) & 0x001f) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 51d58cc..bfc096a 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -84,8 +84,6 @@ struct snd_pcm_ops {
*/
-#define SNDRV_PCM_DEVICES 8
#define SNDRV_PCM_IOCTL1_FALSE ((void *)0) #define SNDRV_PCM_IOCTL1_TRUE ((void *)1)
@@ -416,7 +414,7 @@ struct snd_pcm_str { struct snd_pcm { struct snd_card *card; struct list_head list;
- unsigned int device; /* device number */
- int device; /* device number */ unsigned int info_flags; unsigned short dev_class; unsigned short dev_subclass;
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 4c601b1..4ccd761 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -2947,7 +2947,7 @@ static void register_oss_dsp(struct snd_pcm *pcm, int index) static int snd_pcm_oss_register_minor(struct snd_pcm *pcm) { pcm->oss.reg = 0;
- if (dsp_map[pcm->card->number] == (int)pcm->device) {
- if (dsp_map[pcm->card->number] == pcm->device) { char name[128]; int duplex; register_oss_dsp(pcm, 0);
@@ -2963,7 +2963,7 @@ static int snd_pcm_oss_register_minor(struct snd_pcm *pcm) pcm->oss.reg++; pcm->oss.reg_mask |= 1; }
- if (adsp_map[pcm->card->number] == (int)pcm->device) {
- if (adsp_map[pcm->card->number] == pcm->device) { register_oss_dsp(pcm, 1); pcm->oss.reg++; pcm->oss.reg_mask |= 2;
@@ -2988,7 +2988,7 @@ static int snd_pcm_oss_disconnect_minor(struct snd_pcm *pcm) snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM, pcm->card, 1); }
if (dsp_map[pcm->card->number] == (int)pcm->device) {
if (dsp_map[pcm->card->number] == pcm->device) {
#ifdef SNDRV_OSS_INFO_DEV_AUDIO snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_AUDIO, pcm->card->number); #endif @@ -3019,12 +3019,12 @@ static int __init alsa_pcm_oss_init(void)
/* check device map table */ for (i = 0; i < SNDRV_CARDS; i++) {
if (dsp_map[i] < 0 || dsp_map[i] >= SNDRV_PCM_DEVICES) {
if (dsp_map[i] < 0 || dsp_map[i] >= SNDRV_OS_MINORS) {
You cannot use SNDRV_OS_MINORS unconditionally here. In the case DYNAMIC_MINORS=n, SNDRV_PCM_DEVICES is still valid. Maybe better to define SNDRV_PCM_DEVICES with ifdef, such as,
#ifdef CONFIG_SND_DYNAMIC_MINORS #define SNDRV_PCM_DEVICES (SNDRV_OS_MINORS-2) #else #define SNDRV_PCM_DEVICES 8 #endif
snd_printk(KERN_ERR "invalid dsp_map[%d] = %d\n", i, dsp_map[i]); dsp_map[i] = 0; }
if (adsp_map[i] < 0 || adsp_map[i] >= SNDRV_PCM_DEVICES) {
if (adsp_map[i] < 0 || adsp_map[i] >= SNDRV_OS_MINORS) {
Ditto.
snd_printk(KERN_ERR "invalid adsp_map[%d] = %d\n", i, adsp_map[i]); adsp_map[i] = 1;
diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 9dd9bc7..df4c8a3 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -42,7 +42,7 @@ static int snd_pcm_dev_free(struct snd_device *device); static int snd_pcm_dev_register(struct snd_device *device); static int snd_pcm_dev_disconnect(struct snd_device *device);
-static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device) +static inline struct snd_pcm *snd_pcm_get(struct snd_card *card, int device)
Don't use inline. It's good for a single-line or a pretty small function, but not for else. The compiler is clever enough to inline the functions automatically if needed.
Also, any reason to rename to *_get()? get() is usually paired with put().
{ struct snd_pcm *pcm;
@@ -53,6 +53,37 @@ static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device) return NULL; }
+static inline int snd_pcm_next(struct snd_card *card, int device)
No inline please.
+{
- struct snd_pcm *pcm;
- list_for_each_entry(pcm, &snd_pcm_devices, list) {
if (pcm->card == card && pcm->device > device)
return pcm->device;
else if (pcm->card->number > card->number)
return -1;
- }
- return -1;
+}
+static inline int snd_pcm_add(struct snd_pcm *newpcm)
Ditto.
Otherwise it looks like a really nice fix.
Thanks!
Takashi