xref: /openbsd/sys/dev/pci/fms.c (revision d89ec533)
1 /*	$OpenBSD: fms.c,v 1.30 2016/12/20 15:31:00 ratchov 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_get_props(void *);
89 int	fms_trigger_output(void *, void *, void *, int, void (*)(void *),
90 			   void *, struct audio_params *);
91 int	fms_trigger_input(void *, void *, void *, int, void (*)(void *),
92 			  void *, struct audio_params *);
93 
94 struct  cfdriver fms_cd = {
95 	NULL, "fms", DV_DULL
96 };
97 
98 struct cfattach fms_ca = {
99 	sizeof (struct fms_softc), fms_match, fms_attach
100 };
101 
102 struct audio_hw_if fms_hw_if = {
103 	fms_open,
104 	fms_close,
105 	fms_set_params,
106 	fms_round_blocksize,
107 	NULL,
108 	NULL,
109 	NULL,
110 	NULL,
111 	NULL,
112 	fms_halt_output,
113 	fms_halt_input,
114 	NULL,
115 	NULL,
116 	fms_set_port,
117 	fms_get_port,
118 	fms_query_devinfo,
119 	fms_malloc,
120 	fms_free,
121 	NULL,
122 	fms_get_props,
123 	fms_trigger_output,
124 	fms_trigger_input
125 };
126 
127 int	fms_attach_codec(void *, struct ac97_codec_if *);
128 int	fms_read_codec(void *, u_int8_t, u_int16_t *);
129 int	fms_write_codec(void *, u_int8_t, u_int16_t);
130 void	fms_reset_codec(void *);
131 
132 int	fms_allocmem(struct fms_softc *, size_t, size_t,
133 			  struct fms_dma *);
134 int	fms_freemem(struct fms_softc *, struct fms_dma *);
135 
136 int
137 fms_match(struct device *parent, void *match, void *aux)
138 {
139 	struct pci_attach_args *pa = (struct pci_attach_args *) aux;
140 
141 	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_FORTEMEDIA &&
142 	    PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_FORTEMEDIA_FM801)
143 		return (1);
144 	return (0);
145 }
146 
147 void
148 fms_attach(struct device *parent, struct device *self, void *aux)
149 {
150 	struct pci_attach_args *pa = aux;
151 	struct fms_softc *sc = (struct fms_softc *) self;
152 	struct audio_attach_args aa;
153 	pci_chipset_tag_t pc = pa->pa_pc;
154 	pcitag_t pt = pa->pa_tag;
155 	pci_intr_handle_t ih;
156 	bus_size_t iosize;
157 	const char *intrstr;
158 	u_int16_t k1;
159 	int i;
160 
161 	if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_IO, 0, &sc->sc_iot,
162 	    &sc->sc_ioh, NULL, &iosize, 0)) {
163 		printf(": can't map i/o space\n");
164 		return;
165 	}
166 
167 	if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, 0x30, 2,
168 	    &sc->sc_mpu_ioh)) {
169 		printf(": can't get mpu subregion handle\n");
170 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
171 		return;
172 	}
173 
174 	if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, 0x68, 4,
175 	    &sc->sc_opl_ioh)) {
176 		printf(": can't get opl subregion handle\n");
177 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
178 		return;
179 	}
180 
181 	if (pci_intr_map(pa, &ih)) {
182 		printf(": couldn't map interrupt\n");
183 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
184 		return;
185 	}
186 	intrstr = pci_intr_string(pc, ih);
187 
188 	sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO | IPL_MPSAFE,
189 	    fms_intr, sc, sc->sc_dev.dv_xname);
190 	if (sc->sc_ih == NULL) {
191 		printf(": couldn't establish interrupt");
192 		if (intrstr != NULL)
193 			printf(" at %s", intrstr);
194 		printf("\n");
195 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
196 		return;
197 	}
198 
199 	printf(": %s\n", intrstr);
200 
201 	sc->sc_dmat = pa->pa_dmat;
202 
203 	/* Disable legacy audio (SBPro compatibility) */
204 	pci_conf_write(pc, pt, 0x40, 0);
205 
206 	/* Reset codec and AC'97 */
207 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0020);
208 	delay(2);		/* > 1us according to AC'97 documentation */
209 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0000);
210 	delay(1);		/* > 168.2ns according to AC'97 documentation */
211 
212 	/* Set up volume */
213 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PCM_VOLUME, 0x0808);
214 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_FM_VOLUME, 0x0808);
215 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_I2S_VOLUME, 0x0808);
216 
217 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_RECORD_SOURCE, 0x0000);
218 
219 	/* Unmask playback, record and mpu interrupts, mask the rest */
220 	k1 = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_INTMASK);
221 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_INTMASK,
222 	    (k1 & ~(FM_INTMASK_PLAY | FM_INTMASK_REC | FM_INTMASK_MPU)) |
223 	     FM_INTMASK_VOL);
224 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS,
225 	    FM_INTSTATUS_PLAY | FM_INTSTATUS_REC | FM_INTSTATUS_MPU |
226 	    FM_INTSTATUS_VOL);
227 
228 #if NRADIO > 0
229 	fmsradio_attach(sc);
230 #endif /* NRADIO > 0 */
231 
232 	sc->host_if.arg = sc;
233 	sc->host_if.attach = fms_attach_codec;
234 	sc->host_if.read = fms_read_codec;
235 	sc->host_if.write = fms_write_codec;
236 	sc->host_if.reset = fms_reset_codec;
237 
238 	if (ac97_attach(&sc->host_if) != 0)
239 		return;
240 
241 	/* Turn mute off */
242 	for (i = 0; i < 3; i++) {
243 		static struct {
244 			char *class, *device;
245 		} d[] = {
246 			{ AudioCoutputs, AudioNmaster },
247 			{ AudioCinputs, AudioNdac },
248 			{ AudioCrecord, AudioNvolume }
249 		};
250 		struct mixer_ctrl ctl;
251 
252 		ctl.type = AUDIO_MIXER_ENUM;
253 		ctl.un.ord = 0;
254 		ctl.dev = sc->codec_if->vtbl->get_portnum_by_name(sc->codec_if,
255 			d[i].class, d[i].device, AudioNmute);
256 		fms_set_port(sc, &ctl);
257 	}
258 
259 	audio_attach_mi(&fms_hw_if, sc, &sc->sc_dev);
260 
261 	aa.type = AUDIODEV_TYPE_OPL;
262 	aa.hwif = NULL;
263 	aa.hdl = NULL;
264 	config_found(&sc->sc_dev, &aa, audioprint);
265 
266 	aa.type = AUDIODEV_TYPE_MPU;
267 	aa.hwif = NULL;
268 	aa.hdl = NULL;
269 	sc->sc_mpu_dev = config_found(&sc->sc_dev, &aa, audioprint);
270 }
271 
272 /*
273  * Each AC-link frame takes 20.8us, data should be ready in next frame,
274  * we allow more than two.
275  */
276 #define TIMO 50
277 int
278 fms_read_codec(void *addr, u_int8_t reg, u_int16_t *val)
279 {
280 	struct fms_softc *sc = addr;
281 	int i;
282 
283 	/* Poll until codec is ready */
284 	for (i = 0; i < TIMO && bus_space_read_2(sc->sc_iot, sc->sc_ioh,
285 		 FM_CODEC_CMD) & FM_CODEC_CMD_BUSY; i++)
286 		delay(1);
287 	if (i >= TIMO) {
288 		printf("fms: codec busy\n");
289 		return 1;
290 	}
291 
292 	/* Write register index, read access */
293 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CMD,
294 			  reg | FM_CODEC_CMD_READ);
295 
296 	/* Poll until we have valid data */
297 	for (i = 0; i < TIMO && !(bus_space_read_2(sc->sc_iot, sc->sc_ioh,
298 		 FM_CODEC_CMD) & FM_CODEC_CMD_VALID); i++)
299 		delay(1);
300 	if (i >= TIMO) {
301 		printf("fms: no data from codec\n");
302 		return 1;
303 	}
304 
305 	/* Read data */
306 	*val = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_DATA);
307 	return 0;
308 }
309 
310 int
311 fms_write_codec(void *addr, u_int8_t reg, u_int16_t val)
312 {
313 	struct fms_softc *sc = addr;
314 	int i;
315 
316 	/* Poll until codec is ready */
317 	for (i = 0; i < TIMO && bus_space_read_2(sc->sc_iot, sc->sc_ioh,
318 		 FM_CODEC_CMD) & FM_CODEC_CMD_BUSY; i++)
319 		delay(1);
320 	if (i >= TIMO) {
321 		printf("fms: codec busy\n");
322 		return 1;
323 	}
324 
325 	/* Write data */
326 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_DATA, val);
327 	/* Write index register, write access */
328 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CMD, reg);
329 	return 0;
330 }
331 #undef TIMO
332 
333 int
334 fms_attach_codec(void *addr, struct ac97_codec_if *cif)
335 {
336 	struct fms_softc *sc = addr;
337 
338 	sc->codec_if = cif;
339 	return 0;
340 }
341 
342 /* Cold Reset */
343 void
344 fms_reset_codec(void *addr)
345 {
346 	struct fms_softc *sc = addr;
347 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0020);
348 	delay(2);
349 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0000);
350 	delay(1);
351 }
352 
353 int
354 fms_intr(void *arg)
355 {
356 	struct fms_softc *sc = arg;
357 	u_int16_t istat;
358 
359 	mtx_enter(&audio_lock);
360 	istat = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS);
361 
362 	if (istat & FM_INTSTATUS_PLAY) {
363 		if ((sc->sc_play_nextblk += sc->sc_play_blksize) >=
364 		     sc->sc_play_end)
365 			sc->sc_play_nextblk = sc->sc_play_start;
366 
367 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
368 		    sc->sc_play_flip++ & 1 ?
369 		    FM_PLAY_DMABUF2 : FM_PLAY_DMABUF1, sc->sc_play_nextblk);
370 
371 		if (sc->sc_pintr)
372 			sc->sc_pintr(sc->sc_parg);
373 		else
374 			printf("unexpected play intr\n");
375 	}
376 
377 	if (istat & FM_INTSTATUS_REC) {
378 		if ((sc->sc_rec_nextblk += sc->sc_rec_blksize) >=
379 		     sc->sc_rec_end)
380 			sc->sc_rec_nextblk = sc->sc_rec_start;
381 
382 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
383 		    sc->sc_rec_flip++ & 1 ?
384 		    FM_REC_DMABUF2 : FM_REC_DMABUF1, sc->sc_rec_nextblk);
385 
386 		if (sc->sc_rintr)
387 			sc->sc_rintr(sc->sc_rarg);
388 		else
389 			printf("unexpected rec intr\n");
390 	}
391 
392 #if 0
393 	if (istat & FM_INTSTATUS_MPU)
394 		mpu_intr(sc->sc_mpu_dev);
395 #endif
396 
397 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS,
398 			  istat & (FM_INTSTATUS_PLAY | FM_INTSTATUS_REC));
399 	mtx_leave(&audio_lock);
400 	return 1;
401 }
402 
403 int
404 fms_open(void *addr, int flags)
405 {
406 	/* UNUSED struct fms_softc *sc = addr;*/
407 
408 	return 0;
409 }
410 
411 void
412 fms_close(void *addr)
413 {
414 	/* UNUSED struct fms_softc *sc = addr;*/
415 }
416 
417 /*
418  * Range below -limit- is set to -rate-
419  * What a pity FM801 does not have 24000
420  * 24000 -> 22050 sounds rather poor
421  */
422 struct {
423 	int limit;
424 	int rate;
425 } fms_rates[11] = {
426 	{  6600,  5500 },
427 	{  8750,  8000 },
428 	{ 10250,  9600 },
429 	{ 13200, 11025 },
430 	{ 17500, 16000 },
431 	{ 20500, 19200 },
432 	{ 26500, 22050 },
433 	{ 35000, 32000 },
434 	{ 41000, 38400 },
435 	{ 46000, 44100 },
436 	{ 48000, 48000 },
437 	/* anything above -> 48000 */
438 };
439 
440 int
441 fms_set_params(void *addr, int setmode, int usemode, struct audio_params *play,
442     struct audio_params *rec)
443 {
444 	struct fms_softc *sc = addr;
445 	int i;
446 
447 	if (setmode & AUMODE_PLAY) {
448 		switch(play->encoding) {
449 		case AUDIO_ENCODING_SLINEAR_LE:
450 			if (play->precision != 16)
451 				return EINVAL;
452 			break;
453 		case AUDIO_ENCODING_ULINEAR_LE:
454 		case AUDIO_ENCODING_ULINEAR_BE:
455 			if (play->precision != 8)
456 				return EINVAL;
457 			break;
458 		default:
459 			return EINVAL;
460 		}
461 		play->bps = AUDIO_BPS(play->precision);
462 		play->msb = 1;
463 
464 		for (i = 0; i < 10 && play->sample_rate > fms_rates[i].limit;
465 		     i++)
466 			;
467 		play->sample_rate = fms_rates[i].rate;
468 		sc->sc_play_reg = (play->channels == 2 ? FM_PLAY_STEREO : 0) |
469 		    (play->precision == 16 ? FM_PLAY_16BIT : 0) |
470 		    (i << 8);
471 	}
472 
473 	if (setmode & AUMODE_RECORD) {
474 
475 		switch(rec->encoding) {
476 		case AUDIO_ENCODING_SLINEAR_LE:
477 			if (rec->precision != 16)
478 				return EINVAL;
479 			break;
480 		case AUDIO_ENCODING_ULINEAR_LE:
481 		case AUDIO_ENCODING_ULINEAR_BE:
482 			if (rec->precision != 8)
483 				return EINVAL;
484 			break;
485 		default:
486 			return EINVAL;
487 		}
488 		rec->bps = AUDIO_BPS(rec->precision);
489 		rec->msb = 1;
490 
491 		for (i = 0; i < 10 && rec->sample_rate > fms_rates[i].limit;
492 		     i++)
493 			;
494 		rec->sample_rate = fms_rates[i].rate;
495 		sc->sc_rec_reg =
496 		    (rec->channels == 2 ? FM_REC_STEREO : 0) |
497 		    (rec->precision == 16 ? FM_REC_16BIT : 0) |
498 		    (i << 8);
499 	}
500 
501 	return 0;
502 }
503 
504 int
505 fms_round_blocksize(void *addr, int blk)
506 {
507 	return (blk + 0xf) & ~0xf;
508 }
509 
510 int
511 fms_halt_output(void *addr)
512 {
513 	struct fms_softc *sc = addr;
514 	u_int16_t k1;
515 
516 	mtx_enter(&audio_lock);
517 	k1 = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL);
518 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL,
519 			  (k1 & ~(FM_PLAY_STOPNOW | FM_PLAY_START)) |
520 			  FM_PLAY_BUF1_LAST | FM_PLAY_BUF2_LAST);
521 	mtx_leave(&audio_lock);
522 	return 0;
523 }
524 
525 int
526 fms_halt_input(void *addr)
527 {
528 	struct fms_softc *sc = addr;
529 	u_int16_t k1;
530 
531 	mtx_enter(&audio_lock);
532 	k1 = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL);
533 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL,
534 			  (k1 & ~(FM_REC_STOPNOW | FM_REC_START)) |
535 			  FM_REC_BUF1_LAST | FM_REC_BUF2_LAST);
536 	mtx_leave(&audio_lock);
537 	return 0;
538 }
539 
540 int
541 fms_set_port(void *addr, mixer_ctrl_t *cp)
542 {
543 	struct fms_softc *sc = addr;
544 
545 	return (sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp));
546 }
547 
548 int
549 fms_get_port(void *addr, mixer_ctrl_t *cp)
550 {
551 	struct fms_softc *sc = addr;
552 
553 	return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp));
554 }
555 
556 void *
557 fms_malloc(void *addr, int direction, size_t size, int pool, int flags)
558 {
559 	struct fms_softc *sc = addr;
560 	struct fms_dma *p;
561 	int error;
562 	int rseg;
563 
564 	p = malloc(sizeof(*p), pool, flags);
565 	if (!p)
566 		return 0;
567 
568 	p->size = size;
569 	if ((error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, 0, &p->seg, 1,
570 				      &rseg, BUS_DMA_NOWAIT)) != 0) {
571 		printf("%s: unable to allocate dma, error = %d\n",
572 		       sc->sc_dev.dv_xname, error);
573 		goto fail_alloc;
574 	}
575 
576 	if ((error = bus_dmamem_map(sc->sc_dmat, &p->seg, rseg, size, &p->addr,
577 				    BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
578 		printf("%s: unable to map dma, error = %d\n",
579 		       sc->sc_dev.dv_xname, error);
580 		goto fail_map;
581 	}
582 
583 	if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
584 				       BUS_DMA_NOWAIT, &p->map)) != 0) {
585 		printf("%s: unable to create dma map, error = %d\n",
586 		       sc->sc_dev.dv_xname, error);
587 		goto fail_create;
588 	}
589 
590 	if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, size, NULL,
591 				     BUS_DMA_NOWAIT)) != 0) {
592 		printf("%s: unable to load dma map, error = %d\n",
593 		       sc->sc_dev.dv_xname, error);
594 		goto fail_load;
595 	}
596 
597 	p->next = sc->sc_dmas;
598 	sc->sc_dmas = p;
599 
600 	return p->addr;
601 
602 
603 fail_load:
604 	bus_dmamap_destroy(sc->sc_dmat, p->map);
605 fail_create:
606 	bus_dmamem_unmap(sc->sc_dmat, p->addr, size);
607 fail_map:
608 	bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
609 fail_alloc:
610 	free(p, pool, sizeof(*p));
611 	return 0;
612 }
613 
614 void
615 fms_free(void *addr, void *ptr, int pool)
616 {
617 	struct fms_softc *sc = addr;
618 	struct fms_dma **pp, *p;
619 
620 	for (pp = &(sc->sc_dmas); (p = *pp) != NULL; pp = &p->next)
621 		if (p->addr == ptr) {
622 			bus_dmamap_unload(sc->sc_dmat, p->map);
623 			bus_dmamap_destroy(sc->sc_dmat, p->map);
624 			bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size);
625 			bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
626 
627 			*pp = p->next;
628 			free(p, pool, sizeof(*p));
629 			return;
630 		}
631 
632 	panic("fms_free: trying to free unallocated memory");
633 }
634 
635 int
636 fms_get_props(void *addr)
637 {
638 	return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT |
639 	       AUDIO_PROP_FULLDUPLEX;
640 }
641 
642 int
643 fms_query_devinfo(void *addr, mixer_devinfo_t *dip)
644 {
645 	struct fms_softc *sc = addr;
646 
647 	return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, dip));
648 }
649 
650 int
651 fms_trigger_output(void *addr, void *start, void *end, int blksize,
652     void (*intr)(void *), void *arg, struct audio_params *param)
653 {
654 	struct fms_softc *sc = addr;
655 	struct fms_dma *p;
656 
657 	sc->sc_pintr = intr;
658 	sc->sc_parg = arg;
659 
660 	for (p = sc->sc_dmas; p && p->addr != start; p = p->next)
661 		;
662 
663 	if (!p)
664 		panic("fms_trigger_output: request with bad start "
665 		      "address (%p)", start);
666 
667 	sc->sc_play_start = p->map->dm_segs[0].ds_addr;
668 	sc->sc_play_end = sc->sc_play_start + ((char *)end - (char *)start);
669 	sc->sc_play_blksize = blksize;
670 	sc->sc_play_nextblk = sc->sc_play_start + sc->sc_play_blksize;
671 	sc->sc_play_flip = 0;
672 	mtx_enter(&audio_lock);
673 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_DMALEN, blksize - 1);
674 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_PLAY_DMABUF1,
675 			  sc->sc_play_start);
676 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_PLAY_DMABUF2,
677 			  sc->sc_play_nextblk);
678 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL,
679 			  FM_PLAY_START | FM_PLAY_STOPNOW | sc->sc_play_reg);
680 	mtx_leave(&audio_lock);
681 	return 0;
682 }
683 
684 
685 int
686 fms_trigger_input(void *addr, void *start, void *end, int blksize,
687     void (*intr)(void *), void *arg, struct audio_params *param)
688 {
689 	struct fms_softc *sc = addr;
690 	struct fms_dma *p;
691 
692 	sc->sc_rintr = intr;
693 	sc->sc_rarg = arg;
694 
695 	for (p = sc->sc_dmas; p && p->addr != start; p = p->next)
696 		;
697 
698 	if (!p)
699 		panic("fms_trigger_input: request with bad start "
700 		      "address (%p)", start);
701 
702 	sc->sc_rec_start = p->map->dm_segs[0].ds_addr;
703 	sc->sc_rec_end = sc->sc_rec_start + ((char *)end - (char *)start);
704 	sc->sc_rec_blksize = blksize;
705 	sc->sc_rec_nextblk = sc->sc_rec_start + sc->sc_rec_blksize;
706 	sc->sc_rec_flip = 0;
707 	mtx_enter(&audio_lock);
708 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_DMALEN, blksize - 1);
709 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_REC_DMABUF1,
710 			  sc->sc_rec_start);
711 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_REC_DMABUF2,
712 			  sc->sc_rec_nextblk);
713 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL,
714 			  FM_REC_START | FM_REC_STOPNOW | sc->sc_rec_reg);
715 	mtx_leave(&audio_lock);
716 	return 0;
717 }
718