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:
parent
10a31b01bf
commit
20ac1df714
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=77504
@ -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),
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user