ich.c revision 102106
179047Scg/*
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
2879047Scg#include <dev/sound/pcm/sound.h>
2979047Scg#include <dev/sound/pcm/ac97.h>
3079148Scg#include <dev/sound/pci/ich.h>
3179047Scg
3279047Scg#include <pci/pcireg.h>
3379047Scg#include <pci/pcivar.h>
3479047Scg
3582180ScgSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/ich.c 102106 2002-08-19 16:03:56Z orion $");
3682180Scg
3779047Scg/* -------------------------------------------------------------------- */
3879047Scg
3979047Scg#define ICH_TIMEOUT 1000 /* semaphore timeout polling count */
4079148Scg#define ICH_DTBL_LENGTH 32
4179148Scg#define ICH_DEFAULT_BUFSZ 16384
4283617Scg#define ICH_MAX_BUFSZ 65536
4379047Scg
4490880Salfred#define SIS7012ID       0x70121039      /* SiS 7012 needs special handling */
45102106Sorion#define ICH4ID		0x24c58086	/* ICH4 needs special handling too */
4690880Salfred
4779047Scg/* buffer descriptor */
4879047Scgstruct ich_desc {
4979047Scg	volatile u_int32_t buffer;
5079047Scg	volatile u_int32_t length;
5179047Scg};
5279047Scg
5379047Scgstruct sc_info;
5479047Scg
5579047Scg/* channel registers */
5679047Scgstruct sc_chinfo {
5788361Sorion	u_int32_t num:8, run:1, run_save:1;
5888361Sorion	u_int32_t blksz, blkcnt, spd;
5979148Scg	u_int32_t regbase, spdreg;
6088206Sorion	u_int32_t imask;
6182478Scg	u_int32_t civ;
6279148Scg
6379047Scg	struct snd_dbuf *buffer;
6479047Scg	struct pcm_channel *channel;
6579047Scg	struct sc_info *parent;
6679148Scg
6779148Scg	struct ich_desc *dtbl;
6879047Scg};
6979047Scg
7079047Scg/* device private data */
7179047Scgstruct sc_info {
7279148Scg	device_t dev;
7383617Scg	int hasvra, hasvrm, hasmic;
7483617Scg	unsigned int chnum, bufsz;
7590880Salfred	int sample_size, swap_reg;
7679047Scg
7779148Scg	struct resource *nambar, *nabmbar, *irq;
7879148Scg	int nambarid, nabmbarid, irqid;
7979047Scg	bus_space_tag_t nambart, nabmbart;
8079047Scg	bus_space_handle_t nambarh, nabmbarh;
8179047Scg	bus_dma_tag_t dmat;
8279148Scg	bus_dmamap_t dtmap;
8379148Scg	void *ih;
8479047Scg
8579047Scg	struct ac97_info *codec;
8679148Scg	struct sc_chinfo ch[3];
8788033Sorion	int ac97rate;
8879148Scg	struct ich_desc *dtbl;
8998940Sscottl	struct intr_config_hook	intrhook;
9098940Sscottl	int use_intrhook;
9179047Scg};
9279047Scg
9379047Scg/* -------------------------------------------------------------------- */
9479047Scg
9579148Scgstatic u_int32_t ich_fmt[] = {
9679047Scg	AFMT_STEREO | AFMT_S16_LE,
9779047Scg	0
9879047Scg};
9979148Scgstatic struct pcmchan_caps ich_vrcaps = {8000, 48000, ich_fmt, 0};
10079148Scgstatic struct pcmchan_caps ich_caps = {48000, 48000, ich_fmt, 0};
10179047Scg
10279047Scg/* -------------------------------------------------------------------- */
10379047Scg/* Hardware */
10479047Scgstatic u_int32_t
10579047Scgich_rd(struct sc_info *sc, int regno, int size)
10679047Scg{
10779047Scg	switch (size) {
10879047Scg	case 1:
10979148Scg		return bus_space_read_1(sc->nabmbart, sc->nabmbarh, regno);
11079047Scg	case 2:
11179148Scg		return bus_space_read_2(sc->nabmbart, sc->nabmbarh, regno);
11279047Scg	case 4:
11379148Scg		return bus_space_read_4(sc->nabmbart, sc->nabmbarh, regno);
11479047Scg	default:
11579047Scg		return 0xffffffff;
11679047Scg	}
11779047Scg}
11879047Scg
11979047Scgstatic void
12079047Scgich_wr(struct sc_info *sc, int regno, u_int32_t data, int size)
12179047Scg{
12279047Scg	switch (size) {
12379047Scg	case 1:
12479148Scg		bus_space_write_1(sc->nabmbart, sc->nabmbarh, regno, data);
12579047Scg		break;
12679047Scg	case 2:
12779148Scg		bus_space_write_2(sc->nabmbart, sc->nabmbarh, regno, data);
12879047Scg		break;
12979047Scg	case 4:
13079148Scg		bus_space_write_4(sc->nabmbart, sc->nabmbarh, regno, data);
13179047Scg		break;
13279047Scg	}
13379047Scg}
13479047Scg
13579047Scg/* ac97 codec */
13679047Scgstatic int
13779047Scgich_waitcd(void *devinfo)
13879047Scg{
13979047Scg	int i;
14079047Scg	u_int32_t data;
14179047Scg	struct sc_info *sc = (struct sc_info *)devinfo;
14279148Scg
14379148Scg	for (i = 0; i < ICH_TIMEOUT; i++) {
14479148Scg		data = ich_rd(sc, ICH_REG_ACC_SEMA, 1);
14579047Scg		if ((data & 0x01) == 0)
14679047Scg			return 0;
14779047Scg	}
14879047Scg	device_printf(sc->dev, "CODEC semaphore timeout\n");
14979047Scg	return ETIMEDOUT;
15079047Scg}
15179047Scg
15279047Scgstatic int
15379047Scgich_rdcd(kobj_t obj, void *devinfo, int regno)
15479047Scg{
15579047Scg	struct sc_info *sc = (struct sc_info *)devinfo;
15679148Scg
15779047Scg	regno &= 0xff;
15879047Scg	ich_waitcd(sc);
15979148Scg
16079148Scg	return bus_space_read_2(sc->nambart, sc->nambarh, regno);
16179047Scg}
16279047Scg
16379047Scgstatic int
16479148Scgich_wrcd(kobj_t obj, void *devinfo, int regno, u_int16_t data)
16579047Scg{
16679047Scg	struct sc_info *sc = (struct sc_info *)devinfo;
16779148Scg
16879047Scg	regno &= 0xff;
16979047Scg	ich_waitcd(sc);
17079148Scg	bus_space_write_2(sc->nambart, sc->nambarh, regno, data);
17179148Scg
17279047Scg	return 0;
17379047Scg}
17479047Scg
17579047Scgstatic kobj_method_t ich_ac97_methods[] = {
17679047Scg	KOBJMETHOD(ac97_read,		ich_rdcd),
17779047Scg	KOBJMETHOD(ac97_write,		ich_wrcd),
17879047Scg	{ 0, 0 }
17979047Scg};
18079047ScgAC97_DECLARE(ich_ac97);
18179047Scg
18279047Scg/* -------------------------------------------------------------------- */
18379148Scg/* common routines */
18479047Scg
18579047Scgstatic void
18679148Scgich_filldtbl(struct sc_chinfo *ch)
18779047Scg{
18879148Scg	u_int32_t base;
18982478Scg	int i;
19079047Scg
19179148Scg	base = vtophys(sndbuf_getbuf(ch->buffer));
19279148Scg	ch->blkcnt = sndbuf_getsize(ch->buffer) / ch->blksz;
19379148Scg	if (ch->blkcnt != 2 && ch->blkcnt != 4 && ch->blkcnt != 8 && ch->blkcnt != 16 && ch->blkcnt != 32) {
19479148Scg		ch->blkcnt = 2;
19579148Scg		ch->blksz = sndbuf_getsize(ch->buffer) / ch->blkcnt;
19679047Scg	}
19779047Scg
19879148Scg	for (i = 0; i < ICH_DTBL_LENGTH; i++) {
19982478Scg		ch->dtbl[i].buffer = base + (ch->blksz * (i % ch->blkcnt));
20090880Salfred		ch->dtbl[i].length = ICH_BDC_IOC
20190880Salfred				   | (ch->blksz / ch->parent->sample_size);
20279047Scg	}
20379047Scg}
20479047Scg
20579148Scgstatic int
20679148Scgich_resetchan(struct sc_info *sc, int num)
20779047Scg{
20879148Scg	int i, cr, regbase;
20979047Scg
21079148Scg	if (num == 0)
21179148Scg		regbase = ICH_REG_PO_BASE;
21279148Scg	else if (num == 1)
21379148Scg		regbase = ICH_REG_PI_BASE;
21479148Scg	else if (num == 2)
21579148Scg		regbase = ICH_REG_MC_BASE;
21679148Scg	else
21779148Scg		return ENXIO;
21879047Scg
21979148Scg	ich_wr(sc, regbase + ICH_REG_X_CR, 0, 1);
22079148Scg	DELAY(100);
22179148Scg	ich_wr(sc, regbase + ICH_REG_X_CR, ICH_X_CR_RR, 1);
22279148Scg	for (i = 0; i < ICH_TIMEOUT; i++) {
22379148Scg		cr = ich_rd(sc, regbase + ICH_REG_X_CR, 1);
22479148Scg		if (cr == 0)
22579148Scg			return 0;
22679148Scg	}
22779047Scg
22879148Scg	device_printf(sc->dev, "cannot reset channel %d\n", num);
22979148Scg	return ENXIO;
23079047Scg}
23179047Scg
23279148Scg/* -------------------------------------------------------------------- */
23379148Scg/* channel interface */
23479047Scg
23579047Scgstatic void *
23679148Scgichchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
23779047Scg{
23879047Scg	struct sc_info *sc = devinfo;
23979047Scg	struct sc_chinfo *ch;
24083617Scg	unsigned int num;
24179047Scg
24279148Scg	num = sc->chnum++;
24379148Scg	ch = &sc->ch[num];
24479148Scg	ch->num = num;
24579047Scg	ch->buffer = b;
24679047Scg	ch->channel = c;
24779047Scg	ch->parent = sc;
24879047Scg	ch->run = 0;
24979148Scg	ch->dtbl = sc->dtbl + (ch->num * ICH_DTBL_LENGTH);
25079148Scg	ch->blkcnt = 2;
25183617Scg	ch->blksz = sc->bufsz / ch->blkcnt;
25279047Scg
25379148Scg	switch(ch->num) {
25479148Scg	case 0: /* play */
25579148Scg		KASSERT(dir == PCMDIR_PLAY, ("wrong direction"));
25679148Scg		ch->regbase = ICH_REG_PO_BASE;
25779148Scg		ch->spdreg = sc->hasvra? AC97_REGEXT_FDACRATE : 0;
25888206Sorion		ch->imask = ICH_GLOB_STA_POINT;
25979148Scg		break;
26079047Scg
26182478Scg	case 1: /* record */
26279148Scg		KASSERT(dir == PCMDIR_REC, ("wrong direction"));
26382478Scg		ch->regbase = ICH_REG_PI_BASE;
26482478Scg		ch->spdreg = sc->hasvra? AC97_REGEXT_LADCRATE : 0;
26588206Sorion		ch->imask = ICH_GLOB_STA_PIINT;
26679148Scg		break;
26779047Scg
26882478Scg	case 2: /* mic */
26979148Scg		KASSERT(dir == PCMDIR_REC, ("wrong direction"));
27082478Scg		ch->regbase = ICH_REG_MC_BASE;
27182478Scg		ch->spdreg = sc->hasvrm? AC97_REGEXT_MADCRATE : 0;
27288206Sorion		ch->imask = ICH_GLOB_STA_MINT;
27379148Scg		break;
27479047Scg
27579148Scg	default:
27679148Scg		return NULL;
27779047Scg	}
27879047Scg
27983617Scg	if (sndbuf_alloc(ch->buffer, sc->dmat, sc->bufsz))
28079148Scg		return NULL;
28179047Scg
28279148Scg	ich_wr(sc, ch->regbase + ICH_REG_X_BDBAR, (u_int32_t)vtophys(ch->dtbl), 4);
28379047Scg
28479148Scg	return ch;
28579047Scg}
28679047Scg
28779047Scgstatic int
28879148Scgichchan_setformat(kobj_t obj, void *data, u_int32_t format)
28979047Scg{
29079047Scg	return 0;
29179047Scg}
29279047Scg
29379047Scgstatic int
29479148Scgichchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
29579047Scg{
29679047Scg	struct sc_chinfo *ch = data;
29779047Scg	struct sc_info *sc = ch->parent;
29879047Scg
29988033Sorion	if (ch->spdreg) {
30088033Sorion		int r;
30188033Sorion		if (sc->ac97rate <= 32000 || sc->ac97rate >= 64000)
30288033Sorion			sc->ac97rate = 48000;
30389516Sorion		r = (speed * 48000) / sc->ac97rate;
30494647Sjhay		/*
30594647Sjhay		 * Cast the return value of ac97_setrate() to u_int so that
30694647Sjhay		 * the math don't overflow into the negative range.
30794647Sjhay		 */
30894647Sjhay		ch->spd = ((u_int)ac97_setrate(sc->codec, ch->spdreg, r) *
30994647Sjhay		    sc->ac97rate) / 48000;
31088033Sorion	} else {
31188361Sorion		ch->spd = 48000;
31288033Sorion	}
31388361Sorion	return ch->spd;
31479047Scg}
31579047Scg
31679047Scgstatic int
31779148Scgichchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
31879047Scg{
31979047Scg	struct sc_chinfo *ch = data;
32079148Scg	struct sc_info *sc = ch->parent;
32179047Scg
32279148Scg	ch->blksz = blocksize;
32379148Scg	ich_filldtbl(ch);
32482478Scg	ich_wr(sc, ch->regbase + ICH_REG_X_LVI, ch->blkcnt - 1, 1);
32579047Scg
32679148Scg	return ch->blksz;
32779047Scg}
32879047Scg
32979047Scgstatic int
33079148Scgichchan_trigger(kobj_t obj, void *data, int go)
33179047Scg{
33279047Scg	struct sc_chinfo *ch = data;
33379047Scg	struct sc_info *sc = ch->parent;
33479047Scg
33579047Scg	switch (go) {
33679047Scg	case PCMTRIG_START:
33779047Scg		ch->run = 1;
33879148Scg		ich_wr(sc, ch->regbase + ICH_REG_X_BDBAR, (u_int32_t)vtophys(ch->dtbl), 4);
33989516Sorion		ich_wr(sc, ch->regbase + ICH_REG_X_CR, ICH_X_CR_RPBM | ICH_X_CR_LVBIE | ICH_X_CR_IOCE, 1);
34079047Scg		break;
34179148Scg
34279047Scg	case PCMTRIG_ABORT:
34379148Scg		ich_resetchan(sc, ch->num);
34479047Scg		ch->run = 0;
34579047Scg		break;
34679047Scg	}
34779047Scg	return 0;
34879047Scg}
34979047Scg
35079047Scgstatic int
35179148Scgichchan_getptr(kobj_t obj, void *data)
35279047Scg{
35379047Scg	struct sc_chinfo *ch = data;
35479047Scg	struct sc_info *sc = ch->parent;
35582478Scg      	u_int32_t pos;
35679047Scg
35782478Scg	ch->civ = ich_rd(sc, ch->regbase + ICH_REG_X_CIV, 1) % ch->blkcnt;
35879148Scg
35982478Scg	pos = ch->civ * ch->blksz;
36079148Scg
36179148Scg	return pos;
36279047Scg}
36379047Scg
36479047Scgstatic struct pcmchan_caps *
36579148Scgichchan_getcaps(kobj_t obj, void *data)
36679047Scg{
36779148Scg	struct sc_chinfo *ch = data;
36879148Scg
36979148Scg	return ch->spdreg? &ich_vrcaps : &ich_caps;
37079047Scg}
37179047Scg
37279148Scgstatic kobj_method_t ichchan_methods[] = {
37379148Scg	KOBJMETHOD(channel_init,		ichchan_init),
37479148Scg	KOBJMETHOD(channel_setformat,		ichchan_setformat),
37579148Scg	KOBJMETHOD(channel_setspeed,		ichchan_setspeed),
37679148Scg	KOBJMETHOD(channel_setblocksize,	ichchan_setblocksize),
37779148Scg	KOBJMETHOD(channel_trigger,		ichchan_trigger),
37879148Scg	KOBJMETHOD(channel_getptr,		ichchan_getptr),
37979148Scg	KOBJMETHOD(channel_getcaps,		ichchan_getcaps),
38079047Scg	{ 0, 0 }
38179047Scg};
38279148ScgCHANNEL_DECLARE(ichchan);
38379047Scg
38479047Scg/* -------------------------------------------------------------------- */
38579047Scg/* The interrupt handler */
38679148Scg
38779047Scgstatic void
38879047Scgich_intr(void *p)
38979047Scg{
39079047Scg	struct sc_info *sc = (struct sc_info *)p;
39179047Scg	struct sc_chinfo *ch;
39288206Sorion	u_int32_t cbi, lbi, lvi, st, gs;
39379148Scg	int i;
39479047Scg
39588215Sorion	gs = ich_rd(sc, ICH_REG_GLOB_STA, 4) & ICH_GLOB_STA_IMASK;
39688206Sorion	if (gs & (ICH_GLOB_STA_PRES | ICH_GLOB_STA_SRES)) {
39788206Sorion		/* Clear resume interrupt(s) - nothing doing with them */
39888206Sorion		ich_wr(sc, ICH_REG_GLOB_STA, gs, 4);
39988206Sorion	}
40088206Sorion	gs &= ~(ICH_GLOB_STA_PRES | ICH_GLOB_STA_SRES);
40188206Sorion
40279148Scg	for (i = 0; i < 3; i++) {
40379148Scg		ch = &sc->ch[i];
40488206Sorion		if ((ch->imask & gs) == 0)
40588206Sorion			continue;
40688206Sorion		gs &= ~ch->imask;
40790880Salfred		st = ich_rd(sc, ch->regbase +
40890880Salfred				(sc->swap_reg ? ICH_REG_X_PICB : ICH_REG_X_SR),
40990880Salfred			    2);
41079148Scg		st &= ICH_X_SR_FIFOE | ICH_X_SR_BCIS | ICH_X_SR_LVBCI;
41188206Sorion		if (st & (ICH_X_SR_BCIS | ICH_X_SR_LVBCI)) {
41279148Scg				/* block complete - update buffer */
41388206Sorion			if (ch->run)
41488206Sorion				chn_intr(ch->channel);
41588206Sorion			lvi = ich_rd(sc, ch->regbase + ICH_REG_X_LVI, 1);
41688206Sorion			cbi = ch->civ % ch->blkcnt;
41788206Sorion			if (cbi == 0)
41888206Sorion				cbi = ch->blkcnt - 1;
41988206Sorion			else
42088206Sorion				cbi--;
42188206Sorion			lbi = lvi % ch->blkcnt;
42288206Sorion			if (cbi >= lbi)
42388206Sorion				lvi += cbi - lbi;
42488206Sorion			else
42588206Sorion				lvi += cbi + ch->blkcnt - lbi;
42688206Sorion			lvi %= ICH_DTBL_LENGTH;
42788206Sorion			ich_wr(sc, ch->regbase + ICH_REG_X_LVI, lvi, 1);
42888206Sorion
42979047Scg		}
43088206Sorion		/* clear status bit */
43190880Salfred		ich_wr(sc, ch->regbase +
43290880Salfred			   (sc->swap_reg ? ICH_REG_X_PICB : ICH_REG_X_SR),
43390880Salfred		       st, 2);
43479047Scg	}
43588206Sorion	if (gs != 0) {
43688206Sorion		device_printf(sc->dev,
43788206Sorion			      "Unhandled interrupt, gs_intr = %x\n", gs);
43888206Sorion	}
43979047Scg}
44079047Scg
44188033Sorion/* ------------------------------------------------------------------------- */
44288033Sorion/* Sysctl to control ac97 speed (some boards overclocked ac97). */
44388033Sorion
44488033Sorionstatic int
44588033Sorionich_initsys(struct sc_info* sc)
44688033Sorion{
44788033Sorion#ifdef SND_DYNSYSCTL
44888033Sorion	SYSCTL_ADD_INT(snd_sysctl_tree(sc->dev),
44988033Sorion		       SYSCTL_CHILDREN(snd_sysctl_tree_top(sc->dev)),
45088033Sorion		       OID_AUTO, "ac97rate", CTLFLAG_RW,
45188033Sorion		       &sc->ac97rate, 48000,
45288033Sorion		       "AC97 link rate (default = 48000)");
45388033Sorion#endif /* SND_DYNSYSCTL */
45488033Sorion	return 0;
45588033Sorion}
45688033Sorion
45779047Scg/* -------------------------------------------------------------------- */
45888108Sorion/* Calibrate card (some boards are overclocked and need scaling) */
45988108Sorion
46088108Sorionstatic
46198940Sscottlvoid ich_calibrate(void *arg)
46288108Sorion{
46398940Sscottl	struct sc_info *sc;
46498940Sscottl	struct sc_chinfo *ch;
46589516Sorion	struct timeval t1, t2;
46689516Sorion	u_int8_t ociv, nciv;
46789516Sorion	u_int32_t wait_us, actual_48k_rate, bytes;
46889516Sorion
46998940Sscottl	sc = (struct sc_info *)arg;
47098940Sscottl	ch = &sc->ch[1];
47198940Sscottl
47298940Sscottl	if (sc->use_intrhook)
47398940Sscottl		config_intrhook_disestablish(&sc->intrhook);
47498940Sscottl
47589516Sorion	/*
47689516Sorion	 * Grab audio from input for fixed interval and compare how
47788108Sorion	 * much we actually get with what we expect.  Interval needs
47888108Sorion	 * to be sufficiently short that no interrupts are
47989516Sorion	 * generated.
48089516Sorion	 */
48189516Sorion
48288108Sorion	KASSERT(ch->regbase == ICH_REG_PI_BASE, ("wrong direction"));
48388108Sorion
48489516Sorion	bytes = sndbuf_getsize(ch->buffer) / 2;
48589516Sorion	ichchan_setblocksize(0, ch, bytes);
48688108Sorion
48789516Sorion	/*
48889516Sorion	 * our data format is stereo, 16 bit so each sample is 4 bytes.
48989516Sorion	 * assuming we get 48000 samples per second, we get 192000 bytes/sec.
49089516Sorion	 * we're going to start recording with interrupts disabled and measure
49189516Sorion	 * the time taken for one block to complete.  we know the block size,
49289516Sorion	 * we know the time in microseconds, we calculate the sample rate:
49389516Sorion	 *
49489516Sorion	 * actual_rate [bps] = bytes / (time [s] * 4)
49589516Sorion	 * actual_rate [bps] = (bytes * 1000000) / (time [us] * 4)
49689516Sorion	 * actual_rate [Hz] = (bytes * 250000) / time [us]
49789516Sorion	 */
49888108Sorion
49989516Sorion	/* prepare */
50089516Sorion	ociv = ich_rd(sc, ch->regbase + ICH_REG_X_CIV, 1);
50189516Sorion	nciv = ociv;
50289516Sorion	ich_wr(sc, ch->regbase + ICH_REG_X_BDBAR, (u_int32_t)vtophys(ch->dtbl), 4);
50388108Sorion
50489516Sorion	/* start */
50589516Sorion	microtime(&t1);
50689516Sorion	ich_wr(sc, ch->regbase + ICH_REG_X_CR, ICH_X_CR_RPBM, 1);
50788108Sorion
50889516Sorion	/* wait */
50989516Sorion	while (nciv == ociv) {
51089516Sorion		microtime(&t2);
51189516Sorion		if (t2.tv_sec - t1.tv_sec > 1)
51289516Sorion			break;
51389516Sorion		nciv = ich_rd(sc, ch->regbase + ICH_REG_X_CIV, 1);
51489516Sorion	}
51589516Sorion	microtime(&t2);
51689516Sorion
51789516Sorion	/* stop */
51889516Sorion	ich_wr(sc, ch->regbase + ICH_REG_X_CR, 0, 1);
51989516Sorion
52089516Sorion	/* reset */
52189516Sorion	DELAY(100);
52289516Sorion	ich_wr(sc, ch->regbase + ICH_REG_X_CR, ICH_X_CR_RR, 1);
52389516Sorion
52489516Sorion	/* turn time delta into us */
52589516Sorion	wait_us = ((t2.tv_sec - t1.tv_sec) * 1000000) + t2.tv_usec - t1.tv_usec;
52689516Sorion
52789516Sorion	if (nciv == ociv) {
52889516Sorion		device_printf(sc->dev, "ac97 link rate calibration timed out after %d us\n", wait_us);
52998940Sscottl		return;
53089516Sorion	}
53189516Sorion
53289516Sorion	actual_48k_rate = (bytes * 250000) / wait_us;
53389516Sorion
53489516Sorion	if (actual_48k_rate < 47500 || actual_48k_rate > 48500) {
53588108Sorion		sc->ac97rate = actual_48k_rate;
53688108Sorion	} else {
53788108Sorion		sc->ac97rate = 48000;
53888108Sorion	}
53988209Sorion
54089516Sorion	if (bootverbose || sc->ac97rate != 48000) {
54189516Sorion		device_printf(sc->dev, "measured ac97 link rate at %d Hz", actual_48k_rate);
54289516Sorion		if (sc->ac97rate != actual_48k_rate)
54389516Sorion			printf(", will use %d Hz", sc->ac97rate);
54489516Sorion	 	printf("\n");
54589516Sorion	}
54688209Sorion
54798940Sscottl	return;
54888108Sorion}
54988108Sorion
55088108Sorion/* -------------------------------------------------------------------- */
55179148Scg/* Probe and attach the card */
55279047Scg
55379148Scgstatic void
55479148Scgich_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
55579148Scg{
55679148Scg	return;
55779148Scg}
55879047Scg
55979047Scgstatic int
56079047Scgich_init(struct sc_info *sc)
56179047Scg{
56279047Scg	u_int32_t stat;
56379148Scg	int sz;
56479047Scg
56579148Scg	ich_wr(sc, ICH_REG_GLOB_CNT, ICH_GLOB_CTL_COLD, 4);
56679047Scg	DELAY(600000);
56779148Scg	stat = ich_rd(sc, ICH_REG_GLOB_STA, 4);
56879148Scg
569102106Sorion	if ((stat & ICH_GLOB_STA_PCR) == 0) {
570102106Sorion		/* ICH4 may fail when busmastering is enabled. Continue */
571102106Sorion		if (pci_get_devid(sc->dev) != ICH4ID) {
572102106Sorion			return ENXIO;
573102106Sorion		}
574102106Sorion	}
57579047Scg
57679148Scg	ich_wr(sc, ICH_REG_GLOB_CNT, ICH_GLOB_CTL_COLD | ICH_GLOB_CTL_PRES, 4);
57779047Scg
57883617Scg	if (ich_resetchan(sc, 0) || ich_resetchan(sc, 1))
57979148Scg		return ENXIO;
58083617Scg	if (sc->hasmic && ich_resetchan(sc, 2))
58183617Scg		return ENXIO;
58279148Scg
58379148Scg	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->dtbl, BUS_DMA_NOWAIT, &sc->dtmap))
58479148Scg		return ENOSPC;
58579148Scg
58679148Scg	sz = sizeof(struct ich_desc) * ICH_DTBL_LENGTH * 3;
58779148Scg	if (bus_dmamap_load(sc->dmat, sc->dtmap, sc->dtbl, sz, ich_setmap, NULL, 0)) {
58879148Scg		bus_dmamem_free(sc->dmat, (void **)&sc->dtbl, sc->dtmap);
58979148Scg		return ENOSPC;
59079047Scg	}
59179148Scg
59279148Scg	return 0;
59379047Scg}
59479047Scg
59579047Scgstatic int
59679047Scgich_pci_probe(device_t dev)
59779047Scg{
59879148Scg	switch(pci_get_devid(dev)) {
59979148Scg	case 0x71958086:
60079148Scg		device_set_desc(dev, "Intel 443MX");
60179148Scg		return 0;
60279047Scg
60379148Scg	case 0x24158086:
60479148Scg		device_set_desc(dev, "Intel 82801AA (ICH)");
60579047Scg		return 0;
60679148Scg
60779148Scg	case 0x24258086:
60885946Speter		device_set_desc(dev, "Intel 82801AB (ICH)");
60979148Scg		return 0;
61079148Scg
61179148Scg	case 0x24458086:
61279148Scg		device_set_desc(dev, "Intel 82801BA (ICH2)");
61379148Scg		return 0;
61479148Scg
61585946Speter	case 0x24858086:
61685946Speter		device_set_desc(dev, "Intel 82801CA (ICH3)");
61785946Speter		return 0;
61885946Speter
619102106Sorion	case ICH4ID:
620102106Sorion		device_set_desc(dev, "Intel 82801DB (ICH4)");
621101738Smp		return 0;
622101738Smp
62390880Salfred	case SIS7012ID:
62490880Salfred		device_set_desc(dev, "SiS 7012");
62590880Salfred		return 0;
62690880Salfred
62794798Sjhb	case 0x01b110de:
62894798Sjhb		device_set_desc(dev, "Nvidia nForce AC97 controller");
62994798Sjhb		return 0;
63094798Sjhb
63179148Scg	default:
63279047Scg		return ENXIO;
63379148Scg	}
63479047Scg}
63579047Scg
63679047Scgstatic int
63779047Scgich_pci_attach(device_t dev)
63879047Scg{
63986708Sorion	u_int16_t		extcaps;
64079047Scg	struct sc_info 		*sc;
64179047Scg	char 			status[SND_STATUSLEN];
64279047Scg
64379047Scg	if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT)) == NULL) {
64479047Scg		device_printf(dev, "cannot allocate softc\n");
64579047Scg		return ENXIO;
64679047Scg	}
64779047Scg
64879047Scg	bzero(sc, sizeof(*sc));
64979047Scg	sc->dev = dev;
65079047Scg
65190880Salfred	/*
65290880Salfred	 * The SiS 7012 register set isn't quite like the standard ich.
65390880Salfred	 * There really should be a general "quirks" mechanism.
65490880Salfred	 */
65590880Salfred	if (pci_get_devid(dev) == SIS7012ID) {
65690880Salfred		sc->swap_reg = 1;
65790880Salfred		sc->sample_size = 1;
65890880Salfred	} else {
65990880Salfred		sc->swap_reg = 0;
66090880Salfred		sc->sample_size = 2;
66190880Salfred	}
66290880Salfred
663102106Sorion	/*
664102106Sorion	 * By default, ich4 has NAMBAR and NABMBAR i/o spaces as
665102106Sorion	 * read-only.  Need to enable "legacy support", by poking into
666102106Sorion	 * pci config space.  The driver should use MMBAR and MBBAR,
667102106Sorion	 * but doing so will mess things up here.  ich4 has enough new
668102106Sorion	 * features it warrants it's own driver.
669102106Sorion	 */
670102106Sorion	if (pci_get_devid(dev) == ICH4ID) {
671102106Sorion		pci_write_config(dev, PCIR_ICH_LEGACY, ICH_LEGACY_ENABLE, 1);
672102106Sorion	}
67379047Scg
674102106Sorion	pci_enable_io(dev, SYS_RES_IOPORT);
675102106Sorion	/*
676102106Sorion	 * Enable bus master. On ich4 this may prevent the detection of
677102106Sorion	 * the primary codec becoming ready in ich_init().
678102106Sorion	 */
679102106Sorion	pci_enable_busmaster(dev);
680102106Sorion
68179047Scg	sc->nambarid = PCIR_NAMBAR;
68279047Scg	sc->nabmbarid = PCIR_NABMBAR;
68379148Scg	sc->nambar = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->nambarid, 0, ~0, 1, RF_ACTIVE);
68479148Scg	sc->nabmbar = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->nabmbarid, 0, ~0, 1, RF_ACTIVE);
68579148Scg
68679047Scg	if (!sc->nambar || !sc->nabmbar) {
68779047Scg		device_printf(dev, "unable to map IO port space\n");
68879047Scg		goto bad;
68979047Scg	}
69079148Scg
69179047Scg	sc->nambart = rman_get_bustag(sc->nambar);
69279047Scg	sc->nambarh = rman_get_bushandle(sc->nambar);
69379047Scg	sc->nabmbart = rman_get_bustag(sc->nabmbar);
69479047Scg	sc->nabmbarh = rman_get_bushandle(sc->nabmbar);
69579047Scg
69683617Scg	sc->bufsz = pcm_getbuffersize(dev, 4096, ICH_DEFAULT_BUFSZ, ICH_MAX_BUFSZ);
69782478Scg	if (bus_dma_tag_create(NULL, 8, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
69883617Scg			       NULL, NULL, sc->bufsz, 1, 0x3ffff, 0, &sc->dmat) != 0) {
69979047Scg		device_printf(dev, "unable to create dma tag\n");
70079047Scg		goto bad;
70179047Scg	}
70279047Scg
70389516Sorion	sc->irqid = 0;
70489516Sorion	sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irqid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
70589516Sorion	if (!sc->irq || snd_setup_intr(dev, sc->irq, INTR_MPSAFE, ich_intr, sc, &sc->ih)) {
70689516Sorion		device_printf(dev, "unable to map interrupt\n");
70789516Sorion		goto bad;
70889516Sorion	}
70989516Sorion
71079148Scg	if (ich_init(sc)) {
71179047Scg		device_printf(dev, "unable to initialize the card\n");
71279047Scg		goto bad;
71379047Scg	}
71479047Scg
71579047Scg	sc->codec = AC97_CREATE(dev, sc, ich_ac97);
71679047Scg	if (sc->codec == NULL)
71779047Scg		goto bad;
71879047Scg	mixer_init(dev, ac97_getmixerclass(), sc->codec);
71979148Scg
72079047Scg	/* check and set VRA function */
72186795Sorion	extcaps = ac97_getextcaps(sc->codec);
72286708Sorion	sc->hasvra = extcaps & AC97_EXTCAP_VRA;
72386708Sorion	sc->hasvrm = extcaps & AC97_EXTCAP_VRM;
72494647Sjhay	sc->hasmic = ac97_getcaps(sc->codec) & AC97_CAP_MICCHANNEL;
72594647Sjhay	ac97_setextmode(sc->codec, sc->hasvra | sc->hasvrm);
72679047Scg
72784641Scg	if (pcm_register(dev, sc, 1, sc->hasmic? 2 : 1))
72879148Scg		goto bad;
72979047Scg
73083617Scg	pcm_addchan(dev, PCMDIR_PLAY, &ichchan_class, sc);		/* play */
73183617Scg	pcm_addchan(dev, PCMDIR_REC, &ichchan_class, sc);		/* record */
73283617Scg	if (sc->hasmic)
73383617Scg		pcm_addchan(dev, PCMDIR_REC, &ichchan_class, sc);	/* record mic */
73479148Scg
73584641Scg	snprintf(status, SND_STATUSLEN, "at io 0x%lx, 0x%lx irq %ld bufsz %u",
73684641Scg		 rman_get_start(sc->nambar), rman_get_start(sc->nabmbar), rman_get_start(sc->irq), sc->bufsz);
73779148Scg
73879047Scg	pcm_setstatus(dev, status);
73979047Scg
74088033Sorion	ich_initsys(sc);
74188033Sorion
74298940Sscottl	sc->intrhook.ich_func = ich_calibrate;
74398940Sscottl	sc->intrhook.ich_arg = sc;
74498940Sscottl	sc->use_intrhook = 1;
74598940Sscottl	if (config_intrhook_establish(&sc->intrhook) != 0) {
74698940Sscottl		device_printf(dev, "Cannot establish calibration hook, will calibrate now\n");
74798940Sscottl		sc->use_intrhook = 0;
74898940Sscottl		ich_calibrate(sc);
74998940Sscottl	}
75098940Sscottl
75179047Scg	return 0;
75279047Scg
75379047Scgbad:
75479047Scg	if (sc->codec)
75579047Scg		ac97_destroy(sc->codec);
75689516Sorion	if (sc->ih)
75789516Sorion		bus_teardown_intr(dev, sc->irq, sc->ih);
75889516Sorion	if (sc->irq)
75989516Sorion		bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
76079047Scg	if (sc->nambar)
76179047Scg		bus_release_resource(dev, SYS_RES_IOPORT,
76279047Scg		    sc->nambarid, sc->nambar);
76379047Scg	if (sc->nabmbar)
76479047Scg		bus_release_resource(dev, SYS_RES_IOPORT,
76579047Scg		    sc->nabmbarid, sc->nabmbar);
76679047Scg	free(sc, M_DEVBUF);
76779047Scg	return ENXIO;
76879047Scg}
76979047Scg
77079047Scgstatic int
77179047Scgich_pci_detach(device_t dev)
77279047Scg{
77379047Scg	struct sc_info *sc;
77479047Scg	int r;
77579047Scg
77679047Scg	r = pcm_unregister(dev);
77779047Scg	if (r)
77879047Scg		return r;
77979047Scg	sc = pcm_getdevinfo(dev);
78079047Scg
78179148Scg	bus_teardown_intr(dev, sc->irq, sc->ih);
78279148Scg	bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
78379047Scg	bus_release_resource(dev, SYS_RES_IOPORT, sc->nambarid, sc->nambar);
78479047Scg	bus_release_resource(dev, SYS_RES_IOPORT, sc->nabmbarid, sc->nabmbar);
78579047Scg	bus_dma_tag_destroy(sc->dmat);
78679047Scg	free(sc, M_DEVBUF);
78779047Scg	return 0;
78879047Scg}
78979047Scg
79079047Scgstatic int
79188361Sorionich_pci_suspend(device_t dev)
79288361Sorion{
79388361Sorion	struct sc_info *sc;
79488361Sorion	int i;
79588361Sorion
79688361Sorion	sc = pcm_getdevinfo(dev);
79788361Sorion	for (i = 0 ; i < 3; i++) {
79888361Sorion		sc->ch[i].run_save = sc->ch[i].run;
79988361Sorion		if (sc->ch[i].run) {
80088361Sorion			ichchan_trigger(0, &sc->ch[i], PCMTRIG_ABORT);
80188361Sorion		}
80288361Sorion	}
80388361Sorion	return 0;
80488361Sorion}
80588361Sorion
80688361Sorionstatic int
80779047Scgich_pci_resume(device_t dev)
80879047Scg{
80979047Scg	struct sc_info *sc;
81088361Sorion	int i;
81179047Scg
81279047Scg	sc = pcm_getdevinfo(dev);
81379047Scg
81479047Scg	/* Reinit audio device */
81579047Scg    	if (ich_init(sc) == -1) {
81679047Scg		device_printf(dev, "unable to reinitialize the card\n");
81779047Scg		return ENXIO;
81879047Scg	}
81979047Scg	/* Reinit mixer */
82079047Scg    	if (mixer_reinit(dev) == -1) {
82179047Scg		device_printf(dev, "unable to reinitialize the mixer\n");
82279047Scg		return ENXIO;
82379047Scg	}
82488361Sorion	/* Re-start DMA engines */
82588361Sorion	for (i = 0 ; i < 3; i++) {
82688361Sorion		struct sc_chinfo *ch = &sc->ch[i];
82788361Sorion		if (sc->ch[i].run_save) {
82888361Sorion			ichchan_setblocksize(0, ch, ch->blksz);
82988361Sorion			ichchan_setspeed(0, ch, ch->spd);
83088361Sorion			ichchan_trigger(0, ch, PCMTRIG_START);
83188361Sorion		}
83288361Sorion	}
83379047Scg	return 0;
83479047Scg}
83579047Scg
83679047Scgstatic device_method_t ich_methods[] = {
83779047Scg	/* Device interface */
83879047Scg	DEVMETHOD(device_probe,		ich_pci_probe),
83979047Scg	DEVMETHOD(device_attach,	ich_pci_attach),
84079047Scg	DEVMETHOD(device_detach,	ich_pci_detach),
84188361Sorion	DEVMETHOD(device_suspend, 	ich_pci_suspend),
84279047Scg	DEVMETHOD(device_resume,	ich_pci_resume),
84379047Scg	{ 0, 0 }
84479047Scg};
84579047Scg
84679047Scgstatic driver_t ich_driver = {
84779047Scg	"pcm",
84879047Scg	ich_methods,
84982180Scg	PCM_SOFTC_SIZE,
85079047Scg};
85179047Scg
85279047ScgDRIVER_MODULE(snd_ich, pci, ich_driver, pcm_devclass, 0, 0);
85379047ScgMODULE_DEPEND(snd_ich, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER);
85479047ScgMODULE_VERSION(snd_ich, 1);
855