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