case SND_CTL_IOCTL_RAWMIDI_INFO:
ctrl->result = snd_ctl_rawmidi_info(ctl, &ctrl->u.rawmidi_info);
break;
+ case SND_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE:
+ ctrl->result = snd_ctl_rawmidi_prefer_subdevice(ctl, ctrl->u.rawmidi_prefer_subdevice);
+ break;
case SND_CTL_IOCTL_READ:
ctrl->result = snd_ctl_read1(ctl, &ctrl->u.read);
break;
snd_pcm_info_t pcm_info;
int pcm_prefer_subdevice;
snd_rawmidi_info_t rawmidi_info;
+ int rawmidi_prefer_subdevice;
snd_ctl_event_t read;
} u;
char data[0];
int snd_ctl_pcm_info(snd_ctl_t *handle, snd_pcm_info_t * info);
int snd_ctl_pcm_prefer_subdevice(snd_ctl_t *handle, int subdev);
int snd_ctl_rawmidi_info(snd_ctl_t *handle, snd_rawmidi_info_t * info);
+int snd_ctl_rawmidi_prefer_subdevice(snd_ctl_t *handle, int subdev);
int snd_ctl_read(snd_ctl_t *handle, snd_ctl_callbacks_t * callbacks);
typedef struct snd_rawmidi snd_rawmidi_t;
+int snd_rawmidi_open_subdevice(snd_rawmidi_t **handle, int card, int device, int subdevice, int mode);
int snd_rawmidi_open(snd_rawmidi_t **handle, int card, int device, int mode);
int snd_rawmidi_close(snd_rawmidi_t *handle);
int snd_rawmidi_poll_descriptor(snd_rawmidi_t *handle);
return ctl->ops->rawmidi_info(ctl, info);
}
+int snd_ctl_rawmidi_prefer_subdevice(snd_ctl_t *ctl, int subdev)
+{
+ assert(ctl);
+ return ctl->ops->rawmidi_prefer_subdevice(ctl, subdev);
+}
+
int snd_ctl_read1(snd_ctl_t *ctl, snd_ctl_event_t *event)
{
assert(ctl && event);
return 0;
}
+static int snd_ctl_hw_rawmidi_prefer_subdevice(snd_ctl_t *handle, int subdev)
+{
+ snd_ctl_hw_t *hw = handle->private;
+ if (ioctl(hw->fd, SND_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE, &subdev) < 0)
+ return -errno;
+ return 0;
+}
+
static int snd_ctl_hw_read(snd_ctl_t *handle, snd_ctl_event_t *event)
{
snd_ctl_hw_t *hw = handle->private;
pcm_info: snd_ctl_hw_pcm_info,
pcm_prefer_subdevice: snd_ctl_hw_pcm_prefer_subdevice,
rawmidi_info: snd_ctl_hw_rawmidi_info,
+ rawmidi_prefer_subdevice: snd_ctl_hw_rawmidi_prefer_subdevice,
read: snd_ctl_hw_read,
};
int (*pcm_info)(snd_ctl_t *handle, snd_pcm_info_t * info);
int (*pcm_prefer_subdevice)(snd_ctl_t *handle, int subdev);
int (*rawmidi_info)(snd_ctl_t *handle, snd_rawmidi_info_t * info);
+ int (*rawmidi_prefer_subdevice)(snd_ctl_t *handle, int subdev);
int (*read)(snd_ctl_t *handle, snd_ctl_event_t *event);
};
return err;
}
+static int snd_ctl_shm_rawmidi_prefer_subdevice(snd_ctl_t *ctl, int subdev)
+{
+ snd_ctl_shm_t *shm = ctl->private;
+ snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
+ int err;
+ ctrl->u.rawmidi_prefer_subdevice = subdev;
+ ctrl->cmd = SND_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE;
+ err = snd_ctl_shm_action(ctl);
+ if (err < 0)
+ return err;
+ return err;
+}
+
static int snd_ctl_shm_read(snd_ctl_t *ctl, snd_ctl_event_t *event)
{
snd_ctl_shm_t *shm = ctl->private;
pcm_info: snd_ctl_shm_pcm_info,
pcm_prefer_subdevice: snd_ctl_shm_pcm_prefer_subdevice,
rawmidi_info: snd_ctl_shm_rawmidi_info,
+ rawmidi_prefer_subdevice: snd_ctl_shm_rawmidi_prefer_subdevice,
read: snd_ctl_shm_read,
};
default:
assert(0);
}
- ret = snd_ctl_pcm_prefer_subdevice(ctl, subdevice);
- snd_ctl_close(ctl);
- if (ret < 0)
- return ret;
sprintf(filename, filefmt, card, device);
__again:
- if (attempt++ > 3)
+ if (attempt++ > 3) {
+ snd_ctl_close(ctl);
return -EBUSY;
+ }
+ ret = snd_ctl_pcm_prefer_subdevice(ctl, subdevice);
+ if (ret < 0) {
+ snd_ctl_close(ctl);
+ return ret;
+ }
fmode = O_RDWR;
if (mode & SND_PCM_NONBLOCK)
fmode |= O_NONBLOCK;
fmode |= O_ASYNC;
if ((fd = open(filename, fmode)) < 0) {
SYSERR("open %s failed", filename);
+ snd_ctl_close(ctl);
return -errno;
}
if (ioctl(fd, SND_PCM_IOCTL_PVERSION, &ver) < 0) {
ret = snd_pcm_hw_mmap_status(pcm);
if (ret < 0) {
snd_pcm_close(pcm);
+ snd_ctl_close(ctl);
return ret;
}
ret = snd_pcm_hw_mmap_control(pcm);
if (ret < 0) {
snd_pcm_close(pcm);
+ snd_ctl_close(ctl);
return ret;
}
return 0;
if (pcm)
free(pcm);
close(fd);
+ snd_ctl_close(ctl);
return ret;
}
int mode;
};
-int snd_rawmidi_open(snd_rawmidi_t **handle, int card, int device, int mode)
+int snd_rawmidi_open_subdevice(snd_rawmidi_t **handle, int card, int device, int subdevice, int mode)
{
- int fd, ver;
+ int fd, ver, ret;
+ int attempt = 0;
char filename[32];
+ snd_ctl_t *ctl;
snd_rawmidi_t *rmidi;
+ snd_rawmidi_info_t info;
*handle = NULL;
if (card < 0 || card >= SND_CARDS)
return -EINVAL;
+
+ if ((ret = snd_ctl_hw_open(&ctl, NULL, card)) < 0)
+ return ret;
sprintf(filename, SND_FILE_RAWMIDI, card, device);
+
+ __again:
+ if (attempt++ > 3) {
+ snd_ctl_close(ctl);
+ return -EBUSY;
+ }
+ ret = snd_ctl_rawmidi_prefer_subdevice(ctl, subdevice);
+ if (ret < 0) {
+ snd_ctl_close(ctl);
+ return ret;
+ }
if ((fd = open(filename, mode)) < 0) {
snd_card_load(card);
- if ((fd = open(filename, mode)) < 0)
+ if ((fd = open(filename, mode)) < 0) {
+ snd_ctl_close(ctl);
return -errno;
+ }
}
if (ioctl(fd, SND_RAWMIDI_IOCTL_PVERSION, &ver) < 0) {
+ ret = -errno;
close(fd);
- return -errno;
+ snd_ctl_close(ctl);
+ return ret;
}
if (SND_PROTOCOL_INCOMPATIBLE(ver, SND_RAWMIDI_VERSION_MAX)) {
close(fd);
+ snd_ctl_close(ctl);
return -SND_ERROR_INCOMPATIBLE_VERSION;
}
+ if (subdevice >= 0) {
+ memset(&info, 0, sizeof(info));
+ if (ioctl(fd, SND_RAWMIDI_IOCTL_INFO, &info) < 0) {
+ ret = -errno;
+ close(fd);
+ snd_ctl_close(ctl);
+ return ret;
+ }
+ if (info.subdevice != subdevice) {
+ close(fd);
+ goto __again;
+ }
+ }
rmidi = (snd_rawmidi_t *) calloc(1, sizeof(snd_rawmidi_t));
if (rmidi == NULL) {
close(fd);
+ snd_ctl_close(ctl);
return -ENOMEM;
}
rmidi->card = card;
return 0;
}
+int snd_rawmidi_open(snd_rawmidi_t **handle, int card, int device, int mode)
+{
+ return snd_rawmidi_open_subdevice(handle, card, device, -1, mode);
+}
+
int snd_rawmidi_close(snd_rawmidi_t *rmidi)
{
int res;