xref: /dragonfly/sys/dev/sound/pci/als4000.c (revision cfd1aba3)
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  */
28 
29 /*
30  * als4000.c - driver for the Avance Logic ALS 4000 chipset.
31  *
32  * The ALS4000 is effectively an SB16 with a PCI interface.
33  *
34  * This driver derives from ALS4000a.PDF, Bart Hartgers alsa driver, and
35  * SB16 register descriptions.
36  */
37 
38 #include <dev/sound/pcm/sound.h>
39 #include <dev/sound/pci/sb.h>
40 #include <dev/sound/pci/als4000.h>
41 
42 #include <bus/pci/pcireg.h>
43 #include <bus/pci/pcivar.h>
44 
45 #include "mixer_if.h"
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 	sndlock_t		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, 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(kprintf("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 static const 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 } 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 = NELEM(playback_cmds);
331 	for (i = 0; i < n; i++) {
332 		if (playback_cmds[i].pcm_format == format) {
333 			return &playback_cmds[i];
334 		}
335 	}
336 	DEB(kprintf("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 	snd_mtxlock(sc->lock);
395 	switch(go) {
396 	case PCMTRIG_START:
397 		als_playback_start(ch);
398 		break;
399 	case PCMTRIG_ABORT:
400 		als_playback_stop(ch);
401 		break;
402 	}
403 	snd_mtxunlock(sc->lock);
404 	return 0;
405 }
406 
407 static kobj_method_t alspchan_methods[] = {
408 	KOBJMETHOD(channel_init,		alschan_init),
409 	KOBJMETHOD(channel_setformat,		alschan_setformat),
410 	KOBJMETHOD(channel_setspeed,		alschan_setspeed),
411 	KOBJMETHOD(channel_setblocksize,	alschan_setblocksize),
412 	KOBJMETHOD(channel_trigger,		alspchan_trigger),
413 	KOBJMETHOD(channel_getptr,		alschan_getptr),
414 	KOBJMETHOD(channel_getcaps,		alschan_getcaps),
415 	KOBJMETHOD_END
416 };
417 CHANNEL_DECLARE(alspchan);
418 
419 /* ------------------------------------------------------------------------- */
420 /* Capture channel implementation */
421 
422 static u_int8_t
423 als_get_fifo_format(struct sc_info *sc, u_int32_t format)
424 {
425 	switch (format) {
426 	case AFMT_U8:
427 		return ALS_FIFO1_8BIT;
428 	case AFMT_U8 | AFMT_STEREO:
429 		return ALS_FIFO1_8BIT | ALS_FIFO1_STEREO;
430 	case AFMT_S16_LE:
431 		return ALS_FIFO1_SIGNED;
432 	case AFMT_S16_LE | AFMT_STEREO:
433 		return ALS_FIFO1_SIGNED | ALS_FIFO1_STEREO;
434 	}
435 	device_printf(sc->dev, "format not found: 0x%08x\n", format);
436 	return ALS_FIFO1_8BIT;
437 }
438 
439 static void
440 als_capture_start(struct sc_chinfo *ch)
441 {
442 	struct	sc_info *sc = ch->parent;
443 	u_int32_t	buf, bufsz, count, dma_prog;
444 
445 	buf = sndbuf_getbufaddr(ch->buffer);
446 	bufsz = sndbuf_getsize(ch->buffer);
447 	count = bufsz / 2;
448 	if (ch->format & AFMT_16BIT)
449 		count /= 2;
450 	count--;
451 
452 	als_esp_wr(sc, DSP_CMD_SPKON);
453 	als_set_speed(ch);
454 
455 	als_gcr_wr(sc, ALS_GCR_FIFO1_START, buf);
456 	als_gcr_wr(sc, ALS_GCR_FIFO1_COUNT, (bufsz - 1));
457 
458 	als_mix_wr(sc, ALS_FIFO1_LENGTH_LO, count & 0xff);
459 	als_mix_wr(sc, ALS_FIFO1_LENGTH_HI, count >> 8);
460 
461 	dma_prog = ALS_FIFO1_RUN | als_get_fifo_format(sc, ch->format);
462 	als_mix_wr(sc, ALS_FIFO1_CONTROL, dma_prog);
463 
464 	ch->dma_active = 1;
465 }
466 
467 static int
468 als_capture_stop(struct sc_chinfo *ch)
469 {
470 	struct sc_info *sc = ch->parent;
471 	u_int32_t active;
472 
473 	active = ch->dma_active;
474 	if (active) {
475 		als_mix_wr(sc, ALS_FIFO1_CONTROL, ALS_FIFO1_STOP);
476 	}
477 	ch->dma_active = 0;
478 	return active;
479 }
480 
481 static int
482 alsrchan_trigger(kobj_t obj, void *data, int go)
483 {
484 	struct	sc_chinfo *ch = data;
485 	struct sc_info *sc = ch->parent;
486 
487 	snd_mtxlock(sc->lock);
488 	switch(go) {
489 	case PCMTRIG_START:
490 		als_capture_start(ch);
491 		break;
492 	case PCMTRIG_ABORT:
493 		als_capture_stop(ch);
494 		break;
495 	}
496 	snd_mtxunlock(sc->lock);
497 	return 0;
498 }
499 
500 static kobj_method_t alsrchan_methods[] = {
501 	KOBJMETHOD(channel_init,		alschan_init),
502 	KOBJMETHOD(channel_setformat,		alschan_setformat),
503 	KOBJMETHOD(channel_setspeed,		alschan_setspeed),
504 	KOBJMETHOD(channel_setblocksize,	alschan_setblocksize),
505 	KOBJMETHOD(channel_trigger,		alsrchan_trigger),
506 	KOBJMETHOD(channel_getptr,		alschan_getptr),
507 	KOBJMETHOD(channel_getcaps,		alschan_getcaps),
508 	KOBJMETHOD_END
509 };
510 CHANNEL_DECLARE(alsrchan);
511 
512 /* ------------------------------------------------------------------------- */
513 /* Mixer related */
514 
515 /*
516  * ALS4000 has an sb16 mixer, with some additional controls that we do
517  * not yet a means to support.
518  */
519 
520 static const struct sb16props {
521 	u_int8_t lreg;
522 	u_int8_t rreg;
523 	u_int8_t bits;
524 	u_int8_t oselect;
525 	u_int8_t iselect; /* left input mask */
526 } amt[SOUND_MIXER_NRDEVICES] = {
527 	[SOUND_MIXER_VOLUME]  = { 0x30, 0x31, 5, 0x00, 0x00 },
528 	[SOUND_MIXER_PCM]     = { 0x32, 0x33, 5, 0x00, 0x00 },
529 	[SOUND_MIXER_SYNTH]   = { 0x34, 0x35, 5, 0x60, 0x40 },
530 	[SOUND_MIXER_CD]      = { 0x36, 0x37, 5, 0x06, 0x04 },
531 	[SOUND_MIXER_LINE]    = { 0x38, 0x39, 5, 0x18, 0x10 },
532 	[SOUND_MIXER_MIC]     = { 0x3a, 0x00, 5, 0x01, 0x01 },
533 	[SOUND_MIXER_SPEAKER] = { 0x3b, 0x00, 2, 0x00, 0x00 },
534 	[SOUND_MIXER_IGAIN]   = { 0x3f, 0x40, 2, 0x00, 0x00 },
535 	[SOUND_MIXER_OGAIN]   = { 0x41, 0x42, 2, 0x00, 0x00 },
536 	/* The following have register values but no h/w implementation */
537 	[SOUND_MIXER_TREBLE]  = { 0x44, 0x45, 4, 0x00, 0x00 },
538 	[SOUND_MIXER_BASS]    = { 0x46, 0x47, 4, 0x00, 0x00 }
539 };
540 
541 static int
542 alsmix_init(struct snd_mixer *m)
543 {
544 	u_int32_t i, v;
545 
546 	for (i = v = 0; i < SOUND_MIXER_NRDEVICES; i++) {
547 		if (amt[i].bits) v |= 1 << i;
548 	}
549 	mix_setdevs(m, v);
550 
551 	for (i = v = 0; i < SOUND_MIXER_NRDEVICES; i++) {
552 		if (amt[i].iselect) v |= 1 << i;
553 	}
554 	mix_setrecdevs(m, v);
555 	return 0;
556 }
557 
558 static int
559 alsmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
560 {
561 	struct sc_info *sc = mix_getdevinfo(m);
562 	u_int32_t r, l, v, mask;
563 
564 	/* Fill upper n bits in mask with 1's */
565 	mask = ((1 << amt[dev].bits) - 1) << (8 - amt[dev].bits);
566 
567 	l = (left * mask / 100) & mask;
568 	v = als_mix_rd(sc, amt[dev].lreg) & ~mask;
569 	als_mix_wr(sc, amt[dev].lreg, l | v);
570 
571 	if (amt[dev].rreg) {
572 		r = (right * mask / 100) & mask;
573 		v = als_mix_rd(sc, amt[dev].rreg) & ~mask;
574 		als_mix_wr(sc, amt[dev].rreg, r | v);
575 	} else {
576 		r = 0;
577 	}
578 
579 	/* Zero gain does not mute channel from output, but this does. */
580 	v = als_mix_rd(sc, SB16_OMASK);
581 	if (l == 0 && r == 0) {
582 		v &= ~amt[dev].oselect;
583 	} else {
584 		v |= amt[dev].oselect;
585 	}
586 	als_mix_wr(sc, SB16_OMASK, v);
587 	return 0;
588 }
589 
590 static int
591 alsmix_setrecsrc(struct snd_mixer *m, u_int32_t src)
592 {
593 	struct sc_info *sc = mix_getdevinfo(m);
594 	u_int32_t i, l, r;
595 
596 	for (i = l = r = 0; i < SOUND_MIXER_NRDEVICES; i++) {
597 		if (src & (1 << i)) {
598 			if (amt[i].iselect == 1) {	/* microphone */
599 				l |= amt[i].iselect;
600 				r |= amt[i].iselect;
601 			} else {
602 				l |= amt[i].iselect;
603 				r |= amt[i].iselect >> 1;
604 			}
605 		}
606 	}
607 
608 	als_mix_wr(sc, SB16_IMASK_L, l);
609 	als_mix_wr(sc, SB16_IMASK_R, r);
610 	return src;
611 }
612 
613 static kobj_method_t als_mixer_methods[] = {
614 	KOBJMETHOD(mixer_init,		alsmix_init),
615 	KOBJMETHOD(mixer_set,		alsmix_set),
616 	KOBJMETHOD(mixer_setrecsrc,	alsmix_setrecsrc),
617 	KOBJMETHOD_END
618 };
619 MIXER_DECLARE(als_mixer);
620 
621 /* ------------------------------------------------------------------------- */
622 /* Interrupt Handler */
623 
624 static void
625 als_intr(void *p)
626 {
627 	struct sc_info *sc = (struct sc_info *)p;
628 	u_int8_t intr, sb_status;
629 
630 	snd_mtxlock(sc->lock);
631 	intr = als_intr_rd(sc);
632 
633 	if (intr & 0x80) {
634 		snd_mtxunlock(sc->lock);
635 		chn_intr(sc->pch.channel);
636 		snd_mtxlock(sc->lock);
637 	}
638 
639 	if (intr & 0x40) {
640 		snd_mtxunlock(sc->lock);
641 		chn_intr(sc->rch.channel);
642 		snd_mtxlock(sc->lock);
643 	}
644 
645 	/* ACK interrupt in PCI core */
646 	als_intr_wr(sc, intr);
647 
648 	/* ACK interrupt in SB core */
649 	sb_status = als_mix_rd(sc, IRQ_STAT);
650 
651 	if (sb_status & ALS_IRQ_STATUS8)
652 		als_ack_read(sc, ALS_ESP_RD_STATUS8);
653 	if (sb_status & ALS_IRQ_STATUS16)
654 		als_ack_read(sc, ALS_ESP_RD_STATUS16);
655 	if (sb_status & ALS_IRQ_MPUIN)
656 		als_ack_read(sc, ALS_MIDI_DATA);
657 	if (sb_status & ALS_IRQ_CR1E)
658 		als_ack_read(sc, ALS_CR1E_ACK_PORT);
659 
660 	snd_mtxunlock(sc->lock);
661 	return;
662 }
663 
664 /* ------------------------------------------------------------------------- */
665 /* H/W initialization */
666 
667 static int
668 als_init(struct sc_info *sc)
669 {
670 	u_int32_t i, v;
671 
672 	/* Reset Chip */
673 	if (als_esp_reset(sc)) {
674 		return 1;
675 	}
676 
677 	/* Enable write on DMA_SETUP register */
678 	v = als_mix_rd(sc, ALS_SB16_CONFIG);
679 	als_mix_wr(sc, ALS_SB16_CONFIG, v | 0x80);
680 
681 	/* Select DMA0 */
682 	als_mix_wr(sc, ALS_SB16_DMA_SETUP, 0x01);
683 
684 	/* Disable write on DMA_SETUP register */
685 	als_mix_wr(sc, ALS_SB16_CONFIG, v & 0x7f);
686 
687 	/* Enable interrupts */
688 	v  = als_gcr_rd(sc, ALS_GCR_MISC);
689 	als_gcr_wr(sc, ALS_GCR_MISC, v | 0x28000);
690 
691 	/* Black out GCR DMA registers */
692 	for (i = 0x91; i <= 0x96; i++) {
693 		als_gcr_wr(sc, i, 0);
694 	}
695 
696 	/* Emulation mode */
697 	v = als_gcr_rd(sc, ALS_GCR_DMA_EMULATION);
698 	als_gcr_wr(sc, ALS_GCR_DMA_EMULATION, v);
699 	DEB(kprintf("GCR_DMA_EMULATION 0x%08x\n", v));
700 	return 0;
701 }
702 
703 static void
704 als_uninit(struct sc_info *sc)
705 {
706 	/* Disable interrupts */
707 	als_gcr_wr(sc, ALS_GCR_MISC, 0);
708 }
709 
710 /* ------------------------------------------------------------------------- */
711 /* Probe and attach card */
712 
713 static int
714 als_pci_probe(device_t dev)
715 {
716 	if (pci_get_devid(dev) == ALS_PCI_ID0) {
717 		device_set_desc(dev, "Avance Logic ALS4000");
718 		return BUS_PROBE_DEFAULT;
719 	}
720 	return ENXIO;
721 }
722 
723 static void
724 als_resource_free(device_t dev, struct sc_info *sc)
725 {
726 	if (sc->reg) {
727 		bus_release_resource(dev, SYS_RES_IOPORT, sc->regid, sc->reg);
728 		sc->reg = NULL;
729 	}
730 	if (sc->ih) {
731 		bus_teardown_intr(dev, sc->irq, sc->ih);
732 		sc->ih = NULL;
733 	}
734 	if (sc->irq) {
735 		bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
736 		sc->irq = NULL;
737 	}
738 	if (sc->parent_dmat) {
739 		bus_dma_tag_destroy(sc->parent_dmat);
740 		sc->parent_dmat = 0;
741 	}
742 	if (sc->lock) {
743 		snd_mtxfree(sc->lock);
744 		sc->lock = NULL;
745 	}
746 }
747 
748 static int
749 als_resource_grab(device_t dev, struct sc_info *sc)
750 {
751 	sc->regid = PCIR_BAR(0);
752 	sc->reg = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->regid, 0, ~0,
753 				     ALS_CONFIG_SPACE_BYTES, RF_ACTIVE);
754 	if (sc->reg == NULL) {
755 		device_printf(dev, "unable to allocate register space\n");
756 		goto bad;
757 	}
758 	sc->st = rman_get_bustag(sc->reg);
759 	sc->sh = rman_get_bushandle(sc->reg);
760 
761 	sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid,
762 					 RF_ACTIVE | RF_SHAREABLE);
763 	if (sc->irq == NULL) {
764 		device_printf(dev, "unable to allocate interrupt\n");
765 		goto bad;
766 	}
767 
768 	if (snd_setup_intr(dev, sc->irq, INTR_MPSAFE, als_intr,
769 			   sc, &sc->ih)) {
770 		device_printf(dev, "unable to setup interrupt\n");
771 		goto bad;
772 	}
773 
774 	sc->bufsz = pcm_getbuffersize(dev, 4096, ALS_DEFAULT_BUFSZ, 65536);
775 
776 	if (bus_dma_tag_create(/*parent*/NULL,
777 			       /*alignment*/2, /*boundary*/0,
778 			       /*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
779 			       /*highaddr*/BUS_SPACE_MAXADDR,
780 			       /*filter*/NULL, /*filterarg*/NULL,
781 			       /*maxsize*/sc->bufsz,
782 			       /*nsegments*/1, /*maxsegz*/0x3ffff,
783 			       /*flags*/0,
784 			       &sc->parent_dmat) != 0) {
785 		device_printf(dev, "unable to create dma tag\n");
786 		goto bad;
787 	}
788 	return 0;
789  bad:
790 	als_resource_free(dev, sc);
791 	return ENXIO;
792 }
793 
794 static int
795 als_pci_attach(device_t dev)
796 {
797 	struct sc_info *sc;
798 	u_int32_t data;
799 	char status[SND_STATUSLEN];
800 
801 	sc = kmalloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
802 	sc->lock = snd_mtxcreate(device_get_nameunit(dev), "sound softc");
803 	sc->dev = dev;
804 
805 	data = pci_read_config(dev, PCIR_COMMAND, 2);
806 	data |= (PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
807 	pci_write_config(dev, PCIR_COMMAND, data, 2);
808 	/*
809 	 * By default the power to the various components on the
810          * ALS4000 is entirely controlled by the pci powerstate.  We
811          * could attempt finer grained control by setting GCR6.31.
812 	 */
813 	if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
814 		/* Reset the power state. */
815 		device_printf(dev, "chip is in D%d power mode "
816 			      "-- setting to D0\n", pci_get_powerstate(dev));
817 		pci_set_powerstate(dev, PCI_POWERSTATE_D0);
818 	}
819 
820 	if (als_resource_grab(dev, sc)) {
821 		device_printf(dev, "failed to allocate resources\n");
822 		goto bad_attach;
823 	}
824 
825 	if (als_init(sc)) {
826 		device_printf(dev, "failed to initialize hardware\n");
827 		goto bad_attach;
828 	}
829 
830 	if (mixer_init(dev, &als_mixer_class, sc)) {
831 		device_printf(dev, "failed to initialize mixer\n");
832 		goto bad_attach;
833 	}
834 
835 	if (pcm_register(dev, sc, 1, 1)) {
836 		device_printf(dev, "failed to register pcm entries\n");
837 		goto bad_attach;
838 	}
839 
840 	pcm_addchan(dev, PCMDIR_PLAY, &alspchan_class, sc);
841 	pcm_addchan(dev, PCMDIR_REC,  &alsrchan_class, sc);
842 
843 	ksnprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s",
844 		 rman_get_start(sc->reg), rman_get_start(sc->irq),PCM_KLDSTRING(snd_als4000));
845 	pcm_setstatus(dev, status);
846 	return 0;
847 
848  bad_attach:
849 	als_resource_free(dev, sc);
850 	kfree(sc, M_DEVBUF);
851 	return ENXIO;
852 }
853 
854 static int
855 als_pci_detach(device_t dev)
856 {
857 	struct sc_info *sc;
858 	int r;
859 
860 	r = pcm_unregister(dev);
861 	if (r)
862 		return r;
863 
864 	sc = pcm_getdevinfo(dev);
865 	als_uninit(sc);
866 	als_resource_free(dev, sc);
867 	kfree(sc, M_DEVBUF);
868 	return 0;
869 }
870 
871 static int
872 als_pci_suspend(device_t dev)
873 {
874 	struct sc_info *sc = pcm_getdevinfo(dev);
875 
876 	snd_mtxlock(sc->lock);
877 	sc->pch.dma_was_active = als_playback_stop(&sc->pch);
878 	sc->rch.dma_was_active = als_capture_stop(&sc->rch);
879 	als_uninit(sc);
880 	snd_mtxunlock(sc->lock);
881 	return 0;
882 }
883 
884 static int
885 als_pci_resume(device_t dev)
886 {
887 	struct sc_info *sc = pcm_getdevinfo(dev);
888 
889 
890 	snd_mtxlock(sc->lock);
891 	if (als_init(sc) != 0) {
892 		device_printf(dev, "unable to reinitialize the card\n");
893 		snd_mtxunlock(sc->lock);
894 		return ENXIO;
895 	}
896 
897 	if (mixer_reinit(dev) != 0) {
898 		device_printf(dev, "unable to reinitialize the mixer\n");
899 		snd_mtxunlock(sc->lock);
900 		return ENXIO;
901 	}
902 
903 	if (sc->pch.dma_was_active) {
904 		als_playback_start(&sc->pch);
905 	}
906 
907 	if (sc->rch.dma_was_active) {
908 		als_capture_start(&sc->rch);
909 	}
910 	snd_mtxunlock(sc->lock);
911 
912 	return 0;
913 }
914 
915 static device_method_t als_methods[] = {
916 	/* Device interface */
917 	DEVMETHOD(device_probe,		als_pci_probe),
918 	DEVMETHOD(device_attach,	als_pci_attach),
919 	DEVMETHOD(device_detach,	als_pci_detach),
920 	DEVMETHOD(device_suspend,	als_pci_suspend),
921 	DEVMETHOD(device_resume,	als_pci_resume),
922 	DEVMETHOD_END
923 };
924 
925 static driver_t als_driver = {
926 	"pcm",
927 	als_methods,
928 	PCM_SOFTC_SIZE,
929 };
930 
931 DRIVER_MODULE(snd_als4000, pci, als_driver, pcm_devclass, NULL, NULL);
932 MODULE_DEPEND(snd_als4000, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
933 MODULE_VERSION(snd_als4000, 1);
934