* Re: trying out usb hotplugs
2002-11-29 11:24 ` Jaroslav Kysela
@ 2002-11-29 11:42 ` Takashi Iwai
2002-11-29 12:12 ` Takashi Iwai
1 sibling, 0 replies; 12+ messages in thread
From: Takashi Iwai @ 2002-11-29 11:42 UTC (permalink / raw)
To: Jaroslav Kysela; +Cc: Clemens Ladisch, alsa-devel@lists.sourceforge.net
At Fri, 29 Nov 2002 12:24:50 +0100 (CET),
Jaroslav wrote:
>
> On Fri, 29 Nov 2002, Takashi Iwai wrote:
>
> > At Fri, 29 Nov 2002 10:39:22 +0100 (CET),
> > Jaroslav wrote:
> > >
> > > On Fri, 29 Nov 2002, Takashi Iwai wrote:
> > >
> > > > At Fri, 29 Nov 2002 08:52:43 +0100 (MET),
> > > > Clemens Ladisch wrote:
> > > > >
> > > > > Takashi Iwai wrote:
> > > > > > Martin Langer wrote:
> > > > > > > usb hotplug works perfect if my usbmidi client isn't aconnected to another
> > > > > > > midi client. But the aconnected usb midi device still remains in the clients
> > > > > > > list, after hotpluging out.
> > > > > >
> > > > > > yep, when the connection exists, the connected devices (on both
> > > > > > sides) are regarded as active.
> > > > >
> > > > > The sequencer design allows asynchronous removal of clients.
> > > >
> > > > yes, but this may still try to send some bytes to the unplugged
> > > > rawmidi device at the disconnection. i'll change rawmidi code to
> > > > ignore that.
> > >
> > > Well, I'm trying to solve these "hotplug" problems. Unfortunately, it
> > > seems difficult to detect, if another task is in the middle of our
> > > callback. I think that we'll end up using mutexes.
> >
> > hmm, but mutex costs too much even for non-pluggable devices...
> >
> > in the case of rawmidi and oss-mixer, we can put "disconnected" flag
> > and ignore the access if the flag is on at the rawmidi and oss-mixer
> > routines, so that the control doesn't reach to low-level functions.
>
> Well, but if you check this flag at the beginning, then you don't know, if
> hardware is away in the middle of operation. The point is, that we have
> to finish the last operation and clean structures "when no task is
> inside".
yes. the unplugging may happen at any time, since it's a physical
action and cannot be locked by a kernel :)
this means, the invalid access in the middle of the code cannot be
avoided by a program code unless all function is atomic.
thus, the low-level stuff should take it into account if the card is
pluggable, anyway, for example, avoiding a possible infinte loop,
etc.
in the case of usb, the real critical part depends on the usb core and
controller routine. i hope it's ok.
the "disconnection-check-and-ignore" method is not perfect, but, if
the low level stuff doesn't go crazy even at the disconnected state,
the result wouldn't be so critical.
btw, the oss-emulation problem seems to be on the different point.
the oss-emulation accesses directly to the records without taking any
reference counters. thus snd_*_can_unregister() passes the check even
the control (or pcm) files are still open.
i'll keep on debugging this.
Takashi
-------------------------------------------------------
This SF.net email is sponsored by: Get the new Palm Tungsten T
handheld. Power & Color in a compact size!
http://ads.sourceforge.net/cgi-bin/redirect.pl?palm0002en
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: trying out usb hotplugs
2002-11-29 11:24 ` Jaroslav Kysela
2002-11-29 11:42 ` Takashi Iwai
@ 2002-11-29 12:12 ` Takashi Iwai
2002-11-29 14:05 ` Jaroslav Kysela
1 sibling, 1 reply; 12+ messages in thread
From: Takashi Iwai @ 2002-11-29 12:12 UTC (permalink / raw)
To: Jaroslav Kysela; +Cc: Clemens Ladisch, alsa-devel@lists.sourceforge.net
[-- Attachment #1: Type: text/plain, Size: 77 bytes --]
Hi,
the attached is my latest patch.
could you check it?
thanks,
Takashi
[-- Attachment #2: disconnect-fix.dif --]
[-- Type: application/octet-stream, Size: 13942 bytes --]
Index: alsa-kernel/core/control.c
===================================================================
RCS file: /suse/tiwai/cvs/alsa/alsa-kernel/core/control.c,v
retrieving revision 1.15
diff -u -r1.15 control.c
--- alsa-kernel/core/control.c 28 Nov 2002 09:31:13 -0000 1.15
+++ alsa-kernel/core/control.c 29 Nov 2002 11:52:05 -0000
@@ -78,6 +78,7 @@
ctl->pid = current->pid;
file->private_data = ctl;
write_lock_irqsave(&card->control_rwlock, flags);
+ atomic_inc(&card->ctl_use_count);
list_add_tail(&ctl->list, &card->ctl_files);
write_unlock_irqrestore(&card->control_rwlock, flags);
return 0;
@@ -118,10 +119,8 @@
card = ctl->card;
write_lock_irqsave(&card->control_rwlock, flags);
list_del(&ctl->list);
- write_unlock_irqrestore(&card->control_rwlock, flags);
- if (snd_ctl_can_unregister(card) == 0)
+ if (atomic_dec_and_test(&card->ctl_use_count))
wake_up(&card->shutdown_sleep);
- write_lock(&card->control_owner_lock);
list_for_each(list, &card->controls) {
control = snd_kcontrol(list);
if (control->owner == ctl)
@@ -602,6 +601,9 @@
ctl = snd_magic_cast(snd_ctl_file_t, file->private_data, return -ENXIO);
card = ctl->card;
snd_assert(card != NULL, return -ENXIO);
+ if (card->ctl_shutdown)
+ return -ENODEV;
+
switch (cmd) {
case SNDRV_CTL_IOCTL_PVERSION:
return put_user(SNDRV_CTL_VERSION, (int *)arg) ? -EFAULT : 0;
@@ -832,12 +834,7 @@
int snd_ctl_can_unregister(snd_card_t *card)
{
- int res;
-
- write_lock_irq(&card->control_rwlock);
- res = !list_empty(&card->ctl_files);
- write_unlock_irq(&card->control_rwlock);
- return res;
+ return atomic_read(&card->ctl_use_count) != 0;
}
int snd_ctl_unregister(snd_card_t *card)
Index: alsa-kernel/core/init.c
===================================================================
RCS file: /suse/tiwai/cvs/alsa/alsa-kernel/core/init.c,v
retrieving revision 1.14
diff -u -r1.14 init.c
--- alsa-kernel/core/init.c 28 Nov 2002 09:31:13 -0000 1.14
+++ alsa-kernel/core/init.c 29 Nov 2002 11:54:31 -0000
@@ -96,6 +96,7 @@
INIT_LIST_HEAD(&card->controls);
INIT_LIST_HEAD(&card->ctl_files);
init_waitqueue_head(&card->shutdown_sleep);
+ atomic_set(&card->ctl_use_count, 0);
#ifdef CONFIG_PM
init_MUTEX(&card->power_lock);
init_waitqueue_head(&card->power_sleep);
@@ -138,7 +139,7 @@
#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
if (snd_mixer_oss_notify_callback)
- snd_mixer_oss_notify_callback(card, 1);
+ snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_DISCONNECT);
#endif
/* notify all devices that we are disconnected */
@@ -174,7 +175,7 @@
#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
if (snd_mixer_oss_notify_callback)
- snd_mixer_oss_notify_callback(card, 2);
+ snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE);
#endif
if (snd_device_free_all(card, SNDRV_DEV_CMD_PRE) < 0) {
snd_printk(KERN_ERR "unable to free all devices (pre)\n");
@@ -300,7 +301,7 @@
__skip_info:
#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
if (snd_mixer_oss_notify_callback)
- snd_mixer_oss_notify_callback(card, 0);
+ snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_REGISTER);
#endif
return 0;
}
Index: alsa-kernel/core/rawmidi.c
===================================================================
RCS file: /suse/tiwai/cvs/alsa/alsa-kernel/core/rawmidi.c,v
retrieving revision 1.21
diff -u -r1.21 rawmidi.c
--- alsa-kernel/core/rawmidi.c 28 Nov 2002 09:31:13 -0000 1.21
+++ alsa-kernel/core/rawmidi.c 29 Nov 2002 09:04:56 -0000
@@ -136,6 +136,8 @@
long timeout;
snd_rawmidi_runtime_t *runtime = substream->runtime;
+ if (substream->rmidi->disconnected)
+ return 0;
err = 0;
runtime->drain = 1;
while (runtime->avail < runtime->buffer_size) {
@@ -144,6 +146,8 @@
err = -ERESTARTSYS;
break;
}
+ if (substream->rmidi->disconnected)
+ return 0;
if (runtime->avail < runtime->buffer_size && !timeout) {
snd_printk(KERN_WARNING "rawmidi drain error (avail = %li, buffer_size = %li)\n", (long)runtime->avail, (long)runtime->buffer_size);
err = -EIO;
@@ -1070,6 +1074,9 @@
snd_assert(buf != NULL, return -EINVAL);
snd_assert(runtime->buffer != NULL, return -EINVAL);
+ if (substream->rmidi->disconnected)
+ return -ENODEV;
+
result = 0;
spin_lock_irqsave(&runtime->lock, flags);
if (substream->append) {
@@ -1480,6 +1487,7 @@
snd_rawmidi_t *rmidi = snd_magic_cast(snd_rawmidi_t, device->device_data, return -ENXIO);
int idx;
+ rmidi->disconnected = 1;
down(®ister_mutex);
idx = (rmidi->card->number * SNDRV_RAWMIDI_DEVICES) + rmidi->device;
snd_rawmidi_devices[idx] = NULL;
Index: alsa-kernel/core/oss/mixer_oss.c
===================================================================
RCS file: /suse/tiwai/cvs/alsa/alsa-kernel/core/oss/mixer_oss.c,v
retrieving revision 1.12
diff -u -r1.12 mixer_oss.c
--- alsa-kernel/core/oss/mixer_oss.c 28 Nov 2002 09:31:13 -0000 1.12
+++ alsa-kernel/core/oss/mixer_oss.c 29 Nov 2002 12:08:01 -0000
@@ -53,6 +53,7 @@
fmixer = (snd_mixer_oss_file_t *)snd_kcalloc(sizeof(*fmixer), GFP_KERNEL);
if (fmixer == NULL)
return -ENOMEM;
+ atomic_inc(&card->ctl_use_count);
fmixer->card = card;
fmixer->mixer = card->mixer_oss;
file->private_data = fmixer;
@@ -64,6 +65,8 @@
#ifdef LINUX_2_2
MOD_DEC_USE_COUNT;
#endif
+ if (atomic_dec_and_test(&card->ctl_use_count))
+ wake_up(&card->shutdown_sleep);
return -EFAULT;
}
return 0;
@@ -79,6 +82,8 @@
#ifdef LINUX_2_2
MOD_DEC_USE_COUNT;
#endif
+ if (atomic_dec_and_test(&fmixer->card->ctl_use_count))
+ wake_up(&fmixer->card->shutdown_sleep);
kfree(fmixer);
}
return 0;
@@ -498,6 +503,10 @@
snd_ctl_elem_info_t *uinfo;
snd_ctl_elem_value_t *uctl;
+ /* FIXME: needs lock? */
+ if (fmixer->mixer->disconnected)
+ return;
+
snd_runtime_check(kctl != NULL, return);
uinfo = snd_kcalloc(sizeof(*uinfo), GFP_ATOMIC);
uctl = snd_kcalloc(sizeof(*uctl), GFP_ATOMIC);
@@ -525,6 +534,10 @@
snd_ctl_elem_info_t *uinfo;
snd_ctl_elem_value_t *uctl;
+ /* FIXME: needs lock? */
+ if (fmixer->mixer->disconnected)
+ return;
+
snd_runtime_check(kctl != NULL, return);
uinfo = snd_kcalloc(sizeof(*uinfo), GFP_ATOMIC);
uctl = snd_kcalloc(sizeof(*uctl), GFP_ATOMIC);
@@ -584,6 +597,10 @@
snd_ctl_elem_value_t *uctl;
int res;
+ /* FIXME: needs lock? */
+ if (fmixer->mixer->disconnected)
+ return;
+
snd_runtime_check(kctl != NULL, return);
uinfo = snd_kcalloc(sizeof(*uinfo), GFP_ATOMIC);
uctl = snd_kcalloc(sizeof(*uctl), GFP_ATOMIC);
@@ -614,6 +631,10 @@
snd_ctl_elem_value_t *uctl;
int res;
+ /* FIXME: needs lock? */
+ if (fmixer->mixer->disconnected)
+ return;
+
snd_runtime_check(kctl != NULL, return);
uinfo = snd_kcalloc(sizeof(*uinfo), GFP_ATOMIC);
uctl = snd_kcalloc(sizeof(*uctl), GFP_ATOMIC);
@@ -750,6 +771,10 @@
snd_ctl_elem_value_t *uctl;
int err, idx;
+ /* FIXME: needs lock? */
+ if (mixer->disconnected)
+ return -ENODEV;
+
uinfo = snd_kcalloc(sizeof(*uinfo), GFP_KERNEL);
uctl = snd_kcalloc(sizeof(*uctl), GFP_KERNEL);
if (uinfo == NULL || uctl == NULL) {
@@ -765,7 +790,7 @@
for (idx = 0; idx < 32; idx++) {
if (!(mixer->mask_recsrc & (1 << idx)))
continue;
- pslot = &fmixer->mixer->slots[idx];
+ pslot = &mixer->slots[idx];
slot = (struct slot *)pslot->private_data;
if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
continue;
@@ -799,6 +824,10 @@
snd_ctl_elem_value_t *uctl;
int err, idx;
+ /* FIXME: needs lock? */
+ if (mixer->disconnected)
+ return -ENODEV;
+
uinfo = snd_kcalloc(sizeof(*uinfo), GFP_KERNEL);
uctl = snd_kcalloc(sizeof(*uctl), GFP_KERNEL);
if (uinfo == NULL || uctl == NULL) {
@@ -812,7 +841,7 @@
for (idx = 0; idx < 32; idx++) {
if (!(mixer->mask_recsrc & (1 << idx)))
continue;
- pslot = &fmixer->mixer->slots[idx];
+ pslot = &mixer->slots[idx];
slot = (struct slot *)pslot->private_data;
if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
continue;
@@ -1204,7 +1233,7 @@
{
snd_mixer_oss_t *mixer;
- if (cmd == 0) { /* register */
+ if (cmd == SND_MIXER_OSS_NOTIFY_REGISTER) {
char name[128];
int idx, err;
@@ -1238,10 +1267,11 @@
card->mixer_oss = mixer;
snd_mixer_oss_build(mixer);
snd_mixer_oss_proc_init(mixer);
- } else if (cmd == 1) { /* disconnect */
+ } else if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT) {
mixer = card->mixer_oss;
if (mixer == NULL || !mixer->oss_dev_alloc)
return 0;
+ mixer->disconnected = 1;
snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
mixer->oss_dev_alloc = 0;
} else { /* free */
@@ -1266,7 +1296,7 @@
snd_mixer_oss_notify_callback = snd_mixer_oss_notify_handler;
for (idx = 0; idx < SNDRV_CARDS; idx++) {
if (snd_cards[idx])
- snd_mixer_oss_notify_handler(snd_cards[idx], 0);
+ snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_REGISTER);
}
return 0;
}
@@ -1278,7 +1308,7 @@
snd_mixer_oss_notify_callback = NULL;
for (idx = 0; idx < SNDRV_CARDS; idx++) {
if (snd_cards[idx])
- snd_mixer_oss_notify_handler(snd_cards[idx], 1);
+ snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_FREE);
}
}
Index: alsa-kernel/core/oss/pcm_oss.c
===================================================================
RCS file: /suse/tiwai/cvs/alsa/alsa-kernel/core/oss/pcm_oss.c,v
retrieving revision 1.20
diff -u -r1.20 pcm_oss.c
--- alsa-kernel/core/oss/pcm_oss.c 28 Nov 2002 09:31:13 -0000 1.20
+++ alsa-kernel/core/oss/pcm_oss.c 29 Nov 2002 11:29:18 -0000
@@ -1554,13 +1554,15 @@
err = -ENODEV;
goto __error1;
}
+ atomic_inc(&pcm->use_count);
if (!try_inc_mod_count(pcm->card->module)) {
err = -EFAULT;
+ atomic_dec(&pcm->use_count);
goto __error1;
}
if (snd_task_name(current, task_name, sizeof(task_name)) < 0) {
err = -EFAULT;
- goto __error1;
+ goto __error;
}
if (file->f_mode & FMODE_WRITE)
psetup = snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_PLAYBACK, task_name);
@@ -1639,6 +1641,8 @@
up(&pcm->open_mutex);
wake_up(&pcm->open_wait);
dec_mod_count(pcm->card->module);
+ if (atomic_dec_and_test(&pcm->use_count))
+ wake_up(&pcm->card->shutdown_sleep);
#ifdef LINUX_2_2
MOD_DEC_USE_COUNT;
#endif
Index: alsa-kernel/core/seq/seq_device.c
===================================================================
RCS file: /suse/tiwai/cvs/alsa/alsa-kernel/core/seq/seq_device.c,v
retrieving revision 1.6
diff -u -r1.6 seq_device.c
--- alsa-kernel/core/seq/seq_device.c 13 Aug 2002 16:17:06 -0000 1.6
+++ alsa-kernel/core/seq/seq_device.c 29 Nov 2002 08:45:48 -0000
@@ -92,6 +92,7 @@
static int snd_seq_device_free(snd_seq_device_t *dev);
static int snd_seq_device_dev_free(snd_device_t *device);
static int snd_seq_device_dev_register(snd_device_t *device);
+static int snd_seq_device_dev_disconnect(snd_device_t *device);
static int snd_seq_device_dev_unregister(snd_device_t *device);
static int init_device(snd_seq_device_t *dev, ops_list_t *ops);
@@ -166,6 +167,7 @@
static snd_device_ops_t dops = {
.dev_free = snd_seq_device_dev_free,
.dev_register = snd_seq_device_dev_register,
+ .dev_disconnect = snd_seq_device_dev_disconnect,
.dev_unregister = snd_seq_device_dev_unregister
};
@@ -265,6 +267,22 @@
init_device(dev, ops);
unlock_driver(ops);
+ return 0;
+}
+
+/*
+ * disconnect the device
+ */
+static int snd_seq_device_dev_disconnect(snd_device_t *device)
+{
+ snd_seq_device_t *dev = snd_magic_cast(snd_seq_device_t, device->device_data, return -ENXIO);
+ ops_list_t *ops;
+
+ ops = find_driver(dev->id, 0);
+ if (ops == NULL)
+ return -ENOENT;
+
+ free_device(dev, ops);
return 0;
}
Index: alsa-kernel/include/core.h
===================================================================
RCS file: /suse/tiwai/cvs/alsa/alsa-kernel/include/core.h,v
retrieving revision 1.24
diff -u -r1.24 core.h
--- alsa-kernel/include/core.h 28 Nov 2002 09:31:13 -0000 1.24
+++ alsa-kernel/include/core.h 29 Nov 2002 11:53:54 -0000
@@ -140,6 +140,7 @@
struct list_head controls; /* all controls for this card */
struct list_head ctl_files; /* active control files */
int ctl_shutdown; /* control interface is going down */
+ atomic_t ctl_use_count; /* reference counter for control files */
snd_info_entry_t *proc_root; /* root for soundcard specific files */
snd_info_entry_t *proc_id; /* the card id */
@@ -297,6 +298,9 @@
extern snd_card_t *snd_cards[SNDRV_CARDS];
extern rwlock_t snd_card_rwlock;
#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
+#define SND_MIXER_OSS_NOTIFY_REGISTER 0
+#define SND_MIXER_OSS_NOTIFY_DISCONNECT 1
+#define SND_MIXER_OSS_NOTIFY_FREE 2
extern int (*snd_mixer_oss_notify_callback)(snd_card_t *card, int cmd);
#endif
Index: alsa-kernel/include/mixer_oss.h
===================================================================
RCS file: /suse/tiwai/cvs/alsa/alsa-kernel/include/mixer_oss.h,v
retrieving revision 1.6
diff -u -r1.6 mixer_oss.h
--- alsa-kernel/include/mixer_oss.h 28 Nov 2002 09:31:13 -0000 1.6
+++ alsa-kernel/include/mixer_oss.h 29 Nov 2002 11:53:16 -0000
@@ -61,7 +61,8 @@
void (*private_free_recsrc)(snd_mixer_oss_t *mixer);
struct semaphore reg_mutex;
snd_info_entry_t *proc_entry;
- int oss_dev_alloc;
+ unsigned int oss_dev_alloc: 1;
+ unsigned int disconnected: 1;
/* --- */
int oss_recsrc;
};
Index: alsa-kernel/include/rawmidi.h
===================================================================
RCS file: /suse/tiwai/cvs/alsa/alsa-kernel/include/rawmidi.h,v
retrieving revision 1.10
diff -u -r1.10 rawmidi.h
--- alsa-kernel/include/rawmidi.h 28 Nov 2002 09:31:13 -0000 1.10
+++ alsa-kernel/include/rawmidi.h 29 Nov 2002 09:05:31 -0000
@@ -118,6 +118,7 @@
snd_card_t *card;
atomic_t use_count;
+ unsigned int disconnected: 1;
unsigned int device; /* device number */
unsigned int info_flags; /* SNDRV_RAWMIDI_INFO_XXXX */
^ permalink raw reply [flat|nested] 12+ messages in thread