cmi.c revision 159732
1139749Simp/*- 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 30108533Sschweikh * registers and the 8738 mixer devices. His Linux driver was also a 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 47119287Simp#include <dev/pci/pcireg.h> 48119287Simp#include <dev/pci/pcivar.h> 4972016Scg 5074994Sorion#include <sys/sysctl.h> 51158980Snetchild#include <dev/sound/midi/mpu401.h> 5274994Sorion 5372016Scg#include "mixer_if.h" 54158980Snetchild#include "mpufoi_if.h" 5572016Scg 5682180ScgSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/cmi.c 159732 2006-06-18 14:14:41Z netchild $"); 5782180Scg 5872016Scg/* Supported chip ID's */ 5972016Scg#define CMI8338A_PCI_ID 0x010013f6 6072016Scg#define CMI8338B_PCI_ID 0x010113f6 6172016Scg#define CMI8738_PCI_ID 0x011113f6 6272016Scg#define CMI8738B_PCI_ID 0x011213f6 6372016Scg 6472016Scg/* Buffer size max is 64k for permitted DMA boundaries */ 6584771Sorion#define CMI_DEFAULT_BUFSZ 16384 6672016Scg 6772016Scg/* Interrupts per length of buffer */ 6872016Scg#define CMI_INTR_PER_BUFFER 2 6972016Scg 7072016Scg/* Clarify meaning of named defines in cmireg.h */ 7172016Scg#define CMPCI_REG_DMA0_MAX_SAMPLES CMPCI_REG_DMA0_BYTES 7272016Scg#define CMPCI_REG_DMA0_INTR_SAMPLES CMPCI_REG_DMA0_SAMPLES 7372016Scg#define CMPCI_REG_DMA1_MAX_SAMPLES CMPCI_REG_DMA1_BYTES 7472016Scg#define CMPCI_REG_DMA1_INTR_SAMPLES CMPCI_REG_DMA1_SAMPLES 7572016Scg 7672016Scg/* Our indication of custom mixer control */ 7772016Scg#define CMPCI_NON_SB16_CONTROL 0xff 7872016Scg 7972016Scg/* Debugging macro's */ 8074994Sorion#undef DEB 8172016Scg#ifndef DEB 8272016Scg#define DEB(x) /* x */ 8372016Scg#endif /* DEB */ 8472016Scg 8572016Scg#ifndef DEBMIX 8672016Scg#define DEBMIX(x) /* x */ 8772016Scg#endif /* DEBMIX */ 8872016Scg 8972016Scg/* ------------------------------------------------------------------------- */ 9072016Scg/* Structures */ 9172016Scg 9274994Sorionstruct sc_info; 9372016Scg 9474994Sorionstruct sc_chinfo { 9574994Sorion struct sc_info *parent; 9674994Sorion struct pcm_channel *channel; 9774994Sorion struct snd_dbuf *buffer; 9874994Sorion u_int32_t fmt, spd, phys_buf, bps; 9974994Sorion u_int32_t dma_active:1, dma_was_active:1; 10074994Sorion int dir; 10172016Scg}; 10272016Scg 10374994Sorionstruct sc_info { 10474994Sorion device_t dev; 10573772Scg 10674994Sorion bus_space_tag_t st; 10774994Sorion bus_space_handle_t sh; 10874994Sorion bus_dma_tag_t parent_dmat; 10975174Sorion struct resource *reg, *irq; 11074994Sorion int regid, irqid; 11174994Sorion void *ih; 112107285Scg struct mtx *lock; 11372016Scg 11488032Sorion int spdif_enabled; 11584771Sorion unsigned int bufsz; 11674994Sorion struct sc_chinfo pch, rch; 117158980Snetchild 118158980Snetchild struct mpu401 *mpu; 119158980Snetchild mpu401_intr_t *mpu_intr; 120158980Snetchild struct resource *mpu_reg; 121158980Snetchild int mpu_regid; 122158980Snetchild bus_space_tag_t mpu_bt; 123158980Snetchild bus_space_handle_t mpu_bh; 12472016Scg}; 12572016Scg 12672016Scg/* Channel caps */ 12772016Scg 12872016Scgstatic u_int32_t cmi_fmt[] = { 12972016Scg AFMT_U8, 13072016Scg AFMT_STEREO | AFMT_U8, 13172016Scg AFMT_S16_LE, 13272016Scg AFMT_STEREO | AFMT_S16_LE, 13372016Scg 0 13472016Scg}; 13572016Scg 13674763Scgstatic struct pcmchan_caps cmi_caps = {5512, 48000, cmi_fmt, 0}; 13772016Scg 13872016Scg/* ------------------------------------------------------------------------- */ 13972016Scg/* Register Utilities */ 14072016Scg 14172016Scgstatic u_int32_t 14274994Sorioncmi_rd(struct sc_info *sc, int regno, int size) 14372016Scg{ 14472016Scg switch (size) { 14572016Scg case 1: 14674994Sorion return bus_space_read_1(sc->st, sc->sh, regno); 14772016Scg case 2: 14874994Sorion return bus_space_read_2(sc->st, sc->sh, regno); 14972016Scg case 4: 15074994Sorion return bus_space_read_4(sc->st, sc->sh, regno); 15172016Scg default: 15272016Scg DEB(printf("cmi_rd: failed 0x%04x %d\n", regno, size)); 15372016Scg return 0xFFFFFFFF; 15472016Scg } 15572016Scg} 15672016Scg 15772016Scgstatic void 15874994Sorioncmi_wr(struct sc_info *sc, int regno, u_int32_t data, int size) 15972016Scg{ 16072016Scg switch (size) { 16172016Scg case 1: 16274994Sorion bus_space_write_1(sc->st, sc->sh, regno, data); 16372016Scg break; 16472016Scg case 2: 16574994Sorion bus_space_write_2(sc->st, sc->sh, regno, data); 16672016Scg break; 16772016Scg case 4: 16874994Sorion bus_space_write_4(sc->st, sc->sh, regno, data); 16972016Scg break; 17072016Scg } 17172016Scg} 17272016Scg 17372016Scgstatic void 17478362Scgcmi_partial_wr4(struct sc_info *sc, 17572016Scg int reg, int shift, u_int32_t mask, u_int32_t val) 17672016Scg{ 17772016Scg u_int32_t r; 17872016Scg 17974994Sorion r = cmi_rd(sc, reg, 4); 18072016Scg r &= ~(mask << shift); 18172016Scg r |= val << shift; 18274994Sorion cmi_wr(sc, reg, r, 4); 18372016Scg} 18472016Scg 18572016Scgstatic void 18674994Sorioncmi_clr4(struct sc_info *sc, int reg, u_int32_t mask) 18772016Scg{ 18872016Scg u_int32_t r; 18973772Scg 19074994Sorion r = cmi_rd(sc, reg, 4); 19172016Scg r &= ~mask; 19274994Sorion cmi_wr(sc, reg, r, 4); 19372016Scg} 19472016Scg 19572016Scgstatic void 19674994Sorioncmi_set4(struct sc_info *sc, int reg, u_int32_t mask) 19772016Scg{ 19872016Scg u_int32_t r; 19972016Scg 20074994Sorion r = cmi_rd(sc, reg, 4); 20172016Scg r |= mask; 20274994Sorion cmi_wr(sc, reg, r, 4); 20372016Scg} 20472016Scg 20572016Scg/* ------------------------------------------------------------------------- */ 20672016Scg/* Rate Mapping */ 20772016Scg 20873772Scgstatic int cmi_rates[] = {5512, 8000, 11025, 16000, 20972016Scg 22050, 32000, 44100, 48000}; 21072016Scg#define NUM_CMI_RATES (sizeof(cmi_rates)/sizeof(cmi_rates[0])) 21172016Scg 21272016Scg/* cmpci_rate_to_regvalue returns sampling freq selector for FCR1 21372016Scg * register - reg order is 5k,11k,22k,44k,8k,16k,32k,48k */ 21472016Scg 21573772Scgstatic u_int32_t 21672016Scgcmpci_rate_to_regvalue(int rate) 21772016Scg{ 21872016Scg int i, r; 21973772Scg 22072016Scg for(i = 0; i < NUM_CMI_RATES - 1; i++) { 22172016Scg if (rate < ((cmi_rates[i] + cmi_rates[i + 1]) / 2)) { 22272016Scg break; 22372016Scg } 22472016Scg } 22572016Scg 22672016Scg DEB(printf("cmpci_rate_to_regvalue: %d -> %d\n", rate, cmi_rates[i])); 22772016Scg 22872016Scg r = ((i >> 1) | (i << 2)) & 0x07; 22972016Scg return r; 23072016Scg} 23172016Scg 23273772Scgstatic int 23373772Scgcmpci_regvalue_to_rate(u_int32_t r) 23472016Scg{ 23572016Scg int i; 23672016Scg 23772016Scg i = ((r << 1) | (r >> 2)) & 0x07; 23872016Scg DEB(printf("cmpci_regvalue_to_rate: %d -> %d\n", r, i)); 23972016Scg return cmi_rates[i]; 24072016Scg} 24172016Scg 24272016Scg/* ------------------------------------------------------------------------- */ 24374994Sorion/* ADC/DAC control - there are 2 dma channels on 8738, either can be 24474994Sorion * playback or capture. We use ch0 for playback and ch1 for capture. */ 24572016Scg 24672016Scgstatic void 24778362Scgcmi_dma_prog(struct sc_info *sc, struct sc_chinfo *ch, u_int32_t base) 24872016Scg{ 249102328Sorion u_int32_t s, i, sz; 25074994Sorion 251111183Scognet ch->phys_buf = sndbuf_getbufaddr(ch->buffer); 25274994Sorion 253102328Sorion cmi_wr(sc, base, ch->phys_buf, 4); 25474994Sorion sz = (u_int32_t)sndbuf_getsize(ch->buffer); 25574994Sorion 25674994Sorion s = sz / ch->bps - 1; 25775174Sorion cmi_wr(sc, base + 4, s, 2); 25874994Sorion 25974994Sorion i = sz / (ch->bps * CMI_INTR_PER_BUFFER) - 1; 26075174Sorion cmi_wr(sc, base + 6, i, 2); 26178362Scg} 26274994Sorion 26375174Sorion 26475174Sorionstatic void 26575174Sorioncmi_ch0_start(struct sc_info *sc, struct sc_chinfo *ch) 26675174Sorion{ 26775174Sorion cmi_dma_prog(sc, ch, CMPCI_REG_DMA0_BASE); 26875174Sorion 26978362Scg cmi_set4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_ENABLE); 27078362Scg cmi_set4(sc, CMPCI_REG_INTR_CTRL, 27175174Sorion CMPCI_REG_CH0_INTR_ENABLE); 27275174Sorion 27374994Sorion ch->dma_active = 1; 27472016Scg} 27572016Scg 27674994Sorionstatic u_int32_t 27774994Sorioncmi_ch0_stop(struct sc_info *sc, struct sc_chinfo *ch) 27872016Scg{ 27974994Sorion u_int32_t r = ch->dma_active; 28072016Scg 28175174Sorion cmi_clr4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE); 28278362Scg cmi_clr4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_ENABLE); 28378362Scg cmi_set4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_RESET); 28475290Sorion cmi_clr4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_RESET); 28574994Sorion ch->dma_active = 0; 28674994Sorion return r; 28772016Scg} 28872016Scg 28972016Scgstatic void 29074994Sorioncmi_ch1_start(struct sc_info *sc, struct sc_chinfo *ch) 29172016Scg{ 29275174Sorion cmi_dma_prog(sc, ch, CMPCI_REG_DMA1_BASE); 29378362Scg cmi_set4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_ENABLE); 29475174Sorion /* Enable Interrupts */ 29578362Scg cmi_set4(sc, CMPCI_REG_INTR_CTRL, 29675174Sorion CMPCI_REG_CH1_INTR_ENABLE); 29774994Sorion DEB(printf("cmi_ch1_start: dma prog\n")); 29874994Sorion ch->dma_active = 1; 29972016Scg} 30072016Scg 30174994Sorionstatic u_int32_t 30274994Sorioncmi_ch1_stop(struct sc_info *sc, struct sc_chinfo *ch) 30372016Scg{ 30474994Sorion u_int32_t r = ch->dma_active; 30572016Scg 30675174Sorion cmi_clr4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH1_INTR_ENABLE); 30778362Scg cmi_clr4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_ENABLE); 30878362Scg cmi_set4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_RESET); 30975290Sorion cmi_clr4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_RESET); 31074994Sorion ch->dma_active = 0; 31174994Sorion return r; 31272016Scg} 31372016Scg 31472016Scgstatic void 31574994Sorioncmi_spdif_speed(struct sc_info *sc, int speed) { 31672016Scg u_int32_t fcr1, lcr, mcr; 31772016Scg 31872016Scg if (speed >= 44100) { 31972016Scg fcr1 = CMPCI_REG_SPDIF0_ENABLE; 32072016Scg lcr = CMPCI_REG_XSPDIF_ENABLE; 32173772Scg mcr = (speed == 48000) ? 32272016Scg CMPCI_REG_W_SPDIF_48L | CMPCI_REG_SPDIF_48K : 0; 32372016Scg } else { 32472016Scg fcr1 = mcr = lcr = 0; 32572016Scg } 32672016Scg 32774994Sorion cmi_partial_wr4(sc, CMPCI_REG_MISC, 0, 32872016Scg CMPCI_REG_W_SPDIF_48L | CMPCI_REG_SPDIF_48K, mcr); 32974994Sorion cmi_partial_wr4(sc, CMPCI_REG_FUNC_1, 0, 33074994Sorion CMPCI_REG_SPDIF0_ENABLE, fcr1); 33174994Sorion cmi_partial_wr4(sc, CMPCI_REG_LEGACY_CTRL, 0, 33272016Scg CMPCI_REG_XSPDIF_ENABLE, lcr); 33372016Scg} 33472016Scg 33572016Scg/* ------------------------------------------------------------------------- */ 33672016Scg/* Channel Interface implementation */ 33772016Scg 33872016Scgstatic void * 33978362Scgcmichan_init(kobj_t obj, void *devinfo, 34074994Sorion struct snd_dbuf *b, struct pcm_channel *c, int dir) 34172016Scg{ 34274994Sorion struct sc_info *sc = devinfo; 34374994Sorion struct sc_chinfo *ch = (dir == PCMDIR_PLAY) ? &sc->pch : &sc->rch; 34472016Scg 34574994Sorion ch->parent = sc; 34674994Sorion ch->channel = c; 34774994Sorion ch->bps = 1; 34874994Sorion ch->fmt = AFMT_U8; 34974994Sorion ch->spd = DSP_DEFAULT_SPEED; 35074994Sorion ch->buffer = b; 35174994Sorion ch->dma_active = 0; 35284771Sorion if (sndbuf_alloc(ch->buffer, sc->parent_dmat, sc->bufsz) != 0) { 35372016Scg DEB(printf("cmichan_init failed\n")); 35472016Scg return NULL; 35572016Scg } 35672016Scg 35772016Scg ch->dir = dir; 35883214Sgreen snd_mtxlock(sc->lock); 35975174Sorion if (ch->dir == PCMDIR_PLAY) { 36075174Sorion cmi_dma_prog(sc, ch, CMPCI_REG_DMA0_BASE); 36172016Scg } else { 36275174Sorion cmi_dma_prog(sc, ch, CMPCI_REG_DMA1_BASE); 36372016Scg } 36483214Sgreen snd_mtxunlock(sc->lock); 36572016Scg 36672016Scg return ch; 36772016Scg} 36872016Scg 36973772Scgstatic int 37073772Scgcmichan_setformat(kobj_t obj, void *data, u_int32_t format) 37172016Scg{ 37274994Sorion struct sc_chinfo *ch = data; 37383214Sgreen struct sc_info *sc = ch->parent; 37472016Scg u_int32_t f; 37572016Scg 37672016Scg if (format & AFMT_S16_LE) { 37772016Scg f = CMPCI_REG_FORMAT_16BIT; 37872016Scg ch->bps = 2; 37972016Scg } else { 38072016Scg f = CMPCI_REG_FORMAT_8BIT; 38172016Scg ch->bps = 1; 38272016Scg } 38372016Scg 38472016Scg if (format & AFMT_STEREO) { 38572016Scg f |= CMPCI_REG_FORMAT_STEREO; 38672016Scg ch->bps *= 2; 38772016Scg } else { 38872016Scg f |= CMPCI_REG_FORMAT_MONO; 38972016Scg } 39072016Scg 39183214Sgreen snd_mtxlock(sc->lock); 39272016Scg if (ch->dir == PCMDIR_PLAY) { 39372016Scg cmi_partial_wr4(ch->parent, 39472016Scg CMPCI_REG_CHANNEL_FORMAT, 39572016Scg CMPCI_REG_CH0_FORMAT_SHIFT, 39672016Scg CMPCI_REG_CH0_FORMAT_MASK, 39772016Scg f); 39872016Scg } else { 39972016Scg cmi_partial_wr4(ch->parent, 40072016Scg CMPCI_REG_CHANNEL_FORMAT, 40172016Scg CMPCI_REG_CH1_FORMAT_SHIFT, 40272016Scg CMPCI_REG_CH1_FORMAT_MASK, 40372016Scg f); 40472016Scg } 40583214Sgreen snd_mtxunlock(sc->lock); 40673772Scg ch->fmt = format; 40772016Scg 40872016Scg return 0; 40972016Scg} 41072016Scg 41173772Scgstatic int 41272016Scgcmichan_setspeed(kobj_t obj, void *data, u_int32_t speed) 41373772Scg{ 41474994Sorion struct sc_chinfo *ch = data; 41583214Sgreen struct sc_info *sc = ch->parent; 41672016Scg u_int32_t r, rsp; 41772016Scg 41872016Scg r = cmpci_rate_to_regvalue(speed); 41983214Sgreen snd_mtxlock(sc->lock); 42072016Scg if (ch->dir == PCMDIR_PLAY) { 42188032Sorion if (speed < 44100) { 42288032Sorion /* disable if req before rate change */ 42372016Scg cmi_spdif_speed(ch->parent, speed); 42488032Sorion } 42572016Scg cmi_partial_wr4(ch->parent, 42672016Scg CMPCI_REG_FUNC_1, 42772016Scg CMPCI_REG_DAC_FS_SHIFT, 42872016Scg CMPCI_REG_DAC_FS_MASK, 42972016Scg r); 43088032Sorion if (speed >= 44100 && ch->parent->spdif_enabled) { 43188032Sorion /* enable if req after rate change */ 43272016Scg cmi_spdif_speed(ch->parent, speed); 43388032Sorion } 43472016Scg rsp = cmi_rd(ch->parent, CMPCI_REG_FUNC_1, 4); 43572016Scg rsp >>= CMPCI_REG_DAC_FS_SHIFT; 43672016Scg rsp &= CMPCI_REG_DAC_FS_MASK; 43772016Scg } else { 43872016Scg cmi_partial_wr4(ch->parent, 43972016Scg CMPCI_REG_FUNC_1, 44072016Scg CMPCI_REG_ADC_FS_SHIFT, 44172016Scg CMPCI_REG_ADC_FS_MASK, 44272016Scg r); 44372016Scg rsp = cmi_rd(ch->parent, CMPCI_REG_FUNC_1, 4); 44472016Scg rsp >>= CMPCI_REG_ADC_FS_SHIFT; 44572016Scg rsp &= CMPCI_REG_ADC_FS_MASK; 44672016Scg } 44783214Sgreen snd_mtxunlock(sc->lock); 44872016Scg ch->spd = cmpci_regvalue_to_rate(r); 44972016Scg 45073772Scg DEB(printf("cmichan_setspeed (%s) %d -> %d (%d)\n", 45172016Scg (ch->dir == PCMDIR_PLAY) ? "play" : "rec", 45272016Scg speed, ch->spd, cmpci_regvalue_to_rate(rsp))); 45372016Scg 45472016Scg return ch->spd; 45572016Scg} 45672016Scg 45772016Scgstatic int 45872016Scgcmichan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 45972016Scg{ 46074994Sorion struct sc_chinfo *ch = data; 46184771Sorion struct sc_info *sc = ch->parent; 46272016Scg 46372016Scg /* user has requested interrupts every blocksize bytes */ 46484771Sorion if (blocksize > sc->bufsz / CMI_INTR_PER_BUFFER) { 46584771Sorion blocksize = sc->bufsz / CMI_INTR_PER_BUFFER; 46672016Scg } 46772016Scg sndbuf_resize(ch->buffer, CMI_INTR_PER_BUFFER, blocksize); 46872016Scg 46982834Sorion return blocksize; 47072016Scg} 47172016Scg 47272016Scgstatic int 47372016Scgcmichan_trigger(kobj_t obj, void *data, int go) 47472016Scg{ 47574994Sorion struct sc_chinfo *ch = data; 47674994Sorion struct sc_info *sc = ch->parent; 47772016Scg 47883214Sgreen snd_mtxlock(sc->lock); 47972016Scg if (ch->dir == PCMDIR_PLAY) { 48072016Scg switch(go) { 48172016Scg case PCMTRIG_START: 48274994Sorion cmi_ch0_start(sc, ch); 48372016Scg break; 48472016Scg case PCMTRIG_ABORT: 48574994Sorion cmi_ch0_stop(sc, ch); 48672016Scg break; 48772016Scg } 48873772Scg } else { 48972016Scg switch(go) { 49072016Scg case PCMTRIG_START: 49174994Sorion cmi_ch1_start(sc, ch); 49272016Scg break; 49372016Scg case PCMTRIG_ABORT: 49474994Sorion cmi_ch1_stop(sc, ch); 49572016Scg break; 49672016Scg } 49772016Scg } 49883214Sgreen snd_mtxunlock(sc->lock); 49972016Scg return 0; 50072016Scg} 50172016Scg 50272016Scgstatic int 50372016Scgcmichan_getptr(kobj_t obj, void *data) 50472016Scg{ 50574994Sorion struct sc_chinfo *ch = data; 50674994Sorion struct sc_info *sc = ch->parent; 50772016Scg u_int32_t physptr, bufptr, sz; 50872016Scg 50983214Sgreen snd_mtxlock(sc->lock); 51072016Scg if (ch->dir == PCMDIR_PLAY) { 51174994Sorion physptr = cmi_rd(sc, CMPCI_REG_DMA0_BASE, 4); 51272016Scg } else { 51374994Sorion physptr = cmi_rd(sc, CMPCI_REG_DMA1_BASE, 4); 51472016Scg } 51583214Sgreen snd_mtxunlock(sc->lock); 51673772Scg 51772016Scg sz = sndbuf_getsize(ch->buffer); 51874994Sorion bufptr = (physptr - ch->phys_buf + sz - ch->bps) % sz; 51972016Scg 52072016Scg return bufptr; 52172016Scg} 52272016Scg 52373772Scgstatic void 52473772Scgcmi_intr(void *data) 52572016Scg{ 52674994Sorion struct sc_info *sc = data; 52772016Scg u_int32_t intrstat; 528122461Sscottl u_int32_t toclear; 52972016Scg 53083214Sgreen snd_mtxlock(sc->lock); 53174994Sorion intrstat = cmi_rd(sc, CMPCI_REG_INTR_STATUS, 4); 532122461Sscottl if ((intrstat & CMPCI_REG_ANY_INTR) != 0) { 53372016Scg 534122461Sscottl toclear = 0; 535122461Sscottl if (intrstat & CMPCI_REG_CH0_INTR) { 536122461Sscottl toclear |= CMPCI_REG_CH0_INTR_ENABLE; 537122461Sscottl //cmi_clr4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE); 538122461Sscottl } 53972016Scg 540122461Sscottl if (intrstat & CMPCI_REG_CH1_INTR) { 541122461Sscottl toclear |= CMPCI_REG_CH1_INTR_ENABLE; 542122461Sscottl //cmi_clr4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH1_INTR_ENABLE); 543122461Sscottl } 54472016Scg 545122461Sscottl if (toclear) { 546122461Sscottl cmi_clr4(sc, CMPCI_REG_INTR_CTRL, toclear); 547122461Sscottl snd_mtxunlock(sc->lock); 54872016Scg 549122461Sscottl /* Signal interrupts to channel */ 550122461Sscottl if (intrstat & CMPCI_REG_CH0_INTR) { 551122461Sscottl chn_intr(sc->pch.channel); 552122461Sscottl } 55373772Scg 554122461Sscottl if (intrstat & CMPCI_REG_CH1_INTR) { 555122461Sscottl chn_intr(sc->rch.channel); 556122461Sscottl } 55772016Scg 558122461Sscottl snd_mtxlock(sc->lock); 559122461Sscottl cmi_set4(sc, CMPCI_REG_INTR_CTRL, toclear); 560122461Sscottl 561122461Sscottl } 56272016Scg } 563158980Snetchild if(sc->mpu_intr) { 564158980Snetchild (sc->mpu_intr)(sc->mpu); 565158980Snetchild } 56683214Sgreen snd_mtxunlock(sc->lock); 56772016Scg return; 56872016Scg} 56972016Scg 57074763Scgstatic struct pcmchan_caps * 57172016Scgcmichan_getcaps(kobj_t obj, void *data) 57272016Scg{ 57372016Scg return &cmi_caps; 57472016Scg} 57572016Scg 57672016Scgstatic kobj_method_t cmichan_methods[] = { 57772016Scg KOBJMETHOD(channel_init, cmichan_init), 57872016Scg KOBJMETHOD(channel_setformat, cmichan_setformat), 57972016Scg KOBJMETHOD(channel_setspeed, cmichan_setspeed), 58072016Scg KOBJMETHOD(channel_setblocksize, cmichan_setblocksize), 58172016Scg KOBJMETHOD(channel_trigger, cmichan_trigger), 58272016Scg KOBJMETHOD(channel_getptr, cmichan_getptr), 58372016Scg KOBJMETHOD(channel_getcaps, cmichan_getcaps), 58472016Scg { 0, 0 } 58572016Scg}; 58672016ScgCHANNEL_DECLARE(cmichan); 58772016Scg 58872016Scg/* ------------------------------------------------------------------------- */ 58972016Scg/* Mixer - sb16 with kinks */ 59072016Scg 59173772Scgstatic void 59274994Sorioncmimix_wr(struct sc_info *sc, u_int8_t port, u_int8_t val) 59372016Scg{ 59474994Sorion cmi_wr(sc, CMPCI_REG_SBADDR, port, 1); 59574994Sorion cmi_wr(sc, CMPCI_REG_SBDATA, val, 1); 59672016Scg} 59772016Scg 59873772Scgstatic u_int8_t 59974994Sorioncmimix_rd(struct sc_info *sc, u_int8_t port) 60072016Scg{ 60174994Sorion cmi_wr(sc, CMPCI_REG_SBADDR, port, 1); 60274994Sorion return (u_int8_t)cmi_rd(sc, CMPCI_REG_SBDATA, 1); 60372016Scg} 60472016Scg 60572016Scgstruct sb16props { 60672016Scg u_int8_t rreg; /* right reg chan register */ 60772016Scg u_int8_t stereo:1; /* (no explanation needed, honest) */ 60872016Scg u_int8_t rec:1; /* recording source */ 60972016Scg u_int8_t bits:3; /* num bits to represent maximum gain rep */ 61072016Scg u_int8_t oselect; /* output select mask */ 61172016Scg u_int8_t iselect; /* right input select mask */ 61272016Scg} static const cmt[SOUND_MIXER_NRDEVICES] = { 61373772Scg [SOUND_MIXER_SYNTH] = {CMPCI_SB16_MIXER_FM_R, 1, 1, 5, 61472016Scg CMPCI_SB16_SW_FM, CMPCI_SB16_MIXER_FM_SRC_R}, 61572016Scg [SOUND_MIXER_CD] = {CMPCI_SB16_MIXER_CDDA_R, 1, 1, 5, 61672016Scg CMPCI_SB16_SW_CD, CMPCI_SB16_MIXER_CD_SRC_R}, 61772016Scg [SOUND_MIXER_LINE] = {CMPCI_SB16_MIXER_LINE_R, 1, 1, 5, 61872016Scg CMPCI_SB16_SW_LINE, CMPCI_SB16_MIXER_LINE_SRC_R}, 61973772Scg [SOUND_MIXER_MIC] = {CMPCI_SB16_MIXER_MIC, 0, 1, 5, 62072016Scg CMPCI_SB16_SW_MIC, CMPCI_SB16_MIXER_MIC_SRC}, 62172016Scg [SOUND_MIXER_SPEAKER] = {CMPCI_SB16_MIXER_SPEAKER, 0, 0, 2, 0, 0}, 62272016Scg [SOUND_MIXER_PCM] = {CMPCI_SB16_MIXER_VOICE_R, 1, 0, 5, 0, 0}, 62372016Scg [SOUND_MIXER_VOLUME] = {CMPCI_SB16_MIXER_MASTER_R, 1, 0, 5, 0, 0}, 62472016Scg /* These controls are not implemented in CMI8738, but maybe at a 62572016Scg future date. They are not documented in C-Media documentation, 62672016Scg though appear in other drivers for future h/w (ALSA, Linux, NetBSD). 62772016Scg */ 62873772Scg [SOUND_MIXER_IGAIN] = {CMPCI_SB16_MIXER_INGAIN_R, 1, 0, 2, 0, 0}, 62973772Scg [SOUND_MIXER_OGAIN] = {CMPCI_SB16_MIXER_OUTGAIN_R, 1, 0, 2, 0, 0}, 63073772Scg [SOUND_MIXER_BASS] = {CMPCI_SB16_MIXER_BASS_R, 1, 0, 4, 0, 0}, 63173772Scg [SOUND_MIXER_TREBLE] = {CMPCI_SB16_MIXER_TREBLE_R, 1, 0, 4, 0, 0}, 63274994Sorion /* The mic pre-amp is implemented with non-SB16 compatible 63374994Sorion registers. */ 63472016Scg [SOUND_MIXER_MONITOR] = {CMPCI_NON_SB16_CONTROL, 0, 1, 4, 0}, 63572016Scg}; 63672016Scg 63772016Scg#define MIXER_GAIN_REG_RTOL(r) (r - 1) 63872016Scg 63972016Scgstatic int 64074763Scgcmimix_init(struct snd_mixer *m) 64172016Scg{ 64274994Sorion struct sc_info *sc = mix_getdevinfo(m); 64374994Sorion u_int32_t i,v; 64472016Scg 64574994Sorion for(i = v = 0; i < SOUND_MIXER_NRDEVICES; i++) { 64672016Scg if (cmt[i].bits) v |= 1 << i; 64772016Scg } 64872016Scg mix_setdevs(m, v); 64974994Sorion 65074994Sorion for(i = v = 0; i < SOUND_MIXER_NRDEVICES; i++) { 65174994Sorion if (cmt[i].rec) v |= 1 << i; 65272016Scg } 65372016Scg mix_setrecdevs(m, v); 65472016Scg 65574994Sorion cmimix_wr(sc, CMPCI_SB16_MIXER_RESET, 0); 65674994Sorion cmimix_wr(sc, CMPCI_SB16_MIXER_ADCMIX_L, 0); 65774994Sorion cmimix_wr(sc, CMPCI_SB16_MIXER_ADCMIX_R, 0); 65874994Sorion cmimix_wr(sc, CMPCI_SB16_MIXER_OUTMIX, 65972016Scg CMPCI_SB16_SW_CD | CMPCI_SB16_SW_MIC | CMPCI_SB16_SW_LINE); 66072016Scg return 0; 66172016Scg} 66272016Scg 66372016Scgstatic int 66474763Scgcmimix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 66572016Scg{ 66674994Sorion struct sc_info *sc = mix_getdevinfo(m); 66772016Scg u_int32_t r, l, max; 66872016Scg u_int8_t v; 66972016Scg 67072016Scg max = (1 << cmt[dev].bits) - 1; 67172016Scg 67272016Scg if (cmt[dev].rreg == CMPCI_NON_SB16_CONTROL) { 67374994Sorion /* For time being this can only be one thing (mic in 67474994Sorion * mic/aux reg) */ 67574994Sorion v = cmi_rd(sc, CMPCI_REG_AUX_MIC, 1) & 0xf0; 67672016Scg l = left * max / 100; 67774994Sorion /* 3 bit gain with LSB MICGAIN off(1),on(1) -> 4 bit value */ 67873772Scg v |= ((l << 1) | (~l >> 3)) & 0x0f; 67974994Sorion cmi_wr(sc, CMPCI_REG_AUX_MIC, v, 1); 68072016Scg return 0; 68172016Scg } 68272016Scg 68372016Scg l = (left * max / 100) << (8 - cmt[dev].bits); 68472016Scg if (cmt[dev].stereo) { 68572016Scg r = (right * max / 100) << (8 - cmt[dev].bits); 68674994Sorion cmimix_wr(sc, MIXER_GAIN_REG_RTOL(cmt[dev].rreg), l); 68774994Sorion cmimix_wr(sc, cmt[dev].rreg, r); 68872016Scg DEBMIX(printf("Mixer stereo write dev %d reg 0x%02x "\ 68972016Scg "value 0x%02x:0x%02x\n", 69072016Scg dev, MIXER_GAIN_REG_RTOL(cmt[dev].rreg), l, r)); 69172016Scg } else { 69272016Scg r = l; 69374994Sorion cmimix_wr(sc, cmt[dev].rreg, l); 69472016Scg DEBMIX(printf("Mixer mono write dev %d reg 0x%02x " \ 69572016Scg "value 0x%02x:0x%02x\n", 69672016Scg dev, cmt[dev].rreg, l, l)); 69772016Scg } 69872016Scg 69972016Scg /* Zero gain does not mute channel from output, but this does... */ 70074994Sorion v = cmimix_rd(sc, CMPCI_SB16_MIXER_OUTMIX); 70172016Scg if (l == 0 && r == 0) { 70272016Scg v &= ~cmt[dev].oselect; 70372016Scg } else { 70472016Scg v |= cmt[dev].oselect; 70572016Scg } 70674994Sorion cmimix_wr(sc, CMPCI_SB16_MIXER_OUTMIX, v); 70772016Scg 70872016Scg return 0; 70972016Scg} 71072016Scg 71172016Scgstatic int 71274763Scgcmimix_setrecsrc(struct snd_mixer *m, u_int32_t src) 71372016Scg{ 71474994Sorion struct sc_info *sc = mix_getdevinfo(m); 71572016Scg u_int32_t i, ml, sl; 71672016Scg 71772016Scg ml = sl = 0; 71872016Scg for(i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 71972016Scg if ((1<<i) & src) { 72072016Scg if (cmt[i].stereo) { 72172016Scg sl |= cmt[i].iselect; 72272016Scg } else { 72372016Scg ml |= cmt[i].iselect; 72472016Scg } 72572016Scg } 72672016Scg } 72774994Sorion cmimix_wr(sc, CMPCI_SB16_MIXER_ADCMIX_R, sl|ml); 72872016Scg DEBMIX(printf("cmimix_setrecsrc: reg 0x%02x val 0x%02x\n", 72973772Scg CMPCI_SB16_MIXER_ADCMIX_R, sl|ml)); 73072016Scg ml = CMPCI_SB16_MIXER_SRC_R_TO_L(ml); 73174994Sorion cmimix_wr(sc, CMPCI_SB16_MIXER_ADCMIX_L, sl|ml); 73273772Scg DEBMIX(printf("cmimix_setrecsrc: reg 0x%02x val 0x%02x\n", 73373772Scg CMPCI_SB16_MIXER_ADCMIX_L, sl|ml)); 73472016Scg 73572016Scg return src; 73672016Scg} 73772016Scg 73888032Sorion/* Optional SPDIF support. */ 73988032Sorion 74088032Sorionstatic int 74188032Sorioncmi_initsys(struct sc_info* sc) 74288032Sorion{ 74388032Sorion#ifdef SND_DYNSYSCTL 744159732Snetchild /* XXX: an user should be able to set this with a control tool, 745159732Snetchild if not done before 7.0-RELEASE, this needs to be converted 746159732Snetchild to a device specific sysctl "dev.pcm.X.yyy" via 747159732Snetchild device_get_sysctl_*() as discussed on multimedia@ in msg-id 748159732Snetchild <861wujij2q.fsf@xps.des.no> */ 74988032Sorion SYSCTL_ADD_INT(snd_sysctl_tree(sc->dev), 75088032Sorion SYSCTL_CHILDREN(snd_sysctl_tree_top(sc->dev)), 751159732Snetchild OID_AUTO, "_spdif_enabled", CTLFLAG_RW, 75288032Sorion &sc->spdif_enabled, 0, 75388032Sorion "enable SPDIF output at 44.1 kHz and above"); 75488032Sorion#endif /* SND_DYNSYSCTL */ 75588032Sorion return 0; 75688032Sorion} 75788032Sorion 75888032Sorion/* ------------------------------------------------------------------------- */ 75972016Scgstatic kobj_method_t cmi_mixer_methods[] = { 76072016Scg KOBJMETHOD(mixer_init, cmimix_init), 76172016Scg KOBJMETHOD(mixer_set, cmimix_set), 76272016Scg KOBJMETHOD(mixer_setrecsrc, cmimix_setrecsrc), 76372016Scg { 0, 0 } 76472016Scg}; 76572016ScgMIXER_DECLARE(cmi_mixer); 76672016Scg 767158980Snetchild/* 768158980Snetchild * mpu401 functions 769158980Snetchild */ 770158980Snetchild 771158980Snetchildstatic unsigned char 772158980Snetchildcmi_mread(void *arg, struct sc_info *sc, int reg) 773158980Snetchild{ 774158980Snetchild unsigned int d; 775158980Snetchild 776158980Snetchild d = bus_space_read_1(0,0, 0x330 + reg); 777158980Snetchild /* printf("cmi_mread: reg %x %x\n",reg, d); 778158980Snetchild */ 779158980Snetchild return d; 780158980Snetchild} 781158980Snetchild 782158980Snetchildstatic void 783158980Snetchildcmi_mwrite(void *arg, struct sc_info *sc, int reg, unsigned char b) 784158980Snetchild{ 785158980Snetchild 786158980Snetchild bus_space_write_1(0,0,0x330 + reg , b); 787158980Snetchild} 788158980Snetchild 789158980Snetchildstatic int 790158980Snetchildcmi_muninit(void *arg, struct sc_info *sc) 791158980Snetchild{ 792158980Snetchild 793158980Snetchild snd_mtxlock(sc->lock); 794158980Snetchild sc->mpu_intr = 0; 795158980Snetchild sc->mpu = 0; 796158980Snetchild snd_mtxunlock(sc->lock); 797158980Snetchild 798158980Snetchild return 0; 799158980Snetchild} 800158980Snetchild 801158980Snetchildstatic kobj_method_t cmi_mpu_methods[] = { 802158980Snetchild KOBJMETHOD(mpufoi_read, cmi_mread), 803158980Snetchild KOBJMETHOD(mpufoi_write, cmi_mwrite), 804158980Snetchild KOBJMETHOD(mpufoi_uninit, cmi_muninit), 805158980Snetchild { 0, 0 } 806158980Snetchild}; 807158980Snetchild 808158980SnetchildDEFINE_CLASS(cmi_mpu, cmi_mpu_methods, 0); 809158980Snetchild 810158980Snetchildstatic void 811158980Snetchildcmi_midiattach(struct sc_info *sc) { 812158980Snetchild/* 813158980Snetchild const struct { 814158980Snetchild int port,bits; 815158980Snetchild } *p, ports[] = { 816158980Snetchild {0x330,0}, 817158980Snetchild {0x320,1}, 818158980Snetchild {0x310,2}, 819158980Snetchild {0x300,3}, 820158980Snetchild {0,0} } ; 821158980Snetchild Notes, CMPCI_REG_VMPUSEL sets the io port for the mpu. Does 822158980Snetchild anyone know how to bus_space tag? 823158980Snetchild*/ 824158980Snetchild cmi_clr4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_UART_ENABLE); 825158980Snetchild cmi_clr4(sc, CMPCI_REG_LEGACY_CTRL, 826158980Snetchild CMPCI_REG_VMPUSEL_MASK << CMPCI_REG_VMPUSEL_SHIFT); 827158980Snetchild cmi_set4(sc, CMPCI_REG_LEGACY_CTRL, 828158980Snetchild 0 << CMPCI_REG_VMPUSEL_SHIFT ); 829158980Snetchild cmi_set4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_UART_ENABLE); 830158980Snetchild sc->mpu = mpu401_init(&cmi_mpu_class, sc, cmi_intr, &sc->mpu_intr); 831158980Snetchild} 832158980Snetchild 833158980Snetchild 834158980Snetchild 83572016Scg/* ------------------------------------------------------------------------- */ 83672016Scg/* Power and reset */ 83772016Scg 83872016Scgstatic void 83974994Sorioncmi_power(struct sc_info *sc, int state) 84072016Scg{ 84172016Scg switch (state) { 84272016Scg case 0: /* full power */ 84374994Sorion cmi_clr4(sc, CMPCI_REG_MISC, CMPCI_REG_POWER_DOWN); 84472016Scg break; 84572016Scg default: 84672016Scg /* power off */ 84774994Sorion cmi_set4(sc, CMPCI_REG_MISC, CMPCI_REG_POWER_DOWN); 84872016Scg break; 84972016Scg } 85072016Scg} 85172016Scg 85274994Sorionstatic int 85374994Sorioncmi_init(struct sc_info *sc) 85474994Sorion{ 85574994Sorion /* Effect reset */ 85674994Sorion cmi_set4(sc, CMPCI_REG_MISC, CMPCI_REG_BUS_AND_DSP_RESET); 85774994Sorion DELAY(100); 85874994Sorion cmi_clr4(sc, CMPCI_REG_MISC, CMPCI_REG_BUS_AND_DSP_RESET); 85974994Sorion 86074994Sorion /* Disable interrupts and channels */ 86174994Sorion cmi_clr4(sc, CMPCI_REG_FUNC_0, 86274994Sorion CMPCI_REG_CH0_ENABLE | CMPCI_REG_CH1_ENABLE); 86375174Sorion cmi_clr4(sc, CMPCI_REG_INTR_CTRL, 86475174Sorion CMPCI_REG_CH0_INTR_ENABLE | CMPCI_REG_CH1_INTR_ENABLE); 86574994Sorion 86675174Sorion /* Configure DMA channels, ch0 = play, ch1 = capture */ 86778362Scg cmi_clr4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_DIR); 86878362Scg cmi_set4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_DIR); 86975174Sorion 87074994Sorion /* Attempt to enable 4 Channel output */ 87178362Scg cmi_set4(sc, CMPCI_REG_MISC, CMPCI_REG_N4SPK3D); 87274994Sorion 87374994Sorion /* Disable SPDIF1 - not compatible with config */ 87474994Sorion cmi_clr4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_SPDIF1_ENABLE); 87574994Sorion cmi_clr4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_SPDIF_LOOP); 87674994Sorion 87774994Sorion return 0; 87878362Scg} 87974994Sorion 88074994Sorionstatic void 88174994Sorioncmi_uninit(struct sc_info *sc) 88274994Sorion{ 88374994Sorion /* Disable interrupts and channels */ 88474994Sorion cmi_clr4(sc, CMPCI_REG_INTR_CTRL, 88574994Sorion CMPCI_REG_CH0_INTR_ENABLE | 88674994Sorion CMPCI_REG_CH1_INTR_ENABLE | 88774994Sorion CMPCI_REG_TDMA_INTR_ENABLE); 88874994Sorion cmi_clr4(sc, CMPCI_REG_FUNC_0, 88974994Sorion CMPCI_REG_CH0_ENABLE | CMPCI_REG_CH1_ENABLE); 890158980Snetchild cmi_clr4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_UART_ENABLE); 891158980Snetchild 892158980Snetchild if( sc->mpu ) 893158980Snetchild sc->mpu_intr = 0; 89474994Sorion} 89574994Sorion 89672016Scg/* ------------------------------------------------------------------------- */ 89772016Scg/* Bus and device registration */ 89872016Scgstatic int 89972016Scgcmi_probe(device_t dev) 90072016Scg{ 90172016Scg switch(pci_get_devid(dev)) { 90272016Scg case CMI8338A_PCI_ID: 90372016Scg device_set_desc(dev, "CMedia CMI8338A"); 904142890Simp return BUS_PROBE_DEFAULT; 90572016Scg case CMI8338B_PCI_ID: 90672016Scg device_set_desc(dev, "CMedia CMI8338B"); 907142890Simp return BUS_PROBE_DEFAULT; 90872016Scg case CMI8738_PCI_ID: 90972016Scg device_set_desc(dev, "CMedia CMI8738"); 910142890Simp return BUS_PROBE_DEFAULT; 91172016Scg case CMI8738B_PCI_ID: 91272016Scg device_set_desc(dev, "CMedia CMI8738B"); 913142890Simp return BUS_PROBE_DEFAULT; 91472016Scg default: 91572016Scg return ENXIO; 91672016Scg } 91772016Scg} 91872016Scg 91973772Scgstatic int 92072016Scgcmi_attach(device_t dev) 92172016Scg{ 92274994Sorion struct sc_info *sc; 92374994Sorion u_int32_t data; 92474994Sorion char status[SND_STATUSLEN]; 92572016Scg 92678564Sgreid sc = malloc(sizeof(struct sc_info), M_DEVBUF, M_NOWAIT | M_ZERO); 92774994Sorion if (sc == NULL) { 92872016Scg device_printf(dev, "cannot allocate softc\n"); 92972016Scg return ENXIO; 93072016Scg } 93173772Scg 93293816Sjhb sc->lock = snd_mtxcreate(device_get_nameunit(dev), "sound softc"); 93372016Scg data = pci_read_config(dev, PCIR_COMMAND, 2); 93472016Scg data |= (PCIM_CMD_PORTEN|PCIM_CMD_BUSMASTEREN); 93572016Scg pci_write_config(dev, PCIR_COMMAND, data, 2); 93672016Scg data = pci_read_config(dev, PCIR_COMMAND, 2); 93772016Scg 93888032Sorion sc->dev = dev; 939119690Sjhb sc->regid = PCIR_BAR(0); 940141095Simp sc->reg = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &sc->regid, 941141095Simp RF_ACTIVE); 94274994Sorion if (!sc->reg) { 94372016Scg device_printf(dev, "cmi_attach: Cannot allocate bus resource\n"); 94472016Scg goto bad; 94572016Scg } 94674994Sorion sc->st = rman_get_bustag(sc->reg); 94774994Sorion sc->sh = rman_get_bushandle(sc->reg); 94872016Scg 949158980Snetchild cmi_midiattach(sc); 950158980Snetchild 95174994Sorion sc->irqid = 0; 952127135Snjl sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid, 953127135Snjl RF_ACTIVE | RF_SHAREABLE); 95474994Sorion if (!sc->irq || 955128513Sgreen snd_setup_intr(dev, sc->irq, INTR_MPSAFE, cmi_intr, sc, &sc->ih)) { 95672016Scg device_printf(dev, "cmi_attach: Unable to map interrupt\n"); 95772016Scg goto bad; 95872016Scg } 95973772Scg 96084771Sorion sc->bufsz = pcm_getbuffersize(dev, 4096, CMI_DEFAULT_BUFSZ, 65536); 96184771Sorion 96272016Scg if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, 96372016Scg /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 96472016Scg /*highaddr*/BUS_SPACE_MAXADDR, 96572016Scg /*filter*/NULL, /*filterarg*/NULL, 96684771Sorion /*maxsize*/sc->bufsz, /*nsegments*/1, 96773772Scg /*maxsegz*/0x3ffff, /*flags*/0, 968148590Snetchild /*lockfunc*/NULL, 969148590Snetchild /*lockfunc*/NULL, 97074994Sorion &sc->parent_dmat) != 0) { 97172016Scg device_printf(dev, "cmi_attach: Unable to create dma tag\n"); 97272016Scg goto bad; 97372016Scg } 97472016Scg 97574994Sorion cmi_power(sc, 0); 97675174Sorion if (cmi_init(sc)) 97775174Sorion goto bad; 97872016Scg 97974994Sorion if (mixer_init(dev, &cmi_mixer_class, sc)) 98072016Scg goto bad; 98172016Scg 98274994Sorion if (pcm_register(dev, sc, 1, 1)) 98373772Scg goto bad; 98473772Scg 98588032Sorion cmi_initsys(sc); 98688032Sorion 98774994Sorion pcm_addchan(dev, PCMDIR_PLAY, &cmichan_class, sc); 98874994Sorion pcm_addchan(dev, PCMDIR_REC, &cmichan_class, sc); 98972016Scg 990126695Smatk snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s", 991126695Smatk rman_get_start(sc->reg), rman_get_start(sc->irq),PCM_KLDSTRING(snd_cmi)); 99272016Scg pcm_setstatus(dev, status); 99372016Scg 99472016Scg DEB(printf("cmi_attach: succeeded\n")); 99572016Scg return 0; 99673772Scg 99772016Scg bad: 99878362Scg if (sc->parent_dmat) 99974994Sorion bus_dma_tag_destroy(sc->parent_dmat); 100078362Scg if (sc->ih) 100174994Sorion bus_teardown_intr(dev, sc->irq, sc->ih); 100278362Scg if (sc->irq) 100374994Sorion bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 100478362Scg if (sc->reg) 100574994Sorion bus_release_resource(dev, SYS_RES_IOPORT, sc->regid, sc->reg); 100683214Sgreen if (sc->lock) 100783214Sgreen snd_mtxfree(sc->lock); 100878362Scg if (sc) 100974994Sorion free(sc, M_DEVBUF); 101072016Scg 101172016Scg return ENXIO; 101272016Scg} 101372016Scg 101472016Scgstatic int 101572016Scgcmi_detach(device_t dev) 101672016Scg{ 101774994Sorion struct sc_info *sc; 101872016Scg int r; 101972016Scg 102072016Scg r = pcm_unregister(dev); 102172016Scg if (r) return r; 102272016Scg 102374994Sorion sc = pcm_getdevinfo(dev); 102474994Sorion cmi_uninit(sc); 102574994Sorion cmi_power(sc, 3); 102672016Scg 102774994Sorion bus_dma_tag_destroy(sc->parent_dmat); 102874994Sorion bus_teardown_intr(dev, sc->irq, sc->ih); 102974994Sorion bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 1030158980Snetchild if(sc->mpu) 1031158980Snetchild mpu401_uninit(sc->mpu); 103274994Sorion bus_release_resource(dev, SYS_RES_IOPORT, sc->regid, sc->reg); 1033158980Snetchild if (sc->mpu_reg) 1034158980Snetchild bus_release_resource(dev, SYS_RES_IOPORT, sc->mpu_regid, sc->mpu_reg); 1035158980Snetchild 103683214Sgreen snd_mtxfree(sc->lock); 103774994Sorion free(sc, M_DEVBUF); 103874994Sorion 103972016Scg return 0; 104072016Scg} 104172016Scg 104274994Sorionstatic int 104374994Sorioncmi_suspend(device_t dev) 104474994Sorion{ 104574994Sorion struct sc_info *sc = pcm_getdevinfo(dev); 104674994Sorion 104783214Sgreen snd_mtxlock(sc->lock); 104874994Sorion sc->pch.dma_was_active = cmi_ch0_stop(sc, &sc->pch); 104974994Sorion sc->rch.dma_was_active = cmi_ch1_stop(sc, &sc->rch); 105074994Sorion cmi_power(sc, 3); 105183214Sgreen snd_mtxunlock(sc->lock); 105274994Sorion return 0; 105374994Sorion} 105474994Sorion 105574994Sorionstatic int 105674994Sorioncmi_resume(device_t dev) 105774994Sorion{ 105874994Sorion struct sc_info *sc = pcm_getdevinfo(dev); 105974994Sorion 106083214Sgreen snd_mtxlock(sc->lock); 106174994Sorion cmi_power(sc, 0); 106274994Sorion if (cmi_init(sc) != 0) { 106374994Sorion device_printf(dev, "unable to reinitialize the card\n"); 106483214Sgreen snd_mtxunlock(sc->lock); 106574994Sorion return ENXIO; 106674994Sorion } 106774994Sorion 106874994Sorion if (mixer_reinit(dev) == -1) { 106974994Sorion device_printf(dev, "unable to reinitialize the mixer\n"); 107083214Sgreen snd_mtxunlock(sc->lock); 107174994Sorion return ENXIO; 107278362Scg } 107374994Sorion 107474994Sorion if (sc->pch.dma_was_active) { 107574994Sorion cmichan_setspeed(NULL, &sc->pch, sc->pch.spd); 107674994Sorion cmichan_setformat(NULL, &sc->pch, sc->pch.fmt); 107774994Sorion cmi_ch0_start(sc, &sc->pch); 107874994Sorion } 107974994Sorion 108074994Sorion if (sc->rch.dma_was_active) { 108174994Sorion cmichan_setspeed(NULL, &sc->rch, sc->rch.spd); 108274994Sorion cmichan_setformat(NULL, &sc->rch, sc->rch.fmt); 108374994Sorion cmi_ch1_start(sc, &sc->rch); 108474994Sorion } 108583214Sgreen snd_mtxunlock(sc->lock); 108674994Sorion return 0; 108774994Sorion} 108874994Sorion 108972016Scgstatic device_method_t cmi_methods[] = { 109072016Scg DEVMETHOD(device_probe, cmi_probe), 109172016Scg DEVMETHOD(device_attach, cmi_attach), 109272016Scg DEVMETHOD(device_detach, cmi_detach), 109374994Sorion DEVMETHOD(device_resume, cmi_resume), 109474994Sorion DEVMETHOD(device_suspend, cmi_suspend), 109572016Scg { 0, 0 } 109672016Scg}; 109772016Scg 109872016Scgstatic driver_t cmi_driver = { 109972016Scg "pcm", 110072016Scg cmi_methods, 110182180Scg PCM_SOFTC_SIZE 110272016Scg}; 110372016Scg 110485440SjhbDRIVER_MODULE(snd_cmi, pci, cmi_driver, pcm_devclass, 0, 0); 1105132236StanimuraMODULE_DEPEND(snd_cmi, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 1106158980SnetchildMODULE_DEPEND(snd_cmi, midi, 1,1,1); 110785440SjhbMODULE_VERSION(snd_cmi, 1); 1108