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