summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcg <cg@FreeBSD.org>2001-05-30 22:38:31 +0000
committercg <cg@FreeBSD.org>2001-05-30 22:38:31 +0000
commit67fa2b23c688f8e0aabf6145e161e466255bf08e (patch)
tree18e96b1d78ffd9f224acc212a89f7fc17237d4a7
parent2c8f781b182182f0727542e807496bce89be2bc6 (diff)
downloadFreeBSD-src-67fa2b23c688f8e0aabf6145e161e466255bf08e.zip
FreeBSD-src-67fa2b23c688f8e0aabf6145e161e466255bf08e.tar.gz
update this driver to use new firmware and incorporate many fixes.
this works on cs4630 chips, and should implement the clkrun hack for thinkpads- this will display diagnostic messages when triggered until its correctness is established.
-rw-r--r--sys/dev/sound/pci/csa.c273
-rw-r--r--sys/dev/sound/pci/csapcm.c272
-rw-r--r--sys/dev/sound/pci/csareg.h17
-rw-r--r--sys/dev/sound/pci/csavar.h9
4 files changed, 313 insertions, 258 deletions
diff --git a/sys/dev/sound/pci/csa.c b/sys/dev/sound/pci/csa.c
index 55fa9e7..24adda5 100644
--- a/sys/dev/sound/pci/csa.c
+++ b/sys/dev/sound/pci/csa.c
@@ -48,7 +48,13 @@
#include <pci/pcireg.h>
#include <pci/pcivar.h>
-#include <dev/sound/pci/csaimg.h>
+#include <gnu/dev/sound/pci/csaimg.h>
+
+/* This is the pci device id. */
+#define CS4610_PCI_ID 0x60011013
+#define CS4614_PCI_ID 0x60031013
+#define CS4615_PCI_ID 0x60041013
+#define CS4281_PCI_ID 0x60051013
/* Here is the parameter structure per a device. */
struct csa_softc {
@@ -63,6 +69,7 @@ struct csa_softc {
void *midiintr_arg; /* midi intr arg */
void *ih; /* cookie */
+ struct csa_card *card;
struct csa_bridgeinfo binfo; /* The state of this bridge. */
};
@@ -83,34 +90,153 @@ static driver_intr_t csa_intr;
static int csa_initialize(sc_p scp);
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);
static devclass_t csa_devclass;
+static void
+amp_none(void)
+{
+}
+
+static void
+amp_voyetra(void)
+{
+}
+
static int
-csa_probe(device_t dev)
+clkrun_hack(int run)
{
- char *s;
+#ifdef __i386__
+ devclass_t pci_devclass;
+ device_t *pci_devices, *pci_children, *busp, *childp;
+ int pci_count = 0, pci_childcount = 0;
+ int i, j, port;
+ u_int16_t control;
+ bus_space_tag_t btag;
+
+ printf("clkrun_hack: ");
+ if ((pci_devclass = devclass_find("pci")) == NULL) {
+ printf("can't find devclass 'pci'\n");
+ return ENXIO;
+ }
- s = NULL;
- switch (pci_get_devid(dev)) {
- case CS4610_PCI_ID:
- s = "Crystal Semiconductor CS4610/4611 Audio accelerator";
- break;
- case CS4614_PCI_ID:
- s = "Crystal Semiconductor CS4614/4622/4624 Audio accelerator/4280 Audio controller";
- break;
- case CS4615_PCI_ID:
- s = "Crystal Semiconductor CS4615 Audio accelerator";
- break;
+ devclass_get_devices(pci_devclass, &pci_devices, &pci_count);
+
+ for (i = 0, busp = pci_devices; i < pci_count; i++, busp++) {
+ pci_childcount = 0;
+ device_get_children(*busp, &pci_children, &pci_childcount);
+ for (j = 0, childp = pci_children; j < pci_childcount; j++, childp++) {
+ if (pci_get_vendor(*childp) == 0x8086 && pci_get_device(*childp) == 0x7113) {
+ run = !run;
+ printf("found bx chipset, %sabling clkrun\n", run? "en" : "dis");
+ free(pci_devices, M_TEMP);
+ free(pci_children, M_TEMP);
+
+ port = (pci_read_config(*childp, 0x41, 1) << 8) + 0x10;
+ /* XXX */
+ btag = I386_BUS_SPACE_IO;
+
+ control = bus_space_read_2(btag, 0x0, port);
+ control &= ~0x2000;
+ control |= run? 0 : 0x2000;
+ bus_space_write_2(btag, 0x0, port, control);
+ return 0;
+ }
+ }
+ }
+ printf("can't find bx chipset\n");
+
+ free(pci_devices, M_TEMP);
+ free(pci_children, M_TEMP);
+ return ENXIO;
+#else
+ return 0;
+#endif
+}
+
+static struct csa_card cards_4610[] = {
+ {0, 0, "Unknown/invalid SSID (CS4610)", NULL, NULL, NULL },
+};
+
+static struct csa_card cards_4614[] = {
+ {0x1489, 0x7001, "Genius Soundmaker 128 value", amp_none, NULL, NULL},
+ {0x5053, 0x3357, "Turtle Beach Santa Cruz", amp_voyetra, NULL, NULL},
+ {0x1071, 0x6003, "Mitac MI6020/21", amp_voyetra, NULL, NULL},
+ {0x14AF, 0x0050, "Hercules Game Theatre XP", NULL, NULL, NULL},
+ {0x1681, 0x0050, "Hercules Game Theatre XP", NULL, NULL, NULL},
+ /* Not sure if the 570 needs the clkrun hack */
+ {0x1014, 0x0132, "Thinkpad 570", amp_none, NULL, clkrun_hack},
+ {0x1014, 0x0153, "Thinkpad 600X/A20/T20", amp_none, NULL, clkrun_hack},
+ {0x1014, 0x1010, "Thinkpad 600E (unsupported)", NULL, NULL, NULL},
+ {0, 0, "Unknown/invalid SSID (CS4614)", NULL, NULL, NULL },
+};
+
+static struct csa_card cards_4615[] = {
+ {0, 0, "Unknown/invalid SSID (CS4615)", NULL, NULL, NULL },
+};
+
+static struct csa_card nocard = {0, 0, "unknown", NULL, NULL, NULL };
+
+struct card_type {
+ u_int32_t devid;
+ char *name;
+ struct csa_card *cards;
+};
+
+static struct card_type cards[] = {
+ {CS4610_PCI_ID, "CS4610/CS4611", cards_4610},
+ {CS4614_PCI_ID, "CS4280/CS4614/CS4622/CS4624/CS4630", cards_4614},
+ {CS4615_PCI_ID, "CS4615", cards_4615},
+ {0, NULL, NULL},
+};
+
+static struct card_type *
+csa_findcard(device_t dev)
+{
+ int i;
+
+ i = 0;
+ while (cards[i].devid != 0) {
+ if (pci_get_devid(dev) == cards[i].devid)
+ return &cards[i];
+ i++;
}
+ return NULL;
+}
- if (s != NULL) {
- device_set_desc(dev, s);
- return (0);
+struct csa_card *
+csa_findsubcard(device_t dev)
+{
+ int i;
+ struct card_type *card;
+ struct csa_card *subcard;
+
+ card = csa_findcard(dev);
+ if (card == NULL)
+ return &nocard;
+ subcard = card->cards;
+ i = 0;
+ while (subcard[i].subvendor != 0) {
+ if (pci_get_subvendor(dev) == subcard[i].subvendor
+ && pci_get_subdevice(dev) == subcard[i].subdevice) {
+ return &subcard[i];
+ }
+ i++;
}
+ return &subcard[i];
+}
- return (ENXIO);
+static int
+csa_probe(device_t dev)
+{
+ struct card_type *card;
+
+ card = csa_findcard(dev);
+ if (card) {
+ device_set_desc(dev, card->name);
+ return 0;
+ }
+ return ENXIO;
}
static int
@@ -136,12 +262,15 @@ csa_attach(device_t dev)
/* Allocate the resources. */
resp = &scp->res;
- resp->io_rid = CS461x_IO_OFFSET;
- resp->io = bus_alloc_resource(dev, SYS_RES_MEMORY, &resp->io_rid, 0, ~0, CS461x_IO_SIZE, RF_ACTIVE);
+ scp->card = csa_findsubcard(dev);
+ scp->binfo.card = scp->card;
+ printf("csa: card is %s\n", scp->card->name);
+ resp->io_rid = PCIR_MAPS;
+ resp->io = bus_alloc_resource(dev, SYS_RES_MEMORY, &resp->io_rid, 0, ~0, 1, RF_ACTIVE);
if (resp->io == NULL)
return (ENXIO);
- resp->mem_rid = CS461x_MEM_OFFSET;
- resp->mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &resp->mem_rid, 0, ~0, CS461x_MEM_SIZE, RF_ACTIVE);
+ resp->mem_rid = PCIR_MAPS + 4;
+ resp->mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &resp->mem_rid, 0, ~0, 1, RF_ACTIVE);
if (resp->mem == NULL) {
bus_release_resource(dev, SYS_RES_MEMORY, resp->io_rid, resp->io);
return (ENXIO);
@@ -155,14 +284,16 @@ csa_attach(device_t dev)
}
/* Enable interrupt. */
- if (snd_setup_intr(dev, resp->irq, 0, csa_intr, scp, &scp->ih)) {
+ if (snd_setup_intr(dev, resp->irq, INTR_MPSAFE, 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 0
if ((csa_readio(resp, BA0_HISR) & HISR_INTENA) == 0)
csa_writeio(resp, BA0_HICR, HICR_IEV | HICR_CHGM);
+#endif
/* Initialize the chip. */
if (csa_initialize(scp)) {
@@ -210,6 +341,17 @@ csa_attach(device_t dev)
return (0);
}
+static int
+csa_detach(device_t dev)
+{
+ sc_p scp;
+
+ scp = device_get_softc(dev);
+ device_delete_child(dev, scp->midi);
+ device_delete_child(dev, scp->pcm);
+ return bus_generic_detach(dev);
+}
+
static struct resource *
csa_alloc_resource(device_t bus, device_t child, int type, int *rid,
u_long start, u_long end, u_long count, u_int flags)
@@ -228,10 +370,10 @@ csa_alloc_resource(device_t bus, device_t child, int type, int *rid,
break;
case SYS_RES_MEMORY:
switch (*rid) {
- case CS461x_IO_OFFSET:
+ case PCIR_MAPS:
res = resp->io;
break;
- case CS461x_MEM_OFFSET:
+ case PCIR_MAPS + 4:
res = resp->mem;
break;
default:
@@ -351,7 +493,7 @@ csa_intr(void *arg)
/* Is this interrupt for us? */
hisr = csa_readio(resp, BA0_HISR);
- if ((hisr & ~HISR_INTENA) == 0) {
+ if ((hisr & 0x7fffffff) == 0) {
/* Throw an eoi. */
csa_writeio(resp, BA0_HICR, HICR_IEV | HICR_CHGM);
return;
@@ -364,10 +506,14 @@ csa_intr(void *arg)
scp->binfo.hisr = hisr;
/* Invoke the handlers of the children. */
- if ((hisr & (HISR_VC0 | HISR_VC1)) != 0 && scp->pcmintr != NULL)
+ if ((hisr & (HISR_VC0 | HISR_VC1)) != 0 && scp->pcmintr != NULL) {
scp->pcmintr(scp->pcmintr_arg);
- if ((hisr & HISR_MIDI) != 0 && scp->midiintr != NULL)
+ hisr &= ~(HISR_VC0 | HISR_VC1);
+ }
+ if ((hisr & HISR_MIDI) != 0 && scp->midiintr != NULL) {
scp->midiintr(scp->midiintr_arg);
+ hisr &= ~HISR_MIDI;
+ }
/* Throw an eoi. */
csa_writeio(resp, BA0_HICR, HICR_IEV | HICR_CHGM);
@@ -406,8 +552,10 @@ csa_initialize(sc_p scp)
* there might be logic external to the CS461x that uses the ARST# line
* for a reset.
*/
+ csa_writeio(resp, BA0_ACCTL, 1);
+ DELAY(50);
csa_writeio(resp, BA0_ACCTL, 0);
- DELAY(100);
+ DELAY(50);
csa_writeio(resp, BA0_ACCTL, ACCTL_RSTN);
/*
@@ -429,6 +577,7 @@ csa_initialize(sc_p scp)
* the clock control circuit gets its clock from the correct place.
*/
csa_writeio(resp, BA0_SERMC1, SERMC1_PTC_AC97);
+ DELAY(700000);
/*
* Write the selected clock control setup to the hardware. Do not turn on
@@ -447,7 +596,7 @@ csa_initialize(sc_p scp)
/*
* Wait until the PLL has stabilized.
*/
- DELAY(50000);
+ DELAY(5000);
/*
* Turn on clocking of the core so that we can setup the serial ports.
@@ -562,7 +711,7 @@ csa_initialize(sc_p scp)
/*
* Enable interrupts on the part.
*/
-#if notdef
+#if 0
csa_writeio(resp, BA0_HICR, HICR_IEV | HICR_CHGM);
#endif /* notdef */
@@ -653,48 +802,26 @@ csa_resetdsp(csa_res *resp)
static int
csa_downloadimage(csa_res *resp)
{
- int ret;
- u_long ul, offset;
+ int i;
+ u_int32_t tmp, src, dst, count, data;
- for (ul = 0, offset = 0 ; ul < INKY_MEMORY_COUNT ; ul++) {
- /*
- * DMA this block from host memory to the appropriate
- * memory on the CSDevice.
- */
- ret = csa_transferimage(
- resp,
- BA1Struct.BA1Array + offset,
- BA1Struct.MemoryStat[ul].ulDestByteOffset,
- BA1Struct.MemoryStat[ul].ulSourceByteSize);
- if (ret)
- return (ret);
- offset += BA1Struct.MemoryStat[ul].ulSourceByteSize >> 2;
+ for (i = 0; i < CLEAR__COUNT; i++) {
+ dst = ClrStat[i].BA1__DestByteOffset;
+ count = ClrStat[i].BA1__SourceSize;
+ for (tmp = 0; tmp < count; tmp += 4)
+ csa_writemem(resp, dst + tmp, 0x00000000);
}
- return (0);
-}
-
-static int
-csa_transferimage(csa_res *resp, u_long *src, u_long dest, u_long len)
-{
- u_long ul;
-
- /*
- * We do not allow DMAs from host memory to host memory (although the DMA
- * can do it) and we do not allow DMAs which are not a multiple of 4 bytes
- * in size (because that DMA can not do that). Return an error if either
- * of these conditions exist.
- */
- if ((len & 0x3) != 0)
- return (EINVAL);
-
- /* Check the destination address that it is a multiple of 4 */
- if ((dest & 0x3) != 0)
- return (EINVAL);
-
- /* Write the buffer out. */
- for (ul = 0 ; ul < len ; ul += 4)
- csa_writemem(resp, dest + ul, src[ul >> 2]);
+ for (i = 0; i < FILL__COUNT; i++) {
+ src = 0;
+ dst = FillStat[i].Offset;
+ count = FillStat[i].Size;
+ for (tmp = 0; tmp < count; tmp += 4) {
+ data = FillStat[i].pFill[src];
+ csa_writemem(resp, dst + tmp, data);
+ src++;
+ }
+ }
return (0);
}
@@ -872,7 +999,7 @@ csa_writeio(csa_res *resp, u_long offset, u_int32_t data)
u_int32_t
csa_readmem(csa_res *resp, u_long offset)
{
- return bus_space_read_4(rman_get_bustag(resp->mem), rman_get_bushandle(resp->mem), offset) & 0xffffffff;
+ return bus_space_read_4(rman_get_bustag(resp->mem), rman_get_bushandle(resp->mem), offset);
}
void
@@ -885,7 +1012,7 @@ static device_method_t csa_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, csa_probe),
DEVMETHOD(device_attach, csa_attach),
- DEVMETHOD(device_detach, bus_generic_detach),
+ DEVMETHOD(device_detach, csa_detach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, bus_generic_suspend),
DEVMETHOD(device_resume, bus_generic_resume),
diff --git a/sys/dev/sound/pci/csapcm.c b/sys/dev/sound/pci/csapcm.c
index 399ac15..19ea977 100644
--- a/sys/dev/sound/pci/csapcm.c
+++ b/sys/dev/sound/pci/csapcm.c
@@ -40,6 +40,11 @@
#include <pci/pcireg.h>
#include <pci/pcivar.h>
+/* Buffer size on dma transfer. Fixed for CS416x. */
+#define CS461x_BUFFSIZE (4 * 1024)
+
+#define GOF_PER_SEC 200
+
/* device private data */
struct csa_info;
@@ -48,7 +53,7 @@ struct csa_chinfo {
struct pcm_channel *channel;
struct snd_dbuf *buffer;
int dir;
- u_int32_t fmt;
+ u_int32_t fmt, spd;
int dma;
};
@@ -57,7 +62,9 @@ struct csa_info {
void *ih; /* Interrupt cookie */
bus_dma_tag_t parent_dmat; /* DMA tag */
struct csa_bridgeinfo *binfo; /* The state of the parent. */
+ struct csa_card *card;
+ int active;
/* Contents of board's registers */
u_long pfie;
u_long pctl;
@@ -76,8 +83,6 @@ static void csa_startplaydma(struct csa_info *csa);
static void csa_startcapturedma(struct csa_info *csa);
static void csa_stopplaydma(struct csa_info *csa);
static void csa_stopcapturedma(struct csa_info *csa);
-static void csa_powerupadc(csa_res *resp);
-static void csa_powerupdac(csa_res *resp);
static int csa_startdsp(csa_res *resp);
static int csa_allocres(struct csa_info *scp, device_t dev);
static void csa_releaseres(struct csa_info *scp, device_t dev);
@@ -103,6 +108,24 @@ static u_int32_t csa_recfmt[] = {
static struct pcmchan_caps csa_reccaps = {11025, 48000, csa_recfmt, 0};
/* -------------------------------------------------------------------- */
+
+static int
+csa_active(struct csa_info *csa, int run)
+{
+ int old, go;
+
+ old = csa->active;
+ csa->active += run;
+
+ if ((csa->active == 0 && old == 1) || (csa->active == 1 && old == 0)) {
+ go = csa->active;
+ if (csa->card->active)
+ return csa->card->active(go);
+ }
+ return 0;
+}
+
+/* -------------------------------------------------------------------- */
/* ac97 codec */
static int
@@ -111,8 +134,10 @@ csa_rdcd(kobj_t obj, void *devinfo, int regno)
u_int32_t data;
struct csa_info *csa = (struct csa_info *)devinfo;
+ csa_active(csa, 1);
if (csa_readcodec(&csa->res, regno + BA0_AC97_RESET, &data))
data = 0;
+ csa_active(csa, -1);
return data;
}
@@ -122,7 +147,9 @@ csa_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data)
{
struct csa_info *csa = (struct csa_info *)devinfo;
+ csa_active(csa, 1);
csa_writecodec(&csa->res, regno + BA0_AC97_RESET, data);
+ csa_active(csa, -1);
return 0;
}
@@ -380,86 +407,6 @@ csa_stopcapturedma(struct csa_info *csa)
}
}
-static void
-csa_powerupdac(csa_res *resp)
-{
- int i;
- u_long ul;
-
- /*
- * Power on the DACs on the AC97 codec. We turn off the DAC
- * powerdown bit and write the new value of the power control
- * register.
- */
- ul = csa_readio(resp, BA0_AC97_POWERDOWN);
- ul &= 0xfdff;
- csa_writeio(resp, BA0_AC97_POWERDOWN, ul);
-
- /*
- * Now, we wait until we sample a DAC ready state.
- */
- for (i = 0 ; i < 32 ; i++) {
- /*
- * First, lets wait a short while to let things settle out a
- * bit, and to prevent retrying the read too quickly.
- */
- DELAY(125);
-
- /*
- * Read the current state of the power control register.
- */
- ul = csa_readio(resp, BA0_AC97_POWERDOWN);
-
- /*
- * If the DAC ready state bit is set, then stop waiting.
- */
- if ((ul & 0x2) != 0)
- break;
- }
- /*
- * The DACs are now calibrated, so we can unmute the DAC output.
- */
- csa_writeio(resp, BA0_AC97_PCM_OUT_VOLUME, 0x0808);
-}
-
-static void
-csa_powerupadc(csa_res *resp)
-{
- int i;
- u_long ul;
-
- /*
- * Power on the ADCs on the AC97 codec. We turn off the ADC
- * powerdown bit and write the new value of the power control
- * register.
- */
- ul = csa_readio(resp, BA0_AC97_POWERDOWN);
- ul &= 0xfeff;
- csa_writeio(resp, BA0_AC97_POWERDOWN, ul);
-
- /*
- * Now, we wait until we sample a ADC ready state.
- */
- for (i = 0 ; i < 32 ; i++) {
- /*
- * First, lets wait a short while to let things settle out a
- * bit, and to prevent retrying the read too quickly.
- */
- DELAY(125);
-
- /*
- * Read the current state of the power control register.
- */
- ul = csa_readio(resp, BA0_AC97_POWERDOWN);
-
- /*
- * If the ADC ready state bit is set, then stop waiting.
- */
- if ((ul & 0x1) != 0)
- break;
- }
-}
-
static int
csa_startdsp(csa_res *resp)
{
@@ -486,11 +433,7 @@ csa_startdsp(csa_res *resp)
/*
* Wait a little bit, so we don't issue PCI reads too frequently.
*/
-#if notdef
- DELAY(1000);
-#else
- DELAY(125);
-#endif /* notdef */
+ DELAY(50);
/*
* Fetch the current value of the SP status register.
*/
@@ -511,6 +454,55 @@ csa_startdsp(csa_res *resp)
return (0);
}
+static int
+csa_setupchan(struct csa_chinfo *ch)
+{
+ struct csa_info *csa = ch->parent;
+ csa_res *resp = &csa->res;
+ u_long pdtc, tmp;
+
+ if (ch->dir == PCMDIR_PLAY) {
+ /* direction */
+ csa_writemem(resp, BA1_PBA, vtophys(sndbuf_getbuf(ch->buffer)));
+
+ /* format */
+ csa->pfie = csa_readmem(resp, BA1_PFIE) & ~0x0000f03f;
+ if (!(ch->fmt & AFMT_SIGNED))
+ csa->pfie |= 0x8000;
+ if (ch->fmt & AFMT_BIGENDIAN)
+ csa->pfie |= 0x4000;
+ if (!(ch->fmt & AFMT_STEREO))
+ csa->pfie |= 0x2000;
+ if (ch->fmt & AFMT_8BIT)
+ csa->pfie |= 0x1000;
+ csa_writemem(resp, BA1_PFIE, csa->pfie);
+
+ tmp = 4;
+ if (ch->fmt & AFMT_16BIT)
+ tmp <<= 1;
+ if (ch->fmt & AFMT_STEREO)
+ tmp <<= 1;
+ tmp--;
+
+ pdtc = csa_readmem(resp, BA1_PDTC) & ~0x000001ff;
+ pdtc |= tmp;
+ csa_writemem(resp, BA1_PDTC, pdtc);
+
+ /* rate */
+ csa_setplaysamplerate(resp, ch->spd);
+ } else if (ch->dir == PCMDIR_REC) {
+ /* direction */
+ csa_writemem(resp, BA1_CBA, vtophys(sndbuf_getbuf(ch->buffer)));
+
+ /* format */
+ csa_writemem(resp, BA1_CIE, (csa_readmem(resp, BA1_CIE) & ~0x0000003f) | 0x00000001);
+
+ /* rate */
+ csa_setcapturesamplerate(resp, ch->spd);
+ }
+ return 0;
+}
+
/* -------------------------------------------------------------------- */
/* channel interface */
@@ -523,59 +515,16 @@ csachan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *
ch->parent = csa;
ch->channel = c;
ch->buffer = b;
+ ch->dir = dir;
if (sndbuf_alloc(ch->buffer, csa->parent_dmat, CS461x_BUFFSIZE) == -1) return NULL;
return ch;
}
static int
-csachan_setdir(kobj_t obj, void *data, int dir)
-{
- struct csa_chinfo *ch = data;
- struct csa_info *csa = ch->parent;
- csa_res *resp;
-
- resp = &csa->res;
-
- if (dir == PCMDIR_PLAY)
- csa_writemem(resp, BA1_PBA, vtophys(sndbuf_getbuf(ch->buffer)));
- else
- csa_writemem(resp, BA1_CBA, vtophys(sndbuf_getbuf(ch->buffer)));
- ch->dir = dir;
- return 0;
-}
-
-static int
csachan_setformat(kobj_t obj, void *data, u_int32_t format)
{
struct csa_chinfo *ch = data;
- struct csa_info *csa = ch->parent;
- u_long pdtc;
- csa_res *resp;
-
- resp = &csa->res;
- if (ch->dir == PCMDIR_REC)
- csa_writemem(resp, BA1_CIE, (csa_readmem(resp, BA1_CIE) & ~0x0000003f) | 0x00000001);
- else {
- csa->pfie = csa_readmem(resp, BA1_PFIE) & ~0x0000f03f;
- if (format & AFMT_U8 || format & AFMT_U16_LE || format & AFMT_U16_BE)
- csa->pfie |= 0x8000;
- if (format & AFMT_S16_BE || format & AFMT_U16_BE)
- csa->pfie |= 0x4000;
- if (!(format & AFMT_STEREO))
- csa->pfie |= 0x2000;
- if (format & AFMT_U8 || format & AFMT_S8)
- csa->pfie |= 0x1000;
- csa_writemem(resp, BA1_PFIE, csa->pfie);
- pdtc = csa_readmem(resp, BA1_PDTC) & ~0x000003ff;
- if ((format & AFMT_S16_BE || format & AFMT_U16_BE || format & AFMT_S16_LE || format & AFMT_U16_LE) && (format & AFMT_STEREO))
- pdtc |= 0x00f;
- else if ((format & AFMT_S16_BE || format & AFMT_U16_BE || format & AFMT_S16_LE || format & AFMT_U16_LE) || (format & AFMT_STEREO))
- pdtc |= 0x007;
- else
- pdtc |= 0x003;
- csa_writemem(resp, BA1_PDTC, pdtc);
- }
ch->fmt = format;
return 0;
}
@@ -584,22 +533,9 @@ static int
csachan_setspeed(kobj_t obj, void *data, u_int32_t speed)
{
struct csa_chinfo *ch = data;
- struct csa_info *csa = ch->parent;
- csa_res *resp;
-
- resp = &csa->res;
- if (ch->dir == PCMDIR_PLAY)
- csa_setplaysamplerate(resp, speed);
- else if (ch->dir == PCMDIR_REC)
- csa_setcapturesamplerate(resp, speed);
-
- /* rec/play speeds locked together - should indicate in flags */
-#if 0
- if (ch->direction == PCMDIR_PLAY) d->rec[0].speed = speed;
- else d->play[0].speed = speed;
-#endif
- return speed; /* XXX calc real speed */
+ ch->spd = speed;
+ return ch->spd; /* XXX calc real speed */
}
static int
@@ -617,16 +553,19 @@ csachan_trigger(kobj_t obj, void *data, int go)
if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD)
return 0;
- if (ch->dir == PCMDIR_PLAY) {
- if (go == PCMTRIG_START)
+ if (go == PCMTRIG_START) {
+ csa_active(csa, 1);
+ csa_setupchan(ch);
+ if (ch->dir == PCMDIR_PLAY)
csa_startplaydma(csa);
else
- csa_stopplaydma(csa);
- } else {
- if (go == PCMTRIG_START)
csa_startcapturedma(csa);
+ } else {
+ if (ch->dir == PCMDIR_PLAY)
+ csa_stopplaydma(csa);
else
csa_stopcapturedma(csa);
+ csa_active(csa, -1);
}
return 0;
}
@@ -663,7 +602,6 @@ csachan_getcaps(kobj_t obj, void *data)
static kobj_method_t csachan_methods[] = {
KOBJMETHOD(channel_init, csachan_init),
- KOBJMETHOD(channel_setdir, csachan_setdir),
KOBJMETHOD(channel_setformat, csachan_setformat),
KOBJMETHOD(channel_setspeed, csachan_setspeed),
KOBJMETHOD(channel_setblocksize, csachan_setblocksize),
@@ -677,7 +615,7 @@ CHANNEL_DECLARE(csachan);
/* -------------------------------------------------------------------- */
/* The interrupt handler */
static void
-csa_intr (void *p)
+csa_intr(void *p)
{
struct csa_info *csa = p;
@@ -704,16 +642,13 @@ csa_init(struct csa_info *csa)
csa_stopplaydma(csa);
csa_stopcapturedma(csa);
- /* Crank up the power on the DAC and ADC. */
- csa_powerupadc(resp);
- csa_powerupdac(resp);
+ if (csa_startdsp(resp))
+ return (1);
+ /* Crank up the power on the DAC and ADC. */
csa_setplaysamplerate(resp, 8000);
csa_setcapturesamplerate(resp, 8000);
- if (csa_startdsp(resp))
- return (1);
-
return 0;
}
@@ -725,12 +660,12 @@ csa_allocres(struct csa_info *csa, device_t dev)
resp = &csa->res;
if (resp->io == NULL) {
- resp->io = bus_alloc_resource(dev, SYS_RES_MEMORY, &resp->io_rid, 0, ~0, CS461x_IO_SIZE, RF_ACTIVE);
+ resp->io = bus_alloc_resource(dev, SYS_RES_MEMORY, &resp->io_rid, 0, ~0, 1, RF_ACTIVE);
if (resp->io == NULL)
return (1);
}
if (resp->mem == NULL) {
- resp->mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &resp->mem_rid, 0, ~0, CS461x_MEM_SIZE, RF_ACTIVE);
+ resp->mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &resp->mem_rid, 0, ~0, 1, RF_ACTIVE);
if (resp->mem == NULL)
return (1);
}
@@ -781,9 +716,6 @@ csa_releaseres(struct csa_info *csa, device_t dev)
}
}
-static int pcmcsa_probe(device_t dev);
-static int pcmcsa_attach(device_t dev);
-
static int
pcmcsa_probe(device_t dev)
{
@@ -825,17 +757,20 @@ pcmcsa_attach(device_t dev)
* respectively.
*/
csa->pch.dma = csa->rch.dma = 1;
+ csa->active = 0;
+ csa->card = csa->binfo->card;
/* Allocate the resources. */
resp = &csa->res;
- resp->io_rid = CS461x_IO_OFFSET;
- resp->mem_rid = CS461x_MEM_OFFSET;
+ resp->io_rid = PCIR_MAPS;
+ resp->mem_rid = PCIR_MAPS + 4;
resp->irq_rid = 0;
if (csa_allocres(csa, dev)) {
csa_releaseres(csa, dev);
return (ENXIO);
}
+ csa_active(csa, 1);
if (csa_init(csa)) {
csa_releaseres(csa, dev);
return (ENXIO);
@@ -854,13 +789,14 @@ pcmcsa_attach(device_t dev)
snprintf(status, SND_STATUSLEN, "at irq %ld", rman_get_start(resp->irq));
/* Enable interrupt. */
- if (snd_setup_intr(dev, resp->irq, 0, csa_intr, csa, &csa->ih)) {
+ if (snd_setup_intr(dev, resp->irq, INTR_MPSAFE, csa_intr, csa, &csa->ih)) {
ac97_destroy(codec);
csa_releaseres(csa, dev);
return (ENXIO);
}
csa_writemem(resp, BA1_PFIE, csa_readmem(resp, BA1_PFIE) & ~0x0000f03f);
csa_writemem(resp, BA1_CIE, (csa_readmem(resp, BA1_CIE) & ~0x0000003f) | 0x00000001);
+ csa_active(csa, -1);
if (pcm_register(dev, csa, 1, 1)) {
ac97_destroy(codec);
diff --git a/sys/dev/sound/pci/csareg.h b/sys/dev/sound/pci/csareg.h
index 9fd68d8..8ed292a 100644
--- a/sys/dev/sound/pci/csareg.h
+++ b/sys/dev/sound/pci/csareg.h
@@ -33,23 +33,6 @@
#ifndef _CSA_REG_H
#define _CSA_REG_H
-/* This is the pci device id. */
-#define CS4610_PCI_ID 0x60011013
-#define CS4614_PCI_ID 0x60031013
-#define CS4615_PCI_ID 0x60041013
-#define CS4281_PCI_ID 0x60051013
-
-/* And the offsets in pci configuration space. */
-#define CS461x_IO_OFFSET 0x10
-#define CS461x_IO_SIZE (4 * 1024)
-#define CS461x_MEM_OFFSET 0x14
-#define CS461x_MEM_SIZE (1024 * 1024)
-
-/* Buffer size on dma transfer. Fixed for CS416x. */
-#define CS461x_BUFFSIZE (4 * 1024)
-
-#define GOF_PER_SEC 200
-
/*
* The following constats are orginally in the sample by Crystal Semiconductor.
* Copyright (c) 1996-1998 Crystal Semiconductor Corp.
diff --git a/sys/dev/sound/pci/csavar.h b/sys/dev/sound/pci/csavar.h
index fef2ce8..e2055a4 100644
--- a/sys/dev/sound/pci/csavar.h
+++ b/sys/dev/sound/pci/csavar.h
@@ -28,6 +28,13 @@
#ifndef _CSA_VAR_H
#define _CSA_VAR_H
+struct csa_card {
+ u_int16_t subvendor, subdevice;
+ char *name;
+ void *amp;
+ void *amp_init;
+ int (*active)(int);
+};
/* Resources. */
struct csa_res {
@@ -43,11 +50,13 @@ typedef struct csa_res csa_res;
/* State of the bridge. */
struct csa_bridgeinfo {
u_int32_t hisr; /* The value of HISR on this interrupt. */
+ struct csa_card *card;
};
void csa_clearserialfifos(csa_res *resp);
/* Common functions for csa. */
+struct csa_card *csa_findsubcard(device_t dev);
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