xref: /freebsd/sys/dev/sound/pci/als4000.c (revision 52267f7411adcc76ede961420e08c0e42f42d415)
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 
27 /*
28  * als4000.c - driver for the Avance Logic ALS 4000 chipset.
29  *
30  * The ALS4000 is effectively an SB16 with a PCI interface.
31  *
32  * This driver derives from ALS4000a.PDF, Bart Hartgers alsa driver, and
33  * SB16 register descriptions.
34  */
35 
36 #include <dev/sound/pcm/sound.h>
37 #include <dev/sound/isa/sb.h>
38 #include <dev/sound/pci/als4000.h>
39 
40 #include <dev/pci/pcireg.h>
41 #include <dev/pci/pcivar.h>
42 
43 #include "mixer_if.h"
44 
45 SND_DECLARE_FILE("$FreeBSD$");
46 
47 /* Debugging macro's */
48 #undef DEB
49 #ifndef DEB
50 #define DEB(x)  /* x */
51 #endif /* DEB */
52 
53 #define ALS_DEFAULT_BUFSZ 16384
54 
55 /* ------------------------------------------------------------------------- */
56 /* Structures */
57 
58 struct sc_info;
59 
60 struct sc_chinfo {
61 	struct sc_info		*parent;
62 	struct pcm_channel	*channel;
63 	struct snd_dbuf		*buffer;
64 	u_int32_t		format, speed, phys_buf, bps;
65 	u_int32_t		dma_active:1, dma_was_active:1;
66 	u_int8_t		gcr_fifo_status;
67 	int			dir;
68 };
69 
70 struct sc_info {
71 	device_t		dev;
72 	bus_space_tag_t		st;
73 	bus_space_handle_t	sh;
74 	bus_dma_tag_t		parent_dmat;
75 	struct resource		*reg, *irq;
76 	int			regid, irqid;
77 	void			*ih;
78 	struct mtx		*lock;
79 
80 	unsigned int		bufsz;
81 	struct sc_chinfo	pch, rch;
82 };
83 
84 /* Channel caps */
85 
86 static u_int32_t als_format[] = {
87         AFMT_U8,
88         AFMT_STEREO | AFMT_U8,
89         AFMT_S16_LE,
90         AFMT_STEREO | AFMT_S16_LE,
91         0
92 };
93 
94 /*
95  * I don't believe this rotten soundcard can do 48k, really,
96  * trust me.
97  */
98 static struct pcmchan_caps als_caps = { 4000, 44100, als_format, 0 };
99 
100 /* ------------------------------------------------------------------------- */
101 /* Register Utilities */
102 
103 static u_int32_t
104 als_gcr_rd(struct sc_info *sc, int index)
105 {
106 	bus_space_write_1(sc->st, sc->sh, ALS_GCR_INDEX, index);
107 	return bus_space_read_4(sc->st, sc->sh, ALS_GCR_DATA);
108 }
109 
110 static void
111 als_gcr_wr(struct sc_info *sc, int index, int data)
112 {
113 	bus_space_write_1(sc->st, sc->sh, ALS_GCR_INDEX, index);
114 	bus_space_write_4(sc->st, sc->sh, ALS_GCR_DATA, data);
115 }
116 
117 static u_int8_t
118 als_intr_rd(struct sc_info *sc)
119 {
120 	return bus_space_read_1(sc->st, sc->sh, ALS_SB_MPU_IRQ);
121 }
122 
123 static void
124 als_intr_wr(struct sc_info *sc, u_int8_t data)
125 {
126 	bus_space_write_1(sc->st, sc->sh, ALS_SB_MPU_IRQ, data);
127 }
128 
129 static u_int8_t
130 als_mix_rd(struct sc_info *sc, u_int8_t index)
131 {
132 	bus_space_write_1(sc->st, sc->sh, ALS_MIXER_INDEX, index);
133 	return bus_space_read_1(sc->st, sc->sh, ALS_MIXER_DATA);
134 }
135 
136 static void
137 als_mix_wr(struct sc_info *sc, u_int8_t index, u_int8_t data)
138 {
139 	bus_space_write_1(sc->st, sc->sh, ALS_MIXER_INDEX, index);
140 	bus_space_write_1(sc->st, sc->sh, ALS_MIXER_DATA, data);
141 }
142 
143 static void
144 als_esp_wr(struct sc_info *sc, u_int8_t data)
145 {
146 	u_int32_t	tries, v;
147 
148 	tries = 1000;
149 	do {
150 		v = bus_space_read_1(sc->st, sc->sh, ALS_ESP_WR_STATUS);
151 		if (~v & 0x80)
152 			break;
153 		DELAY(20);
154 	} while (--tries != 0);
155 
156 	if (tries == 0)
157 		device_printf(sc->dev, "als_esp_wr timeout");
158 
159 	bus_space_write_1(sc->st, sc->sh, ALS_ESP_WR_DATA, data);
160 }
161 
162 static int
163 als_esp_reset(struct sc_info *sc)
164 {
165 	u_int32_t	tries, u, v;
166 
167 	bus_space_write_1(sc->st, sc->sh, ALS_ESP_RST, 1);
168 	DELAY(10);
169 	bus_space_write_1(sc->st, sc->sh, ALS_ESP_RST, 0);
170 	DELAY(30);
171 
172 	tries = 1000;
173 	do {
174 		u = bus_space_read_1(sc->st, sc->sh, ALS_ESP_RD_STATUS8);
175 		if (u & 0x80) {
176 			v = bus_space_read_1(sc->st, sc->sh, ALS_ESP_RD_DATA);
177 			if (v == 0xaa)
178 				return 0;
179 			else
180 				break;
181 		}
182 		DELAY(20);
183 	} while (--tries != 0);
184 
185 	if (tries == 0)
186 		device_printf(sc->dev, "als_esp_reset timeout");
187 	return 1;
188 }
189 
190 static u_int8_t
191 als_ack_read(struct sc_info *sc, u_int8_t addr)
192 {
193 	u_int8_t r = bus_space_read_1(sc->st, sc->sh, addr);
194 	return r;
195 }
196 
197 /* ------------------------------------------------------------------------- */
198 /* Common pcm channel implementation */
199 
200 static void *
201 alschan_init(kobj_t obj, void *devinfo,
202 	     struct snd_dbuf *b, struct pcm_channel *c, int dir)
203 {
204 	struct	sc_info	*sc = devinfo;
205 	struct	sc_chinfo *ch;
206 
207 	snd_mtxlock(sc->lock);
208 	if (dir == PCMDIR_PLAY) {
209 		ch = &sc->pch;
210 		ch->gcr_fifo_status = ALS_GCR_FIFO0_STATUS;
211 	} else {
212 		ch = &sc->rch;
213 		ch->gcr_fifo_status = ALS_GCR_FIFO1_STATUS;
214 	}
215 	ch->dir = dir;
216 	ch->parent = sc;
217 	ch->channel = c;
218 	ch->bps = 1;
219 	ch->format = AFMT_U8;
220 	ch->speed = DSP_DEFAULT_SPEED;
221 	ch->buffer = b;
222 	snd_mtxunlock(sc->lock);
223 
224 	if (sndbuf_alloc(ch->buffer, sc->parent_dmat, 0, sc->bufsz) != 0)
225 		return NULL;
226 
227 	return ch;
228 }
229 
230 static int
231 alschan_setformat(kobj_t obj, void *data, u_int32_t format)
232 {
233 	struct	sc_chinfo *ch = data;
234 
235 	ch->format = format;
236 	return 0;
237 }
238 
239 static int
240 alschan_setspeed(kobj_t obj, void *data, u_int32_t speed)
241 {
242 	struct	sc_chinfo *ch = data, *other;
243 	struct  sc_info *sc = ch->parent;
244 
245 	other = (ch->dir == PCMDIR_PLAY) ? &sc->rch : &sc->pch;
246 
247 	/* Deny request if other dma channel is active */
248 	if (other->dma_active) {
249 		ch->speed = other->speed;
250 		return other->speed;
251 	}
252 
253 	ch->speed = speed;
254 	return speed;
255 }
256 
257 static int
258 alschan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
259 {
260 	struct	sc_chinfo *ch = data;
261 	struct	sc_info *sc = ch->parent;
262 
263 	if (blocksize > sc->bufsz / 2) {
264 		blocksize = sc->bufsz / 2;
265 	}
266 	sndbuf_resize(ch->buffer, 2, blocksize);
267 	return blocksize;
268 }
269 
270 static int
271 alschan_getptr(kobj_t obj, void *data)
272 {
273 	struct sc_chinfo *ch = data;
274 	struct sc_info *sc = ch->parent;
275 	int32_t pos, sz;
276 
277 	snd_mtxlock(sc->lock);
278 	pos = als_gcr_rd(ch->parent, ch->gcr_fifo_status) & 0xffff;
279 	snd_mtxunlock(sc->lock);
280 	sz  = sndbuf_getsize(ch->buffer);
281 	return (2 * sz - pos - 1) % sz;
282 }
283 
284 static struct pcmchan_caps*
285 alschan_getcaps(kobj_t obj, void *data)
286 {
287 	return &als_caps;
288 }
289 
290 static void
291 als_set_speed(struct sc_chinfo *ch)
292 {
293 	struct sc_info *sc = ch->parent;
294 	struct sc_chinfo *other;
295 
296 	other = (ch->dir == PCMDIR_PLAY) ? &sc->rch : &sc->pch;
297 	if (other->dma_active == 0) {
298 		als_esp_wr(sc, ALS_ESP_SAMPLE_RATE);
299 		als_esp_wr(sc, ch->speed >> 8);
300 		als_esp_wr(sc, ch->speed & 0xff);
301 	} else {
302 		DEB(printf("speed locked at %d (tried %d)\n",
303 			   other->speed, ch->speed));
304 	}
305 }
306 
307 /* ------------------------------------------------------------------------- */
308 /* Playback channel implementation */
309 
310 #define ALS_8BIT_CMD(x, y)  { (x), (y), DSP_DMA8,  DSP_CMD_DMAPAUSE_8  }
311 #define ALS_16BIT_CMD(x, y) { (x), (y),	DSP_DMA16, DSP_CMD_DMAPAUSE_16 }
312 
313 struct playback_command {
314 	u_int32_t pcm_format;	/* newpcm format */
315 	u_int8_t  format_val;	/* sb16 format value */
316 	u_int8_t  dma_prog;	/* sb16 dma program */
317 	u_int8_t  dma_stop;	/* sb16 stop register */
318 } static const playback_cmds[] = {
319 	ALS_8BIT_CMD(AFMT_U8, DSP_MODE_U8MONO),
320 	ALS_8BIT_CMD(AFMT_U8 | AFMT_STEREO, DSP_MODE_U8STEREO),
321 	ALS_16BIT_CMD(AFMT_S16_LE, DSP_MODE_S16MONO),
322 	ALS_16BIT_CMD(AFMT_S16_LE | AFMT_STEREO, DSP_MODE_S16STEREO),
323 };
324 
325 static const struct playback_command*
326 als_get_playback_command(u_int32_t format)
327 {
328 	u_int32_t i, n;
329 
330 	n = sizeof(playback_cmds) / sizeof(playback_cmds[0]);
331 	for (i = 0; i < n; i++) {
332 		if (playback_cmds[i].pcm_format == format) {
333 			return &playback_cmds[i];
334 		}
335 	}
336 	DEB(printf("als_get_playback_command: invalid format 0x%08x\n",
337 		   format));
338 	return &playback_cmds[0];
339 }
340 
341 static void
342 als_playback_start(struct sc_chinfo *ch)
343 {
344 	const struct playback_command *p;
345 	struct	sc_info *sc = ch->parent;
346 	u_int32_t	buf, bufsz, count, dma_prog;
347 
348 	buf = sndbuf_getbufaddr(ch->buffer);
349 	bufsz = sndbuf_getsize(ch->buffer);
350 	count = bufsz / 2;
351 	if (ch->format & AFMT_16BIT)
352 		count /= 2;
353 	count--;
354 
355 	als_esp_wr(sc, DSP_CMD_SPKON);
356 	als_set_speed(ch);
357 
358 	als_gcr_wr(sc, ALS_GCR_DMA0_START, buf);
359 	als_gcr_wr(sc, ALS_GCR_DMA0_MODE, (bufsz - 1) | 0x180000);
360 
361 	p = als_get_playback_command(ch->format);
362 	dma_prog = p->dma_prog | DSP_F16_DAC | DSP_F16_AUTO | DSP_F16_FIFO_ON;
363 
364 	als_esp_wr(sc, dma_prog);
365 	als_esp_wr(sc, p->format_val);
366 	als_esp_wr(sc, count & 0xff);
367 	als_esp_wr(sc, count >> 8);
368 
369 	ch->dma_active = 1;
370 }
371 
372 static int
373 als_playback_stop(struct sc_chinfo *ch)
374 {
375 	const struct playback_command *p;
376 	struct sc_info *sc = ch->parent;
377 	u_int32_t active;
378 
379 	active = ch->dma_active;
380 	if (active) {
381 		p = als_get_playback_command(ch->format);
382 		als_esp_wr(sc, p->dma_stop);
383 	}
384 	ch->dma_active = 0;
385 	return active;
386 }
387 
388 static int
389 alspchan_trigger(kobj_t obj, void *data, int go)
390 {
391 	struct	sc_chinfo *ch = data;
392 	struct sc_info *sc = ch->parent;
393 
394 	if (!PCMTRIG_COMMON(go))
395 		return 0;
396 
397 	snd_mtxlock(sc->lock);
398 	switch(go) {
399 	case PCMTRIG_START:
400 		als_playback_start(ch);
401 		break;
402 	case PCMTRIG_STOP:
403 	case PCMTRIG_ABORT:
404 		als_playback_stop(ch);
405 		break;
406 	default:
407 		break;
408 	}
409 	snd_mtxunlock(sc->lock);
410 	return 0;
411 }
412 
413 static kobj_method_t alspchan_methods[] = {
414 	KOBJMETHOD(channel_init,		alschan_init),
415 	KOBJMETHOD(channel_setformat,		alschan_setformat),
416 	KOBJMETHOD(channel_setspeed,		alschan_setspeed),
417 	KOBJMETHOD(channel_setblocksize,	alschan_setblocksize),
418 	KOBJMETHOD(channel_trigger,		alspchan_trigger),
419 	KOBJMETHOD(channel_getptr,		alschan_getptr),
420 	KOBJMETHOD(channel_getcaps,		alschan_getcaps),
421 	{ 0, 0 }
422 };
423 CHANNEL_DECLARE(alspchan);
424 
425 /* ------------------------------------------------------------------------- */
426 /* Capture channel implementation */
427 
428 static u_int8_t
429 als_get_fifo_format(struct sc_info *sc, u_int32_t format)
430 {
431 	switch (format) {
432 	case AFMT_U8:
433 		return ALS_FIFO1_8BIT;
434 	case AFMT_U8 | AFMT_STEREO:
435 		return ALS_FIFO1_8BIT | ALS_FIFO1_STEREO;
436 	case AFMT_S16_LE:
437 		return ALS_FIFO1_SIGNED;
438 	case AFMT_S16_LE | AFMT_STEREO:
439 		return ALS_FIFO1_SIGNED | ALS_FIFO1_STEREO;
440 	}
441 	device_printf(sc->dev, "format not found: 0x%08x\n", format);
442 	return ALS_FIFO1_8BIT;
443 }
444 
445 static void
446 als_capture_start(struct sc_chinfo *ch)
447 {
448 	struct	sc_info *sc = ch->parent;
449 	u_int32_t	buf, bufsz, count, dma_prog;
450 
451 	buf = sndbuf_getbufaddr(ch->buffer);
452 	bufsz = sndbuf_getsize(ch->buffer);
453 	count = bufsz / 2;
454 	if (ch->format & AFMT_16BIT)
455 		count /= 2;
456 	count--;
457 
458 	als_esp_wr(sc, DSP_CMD_SPKON);
459 	als_set_speed(ch);
460 
461 	als_gcr_wr(sc, ALS_GCR_FIFO1_START, buf);
462 	als_gcr_wr(sc, ALS_GCR_FIFO1_COUNT, (bufsz - 1));
463 
464 	als_mix_wr(sc, ALS_FIFO1_LENGTH_LO, count & 0xff);
465 	als_mix_wr(sc, ALS_FIFO1_LENGTH_HI, count >> 8);
466 
467 	dma_prog = ALS_FIFO1_RUN | als_get_fifo_format(sc, ch->format);
468 	als_mix_wr(sc, ALS_FIFO1_CONTROL, dma_prog);
469 
470 	ch->dma_active = 1;
471 }
472 
473 static int
474 als_capture_stop(struct sc_chinfo *ch)
475 {
476 	struct sc_info *sc = ch->parent;
477 	u_int32_t active;
478 
479 	active = ch->dma_active;
480 	if (active) {
481 		als_mix_wr(sc, ALS_FIFO1_CONTROL, ALS_FIFO1_STOP);
482 	}
483 	ch->dma_active = 0;
484 	return active;
485 }
486 
487 static int
488 alsrchan_trigger(kobj_t obj, void *data, int go)
489 {
490 	struct	sc_chinfo *ch = data;
491 	struct sc_info *sc = ch->parent;
492 
493 	snd_mtxlock(sc->lock);
494 	switch(go) {
495 	case PCMTRIG_START:
496 		als_capture_start(ch);
497 		break;
498 	case PCMTRIG_STOP:
499 	case PCMTRIG_ABORT:
500 		als_capture_stop(ch);
501 		break;
502 	}
503 	snd_mtxunlock(sc->lock);
504 	return 0;
505 }
506 
507 static kobj_method_t alsrchan_methods[] = {
508 	KOBJMETHOD(channel_init,		alschan_init),
509 	KOBJMETHOD(channel_setformat,		alschan_setformat),
510 	KOBJMETHOD(channel_setspeed,		alschan_setspeed),
511 	KOBJMETHOD(channel_setblocksize,	alschan_setblocksize),
512 	KOBJMETHOD(channel_trigger,		alsrchan_trigger),
513 	KOBJMETHOD(channel_getptr,		alschan_getptr),
514 	KOBJMETHOD(channel_getcaps,		alschan_getcaps),
515 	{ 0, 0 }
516 };
517 CHANNEL_DECLARE(alsrchan);
518 
519 /* ------------------------------------------------------------------------- */
520 /* Mixer related */
521 
522 /*
523  * ALS4000 has an sb16 mixer, with some additional controls that we do
524  * not yet a means to support.
525  */
526 
527 struct sb16props {
528 	u_int8_t lreg;
529 	u_int8_t rreg;
530 	u_int8_t bits;
531 	u_int8_t oselect;
532 	u_int8_t iselect; /* left input mask */
533 } static const amt[SOUND_MIXER_NRDEVICES] = {
534 	[SOUND_MIXER_VOLUME]  = { 0x30, 0x31, 5, 0x00, 0x00 },
535 	[SOUND_MIXER_PCM]     = { 0x32, 0x33, 5, 0x00, 0x00 },
536 	[SOUND_MIXER_SYNTH]   = { 0x34, 0x35, 5, 0x60, 0x40 },
537 	[SOUND_MIXER_CD]      = { 0x36, 0x37, 5, 0x06, 0x04 },
538 	[SOUND_MIXER_LINE]    = { 0x38, 0x39, 5, 0x18, 0x10 },
539 	[SOUND_MIXER_MIC]     = { 0x3a, 0x00, 5, 0x01, 0x01 },
540 	[SOUND_MIXER_SPEAKER] = { 0x3b, 0x00, 2, 0x00, 0x00 },
541 	[SOUND_MIXER_IGAIN]   = { 0x3f, 0x40, 2, 0x00, 0x00 },
542 	[SOUND_MIXER_OGAIN]   = { 0x41, 0x42, 2, 0x00, 0x00 },
543 	/* The following have register values but no h/w implementation */
544 	[SOUND_MIXER_TREBLE]  = { 0x44, 0x45, 4, 0x00, 0x00 },
545 	[SOUND_MIXER_BASS]    = { 0x46, 0x47, 4, 0x00, 0x00 }
546 };
547 
548 static int
549 alsmix_init(struct snd_mixer *m)
550 {
551 	u_int32_t i, v;
552 
553 	for (i = v = 0; i < SOUND_MIXER_NRDEVICES; i++) {
554 		if (amt[i].bits) v |= 1 << i;
555 	}
556 	mix_setdevs(m, v);
557 
558 	for (i = v = 0; i < SOUND_MIXER_NRDEVICES; i++) {
559 		if (amt[i].iselect) v |= 1 << i;
560 	}
561 	mix_setrecdevs(m, v);
562 	return 0;
563 }
564 
565 static int
566 alsmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
567 {
568 	struct sc_info *sc = mix_getdevinfo(m);
569 	u_int32_t r, l, v, mask;
570 
571 	/* Fill upper n bits in mask with 1's */
572 	mask = ((1 << amt[dev].bits) - 1) << (8 - amt[dev].bits);
573 
574 	l = (left * mask / 100) & mask;
575 	v = als_mix_rd(sc, amt[dev].lreg) & ~mask;
576 	als_mix_wr(sc, amt[dev].lreg, l | v);
577 
578 	if (amt[dev].rreg) {
579 		r = (right * mask / 100) & mask;
580 		v = als_mix_rd(sc, amt[dev].rreg) & ~mask;
581 		als_mix_wr(sc, amt[dev].rreg, r | v);
582 	} else {
583 		r = 0;
584 	}
585 
586 	/* Zero gain does not mute channel from output, but this does. */
587 	v = als_mix_rd(sc, SB16_OMASK);
588 	if (l == 0 && r == 0) {
589 		v &= ~amt[dev].oselect;
590 	} else {
591 		v |= amt[dev].oselect;
592 	}
593 	als_mix_wr(sc, SB16_OMASK, v);
594 	return 0;
595 }
596 
597 static int
598 alsmix_setrecsrc(struct snd_mixer *m, u_int32_t src)
599 {
600 	struct sc_info *sc = mix_getdevinfo(m);
601 	u_int32_t i, l, r;
602 
603 	for (i = l = r = 0; i < SOUND_MIXER_NRDEVICES; i++) {
604 		if (src & (1 << i)) {
605 			if (amt[i].iselect == 1) {	/* microphone */
606 				l |= amt[i].iselect;
607 				r |= amt[i].iselect;
608 			} else {
609 				l |= amt[i].iselect;
610 				r |= amt[i].iselect >> 1;
611 			}
612 		}
613 	}
614 
615 	als_mix_wr(sc, SB16_IMASK_L, l);
616 	als_mix_wr(sc, SB16_IMASK_R, r);
617 	return src;
618 }
619 
620 static kobj_method_t als_mixer_methods[] = {
621 	KOBJMETHOD(mixer_init,		alsmix_init),
622 	KOBJMETHOD(mixer_set,		alsmix_set),
623 	KOBJMETHOD(mixer_setrecsrc,	alsmix_setrecsrc),
624 	{ 0, 0 }
625 };
626 MIXER_DECLARE(als_mixer);
627 
628 /* ------------------------------------------------------------------------- */
629 /* Interrupt Handler */
630 
631 static void
632 als_intr(void *p)
633 {
634 	struct sc_info *sc = (struct sc_info *)p;
635 	u_int8_t intr, sb_status;
636 
637 	snd_mtxlock(sc->lock);
638 	intr = als_intr_rd(sc);
639 
640 	if (intr & 0x80) {
641 		snd_mtxunlock(sc->lock);
642 		chn_intr(sc->pch.channel);
643 		snd_mtxlock(sc->lock);
644 	}
645 
646 	if (intr & 0x40) {
647 		snd_mtxunlock(sc->lock);
648 		chn_intr(sc->rch.channel);
649 		snd_mtxlock(sc->lock);
650 	}
651 
652 	/* ACK interrupt in PCI core */
653 	als_intr_wr(sc, intr);
654 
655 	/* ACK interrupt in SB core */
656 	sb_status = als_mix_rd(sc, IRQ_STAT);
657 
658 	if (sb_status & ALS_IRQ_STATUS8)
659 		als_ack_read(sc, ALS_ESP_RD_STATUS8);
660 	if (sb_status & ALS_IRQ_STATUS16)
661 		als_ack_read(sc, ALS_ESP_RD_STATUS16);
662 	if (sb_status & ALS_IRQ_MPUIN)
663 		als_ack_read(sc, ALS_MIDI_DATA);
664 	if (sb_status & ALS_IRQ_CR1E)
665 		als_ack_read(sc, ALS_CR1E_ACK_PORT);
666 
667 	snd_mtxunlock(sc->lock);
668 	return;
669 }
670 
671 /* ------------------------------------------------------------------------- */
672 /* H/W initialization */
673 
674 static int
675 als_init(struct sc_info *sc)
676 {
677 	u_int32_t i, v;
678 
679 	/* Reset Chip */
680 	if (als_esp_reset(sc)) {
681 		return 1;
682 	}
683 
684 	/* Enable write on DMA_SETUP register */
685 	v = als_mix_rd(sc, ALS_SB16_CONFIG);
686 	als_mix_wr(sc, ALS_SB16_CONFIG, v | 0x80);
687 
688 	/* Select DMA0 */
689 	als_mix_wr(sc, ALS_SB16_DMA_SETUP, 0x01);
690 
691 	/* Disable write on DMA_SETUP register */
692 	als_mix_wr(sc, ALS_SB16_CONFIG, v & 0x7f);
693 
694 	/* Enable interrupts */
695 	v  = als_gcr_rd(sc, ALS_GCR_MISC);
696 	als_gcr_wr(sc, ALS_GCR_MISC, v | 0x28000);
697 
698 	/* Black out GCR DMA registers */
699 	for (i = 0x91; i <= 0x96; i++) {
700 		als_gcr_wr(sc, i, 0);
701 	}
702 
703 	/* Emulation mode */
704 	v = als_gcr_rd(sc, ALS_GCR_DMA_EMULATION);
705 	als_gcr_wr(sc, ALS_GCR_DMA_EMULATION, v);
706 	DEB(printf("GCR_DMA_EMULATION 0x%08x\n", v));
707 	return 0;
708 }
709 
710 static void
711 als_uninit(struct sc_info *sc)
712 {
713 	/* Disable interrupts */
714 	als_gcr_wr(sc, ALS_GCR_MISC, 0);
715 }
716 
717 /* ------------------------------------------------------------------------- */
718 /* Probe and attach card */
719 
720 static int
721 als_pci_probe(device_t dev)
722 {
723 	if (pci_get_devid(dev) == ALS_PCI_ID0) {
724 		device_set_desc(dev, "Avance Logic ALS4000");
725 		return BUS_PROBE_DEFAULT;
726 	}
727 	return ENXIO;
728 }
729 
730 static void
731 als_resource_free(device_t dev, struct sc_info *sc)
732 {
733 	if (sc->reg) {
734 		bus_release_resource(dev, SYS_RES_IOPORT, sc->regid, sc->reg);
735 		sc->reg = 0;
736 	}
737 	if (sc->ih) {
738 		bus_teardown_intr(dev, sc->irq, sc->ih);
739 		sc->ih = 0;
740 	}
741 	if (sc->irq) {
742 		bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
743 		sc->irq = 0;
744 	}
745 	if (sc->parent_dmat) {
746 		bus_dma_tag_destroy(sc->parent_dmat);
747 		sc->parent_dmat = 0;
748 	}
749 	if (sc->lock) {
750 		snd_mtxfree(sc->lock);
751 		sc->lock = NULL;
752 	}
753 }
754 
755 static int
756 als_resource_grab(device_t dev, struct sc_info *sc)
757 {
758 	sc->regid = PCIR_BAR(0);
759 	sc->reg = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->regid, 0, ~0,
760 				     ALS_CONFIG_SPACE_BYTES, RF_ACTIVE);
761 	if (sc->reg == 0) {
762 		device_printf(dev, "unable to allocate register space\n");
763 		goto bad;
764 	}
765 	sc->st = rman_get_bustag(sc->reg);
766 	sc->sh = rman_get_bushandle(sc->reg);
767 
768 	sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid,
769 					 RF_ACTIVE | RF_SHAREABLE);
770 	if (sc->irq == 0) {
771 		device_printf(dev, "unable to allocate interrupt\n");
772 		goto bad;
773 	}
774 
775 	if (snd_setup_intr(dev, sc->irq, INTR_MPSAFE, als_intr,
776 			   sc, &sc->ih)) {
777 		device_printf(dev, "unable to setup interrupt\n");
778 		goto bad;
779 	}
780 
781 	sc->bufsz = pcm_getbuffersize(dev, 4096, ALS_DEFAULT_BUFSZ, 65536);
782 
783 	if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev),
784 			       /*alignment*/2, /*boundary*/0,
785 			       /*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
786 			       /*highaddr*/BUS_SPACE_MAXADDR,
787 			       /*filter*/NULL, /*filterarg*/NULL,
788 			       /*maxsize*/sc->bufsz,
789 			       /*nsegments*/1, /*maxsegz*/0x3ffff,
790 			       /*flags*/0, /*lockfunc*/NULL,
791 			       /*lockarg*/NULL, &sc->parent_dmat) != 0) {
792 		device_printf(dev, "unable to create dma tag\n");
793 		goto bad;
794 	}
795 	return 0;
796  bad:
797 	als_resource_free(dev, sc);
798 	return ENXIO;
799 }
800 
801 static int
802 als_pci_attach(device_t dev)
803 {
804 	struct sc_info *sc;
805 	u_int32_t data;
806 	char status[SND_STATUSLEN];
807 
808 	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
809 	sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_als4000 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 	snprintf(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 	free(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 	free(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