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>
This commit is contained in:
parent
030a07e441
commit
f90c06a2b6
4 changed files with 46 additions and 17 deletions
|
@ -21,6 +21,8 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define SNDRV_OS_MINORS 256
|
||||||
|
|
||||||
#define SNDRV_MINOR_DEVICES 32
|
#define SNDRV_MINOR_DEVICES 32
|
||||||
#define SNDRV_MINOR_CARD(minor) ((minor) >> 5)
|
#define SNDRV_MINOR_CARD(minor) ((minor) >> 5)
|
||||||
#define SNDRV_MINOR_DEVICE(minor) ((minor) & 0x001f)
|
#define SNDRV_MINOR_DEVICE(minor) ((minor) & 0x001f)
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
#include <sound/asound.h>
|
#include <sound/asound.h>
|
||||||
#include <sound/memalloc.h>
|
#include <sound/memalloc.h>
|
||||||
|
#include <sound/minors.h>
|
||||||
#include <linux/poll.h>
|
#include <linux/poll.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
|
@ -84,7 +85,11 @@ struct snd_pcm_ops {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define SNDRV_PCM_DEVICES 8
|
#if defined(CONFIG_SND_DYNAMIC_MINORS)
|
||||||
|
#define SNDRV_PCM_DEVICES (SNDRV_OS_MINORS-2)
|
||||||
|
#else
|
||||||
|
#define SNDRV_PCM_DEVICES 8
|
||||||
|
#endif
|
||||||
|
|
||||||
#define SNDRV_PCM_IOCTL1_FALSE ((void *)0)
|
#define SNDRV_PCM_IOCTL1_FALSE ((void *)0)
|
||||||
#define SNDRV_PCM_IOCTL1_TRUE ((void *)1)
|
#define SNDRV_PCM_IOCTL1_TRUE ((void *)1)
|
||||||
|
@ -416,7 +421,7 @@ struct snd_pcm_str {
|
||||||
struct snd_pcm {
|
struct snd_pcm {
|
||||||
struct snd_card *card;
|
struct snd_card *card;
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
unsigned int device; /* device number */
|
int device; /* device number */
|
||||||
unsigned int info_flags;
|
unsigned int info_flags;
|
||||||
unsigned short dev_class;
|
unsigned short dev_class;
|
||||||
unsigned short dev_subclass;
|
unsigned short dev_subclass;
|
||||||
|
|
|
@ -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_register(struct snd_device *device);
|
||||||
static int snd_pcm_dev_disconnect(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 struct snd_pcm *snd_pcm_get(struct snd_card *card, int device)
|
||||||
{
|
{
|
||||||
struct snd_pcm *pcm;
|
struct snd_pcm *pcm;
|
||||||
|
|
||||||
|
@ -53,6 +53,37 @@ static struct snd_pcm *snd_pcm_search(struct snd_card *card, int device)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int snd_pcm_next(struct snd_card *card, int device)
|
||||||
|
{
|
||||||
|
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 int snd_pcm_add(struct snd_pcm *newpcm)
|
||||||
|
{
|
||||||
|
struct snd_pcm *pcm;
|
||||||
|
|
||||||
|
list_for_each_entry(pcm, &snd_pcm_devices, list) {
|
||||||
|
if (pcm->card == newpcm->card && pcm->device == newpcm->device)
|
||||||
|
return -EBUSY;
|
||||||
|
if (pcm->card->number > newpcm->card->number ||
|
||||||
|
(pcm->card == newpcm->card &&
|
||||||
|
pcm->device > newpcm->device)) {
|
||||||
|
list_add(&newpcm->list, pcm->list.prev);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list_add_tail(&newpcm->list, &snd_pcm_devices);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int snd_pcm_control_ioctl(struct snd_card *card,
|
static int snd_pcm_control_ioctl(struct snd_card *card,
|
||||||
struct snd_ctl_file *control,
|
struct snd_ctl_file *control,
|
||||||
unsigned int cmd, unsigned long arg)
|
unsigned int cmd, unsigned long arg)
|
||||||
|
@ -65,14 +96,7 @@ static int snd_pcm_control_ioctl(struct snd_card *card,
|
||||||
if (get_user(device, (int __user *)arg))
|
if (get_user(device, (int __user *)arg))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
mutex_lock(®ister_mutex);
|
mutex_lock(®ister_mutex);
|
||||||
device = device < 0 ? 0 : device + 1;
|
device = snd_pcm_next(card, device);
|
||||||
while (device < SNDRV_PCM_DEVICES) {
|
|
||||||
if (snd_pcm_search(card, device))
|
|
||||||
break;
|
|
||||||
device++;
|
|
||||||
}
|
|
||||||
if (device == SNDRV_PCM_DEVICES)
|
|
||||||
device = -1;
|
|
||||||
mutex_unlock(®ister_mutex);
|
mutex_unlock(®ister_mutex);
|
||||||
if (put_user(device, (int __user *)arg))
|
if (put_user(device, (int __user *)arg))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
@ -98,7 +122,7 @@ static int snd_pcm_control_ioctl(struct snd_card *card,
|
||||||
if (get_user(subdevice, &info->subdevice))
|
if (get_user(subdevice, &info->subdevice))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
mutex_lock(®ister_mutex);
|
mutex_lock(®ister_mutex);
|
||||||
pcm = snd_pcm_search(card, device);
|
pcm = snd_pcm_get(card, device);
|
||||||
if (pcm == NULL) {
|
if (pcm == NULL) {
|
||||||
err = -ENXIO;
|
err = -ENXIO;
|
||||||
goto _error;
|
goto _error;
|
||||||
|
@ -931,11 +955,11 @@ static int snd_pcm_dev_register(struct snd_device *device)
|
||||||
|
|
||||||
snd_assert(pcm != NULL && device != NULL, return -ENXIO);
|
snd_assert(pcm != NULL && device != NULL, return -ENXIO);
|
||||||
mutex_lock(®ister_mutex);
|
mutex_lock(®ister_mutex);
|
||||||
if (snd_pcm_search(pcm->card, pcm->device)) {
|
err = snd_pcm_add(pcm);
|
||||||
|
if (err) {
|
||||||
mutex_unlock(®ister_mutex);
|
mutex_unlock(®ister_mutex);
|
||||||
return -EBUSY;
|
return err;
|
||||||
}
|
}
|
||||||
list_add_tail(&pcm->list, &snd_pcm_devices);
|
|
||||||
for (cidx = 0; cidx < 2; cidx++) {
|
for (cidx = 0; cidx < 2; cidx++) {
|
||||||
int devtype = -1;
|
int devtype = -1;
|
||||||
if (pcm->streams[cidx].substream == NULL)
|
if (pcm->streams[cidx].substream == NULL)
|
||||||
|
|
|
@ -34,8 +34,6 @@
|
||||||
#include <linux/kmod.h>
|
#include <linux/kmod.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
|
|
||||||
#define SNDRV_OS_MINORS 256
|
|
||||||
|
|
||||||
static int major = CONFIG_SND_MAJOR;
|
static int major = CONFIG_SND_MAJOR;
|
||||||
int snd_major;
|
int snd_major;
|
||||||
EXPORT_SYMBOL(snd_major);
|
EXPORT_SYMBOL(snd_major);
|
||||||
|
|
Loading…
Reference in a new issue