envy24.c revision 167608
178189Sbrian/*
278189Sbrian * Copyright (c) 2001 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp>
378189Sbrian * All rights reserved.
478189Sbrian *
578189Sbrian * Redistribution and use in source and binary forms, with or without
66059Samurai * modification, are permitted provided that the following conditions
778189Sbrian * are met:
878189Sbrian * 1. Redistributions of source code must retain the above copyright
978189Sbrian *    notice, this list of conditions and the following disclaimer.
1078189Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1178189Sbrian *    notice, this list of conditions and the following disclaimer in the
1278189Sbrian *    documentation and/or other materials provided with the distribution.
1378189Sbrian *
1478189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
156059Samurai * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1678189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1778189Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1878189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1978189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2078189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2178189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
2278189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2378189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF
2478189Sbrian * SUCH DAMAGE.
2578189Sbrian *
2678189Sbrian */
276059Samurai
2850479Speter#include <dev/sound/pcm/sound.h>
296059Samurai#include <dev/sound/pcm/ac97.h>
3078189Sbrian#include <dev/sound/pci/spicds.h>
3143313Sbrian#include <dev/sound/pci/envy24.h>
3231195Sbrian
3330715Sbrian#include <dev/pci/pcireg.h>
346059Samurai#include <dev/pci/pcivar.h>
356059Samurai
3681634Sbrian#include "mixer_if.h"
3781634Sbrian
3881634SbrianSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/envy24.c 167608 2007-03-15 16:41:27Z ariff $");
3981634Sbrian
406059SamuraiMALLOC_DEFINE(M_ENVY24, "envy24", "envy24 audio");
416059Samurai
426059Samurai/* -------------------------------------------------------------------- */
4313389Sphk
4436285Sbrianstruct sc_info;
4530715Sbrian
4630092Sbrian#define ENVY24_PLAY_CHNUM 10
4781634Sbrian#define ENVY24_REC_CHNUM 12
4830715Sbrian#define ENVY24_PLAY_BUFUNIT (4 /* byte/sample */ * 10 /* channel */)
4981634Sbrian#define ENVY24_REC_BUFUNIT  (4 /* byte/sample */ * 12 /* channel */)
5030715Sbrian#define ENVY24_SAMPLE_NUM   4096
5146686Sbrian
5230715Sbrian#define ENVY24_TIMEOUT 1000
5330715Sbrian
5446686Sbrian#define ENVY24_DEFAULT_FORMAT (AFMT_STEREO | AFMT_S16_LE)
5546686Sbrian
5630715Sbrian#define ENVY24_NAMELEN 32
5730715Sbrian
5830715Sbrianstruct envy24_sample {
5930715Sbrian        volatile u_int32_t buffer;
6030715Sbrian};
6136285Sbrian
6230715Sbriantypedef struct envy24_sample sample32_t;
6336285Sbrian
6436285Sbrian/* channel registers */
6536285Sbrianstruct sc_chinfo {
6681634Sbrian	struct snd_dbuf		*buffer;
6781634Sbrian	struct pcm_channel	*channel;
6836285Sbrian	struct sc_info		*parent;
696059Samurai	int			dir;
7036285Sbrian	unsigned		num; /* hw channel number */
7136285Sbrian
7236285Sbrian	/* channel information */
7336285Sbrian	u_int32_t		format;
7436285Sbrian	u_int32_t		speed;
7543313Sbrian	u_int32_t		blk; /* hw block size(dword) */
7643313Sbrian
7743313Sbrian	/* format conversion structure */
7881634Sbrian	u_int8_t		*data;
7981634Sbrian	unsigned int		size; /* data buffer size(byte) */
8036285Sbrian	int			unit; /* sample size(byte) */
8131195Sbrian	unsigned int		offset; /* samples number offset */
826059Samurai	void			(*emldma)(struct sc_chinfo *);
8358033Sbrian
8458033Sbrian	/* flags */
8558033Sbrian	int			run;
8658033Sbrian};
8758033Sbrian
8858033Sbrian/* codec interface entrys */
8958033Sbrianstruct codec_entry {
9058033Sbrian	void *(*create)(device_t dev, void *devinfo, int dir, int num);
9158033Sbrian	void (*destroy)(void *codec);
9258033Sbrian	void (*init)(void *codec);
9358033Sbrian	void (*reinit)(void *codec);
9458033Sbrian	void (*setvolume)(void *codec, int dir, unsigned int left, unsigned int right);
9558033Sbrian	void (*setrate)(void *codec, int which, int rate);
9658033Sbrian};
9758033Sbrian
9858033Sbrian/* system configuration information */
9958033Sbrianstruct cfg_info {
10058033Sbrian	char *name;
10158033Sbrian	u_int16_t subvendor, subdevice;
10255146Sbrian	u_int8_t scfg, acl, i2s, spdif;
1036059Samurai	u_int8_t gpiomask, gpiostate, gpiodir;
10458033Sbrian	u_int8_t cdti, cclk, cs, cif, type;
10558033Sbrian	u_int8_t free;
10658033Sbrian	struct codec_entry *codec;
10758033Sbrian};
10858033Sbrian
10958033Sbrian/* device private data */
11058033Sbrianstruct sc_info {
11158033Sbrian	device_t	dev;
11258033Sbrian	struct mtx	*lock;
11358033Sbrian
11458033Sbrian	/* Control/Status registor */
11558033Sbrian	struct resource *cs;
11658033Sbrian	int		csid;
11758033Sbrian	bus_space_tag_t cst;
11858033Sbrian	bus_space_handle_t csh;
11958033Sbrian	/* DDMA registor */
12058033Sbrian	struct resource *ddma;
12158034Sbrian	int		ddmaid;
12258033Sbrian	bus_space_tag_t ddmat;
12358033Sbrian	bus_space_handle_t ddmah;
12458033Sbrian	/* Consumer Section DMA Channel Registers */
12558033Sbrian	struct resource *ds;
12658033Sbrian	int		dsid;
12758033Sbrian	bus_space_tag_t dst;
12858033Sbrian	bus_space_handle_t dsh;
12958033Sbrian	/* MultiTrack registor */
13058033Sbrian	struct resource *mt;
13158033Sbrian	int		mtid;
13258033Sbrian	bus_space_tag_t mtt;
13358033Sbrian	bus_space_handle_t mth;
13458033Sbrian	/* DMA tag */
13558033Sbrian	bus_dma_tag_t dmat;
13658033Sbrian	/* IRQ resource */
13758033Sbrian	struct resource *irq;
13858033Sbrian	int		irqid;
13958033Sbrian	void		*ih;
14058033Sbrian
14158033Sbrian	/* system configuration data */
14258033Sbrian	struct cfg_info *cfg;
14358033Sbrian
14458033Sbrian	/* ADC/DAC number and info */
14558033Sbrian	int		adcn, dacn;
14658033Sbrian	void		*adc[4], *dac[4];
14758033Sbrian
14858034Sbrian	/* mixer control data */
14958033Sbrian	u_int32_t	src;
15058033Sbrian	u_int8_t	left[ENVY24_CHAN_NUM];
15149140Sbrian	u_int8_t	right[ENVY24_CHAN_NUM];
15228679Sbrian
1536059Samurai	/* Play/Record DMA fifo */
1546059Samurai	sample32_t	*pbuf;
15549140Sbrian	sample32_t	*rbuf;
15662977Sbrian	u_int32_t	psize, rsize; /* DMA buffer size(byte) */
1576059Samurai	u_int16_t	blk[2]; /* transfer check blocksize(dword) */
15862977Sbrian	bus_dmamap_t	pmap, rmap;
1596059Samurai
16062977Sbrian	/* current status */
1616059Samurai	u_int32_t	speed;
16262977Sbrian	int		run[2];
1636059Samurai	u_int16_t	intr[2];
1646059Samurai	struct pcmchan_caps	caps[2];
1656059Samurai
1666059Samurai	/* channel info table */
16781634Sbrian	unsigned	chnum;
16881634Sbrian	struct sc_chinfo chan[11];
16981634Sbrian};
17081634Sbrian
17149140Sbrian/* -------------------------------------------------------------------- */
17281634Sbrian
17381634Sbrian/*
17481634Sbrian * prototypes
17581634Sbrian */
17681634Sbrian
1776059Samurai/* DMA emulator */
17881634Sbrianstatic void envy24_p8u(struct sc_chinfo *);
17981634Sbrianstatic void envy24_p16sl(struct sc_chinfo *);
18081634Sbrianstatic void envy24_p32sl(struct sc_chinfo *);
1816059Samuraistatic void envy24_r16sl(struct sc_chinfo *);
18249140Sbrianstatic void envy24_r32sl(struct sc_chinfo *);
18381634Sbrian
18449140Sbrian/* channel interface */
18549140Sbrianstatic void *envy24chan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int);
18649140Sbrianstatic int envy24chan_setformat(kobj_t, void *, u_int32_t);
18749140Sbrianstatic int envy24chan_setspeed(kobj_t, void *, u_int32_t);
18849140Sbrianstatic int envy24chan_setblocksize(kobj_t, void *, u_int32_t);
18949140Sbrianstatic int envy24chan_trigger(kobj_t, void *, int);
19081634Sbrianstatic int envy24chan_getptr(kobj_t, void *);
19149140Sbrianstatic struct pcmchan_caps *envy24chan_getcaps(kobj_t, void *);
19281634Sbrian
19381634Sbrian/* mixer interface */
19481634Sbrianstatic int envy24mixer_init(struct snd_mixer *);
19581634Sbrianstatic int envy24mixer_reinit(struct snd_mixer *);
19681634Sbrianstatic int envy24mixer_uninit(struct snd_mixer *);
1976059Samuraistatic int envy24mixer_set(struct snd_mixer *, unsigned, unsigned, unsigned);
19849140Sbrianstatic u_int32_t envy24mixer_setrecsrc(struct snd_mixer *, u_int32_t);
19962977Sbrian
20036285Sbrian/* M-Audio Delta series AK4524 access interface */
20181634Sbrianstatic void *envy24_delta_ak4524_create(device_t, void *, int, int);
20281634Sbrianstatic void envy24_delta_ak4524_destroy(void *);
20381634Sbrianstatic void envy24_delta_ak4524_init(void *);
20481634Sbrianstatic void envy24_delta_ak4524_reinit(void *);
20581634Sbrianstatic void envy24_delta_ak4524_setvolume(void *, int, unsigned int, unsigned int);
20681634Sbrian
20781738Sbrian/* -------------------------------------------------------------------- */
20881738Sbrian
20981634Sbrian/*
21081634Sbrian  system constant tables
21181634Sbrian*/
21281634Sbrian
21381634Sbrian/* API -> hardware channel map */
21481634Sbrianstatic unsigned envy24_chanmap[ENVY24_CHAN_NUM] = {
21581634Sbrian	ENVY24_CHAN_PLAY_SPDIF, /* 0 */
21681634Sbrian	ENVY24_CHAN_PLAY_DAC1,  /* 1 */
21781634Sbrian	ENVY24_CHAN_PLAY_DAC2,  /* 2 */
21881634Sbrian	ENVY24_CHAN_PLAY_DAC3,  /* 3 */
21981634Sbrian	ENVY24_CHAN_PLAY_DAC4,  /* 4 */
22081634Sbrian	ENVY24_CHAN_REC_MIX,    /* 5 */
22181634Sbrian	ENVY24_CHAN_REC_SPDIF,  /* 6 */
22281634Sbrian	ENVY24_CHAN_REC_ADC1,   /* 7 */
22381634Sbrian	ENVY24_CHAN_REC_ADC2,   /* 8 */
22481634Sbrian	ENVY24_CHAN_REC_ADC3,   /* 9 */
22581634Sbrian	ENVY24_CHAN_REC_ADC4,   /* 10 */
22681634Sbrian};
22781634Sbrian
22881634Sbrian/* mixer -> API channel map. see above */
22981634Sbrianstatic int envy24_mixmap[] = {
23081634Sbrian	-1, /* Master output level. It is depend on codec support */
23181634Sbrian	-1, /* Treble level of all output channels */
23281634Sbrian	-1, /* Bass level of all output channels */
23381634Sbrian	-1, /* Volume of synthesier input */
23481634Sbrian	0,  /* Output level for the audio device */
23565181Sbrian	-1, /* Output level for the PC speaker */
23681634Sbrian	7,  /* line in jack */
23781634Sbrian	-1, /* microphone jack */
23881634Sbrian	-1, /* CD audio input */
23981634Sbrian	-1, /* Recording monitor */
24081634Sbrian	1,  /* alternative codec */
24181634Sbrian	-1, /* global recording level */
24249140Sbrian	-1, /* Input gain */
24381634Sbrian	-1, /* Output gain */
24481634Sbrian	8,  /* Input source 1 */
24581634Sbrian	9,  /* Input source 2 */
24681634Sbrian	10, /* Input source 3 */
24781634Sbrian	6,  /* Digital (input) 1 */
24881634Sbrian	-1, /* Digital (input) 2 */
24949140Sbrian	-1, /* Digital (input) 3 */
25081634Sbrian	-1, /* Phone input */
25149140Sbrian	-1, /* Phone output */
25249140Sbrian	-1, /* Video/TV (audio) in */
25349140Sbrian	-1, /* Radio in */
25449140Sbrian	-1, /* Monitor volume */
25549140Sbrian};
25649140Sbrian
25736285Sbrian/* variable rate audio */
25849140Sbrianstatic u_int32_t envy24_speed[] = {
25949140Sbrian    96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000,
26049140Sbrian    12000, 11025, 9600, 8000, 0
26149140Sbrian};
2626059Samurai
26349140Sbrian/* known boards configuration */
26481634Sbrianstatic struct codec_entry delta_codec = {
26581634Sbrian	envy24_delta_ak4524_create,
26681634Sbrian	envy24_delta_ak4524_destroy,
26781634Sbrian	envy24_delta_ak4524_init,
26881634Sbrian	envy24_delta_ak4524_reinit,
26981634Sbrian	envy24_delta_ak4524_setvolume,
27062977Sbrian	NULL, /* setrate */
27162977Sbrian};
27262977Sbrian
27362977Sbrianstatic struct cfg_info cfg_table[] = {
27481634Sbrian	{
27581634Sbrian		"Envy24 audio (M Audio Delta Dio 2496)",
27681634Sbrian		0x1412, 0xd631,
27781634Sbrian		0x10, 0x80, 0xf0, 0x03,
27881634Sbrian		0xff, 0x00, 0x00,
27981634Sbrian		0x10, 0x20, 0x40, 0x00, 0x00,
28049140Sbrian		0x00,
28181634Sbrian		&delta_codec,
28262977Sbrian	},
28381634Sbrian	{
28481634Sbrian		"Envy24 audio (Terratec DMX 6fire)",
28581634Sbrian		0x153b, 0x1138,
28681634Sbrian		0x2f, 0x80, 0xf0, 0x03,
28781634Sbrian		0xc0, 0xff, 0x7f,
28881634Sbrian		0x10, 0x20, 0x01, 0x01, 0x00,
28965181Sbrian		0x00,
29081634Sbrian 		&delta_codec,
29181634Sbrian 	},
29281634Sbrian	{
29381634Sbrian		"Envy24 audio (M Audio Audiophile 2496)",
29481634Sbrian		0x1412, 0xd634,
29562977Sbrian		0x10, 0x80, 0x72, 0x03,
29662977Sbrian		0x04, 0xfe, 0xfb,
29762977Sbrian		0x08, 0x02, 0x20, 0x00, 0x01,
29881634Sbrian		0x00,
29981634Sbrian 		&delta_codec,
30062977Sbrian 	},
30181634Sbrian	{
30262977Sbrian		"Envy24 audio (Generic)",
30381634Sbrian		0, 0,
30451809Sbrian		0x0f, 0x00, 0x01, 0x03,
30551809Sbrian		0xff, 0x00, 0x00,
30681634Sbrian		0x10, 0x20, 0x40, 0x00, 0x00,
30751809Sbrian		0x00,
30851809Sbrian		&delta_codec, /* default codec routines */
30949374Sbrian	}
31062977Sbrian};
31181634Sbrian
31262977Sbrianstatic u_int32_t envy24_recfmt[] = {
31349374Sbrian	AFMT_STEREO | AFMT_S16_LE,
31481634Sbrian	AFMT_STEREO | AFMT_S32_LE,
31581634Sbrian	0
31681634Sbrian};
31765846Sbrianstatic struct pcmchan_caps envy24_reccaps = {8000, 96000, envy24_recfmt, 0};
31881634Sbrian
31981634Sbrianstatic u_int32_t envy24_playfmt[] = {
32062977Sbrian	AFMT_STEREO | AFMT_U8,
32181634Sbrian	AFMT_STEREO | AFMT_S16_LE,
32281634Sbrian	AFMT_STEREO | AFMT_S32_LE,
32362977Sbrian	0
32462977Sbrian};
32562977Sbrian
32662977Sbrianstatic struct pcmchan_caps envy24_playcaps = {8000, 96000, envy24_playfmt, 0};
32762977Sbrian
32862977Sbrianstruct envy24_emldma {
32981634Sbrian	u_int32_t	format;
33062977Sbrian	void		(*emldma)(struct sc_chinfo *);
33181634Sbrian	int		unit;
33281634Sbrian};
33381634Sbrian
33462977Sbrianstatic struct envy24_emldma envy24_pemltab[] = {
33562977Sbrian	{AFMT_STEREO | AFMT_U8, envy24_p8u, 2},
33662977Sbrian	{AFMT_STEREO | AFMT_S16_LE, envy24_p16sl, 4},
33765181Sbrian	{AFMT_STEREO | AFMT_S32_LE, envy24_p32sl, 8},
33865181Sbrian	{0, NULL, 0}
33962977Sbrian};
34065181Sbrian
34162977Sbrianstatic struct envy24_emldma envy24_remltab[] = {
34262977Sbrian	{AFMT_STEREO | AFMT_S16_LE, envy24_r16sl, 4},
34362977Sbrian	{AFMT_STEREO | AFMT_S32_LE, envy24_r32sl, 8},
34462977Sbrian	{0, NULL, 0}
34562977Sbrian};
34662977Sbrian
34762977Sbrian/* -------------------------------------------------------------------- */
34862977Sbrian
34962977Sbrian/* common routines */
35062977Sbrianstatic u_int32_t
35162977Sbrianenvy24_rdcs(struct sc_info *sc, int regno, int size)
35262977Sbrian{
35362977Sbrian	switch (size) {
35462977Sbrian	case 1:
35562977Sbrian		return bus_space_read_1(sc->cst, sc->csh, regno);
35681634Sbrian	case 2:
35762977Sbrian		return bus_space_read_2(sc->cst, sc->csh, regno);
35826516Sbrian	case 4:
35981634Sbrian		return bus_space_read_4(sc->cst, sc->csh, regno);
36081634Sbrian	default:
36181634Sbrian		return 0xffffffff;
36281634Sbrian	}
36381634Sbrian}
36481634Sbrian
36562977Sbrianstatic void
36662977Sbrianenvy24_wrcs(struct sc_info *sc, int regno, u_int32_t data, int size)
36762977Sbrian{
36862977Sbrian	switch (size) {
36962977Sbrian	case 1:
37062977Sbrian		bus_space_write_1(sc->cst, sc->csh, regno, data);
37162977Sbrian		break;
37281634Sbrian	case 2:
37362977Sbrian		bus_space_write_2(sc->cst, sc->csh, regno, data);
37462977Sbrian		break;
37562977Sbrian	case 4:
37681634Sbrian		bus_space_write_4(sc->cst, sc->csh, regno, data);
37762977Sbrian		break;
37862977Sbrian	}
37962977Sbrian}
38062977Sbrian
38162977Sbrianstatic u_int32_t
38262977Sbrianenvy24_rdmt(struct sc_info *sc, int regno, int size)
38362977Sbrian{
38462977Sbrian	switch (size) {
38562977Sbrian	case 1:
38662977Sbrian		return bus_space_read_1(sc->mtt, sc->mth, regno);
38762977Sbrian	case 2:
38862977Sbrian		return bus_space_read_2(sc->mtt, sc->mth, regno);
38962977Sbrian	case 4:
39049140Sbrian		return bus_space_read_4(sc->mtt, sc->mth, regno);
39162977Sbrian	default:
39281634Sbrian		return 0xffffffff;
39381634Sbrian	}
39462977Sbrian}
39549140Sbrian
39662977Sbrianstatic void
39762977Sbrianenvy24_wrmt(struct sc_info *sc, int regno, u_int32_t data, int size)
39862977Sbrian{
39962977Sbrian	switch (size) {
40062977Sbrian	case 1:
40162977Sbrian		bus_space_write_1(sc->mtt, sc->mth, regno, data);
40262977Sbrian		break;
40362977Sbrian	case 2:
40462977Sbrian		bus_space_write_2(sc->mtt, sc->mth, regno, data);
40562977Sbrian		break;
40662977Sbrian	case 4:
40749140Sbrian		bus_space_write_4(sc->mtt, sc->mth, regno, data);
40862977Sbrian		break;
40962977Sbrian	}
41062977Sbrian}
41162977Sbrian
4126059Samuraistatic u_int32_t
41349140Sbrianenvy24_rdci(struct sc_info *sc, int regno)
41449140Sbrian{
41549140Sbrian	envy24_wrcs(sc, ENVY24_CCS_INDEX, regno, 1);
41649140Sbrian	return envy24_rdcs(sc, ENVY24_CCS_DATA, 1);
41749140Sbrian}
41849140Sbrian
41962977Sbrianstatic void
42065181Sbrianenvy24_wrci(struct sc_info *sc, int regno, u_int32_t data)
42162977Sbrian{
42262977Sbrian	envy24_wrcs(sc, ENVY24_CCS_INDEX, regno, 1);
42362977Sbrian	envy24_wrcs(sc, ENVY24_CCS_DATA, data, 1);
42465181Sbrian}
42565181Sbrian
42665181Sbrian/* -------------------------------------------------------------------- */
42781634Sbrian
42865181Sbrian/* I2C port/E2PROM access routines */
42981634Sbrian
43081634Sbrianstatic int
43165181Sbrianenvy24_rdi2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr)
43265181Sbrian{
43362977Sbrian	u_int32_t data;
43465181Sbrian	int i;
43565181Sbrian
43681634Sbrian#if(0)
43765181Sbrian	device_printf(sc->dev, "envy24_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
43865181Sbrian#endif
43981634Sbrian	for (i = 0; i < ENVY24_TIMEOUT; i++) {
44081634Sbrian		data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
44165181Sbrian		if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0)
44265181Sbrian			break;
44381634Sbrian		DELAY(32); /* 31.25kHz */
44465181Sbrian	}
44549140Sbrian	if (i == ENVY24_TIMEOUT) {
44649140Sbrian		return -1;
4476059Samurai	}
4486059Samurai	envy24_wrcs(sc, ENVY24_CCS_I2CADDR, addr, 1);
4496059Samurai	envy24_wrcs(sc, ENVY24_CCS_I2CDEV,
45065181Sbrian	    (dev & ENVY24_CCS_I2CDEV_ADDR) | ENVY24_CCS_I2CDEV_RD, 1);
45165181Sbrian	for (i = 0; i < ENVY24_TIMEOUT; i++) {
45281634Sbrian		data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
45365181Sbrian		if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0)
45465181Sbrian			break;
45581634Sbrian		DELAY(32); /* 31.25kHz */
45681634Sbrian	}
45765181Sbrian	if (i == ENVY24_TIMEOUT) {
45865181Sbrian		return -1;
45981634Sbrian	}
4606059Samurai	data = envy24_rdcs(sc, ENVY24_CCS_I2CDATA, 1);
4616059Samurai
4626059Samurai#if(0)
46358033Sbrian	device_printf(sc->dev, "envy24_rdi2c(): return 0x%x\n", data);
46458033Sbrian#endif
46558033Sbrian	return (int)data;
46658033Sbrian}
46758033Sbrian
46877487Sbrian#if 0
46958033Sbrianstatic int
47058033Sbrianenvy24_wri2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr, u_int32_t data)
47158033Sbrian{
47258033Sbrian	u_int32_t tmp;
47358033Sbrian	int i;
47458033Sbrian
47558033Sbrian#if(0)
47658033Sbrian	device_printf(sc->dev, "envy24_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
47758033Sbrian#endif
47858033Sbrian	for (i = 0; i < ENVY24_TIMEOUT; i++) {
47958033Sbrian		tmp = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
48058033Sbrian		if ((tmp & ENVY24_CCS_I2CSTAT_BSY) == 0)
48158033Sbrian			break;
48262977Sbrian		DELAY(32); /* 31.25kHz */
48358033Sbrian	}
48458033Sbrian	if (i == ENVY24_TIMEOUT) {
48558033Sbrian		return -1;
48658033Sbrian	}
48758033Sbrian	envy24_wrcs(sc, ENVY24_CCS_I2CADDR, addr, 1);
48874049Sbrian	envy24_wrcs(sc, ENVY24_CCS_I2CDATA, data, 1);
48958033Sbrian	envy24_wrcs(sc, ENVY24_CCS_I2CDEV,
49058033Sbrian	    (dev & ENVY24_CCS_I2CDEV_ADDR) | ENVY24_CCS_I2CDEV_WR, 1);
49158033Sbrian	for (i = 0; i < ENVY24_TIMEOUT; i++) {
49274049Sbrian		data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
49358033Sbrian		if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0)
49474049Sbrian			break;
49574049Sbrian		DELAY(32); /* 31.25kHz */
49658033Sbrian	}
49758033Sbrian	if (i == ENVY24_TIMEOUT) {
49858033Sbrian		return -1;
49958033Sbrian	}
50074049Sbrian
50158033Sbrian	return 0;
50258033Sbrian}
50358033Sbrian#endif
50458033Sbrian
50558033Sbrianstatic int
50658033Sbrianenvy24_rdrom(struct sc_info *sc, u_int32_t addr)
50758033Sbrian{
50877487Sbrian	u_int32_t data;
50977487Sbrian
51077487Sbrian#if(0)
51177487Sbrian	device_printf(sc->dev, "envy24_rdrom(sc, 0x%02x)\n", addr);
51277487Sbrian#endif
51377487Sbrian	data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
51477487Sbrian	if ((data & ENVY24_CCS_I2CSTAT_ROM) == 0) {
51577487Sbrian#if(0)
51677487Sbrian		device_printf(sc->dev, "envy24_rdrom(): E2PROM not presented\n");
51758033Sbrian#endif
51858033Sbrian		return -1;
51958033Sbrian	}
5206059Samurai
52181634Sbrian	return envy24_rdi2c(sc, ENVY24_CCS_I2CDEV_ROM, addr);
52281634Sbrian}
5236059Samurai
5246059Samuraistatic struct cfg_info *
52581634Sbrianenvy24_rom2cfg(struct sc_info *sc)
52681634Sbrian{
52781634Sbrian	struct cfg_info *buff;
5286059Samurai	int size;
52958033Sbrian	int i;
53058033Sbrian
53158033Sbrian#if(0)
53281634Sbrian	device_printf(sc->dev, "envy24_rom2cfg(sc)\n");
53381634Sbrian#endif
53481634Sbrian	size = envy24_rdrom(sc, ENVY24_E2PROM_SIZE);
53581634Sbrian	if (size < ENVY24_E2PROM_GPIODIR + 1) {
53681634Sbrian#if(0)
53781634Sbrian		device_printf(sc->dev, "envy24_rom2cfg(): ENVY24_E2PROM_SIZE-->%d\n", size);
53881634Sbrian#endif
53981634Sbrian		return NULL;
54081634Sbrian	}
54137010Sbrian	buff = malloc(sizeof(*buff), M_ENVY24, M_NOWAIT);
54281634Sbrian	if (buff == NULL) {
54381634Sbrian#if(0)
5446059Samurai		device_printf(sc->dev, "envy24_rom2cfg(): malloc()\n");
54558776Sbrian#endif
54658776Sbrian		return NULL;
54726692Sbrian	}
54858033Sbrian	buff->free = 1;
5496059Samurai
55081634Sbrian	buff->subvendor = envy24_rdrom(sc, ENVY24_E2PROM_SUBVENDOR) << 8;
55181634Sbrian	buff->subvendor += envy24_rdrom(sc, ENVY24_E2PROM_SUBVENDOR + 1);
55281634Sbrian	buff->subdevice = envy24_rdrom(sc, ENVY24_E2PROM_SUBDEVICE) << 8;
55381634Sbrian	buff->subdevice += envy24_rdrom(sc, ENVY24_E2PROM_SUBDEVICE + 1);
55481634Sbrian	buff->scfg = envy24_rdrom(sc, ENVY24_E2PROM_SCFG);
55581634Sbrian	buff->acl = envy24_rdrom(sc, ENVY24_E2PROM_ACL);
55681634Sbrian	buff->i2s = envy24_rdrom(sc, ENVY24_E2PROM_I2S);
55781634Sbrian	buff->spdif = envy24_rdrom(sc, ENVY24_E2PROM_SPDIF);
55881634Sbrian	buff->gpiomask = envy24_rdrom(sc, ENVY24_E2PROM_GPIOMASK);
55981738Sbrian	buff->gpiostate = envy24_rdrom(sc, ENVY24_E2PROM_GPIOSTATE);
56081634Sbrian	buff->gpiodir = envy24_rdrom(sc, ENVY24_E2PROM_GPIODIR);
56181634Sbrian
56281634Sbrian	for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++)
56381634Sbrian		if (cfg_table[i].subvendor == buff->subvendor &&
56481634Sbrian		    cfg_table[i].subdevice == buff->subdevice)
56581634Sbrian			break;
56681634Sbrian	buff->name = cfg_table[i].name;
56781634Sbrian	buff->codec = cfg_table[i].codec;
56881634Sbrian
56981634Sbrian	return buff;
57081634Sbrian}
57181634Sbrian
57281634Sbrianstatic void
57381634Sbrianenvy24_cfgfree(struct cfg_info *cfg) {
57481634Sbrian	if (cfg == NULL)
57558033Sbrian		return;
5768857Srgrimes	if (cfg->free)
57726692Sbrian		free(cfg, M_ENVY24);
57862778Sbrian	return;
57962778Sbrian}
58062778Sbrian
58158776Sbrian/* -------------------------------------------------------------------- */
58258776Sbrian
58358776Sbrian/* AC'97 codec access routines */
58428679Sbrian
58526692Sbrian#if 0
5866059Samuraistatic int
58781634Sbrianenvy24_coldcd(struct sc_info *sc)
5886059Samurai{
58926692Sbrian	u_int32_t data;
59081634Sbrian	int i;
59181634Sbrian
59228679Sbrian#if(0)
59381634Sbrian	device_printf(sc->dev, "envy24_coldcd()\n");
59428679Sbrian#endif
59528679Sbrian	envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_CLD, 1);
59681634Sbrian	DELAY(10);
59728679Sbrian	envy24_wrmt(sc, ENVY24_MT_AC97CMD, 0, 1);
5986059Samurai	DELAY(1000);
5996059Samurai	for (i = 0; i < ENVY24_TIMEOUT; i++) {
60051048Sbrian		data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
60181634Sbrian		if (data & ENVY24_MT_AC97CMD_RDY) {
60281634Sbrian			return 0;
60381634Sbrian		}
60481634Sbrian	}
60581634Sbrian
60681634Sbrian	return -1;
60781634Sbrian}
60881634Sbrian#endif
60981634Sbrian
61081634Sbrianstatic int
61181634Sbrianenvy24_slavecd(struct sc_info *sc)
61281634Sbrian{
61381634Sbrian	u_int32_t data;
61481634Sbrian	int i;
61581634Sbrian
6166059Samurai#if(0)
61781634Sbrian	device_printf(sc->dev, "envy24_slavecd()\n");
61881634Sbrian#endif
61951048Sbrian	envy24_wrmt(sc, ENVY24_MT_AC97CMD,
62051048Sbrian	    ENVY24_MT_AC97CMD_CLD | ENVY24_MT_AC97CMD_WRM, 1);
62181634Sbrian	DELAY(10);
62281634Sbrian	envy24_wrmt(sc, ENVY24_MT_AC97CMD, 0, 1);
62351048Sbrian	DELAY(1000);
62451048Sbrian	for (i = 0; i < ENVY24_TIMEOUT; i++) {
62526692Sbrian		data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
62681634Sbrian		if (data & ENVY24_MT_AC97CMD_RDY) {
62728679Sbrian			return 0;
62881634Sbrian		}
62928679Sbrian	}
63028679Sbrian
63181634Sbrian	return -1;
63262977Sbrian}
63328679Sbrian
6346059Samurai#if 0
63562778Sbrianstatic int
63662778Sbrianenvy24_rdcd(kobj_t obj, void *devinfo, int regno)
63781634Sbrian{
63881634Sbrian	struct sc_info *sc = (struct sc_info *)devinfo;
63962778Sbrian	u_int32_t data;
64062778Sbrian	int i;
64162778Sbrian
64281634Sbrian#if(0)
64362778Sbrian	device_printf(sc->dev, "envy24_rdcd(obj, sc, 0x%02x)\n", regno);
64462778Sbrian#endif
64562778Sbrian	envy24_wrmt(sc, ENVY24_MT_AC97IDX, (u_int32_t)regno, 1);
64662778Sbrian	envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_RD, 1);
64762778Sbrian	for (i = 0; i < ENVY24_TIMEOUT; i++) {
64881634Sbrian		data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
64981634Sbrian		if ((data & ENVY24_MT_AC97CMD_RD) == 0)
65062977Sbrian			break;
65162778Sbrian	}
65262778Sbrian	data = envy24_rdmt(sc, ENVY24_MT_AC97DLO, 2);
65362778Sbrian
65462778Sbrian#if(0)
65562778Sbrian	device_printf(sc->dev, "envy24_rdcd(): return 0x%x\n", data);
65662778Sbrian#endif
65762778Sbrian	return (int)data;
65862778Sbrian}
65962778Sbrian
66062778Sbrianstatic int
66162778Sbrianenvy24_wrcd(kobj_t obj, void *devinfo, int regno, u_int16_t data)
66262778Sbrian{
66362778Sbrian	struct sc_info *sc = (struct sc_info *)devinfo;
66462778Sbrian	u_int32_t cmd;
66562778Sbrian	int i;
66662778Sbrian
66762778Sbrian#if(0)
66862778Sbrian	device_printf(sc->dev, "envy24_wrcd(obj, sc, 0x%02x, 0x%04x)\n", regno, data);
66962778Sbrian#endif
67062778Sbrian	envy24_wrmt(sc, ENVY24_MT_AC97IDX, (u_int32_t)regno, 1);
67162778Sbrian	envy24_wrmt(sc, ENVY24_MT_AC97DLO, (u_int32_t)data, 2);
67262778Sbrian	envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_WR, 1);
67362778Sbrian	for (i = 0; i < ENVY24_TIMEOUT; i++) {
67462778Sbrian		cmd = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
6756059Samurai		if ((cmd & ENVY24_MT_AC97CMD_WR) == 0)
67651048Sbrian			break;
67751809Sbrian	}
67851809Sbrian
67951809Sbrian	return 0;
68051809Sbrian}
68181634Sbrian
68251809Sbrianstatic kobj_method_t envy24_ac97_methods[] = {
68351809Sbrian	KOBJMETHOD(ac97_read,	envy24_rdcd),
68481634Sbrian	KOBJMETHOD(ac97_write,	envy24_wrcd),
68551809Sbrian	{0, 0}
68651809Sbrian};
68751809SbrianAC97_DECLARE(envy24_ac97);
68851809Sbrian#endif
68951809Sbrian
69049374Sbrian/* -------------------------------------------------------------------- */
69149372Sbrian
69249372Sbrian/* GPIO access routines */
69349372Sbrian
69481634Sbrianstatic u_int32_t
69549372Sbrianenvy24_gpiord(struct sc_info *sc)
69649372Sbrian{
69781634Sbrian	return envy24_rdci(sc, ENVY24_CCI_GPIODAT);
69849372Sbrian}
69949372Sbrian
70049372Sbrianstatic void
70149374Sbrianenvy24_gpiowr(struct sc_info *sc, u_int32_t data)
70251048Sbrian{
70381634Sbrian#if(0)
70481634Sbrian	device_printf(sc->dev, "envy24_gpiowr(sc, 0x%02x)\n", data & 0xff);
70581634Sbrian	return;
70681634Sbrian#endif
70781634Sbrian	envy24_wrci(sc, ENVY24_CCI_GPIODAT, data);
70881634Sbrian	return;
70981634Sbrian}
71081634Sbrian
71181634Sbrian#if 0
71281634Sbrianstatic u_int32_t
71381634Sbrianenvy24_gpiogetmask(struct sc_info *sc)
71481634Sbrian{
71581634Sbrian	return envy24_rdci(sc, ENVY24_CCI_GPIOMASK);
71681634Sbrian}
71781634Sbrian#endif
71881634Sbrian
71981634Sbrianstatic void
72081634Sbrianenvy24_gpiosetmask(struct sc_info *sc, u_int32_t mask)
72181634Sbrian{
72281634Sbrian	envy24_wrci(sc, ENVY24_CCI_GPIOMASK, mask);
72381634Sbrian	return;
72436961Sbrian}
72536961Sbrian
72636961Sbrian#if 0
72781634Sbrianstatic u_int32_t
72836961Sbrianenvy24_gpiogetdir(struct sc_info *sc)
72936961Sbrian{
73081634Sbrian	return envy24_rdci(sc, ENVY24_CCI_GPIOCTL);
73136961Sbrian}
73281634Sbrian#endif
73375894Sbrian
73481634Sbrianstatic void
73581634Sbrianenvy24_gpiosetdir(struct sc_info *sc, u_int32_t dir)
73681634Sbrian{
73781634Sbrian	envy24_wrci(sc, ENVY24_CCI_GPIOCTL, dir);
73881634Sbrian	return;
73981634Sbrian}
74081634Sbrian
74136961Sbrian/* -------------------------------------------------------------------- */
74236961Sbrian
74351048Sbrian/* M-Audio Delta series AK4524 access interface routine */
74465846Sbrian
74565846Sbrianstruct envy24_delta_ak4524_codec {
74665846Sbrian	struct spicds_info *info;
74781634Sbrian	struct sc_info *parent;
74865846Sbrian	int dir;
74971781Sbrian	int num;
75081634Sbrian	int cs, cclk, cdti;
75165846Sbrian};
75265846Sbrian
75365846Sbrianstatic void
75465846Sbrianenvy24_delta_ak4524_ctl(void *codec, unsigned int cs, unsigned int cclk, unsigned int cdti)
75565846Sbrian{
75665846Sbrian	u_int32_t data = 0;
75765846Sbrian	struct envy24_delta_ak4524_codec *ptr = codec;
75881634Sbrian
75965846Sbrian#if(0)
76071781Sbrian	device_printf(ptr->parent->dev, "--> %d, %d, %d\n", cs, cclk, cdti);
76181634Sbrian#endif
76265846Sbrian	data = envy24_gpiord(ptr->parent);
76365846Sbrian	data &= ~(ptr->cs | ptr->cclk | ptr->cdti);
76465846Sbrian	if (cs) data += ptr->cs;
76565846Sbrian	if (cclk) data += ptr->cclk;
76636961Sbrian	if (cdti) data += ptr->cdti;
76736961Sbrian	envy24_gpiowr(ptr->parent, data);
76881634Sbrian	return;
76936961Sbrian}
77081634Sbrian
77162977Sbrianstatic void *
77236961Sbrianenvy24_delta_ak4524_create(device_t dev, void *info, int dir, int num)
77336961Sbrian{
77481634Sbrian	struct sc_info *sc = info;
77536961Sbrian	struct envy24_delta_ak4524_codec *buff = NULL;
77636961Sbrian
77736961Sbrian#if(0)
77851048Sbrian	device_printf(sc->dev, "envy24_delta_ak4524_create(dev, sc, %d, %d)\n", dir, num);
7796059Samurai#endif
78081634Sbrian
78181634Sbrian	buff = malloc(sizeof(*buff), M_ENVY24, M_NOWAIT);
78250867Sbrian	if (buff == NULL)
78351048Sbrian		return NULL;
78481634Sbrian
78581634Sbrian	if (dir == PCMDIR_REC && sc->adc[num] != NULL)
78650867Sbrian		buff->info = ((struct envy24_delta_ak4524_codec *)sc->adc[num])->info;
78750867Sbrian	else if (dir == PCMDIR_PLAY && sc->dac[num] != NULL)
78826692Sbrian		buff->info = ((struct envy24_delta_ak4524_codec *)sc->dac[num])->info;
78981634Sbrian	else
79028679Sbrian		buff->info = spicds_create(dev, buff, num, envy24_delta_ak4524_ctl);
79181634Sbrian	if (buff->info == NULL) {
79228679Sbrian		free(buff, M_ENVY24);
79328679Sbrian		return NULL;
79481634Sbrian	}
79528679Sbrian
7966059Samurai	buff->parent = sc;
7976059Samurai	buff->dir = dir;
79862977Sbrian	buff->num = num;
79962977Sbrian
80062977Sbrian	return (void *)buff;
80162977Sbrian}
80262977Sbrian
8036059Samuraistatic void
80428679Sbrianenvy24_delta_ak4524_destroy(void *codec)
80562977Sbrian{
80662977Sbrian	struct envy24_delta_ak4524_codec *ptr = codec;
80728679Sbrian	if (ptr == NULL)
8086059Samurai		return;
80981634Sbrian#if(0)
8106059Samurai	device_printf(ptr->parent->dev, "envy24_delta_ak4524_destroy()\n");
81181634Sbrian#endif
81262977Sbrian
81362977Sbrian	if (ptr->dir == PCMDIR_PLAY) {
81462977Sbrian		if (ptr->parent->dac[ptr->num] != NULL)
81562977Sbrian			spicds_destroy(ptr->info);
81662977Sbrian	}
8176059Samurai	else {
8186059Samurai		if (ptr->parent->adc[ptr->num] != NULL)
8196059Samurai			spicds_destroy(ptr->info);
82062778Sbrian	}
82162778Sbrian
82262778Sbrian	free(codec, M_ENVY24);
82362778Sbrian}
82481634Sbrian
82581634Sbrianstatic void
82681634Sbrianenvy24_delta_ak4524_init(void *codec)
82781634Sbrian{
82881634Sbrian#if 0
82981634Sbrian	u_int32_t gpiomask, gpiodir;
83081634Sbrian#endif
83181634Sbrian	struct envy24_delta_ak4524_codec *ptr = codec;
83281634Sbrian	if (ptr == NULL)
83381634Sbrian		return;
8346059Samurai#if(0)
83526692Sbrian	device_printf(ptr->parent->dev, "envy24_delta_ak4524_init()\n");
83681634Sbrian#endif
83731142Sbrian
83836285Sbrian	/*
83958033Sbrian	gpiomask = envy24_gpiogetmask(ptr->parent);
8406059Samurai	gpiomask &= ~(ENVY24_GPIO_AK4524_CDTI | ENVY24_GPIO_AK4524_CCLK | ENVY24_GPIO_AK4524_CS0 | ENVY24_GPIO_AK4524_CS1);
84136285Sbrian	envy24_gpiosetmask(ptr->parent, gpiomask);
84258033Sbrian	gpiodir = envy24_gpiogetdir(ptr->parent);
84362977Sbrian	gpiodir |= ENVY24_GPIO_AK4524_CDTI | ENVY24_GPIO_AK4524_CCLK | ENVY24_GPIO_AK4524_CS0 | ENVY24_GPIO_AK4524_CS1;
84462977Sbrian	envy24_gpiosetdir(ptr->parent, gpiodir);
84562977Sbrian	*/
84681634Sbrian	ptr->cs = ptr->parent->cfg->cs;
84781634Sbrian#if 0
84836285Sbrian	envy24_gpiosetmask(ptr->parent, ENVY24_GPIO_CS8414_STATUS);
84962977Sbrian	envy24_gpiosetdir(ptr->parent, ~ENVY24_GPIO_CS8414_STATUS);
85062977Sbrian	if (ptr->num == 0)
85162977Sbrian		ptr->cs = ENVY24_GPIO_AK4524_CS0;
85262977Sbrian	else
85362977Sbrian		ptr->cs = ENVY24_GPIO_AK4524_CS1;
85462977Sbrian	ptr->cclk = ENVY24_GPIO_AK4524_CCLK;
85562977Sbrian#endif
85662977Sbrian	ptr->cclk = ptr->parent->cfg->cclk;
85762977Sbrian	ptr->cdti = ptr->parent->cfg->cdti;
85862977Sbrian	spicds_settype(ptr->info,  ptr->parent->cfg->type);
85962977Sbrian	spicds_setcif(ptr->info, ptr->parent->cfg->cif);
86062977Sbrian	spicds_setformat(ptr->info,
8616735Samurai	    AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X);
86258033Sbrian	spicds_setdvc(ptr->info, 0);
8636059Samurai	/* for the time being, init only first codec */
86458033Sbrian	if (ptr->num == 0)
86558776Sbrian		spicds_init(ptr->info);
86658033Sbrian}
86758033Sbrian
86858033Sbrianstatic void
8696059Samuraienvy24_delta_ak4524_reinit(void *codec)
8706059Samurai{
87181634Sbrian	struct envy24_delta_ak4524_codec *ptr = codec;
87281634Sbrian	if (ptr == NULL)
87336285Sbrian		return;
8746059Samurai#if(0)
87531343Sbrian	device_printf(ptr->parent->dev, "envy24_delta_ak4524_reinit()\n");
87656413Sbrian#endif
87762977Sbrian
8786059Samurai	spicds_reinit(ptr->info);
87954912Sbrian}
88047168Sbrian
88147168Sbrianstatic void
88247168Sbrianenvy24_delta_ak4524_setvolume(void *codec, int dir, unsigned int left, unsigned int right)
88354912Sbrian{
88481634Sbrian	struct envy24_delta_ak4524_codec *ptr = codec;
88547168Sbrian	if (ptr == NULL)
88646686Sbrian		return;
88726031Sbrian#if(0)
88862977Sbrian	device_printf(ptr->parent->dev, "envy24_delta_ak4524_set()\n");
88981634Sbrian#endif
89081634Sbrian
89181634Sbrian	spicds_set(ptr->info, dir, left, right);
89226031Sbrian}
89362977Sbrian
89481634Sbrian/*
89562977Sbrian  There is no need for AK452[48] codec to set sample rate
89662977Sbrian  static void
89762977Sbrian  envy24_delta_ak4524_setrate(struct envy24_delta_ak4524_codec *codec, int which, int rate)
89862977Sbrian  {
89926031Sbrian  }
90056413Sbrian*/
90181634Sbrian
90256413Sbrian/* -------------------------------------------------------------------- */
90356413Sbrian
90456413Sbrian/* hardware access routeines */
90556413Sbrian
90656413Sbrianstatic struct {
90756413Sbrian	u_int32_t speed;
90846686Sbrian	u_int32_t code;
90946686Sbrian} envy24_speedtab[] = {
91047168Sbrian	{48000, ENVY24_MT_RATE_48000},
91147168Sbrian	{24000, ENVY24_MT_RATE_24000},
91246686Sbrian	{12000, ENVY24_MT_RATE_12000},
91347168Sbrian	{9600, ENVY24_MT_RATE_9600},
91446686Sbrian	{32000, ENVY24_MT_RATE_32000},
91536285Sbrian	{16000, ENVY24_MT_RATE_16000},
91681634Sbrian	{8000, ENVY24_MT_RATE_8000},
9176059Samurai	{96000, ENVY24_MT_RATE_96000},
9186059Samurai	{64000, ENVY24_MT_RATE_64000},
91981634Sbrian	{44100, ENVY24_MT_RATE_44100},
92081634Sbrian	{22050, ENVY24_MT_RATE_22050},
9216059Samurai	{11025, ENVY24_MT_RATE_11025},
92281634Sbrian	{88200, ENVY24_MT_RATE_88200},
9236059Samurai	{0, 0x10}
92481634Sbrian};
92581634Sbrian
92681634Sbrianstatic int
92781634Sbrianenvy24_setspeed(struct sc_info *sc, u_int32_t speed) {
92838557Sbrian	u_int32_t code;
9296059Samurai	int i = 0;
93081634Sbrian
93138544Sbrian#if(0)
93281634Sbrian	device_printf(sc->dev, "envy24_setspeed(sc, %d)\n", speed);
93381634Sbrian#endif
93438544Sbrian	if (speed == 0) {
93581634Sbrian		code = ENVY24_MT_RATE_SPDIF; /* external master clock */
9367001Samurai		envy24_slavecd(sc);
9377001Samurai	}
93881634Sbrian	else {
93981634Sbrian		for (i = 0; envy24_speedtab[i].speed != 0; i++) {
94081634Sbrian			if (envy24_speedtab[i].speed == speed)
9416059Samurai				break;
94281634Sbrian		}
9436059Samurai		code = envy24_speedtab[i].code;
94481634Sbrian	}
94581634Sbrian#if(0)
94681634Sbrian	device_printf(sc->dev, "envy24_setspeed(): speed %d/code 0x%04x\n", envy24_speedtab[i].speed, code);
94781634Sbrian#endif
94878411Sbrian	if (code < 0x10) {
94978411Sbrian		envy24_wrmt(sc, ENVY24_MT_RATE, code, 1);
95081634Sbrian		code = envy24_rdmt(sc, ENVY24_MT_RATE, 1);
95136285Sbrian		code &= ENVY24_MT_RATE_MASK;
95281634Sbrian		for (i = 0; envy24_speedtab[i].code < 0x10; i++) {
95381634Sbrian			if (envy24_speedtab[i].code == code)
95481634Sbrian				break;
95581634Sbrian		}
9566059Samurai		speed = envy24_speedtab[i].speed;
95781634Sbrian	}
958	else
959		speed = 0;
960
961#if(0)
962	device_printf(sc->dev, "envy24_setspeed(): return %d\n", speed);
963#endif
964	return speed;
965}
966
967static void
968envy24_setvolume(struct sc_info *sc, unsigned ch)
969{
970#if(0)
971	device_printf(sc->dev, "envy24_setvolume(sc, %d)\n", ch);
972#endif
973if (sc->cfg->subvendor==0x153b  && sc->cfg->subdevice==0x1138 ) {
974        envy24_wrmt(sc, ENVY24_MT_VOLIDX, 16, 1);
975        envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f7f, 2);
976        envy24_wrmt(sc, ENVY24_MT_VOLIDX, 17, 1);
977        envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f7f, 2);
978	}
979
980	envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2, 1);
981	envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f00 | sc->left[ch], 2);
982	envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2 + 1, 1);
983	envy24_wrmt(sc, ENVY24_MT_VOLUME, (sc->right[ch] << 8) | 0x7f, 2);
984}
985
986static void
987envy24_mutevolume(struct sc_info *sc, unsigned ch)
988{
989	u_int32_t vol;
990
991#if(0)
992	device_printf(sc->dev, "envy24_mutevolume(sc, %d)\n", ch);
993#endif
994	vol = ENVY24_VOL_MUTE << 8 | ENVY24_VOL_MUTE;
995	envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2, 1);
996	envy24_wrmt(sc, ENVY24_MT_VOLUME, vol, 2);
997	envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2 + 1, 1);
998	envy24_wrmt(sc, ENVY24_MT_VOLUME, vol, 2);
999}
1000
1001static u_int32_t
1002envy24_gethwptr(struct sc_info *sc, int dir)
1003{
1004	int unit, regno;
1005	u_int32_t ptr, rtn;
1006
1007#if(0)
1008	device_printf(sc->dev, "envy24_gethwptr(sc, %d)\n", dir);
1009#endif
1010	if (dir == PCMDIR_PLAY) {
1011		rtn = sc->psize / 4;
1012		unit = ENVY24_PLAY_BUFUNIT / 4;
1013		regno = ENVY24_MT_PCNT;
1014	}
1015	else {
1016		rtn = sc->rsize / 4;
1017		unit = ENVY24_REC_BUFUNIT / 4;
1018		regno = ENVY24_MT_RCNT;
1019	}
1020
1021	ptr = envy24_rdmt(sc, regno, 2);
1022	rtn -= (ptr + 1);
1023	rtn /= unit;
1024
1025#if(0)
1026	device_printf(sc->dev, "envy24_gethwptr(): return %d\n", rtn);
1027#endif
1028	return rtn;
1029}
1030
1031static void
1032envy24_updintr(struct sc_info *sc, int dir)
1033{
1034	int regptr, regintr;
1035	u_int32_t mask, intr;
1036	u_int32_t ptr, size, cnt;
1037	u_int16_t blk;
1038
1039#if(0)
1040	device_printf(sc->dev, "envy24_updintr(sc, %d)\n", dir);
1041#endif
1042	if (dir == PCMDIR_PLAY) {
1043		blk = sc->blk[0];
1044		size = sc->psize / 4;
1045		regptr = ENVY24_MT_PCNT;
1046		regintr = ENVY24_MT_PTERM;
1047		mask = ~ENVY24_MT_INT_PMASK;
1048	}
1049	else {
1050		blk = sc->blk[1];
1051		size = sc->rsize / 4;
1052		regptr = ENVY24_MT_RCNT;
1053		regintr = ENVY24_MT_RTERM;
1054		mask = ~ENVY24_MT_INT_RMASK;
1055	}
1056
1057	ptr = size - envy24_rdmt(sc, regptr, 2) - 1;
1058	/*
1059	cnt = blk - ptr % blk - 1;
1060	if (cnt == 0)
1061		cnt = blk - 1;
1062	*/
1063	cnt = blk - 1;
1064#if(0)
1065	device_printf(sc->dev, "envy24_updintr():ptr = %d, blk = %d, cnt = %d\n", ptr, blk, cnt);
1066#endif
1067	envy24_wrmt(sc, regintr, cnt, 2);
1068	intr = envy24_rdmt(sc, ENVY24_MT_INT, 1);
1069#if(0)
1070	device_printf(sc->dev, "envy24_updintr():intr = 0x%02x, mask = 0x%02x\n", intr, mask);
1071#endif
1072	envy24_wrmt(sc, ENVY24_MT_INT, intr & mask, 1);
1073#if(0)
1074	device_printf(sc->dev, "envy24_updintr():INT-->0x%02x\n",
1075		      envy24_rdmt(sc, ENVY24_MT_INT, 1));
1076#endif
1077
1078	return;
1079}
1080
1081#if 0
1082static void
1083envy24_maskintr(struct sc_info *sc, int dir)
1084{
1085	u_int32_t mask, intr;
1086
1087#if(0)
1088	device_printf(sc->dev, "envy24_maskintr(sc, %d)\n", dir);
1089#endif
1090	if (dir == PCMDIR_PLAY)
1091		mask = ENVY24_MT_INT_PMASK;
1092	else
1093		mask = ENVY24_MT_INT_RMASK;
1094	intr = envy24_rdmt(sc, ENVY24_MT_INT, 1);
1095	envy24_wrmt(sc, ENVY24_MT_INT, intr | mask, 1);
1096
1097	return;
1098}
1099#endif
1100
1101static int
1102envy24_checkintr(struct sc_info *sc, int dir)
1103{
1104	u_int32_t mask, stat, intr, rtn;
1105
1106#if(0)
1107	device_printf(sc->dev, "envy24_checkintr(sc, %d)\n", dir);
1108#endif
1109	intr = envy24_rdmt(sc, ENVY24_MT_INT, 1);
1110	if (dir == PCMDIR_PLAY) {
1111		if ((rtn = intr & ENVY24_MT_INT_PSTAT) != 0) {
1112			mask = ~ENVY24_MT_INT_RSTAT;
1113			stat = ENVY24_MT_INT_PSTAT | ENVY24_MT_INT_PMASK;
1114			envy24_wrmt(sc, ENVY24_MT_INT, (intr & mask) | stat, 1);
1115		}
1116	}
1117	else {
1118		if ((rtn = intr & ENVY24_MT_INT_RSTAT) != 0) {
1119			mask = ~ENVY24_MT_INT_PSTAT;
1120			stat = ENVY24_MT_INT_RSTAT | ENVY24_MT_INT_RMASK;
1121			envy24_wrmt(sc, ENVY24_MT_INT, (intr & mask) | stat, 1);
1122		}
1123	}
1124
1125	return rtn;
1126}
1127
1128static void
1129envy24_start(struct sc_info *sc, int dir)
1130{
1131	u_int32_t stat, sw;
1132
1133#if(0)
1134	device_printf(sc->dev, "envy24_start(sc, %d)\n", dir);
1135#endif
1136	if (dir == PCMDIR_PLAY)
1137		sw = ENVY24_MT_PCTL_PSTART;
1138	else
1139		sw = ENVY24_MT_PCTL_RSTART;
1140
1141	stat = envy24_rdmt(sc, ENVY24_MT_PCTL, 1);
1142	envy24_wrmt(sc, ENVY24_MT_PCTL, stat | sw, 1);
1143#if(0)
1144	DELAY(100);
1145	device_printf(sc->dev, "PADDR:0x%08x\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4));
1146	device_printf(sc->dev, "PCNT:%ld\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2));
1147#endif
1148
1149	return;
1150}
1151
1152static void
1153envy24_stop(struct sc_info *sc, int dir)
1154{
1155	u_int32_t stat, sw;
1156
1157#if(0)
1158	device_printf(sc->dev, "envy24_stop(sc, %d)\n", dir);
1159#endif
1160	if (dir == PCMDIR_PLAY)
1161		sw = ~ENVY24_MT_PCTL_PSTART;
1162	else
1163		sw = ~ENVY24_MT_PCTL_RSTART;
1164
1165	stat = envy24_rdmt(sc, ENVY24_MT_PCTL, 1);
1166	envy24_wrmt(sc, ENVY24_MT_PCTL, stat & sw, 1);
1167
1168	return;
1169}
1170
1171static int
1172envy24_route(struct sc_info *sc, int dac, int class, int adc, int rev)
1173{
1174	u_int32_t reg, mask;
1175	u_int32_t left, right;
1176
1177#if(0)
1178	device_printf(sc->dev, "envy24_route(sc, %d, %d, %d, %d)\n",
1179	    dac, class, adc, rev);
1180#endif
1181	/* parameter pattern check */
1182	if (dac < 0 || ENVY24_ROUTE_DAC_SPDIF < dac)
1183		return -1;
1184	if (class == ENVY24_ROUTE_CLASS_MIX &&
1185	    (dac != ENVY24_ROUTE_DAC_1 && dac != ENVY24_ROUTE_DAC_SPDIF))
1186		return -1;
1187	if (rev) {
1188		left = ENVY24_ROUTE_RIGHT;
1189		right = ENVY24_ROUTE_LEFT;
1190	}
1191	else {
1192		left = ENVY24_ROUTE_LEFT;
1193		right = ENVY24_ROUTE_RIGHT;
1194	}
1195
1196	if (dac == ENVY24_ROUTE_DAC_SPDIF) {
1197		reg = class | class << 2 |
1198			((adc << 1 | left) | left << 3) << 8 |
1199			((adc << 1 | right) | right << 3) << 12;
1200#if(0)
1201		device_printf(sc->dev, "envy24_route(): MT_SPDOUT-->0x%04x\n", reg);
1202#endif
1203		envy24_wrmt(sc, ENVY24_MT_SPDOUT, reg, 2);
1204	}
1205	else {
1206		mask = ~(0x0303 << dac * 2);
1207		reg = envy24_rdmt(sc, ENVY24_MT_PSDOUT, 2);
1208		reg = (reg & mask) | ((class | class << 8) << dac * 2);
1209#if(0)
1210		device_printf(sc->dev, "envy24_route(): MT_PSDOUT-->0x%04x\n", reg);
1211#endif
1212		envy24_wrmt(sc, ENVY24_MT_PSDOUT, reg, 2);
1213		mask = ~(0xff << dac * 8);
1214		reg = envy24_rdmt(sc, ENVY24_MT_RECORD, 4);
1215		reg = (reg & mask) |
1216			(((adc << 1 | left) | left << 3) |
1217			 ((adc << 1 | right) | right << 3) << 4) << dac * 8;
1218#if(0)
1219		device_printf(sc->dev, "envy24_route(): MT_RECORD-->0x%08x\n", reg);
1220#endif
1221		envy24_wrmt(sc, ENVY24_MT_RECORD, reg, 4);
1222	}
1223
1224	return 0;
1225}
1226
1227/* -------------------------------------------------------------------- */
1228
1229/* buffer copy routines */
1230static void
1231envy24_p32sl(struct sc_chinfo *ch)
1232{
1233	int length;
1234	sample32_t *dmabuf;
1235	u_int32_t *data;
1236	int src, dst, ssize, dsize, slot;
1237	int i;
1238
1239	length = sndbuf_getready(ch->buffer) / 8;
1240	dmabuf = ch->parent->pbuf;
1241	data = (u_int32_t *)ch->data;
1242	src = sndbuf_getreadyptr(ch->buffer) / 4;
1243	dst = src / 2 + ch->offset;
1244	ssize = ch->size / 4;
1245	dsize = ch->size / 8;
1246	slot = ch->num * 2;
1247
1248	for (i = 0; i < length; i++) {
1249		dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = data[src];
1250		dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = data[src + 1];
1251		dst++;
1252		dst %= dsize;
1253		src += 2;
1254		src %= ssize;
1255	}
1256
1257	return;
1258}
1259
1260static void
1261envy24_p16sl(struct sc_chinfo *ch)
1262{
1263	int length;
1264	sample32_t *dmabuf;
1265	u_int16_t *data;
1266	int src, dst, ssize, dsize, slot;
1267	int i;
1268
1269#if(0)
1270	device_printf(ch->parent->dev, "envy24_p16sl()\n");
1271#endif
1272	length = sndbuf_getready(ch->buffer) / 4;
1273	dmabuf = ch->parent->pbuf;
1274	data = (u_int16_t *)ch->data;
1275	src = sndbuf_getreadyptr(ch->buffer) / 2;
1276	dst = src / 2 + ch->offset;
1277	ssize = ch->size / 2;
1278	dsize = ch->size / 4;
1279	slot = ch->num * 2;
1280#if(0)
1281	device_printf(ch->parent->dev, "envy24_p16sl():%lu-->%lu(%lu)\n", src, dst, length);
1282#endif
1283
1284	for (i = 0; i < length; i++) {
1285		dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = (u_int32_t)data[src] << 16;
1286		dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = (u_int32_t)data[src + 1] << 16;
1287#if(0)
1288		if (i < 16) {
1289			printf("%08x", dmabuf[dst * ENVY24_PLAY_CHNUM + slot]);
1290			printf("%08x", dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1]);
1291		}
1292#endif
1293		dst++;
1294		dst %= dsize;
1295		src += 2;
1296		src %= ssize;
1297	}
1298#if(0)
1299	printf("\n");
1300#endif
1301
1302	return;
1303}
1304
1305static void
1306envy24_p8u(struct sc_chinfo *ch)
1307{
1308	int length;
1309	sample32_t *dmabuf;
1310	u_int8_t *data;
1311	int src, dst, ssize, dsize, slot;
1312	int i;
1313
1314	length = sndbuf_getready(ch->buffer) / 2;
1315	dmabuf = ch->parent->pbuf;
1316	data = (u_int8_t *)ch->data;
1317	src = sndbuf_getreadyptr(ch->buffer);
1318	dst = src / 2 + ch->offset;
1319	ssize = ch->size;
1320	dsize = ch->size / 4;
1321	slot = ch->num * 2;
1322
1323	for (i = 0; i < length; i++) {
1324		dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = ((u_int32_t)data[src] ^ 0x80) << 24;
1325		dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = ((u_int32_t)data[src + 1] ^ 0x80) << 24;
1326		dst++;
1327		dst %= dsize;
1328		src += 2;
1329		src %= ssize;
1330	}
1331
1332	return;
1333}
1334
1335static void
1336envy24_r32sl(struct sc_chinfo *ch)
1337{
1338	int length;
1339	sample32_t *dmabuf;
1340	u_int32_t *data;
1341	int src, dst, ssize, dsize, slot;
1342	int i;
1343
1344	length = sndbuf_getfree(ch->buffer) / 8;
1345	dmabuf = ch->parent->rbuf;
1346	data = (u_int32_t *)ch->data;
1347	dst = sndbuf_getfreeptr(ch->buffer) / 4;
1348	src = dst / 2 + ch->offset;
1349	dsize = ch->size / 4;
1350	ssize = ch->size / 8;
1351	slot = (ch->num - ENVY24_CHAN_REC_ADC1) * 2;
1352
1353	for (i = 0; i < length; i++) {
1354		data[dst] = dmabuf[src * ENVY24_REC_CHNUM + slot].buffer;
1355		data[dst + 1] = dmabuf[src * ENVY24_REC_CHNUM + slot + 1].buffer;
1356		dst += 2;
1357		dst %= dsize;
1358		src++;
1359		src %= ssize;
1360	}
1361
1362	return;
1363}
1364
1365static void
1366envy24_r16sl(struct sc_chinfo *ch)
1367{
1368	int length;
1369	sample32_t *dmabuf;
1370	u_int16_t *data;
1371	int src, dst, ssize, dsize, slot;
1372	int i;
1373
1374	length = sndbuf_getfree(ch->buffer) / 4;
1375	dmabuf = ch->parent->rbuf;
1376	data = (u_int16_t *)ch->data;
1377	dst = sndbuf_getfreeptr(ch->buffer) / 2;
1378	src = dst / 2 + ch->offset;
1379	dsize = ch->size / 2;
1380	ssize = ch->size / 8;
1381	slot = (ch->num - ENVY24_CHAN_REC_ADC1) * 2;
1382
1383	for (i = 0; i < length; i++) {
1384		data[dst] = dmabuf[src * ENVY24_REC_CHNUM + slot].buffer;
1385		data[dst + 1] = dmabuf[src * ENVY24_REC_CHNUM + slot + 1].buffer;
1386		dst += 2;
1387		dst %= dsize;
1388		src++;
1389		src %= ssize;
1390	}
1391
1392	return;
1393}
1394
1395/* -------------------------------------------------------------------- */
1396
1397/* channel interface */
1398static void *
1399envy24chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
1400{
1401	struct sc_info	*sc = (struct sc_info *)devinfo;
1402	struct sc_chinfo *ch;
1403	unsigned num;
1404
1405#if(0)
1406	device_printf(sc->dev, "envy24chan_init(obj, devinfo, b, c, %d)\n", dir);
1407#endif
1408	snd_mtxlock(sc->lock);
1409	if ((sc->chnum > ENVY24_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) ||
1410	    (sc->chnum < ENVY24_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) {
1411		snd_mtxunlock(sc->lock);
1412		return NULL;
1413	}
1414	num = sc->chnum;
1415
1416	ch = &sc->chan[num];
1417	ch->size = 8 * ENVY24_SAMPLE_NUM;
1418	ch->data = malloc(ch->size, M_ENVY24, M_NOWAIT);
1419	if (ch->data == NULL) {
1420		ch->size = 0;
1421		ch = NULL;
1422	}
1423	else {
1424		ch->buffer = b;
1425		ch->channel = c;
1426		ch->parent = sc;
1427		ch->dir = dir;
1428		/* set channel map */
1429		ch->num = envy24_chanmap[num];
1430		snd_mtxunlock(sc->lock);
1431		sndbuf_setup(ch->buffer, ch->data, ch->size);
1432		snd_mtxlock(sc->lock);
1433		/* these 2 values are dummy */
1434		ch->unit = 4;
1435		ch->blk = 10240;
1436	}
1437	snd_mtxunlock(sc->lock);
1438
1439	return ch;
1440}
1441
1442static int
1443envy24chan_free(kobj_t obj, void *data)
1444{
1445	struct sc_chinfo *ch = data;
1446	struct sc_info *sc = ch->parent;
1447
1448#if(0)
1449	device_printf(sc->dev, "envy24chan_free()\n");
1450#endif
1451	snd_mtxlock(sc->lock);
1452	if (ch->data != NULL) {
1453		free(ch->data, M_ENVY24);
1454		ch->data = NULL;
1455	}
1456	snd_mtxunlock(sc->lock);
1457
1458	return 0;
1459}
1460
1461static int
1462envy24chan_setformat(kobj_t obj, void *data, u_int32_t format)
1463{
1464	struct sc_chinfo *ch = data;
1465	struct sc_info *sc = ch->parent;
1466	struct envy24_emldma *emltab;
1467	/* unsigned int bcnt, bsize; */
1468	int i;
1469
1470#if(0)
1471	device_printf(sc->dev, "envy24chan_setformat(obj, data, 0x%08x)\n", format);
1472#endif
1473	snd_mtxlock(sc->lock);
1474	/* check and get format related information */
1475	if (ch->dir == PCMDIR_PLAY)
1476		emltab = envy24_pemltab;
1477	else
1478		emltab = envy24_remltab;
1479	if (emltab == NULL) {
1480		snd_mtxunlock(sc->lock);
1481		return -1;
1482	}
1483	for (i = 0; emltab[i].format != 0; i++)
1484		if (emltab[i].format == format)
1485			break;
1486	if (emltab[i].format == 0) {
1487		snd_mtxunlock(sc->lock);
1488		return -1;
1489	}
1490
1491	/* set format information */
1492	ch->format = format;
1493	ch->emldma = emltab[i].emldma;
1494	if (ch->unit > emltab[i].unit)
1495		ch->blk *= ch->unit / emltab[i].unit;
1496	else
1497		ch->blk /= emltab[i].unit / ch->unit;
1498	ch->unit = emltab[i].unit;
1499
1500	/* set channel buffer information */
1501	ch->size = ch->unit * ENVY24_SAMPLE_NUM;
1502#if 0
1503	if (ch->dir == PCMDIR_PLAY)
1504		bsize = ch->blk * 4 / ENVY24_PLAY_BUFUNIT;
1505	else
1506		bsize = ch->blk * 4 / ENVY24_REC_BUFUNIT;
1507	bsize *= ch->unit;
1508	bcnt = ch->size / bsize;
1509	sndbuf_resize(ch->buffer, bcnt, bsize);
1510#endif
1511	snd_mtxunlock(sc->lock);
1512
1513#if(0)
1514	device_printf(sc->dev, "envy24chan_setformat(): return 0x%08x\n", 0);
1515#endif
1516	return 0;
1517}
1518
1519/*
1520  IMPLEMENT NOTICE: In this driver, setspeed function only do setting
1521  of speed information value. And real hardware speed setting is done
1522  at start triggered(see envy24chan_trigger()). So, at this function
1523  is called, any value that ENVY24 can use is able to set. But, at
1524  start triggerd, some other channel is running, and that channel's
1525  speed isn't same with, then trigger function will fail.
1526*/
1527static int
1528envy24chan_setspeed(kobj_t obj, void *data, u_int32_t speed)
1529{
1530	struct sc_chinfo *ch = data;
1531	u_int32_t val, prev;
1532	int i;
1533
1534#if(0)
1535	device_printf(ch->parent->dev, "envy24chan_setspeed(obj, data, %d)\n", speed);
1536#endif
1537	prev = 0x7fffffff;
1538	for (i = 0; (val = envy24_speed[i]) != 0; i++) {
1539		if (abs(val - speed) < abs(prev - speed))
1540			prev = val;
1541		else
1542			break;
1543	}
1544	ch->speed = prev;
1545
1546#if(0)
1547	device_printf(ch->parent->dev, "envy24chan_setspeed(): return %d\n", ch->speed);
1548#endif
1549	return ch->speed;
1550}
1551
1552static int
1553envy24chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
1554{
1555	struct sc_chinfo *ch = data;
1556	/* struct sc_info *sc = ch->parent; */
1557	u_int32_t size, prev;
1558        unsigned int bcnt, bsize;
1559
1560#if(0)
1561	device_printf(sc->dev, "envy24chan_setblocksize(obj, data, %d)\n", blocksize);
1562#endif
1563	prev = 0x7fffffff;
1564	/* snd_mtxlock(sc->lock); */
1565	for (size = ch->size / 2; size > 0; size /= 2) {
1566		if (abs(size - blocksize) < abs(prev - blocksize))
1567			prev = size;
1568		else
1569			break;
1570	}
1571
1572	ch->blk = prev / ch->unit;
1573	if (ch->dir == PCMDIR_PLAY)
1574		ch->blk *= ENVY24_PLAY_BUFUNIT / 4;
1575	else
1576		ch->blk *= ENVY24_REC_BUFUNIT / 4;
1577	/* set channel buffer information */
1578	/* ch->size = ch->unit * ENVY24_SAMPLE_NUM; */
1579        if (ch->dir == PCMDIR_PLAY)
1580                bsize = ch->blk * 4 / ENVY24_PLAY_BUFUNIT;
1581        else
1582                bsize = ch->blk * 4 / ENVY24_REC_BUFUNIT;
1583        bsize *= ch->unit;
1584        bcnt = ch->size / bsize;
1585        sndbuf_resize(ch->buffer, bcnt, bsize);
1586	/* snd_mtxunlock(sc->lock); */
1587
1588#if(0)
1589	device_printf(sc->dev, "envy24chan_setblocksize(): return %d\n", prev);
1590#endif
1591	return prev;
1592}
1593
1594/* semantic note: must start at beginning of buffer */
1595static int
1596envy24chan_trigger(kobj_t obj, void *data, int go)
1597{
1598	struct sc_chinfo *ch = data;
1599	struct sc_info *sc = ch->parent;
1600	u_int32_t ptr;
1601	int slot;
1602#if 0
1603	int i;
1604
1605	device_printf(sc->dev, "envy24chan_trigger(obj, data, %d)\n", go);
1606#endif
1607	snd_mtxlock(sc->lock);
1608	if (ch->dir == PCMDIR_PLAY)
1609		slot = 0;
1610	else
1611		slot = 1;
1612	switch (go) {
1613	case PCMTRIG_START:
1614#if(0)
1615		device_printf(sc->dev, "envy24chan_trigger(): start\n");
1616#endif
1617		/* check or set channel speed */
1618		if (sc->run[0] == 0 && sc->run[1] == 0) {
1619			sc->speed = envy24_setspeed(sc, ch->speed);
1620			sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed;
1621			sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed;
1622		}
1623		else if (ch->speed != 0 && ch->speed != sc->speed)
1624			return -1;
1625		if (ch->speed == 0)
1626			ch->channel->speed = sc->speed;
1627		/* start or enable channel */
1628		sc->run[slot]++;
1629		if (sc->run[slot] == 1) {
1630			/* first channel */
1631			ch->offset = 0;
1632			sc->blk[slot] = ch->blk;
1633		}
1634		else {
1635			ptr = envy24_gethwptr(sc, ch->dir);
1636			ch->offset = ((ptr / ch->blk + 1) * ch->blk %
1637			    (ch->size / 4)) * 4 / ch->unit;
1638			if (ch->blk < sc->blk[slot])
1639				sc->blk[slot] = ch->blk;
1640		}
1641		if (ch->dir == PCMDIR_PLAY) {
1642			ch->emldma(ch);
1643			envy24_setvolume(sc, ch->num);
1644		}
1645		envy24_updintr(sc, ch->dir);
1646		if (sc->run[slot] == 1)
1647			envy24_start(sc, ch->dir);
1648		ch->run = 1;
1649		break;
1650	case PCMTRIG_EMLDMAWR:
1651#if(0)
1652		device_printf(sc->dev, "envy24chan_trigger(): emldmawr\n");
1653#endif
1654		if (ch->run != 1)
1655			return -1;
1656		ch->emldma(ch);
1657		break;
1658	case PCMTRIG_EMLDMARD:
1659#if(0)
1660		device_printf(sc->dev, "envy24chan_trigger(): emldmard\n");
1661#endif
1662		if (ch->run != 1)
1663			return -1;
1664		ch->emldma(ch);
1665		break;
1666	case PCMTRIG_ABORT:
1667#if(0)
1668		device_printf(sc->dev, "envy24chan_trigger(): abort\n");
1669#endif
1670		ch->run = 0;
1671		sc->run[slot]--;
1672		if (ch->dir == PCMDIR_PLAY)
1673			envy24_mutevolume(sc, ch->num);
1674		if (sc->run[slot] == 0) {
1675			envy24_stop(sc, ch->dir);
1676			sc->intr[slot] = 0;
1677		}
1678#if 0
1679		else if (ch->blk == sc->blk[slot]) {
1680			sc->blk[slot] = ENVY24_SAMPLE_NUM / 2;
1681			for (i = 0; i < ENVY24_CHAN_NUM; i++) {
1682				if (sc->chan[i].dir == ch->dir &&
1683				    sc->chan[i].run == 1 &&
1684				    sc->chan[i].blk < sc->blk[slot])
1685					sc->blk[slot] = sc->chan[i].blk;
1686			}
1687			if (ch->blk != sc->blk[slot])
1688				envy24_updintr(sc, ch->dir);
1689		}
1690#endif
1691		break;
1692	}
1693	snd_mtxunlock(sc->lock);
1694
1695	return 0;
1696}
1697
1698static int
1699envy24chan_getptr(kobj_t obj, void *data)
1700{
1701	struct sc_chinfo *ch = data;
1702	struct sc_info *sc = ch->parent;
1703	u_int32_t ptr;
1704	int rtn;
1705
1706#if(0)
1707	device_printf(sc->dev, "envy24chan_getptr()\n");
1708#endif
1709	snd_mtxlock(sc->lock);
1710	ptr = envy24_gethwptr(sc, ch->dir);
1711	rtn = ptr * ch->unit;
1712	snd_mtxunlock(sc->lock);
1713
1714#if(0)
1715	device_printf(sc->dev, "envy24chan_getptr(): return %d\n",
1716	    rtn);
1717#endif
1718	return rtn;
1719}
1720
1721static struct pcmchan_caps *
1722envy24chan_getcaps(kobj_t obj, void *data)
1723{
1724	struct sc_chinfo *ch = data;
1725	struct sc_info *sc = ch->parent;
1726	struct pcmchan_caps *rtn;
1727
1728#if(0)
1729	device_printf(sc->dev, "envy24chan_getcaps()\n");
1730#endif
1731	snd_mtxlock(sc->lock);
1732	if (ch->dir == PCMDIR_PLAY) {
1733		if (sc->run[0] == 0)
1734			rtn = &envy24_playcaps;
1735		else
1736			rtn = &sc->caps[0];
1737	}
1738	else {
1739		if (sc->run[1] == 0)
1740			rtn = &envy24_reccaps;
1741		else
1742			rtn = &sc->caps[1];
1743	}
1744	snd_mtxunlock(sc->lock);
1745
1746	return rtn;
1747}
1748
1749static kobj_method_t envy24chan_methods[] = {
1750	KOBJMETHOD(channel_init,		envy24chan_init),
1751	KOBJMETHOD(channel_free,		envy24chan_free),
1752	KOBJMETHOD(channel_setformat,		envy24chan_setformat),
1753	KOBJMETHOD(channel_setspeed,		envy24chan_setspeed),
1754	KOBJMETHOD(channel_setblocksize,	envy24chan_setblocksize),
1755	KOBJMETHOD(channel_trigger,		envy24chan_trigger),
1756	KOBJMETHOD(channel_getptr,		envy24chan_getptr),
1757	KOBJMETHOD(channel_getcaps,		envy24chan_getcaps),
1758	{ 0, 0 }
1759};
1760CHANNEL_DECLARE(envy24chan);
1761
1762/* -------------------------------------------------------------------- */
1763
1764/* mixer interface */
1765
1766static int
1767envy24mixer_init(struct snd_mixer *m)
1768{
1769	struct sc_info *sc = mix_getdevinfo(m);
1770
1771#if(0)
1772	device_printf(sc->dev, "envy24mixer_init()\n");
1773#endif
1774	if (sc == NULL)
1775		return -1;
1776
1777	/* set volume control rate */
1778	snd_mtxlock(sc->lock);
1779	envy24_wrmt(sc, ENVY24_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */
1780
1781	mix_setdevs(m, ENVY24_MIX_MASK);
1782	mix_setrecdevs(m, ENVY24_MIX_REC_MASK);
1783	snd_mtxunlock(sc->lock);
1784
1785	return 0;
1786}
1787
1788static int
1789envy24mixer_reinit(struct snd_mixer *m)
1790{
1791	struct sc_info *sc = mix_getdevinfo(m);
1792
1793	if (sc == NULL)
1794		return -1;
1795#if(0)
1796	device_printf(sc->dev, "envy24mixer_reinit()\n");
1797#endif
1798
1799	return 0;
1800}
1801
1802static int
1803envy24mixer_uninit(struct snd_mixer *m)
1804{
1805	struct sc_info *sc = mix_getdevinfo(m);
1806
1807	if (sc == NULL)
1808		return -1;
1809#if(0)
1810	device_printf(sc->dev, "envy24mixer_uninit()\n");
1811#endif
1812
1813	return 0;
1814}
1815
1816static int
1817envy24mixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1818{
1819	struct sc_info *sc = mix_getdevinfo(m);
1820	int ch = envy24_mixmap[dev];
1821	int hwch;
1822	int i;
1823
1824	if (sc == NULL)
1825		return -1;
1826	if (dev == 0 && sc->cfg->codec->setvolume == NULL)
1827		return -1;
1828	if (dev != 0 && ch == -1)
1829		return -1;
1830	hwch = envy24_chanmap[ch];
1831#if(0)
1832	device_printf(sc->dev, "envy24mixer_set(m, %d, %d, %d)\n",
1833	    dev, left, right);
1834#endif
1835
1836	snd_mtxlock(sc->lock);
1837	if (dev == 0) {
1838		for (i = 0; i < sc->dacn; i++) {
1839			sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right);
1840		}
1841	}
1842	else {
1843		/* set volume value for hardware */
1844		if ((sc->left[hwch] = 100 - left) > ENVY24_VOL_MIN)
1845			sc->left[hwch] = ENVY24_VOL_MUTE;
1846		if ((sc->right[hwch] = 100 - right) > ENVY24_VOL_MIN)
1847			sc->right[hwch] = ENVY24_VOL_MUTE;
1848
1849		/* set volume for record channel and running play channel */
1850		if (hwch > ENVY24_CHAN_PLAY_SPDIF || sc->chan[ch].run)
1851			envy24_setvolume(sc, hwch);
1852	}
1853	snd_mtxunlock(sc->lock);
1854
1855	return right << 8 | left;
1856}
1857
1858static u_int32_t
1859envy24mixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
1860{
1861	struct sc_info *sc = mix_getdevinfo(m);
1862	int ch = envy24_mixmap[src];
1863#if(0)
1864	device_printf(sc->dev, "envy24mixer_setrecsrc(m, %d)\n", src);
1865#endif
1866
1867	if (ch > ENVY24_CHAN_PLAY_SPDIF)
1868		sc->src = ch;
1869	return src;
1870}
1871
1872static kobj_method_t envy24mixer_methods[] = {
1873	KOBJMETHOD(mixer_init,		envy24mixer_init),
1874	KOBJMETHOD(mixer_reinit,	envy24mixer_reinit),
1875	KOBJMETHOD(mixer_uninit,	envy24mixer_uninit),
1876	KOBJMETHOD(mixer_set,		envy24mixer_set),
1877	KOBJMETHOD(mixer_setrecsrc,	envy24mixer_setrecsrc),
1878	{ 0, 0 }
1879};
1880MIXER_DECLARE(envy24mixer);
1881
1882/* -------------------------------------------------------------------- */
1883
1884/* The interrupt handler */
1885static void
1886envy24_intr(void *p)
1887{
1888	struct sc_info *sc = (struct sc_info *)p;
1889	struct sc_chinfo *ch;
1890	u_int32_t ptr, dsize, feed;
1891	int i;
1892
1893#if(0)
1894	device_printf(sc->dev, "envy24_intr()\n");
1895#endif
1896	snd_mtxlock(sc->lock);
1897	if (envy24_checkintr(sc, PCMDIR_PLAY)) {
1898#if(0)
1899		device_printf(sc->dev, "envy24_intr(): play\n");
1900#endif
1901		dsize = sc->psize / 4;
1902		ptr = dsize - envy24_rdmt(sc, ENVY24_MT_PCNT, 2) - 1;
1903#if(0)
1904		device_printf(sc->dev, "envy24_intr(): ptr = %d-->", ptr);
1905#endif
1906		ptr -= ptr % sc->blk[0];
1907		feed = (ptr + dsize - sc->intr[0]) % dsize;
1908#if(0)
1909		printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed);
1910#endif
1911		for (i = ENVY24_CHAN_PLAY_DAC1; i <= ENVY24_CHAN_PLAY_SPDIF; i++) {
1912			ch = &sc->chan[i];
1913#if(0)
1914			if (ch->run)
1915				device_printf(sc->dev, "envy24_intr(): chan[%d].blk = %d\n", i, ch->blk);
1916#endif
1917			if (ch->run && ch->blk <= feed) {
1918				snd_mtxunlock(sc->lock);
1919				chn_intr(ch->channel);
1920				snd_mtxlock(sc->lock);
1921			}
1922		}
1923		sc->intr[0] = ptr;
1924		envy24_updintr(sc, PCMDIR_PLAY);
1925	}
1926	if (envy24_checkintr(sc, PCMDIR_REC)) {
1927#if(0)
1928		device_printf(sc->dev, "envy24_intr(): rec\n");
1929#endif
1930		dsize = sc->rsize / 4;
1931		ptr = dsize - envy24_rdmt(sc, ENVY24_MT_RCNT, 2) - 1;
1932		ptr -= ptr % sc->blk[1];
1933		feed = (ptr + dsize - sc->intr[1]) % dsize;
1934		for (i = ENVY24_CHAN_REC_ADC1; i <= ENVY24_CHAN_REC_SPDIF; i++) {
1935			ch = &sc->chan[i];
1936			if (ch->run && ch->blk <= feed) {
1937				snd_mtxunlock(sc->lock);
1938				chn_intr(ch->channel);
1939				snd_mtxlock(sc->lock);
1940			}
1941		}
1942		sc->intr[1] = ptr;
1943		envy24_updintr(sc, PCMDIR_REC);
1944	}
1945	snd_mtxunlock(sc->lock);
1946
1947	return;
1948}
1949
1950/*
1951 * Probe and attach the card
1952 */
1953
1954static int
1955envy24_pci_probe(device_t dev)
1956{
1957	u_int16_t sv, sd;
1958	int i;
1959
1960#if(0)
1961	printf("envy24_pci_probe()\n");
1962#endif
1963	if (pci_get_device(dev) == PCID_ENVY24 &&
1964	    pci_get_vendor(dev) == PCIV_ENVY24) {
1965		sv = pci_get_subvendor(dev);
1966		sd = pci_get_subdevice(dev);
1967		for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
1968			if (cfg_table[i].subvendor == sv &&
1969			    cfg_table[i].subdevice == sd) {
1970				break;
1971			}
1972		}
1973		device_set_desc(dev, cfg_table[i].name);
1974#if(0)
1975		printf("envy24_pci_probe(): return 0\n");
1976#endif
1977		return 0;
1978	}
1979	else {
1980#if(0)
1981		printf("envy24_pci_probe(): return ENXIO\n");
1982#endif
1983		return ENXIO;
1984	}
1985}
1986
1987static void
1988envy24_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1989{
1990	/* struct sc_info *sc = (struct sc_info *)arg; */
1991
1992#if(0)
1993	device_printf(sc->dev, "envy24_dmapsetmap()\n");
1994	if (bootverbose) {
1995		printf("envy24(play): setmap %lx, %lx; ",
1996		    (unsigned long)segs->ds_addr,
1997		    (unsigned long)segs->ds_len);
1998		printf("%p -> %lx\n", sc->pmap, (unsigned long)vtophys(sc->pmap));
1999	}
2000#endif
2001}
2002
2003static void
2004envy24_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2005{
2006	/* struct sc_info *sc = (struct sc_info *)arg; */
2007
2008#if(0)
2009	device_printf(sc->dev, "envy24_dmarsetmap()\n");
2010	if (bootverbose) {
2011		printf("envy24(record): setmap %lx, %lx; ",
2012		    (unsigned long)segs->ds_addr,
2013		    (unsigned long)segs->ds_len);
2014		printf("%p -> %lx\n", sc->rmap, (unsigned long)vtophys(sc->pmap));
2015	}
2016#endif
2017}
2018
2019static void
2020envy24_dmafree(struct sc_info *sc)
2021{
2022#if(0)
2023	device_printf(sc->dev, "envy24_dmafree():");
2024	if (sc->rmap) printf(" sc->rmap(0x%08x)", (u_int32_t)sc->rmap);
2025	else printf(" sc->rmap(null)");
2026	if (sc->pmap) printf(" sc->pmap(0x%08x)", (u_int32_t)sc->pmap);
2027	else printf(" sc->pmap(null)");
2028	if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf);
2029	else printf(" sc->rbuf(null)");
2030	if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf);
2031	else printf(" sc->pbuf(null)\n");
2032#endif
2033#if(0)
2034	if (sc->rmap)
2035		bus_dmamap_unload(sc->dmat, sc->rmap);
2036	if (sc->pmap)
2037		bus_dmamap_unload(sc->dmat, sc->pmap);
2038	if (sc->rbuf)
2039		bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2040	if (sc->pbuf)
2041		bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2042#else
2043	bus_dmamap_unload(sc->dmat, sc->rmap);
2044	bus_dmamap_unload(sc->dmat, sc->pmap);
2045	bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2046	bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2047#endif
2048
2049	sc->rmap = sc->pmap = NULL;
2050	sc->pbuf = NULL;
2051	sc->rbuf = NULL;
2052
2053	return;
2054}
2055
2056static int
2057envy24_dmainit(struct sc_info *sc)
2058{
2059	u_int32_t addr;
2060
2061#if(0)
2062	device_printf(sc->dev, "envy24_dmainit()\n");
2063#endif
2064	/* init values */
2065	sc->psize = ENVY24_PLAY_BUFUNIT * ENVY24_SAMPLE_NUM;
2066	sc->rsize = ENVY24_REC_BUFUNIT * ENVY24_SAMPLE_NUM;
2067	sc->pbuf = NULL;
2068	sc->rbuf = NULL;
2069	sc->pmap = sc->rmap = NULL;
2070	sc->blk[0] = sc->blk[1] = 0;
2071
2072	/* allocate DMA buffer */
2073#if(0)
2074	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->pbuf\n");
2075#endif
2076	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap))
2077		goto bad;
2078#if(0)
2079	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->rbuf\n");
2080#endif
2081	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap))
2082		goto bad;
2083#if(0)
2084	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->pmap\n");
2085#endif
2086	if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24_dmapsetmap, sc, 0))
2087		goto bad;
2088#if(0)
2089	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->rmap\n");
2090#endif
2091	if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24_dmarsetmap, sc, 0))
2092		goto bad;
2093	bzero(sc->pbuf, sc->psize);
2094	bzero(sc->rbuf, sc->rsize);
2095
2096	/* set values to register */
2097	addr = vtophys(sc->pbuf);
2098#if(0)
2099	device_printf(sc->dev, "pbuf(0x%08x)\n", addr);
2100#endif
2101	envy24_wrmt(sc, ENVY24_MT_PADDR, addr, 4);
2102#if(0)
2103	device_printf(sc->dev, "PADDR-->(0x%08x)\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4));
2104	device_printf(sc->dev, "psize(%ld)\n", sc->psize / 4 - 1);
2105#endif
2106	envy24_wrmt(sc, ENVY24_MT_PCNT, sc->psize / 4 - 1, 2);
2107#if(0)
2108	device_printf(sc->dev, "PCNT-->(%ld)\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2));
2109#endif
2110	addr = vtophys(sc->rbuf);
2111	envy24_wrmt(sc, ENVY24_MT_RADDR, addr, 4);
2112	envy24_wrmt(sc, ENVY24_MT_RCNT, sc->rsize / 4 - 1, 2);
2113
2114	return 0;
2115 bad:
2116	envy24_dmafree(sc);
2117	return ENOSPC;
2118}
2119
2120static void
2121envy24_putcfg(struct sc_info *sc)
2122{
2123	device_printf(sc->dev, "system configuration\n");
2124	printf("  SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n",
2125	    sc->cfg->subvendor, sc->cfg->subdevice);
2126	printf("  XIN2 Clock Source: ");
2127	switch (sc->cfg->scfg & PCIM_SCFG_XIN2) {
2128	case 0x00:
2129		printf("22.5792MHz(44.1kHz*512)\n");
2130		break;
2131	case 0x40:
2132		printf("16.9344MHz(44.1kHz*384)\n");
2133		break;
2134	case 0x80:
2135		printf("from external clock synthesizer chip\n");
2136		break;
2137	default:
2138		printf("illeagal system setting\n");
2139	}
2140	printf("  MPU-401 UART(s) #: ");
2141	if (sc->cfg->scfg & PCIM_SCFG_MPU)
2142		printf("2\n");
2143	else
2144		printf("1\n");
2145	printf("  AC'97 codec: ");
2146	if (sc->cfg->scfg & PCIM_SCFG_AC97)
2147		printf("not exist\n");
2148	else
2149		printf("exist\n");
2150	printf("  ADC #: ");
2151	printf("%d\n", sc->adcn);
2152	printf("  DAC #: ");
2153	printf("%d\n", sc->dacn);
2154	printf("  Multi-track converter type: ");
2155	if ((sc->cfg->acl & PCIM_ACL_MTC) == 0) {
2156		printf("AC'97(SDATA_OUT:");
2157		if (sc->cfg->acl & PCIM_ACL_OMODE)
2158			printf("packed");
2159		else
2160			printf("split");
2161		printf("|SDATA_IN:");
2162		if (sc->cfg->acl & PCIM_ACL_IMODE)
2163			printf("packed");
2164		else
2165			printf("split");
2166		printf(")\n");
2167	}
2168	else {
2169		printf("I2S(");
2170		if (sc->cfg->i2s & PCIM_I2S_VOL)
2171			printf("with volume, ");
2172		if (sc->cfg->i2s & PCIM_I2S_96KHZ)
2173			printf("96KHz support, ");
2174		switch (sc->cfg->i2s & PCIM_I2S_RES) {
2175		case PCIM_I2S_16BIT:
2176			printf("16bit resolution, ");
2177			break;
2178		case PCIM_I2S_18BIT:
2179			printf("18bit resolution, ");
2180			break;
2181		case PCIM_I2S_20BIT:
2182			printf("20bit resolution, ");
2183			break;
2184		case PCIM_I2S_24BIT:
2185			printf("24bit resolution, ");
2186			break;
2187		}
2188		printf("ID#0x%x)\n", sc->cfg->i2s & PCIM_I2S_ID);
2189	}
2190	printf("  S/PDIF(IN/OUT): ");
2191	if (sc->cfg->spdif & PCIM_SPDIF_IN)
2192		printf("1/");
2193	else
2194		printf("0/");
2195	if (sc->cfg->spdif & PCIM_SPDIF_OUT)
2196		printf("1 ");
2197	else
2198		printf("0 ");
2199	if (sc->cfg->spdif & (PCIM_SPDIF_IN | PCIM_SPDIF_OUT))
2200		printf("ID# 0x%02x\n", (sc->cfg->spdif & PCIM_SPDIF_ID) >> 2);
2201	printf("  GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n",
2202	    sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate);
2203}
2204
2205static int
2206envy24_init(struct sc_info *sc)
2207{
2208	u_int32_t data;
2209#if(0)
2210	int rtn;
2211#endif
2212	int i;
2213	u_int32_t sv, sd;
2214
2215
2216#if(0)
2217	device_printf(sc->dev, "envy24_init()\n");
2218#endif
2219
2220	/* reset chip */
2221	envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_RESET | ENVY24_CCS_CTL_NATIVE, 1);
2222	DELAY(200);
2223	envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_NATIVE, 1);
2224	DELAY(200);
2225
2226	/* legacy hardware disable */
2227	data = pci_read_config(sc->dev, PCIR_LAC, 2);
2228	data |= PCIM_LAC_DISABLE;
2229	pci_write_config(sc->dev, PCIR_LAC, data, 2);
2230
2231	/* check system configuration */
2232	sc->cfg = NULL;
2233	for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2234		/* 1st: search configuration from table */
2235		sv = pci_get_subvendor(sc->dev);
2236		sd = pci_get_subdevice(sc->dev);
2237		if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) {
2238#if(0)
2239			device_printf(sc->dev, "Set configuration from table\n");
2240#endif
2241			sc->cfg = &cfg_table[i];
2242			break;
2243		}
2244	}
2245	if (sc->cfg == NULL) {
2246		/* 2nd: read configuration from table */
2247		sc->cfg = envy24_rom2cfg(sc);
2248	}
2249	sc->adcn = ((sc->cfg->scfg & PCIM_SCFG_ADC) >> 2) + 1;
2250	sc->dacn = (sc->cfg->scfg & PCIM_SCFG_DAC) + 1;
2251
2252	if (1 /* bootverbose */) {
2253		envy24_putcfg(sc);
2254	}
2255
2256	/* set system configuration */
2257	pci_write_config(sc->dev, PCIR_SCFG, sc->cfg->scfg, 1);
2258	pci_write_config(sc->dev, PCIR_ACL, sc->cfg->acl, 1);
2259	pci_write_config(sc->dev, PCIR_I2S, sc->cfg->i2s, 1);
2260	pci_write_config(sc->dev, PCIR_SPDIF, sc->cfg->spdif, 1);
2261	envy24_gpiosetmask(sc, sc->cfg->gpiomask);
2262	envy24_gpiosetdir(sc, sc->cfg->gpiodir);
2263	envy24_gpiowr(sc, sc->cfg->gpiostate);
2264	for (i = 0; i < sc->adcn; i++) {
2265		sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i);
2266		sc->cfg->codec->init(sc->adc[i]);
2267	}
2268	for (i = 0; i < sc->dacn; i++) {
2269		sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i);
2270		sc->cfg->codec->init(sc->dac[i]);
2271	}
2272
2273	/* initialize DMA buffer */
2274#if(0)
2275	device_printf(sc->dev, "envy24_init(): initialize DMA buffer\n");
2276#endif
2277	if (envy24_dmainit(sc))
2278		return ENOSPC;
2279
2280	/* initialize status */
2281	sc->run[0] = sc->run[1] = 0;
2282	sc->intr[0] = sc->intr[1] = 0;
2283	sc->speed = 0;
2284	sc->caps[0].fmtlist = envy24_playfmt;
2285	sc->caps[1].fmtlist = envy24_recfmt;
2286
2287	/* set channel router */
2288	envy24_route(sc, ENVY24_ROUTE_DAC_1, ENVY24_ROUTE_CLASS_MIX, 0, 0);
2289	envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_DMA, 0, 0);
2290	/* envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_MIX, 0, 0); */
2291
2292	/* set macro interrupt mask */
2293	data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1);
2294	envy24_wrcs(sc, ENVY24_CCS_IMASK, data & ~ENVY24_CCS_IMASK_PMT, 1);
2295	data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1);
2296#if(0)
2297	device_printf(sc->dev, "envy24_init(): CCS_IMASK-->0x%02x\n", data);
2298#endif
2299
2300	return 0;
2301}
2302
2303static int
2304envy24_alloc_resource(struct sc_info *sc)
2305{
2306	/* allocate I/O port resource */
2307	sc->csid = PCIR_CCS;
2308	sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2309	    &sc->csid, 0, ~0, 1, RF_ACTIVE);
2310	sc->ddmaid = PCIR_DDMA;
2311	sc->ddma = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2312	    &sc->ddmaid, 0, ~0, 1, RF_ACTIVE);
2313	sc->dsid = PCIR_DS;
2314	sc->ds = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2315	    &sc->dsid, 0, ~0, 1, RF_ACTIVE);
2316	sc->mtid = PCIR_MT;
2317	sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2318	    &sc->mtid, 0, ~0, 1, RF_ACTIVE);
2319	if (!sc->cs || !sc->ddma || !sc->ds || !sc->mt) {
2320		device_printf(sc->dev, "unable to map IO port space\n");
2321		return ENXIO;
2322	}
2323	sc->cst = rman_get_bustag(sc->cs);
2324	sc->csh = rman_get_bushandle(sc->cs);
2325	sc->ddmat = rman_get_bustag(sc->ddma);
2326	sc->ddmah = rman_get_bushandle(sc->ddma);
2327	sc->dst = rman_get_bustag(sc->ds);
2328	sc->dsh = rman_get_bushandle(sc->ds);
2329	sc->mtt = rman_get_bustag(sc->mt);
2330	sc->mth = rman_get_bushandle(sc->mt);
2331#if(0)
2332	device_printf(sc->dev,
2333	    "IO port register values\nCCS: 0x%lx\nDDMA: 0x%lx\nDS: 0x%lx\nMT: 0x%lx\n",
2334	    pci_read_config(sc->dev, PCIR_CCS, 4),
2335	    pci_read_config(sc->dev, PCIR_DDMA, 4),
2336	    pci_read_config(sc->dev, PCIR_DS, 4),
2337	    pci_read_config(sc->dev, PCIR_MT, 4));
2338#endif
2339
2340	/* allocate interupt resource */
2341	sc->irqid = 0;
2342	sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid,
2343				 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
2344	if (!sc->irq ||
2345	    snd_setup_intr(sc->dev, sc->irq, INTR_MPSAFE, envy24_intr, sc, &sc->ih)) {
2346		device_printf(sc->dev, "unable to map interrupt\n");
2347		return ENXIO;
2348	}
2349
2350	/* allocate DMA resource */
2351	if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev),
2352	    /*alignment*/4,
2353	    /*boundary*/0,
2354	    /*lowaddr*/BUS_SPACE_MAXADDR_ENVY24,
2355	    /*highaddr*/BUS_SPACE_MAXADDR_ENVY24,
2356	    /*filter*/NULL, /*filterarg*/NULL,
2357	    /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24,
2358	    /*nsegments*/1, /*maxsegsz*/0x3ffff,
2359	    /*flags*/0, /*lockfunc*/busdma_lock_mutex,
2360	    /*lockarg*/&Giant, &sc->dmat) != 0) {
2361		device_printf(sc->dev, "unable to create dma tag\n");
2362		return ENXIO;
2363	}
2364
2365	return 0;
2366}
2367
2368static int
2369envy24_pci_attach(device_t dev)
2370{
2371	u_int32_t		data;
2372	struct sc_info 		*sc;
2373	char 			status[SND_STATUSLEN];
2374	int			err = 0;
2375	int			i;
2376
2377#if(0)
2378	device_printf(dev, "envy24_pci_attach()\n");
2379#endif
2380	/* get sc_info data area */
2381	if ((sc = malloc(sizeof(*sc), M_ENVY24, M_NOWAIT)) == NULL) {
2382		device_printf(dev, "cannot allocate softc\n");
2383		return ENXIO;
2384	}
2385
2386	bzero(sc, sizeof(*sc));
2387	sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_envy24 softc");
2388	sc->dev = dev;
2389
2390	/* initialize PCI interface */
2391	data = pci_read_config(dev, PCIR_COMMAND, 2);
2392	data |= (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN);
2393	pci_write_config(dev, PCIR_COMMAND, data, 2);
2394	data = pci_read_config(dev, PCIR_COMMAND, 2);
2395
2396	/* allocate resources */
2397	err = envy24_alloc_resource(sc);
2398	if (err) {
2399		device_printf(dev, "unable to allocate system resources\n");
2400		goto bad;
2401	}
2402
2403	/* initialize card */
2404	err = envy24_init(sc);
2405	if (err) {
2406		device_printf(dev, "unable to initialize the card\n");
2407		goto bad;
2408	}
2409
2410	/* set multi track mixer */
2411	mixer_init(dev, &envy24mixer_class, sc);
2412
2413	/* set channel information */
2414	err = pcm_register(dev, sc, sc->dacn, sc->adcn);
2415	if (err)
2416		goto bad;
2417	sc->chnum = ENVY24_CHAN_PLAY_DAC1;
2418	for (i = 0; i < sc->dacn; i++) {
2419		pcm_addchan(dev, PCMDIR_PLAY, &envy24chan_class, sc);
2420		sc->chnum++;
2421	}
2422	sc->chnum = ENVY24_CHAN_REC_ADC1;
2423	for (i = 0; i < sc->adcn; i++) {
2424		pcm_addchan(dev, PCMDIR_REC, &envy24chan_class, sc);
2425		sc->chnum++;
2426	}
2427
2428	/* set status iformation */
2429	snprintf(status, SND_STATUSLEN,
2430	    "at io 0x%lx:%ld,0x%lx:%ld,0x%lx:%ld,0x%lx:%ld irq %ld",
2431	    rman_get_start(sc->cs),
2432	    rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1,
2433	    rman_get_start(sc->ddma),
2434	    rman_get_end(sc->ddma) - rman_get_start(sc->ddma) + 1,
2435	    rman_get_start(sc->ds),
2436	    rman_get_end(sc->ds) - rman_get_start(sc->ds) + 1,
2437	    rman_get_start(sc->mt),
2438	    rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1,
2439	    rman_get_start(sc->irq));
2440	pcm_setstatus(dev, status);
2441
2442	return 0;
2443
2444bad:
2445	if (sc->ih)
2446		bus_teardown_intr(dev, sc->irq, sc->ih);
2447	if (sc->irq)
2448		bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2449	envy24_dmafree(sc);
2450	if (sc->dmat)
2451		bus_dma_tag_destroy(sc->dmat);
2452	if (sc->cfg->codec->destroy != NULL) {
2453                for (i = 0; i < sc->adcn; i++)
2454                        sc->cfg->codec->destroy(sc->adc[i]);
2455                for (i = 0; i < sc->dacn; i++)
2456                        sc->cfg->codec->destroy(sc->dac[i]);
2457        }
2458	envy24_cfgfree(sc->cfg);
2459	if (sc->cs)
2460		bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2461	if (sc->ddma)
2462		bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma);
2463	if (sc->ds)
2464		bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds);
2465	if (sc->mt)
2466		bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2467	if (sc->lock)
2468		snd_mtxfree(sc->lock);
2469	free(sc, M_ENVY24);
2470	return err;
2471}
2472
2473static int
2474envy24_pci_detach(device_t dev)
2475{
2476	struct sc_info *sc;
2477	int r;
2478	int i;
2479
2480#if(0)
2481	device_printf(dev, "envy24_pci_detach()\n");
2482#endif
2483	sc = pcm_getdevinfo(dev);
2484	if (sc == NULL)
2485		return 0;
2486	r = pcm_unregister(dev);
2487	if (r)
2488		return r;
2489
2490	envy24_dmafree(sc);
2491	if (sc->cfg->codec->destroy != NULL) {
2492		for (i = 0; i < sc->adcn; i++)
2493			sc->cfg->codec->destroy(sc->adc[i]);
2494		for (i = 0; i < sc->dacn; i++)
2495			sc->cfg->codec->destroy(sc->dac[i]);
2496	}
2497	envy24_cfgfree(sc->cfg);
2498	bus_dma_tag_destroy(sc->dmat);
2499	bus_teardown_intr(dev, sc->irq, sc->ih);
2500	bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2501	bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2502	bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma);
2503	bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds);
2504	bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2505	snd_mtxfree(sc->lock);
2506	free(sc, M_ENVY24);
2507	return 0;
2508}
2509
2510static device_method_t envy24_methods[] = {
2511	/* Device interface */
2512	DEVMETHOD(device_probe,		envy24_pci_probe),
2513	DEVMETHOD(device_attach,	envy24_pci_attach),
2514	DEVMETHOD(device_detach,	envy24_pci_detach),
2515	{ 0, 0 }
2516};
2517
2518static driver_t envy24_driver = {
2519	"pcm",
2520	envy24_methods,
2521#if __FreeBSD_version > 500000
2522	PCM_SOFTC_SIZE,
2523#else
2524	sizeof(struct snddev_info),
2525#endif
2526};
2527
2528DRIVER_MODULE(snd_envy24, pci, envy24_driver, pcm_devclass, 0, 0);
2529MODULE_DEPEND(snd_envy24, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2530MODULE_DEPEND(snd_envy24, snd_spicds, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2531MODULE_VERSION(snd_envy24, 1);
2532