cmi.c revision 93816
172016Scg/* 272016Scg * Copyright (c) 2000 Orion Hodson <O.Hodson@cs.ucl.ac.uk> 372016Scg * All rights reserved. 472016Scg * 572016Scg * Redistribution and use in source and binary forms, with or without 672016Scg * modification, are permitted provided that the following conditions 772016Scg * are met: 872016Scg * 1. Redistributions of source code must retain the above copyright 972016Scg * notice, this list of conditions and the following disclaimer. 1072016Scg * 2. Redistributions in binary form must reproduce the above copyright 1172016Scg * notice, this list of conditions and the following disclaimer in the 1272016Scg * documentation and/or other materials provided with the distribution. 1372016Scg * 1472016Scg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1572016Scg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1672016Scg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1772016Scg * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1872016Scg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1972016Scg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2072016Scg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2172016Scg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT 2272016Scg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2372016Scg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF 2472016Scg * SUCH DAMAGE. 2572016Scg * 2672016Scg * This driver exists largely as a result of other people's efforts. 2772016Scg * Much of register handling is based on NetBSD CMI8x38 audio driver 2872016Scg * by Takuya Shiozaki <AoiMoe@imou.to>. Chen-Li Tien 2972016Scg * <cltien@cmedia.com.tw> clarified points regarding the DMA related 3072016Scg * registers and the 8738 mixer devices. His Linux was driver a also 3172016Scg * useful reference point. 3273772Scg * 3378362Scg * TODO: MIDI 3472016Scg * 3572016Scg * SPDIF contributed by Gerhard Gonter <gonter@whisky.wu-wien.ac.at>. 3672016Scg * 3774994Sorion * This card/code does not always manage to sample at 44100 - actual 3874994Sorion * rate drifts slightly between recordings (usually 0-3%). No 3974994Sorion * differences visible in register dumps between times that work and 4074994Sorion * those that don't. 4172016Scg */ 4272016Scg 4372016Scg#include <dev/sound/pcm/sound.h> 4472016Scg#include <dev/sound/pci/cmireg.h> 4572016Scg#include <dev/sound/isa/sb.h> 4672016Scg 4772016Scg#include <pci/pcireg.h> 4872016Scg#include <pci/pcivar.h> 4972016Scg 5074994Sorion#include <sys/sysctl.h> 5174994Sorion 5272016Scg#include "mixer_if.h" 5372016Scg 5482180ScgSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/cmi.c 93816 2002-04-04 20:56:47Z jhb $"); 5582180Scg 5672016Scg/* Supported chip ID's */ 5772016Scg#define CMI8338A_PCI_ID 0x010013f6 5872016Scg#define CMI8338B_PCI_ID 0x010113f6 5972016Scg#define CMI8738_PCI_ID 0x011113f6 6072016Scg#define CMI8738B_PCI_ID 0x011213f6 6172016Scg 6272016Scg/* Buffer size max is 64k for permitted DMA boundaries */ 6384771Sorion#define CMI_DEFAULT_BUFSZ 16384 6472016Scg 6572016Scg/* Interrupts per length of buffer */ 6672016Scg#define CMI_INTR_PER_BUFFER 2 6772016Scg 6872016Scg/* Clarify meaning of named defines in cmireg.h */ 6972016Scg#define CMPCI_REG_DMA0_MAX_SAMPLES CMPCI_REG_DMA0_BYTES 7072016Scg#define CMPCI_REG_DMA0_INTR_SAMPLES CMPCI_REG_DMA0_SAMPLES 7172016Scg#define CMPCI_REG_DMA1_MAX_SAMPLES CMPCI_REG_DMA1_BYTES 7272016Scg#define CMPCI_REG_DMA1_INTR_SAMPLES CMPCI_REG_DMA1_SAMPLES 7372016Scg 7472016Scg/* Our indication of custom mixer control */ 7572016Scg#define CMPCI_NON_SB16_CONTROL 0xff 7672016Scg 7772016Scg/* Debugging macro's */ 7874994Sorion#undef DEB 7972016Scg#ifndef DEB 8072016Scg#define DEB(x) /* x */ 8172016Scg#endif /* DEB */ 8272016Scg 8372016Scg#ifndef DEBMIX 8472016Scg#define DEBMIX(x) /* x */ 8572016Scg#endif /* DEBMIX */ 8672016Scg 8772016Scg/* ------------------------------------------------------------------------- */ 8872016Scg/* Structures */ 8972016Scg 9074994Sorionstruct sc_info; 9172016Scg 9274994Sorionstruct sc_chinfo { 9374994Sorion struct sc_info *parent; 9474994Sorion struct pcm_channel *channel; 9574994Sorion struct snd_dbuf *buffer; 9674994Sorion u_int32_t fmt, spd, phys_buf, bps; 9774994Sorion u_int32_t dma_active:1, dma_was_active:1; 9874994Sorion int dir; 9972016Scg}; 10072016Scg 10174994Sorionstruct sc_info { 10274994Sorion device_t dev; 10373772Scg 10474994Sorion bus_space_tag_t st; 10574994Sorion bus_space_handle_t sh; 10674994Sorion bus_dma_tag_t parent_dmat; 10775174Sorion struct resource *reg, *irq; 10874994Sorion int regid, irqid; 10974994Sorion void *ih; 11083214Sgreen void *lock; 11172016Scg 11288032Sorion int spdif_enabled; 11384771Sorion unsigned int bufsz; 11474994Sorion struct sc_chinfo pch, rch; 11572016Scg}; 11672016Scg 11772016Scg/* Channel caps */ 11872016Scg 11972016Scgstatic u_int32_t cmi_fmt[] = { 12072016Scg AFMT_U8, 12172016Scg AFMT_STEREO | AFMT_U8, 12272016Scg AFMT_S16_LE, 12372016Scg AFMT_STEREO | AFMT_S16_LE, 12472016Scg 0 12572016Scg}; 12672016Scg 12774763Scgstatic struct pcmchan_caps cmi_caps = {5512, 48000, cmi_fmt, 0}; 12872016Scg 12972016Scg/* ------------------------------------------------------------------------- */ 13072016Scg/* Register Utilities */ 13172016Scg 13272016Scgstatic u_int32_t 13374994Sorioncmi_rd(struct sc_info *sc, int regno, int size) 13472016Scg{ 13572016Scg switch (size) { 13672016Scg case 1: 13774994Sorion return bus_space_read_1(sc->st, sc->sh, regno); 13872016Scg case 2: 13974994Sorion return bus_space_read_2(sc->st, sc->sh, regno); 14072016Scg case 4: 14174994Sorion return bus_space_read_4(sc->st, sc->sh, regno); 14272016Scg default: 14372016Scg DEB(printf("cmi_rd: failed 0x%04x %d\n", regno, size)); 14472016Scg return 0xFFFFFFFF; 14572016Scg } 14672016Scg} 14772016Scg 14872016Scgstatic void 14974994Sorioncmi_wr(struct sc_info *sc, int regno, u_int32_t data, int size) 15072016Scg{ 15172016Scg switch (size) { 15272016Scg case 1: 15374994Sorion bus_space_write_1(sc->st, sc->sh, regno, data); 15472016Scg break; 15572016Scg case 2: 15674994Sorion bus_space_write_2(sc->st, sc->sh, regno, data); 15772016Scg break; 15872016Scg case 4: 15974994Sorion bus_space_write_4(sc->st, sc->sh, regno, data); 16072016Scg break; 16172016Scg } 16272016Scg} 16372016Scg 16472016Scgstatic void 16578362Scgcmi_partial_wr4(struct sc_info *sc, 16672016Scg int reg, int shift, u_int32_t mask, u_int32_t val) 16772016Scg{ 16872016Scg u_int32_t r; 16972016Scg 17074994Sorion r = cmi_rd(sc, reg, 4); 17172016Scg r &= ~(mask << shift); 17272016Scg r |= val << shift; 17374994Sorion cmi_wr(sc, reg, r, 4); 17472016Scg} 17572016Scg 17672016Scgstatic void 17774994Sorioncmi_clr4(struct sc_info *sc, int reg, u_int32_t mask) 17872016Scg{ 17972016Scg u_int32_t r; 18073772Scg 18174994Sorion r = cmi_rd(sc, reg, 4); 18272016Scg r &= ~mask; 18374994Sorion cmi_wr(sc, reg, r, 4); 18472016Scg} 18572016Scg 18672016Scgstatic void 18774994Sorioncmi_set4(struct sc_info *sc, int reg, u_int32_t mask) 18872016Scg{ 18972016Scg u_int32_t r; 19072016Scg 19174994Sorion r = cmi_rd(sc, reg, 4); 19272016Scg r |= mask; 19374994Sorion cmi_wr(sc, reg, r, 4); 19472016Scg} 19572016Scg 19672016Scg/* ------------------------------------------------------------------------- */ 19772016Scg/* Rate Mapping */ 19872016Scg 19973772Scgstatic int cmi_rates[] = {5512, 8000, 11025, 16000, 20072016Scg 22050, 32000, 44100, 48000}; 20172016Scg#define NUM_CMI_RATES (sizeof(cmi_rates)/sizeof(cmi_rates[0])) 20272016Scg 20372016Scg/* cmpci_rate_to_regvalue returns sampling freq selector for FCR1 20472016Scg * register - reg order is 5k,11k,22k,44k,8k,16k,32k,48k */ 20572016Scg 20673772Scgstatic u_int32_t 20772016Scgcmpci_rate_to_regvalue(int rate) 20872016Scg{ 20972016Scg int i, r; 21073772Scg 21172016Scg for(i = 0; i < NUM_CMI_RATES - 1; i++) { 21272016Scg if (rate < ((cmi_rates[i] + cmi_rates[i + 1]) / 2)) { 21372016Scg break; 21472016Scg } 21572016Scg } 21672016Scg 21772016Scg DEB(printf("cmpci_rate_to_regvalue: %d -> %d\n", rate, cmi_rates[i])); 21872016Scg 21972016Scg r = ((i >> 1) | (i << 2)) & 0x07; 22072016Scg return r; 22172016Scg} 22272016Scg 22373772Scgstatic int 22473772Scgcmpci_regvalue_to_rate(u_int32_t r) 22572016Scg{ 22672016Scg int i; 22772016Scg 22872016Scg i = ((r << 1) | (r >> 2)) & 0x07; 22972016Scg DEB(printf("cmpci_regvalue_to_rate: %d -> %d\n", r, i)); 23072016Scg return cmi_rates[i]; 23172016Scg} 23272016Scg 23372016Scg/* ------------------------------------------------------------------------- */ 23474994Sorion/* ADC/DAC control - there are 2 dma channels on 8738, either can be 23574994Sorion * playback or capture. We use ch0 for playback and ch1 for capture. */ 23672016Scg 23772016Scgstatic void 23878362Scgcmi_dma_prog(struct sc_info *sc, struct sc_chinfo *ch, u_int32_t base) 23972016Scg{ 24078362Scg u_int32_t s, i, sz, physbuf; 24174994Sorion 24275174Sorion physbuf = vtophys(sndbuf_getbuf(ch->buffer)); 24374994Sorion 24475174Sorion cmi_wr(sc, base, physbuf, 4); 24574994Sorion sz = (u_int32_t)sndbuf_getsize(ch->buffer); 24674994Sorion 24774994Sorion s = sz / ch->bps - 1; 24875174Sorion cmi_wr(sc, base + 4, s, 2); 24974994Sorion 25074994Sorion i = sz / (ch->bps * CMI_INTR_PER_BUFFER) - 1; 25175174Sorion cmi_wr(sc, base + 6, i, 2); 25278362Scg} 25374994Sorion 25475174Sorion 25575174Sorionstatic void 25675174Sorioncmi_ch0_start(struct sc_info *sc, struct sc_chinfo *ch) 25775174Sorion{ 25875174Sorion cmi_dma_prog(sc, ch, CMPCI_REG_DMA0_BASE); 25975174Sorion 26078362Scg cmi_set4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_ENABLE); 26178362Scg cmi_set4(sc, CMPCI_REG_INTR_CTRL, 26275174Sorion CMPCI_REG_CH0_INTR_ENABLE); 26375174Sorion 26474994Sorion ch->dma_active = 1; 26572016Scg} 26672016Scg 26774994Sorionstatic u_int32_t 26874994Sorioncmi_ch0_stop(struct sc_info *sc, struct sc_chinfo *ch) 26972016Scg{ 27074994Sorion u_int32_t r = ch->dma_active; 27172016Scg 27275174Sorion cmi_clr4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE); 27378362Scg cmi_clr4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_ENABLE); 27478362Scg cmi_set4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_RESET); 27575290Sorion cmi_clr4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_RESET); 27674994Sorion ch->dma_active = 0; 27774994Sorion return r; 27872016Scg} 27972016Scg 28072016Scgstatic void 28174994Sorioncmi_ch1_start(struct sc_info *sc, struct sc_chinfo *ch) 28272016Scg{ 28375174Sorion cmi_dma_prog(sc, ch, CMPCI_REG_DMA1_BASE); 28478362Scg cmi_set4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_ENABLE); 28575174Sorion /* Enable Interrupts */ 28678362Scg cmi_set4(sc, CMPCI_REG_INTR_CTRL, 28775174Sorion CMPCI_REG_CH1_INTR_ENABLE); 28874994Sorion DEB(printf("cmi_ch1_start: dma prog\n")); 28974994Sorion ch->dma_active = 1; 29072016Scg} 29172016Scg 29274994Sorionstatic u_int32_t 29374994Sorioncmi_ch1_stop(struct sc_info *sc, struct sc_chinfo *ch) 29472016Scg{ 29574994Sorion u_int32_t r = ch->dma_active; 29672016Scg 29775174Sorion cmi_clr4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH1_INTR_ENABLE); 29878362Scg cmi_clr4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_ENABLE); 29978362Scg cmi_set4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_RESET); 30075290Sorion cmi_clr4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_RESET); 30174994Sorion ch->dma_active = 0; 30274994Sorion return r; 30372016Scg} 30472016Scg 30572016Scgstatic void 30674994Sorioncmi_spdif_speed(struct sc_info *sc, int speed) { 30772016Scg u_int32_t fcr1, lcr, mcr; 30872016Scg 30972016Scg if (speed >= 44100) { 31072016Scg fcr1 = CMPCI_REG_SPDIF0_ENABLE; 31172016Scg lcr = CMPCI_REG_XSPDIF_ENABLE; 31273772Scg mcr = (speed == 48000) ? 31372016Scg CMPCI_REG_W_SPDIF_48L | CMPCI_REG_SPDIF_48K : 0; 31472016Scg } else { 31572016Scg fcr1 = mcr = lcr = 0; 31672016Scg } 31772016Scg 31874994Sorion cmi_partial_wr4(sc, CMPCI_REG_MISC, 0, 31972016Scg CMPCI_REG_W_SPDIF_48L | CMPCI_REG_SPDIF_48K, mcr); 32074994Sorion cmi_partial_wr4(sc, CMPCI_REG_FUNC_1, 0, 32174994Sorion CMPCI_REG_SPDIF0_ENABLE, fcr1); 32274994Sorion cmi_partial_wr4(sc, CMPCI_REG_LEGACY_CTRL, 0, 32372016Scg CMPCI_REG_XSPDIF_ENABLE, lcr); 32472016Scg} 32572016Scg 32672016Scg/* ------------------------------------------------------------------------- */ 32772016Scg/* Channel Interface implementation */ 32872016Scg 32972016Scgstatic void * 33078362Scgcmichan_init(kobj_t obj, void *devinfo, 33174994Sorion struct snd_dbuf *b, struct pcm_channel *c, int dir) 33272016Scg{ 33374994Sorion struct sc_info *sc = devinfo; 33474994Sorion struct sc_chinfo *ch = (dir == PCMDIR_PLAY) ? &sc->pch : &sc->rch; 33572016Scg 33674994Sorion ch->parent = sc; 33774994Sorion ch->channel = c; 33874994Sorion ch->bps = 1; 33974994Sorion ch->fmt = AFMT_U8; 34074994Sorion ch->spd = DSP_DEFAULT_SPEED; 34174994Sorion ch->buffer = b; 34274994Sorion ch->dma_active = 0; 34384771Sorion if (sndbuf_alloc(ch->buffer, sc->parent_dmat, sc->bufsz) != 0) { 34472016Scg DEB(printf("cmichan_init failed\n")); 34572016Scg return NULL; 34672016Scg } 34772016Scg 34872016Scg ch->dir = dir; 34983214Sgreen snd_mtxlock(sc->lock); 35075174Sorion if (ch->dir == PCMDIR_PLAY) { 35175174Sorion cmi_dma_prog(sc, ch, CMPCI_REG_DMA0_BASE); 35272016Scg } else { 35375174Sorion cmi_dma_prog(sc, ch, CMPCI_REG_DMA1_BASE); 35472016Scg } 35583214Sgreen snd_mtxunlock(sc->lock); 35672016Scg 35772016Scg return ch; 35872016Scg} 35972016Scg 36073772Scgstatic int 36173772Scgcmichan_setformat(kobj_t obj, void *data, u_int32_t format) 36272016Scg{ 36374994Sorion struct sc_chinfo *ch = data; 36483214Sgreen struct sc_info *sc = ch->parent; 36572016Scg u_int32_t f; 36672016Scg 36772016Scg if (format & AFMT_S16_LE) { 36872016Scg f = CMPCI_REG_FORMAT_16BIT; 36972016Scg ch->bps = 2; 37072016Scg } else { 37172016Scg f = CMPCI_REG_FORMAT_8BIT; 37272016Scg ch->bps = 1; 37372016Scg } 37472016Scg 37572016Scg if (format & AFMT_STEREO) { 37672016Scg f |= CMPCI_REG_FORMAT_STEREO; 37772016Scg ch->bps *= 2; 37872016Scg } else { 37972016Scg f |= CMPCI_REG_FORMAT_MONO; 38072016Scg } 38172016Scg 38283214Sgreen snd_mtxlock(sc->lock); 38372016Scg if (ch->dir == PCMDIR_PLAY) { 38472016Scg cmi_partial_wr4(ch->parent, 38572016Scg CMPCI_REG_CHANNEL_FORMAT, 38672016Scg CMPCI_REG_CH0_FORMAT_SHIFT, 38772016Scg CMPCI_REG_CH0_FORMAT_MASK, 38872016Scg f); 38972016Scg } else { 39072016Scg cmi_partial_wr4(ch->parent, 39172016Scg CMPCI_REG_CHANNEL_FORMAT, 39272016Scg CMPCI_REG_CH1_FORMAT_SHIFT, 39372016Scg CMPCI_REG_CH1_FORMAT_MASK, 39472016Scg f); 39572016Scg } 39683214Sgreen snd_mtxunlock(sc->lock); 39773772Scg ch->fmt = format; 39872016Scg 39972016Scg return 0; 40072016Scg} 40172016Scg 40273772Scgstatic int 40372016Scgcmichan_setspeed(kobj_t obj, void *data, u_int32_t speed) 40473772Scg{ 40574994Sorion struct sc_chinfo *ch = data; 40683214Sgreen struct sc_info *sc = ch->parent; 40772016Scg u_int32_t r, rsp; 40872016Scg 40972016Scg r = cmpci_rate_to_regvalue(speed); 41083214Sgreen snd_mtxlock(sc->lock); 41172016Scg if (ch->dir == PCMDIR_PLAY) { 41288032Sorion if (speed < 44100) { 41388032Sorion /* disable if req before rate change */ 41472016Scg cmi_spdif_speed(ch->parent, speed); 41588032Sorion } 41672016Scg cmi_partial_wr4(ch->parent, 41772016Scg CMPCI_REG_FUNC_1, 41872016Scg CMPCI_REG_DAC_FS_SHIFT, 41972016Scg CMPCI_REG_DAC_FS_MASK, 42072016Scg r); 42188032Sorion if (speed >= 44100 && ch->parent->spdif_enabled) { 42288032Sorion /* enable if req after rate change */ 42372016Scg cmi_spdif_speed(ch->parent, speed); 42488032Sorion } 42572016Scg rsp = cmi_rd(ch->parent, CMPCI_REG_FUNC_1, 4); 42672016Scg rsp >>= CMPCI_REG_DAC_FS_SHIFT; 42772016Scg rsp &= CMPCI_REG_DAC_FS_MASK; 42872016Scg } else { 42972016Scg cmi_partial_wr4(ch->parent, 43072016Scg CMPCI_REG_FUNC_1, 43172016Scg CMPCI_REG_ADC_FS_SHIFT, 43272016Scg CMPCI_REG_ADC_FS_MASK, 43372016Scg r); 43472016Scg rsp = cmi_rd(ch->parent, CMPCI_REG_FUNC_1, 4); 43572016Scg rsp >>= CMPCI_REG_ADC_FS_SHIFT; 43672016Scg rsp &= CMPCI_REG_ADC_FS_MASK; 43772016Scg } 43883214Sgreen snd_mtxunlock(sc->lock); 43972016Scg ch->spd = cmpci_regvalue_to_rate(r); 44072016Scg 44173772Scg DEB(printf("cmichan_setspeed (%s) %d -> %d (%d)\n", 44272016Scg (ch->dir == PCMDIR_PLAY) ? "play" : "rec", 44372016Scg speed, ch->spd, cmpci_regvalue_to_rate(rsp))); 44472016Scg 44572016Scg return ch->spd; 44672016Scg} 44772016Scg 44872016Scgstatic int 44972016Scgcmichan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 45072016Scg{ 45174994Sorion struct sc_chinfo *ch = data; 45284771Sorion struct sc_info *sc = ch->parent; 45372016Scg 45472016Scg /* user has requested interrupts every blocksize bytes */ 45584771Sorion if (blocksize > sc->bufsz / CMI_INTR_PER_BUFFER) { 45684771Sorion blocksize = sc->bufsz / CMI_INTR_PER_BUFFER; 45772016Scg } 45872016Scg sndbuf_resize(ch->buffer, CMI_INTR_PER_BUFFER, blocksize); 45972016Scg 46082834Sorion return blocksize; 46172016Scg} 46272016Scg 46372016Scgstatic int 46472016Scgcmichan_trigger(kobj_t obj, void *data, int go) 46572016Scg{ 46674994Sorion struct sc_chinfo *ch = data; 46774994Sorion struct sc_info *sc = ch->parent; 46872016Scg 46983214Sgreen snd_mtxlock(sc->lock); 47072016Scg if (ch->dir == PCMDIR_PLAY) { 47172016Scg switch(go) { 47272016Scg case PCMTRIG_START: 47374994Sorion cmi_ch0_start(sc, ch); 47472016Scg break; 47572016Scg case PCMTRIG_ABORT: 47674994Sorion cmi_ch0_stop(sc, ch); 47772016Scg break; 47872016Scg } 47973772Scg } else { 48072016Scg switch(go) { 48172016Scg case PCMTRIG_START: 48274994Sorion cmi_ch1_start(sc, ch); 48372016Scg break; 48472016Scg case PCMTRIG_ABORT: 48574994Sorion cmi_ch1_stop(sc, ch); 48672016Scg break; 48772016Scg } 48872016Scg } 48983214Sgreen snd_mtxunlock(sc->lock); 49072016Scg return 0; 49172016Scg} 49272016Scg 49372016Scgstatic int 49472016Scgcmichan_getptr(kobj_t obj, void *data) 49572016Scg{ 49674994Sorion struct sc_chinfo *ch = data; 49774994Sorion struct sc_info *sc = ch->parent; 49872016Scg u_int32_t physptr, bufptr, sz; 49972016Scg 50083214Sgreen snd_mtxlock(sc->lock); 50172016Scg if (ch->dir == PCMDIR_PLAY) { 50274994Sorion physptr = cmi_rd(sc, CMPCI_REG_DMA0_BASE, 4); 50372016Scg } else { 50474994Sorion physptr = cmi_rd(sc, CMPCI_REG_DMA1_BASE, 4); 50572016Scg } 50683214Sgreen snd_mtxunlock(sc->lock); 50773772Scg 50872016Scg sz = sndbuf_getsize(ch->buffer); 50974994Sorion bufptr = (physptr - ch->phys_buf + sz - ch->bps) % sz; 51072016Scg 51172016Scg return bufptr; 51272016Scg} 51372016Scg 51473772Scgstatic void 51573772Scgcmi_intr(void *data) 51672016Scg{ 51774994Sorion struct sc_info *sc = data; 51872016Scg u_int32_t intrstat; 51972016Scg 52083214Sgreen snd_mtxlock(sc->lock); 52174994Sorion intrstat = cmi_rd(sc, CMPCI_REG_INTR_STATUS, 4); 52272016Scg if ((intrstat & CMPCI_REG_ANY_INTR) == 0) { 52383214Sgreen goto out; 52472016Scg } 52572016Scg 52672016Scg /* Disable interrupts */ 52772016Scg if (intrstat & CMPCI_REG_CH0_INTR) { 52874994Sorion cmi_clr4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE); 52972016Scg } 53072016Scg 53172016Scg if (intrstat & CMPCI_REG_CH1_INTR) { 53274994Sorion cmi_clr4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH1_INTR_ENABLE); 53372016Scg } 53472016Scg 53572016Scg /* Signal interrupts to channel */ 53672016Scg if (intrstat & CMPCI_REG_CH0_INTR) { 53774994Sorion chn_intr(sc->pch.channel); 53872016Scg } 53972016Scg 54072016Scg if (intrstat & CMPCI_REG_CH1_INTR) { 54174994Sorion chn_intr(sc->rch.channel); 54272016Scg } 54373772Scg 54472016Scg /* Enable interrupts */ 54572016Scg if (intrstat & CMPCI_REG_CH0_INTR) { 54674994Sorion cmi_set4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE); 54772016Scg } 54872016Scg 54972016Scg if (intrstat & CMPCI_REG_CH1_INTR) { 55074994Sorion cmi_set4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH1_INTR_ENABLE); 55172016Scg } 55272016Scg 55383214Sgreenout: 55483214Sgreen snd_mtxunlock(sc->lock); 55572016Scg return; 55672016Scg} 55772016Scg 55874763Scgstatic struct pcmchan_caps * 55972016Scgcmichan_getcaps(kobj_t obj, void *data) 56072016Scg{ 56172016Scg return &cmi_caps; 56272016Scg} 56372016Scg 56472016Scgstatic kobj_method_t cmichan_methods[] = { 56572016Scg KOBJMETHOD(channel_init, cmichan_init), 56672016Scg KOBJMETHOD(channel_setformat, cmichan_setformat), 56772016Scg KOBJMETHOD(channel_setspeed, cmichan_setspeed), 56872016Scg KOBJMETHOD(channel_setblocksize, cmichan_setblocksize), 56972016Scg KOBJMETHOD(channel_trigger, cmichan_trigger), 57072016Scg KOBJMETHOD(channel_getptr, cmichan_getptr), 57172016Scg KOBJMETHOD(channel_getcaps, cmichan_getcaps), 57272016Scg { 0, 0 } 57372016Scg}; 57472016ScgCHANNEL_DECLARE(cmichan); 57572016Scg 57672016Scg/* ------------------------------------------------------------------------- */ 57772016Scg/* Mixer - sb16 with kinks */ 57872016Scg 57973772Scgstatic void 58074994Sorioncmimix_wr(struct sc_info *sc, u_int8_t port, u_int8_t val) 58172016Scg{ 58274994Sorion cmi_wr(sc, CMPCI_REG_SBADDR, port, 1); 58374994Sorion cmi_wr(sc, CMPCI_REG_SBDATA, val, 1); 58472016Scg} 58572016Scg 58673772Scgstatic u_int8_t 58774994Sorioncmimix_rd(struct sc_info *sc, u_int8_t port) 58872016Scg{ 58974994Sorion cmi_wr(sc, CMPCI_REG_SBADDR, port, 1); 59074994Sorion return (u_int8_t)cmi_rd(sc, CMPCI_REG_SBDATA, 1); 59172016Scg} 59272016Scg 59372016Scgstruct sb16props { 59472016Scg u_int8_t rreg; /* right reg chan register */ 59572016Scg u_int8_t stereo:1; /* (no explanation needed, honest) */ 59672016Scg u_int8_t rec:1; /* recording source */ 59772016Scg u_int8_t bits:3; /* num bits to represent maximum gain rep */ 59872016Scg u_int8_t oselect; /* output select mask */ 59972016Scg u_int8_t iselect; /* right input select mask */ 60072016Scg} static const cmt[SOUND_MIXER_NRDEVICES] = { 60173772Scg [SOUND_MIXER_SYNTH] = {CMPCI_SB16_MIXER_FM_R, 1, 1, 5, 60272016Scg CMPCI_SB16_SW_FM, CMPCI_SB16_MIXER_FM_SRC_R}, 60372016Scg [SOUND_MIXER_CD] = {CMPCI_SB16_MIXER_CDDA_R, 1, 1, 5, 60472016Scg CMPCI_SB16_SW_CD, CMPCI_SB16_MIXER_CD_SRC_R}, 60572016Scg [SOUND_MIXER_LINE] = {CMPCI_SB16_MIXER_LINE_R, 1, 1, 5, 60672016Scg CMPCI_SB16_SW_LINE, CMPCI_SB16_MIXER_LINE_SRC_R}, 60773772Scg [SOUND_MIXER_MIC] = {CMPCI_SB16_MIXER_MIC, 0, 1, 5, 60872016Scg CMPCI_SB16_SW_MIC, CMPCI_SB16_MIXER_MIC_SRC}, 60972016Scg [SOUND_MIXER_SPEAKER] = {CMPCI_SB16_MIXER_SPEAKER, 0, 0, 2, 0, 0}, 61072016Scg [SOUND_MIXER_PCM] = {CMPCI_SB16_MIXER_VOICE_R, 1, 0, 5, 0, 0}, 61172016Scg [SOUND_MIXER_VOLUME] = {CMPCI_SB16_MIXER_MASTER_R, 1, 0, 5, 0, 0}, 61272016Scg /* These controls are not implemented in CMI8738, but maybe at a 61372016Scg future date. They are not documented in C-Media documentation, 61472016Scg though appear in other drivers for future h/w (ALSA, Linux, NetBSD). 61572016Scg */ 61673772Scg [SOUND_MIXER_IGAIN] = {CMPCI_SB16_MIXER_INGAIN_R, 1, 0, 2, 0, 0}, 61773772Scg [SOUND_MIXER_OGAIN] = {CMPCI_SB16_MIXER_OUTGAIN_R, 1, 0, 2, 0, 0}, 61873772Scg [SOUND_MIXER_BASS] = {CMPCI_SB16_MIXER_BASS_R, 1, 0, 4, 0, 0}, 61973772Scg [SOUND_MIXER_TREBLE] = {CMPCI_SB16_MIXER_TREBLE_R, 1, 0, 4, 0, 0}, 62074994Sorion /* The mic pre-amp is implemented with non-SB16 compatible 62174994Sorion registers. */ 62272016Scg [SOUND_MIXER_MONITOR] = {CMPCI_NON_SB16_CONTROL, 0, 1, 4, 0}, 62372016Scg}; 62472016Scg 62572016Scg#define MIXER_GAIN_REG_RTOL(r) (r - 1) 62672016Scg 62772016Scgstatic int 62874763Scgcmimix_init(struct snd_mixer *m) 62972016Scg{ 63074994Sorion struct sc_info *sc = mix_getdevinfo(m); 63174994Sorion u_int32_t i,v; 63272016Scg 63374994Sorion for(i = v = 0; i < SOUND_MIXER_NRDEVICES; i++) { 63472016Scg if (cmt[i].bits) v |= 1 << i; 63572016Scg } 63672016Scg mix_setdevs(m, v); 63774994Sorion 63874994Sorion for(i = v = 0; i < SOUND_MIXER_NRDEVICES; i++) { 63974994Sorion if (cmt[i].rec) v |= 1 << i; 64072016Scg } 64172016Scg mix_setrecdevs(m, v); 64272016Scg 64374994Sorion cmimix_wr(sc, CMPCI_SB16_MIXER_RESET, 0); 64474994Sorion cmimix_wr(sc, CMPCI_SB16_MIXER_ADCMIX_L, 0); 64574994Sorion cmimix_wr(sc, CMPCI_SB16_MIXER_ADCMIX_R, 0); 64674994Sorion cmimix_wr(sc, CMPCI_SB16_MIXER_OUTMIX, 64772016Scg CMPCI_SB16_SW_CD | CMPCI_SB16_SW_MIC | CMPCI_SB16_SW_LINE); 64872016Scg return 0; 64972016Scg} 65072016Scg 65172016Scgstatic int 65274763Scgcmimix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 65372016Scg{ 65474994Sorion struct sc_info *sc = mix_getdevinfo(m); 65572016Scg u_int32_t r, l, max; 65672016Scg u_int8_t v; 65772016Scg 65872016Scg max = (1 << cmt[dev].bits) - 1; 65972016Scg 66072016Scg if (cmt[dev].rreg == CMPCI_NON_SB16_CONTROL) { 66174994Sorion /* For time being this can only be one thing (mic in 66274994Sorion * mic/aux reg) */ 66374994Sorion v = cmi_rd(sc, CMPCI_REG_AUX_MIC, 1) & 0xf0; 66472016Scg l = left * max / 100; 66574994Sorion /* 3 bit gain with LSB MICGAIN off(1),on(1) -> 4 bit value */ 66673772Scg v |= ((l << 1) | (~l >> 3)) & 0x0f; 66774994Sorion cmi_wr(sc, CMPCI_REG_AUX_MIC, v, 1); 66872016Scg return 0; 66972016Scg } 67072016Scg 67172016Scg l = (left * max / 100) << (8 - cmt[dev].bits); 67272016Scg if (cmt[dev].stereo) { 67372016Scg r = (right * max / 100) << (8 - cmt[dev].bits); 67474994Sorion cmimix_wr(sc, MIXER_GAIN_REG_RTOL(cmt[dev].rreg), l); 67574994Sorion cmimix_wr(sc, cmt[dev].rreg, r); 67672016Scg DEBMIX(printf("Mixer stereo write dev %d reg 0x%02x "\ 67772016Scg "value 0x%02x:0x%02x\n", 67872016Scg dev, MIXER_GAIN_REG_RTOL(cmt[dev].rreg), l, r)); 67972016Scg } else { 68072016Scg r = l; 68174994Sorion cmimix_wr(sc, cmt[dev].rreg, l); 68272016Scg DEBMIX(printf("Mixer mono write dev %d reg 0x%02x " \ 68372016Scg "value 0x%02x:0x%02x\n", 68472016Scg dev, cmt[dev].rreg, l, l)); 68572016Scg } 68672016Scg 68772016Scg /* Zero gain does not mute channel from output, but this does... */ 68874994Sorion v = cmimix_rd(sc, CMPCI_SB16_MIXER_OUTMIX); 68972016Scg if (l == 0 && r == 0) { 69072016Scg v &= ~cmt[dev].oselect; 69172016Scg } else { 69272016Scg v |= cmt[dev].oselect; 69372016Scg } 69474994Sorion cmimix_wr(sc, CMPCI_SB16_MIXER_OUTMIX, v); 69572016Scg 69672016Scg return 0; 69772016Scg} 69872016Scg 69972016Scgstatic int 70074763Scgcmimix_setrecsrc(struct snd_mixer *m, u_int32_t src) 70172016Scg{ 70274994Sorion struct sc_info *sc = mix_getdevinfo(m); 70372016Scg u_int32_t i, ml, sl; 70472016Scg 70572016Scg ml = sl = 0; 70672016Scg for(i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 70772016Scg if ((1<<i) & src) { 70872016Scg if (cmt[i].stereo) { 70972016Scg sl |= cmt[i].iselect; 71072016Scg } else { 71172016Scg ml |= cmt[i].iselect; 71272016Scg } 71372016Scg } 71472016Scg } 71574994Sorion cmimix_wr(sc, CMPCI_SB16_MIXER_ADCMIX_R, sl|ml); 71672016Scg DEBMIX(printf("cmimix_setrecsrc: reg 0x%02x val 0x%02x\n", 71773772Scg CMPCI_SB16_MIXER_ADCMIX_R, sl|ml)); 71872016Scg ml = CMPCI_SB16_MIXER_SRC_R_TO_L(ml); 71974994Sorion cmimix_wr(sc, CMPCI_SB16_MIXER_ADCMIX_L, sl|ml); 72073772Scg DEBMIX(printf("cmimix_setrecsrc: reg 0x%02x val 0x%02x\n", 72173772Scg CMPCI_SB16_MIXER_ADCMIX_L, sl|ml)); 72272016Scg 72372016Scg return src; 72472016Scg} 72572016Scg 72688032Sorion/* Optional SPDIF support. */ 72788032Sorion 72888032Sorionstatic int 72988032Sorioncmi_initsys(struct sc_info* sc) 73088032Sorion{ 73188032Sorion#ifdef SND_DYNSYSCTL 73288032Sorion SYSCTL_ADD_INT(snd_sysctl_tree(sc->dev), 73388032Sorion SYSCTL_CHILDREN(snd_sysctl_tree_top(sc->dev)), 73488032Sorion OID_AUTO, "spdif_enabled", CTLFLAG_RW, 73588032Sorion &sc->spdif_enabled, 0, 73688032Sorion "enable SPDIF output at 44.1 kHz and above"); 73788032Sorion#endif /* SND_DYNSYSCTL */ 73888032Sorion return 0; 73988032Sorion} 74088032Sorion 74188032Sorion/* ------------------------------------------------------------------------- */ 74272016Scgstatic kobj_method_t cmi_mixer_methods[] = { 74372016Scg KOBJMETHOD(mixer_init, cmimix_init), 74472016Scg KOBJMETHOD(mixer_set, cmimix_set), 74572016Scg KOBJMETHOD(mixer_setrecsrc, cmimix_setrecsrc), 74672016Scg { 0, 0 } 74772016Scg}; 74872016ScgMIXER_DECLARE(cmi_mixer); 74972016Scg 75072016Scg/* ------------------------------------------------------------------------- */ 75172016Scg/* Power and reset */ 75272016Scg 75372016Scgstatic void 75474994Sorioncmi_power(struct sc_info *sc, int state) 75572016Scg{ 75672016Scg switch (state) { 75772016Scg case 0: /* full power */ 75874994Sorion cmi_clr4(sc, CMPCI_REG_MISC, CMPCI_REG_POWER_DOWN); 75972016Scg break; 76072016Scg default: 76172016Scg /* power off */ 76274994Sorion cmi_set4(sc, CMPCI_REG_MISC, CMPCI_REG_POWER_DOWN); 76372016Scg break; 76472016Scg } 76572016Scg} 76672016Scg 76774994Sorionstatic int 76874994Sorioncmi_init(struct sc_info *sc) 76974994Sorion{ 77074994Sorion /* Effect reset */ 77174994Sorion cmi_set4(sc, CMPCI_REG_MISC, CMPCI_REG_BUS_AND_DSP_RESET); 77274994Sorion DELAY(100); 77374994Sorion cmi_clr4(sc, CMPCI_REG_MISC, CMPCI_REG_BUS_AND_DSP_RESET); 77474994Sorion 77574994Sorion /* Disable interrupts and channels */ 77674994Sorion cmi_clr4(sc, CMPCI_REG_FUNC_0, 77774994Sorion CMPCI_REG_CH0_ENABLE | CMPCI_REG_CH1_ENABLE); 77875174Sorion cmi_clr4(sc, CMPCI_REG_INTR_CTRL, 77975174Sorion CMPCI_REG_CH0_INTR_ENABLE | CMPCI_REG_CH1_INTR_ENABLE); 78074994Sorion 78175174Sorion /* Configure DMA channels, ch0 = play, ch1 = capture */ 78278362Scg cmi_clr4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_DIR); 78378362Scg cmi_set4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_DIR); 78475174Sorion 78574994Sorion /* Attempt to enable 4 Channel output */ 78678362Scg cmi_set4(sc, CMPCI_REG_MISC, CMPCI_REG_N4SPK3D); 78774994Sorion 78874994Sorion /* Disable SPDIF1 - not compatible with config */ 78974994Sorion cmi_clr4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_SPDIF1_ENABLE); 79074994Sorion cmi_clr4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_SPDIF_LOOP); 79174994Sorion 79274994Sorion return 0; 79378362Scg} 79474994Sorion 79574994Sorionstatic void 79674994Sorioncmi_uninit(struct sc_info *sc) 79774994Sorion{ 79874994Sorion /* Disable interrupts and channels */ 79974994Sorion cmi_clr4(sc, CMPCI_REG_INTR_CTRL, 80074994Sorion CMPCI_REG_CH0_INTR_ENABLE | 80174994Sorion CMPCI_REG_CH1_INTR_ENABLE | 80274994Sorion CMPCI_REG_TDMA_INTR_ENABLE); 80374994Sorion cmi_clr4(sc, CMPCI_REG_FUNC_0, 80474994Sorion CMPCI_REG_CH0_ENABLE | CMPCI_REG_CH1_ENABLE); 80574994Sorion} 80674994Sorion 80772016Scg/* ------------------------------------------------------------------------- */ 80872016Scg/* Bus and device registration */ 80972016Scgstatic int 81072016Scgcmi_probe(device_t dev) 81172016Scg{ 81272016Scg switch(pci_get_devid(dev)) { 81372016Scg case CMI8338A_PCI_ID: 81472016Scg device_set_desc(dev, "CMedia CMI8338A"); 81572016Scg return 0; 81672016Scg case CMI8338B_PCI_ID: 81772016Scg device_set_desc(dev, "CMedia CMI8338B"); 81872016Scg return 0; 81972016Scg case CMI8738_PCI_ID: 82072016Scg device_set_desc(dev, "CMedia CMI8738"); 82172016Scg return 0; 82272016Scg case CMI8738B_PCI_ID: 82372016Scg device_set_desc(dev, "CMedia CMI8738B"); 82472016Scg return 0; 82572016Scg default: 82672016Scg return ENXIO; 82772016Scg } 82872016Scg} 82972016Scg 83073772Scgstatic int 83172016Scgcmi_attach(device_t dev) 83272016Scg{ 83374994Sorion struct snddev_info *d; 83474994Sorion struct sc_info *sc; 83574994Sorion u_int32_t data; 83674994Sorion char status[SND_STATUSLEN]; 83772016Scg 83872016Scg d = device_get_softc(dev); 83978564Sgreid sc = malloc(sizeof(struct sc_info), M_DEVBUF, M_NOWAIT | M_ZERO); 84074994Sorion if (sc == NULL) { 84172016Scg device_printf(dev, "cannot allocate softc\n"); 84272016Scg return ENXIO; 84372016Scg } 84473772Scg 84593816Sjhb sc->lock = snd_mtxcreate(device_get_nameunit(dev), "sound softc"); 84672016Scg data = pci_read_config(dev, PCIR_COMMAND, 2); 84772016Scg data |= (PCIM_CMD_PORTEN|PCIM_CMD_BUSMASTEREN); 84872016Scg pci_write_config(dev, PCIR_COMMAND, data, 2); 84972016Scg data = pci_read_config(dev, PCIR_COMMAND, 2); 85072016Scg 85188032Sorion sc->dev = dev; 85274994Sorion sc->regid = PCIR_MAPS; 85374994Sorion sc->reg = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->regid, 85472016Scg 0, BUS_SPACE_UNRESTRICTED, 1, RF_ACTIVE); 85574994Sorion if (!sc->reg) { 85672016Scg device_printf(dev, "cmi_attach: Cannot allocate bus resource\n"); 85772016Scg goto bad; 85872016Scg } 85974994Sorion sc->st = rman_get_bustag(sc->reg); 86074994Sorion sc->sh = rman_get_bushandle(sc->reg); 86172016Scg 86274994Sorion sc->irqid = 0; 86374994Sorion sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irqid, 86472016Scg 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); 86574994Sorion if (!sc->irq || 86683214Sgreen snd_setup_intr(dev, sc->irq, INTR_MPSAFE, cmi_intr, sc, &sc->ih)) { 86772016Scg device_printf(dev, "cmi_attach: Unable to map interrupt\n"); 86872016Scg goto bad; 86972016Scg } 87073772Scg 87184771Sorion sc->bufsz = pcm_getbuffersize(dev, 4096, CMI_DEFAULT_BUFSZ, 65536); 87284771Sorion 87372016Scg if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, 87472016Scg /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 87572016Scg /*highaddr*/BUS_SPACE_MAXADDR, 87672016Scg /*filter*/NULL, /*filterarg*/NULL, 87784771Sorion /*maxsize*/sc->bufsz, /*nsegments*/1, 87873772Scg /*maxsegz*/0x3ffff, /*flags*/0, 87974994Sorion &sc->parent_dmat) != 0) { 88072016Scg device_printf(dev, "cmi_attach: Unable to create dma tag\n"); 88172016Scg goto bad; 88272016Scg } 88372016Scg 88474994Sorion cmi_power(sc, 0); 88575174Sorion if (cmi_init(sc)) 88675174Sorion goto bad; 88772016Scg 88874994Sorion if (mixer_init(dev, &cmi_mixer_class, sc)) 88972016Scg goto bad; 89072016Scg 89174994Sorion if (pcm_register(dev, sc, 1, 1)) 89273772Scg goto bad; 89373772Scg 89488032Sorion cmi_initsys(sc); 89588032Sorion 89674994Sorion pcm_addchan(dev, PCMDIR_PLAY, &cmichan_class, sc); 89774994Sorion pcm_addchan(dev, PCMDIR_REC, &cmichan_class, sc); 89872016Scg 89972016Scg snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld", 90074994Sorion rman_get_start(sc->reg), rman_get_start(sc->irq)); 90172016Scg pcm_setstatus(dev, status); 90272016Scg 90372016Scg DEB(printf("cmi_attach: succeeded\n")); 90472016Scg return 0; 90573772Scg 90672016Scg bad: 90778362Scg if (sc->parent_dmat) 90874994Sorion bus_dma_tag_destroy(sc->parent_dmat); 90978362Scg if (sc->ih) 91074994Sorion bus_teardown_intr(dev, sc->irq, sc->ih); 91178362Scg if (sc->irq) 91274994Sorion bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 91378362Scg if (sc->reg) 91474994Sorion bus_release_resource(dev, SYS_RES_IOPORT, sc->regid, sc->reg); 91583214Sgreen if (sc->lock) 91683214Sgreen snd_mtxfree(sc->lock); 91778362Scg if (sc) 91874994Sorion free(sc, M_DEVBUF); 91972016Scg 92072016Scg return ENXIO; 92172016Scg} 92272016Scg 92372016Scgstatic int 92472016Scgcmi_detach(device_t dev) 92572016Scg{ 92674994Sorion struct sc_info *sc; 92772016Scg int r; 92872016Scg 92972016Scg r = pcm_unregister(dev); 93072016Scg if (r) return r; 93172016Scg 93274994Sorion sc = pcm_getdevinfo(dev); 93374994Sorion cmi_uninit(sc); 93474994Sorion cmi_power(sc, 3); 93572016Scg 93674994Sorion bus_dma_tag_destroy(sc->parent_dmat); 93774994Sorion bus_teardown_intr(dev, sc->irq, sc->ih); 93874994Sorion bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 93974994Sorion bus_release_resource(dev, SYS_RES_IOPORT, sc->regid, sc->reg); 94083214Sgreen snd_mtxfree(sc->lock); 94174994Sorion free(sc, M_DEVBUF); 94274994Sorion 94372016Scg return 0; 94472016Scg} 94572016Scg 94674994Sorionstatic int 94774994Sorioncmi_suspend(device_t dev) 94874994Sorion{ 94974994Sorion struct sc_info *sc = pcm_getdevinfo(dev); 95074994Sorion 95183214Sgreen snd_mtxlock(sc->lock); 95274994Sorion sc->pch.dma_was_active = cmi_ch0_stop(sc, &sc->pch); 95374994Sorion sc->rch.dma_was_active = cmi_ch1_stop(sc, &sc->rch); 95474994Sorion cmi_power(sc, 3); 95583214Sgreen snd_mtxunlock(sc->lock); 95674994Sorion return 0; 95774994Sorion} 95874994Sorion 95974994Sorionstatic int 96074994Sorioncmi_resume(device_t dev) 96174994Sorion{ 96274994Sorion struct sc_info *sc = pcm_getdevinfo(dev); 96374994Sorion 96483214Sgreen snd_mtxlock(sc->lock); 96574994Sorion cmi_power(sc, 0); 96674994Sorion if (cmi_init(sc) != 0) { 96774994Sorion device_printf(dev, "unable to reinitialize the card\n"); 96883214Sgreen snd_mtxunlock(sc->lock); 96974994Sorion return ENXIO; 97074994Sorion } 97174994Sorion 97274994Sorion if (mixer_reinit(dev) == -1) { 97374994Sorion device_printf(dev, "unable to reinitialize the mixer\n"); 97483214Sgreen snd_mtxunlock(sc->lock); 97574994Sorion return ENXIO; 97678362Scg } 97774994Sorion 97874994Sorion if (sc->pch.dma_was_active) { 97974994Sorion cmichan_setspeed(NULL, &sc->pch, sc->pch.spd); 98074994Sorion cmichan_setformat(NULL, &sc->pch, sc->pch.fmt); 98174994Sorion cmi_ch0_start(sc, &sc->pch); 98274994Sorion } 98374994Sorion 98474994Sorion if (sc->rch.dma_was_active) { 98574994Sorion cmichan_setspeed(NULL, &sc->rch, sc->rch.spd); 98674994Sorion cmichan_setformat(NULL, &sc->rch, sc->rch.fmt); 98774994Sorion cmi_ch1_start(sc, &sc->rch); 98874994Sorion } 98983214Sgreen snd_mtxunlock(sc->lock); 99074994Sorion return 0; 99174994Sorion} 99274994Sorion 99372016Scgstatic device_method_t cmi_methods[] = { 99472016Scg DEVMETHOD(device_probe, cmi_probe), 99572016Scg DEVMETHOD(device_attach, cmi_attach), 99672016Scg DEVMETHOD(device_detach, cmi_detach), 99774994Sorion DEVMETHOD(device_resume, cmi_resume), 99874994Sorion DEVMETHOD(device_suspend, cmi_suspend), 99972016Scg { 0, 0 } 100072016Scg}; 100172016Scg 100272016Scgstatic driver_t cmi_driver = { 100372016Scg "pcm", 100472016Scg cmi_methods, 100582180Scg PCM_SOFTC_SIZE 100672016Scg}; 100772016Scg 100885440SjhbDRIVER_MODULE(snd_cmi, pci, cmi_driver, pcm_devclass, 0, 0); 100985440SjhbMODULE_DEPEND(snd_cmi, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); 101085440SjhbMODULE_VERSION(snd_cmi, 1); 1011