1139749Simp/*-
253553Stanimura * Copyright (c) 1999 Seigo Tanimura
353553Stanimura * All rights reserved.
453553Stanimura *
554377Stanimura * Portions of this source are based on cwcealdr.cpp and dhwiface.cpp in
654377Stanimura * cwcealdr1.zip, the sample sources by Crystal Semiconductor.
754377Stanimura * Copyright (c) 1996-1998 Crystal Semiconductor Corp.
854377Stanimura *
953553Stanimura * Redistribution and use in source and binary forms, with or without
1053553Stanimura * modification, are permitted provided that the following conditions
1153553Stanimura * are met:
1253553Stanimura * 1. Redistributions of source code must retain the above copyright
1353553Stanimura *    notice, this list of conditions and the following disclaimer.
1453553Stanimura * 2. Redistributions in binary form must reproduce the above copyright
1553553Stanimura *    notice, this list of conditions and the following disclaimer in the
1653553Stanimura *    documentation and/or other materials provided with the distribution.
1753553Stanimura *
1853553Stanimura * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1953553Stanimura * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2053553Stanimura * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2153553Stanimura * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2253553Stanimura * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2353553Stanimura * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2453553Stanimura * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2553553Stanimura * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2653553Stanimura * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2753553Stanimura * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2853553Stanimura * SUCH DAMAGE.
2953553Stanimura */
3053553Stanimura
3153553Stanimura#include <sys/param.h>
3253553Stanimura#include <sys/systm.h>
3353553Stanimura#include <sys/kernel.h>
3453553Stanimura#include <sys/bus.h>
3553553Stanimura#include <sys/malloc.h>
3653553Stanimura#include <sys/module.h>
3753553Stanimura#include <machine/resource.h>
3853553Stanimura#include <machine/bus.h>
3953553Stanimura#include <sys/rman.h>
40193640Sariff
41193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS
42193640Sariff#include "opt_snd.h"
43193640Sariff#endif
44193640Sariff
4562483Scg#include <dev/sound/pcm/sound.h>
4653553Stanimura#include <dev/sound/chip.h>
4753553Stanimura#include <dev/sound/pci/csareg.h>
4853553Stanimura#include <dev/sound/pci/csavar.h>
4953553Stanimura
50119287Simp#include <dev/pci/pcireg.h>
51119287Simp#include <dev/pci/pcivar.h>
5253553Stanimura
53230897Spfg#include <dev/sound/pci/cs461x_dsp.h>
5453553Stanimura
5582180ScgSND_DECLARE_FILE("$FreeBSD: stable/10/sys/dev/sound/pci/csa.c 339297 2018-10-10 22:51:45Z avatar $");
5682180Scg
5777504Scg/* This is the pci device id. */
5877504Scg#define CS4610_PCI_ID 0x60011013
5977504Scg#define CS4614_PCI_ID 0x60031013
6077504Scg#define CS4615_PCI_ID 0x60041013
6177504Scg
6253553Stanimura/* Here is the parameter structure per a device. */
6353553Stanimurastruct csa_softc {
6453553Stanimura	device_t dev; /* device */
6553553Stanimura	csa_res res; /* resources */
6653553Stanimura
6753553Stanimura	device_t pcm; /* pcm device */
6853553Stanimura	driver_intr_t* pcmintr; /* pcm intr */
6953553Stanimura	void *pcmintr_arg; /* pcm intr arg */
7053553Stanimura	device_t midi; /* midi device */
7153553Stanimura	driver_intr_t* midiintr; /* midi intr */
7253553Stanimura	void *midiintr_arg; /* midi intr arg */
7353553Stanimura	void *ih; /* cookie */
7455320Stanimura
7577504Scg	struct csa_card *card;
7655320Stanimura	struct csa_bridgeinfo binfo; /* The state of this bridge. */
7753553Stanimura};
7853553Stanimura
7953553Stanimuratypedef struct csa_softc *sc_p;
8053553Stanimura
8153553Stanimurastatic int csa_probe(device_t dev);
8253553Stanimurastatic int csa_attach(device_t dev);
8353553Stanimurastatic struct resource *csa_alloc_resource(device_t bus, device_t child, int type, int *rid,
8453553Stanimura					      u_long start, u_long end, u_long count, u_int flags);
8553553Stanimurastatic int csa_release_resource(device_t bus, device_t child, int type, int rid,
8653553Stanimura				   struct resource *r);
8755320Stanimurastatic int csa_setup_intr(device_t bus, device_t child,
8855320Stanimura			  struct resource *irq, int flags,
89166918Sariff#if __FreeBSD_version >= 700031
90166918Sariff			  driver_filter_t *filter,
91166918Sariff#endif
92166918Sariff			  driver_intr_t *intr,  void *arg, void **cookiep);
9355320Stanimurastatic int csa_teardown_intr(device_t bus, device_t child,
9455320Stanimura			     struct resource *irq, void *cookie);
9555320Stanimurastatic driver_intr_t csa_intr;
9653553Stanimurastatic int csa_initialize(sc_p scp);
9753553Stanimurastatic int csa_downloadimage(csa_res *resp);
98230897Spfgstatic int csa_transferimage(csa_res *resp, u_int32_t *src, u_long dest, u_long len);
9953553Stanimura
10053553Stanimurastatic devclass_t csa_devclass;
10153553Stanimura
10277504Scgstatic void
10377504Scgamp_none(void)
10477504Scg{
10577504Scg}
10677504Scg
10777504Scgstatic void
10877504Scgamp_voyetra(void)
10977504Scg{
11077504Scg}
11177504Scg
11253553Stanimurastatic int
11377504Scgclkrun_hack(int run)
11453553Stanimura{
11577504Scg#ifdef __i386__
11677504Scg	devclass_t		pci_devclass;
11777504Scg	device_t		*pci_devices, *pci_children, *busp, *childp;
11877504Scg	int			pci_count = 0, pci_childcount = 0;
11977504Scg	int			i, j, port;
12077504Scg	u_int16_t		control;
12177504Scg	bus_space_tag_t		btag;
12253553Stanimura
12377504Scg	if ((pci_devclass = devclass_find("pci")) == NULL) {
12477504Scg		return ENXIO;
12553553Stanimura	}
12653553Stanimura
12777504Scg	devclass_get_devices(pci_devclass, &pci_devices, &pci_count);
12877504Scg
12977504Scg	for (i = 0, busp = pci_devices; i < pci_count; i++, busp++) {
13077504Scg		pci_childcount = 0;
131182077Simp		if (device_get_children(*busp, &pci_children, &pci_childcount))
132182077Simp			continue;
13377504Scg		for (j = 0, childp = pci_children; j < pci_childcount; j++, childp++) {
13477504Scg			if (pci_get_vendor(*childp) == 0x8086 && pci_get_device(*childp) == 0x7113) {
13577504Scg				port = (pci_read_config(*childp, 0x41, 1) << 8) + 0x10;
13677504Scg				/* XXX */
137216592Stijl				btag = X86_BUS_SPACE_IO;
13877504Scg
13977504Scg				control = bus_space_read_2(btag, 0x0, port);
14077504Scg				control &= ~0x2000;
14177504Scg				control |= run? 0 : 0x2000;
14277504Scg				bus_space_write_2(btag, 0x0, port, control);
14378429Scg				free(pci_devices, M_TEMP);
14478429Scg				free(pci_children, M_TEMP);
14577504Scg				return 0;
14677504Scg			}
14777504Scg		}
14878429Scg		free(pci_children, M_TEMP);
14953553Stanimura	}
15053553Stanimura
15177504Scg	free(pci_devices, M_TEMP);
15277504Scg	return ENXIO;
15377504Scg#else
15477504Scg	return 0;
15577504Scg#endif
15653553Stanimura}
15753553Stanimura
15877504Scgstatic struct csa_card cards_4610[] = {
15978673Scg	{0, 0, "Unknown/invalid SSID (CS4610)", NULL, NULL, NULL, 0},
16077504Scg};
16177504Scg
16277504Scgstatic struct csa_card cards_4614[] = {
16378673Scg	{0x1489, 0x7001, "Genius Soundmaker 128 value", amp_none, NULL, NULL, 0},
16478673Scg	{0x5053, 0x3357, "Turtle Beach Santa Cruz", amp_voyetra, NULL, NULL, 1},
16578673Scg	{0x1071, 0x6003, "Mitac MI6020/21", amp_voyetra, NULL, NULL, 0},
16678673Scg	{0x14AF, 0x0050, "Hercules Game Theatre XP", NULL, NULL, NULL, 0},
16778673Scg	{0x1681, 0x0050, "Hercules Game Theatre XP", NULL, NULL, NULL, 0},
16886409Sasmodai	{0x1014, 0x0132, "Thinkpad 570", amp_none, NULL, NULL, 0},
16978673Scg	{0x1014, 0x0153, "Thinkpad 600X/A20/T20", amp_none, NULL, clkrun_hack, 0},
17078673Scg	{0x1014, 0x1010, "Thinkpad 600E (unsupported)", NULL, NULL, NULL, 0},
171339297Savatar	{0x153b, 0x1136, "Terratec SiXPack 5.1+", NULL, NULL, NULL, 0},
17278673Scg	{0, 0, "Unknown/invalid SSID (CS4614)", NULL, NULL, NULL, 0},
17377504Scg};
17477504Scg
17577504Scgstatic struct csa_card cards_4615[] = {
17678673Scg	{0, 0, "Unknown/invalid SSID (CS4615)", NULL, NULL, NULL, 0},
17777504Scg};
17877504Scg
17978673Scgstatic struct csa_card nocard = {0, 0, "unknown", NULL, NULL, NULL, 0};
18077504Scg
18177504Scgstruct card_type {
18277504Scg	u_int32_t devid;
18377504Scg	char *name;
18477504Scg	struct csa_card *cards;
18577504Scg};
18677504Scg
18777504Scgstatic struct card_type cards[] = {
18877504Scg	{CS4610_PCI_ID, "CS4610/CS4611", cards_4610},
18977504Scg	{CS4614_PCI_ID, "CS4280/CS4614/CS4622/CS4624/CS4630", cards_4614},
19077504Scg	{CS4615_PCI_ID, "CS4615", cards_4615},
19177504Scg	{0, NULL, NULL},
19277504Scg};
19377504Scg
19477504Scgstatic struct card_type *
19577504Scgcsa_findcard(device_t dev)
19677504Scg{
19777504Scg	int i;
19877504Scg
19977504Scg	i = 0;
20077504Scg	while (cards[i].devid != 0) {
20177504Scg		if (pci_get_devid(dev) == cards[i].devid)
20277504Scg			return &cards[i];
20377504Scg		i++;
20477504Scg	}
20577504Scg	return NULL;
20677504Scg}
20777504Scg
20877504Scgstruct csa_card *
20977504Scgcsa_findsubcard(device_t dev)
21077504Scg{
21177504Scg	int i;
21277504Scg	struct card_type *card;
21377504Scg	struct csa_card *subcard;
21477504Scg
21577504Scg	card = csa_findcard(dev);
21677504Scg	if (card == NULL)
21777504Scg		return &nocard;
21877504Scg	subcard = card->cards;
21977504Scg	i = 0;
22077504Scg	while (subcard[i].subvendor != 0) {
22177504Scg		if (pci_get_subvendor(dev) == subcard[i].subvendor
22277504Scg		    && pci_get_subdevice(dev) == subcard[i].subdevice) {
22377504Scg			return &subcard[i];
22477504Scg		}
22577504Scg		i++;
22677504Scg	}
22777504Scg	return &subcard[i];
22877504Scg}
22977504Scg
23053553Stanimurastatic int
23177504Scgcsa_probe(device_t dev)
23277504Scg{
23377504Scg	struct card_type *card;
23477504Scg
23577504Scg	card = csa_findcard(dev);
23677504Scg	if (card) {
23777504Scg		device_set_desc(dev, card->name);
238142890Simp		return BUS_PROBE_DEFAULT;
23977504Scg	}
24077504Scg	return ENXIO;
24177504Scg}
24277504Scg
24377504Scgstatic int
24453553Stanimuracsa_attach(device_t dev)
24553553Stanimura{
24653553Stanimura	sc_p scp;
24753553Stanimura	csa_res *resp;
24855320Stanimura	struct sndcard_func *func;
24978421Stmm	int error = ENXIO;
25053553Stanimura
25153553Stanimura	scp = device_get_softc(dev);
25253553Stanimura
25353553Stanimura	/* Fill in the softc. */
25453553Stanimura	bzero(scp, sizeof(*scp));
25553553Stanimura	scp->dev = dev;
25653553Stanimura
257254263Sscottl	pci_enable_busmaster(dev);
25853553Stanimura
25953553Stanimura	/* Allocate the resources. */
26053553Stanimura	resp = &scp->res;
26177504Scg	scp->card = csa_findsubcard(dev);
26277504Scg	scp->binfo.card = scp->card;
26377504Scg	printf("csa: card is %s\n", scp->card->name);
264119690Sjhb	resp->io_rid = PCIR_BAR(0);
265127135Snjl	resp->io = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
266127135Snjl		&resp->io_rid, RF_ACTIVE);
26753553Stanimura	if (resp->io == NULL)
26853553Stanimura		return (ENXIO);
269119690Sjhb	resp->mem_rid = PCIR_BAR(1);
270127135Snjl	resp->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
271127135Snjl		&resp->mem_rid, RF_ACTIVE);
27278421Stmm	if (resp->mem == NULL)
27378421Stmm		goto err_io;
27453553Stanimura	resp->irq_rid = 0;
275127135Snjl	resp->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
276127135Snjl		&resp->irq_rid, RF_ACTIVE | RF_SHAREABLE);
27778421Stmm	if (resp->irq == NULL)
27878421Stmm		goto err_mem;
27953553Stanimura
28055320Stanimura	/* Enable interrupt. */
281128232Sgreen	if (snd_setup_intr(dev, resp->irq, 0, csa_intr, scp, &scp->ih))
28278421Stmm		goto err_intr;
28377504Scg#if 0
28455320Stanimura	if ((csa_readio(resp, BA0_HISR) & HISR_INTENA) == 0)
28555320Stanimura		csa_writeio(resp, BA0_HICR, HICR_IEV | HICR_CHGM);
28677504Scg#endif
28755320Stanimura
28853553Stanimura	/* Initialize the chip. */
28978421Stmm	if (csa_initialize(scp))
29078421Stmm		goto err_teardown;
29153553Stanimura
29253553Stanimura	/* Reset the Processor. */
29353553Stanimura	csa_resetdsp(resp);
29453553Stanimura
29553553Stanimura	/* Download the Processor Image to the processor. */
29678421Stmm	if (csa_downloadimage(resp))
29778421Stmm		goto err_teardown;
29853553Stanimura
29955320Stanimura	/* Attach the children. */
30055320Stanimura
30155320Stanimura	/* PCM Audio */
30278564Sgreid	func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO);
30378421Stmm	if (func == NULL) {
30478421Stmm		error = ENOMEM;
30578421Stmm		goto err_teardown;
30678421Stmm	}
30755320Stanimura	func->varinfo = &scp->binfo;
30855320Stanimura	func->func = SCF_PCM;
30955320Stanimura	scp->pcm = device_add_child(dev, "pcm", -1);
31055320Stanimura	device_set_ivars(scp->pcm, func);
31155320Stanimura
31255320Stanimura	/* Midi Interface */
31378564Sgreid	func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO);
31478421Stmm	if (func == NULL) {
31578421Stmm		error = ENOMEM;
31678421Stmm		goto err_teardown;
31778421Stmm	}
31855320Stanimura	func->varinfo = &scp->binfo;
31955320Stanimura	func->func = SCF_MIDI;
32055320Stanimura	scp->midi = device_add_child(dev, "midi", -1);
32155320Stanimura	device_set_ivars(scp->midi, func);
32255320Stanimura
32353553Stanimura	bus_generic_attach(dev);
32453553Stanimura
32553553Stanimura	return (0);
32678421Stmm
32778421Stmmerr_teardown:
32878421Stmm	bus_teardown_intr(dev, resp->irq, scp->ih);
32978421Stmmerr_intr:
33078421Stmm	bus_release_resource(dev, SYS_RES_IRQ, resp->irq_rid, resp->irq);
33178421Stmmerr_mem:
33278421Stmm	bus_release_resource(dev, SYS_RES_MEMORY, resp->mem_rid, resp->mem);
33378421Stmmerr_io:
33478421Stmm	bus_release_resource(dev, SYS_RES_MEMORY, resp->io_rid, resp->io);
33578421Stmm	return (error);
33653553Stanimura}
33753553Stanimura
33877504Scgstatic int
33977504Scgcsa_detach(device_t dev)
34077504Scg{
34182379Scg	csa_res *resp;
34277504Scg	sc_p scp;
343167667Sariff	struct sndcard_func *func;
34482379Scg	int err;
34577504Scg
34677504Scg	scp = device_get_softc(dev);
34782379Scg	resp = &scp->res;
34882379Scg
349167667Sariff	if (scp->midi != NULL) {
350167667Sariff		func = device_get_ivars(scp->midi);
35182379Scg		err = device_delete_child(dev, scp->midi);
352167667Sariff		if (err != 0)
353167667Sariff			return err;
354167667Sariff		if (func != NULL)
355167667Sariff			free(func, M_DEVBUF);
356167667Sariff		scp->midi = NULL;
357167667Sariff	}
35882379Scg
359167667Sariff	if (scp->pcm != NULL) {
360167667Sariff		func = device_get_ivars(scp->pcm);
36182379Scg		err = device_delete_child(dev, scp->pcm);
362167667Sariff		if (err != 0)
363167667Sariff			return err;
364167667Sariff		if (func != NULL)
365167667Sariff			free(func, M_DEVBUF);
366167667Sariff		scp->pcm = NULL;
367167667Sariff	}
36882379Scg
36982379Scg	bus_teardown_intr(dev, resp->irq, scp->ih);
37082379Scg	bus_release_resource(dev, SYS_RES_IRQ, resp->irq_rid, resp->irq);
37182379Scg	bus_release_resource(dev, SYS_RES_MEMORY, resp->mem_rid, resp->mem);
37282379Scg	bus_release_resource(dev, SYS_RES_MEMORY, resp->io_rid, resp->io);
37382379Scg
37477504Scg	return bus_generic_detach(dev);
37577504Scg}
37677504Scg
377100634Sambriskostatic int
378100634Sambriskocsa_resume(device_t dev)
379100634Sambrisko{
380147626Sglebius	csa_res *resp;
381147626Sglebius	sc_p scp;
382147626Sglebius
383147626Sglebius	scp = device_get_softc(dev);
384147626Sglebius	resp = &scp->res;
385147626Sglebius
386147626Sglebius	/* Initialize the chip. */
387147626Sglebius	if (csa_initialize(scp))
388147626Sglebius		return (ENXIO);
389147626Sglebius
390147626Sglebius	/* Reset the Processor. */
391147626Sglebius	csa_resetdsp(resp);
392147626Sglebius
393147626Sglebius	/* Download the Processor Image to the processor. */
394147626Sglebius	if (csa_downloadimage(resp))
395147626Sglebius		return (ENXIO);
396147626Sglebius
397147626Sglebius	return (bus_generic_resume(dev));
398100634Sambrisko}
399100634Sambrisko
40053553Stanimurastatic struct resource *
40153553Stanimuracsa_alloc_resource(device_t bus, device_t child, int type, int *rid,
40253553Stanimura		      u_long start, u_long end, u_long count, u_int flags)
40353553Stanimura{
40453553Stanimura	sc_p scp;
40553553Stanimura	csa_res *resp;
40653553Stanimura	struct resource *res;
40753553Stanimura
40853553Stanimura	scp = device_get_softc(bus);
40953553Stanimura	resp = &scp->res;
41053553Stanimura	switch (type) {
41153553Stanimura	case SYS_RES_IRQ:
41253553Stanimura		if (*rid != 0)
41353553Stanimura			return (NULL);
41453553Stanimura		res = resp->irq;
41553553Stanimura		break;
41653553Stanimura	case SYS_RES_MEMORY:
41753553Stanimura		switch (*rid) {
418119690Sjhb		case PCIR_BAR(0):
41953553Stanimura			res = resp->io;
42053553Stanimura			break;
421119690Sjhb		case PCIR_BAR(1):
42253553Stanimura			res = resp->mem;
42353553Stanimura			break;
42453553Stanimura		default:
42553553Stanimura			return (NULL);
42653553Stanimura		}
42753553Stanimura		break;
42853553Stanimura	default:
42953553Stanimura		return (NULL);
43053553Stanimura	}
43153553Stanimura
43253553Stanimura	return res;
43353553Stanimura}
43453553Stanimura
43553553Stanimurastatic int
43653553Stanimuracsa_release_resource(device_t bus, device_t child, int type, int rid,
43753553Stanimura			struct resource *r)
43853553Stanimura{
43953553Stanimura	return (0);
44053553Stanimura}
44153553Stanimura
44255320Stanimura/*
44355320Stanimura * The following three functions deal with interrupt handling.
44455320Stanimura * An interrupt is primarily handled by the bridge driver.
44555320Stanimura * The bridge driver then determines the child devices to pass
44655320Stanimura * the interrupt. Certain information of the device can be read
44755320Stanimura * only once(eg the value of HISR). The bridge driver is responsible
44855320Stanimura * to pass such the information to the children.
44955320Stanimura */
45055320Stanimura
45153553Stanimurastatic int
45255320Stanimuracsa_setup_intr(device_t bus, device_t child,
45355320Stanimura	       struct resource *irq, int flags,
454166918Sariff#if __FreeBSD_version >= 700031
455166918Sariff	       driver_filter_t *filter,
456166918Sariff#endif
457166918Sariff	       driver_intr_t *intr, void *arg, void **cookiep)
45855320Stanimura{
45955320Stanimura	sc_p scp;
46055320Stanimura	csa_res *resp;
46155320Stanimura	struct sndcard_func *func;
46255320Stanimura
463166918Sariff#if __FreeBSD_version >= 700031
464166901Spiso	if (filter != NULL) {
465166901Spiso		printf("ata-csa.c: we cannot use a filter here\n");
466166901Spiso		return (EINVAL);
467166901Spiso	}
468166918Sariff#endif
46955320Stanimura	scp = device_get_softc(bus);
47055320Stanimura	resp = &scp->res;
47155320Stanimura
47255320Stanimura	/*
47355320Stanimura	 * Look at the function code of the child to determine
47455320Stanimura	 * the appropriate hander for it.
47555320Stanimura	 */
47655320Stanimura	func = device_get_ivars(child);
47755320Stanimura	if (func == NULL || irq != resp->irq)
47855320Stanimura		return (EINVAL);
47955320Stanimura
48055320Stanimura	switch (func->func) {
48155320Stanimura	case SCF_PCM:
48255320Stanimura		scp->pcmintr = intr;
48355320Stanimura		scp->pcmintr_arg = arg;
48455320Stanimura		break;
48555320Stanimura
48655320Stanimura	case SCF_MIDI:
48755320Stanimura		scp->midiintr = intr;
48855320Stanimura		scp->midiintr_arg = arg;
48955320Stanimura		break;
49055320Stanimura
49155320Stanimura	default:
49255320Stanimura		return (EINVAL);
49355320Stanimura	}
49455320Stanimura	*cookiep = scp;
49555320Stanimura	if ((csa_readio(resp, BA0_HISR) & HISR_INTENA) == 0)
49655320Stanimura		csa_writeio(resp, BA0_HICR, HICR_IEV | HICR_CHGM);
49755320Stanimura
49855320Stanimura	return (0);
49955320Stanimura}
50055320Stanimura
50155320Stanimurastatic int
50255320Stanimuracsa_teardown_intr(device_t bus, device_t child,
50355320Stanimura		  struct resource *irq, void *cookie)
50455320Stanimura{
50555320Stanimura	sc_p scp;
50655320Stanimura	csa_res *resp;
50755320Stanimura	struct sndcard_func *func;
50855320Stanimura
50955320Stanimura	scp = device_get_softc(bus);
51055320Stanimura	resp = &scp->res;
51155320Stanimura
51255320Stanimura	/*
51355320Stanimura	 * Look at the function code of the child to determine
51455320Stanimura	 * the appropriate hander for it.
51555320Stanimura	 */
51655320Stanimura	func = device_get_ivars(child);
51755320Stanimura	if (func == NULL || irq != resp->irq || cookie != scp)
51855320Stanimura		return (EINVAL);
51955320Stanimura
52055320Stanimura	switch (func->func) {
52155320Stanimura	case SCF_PCM:
52255320Stanimura		scp->pcmintr = NULL;
52355320Stanimura		scp->pcmintr_arg = NULL;
52455320Stanimura		break;
52555320Stanimura
52655320Stanimura	case SCF_MIDI:
52755320Stanimura		scp->midiintr = NULL;
52855320Stanimura		scp->midiintr_arg = NULL;
52955320Stanimura		break;
53055320Stanimura
53155320Stanimura	default:
53255320Stanimura		return (EINVAL);
53355320Stanimura	}
53455320Stanimura
53555320Stanimura	return (0);
53655320Stanimura}
53755320Stanimura
53855320Stanimura/* The interrupt handler */
53955320Stanimurastatic void
54055320Stanimuracsa_intr(void *arg)
54155320Stanimura{
54255320Stanimura	sc_p scp = arg;
54355320Stanimura	csa_res *resp;
54455320Stanimura	u_int32_t hisr;
54555320Stanimura
54655320Stanimura	resp = &scp->res;
54755320Stanimura
54855320Stanimura	/* Is this interrupt for us? */
54955320Stanimura	hisr = csa_readio(resp, BA0_HISR);
55077504Scg	if ((hisr & 0x7fffffff) == 0) {
55155320Stanimura		/* Throw an eoi. */
55255320Stanimura		csa_writeio(resp, BA0_HICR, HICR_IEV | HICR_CHGM);
55355320Stanimura		return;
55455320Stanimura	}
55555320Stanimura
55655320Stanimura	/*
55755320Stanimura	 * Pass the value of HISR via struct csa_bridgeinfo.
55855320Stanimura	 * The children get access through their ivars.
55955320Stanimura	 */
56055320Stanimura	scp->binfo.hisr = hisr;
56155320Stanimura
56255320Stanimura	/* Invoke the handlers of the children. */
56377504Scg	if ((hisr & (HISR_VC0 | HISR_VC1)) != 0 && scp->pcmintr != NULL) {
56455320Stanimura		scp->pcmintr(scp->pcmintr_arg);
56577504Scg		hisr &= ~(HISR_VC0 | HISR_VC1);
56677504Scg	}
56777504Scg	if ((hisr & HISR_MIDI) != 0 && scp->midiintr != NULL) {
56855320Stanimura		scp->midiintr(scp->midiintr_arg);
56977504Scg		hisr &= ~HISR_MIDI;
57077504Scg	}
57155320Stanimura
57255320Stanimura	/* Throw an eoi. */
57355320Stanimura	csa_writeio(resp, BA0_HICR, HICR_IEV | HICR_CHGM);
57455320Stanimura}
57555320Stanimura
57655320Stanimurastatic int
57753553Stanimuracsa_initialize(sc_p scp)
57853553Stanimura{
57953553Stanimura	int i;
58053553Stanimura	u_int32_t acsts, acisv;
58153553Stanimura	csa_res *resp;
58253553Stanimura
58353553Stanimura	resp = &scp->res;
58453553Stanimura
58553553Stanimura	/*
58653553Stanimura	 * First, blast the clock control register to zero so that the PLL starts
58753553Stanimura	 * out in a known state, and blast the master serial port control register
58853553Stanimura	 * to zero so that the serial ports also start out in a known state.
58953553Stanimura	 */
59053553Stanimura	csa_writeio(resp, BA0_CLKCR1, 0);
59153553Stanimura	csa_writeio(resp, BA0_SERMC1, 0);
59253553Stanimura
59353553Stanimura	/*
59453553Stanimura	 * If we are in AC97 mode, then we must set the part to a host controlled
59553553Stanimura	 * AC-link.  Otherwise, we won't be able to bring up the link.
59653553Stanimura	 */
59753553Stanimura#if 1
59853553Stanimura	csa_writeio(resp, BA0_SERACC, SERACC_HSP | SERACC_CODEC_TYPE_1_03); /* 1.03 codec */
59953553Stanimura#else
60053553Stanimura	csa_writeio(resp, BA0_SERACC, SERACC_HSP | SERACC_CODEC_TYPE_2_0); /* 2.0 codec */
60153553Stanimura#endif /* 1 */
60253553Stanimura
60353553Stanimura	/*
60453553Stanimura	 * Drive the ARST# pin low for a minimum of 1uS (as defined in the AC97
60553553Stanimura	 * spec) and then drive it high.  This is done for non AC97 modes since
60653553Stanimura	 * there might be logic external to the CS461x that uses the ARST# line
60753553Stanimura	 * for a reset.
60853553Stanimura	 */
60977504Scg	csa_writeio(resp, BA0_ACCTL, 1);
61077504Scg	DELAY(50);
61153553Stanimura	csa_writeio(resp, BA0_ACCTL, 0);
61277504Scg	DELAY(50);
61353553Stanimura	csa_writeio(resp, BA0_ACCTL, ACCTL_RSTN);
61453553Stanimura
61553553Stanimura	/*
61653553Stanimura	 * The first thing we do here is to enable sync generation.  As soon
61753553Stanimura	 * as we start receiving bit clock, we'll start producing the SYNC
61853553Stanimura	 * signal.
61953553Stanimura	 */
62053553Stanimura	csa_writeio(resp, BA0_ACCTL, ACCTL_ESYN | ACCTL_RSTN);
62153553Stanimura
62253553Stanimura	/*
62353553Stanimura	 * Now wait for a short while to allow the AC97 part to start
62453553Stanimura	 * generating bit clock (so we don't try to start the PLL without an
62553553Stanimura	 * input clock).
62653553Stanimura	 */
62753553Stanimura	DELAY(50000);
62853553Stanimura
62953553Stanimura	/*
63053553Stanimura	 * Set the serial port timing configuration, so that
63153553Stanimura	 * the clock control circuit gets its clock from the correct place.
63253553Stanimura	 */
63353553Stanimura	csa_writeio(resp, BA0_SERMC1, SERMC1_PTC_AC97);
63477504Scg	DELAY(700000);
63553553Stanimura
63653553Stanimura	/*
63753553Stanimura	 * Write the selected clock control setup to the hardware.  Do not turn on
63853553Stanimura	 * SWCE yet (if requested), so that the devices clocked by the output of
63953553Stanimura	 * PLL are not clocked until the PLL is stable.
64053553Stanimura	 */
64153553Stanimura	csa_writeio(resp, BA0_PLLCC, PLLCC_LPF_1050_2780_KHZ | PLLCC_CDR_73_104_MHZ);
64253553Stanimura	csa_writeio(resp, BA0_PLLM, 0x3a);
64353553Stanimura	csa_writeio(resp, BA0_CLKCR2, CLKCR2_PDIVS_8);
64453553Stanimura
64553553Stanimura	/*
64653553Stanimura	 * Power up the PLL.
64753553Stanimura	 */
64853553Stanimura	csa_writeio(resp, BA0_CLKCR1, CLKCR1_PLLP);
64953553Stanimura
65053553Stanimura	/*
65153553Stanimura	 * Wait until the PLL has stabilized.
65253553Stanimura	 */
65377504Scg	DELAY(5000);
65453553Stanimura
65553553Stanimura	/*
65653553Stanimura	 * Turn on clocking of the core so that we can setup the serial ports.
65753553Stanimura	 */
65853553Stanimura	csa_writeio(resp, BA0_CLKCR1, csa_readio(resp, BA0_CLKCR1) | CLKCR1_SWCE);
65953553Stanimura
66053553Stanimura	/*
66153553Stanimura	 * Fill the serial port FIFOs with silence.
66253553Stanimura	 */
66353553Stanimura	csa_clearserialfifos(resp);
66453553Stanimura
66553553Stanimura	/*
66653553Stanimura	 * Set the serial port FIFO pointer to the first sample in the FIFO.
66753553Stanimura	 */
668153084Sru#ifdef notdef
66953553Stanimura	csa_writeio(resp, BA0_SERBSP, 0);
67053553Stanimura#endif /* notdef */
67153553Stanimura
67253553Stanimura	/*
67353553Stanimura	 *  Write the serial port configuration to the part.  The master
67453553Stanimura	 *  enable bit is not set until all other values have been written.
67553553Stanimura	 */
67653553Stanimura	csa_writeio(resp, BA0_SERC1, SERC1_SO1F_AC97 | SERC1_SO1EN);
67753553Stanimura	csa_writeio(resp, BA0_SERC2, SERC2_SI1F_AC97 | SERC1_SO1EN);
67853553Stanimura	csa_writeio(resp, BA0_SERMC1, SERMC1_PTC_AC97 | SERMC1_MSPE);
67953553Stanimura
68053553Stanimura	/*
68153553Stanimura	 * Wait for the codec ready signal from the AC97 codec.
68253553Stanimura	 */
68353553Stanimura	acsts = 0;
68453553Stanimura	for (i = 0 ; i < 1000 ; i++) {
68553553Stanimura		/*
68653553Stanimura		 * First, lets wait a short while to let things settle out a bit,
68753553Stanimura		 * and to prevent retrying the read too quickly.
68853553Stanimura		 */
68955288Stanimura		DELAY(125);
69053553Stanimura
69153553Stanimura		/*
69253553Stanimura		 * Read the AC97 status register to see if we've seen a CODEC READY
69353553Stanimura		 * signal from the AC97 codec.
69453553Stanimura		 */
69553553Stanimura		acsts = csa_readio(resp, BA0_ACSTS);
69653553Stanimura		if ((acsts & ACSTS_CRDY) != 0)
69753553Stanimura			break;
69853553Stanimura	}
69953553Stanimura
70053553Stanimura	/*
70153553Stanimura	 * Make sure we sampled CODEC READY.
70253553Stanimura	 */
70353553Stanimura	if ((acsts & ACSTS_CRDY) == 0)
70453553Stanimura		return (ENXIO);
70553553Stanimura
70653553Stanimura	/*
70753553Stanimura	 * Assert the vaid frame signal so that we can start sending commands
70853553Stanimura	 * to the AC97 codec.
70953553Stanimura	 */
71053553Stanimura	csa_writeio(resp, BA0_ACCTL, ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN);
71153553Stanimura
71253553Stanimura	/*
71353553Stanimura	 * Wait until we've sampled input slots 3 and 4 as valid, meaning that
71453553Stanimura	 * the codec is pumping ADC data across the AC-link.
71553553Stanimura	 */
71653553Stanimura	acisv = 0;
717338326Savatar	for (i = 0 ; i < 2000 ; i++) {
71853553Stanimura		/*
71953553Stanimura		 * First, lets wait a short while to let things settle out a bit,
72053553Stanimura		 * and to prevent retrying the read too quickly.
72153553Stanimura		 */
722153084Sru#ifdef notdef
72353553Stanimura		DELAY(10000000L); /* clw */
72453553Stanimura#else
72555288Stanimura		DELAY(1000);
72653553Stanimura#endif /* notdef */
72753553Stanimura		/*
72853553Stanimura		 * Read the input slot valid register and see if input slots 3 and
72953553Stanimura		 * 4 are valid yet.
73053553Stanimura		 */
73153553Stanimura		acisv = csa_readio(resp, BA0_ACISV);
73253553Stanimura		if ((acisv & (ACISV_ISV3 | ACISV_ISV4)) == (ACISV_ISV3 | ACISV_ISV4))
73353553Stanimura			break;
73453553Stanimura	}
73553553Stanimura	/*
73653553Stanimura	 * Make sure we sampled valid input slots 3 and 4.  If not, then return
73753553Stanimura	 * an error.
73853553Stanimura	 */
73953553Stanimura	if ((acisv & (ACISV_ISV3 | ACISV_ISV4)) != (ACISV_ISV3 | ACISV_ISV4))
74053553Stanimura		return (ENXIO);
74153553Stanimura
74253553Stanimura	/*
74353553Stanimura	 * Now, assert valid frame and the slot 3 and 4 valid bits.  This will
74453553Stanimura	 * commense the transfer of digital audio data to the AC97 codec.
74553553Stanimura	 */
74653553Stanimura	csa_writeio(resp, BA0_ACOSV, ACOSV_SLV3 | ACOSV_SLV4);
74753553Stanimura
74853553Stanimura	/*
74953553Stanimura	 * Power down the DAC and ADC.  We will power them up (if) when we need
75053553Stanimura	 * them.
75153553Stanimura	 */
752153084Sru#ifdef notdef
75353553Stanimura	csa_writeio(resp, BA0_AC97_POWERDOWN, 0x300);
75453553Stanimura#endif /* notdef */
75553553Stanimura
75653553Stanimura	/*
75761347Scg	 * Turn off the Processor by turning off the software clock enable flag in
75853553Stanimura	 * the clock control register.
75953553Stanimura	 */
760153084Sru#ifdef notdef
76153553Stanimura	clkcr1 = csa_readio(resp, BA0_CLKCR1) & ~CLKCR1_SWCE;
76253553Stanimura	csa_writeio(resp, BA0_CLKCR1, clkcr1);
76353553Stanimura#endif /* notdef */
76453553Stanimura
76553553Stanimura	/*
76653553Stanimura	 * Enable interrupts on the part.
76753553Stanimura	 */
76877504Scg#if 0
76953553Stanimura	csa_writeio(resp, BA0_HICR, HICR_IEV | HICR_CHGM);
77053553Stanimura#endif /* notdef */
77153553Stanimura
77253553Stanimura	return (0);
77353553Stanimura}
77453553Stanimura
77555320Stanimuravoid
77653553Stanimuracsa_clearserialfifos(csa_res *resp)
77753553Stanimura{
77853553Stanimura	int i, j, pwr;
77953553Stanimura	u_int8_t clkcr1, serbst;
78053553Stanimura
78153553Stanimura	/*
78253553Stanimura	 * See if the devices are powered down.  If so, we must power them up first
78353553Stanimura	 * or they will not respond.
78453553Stanimura	 */
78553553Stanimura	pwr = 1;
78653553Stanimura	clkcr1 = csa_readio(resp, BA0_CLKCR1);
78753553Stanimura	if ((clkcr1 & CLKCR1_SWCE) == 0) {
78853553Stanimura		csa_writeio(resp, BA0_CLKCR1, clkcr1 | CLKCR1_SWCE);
78953553Stanimura		pwr = 0;
79053553Stanimura	}
79153553Stanimura
79253553Stanimura	/*
79353553Stanimura	 * We want to clear out the serial port FIFOs so we don't end up playing
79453553Stanimura	 * whatever random garbage happens to be in them.  We fill the sample FIFOs
79553553Stanimura	 * with zero (silence).
79653553Stanimura	 */
79753553Stanimura	csa_writeio(resp, BA0_SERBWP, 0);
79853553Stanimura
79953553Stanimura	/* Fill all 256 sample FIFO locations. */
80053553Stanimura	serbst = 0;
80153553Stanimura	for (i = 0 ; i < 256 ; i++) {
80253553Stanimura		/* Make sure the previous FIFO write operation has completed. */
80353553Stanimura		for (j = 0 ; j < 5 ; j++) {
80455288Stanimura			DELAY(100);
80553553Stanimura			serbst = csa_readio(resp, BA0_SERBST);
80653553Stanimura			if ((serbst & SERBST_WBSY) == 0)
80753553Stanimura				break;
80853553Stanimura		}
80953553Stanimura		if ((serbst & SERBST_WBSY) != 0) {
81053553Stanimura			if (!pwr)
81153553Stanimura				csa_writeio(resp, BA0_CLKCR1, clkcr1);
81253553Stanimura		}
81353553Stanimura		/* Write the serial port FIFO index. */
81453553Stanimura		csa_writeio(resp, BA0_SERBAD, i);
81553553Stanimura		/* Tell the serial port to load the new value into the FIFO location. */
81653553Stanimura		csa_writeio(resp, BA0_SERBCM, SERBCM_WRC);
81753553Stanimura	}
81853553Stanimura	/*
81953553Stanimura	 *  Now, if we powered up the devices, then power them back down again.
82053553Stanimura	 *  This is kinda ugly, but should never happen.
82153553Stanimura	 */
82253553Stanimura	if (!pwr)
82353553Stanimura		csa_writeio(resp, BA0_CLKCR1, clkcr1);
82453553Stanimura}
82553553Stanimura
826147626Sglebiusvoid
82753553Stanimuracsa_resetdsp(csa_res *resp)
82853553Stanimura{
82953553Stanimura	int i;
83053553Stanimura
83153553Stanimura	/*
83253553Stanimura	 * Write the reset bit of the SP control register.
83353553Stanimura	 */
83453553Stanimura	csa_writemem(resp, BA1_SPCR, SPCR_RSTSP);
83553553Stanimura
83653553Stanimura	/*
83753553Stanimura	 * Write the control register.
83853553Stanimura	 */
83953553Stanimura	csa_writemem(resp, BA1_SPCR, SPCR_DRQEN);
84053553Stanimura
84153553Stanimura	/*
84253553Stanimura	 * Clear the trap registers.
84353553Stanimura	 */
84453553Stanimura	for (i = 0 ; i < 8 ; i++) {
84553553Stanimura		csa_writemem(resp, BA1_DREG, DREG_REGID_TRAP_SELECT + i);
84653553Stanimura		csa_writemem(resp, BA1_TWPR, 0xffff);
84753553Stanimura	}
84853553Stanimura	csa_writemem(resp, BA1_DREG, 0);
84953553Stanimura
85053553Stanimura	/*
85153553Stanimura	 * Set the frame timer to reflect the number of cycles per frame.
85253553Stanimura	 */
85353553Stanimura	csa_writemem(resp, BA1_FRMT, 0xadf);
85453553Stanimura}
85553553Stanimura
85653553Stanimurastatic int
85753553Stanimuracsa_downloadimage(csa_res *resp)
85853553Stanimura{
859230897Spfg	int ret;
860230897Spfg	u_long ul, offset;
86153553Stanimura
862230897Spfg	for (ul = 0, offset = 0 ; ul < INKY_MEMORY_COUNT ; ul++) {
863230897Spfg	        /*
864230897Spfg	         * DMA this block from host memory to the appropriate
865230897Spfg	         * memory on the CSDevice.
866230897Spfg	         */
867230897Spfg		ret = csa_transferimage(resp,
868230897Spfg		    cs461x_firmware.BA1Array + offset,
869230897Spfg		    cs461x_firmware.MemoryStat[ul].ulDestAddr,
870230897Spfg		    cs461x_firmware.MemoryStat[ul].ulSourceSize);
871230897Spfg		if (ret)
872230897Spfg			return (ret);
873230897Spfg		offset += cs461x_firmware.MemoryStat[ul].ulSourceSize >> 2;
87453553Stanimura	}
875230897Spfg	return (0);
876230897Spfg}
87753553Stanimura
878230897Spfgstatic int
879230897Spfgcsa_transferimage(csa_res *resp, u_int32_t *src, u_long dest, u_long len)
880230897Spfg{
881230897Spfg	u_long ul;
882230897Spfg
883230897Spfg	/*
884230897Spfg	 * We do not allow DMAs from host memory to host memory (although the DMA
885230897Spfg	 * can do it) and we do not allow DMAs which are not a multiple of 4 bytes
886230897Spfg	 * in size (because that DMA can not do that).  Return an error if either
887230897Spfg	 * of these conditions exist.
888230897Spfg	 */
889230897Spfg	if ((len & 0x3) != 0)
890230897Spfg		return (EINVAL);
89153553Stanimura
892230897Spfg	/* Check the destination address that it is a multiple of 4 */
893230897Spfg	if ((dest & 0x3) != 0)
894230897Spfg		return (EINVAL);
895230897Spfg
896230897Spfg	/* Write the buffer out. */
897230897Spfg	for (ul = 0 ; ul < len ; ul += 4)
898230897Spfg		csa_writemem(resp, dest + ul, src[ul >> 2]);
89953553Stanimura	return (0);
90053553Stanimura}
90153553Stanimura
90253553Stanimuraint
90353553Stanimuracsa_readcodec(csa_res *resp, u_long offset, u_int32_t *data)
90453553Stanimura{
90553553Stanimura	int i;
906193640Sariff	u_int32_t acctl, acsts;
90753553Stanimura
90853553Stanimura	/*
90953553Stanimura	 * Make sure that there is not data sitting around from a previous
91053553Stanimura	 * uncompleted access. ACSDA = Status Data Register = 47Ch
91153553Stanimura	 */
912193640Sariff	csa_readio(resp, BA0_ACSDA);
91353553Stanimura
91453553Stanimura	/*
91553553Stanimura	 * Setup the AC97 control registers on the CS461x to send the
91653553Stanimura	 * appropriate command to the AC97 to perform the read.
91753553Stanimura	 * ACCAD = Command Address Register = 46Ch
91853553Stanimura	 * ACCDA = Command Data Register = 470h
91953553Stanimura	 * ACCTL = Control Register = 460h
92053553Stanimura	 * set DCV - will clear when process completed
92153553Stanimura	 * set CRW - Read command
92253553Stanimura	 * set VFRM - valid frame enabled
92353553Stanimura	 * set ESYN - ASYNC generation enabled
92453553Stanimura	 * set RSTN - ARST# inactive, AC97 codec not reset
92553553Stanimura	 */
92653553Stanimura
92753553Stanimura	/*
92853553Stanimura	 * Get the actual AC97 register from the offset
92953553Stanimura	 */
93053553Stanimura	csa_writeio(resp, BA0_ACCAD, offset - BA0_AC97_RESET);
93153553Stanimura	csa_writeio(resp, BA0_ACCDA, 0);
93253553Stanimura	csa_writeio(resp, BA0_ACCTL, ACCTL_DCV | ACCTL_CRW | ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN);
93353553Stanimura
93453553Stanimura	/*
93553553Stanimura	 * Wait for the read to occur.
93653553Stanimura	 */
93753553Stanimura	acctl = 0;
93853553Stanimura	for (i = 0 ; i < 10 ; i++) {
93953553Stanimura		/*
94053553Stanimura		 * First, we want to wait for a short time.
94153553Stanimura		 */
94253553Stanimura		DELAY(25);
94353553Stanimura
94453553Stanimura		/*
94553553Stanimura		 * Now, check to see if the read has completed.
94653553Stanimura		 * ACCTL = 460h, DCV should be reset by now and 460h = 17h
94753553Stanimura		 */
94853553Stanimura		acctl = csa_readio(resp, BA0_ACCTL);
94953553Stanimura		if ((acctl & ACCTL_DCV) == 0)
95053553Stanimura			break;
95153553Stanimura	}
95253553Stanimura
95353553Stanimura	/*
95453553Stanimura	 * Make sure the read completed.
95553553Stanimura	 */
95653553Stanimura	if ((acctl & ACCTL_DCV) != 0)
95753553Stanimura		return (EAGAIN);
95853553Stanimura
95953553Stanimura	/*
96053553Stanimura	 * Wait for the valid status bit to go active.
96153553Stanimura	 */
96253553Stanimura	acsts = 0;
96353553Stanimura	for (i = 0 ; i < 10 ; i++) {
96453553Stanimura		/*
96553553Stanimura		 * Read the AC97 status register.
96653553Stanimura		 * ACSTS = Status Register = 464h
96753553Stanimura		 */
96853553Stanimura		acsts = csa_readio(resp, BA0_ACSTS);
96953553Stanimura		/*
97053553Stanimura		 * See if we have valid status.
97153553Stanimura		 * VSTS - Valid Status
97253553Stanimura		 */
97353553Stanimura		if ((acsts & ACSTS_VSTS) != 0)
97453553Stanimura			break;
97553553Stanimura		/*
97653553Stanimura		 * Wait for a short while.
97753553Stanimura		 */
97853553Stanimura		 DELAY(25);
97953553Stanimura	}
98053553Stanimura
98153553Stanimura	/*
98253553Stanimura	 * Make sure we got valid status.
98353553Stanimura	 */
98453553Stanimura	if ((acsts & ACSTS_VSTS) == 0)
98553553Stanimura		return (EAGAIN);
98653553Stanimura
98753553Stanimura	/*
98853553Stanimura	 * Read the data returned from the AC97 register.
98962483Scg	 * ACSDA = Status Data Register = 474h
99053553Stanimura	 */
99162483Scg	*data = csa_readio(resp, BA0_ACSDA);
99253553Stanimura
99353553Stanimura	return (0);
99453553Stanimura}
99553553Stanimura
99653553Stanimuraint
99753553Stanimuracsa_writecodec(csa_res *resp, u_long offset, u_int32_t data)
99853553Stanimura{
99953553Stanimura	int i;
100053553Stanimura	u_int32_t acctl;
100153553Stanimura
100253553Stanimura	/*
100353553Stanimura	 * Setup the AC97 control registers on the CS461x to send the
100453553Stanimura	 * appropriate command to the AC97 to perform the write.
100553553Stanimura	 * ACCAD = Command Address Register = 46Ch
100653553Stanimura	 * ACCDA = Command Data Register = 470h
100753553Stanimura	 * ACCTL = Control Register = 460h
100853553Stanimura	 * set DCV - will clear when process completed
100953553Stanimura	 * set VFRM - valid frame enabled
101053553Stanimura	 * set ESYN - ASYNC generation enabled
101153553Stanimura	 * set RSTN - ARST# inactive, AC97 codec not reset
101253553Stanimura	 */
101353553Stanimura
101453553Stanimura	/*
101553553Stanimura	 * Get the actual AC97 register from the offset
101653553Stanimura	 */
101753553Stanimura	csa_writeio(resp, BA0_ACCAD, offset - BA0_AC97_RESET);
101853553Stanimura	csa_writeio(resp, BA0_ACCDA, data);
101953553Stanimura	csa_writeio(resp, BA0_ACCTL, ACCTL_DCV | ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN);
102053553Stanimura
102153553Stanimura	/*
102253553Stanimura	 * Wait for the write to occur.
102353553Stanimura	 */
102453553Stanimura	acctl = 0;
102553553Stanimura	for (i = 0 ; i < 10 ; i++) {
102653553Stanimura		/*
102753553Stanimura		 * First, we want to wait for a short time.
102853553Stanimura		 */
102953553Stanimura		DELAY(25);
103053553Stanimura
103153553Stanimura		/*
103253553Stanimura		 * Now, check to see if the read has completed.
103353553Stanimura		 * ACCTL = 460h, DCV should be reset by now and 460h = 17h
103453553Stanimura		 */
103553553Stanimura		acctl = csa_readio(resp, BA0_ACCTL);
103653553Stanimura		if ((acctl & ACCTL_DCV) == 0)
103753553Stanimura			break;
103853553Stanimura	}
103953553Stanimura
104053553Stanimura	/*
104153553Stanimura	 * Make sure the write completed.
104253553Stanimura	 */
104353553Stanimura	if ((acctl & ACCTL_DCV) != 0)
104453553Stanimura		return (EAGAIN);
104553553Stanimura
104653553Stanimura	return (0);
104753553Stanimura}
104853553Stanimura
104953553Stanimurau_int32_t
105053553Stanimuracsa_readio(csa_res *resp, u_long offset)
105153553Stanimura{
105253553Stanimura	u_int32_t ul;
105353553Stanimura
105453553Stanimura	if (offset < BA0_AC97_RESET)
105553553Stanimura		return bus_space_read_4(rman_get_bustag(resp->io), rman_get_bushandle(resp->io), offset) & 0xffffffff;
105653553Stanimura	else {
105753553Stanimura		if (csa_readcodec(resp, offset, &ul))
105853553Stanimura			ul = 0;
105953553Stanimura		return (ul);
106053553Stanimura	}
106153553Stanimura}
106253553Stanimura
106353553Stanimuravoid
106453553Stanimuracsa_writeio(csa_res *resp, u_long offset, u_int32_t data)
106553553Stanimura{
106653553Stanimura	if (offset < BA0_AC97_RESET)
106753553Stanimura		bus_space_write_4(rman_get_bustag(resp->io), rman_get_bushandle(resp->io), offset, data);
106853553Stanimura	else
106953553Stanimura		csa_writecodec(resp, offset, data);
107053553Stanimura}
107153553Stanimura
107253553Stanimurau_int32_t
107353553Stanimuracsa_readmem(csa_res *resp, u_long offset)
107453553Stanimura{
107577504Scg	return bus_space_read_4(rman_get_bustag(resp->mem), rman_get_bushandle(resp->mem), offset);
107653553Stanimura}
107753553Stanimura
107853553Stanimuravoid
107953553Stanimuracsa_writemem(csa_res *resp, u_long offset, u_int32_t data)
108053553Stanimura{
108153553Stanimura	bus_space_write_4(rman_get_bustag(resp->mem), rman_get_bushandle(resp->mem), offset, data);
108253553Stanimura}
108353553Stanimura
108453553Stanimurastatic device_method_t csa_methods[] = {
108553553Stanimura	/* Device interface */
108653553Stanimura	DEVMETHOD(device_probe,		csa_probe),
108753553Stanimura	DEVMETHOD(device_attach,	csa_attach),
108877504Scg	DEVMETHOD(device_detach,	csa_detach),
108953553Stanimura	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
109053553Stanimura	DEVMETHOD(device_suspend,	bus_generic_suspend),
1091100634Sambrisko	DEVMETHOD(device_resume,	csa_resume),
109253553Stanimura
109353553Stanimura	/* Bus interface */
109453553Stanimura	DEVMETHOD(bus_alloc_resource,	csa_alloc_resource),
109553553Stanimura	DEVMETHOD(bus_release_resource,	csa_release_resource),
109653553Stanimura	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
109753553Stanimura	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
109855320Stanimura	DEVMETHOD(bus_setup_intr,	csa_setup_intr),
109955320Stanimura	DEVMETHOD(bus_teardown_intr,	csa_teardown_intr),
110053553Stanimura
1101227843Smarius	DEVMETHOD_END
110253553Stanimura};
110353553Stanimura
110453553Stanimurastatic driver_t csa_driver = {
110553553Stanimura	"csa",
110653553Stanimura	csa_methods,
110753553Stanimura	sizeof(struct csa_softc),
110853553Stanimura};
110953553Stanimura
111053553Stanimura/*
111153553Stanimura * csa can be attached to a pci bus.
111253553Stanimura */
111362483ScgDRIVER_MODULE(snd_csa, pci, csa_driver, csa_devclass, 0, 0);
1114132236StanimuraMODULE_DEPEND(snd_csa, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
111562483ScgMODULE_VERSION(snd_csa, 1);
1116