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. 25192919Sjoel */ 26192919Sjoel 27192919Sjoel/* 2872016Scg * This driver exists largely as a result of other people's efforts. 2972016Scg * Much of register handling is based on NetBSD CMI8x38 audio driver 3072016Scg * by Takuya Shiozaki <AoiMoe@imou.to>. Chen-Li Tien 3172016Scg * <cltien@cmedia.com.tw> clarified points regarding the DMA related 32108533Sschweikh * registers and the 8738 mixer devices. His Linux driver was also a 3372016Scg * useful reference point. 3473772Scg * 3578362Scg * TODO: MIDI 3672016Scg * 3772016Scg * SPDIF contributed by Gerhard Gonter <gonter@whisky.wu-wien.ac.at>. 3872016Scg * 3974994Sorion * This card/code does not always manage to sample at 44100 - actual 4074994Sorion * rate drifts slightly between recordings (usually 0-3%). No 4174994Sorion * differences visible in register dumps between times that work and 4274994Sorion * those that don't. 4372016Scg */ 4472016Scg 45193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS 46193640Sariff#include "opt_snd.h" 47193640Sariff#endif 48193640Sariff 4972016Scg#include <dev/sound/pcm/sound.h> 5072016Scg#include <dev/sound/pci/cmireg.h> 5172016Scg#include <dev/sound/isa/sb.h> 5272016Scg 53119287Simp#include <dev/pci/pcireg.h> 54119287Simp#include <dev/pci/pcivar.h> 5572016Scg 5674994Sorion#include <sys/sysctl.h> 57158980Snetchild#include <dev/sound/midi/mpu401.h> 5874994Sorion 5972016Scg#include "mixer_if.h" 60158980Snetchild#include "mpufoi_if.h" 6172016Scg 6282180ScgSND_DECLARE_FILE("$FreeBSD$"); 6382180Scg 6472016Scg/* Supported chip ID's */ 6572016Scg#define CMI8338A_PCI_ID 0x010013f6 6672016Scg#define CMI8338B_PCI_ID 0x010113f6 6772016Scg#define CMI8738_PCI_ID 0x011113f6 6872016Scg#define CMI8738B_PCI_ID 0x011213f6 69187375Skeramida#define CMI120_USB_ID 0x01030d8c 7072016Scg 7172016Scg/* Buffer size max is 64k for permitted DMA boundaries */ 7284771Sorion#define CMI_DEFAULT_BUFSZ 16384 7372016Scg 7472016Scg/* Interrupts per length of buffer */ 7572016Scg#define CMI_INTR_PER_BUFFER 2 7672016Scg 7772016Scg/* Clarify meaning of named defines in cmireg.h */ 7872016Scg#define CMPCI_REG_DMA0_MAX_SAMPLES CMPCI_REG_DMA0_BYTES 7972016Scg#define CMPCI_REG_DMA0_INTR_SAMPLES CMPCI_REG_DMA0_SAMPLES 8072016Scg#define CMPCI_REG_DMA1_MAX_SAMPLES CMPCI_REG_DMA1_BYTES 8172016Scg#define CMPCI_REG_DMA1_INTR_SAMPLES CMPCI_REG_DMA1_SAMPLES 8272016Scg 8372016Scg/* Our indication of custom mixer control */ 8472016Scg#define CMPCI_NON_SB16_CONTROL 0xff 8572016Scg 8672016Scg/* Debugging macro's */ 8774994Sorion#undef DEB 8872016Scg#ifndef DEB 8972016Scg#define DEB(x) /* x */ 9072016Scg#endif /* DEB */ 9172016Scg 9272016Scg#ifndef DEBMIX 9372016Scg#define DEBMIX(x) /* x */ 9472016Scg#endif /* DEBMIX */ 9572016Scg 9672016Scg/* ------------------------------------------------------------------------- */ 9772016Scg/* Structures */ 9872016Scg 9974994Sorionstruct sc_info; 10072016Scg 10174994Sorionstruct sc_chinfo { 10274994Sorion struct sc_info *parent; 10374994Sorion struct pcm_channel *channel; 10474994Sorion struct snd_dbuf *buffer; 10574994Sorion u_int32_t fmt, spd, phys_buf, bps; 10674994Sorion u_int32_t dma_active:1, dma_was_active:1; 10774994Sorion int dir; 10872016Scg}; 10972016Scg 11074994Sorionstruct sc_info { 11174994Sorion device_t dev; 11273772Scg 11374994Sorion bus_space_tag_t st; 11474994Sorion bus_space_handle_t sh; 11574994Sorion bus_dma_tag_t parent_dmat; 11675174Sorion struct resource *reg, *irq; 11774994Sorion int regid, irqid; 11874994Sorion void *ih; 119107285Scg struct mtx *lock; 12072016Scg 12188032Sorion int spdif_enabled; 12284771Sorion unsigned int bufsz; 12374994Sorion struct sc_chinfo pch, rch; 124158980Snetchild 125158980Snetchild struct mpu401 *mpu; 126158980Snetchild mpu401_intr_t *mpu_intr; 127158980Snetchild struct resource *mpu_reg; 128158980Snetchild int mpu_regid; 129158980Snetchild bus_space_tag_t mpu_bt; 130158980Snetchild bus_space_handle_t mpu_bh; 13172016Scg}; 13272016Scg 13372016Scg/* Channel caps */ 13472016Scg 13572016Scgstatic u_int32_t cmi_fmt[] = { 136193640Sariff SND_FORMAT(AFMT_U8, 1, 0), 137193640Sariff SND_FORMAT(AFMT_U8, 2, 0), 138193640Sariff SND_FORMAT(AFMT_S16_LE, 1, 0), 139193640Sariff SND_FORMAT(AFMT_S16_LE, 2, 0), 14072016Scg 0 14172016Scg}; 14272016Scg 14374763Scgstatic struct pcmchan_caps cmi_caps = {5512, 48000, cmi_fmt, 0}; 14472016Scg 14572016Scg/* ------------------------------------------------------------------------- */ 14672016Scg/* Register Utilities */ 14772016Scg 14872016Scgstatic u_int32_t 14974994Sorioncmi_rd(struct sc_info *sc, int regno, int size) 15072016Scg{ 15172016Scg switch (size) { 15272016Scg case 1: 15374994Sorion return bus_space_read_1(sc->st, sc->sh, regno); 15472016Scg case 2: 15574994Sorion return bus_space_read_2(sc->st, sc->sh, regno); 15672016Scg case 4: 15774994Sorion return bus_space_read_4(sc->st, sc->sh, regno); 15872016Scg default: 15972016Scg DEB(printf("cmi_rd: failed 0x%04x %d\n", regno, size)); 16072016Scg return 0xFFFFFFFF; 16172016Scg } 16272016Scg} 16372016Scg 16472016Scgstatic void 16574994Sorioncmi_wr(struct sc_info *sc, int regno, u_int32_t data, int size) 16672016Scg{ 16772016Scg switch (size) { 16872016Scg case 1: 16974994Sorion bus_space_write_1(sc->st, sc->sh, regno, data); 17072016Scg break; 17172016Scg case 2: 17274994Sorion bus_space_write_2(sc->st, sc->sh, regno, data); 17372016Scg break; 17472016Scg case 4: 17574994Sorion bus_space_write_4(sc->st, sc->sh, regno, data); 17672016Scg break; 17772016Scg } 17872016Scg} 17972016Scg 18072016Scgstatic void 18178362Scgcmi_partial_wr4(struct sc_info *sc, 18272016Scg int reg, int shift, u_int32_t mask, u_int32_t val) 18372016Scg{ 18472016Scg u_int32_t r; 18572016Scg 18674994Sorion r = cmi_rd(sc, reg, 4); 18772016Scg r &= ~(mask << shift); 18872016Scg r |= val << shift; 18974994Sorion cmi_wr(sc, reg, r, 4); 19072016Scg} 19172016Scg 19272016Scgstatic void 19374994Sorioncmi_clr4(struct sc_info *sc, int reg, u_int32_t mask) 19472016Scg{ 19572016Scg u_int32_t r; 19673772Scg 19774994Sorion r = cmi_rd(sc, reg, 4); 19872016Scg r &= ~mask; 19974994Sorion cmi_wr(sc, reg, r, 4); 20072016Scg} 20172016Scg 20272016Scgstatic void 20374994Sorioncmi_set4(struct sc_info *sc, int reg, u_int32_t mask) 20472016Scg{ 20572016Scg u_int32_t r; 20672016Scg 20774994Sorion r = cmi_rd(sc, reg, 4); 20872016Scg r |= mask; 20974994Sorion cmi_wr(sc, reg, r, 4); 21072016Scg} 21172016Scg 21272016Scg/* ------------------------------------------------------------------------- */ 21372016Scg/* Rate Mapping */ 21472016Scg 21573772Scgstatic int cmi_rates[] = {5512, 8000, 11025, 16000, 21672016Scg 22050, 32000, 44100, 48000}; 21772016Scg#define NUM_CMI_RATES (sizeof(cmi_rates)/sizeof(cmi_rates[0])) 21872016Scg 21972016Scg/* cmpci_rate_to_regvalue returns sampling freq selector for FCR1 22072016Scg * register - reg order is 5k,11k,22k,44k,8k,16k,32k,48k */ 22172016Scg 22273772Scgstatic u_int32_t 22372016Scgcmpci_rate_to_regvalue(int rate) 22472016Scg{ 22572016Scg int i, r; 22673772Scg 22772016Scg for(i = 0; i < NUM_CMI_RATES - 1; i++) { 22872016Scg if (rate < ((cmi_rates[i] + cmi_rates[i + 1]) / 2)) { 22972016Scg break; 23072016Scg } 23172016Scg } 23272016Scg 23372016Scg DEB(printf("cmpci_rate_to_regvalue: %d -> %d\n", rate, cmi_rates[i])); 23472016Scg 23572016Scg r = ((i >> 1) | (i << 2)) & 0x07; 23672016Scg return r; 23772016Scg} 23872016Scg 23973772Scgstatic int 24073772Scgcmpci_regvalue_to_rate(u_int32_t r) 24172016Scg{ 24272016Scg int i; 24372016Scg 24472016Scg i = ((r << 1) | (r >> 2)) & 0x07; 24572016Scg DEB(printf("cmpci_regvalue_to_rate: %d -> %d\n", r, i)); 24672016Scg return cmi_rates[i]; 24772016Scg} 24872016Scg 24972016Scg/* ------------------------------------------------------------------------- */ 25074994Sorion/* ADC/DAC control - there are 2 dma channels on 8738, either can be 25174994Sorion * playback or capture. We use ch0 for playback and ch1 for capture. */ 25272016Scg 25372016Scgstatic void 25478362Scgcmi_dma_prog(struct sc_info *sc, struct sc_chinfo *ch, u_int32_t base) 25572016Scg{ 256102328Sorion u_int32_t s, i, sz; 25774994Sorion 258111183Scognet ch->phys_buf = sndbuf_getbufaddr(ch->buffer); 25974994Sorion 260102328Sorion cmi_wr(sc, base, ch->phys_buf, 4); 26174994Sorion sz = (u_int32_t)sndbuf_getsize(ch->buffer); 26274994Sorion 26374994Sorion s = sz / ch->bps - 1; 26475174Sorion cmi_wr(sc, base + 4, s, 2); 26574994Sorion 26674994Sorion i = sz / (ch->bps * CMI_INTR_PER_BUFFER) - 1; 26775174Sorion cmi_wr(sc, base + 6, i, 2); 26878362Scg} 26974994Sorion 27075174Sorion 27175174Sorionstatic void 27275174Sorioncmi_ch0_start(struct sc_info *sc, struct sc_chinfo *ch) 27375174Sorion{ 27475174Sorion cmi_dma_prog(sc, ch, CMPCI_REG_DMA0_BASE); 27575174Sorion 27678362Scg cmi_set4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_ENABLE); 27778362Scg cmi_set4(sc, CMPCI_REG_INTR_CTRL, 27875174Sorion CMPCI_REG_CH0_INTR_ENABLE); 27975174Sorion 28074994Sorion ch->dma_active = 1; 28172016Scg} 28272016Scg 28374994Sorionstatic u_int32_t 28474994Sorioncmi_ch0_stop(struct sc_info *sc, struct sc_chinfo *ch) 28572016Scg{ 28674994Sorion u_int32_t r = ch->dma_active; 28772016Scg 28875174Sorion cmi_clr4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE); 28978362Scg cmi_clr4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_ENABLE); 29078362Scg cmi_set4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_RESET); 29175290Sorion cmi_clr4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_RESET); 29274994Sorion ch->dma_active = 0; 29374994Sorion return r; 29472016Scg} 29572016Scg 29672016Scgstatic void 29774994Sorioncmi_ch1_start(struct sc_info *sc, struct sc_chinfo *ch) 29872016Scg{ 29975174Sorion cmi_dma_prog(sc, ch, CMPCI_REG_DMA1_BASE); 30078362Scg cmi_set4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_ENABLE); 30175174Sorion /* Enable Interrupts */ 30278362Scg cmi_set4(sc, CMPCI_REG_INTR_CTRL, 30375174Sorion CMPCI_REG_CH1_INTR_ENABLE); 30474994Sorion DEB(printf("cmi_ch1_start: dma prog\n")); 30574994Sorion ch->dma_active = 1; 30672016Scg} 30772016Scg 30874994Sorionstatic u_int32_t 30974994Sorioncmi_ch1_stop(struct sc_info *sc, struct sc_chinfo *ch) 31072016Scg{ 31174994Sorion u_int32_t r = ch->dma_active; 31272016Scg 31375174Sorion cmi_clr4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH1_INTR_ENABLE); 31478362Scg cmi_clr4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_ENABLE); 31578362Scg cmi_set4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_RESET); 31675290Sorion cmi_clr4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_RESET); 31774994Sorion ch->dma_active = 0; 31874994Sorion return r; 31972016Scg} 32072016Scg 32172016Scgstatic void 32274994Sorioncmi_spdif_speed(struct sc_info *sc, int speed) { 32372016Scg u_int32_t fcr1, lcr, mcr; 32472016Scg 32572016Scg if (speed >= 44100) { 32672016Scg fcr1 = CMPCI_REG_SPDIF0_ENABLE; 32772016Scg lcr = CMPCI_REG_XSPDIF_ENABLE; 32873772Scg mcr = (speed == 48000) ? 32972016Scg CMPCI_REG_W_SPDIF_48L | CMPCI_REG_SPDIF_48K : 0; 33072016Scg } else { 33172016Scg fcr1 = mcr = lcr = 0; 33272016Scg } 33372016Scg 33474994Sorion cmi_partial_wr4(sc, CMPCI_REG_MISC, 0, 33572016Scg CMPCI_REG_W_SPDIF_48L | CMPCI_REG_SPDIF_48K, mcr); 33674994Sorion cmi_partial_wr4(sc, CMPCI_REG_FUNC_1, 0, 33774994Sorion CMPCI_REG_SPDIF0_ENABLE, fcr1); 33874994Sorion cmi_partial_wr4(sc, CMPCI_REG_LEGACY_CTRL, 0, 33972016Scg CMPCI_REG_XSPDIF_ENABLE, lcr); 34072016Scg} 34172016Scg 34272016Scg/* ------------------------------------------------------------------------- */ 34372016Scg/* Channel Interface implementation */ 34472016Scg 34572016Scgstatic void * 34678362Scgcmichan_init(kobj_t obj, void *devinfo, 34774994Sorion struct snd_dbuf *b, struct pcm_channel *c, int dir) 34872016Scg{ 34974994Sorion struct sc_info *sc = devinfo; 35074994Sorion struct sc_chinfo *ch = (dir == PCMDIR_PLAY) ? &sc->pch : &sc->rch; 35172016Scg 35274994Sorion ch->parent = sc; 35374994Sorion ch->channel = c; 35474994Sorion ch->bps = 1; 355193640Sariff ch->fmt = SND_FORMAT(AFMT_U8, 1, 0); 35674994Sorion ch->spd = DSP_DEFAULT_SPEED; 35774994Sorion ch->buffer = b; 35874994Sorion ch->dma_active = 0; 359168847Sariff if (sndbuf_alloc(ch->buffer, sc->parent_dmat, 0, sc->bufsz) != 0) { 36072016Scg DEB(printf("cmichan_init failed\n")); 36172016Scg return NULL; 36272016Scg } 36372016Scg 36472016Scg ch->dir = dir; 36583214Sgreen snd_mtxlock(sc->lock); 36675174Sorion if (ch->dir == PCMDIR_PLAY) { 36775174Sorion cmi_dma_prog(sc, ch, CMPCI_REG_DMA0_BASE); 36872016Scg } else { 36975174Sorion cmi_dma_prog(sc, ch, CMPCI_REG_DMA1_BASE); 37072016Scg } 37183214Sgreen snd_mtxunlock(sc->lock); 37272016Scg 37372016Scg return ch; 37472016Scg} 37572016Scg 37673772Scgstatic int 37773772Scgcmichan_setformat(kobj_t obj, void *data, u_int32_t format) 37872016Scg{ 37974994Sorion struct sc_chinfo *ch = data; 38083214Sgreen struct sc_info *sc = ch->parent; 38172016Scg u_int32_t f; 38272016Scg 38372016Scg if (format & AFMT_S16_LE) { 38472016Scg f = CMPCI_REG_FORMAT_16BIT; 38572016Scg ch->bps = 2; 38672016Scg } else { 38772016Scg f = CMPCI_REG_FORMAT_8BIT; 38872016Scg ch->bps = 1; 38972016Scg } 39072016Scg 391193640Sariff if (AFMT_CHANNEL(format) > 1) { 39272016Scg f |= CMPCI_REG_FORMAT_STEREO; 39372016Scg ch->bps *= 2; 39472016Scg } else { 39572016Scg f |= CMPCI_REG_FORMAT_MONO; 39672016Scg } 39772016Scg 39883214Sgreen snd_mtxlock(sc->lock); 39972016Scg if (ch->dir == PCMDIR_PLAY) { 40072016Scg cmi_partial_wr4(ch->parent, 40172016Scg CMPCI_REG_CHANNEL_FORMAT, 40272016Scg CMPCI_REG_CH0_FORMAT_SHIFT, 40372016Scg CMPCI_REG_CH0_FORMAT_MASK, 40472016Scg f); 40572016Scg } else { 40672016Scg cmi_partial_wr4(ch->parent, 40772016Scg CMPCI_REG_CHANNEL_FORMAT, 40872016Scg CMPCI_REG_CH1_FORMAT_SHIFT, 40972016Scg CMPCI_REG_CH1_FORMAT_MASK, 41072016Scg f); 41172016Scg } 41283214Sgreen snd_mtxunlock(sc->lock); 41373772Scg ch->fmt = format; 41472016Scg 41572016Scg return 0; 41672016Scg} 41772016Scg 418193640Sariffstatic u_int32_t 41972016Scgcmichan_setspeed(kobj_t obj, void *data, u_int32_t speed) 42073772Scg{ 42174994Sorion struct sc_chinfo *ch = data; 42283214Sgreen struct sc_info *sc = ch->parent; 42372016Scg u_int32_t r, rsp; 42472016Scg 42572016Scg r = cmpci_rate_to_regvalue(speed); 42683214Sgreen snd_mtxlock(sc->lock); 42772016Scg if (ch->dir == PCMDIR_PLAY) { 42888032Sorion if (speed < 44100) { 42988032Sorion /* disable if req before rate change */ 43072016Scg cmi_spdif_speed(ch->parent, speed); 43188032Sorion } 43272016Scg cmi_partial_wr4(ch->parent, 43372016Scg CMPCI_REG_FUNC_1, 43472016Scg CMPCI_REG_DAC_FS_SHIFT, 43572016Scg CMPCI_REG_DAC_FS_MASK, 43672016Scg r); 43788032Sorion if (speed >= 44100 && ch->parent->spdif_enabled) { 43888032Sorion /* enable if req after rate change */ 43972016Scg cmi_spdif_speed(ch->parent, speed); 44088032Sorion } 44172016Scg rsp = cmi_rd(ch->parent, CMPCI_REG_FUNC_1, 4); 44272016Scg rsp >>= CMPCI_REG_DAC_FS_SHIFT; 44372016Scg rsp &= CMPCI_REG_DAC_FS_MASK; 44472016Scg } else { 44572016Scg cmi_partial_wr4(ch->parent, 44672016Scg CMPCI_REG_FUNC_1, 44772016Scg CMPCI_REG_ADC_FS_SHIFT, 44872016Scg CMPCI_REG_ADC_FS_MASK, 44972016Scg r); 45072016Scg rsp = cmi_rd(ch->parent, CMPCI_REG_FUNC_1, 4); 45172016Scg rsp >>= CMPCI_REG_ADC_FS_SHIFT; 45272016Scg rsp &= CMPCI_REG_ADC_FS_MASK; 45372016Scg } 45483214Sgreen snd_mtxunlock(sc->lock); 45572016Scg ch->spd = cmpci_regvalue_to_rate(r); 45672016Scg 45773772Scg DEB(printf("cmichan_setspeed (%s) %d -> %d (%d)\n", 45872016Scg (ch->dir == PCMDIR_PLAY) ? "play" : "rec", 45972016Scg speed, ch->spd, cmpci_regvalue_to_rate(rsp))); 46072016Scg 46172016Scg return ch->spd; 46272016Scg} 46372016Scg 464193640Sariffstatic u_int32_t 46572016Scgcmichan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 46672016Scg{ 46774994Sorion struct sc_chinfo *ch = data; 46884771Sorion struct sc_info *sc = ch->parent; 46972016Scg 47072016Scg /* user has requested interrupts every blocksize bytes */ 47184771Sorion if (blocksize > sc->bufsz / CMI_INTR_PER_BUFFER) { 47284771Sorion blocksize = sc->bufsz / CMI_INTR_PER_BUFFER; 47372016Scg } 47472016Scg sndbuf_resize(ch->buffer, CMI_INTR_PER_BUFFER, blocksize); 47572016Scg 47682834Sorion return blocksize; 47772016Scg} 47872016Scg 47972016Scgstatic int 48072016Scgcmichan_trigger(kobj_t obj, void *data, int go) 48172016Scg{ 48274994Sorion struct sc_chinfo *ch = data; 48374994Sorion struct sc_info *sc = ch->parent; 48472016Scg 485170521Sariff if (!PCMTRIG_COMMON(go)) 486170521Sariff return 0; 487170521Sariff 48883214Sgreen snd_mtxlock(sc->lock); 48972016Scg if (ch->dir == PCMDIR_PLAY) { 49072016Scg switch(go) { 49172016Scg case PCMTRIG_START: 49274994Sorion cmi_ch0_start(sc, ch); 49372016Scg break; 494170521Sariff case PCMTRIG_STOP: 49572016Scg case PCMTRIG_ABORT: 49674994Sorion cmi_ch0_stop(sc, ch); 49772016Scg break; 49872016Scg } 49973772Scg } else { 50072016Scg switch(go) { 50172016Scg case PCMTRIG_START: 50274994Sorion cmi_ch1_start(sc, ch); 50372016Scg break; 504170521Sariff case PCMTRIG_STOP: 50572016Scg case PCMTRIG_ABORT: 50674994Sorion cmi_ch1_stop(sc, ch); 50772016Scg break; 50872016Scg } 50972016Scg } 51083214Sgreen snd_mtxunlock(sc->lock); 51172016Scg return 0; 51272016Scg} 51372016Scg 514193640Sariffstatic u_int32_t 51572016Scgcmichan_getptr(kobj_t obj, void *data) 51672016Scg{ 51774994Sorion struct sc_chinfo *ch = data; 51874994Sorion struct sc_info *sc = ch->parent; 51972016Scg u_int32_t physptr, bufptr, sz; 52072016Scg 52183214Sgreen snd_mtxlock(sc->lock); 52272016Scg if (ch->dir == PCMDIR_PLAY) { 52374994Sorion physptr = cmi_rd(sc, CMPCI_REG_DMA0_BASE, 4); 52472016Scg } else { 52574994Sorion physptr = cmi_rd(sc, CMPCI_REG_DMA1_BASE, 4); 52672016Scg } 52783214Sgreen snd_mtxunlock(sc->lock); 52873772Scg 52972016Scg sz = sndbuf_getsize(ch->buffer); 53074994Sorion bufptr = (physptr - ch->phys_buf + sz - ch->bps) % sz; 53172016Scg 53272016Scg return bufptr; 53372016Scg} 53472016Scg 53573772Scgstatic void 53673772Scgcmi_intr(void *data) 53772016Scg{ 53874994Sorion struct sc_info *sc = data; 53972016Scg u_int32_t intrstat; 540122461Sscottl u_int32_t toclear; 54172016Scg 54283214Sgreen snd_mtxlock(sc->lock); 54374994Sorion intrstat = cmi_rd(sc, CMPCI_REG_INTR_STATUS, 4); 544122461Sscottl if ((intrstat & CMPCI_REG_ANY_INTR) != 0) { 54572016Scg 546122461Sscottl toclear = 0; 547122461Sscottl if (intrstat & CMPCI_REG_CH0_INTR) { 548122461Sscottl toclear |= CMPCI_REG_CH0_INTR_ENABLE; 549122461Sscottl //cmi_clr4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE); 550122461Sscottl } 55172016Scg 552122461Sscottl if (intrstat & CMPCI_REG_CH1_INTR) { 553122461Sscottl toclear |= CMPCI_REG_CH1_INTR_ENABLE; 554122461Sscottl //cmi_clr4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH1_INTR_ENABLE); 555122461Sscottl } 55672016Scg 557122461Sscottl if (toclear) { 558122461Sscottl cmi_clr4(sc, CMPCI_REG_INTR_CTRL, toclear); 559122461Sscottl snd_mtxunlock(sc->lock); 56072016Scg 561122461Sscottl /* Signal interrupts to channel */ 562122461Sscottl if (intrstat & CMPCI_REG_CH0_INTR) { 563122461Sscottl chn_intr(sc->pch.channel); 564122461Sscottl } 56573772Scg 566122461Sscottl if (intrstat & CMPCI_REG_CH1_INTR) { 567122461Sscottl chn_intr(sc->rch.channel); 568122461Sscottl } 56972016Scg 570122461Sscottl snd_mtxlock(sc->lock); 571122461Sscottl cmi_set4(sc, CMPCI_REG_INTR_CTRL, toclear); 572122461Sscottl 573122461Sscottl } 57472016Scg } 575158980Snetchild if(sc->mpu_intr) { 576158980Snetchild (sc->mpu_intr)(sc->mpu); 577158980Snetchild } 57883214Sgreen snd_mtxunlock(sc->lock); 57972016Scg return; 58072016Scg} 58172016Scg 58274763Scgstatic struct pcmchan_caps * 58372016Scgcmichan_getcaps(kobj_t obj, void *data) 58472016Scg{ 58572016Scg return &cmi_caps; 58672016Scg} 58772016Scg 58872016Scgstatic kobj_method_t cmichan_methods[] = { 58972016Scg KOBJMETHOD(channel_init, cmichan_init), 59072016Scg KOBJMETHOD(channel_setformat, cmichan_setformat), 59172016Scg KOBJMETHOD(channel_setspeed, cmichan_setspeed), 59272016Scg KOBJMETHOD(channel_setblocksize, cmichan_setblocksize), 59372016Scg KOBJMETHOD(channel_trigger, cmichan_trigger), 59472016Scg KOBJMETHOD(channel_getptr, cmichan_getptr), 59572016Scg KOBJMETHOD(channel_getcaps, cmichan_getcaps), 596193640Sariff KOBJMETHOD_END 59772016Scg}; 59872016ScgCHANNEL_DECLARE(cmichan); 59972016Scg 60072016Scg/* ------------------------------------------------------------------------- */ 60172016Scg/* Mixer - sb16 with kinks */ 60272016Scg 60373772Scgstatic void 60474994Sorioncmimix_wr(struct sc_info *sc, u_int8_t port, u_int8_t val) 60572016Scg{ 60674994Sorion cmi_wr(sc, CMPCI_REG_SBADDR, port, 1); 60774994Sorion cmi_wr(sc, CMPCI_REG_SBDATA, val, 1); 60872016Scg} 60972016Scg 61073772Scgstatic u_int8_t 61174994Sorioncmimix_rd(struct sc_info *sc, u_int8_t port) 61272016Scg{ 61374994Sorion cmi_wr(sc, CMPCI_REG_SBADDR, port, 1); 61474994Sorion return (u_int8_t)cmi_rd(sc, CMPCI_REG_SBDATA, 1); 61572016Scg} 61672016Scg 61772016Scgstruct sb16props { 61872016Scg u_int8_t rreg; /* right reg chan register */ 61972016Scg u_int8_t stereo:1; /* (no explanation needed, honest) */ 62072016Scg u_int8_t rec:1; /* recording source */ 62172016Scg u_int8_t bits:3; /* num bits to represent maximum gain rep */ 62272016Scg u_int8_t oselect; /* output select mask */ 62372016Scg u_int8_t iselect; /* right input select mask */ 62472016Scg} static const cmt[SOUND_MIXER_NRDEVICES] = { 62573772Scg [SOUND_MIXER_SYNTH] = {CMPCI_SB16_MIXER_FM_R, 1, 1, 5, 62672016Scg CMPCI_SB16_SW_FM, CMPCI_SB16_MIXER_FM_SRC_R}, 62772016Scg [SOUND_MIXER_CD] = {CMPCI_SB16_MIXER_CDDA_R, 1, 1, 5, 62872016Scg CMPCI_SB16_SW_CD, CMPCI_SB16_MIXER_CD_SRC_R}, 62972016Scg [SOUND_MIXER_LINE] = {CMPCI_SB16_MIXER_LINE_R, 1, 1, 5, 63072016Scg CMPCI_SB16_SW_LINE, CMPCI_SB16_MIXER_LINE_SRC_R}, 63173772Scg [SOUND_MIXER_MIC] = {CMPCI_SB16_MIXER_MIC, 0, 1, 5, 63272016Scg CMPCI_SB16_SW_MIC, CMPCI_SB16_MIXER_MIC_SRC}, 63372016Scg [SOUND_MIXER_SPEAKER] = {CMPCI_SB16_MIXER_SPEAKER, 0, 0, 2, 0, 0}, 63472016Scg [SOUND_MIXER_PCM] = {CMPCI_SB16_MIXER_VOICE_R, 1, 0, 5, 0, 0}, 63572016Scg [SOUND_MIXER_VOLUME] = {CMPCI_SB16_MIXER_MASTER_R, 1, 0, 5, 0, 0}, 63672016Scg /* These controls are not implemented in CMI8738, but maybe at a 63772016Scg future date. They are not documented in C-Media documentation, 63872016Scg though appear in other drivers for future h/w (ALSA, Linux, NetBSD). 63972016Scg */ 64073772Scg [SOUND_MIXER_IGAIN] = {CMPCI_SB16_MIXER_INGAIN_R, 1, 0, 2, 0, 0}, 64173772Scg [SOUND_MIXER_OGAIN] = {CMPCI_SB16_MIXER_OUTGAIN_R, 1, 0, 2, 0, 0}, 64273772Scg [SOUND_MIXER_BASS] = {CMPCI_SB16_MIXER_BASS_R, 1, 0, 4, 0, 0}, 64373772Scg [SOUND_MIXER_TREBLE] = {CMPCI_SB16_MIXER_TREBLE_R, 1, 0, 4, 0, 0}, 64474994Sorion /* The mic pre-amp is implemented with non-SB16 compatible 64574994Sorion registers. */ 64672016Scg [SOUND_MIXER_MONITOR] = {CMPCI_NON_SB16_CONTROL, 0, 1, 4, 0}, 64772016Scg}; 64872016Scg 64972016Scg#define MIXER_GAIN_REG_RTOL(r) (r - 1) 65072016Scg 65172016Scgstatic int 65274763Scgcmimix_init(struct snd_mixer *m) 65372016Scg{ 65474994Sorion struct sc_info *sc = mix_getdevinfo(m); 65574994Sorion u_int32_t i,v; 65672016Scg 65774994Sorion for(i = v = 0; i < SOUND_MIXER_NRDEVICES; i++) { 65872016Scg if (cmt[i].bits) v |= 1 << i; 65972016Scg } 66072016Scg mix_setdevs(m, v); 66174994Sorion 66274994Sorion for(i = v = 0; i < SOUND_MIXER_NRDEVICES; i++) { 66374994Sorion if (cmt[i].rec) v |= 1 << i; 66472016Scg } 66572016Scg mix_setrecdevs(m, v); 66672016Scg 66774994Sorion cmimix_wr(sc, CMPCI_SB16_MIXER_RESET, 0); 66874994Sorion cmimix_wr(sc, CMPCI_SB16_MIXER_ADCMIX_L, 0); 66974994Sorion cmimix_wr(sc, CMPCI_SB16_MIXER_ADCMIX_R, 0); 67074994Sorion cmimix_wr(sc, CMPCI_SB16_MIXER_OUTMIX, 67172016Scg CMPCI_SB16_SW_CD | CMPCI_SB16_SW_MIC | CMPCI_SB16_SW_LINE); 67272016Scg return 0; 67372016Scg} 67472016Scg 67572016Scgstatic int 67674763Scgcmimix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 67772016Scg{ 67874994Sorion struct sc_info *sc = mix_getdevinfo(m); 67972016Scg u_int32_t r, l, max; 68072016Scg u_int8_t v; 68172016Scg 68272016Scg max = (1 << cmt[dev].bits) - 1; 68372016Scg 68472016Scg if (cmt[dev].rreg == CMPCI_NON_SB16_CONTROL) { 68574994Sorion /* For time being this can only be one thing (mic in 68674994Sorion * mic/aux reg) */ 68774994Sorion v = cmi_rd(sc, CMPCI_REG_AUX_MIC, 1) & 0xf0; 68872016Scg l = left * max / 100; 68974994Sorion /* 3 bit gain with LSB MICGAIN off(1),on(1) -> 4 bit value */ 69073772Scg v |= ((l << 1) | (~l >> 3)) & 0x0f; 69174994Sorion cmi_wr(sc, CMPCI_REG_AUX_MIC, v, 1); 69272016Scg return 0; 69372016Scg } 69472016Scg 69572016Scg l = (left * max / 100) << (8 - cmt[dev].bits); 69672016Scg if (cmt[dev].stereo) { 69772016Scg r = (right * max / 100) << (8 - cmt[dev].bits); 69874994Sorion cmimix_wr(sc, MIXER_GAIN_REG_RTOL(cmt[dev].rreg), l); 69974994Sorion cmimix_wr(sc, cmt[dev].rreg, r); 70072016Scg DEBMIX(printf("Mixer stereo write dev %d reg 0x%02x "\ 70172016Scg "value 0x%02x:0x%02x\n", 70272016Scg dev, MIXER_GAIN_REG_RTOL(cmt[dev].rreg), l, r)); 70372016Scg } else { 70472016Scg r = l; 70574994Sorion cmimix_wr(sc, cmt[dev].rreg, l); 70672016Scg DEBMIX(printf("Mixer mono write dev %d reg 0x%02x " \ 70772016Scg "value 0x%02x:0x%02x\n", 70872016Scg dev, cmt[dev].rreg, l, l)); 70972016Scg } 71072016Scg 71172016Scg /* Zero gain does not mute channel from output, but this does... */ 71274994Sorion v = cmimix_rd(sc, CMPCI_SB16_MIXER_OUTMIX); 71372016Scg if (l == 0 && r == 0) { 71472016Scg v &= ~cmt[dev].oselect; 71572016Scg } else { 71672016Scg v |= cmt[dev].oselect; 71772016Scg } 71874994Sorion cmimix_wr(sc, CMPCI_SB16_MIXER_OUTMIX, v); 71972016Scg 72072016Scg return 0; 72172016Scg} 72272016Scg 723193640Sariffstatic u_int32_t 72474763Scgcmimix_setrecsrc(struct snd_mixer *m, u_int32_t src) 72572016Scg{ 72674994Sorion struct sc_info *sc = mix_getdevinfo(m); 72772016Scg u_int32_t i, ml, sl; 72872016Scg 72972016Scg ml = sl = 0; 73072016Scg for(i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 73172016Scg if ((1<<i) & src) { 73272016Scg if (cmt[i].stereo) { 73372016Scg sl |= cmt[i].iselect; 73472016Scg } else { 73572016Scg ml |= cmt[i].iselect; 73672016Scg } 73772016Scg } 73872016Scg } 73974994Sorion cmimix_wr(sc, CMPCI_SB16_MIXER_ADCMIX_R, sl|ml); 74072016Scg DEBMIX(printf("cmimix_setrecsrc: reg 0x%02x val 0x%02x\n", 74173772Scg CMPCI_SB16_MIXER_ADCMIX_R, sl|ml)); 74272016Scg ml = CMPCI_SB16_MIXER_SRC_R_TO_L(ml); 74374994Sorion cmimix_wr(sc, CMPCI_SB16_MIXER_ADCMIX_L, sl|ml); 74473772Scg DEBMIX(printf("cmimix_setrecsrc: reg 0x%02x val 0x%02x\n", 74573772Scg CMPCI_SB16_MIXER_ADCMIX_L, sl|ml)); 74672016Scg 74772016Scg return src; 74872016Scg} 74972016Scg 75088032Sorion/* Optional SPDIF support. */ 75188032Sorion 75288032Sorionstatic int 75388032Sorioncmi_initsys(struct sc_info* sc) 75488032Sorion{ 755159732Snetchild /* XXX: an user should be able to set this with a control tool, 756159732Snetchild if not done before 7.0-RELEASE, this needs to be converted 757159732Snetchild to a device specific sysctl "dev.pcm.X.yyy" via 758159732Snetchild device_get_sysctl_*() as discussed on multimedia@ in msg-id 759159732Snetchild <861wujij2q.fsf@xps.des.no> */ 760164614Sariff SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->dev), 761164614Sariff SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), 762164614Sariff OID_AUTO, "spdif_enabled", CTLFLAG_RW, 76388032Sorion &sc->spdif_enabled, 0, 76488032Sorion "enable SPDIF output at 44.1 kHz and above"); 765193640Sariff 76688032Sorion return 0; 76788032Sorion} 76888032Sorion 76988032Sorion/* ------------------------------------------------------------------------- */ 77072016Scgstatic kobj_method_t cmi_mixer_methods[] = { 77172016Scg KOBJMETHOD(mixer_init, cmimix_init), 77272016Scg KOBJMETHOD(mixer_set, cmimix_set), 77372016Scg KOBJMETHOD(mixer_setrecsrc, cmimix_setrecsrc), 774193640Sariff KOBJMETHOD_END 77572016Scg}; 77672016ScgMIXER_DECLARE(cmi_mixer); 77772016Scg 778158980Snetchild/* 779158980Snetchild * mpu401 functions 780158980Snetchild */ 781158980Snetchild 782158980Snetchildstatic unsigned char 783193640Sariffcmi_mread(struct mpu401 *arg, void *sc, int reg) 784158980Snetchild{ 785158980Snetchild unsigned int d; 786158980Snetchild 787158980Snetchild d = bus_space_read_1(0,0, 0x330 + reg); 788158980Snetchild /* printf("cmi_mread: reg %x %x\n",reg, d); 789158980Snetchild */ 790158980Snetchild return d; 791158980Snetchild} 792158980Snetchild 793158980Snetchildstatic void 794193640Sariffcmi_mwrite(struct mpu401 *arg, void *sc, int reg, unsigned char b) 795158980Snetchild{ 796158980Snetchild 797158980Snetchild bus_space_write_1(0,0,0x330 + reg , b); 798158980Snetchild} 799158980Snetchild 800158980Snetchildstatic int 801193640Sariffcmi_muninit(struct mpu401 *arg, void *cookie) 802158980Snetchild{ 803193640Sariff struct sc_info *sc = cookie; 804158980Snetchild 805158980Snetchild snd_mtxlock(sc->lock); 806158980Snetchild sc->mpu_intr = 0; 807158980Snetchild sc->mpu = 0; 808158980Snetchild snd_mtxunlock(sc->lock); 809158980Snetchild 810158980Snetchild return 0; 811158980Snetchild} 812158980Snetchild 813158980Snetchildstatic kobj_method_t cmi_mpu_methods[] = { 814158980Snetchild KOBJMETHOD(mpufoi_read, cmi_mread), 815158980Snetchild KOBJMETHOD(mpufoi_write, cmi_mwrite), 816158980Snetchild KOBJMETHOD(mpufoi_uninit, cmi_muninit), 817193640Sariff KOBJMETHOD_END 818158980Snetchild}; 819158980Snetchild 820160384Snetchildstatic DEFINE_CLASS(cmi_mpu, cmi_mpu_methods, 0); 821158980Snetchild 822158980Snetchildstatic void 823158980Snetchildcmi_midiattach(struct sc_info *sc) { 824158980Snetchild/* 825158980Snetchild const struct { 826158980Snetchild int port,bits; 827158980Snetchild } *p, ports[] = { 828158980Snetchild {0x330,0}, 829158980Snetchild {0x320,1}, 830158980Snetchild {0x310,2}, 831158980Snetchild {0x300,3}, 832158980Snetchild {0,0} } ; 833158980Snetchild Notes, CMPCI_REG_VMPUSEL sets the io port for the mpu. Does 834158980Snetchild anyone know how to bus_space tag? 835158980Snetchild*/ 836158980Snetchild cmi_clr4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_UART_ENABLE); 837158980Snetchild cmi_clr4(sc, CMPCI_REG_LEGACY_CTRL, 838158980Snetchild CMPCI_REG_VMPUSEL_MASK << CMPCI_REG_VMPUSEL_SHIFT); 839158980Snetchild cmi_set4(sc, CMPCI_REG_LEGACY_CTRL, 840158980Snetchild 0 << CMPCI_REG_VMPUSEL_SHIFT ); 841158980Snetchild cmi_set4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_UART_ENABLE); 842158980Snetchild sc->mpu = mpu401_init(&cmi_mpu_class, sc, cmi_intr, &sc->mpu_intr); 843158980Snetchild} 844158980Snetchild 845158980Snetchild 846158980Snetchild 84772016Scg/* ------------------------------------------------------------------------- */ 84872016Scg/* Power and reset */ 84972016Scg 85072016Scgstatic void 85174994Sorioncmi_power(struct sc_info *sc, int state) 85272016Scg{ 85372016Scg switch (state) { 85472016Scg case 0: /* full power */ 85574994Sorion cmi_clr4(sc, CMPCI_REG_MISC, CMPCI_REG_POWER_DOWN); 85672016Scg break; 85772016Scg default: 85872016Scg /* power off */ 85974994Sorion cmi_set4(sc, CMPCI_REG_MISC, CMPCI_REG_POWER_DOWN); 86072016Scg break; 86172016Scg } 86272016Scg} 86372016Scg 86474994Sorionstatic int 86574994Sorioncmi_init(struct sc_info *sc) 86674994Sorion{ 86774994Sorion /* Effect reset */ 86874994Sorion cmi_set4(sc, CMPCI_REG_MISC, CMPCI_REG_BUS_AND_DSP_RESET); 86974994Sorion DELAY(100); 87074994Sorion cmi_clr4(sc, CMPCI_REG_MISC, CMPCI_REG_BUS_AND_DSP_RESET); 87174994Sorion 87274994Sorion /* Disable interrupts and channels */ 87374994Sorion cmi_clr4(sc, CMPCI_REG_FUNC_0, 87474994Sorion CMPCI_REG_CH0_ENABLE | CMPCI_REG_CH1_ENABLE); 87575174Sorion cmi_clr4(sc, CMPCI_REG_INTR_CTRL, 87675174Sorion CMPCI_REG_CH0_INTR_ENABLE | CMPCI_REG_CH1_INTR_ENABLE); 87774994Sorion 87875174Sorion /* Configure DMA channels, ch0 = play, ch1 = capture */ 87978362Scg cmi_clr4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_DIR); 88078362Scg cmi_set4(sc, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_DIR); 88175174Sorion 88274994Sorion /* Attempt to enable 4 Channel output */ 88378362Scg cmi_set4(sc, CMPCI_REG_MISC, CMPCI_REG_N4SPK3D); 88474994Sorion 88574994Sorion /* Disable SPDIF1 - not compatible with config */ 88674994Sorion cmi_clr4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_SPDIF1_ENABLE); 88774994Sorion cmi_clr4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_SPDIF_LOOP); 88874994Sorion 88974994Sorion return 0; 89078362Scg} 89174994Sorion 89274994Sorionstatic void 89374994Sorioncmi_uninit(struct sc_info *sc) 89474994Sorion{ 89574994Sorion /* Disable interrupts and channels */ 89674994Sorion cmi_clr4(sc, CMPCI_REG_INTR_CTRL, 89774994Sorion CMPCI_REG_CH0_INTR_ENABLE | 89874994Sorion CMPCI_REG_CH1_INTR_ENABLE | 89974994Sorion CMPCI_REG_TDMA_INTR_ENABLE); 90074994Sorion cmi_clr4(sc, CMPCI_REG_FUNC_0, 90174994Sorion CMPCI_REG_CH0_ENABLE | CMPCI_REG_CH1_ENABLE); 902158980Snetchild cmi_clr4(sc, CMPCI_REG_FUNC_1, CMPCI_REG_UART_ENABLE); 903158980Snetchild 904158980Snetchild if( sc->mpu ) 905158980Snetchild sc->mpu_intr = 0; 90674994Sorion} 90774994Sorion 90872016Scg/* ------------------------------------------------------------------------- */ 90972016Scg/* Bus and device registration */ 91072016Scgstatic int 91172016Scgcmi_probe(device_t dev) 91272016Scg{ 91372016Scg switch(pci_get_devid(dev)) { 91472016Scg case CMI8338A_PCI_ID: 91572016Scg device_set_desc(dev, "CMedia CMI8338A"); 916142890Simp return BUS_PROBE_DEFAULT; 91772016Scg case CMI8338B_PCI_ID: 91872016Scg device_set_desc(dev, "CMedia CMI8338B"); 919142890Simp return BUS_PROBE_DEFAULT; 92072016Scg case CMI8738_PCI_ID: 92172016Scg device_set_desc(dev, "CMedia CMI8738"); 922142890Simp return BUS_PROBE_DEFAULT; 92372016Scg case CMI8738B_PCI_ID: 92472016Scg device_set_desc(dev, "CMedia CMI8738B"); 925142890Simp return BUS_PROBE_DEFAULT; 926187375Skeramida case CMI120_USB_ID: 927187375Skeramida device_set_desc(dev, "CMedia CMI120"); 928187375Skeramida return BUS_PROBE_DEFAULT; 92972016Scg default: 93072016Scg return ENXIO; 93172016Scg } 93272016Scg} 93372016Scg 93473772Scgstatic int 93572016Scgcmi_attach(device_t dev) 93672016Scg{ 93774994Sorion struct sc_info *sc; 93874994Sorion char status[SND_STATUSLEN]; 93972016Scg 940170873Sariff sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); 941167608Sariff sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_cmi softc"); 942254306Sscottl pci_enable_busmaster(dev); 94372016Scg 94488032Sorion sc->dev = dev; 945119690Sjhb sc->regid = PCIR_BAR(0); 946141095Simp sc->reg = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &sc->regid, 947141095Simp RF_ACTIVE); 94874994Sorion if (!sc->reg) { 94972016Scg device_printf(dev, "cmi_attach: Cannot allocate bus resource\n"); 95072016Scg goto bad; 95172016Scg } 95274994Sorion sc->st = rman_get_bustag(sc->reg); 95374994Sorion sc->sh = rman_get_bushandle(sc->reg); 95472016Scg 955168486Sariff if (0) 956168486Sariff cmi_midiattach(sc); 957158980Snetchild 95874994Sorion sc->irqid = 0; 959127135Snjl sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid, 960127135Snjl RF_ACTIVE | RF_SHAREABLE); 96174994Sorion if (!sc->irq || 962128513Sgreen snd_setup_intr(dev, sc->irq, INTR_MPSAFE, cmi_intr, sc, &sc->ih)) { 96372016Scg device_printf(dev, "cmi_attach: Unable to map interrupt\n"); 96472016Scg goto bad; 96572016Scg } 96673772Scg 96784771Sorion sc->bufsz = pcm_getbuffersize(dev, 4096, CMI_DEFAULT_BUFSZ, 65536); 96884771Sorion 969166904Snetchild if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2, 970166904Snetchild /*boundary*/0, 97172016Scg /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 97272016Scg /*highaddr*/BUS_SPACE_MAXADDR, 97372016Scg /*filter*/NULL, /*filterarg*/NULL, 97484771Sorion /*maxsize*/sc->bufsz, /*nsegments*/1, 97573772Scg /*maxsegz*/0x3ffff, /*flags*/0, 976148590Snetchild /*lockfunc*/NULL, 977148590Snetchild /*lockfunc*/NULL, 97874994Sorion &sc->parent_dmat) != 0) { 97972016Scg device_printf(dev, "cmi_attach: Unable to create dma tag\n"); 98072016Scg goto bad; 98172016Scg } 98272016Scg 98374994Sorion cmi_power(sc, 0); 98475174Sorion if (cmi_init(sc)) 98575174Sorion goto bad; 98672016Scg 98774994Sorion if (mixer_init(dev, &cmi_mixer_class, sc)) 98872016Scg goto bad; 98972016Scg 99074994Sorion if (pcm_register(dev, sc, 1, 1)) 99173772Scg goto bad; 99273772Scg 99388032Sorion cmi_initsys(sc); 99488032Sorion 99574994Sorion pcm_addchan(dev, PCMDIR_PLAY, &cmichan_class, sc); 99674994Sorion pcm_addchan(dev, PCMDIR_REC, &cmichan_class, sc); 99772016Scg 998126695Smatk snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s", 999126695Smatk rman_get_start(sc->reg), rman_get_start(sc->irq),PCM_KLDSTRING(snd_cmi)); 100072016Scg pcm_setstatus(dev, status); 100172016Scg 100272016Scg DEB(printf("cmi_attach: succeeded\n")); 100372016Scg return 0; 100473772Scg 100572016Scg bad: 100678362Scg if (sc->parent_dmat) 100774994Sorion bus_dma_tag_destroy(sc->parent_dmat); 100878362Scg if (sc->ih) 100974994Sorion bus_teardown_intr(dev, sc->irq, sc->ih); 101078362Scg if (sc->irq) 101174994Sorion bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 101278362Scg if (sc->reg) 101374994Sorion bus_release_resource(dev, SYS_RES_IOPORT, sc->regid, sc->reg); 101483214Sgreen if (sc->lock) 101583214Sgreen snd_mtxfree(sc->lock); 101678362Scg if (sc) 101774994Sorion free(sc, M_DEVBUF); 101872016Scg 101972016Scg return ENXIO; 102072016Scg} 102172016Scg 102272016Scgstatic int 102372016Scgcmi_detach(device_t dev) 102472016Scg{ 102574994Sorion struct sc_info *sc; 102672016Scg int r; 102772016Scg 102872016Scg r = pcm_unregister(dev); 102972016Scg if (r) return r; 103072016Scg 103174994Sorion sc = pcm_getdevinfo(dev); 103274994Sorion cmi_uninit(sc); 103374994Sorion cmi_power(sc, 3); 103472016Scg 103574994Sorion bus_dma_tag_destroy(sc->parent_dmat); 103674994Sorion bus_teardown_intr(dev, sc->irq, sc->ih); 103774994Sorion bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 1038158980Snetchild if(sc->mpu) 1039158980Snetchild mpu401_uninit(sc->mpu); 104074994Sorion bus_release_resource(dev, SYS_RES_IOPORT, sc->regid, sc->reg); 1041158980Snetchild if (sc->mpu_reg) 1042158980Snetchild bus_release_resource(dev, SYS_RES_IOPORT, sc->mpu_regid, sc->mpu_reg); 1043158980Snetchild 104483214Sgreen snd_mtxfree(sc->lock); 104574994Sorion free(sc, M_DEVBUF); 104674994Sorion 104772016Scg return 0; 104872016Scg} 104972016Scg 105074994Sorionstatic int 105174994Sorioncmi_suspend(device_t dev) 105274994Sorion{ 105374994Sorion struct sc_info *sc = pcm_getdevinfo(dev); 105474994Sorion 105583214Sgreen snd_mtxlock(sc->lock); 105674994Sorion sc->pch.dma_was_active = cmi_ch0_stop(sc, &sc->pch); 105774994Sorion sc->rch.dma_was_active = cmi_ch1_stop(sc, &sc->rch); 105874994Sorion cmi_power(sc, 3); 105983214Sgreen snd_mtxunlock(sc->lock); 106074994Sorion return 0; 106174994Sorion} 106274994Sorion 106374994Sorionstatic int 106474994Sorioncmi_resume(device_t dev) 106574994Sorion{ 106674994Sorion struct sc_info *sc = pcm_getdevinfo(dev); 106774994Sorion 106883214Sgreen snd_mtxlock(sc->lock); 106974994Sorion cmi_power(sc, 0); 107074994Sorion if (cmi_init(sc) != 0) { 107174994Sorion device_printf(dev, "unable to reinitialize the card\n"); 107283214Sgreen snd_mtxunlock(sc->lock); 107374994Sorion return ENXIO; 107474994Sorion } 107574994Sorion 107674994Sorion if (mixer_reinit(dev) == -1) { 107774994Sorion device_printf(dev, "unable to reinitialize the mixer\n"); 107883214Sgreen snd_mtxunlock(sc->lock); 107974994Sorion return ENXIO; 108078362Scg } 108174994Sorion 108274994Sorion if (sc->pch.dma_was_active) { 108374994Sorion cmichan_setspeed(NULL, &sc->pch, sc->pch.spd); 108474994Sorion cmichan_setformat(NULL, &sc->pch, sc->pch.fmt); 108574994Sorion cmi_ch0_start(sc, &sc->pch); 108674994Sorion } 108774994Sorion 108874994Sorion if (sc->rch.dma_was_active) { 108974994Sorion cmichan_setspeed(NULL, &sc->rch, sc->rch.spd); 109074994Sorion cmichan_setformat(NULL, &sc->rch, sc->rch.fmt); 109174994Sorion cmi_ch1_start(sc, &sc->rch); 109274994Sorion } 109383214Sgreen snd_mtxunlock(sc->lock); 109474994Sorion return 0; 109574994Sorion} 109674994Sorion 109772016Scgstatic device_method_t cmi_methods[] = { 109872016Scg DEVMETHOD(device_probe, cmi_probe), 109972016Scg DEVMETHOD(device_attach, cmi_attach), 110072016Scg DEVMETHOD(device_detach, cmi_detach), 110174994Sorion DEVMETHOD(device_resume, cmi_resume), 110274994Sorion DEVMETHOD(device_suspend, cmi_suspend), 110372016Scg { 0, 0 } 110472016Scg}; 110572016Scg 110672016Scgstatic driver_t cmi_driver = { 110772016Scg "pcm", 110872016Scg cmi_methods, 110982180Scg PCM_SOFTC_SIZE 111072016Scg}; 111172016Scg 111285440SjhbDRIVER_MODULE(snd_cmi, pci, cmi_driver, pcm_devclass, 0, 0); 1113132236StanimuraMODULE_DEPEND(snd_cmi, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 1114158980SnetchildMODULE_DEPEND(snd_cmi, midi, 1,1,1); 111585440SjhbMODULE_VERSION(snd_cmi, 1); 1116