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.
This commit is contained in:
Cameron Grant 2001-05-30 22:38:31 +00:00
parent 10a31b01bf
commit 20ac1df714
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=77504
4 changed files with 316 additions and 261 deletions

View File

@ -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
clkrun_hack(int run)
{
#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;
}
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;
}
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];
}
static int
csa_probe(device_t dev)
{
char *s;
struct card_type *card;
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;
card = csa_findcard(dev);
if (card) {
device_set_desc(dev, card->name);
return 0;
}
if (s != NULL) {
device_set_desc(dev, s);
return (0);
}
return (ENXIO);
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),

View File

@ -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);
@ -102,6 +107,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 */
@ -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);
csa_setplaysamplerate(resp, 8000);
csa_setcapturesamplerate(resp, 8000);
if (csa_startdsp(resp))
return (1);
/* Crank up the power on the DAC and ADC. */
csa_setplaysamplerate(resp, 8000);
csa_setcapturesamplerate(resp, 8000);
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);

View File

@ -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.

View File

@ -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);