1139749Simp/*-
279047Scg * Copyright (c) 2000 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp>
379148Scg * Copyright (c) 2001 Cameron Grant <cg@freebsd.org>
479047Scg * All rights reserved.
579047Scg *
679047Scg * Redistribution and use in source and binary forms, with or without
779047Scg * modification, are permitted provided that the following conditions
879047Scg * are met:
979047Scg * 1. Redistributions of source code must retain the above copyright
1079047Scg *    notice, this list of conditions and the following disclaimer.
1179047Scg * 2. Redistributions in binary form must reproduce the above copyright
1279047Scg *    notice, this list of conditions and the following disclaimer in the
1379047Scg *    documentation and/or other materials provided with the distribution.
1479047Scg *
1579047Scg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1679047Scg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1779047Scg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1879047Scg * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1979047Scg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2079047Scg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2179047Scg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2279047Scg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
2379047Scg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2479047Scg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF
2579047Scg * SUCH DAMAGE.
2679047Scg */
2779047Scg
28193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS
29193640Sariff#include "opt_snd.h"
30193640Sariff#endif
31193640Sariff
3279047Scg#include <dev/sound/pcm/sound.h>
3379047Scg#include <dev/sound/pcm/ac97.h>
3479148Scg#include <dev/sound/pci/ich.h>
3579047Scg
36119287Simp#include <dev/pci/pcireg.h>
37119287Simp#include <dev/pci/pcivar.h>
3879047Scg
3982180ScgSND_DECLARE_FILE("$FreeBSD$");
4082180Scg
4179047Scg/* -------------------------------------------------------------------- */
4279047Scg
43164614Sariff#define ICH_TIMEOUT		1000 /* semaphore timeout polling count */
44164614Sariff#define ICH_DTBL_LENGTH		32
45164614Sariff#define ICH_DEFAULT_BUFSZ	16384
46164614Sariff#define ICH_MAX_BUFSZ		65536
47164614Sariff#define ICH_MIN_BUFSZ		4096
48164614Sariff#define ICH_DEFAULT_BLKCNT	2
49164614Sariff#define ICH_MAX_BLKCNT		32
50164614Sariff#define ICH_MIN_BLKCNT		2
51169278Sariff#define ICH_MIN_BLKSZ		64
5279047Scg
53152420Sariff#define INTEL_VENDORID	0x8086
54152420Sariff#define SIS_VENDORID	0x1039
55152420Sariff#define NVIDIA_VENDORID	0x10de
56152420Sariff#define AMD_VENDORID	0x1022
5790880Salfred
58152420Sariff#define INTEL_82440MX	0x7195
59152420Sariff#define INTEL_82801AA	0x2415
60152420Sariff#define INTEL_82801AB	0x2425
61152420Sariff#define INTEL_82801BA	0x2445
62152420Sariff#define INTEL_82801CA	0x2485
63152420Sariff#define INTEL_82801DB	0x24c5	/* ICH4 needs special handling */
64152420Sariff#define INTEL_82801EB	0x24d5	/* ICH5 needs to be treated as ICH4 */
65152420Sariff#define INTEL_6300ESB	0x25a6	/* 6300ESB needs to be treated as ICH4 */
66152420Sariff#define INTEL_82801FB	0x266e	/* ICH6 needs to be treated as ICH4 */
67152420Sariff#define INTEL_82801GB	0x27de	/* ICH7 needs to be treated as ICH4 */
68152420Sariff#define SIS_7012	0x7012	/* SiS 7012 needs special handling */
69152420Sariff#define NVIDIA_NFORCE	0x01b1
70152420Sariff#define NVIDIA_NFORCE2	0x006a
71152420Sariff#define NVIDIA_NFORCE2_400	0x008a
72152420Sariff#define NVIDIA_NFORCE3	0x00da
73152420Sariff#define NVIDIA_NFORCE3_250	0x00ea
74152420Sariff#define NVIDIA_NFORCE4	0x0059
75157436Sariff#define NVIDIA_NFORCE_410_MCP	0x026b
76165304Sariff#define NVIDIA_NFORCE4_MCP	0x003a
77152420Sariff#define AMD_768		0x7445
78152420Sariff#define AMD_8111	0x746d
79152420Sariff
80152420Sariff#define ICH_LOCK(sc)		snd_mtxlock((sc)->ich_lock)
81152420Sariff#define ICH_UNLOCK(sc)		snd_mtxunlock((sc)->ich_lock)
82152420Sariff#define ICH_LOCK_ASSERT(sc)	snd_mtxassert((sc)->ich_lock)
83152420Sariff
84164614Sariff#if 0
85164614Sariff#define ICH_DEBUG(stmt)		do {	\
86164614Sariff	stmt				\
87193640Sariff} while (0)
88164614Sariff#else
89169278Sariff#define ICH_DEBUG(...)
90164614Sariff#endif
91164614Sariff
92169278Sariff#define ICH_CALIBRATE_DONE	(1 << 0)
93169278Sariff#define ICH_IGNORE_PCR		(1 << 1)
94169278Sariff#define ICH_IGNORE_RESET	(1 << 2)
95169278Sariff#define ICH_FIXED_RATE		(1 << 3)
96169278Sariff#define ICH_DMA_NOCACHE		(1 << 4)
97169278Sariff#define ICH_HIGH_LATENCY	(1 << 5)
98169278Sariff
99152420Sariffstatic const struct ich_type {
100152420Sariff        uint16_t	vendor;
101152420Sariff        uint16_t	devid;
102152420Sariff	uint32_t	options;
103152420Sariff#define PROBE_LOW	0x01
104152420Sariff        char		*name;
105152420Sariff} ich_devs[] = {
106152420Sariff	{ INTEL_VENDORID,	INTEL_82440MX,	0,
107152420Sariff		"Intel 440MX" },
108152420Sariff	{ INTEL_VENDORID,	INTEL_82801AA,	0,
109152420Sariff		"Intel ICH (82801AA)" },
110152420Sariff	{ INTEL_VENDORID,	INTEL_82801AB,	0,
111152420Sariff		"Intel ICH (82801AB)" },
112152420Sariff	{ INTEL_VENDORID,	INTEL_82801BA,	0,
113152420Sariff		"Intel ICH2 (82801BA)" },
114152420Sariff	{ INTEL_VENDORID,	INTEL_82801CA,	0,
115152420Sariff		"Intel ICH3 (82801CA)" },
116152420Sariff	{ INTEL_VENDORID,	INTEL_82801DB,	PROBE_LOW,
117152420Sariff		"Intel ICH4 (82801DB)" },
118152420Sariff	{ INTEL_VENDORID,	INTEL_82801EB,	PROBE_LOW,
119152420Sariff		"Intel ICH5 (82801EB)" },
120152420Sariff	{ INTEL_VENDORID,	INTEL_6300ESB,	PROBE_LOW,
121152420Sariff		"Intel 6300ESB" },
122152420Sariff	{ INTEL_VENDORID,	INTEL_82801FB,	PROBE_LOW,
123152420Sariff		"Intel ICH6 (82801FB)" },
124152420Sariff	{ INTEL_VENDORID,	INTEL_82801GB,	PROBE_LOW,
125152420Sariff		"Intel ICH7 (82801GB)" },
126152420Sariff	{ SIS_VENDORID,		SIS_7012,	0,
127152420Sariff		"SiS 7012" },
128152420Sariff	{ NVIDIA_VENDORID,	NVIDIA_NFORCE,	0,
129152420Sariff		"nVidia nForce" },
130152420Sariff	{ NVIDIA_VENDORID,	NVIDIA_NFORCE2,	0,
131152420Sariff		"nVidia nForce2" },
132152420Sariff	{ NVIDIA_VENDORID,	NVIDIA_NFORCE2_400,	0,
133152420Sariff		"nVidia nForce2 400" },
134152420Sariff	{ NVIDIA_VENDORID,	NVIDIA_NFORCE3,	0,
135152420Sariff		"nVidia nForce3" },
136152420Sariff	{ NVIDIA_VENDORID,	NVIDIA_NFORCE3_250,	0,
137152420Sariff		"nVidia nForce3 250" },
138152420Sariff	{ NVIDIA_VENDORID,	NVIDIA_NFORCE4,	0,
139152420Sariff		"nVidia nForce4" },
140157436Sariff	{ NVIDIA_VENDORID,	NVIDIA_NFORCE_410_MCP,	0,
141157436Sariff		"nVidia nForce 410 MCP" },
142165304Sariff	{ NVIDIA_VENDORID,	NVIDIA_NFORCE4_MCP,	0,
143165304Sariff		"nVidia nForce 4 MCP" },
144152420Sariff	{ AMD_VENDORID,		AMD_768,	0,
145152420Sariff		"AMD-768" },
146152420Sariff	{ AMD_VENDORID,		AMD_8111,	0,
147152420Sariff		"AMD-8111" }
148152420Sariff};
149152420Sariff
15079047Scg/* buffer descriptor */
15179047Scgstruct ich_desc {
152164614Sariff	volatile uint32_t buffer;
153164614Sariff	volatile uint32_t length;
15479047Scg};
15579047Scg
15679047Scgstruct sc_info;
15779047Scg
15879047Scg/* channel registers */
15979047Scgstruct sc_chinfo {
160164614Sariff	uint32_t num:8, run:1, run_save:1;
161164614Sariff	uint32_t blksz, blkcnt, spd;
162164614Sariff	uint32_t regbase, spdreg;
163164614Sariff	uint32_t imask;
164164614Sariff	uint32_t civ;
16579148Scg
16679047Scg	struct snd_dbuf *buffer;
16779047Scg	struct pcm_channel *channel;
16879047Scg	struct sc_info *parent;
16979148Scg
17079148Scg	struct ich_desc *dtbl;
171111183Scognet	bus_addr_t desc_addr;
17279047Scg};
17379047Scg
17479047Scg/* device private data */
17579047Scgstruct sc_info {
17679148Scg	device_t dev;
17783617Scg	int hasvra, hasvrm, hasmic;
178164614Sariff	unsigned int chnum, bufsz, blkcnt;
179169278Sariff	int sample_size, swap_reg;
18079047Scg
18179148Scg	struct resource *nambar, *nabmbar, *irq;
182118729Sorion	int regtype, nambarid, nabmbarid, irqid;
18379047Scg	bus_space_tag_t nambart, nabmbart;
18479047Scg	bus_space_handle_t nambarh, nabmbarh;
185169278Sariff	bus_dma_tag_t dmat, chan_dmat;
18679148Scg	bus_dmamap_t dtmap;
18779148Scg	void *ih;
18879047Scg
18979047Scg	struct ac97_info *codec;
19079148Scg	struct sc_chinfo ch[3];
191169278Sariff	int ac97rate;
19279148Scg	struct ich_desc *dtbl;
193169278Sariff	unsigned int dtbl_size;
194111183Scognet	bus_addr_t desc_addr;
19598940Sscottl	struct intr_config_hook	intrhook;
196152420Sariff	uint16_t vendor;
197152420Sariff	uint16_t devid;
198152644Syongari	uint32_t flags;
199152420Sariff	struct mtx *ich_lock;
20079047Scg};
20179047Scg
20279047Scg/* -------------------------------------------------------------------- */
20379047Scg
204164614Sariffstatic uint32_t ich_fmt[] = {
205193640Sariff	SND_FORMAT(AFMT_S16_LE, 2, 0),
20679047Scg	0
20779047Scg};
20879148Scgstatic struct pcmchan_caps ich_vrcaps = {8000, 48000, ich_fmt, 0};
20979148Scgstatic struct pcmchan_caps ich_caps = {48000, 48000, ich_fmt, 0};
21079047Scg
21179047Scg/* -------------------------------------------------------------------- */
21279047Scg/* Hardware */
213164614Sariffstatic __inline uint32_t
21479047Scgich_rd(struct sc_info *sc, int regno, int size)
21579047Scg{
21679047Scg	switch (size) {
21779047Scg	case 1:
218164614Sariff		return (bus_space_read_1(sc->nabmbart, sc->nabmbarh, regno));
21979047Scg	case 2:
220164614Sariff		return (bus_space_read_2(sc->nabmbart, sc->nabmbarh, regno));
22179047Scg	case 4:
222164614Sariff		return (bus_space_read_4(sc->nabmbart, sc->nabmbarh, regno));
22379047Scg	default:
224164614Sariff		return (0xffffffff);
22579047Scg	}
22679047Scg}
22779047Scg
228152420Sariffstatic __inline void
229164614Sariffich_wr(struct sc_info *sc, int regno, uint32_t data, int size)
23079047Scg{
23179047Scg	switch (size) {
23279047Scg	case 1:
23379148Scg		bus_space_write_1(sc->nabmbart, sc->nabmbarh, regno, data);
23479047Scg		break;
23579047Scg	case 2:
23679148Scg		bus_space_write_2(sc->nabmbart, sc->nabmbarh, regno, data);
23779047Scg		break;
23879047Scg	case 4:
23979148Scg		bus_space_write_4(sc->nabmbart, sc->nabmbarh, regno, data);
24079047Scg		break;
24179047Scg	}
24279047Scg}
24379047Scg
24479047Scg/* ac97 codec */
24579047Scgstatic int
24679047Scgich_waitcd(void *devinfo)
24779047Scg{
248164614Sariff	struct sc_info *sc = (struct sc_info *)devinfo;
249164614Sariff	uint32_t data;
25079047Scg	int i;
25179148Scg
25279148Scg	for (i = 0; i < ICH_TIMEOUT; i++) {
25379148Scg		data = ich_rd(sc, ICH_REG_ACC_SEMA, 1);
25479047Scg		if ((data & 0x01) == 0)
255164614Sariff			return (0);
256152644Syongari		DELAY(1);
25779047Scg	}
258169278Sariff	if ((sc->flags & ICH_IGNORE_PCR) != 0)
259152644Syongari		return (0);
26079047Scg	device_printf(sc->dev, "CODEC semaphore timeout\n");
261164614Sariff	return (ETIMEDOUT);
26279047Scg}
26379047Scg
26479047Scgstatic int
26579047Scgich_rdcd(kobj_t obj, void *devinfo, int regno)
26679047Scg{
26779047Scg	struct sc_info *sc = (struct sc_info *)devinfo;
26879148Scg
26979047Scg	regno &= 0xff;
27079047Scg	ich_waitcd(sc);
27179148Scg
272164614Sariff	return (bus_space_read_2(sc->nambart, sc->nambarh, regno));
27379047Scg}
27479047Scg
27579047Scgstatic int
276193640Sariffich_wrcd(kobj_t obj, void *devinfo, int regno, uint32_t data)
27779047Scg{
27879047Scg	struct sc_info *sc = (struct sc_info *)devinfo;
27979148Scg
28079047Scg	regno &= 0xff;
28179047Scg	ich_waitcd(sc);
28279148Scg	bus_space_write_2(sc->nambart, sc->nambarh, regno, data);
28379148Scg
284164614Sariff	return (0);
28579047Scg}
28679047Scg
28779047Scgstatic kobj_method_t ich_ac97_methods[] = {
28879047Scg	KOBJMETHOD(ac97_read,		ich_rdcd),
28979047Scg	KOBJMETHOD(ac97_write,		ich_wrcd),
290193640Sariff	KOBJMETHOD_END
29179047Scg};
29279047ScgAC97_DECLARE(ich_ac97);
29379047Scg
29479047Scg/* -------------------------------------------------------------------- */
29579148Scg/* common routines */
29679047Scg
29779047Scgstatic void
29879148Scgich_filldtbl(struct sc_chinfo *ch)
29979047Scg{
300152420Sariff	struct sc_info *sc = ch->parent;
301164614Sariff	uint32_t base;
30282478Scg	int i;
30379047Scg
304111183Scognet	base = sndbuf_getbufaddr(ch->buffer);
305164614Sariff	if ((ch->blksz * ch->blkcnt) > sndbuf_getmaxsize(ch->buffer))
306164614Sariff		ch->blksz = sndbuf_getmaxsize(ch->buffer) / ch->blkcnt;
307164614Sariff	if ((sndbuf_getblksz(ch->buffer) != ch->blksz ||
308164614Sariff	    sndbuf_getblkcnt(ch->buffer) != ch->blkcnt) &&
309164614Sariff	    sndbuf_resize(ch->buffer, ch->blkcnt, ch->blksz) != 0)
310164614Sariff		device_printf(sc->dev, "%s: failed blksz=%u blkcnt=%u\n",
311164614Sariff		    __func__, ch->blksz, ch->blkcnt);
312152420Sariff	ch->blksz = sndbuf_getblksz(ch->buffer);
31379047Scg
31479148Scg	for (i = 0; i < ICH_DTBL_LENGTH; i++) {
31582478Scg		ch->dtbl[i].buffer = base + (ch->blksz * (i % ch->blkcnt));
31690880Salfred		ch->dtbl[i].length = ICH_BDC_IOC
31790880Salfred				   | (ch->blksz / ch->parent->sample_size);
31879047Scg	}
31979047Scg}
32079047Scg
32179148Scgstatic int
32279148Scgich_resetchan(struct sc_info *sc, int num)
32379047Scg{
32479148Scg	int i, cr, regbase;
32579047Scg
32679148Scg	if (num == 0)
32779148Scg		regbase = ICH_REG_PO_BASE;
32879148Scg	else if (num == 1)
32979148Scg		regbase = ICH_REG_PI_BASE;
33079148Scg	else if (num == 2)
33179148Scg		regbase = ICH_REG_MC_BASE;
33279148Scg	else
333164614Sariff		return (ENXIO);
33479047Scg
33579148Scg	ich_wr(sc, regbase + ICH_REG_X_CR, 0, 1);
336150979Snetchild#if 1
337150979Snetchild	/* This may result in no sound output on NForce 2 MBs, see PR 73987 */
33879148Scg	DELAY(100);
339150979Snetchild#else
340150979Snetchild	(void)ich_rd(sc, regbase + ICH_REG_X_CR, 1);
341150979Snetchild#endif
34279148Scg	ich_wr(sc, regbase + ICH_REG_X_CR, ICH_X_CR_RR, 1);
34379148Scg	for (i = 0; i < ICH_TIMEOUT; i++) {
34479148Scg		cr = ich_rd(sc, regbase + ICH_REG_X_CR, 1);
34579148Scg		if (cr == 0)
346164614Sariff			return (0);
347169278Sariff		DELAY(1);
34879148Scg	}
34979047Scg
350169278Sariff	if (sc->flags & ICH_IGNORE_RESET)
351169278Sariff		return (0);
352169278Sariff#if 0
353169278Sariff	else if (sc->vendor == NVIDIA_VENDORID) {
354169278Sariff	    	sc->flags |= ICH_IGNORE_RESET;
355169278Sariff		device_printf(sc->dev, "ignoring reset failure!\n");
356169278Sariff		return (0);
357169278Sariff	}
358169278Sariff#endif
359169278Sariff
36079148Scg	device_printf(sc->dev, "cannot reset channel %d\n", num);
361164614Sariff	return (ENXIO);
36279047Scg}
36379047Scg
36479148Scg/* -------------------------------------------------------------------- */
36579148Scg/* channel interface */
36679047Scg
36779047Scgstatic void *
36879148Scgichchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
36979047Scg{
37079047Scg	struct sc_info *sc = devinfo;
37179047Scg	struct sc_chinfo *ch;
37283617Scg	unsigned int num;
37379047Scg
374152420Sariff	ICH_LOCK(sc);
37579148Scg	num = sc->chnum++;
37679148Scg	ch = &sc->ch[num];
37779148Scg	ch->num = num;
37879047Scg	ch->buffer = b;
37979047Scg	ch->channel = c;
38079047Scg	ch->parent = sc;
38179047Scg	ch->run = 0;
38279148Scg	ch->dtbl = sc->dtbl + (ch->num * ICH_DTBL_LENGTH);
383169278Sariff	ch->desc_addr = sc->desc_addr +
384169278Sariff	    (ch->num * ICH_DTBL_LENGTH * sizeof(struct ich_desc));
385164614Sariff	ch->blkcnt = sc->blkcnt;
38683617Scg	ch->blksz = sc->bufsz / ch->blkcnt;
38779047Scg
38879148Scg	switch(ch->num) {
38979148Scg	case 0: /* play */
39079148Scg		KASSERT(dir == PCMDIR_PLAY, ("wrong direction"));
39179148Scg		ch->regbase = ICH_REG_PO_BASE;
392164614Sariff		ch->spdreg = (sc->hasvra) ? AC97_REGEXT_FDACRATE : 0;
39388206Sorion		ch->imask = ICH_GLOB_STA_POINT;
39479148Scg		break;
39579047Scg
39682478Scg	case 1: /* record */
39779148Scg		KASSERT(dir == PCMDIR_REC, ("wrong direction"));
39882478Scg		ch->regbase = ICH_REG_PI_BASE;
399164614Sariff		ch->spdreg = (sc->hasvra) ? AC97_REGEXT_LADCRATE : 0;
40088206Sorion		ch->imask = ICH_GLOB_STA_PIINT;
40179148Scg		break;
40279047Scg
40382478Scg	case 2: /* mic */
40479148Scg		KASSERT(dir == PCMDIR_REC, ("wrong direction"));
40582478Scg		ch->regbase = ICH_REG_MC_BASE;
406164614Sariff		ch->spdreg = (sc->hasvrm) ? AC97_REGEXT_MADCRATE : 0;
40788206Sorion		ch->imask = ICH_GLOB_STA_MINT;
40879148Scg		break;
40979047Scg
41079148Scg	default:
411164614Sariff		return (NULL);
41279047Scg	}
41379047Scg
414169278Sariff	if (sc->flags & ICH_FIXED_RATE)
415164614Sariff		ch->spdreg = 0;
416164614Sariff
417152420Sariff	ICH_UNLOCK(sc);
418169278Sariff	if (sndbuf_alloc(ch->buffer, sc->chan_dmat,
419169278Sariff	    ((sc->flags & ICH_DMA_NOCACHE) ? BUS_DMA_NOCACHE : 0),
420169278Sariff	    sc->bufsz) != 0)
421164614Sariff		return (NULL);
42279047Scg
423152420Sariff	ICH_LOCK(sc);
424164614Sariff	ich_wr(sc, ch->regbase + ICH_REG_X_BDBAR, (uint32_t)(ch->desc_addr), 4);
425152420Sariff	ICH_UNLOCK(sc);
42679047Scg
427164614Sariff	return (ch);
42879047Scg}
42979047Scg
43079047Scgstatic int
431164614Sariffichchan_setformat(kobj_t obj, void *data, uint32_t format)
43279047Scg{
433164614Sariff
434164614Sariff	ICH_DEBUG(
435164614Sariff		struct sc_chinfo *ch = data;
436164614Sariff		struct sc_info *sc = ch->parent;
437169278Sariff		if (!(sc->flags & ICH_CALIBRATE_DONE))
438164614Sariff			device_printf(sc->dev,
439164614Sariff			    "WARNING: %s() called before calibration!\n",
440164614Sariff			    __func__);
441164614Sariff	);
442164614Sariff
443164614Sariff	return (0);
44479047Scg}
44579047Scg
446193640Sariffstatic uint32_t
447164614Sariffichchan_setspeed(kobj_t obj, void *data, uint32_t speed)
44879047Scg{
44979047Scg	struct sc_chinfo *ch = data;
45079047Scg	struct sc_info *sc = ch->parent;
45179047Scg
452164614Sariff	ICH_DEBUG(
453169278Sariff		if (!(sc->flags & ICH_CALIBRATE_DONE))
454164614Sariff			device_printf(sc->dev,
455164614Sariff			    "WARNING: %s() called before calibration!\n",
456164614Sariff			    __func__);
457164614Sariff	);
458164614Sariff
45988033Sorion	if (ch->spdreg) {
460152420Sariff		int r, ac97rate;
461152420Sariff
462152420Sariff		ICH_LOCK(sc);
46388033Sorion		if (sc->ac97rate <= 32000 || sc->ac97rate >= 64000)
46488033Sorion			sc->ac97rate = 48000;
465152420Sariff		ac97rate = sc->ac97rate;
466152420Sariff		ICH_UNLOCK(sc);
467152420Sariff		r = (speed * 48000) / ac97rate;
46894647Sjhay		/*
469164614Sariff		 * Cast the return value of ac97_setrate() to uint64 so that
47094647Sjhay		 * the math don't overflow into the negative range.
47194647Sjhay		 */
472164614Sariff		ch->spd = ((uint64_t)ac97_setrate(sc->codec, ch->spdreg, r) *
473152420Sariff				ac97rate) / 48000;
47488033Sorion	} else {
47588361Sorion		ch->spd = 48000;
47688033Sorion	}
477164614Sariff	return (ch->spd);
47879047Scg}
47979047Scg
480193640Sariffstatic uint32_t
481164614Sariffichchan_setblocksize(kobj_t obj, void *data, uint32_t blocksize)
48279047Scg{
48379047Scg	struct sc_chinfo *ch = data;
48479148Scg	struct sc_info *sc = ch->parent;
48579047Scg
486164614Sariff	ICH_DEBUG(
487169278Sariff		if (!(sc->flags & ICH_CALIBRATE_DONE))
488164614Sariff			device_printf(sc->dev,
489164614Sariff			    "WARNING: %s() called before calibration!\n",
490164614Sariff			    __func__);
491164614Sariff	);
492164614Sariff
493169278Sariff	if (sc->flags & ICH_HIGH_LATENCY)
494169278Sariff		blocksize = sndbuf_getmaxsize(ch->buffer) / ch->blkcnt;
495169278Sariff
496169278Sariff	if (blocksize < ICH_MIN_BLKSZ)
497169278Sariff		blocksize = ICH_MIN_BLKSZ;
498169278Sariff	blocksize &= ~(ICH_MIN_BLKSZ - 1);
49979148Scg	ch->blksz = blocksize;
50079148Scg	ich_filldtbl(ch);
501152420Sariff	ICH_LOCK(sc);
50282478Scg	ich_wr(sc, ch->regbase + ICH_REG_X_LVI, ch->blkcnt - 1, 1);
503152420Sariff	ICH_UNLOCK(sc);
50479047Scg
505164614Sariff	return (ch->blksz);
50679047Scg}
50779047Scg
50879047Scgstatic int
50979148Scgichchan_trigger(kobj_t obj, void *data, int go)
51079047Scg{
51179047Scg	struct sc_chinfo *ch = data;
51279047Scg	struct sc_info *sc = ch->parent;
51379047Scg
514164614Sariff	ICH_DEBUG(
515169278Sariff		if (!(sc->flags & ICH_CALIBRATE_DONE))
516164614Sariff			device_printf(sc->dev,
517164614Sariff			    "WARNING: %s() called before calibration!\n",
518164614Sariff			    __func__);
519164614Sariff	);
520164614Sariff
52179047Scg	switch (go) {
52279047Scg	case PCMTRIG_START:
52379047Scg		ch->run = 1;
524152420Sariff		ICH_LOCK(sc);
525164614Sariff		ich_wr(sc, ch->regbase + ICH_REG_X_BDBAR, (uint32_t)(ch->desc_addr), 4);
52689516Sorion		ich_wr(sc, ch->regbase + ICH_REG_X_CR, ICH_X_CR_RPBM | ICH_X_CR_LVBIE | ICH_X_CR_IOCE, 1);
527152420Sariff		ICH_UNLOCK(sc);
52879047Scg		break;
529170521Sariff	case PCMTRIG_STOP:
53079047Scg	case PCMTRIG_ABORT:
531152420Sariff		ICH_LOCK(sc);
53279148Scg		ich_resetchan(sc, ch->num);
533152420Sariff		ICH_UNLOCK(sc);
53479047Scg		ch->run = 0;
53579047Scg		break;
536170521Sariff	default:
537170521Sariff		break;
53879047Scg	}
539164614Sariff	return (0);
54079047Scg}
54179047Scg
542193640Sariffstatic uint32_t
54379148Scgichchan_getptr(kobj_t obj, void *data)
54479047Scg{
54579047Scg	struct sc_chinfo *ch = data;
54679047Scg	struct sc_info *sc = ch->parent;
547164614Sariff      	uint32_t pos;
54879047Scg
549164614Sariff	ICH_DEBUG(
550169278Sariff		if (!(sc->flags & ICH_CALIBRATE_DONE))
551164614Sariff			device_printf(sc->dev,
552164614Sariff			    "WARNING: %s() called before calibration!\n",
553164614Sariff			    __func__);
554164614Sariff	);
555164614Sariff
556152420Sariff	ICH_LOCK(sc);
55782478Scg	ch->civ = ich_rd(sc, ch->regbase + ICH_REG_X_CIV, 1) % ch->blkcnt;
558152420Sariff	ICH_UNLOCK(sc);
55979148Scg
56082478Scg	pos = ch->civ * ch->blksz;
56179148Scg
562164614Sariff	return (pos);
56379047Scg}
56479047Scg
56579047Scgstatic struct pcmchan_caps *
56679148Scgichchan_getcaps(kobj_t obj, void *data)
56779047Scg{
56879148Scg	struct sc_chinfo *ch = data;
56979148Scg
570164614Sariff	ICH_DEBUG(
571164614Sariff		struct sc_info *sc = ch->parent;
572164614Sariff
573169278Sariff		if (!(sc->flags & ICH_CALIBRATE_DONE))
574164614Sariff			device_printf(ch->parent->dev,
575164614Sariff			    "WARNING: %s() called before calibration!\n",
576164614Sariff			    __func__);
577164614Sariff	);
578164614Sariff
579164614Sariff	return ((ch->spdreg) ? &ich_vrcaps : &ich_caps);
58079047Scg}
58179047Scg
58279148Scgstatic kobj_method_t ichchan_methods[] = {
58379148Scg	KOBJMETHOD(channel_init,		ichchan_init),
58479148Scg	KOBJMETHOD(channel_setformat,		ichchan_setformat),
58579148Scg	KOBJMETHOD(channel_setspeed,		ichchan_setspeed),
58679148Scg	KOBJMETHOD(channel_setblocksize,	ichchan_setblocksize),
58779148Scg	KOBJMETHOD(channel_trigger,		ichchan_trigger),
58879148Scg	KOBJMETHOD(channel_getptr,		ichchan_getptr),
58979148Scg	KOBJMETHOD(channel_getcaps,		ichchan_getcaps),
590193640Sariff	KOBJMETHOD_END
59179047Scg};
59279148ScgCHANNEL_DECLARE(ichchan);
59379047Scg
59479047Scg/* -------------------------------------------------------------------- */
59579047Scg/* The interrupt handler */
59679148Scg
59779047Scgstatic void
59879047Scgich_intr(void *p)
59979047Scg{
60079047Scg	struct sc_info *sc = (struct sc_info *)p;
60179047Scg	struct sc_chinfo *ch;
602164614Sariff	uint32_t cbi, lbi, lvi, st, gs;
60379148Scg	int i;
60479047Scg
605152420Sariff	ICH_LOCK(sc);
606164614Sariff
607164614Sariff	ICH_DEBUG(
608169278Sariff		if (!(sc->flags & ICH_CALIBRATE_DONE))
609164614Sariff			device_printf(sc->dev,
610164614Sariff			    "WARNING: %s() called before calibration!\n",
611164614Sariff			    __func__);
612164614Sariff	);
613164614Sariff
61488215Sorion	gs = ich_rd(sc, ICH_REG_GLOB_STA, 4) & ICH_GLOB_STA_IMASK;
61588206Sorion	if (gs & (ICH_GLOB_STA_PRES | ICH_GLOB_STA_SRES)) {
61688206Sorion		/* Clear resume interrupt(s) - nothing doing with them */
61788206Sorion		ich_wr(sc, ICH_REG_GLOB_STA, gs, 4);
61888206Sorion	}
61988206Sorion	gs &= ~(ICH_GLOB_STA_PRES | ICH_GLOB_STA_SRES);
62088206Sorion
62179148Scg	for (i = 0; i < 3; i++) {
62279148Scg		ch = &sc->ch[i];
623117272Scg		if ((ch->imask & gs) == 0)
62488206Sorion			continue;
62588206Sorion		gs &= ~ch->imask;
626117272Scg		st = ich_rd(sc, ch->regbase +
627164614Sariff				((sc->swap_reg) ? ICH_REG_X_PICB : ICH_REG_X_SR),
62890880Salfred			    2);
62979148Scg		st &= ICH_X_SR_FIFOE | ICH_X_SR_BCIS | ICH_X_SR_LVBCI;
63088206Sorion		if (st & (ICH_X_SR_BCIS | ICH_X_SR_LVBCI)) {
63179148Scg				/* block complete - update buffer */
632152420Sariff			if (ch->run) {
633152420Sariff				ICH_UNLOCK(sc);
63488206Sorion				chn_intr(ch->channel);
635152420Sariff				ICH_LOCK(sc);
636152420Sariff			}
63788206Sorion			lvi = ich_rd(sc, ch->regbase + ICH_REG_X_LVI, 1);
63888206Sorion			cbi = ch->civ % ch->blkcnt;
63988206Sorion			if (cbi == 0)
64088206Sorion				cbi = ch->blkcnt - 1;
64188206Sorion			else
64288206Sorion				cbi--;
64388206Sorion			lbi = lvi % ch->blkcnt;
64488206Sorion			if (cbi >= lbi)
64588206Sorion				lvi += cbi - lbi;
64688206Sorion			else
64788206Sorion				lvi += cbi + ch->blkcnt - lbi;
64888206Sorion			lvi %= ICH_DTBL_LENGTH;
64988206Sorion			ich_wr(sc, ch->regbase + ICH_REG_X_LVI, lvi, 1);
65088206Sorion
65179047Scg		}
65288206Sorion		/* clear status bit */
653117272Scg		ich_wr(sc, ch->regbase +
654164614Sariff			   ((sc->swap_reg) ? ICH_REG_X_PICB : ICH_REG_X_SR),
65590880Salfred		       st, 2);
65679047Scg	}
657152420Sariff	ICH_UNLOCK(sc);
65888206Sorion	if (gs != 0) {
659117272Scg		device_printf(sc->dev,
66088206Sorion			      "Unhandled interrupt, gs_intr = %x\n", gs);
66188206Sorion	}
66279047Scg}
66379047Scg
66488033Sorion/* ------------------------------------------------------------------------- */
665117272Scg/* Sysctl to control ac97 speed (some boards appear to end up using
666117272Scg * XTAL_IN rather than BIT_CLK for link timing).
667113056Sorion */
66888033Sorion
66988033Sorionstatic int
67088033Sorionich_initsys(struct sc_info* sc)
67188033Sorion{
672159732Snetchild	/* XXX: this should move to a device specific sysctl "dev.pcm.X.yyy"
673159732Snetchild	   via device_get_sysctl_*() as discussed on multimedia@ in msg-id
674159732Snetchild	   <861wujij2q.fsf@xps.des.no> */
675164614Sariff	SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->dev),
676164614Sariff		       SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)),
677117272Scg		       OID_AUTO, "ac97rate", CTLFLAG_RW,
678117272Scg		       &sc->ac97rate, 48000,
67988033Sorion		       "AC97 link rate (default = 48000)");
680193640Sariff
681164614Sariff	return (0);
68288033Sorion}
68388033Sorion
684164614Sariffstatic void
685164614Sariffich_setstatus(struct sc_info *sc)
686164614Sariff{
687164614Sariff	char status[SND_STATUSLEN];
688164614Sariff
689164614Sariff	snprintf(status, SND_STATUSLEN,
690164614Sariff	    "at io 0x%lx, 0x%lx irq %ld bufsz %u %s",
691164614Sariff	    rman_get_start(sc->nambar), rman_get_start(sc->nabmbar),
692164614Sariff	    rman_get_start(sc->irq), sc->bufsz,PCM_KLDSTRING(snd_ich));
693164614Sariff
694169278Sariff	if (bootverbose && (sc->flags & ICH_DMA_NOCACHE))
695169278Sariff		device_printf(sc->dev,
696169278Sariff		    "PCI Master abort workaround enabled\n");
697169278Sariff
698164614Sariff	pcm_setstatus(sc->dev, status);
699164614Sariff}
700164614Sariff
70179047Scg/* -------------------------------------------------------------------- */
702117272Scg/* Calibrate card to determine the clock source.  The source maybe a
703113056Sorion * function of the ac97 codec initialization code (to be investigated).
704113056Sorion */
70588108Sorion
706164614Sariffstatic void
707164614Sariffich_calibrate(void *arg)
70888108Sorion{
70998940Sscottl	struct sc_info *sc;
71098940Sscottl	struct sc_chinfo *ch;
71189516Sorion	struct timeval t1, t2;
712164614Sariff	uint8_t ociv, nciv;
713164614Sariff	uint32_t wait_us, actual_48k_rate, oblkcnt;
71489516Sorion
71598940Sscottl	sc = (struct sc_info *)arg;
716164614Sariff	ICH_LOCK(sc);
71798940Sscottl	ch = &sc->ch[1];
71898940Sscottl
719169278Sariff	if (sc->intrhook.ich_func != NULL) {
72098940Sscottl		config_intrhook_disestablish(&sc->intrhook);
721169278Sariff		sc->intrhook.ich_func = NULL;
722169278Sariff	}
72398940Sscottl
72489516Sorion	/*
72589516Sorion	 * Grab audio from input for fixed interval and compare how
72688108Sorion	 * much we actually get with what we expect.  Interval needs
72788108Sorion	 * to be sufficiently short that no interrupts are
72889516Sorion	 * generated.
72989516Sorion	 */
73089516Sorion
73188108Sorion	KASSERT(ch->regbase == ICH_REG_PI_BASE, ("wrong direction"));
73288108Sorion
733164614Sariff	oblkcnt = ch->blkcnt;
734164614Sariff	ch->blkcnt = 2;
735169278Sariff	sc->flags |= ICH_CALIBRATE_DONE;
736164614Sariff	ICH_UNLOCK(sc);
737164614Sariff	ichchan_setblocksize(0, ch, sndbuf_getmaxsize(ch->buffer) >> 1);
738164614Sariff	ICH_LOCK(sc);
739169278Sariff	sc->flags &= ~ICH_CALIBRATE_DONE;
74088108Sorion
74189516Sorion	/*
74289516Sorion	 * our data format is stereo, 16 bit so each sample is 4 bytes.
74389516Sorion	 * assuming we get 48000 samples per second, we get 192000 bytes/sec.
74489516Sorion	 * we're going to start recording with interrupts disabled and measure
74589516Sorion	 * the time taken for one block to complete.  we know the block size,
74689516Sorion	 * we know the time in microseconds, we calculate the sample rate:
74789516Sorion	 *
74889516Sorion	 * actual_rate [bps] = bytes / (time [s] * 4)
74989516Sorion	 * actual_rate [bps] = (bytes * 1000000) / (time [us] * 4)
75089516Sorion	 * actual_rate [Hz] = (bytes * 250000) / time [us]
75189516Sorion	 */
75288108Sorion
75389516Sorion	/* prepare */
75489516Sorion	ociv = ich_rd(sc, ch->regbase + ICH_REG_X_CIV, 1);
75589516Sorion	nciv = ociv;
756164614Sariff	ich_wr(sc, ch->regbase + ICH_REG_X_BDBAR, (uint32_t)(ch->desc_addr), 4);
75788108Sorion
75889516Sorion	/* start */
75989516Sorion	microtime(&t1);
76089516Sorion	ich_wr(sc, ch->regbase + ICH_REG_X_CR, ICH_X_CR_RPBM, 1);
76188108Sorion
76289516Sorion	/* wait */
763164614Sariff	do {
76489516Sorion		microtime(&t2);
76589516Sorion		if (t2.tv_sec - t1.tv_sec > 1)
76689516Sorion			break;
76789516Sorion		nciv = ich_rd(sc, ch->regbase + ICH_REG_X_CIV, 1);
768164614Sariff	} while (nciv == ociv);
76989516Sorion
77089516Sorion	/* stop */
77189516Sorion	ich_wr(sc, ch->regbase + ICH_REG_X_CR, 0, 1);
77289516Sorion
77389516Sorion	/* reset */
77489516Sorion	DELAY(100);
77589516Sorion	ich_wr(sc, ch->regbase + ICH_REG_X_CR, ICH_X_CR_RR, 1);
776164614Sariff	ch->blkcnt = oblkcnt;
77789516Sorion
77889516Sorion	/* turn time delta into us */
77989516Sorion	wait_us = ((t2.tv_sec - t1.tv_sec) * 1000000) + t2.tv_usec - t1.tv_usec;
78089516Sorion
78189516Sorion	if (nciv == ociv) {
78289516Sorion		device_printf(sc->dev, "ac97 link rate calibration timed out after %d us\n", wait_us);
783169278Sariff		sc->flags |= ICH_CALIBRATE_DONE;
784164614Sariff		ICH_UNLOCK(sc);
785164614Sariff		ich_setstatus(sc);
78698940Sscottl		return;
78789516Sorion	}
78889516Sorion
789171363Sariff	/* Just in case the timecounter screwed. It is possible, really. */
790171363Sariff	if (wait_us > 0)
791171363Sariff		actual_48k_rate = ((uint64_t)ch->blksz * 250000) / wait_us;
792171363Sariff	else
793171363Sariff		actual_48k_rate = 48000;
79489516Sorion
79589516Sorion	if (actual_48k_rate < 47500 || actual_48k_rate > 48500) {
79688108Sorion		sc->ac97rate = actual_48k_rate;
79788108Sorion	} else {
79888108Sorion		sc->ac97rate = 48000;
79988108Sorion	}
80088209Sorion
80189516Sorion	if (bootverbose || sc->ac97rate != 48000) {
80289516Sorion		device_printf(sc->dev, "measured ac97 link rate at %d Hz", actual_48k_rate);
80389516Sorion		if (sc->ac97rate != actual_48k_rate)
80489516Sorion			printf(", will use %d Hz", sc->ac97rate);
80589516Sorion	 	printf("\n");
80689516Sorion	}
807169278Sariff	sc->flags |= ICH_CALIBRATE_DONE;
808164614Sariff	ICH_UNLOCK(sc);
80988209Sorion
810164614Sariff	ich_setstatus(sc);
811164614Sariff
81298940Sscottl	return;
81388108Sorion}
81488108Sorion
81588108Sorion/* -------------------------------------------------------------------- */
81679148Scg/* Probe and attach the card */
81779047Scg
81879148Scgstatic void
81979148Scgich_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
82079148Scg{
821111183Scognet	struct sc_info *sc = (struct sc_info *)arg;
822111183Scognet	sc->desc_addr = segs->ds_addr;
82379148Scg	return;
82479148Scg}
82579047Scg
82679047Scgstatic int
82779047Scgich_init(struct sc_info *sc)
82879047Scg{
829164614Sariff	uint32_t stat;
83079047Scg
83179148Scg	ich_wr(sc, ICH_REG_GLOB_CNT, ICH_GLOB_CTL_COLD, 4);
83279047Scg	DELAY(600000);
83379148Scg	stat = ich_rd(sc, ICH_REG_GLOB_STA, 4);
83479148Scg
835102106Sorion	if ((stat & ICH_GLOB_STA_PCR) == 0) {
836117296Scg		/* ICH4/ICH5 may fail when busmastering is enabled. Continue */
837152420Sariff		if (sc->vendor == INTEL_VENDORID && (
838152420Sariff		    sc->devid == INTEL_82801DB || sc->devid == INTEL_82801EB ||
839152420Sariff		    sc->devid == INTEL_6300ESB || sc->devid == INTEL_82801FB ||
840152420Sariff		    sc->devid == INTEL_82801GB)) {
841169278Sariff			sc->flags |= ICH_IGNORE_PCR;
842152644Syongari			device_printf(sc->dev, "primary codec not ready!\n");
843102106Sorion		}
844102106Sorion	}
84579047Scg
846157028Sariff#if 0
84779148Scg	ich_wr(sc, ICH_REG_GLOB_CNT, ICH_GLOB_CTL_COLD | ICH_GLOB_CTL_PRES, 4);
848157028Sariff#else
849157028Sariff	ich_wr(sc, ICH_REG_GLOB_CNT, ICH_GLOB_CTL_COLD, 4);
850157028Sariff#endif
85179047Scg
85283617Scg	if (ich_resetchan(sc, 0) || ich_resetchan(sc, 1))
853164614Sariff		return (ENXIO);
85483617Scg	if (sc->hasmic && ich_resetchan(sc, 2))
855164614Sariff		return (ENXIO);
85679148Scg
857164614Sariff	return (0);
85879047Scg}
85979047Scg
86079047Scgstatic int
86179047Scgich_pci_probe(device_t dev)
86279047Scg{
863152420Sariff	int i;
864152420Sariff	uint16_t devid, vendor;
86579047Scg
866152420Sariff	vendor = pci_get_vendor(dev);
867152420Sariff	devid = pci_get_device(dev);
868152420Sariff	for (i = 0; i < sizeof(ich_devs)/sizeof(ich_devs[0]); i++) {
869152420Sariff		if (vendor == ich_devs[i].vendor &&
870152420Sariff				devid == ich_devs[i].devid) {
871152420Sariff			device_set_desc(dev, ich_devs[i].name);
872152420Sariff			/* allow a better driver to override us */
873152420Sariff			if ((ich_devs[i].options & PROBE_LOW) != 0)
874152420Sariff				return (BUS_PROBE_LOW_PRIORITY);
875152420Sariff			return (BUS_PROBE_DEFAULT);
876152420Sariff		}
87779148Scg	}
878152420Sariff	return (ENXIO);
87979047Scg}
88079047Scg
88179047Scgstatic int
88279047Scgich_pci_attach(device_t dev)
88379047Scg{
884154168Sariff	uint32_t		subdev;
885164614Sariff	uint16_t		extcaps;
886152420Sariff	uint16_t		devid, vendor;
88779047Scg	struct sc_info 		*sc;
888164614Sariff	int			i;
88979047Scg
890170873Sariff	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
891167608Sariff	sc->ich_lock = snd_mtxcreate(device_get_nameunit(dev), "snd_ich softc");
89279047Scg	sc->dev = dev;
89379047Scg
894152420Sariff	vendor = sc->vendor = pci_get_vendor(dev);
895152420Sariff	devid = sc->devid = pci_get_device(dev);
896154168Sariff	subdev = (pci_get_subdevice(dev) << 16) | pci_get_subvendor(dev);
89790880Salfred	/*
89890880Salfred	 * The SiS 7012 register set isn't quite like the standard ich.
89990880Salfred	 * There really should be a general "quirks" mechanism.
90090880Salfred	 */
901152420Sariff	if (vendor == SIS_VENDORID && devid == SIS_7012) {
90290880Salfred		sc->swap_reg = 1;
90390880Salfred		sc->sample_size = 1;
90490880Salfred	} else {
90590880Salfred		sc->swap_reg = 0;
90690880Salfred		sc->sample_size = 2;
90790880Salfred	}
90890880Salfred
909102106Sorion	/*
910169278Sariff	 * Intel 440MX Errata #36
911169278Sariff	 * - AC97 Soft Audio and Soft Modem Master Abort Errata
912169278Sariff	 *
913169278Sariff	 * http://www.intel.com/design/chipsets/specupdt/245051.htm
914169278Sariff	 */
915169278Sariff	if (vendor == INTEL_VENDORID && devid == INTEL_82440MX)
916169278Sariff		sc->flags |= ICH_DMA_NOCACHE;
917169278Sariff
918169278Sariff	/*
919152644Syongari	 * Enable bus master. On ich4/5 this may prevent the detection of
920152644Syongari	 * the primary codec becoming ready in ich_init().
921152644Syongari	 */
922152644Syongari	pci_enable_busmaster(dev);
923152644Syongari
924152644Syongari	/*
925127651Smatk	 * By default, ich4 has NAMBAR and NABMBAR i/o spaces as
926127651Smatk	 * read-only.  Need to enable "legacy support", by poking into
927127651Smatk	 * pci config space.  The driver should use MMBAR and MBBAR,
928127651Smatk	 * but doing so will mess things up here.  ich4 has enough new
929127651Smatk	 * features it warrants it's own driver.
930127651Smatk	 */
931152644Syongari	if (vendor == INTEL_VENDORID && (devid == INTEL_82801DB ||
932152644Syongari	    devid == INTEL_82801EB || devid == INTEL_6300ESB ||
933152644Syongari	    devid == INTEL_82801FB || devid == INTEL_82801GB)) {
934118729Sorion		sc->nambarid = PCIR_MMBAR;
935118729Sorion		sc->nabmbarid = PCIR_MBBAR;
936118729Sorion		sc->regtype = SYS_RES_MEMORY;
937152644Syongari		pci_write_config(dev, PCIR_ICH_LEGACY, ICH_LEGACY_ENABLE, 1);
938118729Sorion	} else {
939118729Sorion		sc->nambarid = PCIR_NAMBAR;
940118729Sorion		sc->nabmbarid = PCIR_NABMBAR;
941118729Sorion		sc->regtype = SYS_RES_IOPORT;
942118729Sorion	}
94379148Scg
944127135Snjl	sc->nambar = bus_alloc_resource_any(dev, sc->regtype,
945127135Snjl		&sc->nambarid, RF_ACTIVE);
946127135Snjl	sc->nabmbar = bus_alloc_resource_any(dev, sc->regtype,
947127135Snjl		&sc->nabmbarid, RF_ACTIVE);
948118729Sorion
94979047Scg	if (!sc->nambar || !sc->nabmbar) {
95079047Scg		device_printf(dev, "unable to map IO port space\n");
95179047Scg		goto bad;
95279047Scg	}
95379148Scg
95479047Scg	sc->nambart = rman_get_bustag(sc->nambar);
95579047Scg	sc->nambarh = rman_get_bushandle(sc->nambar);
95679047Scg	sc->nabmbart = rman_get_bustag(sc->nabmbar);
95779047Scg	sc->nabmbarh = rman_get_bushandle(sc->nabmbar);
95879047Scg
959164614Sariff	sc->bufsz = pcm_getbuffersize(dev,
960164614Sariff	    ICH_MIN_BUFSZ, ICH_DEFAULT_BUFSZ, ICH_MAX_BUFSZ);
961164614Sariff
962169278Sariff	if (resource_int_value(device_get_name(dev),
963169278Sariff	    device_get_unit(dev), "blocksize", &i) == 0 && i > 0) {
964164614Sariff		sc->blkcnt = sc->bufsz / i;
965164614Sariff		i = 0;
966164614Sariff		while (sc->blkcnt >> i)
967164614Sariff			i++;
968164614Sariff		sc->blkcnt = 1 << (i - 1);
969164614Sariff		if (sc->blkcnt < ICH_MIN_BLKCNT)
970164614Sariff			sc->blkcnt = ICH_MIN_BLKCNT;
971164614Sariff		else if (sc->blkcnt > ICH_MAX_BLKCNT)
972164614Sariff			sc->blkcnt = ICH_MAX_BLKCNT;
973164614Sariff	} else
974164614Sariff		sc->blkcnt = ICH_DEFAULT_BLKCNT;
975164614Sariff
976169278Sariff	if (resource_int_value(device_get_name(dev),
977169278Sariff	    device_get_unit(dev), "highlatency", &i) == 0 && i != 0) {
978169278Sariff		sc->flags |= ICH_HIGH_LATENCY;
979169278Sariff		sc->blkcnt = ICH_MIN_BLKCNT;
98079047Scg	}
98179047Scg
982169278Sariff	if (resource_int_value(device_get_name(dev),
983169278Sariff	    device_get_unit(dev), "fixedrate", &i) == 0 && i != 0)
984169278Sariff		sc->flags |= ICH_FIXED_RATE;
985169278Sariff
986174552Sariff	if (resource_int_value(device_get_name(dev),
987174552Sariff	    device_get_unit(dev), "micchannel_enabled", &i) == 0 && i != 0)
988174552Sariff		sc->hasmic = 1;
989174552Sariff
99089516Sorion	sc->irqid = 0;
991127135Snjl	sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid,
992169278Sariff	    RF_ACTIVE | RF_SHAREABLE);
993169278Sariff	if (!sc->irq || snd_setup_intr(dev, sc->irq, INTR_MPSAFE, ich_intr,
994169278Sariff	    sc, &sc->ih)) {
99589516Sorion		device_printf(dev, "unable to map interrupt\n");
99689516Sorion		goto bad;
99789516Sorion	}
99889516Sorion
99979148Scg	if (ich_init(sc)) {
100079047Scg		device_printf(dev, "unable to initialize the card\n");
100179047Scg		goto bad;
100279047Scg	}
100379047Scg
100479047Scg	sc->codec = AC97_CREATE(dev, sc, ich_ac97);
100579047Scg	if (sc->codec == NULL)
100679047Scg		goto bad;
1007154132Sariff
1008154132Sariff	/*
1009154168Sariff	 * Turn on inverted external amplifier sense flags for few
1010154168Sariff	 * 'special' boards.
1011154132Sariff	 */
1012154168Sariff	switch (subdev) {
1013154378Sariff	case 0x202f161f:	/* Gateway 7326GZ */
1014154168Sariff	case 0x203a161f:	/* Gateway 4028GZ */
1015191911Smav	case 0x203e161f:	/* Gateway 3520GZ/M210 */
1016156376Sariff	case 0x204c161f:	/* Kvazar-Micro Senator 3592XT */
1017154378Sariff	case 0x8144104d:	/* Sony VAIO PCG-TR* */
1018158210Sariff	case 0x8197104d:	/* Sony S1XP */
1019156308Sariff	case 0x81c0104d:	/* Sony VAIO type T */
1020158210Sariff	case 0x81c5104d:	/* Sony VAIO VGN B1VP/B1XP */
1021161300Syongari	case 0x3089103c:	/* Compaq Presario B3800 */
1022164783Sariff	case 0x309a103c:	/* HP Compaq nx4300 */
1023164614Sariff	case 0x82131033:	/* NEC VersaPro VJ10F/BH */
1024164614Sariff	case 0x82be1033:	/* NEC VersaPro VJ12F/CH */
1025154132Sariff		ac97_setflags(sc->codec, ac97_getflags(sc->codec) | AC97_F_EAPD_INV);
1026154168Sariff		break;
1027154168Sariff	default:
1028154168Sariff		break;
1029154168Sariff	}
1030154132Sariff
103179047Scg	mixer_init(dev, ac97_getmixerclass(), sc->codec);
103279148Scg
103379047Scg	/* check and set VRA function */
103486795Sorion	extcaps = ac97_getextcaps(sc->codec);
103586708Sorion	sc->hasvra = extcaps & AC97_EXTCAP_VRA;
103686708Sorion	sc->hasvrm = extcaps & AC97_EXTCAP_VRM;
1037174552Sariff	sc->hasmic = (sc->hasmic != 0 &&
1038174552Sariff	    (ac97_getcaps(sc->codec) & AC97_CAP_MICCHANNEL)) ? 1 : 0;
103994647Sjhay	ac97_setextmode(sc->codec, sc->hasvra | sc->hasvrm);
104079047Scg
1041169278Sariff	sc->dtbl_size = sizeof(struct ich_desc) * ICH_DTBL_LENGTH *
1042169278Sariff	    ((sc->hasmic) ? 3 : 2);
1043169278Sariff
1044169278Sariff	/* BDL tag */
1045169278Sariff	if (bus_dma_tag_create(bus_get_dma_tag(dev), 8, 0,
1046169278Sariff	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
1047169278Sariff	    sc->dtbl_size, 1, 0x3ffff, 0, NULL, NULL, &sc->dmat) != 0) {
1048169278Sariff		device_printf(dev, "unable to create dma tag\n");
1049169278Sariff		goto bad;
1050169278Sariff	}
1051169278Sariff
1052169278Sariff	/* PCM channel tag */
1053169278Sariff	if (bus_dma_tag_create(bus_get_dma_tag(dev), ICH_MIN_BLKSZ, 0,
1054169278Sariff	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
1055169278Sariff	    sc->bufsz, 1, 0x3ffff, 0, NULL, NULL, &sc->chan_dmat) != 0) {
1056169278Sariff		device_printf(dev, "unable to create dma tag\n");
1057169278Sariff		goto bad;
1058169278Sariff	}
1059169278Sariff
1060169278Sariff	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->dtbl, BUS_DMA_NOWAIT |
1061169278Sariff	    ((sc->flags & ICH_DMA_NOCACHE) ? BUS_DMA_NOCACHE : 0),
1062169278Sariff	    &sc->dtmap))
1063169278Sariff		goto bad;
1064169278Sariff
1065169278Sariff	if (bus_dmamap_load(sc->dmat, sc->dtmap, sc->dtbl, sc->dtbl_size,
1066169278Sariff	    ich_setmap, sc, 0))
1067169278Sariff		goto bad;
1068169278Sariff
1069164614Sariff	if (pcm_register(dev, sc, 1, (sc->hasmic) ? 2 : 1))
107079148Scg		goto bad;
107179047Scg
107283617Scg	pcm_addchan(dev, PCMDIR_PLAY, &ichchan_class, sc);		/* play */
107383617Scg	pcm_addchan(dev, PCMDIR_REC, &ichchan_class, sc);		/* record */
107483617Scg	if (sc->hasmic)
107583617Scg		pcm_addchan(dev, PCMDIR_REC, &ichchan_class, sc);	/* record mic */
107679148Scg
1077169278Sariff	if (sc->flags & ICH_FIXED_RATE) {
1078169278Sariff		sc->flags |= ICH_CALIBRATE_DONE;
1079169278Sariff		ich_setstatus(sc);
1080169278Sariff	} else {
1081164614Sariff		ich_initsys(sc);
108279148Scg
1083164614Sariff		sc->intrhook.ich_func = ich_calibrate;
1084164614Sariff		sc->intrhook.ich_arg = sc;
1085169278Sariff		if (cold == 0 ||
1086169278Sariff		    config_intrhook_establish(&sc->intrhook) != 0) {
1087169278Sariff			sc->intrhook.ich_func = NULL;
1088164614Sariff			ich_calibrate(sc);
1089164614Sariff		}
109098940Sscottl	}
109198940Sscottl
1092164614Sariff	return (0);
109379047Scg
109479047Scgbad:
109579047Scg	if (sc->codec)
109679047Scg		ac97_destroy(sc->codec);
109789516Sorion	if (sc->ih)
109889516Sorion		bus_teardown_intr(dev, sc->irq, sc->ih);
109989516Sorion	if (sc->irq)
110089516Sorion		bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
110179047Scg	if (sc->nambar)
1102118729Sorion		bus_release_resource(dev, sc->regtype,
110379047Scg		    sc->nambarid, sc->nambar);
110479047Scg	if (sc->nabmbar)
1105118729Sorion		bus_release_resource(dev, sc->regtype,
110679047Scg		    sc->nabmbarid, sc->nabmbar);
1107155568Sariff	if (sc->dtmap)
1108155568Sariff		bus_dmamap_unload(sc->dmat, sc->dtmap);
1109167773Sariff	if (sc->dtbl)
1110167773Sariff		bus_dmamem_free(sc->dmat, sc->dtbl, sc->dtmap);
1111169278Sariff	if (sc->chan_dmat)
1112169278Sariff		bus_dma_tag_destroy(sc->chan_dmat);
1113155568Sariff	if (sc->dmat)
1114155568Sariff		bus_dma_tag_destroy(sc->dmat);
1115152420Sariff	if (sc->ich_lock)
1116152420Sariff		snd_mtxfree(sc->ich_lock);
111779047Scg	free(sc, M_DEVBUF);
1118164614Sariff	return (ENXIO);
111979047Scg}
112079047Scg
112179047Scgstatic int
112279047Scgich_pci_detach(device_t dev)
112379047Scg{
112479047Scg	struct sc_info *sc;
112579047Scg	int r;
112679047Scg
112779047Scg	r = pcm_unregister(dev);
112879047Scg	if (r)
1129164614Sariff		return (r);
113079047Scg	sc = pcm_getdevinfo(dev);
113179047Scg
113279148Scg	bus_teardown_intr(dev, sc->irq, sc->ih);
113379148Scg	bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
1134118729Sorion	bus_release_resource(dev, sc->regtype, sc->nambarid, sc->nambar);
1135118729Sorion	bus_release_resource(dev, sc->regtype, sc->nabmbarid, sc->nabmbar);
1136155568Sariff	bus_dmamap_unload(sc->dmat, sc->dtmap);
1137167773Sariff	bus_dmamem_free(sc->dmat, sc->dtbl, sc->dtmap);
1138169278Sariff	bus_dma_tag_destroy(sc->chan_dmat);
113979047Scg	bus_dma_tag_destroy(sc->dmat);
1140152420Sariff	snd_mtxfree(sc->ich_lock);
114179047Scg	free(sc, M_DEVBUF);
1142164614Sariff	return (0);
114379047Scg}
114479047Scg
1145120101Snjlstatic void
1146120101Snjlich_pci_codec_reset(struct sc_info *sc)
1147120101Snjl{
1148120101Snjl	int i;
1149120101Snjl	uint32_t control;
1150120101Snjl
1151120101Snjl	control = ich_rd(sc, ICH_REG_GLOB_CNT, 4);
1152120101Snjl	control &= ~(ICH_GLOB_CTL_SHUT);
1153120101Snjl	control |= (control & ICH_GLOB_CTL_COLD) ?
1154120101Snjl		    ICH_GLOB_CTL_WARM : ICH_GLOB_CTL_COLD;
1155120101Snjl	ich_wr(sc, ICH_REG_GLOB_CNT, control, 4);
1156120101Snjl
1157120101Snjl	for (i = 500000; i; i--) {
1158120101Snjl	     	if (ich_rd(sc, ICH_REG_GLOB_STA, 4) & ICH_GLOB_STA_PCR)
1159120101Snjl			break;		/*		or ICH_SCR? */
1160120101Snjl		DELAY(1);
1161120101Snjl	}
1162120101Snjl
1163120101Snjl	if (i <= 0)
1164120101Snjl		printf("%s: time out\n", __func__);
1165120101Snjl}
1166120101Snjl
116779047Scgstatic int
116888361Sorionich_pci_suspend(device_t dev)
116988361Sorion{
117088361Sorion	struct sc_info *sc;
117188361Sorion	int i;
117288361Sorion
1173117296Scg	sc = pcm_getdevinfo(dev);
1174152420Sariff	ICH_LOCK(sc);
117588361Sorion	for (i = 0 ; i < 3; i++) {
117688361Sorion		sc->ch[i].run_save = sc->ch[i].run;
117788361Sorion		if (sc->ch[i].run) {
1178152420Sariff			ICH_UNLOCK(sc);
117988361Sorion			ichchan_trigger(0, &sc->ch[i], PCMTRIG_ABORT);
1180152420Sariff			ICH_LOCK(sc);
118188361Sorion		}
118288361Sorion	}
1183152420Sariff	ICH_UNLOCK(sc);
1184164614Sariff	return (0);
118588361Sorion}
118688361Sorion
118788361Sorionstatic int
118879047Scgich_pci_resume(device_t dev)
118979047Scg{
119079047Scg	struct sc_info *sc;
119188361Sorion	int i;
119279047Scg
119379047Scg	sc = pcm_getdevinfo(dev);
119479047Scg
1195152420Sariff	ICH_LOCK(sc);
119679047Scg	/* Reinit audio device */
119779047Scg    	if (ich_init(sc) == -1) {
119879047Scg		device_printf(dev, "unable to reinitialize the card\n");
1199152420Sariff		ICH_UNLOCK(sc);
1200164614Sariff		return (ENXIO);
120179047Scg	}
120279047Scg	/* Reinit mixer */
1203120101Snjl	ich_pci_codec_reset(sc);
1204155568Sariff	ICH_UNLOCK(sc);
1205120101Snjl	ac97_setextmode(sc->codec, sc->hasvra | sc->hasvrm);
120679047Scg    	if (mixer_reinit(dev) == -1) {
120779047Scg		device_printf(dev, "unable to reinitialize the mixer\n");
1208164614Sariff		return (ENXIO);
120979047Scg	}
121088361Sorion	/* Re-start DMA engines */
121188361Sorion	for (i = 0 ; i < 3; i++) {
121288361Sorion		struct sc_chinfo *ch = &sc->ch[i];
121388361Sorion		if (sc->ch[i].run_save) {
121488361Sorion			ichchan_setblocksize(0, ch, ch->blksz);
121588361Sorion			ichchan_setspeed(0, ch, ch->spd);
121688361Sorion			ichchan_trigger(0, ch, PCMTRIG_START);
121788361Sorion		}
121888361Sorion	}
1219164614Sariff	return (0);
122079047Scg}
122179047Scg
122279047Scgstatic device_method_t ich_methods[] = {
122379047Scg	/* Device interface */
122479047Scg	DEVMETHOD(device_probe,		ich_pci_probe),
122579047Scg	DEVMETHOD(device_attach,	ich_pci_attach),
122679047Scg	DEVMETHOD(device_detach,	ich_pci_detach),
122788361Sorion	DEVMETHOD(device_suspend, 	ich_pci_suspend),
122879047Scg	DEVMETHOD(device_resume,	ich_pci_resume),
122979047Scg	{ 0, 0 }
123079047Scg};
123179047Scg
123279047Scgstatic driver_t ich_driver = {
123379047Scg	"pcm",
123479047Scg	ich_methods,
123582180Scg	PCM_SOFTC_SIZE,
123679047Scg};
123779047Scg
123879047ScgDRIVER_MODULE(snd_ich, pci, ich_driver, pcm_devclass, 0, 0);
1239132236StanimuraMODULE_DEPEND(snd_ich, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
124079047ScgMODULE_VERSION(snd_ich, 1);
1241