ich.c revision 88033
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 88033 2001-12-17 01:57:42Z 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
4479047Scg/* buffer descriptor */
4579047Scgstruct ich_desc {
4679047Scg	volatile u_int32_t buffer;
4779047Scg	volatile u_int32_t length;
4879047Scg};
4979047Scg
5079047Scgstruct sc_info;
5179047Scg
5279047Scg/* channel registers */
5379047Scgstruct sc_chinfo {
5479148Scg	u_int32_t num, run;
5579148Scg	u_int32_t blksz, blkcnt;
5679148Scg	u_int32_t regbase, spdreg;
5782478Scg	u_int32_t civ;
5879148Scg
5979047Scg	struct snd_dbuf *buffer;
6079047Scg	struct pcm_channel *channel;
6179047Scg	struct sc_info *parent;
6279148Scg
6379148Scg	struct ich_desc *dtbl;
6479047Scg};
6579047Scg
6679047Scg/* device private data */
6779047Scgstruct sc_info {
6879148Scg	device_t dev;
6983617Scg	int hasvra, hasvrm, hasmic;
7083617Scg	unsigned int chnum, bufsz;
7179047Scg
7279148Scg	struct resource *nambar, *nabmbar, *irq;
7379148Scg	int nambarid, nabmbarid, irqid;
7479047Scg	bus_space_tag_t nambart, nabmbart;
7579047Scg	bus_space_handle_t nambarh, nabmbarh;
7679047Scg	bus_dma_tag_t dmat;
7779148Scg	bus_dmamap_t dtmap;
7879148Scg	void *ih;
7979047Scg
8079047Scg	struct ac97_info *codec;
8179148Scg	struct sc_chinfo ch[3];
8288033Sorion	int ac97rate;
8379148Scg	struct ich_desc *dtbl;
8479047Scg};
8579047Scg
8679047Scg/* -------------------------------------------------------------------- */
8779047Scg
8879148Scgstatic u_int32_t ich_fmt[] = {
8979047Scg	AFMT_STEREO | AFMT_S16_LE,
9079047Scg	0
9179047Scg};
9279148Scgstatic struct pcmchan_caps ich_vrcaps = {8000, 48000, ich_fmt, 0};
9379148Scgstatic struct pcmchan_caps ich_caps = {48000, 48000, ich_fmt, 0};
9479047Scg
9579047Scg/* -------------------------------------------------------------------- */
9679047Scg/* Hardware */
9779047Scgstatic u_int32_t
9879047Scgich_rd(struct sc_info *sc, int regno, int size)
9979047Scg{
10079047Scg	switch (size) {
10179047Scg	case 1:
10279148Scg		return bus_space_read_1(sc->nabmbart, sc->nabmbarh, regno);
10379047Scg	case 2:
10479148Scg		return bus_space_read_2(sc->nabmbart, sc->nabmbarh, regno);
10579047Scg	case 4:
10679148Scg		return bus_space_read_4(sc->nabmbart, sc->nabmbarh, regno);
10779047Scg	default:
10879047Scg		return 0xffffffff;
10979047Scg	}
11079047Scg}
11179047Scg
11279047Scgstatic void
11379047Scgich_wr(struct sc_info *sc, int regno, u_int32_t data, int size)
11479047Scg{
11579047Scg	switch (size) {
11679047Scg	case 1:
11779148Scg		bus_space_write_1(sc->nabmbart, sc->nabmbarh, regno, data);
11879047Scg		break;
11979047Scg	case 2:
12079148Scg		bus_space_write_2(sc->nabmbart, sc->nabmbarh, regno, data);
12179047Scg		break;
12279047Scg	case 4:
12379148Scg		bus_space_write_4(sc->nabmbart, sc->nabmbarh, regno, data);
12479047Scg		break;
12579047Scg	}
12679047Scg}
12779047Scg
12879047Scg/* ac97 codec */
12979047Scgstatic int
13079047Scgich_waitcd(void *devinfo)
13179047Scg{
13279047Scg	int i;
13379047Scg	u_int32_t data;
13479047Scg	struct sc_info *sc = (struct sc_info *)devinfo;
13579148Scg
13679148Scg	for (i = 0; i < ICH_TIMEOUT; i++) {
13779148Scg		data = ich_rd(sc, ICH_REG_ACC_SEMA, 1);
13879047Scg		if ((data & 0x01) == 0)
13979047Scg			return 0;
14079047Scg	}
14179047Scg	device_printf(sc->dev, "CODEC semaphore timeout\n");
14279047Scg	return ETIMEDOUT;
14379047Scg}
14479047Scg
14579047Scgstatic int
14679047Scgich_rdcd(kobj_t obj, void *devinfo, int regno)
14779047Scg{
14879047Scg	struct sc_info *sc = (struct sc_info *)devinfo;
14979148Scg
15079047Scg	regno &= 0xff;
15179047Scg	ich_waitcd(sc);
15279148Scg
15379148Scg	return bus_space_read_2(sc->nambart, sc->nambarh, regno);
15479047Scg}
15579047Scg
15679047Scgstatic int
15779148Scgich_wrcd(kobj_t obj, void *devinfo, int regno, u_int16_t data)
15879047Scg{
15979047Scg	struct sc_info *sc = (struct sc_info *)devinfo;
16079148Scg
16179047Scg	regno &= 0xff;
16279047Scg	ich_waitcd(sc);
16379148Scg	bus_space_write_2(sc->nambart, sc->nambarh, regno, data);
16479148Scg
16579047Scg	return 0;
16679047Scg}
16779047Scg
16879047Scgstatic kobj_method_t ich_ac97_methods[] = {
16979047Scg	KOBJMETHOD(ac97_read,		ich_rdcd),
17079047Scg	KOBJMETHOD(ac97_write,		ich_wrcd),
17179047Scg	{ 0, 0 }
17279047Scg};
17379047ScgAC97_DECLARE(ich_ac97);
17479047Scg
17579047Scg/* -------------------------------------------------------------------- */
17679148Scg/* common routines */
17779047Scg
17879047Scgstatic void
17979148Scgich_filldtbl(struct sc_chinfo *ch)
18079047Scg{
18179148Scg	u_int32_t base;
18282478Scg	int i;
18379047Scg
18479148Scg	base = vtophys(sndbuf_getbuf(ch->buffer));
18579148Scg	ch->blkcnt = sndbuf_getsize(ch->buffer) / ch->blksz;
18679148Scg	if (ch->blkcnt != 2 && ch->blkcnt != 4 && ch->blkcnt != 8 && ch->blkcnt != 16 && ch->blkcnt != 32) {
18779148Scg		ch->blkcnt = 2;
18879148Scg		ch->blksz = sndbuf_getsize(ch->buffer) / ch->blkcnt;
18979047Scg	}
19079047Scg
19179148Scg	for (i = 0; i < ICH_DTBL_LENGTH; i++) {
19282478Scg		ch->dtbl[i].buffer = base + (ch->blksz * (i % ch->blkcnt));
19382478Scg		ch->dtbl[i].length = ICH_BDC_IOC | (ch->blksz / 2);
19479047Scg	}
19579047Scg}
19679047Scg
19779148Scgstatic int
19879148Scgich_resetchan(struct sc_info *sc, int num)
19979047Scg{
20079148Scg	int i, cr, regbase;
20179047Scg
20279148Scg	if (num == 0)
20379148Scg		regbase = ICH_REG_PO_BASE;
20479148Scg	else if (num == 1)
20579148Scg		regbase = ICH_REG_PI_BASE;
20679148Scg	else if (num == 2)
20779148Scg		regbase = ICH_REG_MC_BASE;
20879148Scg	else
20979148Scg		return ENXIO;
21079047Scg
21179148Scg	ich_wr(sc, regbase + ICH_REG_X_CR, 0, 1);
21279148Scg	DELAY(100);
21379148Scg	ich_wr(sc, regbase + ICH_REG_X_CR, ICH_X_CR_RR, 1);
21479148Scg	for (i = 0; i < ICH_TIMEOUT; i++) {
21579148Scg		cr = ich_rd(sc, regbase + ICH_REG_X_CR, 1);
21679148Scg		if (cr == 0)
21779148Scg			return 0;
21879148Scg	}
21979047Scg
22079148Scg	device_printf(sc->dev, "cannot reset channel %d\n", num);
22179148Scg	return ENXIO;
22279047Scg}
22379047Scg
22479148Scg/* -------------------------------------------------------------------- */
22579148Scg/* channel interface */
22679047Scg
22779047Scgstatic void *
22879148Scgichchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
22979047Scg{
23079047Scg	struct sc_info *sc = devinfo;
23179047Scg	struct sc_chinfo *ch;
23283617Scg	unsigned int num;
23379047Scg
23479148Scg	num = sc->chnum++;
23579148Scg	ch = &sc->ch[num];
23679148Scg	ch->num = num;
23779047Scg	ch->buffer = b;
23879047Scg	ch->channel = c;
23979047Scg	ch->parent = sc;
24079047Scg	ch->run = 0;
24179148Scg	ch->dtbl = sc->dtbl + (ch->num * ICH_DTBL_LENGTH);
24279148Scg	ch->blkcnt = 2;
24383617Scg	ch->blksz = sc->bufsz / ch->blkcnt;
24479047Scg
24579148Scg	switch(ch->num) {
24679148Scg	case 0: /* play */
24779148Scg		KASSERT(dir == PCMDIR_PLAY, ("wrong direction"));
24879148Scg		ch->regbase = ICH_REG_PO_BASE;
24979148Scg		ch->spdreg = sc->hasvra? AC97_REGEXT_FDACRATE : 0;
25079148Scg		break;
25179047Scg
25282478Scg	case 1: /* record */
25379148Scg		KASSERT(dir == PCMDIR_REC, ("wrong direction"));
25482478Scg		ch->regbase = ICH_REG_PI_BASE;
25582478Scg		ch->spdreg = sc->hasvra? AC97_REGEXT_LADCRATE : 0;
25679148Scg		break;
25779047Scg
25882478Scg	case 2: /* mic */
25979148Scg		KASSERT(dir == PCMDIR_REC, ("wrong direction"));
26082478Scg		ch->regbase = ICH_REG_MC_BASE;
26182478Scg		ch->spdreg = sc->hasvrm? AC97_REGEXT_MADCRATE : 0;
26279148Scg		break;
26379047Scg
26479148Scg	default:
26579148Scg		return NULL;
26679047Scg	}
26779047Scg
26883617Scg	if (sndbuf_alloc(ch->buffer, sc->dmat, sc->bufsz))
26979148Scg		return NULL;
27079047Scg
27179148Scg	ich_wr(sc, ch->regbase + ICH_REG_X_BDBAR, (u_int32_t)vtophys(ch->dtbl), 4);
27279047Scg
27379148Scg	return ch;
27479047Scg}
27579047Scg
27679047Scgstatic int
27779148Scgichchan_setformat(kobj_t obj, void *data, u_int32_t format)
27879047Scg{
27979047Scg	return 0;
28079047Scg}
28179047Scg
28279047Scgstatic int
28379148Scgichchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
28479047Scg{
28579047Scg	struct sc_chinfo *ch = data;
28679047Scg	struct sc_info *sc = ch->parent;
28779047Scg
28888033Sorion	if (ch->spdreg) {
28988033Sorion		int r;
29088033Sorion		if (sc->ac97rate <= 32000 || sc->ac97rate >= 64000)
29188033Sorion			sc->ac97rate = 48000;
29288033Sorion		r = speed * 48000 / sc->ac97rate;
29388033Sorion		return ac97_setrate(sc->codec, ch->spdreg, r) *
29488033Sorion			sc->ac97rate / 48000;
29588033Sorion	} else {
29679148Scg		return 48000;
29788033Sorion	}
29879047Scg}
29979047Scg
30079047Scgstatic int
30179148Scgichchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
30279047Scg{
30379047Scg	struct sc_chinfo *ch = data;
30479148Scg	struct sc_info *sc = ch->parent;
30579047Scg
30679148Scg	ch->blksz = blocksize;
30779148Scg	ich_filldtbl(ch);
30882478Scg	ich_wr(sc, ch->regbase + ICH_REG_X_LVI, ch->blkcnt - 1, 1);
30979047Scg
31079148Scg	return ch->blksz;
31179047Scg}
31279047Scg
31379047Scgstatic int
31479148Scgichchan_trigger(kobj_t obj, void *data, int go)
31579047Scg{
31679047Scg	struct sc_chinfo *ch = data;
31779047Scg	struct sc_info *sc = ch->parent;
31879047Scg
31979047Scg	switch (go) {
32079047Scg	case PCMTRIG_START:
32179047Scg		ch->run = 1;
32279148Scg		ich_wr(sc, ch->regbase + ICH_REG_X_BDBAR, (u_int32_t)vtophys(ch->dtbl), 4);
32379148Scg		ich_wr(sc, ch->regbase + ICH_REG_X_CR, ICH_X_CR_RPBM | ICH_X_CR_LVBIE | ICH_X_CR_IOCE | ICH_X_CR_FEIE, 1);
32479047Scg		break;
32579148Scg
32679047Scg	case PCMTRIG_ABORT:
32779148Scg		ich_resetchan(sc, ch->num);
32879047Scg		ch->run = 0;
32979047Scg		break;
33079047Scg	}
33179047Scg	return 0;
33279047Scg}
33379047Scg
33479047Scgstatic int
33579148Scgichchan_getptr(kobj_t obj, void *data)
33679047Scg{
33779047Scg	struct sc_chinfo *ch = data;
33879047Scg	struct sc_info *sc = ch->parent;
33982478Scg      	u_int32_t pos;
34079047Scg
34182478Scg	ch->civ = ich_rd(sc, ch->regbase + ICH_REG_X_CIV, 1) % ch->blkcnt;
34279148Scg
34382478Scg	pos = ch->civ * ch->blksz;
34479148Scg
34579148Scg	return pos;
34679047Scg}
34779047Scg
34879047Scgstatic struct pcmchan_caps *
34979148Scgichchan_getcaps(kobj_t obj, void *data)
35079047Scg{
35179148Scg	struct sc_chinfo *ch = data;
35279148Scg
35379148Scg	return ch->spdreg? &ich_vrcaps : &ich_caps;
35479047Scg}
35579047Scg
35679148Scgstatic kobj_method_t ichchan_methods[] = {
35779148Scg	KOBJMETHOD(channel_init,		ichchan_init),
35879148Scg	KOBJMETHOD(channel_setformat,		ichchan_setformat),
35979148Scg	KOBJMETHOD(channel_setspeed,		ichchan_setspeed),
36079148Scg	KOBJMETHOD(channel_setblocksize,	ichchan_setblocksize),
36179148Scg	KOBJMETHOD(channel_trigger,		ichchan_trigger),
36279148Scg	KOBJMETHOD(channel_getptr,		ichchan_getptr),
36379148Scg	KOBJMETHOD(channel_getcaps,		ichchan_getcaps),
36479047Scg	{ 0, 0 }
36579047Scg};
36679148ScgCHANNEL_DECLARE(ichchan);
36779047Scg
36879047Scg/* -------------------------------------------------------------------- */
36979047Scg/* The interrupt handler */
37079148Scg
37179047Scgstatic void
37279047Scgich_intr(void *p)
37379047Scg{
37479047Scg	struct sc_info *sc = (struct sc_info *)p;
37579047Scg	struct sc_chinfo *ch;
37682478Scg	u_int32_t cbi, lbi, lvi, st;
37779148Scg	int i;
37879047Scg
37979148Scg	for (i = 0; i < 3; i++) {
38079148Scg		ch = &sc->ch[i];
38179047Scg		/* check channel status */
38279148Scg		st = ich_rd(sc, ch->regbase + ICH_REG_X_SR, 2);
38379148Scg		st &= ICH_X_SR_FIFOE | ICH_X_SR_BCIS | ICH_X_SR_LVBCI;
38479148Scg		if (st != 0) {
38582478Scg			if (st & (ICH_X_SR_BCIS | ICH_X_SR_LVBCI)) {
38679148Scg				/* block complete - update buffer */
38779148Scg				if (ch->run)
38879148Scg					chn_intr(ch->channel);
38979148Scg				lvi = ich_rd(sc, ch->regbase + ICH_REG_X_LVI, 1);
39082478Scg				cbi = ch->civ % ch->blkcnt;
39182478Scg				if (cbi == 0)
39282478Scg					cbi = ch->blkcnt - 1;
39382478Scg				else
39482478Scg					cbi--;
39582478Scg				lbi = lvi % ch->blkcnt;
39682478Scg				if (cbi >= lbi)
39782478Scg					lvi += cbi - lbi;
39882478Scg				else
39982478Scg					lvi += cbi + ch->blkcnt - lbi;
40079148Scg				lvi %= ICH_DTBL_LENGTH;
40179148Scg				ich_wr(sc, ch->regbase + ICH_REG_X_LVI, lvi, 1);
40279047Scg			}
40382478Scg			/* clear status bit */
40482478Scg			ich_wr(sc, ch->regbase + ICH_REG_X_SR, st, 2);
40579047Scg		}
40679047Scg	}
40779047Scg}
40879047Scg
40988033Sorion/* ------------------------------------------------------------------------- */
41088033Sorion/* Sysctl to control ac97 speed (some boards overclocked ac97). */
41188033Sorion
41288033Sorionstatic int
41388033Sorionich_initsys(struct sc_info* sc)
41488033Sorion{
41588033Sorion#ifdef SND_DYNSYSCTL
41688033Sorion	SYSCTL_ADD_INT(snd_sysctl_tree(sc->dev),
41788033Sorion		       SYSCTL_CHILDREN(snd_sysctl_tree_top(sc->dev)),
41888033Sorion		       OID_AUTO, "ac97rate", CTLFLAG_RW,
41988033Sorion		       &sc->ac97rate, 48000,
42088033Sorion		       "AC97 link rate (default = 48000)");
42188033Sorion#endif /* SND_DYNSYSCTL */
42288033Sorion	return 0;
42388033Sorion}
42488033Sorion
42579047Scg/* -------------------------------------------------------------------- */
42679148Scg/* Probe and attach the card */
42779047Scg
42879148Scgstatic void
42979148Scgich_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
43079148Scg{
43179148Scg	return;
43279148Scg}
43379047Scg
43479047Scgstatic int
43579047Scgich_init(struct sc_info *sc)
43679047Scg{
43779047Scg	u_int32_t stat;
43879148Scg	int sz;
43979047Scg
44079148Scg	ich_wr(sc, ICH_REG_GLOB_CNT, ICH_GLOB_CTL_COLD, 4);
44179047Scg	DELAY(600000);
44279148Scg	stat = ich_rd(sc, ICH_REG_GLOB_STA, 4);
44379148Scg
44479047Scg	if ((stat & ICH_GLOB_STA_PCR) == 0)
44579148Scg		return ENXIO;
44679047Scg
44779148Scg	ich_wr(sc, ICH_REG_GLOB_CNT, ICH_GLOB_CTL_COLD | ICH_GLOB_CTL_PRES, 4);
44879047Scg
44983617Scg	if (ich_resetchan(sc, 0) || ich_resetchan(sc, 1))
45079148Scg		return ENXIO;
45183617Scg	if (sc->hasmic && ich_resetchan(sc, 2))
45283617Scg		return ENXIO;
45379148Scg
45479148Scg	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->dtbl, BUS_DMA_NOWAIT, &sc->dtmap))
45579148Scg		return ENOSPC;
45679148Scg
45779148Scg	sz = sizeof(struct ich_desc) * ICH_DTBL_LENGTH * 3;
45879148Scg	if (bus_dmamap_load(sc->dmat, sc->dtmap, sc->dtbl, sz, ich_setmap, NULL, 0)) {
45979148Scg		bus_dmamem_free(sc->dmat, (void **)&sc->dtbl, sc->dtmap);
46079148Scg		return ENOSPC;
46179047Scg	}
46279148Scg
46379148Scg	return 0;
46479047Scg}
46579047Scg
46679047Scgstatic int
46779047Scgich_pci_probe(device_t dev)
46879047Scg{
46979148Scg	switch(pci_get_devid(dev)) {
47079148Scg	case 0x71958086:
47179148Scg		device_set_desc(dev, "Intel 443MX");
47279148Scg		return 0;
47379047Scg
47479148Scg	case 0x24158086:
47579148Scg		device_set_desc(dev, "Intel 82801AA (ICH)");
47679047Scg		return 0;
47779148Scg
47879148Scg	case 0x24258086:
47985946Speter		device_set_desc(dev, "Intel 82801AB (ICH)");
48079148Scg		return 0;
48179148Scg
48279148Scg	case 0x24458086:
48379148Scg		device_set_desc(dev, "Intel 82801BA (ICH2)");
48479148Scg		return 0;
48579148Scg
48685946Speter	case 0x24858086:
48785946Speter		device_set_desc(dev, "Intel 82801CA (ICH3)");
48885946Speter		return 0;
48985946Speter
49079148Scg	default:
49179047Scg		return ENXIO;
49279148Scg	}
49379047Scg}
49479047Scg
49579047Scgstatic int
49679047Scgich_pci_attach(device_t dev)
49779047Scg{
49879047Scg	u_int32_t		data;
49986708Sorion	u_int16_t		extcaps;
50079047Scg	struct sc_info 		*sc;
50179047Scg	char 			status[SND_STATUSLEN];
50279047Scg
50379047Scg	if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT)) == NULL) {
50479047Scg		device_printf(dev, "cannot allocate softc\n");
50579047Scg		return ENXIO;
50679047Scg	}
50779047Scg
50879047Scg	bzero(sc, sizeof(*sc));
50979047Scg	sc->dev = dev;
51079047Scg
51179047Scg	data = pci_read_config(dev, PCIR_COMMAND, 2);
51279047Scg	data |= (PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
51379047Scg	pci_write_config(dev, PCIR_COMMAND, data, 2);
51479047Scg	data = pci_read_config(dev, PCIR_COMMAND, 2);
51579047Scg
51679047Scg	sc->nambarid = PCIR_NAMBAR;
51779047Scg	sc->nabmbarid = PCIR_NABMBAR;
51879148Scg	sc->nambar = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->nambarid, 0, ~0, 1, RF_ACTIVE);
51979148Scg	sc->nabmbar = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->nabmbarid, 0, ~0, 1, RF_ACTIVE);
52079148Scg
52179047Scg	if (!sc->nambar || !sc->nabmbar) {
52279047Scg		device_printf(dev, "unable to map IO port space\n");
52379047Scg		goto bad;
52479047Scg	}
52579148Scg
52679047Scg	sc->nambart = rman_get_bustag(sc->nambar);
52779047Scg	sc->nambarh = rman_get_bushandle(sc->nambar);
52879047Scg	sc->nabmbart = rman_get_bustag(sc->nabmbar);
52979047Scg	sc->nabmbarh = rman_get_bushandle(sc->nabmbar);
53079047Scg
53183617Scg	sc->bufsz = pcm_getbuffersize(dev, 4096, ICH_DEFAULT_BUFSZ, ICH_MAX_BUFSZ);
53282478Scg	if (bus_dma_tag_create(NULL, 8, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
53383617Scg			       NULL, NULL, sc->bufsz, 1, 0x3ffff, 0, &sc->dmat) != 0) {
53479047Scg		device_printf(dev, "unable to create dma tag\n");
53579047Scg		goto bad;
53679047Scg	}
53779047Scg
53879148Scg	if (ich_init(sc)) {
53979047Scg		device_printf(dev, "unable to initialize the card\n");
54079047Scg		goto bad;
54179047Scg	}
54279047Scg
54379047Scg	sc->codec = AC97_CREATE(dev, sc, ich_ac97);
54479047Scg	if (sc->codec == NULL)
54579047Scg		goto bad;
54679047Scg	mixer_init(dev, ac97_getmixerclass(), sc->codec);
54779148Scg
54879047Scg	/* check and set VRA function */
54986795Sorion	extcaps = ac97_getextcaps(sc->codec);
55086708Sorion	sc->hasvra = extcaps & AC97_EXTCAP_VRA;
55186708Sorion	sc->hasvrm = extcaps & AC97_EXTCAP_VRM;
55286795Sorion	sc->hasmic = extcaps & AC97_CAP_MICCHANNEL;
55386795Sorion	ac97_setextmode(sc->codec, sc->hasvra | sc->hasvrm | sc->hasmic);
55479047Scg
55579047Scg	sc->irqid = 0;
55679148Scg	sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irqid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
55779148Scg	if (!sc->irq || snd_setup_intr(dev, sc->irq, INTR_MPSAFE, ich_intr, sc, &sc->ih)) {
55879047Scg		device_printf(dev, "unable to map interrupt\n");
55979047Scg		goto bad;
56079047Scg	}
56179047Scg
56284641Scg	if (pcm_register(dev, sc, 1, sc->hasmic? 2 : 1))
56379148Scg		goto bad;
56479047Scg
56583617Scg	pcm_addchan(dev, PCMDIR_PLAY, &ichchan_class, sc);		/* play */
56683617Scg	pcm_addchan(dev, PCMDIR_REC, &ichchan_class, sc);		/* record */
56783617Scg	if (sc->hasmic)
56883617Scg		pcm_addchan(dev, PCMDIR_REC, &ichchan_class, sc);	/* record mic */
56979148Scg
57084641Scg	snprintf(status, SND_STATUSLEN, "at io 0x%lx, 0x%lx irq %ld bufsz %u",
57184641Scg		 rman_get_start(sc->nambar), rman_get_start(sc->nabmbar), rman_get_start(sc->irq), sc->bufsz);
57279148Scg
57379047Scg	pcm_setstatus(dev, status);
57479047Scg
57588033Sorion	ich_initsys(sc);
57688033Sorion
57779047Scg	return 0;
57879047Scg
57979047Scgbad:
58079047Scg	if (sc->codec)
58179047Scg		ac97_destroy(sc->codec);
58279047Scg	if (sc->nambar)
58379047Scg		bus_release_resource(dev, SYS_RES_IOPORT,
58479047Scg		    sc->nambarid, sc->nambar);
58579047Scg	if (sc->nabmbar)
58679047Scg		bus_release_resource(dev, SYS_RES_IOPORT,
58779047Scg		    sc->nabmbarid, sc->nabmbar);
58879047Scg	if (sc->ih)
58979047Scg		bus_teardown_intr(dev, sc->irq, sc->ih);
59079047Scg	if (sc->irq)
59179047Scg		bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
59279047Scg	free(sc, M_DEVBUF);
59379047Scg	return ENXIO;
59479047Scg}
59579047Scg
59679047Scgstatic int
59779047Scgich_pci_detach(device_t dev)
59879047Scg{
59979047Scg	struct sc_info *sc;
60079047Scg	int r;
60179047Scg
60279047Scg	r = pcm_unregister(dev);
60379047Scg	if (r)
60479047Scg		return r;
60579047Scg	sc = pcm_getdevinfo(dev);
60679047Scg
60779148Scg	bus_teardown_intr(dev, sc->irq, sc->ih);
60879148Scg	bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
60979047Scg	bus_release_resource(dev, SYS_RES_IOPORT, sc->nambarid, sc->nambar);
61079047Scg	bus_release_resource(dev, SYS_RES_IOPORT, sc->nabmbarid, sc->nabmbar);
61179047Scg	bus_dma_tag_destroy(sc->dmat);
61279047Scg	free(sc, M_DEVBUF);
61379047Scg	return 0;
61479047Scg}
61579047Scg
61679047Scgstatic int
61779047Scgich_pci_resume(device_t dev)
61879047Scg{
61979047Scg	struct sc_info *sc;
62079047Scg
62179047Scg	sc = pcm_getdevinfo(dev);
62279047Scg
62379047Scg	/* Reinit audio device */
62479047Scg    	if (ich_init(sc) == -1) {
62579047Scg		device_printf(dev, "unable to reinitialize the card\n");
62679047Scg		return ENXIO;
62779047Scg	}
62879047Scg	/* Reinit mixer */
62979047Scg    	if (mixer_reinit(dev) == -1) {
63079047Scg		device_printf(dev, "unable to reinitialize the mixer\n");
63179047Scg		return ENXIO;
63279047Scg	}
63379047Scg	return 0;
63479047Scg}
63579047Scg
63679047Scgstatic device_method_t ich_methods[] = {
63779047Scg	/* Device interface */
63879047Scg	DEVMETHOD(device_probe,		ich_pci_probe),
63979047Scg	DEVMETHOD(device_attach,	ich_pci_attach),
64079047Scg	DEVMETHOD(device_detach,	ich_pci_detach),
64179047Scg	DEVMETHOD(device_resume,	ich_pci_resume),
64279047Scg	{ 0, 0 }
64379047Scg};
64479047Scg
64579047Scgstatic driver_t ich_driver = {
64679047Scg	"pcm",
64779047Scg	ich_methods,
64882180Scg	PCM_SOFTC_SIZE,
64979047Scg};
65079047Scg
65179047ScgDRIVER_MODULE(snd_ich, pci, ich_driver, pcm_devclass, 0, 0);
65279047ScgMODULE_DEPEND(snd_ich, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER);
65379047ScgMODULE_VERSION(snd_ich, 1);
654