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