cmi.c revision 158980
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 158980 2006-05-27 16:51:37Z 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 74488032Sorion SYSCTL_ADD_INT(snd_sysctl_tree(sc->dev), 74588032Sorion SYSCTL_CHILDREN(snd_sysctl_tree_top(sc->dev)), 74688032Sorion OID_AUTO, "spdif_enabled", CTLFLAG_RW, 74788032Sorion &sc->spdif_enabled, 0, 74888032Sorion "enable SPDIF output at 44.1 kHz and above"); 74988032Sorion#endif /* SND_DYNSYSCTL */ 75088032Sorion return 0; 75188032Sorion} 75288032Sorion 75388032Sorion/* ------------------------------------------------------------------------- */ 75472016Scgstatic kobj_method_t cmi_mixer_methods[] = { 75572016Scg KOBJMETHOD(mixer_init, cmimix_init), 75672016Scg KOBJMETHOD(mixer_set, cmimix_set), 75772016Scg KOBJMETHOD(mixer_setrecsrc, cmimix_setrecsrc), 75872016Scg { 0, 0 } 75972016Scg}; 76072016ScgMIXER_DECLARE(cmi_mixer); 76172016Scg 762158980Snetchild/* 763158980Snetchild * mpu401 functions 764158980Snetchild */ 765158980Snetchild 766158980Snetchildstatic unsigned char 767158980Snetchildcmi_mread(void *arg, struct sc_info *sc, int reg) 768158980Snetchild{ 769158980Snetchild unsigned int d; 770158980Snetchild 771158980Snetchild d = bus_space_read_1(0,0, 0x330 + reg); 772158980Snetchild /* printf("cmi_mread: reg %x %x\n",reg, d); 773158980Snetchild */ 774158980Snetchild return d; 775158980Snetchild} 776158980Snetchild 777158980Snetchildstatic void 778158980Snetchildcmi_mwrite(void *arg, struct sc_info *sc, int reg, unsigned char b) 779158980Snetchild{ 780158980Snetchild 781158980Snetchild bus_space_write_1(0,0,0x330 + reg , b); 782158980Snetchild} 783158980Snetchild 784158980Snetchildstatic int 785158980Snetchildcmi_muninit(void *arg, struct sc_info *sc) 786158980Snetchild{ 787158980Snetchild 788158980Snetchild snd_mtxlock(sc->lock); 789158980Snetchild sc->mpu_intr = 0; 790158980Snetchild sc->mpu = 0; 791158980Snetchild snd_mtxunlock(sc->lock); 792158980Snetchild 793158980Snetchild return 0; 794158980Snetchild} 795158980Snetchild 796158980Snetchildstatic kobj_method_t cmi_mpu_methods[] = { 797158980Snetchild KOBJMETHOD(mpufoi_read, cmi_mread), 798158980Snetchild KOBJMETHOD(mpufoi_write, cmi_mwrite), 799158980Snetchild KOBJMETHOD(mpufoi_uninit, cmi_muninit), 800158980Snetchild { 0, 0 } 801158980Snetchild}; 802158980Snetchild 803158980SnetchildDEFINE_CLASS(cmi_mpu, cmi_mpu_methods, 0); 804158980Snetchild 805158980Snetchildstatic void 806158980Snetchildcmi_midiattach(struct sc_info *sc) { 807158980Snetchild/* 808158980Snetchild const struct { 809158980Snetchild int port,bits; 810158980Snetchild } *p, ports[] = { 811158980Snetchild {0x330,0}, 812158980Snetchild {0x320,1}, 813158980Snetchild {0x310,2}, 814158980Snetchild {0x300,3}, 815158980Snetchild {0,0} } ; 816158980Snetchild Notes, CMPCI_REG_VMPUSEL sets the io port for the mpu. Does 817158980Snetchild anyone know how to bus_space tag? 818158980Snetchild*/ 819158980Snetchild cmi_clr4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_UART_ENABLE); 820158980Snetchild cmi_clr4(sc, CMPCI_REG_LEGACY_CTRL, 821158980Snetchild CMPCI_REG_VMPUSEL_MASK << CMPCI_REG_VMPUSEL_SHIFT); 822158980Snetchild cmi_set4(sc, CMPCI_REG_LEGACY_CTRL, 823158980Snetchild 0 << CMPCI_REG_VMPUSEL_SHIFT ); 824158980Snetchild cmi_set4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_UART_ENABLE); 825158980Snetchild sc->mpu = mpu401_init(&cmi_mpu_class, sc, cmi_intr, &sc->mpu_intr); 826158980Snetchild} 827158980Snetchild 828158980Snetchild 829158980Snetchild 83072016Scg/* ------------------------------------------------------------------------- */ 83172016Scg/* Power and reset */ 83272016Scg 83372016Scgstatic void 83474994Sorioncmi_power(struct sc_info *sc, int state) 83572016Scg{ 83672016Scg switch (state) { 83772016Scg case 0: /* full power */ 83874994Sorion cmi_clr4(sc, CMPCI_REG_MISC, CMPCI_REG_POWER_DOWN); 83972016Scg break; 84072016Scg default: 84172016Scg /* power off */ 84274994Sorion cmi_set4(sc, CMPCI_REG_MISC, CMPCI_REG_POWER_DOWN); 84372016Scg break; 84472016Scg } 84572016Scg} 84672016Scg 84774994Sorionstatic int 84874994Sorioncmi_init(struct sc_info *sc) 84974994Sorion{ 85074994Sorion /* Effect reset */ 85174994Sorion cmi_set4(sc, CMPCI_REG_MISC, CMPCI_REG_BUS_AND_DSP_RESET); 85274994Sorion DELAY(100); 85374994Sorion cmi_clr4(sc, CMPCI_REG_MISC, CMPCI_REG_BUS_AND_DSP_RESET); 85474994Sorion 85574994Sorion /* Disable interrupts and channels */ 85674994Sorion cmi_clr4(sc, CMPCI_REG_FUNC_0, 85774994Sorion CMPCI_REG_CH0_ENABLE | CMPCI_REG_CH1_ENABLE); 85875174Sorion cmi_clr4(sc, CMPCI_REG_INTR_CTRL, 85975174Sorion CMPCI_REG_CH0_INTR_ENABLE | CMPCI_REG_CH1_INTR_ENABLE); 86074994Sorion 86175174Sorion /* Configure DMA channels, ch0 = play, ch1 = capture */ 86278362Scg cmi_clr4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_DIR); 86378362Scg cmi_set4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_DIR); 86475174Sorion 86574994Sorion /* Attempt to enable 4 Channel output */ 86678362Scg cmi_set4(sc, CMPCI_REG_MISC, CMPCI_REG_N4SPK3D); 86774994Sorion 86874994Sorion /* Disable SPDIF1 - not compatible with config */ 86974994Sorion cmi_clr4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_SPDIF1_ENABLE); 87074994Sorion cmi_clr4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_SPDIF_LOOP); 87174994Sorion 87274994Sorion return 0; 87378362Scg} 87474994Sorion 87574994Sorionstatic void 87674994Sorioncmi_uninit(struct sc_info *sc) 87774994Sorion{ 87874994Sorion /* Disable interrupts and channels */ 87974994Sorion cmi_clr4(sc, CMPCI_REG_INTR_CTRL, 88074994Sorion CMPCI_REG_CH0_INTR_ENABLE | 88174994Sorion CMPCI_REG_CH1_INTR_ENABLE | 88274994Sorion CMPCI_REG_TDMA_INTR_ENABLE); 88374994Sorion cmi_clr4(sc, CMPCI_REG_FUNC_0, 88474994Sorion CMPCI_REG_CH0_ENABLE | CMPCI_REG_CH1_ENABLE); 885158980Snetchild cmi_clr4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_UART_ENABLE); 886158980Snetchild 887158980Snetchild if( sc->mpu ) 888158980Snetchild sc->mpu_intr = 0; 88974994Sorion} 89074994Sorion 89172016Scg/* ------------------------------------------------------------------------- */ 89272016Scg/* Bus and device registration */ 89372016Scgstatic int 89472016Scgcmi_probe(device_t dev) 89572016Scg{ 89672016Scg switch(pci_get_devid(dev)) { 89772016Scg case CMI8338A_PCI_ID: 89872016Scg device_set_desc(dev, "CMedia CMI8338A"); 899142890Simp return BUS_PROBE_DEFAULT; 90072016Scg case CMI8338B_PCI_ID: 90172016Scg device_set_desc(dev, "CMedia CMI8338B"); 902142890Simp return BUS_PROBE_DEFAULT; 90372016Scg case CMI8738_PCI_ID: 90472016Scg device_set_desc(dev, "CMedia CMI8738"); 905142890Simp return BUS_PROBE_DEFAULT; 90672016Scg case CMI8738B_PCI_ID: 90772016Scg device_set_desc(dev, "CMedia CMI8738B"); 908142890Simp return BUS_PROBE_DEFAULT; 90972016Scg default: 91072016Scg return ENXIO; 91172016Scg } 91272016Scg} 91372016Scg 91473772Scgstatic int 91572016Scgcmi_attach(device_t dev) 91672016Scg{ 91774994Sorion struct sc_info *sc; 91874994Sorion u_int32_t data; 91974994Sorion char status[SND_STATUSLEN]; 92072016Scg 92178564Sgreid sc = malloc(sizeof(struct sc_info), M_DEVBUF, M_NOWAIT | M_ZERO); 92274994Sorion if (sc == NULL) { 92372016Scg device_printf(dev, "cannot allocate softc\n"); 92472016Scg return ENXIO; 92572016Scg } 92673772Scg 92793816Sjhb sc->lock = snd_mtxcreate(device_get_nameunit(dev), "sound softc"); 92872016Scg data = pci_read_config(dev, PCIR_COMMAND, 2); 92972016Scg data |= (PCIM_CMD_PORTEN|PCIM_CMD_BUSMASTEREN); 93072016Scg pci_write_config(dev, PCIR_COMMAND, data, 2); 93172016Scg data = pci_read_config(dev, PCIR_COMMAND, 2); 93272016Scg 93388032Sorion sc->dev = dev; 934119690Sjhb sc->regid = PCIR_BAR(0); 935141095Simp sc->reg = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &sc->regid, 936141095Simp RF_ACTIVE); 93774994Sorion if (!sc->reg) { 93872016Scg device_printf(dev, "cmi_attach: Cannot allocate bus resource\n"); 93972016Scg goto bad; 94072016Scg } 94174994Sorion sc->st = rman_get_bustag(sc->reg); 94274994Sorion sc->sh = rman_get_bushandle(sc->reg); 94372016Scg 944158980Snetchild cmi_midiattach(sc); 945158980Snetchild 94674994Sorion sc->irqid = 0; 947127135Snjl sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid, 948127135Snjl RF_ACTIVE | RF_SHAREABLE); 94974994Sorion if (!sc->irq || 950128513Sgreen snd_setup_intr(dev, sc->irq, INTR_MPSAFE, cmi_intr, sc, &sc->ih)) { 95172016Scg device_printf(dev, "cmi_attach: Unable to map interrupt\n"); 95272016Scg goto bad; 95372016Scg } 95473772Scg 95584771Sorion sc->bufsz = pcm_getbuffersize(dev, 4096, CMI_DEFAULT_BUFSZ, 65536); 95684771Sorion 95772016Scg if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, 95872016Scg /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 95972016Scg /*highaddr*/BUS_SPACE_MAXADDR, 96072016Scg /*filter*/NULL, /*filterarg*/NULL, 96184771Sorion /*maxsize*/sc->bufsz, /*nsegments*/1, 96273772Scg /*maxsegz*/0x3ffff, /*flags*/0, 963148590Snetchild /*lockfunc*/NULL, 964148590Snetchild /*lockfunc*/NULL, 96574994Sorion &sc->parent_dmat) != 0) { 96672016Scg device_printf(dev, "cmi_attach: Unable to create dma tag\n"); 96772016Scg goto bad; 96872016Scg } 96972016Scg 97074994Sorion cmi_power(sc, 0); 97175174Sorion if (cmi_init(sc)) 97275174Sorion goto bad; 97372016Scg 97474994Sorion if (mixer_init(dev, &cmi_mixer_class, sc)) 97572016Scg goto bad; 97672016Scg 97774994Sorion if (pcm_register(dev, sc, 1, 1)) 97873772Scg goto bad; 97973772Scg 98088032Sorion cmi_initsys(sc); 98188032Sorion 98274994Sorion pcm_addchan(dev, PCMDIR_PLAY, &cmichan_class, sc); 98374994Sorion pcm_addchan(dev, PCMDIR_REC, &cmichan_class, sc); 98472016Scg 985126695Smatk snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s", 986126695Smatk rman_get_start(sc->reg), rman_get_start(sc->irq),PCM_KLDSTRING(snd_cmi)); 98772016Scg pcm_setstatus(dev, status); 98872016Scg 98972016Scg DEB(printf("cmi_attach: succeeded\n")); 99072016Scg return 0; 99173772Scg 99272016Scg bad: 99378362Scg if (sc->parent_dmat) 99474994Sorion bus_dma_tag_destroy(sc->parent_dmat); 99578362Scg if (sc->ih) 99674994Sorion bus_teardown_intr(dev, sc->irq, sc->ih); 99778362Scg if (sc->irq) 99874994Sorion bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 99978362Scg if (sc->reg) 100074994Sorion bus_release_resource(dev, SYS_RES_IOPORT, sc->regid, sc->reg); 100183214Sgreen if (sc->lock) 100283214Sgreen snd_mtxfree(sc->lock); 100378362Scg if (sc) 100474994Sorion free(sc, M_DEVBUF); 100572016Scg 100672016Scg return ENXIO; 100772016Scg} 100872016Scg 100972016Scgstatic int 101072016Scgcmi_detach(device_t dev) 101172016Scg{ 101274994Sorion struct sc_info *sc; 101372016Scg int r; 101472016Scg 101572016Scg r = pcm_unregister(dev); 101672016Scg if (r) return r; 101772016Scg 101874994Sorion sc = pcm_getdevinfo(dev); 101974994Sorion cmi_uninit(sc); 102074994Sorion cmi_power(sc, 3); 102172016Scg 102274994Sorion bus_dma_tag_destroy(sc->parent_dmat); 102374994Sorion bus_teardown_intr(dev, sc->irq, sc->ih); 102474994Sorion bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 1025158980Snetchild if(sc->mpu) 1026158980Snetchild mpu401_uninit(sc->mpu); 102774994Sorion bus_release_resource(dev, SYS_RES_IOPORT, sc->regid, sc->reg); 1028158980Snetchild if (sc->mpu_reg) 1029158980Snetchild bus_release_resource(dev, SYS_RES_IOPORT, sc->mpu_regid, sc->mpu_reg); 1030158980Snetchild 103183214Sgreen snd_mtxfree(sc->lock); 103274994Sorion free(sc, M_DEVBUF); 103374994Sorion 103472016Scg return 0; 103572016Scg} 103672016Scg 103774994Sorionstatic int 103874994Sorioncmi_suspend(device_t dev) 103974994Sorion{ 104074994Sorion struct sc_info *sc = pcm_getdevinfo(dev); 104174994Sorion 104283214Sgreen snd_mtxlock(sc->lock); 104374994Sorion sc->pch.dma_was_active = cmi_ch0_stop(sc, &sc->pch); 104474994Sorion sc->rch.dma_was_active = cmi_ch1_stop(sc, &sc->rch); 104574994Sorion cmi_power(sc, 3); 104683214Sgreen snd_mtxunlock(sc->lock); 104774994Sorion return 0; 104874994Sorion} 104974994Sorion 105074994Sorionstatic int 105174994Sorioncmi_resume(device_t dev) 105274994Sorion{ 105374994Sorion struct sc_info *sc = pcm_getdevinfo(dev); 105474994Sorion 105583214Sgreen snd_mtxlock(sc->lock); 105674994Sorion cmi_power(sc, 0); 105774994Sorion if (cmi_init(sc) != 0) { 105874994Sorion device_printf(dev, "unable to reinitialize the card\n"); 105983214Sgreen snd_mtxunlock(sc->lock); 106074994Sorion return ENXIO; 106174994Sorion } 106274994Sorion 106374994Sorion if (mixer_reinit(dev) == -1) { 106474994Sorion device_printf(dev, "unable to reinitialize the mixer\n"); 106583214Sgreen snd_mtxunlock(sc->lock); 106674994Sorion return ENXIO; 106778362Scg } 106874994Sorion 106974994Sorion if (sc->pch.dma_was_active) { 107074994Sorion cmichan_setspeed(NULL, &sc->pch, sc->pch.spd); 107174994Sorion cmichan_setformat(NULL, &sc->pch, sc->pch.fmt); 107274994Sorion cmi_ch0_start(sc, &sc->pch); 107374994Sorion } 107474994Sorion 107574994Sorion if (sc->rch.dma_was_active) { 107674994Sorion cmichan_setspeed(NULL, &sc->rch, sc->rch.spd); 107774994Sorion cmichan_setformat(NULL, &sc->rch, sc->rch.fmt); 107874994Sorion cmi_ch1_start(sc, &sc->rch); 107974994Sorion } 108083214Sgreen snd_mtxunlock(sc->lock); 108174994Sorion return 0; 108274994Sorion} 108374994Sorion 108472016Scgstatic device_method_t cmi_methods[] = { 108572016Scg DEVMETHOD(device_probe, cmi_probe), 108672016Scg DEVMETHOD(device_attach, cmi_attach), 108772016Scg DEVMETHOD(device_detach, cmi_detach), 108874994Sorion DEVMETHOD(device_resume, cmi_resume), 108974994Sorion DEVMETHOD(device_suspend, cmi_suspend), 109072016Scg { 0, 0 } 109172016Scg}; 109272016Scg 109372016Scgstatic driver_t cmi_driver = { 109472016Scg "pcm", 109572016Scg cmi_methods, 109682180Scg PCM_SOFTC_SIZE 109772016Scg}; 109872016Scg 109985440SjhbDRIVER_MODULE(snd_cmi, pci, cmi_driver, pcm_devclass, 0, 0); 1100132236StanimuraMODULE_DEPEND(snd_cmi, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 1101158980SnetchildMODULE_DEPEND(snd_cmi, midi, 1,1,1); 110285440SjhbMODULE_VERSION(snd_cmi, 1); 1103