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