xref: /dragonfly/sys/dev/sound/pci/als4000.c (revision 6b5c5d0d)
1 /*-
2  * Copyright (c) 2001 Orion Hodson <oho@acm.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD: src/sys/dev/sound/pci/als4000.c,v 1.18.2.1 2005/12/30 19:55:53 netchild Exp $
27  * $DragonFly: src/sys/dev/sound/pci/als4000.c,v 1.11 2007/06/16 20:07:19 dillon Exp $
28  */
29 
30 /*
31  * als4000.c - driver for the Avance Logic ALS 4000 chipset.
32  *
33  * The ALS4000 is effectively an SB16 with a PCI interface.
34  *
35  * This driver derives from ALS4000a.PDF, Bart Hartgers alsa driver, and
36  * SB16 register descriptions.
37  */
38 
39 #include <dev/sound/pcm/sound.h>
40 #include <dev/sound/isa/sb.h>
41 #include <dev/sound/pci/als4000.h>
42 
43 #include <bus/pci/pcireg.h>
44 #include <bus/pci/pcivar.h>
45 
46 #include "mixer_if.h"
47 
48 SND_DECLARE_FILE("$DragonFly: src/sys/dev/sound/pci/als4000.c,v 1.11 2007/06/16 20:07:19 dillon Exp $");
49 
50 /* Debugging macro's */
51 #undef DEB
52 #ifndef DEB
53 #define DEB(x)  /* x */
54 #endif /* DEB */
55 
56 #define ALS_DEFAULT_BUFSZ 16384
57 
58 /* ------------------------------------------------------------------------- */
59 /* Structures */
60 
61 struct sc_info;
62 
63 struct sc_chinfo {
64 	struct sc_info		*parent;
65 	struct pcm_channel	*channel;
66 	struct snd_dbuf		*buffer;
67 	u_int32_t		format, speed, phys_buf, bps;
68 	u_int32_t		dma_active:1, dma_was_active:1;
69 	u_int8_t		gcr_fifo_status;
70 	int			dir;
71 };
72 
73 struct sc_info {
74 	device_t		dev;
75 	bus_space_tag_t		st;
76 	bus_space_handle_t	sh;
77 	bus_dma_tag_t		parent_dmat;
78 	struct resource		*reg, *irq;
79 	int			regid, irqid;
80 	void			*ih;
81 	sndlock_t		lock;
82 
83 	unsigned int		bufsz;
84 	struct sc_chinfo	pch, rch;
85 };
86 
87 /* Channel caps */
88 
89 static u_int32_t als_format[] = {
90         AFMT_U8,
91         AFMT_STEREO | AFMT_U8,
92         AFMT_S16_LE,
93         AFMT_STEREO | AFMT_S16_LE,
94         0
95 };
96 
97 /*
98  * I don't believe this rotten soundcard can do 48k, really,
99  * trust me.
100  */
101 static struct pcmchan_caps als_caps = { 4000, 44100, als_format, 0 };
102 
103 /* ------------------------------------------------------------------------- */
104 /* Register Utilities */
105 
106 static u_int32_t
107 als_gcr_rd(struct sc_info *sc, int index)
108 {
109 	bus_space_write_1(sc->st, sc->sh, ALS_GCR_INDEX, index);
110 	return bus_space_read_4(sc->st, sc->sh, ALS_GCR_DATA);
111 }
112 
113 static void
114 als_gcr_wr(struct sc_info *sc, int index, int data)
115 {
116 	bus_space_write_1(sc->st, sc->sh, ALS_GCR_INDEX, index);
117 	bus_space_write_4(sc->st, sc->sh, ALS_GCR_DATA, data);
118 }
119 
120 static u_int8_t
121 als_intr_rd(struct sc_info *sc)
122 {
123 	return bus_space_read_1(sc->st, sc->sh, ALS_SB_MPU_IRQ);
124 }
125 
126 static void
127 als_intr_wr(struct sc_info *sc, u_int8_t data)
128 {
129 	bus_space_write_1(sc->st, sc->sh, ALS_SB_MPU_IRQ, data);
130 }
131 
132 static u_int8_t
133 als_mix_rd(struct sc_info *sc, u_int8_t index)
134 {
135 	bus_space_write_1(sc->st, sc->sh, ALS_MIXER_INDEX, index);
136 	return bus_space_read_1(sc->st, sc->sh, ALS_MIXER_DATA);
137 }
138 
139 static void
140 als_mix_wr(struct sc_info *sc, u_int8_t index, u_int8_t data)
141 {
142 	bus_space_write_1(sc->st, sc->sh, ALS_MIXER_INDEX, index);
143 	bus_space_write_1(sc->st, sc->sh, ALS_MIXER_DATA, data);
144 }
145 
146 static void
147 als_esp_wr(struct sc_info *sc, u_int8_t data)
148 {
149 	u_int32_t	tries, v;
150 
151 	tries = 1000;
152 	do {
153 		v = bus_space_read_1(sc->st, sc->sh, ALS_ESP_WR_STATUS);
154 		if (~v & 0x80)
155 			break;
156 		DELAY(20);
157 	} while (--tries != 0);
158 
159 	if (tries == 0)
160 		device_printf(sc->dev, "als_esp_wr timeout");
161 
162 	bus_space_write_1(sc->st, sc->sh, ALS_ESP_WR_DATA, data);
163 }
164 
165 static int
166 als_esp_reset(struct sc_info *sc)
167 {
168 	u_int32_t	tries, u, v;
169 
170 	bus_space_write_1(sc->st, sc->sh, ALS_ESP_RST, 1);
171 	DELAY(10);
172 	bus_space_write_1(sc->st, sc->sh, ALS_ESP_RST, 0);
173 	DELAY(30);
174 
175 	tries = 1000;
176 	do {
177 		u = bus_space_read_1(sc->st, sc->sh, ALS_ESP_RD_STATUS8);
178 		if (u & 0x80) {
179 			v = bus_space_read_1(sc->st, sc->sh, ALS_ESP_RD_DATA);
180 			if (v == 0xaa)
181 				return 0;
182 			else
183 				break;
184 		}
185 		DELAY(20);
186 	} while (--tries != 0);
187 
188 	if (tries == 0)
189 		device_printf(sc->dev, "als_esp_reset timeout");
190 	return 1;
191 }
192 
193 static u_int8_t
194 als_ack_read(struct sc_info *sc, u_int8_t addr)
195 {
196 	u_int8_t r = bus_space_read_1(sc->st, sc->sh, addr);
197 	return r;
198 }
199 
200 /* ------------------------------------------------------------------------- */
201 /* Common pcm channel implementation */
202 
203 static void *
204 alschan_init(kobj_t obj, void *devinfo,
205 	     struct snd_dbuf *b, struct pcm_channel *c, int dir)
206 {
207 	struct	sc_info	*sc = devinfo;
208 	struct	sc_chinfo *ch;
209 
210 	snd_mtxlock(sc->lock);
211 	if (dir == PCMDIR_PLAY) {
212 		ch = &sc->pch;
213 		ch->gcr_fifo_status = ALS_GCR_FIFO0_STATUS;
214 	} else {
215 		ch = &sc->rch;
216 		ch->gcr_fifo_status = ALS_GCR_FIFO1_STATUS;
217 	}
218 	ch->dir = dir;
219 	ch->parent = sc;
220 	ch->channel = c;
221 	ch->bps = 1;
222 	ch->format = AFMT_U8;
223 	ch->speed = DSP_DEFAULT_SPEED;
224 	ch->buffer = b;
225 	snd_mtxunlock(sc->lock);
226 
227 	if (sndbuf_alloc(ch->buffer, sc->parent_dmat, sc->bufsz) != 0)
228 		return NULL;
229 
230 	return ch;
231 }
232 
233 static int
234 alschan_setformat(kobj_t obj, void *data, u_int32_t format)
235 {
236 	struct	sc_chinfo *ch = data;
237 
238 	ch->format = format;
239 	return 0;
240 }
241 
242 static int
243 alschan_setspeed(kobj_t obj, void *data, u_int32_t speed)
244 {
245 	struct	sc_chinfo *ch = data, *other;
246 	struct  sc_info *sc = ch->parent;
247 
248 	other = (ch->dir == PCMDIR_PLAY) ? &sc->rch : &sc->pch;
249 
250 	/* Deny request if other dma channel is active */
251 	if (other->dma_active) {
252 		ch->speed = other->speed;
253 		return other->speed;
254 	}
255 
256 	ch->speed = speed;
257 	return speed;
258 }
259 
260 static int
261 alschan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
262 {
263 	struct	sc_chinfo *ch = data;
264 	struct	sc_info *sc = ch->parent;
265 
266 	if (blocksize > sc->bufsz / 2) {
267 		blocksize = sc->bufsz / 2;
268 	}
269 	sndbuf_resize(ch->buffer, 2, blocksize);
270 	return blocksize;
271 }
272 
273 static int
274 alschan_getptr(kobj_t obj, void *data)
275 {
276 	struct sc_chinfo *ch = data;
277 	struct sc_info *sc = ch->parent;
278 	int32_t pos, sz;
279 
280 	snd_mtxlock(sc->lock);
281 	pos = als_gcr_rd(ch->parent, ch->gcr_fifo_status) & 0xffff;
282 	snd_mtxunlock(sc->lock);
283 	sz  = sndbuf_getsize(ch->buffer);
284 	return (2 * sz - pos - 1) % sz;
285 }
286 
287 static struct pcmchan_caps*
288 alschan_getcaps(kobj_t obj, void *data)
289 {
290 	return &als_caps;
291 }
292 
293 static void
294 als_set_speed(struct sc_chinfo *ch)
295 {
296 	struct sc_info *sc = ch->parent;
297 	struct sc_chinfo *other;
298 
299 	other = (ch->dir == PCMDIR_PLAY) ? &sc->rch : &sc->pch;
300 	if (other->dma_active == 0) {
301 		als_esp_wr(sc, ALS_ESP_SAMPLE_RATE);
302 		als_esp_wr(sc, ch->speed >> 8);
303 		als_esp_wr(sc, ch->speed & 0xff);
304 	} else {
305 		DEB(kprintf("speed locked at %d (tried %d)\n",
306 			   other->speed, ch->speed));
307 	}
308 }
309 
310 /* ------------------------------------------------------------------------- */
311 /* Playback channel implementation */
312 
313 #define ALS_8BIT_CMD(x, y)  { (x), (y), DSP_DMA8,  DSP_CMD_DMAPAUSE_8  }
314 #define ALS_16BIT_CMD(x, y) { (x), (y),	DSP_DMA16, DSP_CMD_DMAPAUSE_16 }
315 
316 struct playback_command {
317 	u_int32_t pcm_format;	/* newpcm format */
318 	u_int8_t  format_val;	/* sb16 format value */
319 	u_int8_t  dma_prog;	/* sb16 dma program */
320 	u_int8_t  dma_stop;	/* sb16 stop register */
321 } static const playback_cmds[] = {
322 	ALS_8BIT_CMD(AFMT_U8, DSP_MODE_U8MONO),
323 	ALS_8BIT_CMD(AFMT_U8 | AFMT_STEREO, DSP_MODE_U8STEREO),
324 	ALS_16BIT_CMD(AFMT_S16_LE, DSP_MODE_S16MONO),
325 	ALS_16BIT_CMD(AFMT_S16_LE | AFMT_STEREO, DSP_MODE_S16STEREO),
326 };
327 
328 static const struct playback_command*
329 als_get_playback_command(u_int32_t format)
330 {
331 	u_int32_t i, n;
332 
333 	n = sizeof(playback_cmds) / sizeof(playback_cmds[0]);
334 	for (i = 0; i < n; i++) {
335 		if (playback_cmds[i].pcm_format == format) {
336 			return &playback_cmds[i];
337 		}
338 	}
339 	DEB(kprintf("als_get_playback_command: invalid format 0x%08x\n",
340 		   format));
341 	return &playback_cmds[0];
342 }
343 
344 static void
345 als_playback_start(struct sc_chinfo *ch)
346 {
347 	const struct playback_command *p;
348 	struct	sc_info *sc = ch->parent;
349 	u_int32_t	buf, bufsz, count, dma_prog;
350 
351 	buf = sndbuf_getbufaddr(ch->buffer);
352 	bufsz = sndbuf_getsize(ch->buffer);
353 	count = bufsz / 2;
354 	if (ch->format & AFMT_16BIT)
355 		count /= 2;
356 	count--;
357 
358 	als_esp_wr(sc, DSP_CMD_SPKON);
359 	als_set_speed(ch);
360 
361 	als_gcr_wr(sc, ALS_GCR_DMA0_START, buf);
362 	als_gcr_wr(sc, ALS_GCR_DMA0_MODE, (bufsz - 1) | 0x180000);
363 
364 	p = als_get_playback_command(ch->format);
365 	dma_prog = p->dma_prog | DSP_F16_DAC | DSP_F16_AUTO | DSP_F16_FIFO_ON;
366 
367 	als_esp_wr(sc, dma_prog);
368 	als_esp_wr(sc, p->format_val);
369 	als_esp_wr(sc, count & 0xff);
370 	als_esp_wr(sc, count >> 8);
371 
372 	ch->dma_active = 1;
373 }
374 
375 static int
376 als_playback_stop(struct sc_chinfo *ch)
377 {
378 	const struct playback_command *p;
379 	struct sc_info *sc = ch->parent;
380 	u_int32_t active;
381 
382 	active = ch->dma_active;
383 	if (active) {
384 		p = als_get_playback_command(ch->format);
385 		als_esp_wr(sc, p->dma_stop);
386 	}
387 	ch->dma_active = 0;
388 	return active;
389 }
390 
391 static int
392 alspchan_trigger(kobj_t obj, void *data, int go)
393 {
394 	struct	sc_chinfo *ch = data;
395 	struct sc_info *sc = ch->parent;
396 
397 	snd_mtxlock(sc->lock);
398 	switch(go) {
399 	case PCMTRIG_START:
400 		als_playback_start(ch);
401 		break;
402 	case PCMTRIG_ABORT:
403 		als_playback_stop(ch);
404 		break;
405 	}
406 	snd_mtxunlock(sc->lock);
407 	return 0;
408 }
409 
410 static kobj_method_t alspchan_methods[] = {
411 	KOBJMETHOD(channel_init,		alschan_init),
412 	KOBJMETHOD(channel_setformat,		alschan_setformat),
413 	KOBJMETHOD(channel_setspeed,		alschan_setspeed),
414 	KOBJMETHOD(channel_setblocksize,	alschan_setblocksize),
415 	KOBJMETHOD(channel_trigger,		alspchan_trigger),
416 	KOBJMETHOD(channel_getptr,		alschan_getptr),
417 	KOBJMETHOD(channel_getcaps,		alschan_getcaps),
418 	{ 0, 0 }
419 };
420 CHANNEL_DECLARE(alspchan);
421 
422 /* ------------------------------------------------------------------------- */
423 /* Capture channel implementation */
424 
425 static u_int8_t
426 als_get_fifo_format(struct sc_info *sc, u_int32_t format)
427 {
428 	switch (format) {
429 	case AFMT_U8:
430 		return ALS_FIFO1_8BIT;
431 	case AFMT_U8 | AFMT_STEREO:
432 		return ALS_FIFO1_8BIT | ALS_FIFO1_STEREO;
433 	case AFMT_S16_LE:
434 		return ALS_FIFO1_SIGNED;
435 	case AFMT_S16_LE | AFMT_STEREO:
436 		return ALS_FIFO1_SIGNED | ALS_FIFO1_STEREO;
437 	}
438 	device_printf(sc->dev, "format not found: 0x%08x\n", format);
439 	return ALS_FIFO1_8BIT;
440 }
441 
442 static void
443 als_capture_start(struct sc_chinfo *ch)
444 {
445 	struct	sc_info *sc = ch->parent;
446 	u_int32_t	buf, bufsz, count, dma_prog;
447 
448 	buf = sndbuf_getbufaddr(ch->buffer);
449 	bufsz = sndbuf_getsize(ch->buffer);
450 	count = bufsz / 2;
451 	if (ch->format & AFMT_16BIT)
452 		count /= 2;
453 	count--;
454 
455 	als_esp_wr(sc, DSP_CMD_SPKON);
456 	als_set_speed(ch);
457 
458 	als_gcr_wr(sc, ALS_GCR_FIFO1_START, buf);
459 	als_gcr_wr(sc, ALS_GCR_FIFO1_COUNT, (bufsz - 1));
460 
461 	als_mix_wr(sc, ALS_FIFO1_LENGTH_LO, count & 0xff);
462 	als_mix_wr(sc, ALS_FIFO1_LENGTH_HI, count >> 8);
463 
464 	dma_prog = ALS_FIFO1_RUN | als_get_fifo_format(sc, ch->format);
465 	als_mix_wr(sc, ALS_FIFO1_CONTROL, dma_prog);
466 
467 	ch->dma_active = 1;
468 }
469 
470 static int
471 als_capture_stop(struct sc_chinfo *ch)
472 {
473 	struct sc_info *sc = ch->parent;
474 	u_int32_t active;
475 
476 	active = ch->dma_active;
477 	if (active) {
478 		als_mix_wr(sc, ALS_FIFO1_CONTROL, ALS_FIFO1_STOP);
479 	}
480 	ch->dma_active = 0;
481 	return active;
482 }
483 
484 static int
485 alsrchan_trigger(kobj_t obj, void *data, int go)
486 {
487 	struct	sc_chinfo *ch = data;
488 	struct sc_info *sc = ch->parent;
489 
490 	snd_mtxlock(sc->lock);
491 	switch(go) {
492 	case PCMTRIG_START:
493 		als_capture_start(ch);
494 		break;
495 	case PCMTRIG_ABORT:
496 		als_capture_stop(ch);
497 		break;
498 	}
499 	snd_mtxunlock(sc->lock);
500 	return 0;
501 }
502 
503 static kobj_method_t alsrchan_methods[] = {
504 	KOBJMETHOD(channel_init,		alschan_init),
505 	KOBJMETHOD(channel_setformat,		alschan_setformat),
506 	KOBJMETHOD(channel_setspeed,		alschan_setspeed),
507 	KOBJMETHOD(channel_setblocksize,	alschan_setblocksize),
508 	KOBJMETHOD(channel_trigger,		alsrchan_trigger),
509 	KOBJMETHOD(channel_getptr,		alschan_getptr),
510 	KOBJMETHOD(channel_getcaps,		alschan_getcaps),
511 	{ 0, 0 }
512 };
513 CHANNEL_DECLARE(alsrchan);
514 
515 /* ------------------------------------------------------------------------- */
516 /* Mixer related */
517 
518 /*
519  * ALS4000 has an sb16 mixer, with some additional controls that we do
520  * not yet a means to support.
521  */
522 
523 struct sb16props {
524 	u_int8_t lreg;
525 	u_int8_t rreg;
526 	u_int8_t bits;
527 	u_int8_t oselect;
528 	u_int8_t iselect; /* left input mask */
529 } static const amt[SOUND_MIXER_NRDEVICES] = {
530 	[SOUND_MIXER_VOLUME]  = { 0x30, 0x31, 5, 0x00, 0x00 },
531 	[SOUND_MIXER_PCM]     = { 0x32, 0x33, 5, 0x00, 0x00 },
532 	[SOUND_MIXER_SYNTH]   = { 0x34, 0x35, 5, 0x60, 0x40 },
533 	[SOUND_MIXER_CD]      = { 0x36, 0x37, 5, 0x06, 0x04 },
534 	[SOUND_MIXER_LINE]    = { 0x38, 0x39, 5, 0x18, 0x10 },
535 	[SOUND_MIXER_MIC]     = { 0x3a, 0x00, 5, 0x01, 0x01 },
536 	[SOUND_MIXER_SPEAKER] = { 0x3b, 0x00, 2, 0x00, 0x00 },
537 	[SOUND_MIXER_IGAIN]   = { 0x3f, 0x40, 2, 0x00, 0x00 },
538 	[SOUND_MIXER_OGAIN]   = { 0x41, 0x42, 2, 0x00, 0x00 },
539 	/* The following have register values but no h/w implementation */
540 	[SOUND_MIXER_TREBLE]  = { 0x44, 0x45, 4, 0x00, 0x00 },
541 	[SOUND_MIXER_BASS]    = { 0x46, 0x47, 4, 0x00, 0x00 }
542 };
543 
544 static int
545 alsmix_init(struct snd_mixer *m)
546 {
547 	u_int32_t i, v;
548 
549 	for (i = v = 0; i < SOUND_MIXER_NRDEVICES; i++) {
550 		if (amt[i].bits) v |= 1 << i;
551 	}
552 	mix_setdevs(m, v);
553 
554 	for (i = v = 0; i < SOUND_MIXER_NRDEVICES; i++) {
555 		if (amt[i].iselect) v |= 1 << i;
556 	}
557 	mix_setrecdevs(m, v);
558 	return 0;
559 }
560 
561 static int
562 alsmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
563 {
564 	struct sc_info *sc = mix_getdevinfo(m);
565 	u_int32_t r, l, v, mask;
566 
567 	/* Fill upper n bits in mask with 1's */
568 	mask = ((1 << amt[dev].bits) - 1) << (8 - amt[dev].bits);
569 
570 	l = (left * mask / 100) & mask;
571 	v = als_mix_rd(sc, amt[dev].lreg) & ~mask;
572 	als_mix_wr(sc, amt[dev].lreg, l | v);
573 
574 	if (amt[dev].rreg) {
575 		r = (right * mask / 100) & mask;
576 		v = als_mix_rd(sc, amt[dev].rreg) & ~mask;
577 		als_mix_wr(sc, amt[dev].rreg, r | v);
578 	} else {
579 		r = 0;
580 	}
581 
582 	/* Zero gain does not mute channel from output, but this does. */
583 	v = als_mix_rd(sc, SB16_OMASK);
584 	if (l == 0 && r == 0) {
585 		v &= ~amt[dev].oselect;
586 	} else {
587 		v |= amt[dev].oselect;
588 	}
589 	als_mix_wr(sc, SB16_OMASK, v);
590 	return 0;
591 }
592 
593 static int
594 alsmix_setrecsrc(struct snd_mixer *m, u_int32_t src)
595 {
596 	struct sc_info *sc = mix_getdevinfo(m);
597 	u_int32_t i, l, r;
598 
599 	for (i = l = r = 0; i < SOUND_MIXER_NRDEVICES; i++) {
600 		if (src & (1 << i)) {
601 			if (amt[i].iselect == 1) {	/* microphone */
602 				l |= amt[i].iselect;
603 				r |= amt[i].iselect;
604 			} else {
605 				l |= amt[i].iselect;
606 				r |= amt[i].iselect >> 1;
607 			}
608 		}
609 	}
610 
611 	als_mix_wr(sc, SB16_IMASK_L, l);
612 	als_mix_wr(sc, SB16_IMASK_R, r);
613 	return src;
614 }
615 
616 static kobj_method_t als_mixer_methods[] = {
617 	KOBJMETHOD(mixer_init,		alsmix_init),
618 	KOBJMETHOD(mixer_set,		alsmix_set),
619 	KOBJMETHOD(mixer_setrecsrc,	alsmix_setrecsrc),
620 	{ 0, 0 }
621 };
622 MIXER_DECLARE(als_mixer);
623 
624 /* ------------------------------------------------------------------------- */
625 /* Interrupt Handler */
626 
627 static void
628 als_intr(void *p)
629 {
630 	struct sc_info *sc = (struct sc_info *)p;
631 	u_int8_t intr, sb_status;
632 
633 	snd_mtxlock(sc->lock);
634 	intr = als_intr_rd(sc);
635 
636 	if (intr & 0x80) {
637 		snd_mtxunlock(sc->lock);
638 		chn_intr(sc->pch.channel);
639 		snd_mtxlock(sc->lock);
640 	}
641 
642 	if (intr & 0x40) {
643 		snd_mtxunlock(sc->lock);
644 		chn_intr(sc->rch.channel);
645 		snd_mtxlock(sc->lock);
646 	}
647 
648 	/* ACK interrupt in PCI core */
649 	als_intr_wr(sc, intr);
650 
651 	/* ACK interrupt in SB core */
652 	sb_status = als_mix_rd(sc, IRQ_STAT);
653 
654 	if (sb_status & ALS_IRQ_STATUS8)
655 		als_ack_read(sc, ALS_ESP_RD_STATUS8);
656 	if (sb_status & ALS_IRQ_STATUS16)
657 		als_ack_read(sc, ALS_ESP_RD_STATUS16);
658 	if (sb_status & ALS_IRQ_MPUIN)
659 		als_ack_read(sc, ALS_MIDI_DATA);
660 	if (sb_status & ALS_IRQ_CR1E)
661 		als_ack_read(sc, ALS_CR1E_ACK_PORT);
662 
663 	snd_mtxunlock(sc->lock);
664 	return;
665 }
666 
667 /* ------------------------------------------------------------------------- */
668 /* H/W initialization */
669 
670 static int
671 als_init(struct sc_info *sc)
672 {
673 	u_int32_t i, v;
674 
675 	/* Reset Chip */
676 	if (als_esp_reset(sc)) {
677 		return 1;
678 	}
679 
680 	/* Enable write on DMA_SETUP register */
681 	v = als_mix_rd(sc, ALS_SB16_CONFIG);
682 	als_mix_wr(sc, ALS_SB16_CONFIG, v | 0x80);
683 
684 	/* Select DMA0 */
685 	als_mix_wr(sc, ALS_SB16_DMA_SETUP, 0x01);
686 
687 	/* Disable write on DMA_SETUP register */
688 	als_mix_wr(sc, ALS_SB16_CONFIG, v & 0x7f);
689 
690 	/* Enable interrupts */
691 	v  = als_gcr_rd(sc, ALS_GCR_MISC);
692 	als_gcr_wr(sc, ALS_GCR_MISC, v | 0x28000);
693 
694 	/* Black out GCR DMA registers */
695 	for (i = 0x91; i <= 0x96; i++) {
696 		als_gcr_wr(sc, i, 0);
697 	}
698 
699 	/* Emulation mode */
700 	v = als_gcr_rd(sc, ALS_GCR_DMA_EMULATION);
701 	als_gcr_wr(sc, ALS_GCR_DMA_EMULATION, v);
702 	DEB(kprintf("GCR_DMA_EMULATION 0x%08x\n", v));
703 	return 0;
704 }
705 
706 static void
707 als_uninit(struct sc_info *sc)
708 {
709 	/* Disable interrupts */
710 	als_gcr_wr(sc, ALS_GCR_MISC, 0);
711 }
712 
713 /* ------------------------------------------------------------------------- */
714 /* Probe and attach card */
715 
716 static int
717 als_pci_probe(device_t dev)
718 {
719 	if (pci_get_devid(dev) == ALS_PCI_ID0) {
720 		device_set_desc(dev, "Avance Logic ALS4000");
721 		return BUS_PROBE_DEFAULT;
722 	}
723 	return ENXIO;
724 }
725 
726 static void
727 als_resource_free(device_t dev, struct sc_info *sc)
728 {
729 	if (sc->reg) {
730 		bus_release_resource(dev, SYS_RES_IOPORT, sc->regid, sc->reg);
731 		sc->reg = 0;
732 	}
733 	if (sc->ih) {
734 		bus_teardown_intr(dev, sc->irq, sc->ih);
735 		sc->ih = 0;
736 	}
737 	if (sc->irq) {
738 		bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
739 		sc->irq = 0;
740 	}
741 	if (sc->parent_dmat) {
742 		bus_dma_tag_destroy(sc->parent_dmat);
743 		sc->parent_dmat = 0;
744 	}
745 	if (sc->lock) {
746 		snd_mtxfree(sc->lock);
747 		sc->lock = NULL;
748 	}
749 }
750 
751 static int
752 als_resource_grab(device_t dev, struct sc_info *sc)
753 {
754 	sc->regid = PCIR_BAR(0);
755 	sc->reg = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->regid, 0, ~0,
756 				     ALS_CONFIG_SPACE_BYTES, RF_ACTIVE);
757 	if (sc->reg == 0) {
758 		device_printf(dev, "unable to allocate register space\n");
759 		goto bad;
760 	}
761 	sc->st = rman_get_bustag(sc->reg);
762 	sc->sh = rman_get_bushandle(sc->reg);
763 
764 	sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid,
765 					 RF_ACTIVE | RF_SHAREABLE);
766 	if (sc->irq == 0) {
767 		device_printf(dev, "unable to allocate interrupt\n");
768 		goto bad;
769 	}
770 
771 	if (snd_setup_intr(dev, sc->irq, INTR_MPSAFE, als_intr,
772 			   sc, &sc->ih)) {
773 		device_printf(dev, "unable to setup interrupt\n");
774 		goto bad;
775 	}
776 
777 	sc->bufsz = pcm_getbuffersize(dev, 4096, ALS_DEFAULT_BUFSZ, 65536);
778 
779 	if (bus_dma_tag_create(/*parent*/NULL,
780 			       /*alignment*/2, /*boundary*/0,
781 			       /*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
782 			       /*highaddr*/BUS_SPACE_MAXADDR,
783 			       /*filter*/NULL, /*filterarg*/NULL,
784 			       /*maxsize*/sc->bufsz,
785 			       /*nsegments*/1, /*maxsegz*/0x3ffff,
786 			       /*flags*/0,
787 			       &sc->parent_dmat) != 0) {
788 		device_printf(dev, "unable to create dma tag\n");
789 		goto bad;
790 	}
791 	return 0;
792  bad:
793 	als_resource_free(dev, sc);
794 	return ENXIO;
795 }
796 
797 static int
798 als_pci_attach(device_t dev)
799 {
800 	struct sc_info *sc;
801 	u_int32_t data;
802 	char status[SND_STATUSLEN];
803 
804 	if ((sc = kmalloc(sizeof(*sc), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) {
805 		device_printf(dev, "cannot allocate softc\n");
806 		return ENXIO;
807 	}
808 
809 	sc->lock = snd_mtxcreate(device_get_nameunit(dev), "sound softc");
810 	sc->dev = dev;
811 
812 	data = pci_read_config(dev, PCIR_COMMAND, 2);
813 	data |= (PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
814 	pci_write_config(dev, PCIR_COMMAND, data, 2);
815 	/*
816 	 * By default the power to the various components on the
817          * ALS4000 is entirely controlled by the pci powerstate.  We
818          * could attempt finer grained control by setting GCR6.31.
819 	 */
820 #if __FreeBSD_version > 500000
821 	if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
822 		/* Reset the power state. */
823 		device_printf(dev, "chip is in D%d power mode "
824 			      "-- setting to D0\n", pci_get_powerstate(dev));
825 		pci_set_powerstate(dev, PCI_POWERSTATE_D0);
826 	}
827 #else
828 	data = pci_read_config(dev, ALS_PCI_POWERREG, 2);
829 	if ((data & 0x03) != 0) {
830 		device_printf(dev, "chip is in D%d power mode "
831 			      "-- setting to D0\n", data & 0x03);
832 		data &= ~0x03;
833 		pci_write_config(dev, ALS_PCI_POWERREG, data, 2);
834 	}
835 #endif
836 
837 	if (als_resource_grab(dev, sc)) {
838 		device_printf(dev, "failed to allocate resources\n");
839 		goto bad_attach;
840 	}
841 
842 	if (als_init(sc)) {
843 		device_printf(dev, "failed to initialize hardware\n");
844 		goto bad_attach;
845 	}
846 
847 	if (mixer_init(dev, &als_mixer_class, sc)) {
848 		device_printf(dev, "failed to initialize mixer\n");
849 		goto bad_attach;
850 	}
851 
852 	if (pcm_register(dev, sc, 1, 1)) {
853 		device_printf(dev, "failed to register pcm entries\n");
854 		goto bad_attach;
855 	}
856 
857 	pcm_addchan(dev, PCMDIR_PLAY, &alspchan_class, sc);
858 	pcm_addchan(dev, PCMDIR_REC,  &alsrchan_class, sc);
859 
860 	ksnprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s",
861 		 rman_get_start(sc->reg), rman_get_start(sc->irq),PCM_KLDSTRING(snd_als4000));
862 	pcm_setstatus(dev, status);
863 	return 0;
864 
865  bad_attach:
866 	als_resource_free(dev, sc);
867 	kfree(sc, M_DEVBUF);
868 	return ENXIO;
869 }
870 
871 static int
872 als_pci_detach(device_t dev)
873 {
874 	struct sc_info *sc;
875 	int r;
876 
877 	r = pcm_unregister(dev);
878 	if (r)
879 		return r;
880 
881 	sc = pcm_getdevinfo(dev);
882 	als_uninit(sc);
883 	als_resource_free(dev, sc);
884 	kfree(sc, M_DEVBUF);
885 	return 0;
886 }
887 
888 static int
889 als_pci_suspend(device_t dev)
890 {
891 	struct sc_info *sc = pcm_getdevinfo(dev);
892 
893 	snd_mtxlock(sc->lock);
894 	sc->pch.dma_was_active = als_playback_stop(&sc->pch);
895 	sc->rch.dma_was_active = als_capture_stop(&sc->rch);
896 	als_uninit(sc);
897 	snd_mtxunlock(sc->lock);
898 	return 0;
899 }
900 
901 static int
902 als_pci_resume(device_t dev)
903 {
904 	struct sc_info *sc = pcm_getdevinfo(dev);
905 
906 
907 	snd_mtxlock(sc->lock);
908 	if (als_init(sc) != 0) {
909 		device_printf(dev, "unable to reinitialize the card\n");
910 		snd_mtxunlock(sc->lock);
911 		return ENXIO;
912 	}
913 
914 	if (mixer_reinit(dev) != 0) {
915 		device_printf(dev, "unable to reinitialize the mixer\n");
916 		snd_mtxunlock(sc->lock);
917 		return ENXIO;
918 	}
919 
920 	if (sc->pch.dma_was_active) {
921 		als_playback_start(&sc->pch);
922 	}
923 
924 	if (sc->rch.dma_was_active) {
925 		als_capture_start(&sc->rch);
926 	}
927 	snd_mtxunlock(sc->lock);
928 
929 	return 0;
930 }
931 
932 static device_method_t als_methods[] = {
933 	/* Device interface */
934 	DEVMETHOD(device_probe,		als_pci_probe),
935 	DEVMETHOD(device_attach,	als_pci_attach),
936 	DEVMETHOD(device_detach,	als_pci_detach),
937 	DEVMETHOD(device_suspend,	als_pci_suspend),
938 	DEVMETHOD(device_resume,	als_pci_resume),
939 	{ 0, 0 }
940 };
941 
942 static driver_t als_driver = {
943 	"pcm",
944 	als_methods,
945 	PCM_SOFTC_SIZE,
946 };
947 
948 DRIVER_MODULE(snd_als4000, pci, als_driver, pcm_devclass, 0, 0);
949 MODULE_DEPEND(snd_als4000, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
950 MODULE_VERSION(snd_als4000, 1);
951