summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortanimura <tanimura@FreeBSD.org>2000-01-03 02:51:16 +0000
committertanimura <tanimura@FreeBSD.org>2000-01-03 02:51:16 +0000
commit745351b771544bb075854f44d7b05678b9c5ee25 (patch)
tree72322c95acd5e63f61d62b0739947352a24f6cab
parent424e26f8b3df930160d8988532291e37a76170d0 (diff)
downloadFreeBSD-src-745351b771544bb075854f44d7b05678b9c5ee25.zip
FreeBSD-src-745351b771544bb075854f44d7b05678b9c5ee25.tar.gz
- Handle an interrupt for csa primarily in the bridge driver,
then invoke the children. As the value of HISR can be read only once, pass the HISR to the children via struct csa_bridgeinfo, stored in the ivars of them. - Clear the contents of serial FIFO upon stopping the DMA for playing. This may eliminate buzz on playing. Experimental.
-rw-r--r--sys/dev/sound/chip.h7
-rw-r--r--sys/dev/sound/pci/csa.c206
-rw-r--r--sys/dev/sound/pci/csapcm.c31
-rw-r--r--sys/dev/sound/pci/csavar.h7
4 files changed, 195 insertions, 56 deletions
diff --git a/sys/dev/sound/chip.h b/sys/dev/sound/chip.h
index 82704ed..012910c 100644
--- a/sys/dev/sound/chip.h
+++ b/sys/dev/sound/chip.h
@@ -38,9 +38,10 @@ enum {
/*
* This is the device information struct, used by
- * sndcard device to pass the device function code
- * to the driver.
+ * a bridge device to pass the device function code
+ * to the children.
*/
struct sndcard_func {
- int func;
+ int func; /* The function code. */
+ void *varinfo; /* Bridge-specific information. */
};
diff --git a/sys/dev/sound/pci/csa.c b/sys/dev/sound/pci/csa.c
index 8ab596e..2a23869 100644
--- a/sys/dev/sound/pci/csa.c
+++ b/sys/dev/sound/pci/csa.c
@@ -1,4 +1,4 @@
-/*-
+/*
* Copyright (c) 1999 Seigo Tanimura
* All rights reserved.
*
@@ -68,6 +68,8 @@ struct csa_softc {
void *midiintr_arg; /* midi intr arg */
#endif /* notyet */
void *ih; /* cookie */
+
+ struct csa_bridgeinfo binfo; /* The state of this bridge. */
};
typedef struct csa_softc *sc_p;
@@ -80,8 +82,13 @@ static struct resource *csa_alloc_resource(device_t bus, device_t child, int typ
u_long start, u_long end, u_long count, u_int flags);
static int csa_release_resource(device_t bus, device_t child, int type, int rid,
struct resource *r);
+static int csa_setup_intr(device_t bus, device_t child,
+ struct resource *irq, int flags,
+ driver_intr_t *intr, void *arg, void **cookiep);
+static int csa_teardown_intr(device_t bus, device_t child,
+ struct resource *irq, void *cookie);
+static driver_intr_t csa_intr;
static int csa_initialize(sc_p scp);
-static void csa_clearserialfifos(csa_res *resp);
static void csa_resetdsp(csa_res *resp);
static int csa_downloadimage(csa_res *resp);
static int csa_transferimage(csa_res *resp, u_long *src, u_long dest, u_long len);
@@ -92,9 +99,7 @@ static devclass_t csa_devclass;
static int
csa_probe(device_t dev)
{
- device_t child;
char *s;
- struct sndcard_func *func;
s = NULL;
switch (pci_get_devid(dev)) {
@@ -114,27 +119,6 @@ csa_probe(device_t dev)
if (s != NULL) {
device_set_desc(dev, s);
-
- /* PCM Audio */
- func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT);
- if (func == NULL)
- return (ENOMEM);
- bzero(func, sizeof(*func));
- func->func = SCF_PCM;
- child = device_add_child(dev, "pcm", -1);
- device_set_ivars(child, func);
-
-#if notyet
- /* Midi Interface */
- func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT);
- if (func == NULL)
- return (ENOMEM);
- bzero(func, sizeof(*func));
- func->func = SCF_MIDI;
- child = device_add_child(dev, "midi", -1);
- device_set_ivars(child, func);
-#endif /* notyet */
-
return (0);
}
@@ -147,6 +131,7 @@ csa_attach(device_t dev)
u_int32_t stcmd;
sc_p scp;
csa_res *resp;
+ struct sndcard_func *func;
scp = device_get_softc(dev);
@@ -160,10 +145,6 @@ csa_attach(device_t dev)
stcmd |= (PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
pci_write_config(dev, PCIR_COMMAND, 4, stcmd);
}
- stcmd = pci_read_config(dev, PCIR_LATTIMER, 4);
- if (stcmd < 32)
- stcmd = 32;
- pci_write_config(dev, PCIR_LATTIMER, 4, stcmd);
/* Allocate the resources. */
resp = &scp->res;
@@ -185,6 +166,16 @@ csa_attach(device_t dev)
return (ENXIO);
}
+ /* Enable interrupt. */
+ if (bus_setup_intr(dev, resp->irq, INTR_TYPE_TTY, csa_intr, scp, &scp->ih)) {
+ bus_release_resource(dev, SYS_RES_MEMORY, resp->io_rid, resp->io);
+ bus_release_resource(dev, SYS_RES_MEMORY, resp->mem_rid, resp->mem);
+ bus_release_resource(dev, SYS_RES_IRQ, resp->irq_rid, resp->irq);
+ return (ENXIO);
+ }
+ if ((csa_readio(resp, BA0_HISR) & HISR_INTENA) == 0)
+ csa_writeio(resp, BA0_HICR, HICR_IEV | HICR_CHGM);
+
/* Initialize the chip. */
if (csa_initialize(scp)) {
bus_release_resource(dev, SYS_RES_MEMORY, resp->io_rid, resp->io);
@@ -204,6 +195,30 @@ csa_attach(device_t dev)
return (ENXIO);
}
+ /* Attach the children. */
+
+ /* PCM Audio */
+ func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT);
+ if (func == NULL)
+ return (ENOMEM);
+ bzero(func, sizeof(*func));
+ func->varinfo = &scp->binfo;
+ func->func = SCF_PCM;
+ scp->pcm = device_add_child(dev, "pcm", -1);
+ device_set_ivars(scp->pcm, func);
+
+#if notyet
+ /* Midi Interface */
+ func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT);
+ if (func == NULL)
+ return (ENOMEM);
+ bzero(func, sizeof(*func));
+ func->varinfo = &scp->binfo;
+ func->func = SCF_MIDI;
+ scp->midi = device_add_child(dev, "midi", -1);
+ device_set_ivars(scp->midi, func);
+#endif /* notyet */
+
bus_generic_attach(dev);
return (0);
@@ -252,6 +267,133 @@ csa_release_resource(device_t bus, device_t child, int type, int rid,
return (0);
}
+/*
+ * The following three functions deal with interrupt handling.
+ * An interrupt is primarily handled by the bridge driver.
+ * The bridge driver then determines the child devices to pass
+ * the interrupt. Certain information of the device can be read
+ * only once(eg the value of HISR). The bridge driver is responsible
+ * to pass such the information to the children.
+ */
+
+static int
+csa_setup_intr(device_t bus, device_t child,
+ struct resource *irq, int flags,
+ driver_intr_t *intr, void *arg, void **cookiep)
+{
+ sc_p scp;
+ csa_res *resp;
+ struct sndcard_func *func;
+
+ scp = device_get_softc(bus);
+ resp = &scp->res;
+
+ /*
+ * Look at the function code of the child to determine
+ * the appropriate hander for it.
+ */
+ func = device_get_ivars(child);
+ if (func == NULL || irq != resp->irq)
+ return (EINVAL);
+
+ switch (func->func) {
+ case SCF_PCM:
+ scp->pcmintr = intr;
+ scp->pcmintr_arg = arg;
+ break;
+
+#if notyet
+ case SCF_MIDI:
+ scp->midiintr = intr;
+ scp->midiintr_arg = arg;
+ break;
+#endif /* notyet */
+
+ default:
+ return (EINVAL);
+ }
+ *cookiep = scp;
+ if ((csa_readio(resp, BA0_HISR) & HISR_INTENA) == 0)
+ csa_writeio(resp, BA0_HICR, HICR_IEV | HICR_CHGM);
+
+ return (0);
+}
+
+static int
+csa_teardown_intr(device_t bus, device_t child,
+ struct resource *irq, void *cookie)
+{
+ sc_p scp;
+ csa_res *resp;
+ struct sndcard_func *func;
+
+ scp = device_get_softc(bus);
+ resp = &scp->res;
+
+ /*
+ * Look at the function code of the child to determine
+ * the appropriate hander for it.
+ */
+ func = device_get_ivars(child);
+ if (func == NULL || irq != resp->irq || cookie != scp)
+ return (EINVAL);
+
+ switch (func->func) {
+ case SCF_PCM:
+ scp->pcmintr = NULL;
+ scp->pcmintr_arg = NULL;
+ break;
+
+#if notyet
+ case SCF_MIDI:
+ scp->midiintr = NULL;
+ scp->midiintr_arg = NULL;
+ break;
+#endif /* notyet */
+
+ default:
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+/* The interrupt handler */
+static void
+csa_intr(void *arg)
+{
+ sc_p scp = arg;
+ csa_res *resp;
+ u_int32_t hisr;
+
+ resp = &scp->res;
+
+ /* Is this interrupt for us? */
+ hisr = csa_readio(resp, BA0_HISR);
+ if ((hisr & ~HISR_INTENA) == 0) {
+ /* Throw an eoi. */
+ csa_writeio(resp, BA0_HICR, HICR_IEV | HICR_CHGM);
+ return;
+ }
+
+ /*
+ * Pass the value of HISR via struct csa_bridgeinfo.
+ * The children get access through their ivars.
+ */
+ scp->binfo.hisr = hisr;
+
+ /* Invoke the handlers of the children. */
+ if ((hisr & (HISR_VC0 | HISR_VC1)) != 0 && scp->pcmintr != NULL)
+ scp->pcmintr(scp->pcmintr_arg);
+#if notyet
+ if ((hisr & HISR_MIDI) != 0 && scp->midiintr != NULL)
+ scp->midiintr(scp->midiintr_arg);
+#endif /* notyet */
+
+ /* Throw an eoi. */
+ csa_writeio(resp, BA0_HICR, HICR_IEV | HICR_CHGM);
+}
+
static int
csa_initialize(sc_p scp)
{
@@ -448,7 +590,7 @@ csa_initialize(sc_p scp)
return (0);
}
-static void
+void
csa_clearserialfifos(csa_res *resp)
{
int i, j, pwr;
@@ -776,8 +918,8 @@ static device_method_t csa_methods[] = {
DEVMETHOD(bus_release_resource, csa_release_resource),
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
- DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
- DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
+ DEVMETHOD(bus_setup_intr, csa_setup_intr),
+ DEVMETHOD(bus_teardown_intr, csa_teardown_intr),
{ 0, 0 }
};
diff --git a/sys/dev/sound/pci/csapcm.c b/sys/dev/sound/pci/csapcm.c
index b67f2c9..fff8bb2 100644
--- a/sys/dev/sound/pci/csapcm.c
+++ b/sys/dev/sound/pci/csapcm.c
@@ -1,4 +1,4 @@
-/*-
+/*
* Copyright (c) 1999 Seigo Tanimura
* All rights reserved.
*
@@ -55,6 +55,7 @@ struct csa_info {
csa_res res; /* resource */
void *ih; /* Interrupt cookie */
bus_dma_tag_t parent_dmat; /* DMA tag */
+ struct csa_bridgeinfo *binfo; /* The state of the parent. */
/* Contents of board's registers */
u_long pfie;
@@ -438,6 +439,9 @@ csa_stopplaydma(struct csa_info *csa)
csa->pctl = ul & 0xffff0000;
csa_writemem(resp, BA1_PCTL, ul & 0x0000ffff);
csa_writemem(resp, BA1_PVOL, 0xffffffff);
+
+ /* Clear the serial fifos. */
+ csa_clearserialfifos(resp);
}
static void
@@ -619,27 +623,11 @@ static void
csa_intr (void *p)
{
struct csa_info *csa = p;
- csa_res *resp;
- u_int hisr;
- resp = &csa->res;
-
- /* Is this interrupt for us? */
- /* XXX The parent device should handle this. */
- hisr = csa_readio(resp, BA0_HISR);
- if ((hisr & ~HISR_INTENA) == 0) {
- /* Throw an eoi. */
- csa_writeio(resp, BA0_HICR, HICR_IEV | HICR_CHGM);
- return;
- }
-
- if ((hisr & HISR_VC0) != 0)
+ if ((csa->binfo->hisr & HISR_VC0) != 0)
chn_intr(csa->pch.channel);
- if ((hisr & HISR_VC1) != 0)
+ if ((csa->binfo->hisr & HISR_VC1) != 0)
chn_intr(csa->rch.channel);
-
- /* Throw an eoi. */
- csa_writeio(resp, BA0_HICR, HICR_IEV | HICR_CHGM);
}
/* -------------------------------------------------------------------- */
@@ -756,6 +744,7 @@ pcmcsa_attach(device_t dev)
int unit;
char status[SND_STATUSLEN];
struct ac97_info *codec;
+ struct sndcard_func *func;
devinfo = device_get_softc(dev);
csa = malloc(sizeof(*csa), M_DEVBUF, M_NOWAIT);
@@ -763,6 +752,8 @@ pcmcsa_attach(device_t dev)
return (ENOMEM);
bzero(csa, sizeof(*csa));
unit = device_get_unit(dev);
+ func = device_get_ivars(dev);
+ csa->binfo = func->varinfo;
/* Allocate the resources. */
resp = &csa->res;
@@ -790,8 +781,6 @@ pcmcsa_attach(device_t dev)
csa_releaseres(csa, dev);
return (ENXIO);
}
- if ((csa_readio(resp, BA0_HISR) & HISR_INTENA) == 0)
- csa_writeio(resp, BA0_HICR, HICR_IEV | HICR_CHGM);
csa_writemem(resp, BA1_PFIE, csa_readmem(resp, BA1_PFIE) & ~0x0000f03f);
csa_writemem(resp, BA1_CIE, (csa_readmem(resp, BA1_CIE) & ~0x0000003f) | 0x00000001);
diff --git a/sys/dev/sound/pci/csavar.h b/sys/dev/sound/pci/csavar.h
index 0f3d4f9..fef2ce8 100644
--- a/sys/dev/sound/pci/csavar.h
+++ b/sys/dev/sound/pci/csavar.h
@@ -40,6 +40,13 @@ struct csa_res {
};
typedef struct csa_res csa_res;
+/* State of the bridge. */
+struct csa_bridgeinfo {
+ u_int32_t hisr; /* The value of HISR on this interrupt. */
+};
+
+void csa_clearserialfifos(csa_res *resp);
+
/* Common functions for csa. */
int csa_readcodec(csa_res *resp, u_long offset, u_int32_t *data);
int csa_writecodec(csa_res *resp, u_long offset, u_int32_t data);
OpenPOWER on IntegriCloud