Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F163690321
D58370.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
5 KB
Referenced Files
None
Subscribers
None
D58370.diff
View Options
diff --git a/sys/dev/sound/pci/hdspe-pcm.c b/sys/dev/sound/pci/hdspe-pcm.c
--- a/sys/dev/sound/pci/hdspe-pcm.c
+++ b/sys/dev/sound/pci/hdspe-pcm.c
@@ -391,35 +391,21 @@
{
struct sc_pcminfo *scp;
struct sc_chinfo *ch;
- device_t *devlist;
- int devcount;
- int i, j;
- int err;
-
- if ((err = device_get_children(sc->dev, &devlist, &devcount)) != 0)
- goto bad;
+ unsigned int i;
+ int j;
- for (i = 0; i < devcount; i++) {
- scp = device_get_ivars(devlist[i]);
+ for (i = 0; i < HDSPE_MAX_PCMDEV; i++) {
+ scp = sc->pcms[i];
+ if (scp == NULL)
+ continue;
for (j = 0; j < scp->chnum; j++) {
ch = &scp->chan[j];
if (ch->run)
- goto bad;
+ return (1);
}
}
- free(devlist, M_TEMP);
-
return (0);
-bad:
-
-#if 0
- device_printf(sc->dev, "hdspe is running\n");
-#endif
-
- free(devlist, M_TEMP);
-
- return (1);
}
static void
@@ -1034,12 +1020,15 @@
{
char status[SND_STATUSLEN];
struct sc_pcminfo *scp;
+ struct sc_info *sc;
const char *buf;
uint32_t pcm_flags;
int err;
int play, rec;
+ int i;
scp = device_get_ivars(dev);
+ sc = scp->sc;
scp->ih = &hdspe_pcm_intr;
if (scp->hc->ports & HDSPE_CHAN_AIO_ALL)
@@ -1077,8 +1066,8 @@
}
snprintf(status, SND_STATUSLEN, "port 0x%jx irq %jd on %s",
- rman_get_start(scp->sc->cs),
- rman_get_start(scp->sc->irq),
+ rman_get_start(sc->cs),
+ rman_get_start(sc->irq),
device_get_nameunit(device_get_parent(dev)));
err = pcm_register(dev, status);
if (err) {
@@ -1088,19 +1077,78 @@
mixer_init(dev, &hdspemixer_class, scp);
+ /* Register the PCM child for interrupt dispatch. */
+ mtx_lock(&sc->lock);
+ for (i = 0; i < HDSPE_MAX_PCMDEV; i++) {
+ if (sc->pcms[i] == NULL) {
+ sc->pcms[i] = scp;
+ break;
+ }
+ }
+ mtx_unlock(&sc->lock);
+ if (i == HDSPE_MAX_PCMDEV)
+ device_printf(dev, "Too many PCM children.\n");
+
return (0);
}
+static int
+hdspe_pcm_quiesce(struct sc_pcminfo *scp)
+{
+ struct sc_info *sc;
+ unsigned int i;
+ int slot;
+
+ sc = scp->sc;
+ slot = -1;
+ mtx_lock(&sc->lock);
+ for (i = 0; i < HDSPE_MAX_PCMDEV; i++) {
+ if (sc->pcms[i] == scp) {
+ sc->pcm_detaching[i] = true;
+ while (sc->pcm_refs[i] != 0)
+ cv_wait(&sc->pcm_cv, &sc->lock);
+ slot = (int)i;
+ break;
+ }
+ }
+ mtx_unlock(&sc->lock);
+ return (slot);
+}
+
+static void
+hdspe_pcm_unquiesce(struct sc_pcminfo *scp, int slot, bool detach)
+{
+ struct sc_info *sc;
+
+ sc = scp->sc;
+ mtx_lock(&sc->lock);
+ KASSERT(slot >= 0 && slot < HDSPE_MAX_PCMDEV &&
+ sc->pcms[slot] == scp && sc->pcm_detaching[slot],
+ ("invalid PCM slot %d", slot));
+ if (detach)
+ sc->pcms[slot] = NULL;
+ sc->pcm_detaching[slot] = false;
+ mtx_unlock(&sc->lock);
+}
+
static int
hdspe_pcm_detach(device_t dev)
{
- int err;
+ struct sc_pcminfo *scp;
+ int err, slot;
+
+ scp = device_get_ivars(dev);
+ slot = hdspe_pcm_quiesce(scp);
err = pcm_unregister(dev);
if (err) {
device_printf(dev, "Can't unregister device.\n");
+ if (slot >= 0)
+ hdspe_pcm_unquiesce(scp, slot, false);
return (err);
}
+ if (slot >= 0)
+ hdspe_pcm_unquiesce(scp, slot, true);
return (0);
}
diff --git a/sys/dev/sound/pci/hdspe.h b/sys/dev/sound/pci/hdspe.h
--- a/sys/dev/sound/pci/hdspe.h
+++ b/sys/dev/sound/pci/hdspe.h
@@ -211,6 +211,9 @@
struct hdspe_channel *hc;
};
+/* Maximum number of PCM children. */
+#define HDSPE_MAX_PCMDEV 8
+
/* HDSPe device private data */
struct sc_info {
device_t dev;
@@ -241,6 +244,12 @@
uint32_t speed;
uint32_t force_period;
uint32_t force_speed;
+
+ /* PCM children used for interrupt dispatch. */
+ struct sc_pcminfo *pcms[HDSPE_MAX_PCMDEV];
+ unsigned int pcm_refs[HDSPE_MAX_PCMDEV];
+ bool pcm_detaching[HDSPE_MAX_PCMDEV];
+ struct cv pcm_cv;
};
#define hdspe_read_1(sc, regno) \
diff --git a/sys/dev/sound/pci/hdspe.c b/sys/dev/sound/pci/hdspe.c
--- a/sys/dev/sound/pci/hdspe.c
+++ b/sys/dev/sound/pci/hdspe.c
@@ -111,11 +111,8 @@
{
struct sc_pcminfo *scp;
struct sc_info *sc;
- device_t *devlist;
- int devcount;
+ unsigned int i;
int status;
- int err;
- int i;
sc = (struct sc_info *)p;
@@ -123,17 +120,18 @@
status = hdspe_read_1(sc, HDSPE_STATUS_REG);
if (status & HDSPE_AUDIO_IRQ_PENDING) {
- if ((err = device_get_children(sc->dev, &devlist, &devcount)) != 0)
- return;
-
- for (i = 0; i < devcount; i++) {
- scp = device_get_ivars(devlist[i]);
- if (scp->ih != NULL)
- scp->ih(scp);
+ for (i = 0; i < HDSPE_MAX_PCMDEV; i++) {
+ scp = sc->pcms[i];
+ if (scp == NULL || sc->pcm_detaching[i] ||
+ scp->ih == NULL)
+ continue;
+ sc->pcm_refs[i]++;
+ scp->ih(scp);
+ if (--sc->pcm_refs[i] == 0 && sc->pcm_detaching[i])
+ cv_broadcast(&sc->pcm_cv);
}
hdspe_write_1(sc, HDSPE_INTERRUPT_ACK, 0);
- free(devlist, M_TEMP);
}
mtx_unlock(&sc->lock);
@@ -844,6 +842,7 @@
"Analog input level ('LowGain', '+4dBU', '-10dBV')");
}
+ cv_init(&sc->pcm_cv, "snd_hdspe pcm");
bus_attach_children(dev);
return (0);
}
@@ -891,6 +890,7 @@
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
if (sc->cs)
bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0), sc->cs);
+ cv_destroy(&sc->pcm_cv);
mtx_destroy(&sc->lock);
return (0);
@@ -907,7 +907,7 @@
static driver_t hdspe_driver = {
"hdspe",
hdspe_methods,
- PCM_SOFTC_SIZE,
+ sizeof(struct sc_info),
};
DRIVER_MODULE(snd_hdspe, pci, hdspe_driver, 0, 0);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Jul 26, 12:28 PM (46 m, 52 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35467320
Default Alt Text
D58370.diff (5 KB)
Attached To
Mode
D58370: snd_hdspe: Avoid allocation in the interrupt handler
Attached
Detach File
Event Timeline
Log In to Comment