xref: /openbsd-src/sys/dev/pci/fms.c (revision 3374c67d44f9b75b98444cbf63020f777792342e)
1 /*	$OpenBSD: fms.c,v 1.36 2022/10/26 20:19:08 kn Exp $ */
2 /*	$NetBSD: fms.c,v 1.5.4.1 2000/06/30 16:27:50 simonb Exp $	*/
3 
4 /*-
5  * Copyright (c) 1999 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Witold J. Wnuk.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * Forte Media FM801 Audio Device Driver
35  */
36 
37 #include "radio.h"
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/malloc.h>
43 #include <sys/device.h>
44 #include <sys/audioio.h>
45 
46 #include <machine/bus.h>
47 #include <machine/cpu.h>
48 
49 #include <dev/pci/pcidevs.h>
50 #include <dev/pci/pcivar.h>
51 
52 #include <dev/audio_if.h>
53 #include <dev/ic/ac97.h>
54 #if 0
55 #include <dev/ic/mpuvar.h>
56 #endif
57 
58 #include <dev/pci/fmsreg.h>
59 #include <dev/pci/fmsvar.h>
60 
61 
62 struct fms_dma {
63 	struct fms_dma *next;
64 	caddr_t addr;
65 	size_t size;
66 	bus_dmamap_t map;
67 	bus_dma_segment_t seg;
68 };
69 
70 
71 
72 int	fms_match(struct device *, void *, void *);
73 void	fms_attach(struct device *, struct device *, void *);
74 int	fms_intr(void *);
75 
76 int	fms_open(void *, int);
77 void	fms_close(void *);
78 int	fms_set_params(void *, int, int, struct audio_params *,
79 			    struct audio_params *);
80 int	fms_round_blocksize(void *, int);
81 int	fms_halt_output(void *);
82 int	fms_halt_input(void *);
83 int	fms_set_port(void *, mixer_ctrl_t *);
84 int	fms_get_port(void *, mixer_ctrl_t *);
85 int	fms_query_devinfo(void *, mixer_devinfo_t *);
86 void	*fms_malloc(void *, int, size_t, int, int);
87 void	fms_free(void *, void *, int);
88 int	fms_trigger_output(void *, void *, void *, int, void (*)(void *),
89 			   void *, struct audio_params *);
90 int	fms_trigger_input(void *, void *, void *, int, void (*)(void *),
91 			  void *, struct audio_params *);
92 
93 struct  cfdriver fms_cd = {
94 	NULL, "fms", DV_DULL
95 };
96 
97 const struct cfattach fms_ca = {
98 	sizeof (struct fms_softc), fms_match, fms_attach
99 };
100 
101 const struct audio_hw_if fms_hw_if = {
102 	.open = fms_open,
103 	.close = fms_close,
104 	.set_params = fms_set_params,
105 	.round_blocksize = fms_round_blocksize,
106 	.halt_output = fms_halt_output,
107 	.halt_input = fms_halt_input,
108 	.set_port = fms_set_port,
109 	.get_port = fms_get_port,
110 	.query_devinfo = fms_query_devinfo,
111 	.allocm = fms_malloc,
112 	.freem = fms_free,
113 	.trigger_output = fms_trigger_output,
114 	.trigger_input = fms_trigger_input,
115 };
116 
117 int	fms_attach_codec(void *, struct ac97_codec_if *);
118 int	fms_read_codec(void *, u_int8_t, u_int16_t *);
119 int	fms_write_codec(void *, u_int8_t, u_int16_t);
120 void	fms_reset_codec(void *);
121 
122 int	fms_allocmem(struct fms_softc *, size_t, size_t,
123 			  struct fms_dma *);
124 int	fms_freemem(struct fms_softc *, struct fms_dma *);
125 
126 int
127 fms_match(struct device *parent, void *match, void *aux)
128 {
129 	struct pci_attach_args *pa = (struct pci_attach_args *) aux;
130 
131 	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_FORTEMEDIA &&
132 	    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_FORTEMEDIA_FM801)
133 		return (1);
134 	return (0);
135 }
136 
137 void
138 fms_attach(struct device *parent, struct device *self, void *aux)
139 {
140 	struct pci_attach_args *pa = aux;
141 	struct fms_softc *sc = (struct fms_softc *) self;
142 	struct audio_attach_args aa;
143 	pci_chipset_tag_t pc = pa->pa_pc;
144 	pcitag_t pt = pa->pa_tag;
145 	pci_intr_handle_t ih;
146 	bus_size_t iosize;
147 	const char *intrstr;
148 	u_int16_t k1;
149 	int i;
150 
151 	if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_IO, 0, &sc->sc_iot,
152 	    &sc->sc_ioh, NULL, &iosize, 0)) {
153 		printf(": can't map i/o space\n");
154 		return;
155 	}
156 
157 	if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, 0x30, 2,
158 	    &sc->sc_mpu_ioh)) {
159 		printf(": can't get mpu subregion handle\n");
160 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
161 		return;
162 	}
163 
164 	if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, 0x68, 4,
165 	    &sc->sc_opl_ioh)) {
166 		printf(": can't get opl subregion handle\n");
167 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
168 		return;
169 	}
170 
171 	if (pci_intr_map(pa, &ih)) {
172 		printf(": couldn't map interrupt\n");
173 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
174 		return;
175 	}
176 	intrstr = pci_intr_string(pc, ih);
177 
178 	sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO | IPL_MPSAFE,
179 	    fms_intr, sc, sc->sc_dev.dv_xname);
180 	if (sc->sc_ih == NULL) {
181 		printf(": couldn't establish interrupt");
182 		if (intrstr != NULL)
183 			printf(" at %s", intrstr);
184 		printf("\n");
185 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
186 		return;
187 	}
188 
189 	printf(": %s\n", intrstr);
190 
191 	sc->sc_dmat = pa->pa_dmat;
192 
193 	/* Disable legacy audio (SBPro compatibility) */
194 	pci_conf_write(pc, pt, 0x40, 0);
195 
196 	/* Reset codec and AC'97 */
197 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0020);
198 	delay(2);		/* > 1us according to AC'97 documentation */
199 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0000);
200 	delay(1);		/* > 168.2ns according to AC'97 documentation */
201 
202 	/* Set up volume */
203 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PCM_VOLUME, 0x0808);
204 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_FM_VOLUME, 0x0808);
205 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_I2S_VOLUME, 0x0808);
206 
207 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_RECORD_SOURCE, 0x0000);
208 
209 	/* Unmask playback, record and mpu interrupts, mask the rest */
210 	k1 = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_INTMASK);
211 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_INTMASK,
212 	    (k1 & ~(FM_INTMASK_PLAY | FM_INTMASK_REC | FM_INTMASK_MPU)) |
213 	     FM_INTMASK_VOL);
214 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS,
215 	    FM_INTSTATUS_PLAY | FM_INTSTATUS_REC | FM_INTSTATUS_MPU |
216 	    FM_INTSTATUS_VOL);
217 
218 #if NRADIO > 0
219 	fmsradio_attach(sc);
220 #endif /* NRADIO > 0 */
221 
222 	sc->host_if.arg = sc;
223 	sc->host_if.attach = fms_attach_codec;
224 	sc->host_if.read = fms_read_codec;
225 	sc->host_if.write = fms_write_codec;
226 	sc->host_if.reset = fms_reset_codec;
227 
228 	if (ac97_attach(&sc->host_if) != 0)
229 		return;
230 
231 	/* Turn mute off */
232 	for (i = 0; i < 3; i++) {
233 		static struct {
234 			char *class, *device;
235 		} d[] = {
236 			{ AudioCoutputs, AudioNmaster },
237 			{ AudioCinputs, AudioNdac },
238 			{ AudioCrecord, AudioNvolume }
239 		};
240 		struct mixer_ctrl ctl;
241 
242 		ctl.type = AUDIO_MIXER_ENUM;
243 		ctl.un.ord = 0;
244 		ctl.dev = sc->codec_if->vtbl->get_portnum_by_name(sc->codec_if,
245 			d[i].class, d[i].device, AudioNmute);
246 		fms_set_port(sc, &ctl);
247 	}
248 
249 	audio_attach_mi(&fms_hw_if, sc, NULL, &sc->sc_dev);
250 
251 	aa.type = AUDIODEV_TYPE_OPL;
252 	aa.hwif = NULL;
253 	aa.hdl = NULL;
254 	config_found(&sc->sc_dev, &aa, audioprint);
255 
256 	aa.type = AUDIODEV_TYPE_MPU;
257 	aa.hwif = NULL;
258 	aa.hdl = NULL;
259 	sc->sc_mpu_dev = config_found(&sc->sc_dev, &aa, audioprint);
260 }
261 
262 /*
263  * Each AC-link frame takes 20.8us, data should be ready in next frame,
264  * we allow more than two.
265  */
266 #define TIMO 50
267 int
268 fms_read_codec(void *addr, u_int8_t reg, u_int16_t *val)
269 {
270 	struct fms_softc *sc = addr;
271 	int i;
272 
273 	/* Poll until codec is ready */
274 	for (i = 0; i < TIMO && bus_space_read_2(sc->sc_iot, sc->sc_ioh,
275 		 FM_CODEC_CMD) & FM_CODEC_CMD_BUSY; i++)
276 		delay(1);
277 	if (i >= TIMO) {
278 		printf("fms: codec busy\n");
279 		return 1;
280 	}
281 
282 	/* Write register index, read access */
283 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CMD,
284 			  reg | FM_CODEC_CMD_READ);
285 
286 	/* Poll until we have valid data */
287 	for (i = 0; i < TIMO && !(bus_space_read_2(sc->sc_iot, sc->sc_ioh,
288 		 FM_CODEC_CMD) & FM_CODEC_CMD_VALID); i++)
289 		delay(1);
290 	if (i >= TIMO) {
291 		printf("fms: no data from codec\n");
292 		return 1;
293 	}
294 
295 	/* Read data */
296 	*val = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_DATA);
297 	return 0;
298 }
299 
300 int
301 fms_write_codec(void *addr, u_int8_t reg, u_int16_t val)
302 {
303 	struct fms_softc *sc = addr;
304 	int i;
305 
306 	/* Poll until codec is ready */
307 	for (i = 0; i < TIMO && bus_space_read_2(sc->sc_iot, sc->sc_ioh,
308 		 FM_CODEC_CMD) & FM_CODEC_CMD_BUSY; i++)
309 		delay(1);
310 	if (i >= TIMO) {
311 		printf("fms: codec busy\n");
312 		return 1;
313 	}
314 
315 	/* Write data */
316 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_DATA, val);
317 	/* Write index register, write access */
318 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CMD, reg);
319 	return 0;
320 }
321 #undef TIMO
322 
323 int
324 fms_attach_codec(void *addr, struct ac97_codec_if *cif)
325 {
326 	struct fms_softc *sc = addr;
327 
328 	sc->codec_if = cif;
329 	return 0;
330 }
331 
332 /* Cold Reset */
333 void
334 fms_reset_codec(void *addr)
335 {
336 	struct fms_softc *sc = addr;
337 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0020);
338 	delay(2);
339 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0000);
340 	delay(1);
341 }
342 
343 int
344 fms_intr(void *arg)
345 {
346 	struct fms_softc *sc = arg;
347 	u_int16_t istat;
348 
349 	mtx_enter(&audio_lock);
350 	istat = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS);
351 
352 	if (istat & FM_INTSTATUS_PLAY) {
353 		if ((sc->sc_play_nextblk += sc->sc_play_blksize) >=
354 		     sc->sc_play_end)
355 			sc->sc_play_nextblk = sc->sc_play_start;
356 
357 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
358 		    sc->sc_play_flip++ & 1 ?
359 		    FM_PLAY_DMABUF2 : FM_PLAY_DMABUF1, sc->sc_play_nextblk);
360 
361 		if (sc->sc_pintr)
362 			sc->sc_pintr(sc->sc_parg);
363 		else
364 			printf("unexpected play intr\n");
365 	}
366 
367 	if (istat & FM_INTSTATUS_REC) {
368 		if ((sc->sc_rec_nextblk += sc->sc_rec_blksize) >=
369 		     sc->sc_rec_end)
370 			sc->sc_rec_nextblk = sc->sc_rec_start;
371 
372 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
373 		    sc->sc_rec_flip++ & 1 ?
374 		    FM_REC_DMABUF2 : FM_REC_DMABUF1, sc->sc_rec_nextblk);
375 
376 		if (sc->sc_rintr)
377 			sc->sc_rintr(sc->sc_rarg);
378 		else
379 			printf("unexpected rec intr\n");
380 	}
381 
382 #if 0
383 	if (istat & FM_INTSTATUS_MPU)
384 		mpu_intr(sc->sc_mpu_dev);
385 #endif
386 
387 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS,
388 			  istat & (FM_INTSTATUS_PLAY | FM_INTSTATUS_REC));
389 	mtx_leave(&audio_lock);
390 	return 1;
391 }
392 
393 int
394 fms_open(void *addr, int flags)
395 {
396 	/* UNUSED struct fms_softc *sc = addr;*/
397 
398 	return 0;
399 }
400 
401 void
402 fms_close(void *addr)
403 {
404 	/* UNUSED struct fms_softc *sc = addr;*/
405 }
406 
407 /*
408  * Range below -limit- is set to -rate-
409  * What a pity FM801 does not have 24000
410  * 24000 -> 22050 sounds rather poor
411  */
412 struct {
413 	int limit;
414 	int rate;
415 } fms_rates[11] = {
416 	{  6600,  5500 },
417 	{  8750,  8000 },
418 	{ 10250,  9600 },
419 	{ 13200, 11025 },
420 	{ 17500, 16000 },
421 	{ 20500, 19200 },
422 	{ 26500, 22050 },
423 	{ 35000, 32000 },
424 	{ 41000, 38400 },
425 	{ 46000, 44100 },
426 	{ 48000, 48000 },
427 	/* anything above -> 48000 */
428 };
429 
430 int
431 fms_set_params(void *addr, int setmode, int usemode, struct audio_params *play,
432     struct audio_params *rec)
433 {
434 	struct fms_softc *sc = addr;
435 	int i;
436 
437 	if (setmode & AUMODE_PLAY) {
438 		switch(play->encoding) {
439 		case AUDIO_ENCODING_SLINEAR_LE:
440 			if (play->precision != 16)
441 				return EINVAL;
442 			break;
443 		case AUDIO_ENCODING_ULINEAR_LE:
444 		case AUDIO_ENCODING_ULINEAR_BE:
445 			if (play->precision != 8)
446 				return EINVAL;
447 			break;
448 		default:
449 			return EINVAL;
450 		}
451 		play->bps = AUDIO_BPS(play->precision);
452 		play->msb = 1;
453 
454 		for (i = 0; i < 10 && play->sample_rate > fms_rates[i].limit;
455 		     i++)
456 			;
457 		play->sample_rate = fms_rates[i].rate;
458 		sc->sc_play_reg = (play->channels == 2 ? FM_PLAY_STEREO : 0) |
459 		    (play->precision == 16 ? FM_PLAY_16BIT : 0) |
460 		    (i << 8);
461 	}
462 
463 	if (setmode & AUMODE_RECORD) {
464 
465 		switch(rec->encoding) {
466 		case AUDIO_ENCODING_SLINEAR_LE:
467 			if (rec->precision != 16)
468 				return EINVAL;
469 			break;
470 		case AUDIO_ENCODING_ULINEAR_LE:
471 		case AUDIO_ENCODING_ULINEAR_BE:
472 			if (rec->precision != 8)
473 				return EINVAL;
474 			break;
475 		default:
476 			return EINVAL;
477 		}
478 		rec->bps = AUDIO_BPS(rec->precision);
479 		rec->msb = 1;
480 
481 		for (i = 0; i < 10 && rec->sample_rate > fms_rates[i].limit;
482 		     i++)
483 			;
484 		rec->sample_rate = fms_rates[i].rate;
485 		sc->sc_rec_reg =
486 		    (rec->channels == 2 ? FM_REC_STEREO : 0) |
487 		    (rec->precision == 16 ? FM_REC_16BIT : 0) |
488 		    (i << 8);
489 	}
490 
491 	return 0;
492 }
493 
494 int
495 fms_round_blocksize(void *addr, int blk)
496 {
497 	return (blk + 0xf) & ~0xf;
498 }
499 
500 int
501 fms_halt_output(void *addr)
502 {
503 	struct fms_softc *sc = addr;
504 	u_int16_t k1;
505 
506 	mtx_enter(&audio_lock);
507 	k1 = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL);
508 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL,
509 			  (k1 & ~(FM_PLAY_STOPNOW | FM_PLAY_START)) |
510 			  FM_PLAY_BUF1_LAST | FM_PLAY_BUF2_LAST);
511 	mtx_leave(&audio_lock);
512 	return 0;
513 }
514 
515 int
516 fms_halt_input(void *addr)
517 {
518 	struct fms_softc *sc = addr;
519 	u_int16_t k1;
520 
521 	mtx_enter(&audio_lock);
522 	k1 = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL);
523 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL,
524 			  (k1 & ~(FM_REC_STOPNOW | FM_REC_START)) |
525 			  FM_REC_BUF1_LAST | FM_REC_BUF2_LAST);
526 	mtx_leave(&audio_lock);
527 	return 0;
528 }
529 
530 int
531 fms_set_port(void *addr, mixer_ctrl_t *cp)
532 {
533 	struct fms_softc *sc = addr;
534 
535 	return (sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp));
536 }
537 
538 int
539 fms_get_port(void *addr, mixer_ctrl_t *cp)
540 {
541 	struct fms_softc *sc = addr;
542 
543 	return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp));
544 }
545 
546 void *
547 fms_malloc(void *addr, int direction, size_t size, int pool, int flags)
548 {
549 	struct fms_softc *sc = addr;
550 	struct fms_dma *p;
551 	int error;
552 	int rseg;
553 
554 	p = malloc(sizeof(*p), pool, flags);
555 	if (!p)
556 		return 0;
557 
558 	p->size = size;
559 	if ((error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, 0, &p->seg, 1,
560 				      &rseg, BUS_DMA_NOWAIT)) != 0) {
561 		printf("%s: unable to allocate dma, error = %d\n",
562 		       sc->sc_dev.dv_xname, error);
563 		goto fail_alloc;
564 	}
565 
566 	if ((error = bus_dmamem_map(sc->sc_dmat, &p->seg, rseg, size, &p->addr,
567 				    BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
568 		printf("%s: unable to map dma, error = %d\n",
569 		       sc->sc_dev.dv_xname, error);
570 		goto fail_map;
571 	}
572 
573 	if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
574 				       BUS_DMA_NOWAIT, &p->map)) != 0) {
575 		printf("%s: unable to create dma map, error = %d\n",
576 		       sc->sc_dev.dv_xname, error);
577 		goto fail_create;
578 	}
579 
580 	if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, size, NULL,
581 				     BUS_DMA_NOWAIT)) != 0) {
582 		printf("%s: unable to load dma map, error = %d\n",
583 		       sc->sc_dev.dv_xname, error);
584 		goto fail_load;
585 	}
586 
587 	p->next = sc->sc_dmas;
588 	sc->sc_dmas = p;
589 
590 	return p->addr;
591 
592 
593 fail_load:
594 	bus_dmamap_destroy(sc->sc_dmat, p->map);
595 fail_create:
596 	bus_dmamem_unmap(sc->sc_dmat, p->addr, size);
597 fail_map:
598 	bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
599 fail_alloc:
600 	free(p, pool, sizeof(*p));
601 	return 0;
602 }
603 
604 void
605 fms_free(void *addr, void *ptr, int pool)
606 {
607 	struct fms_softc *sc = addr;
608 	struct fms_dma **pp, *p;
609 
610 	for (pp = &(sc->sc_dmas); (p = *pp) != NULL; pp = &p->next)
611 		if (p->addr == ptr) {
612 			bus_dmamap_unload(sc->sc_dmat, p->map);
613 			bus_dmamap_destroy(sc->sc_dmat, p->map);
614 			bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size);
615 			bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
616 
617 			*pp = p->next;
618 			free(p, pool, sizeof(*p));
619 			return;
620 		}
621 
622 	panic("fms_free: trying to free unallocated memory");
623 }
624 
625 int
626 fms_query_devinfo(void *addr, mixer_devinfo_t *dip)
627 {
628 	struct fms_softc *sc = addr;
629 
630 	return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, dip));
631 }
632 
633 int
634 fms_trigger_output(void *addr, void *start, void *end, int blksize,
635     void (*intr)(void *), void *arg, struct audio_params *param)
636 {
637 	struct fms_softc *sc = addr;
638 	struct fms_dma *p;
639 
640 	sc->sc_pintr = intr;
641 	sc->sc_parg = arg;
642 
643 	for (p = sc->sc_dmas; p && p->addr != start; p = p->next)
644 		;
645 
646 	if (!p)
647 		panic("fms_trigger_output: request with bad start "
648 		      "address (%p)", start);
649 
650 	sc->sc_play_start = p->map->dm_segs[0].ds_addr;
651 	sc->sc_play_end = sc->sc_play_start + ((char *)end - (char *)start);
652 	sc->sc_play_blksize = blksize;
653 	sc->sc_play_nextblk = sc->sc_play_start + sc->sc_play_blksize;
654 	sc->sc_play_flip = 0;
655 	mtx_enter(&audio_lock);
656 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_DMALEN, blksize - 1);
657 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_PLAY_DMABUF1,
658 			  sc->sc_play_start);
659 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_PLAY_DMABUF2,
660 			  sc->sc_play_nextblk);
661 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL,
662 			  FM_PLAY_START | FM_PLAY_STOPNOW | sc->sc_play_reg);
663 	mtx_leave(&audio_lock);
664 	return 0;
665 }
666 
667 
668 int
669 fms_trigger_input(void *addr, void *start, void *end, int blksize,
670     void (*intr)(void *), void *arg, struct audio_params *param)
671 {
672 	struct fms_softc *sc = addr;
673 	struct fms_dma *p;
674 
675 	sc->sc_rintr = intr;
676 	sc->sc_rarg = arg;
677 
678 	for (p = sc->sc_dmas; p && p->addr != start; p = p->next)
679 		;
680 
681 	if (!p)
682 		panic("fms_trigger_input: request with bad start "
683 		      "address (%p)", start);
684 
685 	sc->sc_rec_start = p->map->dm_segs[0].ds_addr;
686 	sc->sc_rec_end = sc->sc_rec_start + ((char *)end - (char *)start);
687 	sc->sc_rec_blksize = blksize;
688 	sc->sc_rec_nextblk = sc->sc_rec_start + sc->sc_rec_blksize;
689 	sc->sc_rec_flip = 0;
690 	mtx_enter(&audio_lock);
691 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_DMALEN, blksize - 1);
692 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_REC_DMABUF1,
693 			  sc->sc_rec_start);
694 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_REC_DMABUF2,
695 			  sc->sc_rec_nextblk);
696 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL,
697 			  FM_REC_START | FM_REC_STOPNOW | sc->sc_rec_reg);
698 	mtx_leave(&audio_lock);
699 	return 0;
700 }
701