xref: /dragonfly/sys/dev/sound/pci/envy24ht.c (revision 030b0c8c)
12a1ad637SFrançois Tigeot /*-
24886ec58SHasso Tepper  * Copyright (c) 2006 Konstantin Dimitrov <kosio.dimitrov@gmail.com>
34886ec58SHasso Tepper  * Copyright (c) 2001 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp>
44886ec58SHasso Tepper  * All rights reserved.
54886ec58SHasso Tepper  *
64886ec58SHasso Tepper  * Redistribution and use in source and binary forms, with or without
74886ec58SHasso Tepper  * modification, are permitted provided that the following conditions
84886ec58SHasso Tepper  * are met:
94886ec58SHasso Tepper  * 1. Redistributions of source code must retain the above copyright
104886ec58SHasso Tepper  *    notice, this list of conditions and the following disclaimer.
114886ec58SHasso Tepper  * 2. Redistributions in binary form must reproduce the above copyright
124886ec58SHasso Tepper  *    notice, this list of conditions and the following disclaimer in the
134886ec58SHasso Tepper  *    documentation and/or other materials provided with the distribution.
144886ec58SHasso Tepper  *
154886ec58SHasso Tepper  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
164886ec58SHasso Tepper  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
174886ec58SHasso Tepper  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
184886ec58SHasso Tepper  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
194886ec58SHasso Tepper  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
204886ec58SHasso Tepper  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
214886ec58SHasso Tepper  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
224886ec58SHasso Tepper  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
234886ec58SHasso Tepper  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
244886ec58SHasso Tepper  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
254886ec58SHasso Tepper  * SUCH DAMAGE.
264886ec58SHasso Tepper  *
274886ec58SHasso Tepper  */
284886ec58SHasso Tepper 
294886ec58SHasso Tepper /*
304886ec58SHasso Tepper  * Konstantin Dimitrov's thanks list:
314886ec58SHasso Tepper  *
324886ec58SHasso Tepper  * A huge thanks goes to Spas Filipov for his friendship, support and his
334886ec58SHasso Tepper  * generous gift - an 'Audiotrak Prodigy HD2' audio card! I also want to
344886ec58SHasso Tepper  * thank Keiichi Iwasaki and his parents, because they helped Spas to get
354886ec58SHasso Tepper  * the card from Japan! Having hardware sample of Prodigy HD2 made adding
364886ec58SHasso Tepper  * support for that great card very easy and real fun and pleasure.
374886ec58SHasso Tepper  *
384886ec58SHasso Tepper  */
394886ec58SHasso Tepper 
402a1ad637SFrançois Tigeot #ifdef HAVE_KERNEL_OPTION_HEADERS
412a1ad637SFrançois Tigeot #include "opt_snd.h"
422a1ad637SFrançois Tigeot #endif
432a1ad637SFrançois Tigeot 
444886ec58SHasso Tepper #include <dev/sound/pcm/sound.h>
454886ec58SHasso Tepper #include <dev/sound/pcm/ac97.h>
464886ec58SHasso Tepper #include <dev/sound/pci/spicds.h>
474886ec58SHasso Tepper #include <dev/sound/pci/envy24ht.h>
484886ec58SHasso Tepper 
4967931cc4SFrançois Tigeot #include <bus/pci/pcireg.h>
5067931cc4SFrançois Tigeot #include <bus/pci/pcivar.h>
514886ec58SHasso Tepper 
524886ec58SHasso Tepper #include "mixer_if.h"
534886ec58SHasso Tepper 
542a1ad637SFrançois Tigeot SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/envy24ht.c 274035 2014-11-03 11:11:45Z bapt $");
554886ec58SHasso Tepper 
562a1ad637SFrançois Tigeot static MALLOC_DEFINE(M_ENVY24HT, "envy24ht", "envy24ht audio");
574886ec58SHasso Tepper 
584886ec58SHasso Tepper /* -------------------------------------------------------------------- */
594886ec58SHasso Tepper 
604886ec58SHasso Tepper struct sc_info;
614886ec58SHasso Tepper 
624886ec58SHasso Tepper #define ENVY24HT_PLAY_CHNUM 8
634886ec58SHasso Tepper #define ENVY24HT_REC_CHNUM 2
644886ec58SHasso Tepper #define ENVY24HT_PLAY_BUFUNIT (4 /* byte/sample */ * 8 /* channel */)
654886ec58SHasso Tepper #define ENVY24HT_REC_BUFUNIT  (4 /* byte/sample */ * 2 /* channel */)
664886ec58SHasso Tepper #define ENVY24HT_SAMPLE_NUM   4096
674886ec58SHasso Tepper 
684886ec58SHasso Tepper #define ENVY24HT_TIMEOUT 1000
694886ec58SHasso Tepper 
702a1ad637SFrançois Tigeot #define ENVY24HT_DEFAULT_FORMAT	SND_FORMAT(AFMT_S16_LE, 2, 0)
714886ec58SHasso Tepper 
724886ec58SHasso Tepper #define ENVY24HT_NAMELEN 32
734886ec58SHasso Tepper 
744886ec58SHasso Tepper struct envy24ht_sample {
754886ec58SHasso Tepper         volatile u_int32_t buffer;
764886ec58SHasso Tepper };
774886ec58SHasso Tepper 
784886ec58SHasso Tepper typedef struct envy24ht_sample sample32_t;
794886ec58SHasso Tepper 
804886ec58SHasso Tepper /* channel registers */
814886ec58SHasso Tepper struct sc_chinfo {
824886ec58SHasso Tepper 	struct snd_dbuf		*buffer;
834886ec58SHasso Tepper 	struct pcm_channel	*channel;
844886ec58SHasso Tepper 	struct sc_info		*parent;
854886ec58SHasso Tepper 	int			dir;
864886ec58SHasso Tepper 	unsigned		num; /* hw channel number */
874886ec58SHasso Tepper 
884886ec58SHasso Tepper 	/* channel information */
894886ec58SHasso Tepper 	u_int32_t		format;
904886ec58SHasso Tepper 	u_int32_t		speed;
914886ec58SHasso Tepper 	u_int32_t		blk; /* hw block size(dword) */
924886ec58SHasso Tepper 
934886ec58SHasso Tepper 	/* format conversion structure */
944886ec58SHasso Tepper 	u_int8_t		*data;
954886ec58SHasso Tepper 	unsigned int		size; /* data buffer size(byte) */
964886ec58SHasso Tepper 	int			unit; /* sample size(byte) */
974886ec58SHasso Tepper 	unsigned int		offset; /* samples number offset */
984886ec58SHasso Tepper 	void			(*emldma)(struct sc_chinfo *);
994886ec58SHasso Tepper 
1004886ec58SHasso Tepper 	/* flags */
1014886ec58SHasso Tepper 	int			run;
1024886ec58SHasso Tepper };
1034886ec58SHasso Tepper 
1044886ec58SHasso Tepper /* codec interface entrys */
1054886ec58SHasso Tepper struct codec_entry {
1064886ec58SHasso Tepper 	void *(*create)(device_t dev, void *devinfo, int dir, int num);
1074886ec58SHasso Tepper 	void (*destroy)(void *codec);
1084886ec58SHasso Tepper 	void (*init)(void *codec);
1094886ec58SHasso Tepper 	void (*reinit)(void *codec);
1104886ec58SHasso Tepper 	void (*setvolume)(void *codec, int dir, unsigned int left, unsigned int right);
1114886ec58SHasso Tepper 	void (*setrate)(void *codec, int which, int rate);
1124886ec58SHasso Tepper };
1134886ec58SHasso Tepper 
1144886ec58SHasso Tepper /* system configuration information */
1154886ec58SHasso Tepper struct cfg_info {
1164886ec58SHasso Tepper 	char *name;
1174886ec58SHasso Tepper 	u_int16_t subvendor, subdevice;
1184886ec58SHasso Tepper 	u_int8_t scfg, acl, i2s, spdif;
1194886ec58SHasso Tepper 	u_int32_t gpiomask, gpiostate, gpiodir;
1204886ec58SHasso Tepper 	u_int32_t cdti, cclk, cs;
1214886ec58SHasso Tepper 	u_int8_t cif, type, free;
1224886ec58SHasso Tepper 	struct codec_entry *codec;
1234886ec58SHasso Tepper };
1244886ec58SHasso Tepper 
1254886ec58SHasso Tepper /* device private data */
1264886ec58SHasso Tepper struct sc_info {
1274886ec58SHasso Tepper 	device_t	dev;
12867931cc4SFrançois Tigeot 	struct lock	*lock;
1294886ec58SHasso Tepper 
1304886ec58SHasso Tepper 	/* Control/Status registor */
1314886ec58SHasso Tepper 	struct resource *cs;
1324886ec58SHasso Tepper 	int		csid;
1334886ec58SHasso Tepper 	bus_space_tag_t cst;
1344886ec58SHasso Tepper 	bus_space_handle_t csh;
1354886ec58SHasso Tepper 	/* MultiTrack registor */
1364886ec58SHasso Tepper 	struct resource *mt;
1374886ec58SHasso Tepper 	int		mtid;
1384886ec58SHasso Tepper 	bus_space_tag_t mtt;
1394886ec58SHasso Tepper 	bus_space_handle_t mth;
1404886ec58SHasso Tepper 	/* DMA tag */
1414886ec58SHasso Tepper 	bus_dma_tag_t dmat;
1424886ec58SHasso Tepper 	/* IRQ resource */
1434886ec58SHasso Tepper 	struct resource *irq;
1444886ec58SHasso Tepper 	int		irqid;
1454886ec58SHasso Tepper 	void		*ih;
1464886ec58SHasso Tepper 
1474886ec58SHasso Tepper 	/* system configuration data */
1484886ec58SHasso Tepper 	struct cfg_info *cfg;
1494886ec58SHasso Tepper 
1504886ec58SHasso Tepper 	/* ADC/DAC number and info */
1514886ec58SHasso Tepper 	int		adcn, dacn;
1524886ec58SHasso Tepper 	void		*adc[4], *dac[4];
1534886ec58SHasso Tepper 
1544886ec58SHasso Tepper 	/* mixer control data */
1554886ec58SHasso Tepper 	u_int32_t	src;
1564886ec58SHasso Tepper 	u_int8_t	left[ENVY24HT_CHAN_NUM];
1574886ec58SHasso Tepper 	u_int8_t	right[ENVY24HT_CHAN_NUM];
1584886ec58SHasso Tepper 
1594886ec58SHasso Tepper 	/* Play/Record DMA fifo */
1604886ec58SHasso Tepper 	sample32_t	*pbuf;
1614886ec58SHasso Tepper 	sample32_t	*rbuf;
1624886ec58SHasso Tepper 	u_int32_t	psize, rsize; /* DMA buffer size(byte) */
1634886ec58SHasso Tepper 	u_int16_t	blk[2]; /* transfer check blocksize(dword) */
1644886ec58SHasso Tepper 	bus_dmamap_t	pmap, rmap;
1652a1ad637SFrançois Tigeot 	bus_addr_t	paddr, raddr;
1664886ec58SHasso Tepper 
1674886ec58SHasso Tepper 	/* current status */
1684886ec58SHasso Tepper 	u_int32_t	speed;
1694886ec58SHasso Tepper 	int		run[2];
1704886ec58SHasso Tepper 	u_int16_t	intr[2];
1714886ec58SHasso Tepper 	struct pcmchan_caps	caps[2];
1724886ec58SHasso Tepper 
1734886ec58SHasso Tepper 	/* channel info table */
1744886ec58SHasso Tepper 	unsigned	chnum;
1754886ec58SHasso Tepper 	struct sc_chinfo chan[11];
1764886ec58SHasso Tepper };
1774886ec58SHasso Tepper 
1784886ec58SHasso Tepper /* -------------------------------------------------------------------- */
1794886ec58SHasso Tepper 
1804886ec58SHasso Tepper /*
1814886ec58SHasso Tepper  * prototypes
1824886ec58SHasso Tepper  */
1834886ec58SHasso Tepper 
1844886ec58SHasso Tepper /* DMA emulator */
1854886ec58SHasso Tepper static void envy24ht_p8u(struct sc_chinfo *);
1864886ec58SHasso Tepper static void envy24ht_p16sl(struct sc_chinfo *);
1874886ec58SHasso Tepper static void envy24ht_p32sl(struct sc_chinfo *);
1884886ec58SHasso Tepper static void envy24ht_r16sl(struct sc_chinfo *);
1894886ec58SHasso Tepper static void envy24ht_r32sl(struct sc_chinfo *);
1904886ec58SHasso Tepper 
1914886ec58SHasso Tepper /* channel interface */
1924886ec58SHasso Tepper static void *envy24htchan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int);
1934886ec58SHasso Tepper static int envy24htchan_setformat(kobj_t, void *, u_int32_t);
1942a1ad637SFrançois Tigeot static u_int32_t envy24htchan_setspeed(kobj_t, void *, u_int32_t);
1952a1ad637SFrançois Tigeot static u_int32_t envy24htchan_setblocksize(kobj_t, void *, u_int32_t);
1964886ec58SHasso Tepper static int envy24htchan_trigger(kobj_t, void *, int);
1972a1ad637SFrançois Tigeot static u_int32_t envy24htchan_getptr(kobj_t, void *);
1984886ec58SHasso Tepper static struct pcmchan_caps *envy24htchan_getcaps(kobj_t, void *);
1994886ec58SHasso Tepper 
2004886ec58SHasso Tepper /* mixer interface */
2014886ec58SHasso Tepper static int envy24htmixer_init(struct snd_mixer *);
2024886ec58SHasso Tepper static int envy24htmixer_reinit(struct snd_mixer *);
2034886ec58SHasso Tepper static int envy24htmixer_uninit(struct snd_mixer *);
2044886ec58SHasso Tepper static int envy24htmixer_set(struct snd_mixer *, unsigned, unsigned, unsigned);
2054886ec58SHasso Tepper static u_int32_t envy24htmixer_setrecsrc(struct snd_mixer *, u_int32_t);
2064886ec58SHasso Tepper 
2074886ec58SHasso Tepper /* SPI codec access interface */
2084886ec58SHasso Tepper static void *envy24ht_spi_create(device_t, void *, int, int);
2094886ec58SHasso Tepper static void envy24ht_spi_destroy(void *);
2104886ec58SHasso Tepper static void envy24ht_spi_init(void *);
2114886ec58SHasso Tepper static void envy24ht_spi_reinit(void *);
2124886ec58SHasso Tepper static void envy24ht_spi_setvolume(void *, int, unsigned int, unsigned int);
2134886ec58SHasso Tepper 
2144886ec58SHasso Tepper /* -------------------------------------------------------------------- */
2154886ec58SHasso Tepper 
2164886ec58SHasso Tepper /*
2174886ec58SHasso Tepper   system constant tables
2184886ec58SHasso Tepper */
2194886ec58SHasso Tepper 
2204886ec58SHasso Tepper /* API -> hardware channel map */
2214886ec58SHasso Tepper static unsigned envy24ht_chanmap[ENVY24HT_CHAN_NUM] = {
2224886ec58SHasso Tepper 	ENVY24HT_CHAN_PLAY_DAC1,  /* 1 */
2234886ec58SHasso Tepper 	ENVY24HT_CHAN_PLAY_DAC2,  /* 2 */
2244886ec58SHasso Tepper 	ENVY24HT_CHAN_PLAY_DAC3,  /* 3 */
2254886ec58SHasso Tepper 	ENVY24HT_CHAN_PLAY_DAC4,  /* 4 */
2264886ec58SHasso Tepper 	ENVY24HT_CHAN_PLAY_SPDIF, /* 0 */
2274886ec58SHasso Tepper 	ENVY24HT_CHAN_REC_MIX,    /* 5 */
2284886ec58SHasso Tepper 	ENVY24HT_CHAN_REC_SPDIF,  /* 6 */
2294886ec58SHasso Tepper 	ENVY24HT_CHAN_REC_ADC1,   /* 7 */
2304886ec58SHasso Tepper 	ENVY24HT_CHAN_REC_ADC2,   /* 8 */
2314886ec58SHasso Tepper 	ENVY24HT_CHAN_REC_ADC3,   /* 9 */
2324886ec58SHasso Tepper 	ENVY24HT_CHAN_REC_ADC4,   /* 10 */
2334886ec58SHasso Tepper };
2344886ec58SHasso Tepper 
2354886ec58SHasso Tepper /* mixer -> API channel map. see above */
2364886ec58SHasso Tepper static int envy24ht_mixmap[] = {
2374886ec58SHasso Tepper 	-1, /* Master output level. It is depend on codec support */
2384886ec58SHasso Tepper 	-1, /* Treble level of all output channels */
2394886ec58SHasso Tepper 	-1, /* Bass level of all output channels */
2404886ec58SHasso Tepper 	-1, /* Volume of synthesier input */
2414886ec58SHasso Tepper 	0,  /* Output level for the audio device */
2424886ec58SHasso Tepper 	-1, /* Output level for the PC speaker */
2434886ec58SHasso Tepper 	7,  /* line in jack */
2444886ec58SHasso Tepper 	-1, /* microphone jack */
2454886ec58SHasso Tepper 	-1, /* CD audio input */
2464886ec58SHasso Tepper 	-1, /* Recording monitor */
2474886ec58SHasso Tepper 	1,  /* alternative codec */
2484886ec58SHasso Tepper 	-1, /* global recording level */
2494886ec58SHasso Tepper 	-1, /* Input gain */
2504886ec58SHasso Tepper 	-1, /* Output gain */
2514886ec58SHasso Tepper 	8,  /* Input source 1 */
2524886ec58SHasso Tepper 	9,  /* Input source 2 */
2534886ec58SHasso Tepper 	10, /* Input source 3 */
2544886ec58SHasso Tepper 	6,  /* Digital (input) 1 */
2554886ec58SHasso Tepper 	-1, /* Digital (input) 2 */
2564886ec58SHasso Tepper 	-1, /* Digital (input) 3 */
2574886ec58SHasso Tepper 	-1, /* Phone input */
2584886ec58SHasso Tepper 	-1, /* Phone output */
2594886ec58SHasso Tepper 	-1, /* Video/TV (audio) in */
2604886ec58SHasso Tepper 	-1, /* Radio in */
2614886ec58SHasso Tepper 	-1, /* Monitor volume */
2624886ec58SHasso Tepper };
2634886ec58SHasso Tepper 
2644886ec58SHasso Tepper /* variable rate audio */
2654886ec58SHasso Tepper static u_int32_t envy24ht_speed[] = {
2664886ec58SHasso Tepper     192000, 176400, 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000,
2674886ec58SHasso Tepper     12000, 11025, 9600, 8000, 0
2684886ec58SHasso Tepper };
2694886ec58SHasso Tepper 
2704886ec58SHasso Tepper /* known boards configuration */
2714886ec58SHasso Tepper static struct codec_entry spi_codec = {
2724886ec58SHasso Tepper 	envy24ht_spi_create,
2734886ec58SHasso Tepper 	envy24ht_spi_destroy,
2744886ec58SHasso Tepper 	envy24ht_spi_init,
2754886ec58SHasso Tepper 	envy24ht_spi_reinit,
2764886ec58SHasso Tepper 	envy24ht_spi_setvolume,
2774886ec58SHasso Tepper 	NULL, /* setrate */
2784886ec58SHasso Tepper };
2794886ec58SHasso Tepper 
2804886ec58SHasso Tepper static struct cfg_info cfg_table[] = {
2814886ec58SHasso Tepper 	{
2824886ec58SHasso Tepper 		"Envy24HT audio (Terratec Aureon 7.1 Space)",
2834886ec58SHasso Tepper 		0x153b, 0x1145,
2844886ec58SHasso Tepper 		0x0b, 0x80, 0xfc, 0xc3,
2854886ec58SHasso Tepper 		0x21efff, 0x7fffff, 0x5e1000,
2864886ec58SHasso Tepper 		0x40000, 0x80000, 0x1000, 0x00, 0x02,
2874886ec58SHasso Tepper 		0,
2884886ec58SHasso Tepper 		&spi_codec,
2894886ec58SHasso Tepper 	},
2904886ec58SHasso Tepper         {
2914886ec58SHasso Tepper                 "Envy24HT audio (Terratec Aureon 5.1 Sky)",
2924886ec58SHasso Tepper                 0x153b, 0x1147,
2934886ec58SHasso Tepper                 0x0a, 0x80, 0xfc, 0xc3,
2944886ec58SHasso Tepper                 0x21efff, 0x7fffff, 0x5e1000,
2954886ec58SHasso Tepper                 0x40000, 0x80000, 0x1000, 0x00, 0x02,
2964886ec58SHasso Tepper                 0,
2974886ec58SHasso Tepper                 &spi_codec,
2984886ec58SHasso Tepper         },
2994886ec58SHasso Tepper 	        {
3004886ec58SHasso Tepper                 "Envy24HT audio (Terratec Aureon 7.1 Universe)",
3014886ec58SHasso Tepper                 0x153b, 0x1153,
3024886ec58SHasso Tepper                 0x0b, 0x80, 0xfc, 0xc3,
3034886ec58SHasso Tepper                 0x21efff, 0x7fffff, 0x5e1000,
3044886ec58SHasso Tepper                 0x40000, 0x80000, 0x1000, 0x00, 0x02,
3054886ec58SHasso Tepper                 0,
3064886ec58SHasso Tepper                 &spi_codec,
3074886ec58SHasso Tepper         },
3084886ec58SHasso Tepper         {
3094886ec58SHasso Tepper                 "Envy24HT audio (AudioTrak Prodigy 7.1)",
3104886ec58SHasso Tepper                 0x4933, 0x4553,
3114886ec58SHasso Tepper                 0x0b, 0x80, 0xfc, 0xc3,
3124886ec58SHasso Tepper                 0x21efff, 0x7fffff, 0x5e1000,
3134886ec58SHasso Tepper                 0x40000, 0x80000, 0x1000, 0x00, 0x02,
3144886ec58SHasso Tepper                 0,
3154886ec58SHasso Tepper                 &spi_codec,
3164886ec58SHasso Tepper         },
3174886ec58SHasso Tepper         {
3184886ec58SHasso Tepper                 "Envy24HT audio (Terratec PHASE 28)",
3194886ec58SHasso Tepper                 0x153b, 0x1149,
3204886ec58SHasso Tepper                 0x0b, 0x80, 0xfc, 0xc3,
3214886ec58SHasso Tepper                 0x21efff, 0x7fffff, 0x5e1000,
3224886ec58SHasso Tepper                 0x40000, 0x80000, 0x1000, 0x00, 0x02,
3234886ec58SHasso Tepper                 0,
3244886ec58SHasso Tepper                 &spi_codec,
3254886ec58SHasso Tepper         },
3264886ec58SHasso Tepper         {
3274886ec58SHasso Tepper                 "Envy24HT-S audio (Terratec PHASE 22)",
3284886ec58SHasso Tepper                 0x153b, 0x1150,
3294886ec58SHasso Tepper                 0x10, 0x80, 0xf0, 0xc3,
3304886ec58SHasso Tepper                 0x7ffbc7, 0x7fffff, 0x438,
3312a1ad637SFrançois Tigeot                 0x10, 0x20, 0x400, 0x01, 0x00,
3324886ec58SHasso Tepper                 0,
3334886ec58SHasso Tepper                 &spi_codec,
3344886ec58SHasso Tepper         },
3354886ec58SHasso Tepper         {
3364886ec58SHasso Tepper                 "Envy24HT audio (AudioTrak Prodigy 7.1 LT)",
3374886ec58SHasso Tepper                 0x3132, 0x4154,
3384886ec58SHasso Tepper                 0x4b, 0x80, 0xfc, 0xc3,
3394886ec58SHasso Tepper                 0x7ff8ff, 0x7fffff, 0x700,
3404886ec58SHasso Tepper                 0x400, 0x200, 0x100, 0x00, 0x02,
3414886ec58SHasso Tepper                 0,
3424886ec58SHasso Tepper                 &spi_codec,
3434886ec58SHasso Tepper         },
3444886ec58SHasso Tepper         {
3454886ec58SHasso Tepper                 "Envy24HT audio (AudioTrak Prodigy 7.1 XT)",
3464886ec58SHasso Tepper                 0x3136, 0x4154,
3474886ec58SHasso Tepper                 0x4b, 0x80, 0xfc, 0xc3,
3484886ec58SHasso Tepper                 0x7ff8ff, 0x7fffff, 0x700,
3494886ec58SHasso Tepper                 0x400, 0x200, 0x100, 0x00, 0x02,
3504886ec58SHasso Tepper                 0,
3514886ec58SHasso Tepper                 &spi_codec,
3524886ec58SHasso Tepper         },
3534886ec58SHasso Tepper         {
3544886ec58SHasso Tepper                 "Envy24HT audio (M-Audio Revolution 7.1)",
3554886ec58SHasso Tepper                 0x1412, 0x3630,
3564886ec58SHasso Tepper                 0x43, 0x80, 0xf8, 0xc1,
3572a1ad637SFrançois Tigeot                 0x3fff85, 0x400072, 0x4000fa,
3584886ec58SHasso Tepper                 0x08, 0x02, 0x20, 0x00, 0x04,
3594886ec58SHasso Tepper                 0,
3604886ec58SHasso Tepper                 &spi_codec,
3614886ec58SHasso Tepper         },
3624886ec58SHasso Tepper         {
3634886ec58SHasso Tepper                 "Envy24GT audio (M-Audio Revolution 5.1)",
3644886ec58SHasso Tepper                 0x1412, 0x3631,
3654886ec58SHasso Tepper                 0x42, 0x80, 0xf8, 0xc1,
3662a1ad637SFrançois Tigeot                 0x3fff05, 0x4000f0, 0x4000fa,
3674886ec58SHasso Tepper                 0x08, 0x02, 0x10, 0x00, 0x03,
3684886ec58SHasso Tepper                 0,
3694886ec58SHasso Tepper                 &spi_codec,
3704886ec58SHasso Tepper         },
3714886ec58SHasso Tepper         {
3724886ec58SHasso Tepper                 "Envy24HT audio (M-Audio Audiophile 192)",
3734886ec58SHasso Tepper                 0x1412, 0x3632,
3744886ec58SHasso Tepper                 0x68, 0x80, 0xf8, 0xc3,
3754886ec58SHasso Tepper                 0x45, 0x4000b5, 0x7fffba,
3764886ec58SHasso Tepper                 0x08, 0x02, 0x10, 0x00, 0x03,
3774886ec58SHasso Tepper                 0,
3784886ec58SHasso Tepper                 &spi_codec,
3794886ec58SHasso Tepper         },
3804886ec58SHasso Tepper         {
3814886ec58SHasso Tepper                 "Envy24HT audio (AudioTrak Prodigy HD2)",
3824886ec58SHasso Tepper                 0x3137, 0x4154,
3834886ec58SHasso Tepper                 0x68, 0x80, 0x78, 0xc3,
3844886ec58SHasso Tepper                 0xfff8ff, 0x200700, 0xdfffff,
3854886ec58SHasso Tepper                 0x400, 0x200, 0x100, 0x00, 0x05,
3864886ec58SHasso Tepper                 0,
3874886ec58SHasso Tepper                 &spi_codec,
3884886ec58SHasso Tepper         },
3894886ec58SHasso Tepper         {
3904886ec58SHasso Tepper                 "Envy24HT audio (ESI Juli@)",
3914886ec58SHasso Tepper                 0x3031, 0x4553,
3924886ec58SHasso Tepper                 0x20, 0x80, 0xf8, 0xc3,
3934886ec58SHasso Tepper                 0x7fff9f, 0x8016, 0x7fff9f,
3944886ec58SHasso Tepper                 0x08, 0x02, 0x10, 0x00, 0x03,
3954886ec58SHasso Tepper                 0,
3964886ec58SHasso Tepper                 &spi_codec,
3974886ec58SHasso Tepper         },
3984886ec58SHasso Tepper 	{
3992a1ad637SFrançois Tigeot                 "Envy24HT-S audio (Terrasoniq TS22PCI)",
4002a1ad637SFrançois Tigeot                 0x153b, 0x117b,
4012a1ad637SFrançois Tigeot                 0x10, 0x80, 0xf0, 0xc3,
4022a1ad637SFrançois Tigeot                 0x7ffbc7, 0x7fffff, 0x438,
4032a1ad637SFrançois Tigeot                 0x10, 0x20, 0x400, 0x01, 0x00,
4042a1ad637SFrançois Tigeot                 0,
4052a1ad637SFrançois Tigeot                 &spi_codec,
4062a1ad637SFrançois Tigeot 	},
4072a1ad637SFrançois Tigeot 	{
4084886ec58SHasso Tepper 		"Envy24HT audio (Generic)",
4094886ec58SHasso Tepper 		0, 0,
4104886ec58SHasso Tepper 		0x0b, 0x80, 0xfc, 0xc3,
4114886ec58SHasso Tepper 		0x21efff, 0x7fffff, 0x5e1000,
4124886ec58SHasso Tepper                 0x40000, 0x80000, 0x1000, 0x00, 0x02,
4134886ec58SHasso Tepper 		0,
4144886ec58SHasso Tepper 		&spi_codec, /* default codec routines */
4154886ec58SHasso Tepper 	}
4164886ec58SHasso Tepper };
4174886ec58SHasso Tepper 
4184886ec58SHasso Tepper static u_int32_t envy24ht_recfmt[] = {
4192a1ad637SFrançois Tigeot 	SND_FORMAT(AFMT_S16_LE, 2, 0),
4202a1ad637SFrançois Tigeot 	SND_FORMAT(AFMT_S32_LE, 2, 0),
4214886ec58SHasso Tepper 	0
4224886ec58SHasso Tepper };
4234886ec58SHasso Tepper static struct pcmchan_caps envy24ht_reccaps = {8000, 96000, envy24ht_recfmt, 0};
4244886ec58SHasso Tepper 
4254886ec58SHasso Tepper static u_int32_t envy24ht_playfmt[] = {
4262a1ad637SFrançois Tigeot 	SND_FORMAT(AFMT_U8, 2, 0),
4272a1ad637SFrançois Tigeot 	SND_FORMAT(AFMT_S16_LE, 2, 0),
4282a1ad637SFrançois Tigeot 	SND_FORMAT(AFMT_S32_LE, 2, 0),
4294886ec58SHasso Tepper 	0
4304886ec58SHasso Tepper };
4314886ec58SHasso Tepper 
4324886ec58SHasso Tepper static struct pcmchan_caps envy24ht_playcaps = {8000, 192000, envy24ht_playfmt, 0};
4334886ec58SHasso Tepper 
4344886ec58SHasso Tepper struct envy24ht_emldma {
4354886ec58SHasso Tepper 	u_int32_t	format;
4364886ec58SHasso Tepper 	void		(*emldma)(struct sc_chinfo *);
4374886ec58SHasso Tepper 	int		unit;
4384886ec58SHasso Tepper };
4394886ec58SHasso Tepper 
4404886ec58SHasso Tepper static struct envy24ht_emldma envy24ht_pemltab[] = {
4412a1ad637SFrançois Tigeot 	{SND_FORMAT(AFMT_U8, 2, 0), envy24ht_p8u, 2},
4422a1ad637SFrançois Tigeot 	{SND_FORMAT(AFMT_S16_LE, 2, 0), envy24ht_p16sl, 4},
4432a1ad637SFrançois Tigeot 	{SND_FORMAT(AFMT_S32_LE, 2, 0), envy24ht_p32sl, 8},
4444886ec58SHasso Tepper 	{0, NULL, 0}
4454886ec58SHasso Tepper };
4464886ec58SHasso Tepper 
4474886ec58SHasso Tepper static struct envy24ht_emldma envy24ht_remltab[] = {
4482a1ad637SFrançois Tigeot 	{SND_FORMAT(AFMT_S16_LE, 2, 0), envy24ht_r16sl, 4},
4492a1ad637SFrançois Tigeot 	{SND_FORMAT(AFMT_S32_LE, 2, 0), envy24ht_r32sl, 8},
4504886ec58SHasso Tepper 	{0, NULL, 0}
4514886ec58SHasso Tepper };
4524886ec58SHasso Tepper 
4534886ec58SHasso Tepper /* -------------------------------------------------------------------- */
4544886ec58SHasso Tepper 
4554886ec58SHasso Tepper /* common routines */
4564886ec58SHasso Tepper static u_int32_t
envy24ht_rdcs(struct sc_info * sc,int regno,int size)4574886ec58SHasso Tepper envy24ht_rdcs(struct sc_info *sc, int regno, int size)
4584886ec58SHasso Tepper {
4594886ec58SHasso Tepper 	switch (size) {
4604886ec58SHasso Tepper 	case 1:
4614886ec58SHasso Tepper 		return bus_space_read_1(sc->cst, sc->csh, regno);
4624886ec58SHasso Tepper 	case 2:
4634886ec58SHasso Tepper 		return bus_space_read_2(sc->cst, sc->csh, regno);
4644886ec58SHasso Tepper 	case 4:
4654886ec58SHasso Tepper 		return bus_space_read_4(sc->cst, sc->csh, regno);
4664886ec58SHasso Tepper 	default:
4674886ec58SHasso Tepper 		return 0xffffffff;
4684886ec58SHasso Tepper 	}
4694886ec58SHasso Tepper }
4704886ec58SHasso Tepper 
4714886ec58SHasso Tepper static void
envy24ht_wrcs(struct sc_info * sc,int regno,u_int32_t data,int size)4724886ec58SHasso Tepper envy24ht_wrcs(struct sc_info *sc, int regno, u_int32_t data, int size)
4734886ec58SHasso Tepper {
4744886ec58SHasso Tepper 	switch (size) {
4754886ec58SHasso Tepper 	case 1:
4764886ec58SHasso Tepper 		bus_space_write_1(sc->cst, sc->csh, regno, data);
4774886ec58SHasso Tepper 		break;
4784886ec58SHasso Tepper 	case 2:
4794886ec58SHasso Tepper 		bus_space_write_2(sc->cst, sc->csh, regno, data);
4804886ec58SHasso Tepper 		break;
4814886ec58SHasso Tepper 	case 4:
4824886ec58SHasso Tepper 		bus_space_write_4(sc->cst, sc->csh, regno, data);
4834886ec58SHasso Tepper 		break;
4844886ec58SHasso Tepper 	}
4854886ec58SHasso Tepper }
4864886ec58SHasso Tepper 
4874886ec58SHasso Tepper static u_int32_t
envy24ht_rdmt(struct sc_info * sc,int regno,int size)4884886ec58SHasso Tepper envy24ht_rdmt(struct sc_info *sc, int regno, int size)
4894886ec58SHasso Tepper {
4904886ec58SHasso Tepper 	switch (size) {
4914886ec58SHasso Tepper 	case 1:
4924886ec58SHasso Tepper 		return bus_space_read_1(sc->mtt, sc->mth, regno);
4934886ec58SHasso Tepper 	case 2:
4944886ec58SHasso Tepper 		return bus_space_read_2(sc->mtt, sc->mth, regno);
4954886ec58SHasso Tepper 	case 4:
4964886ec58SHasso Tepper 		return bus_space_read_4(sc->mtt, sc->mth, regno);
4974886ec58SHasso Tepper 	default:
4984886ec58SHasso Tepper 		return 0xffffffff;
4994886ec58SHasso Tepper 	}
5004886ec58SHasso Tepper }
5014886ec58SHasso Tepper 
5024886ec58SHasso Tepper static void
envy24ht_wrmt(struct sc_info * sc,int regno,u_int32_t data,int size)5034886ec58SHasso Tepper envy24ht_wrmt(struct sc_info *sc, int regno, u_int32_t data, int size)
5044886ec58SHasso Tepper {
5054886ec58SHasso Tepper 	switch (size) {
5064886ec58SHasso Tepper 	case 1:
5074886ec58SHasso Tepper 		bus_space_write_1(sc->mtt, sc->mth, regno, data);
5084886ec58SHasso Tepper 		break;
5094886ec58SHasso Tepper 	case 2:
5104886ec58SHasso Tepper 		bus_space_write_2(sc->mtt, sc->mth, regno, data);
5114886ec58SHasso Tepper 		break;
5124886ec58SHasso Tepper 	case 4:
5134886ec58SHasso Tepper 		bus_space_write_4(sc->mtt, sc->mth, regno, data);
5144886ec58SHasso Tepper 		break;
5154886ec58SHasso Tepper 	}
5164886ec58SHasso Tepper }
5174886ec58SHasso Tepper 
5184886ec58SHasso Tepper /* -------------------------------------------------------------------- */
5194886ec58SHasso Tepper 
5204886ec58SHasso Tepper /* I2C port/E2PROM access routines */
5214886ec58SHasso Tepper 
5224886ec58SHasso Tepper static int
envy24ht_rdi2c(struct sc_info * sc,u_int32_t dev,u_int32_t addr)5234886ec58SHasso Tepper envy24ht_rdi2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr)
5244886ec58SHasso Tepper {
5254886ec58SHasso Tepper 	u_int32_t data;
5264886ec58SHasso Tepper 	int i;
5274886ec58SHasso Tepper 
5282a1ad637SFrançois Tigeot #if(0)
5294886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
5304886ec58SHasso Tepper #endif
5314886ec58SHasso Tepper 	for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
5324886ec58SHasso Tepper 		data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
5334886ec58SHasso Tepper 		if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
5344886ec58SHasso Tepper 			break;
5354886ec58SHasso Tepper 		DELAY(32); /* 31.25kHz */
5364886ec58SHasso Tepper 	}
5374886ec58SHasso Tepper 	if (i == ENVY24HT_TIMEOUT) {
5384886ec58SHasso Tepper 		return -1;
5394886ec58SHasso Tepper 	}
5404886ec58SHasso Tepper 	envy24ht_wrcs(sc, ENVY24HT_CCS_I2CADDR, addr, 1);
5414886ec58SHasso Tepper 	envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDEV,
5424886ec58SHasso Tepper 	    (dev & ENVY24HT_CCS_I2CDEV_ADDR) | ENVY24HT_CCS_I2CDEV_RD, 1);
5434886ec58SHasso Tepper 	for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
5444886ec58SHasso Tepper 		data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
5454886ec58SHasso Tepper 		if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
5464886ec58SHasso Tepper 			break;
5474886ec58SHasso Tepper 		DELAY(32); /* 31.25kHz */
5484886ec58SHasso Tepper 	}
5494886ec58SHasso Tepper 	if (i == ENVY24HT_TIMEOUT) {
5504886ec58SHasso Tepper 		return -1;
5514886ec58SHasso Tepper 	}
5524886ec58SHasso Tepper 	data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CDATA, 1);
5534886ec58SHasso Tepper 
5542a1ad637SFrançois Tigeot #if(0)
5554886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_rdi2c(): return 0x%x\n", data);
5564886ec58SHasso Tepper #endif
5574886ec58SHasso Tepper 	return (int)data;
5584886ec58SHasso Tepper }
5594886ec58SHasso Tepper 
5604886ec58SHasso Tepper static int
envy24ht_wri2c(struct sc_info * sc,u_int32_t dev,u_int32_t addr,u_int32_t data)5614886ec58SHasso Tepper envy24ht_wri2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr, u_int32_t data)
5624886ec58SHasso Tepper {
5634886ec58SHasso Tepper 	u_int32_t tmp;
5644886ec58SHasso Tepper 	int i;
5654886ec58SHasso Tepper 
5662a1ad637SFrançois Tigeot #if(0)
5674886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
5684886ec58SHasso Tepper #endif
5694886ec58SHasso Tepper 	for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
5704886ec58SHasso Tepper 		tmp = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
5714886ec58SHasso Tepper 		if ((tmp & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
5724886ec58SHasso Tepper 			break;
5734886ec58SHasso Tepper 		DELAY(32); /* 31.25kHz */
5744886ec58SHasso Tepper 	}
5754886ec58SHasso Tepper 	if (i == ENVY24HT_TIMEOUT) {
5764886ec58SHasso Tepper 		return -1;
5774886ec58SHasso Tepper 	}
5784886ec58SHasso Tepper 	envy24ht_wrcs(sc, ENVY24HT_CCS_I2CADDR, addr, 1);
5794886ec58SHasso Tepper 	envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDATA, data, 1);
5804886ec58SHasso Tepper 	envy24ht_wrcs(sc, ENVY24HT_CCS_I2CDEV,
5814886ec58SHasso Tepper 	    (dev & ENVY24HT_CCS_I2CDEV_ADDR) | ENVY24HT_CCS_I2CDEV_WR, 1);
5824886ec58SHasso Tepper 	for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
5834886ec58SHasso Tepper 		data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
5844886ec58SHasso Tepper 		if ((data & ENVY24HT_CCS_I2CSTAT_BSY) == 0)
5854886ec58SHasso Tepper 			break;
5864886ec58SHasso Tepper 		DELAY(32); /* 31.25kHz */
5874886ec58SHasso Tepper 	}
5884886ec58SHasso Tepper 	if (i == ENVY24HT_TIMEOUT) {
5894886ec58SHasso Tepper 		return -1;
5904886ec58SHasso Tepper 	}
5914886ec58SHasso Tepper 
5924886ec58SHasso Tepper 	return 0;
5934886ec58SHasso Tepper }
5944886ec58SHasso Tepper 
5954886ec58SHasso Tepper static int
envy24ht_rdrom(struct sc_info * sc,u_int32_t addr)5964886ec58SHasso Tepper envy24ht_rdrom(struct sc_info *sc, u_int32_t addr)
5974886ec58SHasso Tepper {
5984886ec58SHasso Tepper 	u_int32_t data;
5994886ec58SHasso Tepper 
6002a1ad637SFrançois Tigeot #if(0)
6014886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_rdrom(sc, 0x%02x)\n", addr);
6024886ec58SHasso Tepper #endif
6034886ec58SHasso Tepper 	data = envy24ht_rdcs(sc, ENVY24HT_CCS_I2CSTAT, 1);
6044886ec58SHasso Tepper 	if ((data & ENVY24HT_CCS_I2CSTAT_ROM) == 0) {
6052a1ad637SFrançois Tigeot #if(0)
6064886ec58SHasso Tepper 		device_printf(sc->dev, "envy24ht_rdrom(): E2PROM not presented\n");
6074886ec58SHasso Tepper #endif
6084886ec58SHasso Tepper 		return -1;
6094886ec58SHasso Tepper 	}
6104886ec58SHasso Tepper 
6114886ec58SHasso Tepper 	return envy24ht_rdi2c(sc, ENVY24HT_CCS_I2CDEV_ROM, addr);
6124886ec58SHasso Tepper }
6134886ec58SHasso Tepper 
6144886ec58SHasso Tepper static struct cfg_info *
envy24ht_rom2cfg(struct sc_info * sc)6154886ec58SHasso Tepper envy24ht_rom2cfg(struct sc_info *sc)
6164886ec58SHasso Tepper {
6174886ec58SHasso Tepper 	struct cfg_info *buff;
6184886ec58SHasso Tepper 	int size;
6194886ec58SHasso Tepper 	int i;
6204886ec58SHasso Tepper 
6212a1ad637SFrançois Tigeot #if(0)
6224886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_rom2cfg(sc)\n");
6234886ec58SHasso Tepper #endif
6244886ec58SHasso Tepper 	size = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SIZE);
6254886ec58SHasso Tepper 	if ((size < ENVY24HT_E2PROM_GPIOSTATE + 3) || (size == 0x78)) {
6262a1ad637SFrançois Tigeot #if(0)
6274886ec58SHasso Tepper 		device_printf(sc->dev, "envy24ht_rom2cfg(): ENVY24HT_E2PROM_SIZE-->%d\n", size);
6284886ec58SHasso Tepper #endif
6294e8e900cSMatthew Dillon         buff = kmalloc(sizeof(*buff), M_ENVY24HT, M_WAITOK | M_ZERO);
6302a1ad637SFrançois Tigeot         if (buff == NULL) {
6312a1ad637SFrançois Tigeot #if(0)
6322a1ad637SFrançois Tigeot                 device_printf(sc->dev, "envy24ht_rom2cfg(): malloc()\n");
6332a1ad637SFrançois Tigeot #endif
6342a1ad637SFrançois Tigeot                 return NULL;
6352a1ad637SFrançois Tigeot         }
6364886ec58SHasso Tepper         buff->free = 1;
6374886ec58SHasso Tepper 
6384886ec58SHasso Tepper 	/* no valid e2prom, using default values */
6394886ec58SHasso Tepper         buff->subvendor = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR) << 8;
6404886ec58SHasso Tepper         buff->subvendor += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR + 1);
6414886ec58SHasso Tepper         buff->subdevice = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE) << 8;
6424886ec58SHasso Tepper         buff->subdevice += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE + 1);
6434886ec58SHasso Tepper         buff->scfg = 0x0b;
6444886ec58SHasso Tepper         buff->acl = 0x80;
6454886ec58SHasso Tepper         buff->i2s = 0xfc;
6464886ec58SHasso Tepper         buff->spdif = 0xc3;
6474886ec58SHasso Tepper         buff->gpiomask = 0x21efff;
6484886ec58SHasso Tepper         buff->gpiostate = 0x7fffff;
6494886ec58SHasso Tepper         buff->gpiodir = 0x5e1000;
6504886ec58SHasso Tepper 	buff->cdti = 0x40000;
6514886ec58SHasso Tepper 	buff->cclk = 0x80000;
6524886ec58SHasso Tepper 	buff->cs = 0x1000;
6534886ec58SHasso Tepper 	buff->cif = 0x00;
6544886ec58SHasso Tepper 	buff->type = 0x02;
6554886ec58SHasso Tepper 
6564886ec58SHasso Tepper         for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0;
6574886ec58SHasso Tepper i++)
6584886ec58SHasso Tepper                 if (cfg_table[i].subvendor == buff->subvendor &&
6594886ec58SHasso Tepper                     cfg_table[i].subdevice == buff->subdevice)
6604886ec58SHasso Tepper                         break;
6614886ec58SHasso Tepper         buff->name = cfg_table[i].name;
6624886ec58SHasso Tepper         buff->codec = cfg_table[i].codec;
6634886ec58SHasso Tepper 
6644886ec58SHasso Tepper 		return buff;
6654886ec58SHasso Tepper #if 0
6664886ec58SHasso Tepper 		return NULL;
6674886ec58SHasso Tepper #endif
6684886ec58SHasso Tepper 	}
6694e8e900cSMatthew Dillon 	buff = kmalloc(sizeof(*buff), M_ENVY24HT, M_WAITOK | M_ZERO);
6702a1ad637SFrançois Tigeot 	if (buff == NULL) {
6712a1ad637SFrançois Tigeot #if(0)
6722a1ad637SFrançois Tigeot 		device_printf(sc->dev, "envy24ht_rom2cfg(): malloc()\n");
6732a1ad637SFrançois Tigeot #endif
6742a1ad637SFrançois Tigeot 		return NULL;
6752a1ad637SFrançois Tigeot 	}
6764886ec58SHasso Tepper 	buff->free = 1;
6774886ec58SHasso Tepper 
6784886ec58SHasso Tepper 	buff->subvendor = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR) << 8;
6794886ec58SHasso Tepper 	buff->subvendor += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBVENDOR + 1);
6804886ec58SHasso Tepper 	buff->subdevice = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE) << 8;
6814886ec58SHasso Tepper 	buff->subdevice += envy24ht_rdrom(sc, ENVY24HT_E2PROM_SUBDEVICE + 1);
6824886ec58SHasso Tepper 	buff->scfg = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SCFG);
6834886ec58SHasso Tepper 	buff->acl = envy24ht_rdrom(sc, ENVY24HT_E2PROM_ACL);
6844886ec58SHasso Tepper 	buff->i2s = envy24ht_rdrom(sc, ENVY24HT_E2PROM_I2S);
6854886ec58SHasso Tepper 	buff->spdif = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SPDIF);
6864886ec58SHasso Tepper 	buff->gpiomask = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK) | \
6874886ec58SHasso Tepper 	envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK + 1) << 8 | \
6884886ec58SHasso Tepper 	envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOMASK + 2) << 16;
6894886ec58SHasso Tepper 	buff->gpiostate = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE) | \
6904886ec58SHasso Tepper 	envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE + 1) << 8 | \
6914886ec58SHasso Tepper 	envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIOSTATE + 2) << 16;
6924886ec58SHasso Tepper 	buff->gpiodir = envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR) | \
6934886ec58SHasso Tepper 	envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR + 1) << 8 | \
6944886ec58SHasso Tepper 	envy24ht_rdrom(sc, ENVY24HT_E2PROM_GPIODIR + 2) << 16;
6954886ec58SHasso Tepper 
6964886ec58SHasso Tepper 	for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++)
6974886ec58SHasso Tepper 		if (cfg_table[i].subvendor == buff->subvendor &&
6984886ec58SHasso Tepper 		    cfg_table[i].subdevice == buff->subdevice)
6994886ec58SHasso Tepper 			break;
7004886ec58SHasso Tepper 	buff->name = cfg_table[i].name;
7014886ec58SHasso Tepper 	buff->codec = cfg_table[i].codec;
7024886ec58SHasso Tepper 
7034886ec58SHasso Tepper 	return buff;
7044886ec58SHasso Tepper }
7054886ec58SHasso Tepper 
7064886ec58SHasso Tepper static void
envy24ht_cfgfree(struct cfg_info * cfg)7074886ec58SHasso Tepper envy24ht_cfgfree(struct cfg_info *cfg) {
7084886ec58SHasso Tepper 	if (cfg == NULL)
7094886ec58SHasso Tepper 		return;
7104886ec58SHasso Tepper 	if (cfg->free)
71167931cc4SFrançois Tigeot 		kfree(cfg, M_ENVY24HT);
7124886ec58SHasso Tepper 	return;
7134886ec58SHasso Tepper }
7144886ec58SHasso Tepper 
7154886ec58SHasso Tepper /* -------------------------------------------------------------------- */
7164886ec58SHasso Tepper 
7174886ec58SHasso Tepper /* AC'97 codec access routines */
7184886ec58SHasso Tepper 
7194886ec58SHasso Tepper #if 0
7204886ec58SHasso Tepper static int
envy24ht_coldcd(struct sc_info * sc)7214886ec58SHasso Tepper envy24ht_coldcd(struct sc_info *sc)
7224886ec58SHasso Tepper {
7234886ec58SHasso Tepper 	u_int32_t data;
7244886ec58SHasso Tepper 	int i;
7254886ec58SHasso Tepper 
7262a1ad637SFrançois Tigeot #if(0)
7274886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_coldcd()\n");
7284886ec58SHasso Tepper #endif
7294886ec58SHasso Tepper 	envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_CLD, 1);
7304886ec58SHasso Tepper 	DELAY(10);
7314886ec58SHasso Tepper 	envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, 0, 1);
7324886ec58SHasso Tepper 	DELAY(1000);
7334886ec58SHasso Tepper 	for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
7344886ec58SHasso Tepper 		data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
7354886ec58SHasso Tepper 		if (data & ENVY24HT_MT_AC97CMD_RDY) {
7364886ec58SHasso Tepper 			return 0;
7374886ec58SHasso Tepper 		}
7384886ec58SHasso Tepper 	}
7394886ec58SHasso Tepper 
7404886ec58SHasso Tepper 	return -1;
7414886ec58SHasso Tepper }
7424886ec58SHasso Tepper 
7434886ec58SHasso Tepper static int
envy24ht_slavecd(struct sc_info * sc)7444886ec58SHasso Tepper envy24ht_slavecd(struct sc_info *sc)
7454886ec58SHasso Tepper {
7464886ec58SHasso Tepper 	u_int32_t data;
7474886ec58SHasso Tepper 	int i;
7484886ec58SHasso Tepper 
7492a1ad637SFrançois Tigeot #if(0)
7504886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_slavecd()\n");
7514886ec58SHasso Tepper #endif
7524886ec58SHasso Tepper 	envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD,
7534886ec58SHasso Tepper 	    ENVY24HT_MT_AC97CMD_CLD | ENVY24HT_MT_AC97CMD_WRM, 1);
7544886ec58SHasso Tepper 	DELAY(10);
7554886ec58SHasso Tepper 	envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, 0, 1);
7564886ec58SHasso Tepper 	DELAY(1000);
7574886ec58SHasso Tepper 	for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
7584886ec58SHasso Tepper 		data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
7594886ec58SHasso Tepper 		if (data & ENVY24HT_MT_AC97CMD_RDY) {
7604886ec58SHasso Tepper 			return 0;
7614886ec58SHasso Tepper 		}
7624886ec58SHasso Tepper 	}
7634886ec58SHasso Tepper 
7644886ec58SHasso Tepper 	return -1;
7654886ec58SHasso Tepper }
7664886ec58SHasso Tepper 
7674886ec58SHasso Tepper static int
envy24ht_rdcd(kobj_t obj,void * devinfo,int regno)7684886ec58SHasso Tepper envy24ht_rdcd(kobj_t obj, void *devinfo, int regno)
7694886ec58SHasso Tepper {
7704886ec58SHasso Tepper 	struct sc_info *sc = (struct sc_info *)devinfo;
7714886ec58SHasso Tepper 	u_int32_t data;
7724886ec58SHasso Tepper 	int i;
7734886ec58SHasso Tepper 
7742a1ad637SFrançois Tigeot #if(0)
7754886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_rdcd(obj, sc, 0x%02x)\n", regno);
7764886ec58SHasso Tepper #endif
7774886ec58SHasso Tepper 	envy24ht_wrmt(sc, ENVY24HT_MT_AC97IDX, (u_int32_t)regno, 1);
7784886ec58SHasso Tepper 	envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_RD, 1);
7794886ec58SHasso Tepper 	for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
7804886ec58SHasso Tepper 		data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
7814886ec58SHasso Tepper 		if ((data & ENVY24HT_MT_AC97CMD_RD) == 0)
7824886ec58SHasso Tepper 			break;
7834886ec58SHasso Tepper 	}
7844886ec58SHasso Tepper 	data = envy24ht_rdmt(sc, ENVY24HT_MT_AC97DLO, 2);
7854886ec58SHasso Tepper 
7862a1ad637SFrançois Tigeot #if(0)
7874886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_rdcd(): return 0x%x\n", data);
7884886ec58SHasso Tepper #endif
7894886ec58SHasso Tepper 	return (int)data;
7904886ec58SHasso Tepper }
7914886ec58SHasso Tepper 
7924886ec58SHasso Tepper static int
envy24ht_wrcd(kobj_t obj,void * devinfo,int regno,u_int16_t data)7934886ec58SHasso Tepper envy24ht_wrcd(kobj_t obj, void *devinfo, int regno, u_int16_t data)
7944886ec58SHasso Tepper {
7954886ec58SHasso Tepper 	struct sc_info *sc = (struct sc_info *)devinfo;
7964886ec58SHasso Tepper 	u_int32_t cmd;
7974886ec58SHasso Tepper 	int i;
7984886ec58SHasso Tepper 
7992a1ad637SFrançois Tigeot #if(0)
8004886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_wrcd(obj, sc, 0x%02x, 0x%04x)\n", regno, data);
8014886ec58SHasso Tepper #endif
8024886ec58SHasso Tepper 	envy24ht_wrmt(sc, ENVY24HT_MT_AC97IDX, (u_int32_t)regno, 1);
8034886ec58SHasso Tepper 	envy24ht_wrmt(sc, ENVY24HT_MT_AC97DLO, (u_int32_t)data, 2);
8044886ec58SHasso Tepper 	envy24ht_wrmt(sc, ENVY24HT_MT_AC97CMD, ENVY24HT_MT_AC97CMD_WR, 1);
8054886ec58SHasso Tepper 	for (i = 0; i < ENVY24HT_TIMEOUT; i++) {
8064886ec58SHasso Tepper 		cmd = envy24ht_rdmt(sc, ENVY24HT_MT_AC97CMD, 1);
8074886ec58SHasso Tepper 		if ((cmd & ENVY24HT_MT_AC97CMD_WR) == 0)
8084886ec58SHasso Tepper 			break;
8094886ec58SHasso Tepper 	}
8104886ec58SHasso Tepper 
8114886ec58SHasso Tepper 	return 0;
8124886ec58SHasso Tepper }
8134886ec58SHasso Tepper 
8144886ec58SHasso Tepper static kobj_method_t envy24ht_ac97_methods[] = {
8154886ec58SHasso Tepper 	KOBJMETHOD(ac97_read,	envy24ht_rdcd),
8164886ec58SHasso Tepper 	KOBJMETHOD(ac97_write,	envy24ht_wrcd),
8177774cda2SSascha Wildner 	KOBJMETHOD_END
8184886ec58SHasso Tepper };
8194886ec58SHasso Tepper AC97_DECLARE(envy24ht_ac97);
8204886ec58SHasso Tepper #endif
8214886ec58SHasso Tepper 
8224886ec58SHasso Tepper /* -------------------------------------------------------------------- */
8234886ec58SHasso Tepper 
8244886ec58SHasso Tepper /* GPIO access routines */
8254886ec58SHasso Tepper 
8264886ec58SHasso Tepper static u_int32_t
envy24ht_gpiord(struct sc_info * sc)8274886ec58SHasso Tepper envy24ht_gpiord(struct sc_info *sc)
8284886ec58SHasso Tepper {
8294886ec58SHasso Tepper 	if (sc->cfg->subvendor == 0x153b  && sc->cfg->subdevice == 0x1150)
8304886ec58SHasso Tepper 	return envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LDATA, 2);
8314886ec58SHasso Tepper 	else
8324886ec58SHasso Tepper 	return (envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_HDATA, 1) << 16 | envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LDATA, 2));
8334886ec58SHasso Tepper }
8344886ec58SHasso Tepper 
8354886ec58SHasso Tepper static void
envy24ht_gpiowr(struct sc_info * sc,u_int32_t data)8364886ec58SHasso Tepper envy24ht_gpiowr(struct sc_info *sc, u_int32_t data)
8374886ec58SHasso Tepper {
8382a1ad637SFrançois Tigeot #if(0)
8394886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_gpiowr(sc, 0x%02x)\n", data & 0x7FFFFF);
8404886ec58SHasso Tepper 	return;
8414886ec58SHasso Tepper #endif
8424886ec58SHasso Tepper 	envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_LDATA, data, 2);
8434886ec58SHasso Tepper 	if (sc->cfg->subdevice != 0x1150)
8444886ec58SHasso Tepper 	envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_HDATA, data >> 16, 1);
8454886ec58SHasso Tepper 	return;
8464886ec58SHasso Tepper }
8474886ec58SHasso Tepper 
8484886ec58SHasso Tepper #if 0
8494886ec58SHasso Tepper static u_int32_t
envy24ht_gpiogetmask(struct sc_info * sc)8504886ec58SHasso Tepper envy24ht_gpiogetmask(struct sc_info *sc)
8514886ec58SHasso Tepper {
8524886ec58SHasso Tepper 	return (envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_HMASK, 1) << 16 | envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_LMASK, 2));
8534886ec58SHasso Tepper }
8544886ec58SHasso Tepper #endif
8554886ec58SHasso Tepper 
8564886ec58SHasso Tepper static void
envy24ht_gpiosetmask(struct sc_info * sc,u_int32_t mask)8574886ec58SHasso Tepper envy24ht_gpiosetmask(struct sc_info *sc, u_int32_t mask)
8584886ec58SHasso Tepper {
8594886ec58SHasso Tepper         envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_LMASK, mask, 2);
8604886ec58SHasso Tepper 	if (sc->cfg->subdevice != 0x1150)
8614886ec58SHasso Tepper         envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_HMASK, mask >> 16, 1);
8624886ec58SHasso Tepper 	return;
8634886ec58SHasso Tepper }
8644886ec58SHasso Tepper 
8654886ec58SHasso Tepper #if 0
8664886ec58SHasso Tepper static u_int32_t
envy24ht_gpiogetdir(struct sc_info * sc)8674886ec58SHasso Tepper envy24ht_gpiogetdir(struct sc_info *sc)
8684886ec58SHasso Tepper {
8694886ec58SHasso Tepper 	return envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, 4);
8704886ec58SHasso Tepper }
8714886ec58SHasso Tepper #endif
8724886ec58SHasso Tepper 
8734886ec58SHasso Tepper static void
envy24ht_gpiosetdir(struct sc_info * sc,u_int32_t dir)8744886ec58SHasso Tepper envy24ht_gpiosetdir(struct sc_info *sc, u_int32_t dir)
8754886ec58SHasso Tepper {
8764886ec58SHasso Tepper 	if (sc->cfg->subvendor == 0x153b  && sc->cfg->subdevice == 0x1150)
8774886ec58SHasso Tepper 	envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, dir, 2);
8784886ec58SHasso Tepper 	else
8794886ec58SHasso Tepper 	envy24ht_wrcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, dir, 4);
8804886ec58SHasso Tepper 	return;
8814886ec58SHasso Tepper }
8824886ec58SHasso Tepper 
8834886ec58SHasso Tepper /* -------------------------------------------------------------------- */
8844886ec58SHasso Tepper 
8854886ec58SHasso Tepper /* SPI codec access interface routine */
8864886ec58SHasso Tepper 
8874886ec58SHasso Tepper struct envy24ht_spi_codec {
8884886ec58SHasso Tepper 	struct spicds_info *info;
8894886ec58SHasso Tepper 	struct sc_info *parent;
8904886ec58SHasso Tepper 	int dir;
8914886ec58SHasso Tepper 	int num;
8924886ec58SHasso Tepper 	int cs, cclk, cdti;
8934886ec58SHasso Tepper };
8944886ec58SHasso Tepper 
8954886ec58SHasso Tepper static void
envy24ht_spi_ctl(void * codec,unsigned int cs,unsigned int cclk,unsigned int cdti)8964886ec58SHasso Tepper envy24ht_spi_ctl(void *codec, unsigned int cs, unsigned int cclk, unsigned int cdti)
8974886ec58SHasso Tepper {
8984886ec58SHasso Tepper 	u_int32_t data = 0;
8994886ec58SHasso Tepper 	struct envy24ht_spi_codec *ptr = codec;
9004886ec58SHasso Tepper 
9012a1ad637SFrançois Tigeot #if(0)
9024886ec58SHasso Tepper 	device_printf(ptr->parent->dev, "--> %d, %d, %d\n", cs, cclk, cdti);
9034886ec58SHasso Tepper #endif
9044886ec58SHasso Tepper 	data = envy24ht_gpiord(ptr->parent);
9054886ec58SHasso Tepper 	data &= ~(ptr->cs | ptr->cclk | ptr->cdti);
9064886ec58SHasso Tepper 	if (cs) data += ptr->cs;
9074886ec58SHasso Tepper 	if (cclk) data += ptr->cclk;
9084886ec58SHasso Tepper 	if (cdti) data += ptr->cdti;
9094886ec58SHasso Tepper 	envy24ht_gpiowr(ptr->parent, data);
9104886ec58SHasso Tepper 	return;
9114886ec58SHasso Tepper }
9124886ec58SHasso Tepper 
9134886ec58SHasso Tepper static void *
envy24ht_spi_create(device_t dev,void * info,int dir,int num)9144886ec58SHasso Tepper envy24ht_spi_create(device_t dev, void *info, int dir, int num)
9154886ec58SHasso Tepper {
9164886ec58SHasso Tepper 	struct sc_info *sc = info;
9174886ec58SHasso Tepper 	struct envy24ht_spi_codec *buff = NULL;
9184886ec58SHasso Tepper 
9192a1ad637SFrançois Tigeot #if(0)
9204886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_spi_create(dev, sc, %d, %d)\n", dir, num);
9214886ec58SHasso Tepper #endif
9224886ec58SHasso Tepper 
9234e8e900cSMatthew Dillon 	buff = kmalloc(sizeof(*buff), M_ENVY24HT, M_WAITOK | M_ZERO);
9242a1ad637SFrançois Tigeot 	if (buff == NULL)
9252a1ad637SFrançois Tigeot 		return NULL;
9264886ec58SHasso Tepper 
9274886ec58SHasso Tepper 	if (dir == PCMDIR_REC && sc->adc[num] != NULL)
9284886ec58SHasso Tepper 		buff->info = ((struct envy24ht_spi_codec *)sc->adc[num])->info;
9294886ec58SHasso Tepper 	else if (dir == PCMDIR_PLAY && sc->dac[num] != NULL)
9304886ec58SHasso Tepper 		buff->info = ((struct envy24ht_spi_codec *)sc->dac[num])->info;
9314886ec58SHasso Tepper 	else
9324886ec58SHasso Tepper 		buff->info = spicds_create(dev, buff, num, envy24ht_spi_ctl);
9334886ec58SHasso Tepper 	if (buff->info == NULL) {
93467931cc4SFrançois Tigeot 		kfree(buff, M_ENVY24HT);
9354886ec58SHasso Tepper 		return NULL;
9364886ec58SHasso Tepper 	}
9374886ec58SHasso Tepper 
9384886ec58SHasso Tepper 	buff->parent = sc;
9394886ec58SHasso Tepper 	buff->dir = dir;
9404886ec58SHasso Tepper 	buff->num = num;
9414886ec58SHasso Tepper 
9424886ec58SHasso Tepper 	return (void *)buff;
9434886ec58SHasso Tepper }
9444886ec58SHasso Tepper 
9454886ec58SHasso Tepper static void
envy24ht_spi_destroy(void * codec)9464886ec58SHasso Tepper envy24ht_spi_destroy(void *codec)
9474886ec58SHasso Tepper {
9484886ec58SHasso Tepper 	struct envy24ht_spi_codec *ptr = codec;
9494886ec58SHasso Tepper 	if (ptr == NULL)
9504886ec58SHasso Tepper 		return;
9512a1ad637SFrançois Tigeot #if(0)
9524886ec58SHasso Tepper 	device_printf(ptr->parent->dev, "envy24ht_spi_destroy()\n");
9534886ec58SHasso Tepper #endif
9544886ec58SHasso Tepper 
9554886ec58SHasso Tepper 	if (ptr->dir == PCMDIR_PLAY) {
9564886ec58SHasso Tepper 		if (ptr->parent->dac[ptr->num] != NULL)
9574886ec58SHasso Tepper 			spicds_destroy(ptr->info);
9584886ec58SHasso Tepper 	}
9594886ec58SHasso Tepper 	else {
9604886ec58SHasso Tepper 		if (ptr->parent->adc[ptr->num] != NULL)
9614886ec58SHasso Tepper 			spicds_destroy(ptr->info);
9624886ec58SHasso Tepper 	}
9634886ec58SHasso Tepper 
96467931cc4SFrançois Tigeot 	kfree(codec, M_ENVY24HT);
9654886ec58SHasso Tepper }
9664886ec58SHasso Tepper 
9674886ec58SHasso Tepper static void
envy24ht_spi_init(void * codec)9684886ec58SHasso Tepper envy24ht_spi_init(void *codec)
9694886ec58SHasso Tepper {
9704886ec58SHasso Tepper 	struct envy24ht_spi_codec *ptr = codec;
9714886ec58SHasso Tepper 	if (ptr == NULL)
9724886ec58SHasso Tepper 		return;
9732a1ad637SFrançois Tigeot #if(0)
9744886ec58SHasso Tepper 	device_printf(ptr->parent->dev, "envy24ht_spicds_init()\n");
9754886ec58SHasso Tepper #endif
9764886ec58SHasso Tepper         ptr->cs = ptr->parent->cfg->cs;
9774886ec58SHasso Tepper 	ptr->cclk = ptr->parent->cfg->cclk;
9784886ec58SHasso Tepper 	ptr->cdti =  ptr->parent->cfg->cdti;
9794886ec58SHasso Tepper 	spicds_settype(ptr->info, ptr->parent->cfg->type);
9804886ec58SHasso Tepper 	spicds_setcif(ptr->info, ptr->parent->cfg->cif);
9814886ec58SHasso Tepper 	if (ptr->parent->cfg->type == SPICDS_TYPE_AK4524 || \
9824886ec58SHasso Tepper 	ptr->parent->cfg->type == SPICDS_TYPE_AK4528) {
9834886ec58SHasso Tepper 	spicds_setformat(ptr->info,
9844886ec58SHasso Tepper 	    AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X);
9854886ec58SHasso Tepper 	spicds_setdvc(ptr->info, AK452X_DVC_DEMOFF);
9864886ec58SHasso Tepper 	}
9874886ec58SHasso Tepper 
9884886ec58SHasso Tepper 	/* for the time being, init only first codec */
9894886ec58SHasso Tepper 	if (ptr->num == 0)
9904886ec58SHasso Tepper 	spicds_init(ptr->info);
9914886ec58SHasso Tepper }
9924886ec58SHasso Tepper 
9934886ec58SHasso Tepper static void
envy24ht_spi_reinit(void * codec)9944886ec58SHasso Tepper envy24ht_spi_reinit(void *codec)
9954886ec58SHasso Tepper {
9964886ec58SHasso Tepper 	struct envy24ht_spi_codec *ptr = codec;
9974886ec58SHasso Tepper 	if (ptr == NULL)
9984886ec58SHasso Tepper 		return;
9992a1ad637SFrançois Tigeot #if(0)
10004886ec58SHasso Tepper 	device_printf(ptr->parent->dev, "envy24ht_spi_reinit()\n");
10014886ec58SHasso Tepper #endif
10024886ec58SHasso Tepper 
10034886ec58SHasso Tepper 	spicds_reinit(ptr->info);
10044886ec58SHasso Tepper }
10054886ec58SHasso Tepper 
10064886ec58SHasso Tepper static void
envy24ht_spi_setvolume(void * codec,int dir,unsigned int left,unsigned int right)10074886ec58SHasso Tepper envy24ht_spi_setvolume(void *codec, int dir, unsigned int left, unsigned int right)
10084886ec58SHasso Tepper {
10094886ec58SHasso Tepper 	struct envy24ht_spi_codec *ptr = codec;
10104886ec58SHasso Tepper 	if (ptr == NULL)
10114886ec58SHasso Tepper 		return;
10122a1ad637SFrançois Tigeot #if(0)
10134886ec58SHasso Tepper 	device_printf(ptr->parent->dev, "envy24ht_spi_set()\n");
10144886ec58SHasso Tepper #endif
10154886ec58SHasso Tepper 
10164886ec58SHasso Tepper 	spicds_set(ptr->info, dir, left, right);
10174886ec58SHasso Tepper }
10184886ec58SHasso Tepper 
10194886ec58SHasso Tepper /* -------------------------------------------------------------------- */
10204886ec58SHasso Tepper 
10214886ec58SHasso Tepper /* hardware access routeines */
10224886ec58SHasso Tepper 
10234886ec58SHasso Tepper static struct {
10244886ec58SHasso Tepper 	u_int32_t speed;
10254886ec58SHasso Tepper 	u_int32_t code;
10264886ec58SHasso Tepper } envy24ht_speedtab[] = {
10274886ec58SHasso Tepper 	{48000, ENVY24HT_MT_RATE_48000},
10284886ec58SHasso Tepper 	{24000, ENVY24HT_MT_RATE_24000},
10294886ec58SHasso Tepper 	{12000, ENVY24HT_MT_RATE_12000},
10304886ec58SHasso Tepper 	{9600, ENVY24HT_MT_RATE_9600},
10314886ec58SHasso Tepper 	{32000, ENVY24HT_MT_RATE_32000},
10324886ec58SHasso Tepper 	{16000, ENVY24HT_MT_RATE_16000},
10334886ec58SHasso Tepper 	{8000, ENVY24HT_MT_RATE_8000},
10344886ec58SHasso Tepper 	{96000, ENVY24HT_MT_RATE_96000},
10354886ec58SHasso Tepper 	{192000, ENVY24HT_MT_RATE_192000},
10364886ec58SHasso Tepper 	{64000, ENVY24HT_MT_RATE_64000},
10374886ec58SHasso Tepper 	{44100, ENVY24HT_MT_RATE_44100},
10384886ec58SHasso Tepper 	{22050, ENVY24HT_MT_RATE_22050},
10394886ec58SHasso Tepper 	{11025, ENVY24HT_MT_RATE_11025},
10404886ec58SHasso Tepper 	{88200, ENVY24HT_MT_RATE_88200},
10414886ec58SHasso Tepper 	{176400, ENVY24HT_MT_RATE_176400},
10424886ec58SHasso Tepper 	{0, 0x10}
10434886ec58SHasso Tepper };
10444886ec58SHasso Tepper 
10452a1ad637SFrançois Tigeot static u_int32_t
envy24ht_setspeed(struct sc_info * sc,u_int32_t speed)10464886ec58SHasso Tepper envy24ht_setspeed(struct sc_info *sc, u_int32_t speed) {
10474886ec58SHasso Tepper 	u_int32_t code, i2sfmt;
10484886ec58SHasso Tepper 	int i = 0;
10494886ec58SHasso Tepper 
10502a1ad637SFrançois Tigeot #if(0)
10514886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_setspeed(sc, %d)\n", speed);
10524886ec58SHasso Tepper 	if (speed == 0) {
10534886ec58SHasso Tepper 		code = ENVY24HT_MT_RATE_SPDIF; /* external master clock */
10544886ec58SHasso Tepper 		envy24ht_slavecd(sc);
10554886ec58SHasso Tepper 	}
10564886ec58SHasso Tepper 	else {
10574886ec58SHasso Tepper #endif
10584886ec58SHasso Tepper 		for (i = 0; envy24ht_speedtab[i].speed != 0; i++) {
10594886ec58SHasso Tepper 			if (envy24ht_speedtab[i].speed == speed)
10604886ec58SHasso Tepper 				break;
10614886ec58SHasso Tepper 		}
10624886ec58SHasso Tepper 		code = envy24ht_speedtab[i].code;
10634886ec58SHasso Tepper #if 0
10644886ec58SHasso Tepper 	}
10654886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_setspeed(): speed %d/code 0x%04x\n", envy24ht_speedtab[i].speed, code);
10664886ec58SHasso Tepper #endif
10674886ec58SHasso Tepper 	if (code < 0x10) {
10684886ec58SHasso Tepper 		envy24ht_wrmt(sc, ENVY24HT_MT_RATE, code, 1);
10694886ec58SHasso Tepper 		if ((((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) == 0x00) && (code == ENVY24HT_MT_RATE_192000)) || \
10704886ec58SHasso Tepper 									    (code == ENVY24HT_MT_RATE_176400)) {
10714886ec58SHasso Tepper 			i2sfmt = envy24ht_rdmt(sc, ENVY24HT_MT_I2S, 1);
10724886ec58SHasso Tepper 			i2sfmt |= ENVY24HT_MT_I2S_MLR128;
10734886ec58SHasso Tepper 			envy24ht_wrmt(sc, ENVY24HT_MT_I2S, i2sfmt, 1);
10744886ec58SHasso Tepper 		}
10754886ec58SHasso Tepper 		else {
10764886ec58SHasso Tepper 			i2sfmt = envy24ht_rdmt(sc, ENVY24HT_MT_I2S, 1);
10774886ec58SHasso Tepper 			i2sfmt &= ~ENVY24HT_MT_I2S_MLR128;
10784886ec58SHasso Tepper 			envy24ht_wrmt(sc, ENVY24HT_MT_I2S, i2sfmt, 1);
10794886ec58SHasso Tepper 		}
10804886ec58SHasso Tepper 		code = envy24ht_rdmt(sc, ENVY24HT_MT_RATE, 1);
10814886ec58SHasso Tepper 		code &= ENVY24HT_MT_RATE_MASK;
10824886ec58SHasso Tepper 		for (i = 0; envy24ht_speedtab[i].code < 0x10; i++) {
10834886ec58SHasso Tepper 			if (envy24ht_speedtab[i].code == code)
10844886ec58SHasso Tepper 				break;
10854886ec58SHasso Tepper 		}
10864886ec58SHasso Tepper 		speed = envy24ht_speedtab[i].speed;
10874886ec58SHasso Tepper 	}
10884886ec58SHasso Tepper 	else
10894886ec58SHasso Tepper 		speed = 0;
10904886ec58SHasso Tepper 
10912a1ad637SFrançois Tigeot #if(0)
10924886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_setspeed(): return %d\n", speed);
10934886ec58SHasso Tepper #endif
10944886ec58SHasso Tepper 	return speed;
10954886ec58SHasso Tepper }
10964886ec58SHasso Tepper 
10974886ec58SHasso Tepper static void
envy24ht_setvolume(struct sc_info * sc,unsigned ch)10984886ec58SHasso Tepper envy24ht_setvolume(struct sc_info *sc, unsigned ch)
10994886ec58SHasso Tepper {
11002a1ad637SFrançois Tigeot #if(0)
11014886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_setvolume(sc, %d)\n", ch);
11024886ec58SHasso Tepper 	envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2, 1);
11034886ec58SHasso Tepper 	envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, 0x7f00 | sc->left[ch], 2);
11044886ec58SHasso Tepper 	envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2 + 1, 1);
11054886ec58SHasso Tepper 	envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, (sc->right[ch] << 8) | 0x7f, 2);
11064886ec58SHasso Tepper #endif
11074886ec58SHasso Tepper }
11084886ec58SHasso Tepper 
11094886ec58SHasso Tepper static void
envy24ht_mutevolume(struct sc_info * sc,unsigned ch)11104886ec58SHasso Tepper envy24ht_mutevolume(struct sc_info *sc, unsigned ch)
11114886ec58SHasso Tepper {
11124886ec58SHasso Tepper #if 0
11134886ec58SHasso Tepper 	u_int32_t vol;
11144886ec58SHasso Tepper 
11154886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_mutevolume(sc, %d)\n", ch);
11164886ec58SHasso Tepper 	vol = ENVY24HT_VOL_MUTE << 8 | ENVY24HT_VOL_MUTE;
11174886ec58SHasso Tepper 	envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2, 1);
11184886ec58SHasso Tepper 	envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, vol, 2);
11194886ec58SHasso Tepper 	envy24ht_wrmt(sc, ENVY24HT_MT_VOLIDX, ch * 2 + 1, 1);
11204886ec58SHasso Tepper 	envy24ht_wrmt(sc, ENVY24HT_MT_VOLUME, vol, 2);
11214886ec58SHasso Tepper #endif
11224886ec58SHasso Tepper }
11234886ec58SHasso Tepper 
11244886ec58SHasso Tepper static u_int32_t
envy24ht_gethwptr(struct sc_info * sc,int dir)11254886ec58SHasso Tepper envy24ht_gethwptr(struct sc_info *sc, int dir)
11264886ec58SHasso Tepper {
11274886ec58SHasso Tepper 	int unit, regno;
11284886ec58SHasso Tepper 	u_int32_t ptr, rtn;
11294886ec58SHasso Tepper 
11302a1ad637SFrançois Tigeot #if(0)
11314886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_gethwptr(sc, %d)\n", dir);
11324886ec58SHasso Tepper #endif
11334886ec58SHasso Tepper 	if (dir == PCMDIR_PLAY) {
11344886ec58SHasso Tepper 		rtn = sc->psize / 4;
11354886ec58SHasso Tepper 		unit = ENVY24HT_PLAY_BUFUNIT / 4;
11364886ec58SHasso Tepper 		regno = ENVY24HT_MT_PCNT;
11374886ec58SHasso Tepper 	}
11384886ec58SHasso Tepper 	else {
11394886ec58SHasso Tepper 		rtn = sc->rsize / 4;
11404886ec58SHasso Tepper 		unit = ENVY24HT_REC_BUFUNIT / 4;
11414886ec58SHasso Tepper 		regno = ENVY24HT_MT_RCNT;
11424886ec58SHasso Tepper 	}
11434886ec58SHasso Tepper 
11444886ec58SHasso Tepper 	ptr = envy24ht_rdmt(sc, regno, 2);
11454886ec58SHasso Tepper 	rtn -= (ptr + 1);
11464886ec58SHasso Tepper 	rtn /= unit;
11474886ec58SHasso Tepper 
11482a1ad637SFrançois Tigeot #if(0)
11494886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_gethwptr(): return %d\n", rtn);
11504886ec58SHasso Tepper #endif
11514886ec58SHasso Tepper 	return rtn;
11524886ec58SHasso Tepper }
11534886ec58SHasso Tepper 
11544886ec58SHasso Tepper static void
envy24ht_updintr(struct sc_info * sc,int dir)11554886ec58SHasso Tepper envy24ht_updintr(struct sc_info *sc, int dir)
11564886ec58SHasso Tepper {
11574886ec58SHasso Tepper 	int regptr, regintr;
11584886ec58SHasso Tepper 	u_int32_t mask, intr;
11594886ec58SHasso Tepper 	u_int32_t ptr, size, cnt;
11604886ec58SHasso Tepper 	u_int16_t blk;
11614886ec58SHasso Tepper 
11622a1ad637SFrançois Tigeot #if(0)
11634886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_updintr(sc, %d)\n", dir);
11644886ec58SHasso Tepper #endif
11654886ec58SHasso Tepper 	if (dir == PCMDIR_PLAY) {
11664886ec58SHasso Tepper 		blk = sc->blk[0];
11674886ec58SHasso Tepper 		size = sc->psize / 4;
11684886ec58SHasso Tepper 		regptr = ENVY24HT_MT_PCNT;
11694886ec58SHasso Tepper 		regintr = ENVY24HT_MT_PTERM;
11704886ec58SHasso Tepper 		mask = ~ENVY24HT_MT_INT_PMASK;
11714886ec58SHasso Tepper 	}
11724886ec58SHasso Tepper 	else {
11734886ec58SHasso Tepper 		blk = sc->blk[1];
11744886ec58SHasso Tepper 		size = sc->rsize / 4;
11754886ec58SHasso Tepper 		regptr = ENVY24HT_MT_RCNT;
11764886ec58SHasso Tepper 		regintr = ENVY24HT_MT_RTERM;
11774886ec58SHasso Tepper 		mask = ~ENVY24HT_MT_INT_RMASK;
11784886ec58SHasso Tepper 	}
11794886ec58SHasso Tepper 
11804886ec58SHasso Tepper 	ptr = size - envy24ht_rdmt(sc, regptr, 2) - 1;
11814886ec58SHasso Tepper 	/*
11824886ec58SHasso Tepper 	cnt = blk - ptr % blk - 1;
11834886ec58SHasso Tepper 	if (cnt == 0)
11844886ec58SHasso Tepper 		cnt = blk - 1;
11854886ec58SHasso Tepper 	*/
11864886ec58SHasso Tepper 	cnt = blk - 1;
11872a1ad637SFrançois Tigeot #if(0)
11884886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_updintr():ptr = %d, blk = %d, cnt = %d\n", ptr, blk, cnt);
11894886ec58SHasso Tepper #endif
11904886ec58SHasso Tepper 	envy24ht_wrmt(sc, regintr, cnt, 2);
11914886ec58SHasso Tepper 	intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
11922a1ad637SFrançois Tigeot #if(0)
11934886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_updintr():intr = 0x%02x, mask = 0x%02x\n", intr, mask);
11944886ec58SHasso Tepper #endif
11954886ec58SHasso Tepper 	envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, intr & mask, 1);
11962a1ad637SFrançois Tigeot #if(0)
11974886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_updintr():INT-->0x%02x\n",
11984886ec58SHasso Tepper 		      envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1));
11994886ec58SHasso Tepper #endif
12004886ec58SHasso Tepper 
12014886ec58SHasso Tepper 	return;
12024886ec58SHasso Tepper }
12034886ec58SHasso Tepper 
12044886ec58SHasso Tepper #if 0
12054886ec58SHasso Tepper static void
envy24ht_maskintr(struct sc_info * sc,int dir)12064886ec58SHasso Tepper envy24ht_maskintr(struct sc_info *sc, int dir)
12074886ec58SHasso Tepper {
12084886ec58SHasso Tepper 	u_int32_t mask, intr;
12094886ec58SHasso Tepper 
12102a1ad637SFrançois Tigeot #if(0)
12114886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_maskintr(sc, %d)\n", dir);
12124886ec58SHasso Tepper #endif
12134886ec58SHasso Tepper 	if (dir == PCMDIR_PLAY)
12144886ec58SHasso Tepper 		mask = ENVY24HT_MT_INT_PMASK;
12154886ec58SHasso Tepper 	else
12164886ec58SHasso Tepper 		mask = ENVY24HT_MT_INT_RMASK;
12174886ec58SHasso Tepper 	intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT, 1);
12184886ec58SHasso Tepper 	envy24ht_wrmt(sc, ENVY24HT_MT_INT, intr | mask, 1);
12194886ec58SHasso Tepper 
12204886ec58SHasso Tepper 	return;
12214886ec58SHasso Tepper }
12224886ec58SHasso Tepper #endif
12234886ec58SHasso Tepper 
12244886ec58SHasso Tepper static int
envy24ht_checkintr(struct sc_info * sc,int dir)12254886ec58SHasso Tepper envy24ht_checkintr(struct sc_info *sc, int dir)
12264886ec58SHasso Tepper {
12274886ec58SHasso Tepper 	u_int32_t mask, stat, intr, rtn;
12284886ec58SHasso Tepper 
12292a1ad637SFrançois Tigeot #if(0)
12304886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_checkintr(sc, %d)\n", dir);
12314886ec58SHasso Tepper #endif
12324886ec58SHasso Tepper 	intr = envy24ht_rdmt(sc, ENVY24HT_MT_INT_STAT, 1);
12334886ec58SHasso Tepper 	if (dir == PCMDIR_PLAY) {
12344886ec58SHasso Tepper 		if ((rtn = intr & ENVY24HT_MT_INT_PSTAT) != 0) {
12354886ec58SHasso Tepper 			mask = ~ENVY24HT_MT_INT_RSTAT;
12364886ec58SHasso Tepper 			envy24ht_wrmt(sc, 0x1a, 0x01, 1);
12374886ec58SHasso Tepper 			envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_PSTAT | 0x08, 1);
12384886ec58SHasso Tepper 			stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
12394886ec58SHasso Tepper 			envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_PMASK, 1);
12404886ec58SHasso Tepper 		}
12414886ec58SHasso Tepper 	}
12424886ec58SHasso Tepper 	else {
12434886ec58SHasso Tepper 		if ((rtn = intr & ENVY24HT_MT_INT_RSTAT) != 0) {
12444886ec58SHasso Tepper 			mask = ~ENVY24HT_MT_INT_PSTAT;
12454886ec58SHasso Tepper #if 0
12464886ec58SHasso Tepper 			stat = ENVY24HT_MT_INT_RSTAT | ENVY24HT_MT_INT_RMASK;
12474886ec58SHasso Tepper #endif
12484886ec58SHasso Tepper 			envy24ht_wrmt(sc, ENVY24HT_MT_INT_STAT, (intr & mask) | ENVY24HT_MT_INT_RSTAT, 1);
12494886ec58SHasso Tepper 			stat = envy24ht_rdmt(sc, ENVY24HT_MT_INT_MASK, 1);
12504886ec58SHasso Tepper 			envy24ht_wrmt(sc, ENVY24HT_MT_INT_MASK, stat | ENVY24HT_MT_INT_RMASK, 1);
12514886ec58SHasso Tepper 		}
12524886ec58SHasso Tepper 	}
12534886ec58SHasso Tepper 
12544886ec58SHasso Tepper 	return rtn;
12554886ec58SHasso Tepper }
12564886ec58SHasso Tepper 
12574886ec58SHasso Tepper static void
envy24ht_start(struct sc_info * sc,int dir)12584886ec58SHasso Tepper envy24ht_start(struct sc_info *sc, int dir)
12594886ec58SHasso Tepper {
12604886ec58SHasso Tepper 	u_int32_t stat, sw;
12614886ec58SHasso Tepper 
12622a1ad637SFrançois Tigeot #if(0)
12634886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_start(sc, %d)\n", dir);
12644886ec58SHasso Tepper #endif
12654886ec58SHasso Tepper 	if (dir == PCMDIR_PLAY)
12664886ec58SHasso Tepper 		sw = ENVY24HT_MT_PCTL_PSTART;
12674886ec58SHasso Tepper 	else
12684886ec58SHasso Tepper 		sw = ENVY24HT_MT_PCTL_RSTART;
12694886ec58SHasso Tepper 
12704886ec58SHasso Tepper 	stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1);
12714886ec58SHasso Tepper 	envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat | sw, 1);
12722a1ad637SFrançois Tigeot #if(0)
12734886ec58SHasso Tepper 	DELAY(100);
12744886ec58SHasso Tepper 	device_printf(sc->dev, "PADDR:0x%08x\n", envy24ht_rdmt(sc, ENVY24HT_MT_PADDR, 4));
12754886ec58SHasso Tepper 	device_printf(sc->dev, "PCNT:%ld\n", envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2));
12764886ec58SHasso Tepper #endif
12774886ec58SHasso Tepper 
12784886ec58SHasso Tepper 	return;
12794886ec58SHasso Tepper }
12804886ec58SHasso Tepper 
12814886ec58SHasso Tepper static void
envy24ht_stop(struct sc_info * sc,int dir)12824886ec58SHasso Tepper envy24ht_stop(struct sc_info *sc, int dir)
12834886ec58SHasso Tepper {
12844886ec58SHasso Tepper 	u_int32_t stat, sw;
12854886ec58SHasso Tepper 
12862a1ad637SFrançois Tigeot #if(0)
12874886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_stop(sc, %d)\n", dir);
12884886ec58SHasso Tepper #endif
12894886ec58SHasso Tepper 	if (dir == PCMDIR_PLAY)
12904886ec58SHasso Tepper 		sw = ~ENVY24HT_MT_PCTL_PSTART;
12914886ec58SHasso Tepper 	else
12924886ec58SHasso Tepper 		sw = ~ENVY24HT_MT_PCTL_RSTART;
12934886ec58SHasso Tepper 
12944886ec58SHasso Tepper 	stat = envy24ht_rdmt(sc, ENVY24HT_MT_PCTL, 1);
12954886ec58SHasso Tepper 	envy24ht_wrmt(sc, ENVY24HT_MT_PCTL, stat & sw, 1);
12964886ec58SHasso Tepper 
12974886ec58SHasso Tepper 	return;
12984886ec58SHasso Tepper }
12994886ec58SHasso Tepper 
13004886ec58SHasso Tepper #if 0
13014886ec58SHasso Tepper static int
envy24ht_route(struct sc_info * sc,int dac,int class,int adc,int rev)13024886ec58SHasso Tepper envy24ht_route(struct sc_info *sc, int dac, int class, int adc, int rev)
13034886ec58SHasso Tepper {
13044886ec58SHasso Tepper 	return 0;
13054886ec58SHasso Tepper }
13064886ec58SHasso Tepper #endif
13074886ec58SHasso Tepper 
13084886ec58SHasso Tepper /* -------------------------------------------------------------------- */
13094886ec58SHasso Tepper 
13104886ec58SHasso Tepper /* buffer copy routines */
13114886ec58SHasso Tepper static void
envy24ht_p32sl(struct sc_chinfo * ch)13124886ec58SHasso Tepper envy24ht_p32sl(struct sc_chinfo *ch)
13134886ec58SHasso Tepper {
13144886ec58SHasso Tepper 	int length;
13154886ec58SHasso Tepper 	sample32_t *dmabuf;
13164886ec58SHasso Tepper 	u_int32_t *data;
13174886ec58SHasso Tepper 	int src, dst, ssize, dsize, slot;
13184886ec58SHasso Tepper 	int i;
13194886ec58SHasso Tepper 
13204886ec58SHasso Tepper 	length = sndbuf_getready(ch->buffer) / 8;
13214886ec58SHasso Tepper 	dmabuf = ch->parent->pbuf;
13224886ec58SHasso Tepper 	data = (u_int32_t *)ch->data;
13234886ec58SHasso Tepper 	src = sndbuf_getreadyptr(ch->buffer) / 4;
13244886ec58SHasso Tepper 	dst = src / 2 + ch->offset;
13254886ec58SHasso Tepper 	ssize = ch->size / 4;
13264886ec58SHasso Tepper 	dsize = ch->size / 8;
13274886ec58SHasso Tepper 	slot = ch->num * 2;
13284886ec58SHasso Tepper 
13294886ec58SHasso Tepper 	for (i = 0; i < length; i++) {
13304886ec58SHasso Tepper 		dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = data[src];
13314886ec58SHasso Tepper 		dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = data[src + 1];
13324886ec58SHasso Tepper 		dst++;
13334886ec58SHasso Tepper 		dst %= dsize;
13344886ec58SHasso Tepper 		src += 2;
13354886ec58SHasso Tepper 		src %= ssize;
13364886ec58SHasso Tepper 	}
13374886ec58SHasso Tepper 
13384886ec58SHasso Tepper 	return;
13394886ec58SHasso Tepper }
13404886ec58SHasso Tepper 
13414886ec58SHasso Tepper static void
envy24ht_p16sl(struct sc_chinfo * ch)13424886ec58SHasso Tepper envy24ht_p16sl(struct sc_chinfo *ch)
13434886ec58SHasso Tepper {
13444886ec58SHasso Tepper 	int length;
13454886ec58SHasso Tepper 	sample32_t *dmabuf;
13464886ec58SHasso Tepper 	u_int16_t *data;
13474886ec58SHasso Tepper 	int src, dst, ssize, dsize, slot;
13484886ec58SHasso Tepper 	int i;
13494886ec58SHasso Tepper 
13502a1ad637SFrançois Tigeot #if(0)
13514886ec58SHasso Tepper 	device_printf(ch->parent->dev, "envy24ht_p16sl()\n");
13524886ec58SHasso Tepper #endif
13534886ec58SHasso Tepper 	length = sndbuf_getready(ch->buffer) / 4;
13544886ec58SHasso Tepper 	dmabuf = ch->parent->pbuf;
13554886ec58SHasso Tepper 	data = (u_int16_t *)ch->data;
13564886ec58SHasso Tepper 	src = sndbuf_getreadyptr(ch->buffer) / 2;
13574886ec58SHasso Tepper 	dst = src / 2 + ch->offset;
13584886ec58SHasso Tepper 	ssize = ch->size / 2;
13594886ec58SHasso Tepper 	dsize = ch->size / 4;
13604886ec58SHasso Tepper 	slot = ch->num * 2;
13612a1ad637SFrançois Tigeot #if(0)
13624886ec58SHasso Tepper 	device_printf(ch->parent->dev, "envy24ht_p16sl():%lu-->%lu(%lu)\n", src, dst, length);
13634886ec58SHasso Tepper #endif
13644886ec58SHasso Tepper 
13654886ec58SHasso Tepper 	for (i = 0; i < length; i++) {
13664886ec58SHasso Tepper 		dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = (u_int32_t)data[src] << 16;
13674886ec58SHasso Tepper 		dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = (u_int32_t)data[src + 1] << 16;
13682a1ad637SFrançois Tigeot #if(0)
13694886ec58SHasso Tepper 		if (i < 16) {
13702a1ad637SFrançois Tigeot 			printf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot]);
13712a1ad637SFrançois Tigeot 			printf("%08x", dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1]);
13724886ec58SHasso Tepper 		}
13734886ec58SHasso Tepper #endif
13744886ec58SHasso Tepper 		dst++;
13754886ec58SHasso Tepper 		dst %= dsize;
13764886ec58SHasso Tepper 		src += 2;
13774886ec58SHasso Tepper 		src %= ssize;
13784886ec58SHasso Tepper 	}
13792a1ad637SFrançois Tigeot #if(0)
13802a1ad637SFrançois Tigeot 	printf("\n");
13814886ec58SHasso Tepper #endif
13824886ec58SHasso Tepper 
13834886ec58SHasso Tepper 	return;
13844886ec58SHasso Tepper }
13854886ec58SHasso Tepper 
13864886ec58SHasso Tepper static void
envy24ht_p8u(struct sc_chinfo * ch)13874886ec58SHasso Tepper envy24ht_p8u(struct sc_chinfo *ch)
13884886ec58SHasso Tepper {
13894886ec58SHasso Tepper 	int length;
13904886ec58SHasso Tepper 	sample32_t *dmabuf;
13914886ec58SHasso Tepper 	u_int8_t *data;
13924886ec58SHasso Tepper 	int src, dst, ssize, dsize, slot;
13934886ec58SHasso Tepper 	int i;
13944886ec58SHasso Tepper 
13954886ec58SHasso Tepper 	length = sndbuf_getready(ch->buffer) / 2;
13964886ec58SHasso Tepper 	dmabuf = ch->parent->pbuf;
13972a1ad637SFrançois Tigeot 	data = (u_int8_t *)ch->data;
13984886ec58SHasso Tepper 	src = sndbuf_getreadyptr(ch->buffer);
13994886ec58SHasso Tepper 	dst = src / 2 + ch->offset;
14004886ec58SHasso Tepper 	ssize = ch->size;
14014886ec58SHasso Tepper 	dsize = ch->size / 4;
14024886ec58SHasso Tepper 	slot = ch->num * 2;
14034886ec58SHasso Tepper 
14044886ec58SHasso Tepper 	for (i = 0; i < length; i++) {
14054886ec58SHasso Tepper 		dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot].buffer = ((u_int32_t)data[src] ^ 0x80) << 24;
14064886ec58SHasso Tepper 		dmabuf[dst * ENVY24HT_PLAY_CHNUM + slot + 1].buffer = ((u_int32_t)data[src + 1] ^ 0x80) << 24;
14074886ec58SHasso Tepper 		dst++;
14084886ec58SHasso Tepper 		dst %= dsize;
14094886ec58SHasso Tepper 		src += 2;
14104886ec58SHasso Tepper 		src %= ssize;
14114886ec58SHasso Tepper 	}
14124886ec58SHasso Tepper 
14134886ec58SHasso Tepper 	return;
14144886ec58SHasso Tepper }
14154886ec58SHasso Tepper 
14164886ec58SHasso Tepper static void
envy24ht_r32sl(struct sc_chinfo * ch)14174886ec58SHasso Tepper envy24ht_r32sl(struct sc_chinfo *ch)
14184886ec58SHasso Tepper {
14194886ec58SHasso Tepper 	int length;
14204886ec58SHasso Tepper 	sample32_t *dmabuf;
14214886ec58SHasso Tepper 	u_int32_t *data;
14224886ec58SHasso Tepper 	int src, dst, ssize, dsize, slot;
14234886ec58SHasso Tepper 	int i;
14244886ec58SHasso Tepper 
14254886ec58SHasso Tepper 	length = sndbuf_getfree(ch->buffer) / 8;
14264886ec58SHasso Tepper 	dmabuf = ch->parent->rbuf;
14274886ec58SHasso Tepper 	data = (u_int32_t *)ch->data;
14284886ec58SHasso Tepper 	dst = sndbuf_getfreeptr(ch->buffer) / 4;
14294886ec58SHasso Tepper 	src = dst / 2 + ch->offset;
14304886ec58SHasso Tepper 	dsize = ch->size / 4;
14314886ec58SHasso Tepper 	ssize = ch->size / 8;
14324886ec58SHasso Tepper 	slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2;
14334886ec58SHasso Tepper 
14344886ec58SHasso Tepper 	for (i = 0; i < length; i++) {
14354886ec58SHasso Tepper 		data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer;
14364886ec58SHasso Tepper 		data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer;
14374886ec58SHasso Tepper 		dst += 2;
14384886ec58SHasso Tepper 		dst %= dsize;
14394886ec58SHasso Tepper 		src++;
14404886ec58SHasso Tepper 		src %= ssize;
14414886ec58SHasso Tepper 	}
14424886ec58SHasso Tepper 
14434886ec58SHasso Tepper 	return;
14444886ec58SHasso Tepper }
14454886ec58SHasso Tepper 
14464886ec58SHasso Tepper static void
envy24ht_r16sl(struct sc_chinfo * ch)14474886ec58SHasso Tepper envy24ht_r16sl(struct sc_chinfo *ch)
14484886ec58SHasso Tepper {
14494886ec58SHasso Tepper 	int length;
14504886ec58SHasso Tepper 	sample32_t *dmabuf;
14514886ec58SHasso Tepper 	u_int16_t *data;
14524886ec58SHasso Tepper 	int src, dst, ssize, dsize, slot;
14534886ec58SHasso Tepper 	int i;
14544886ec58SHasso Tepper 
14554886ec58SHasso Tepper 	length = sndbuf_getfree(ch->buffer) / 4;
14564886ec58SHasso Tepper 	dmabuf = ch->parent->rbuf;
14574886ec58SHasso Tepper 	data = (u_int16_t *)ch->data;
14584886ec58SHasso Tepper 	dst = sndbuf_getfreeptr(ch->buffer) / 2;
14594886ec58SHasso Tepper 	src = dst / 2 + ch->offset;
14604886ec58SHasso Tepper 	dsize = ch->size / 2;
14614886ec58SHasso Tepper 	ssize = ch->size / 8;
14624886ec58SHasso Tepper 	slot = (ch->num - ENVY24HT_CHAN_REC_ADC1) * 2;
14634886ec58SHasso Tepper 
14644886ec58SHasso Tepper 	for (i = 0; i < length; i++) {
14654886ec58SHasso Tepper 		data[dst] = dmabuf[src * ENVY24HT_REC_CHNUM + slot].buffer;
14664886ec58SHasso Tepper 		data[dst + 1] = dmabuf[src * ENVY24HT_REC_CHNUM + slot + 1].buffer;
14674886ec58SHasso Tepper 		dst += 2;
14684886ec58SHasso Tepper 		dst %= dsize;
14694886ec58SHasso Tepper 		src++;
14704886ec58SHasso Tepper 		src %= ssize;
14714886ec58SHasso Tepper 	}
14724886ec58SHasso Tepper 
14734886ec58SHasso Tepper 	return;
14744886ec58SHasso Tepper }
14754886ec58SHasso Tepper 
14764886ec58SHasso Tepper /* -------------------------------------------------------------------- */
14774886ec58SHasso Tepper 
14784886ec58SHasso Tepper /* channel interface */
14794886ec58SHasso Tepper static void *
envy24htchan_init(kobj_t obj,void * devinfo,struct snd_dbuf * b,struct pcm_channel * c,int dir)14804886ec58SHasso Tepper envy24htchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
14814886ec58SHasso Tepper {
14824886ec58SHasso Tepper 	struct sc_info	*sc = (struct sc_info *)devinfo;
14834886ec58SHasso Tepper 	struct sc_chinfo *ch;
14844886ec58SHasso Tepper 	unsigned num;
14854886ec58SHasso Tepper 
14862a1ad637SFrançois Tigeot #if(0)
14874886ec58SHasso Tepper 	device_printf(sc->dev, "envy24htchan_init(obj, devinfo, b, c, %d)\n", dir);
14884886ec58SHasso Tepper #endif
14894886ec58SHasso Tepper 	snd_mtxlock(sc->lock);
14904886ec58SHasso Tepper #if 0
14914886ec58SHasso Tepper 	if ((sc->chnum > ENVY24HT_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) ||
14924886ec58SHasso Tepper 	    (sc->chnum < ENVY24HT_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) {
14934886ec58SHasso Tepper 		snd_mtxunlock(sc->lock);
14944886ec58SHasso Tepper 		return NULL;
14954886ec58SHasso Tepper 	}
14964886ec58SHasso Tepper #endif
14974886ec58SHasso Tepper 	num = sc->chnum;
14984886ec58SHasso Tepper 
14994886ec58SHasso Tepper 	ch = &sc->chan[num];
15004886ec58SHasso Tepper 	ch->size = 8 * ENVY24HT_SAMPLE_NUM;
15014e8e900cSMatthew Dillon 	ch->data = kmalloc(ch->size, M_ENVY24HT, M_WAITOK | M_ZERO);
15022a1ad637SFrançois Tigeot 	if (ch->data == NULL) {
15032a1ad637SFrançois Tigeot 		ch->size = 0;
15042a1ad637SFrançois Tigeot 		ch = NULL;
15052a1ad637SFrançois Tigeot 	}
15062a1ad637SFrançois Tigeot 	else {
15074886ec58SHasso Tepper 		ch->buffer = b;
15084886ec58SHasso Tepper 		ch->channel = c;
15094886ec58SHasso Tepper 		ch->parent = sc;
15104886ec58SHasso Tepper 		ch->dir = dir;
15114886ec58SHasso Tepper 		/* set channel map */
15124886ec58SHasso Tepper 		ch->num = envy24ht_chanmap[num];
15134886ec58SHasso Tepper 		snd_mtxunlock(sc->lock);
15144886ec58SHasso Tepper 		sndbuf_setup(ch->buffer, ch->data, ch->size);
15154886ec58SHasso Tepper 		snd_mtxlock(sc->lock);
15164886ec58SHasso Tepper 		/* these 2 values are dummy */
15174886ec58SHasso Tepper 		ch->unit = 4;
15184886ec58SHasso Tepper 		ch->blk = 10240;
15194886ec58SHasso Tepper 	}
15204886ec58SHasso Tepper 	snd_mtxunlock(sc->lock);
15214886ec58SHasso Tepper 
15224886ec58SHasso Tepper 	return ch;
15234886ec58SHasso Tepper }
15244886ec58SHasso Tepper 
15254886ec58SHasso Tepper static int
envy24htchan_free(kobj_t obj,void * data)15264886ec58SHasso Tepper envy24htchan_free(kobj_t obj, void *data)
15274886ec58SHasso Tepper {
15284886ec58SHasso Tepper 	struct sc_chinfo *ch = data;
15294886ec58SHasso Tepper 	struct sc_info *sc = ch->parent;
15304886ec58SHasso Tepper 
15312a1ad637SFrançois Tigeot #if(0)
15324886ec58SHasso Tepper 	device_printf(sc->dev, "envy24htchan_free()\n");
15334886ec58SHasso Tepper #endif
15344886ec58SHasso Tepper 	snd_mtxlock(sc->lock);
15354886ec58SHasso Tepper 	if (ch->data != NULL) {
153667931cc4SFrançois Tigeot 		kfree(ch->data, M_ENVY24HT);
15374886ec58SHasso Tepper 		ch->data = NULL;
15384886ec58SHasso Tepper 	}
15394886ec58SHasso Tepper 	snd_mtxunlock(sc->lock);
15404886ec58SHasso Tepper 
15414886ec58SHasso Tepper 	return 0;
15424886ec58SHasso Tepper }
15434886ec58SHasso Tepper 
15444886ec58SHasso Tepper static int
envy24htchan_setformat(kobj_t obj,void * data,u_int32_t format)15454886ec58SHasso Tepper envy24htchan_setformat(kobj_t obj, void *data, u_int32_t format)
15464886ec58SHasso Tepper {
15474886ec58SHasso Tepper 	struct sc_chinfo *ch = data;
15484886ec58SHasso Tepper 	struct sc_info *sc = ch->parent;
15494886ec58SHasso Tepper 	struct envy24ht_emldma *emltab;
15504886ec58SHasso Tepper 	/* unsigned int bcnt, bsize; */
15514886ec58SHasso Tepper 	int i;
15524886ec58SHasso Tepper 
15532a1ad637SFrançois Tigeot #if(0)
15544886ec58SHasso Tepper 	device_printf(sc->dev, "envy24htchan_setformat(obj, data, 0x%08x)\n", format);
15554886ec58SHasso Tepper #endif
15564886ec58SHasso Tepper 	snd_mtxlock(sc->lock);
15574886ec58SHasso Tepper 	/* check and get format related information */
15584886ec58SHasso Tepper 	if (ch->dir == PCMDIR_PLAY)
15594886ec58SHasso Tepper 		emltab = envy24ht_pemltab;
15604886ec58SHasso Tepper 	else
15614886ec58SHasso Tepper 		emltab = envy24ht_remltab;
15624886ec58SHasso Tepper 	if (emltab == NULL) {
15634886ec58SHasso Tepper 		snd_mtxunlock(sc->lock);
15644886ec58SHasso Tepper 		return -1;
15654886ec58SHasso Tepper 	}
15664886ec58SHasso Tepper 	for (i = 0; emltab[i].format != 0; i++)
15674886ec58SHasso Tepper 		if (emltab[i].format == format)
15684886ec58SHasso Tepper 			break;
15694886ec58SHasso Tepper 	if (emltab[i].format == 0) {
15704886ec58SHasso Tepper 		snd_mtxunlock(sc->lock);
15714886ec58SHasso Tepper 		return -1;
15724886ec58SHasso Tepper 	}
15734886ec58SHasso Tepper 
15744886ec58SHasso Tepper 	/* set format information */
15754886ec58SHasso Tepper 	ch->format = format;
15764886ec58SHasso Tepper 	ch->emldma = emltab[i].emldma;
15774886ec58SHasso Tepper 	if (ch->unit > emltab[i].unit)
15784886ec58SHasso Tepper 		ch->blk *= ch->unit / emltab[i].unit;
15794886ec58SHasso Tepper 	else
15804886ec58SHasso Tepper 		ch->blk /= emltab[i].unit / ch->unit;
15814886ec58SHasso Tepper 	ch->unit = emltab[i].unit;
15824886ec58SHasso Tepper 
15834886ec58SHasso Tepper 	/* set channel buffer information */
15844886ec58SHasso Tepper 	ch->size = ch->unit * ENVY24HT_SAMPLE_NUM;
15854886ec58SHasso Tepper #if 0
15864886ec58SHasso Tepper 	if (ch->dir == PCMDIR_PLAY)
15874886ec58SHasso Tepper 		bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT;
15884886ec58SHasso Tepper 	else
15894886ec58SHasso Tepper 		bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT;
15904886ec58SHasso Tepper 	bsize *= ch->unit;
15914886ec58SHasso Tepper 	bcnt = ch->size / bsize;
15924886ec58SHasso Tepper 	sndbuf_resize(ch->buffer, bcnt, bsize);
15934886ec58SHasso Tepper #endif
15944886ec58SHasso Tepper 	snd_mtxunlock(sc->lock);
15954886ec58SHasso Tepper 
15962a1ad637SFrançois Tigeot #if(0)
15974886ec58SHasso Tepper 	device_printf(sc->dev, "envy24htchan_setformat(): return 0x%08x\n", 0);
15984886ec58SHasso Tepper #endif
15994886ec58SHasso Tepper 	return 0;
16004886ec58SHasso Tepper }
16014886ec58SHasso Tepper 
16024886ec58SHasso Tepper /*
16034886ec58SHasso Tepper   IMPLEMENT NOTICE: In this driver, setspeed function only do setting
16044886ec58SHasso Tepper   of speed information value. And real hardware speed setting is done
16054886ec58SHasso Tepper   at start triggered(see envy24htchan_trigger()). So, at this function
16064886ec58SHasso Tepper   is called, any value that ENVY24 can use is able to set. But, at
16074886ec58SHasso Tepper   start triggerd, some other channel is running, and that channel's
16084886ec58SHasso Tepper   speed isn't same with, then trigger function will fail.
16094886ec58SHasso Tepper */
16102a1ad637SFrançois Tigeot static u_int32_t
envy24htchan_setspeed(kobj_t obj,void * data,u_int32_t speed)16114886ec58SHasso Tepper envy24htchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
16124886ec58SHasso Tepper {
16134886ec58SHasso Tepper 	struct sc_chinfo *ch = data;
16144886ec58SHasso Tepper 	u_int32_t val, prev;
16154886ec58SHasso Tepper 	int i;
16164886ec58SHasso Tepper 
16172a1ad637SFrançois Tigeot #if(0)
16184886ec58SHasso Tepper 	device_printf(ch->parent->dev, "envy24htchan_setspeed(obj, data, %d)\n", speed);
16194886ec58SHasso Tepper #endif
16204886ec58SHasso Tepper 	prev = 0x7fffffff;
16214886ec58SHasso Tepper 	for (i = 0; (val = envy24ht_speed[i]) != 0; i++) {
16224886ec58SHasso Tepper 		if (abs(val - speed) < abs(prev - speed))
16234886ec58SHasso Tepper 			prev = val;
16244886ec58SHasso Tepper 		else
16254886ec58SHasso Tepper 			break;
16264886ec58SHasso Tepper 	}
16274886ec58SHasso Tepper 	ch->speed = prev;
16284886ec58SHasso Tepper 
16292a1ad637SFrançois Tigeot #if(0)
16304886ec58SHasso Tepper 	device_printf(ch->parent->dev, "envy24htchan_setspeed(): return %d\n", ch->speed);
16314886ec58SHasso Tepper #endif
16324886ec58SHasso Tepper 	return ch->speed;
16334886ec58SHasso Tepper }
16344886ec58SHasso Tepper 
16352a1ad637SFrançois Tigeot static u_int32_t
envy24htchan_setblocksize(kobj_t obj,void * data,u_int32_t blocksize)16364886ec58SHasso Tepper envy24htchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
16374886ec58SHasso Tepper {
16384886ec58SHasso Tepper 	struct sc_chinfo *ch = data;
16394886ec58SHasso Tepper 	/* struct sc_info *sc = ch->parent; */
16404886ec58SHasso Tepper 	u_int32_t size, prev;
16414886ec58SHasso Tepper 	unsigned int bcnt, bsize;
16424886ec58SHasso Tepper 
16432a1ad637SFrançois Tigeot #if(0)
16444886ec58SHasso Tepper 	device_printf(sc->dev, "envy24htchan_setblocksize(obj, data, %d)\n", blocksize);
16454886ec58SHasso Tepper #endif
16464886ec58SHasso Tepper 	prev = 0x7fffffff;
16474886ec58SHasso Tepper 	/* snd_mtxlock(sc->lock); */
16484886ec58SHasso Tepper 	for (size = ch->size / 2; size > 0; size /= 2) {
16494886ec58SHasso Tepper 		if (abs(size - blocksize) < abs(prev - blocksize))
16504886ec58SHasso Tepper 			prev = size;
16514886ec58SHasso Tepper 		else
16524886ec58SHasso Tepper 			break;
16534886ec58SHasso Tepper 	}
16544886ec58SHasso Tepper 
16554886ec58SHasso Tepper 	ch->blk = prev / ch->unit;
16564886ec58SHasso Tepper 	if (ch->dir == PCMDIR_PLAY)
16574886ec58SHasso Tepper 		ch->blk *= ENVY24HT_PLAY_BUFUNIT / 4;
16584886ec58SHasso Tepper 	else
16594886ec58SHasso Tepper 		ch->blk *= ENVY24HT_REC_BUFUNIT / 4;
16604886ec58SHasso Tepper         /* set channel buffer information */
16614886ec58SHasso Tepper         /* ch->size = ch->unit * ENVY24HT_SAMPLE_NUM; */
16624886ec58SHasso Tepper         if (ch->dir == PCMDIR_PLAY)
16634886ec58SHasso Tepper                 bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT;
16644886ec58SHasso Tepper         else
16654886ec58SHasso Tepper                 bsize = ch->blk * 4 / ENVY24HT_REC_BUFUNIT;
16664886ec58SHasso Tepper         bsize *= ch->unit;
16674886ec58SHasso Tepper         bcnt = ch->size / bsize;
16684886ec58SHasso Tepper         sndbuf_resize(ch->buffer, bcnt, bsize);
16694886ec58SHasso Tepper 	/* snd_mtxunlock(sc->lock); */
16704886ec58SHasso Tepper 
16712a1ad637SFrançois Tigeot #if(0)
16724886ec58SHasso Tepper 	device_printf(sc->dev, "envy24htchan_setblocksize(): return %d\n", prev);
16734886ec58SHasso Tepper #endif
16744886ec58SHasso Tepper 	return prev;
16754886ec58SHasso Tepper }
16764886ec58SHasso Tepper 
16774886ec58SHasso Tepper /* semantic note: must start at beginning of buffer */
16784886ec58SHasso Tepper static int
envy24htchan_trigger(kobj_t obj,void * data,int go)16794886ec58SHasso Tepper envy24htchan_trigger(kobj_t obj, void *data, int go)
16804886ec58SHasso Tepper {
16814886ec58SHasso Tepper 	struct sc_chinfo *ch = data;
16824886ec58SHasso Tepper 	struct sc_info *sc = ch->parent;
16834886ec58SHasso Tepper 	u_int32_t ptr;
16844886ec58SHasso Tepper 	int slot;
16852a1ad637SFrançois Tigeot 	int error = 0;
16864886ec58SHasso Tepper #if 0
16874886ec58SHasso Tepper 	int i;
16884886ec58SHasso Tepper 
16894886ec58SHasso Tepper 	device_printf(sc->dev, "envy24htchan_trigger(obj, data, %d)\n", go);
16904886ec58SHasso Tepper #endif
16914886ec58SHasso Tepper 	snd_mtxlock(sc->lock);
16924886ec58SHasso Tepper 	if (ch->dir == PCMDIR_PLAY)
16934886ec58SHasso Tepper 		slot = 0;
16944886ec58SHasso Tepper 	else
16954886ec58SHasso Tepper 		slot = 1;
16964886ec58SHasso Tepper 	switch (go) {
16974886ec58SHasso Tepper 	case PCMTRIG_START:
16982a1ad637SFrançois Tigeot #if(0)
16994886ec58SHasso Tepper 		device_printf(sc->dev, "envy24htchan_trigger(): start\n");
17004886ec58SHasso Tepper #endif
17014886ec58SHasso Tepper 		/* check or set channel speed */
17024886ec58SHasso Tepper 		if (sc->run[0] == 0 && sc->run[1] == 0) {
17034886ec58SHasso Tepper 			sc->speed = envy24ht_setspeed(sc, ch->speed);
17044886ec58SHasso Tepper 			sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed;
17054886ec58SHasso Tepper 			sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed;
17064886ec58SHasso Tepper 		}
17072a1ad637SFrançois Tigeot 		else if (ch->speed != 0 && ch->speed != sc->speed) {
17082a1ad637SFrançois Tigeot 			error = -1;
17092a1ad637SFrançois Tigeot 			goto fail;
17102a1ad637SFrançois Tigeot 		}
17114886ec58SHasso Tepper 		if (ch->speed == 0)
17124886ec58SHasso Tepper 			ch->channel->speed = sc->speed;
17134886ec58SHasso Tepper 		/* start or enable channel */
17144886ec58SHasso Tepper 		sc->run[slot]++;
17154886ec58SHasso Tepper 		if (sc->run[slot] == 1) {
17164886ec58SHasso Tepper 			/* first channel */
17174886ec58SHasso Tepper 			ch->offset = 0;
17184886ec58SHasso Tepper 			sc->blk[slot] = ch->blk;
17194886ec58SHasso Tepper 		}
17204886ec58SHasso Tepper 		else {
17214886ec58SHasso Tepper 			ptr = envy24ht_gethwptr(sc, ch->dir);
17224886ec58SHasso Tepper 			ch->offset = ((ptr / ch->blk + 1) * ch->blk %
17234886ec58SHasso Tepper 			    (ch->size / 4)) * 4 / ch->unit;
17244886ec58SHasso Tepper 			if (ch->blk < sc->blk[slot])
17254886ec58SHasso Tepper 				sc->blk[slot] = ch->blk;
17264886ec58SHasso Tepper 		}
17274886ec58SHasso Tepper 		if (ch->dir == PCMDIR_PLAY) {
17284886ec58SHasso Tepper 			ch->emldma(ch);
17294886ec58SHasso Tepper 			envy24ht_setvolume(sc, ch->num);
17304886ec58SHasso Tepper 		}
17314886ec58SHasso Tepper 		envy24ht_updintr(sc, ch->dir);
17324886ec58SHasso Tepper 		if (sc->run[slot] == 1)
17334886ec58SHasso Tepper 			envy24ht_start(sc, ch->dir);
17344886ec58SHasso Tepper 		ch->run = 1;
17354886ec58SHasso Tepper 		break;
17364886ec58SHasso Tepper 	case PCMTRIG_EMLDMAWR:
17372a1ad637SFrançois Tigeot #if(0)
17384886ec58SHasso Tepper 		device_printf(sc->dev, "envy24htchan_trigger(): emldmawr\n");
17394886ec58SHasso Tepper #endif
17402a1ad637SFrançois Tigeot 		if (ch->run != 1) {
17412a1ad637SFrançois Tigeot 			error = -1;
17422a1ad637SFrançois Tigeot 			goto fail;
17432a1ad637SFrançois Tigeot 		}
17444886ec58SHasso Tepper 		ch->emldma(ch);
17454886ec58SHasso Tepper 		break;
17464886ec58SHasso Tepper 	case PCMTRIG_EMLDMARD:
17472a1ad637SFrançois Tigeot #if(0)
17484886ec58SHasso Tepper 		device_printf(sc->dev, "envy24htchan_trigger(): emldmard\n");
17494886ec58SHasso Tepper #endif
17502a1ad637SFrançois Tigeot 		if (ch->run != 1) {
17512a1ad637SFrançois Tigeot 			error = -1;
17522a1ad637SFrançois Tigeot 			goto fail;
17532a1ad637SFrançois Tigeot 		}
17544886ec58SHasso Tepper 		ch->emldma(ch);
17554886ec58SHasso Tepper 		break;
17564886ec58SHasso Tepper 	case PCMTRIG_ABORT:
17574886ec58SHasso Tepper 		if (ch->run) {
17582a1ad637SFrançois Tigeot #if(0)
17594886ec58SHasso Tepper 		device_printf(sc->dev, "envy24htchan_trigger(): abort\n");
17604886ec58SHasso Tepper #endif
17614886ec58SHasso Tepper 		ch->run = 0;
17624886ec58SHasso Tepper 		sc->run[slot]--;
17634886ec58SHasso Tepper 		if (ch->dir == PCMDIR_PLAY)
17644886ec58SHasso Tepper 			envy24ht_mutevolume(sc, ch->num);
17654886ec58SHasso Tepper 		if (sc->run[slot] == 0) {
17664886ec58SHasso Tepper 			envy24ht_stop(sc, ch->dir);
17674886ec58SHasso Tepper 			sc->intr[slot] = 0;
17684886ec58SHasso Tepper 		}
17694886ec58SHasso Tepper /*		else if (ch->blk == sc->blk[slot]) {
17704886ec58SHasso Tepper 			sc->blk[slot] = ENVY24HT_SAMPLE_NUM / 2;
17714886ec58SHasso Tepper 			for (i = 0; i < ENVY24HT_CHAN_NUM; i++) {
17724886ec58SHasso Tepper 				if (sc->chan[i].dir == ch->dir &&
17734886ec58SHasso Tepper 				    sc->chan[i].run == 1 &&
17744886ec58SHasso Tepper 				    sc->chan[i].blk < sc->blk[slot])
17754886ec58SHasso Tepper 					sc->blk[slot] = sc->chan[i].blk;
17764886ec58SHasso Tepper 			}
17774886ec58SHasso Tepper 			if (ch->blk != sc->blk[slot])
17784886ec58SHasso Tepper 				envy24ht_updintr(sc, ch->dir);
17794886ec58SHasso Tepper 		}*/
17804886ec58SHasso Tepper 		}
17814886ec58SHasso Tepper 		break;
17824886ec58SHasso Tepper 	}
17832a1ad637SFrançois Tigeot fail:
17844886ec58SHasso Tepper 	snd_mtxunlock(sc->lock);
17852a1ad637SFrançois Tigeot 	return (error);
17864886ec58SHasso Tepper }
17874886ec58SHasso Tepper 
17882a1ad637SFrançois Tigeot static u_int32_t
envy24htchan_getptr(kobj_t obj,void * data)17894886ec58SHasso Tepper envy24htchan_getptr(kobj_t obj, void *data)
17904886ec58SHasso Tepper {
17914886ec58SHasso Tepper 	struct sc_chinfo *ch = data;
17924886ec58SHasso Tepper 	struct sc_info *sc = ch->parent;
17932a1ad637SFrançois Tigeot 	u_int32_t ptr, rtn;
17944886ec58SHasso Tepper 
17952a1ad637SFrançois Tigeot #if(0)
17964886ec58SHasso Tepper 	device_printf(sc->dev, "envy24htchan_getptr()\n");
17974886ec58SHasso Tepper #endif
17984886ec58SHasso Tepper 	snd_mtxlock(sc->lock);
17994886ec58SHasso Tepper 	ptr = envy24ht_gethwptr(sc, ch->dir);
18004886ec58SHasso Tepper 	rtn = ptr * ch->unit;
18014886ec58SHasso Tepper 	snd_mtxunlock(sc->lock);
18024886ec58SHasso Tepper 
18032a1ad637SFrançois Tigeot #if(0)
18044886ec58SHasso Tepper 	device_printf(sc->dev, "envy24htchan_getptr(): return %d\n",
18054886ec58SHasso Tepper 	    rtn);
18064886ec58SHasso Tepper #endif
18074886ec58SHasso Tepper 	return rtn;
18084886ec58SHasso Tepper }
18094886ec58SHasso Tepper 
18104886ec58SHasso Tepper static struct pcmchan_caps *
envy24htchan_getcaps(kobj_t obj,void * data)18114886ec58SHasso Tepper envy24htchan_getcaps(kobj_t obj, void *data)
18124886ec58SHasso Tepper {
18134886ec58SHasso Tepper 	struct sc_chinfo *ch = data;
18144886ec58SHasso Tepper 	struct sc_info *sc = ch->parent;
18154886ec58SHasso Tepper 	struct pcmchan_caps *rtn;
18164886ec58SHasso Tepper 
18172a1ad637SFrançois Tigeot #if(0)
18184886ec58SHasso Tepper 	device_printf(sc->dev, "envy24htchan_getcaps()\n");
18194886ec58SHasso Tepper #endif
18204886ec58SHasso Tepper 	snd_mtxlock(sc->lock);
18214886ec58SHasso Tepper 	if (ch->dir == PCMDIR_PLAY) {
18224886ec58SHasso Tepper 		if (sc->run[0] == 0)
18234886ec58SHasso Tepper 			rtn = &envy24ht_playcaps;
18244886ec58SHasso Tepper 		else
18254886ec58SHasso Tepper 			rtn = &sc->caps[0];
18264886ec58SHasso Tepper 	}
18274886ec58SHasso Tepper 	else {
18284886ec58SHasso Tepper 		if (sc->run[1] == 0)
18294886ec58SHasso Tepper 			rtn = &envy24ht_reccaps;
18304886ec58SHasso Tepper 		else
18314886ec58SHasso Tepper 			rtn = &sc->caps[1];
18324886ec58SHasso Tepper 	}
18334886ec58SHasso Tepper 	snd_mtxunlock(sc->lock);
18344886ec58SHasso Tepper 
18354886ec58SHasso Tepper 	return rtn;
18364886ec58SHasso Tepper }
18374886ec58SHasso Tepper 
18384886ec58SHasso Tepper static kobj_method_t envy24htchan_methods[] = {
18394886ec58SHasso Tepper 	KOBJMETHOD(channel_init,		envy24htchan_init),
18404886ec58SHasso Tepper 	KOBJMETHOD(channel_free,		envy24htchan_free),
18414886ec58SHasso Tepper 	KOBJMETHOD(channel_setformat,		envy24htchan_setformat),
18424886ec58SHasso Tepper 	KOBJMETHOD(channel_setspeed,		envy24htchan_setspeed),
18434886ec58SHasso Tepper 	KOBJMETHOD(channel_setblocksize,	envy24htchan_setblocksize),
18444886ec58SHasso Tepper 	KOBJMETHOD(channel_trigger,		envy24htchan_trigger),
18454886ec58SHasso Tepper 	KOBJMETHOD(channel_getptr,		envy24htchan_getptr),
18464886ec58SHasso Tepper 	KOBJMETHOD(channel_getcaps,		envy24htchan_getcaps),
18477774cda2SSascha Wildner 	KOBJMETHOD_END
18484886ec58SHasso Tepper };
18494886ec58SHasso Tepper CHANNEL_DECLARE(envy24htchan);
18504886ec58SHasso Tepper 
18514886ec58SHasso Tepper /* -------------------------------------------------------------------- */
18524886ec58SHasso Tepper 
18534886ec58SHasso Tepper /* mixer interface */
18544886ec58SHasso Tepper 
18554886ec58SHasso Tepper static int
envy24htmixer_init(struct snd_mixer * m)18564886ec58SHasso Tepper envy24htmixer_init(struct snd_mixer *m)
18574886ec58SHasso Tepper {
18584886ec58SHasso Tepper 	struct sc_info *sc = mix_getdevinfo(m);
18594886ec58SHasso Tepper 
18602a1ad637SFrançois Tigeot #if(0)
18614886ec58SHasso Tepper 	device_printf(sc->dev, "envy24htmixer_init()\n");
18624886ec58SHasso Tepper #endif
18634886ec58SHasso Tepper 	if (sc == NULL)
18644886ec58SHasso Tepper 		return -1;
18654886ec58SHasso Tepper 
18664886ec58SHasso Tepper 	/* set volume control rate */
18674886ec58SHasso Tepper 	snd_mtxlock(sc->lock);
18684886ec58SHasso Tepper #if 0
18694886ec58SHasso Tepper 	envy24ht_wrmt(sc, ENVY24HT_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */
18704886ec58SHasso Tepper #endif
18714886ec58SHasso Tepper 
18724886ec58SHasso Tepper 	pcm_setflags(sc->dev, pcm_getflags(sc->dev) | SD_F_SOFTPCMVOL);
18734886ec58SHasso Tepper 
18744886ec58SHasso Tepper 	mix_setdevs(m, ENVY24HT_MIX_MASK);
18754886ec58SHasso Tepper 	mix_setrecdevs(m, ENVY24HT_MIX_REC_MASK);
18764886ec58SHasso Tepper 
18774886ec58SHasso Tepper 	snd_mtxunlock(sc->lock);
18784886ec58SHasso Tepper 
18794886ec58SHasso Tepper 	return 0;
18804886ec58SHasso Tepper }
18814886ec58SHasso Tepper 
18824886ec58SHasso Tepper static int
envy24htmixer_reinit(struct snd_mixer * m)18834886ec58SHasso Tepper envy24htmixer_reinit(struct snd_mixer *m)
18844886ec58SHasso Tepper {
18854886ec58SHasso Tepper 	struct sc_info *sc = mix_getdevinfo(m);
18864886ec58SHasso Tepper 
18874886ec58SHasso Tepper 	if (sc == NULL)
18884886ec58SHasso Tepper 		return -1;
18892a1ad637SFrançois Tigeot #if(0)
18904886ec58SHasso Tepper 	device_printf(sc->dev, "envy24htmixer_reinit()\n");
18914886ec58SHasso Tepper #endif
18924886ec58SHasso Tepper 
18934886ec58SHasso Tepper 	return 0;
18944886ec58SHasso Tepper }
18954886ec58SHasso Tepper 
18964886ec58SHasso Tepper static int
envy24htmixer_uninit(struct snd_mixer * m)18974886ec58SHasso Tepper envy24htmixer_uninit(struct snd_mixer *m)
18984886ec58SHasso Tepper {
18994886ec58SHasso Tepper 	struct sc_info *sc = mix_getdevinfo(m);
19004886ec58SHasso Tepper 
19014886ec58SHasso Tepper 	if (sc == NULL)
19024886ec58SHasso Tepper 		return -1;
19032a1ad637SFrançois Tigeot #if(0)
19044886ec58SHasso Tepper 	device_printf(sc->dev, "envy24htmixer_uninit()\n");
19054886ec58SHasso Tepper #endif
19064886ec58SHasso Tepper 
19074886ec58SHasso Tepper 	return 0;
19084886ec58SHasso Tepper }
19094886ec58SHasso Tepper 
19104886ec58SHasso Tepper static int
envy24htmixer_set(struct snd_mixer * m,unsigned dev,unsigned left,unsigned right)19114886ec58SHasso Tepper envy24htmixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
19124886ec58SHasso Tepper {
19134886ec58SHasso Tepper 	struct sc_info *sc = mix_getdevinfo(m);
19144886ec58SHasso Tepper 	int ch = envy24ht_mixmap[dev];
19154886ec58SHasso Tepper 	int hwch;
19164886ec58SHasso Tepper 	int i;
19174886ec58SHasso Tepper 
19184886ec58SHasso Tepper 	if (sc == NULL)
19194886ec58SHasso Tepper 		return -1;
19204886ec58SHasso Tepper 	if (dev == 0 && sc->cfg->codec->setvolume == NULL)
19214886ec58SHasso Tepper 		return -1;
19224886ec58SHasso Tepper 	if (dev != 0 && ch == -1)
19234886ec58SHasso Tepper 		return -1;
19244886ec58SHasso Tepper 	hwch = envy24ht_chanmap[ch];
19252a1ad637SFrançois Tigeot #if(0)
19264886ec58SHasso Tepper 	device_printf(sc->dev, "envy24htmixer_set(m, %d, %d, %d)\n",
19274886ec58SHasso Tepper 	    dev, left, right);
19284886ec58SHasso Tepper #endif
19294886ec58SHasso Tepper 
19304886ec58SHasso Tepper 	snd_mtxlock(sc->lock);
19314886ec58SHasso Tepper 	if (dev == 0) {
19324886ec58SHasso Tepper 		for (i = 0; i < sc->dacn; i++) {
19334886ec58SHasso Tepper 			sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right);
19344886ec58SHasso Tepper 		}
19354886ec58SHasso Tepper 	}
19364886ec58SHasso Tepper 	else {
19374886ec58SHasso Tepper 		/* set volume value for hardware */
19384886ec58SHasso Tepper 		if ((sc->left[hwch] = 100 - left) > ENVY24HT_VOL_MIN)
19394886ec58SHasso Tepper 			sc->left[hwch] = ENVY24HT_VOL_MUTE;
19404886ec58SHasso Tepper 		if ((sc->right[hwch] = 100 - right) > ENVY24HT_VOL_MIN)
19414886ec58SHasso Tepper 			sc->right[hwch] = ENVY24HT_VOL_MUTE;
19424886ec58SHasso Tepper 
19434886ec58SHasso Tepper 		/* set volume for record channel and running play channel */
19444886ec58SHasso Tepper 		if (hwch > ENVY24HT_CHAN_PLAY_SPDIF || sc->chan[ch].run)
19454886ec58SHasso Tepper 			envy24ht_setvolume(sc, hwch);
19464886ec58SHasso Tepper 	}
19474886ec58SHasso Tepper 	snd_mtxunlock(sc->lock);
19484886ec58SHasso Tepper 
19494886ec58SHasso Tepper 	return right << 8 | left;
19504886ec58SHasso Tepper }
19514886ec58SHasso Tepper 
19524886ec58SHasso Tepper static u_int32_t
envy24htmixer_setrecsrc(struct snd_mixer * m,u_int32_t src)19534886ec58SHasso Tepper envy24htmixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
19544886ec58SHasso Tepper {
19554886ec58SHasso Tepper 	struct sc_info *sc = mix_getdevinfo(m);
19564886ec58SHasso Tepper 	int ch = envy24ht_mixmap[src];
19572a1ad637SFrançois Tigeot #if(0)
19584886ec58SHasso Tepper 	device_printf(sc->dev, "envy24htmixer_setrecsrc(m, %d)\n", src);
19594886ec58SHasso Tepper #endif
19604886ec58SHasso Tepper 
19614886ec58SHasso Tepper 	if (ch > ENVY24HT_CHAN_PLAY_SPDIF)
19624886ec58SHasso Tepper 		sc->src = ch;
19634886ec58SHasso Tepper 	return src;
19644886ec58SHasso Tepper }
19654886ec58SHasso Tepper 
19664886ec58SHasso Tepper static kobj_method_t envy24htmixer_methods[] = {
19674886ec58SHasso Tepper 	KOBJMETHOD(mixer_init,		envy24htmixer_init),
19684886ec58SHasso Tepper 	KOBJMETHOD(mixer_reinit,	envy24htmixer_reinit),
19694886ec58SHasso Tepper 	KOBJMETHOD(mixer_uninit,	envy24htmixer_uninit),
19704886ec58SHasso Tepper 	KOBJMETHOD(mixer_set,		envy24htmixer_set),
19714886ec58SHasso Tepper 	KOBJMETHOD(mixer_setrecsrc,	envy24htmixer_setrecsrc),
19727774cda2SSascha Wildner 	KOBJMETHOD_END
19734886ec58SHasso Tepper };
19744886ec58SHasso Tepper MIXER_DECLARE(envy24htmixer);
19754886ec58SHasso Tepper 
19764886ec58SHasso Tepper /* -------------------------------------------------------------------- */
19774886ec58SHasso Tepper 
19784886ec58SHasso Tepper /* The interrupt handler */
19794886ec58SHasso Tepper static void
envy24ht_intr(void * p)19804886ec58SHasso Tepper envy24ht_intr(void *p)
19814886ec58SHasso Tepper {
19824886ec58SHasso Tepper 	struct sc_info *sc = (struct sc_info *)p;
19834886ec58SHasso Tepper 	struct sc_chinfo *ch;
19844886ec58SHasso Tepper 	u_int32_t ptr, dsize, feed;
19854886ec58SHasso Tepper 	int i;
19864886ec58SHasso Tepper 
19872a1ad637SFrançois Tigeot #if(0)
19884886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_intr()\n");
19894886ec58SHasso Tepper #endif
19904886ec58SHasso Tepper 	snd_mtxlock(sc->lock);
19914886ec58SHasso Tepper 	if (envy24ht_checkintr(sc, PCMDIR_PLAY)) {
19922a1ad637SFrançois Tigeot #if(0)
19934886ec58SHasso Tepper 		device_printf(sc->dev, "envy24ht_intr(): play\n");
19944886ec58SHasso Tepper #endif
19954886ec58SHasso Tepper 		dsize = sc->psize / 4;
19964886ec58SHasso Tepper 		ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2) - 1;
19972a1ad637SFrançois Tigeot #if(0)
19984886ec58SHasso Tepper 		device_printf(sc->dev, "envy24ht_intr(): ptr = %d-->", ptr);
19994886ec58SHasso Tepper #endif
20004886ec58SHasso Tepper 		ptr -= ptr % sc->blk[0];
20014886ec58SHasso Tepper 		feed = (ptr + dsize - sc->intr[0]) % dsize;
20022a1ad637SFrançois Tigeot #if(0)
20032a1ad637SFrançois Tigeot 		printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed);
20044886ec58SHasso Tepper #endif
20054886ec58SHasso Tepper 		for (i = ENVY24HT_CHAN_PLAY_DAC1; i <= ENVY24HT_CHAN_PLAY_SPDIF; i++) {
20064886ec58SHasso Tepper 			ch = &sc->chan[i];
20072a1ad637SFrançois Tigeot #if(0)
20084886ec58SHasso Tepper 			if (ch->run)
20094886ec58SHasso Tepper 				device_printf(sc->dev, "envy24ht_intr(): chan[%d].blk = %d\n", i, ch->blk);
20104886ec58SHasso Tepper #endif
20114886ec58SHasso Tepper 			if (ch->run && ch->blk <= feed) {
20124886ec58SHasso Tepper 				snd_mtxunlock(sc->lock);
20134886ec58SHasso Tepper 				chn_intr(ch->channel);
20144886ec58SHasso Tepper 				snd_mtxlock(sc->lock);
20154886ec58SHasso Tepper 			}
20164886ec58SHasso Tepper 		}
20174886ec58SHasso Tepper 		sc->intr[0] = ptr;
20184886ec58SHasso Tepper 		envy24ht_updintr(sc, PCMDIR_PLAY);
20194886ec58SHasso Tepper 	}
20204886ec58SHasso Tepper 	if (envy24ht_checkintr(sc, PCMDIR_REC)) {
20212a1ad637SFrançois Tigeot #if(0)
20224886ec58SHasso Tepper 		device_printf(sc->dev, "envy24ht_intr(): rec\n");
20234886ec58SHasso Tepper #endif
20244886ec58SHasso Tepper 		dsize = sc->rsize / 4;
20254886ec58SHasso Tepper 		ptr = dsize - envy24ht_rdmt(sc, ENVY24HT_MT_RCNT, 2) - 1;
20264886ec58SHasso Tepper 		ptr -= ptr % sc->blk[1];
20274886ec58SHasso Tepper 		feed = (ptr + dsize - sc->intr[1]) % dsize;
20284886ec58SHasso Tepper 		for (i = ENVY24HT_CHAN_REC_ADC1; i <= ENVY24HT_CHAN_REC_SPDIF; i++) {
20294886ec58SHasso Tepper 			ch = &sc->chan[i];
20304886ec58SHasso Tepper 			if (ch->run && ch->blk <= feed) {
20314886ec58SHasso Tepper 				snd_mtxunlock(sc->lock);
20324886ec58SHasso Tepper 				chn_intr(ch->channel);
20334886ec58SHasso Tepper 				snd_mtxlock(sc->lock);
20344886ec58SHasso Tepper 			}
20354886ec58SHasso Tepper 		}
20364886ec58SHasso Tepper 		sc->intr[1] = ptr;
20374886ec58SHasso Tepper 		envy24ht_updintr(sc, PCMDIR_REC);
20384886ec58SHasso Tepper 	}
20394886ec58SHasso Tepper 	snd_mtxunlock(sc->lock);
20404886ec58SHasso Tepper 
20414886ec58SHasso Tepper 	return;
20424886ec58SHasso Tepper }
20434886ec58SHasso Tepper 
20444886ec58SHasso Tepper /*
20454886ec58SHasso Tepper  * Probe and attach the card
20464886ec58SHasso Tepper  */
20474886ec58SHasso Tepper 
20484886ec58SHasso Tepper static int
envy24ht_pci_probe(device_t dev)20494886ec58SHasso Tepper envy24ht_pci_probe(device_t dev)
20504886ec58SHasso Tepper {
20514886ec58SHasso Tepper 	u_int16_t sv, sd;
20524886ec58SHasso Tepper 	int i;
20534886ec58SHasso Tepper 
20542a1ad637SFrançois Tigeot #if(0)
20552a1ad637SFrançois Tigeot 	printf("envy24ht_pci_probe()\n");
20564886ec58SHasso Tepper #endif
20574886ec58SHasso Tepper 	if (pci_get_device(dev) == PCID_ENVY24HT &&
20584886ec58SHasso Tepper 	    pci_get_vendor(dev) == PCIV_ENVY24) {
20594886ec58SHasso Tepper 		sv = pci_get_subvendor(dev);
20604886ec58SHasso Tepper 		sd = pci_get_subdevice(dev);
20614886ec58SHasso Tepper 		for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
20624886ec58SHasso Tepper 			if (cfg_table[i].subvendor == sv &&
20634886ec58SHasso Tepper 			    cfg_table[i].subdevice == sd) {
20644886ec58SHasso Tepper 				break;
20654886ec58SHasso Tepper 			}
20664886ec58SHasso Tepper 		}
20674886ec58SHasso Tepper 		device_set_desc(dev, cfg_table[i].name);
20682a1ad637SFrançois Tigeot #if(0)
20692a1ad637SFrançois Tigeot 		printf("envy24ht_pci_probe(): return 0\n");
20704886ec58SHasso Tepper #endif
20714886ec58SHasso Tepper 		return 0;
20724886ec58SHasso Tepper 	}
20734886ec58SHasso Tepper 	else {
20742a1ad637SFrançois Tigeot #if(0)
20752a1ad637SFrançois Tigeot 		printf("envy24ht_pci_probe(): return ENXIO\n");
20764886ec58SHasso Tepper #endif
20774886ec58SHasso Tepper 		return ENXIO;
20784886ec58SHasso Tepper 	}
20794886ec58SHasso Tepper }
20804886ec58SHasso Tepper 
20814886ec58SHasso Tepper static void
envy24ht_dmapsetmap(void * arg,bus_dma_segment_t * segs,int nseg,int error)20824886ec58SHasso Tepper envy24ht_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
20834886ec58SHasso Tepper {
20842a1ad637SFrançois Tigeot 	struct sc_info *sc = arg;
20854886ec58SHasso Tepper 
20862a1ad637SFrançois Tigeot 	sc->paddr = segs->ds_addr;
20872a1ad637SFrançois Tigeot #if(0)
20884886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_dmapsetmap()\n");
20894886ec58SHasso Tepper 	if (bootverbose) {
20902a1ad637SFrançois Tigeot 		printf("envy24ht(play): setmap %lx, %lx; ",
20914886ec58SHasso Tepper 		    (unsigned long)segs->ds_addr,
20924886ec58SHasso Tepper 		    (unsigned long)segs->ds_len);
20934886ec58SHasso Tepper 	}
20944886ec58SHasso Tepper #endif
20952a1ad637SFrançois Tigeot 	envy24ht_wrmt(sc, ENVY24HT_MT_PADDR, (uint32_t)segs->ds_addr, 4);
20962a1ad637SFrançois Tigeot 	envy24ht_wrmt(sc, ENVY24HT_MT_PCNT, (uint32_t)(segs->ds_len / 4 - 1), 2);
20974886ec58SHasso Tepper }
20984886ec58SHasso Tepper 
20994886ec58SHasso Tepper static void
envy24ht_dmarsetmap(void * arg,bus_dma_segment_t * segs,int nseg,int error)21004886ec58SHasso Tepper envy24ht_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
21014886ec58SHasso Tepper {
21022a1ad637SFrançois Tigeot 	struct sc_info *sc = arg;
21034886ec58SHasso Tepper 
21042a1ad637SFrançois Tigeot 	sc->raddr = segs->ds_addr;
21052a1ad637SFrançois Tigeot #if(0)
21064886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_dmarsetmap()\n");
21074886ec58SHasso Tepper 	if (bootverbose) {
21082a1ad637SFrançois Tigeot 		printf("envy24ht(record): setmap %lx, %lx; ",
21094886ec58SHasso Tepper 		    (unsigned long)segs->ds_addr,
21104886ec58SHasso Tepper 		    (unsigned long)segs->ds_len);
21114886ec58SHasso Tepper 	}
21124886ec58SHasso Tepper #endif
21132a1ad637SFrançois Tigeot 	envy24ht_wrmt(sc, ENVY24HT_MT_RADDR, (uint32_t)segs->ds_addr, 4);
21142a1ad637SFrançois Tigeot 	envy24ht_wrmt(sc, ENVY24HT_MT_RCNT, (uint32_t)(segs->ds_len / 4 - 1), 2);
21154886ec58SHasso Tepper }
21164886ec58SHasso Tepper 
21174886ec58SHasso Tepper static void
envy24ht_dmafree(struct sc_info * sc)21184886ec58SHasso Tepper envy24ht_dmafree(struct sc_info *sc)
21194886ec58SHasso Tepper {
21202a1ad637SFrançois Tigeot #if(0)
21214886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_dmafree():");
21222a1ad637SFrançois Tigeot 	printf(" sc->raddr(0x%08x)", (u_int32_t)sc->raddr);
21232a1ad637SFrançois Tigeot 	printf(" sc->paddr(0x%08x)", (u_int32_t)sc->paddr);
21242a1ad637SFrançois Tigeot 	if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf);
21252a1ad637SFrançois Tigeot 	else printf(" sc->rbuf(null)");
21262a1ad637SFrançois Tigeot 	if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf);
21272a1ad637SFrançois Tigeot 	else printf(" sc->pbuf(null)\n");
21284886ec58SHasso Tepper #endif
21292a1ad637SFrançois Tigeot #if(0)
21302a1ad637SFrançois Tigeot 	if (sc->raddr)
21314886ec58SHasso Tepper 		bus_dmamap_unload(sc->dmat, sc->rmap);
21322a1ad637SFrançois Tigeot 	if (sc->paddr)
21334886ec58SHasso Tepper 		bus_dmamap_unload(sc->dmat, sc->pmap);
21344886ec58SHasso Tepper 	if (sc->rbuf)
21354886ec58SHasso Tepper 		bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
21364886ec58SHasso Tepper 	if (sc->pbuf)
21374886ec58SHasso Tepper 		bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
21384886ec58SHasso Tepper #else
21394886ec58SHasso Tepper 	bus_dmamap_unload(sc->dmat, sc->rmap);
21404886ec58SHasso Tepper 	bus_dmamap_unload(sc->dmat, sc->pmap);
21414886ec58SHasso Tepper 	bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
21424886ec58SHasso Tepper 	bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
21434886ec58SHasso Tepper #endif
21444886ec58SHasso Tepper 
21452a1ad637SFrançois Tigeot 	sc->raddr = sc->paddr = 0;
21464886ec58SHasso Tepper 	sc->pbuf = NULL;
21474886ec58SHasso Tepper 	sc->rbuf = NULL;
21484886ec58SHasso Tepper 
21494886ec58SHasso Tepper 	return;
21504886ec58SHasso Tepper }
21514886ec58SHasso Tepper 
21524886ec58SHasso Tepper static int
envy24ht_dmainit(struct sc_info * sc)21534886ec58SHasso Tepper envy24ht_dmainit(struct sc_info *sc)
21544886ec58SHasso Tepper {
21554886ec58SHasso Tepper 
21562a1ad637SFrançois Tigeot #if(0)
21574886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_dmainit()\n");
21584886ec58SHasso Tepper #endif
21594886ec58SHasso Tepper 	/* init values */
21604886ec58SHasso Tepper 	sc->psize = ENVY24HT_PLAY_BUFUNIT * ENVY24HT_SAMPLE_NUM;
21614886ec58SHasso Tepper 	sc->rsize = ENVY24HT_REC_BUFUNIT * ENVY24HT_SAMPLE_NUM;
21624886ec58SHasso Tepper 	sc->pbuf = NULL;
21634886ec58SHasso Tepper 	sc->rbuf = NULL;
21642a1ad637SFrançois Tigeot 	sc->paddr = sc->raddr = 0;
21654886ec58SHasso Tepper 	sc->blk[0] = sc->blk[1] = 0;
21664886ec58SHasso Tepper 
21674886ec58SHasso Tepper 	/* allocate DMA buffer */
21682a1ad637SFrançois Tigeot #if(0)
21694886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->pbuf\n");
21704886ec58SHasso Tepper #endif
21714886ec58SHasso Tepper 	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap))
21724886ec58SHasso Tepper 		goto bad;
21732a1ad637SFrançois Tigeot #if(0)
21744886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->rbuf\n");
21754886ec58SHasso Tepper #endif
21764886ec58SHasso Tepper 	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap))
21774886ec58SHasso Tepper 		goto bad;
21782a1ad637SFrançois Tigeot #if(0)
21794886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->pmap\n");
21804886ec58SHasso Tepper #endif
21812a1ad637SFrançois Tigeot 	if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24ht_dmapsetmap, sc, BUS_DMA_NOWAIT))
21824886ec58SHasso Tepper 		goto bad;
21832a1ad637SFrançois Tigeot #if(0)
21844886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->rmap\n");
21854886ec58SHasso Tepper #endif
21862a1ad637SFrançois Tigeot 	if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24ht_dmarsetmap, sc, BUS_DMA_NOWAIT))
21874886ec58SHasso Tepper 		goto bad;
21884886ec58SHasso Tepper 	bzero(sc->pbuf, sc->psize);
21894886ec58SHasso Tepper 	bzero(sc->rbuf, sc->rsize);
21904886ec58SHasso Tepper 
21914886ec58SHasso Tepper 	return 0;
21924886ec58SHasso Tepper  bad:
21934886ec58SHasso Tepper 	envy24ht_dmafree(sc);
21944886ec58SHasso Tepper 	return ENOSPC;
21954886ec58SHasso Tepper }
21964886ec58SHasso Tepper 
21974886ec58SHasso Tepper static void
envy24ht_putcfg(struct sc_info * sc)21984886ec58SHasso Tepper envy24ht_putcfg(struct sc_info *sc)
21994886ec58SHasso Tepper {
22004886ec58SHasso Tepper 	device_printf(sc->dev, "system configuration\n");
220167931cc4SFrançois Tigeot 	kprintf("  SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n",
22024886ec58SHasso Tepper 	    sc->cfg->subvendor, sc->cfg->subdevice);
220367931cc4SFrançois Tigeot 	kprintf("  XIN2 Clock Source: ");
22044886ec58SHasso Tepper 	switch (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) {
22054886ec58SHasso Tepper 	case 0x00:
220667931cc4SFrançois Tigeot 		kprintf("24.576MHz(96kHz*256)\n");
22074886ec58SHasso Tepper 		break;
22084886ec58SHasso Tepper 	case 0x40:
220967931cc4SFrançois Tigeot 		kprintf("49.152MHz(192kHz*256)\n");
22104886ec58SHasso Tepper 		break;
22114886ec58SHasso Tepper 	case 0x80:
221267931cc4SFrançois Tigeot 		kprintf("reserved\n");
22134886ec58SHasso Tepper 		break;
22144886ec58SHasso Tepper 	default:
22154cad9222SSascha Wildner 		kprintf("illegal system setting\n");
22164886ec58SHasso Tepper 	}
221767931cc4SFrançois Tigeot 	kprintf("  MPU-401 UART(s) #: ");
22184886ec58SHasso Tepper 	if (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_MPU)
221967931cc4SFrançois Tigeot 		kprintf("1\n");
22204886ec58SHasso Tepper 	else
222167931cc4SFrançois Tigeot 		kprintf("not implemented\n");
22224886ec58SHasso Tepper         switch (sc->adcn) {
2223d78296faSSascha Wildner         case 0x01:
2224d78296faSSascha Wildner 	case 0x02:
222567931cc4SFrançois Tigeot                 kprintf("  ADC #: ");
222667931cc4SFrançois Tigeot                 kprintf("%d\n", sc->adcn);
22274886ec58SHasso Tepper                 break;
22284886ec58SHasso Tepper         case 0x03:
222967931cc4SFrançois Tigeot                 kprintf("  ADC #: ");
223067931cc4SFrançois Tigeot                 kprintf("%d", 1);
223167931cc4SFrançois Tigeot                 kprintf(" and SPDIF receiver connected\n");
22324886ec58SHasso Tepper                 break;
22334886ec58SHasso Tepper         default:
223467931cc4SFrançois Tigeot                 kprintf("  no physical inputs\n");
22354886ec58SHasso Tepper         }
223667931cc4SFrançois Tigeot 	kprintf("  DAC #: ");
223767931cc4SFrançois Tigeot 	kprintf("%d\n", sc->dacn);
223867931cc4SFrançois Tigeot 	kprintf("  Multi-track converter type: ");
22394886ec58SHasso Tepper 	if ((sc->cfg->acl & ENVY24HT_CCSM_ACL_MTC) == 0) {
224067931cc4SFrançois Tigeot 		kprintf("AC'97(SDATA_OUT:");
22414886ec58SHasso Tepper 		if (sc->cfg->acl & ENVY24HT_CCSM_ACL_OMODE)
224267931cc4SFrançois Tigeot 			kprintf("packed");
22434886ec58SHasso Tepper 		else
224467931cc4SFrançois Tigeot 			kprintf("split");
224567931cc4SFrançois Tigeot 		kprintf(")\n");
22464886ec58SHasso Tepper 	}
22474886ec58SHasso Tepper 	else {
224867931cc4SFrançois Tigeot 		kprintf("I2S(");
22494886ec58SHasso Tepper 		if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_VOL)
225067931cc4SFrançois Tigeot 			kprintf("with volume, ");
22514886ec58SHasso Tepper                 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_192KHZ)
225267931cc4SFrançois Tigeot                         kprintf("192KHz support, ");
22534886ec58SHasso Tepper                 else
22544886ec58SHasso Tepper                 if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_96KHZ)
225567931cc4SFrançois Tigeot                         kprintf("192KHz support, ");
22564886ec58SHasso Tepper                 else
225767931cc4SFrançois Tigeot                         kprintf("48KHz support, ");
22584886ec58SHasso Tepper 		switch (sc->cfg->i2s & ENVY24HT_CCSM_I2S_RES) {
22594886ec58SHasso Tepper 		case ENVY24HT_CCSM_I2S_16BIT:
226067931cc4SFrançois Tigeot 			kprintf("16bit resolution, ");
22614886ec58SHasso Tepper 			break;
22624886ec58SHasso Tepper 		case ENVY24HT_CCSM_I2S_18BIT:
226367931cc4SFrançois Tigeot 			kprintf("18bit resolution, ");
22644886ec58SHasso Tepper 			break;
22654886ec58SHasso Tepper 		case ENVY24HT_CCSM_I2S_20BIT:
226667931cc4SFrançois Tigeot 			kprintf("20bit resolution, ");
22674886ec58SHasso Tepper 			break;
22684886ec58SHasso Tepper 		case ENVY24HT_CCSM_I2S_24BIT:
226967931cc4SFrançois Tigeot 			kprintf("24bit resolution, ");
22704886ec58SHasso Tepper 			break;
22714886ec58SHasso Tepper 		}
227267931cc4SFrançois Tigeot 		kprintf("ID#0x%x)\n", sc->cfg->i2s & ENVY24HT_CCSM_I2S_ID);
22734886ec58SHasso Tepper 	}
227467931cc4SFrançois Tigeot 	kprintf("  S/PDIF(IN/OUT): ");
22754886ec58SHasso Tepper 	if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_IN)
227667931cc4SFrançois Tigeot 		kprintf("1/");
22774886ec58SHasso Tepper 	else
227867931cc4SFrançois Tigeot 		kprintf("0/");
22794886ec58SHasso Tepper 	if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_OUT)
228067931cc4SFrançois Tigeot 		kprintf("1 ");
22814886ec58SHasso Tepper 	else
228267931cc4SFrançois Tigeot 		kprintf("0 ");
22834886ec58SHasso Tepper 	if (sc->cfg->spdif & (ENVY24HT_CCSM_SPDIF_IN | ENVY24HT_CCSM_SPDIF_OUT))
228467931cc4SFrançois Tigeot 		kprintf("ID# 0x%02x\n", (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_ID) >> 2);
228567931cc4SFrançois Tigeot 	kprintf("  GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n",
22864886ec58SHasso Tepper 	    sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate);
22874886ec58SHasso Tepper }
22884886ec58SHasso Tepper 
22894886ec58SHasso Tepper static int
envy24ht_init(struct sc_info * sc)22904886ec58SHasso Tepper envy24ht_init(struct sc_info *sc)
22914886ec58SHasso Tepper {
22924886ec58SHasso Tepper 	u_int32_t data;
22932a1ad637SFrançois Tigeot #if(0)
22944886ec58SHasso Tepper 	int rtn;
22954886ec58SHasso Tepper #endif
22964886ec58SHasso Tepper 	int i;
22974886ec58SHasso Tepper 	u_int32_t sv, sd;
22984886ec58SHasso Tepper 
22994886ec58SHasso Tepper 
23002a1ad637SFrançois Tigeot #if(0)
23014886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_init()\n");
23024886ec58SHasso Tepper #endif
23034886ec58SHasso Tepper 
23044886ec58SHasso Tepper 	/* reset chip */
23054886ec58SHasso Tepper #if 0
23064886ec58SHasso Tepper 	envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_RESET, 1);
23074886ec58SHasso Tepper 	DELAY(200);
23084886ec58SHasso Tepper 	envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_NATIVE, 1);
23094886ec58SHasso Tepper 	DELAY(200);
23104886ec58SHasso Tepper 
23114886ec58SHasso Tepper 	/* legacy hardware disable */
23124886ec58SHasso Tepper 	data = pci_read_config(sc->dev, PCIR_LAC, 2);
23134886ec58SHasso Tepper 	data |= PCIM_LAC_DISABLE;
23144886ec58SHasso Tepper 	pci_write_config(sc->dev, PCIR_LAC, data, 2);
23154886ec58SHasso Tepper #endif
23164886ec58SHasso Tepper 
23174886ec58SHasso Tepper 	/* check system configuration */
23184886ec58SHasso Tepper 	sc->cfg = NULL;
23194886ec58SHasso Tepper 	for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
23204886ec58SHasso Tepper 		/* 1st: search configuration from table */
23214886ec58SHasso Tepper 		sv = pci_get_subvendor(sc->dev);
23224886ec58SHasso Tepper 		sd = pci_get_subdevice(sc->dev);
23234886ec58SHasso Tepper 		if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) {
23242a1ad637SFrançois Tigeot #if(0)
23254886ec58SHasso Tepper 			device_printf(sc->dev, "Set configuration from table\n");
23264886ec58SHasso Tepper #endif
23274886ec58SHasso Tepper 			sc->cfg = &cfg_table[i];
23284886ec58SHasso Tepper 			break;
23294886ec58SHasso Tepper 		}
23304886ec58SHasso Tepper 	}
23314886ec58SHasso Tepper 	if (sc->cfg == NULL) {
23324886ec58SHasso Tepper 		/* 2nd: read configuration from table */
23334886ec58SHasso Tepper 		sc->cfg = envy24ht_rom2cfg(sc);
23344886ec58SHasso Tepper 	}
23354886ec58SHasso Tepper 	sc->adcn = ((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_ADC) >> 2) + 1; /* need to be fixed */
23364886ec58SHasso Tepper 	sc->dacn = (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_DAC) + 1;
23374886ec58SHasso Tepper 
23384886ec58SHasso Tepper 	if (1 /* bootverbose */) {
23394886ec58SHasso Tepper 		envy24ht_putcfg(sc);
23404886ec58SHasso Tepper 	}
23414886ec58SHasso Tepper 
23424886ec58SHasso Tepper 	/* set system configuration */
23434886ec58SHasso Tepper 	envy24ht_wrcs(sc, ENVY24HT_CCS_SCFG, sc->cfg->scfg, 1);
23444886ec58SHasso Tepper 	envy24ht_wrcs(sc, ENVY24HT_CCS_ACL, sc->cfg->acl, 1);
23454886ec58SHasso Tepper 	envy24ht_wrcs(sc, ENVY24HT_CCS_I2S, sc->cfg->i2s, 1);
23464886ec58SHasso Tepper 	envy24ht_wrcs(sc, ENVY24HT_CCS_SPDIF, sc->cfg->spdif, 1);
23474886ec58SHasso Tepper 	envy24ht_gpiosetmask(sc, sc->cfg->gpiomask);
23484886ec58SHasso Tepper 	envy24ht_gpiosetdir(sc, sc->cfg->gpiodir);
23494886ec58SHasso Tepper 	envy24ht_gpiowr(sc, sc->cfg->gpiostate);
23504886ec58SHasso Tepper 
23514886ec58SHasso Tepper 	if ((sc->cfg->subvendor == 0x3031) && (sc->cfg->subdevice == 0x4553)) {
23524886ec58SHasso Tepper 		envy24ht_wri2c(sc, 0x22, 0x00, 0x07);
23534886ec58SHasso Tepper 		envy24ht_wri2c(sc, 0x22, 0x04, 0x5f | 0x80);
23544886ec58SHasso Tepper 		envy24ht_wri2c(sc, 0x22, 0x05, 0x5f | 0x80);
23554886ec58SHasso Tepper 	}
23564886ec58SHasso Tepper 
23574886ec58SHasso Tepper 	for (i = 0; i < sc->adcn; i++) {
23584886ec58SHasso Tepper 		sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i);
23594886ec58SHasso Tepper 		sc->cfg->codec->init(sc->adc[i]);
23604886ec58SHasso Tepper 	}
23614886ec58SHasso Tepper 	for (i = 0; i < sc->dacn; i++) {
23624886ec58SHasso Tepper 		sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i);
23634886ec58SHasso Tepper 		sc->cfg->codec->init(sc->dac[i]);
23644886ec58SHasso Tepper 	}
23654886ec58SHasso Tepper 
23664886ec58SHasso Tepper 	/* initialize DMA buffer */
23672a1ad637SFrançois Tigeot #if(0)
23684886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_init(): initialize DMA buffer\n");
23694886ec58SHasso Tepper #endif
23704886ec58SHasso Tepper 	if (envy24ht_dmainit(sc))
23714886ec58SHasso Tepper 		return ENOSPC;
23724886ec58SHasso Tepper 
23734886ec58SHasso Tepper 	/* initialize status */
23744886ec58SHasso Tepper 	sc->run[0] = sc->run[1] = 0;
23754886ec58SHasso Tepper 	sc->intr[0] = sc->intr[1] = 0;
23764886ec58SHasso Tepper 	sc->speed = 0;
23774886ec58SHasso Tepper 	sc->caps[0].fmtlist = envy24ht_playfmt;
23784886ec58SHasso Tepper 	sc->caps[1].fmtlist = envy24ht_recfmt;
23794886ec58SHasso Tepper 
23804886ec58SHasso Tepper 	/* set channel router */
23814886ec58SHasso Tepper #if 0
23824886ec58SHasso Tepper 	envy24ht_route(sc, ENVY24HT_ROUTE_DAC_1, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
23834886ec58SHasso Tepper 	envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_DMA, 0, 0);
23844886ec58SHasso Tepper 	envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
23854886ec58SHasso Tepper #endif
23864886ec58SHasso Tepper 
23874886ec58SHasso Tepper 	/* set macro interrupt mask */
23884886ec58SHasso Tepper 	data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
23894886ec58SHasso Tepper 	envy24ht_wrcs(sc, ENVY24HT_CCS_IMASK, data & ~ENVY24HT_CCS_IMASK_PMT, 1);
23904886ec58SHasso Tepper 	data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
23912a1ad637SFrançois Tigeot #if(0)
23924886ec58SHasso Tepper 	device_printf(sc->dev, "envy24ht_init(): CCS_IMASK-->0x%02x\n", data);
23934886ec58SHasso Tepper #endif
23944886ec58SHasso Tepper 
23954886ec58SHasso Tepper 	return 0;
23964886ec58SHasso Tepper }
23974886ec58SHasso Tepper 
23984886ec58SHasso Tepper static int
envy24ht_alloc_resource(struct sc_info * sc)23994886ec58SHasso Tepper envy24ht_alloc_resource(struct sc_info *sc)
24004886ec58SHasso Tepper {
24014886ec58SHasso Tepper 	/* allocate I/O port resource */
24024886ec58SHasso Tepper 	sc->csid = PCIR_CCS;
24034886ec58SHasso Tepper 	sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
24044886ec58SHasso Tepper 	    &sc->csid, 0, ~0, 1, RF_ACTIVE);
24054886ec58SHasso Tepper 	sc->mtid = ENVY24HT_PCIR_MT;
24064886ec58SHasso Tepper 	sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
24074886ec58SHasso Tepper 	    &sc->mtid, 0, ~0, 1, RF_ACTIVE);
24084886ec58SHasso Tepper 	if (!sc->cs || !sc->mt) {
24094886ec58SHasso Tepper 		device_printf(sc->dev, "unable to map IO port space\n");
24104886ec58SHasso Tepper 		return ENXIO;
24114886ec58SHasso Tepper 	}
24124886ec58SHasso Tepper 	sc->cst = rman_get_bustag(sc->cs);
24134886ec58SHasso Tepper 	sc->csh = rman_get_bushandle(sc->cs);
24144886ec58SHasso Tepper 	sc->mtt = rman_get_bustag(sc->mt);
24154886ec58SHasso Tepper 	sc->mth = rman_get_bushandle(sc->mt);
24162a1ad637SFrançois Tigeot #if(0)
24174886ec58SHasso Tepper 	device_printf(sc->dev,
24184886ec58SHasso Tepper 	    "IO port register values\nCCS: 0x%lx\nMT: 0x%lx\n",
24194886ec58SHasso Tepper 	    pci_read_config(sc->dev, PCIR_CCS, 4),
24204886ec58SHasso Tepper 	    pci_read_config(sc->dev, PCIR_MT, 4));
24214886ec58SHasso Tepper #endif
24224886ec58SHasso Tepper 
24232a1ad637SFrançois Tigeot 	/* allocate interrupt resource */
24244886ec58SHasso Tepper 	sc->irqid = 0;
24254886ec58SHasso Tepper 	sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid,
24264886ec58SHasso Tepper 				 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
24274886ec58SHasso Tepper 	if (!sc->irq ||
24282a1ad637SFrançois Tigeot 	    snd_setup_intr(sc->dev, sc->irq, INTR_MPSAFE, envy24ht_intr, sc, &sc->ih)) {
24294886ec58SHasso Tepper 		device_printf(sc->dev, "unable to map interrupt\n");
24304886ec58SHasso Tepper 		return ENXIO;
24314886ec58SHasso Tepper 	}
24324886ec58SHasso Tepper 
24334886ec58SHasso Tepper 	/* allocate DMA resource */
24342a1ad637SFrançois Tigeot 	if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev),
24354886ec58SHasso Tepper 	    /*alignment*/4,
24364886ec58SHasso Tepper 	    /*boundary*/0,
24372a1ad637SFrançois Tigeot 	    /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
24382a1ad637SFrançois Tigeot 	    /*highaddr*/BUS_SPACE_MAXADDR,
24394886ec58SHasso Tepper 	    /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24,
24404886ec58SHasso Tepper 	    /*nsegments*/1, /*maxsegsz*/0x3ffff,
24414923c0eaSFrançois Tigeot 	    /*flags*/0,
24424923c0eaSFrançois Tigeot 	    &sc->dmat) != 0) {
24434886ec58SHasso Tepper 		device_printf(sc->dev, "unable to create dma tag\n");
24444886ec58SHasso Tepper 		return ENXIO;
24454886ec58SHasso Tepper 	}
24464886ec58SHasso Tepper 
24474886ec58SHasso Tepper 	return 0;
24484886ec58SHasso Tepper }
24494886ec58SHasso Tepper 
24504886ec58SHasso Tepper static int
envy24ht_pci_attach(device_t dev)24514886ec58SHasso Tepper envy24ht_pci_attach(device_t dev)
24524886ec58SHasso Tepper {
24534886ec58SHasso Tepper 	struct sc_info 		*sc;
24544886ec58SHasso Tepper 	char 			status[SND_STATUSLEN];
24554886ec58SHasso Tepper 	int			err = 0;
24564886ec58SHasso Tepper 	int			i;
24574886ec58SHasso Tepper 
24582a1ad637SFrançois Tigeot #if(0)
24594886ec58SHasso Tepper 	device_printf(dev, "envy24ht_pci_attach()\n");
24604886ec58SHasso Tepper #endif
24614886ec58SHasso Tepper 	/* get sc_info data area */
24624e8e900cSMatthew Dillon 	if ((sc = kmalloc(sizeof(*sc), M_ENVY24HT, M_WAITOK | M_ZERO)) == NULL) {
24632a1ad637SFrançois Tigeot 		device_printf(dev, "cannot allocate softc\n");
24642a1ad637SFrançois Tigeot 		return ENXIO;
24652a1ad637SFrançois Tigeot 	}
24662a1ad637SFrançois Tigeot 
24672a1ad637SFrançois Tigeot 	bzero(sc, sizeof(*sc));
24684886ec58SHasso Tepper 	sc->lock = snd_mtxcreate(device_get_nameunit(dev),
24694886ec58SHasso Tepper 	    "snd_envy24ht softc");
24704886ec58SHasso Tepper 	sc->dev = dev;
24714886ec58SHasso Tepper 
24724886ec58SHasso Tepper 	/* initialize PCI interface */
24732a1ad637SFrançois Tigeot 	pci_enable_busmaster(dev);
24744886ec58SHasso Tepper 
24754886ec58SHasso Tepper 	/* allocate resources */
24764886ec58SHasso Tepper 	err = envy24ht_alloc_resource(sc);
24774886ec58SHasso Tepper 	if (err) {
24784886ec58SHasso Tepper 		device_printf(dev, "unable to allocate system resources\n");
24794886ec58SHasso Tepper 		goto bad;
24804886ec58SHasso Tepper 	}
24814886ec58SHasso Tepper 
24824886ec58SHasso Tepper 	/* initialize card */
24834886ec58SHasso Tepper 	err = envy24ht_init(sc);
24844886ec58SHasso Tepper 	if (err) {
24854886ec58SHasso Tepper 		device_printf(dev, "unable to initialize the card\n");
24864886ec58SHasso Tepper 		goto bad;
24874886ec58SHasso Tepper 	}
24884886ec58SHasso Tepper 
24894886ec58SHasso Tepper 	/* set multi track mixer */
24904886ec58SHasso Tepper 	mixer_init(dev, &envy24htmixer_class, sc);
24914886ec58SHasso Tepper 
24924886ec58SHasso Tepper 	/* set channel information */
24934886ec58SHasso Tepper 	/* err = pcm_register(dev, sc, 5, 2 + sc->adcn); */
24944886ec58SHasso Tepper 	err = pcm_register(dev, sc, 1, 2 + sc->adcn);
24954886ec58SHasso Tepper 	if (err)
24964886ec58SHasso Tepper 		goto bad;
24974886ec58SHasso Tepper 	sc->chnum = 0;
24984886ec58SHasso Tepper 	/* for (i = 0; i < 5; i++) { */
24994886ec58SHasso Tepper 		pcm_addchan(dev, PCMDIR_PLAY, &envy24htchan_class, sc);
25004886ec58SHasso Tepper 		sc->chnum++;
25014886ec58SHasso Tepper 	/* } */
25024886ec58SHasso Tepper 	for (i = 0; i < 2 + sc->adcn; i++) {
25034886ec58SHasso Tepper 		pcm_addchan(dev, PCMDIR_REC, &envy24htchan_class, sc);
25044886ec58SHasso Tepper 		sc->chnum++;
25054886ec58SHasso Tepper 	}
25064886ec58SHasso Tepper 
25074886ec58SHasso Tepper 	/* set status iformation */
250867931cc4SFrançois Tigeot 	ksnprintf(status, SND_STATUSLEN,
25094886ec58SHasso Tepper 	    "at io 0x%lx:%ld,0x%lx:%ld irq %ld",
25104886ec58SHasso Tepper 	    rman_get_start(sc->cs),
25114886ec58SHasso Tepper 	    rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1,
25124886ec58SHasso Tepper 	    rman_get_start(sc->mt),
25134886ec58SHasso Tepper 	    rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1,
25144886ec58SHasso Tepper 	    rman_get_start(sc->irq));
25154886ec58SHasso Tepper 	pcm_setstatus(dev, status);
25164886ec58SHasso Tepper 
25174886ec58SHasso Tepper 	return 0;
25184886ec58SHasso Tepper 
25194886ec58SHasso Tepper bad:
25204886ec58SHasso Tepper 	if (sc->ih)
25214886ec58SHasso Tepper 		bus_teardown_intr(dev, sc->irq, sc->ih);
25224886ec58SHasso Tepper 	if (sc->irq)
25234886ec58SHasso Tepper 		bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
25244886ec58SHasso Tepper 	envy24ht_dmafree(sc);
25254886ec58SHasso Tepper 	if (sc->dmat)
25264886ec58SHasso Tepper 		bus_dma_tag_destroy(sc->dmat);
25274886ec58SHasso Tepper         if (sc->cfg->codec->destroy != NULL) {
25284886ec58SHasso Tepper                 for (i = 0; i < sc->adcn; i++)
25294886ec58SHasso Tepper                         sc->cfg->codec->destroy(sc->adc[i]);
25304886ec58SHasso Tepper                 for (i = 0; i < sc->dacn; i++)
25314886ec58SHasso Tepper                         sc->cfg->codec->destroy(sc->dac[i]);
25324886ec58SHasso Tepper         }
25334886ec58SHasso Tepper 	envy24ht_cfgfree(sc->cfg);
25344886ec58SHasso Tepper 	if (sc->cs)
25354886ec58SHasso Tepper 		bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
25364886ec58SHasso Tepper 	if (sc->mt)
25374886ec58SHasso Tepper 		bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
25384886ec58SHasso Tepper 	if (sc->lock)
25394886ec58SHasso Tepper 		snd_mtxfree(sc->lock);
254067931cc4SFrançois Tigeot 	kfree(sc, M_ENVY24HT);
25414886ec58SHasso Tepper 	return err;
25424886ec58SHasso Tepper }
25434886ec58SHasso Tepper 
25444886ec58SHasso Tepper static int
envy24ht_pci_detach(device_t dev)25454886ec58SHasso Tepper envy24ht_pci_detach(device_t dev)
25464886ec58SHasso Tepper {
25474886ec58SHasso Tepper 	struct sc_info *sc;
25484886ec58SHasso Tepper 	int r;
25494886ec58SHasso Tepper 	int i;
25504886ec58SHasso Tepper 
25512a1ad637SFrançois Tigeot #if(0)
25524886ec58SHasso Tepper 	device_printf(dev, "envy24ht_pci_detach()\n");
25534886ec58SHasso Tepper #endif
25544886ec58SHasso Tepper 	sc = pcm_getdevinfo(dev);
25554886ec58SHasso Tepper 	if (sc == NULL)
25564886ec58SHasso Tepper 		return 0;
25574886ec58SHasso Tepper 	r = pcm_unregister(dev);
25584886ec58SHasso Tepper 	if (r)
25594886ec58SHasso Tepper 		return r;
25604886ec58SHasso Tepper 
25614886ec58SHasso Tepper 	envy24ht_dmafree(sc);
25624886ec58SHasso Tepper 	if (sc->cfg->codec->destroy != NULL) {
25634886ec58SHasso Tepper 		for (i = 0; i < sc->adcn; i++)
25644886ec58SHasso Tepper 			sc->cfg->codec->destroy(sc->adc[i]);
25654886ec58SHasso Tepper 		for (i = 0; i < sc->dacn; i++)
25664886ec58SHasso Tepper 			sc->cfg->codec->destroy(sc->dac[i]);
25674886ec58SHasso Tepper 	}
25684886ec58SHasso Tepper 	envy24ht_cfgfree(sc->cfg);
25694886ec58SHasso Tepper 	bus_dma_tag_destroy(sc->dmat);
25704886ec58SHasso Tepper 	bus_teardown_intr(dev, sc->irq, sc->ih);
25714886ec58SHasso Tepper 	bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
25724886ec58SHasso Tepper 	bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
25734886ec58SHasso Tepper 	bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
25744886ec58SHasso Tepper 	snd_mtxfree(sc->lock);
257567931cc4SFrançois Tigeot 	kfree(sc, M_ENVY24HT);
25764886ec58SHasso Tepper 	return 0;
25774886ec58SHasso Tepper }
25784886ec58SHasso Tepper 
25794886ec58SHasso Tepper static device_method_t envy24ht_methods[] = {
25804886ec58SHasso Tepper 	/* Device interface */
25814886ec58SHasso Tepper 	DEVMETHOD(device_probe,		envy24ht_pci_probe),
25824886ec58SHasso Tepper 	DEVMETHOD(device_attach,	envy24ht_pci_attach),
25834886ec58SHasso Tepper 	DEVMETHOD(device_detach,	envy24ht_pci_detach),
25842a1ad637SFrançois Tigeot 	{ 0, 0 }
25854886ec58SHasso Tepper };
25864886ec58SHasso Tepper 
25874886ec58SHasso Tepper static driver_t envy24ht_driver = {
25884886ec58SHasso Tepper 	"pcm",
25894886ec58SHasso Tepper 	envy24ht_methods,
25904886ec58SHasso Tepper 	PCM_SOFTC_SIZE,
25914886ec58SHasso Tepper };
25924886ec58SHasso Tepper 
2593*aa6ac96eSSascha Wildner DRIVER_MODULE(snd_envy24ht, pci, envy24ht_driver, pcm_devclass, NULL, NULL);
25944886ec58SHasso Tepper MODULE_DEPEND(snd_envy24ht, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
25954886ec58SHasso Tepper MODULE_DEPEND(snd_envy24ht, snd_spicds, 1, 1, 1);
25964886ec58SHasso Tepper MODULE_VERSION(snd_envy24ht, 1);
2597