1139749Simp/*-
2119853Scg * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
355639Scg * All rights reserved.
455639Scg *
555639Scg * Derived from the public domain Linux driver
655639Scg *
755639Scg * Redistribution and use in source and binary forms, with or without
855639Scg * modification, are permitted provided that the following conditions
955639Scg * are met:
1055639Scg * 1. Redistributions of source code must retain the above copyright
1155639Scg *    notice, this list of conditions and the following disclaimer.
1255639Scg * 2. Redistributions in binary form must reproduce the above copyright
1355639Scg *    notice, this list of conditions and the following disclaimer in the
1455639Scg *    documentation and/or other materials provided with the distribution.
1555639Scg *
1655639Scg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1755639Scg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1855639Scg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1955639Scg * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2055639Scg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2155639Scg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2255639Scg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2355639Scg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
2455639Scg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2555639Scg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF
2655639Scg * SUCH DAMAGE.
2755639Scg */
2855639Scg
29193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS
30193640Sariff#include "opt_snd.h"
31193640Sariff#endif
32193640Sariff
3355639Scg#include <dev/sound/pcm/sound.h>
3455639Scg#include <dev/sound/pcm/ac97.h>
3555639Scg#include <dev/sound/pci/neomagic.h>
3655639Scg#include <dev/sound/pci/neomagic-coeff.h>
3755639Scg
38119287Simp#include <dev/pci/pcireg.h>
39119287Simp#include <dev/pci/pcivar.h>
4055639Scg
4182180ScgSND_DECLARE_FILE("$FreeBSD$");
4282180Scg
4355639Scg/* -------------------------------------------------------------------- */
4455639Scg
4555639Scg#define	NM_BUFFSIZE	16384
4655639Scg
4755639Scg#define NM256AV_PCI_ID 	0x800510c8
4855639Scg#define NM256ZX_PCI_ID 	0x800610c8
4955639Scg
5055639Scgstruct sc_info;
5155639Scg
5255639Scg/* channel registers */
5355639Scgstruct sc_chinfo {
5491607Sorion	int active, spd, dir, fmt;
5591607Sorion	u_int32_t blksize, wmark;
5674763Scg	struct snd_dbuf *buffer;
5774763Scg	struct pcm_channel *channel;
5855639Scg	struct sc_info *parent;
5955639Scg};
6055639Scg
6155639Scg/* device private data */
6255639Scgstruct sc_info {
6355639Scg	device_t	dev;
6455639Scg	u_int32_t 	type;
6555639Scg
6655639Scg	struct resource *reg, *irq, *buf;
6755639Scg	int		regid, irqid, bufid;
6855639Scg	void		*ih;
6955639Scg
7055639Scg	u_int32_t 	ac97_base, ac97_status, ac97_busy;
7155639Scg	u_int32_t	buftop, pbuf, rbuf, cbuf, acbuf;
7255639Scg	u_int32_t	playint, recint, misc1int, misc2int;
7355639Scg	u_int32_t	irsz, badintr;
7455639Scg
7555639Scg	struct sc_chinfo pch, rch;
7655639Scg};
7755639Scg
7855639Scg/* -------------------------------------------------------------------- */
7955639Scg
8055639Scg/*
8155639Scg * prototypes
8255639Scg */
8355639Scg
8455639Scg/* stuff */
8555639Scgstatic int 	 nm_loadcoeff(struct sc_info *sc, int dir, int num);
8655639Scgstatic int	 nm_setch(struct sc_chinfo *ch);
8755639Scgstatic int       nm_init(struct sc_info *);
8855639Scgstatic void      nm_intr(void *);
8955639Scg
9055639Scg/* talk to the card */
9155639Scgstatic u_int32_t nm_rd(struct sc_info *, int, int);
9255639Scgstatic void 	 nm_wr(struct sc_info *, int, u_int32_t, int);
9355639Scgstatic u_int32_t nm_rdbuf(struct sc_info *, int, int);
9455639Scgstatic void 	 nm_wrbuf(struct sc_info *, int, u_int32_t, int);
9555639Scg
9655802Scgstatic u_int32_t badcards[] = {
9755802Scg	0x0007103c,
9855802Scg	0x008f1028,
9964461Scg	0x00dd1014,
10075382Sgreid	0x8005110a,
10155802Scg};
10255802Scg#define NUM_BADCARDS (sizeof(badcards) / sizeof(u_int32_t))
10355802Scg
10455639Scg/* The actual rates supported by the card. */
10555639Scgstatic int samplerates[9] = {
10655802Scg	8000,
10755802Scg	11025,
10855802Scg	16000,
10955802Scg	22050,
11055802Scg	24000,
11155802Scg	32000,
11255802Scg	44100,
11355802Scg	48000,
11455802Scg	99999999
11555639Scg};
11655639Scg
11755639Scg/* -------------------------------------------------------------------- */
11855639Scg
11964881Scgstatic u_int32_t nm_fmt[] = {
120193640Sariff	SND_FORMAT(AFMT_U8, 1, 0),
121193640Sariff	SND_FORMAT(AFMT_U8, 2, 0),
122193640Sariff	SND_FORMAT(AFMT_S16_LE, 1, 0),
123193640Sariff	SND_FORMAT(AFMT_S16_LE, 2, 0),
12464881Scg	0
12555639Scg};
12674763Scgstatic struct pcmchan_caps nm_caps = {4000, 48000, nm_fmt, 0};
12755639Scg
12855639Scg/* -------------------------------------------------------------------- */
12955639Scg
13055639Scg/* Hardware */
13155639Scgstatic u_int32_t
13255639Scgnm_rd(struct sc_info *sc, int regno, int size)
13355639Scg{
13455639Scg	bus_space_tag_t st = rman_get_bustag(sc->reg);
13555639Scg	bus_space_handle_t sh = rman_get_bushandle(sc->reg);
13655639Scg
13755639Scg	switch (size) {
13855639Scg	case 1:
13955639Scg		return bus_space_read_1(st, sh, regno);
14055639Scg	case 2:
14155639Scg		return bus_space_read_2(st, sh, regno);
14255639Scg	case 4:
14355639Scg		return bus_space_read_4(st, sh, regno);
14455639Scg	default:
14555639Scg		return 0xffffffff;
14655639Scg	}
14755639Scg}
14855639Scg
14955639Scgstatic void
15055639Scgnm_wr(struct sc_info *sc, int regno, u_int32_t data, int size)
15155639Scg{
15255639Scg	bus_space_tag_t st = rman_get_bustag(sc->reg);
15355639Scg	bus_space_handle_t sh = rman_get_bushandle(sc->reg);
15455639Scg
15555639Scg	switch (size) {
15655639Scg	case 1:
15755639Scg		bus_space_write_1(st, sh, regno, data);
15855639Scg		break;
15955639Scg	case 2:
16055639Scg		bus_space_write_2(st, sh, regno, data);
16155639Scg		break;
16255639Scg	case 4:
16355639Scg		bus_space_write_4(st, sh, regno, data);
16455639Scg		break;
16555639Scg	}
16655639Scg}
16755639Scg
16855639Scgstatic u_int32_t
16955639Scgnm_rdbuf(struct sc_info *sc, int regno, int size)
17055639Scg{
17155639Scg	bus_space_tag_t st = rman_get_bustag(sc->buf);
17255639Scg	bus_space_handle_t sh = rman_get_bushandle(sc->buf);
17355639Scg
17455639Scg	switch (size) {
17555639Scg	case 1:
17655639Scg		return bus_space_read_1(st, sh, regno);
17755639Scg	case 2:
17855639Scg		return bus_space_read_2(st, sh, regno);
17955639Scg	case 4:
18055639Scg		return bus_space_read_4(st, sh, regno);
18155639Scg	default:
18255639Scg		return 0xffffffff;
18355639Scg	}
18455639Scg}
18555639Scg
18655639Scgstatic void
18755639Scgnm_wrbuf(struct sc_info *sc, int regno, u_int32_t data, int size)
18855639Scg{
18955639Scg	bus_space_tag_t st = rman_get_bustag(sc->buf);
19055639Scg	bus_space_handle_t sh = rman_get_bushandle(sc->buf);
19155639Scg
19255639Scg	switch (size) {
19355639Scg	case 1:
19455639Scg		bus_space_write_1(st, sh, regno, data);
19555639Scg		break;
19655639Scg	case 2:
19755639Scg		bus_space_write_2(st, sh, regno, data);
19855639Scg		break;
19955639Scg	case 4:
20055639Scg		bus_space_write_4(st, sh, regno, data);
20155639Scg		break;
20255639Scg	}
20355639Scg}
20455639Scg
20570134Scg/* -------------------------------------------------------------------- */
20655639Scg/* ac97 codec */
20755639Scgstatic int
20855639Scgnm_waitcd(struct sc_info *sc)
20955639Scg{
21055639Scg	int cnt = 10;
21191607Sorion	int fail = 1;
21255639Scg
21355639Scg	while (cnt-- > 0) {
21491607Sorion		if (nm_rd(sc, sc->ac97_status, 2) & sc->ac97_busy) {
21555639Scg			DELAY(100);
21691607Sorion		} else {
21791607Sorion			fail = 0;
21855639Scg			break;
21991607Sorion		}
22055639Scg	}
22191607Sorion	return (fail);
22255639Scg}
22355639Scg
22455639Scgstatic u_int32_t
22570134Scgnm_initcd(kobj_t obj, void *devinfo)
22658384Scg{
22758384Scg	struct sc_info *sc = (struct sc_info *)devinfo;
22858384Scg
22958384Scg	nm_wr(sc, 0x6c0, 0x01, 1);
230149997Snetchild#if 0
231149997Snetchild	/*
232149997Snetchild	 * The following code-line may cause a hang for some chipsets, see
233149997Snetchild	 * PR 56617.
234149997Snetchild	 * In case of a bugreport without this line have a look at the PR and
235149997Snetchild	 * conditionize the code-line based upon the specific version of
236149997Snetchild	 * the chip.
237149997Snetchild	 */
23858384Scg	nm_wr(sc, 0x6cc, 0x87, 1);
239149997Snetchild#endif
24058384Scg	nm_wr(sc, 0x6cc, 0x80, 1);
24158384Scg	nm_wr(sc, 0x6cc, 0x00, 1);
24265490Scg	return 1;
24358384Scg}
24458384Scg
24570134Scgstatic int
24670134Scgnm_rdcd(kobj_t obj, void *devinfo, int regno)
24755639Scg{
24855639Scg	struct sc_info *sc = (struct sc_info *)devinfo;
24955639Scg	u_int32_t x;
25055639Scg
25155639Scg	if (!nm_waitcd(sc)) {
25255639Scg		x = nm_rd(sc, sc->ac97_base + regno, 2);
25355639Scg		DELAY(1000);
25455639Scg		return x;
25555639Scg	} else {
25655639Scg		device_printf(sc->dev, "ac97 codec not ready\n");
25770134Scg		return -1;
25855639Scg	}
25955639Scg}
26055639Scg
26170134Scgstatic int
26270134Scgnm_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data)
26355639Scg{
26455639Scg	struct sc_info *sc = (struct sc_info *)devinfo;
26555639Scg	int cnt = 3;
26655639Scg
26755639Scg	if (!nm_waitcd(sc)) {
26855639Scg		while (cnt-- > 0) {
26955639Scg			nm_wr(sc, sc->ac97_base + regno, data, 2);
27055639Scg			if (!nm_waitcd(sc)) {
27155639Scg				DELAY(1000);
27270134Scg				return 0;
27355639Scg			}
27455639Scg		}
27555639Scg	}
27655639Scg	device_printf(sc->dev, "ac97 codec not ready\n");
27770134Scg	return -1;
27855639Scg}
27955639Scg
28070134Scgstatic kobj_method_t nm_ac97_methods[] = {
28170134Scg    	KOBJMETHOD(ac97_init,		nm_initcd),
28270134Scg    	KOBJMETHOD(ac97_read,		nm_rdcd),
28370134Scg    	KOBJMETHOD(ac97_write,		nm_wrcd),
284193640Sariff	KOBJMETHOD_END
28570134Scg};
28670134ScgAC97_DECLARE(nm_ac97);
28770134Scg
28870134Scg/* -------------------------------------------------------------------- */
28970134Scg
29055639Scgstatic void
29155639Scgnm_ackint(struct sc_info *sc, u_int32_t num)
29255639Scg{
29355639Scg	if (sc->type == NM256AV_PCI_ID) {
29455639Scg		nm_wr(sc, NM_INT_REG, num << 1, 2);
29555639Scg	} else if (sc->type == NM256ZX_PCI_ID) {
29655639Scg		nm_wr(sc, NM_INT_REG, num, 4);
29755639Scg	}
29855639Scg}
29955639Scg
30055639Scgstatic int
30155639Scgnm_loadcoeff(struct sc_info *sc, int dir, int num)
30255639Scg{
30355639Scg	int ofs, sz, i;
30455639Scg	u_int32_t addr;
30555639Scg
30655639Scg	addr = (dir == PCMDIR_PLAY)? 0x01c : 0x21c;
30755639Scg	if (dir == PCMDIR_REC)
30855639Scg		num += 8;
30955639Scg	sz = coefficientSizes[num];
31055639Scg	ofs = 0;
31155639Scg	while (num-- > 0)
31255639Scg		ofs+= coefficientSizes[num];
31355639Scg	for (i = 0; i < sz; i++)
31455639Scg		nm_wrbuf(sc, sc->cbuf + i, coefficients[ofs + i], 1);
31555639Scg	nm_wr(sc, addr, sc->cbuf, 4);
31655639Scg	if (dir == PCMDIR_PLAY)
31755639Scg		sz--;
31855639Scg	nm_wr(sc, addr + 4, sc->cbuf + sz, 4);
31955639Scg	return 0;
32055639Scg}
32155639Scg
32255639Scgstatic int
32355639Scgnm_setch(struct sc_chinfo *ch)
32455639Scg{
32555639Scg	struct sc_info *sc = ch->parent;
32655639Scg	u_int32_t base;
32755639Scg	u_int8_t x;
32855639Scg
32955639Scg	for (x = 0; x < 8; x++)
33055639Scg		if (ch->spd < (samplerates[x] + samplerates[x + 1]) / 2)
33155639Scg			break;
33255639Scg
33355639Scg	if (x == 8) return 1;
33455639Scg
33555639Scg	ch->spd = samplerates[x];
33655639Scg	nm_loadcoeff(sc, ch->dir, x);
33755639Scg
33855639Scg	x <<= 4;
33955639Scg	x &= NM_RATE_MASK;
34055639Scg	if (ch->fmt & AFMT_16BIT) x |= NM_RATE_BITS_16;
341193640Sariff	if (AFMT_CHANNEL(ch->fmt) > 1) x |= NM_RATE_STEREO;
34255639Scg
34355639Scg	base = (ch->dir == PCMDIR_PLAY)? NM_PLAYBACK_REG_OFFSET : NM_RECORD_REG_OFFSET;
34455639Scg	nm_wr(sc, base + NM_RATE_REG_OFFSET, x, 1);
34555639Scg	return 0;
34655639Scg}
34755639Scg
34855639Scg/* channel interface */
34955639Scgstatic void *
35074763Scgnmchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
35155639Scg{
35255639Scg	struct sc_info *sc = devinfo;
35355639Scg	struct sc_chinfo *ch;
35455639Scg	u_int32_t chnbuf;
35555639Scg
35655639Scg	chnbuf = (dir == PCMDIR_PLAY)? sc->pbuf : sc->rbuf;
35755639Scg	ch = (dir == PCMDIR_PLAY)? &sc->pch : &sc->rch;
35891607Sorion	ch->active = 0;
35991607Sorion	ch->blksize = 0;
36091607Sorion	ch->wmark = 0;
36155639Scg	ch->buffer = b;
36270291Scg	sndbuf_setup(ch->buffer, (u_int8_t *)rman_get_virtual(sc->buf) + chnbuf, NM_BUFFSIZE);
36355878Scg	if (bootverbose)
36455878Scg		device_printf(sc->dev, "%s buf %p\n", (dir == PCMDIR_PLAY)?
36574763Scg			      "play" : "rec", sndbuf_getbuf(ch->buffer));
36655639Scg	ch->parent = sc;
36755639Scg	ch->channel = c;
36855639Scg	ch->dir = dir;
36955639Scg	return ch;
37055639Scg}
37155639Scg
37255639Scgstatic int
37370134Scgnmchan_free(kobj_t obj, void *data)
37465340Scg{
37565340Scg	return 0;
37665340Scg}
37765340Scg
37865340Scgstatic int
37970134Scgnmchan_setformat(kobj_t obj, void *data, u_int32_t format)
38055639Scg{
38155639Scg	struct sc_chinfo *ch = data;
38255639Scg
38355639Scg	ch->fmt = format;
38455639Scg	return nm_setch(ch);
38555639Scg}
38655639Scg
387193640Sariffstatic u_int32_t
38870134Scgnmchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
38955639Scg{
39055639Scg	struct sc_chinfo *ch = data;
39155639Scg
39255639Scg	ch->spd = speed;
39355700Scg	return nm_setch(ch)? 0 : ch->spd;
39455639Scg}
39555639Scg
396193640Sariffstatic u_int32_t
39770134Scgnmchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
39855639Scg{
39991607Sorion	struct sc_chinfo *ch = data;
40091607Sorion
40191607Sorion	ch->blksize = blocksize;
40291607Sorion
40355639Scg	return blocksize;
40455639Scg}
40555639Scg
40655639Scgstatic int
40770134Scgnmchan_trigger(kobj_t obj, void *data, int go)
40855639Scg{
40955639Scg	struct sc_chinfo *ch = data;
41055639Scg	struct sc_info *sc = ch->parent;
41155639Scg	int ssz;
41255639Scg
413170521Sariff	if (!PCMTRIG_COMMON(go))
41460958Scg		return 0;
41555639Scg
41655639Scg	ssz = (ch->fmt & AFMT_16BIT)? 2 : 1;
417193640Sariff	if (AFMT_CHANNEL(ch->fmt) > 1)
41855639Scg		ssz <<= 1;
41955639Scg
42055639Scg	if (ch->dir == PCMDIR_PLAY) {
42155639Scg		if (go == PCMTRIG_START) {
42291607Sorion			ch->active = 1;
42391607Sorion			ch->wmark = ch->blksize;
42455639Scg			nm_wr(sc, NM_PBUFFER_START, sc->pbuf, 4);
42555639Scg			nm_wr(sc, NM_PBUFFER_END, sc->pbuf + NM_BUFFSIZE - ssz, 4);
42655639Scg			nm_wr(sc, NM_PBUFFER_CURRP, sc->pbuf, 4);
42791607Sorion			nm_wr(sc, NM_PBUFFER_WMARK, sc->pbuf + ch->wmark, 4);
42855639Scg			nm_wr(sc, NM_PLAYBACK_ENABLE_REG, NM_PLAYBACK_FREERUN |
42955639Scg				NM_PLAYBACK_ENABLE_FLAG, 1);
43055639Scg			nm_wr(sc, NM_AUDIO_MUTE_REG, 0, 2);
43155639Scg		} else {
43291607Sorion			ch->active = 0;
43355639Scg			nm_wr(sc, NM_PLAYBACK_ENABLE_REG, 0, 1);
43455639Scg			nm_wr(sc, NM_AUDIO_MUTE_REG, NM_AUDIO_MUTE_BOTH, 2);
43555639Scg		}
43655639Scg	} else {
43755639Scg		if (go == PCMTRIG_START) {
43891607Sorion			ch->active = 1;
43991607Sorion			ch->wmark = ch->blksize;
44055639Scg			nm_wr(sc, NM_RECORD_ENABLE_REG, NM_RECORD_FREERUN |
44155639Scg				NM_RECORD_ENABLE_FLAG, 1);
44255639Scg			nm_wr(sc, NM_RBUFFER_START, sc->rbuf, 4);
44355639Scg			nm_wr(sc, NM_RBUFFER_END, sc->rbuf + NM_BUFFSIZE, 4);
44455639Scg			nm_wr(sc, NM_RBUFFER_CURRP, sc->rbuf, 4);
44591607Sorion			nm_wr(sc, NM_RBUFFER_WMARK, sc->rbuf + ch->wmark, 4);
44655639Scg		} else {
44791607Sorion			ch->active = 0;
44855639Scg			nm_wr(sc, NM_RECORD_ENABLE_REG, 0, 1);
44955639Scg		}
45055639Scg	}
45155639Scg	return 0;
45255639Scg}
45355639Scg
454193640Sariffstatic u_int32_t
45570134Scgnmchan_getptr(kobj_t obj, void *data)
45655639Scg{
45755639Scg	struct sc_chinfo *ch = data;
45855639Scg	struct sc_info *sc = ch->parent;
45955639Scg
46055639Scg	if (ch->dir == PCMDIR_PLAY)
46155639Scg		return nm_rd(sc, NM_PBUFFER_CURRP, 4) - sc->pbuf;
46255639Scg	else
46355639Scg		return nm_rd(sc, NM_RBUFFER_CURRP, 4) - sc->rbuf;
46455639Scg}
46555639Scg
46674763Scgstatic struct pcmchan_caps *
46770134Scgnmchan_getcaps(kobj_t obj, void *data)
46855639Scg{
46955639Scg	return &nm_caps;
47055639Scg}
47155639Scg
47270134Scgstatic kobj_method_t nmchan_methods[] = {
47370134Scg    	KOBJMETHOD(channel_init,		nmchan_init),
47470134Scg    	KOBJMETHOD(channel_free,		nmchan_free),
47570134Scg    	KOBJMETHOD(channel_setformat,		nmchan_setformat),
47670134Scg    	KOBJMETHOD(channel_setspeed,		nmchan_setspeed),
47770134Scg    	KOBJMETHOD(channel_setblocksize,	nmchan_setblocksize),
47870134Scg    	KOBJMETHOD(channel_trigger,		nmchan_trigger),
47970134Scg    	KOBJMETHOD(channel_getptr,		nmchan_getptr),
48070134Scg    	KOBJMETHOD(channel_getcaps,		nmchan_getcaps),
481193640Sariff	KOBJMETHOD_END
48270134Scg};
48370134ScgCHANNEL_DECLARE(nmchan);
48470134Scg
48555639Scg/* The interrupt handler */
48655639Scgstatic void
48755639Scgnm_intr(void *p)
48855639Scg{
48955639Scg	struct sc_info *sc = (struct sc_info *)p;
49064461Scg	int status, x;
49155639Scg
49255639Scg	status = nm_rd(sc, NM_INT_REG, sc->irsz);
49364461Scg	if (status == 0)
49455639Scg		return;
49555639Scg
49655639Scg	if (status & sc->playint) {
49755639Scg		status &= ~sc->playint;
49891607Sorion		sc->pch.wmark += sc->pch.blksize;
49991607Sorion		sc->pch.wmark %= NM_BUFFSIZE;
50091607Sorion		nm_wr(sc, NM_PBUFFER_WMARK, sc->pbuf + sc->pch.wmark, 4);
50191607Sorion
50255639Scg		nm_ackint(sc, sc->playint);
50355639Scg		chn_intr(sc->pch.channel);
50455639Scg	}
50555639Scg	if (status & sc->recint) {
50655639Scg		status &= ~sc->recint;
50791607Sorion		sc->rch.wmark += sc->rch.blksize;
50891607Sorion		sc->rch.wmark %= NM_BUFFSIZE;
50991607Sorion		nm_wr(sc, NM_RBUFFER_WMARK, sc->rbuf + sc->rch.wmark, 4);
51091607Sorion
51155639Scg		nm_ackint(sc, sc->recint);
51255639Scg		chn_intr(sc->rch.channel);
51355639Scg	}
51455639Scg	if (status & sc->misc1int) {
51555639Scg		status &= ~sc->misc1int;
51655639Scg		nm_ackint(sc, sc->misc1int);
51755639Scg		x = nm_rd(sc, 0x400, 1);
51855639Scg		nm_wr(sc, 0x400, x | 2, 1);
51955639Scg	 	device_printf(sc->dev, "misc int 1\n");
52055639Scg	}
52155639Scg	if (status & sc->misc2int) {
52255639Scg		status &= ~sc->misc2int;
52355639Scg		nm_ackint(sc, sc->misc2int);
52455639Scg		x = nm_rd(sc, 0x400, 1);
52555639Scg		nm_wr(sc, 0x400, x & ~2, 1);
52655639Scg	 	device_printf(sc->dev, "misc int 2\n");
52755639Scg	}
52855639Scg	if (status) {
52964461Scg		nm_ackint(sc, status);
53055639Scg	 	device_printf(sc->dev, "unknown int\n");
53155639Scg	}
53255639Scg}
53355639Scg
53455639Scg/* -------------------------------------------------------------------- */
53555639Scg
53655639Scg/*
53755639Scg * Probe and attach the card
53855639Scg */
53955639Scg
54055639Scgstatic int
54155639Scgnm_init(struct sc_info *sc)
54255639Scg{
54355639Scg	u_int32_t ofs, i;
54455639Scg
54555639Scg	if (sc->type == NM256AV_PCI_ID) {
54655639Scg		sc->ac97_base = NM_MIXER_OFFSET;
54755639Scg		sc->ac97_status = NM_MIXER_STATUS_OFFSET;
54855639Scg		sc->ac97_busy = NM_MIXER_READY_MASK;
54955639Scg
55055639Scg		sc->buftop = 2560 * 1024;
55155639Scg
55255639Scg		sc->irsz = 2;
55355639Scg		sc->playint = NM_PLAYBACK_INT;
55455639Scg		sc->recint = NM_RECORD_INT;
55555639Scg		sc->misc1int = NM_MISC_INT_1;
55655639Scg		sc->misc2int = NM_MISC_INT_2;
55755639Scg	} else if (sc->type == NM256ZX_PCI_ID) {
55855639Scg		sc->ac97_base = NM_MIXER_OFFSET;
55955639Scg		sc->ac97_status = NM2_MIXER_STATUS_OFFSET;
56055639Scg		sc->ac97_busy = NM2_MIXER_READY_MASK;
56155639Scg
56255639Scg		sc->buftop = (nm_rd(sc, 0xa0b, 2)? 6144 : 4096) * 1024;
56355639Scg
56455639Scg		sc->irsz = 4;
56555639Scg		sc->playint = NM2_PLAYBACK_INT;
56655639Scg		sc->recint = NM2_RECORD_INT;
56755639Scg		sc->misc1int = NM2_MISC_INT_1;
56855639Scg		sc->misc2int = NM2_MISC_INT_2;
56955713Scg	} else return -1;
57055639Scg	sc->badintr = 0;
57155639Scg	ofs = sc->buftop - 0x0400;
57255639Scg	sc->buftop -= 0x1400;
57355639Scg
57491607Sorion	if (bootverbose)
57591607Sorion		device_printf(sc->dev, "buftop is 0x%08x\n", sc->buftop);
57655639Scg 	if ((nm_rdbuf(sc, ofs, 4) & NM_SIG_MASK) == NM_SIGNATURE) {
57755639Scg		i = nm_rdbuf(sc, ofs + 4, 4);
57891607Sorion		if (i != 0 && i != 0xffffffff) {
57991607Sorion			if (bootverbose)
58091607Sorion				device_printf(sc->dev, "buftop is changed to 0x%08x\n", i);
58155639Scg			sc->buftop = i;
58291607Sorion		}
58355639Scg	}
58455639Scg
58555639Scg	sc->cbuf = sc->buftop - NM_MAX_COEFFICIENT;
58655639Scg	sc->rbuf = sc->cbuf - NM_BUFFSIZE;
58755639Scg	sc->pbuf = sc->rbuf - NM_BUFFSIZE;
58855639Scg	sc->acbuf = sc->pbuf - (NM_TOTAL_COEFF_COUNT * 4);
58955639Scg
59055639Scg	nm_wr(sc, 0, 0x11, 1);
59155639Scg	nm_wr(sc, NM_RECORD_ENABLE_REG, 0, 1);
59255639Scg	nm_wr(sc, 0x214, 0, 2);
59355639Scg
59455639Scg	return 0;
59555639Scg}
59655639Scg
59755639Scgstatic int
59855639Scgnm_pci_probe(device_t dev)
59955639Scg{
60075382Sgreid	struct sc_info *sc = NULL;
60155639Scg	char *s = NULL;
602254263Sscottl	u_int32_t subdev, i;
60355639Scg
60455802Scg	subdev = (pci_get_subdevice(dev) << 16) | pci_get_subvendor(dev);
60555639Scg	switch (pci_get_devid(dev)) {
60655639Scg	case NM256AV_PCI_ID:
60755802Scg		i = 0;
60855802Scg		while ((i < NUM_BADCARDS) && (badcards[i] != subdev))
60955802Scg			i++;
61075382Sgreid
61175382Sgreid		/* Try to catch other non-ac97 cards */
61275382Sgreid
61375382Sgreid		if (i == NUM_BADCARDS) {
61478564Sgreid			if (!(sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT | M_ZERO))) {
61575382Sgreid				device_printf(dev, "cannot allocate softc\n");
61675382Sgreid				return ENXIO;
61775382Sgreid			}
61875382Sgreid
619119690Sjhb			sc->regid = PCIR_BAR(1);
620127135Snjl			sc->reg = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
621127135Snjl							 &sc->regid,
622127135Snjl							 RF_ACTIVE);
62375382Sgreid
62475382Sgreid			if (!sc->reg) {
62575382Sgreid				device_printf(dev, "unable to map register space\n");
62675382Sgreid				free(sc, M_DEVBUF);
62775382Sgreid				return ENXIO;
62875382Sgreid			}
62975382Sgreid
63091607Sorion			/*
63191607Sorion			 * My Panasonic CF-M2EV needs resetting device
63291607Sorion			 * before checking mixer is present or not.
63391607Sorion			 * t.ichinoseki@nifty.com.
63491607Sorion			 */
63591607Sorion			nm_wr(sc, 0, 0x11, 1); /* reset device */
63678362Scg			if ((nm_rd(sc, NM_MIXER_PRESENCE, 2) &
63775382Sgreid				NM_PRESENCE_MASK) != NM_PRESENCE_VALUE) {
63875382Sgreid				i = 0;	/* non-ac97 card, but not listed */
63975382Sgreid				DEB(device_printf(dev, "subdev = 0x%x - badcard?\n",
64075382Sgreid				    subdev));
64175382Sgreid			}
64275382Sgreid			bus_release_resource(dev, SYS_RES_MEMORY, sc->regid,
64375382Sgreid					     sc->reg);
64475382Sgreid			free(sc, M_DEVBUF);
64575382Sgreid		}
64675382Sgreid
64755802Scg		if (i == NUM_BADCARDS)
64855802Scg			s = "NeoMagic 256AV";
64955878Scg		DEB(else)
65055878Scg			DEB(device_printf(dev, "this is a non-ac97 NM256AV, not attaching\n"));
65175382Sgreid
65255639Scg		break;
65355639Scg
65455639Scg	case NM256ZX_PCI_ID:
65555639Scg		s = "NeoMagic 256ZX";
65655639Scg		break;
65755639Scg	}
65855639Scg
65955639Scg	if (s) device_set_desc(dev, s);
66055639Scg	return s? 0 : ENXIO;
66155639Scg}
66255639Scg
66355639Scgstatic int
66455639Scgnm_pci_attach(device_t dev)
66555639Scg{
66655639Scg	struct sc_info *sc;
66765644Scg	struct ac97_info *codec = 0;
66855639Scg	char 		status[SND_STATUSLEN];
66955639Scg
670170873Sariff	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
67155639Scg	sc->dev = dev;
67255639Scg	sc->type = pci_get_devid(dev);
67355639Scg
674254263Sscottl	pci_enable_busmaster(dev);
67555639Scg
676119690Sjhb	sc->bufid = PCIR_BAR(0);
677127135Snjl	sc->buf = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->bufid,
678127135Snjl					 RF_ACTIVE);
679119690Sjhb	sc->regid = PCIR_BAR(1);
680127135Snjl	sc->reg = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->regid,
681127135Snjl					 RF_ACTIVE);
68255639Scg
68355639Scg	if (!sc->buf || !sc->reg) {
68455639Scg		device_printf(dev, "unable to map register space\n");
68555639Scg		goto bad;
68655639Scg	}
68755639Scg
68855639Scg	if (nm_init(sc) == -1) {
68955639Scg		device_printf(dev, "unable to initialize the card\n");
69055639Scg		goto bad;
69155639Scg	}
69255639Scg
69370134Scg	codec = AC97_CREATE(dev, sc, nm_ac97);
69455639Scg	if (codec == NULL) goto bad;
69570134Scg	if (mixer_init(dev, ac97_getmixerclass(), codec) == -1) goto bad;
69655639Scg
69755639Scg	sc->irqid = 0;
698127135Snjl	sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid,
699127135Snjl					 RF_ACTIVE | RF_SHAREABLE);
70074763Scg	if (!sc->irq || snd_setup_intr(dev, sc->irq, 0, nm_intr, sc, &sc->ih)) {
70155639Scg		device_printf(dev, "unable to map interrupt\n");
70255639Scg		goto bad;
70355639Scg	}
70455639Scg
705126695Smatk	snprintf(status, SND_STATUSLEN, "at memory 0x%lx, 0x%lx irq %ld %s",
70655639Scg		 rman_get_start(sc->buf), rman_get_start(sc->reg),
707126695Smatk		 rman_get_start(sc->irq),PCM_KLDSTRING(snd_neomagic));
70855639Scg
70955639Scg	if (pcm_register(dev, sc, 1, 1)) goto bad;
71070134Scg	pcm_addchan(dev, PCMDIR_REC, &nmchan_class, sc);
71170134Scg	pcm_addchan(dev, PCMDIR_PLAY, &nmchan_class, sc);
71255639Scg	pcm_setstatus(dev, status);
71355639Scg
71455639Scg	return 0;
71555639Scg
71655639Scgbad:
71765644Scg	if (codec) ac97_destroy(codec);
71855639Scg	if (sc->buf) bus_release_resource(dev, SYS_RES_MEMORY, sc->bufid, sc->buf);
71955639Scg	if (sc->reg) bus_release_resource(dev, SYS_RES_MEMORY, sc->regid, sc->reg);
72055639Scg	if (sc->ih) bus_teardown_intr(dev, sc->irq, sc->ih);
72155639Scg	if (sc->irq) bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
72255639Scg	free(sc, M_DEVBUF);
72355639Scg	return ENXIO;
72455639Scg}
72555639Scg
72658384Scgstatic int
72765644Scgnm_pci_detach(device_t dev)
72865644Scg{
72965644Scg	int r;
73065644Scg	struct sc_info *sc;
73165644Scg
73265644Scg	r = pcm_unregister(dev);
73365644Scg	if (r)
73465644Scg		return r;
73565644Scg
73665644Scg	sc = pcm_getdevinfo(dev);
73765644Scg	bus_release_resource(dev, SYS_RES_MEMORY, sc->bufid, sc->buf);
73865644Scg	bus_release_resource(dev, SYS_RES_MEMORY, sc->regid, sc->reg);
73965644Scg	bus_teardown_intr(dev, sc->irq, sc->ih);
74065644Scg	bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
74165644Scg	free(sc, M_DEVBUF);
74265644Scg
74365644Scg	return 0;
74465644Scg}
74565644Scg
74665644Scgstatic int
74791607Sorionnm_pci_suspend(device_t dev)
74891607Sorion{
74991607Sorion	struct sc_info *sc;
75091607Sorion
75191607Sorion	sc = pcm_getdevinfo(dev);
75291607Sorion
75391607Sorion	/* stop playing */
75491607Sorion	if (sc->pch.active) {
75591607Sorion		nm_wr(sc, NM_PLAYBACK_ENABLE_REG, 0, 1);
75691607Sorion		nm_wr(sc, NM_AUDIO_MUTE_REG, NM_AUDIO_MUTE_BOTH, 2);
75791607Sorion	}
75891607Sorion	/* stop recording */
75991607Sorion	if (sc->rch.active) {
76091607Sorion		nm_wr(sc, NM_RECORD_ENABLE_REG, 0, 1);
76191607Sorion	}
76291607Sorion	return 0;
76391607Sorion}
76491607Sorion
76591607Sorionstatic int
76658384Scgnm_pci_resume(device_t dev)
76758384Scg{
76858384Scg	struct sc_info *sc;
76958384Scg
77058384Scg	sc = pcm_getdevinfo(dev);
77158384Scg
77291607Sorion	/*
77391607Sorion	 * Reinit audio device.
77491607Sorion	 * Don't call nm_init(). It would change buftop if X ran or
77591607Sorion	 * is running. This makes playing and recording buffer address
77691607Sorion	 * shift but these buffers of channel layer are not changed.
77791607Sorion	 * As a result of this inconsistency, periodic noise will be
77891607Sorion	 * generated while playing.
77991607Sorion	 */
78091607Sorion	nm_wr(sc, 0, 0x11, 1);
78191607Sorion	nm_wr(sc, 0x214, 0, 2);
78291607Sorion
78358384Scg	/* Reinit mixer */
78465340Scg    	if (mixer_reinit(dev) == -1) {
78558384Scg		device_printf(dev, "unable to reinitialize the mixer\n");
78658384Scg		return ENXIO;
78758384Scg	}
78891607Sorion	/* restart playing */
78991607Sorion	if (sc->pch.active) {
79091607Sorion		nm_wr(sc, NM_PLAYBACK_ENABLE_REG, NM_PLAYBACK_FREERUN |
79191607Sorion			  NM_PLAYBACK_ENABLE_FLAG, 1);
79291607Sorion		nm_wr(sc, NM_AUDIO_MUTE_REG, 0, 2);
79391607Sorion	}
79491607Sorion	/* restart recording */
79591607Sorion	if (sc->rch.active) {
79691607Sorion		nm_wr(sc, NM_RECORD_ENABLE_REG, NM_RECORD_FREERUN |
79791607Sorion			  NM_RECORD_ENABLE_FLAG, 1);
79891607Sorion	}
79958384Scg	return 0;
80058384Scg}
80158384Scg
80255639Scgstatic device_method_t nm_methods[] = {
80355639Scg	/* Device interface */
80455639Scg	DEVMETHOD(device_probe,		nm_pci_probe),
80555639Scg	DEVMETHOD(device_attach,	nm_pci_attach),
80666012Scg	DEVMETHOD(device_detach,	nm_pci_detach),
80791607Sorion	DEVMETHOD(device_suspend,	nm_pci_suspend),
80858384Scg	DEVMETHOD(device_resume,	nm_pci_resume),
80955639Scg	{ 0, 0 }
81055639Scg};
81155639Scg
81255639Scgstatic driver_t nm_driver = {
81355639Scg	"pcm",
81455639Scg	nm_methods,
81582180Scg	PCM_SOFTC_SIZE,
81655639Scg};
81755639Scg
81862483ScgDRIVER_MODULE(snd_neomagic, pci, nm_driver, pcm_devclass, 0, 0);
819132236StanimuraMODULE_DEPEND(snd_neomagic, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
82062483ScgMODULE_VERSION(snd_neomagic, 1);
821