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