summaryrefslogtreecommitdiffstats
path: root/sys/dev/sound/pci/csa.c
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 /sys/dev/sound/pci/csa.c
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.
Diffstat (limited to 'sys/dev/sound/pci/csa.c')
-rw-r--r--sys/dev/sound/pci/csa.c206
1 files changed, 174 insertions, 32 deletions
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 }
};
OpenPOWER on IntegriCloud