xref: /netbsd-src/sys/dev/pci/fms.c (revision 3b01aba77a7a698587faaae455bbfe740923c1f5)
1 /*	$NetBSD: fms.c,v 1.9 2000/12/28 22:59:12 sommerfeld Exp $	*/
2 
3 /*-
4  * Copyright (c) 1999 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Witold J. Wnuk.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the NetBSD
21  *	Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * Forte Media FM801 Audio Device Driver
41  */
42 
43 #include "mpu.h"
44 
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/malloc.h>
49 #include <sys/device.h>
50 #include <sys/audioio.h>
51 
52 #include <uvm/uvm_extern.h>
53 
54 #include <machine/bus.h>
55 #include <machine/cpu.h>
56 
57 #include <dev/pci/pcidevs.h>
58 #include <dev/pci/pcivar.h>
59 
60 #include <dev/audio_if.h>
61 #include <dev/mulaw.h>
62 #include <dev/auconv.h>
63 
64 #include <dev/ic/ac97var.h>
65 #include <dev/ic/mpuvar.h>
66 
67 #include <dev/pci/fmsvar.h>
68 
69 
70 struct fms_dma {
71 	struct fms_dma *next;
72 	caddr_t addr;
73 	size_t size;
74 	bus_dmamap_t map;
75 	bus_dma_segment_t seg;
76 };
77 
78 
79 
80 int	fms_match __P((struct device *, struct cfdata *, void *));
81 void	fms_attach __P((struct device *, struct device *, void *));
82 int	fms_intr __P((void *));
83 
84 int	fms_open __P((void *, int));
85 void	fms_close __P((void *));
86 int	fms_query_encoding __P((void *, struct audio_encoding *));
87 int	fms_set_params __P((void *, int, int, struct audio_params *,
88 			    struct audio_params *));
89 int	fms_round_blocksize __P((void *, int));
90 int	fms_halt_output __P((void *));
91 int	fms_halt_input __P((void *));
92 int	fms_getdev __P((void *, struct audio_device *));
93 int	fms_set_port __P((void *, mixer_ctrl_t *));
94 int	fms_get_port __P((void *, mixer_ctrl_t *));
95 int	fms_query_devinfo __P((void *, mixer_devinfo_t *));
96 void	*fms_malloc __P((void *, int, size_t, int, int));
97 void	fms_free __P((void *, void *, int));
98 size_t	fms_round_buffersize __P((void *, int, size_t));
99 paddr_t	fms_mappage __P((void *, void *, off_t, int));
100 int	fms_get_props __P((void *));
101 int	fms_trigger_output __P((void *, void *, void *, int, void (*)(void *),
102 				void *, struct audio_params *));
103 int	fms_trigger_input __P((void *, void *, void *, int, void (*)(void *),
104 			       void *, struct audio_params *));
105 
106 struct cfattach fms_ca = {
107 	sizeof (struct fms_softc), fms_match, fms_attach
108 };
109 
110 struct audio_device fms_device = {
111 	"Forte Media 801",
112 	"1.0",
113 	"fms"
114 };
115 
116 
117 struct audio_hw_if fms_hw_if = {
118 	fms_open,
119 	fms_close,
120 	NULL,
121 	fms_query_encoding,
122 	fms_set_params,
123 	fms_round_blocksize,
124 	NULL,
125 	NULL,
126 	NULL,
127 	NULL,
128 	NULL,
129 	fms_halt_output,
130 	fms_halt_input,
131 	NULL,
132 	fms_getdev,
133 	NULL,
134 	fms_set_port,
135 	fms_get_port,
136 	fms_query_devinfo,
137 	fms_malloc,
138 	fms_free,
139 	fms_round_buffersize,
140 	fms_mappage,
141 	fms_get_props,
142 	fms_trigger_output,
143 	fms_trigger_input,
144 };
145 
146 int	fms_attach_codec __P((void *, struct ac97_codec_if *));
147 int	fms_read_codec __P((void *, u_int8_t, u_int16_t *));
148 int	fms_write_codec __P((void *, u_int8_t, u_int16_t));
149 void	fms_reset_codec __P((void *));
150 
151 int	fms_allocmem __P((struct fms_softc *, size_t, size_t,
152 			  struct fms_dma *));
153 int	fms_freemem __P((struct fms_softc *, struct fms_dma *));
154 
155 #define FM_PCM_VOLUME		0x00
156 #define FM_FM_VOLUME		0x02
157 #define FM_I2S_VOLUME		0x04
158 #define FM_RECORD_SOURCE	0x06
159 
160 #define FM_PLAY_CTL		0x08
161 #define  FM_PLAY_RATE_MASK		0x0f00
162 #define  FM_PLAY_BUF1_LAST		0x0001
163 #define  FM_PLAY_BUF2_LAST		0x0002
164 #define  FM_PLAY_START			0x0020
165 #define  FM_PLAY_PAUSE			0x0040
166 #define  FM_PLAY_STOPNOW		0x0080
167 #define  FM_PLAY_16BIT			0x4000
168 #define  FM_PLAY_STEREO			0x8000
169 
170 #define FM_PLAY_DMALEN		0x0a
171 #define FM_PLAY_DMABUF1		0x0c
172 #define FM_PLAY_DMABUF2		0x10
173 
174 
175 #define FM_REC_CTL		0x14
176 #define  FM_REC_RATE_MASK		0x0f00
177 #define  FM_REC_BUF1_LAST		0x0001
178 #define  FM_REC_BUF2_LAST		0x0002
179 #define  FM_REC_START			0x0020
180 #define  FM_REC_PAUSE			0x0040
181 #define  FM_REC_STOPNOW			0x0080
182 #define  FM_REC_16BIT			0x4000
183 #define  FM_REC_STEREO			0x8000
184 
185 
186 #define FM_REC_DMALEN		0x16
187 #define FM_REC_DMABUF1		0x18
188 #define FM_REC_DMABUF2		0x1c
189 
190 #define FM_CODEC_CTL		0x22
191 #define FM_VOLUME		0x26
192 #define  FM_VOLUME_MUTE			0x8000
193 
194 #define FM_CODEC_CMD		0x2a
195 #define  FM_CODEC_CMD_READ		0x0080
196 #define  FM_CODEC_CMD_VALID		0x0100
197 #define  FM_CODEC_CMD_BUSY		0x0200
198 
199 #define FM_CODEC_DATA		0x2c
200 
201 #define FM_IO_CTL		0x52
202 #define FM_CARD_CTL		0x54
203 
204 #define FM_INTMASK		0x56
205 #define  FM_INTMASK_PLAY		0x0001
206 #define  FM_INTMASK_REC			0x0002
207 #define  FM_INTMASK_VOL			0x0040
208 #define  FM_INTMASK_MPU			0x0080
209 
210 #define FM_INTSTATUS		0x5a
211 #define  FM_INTSTATUS_PLAY		0x0100
212 #define  FM_INTSTATUS_REC		0x0200
213 #define  FM_INTSTATUS_VOL		0x4000
214 #define  FM_INTSTATUS_MPU		0x8000
215 
216 
217 
218 int
219 fms_match(parent, match, aux)
220 	struct device *parent;
221 	struct cfdata *match;
222 	void *aux;
223 {
224 	struct pci_attach_args *pa = (struct pci_attach_args *) aux;
225 
226 	if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_FORTEMEDIA)
227 		return 0;
228 	if (PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_FORTEMEDIA_FM801)
229 		return 0;
230 
231 	return 1;
232 }
233 
234 void
235 fms_attach(parent, self, aux)
236 	struct device *parent;
237 	struct device *self;
238 	void *aux;
239 {
240 	struct pci_attach_args *pa = aux;
241 	struct fms_softc *sc = (struct fms_softc *) self;
242 	struct audio_attach_args aa;
243 	const char *intrstr = NULL;
244 	pci_chipset_tag_t pc = pa->pa_pc;
245 	pcitag_t pt = pa->pa_tag;
246 	pci_intr_handle_t ih;
247 	int i;
248 
249 	u_int16_t k1;
250 
251 	printf(": Forte Media FM-801\n");
252 
253 	if (pci_intr_map(pa, &ih)) {
254 		printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname);
255 		return;
256 	}
257 	intrstr = pci_intr_string(pc, ih);
258 
259 	sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, fms_intr, sc);
260 	if (sc->sc_ih == NULL) {
261 		printf("%s: couldn't establish interrupt",sc->sc_dev.dv_xname);
262 		if (intrstr != NULL)
263 			printf(" at %s", intrstr);
264 		printf("\n");
265 		return;
266 	}
267 
268 	sc->sc_dmat = pa->pa_dmat;
269 
270 	printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);
271 
272 	if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_IO, 0, &sc->sc_iot,
273 			   &sc->sc_ioh, &sc->sc_ioaddr, &sc->sc_iosize)) {
274 		printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname);
275 		return;
276 	}
277 
278 	if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, 0x30, 2,
279 				&sc->sc_mpu_ioh))
280 		panic("fms_attach: can't get mpu subregion handle");
281 
282 	if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, 0x68, 4,
283 				&sc->sc_opl_ioh))
284 		panic("fms_attach: can't get opl subregion handle");
285 
286 	/* Disable legacy audio (SBPro compatibility) */
287 	pci_conf_write(pc, pt, 0x40, 0);
288 
289 	/* Reset codec and AC'97 */
290 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0020);
291 	delay(2);		/* > 1us according to AC'97 documentation */
292 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0000);
293 	delay(1);		/* > 168.2ns according to AC'97 documentation */
294 
295 	/* Set up volume */
296 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PCM_VOLUME, 0x0808);
297 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_FM_VOLUME, 0x0808);
298 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_I2S_VOLUME, 0x0808);
299 
300 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_RECORD_SOURCE, 0x0000);
301 
302 	/* Unmask playback, record and mpu interrupts, mask the rest */
303 	k1 = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_INTMASK);
304 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_INTMASK,
305 	    (k1 & ~(FM_INTMASK_PLAY | FM_INTMASK_REC | FM_INTMASK_MPU)) |
306 	     FM_INTMASK_VOL);
307 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS,
308 	    FM_INTSTATUS_PLAY | FM_INTSTATUS_REC | FM_INTSTATUS_MPU |
309 	    FM_INTSTATUS_VOL);
310 
311 	sc->host_if.arg = sc;
312 	sc->host_if.attach = fms_attach_codec;
313 	sc->host_if.read = fms_read_codec;
314 	sc->host_if.write = fms_write_codec;
315 	sc->host_if.reset = fms_reset_codec;
316 
317 	if (ac97_attach(&sc->host_if) != 0)
318 		return;
319 
320 	/* Turn mute off */
321 	for (i = 0; i < 3; i++) {
322 		static struct {
323 			char *class, *device;
324 		} d[] = {
325 			{ AudioCoutputs, AudioNmaster },
326 			{ AudioCinputs, AudioNdac },
327 			{ AudioCrecord, AudioNvolume }
328 		};
329 		struct mixer_ctrl ctl;
330 
331 		ctl.type = AUDIO_MIXER_ENUM;
332 		ctl.un.ord = 0;
333 		ctl.dev = sc->codec_if->vtbl->get_portnum_by_name(sc->codec_if,
334 			d[i].class, d[i].device, AudioNmute);
335 		fms_set_port(sc, &ctl);
336 	}
337 
338 	audio_attach_mi(&fms_hw_if, sc, &sc->sc_dev);
339 
340 	aa.type = AUDIODEV_TYPE_OPL;
341 	aa.hwif = NULL;
342 	aa.hdl = NULL;
343 	config_found(&sc->sc_dev, &aa, audioprint);
344 
345 	aa.type = AUDIODEV_TYPE_MPU;
346 	aa.hwif = NULL;
347 	aa.hdl = NULL;
348 	sc->sc_mpu_dev = config_found(&sc->sc_dev, &aa, audioprint);
349 }
350 
351 /*
352  * Each AC-link frame takes 20.8us, data should be ready in next frame,
353  * we allow more than two.
354  */
355 #define TIMO 50
356 int
357 fms_read_codec(addr, reg, val)
358 	void *addr;
359 	u_int8_t reg;
360 	u_int16_t *val;
361 {
362 	struct fms_softc *sc = addr;
363 	int i;
364 
365 	/* Poll until codec is ready */
366 	for (i = 0; i < TIMO && bus_space_read_2(sc->sc_iot, sc->sc_ioh,
367 		 FM_CODEC_CMD) & FM_CODEC_CMD_BUSY; i++)
368 		delay(1);
369 	if (i >= TIMO) {
370 		printf("fms: codec busy\n");
371 		return 1;
372 	}
373 
374 	/* Write register index, read access */
375 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CMD,
376 			  reg | FM_CODEC_CMD_READ);
377 
378 	/* Poll until we have valid data */
379 	for (i = 0; i < TIMO && !(bus_space_read_2(sc->sc_iot, sc->sc_ioh,
380 		 FM_CODEC_CMD) & FM_CODEC_CMD_VALID); i++)
381 		delay(1);
382 	if (i >= TIMO) {
383 		printf("fms: no data from codec\n");
384 		return 1;
385 	}
386 
387 	/* Read data */
388 	*val = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_DATA);
389 	return 0;
390 }
391 
392 int
393 fms_write_codec(addr, reg, val)
394 	void *addr;
395 	u_int8_t reg;
396 	u_int16_t val;
397 {
398 	struct fms_softc *sc = addr;
399 	int i;
400 
401 	/* Poll until codec is ready */
402 	for (i = 0; i < TIMO && bus_space_read_2(sc->sc_iot, sc->sc_ioh,
403 		 FM_CODEC_CMD) & FM_CODEC_CMD_BUSY; i++)
404 		delay(1);
405 	if (i >= TIMO) {
406 		printf("fms: codec busy\n");
407 		return 1;
408 	}
409 
410 	/* Write data */
411 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_DATA, val);
412 	/* Write index register, write access */
413 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CMD, reg);
414 	return 0;
415 }
416 #undef TIMO
417 
418 int
419 fms_attach_codec(addr, cif)
420 	void *addr;
421 	struct ac97_codec_if *cif;
422 {
423 	struct fms_softc *sc = addr;
424 
425 	sc->codec_if = cif;
426 	return 0;
427 }
428 
429 /* Cold Reset */
430 void
431 fms_reset_codec(addr)
432 	void *addr;
433 {
434 	struct fms_softc *sc = addr;
435 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0020);
436 	delay(2);
437 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0000);
438 	delay(1);
439 }
440 
441 int
442 fms_intr(arg)
443 	void *arg;
444 {
445 	struct fms_softc *sc = arg;
446 	u_int16_t istat;
447 
448 	istat = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS);
449 
450 	if (istat & FM_INTSTATUS_PLAY) {
451 		if ((sc->sc_play_nextblk += sc->sc_play_blksize) >=
452 		     sc->sc_play_end)
453 			sc->sc_play_nextblk = sc->sc_play_start;
454 
455 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
456 		    sc->sc_play_flip++ & 1 ?
457 		    FM_PLAY_DMABUF2 : FM_PLAY_DMABUF1, sc->sc_play_nextblk);
458 
459 		if (sc->sc_pintr)
460 			sc->sc_pintr(sc->sc_parg);
461 		else
462 			printf("unexpected play intr\n");
463 	}
464 
465 	if (istat & FM_INTSTATUS_REC) {
466 		if ((sc->sc_rec_nextblk += sc->sc_rec_blksize) >=
467 		     sc->sc_rec_end)
468 			sc->sc_rec_nextblk = sc->sc_rec_start;
469 
470 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
471 		    sc->sc_rec_flip++ & 1 ?
472 		    FM_REC_DMABUF2 : FM_REC_DMABUF1, sc->sc_rec_nextblk);
473 
474 		if (sc->sc_rintr)
475 			sc->sc_rintr(sc->sc_rarg);
476 		else
477 			printf("unexpected rec intr\n");
478 	}
479 
480 #if NMPU > 0
481 	if (istat & FM_INTSTATUS_MPU)
482 		mpu_intr(sc->sc_mpu_dev);
483 #endif
484 
485 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS,
486 			  istat & (FM_INTSTATUS_PLAY | FM_INTSTATUS_REC));
487 
488 	return 1;
489 }
490 
491 int
492 fms_open(addr, flags)
493 	void *addr;
494 	int flags;
495 {
496 	/* UNUSED struct fms_softc *sc = addr;*/
497 
498 	return 0;
499 }
500 
501 void
502 fms_close(addr)
503 	void *addr;
504 {
505 	/* UNUSED struct fms_softc *sc = addr;*/
506 }
507 
508 int
509 fms_query_encoding(addr, fp)
510 	void *addr;
511 	struct audio_encoding *fp;
512 {
513 
514 	switch (fp->index) {
515 	case 0:
516 		strcpy(fp->name, AudioEmulaw);
517 		fp->encoding = AUDIO_ENCODING_ULAW;
518 		fp->precision = 8;
519 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
520 		return 0;
521 	case 1:
522 		strcpy(fp->name, AudioEslinear_le);
523 		fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
524 		fp->precision = 16;
525 		fp->flags = 0;
526 		return 0;
527 	case 2:
528 		strcpy(fp->name, AudioEulinear);
529 		fp->encoding = AUDIO_ENCODING_ULINEAR;
530 		fp->precision = 8;
531 		fp->flags = 0;
532 		return 0;
533 	case 3:
534 		strcpy(fp->name, AudioEalaw);
535 		fp->encoding = AUDIO_ENCODING_ALAW;
536 		fp->precision = 8;
537 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
538 		return 0;
539 	case 4:
540 		strcpy(fp->name, AudioEulinear_le);
541 		fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
542 		fp->precision = 16;
543 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
544 		return 0;
545 	case 5:
546 		strcpy(fp->name, AudioEslinear);
547 		fp->encoding = AUDIO_ENCODING_SLINEAR;
548 		fp->precision = 8;
549 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
550 		return 0;
551 	case 6:
552 		strcpy(fp->name, AudioEulinear_be);
553 		fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
554 		fp->precision = 16;
555 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
556 		return 0;
557 	case 7:
558 		strcpy(fp->name, AudioEslinear_be);
559 		fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
560 		fp->precision = 16;
561 		fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
562 		return 0;
563 	default:
564 		return EINVAL;
565 	}
566 }
567 
568 /*
569  * Range below -limit- is set to -rate-
570  * What a pity FM801 does not have 24000
571  * 24000 -> 22050 sounds rather poor
572  */
573 struct {
574 	int limit;
575 	int rate;
576 } fms_rates[11] = {
577 	{  6600,  5500 },
578 	{  8750,  8000 },
579 	{ 10250,  9600 },
580 	{ 13200, 11025 },
581 	{ 17500, 16000 },
582 	{ 20500, 19200 },
583 	{ 26500, 22050 },
584 	{ 35000, 32000 },
585 	{ 41000, 38400 },
586 	{ 46000, 44100 },
587 	{ 48000, 48000 },
588 	/* anything above -> 48000 */
589 };
590 
591 int
592 fms_set_params(addr, setmode, usemode, play, rec)
593 	void *addr;
594 	int setmode, usemode;
595 	struct audio_params *play, *rec;
596 {
597 	struct fms_softc *sc = addr;
598 	int i;
599 
600 	if (setmode & AUMODE_PLAY) {
601 		play->factor = 1;
602 		play->sw_code = 0;
603 		switch(play->encoding) {
604 		case AUDIO_ENCODING_ULAW:
605 			play->factor = 2;
606 			play->sw_code = mulaw_to_slinear16_le;
607 			break;
608 		case AUDIO_ENCODING_SLINEAR_LE:
609 			if (play->precision == 8)
610 				play->sw_code = change_sign8;
611 			break;
612 		case AUDIO_ENCODING_ULINEAR_LE:
613 			if (play->precision == 16)
614 				play->sw_code = change_sign16_le;
615 			break;
616 		case AUDIO_ENCODING_ALAW:
617 			play->factor = 2;
618 			play->sw_code = alaw_to_slinear16_le;
619 			break;
620 		case AUDIO_ENCODING_SLINEAR_BE:
621 			if (play->precision == 16)
622 				play->sw_code = swap_bytes;
623 			else
624 				play->sw_code = change_sign8;
625 			break;
626 		case AUDIO_ENCODING_ULINEAR_BE:
627 			if (play->precision == 16)
628 				play->sw_code = change_sign16_swap_bytes_le;
629 			break;
630 		default:
631 			return EINVAL;
632 		}
633 		for (i = 0; i < 10 && play->sample_rate > fms_rates[i].limit;
634 		     i++)
635 			;
636 		play->sample_rate = fms_rates[i].rate;
637 		sc->sc_play_reg = (play->channels == 2 ? FM_PLAY_STEREO : 0) |
638 		    (play->precision * play->factor == 16 ? FM_PLAY_16BIT : 0) |
639 		    (i << 8);
640 	}
641 
642 	if (setmode & AUMODE_RECORD) {
643 
644 		rec->factor = 1;
645 		rec->sw_code = 0;
646 		switch(rec->encoding) {
647 		case AUDIO_ENCODING_ULAW:
648 			rec->sw_code = ulinear8_to_mulaw;
649 			break;
650 		case AUDIO_ENCODING_SLINEAR_LE:
651 			if (rec->precision == 8)
652 				rec->sw_code = change_sign8;
653 			break;
654 		case AUDIO_ENCODING_ULINEAR_LE:
655 			if (rec->precision == 16)
656 				rec->sw_code = change_sign16_le;
657 			break;
658 		case AUDIO_ENCODING_ALAW:
659 			rec->sw_code = ulinear8_to_alaw;
660 			break;
661 		case AUDIO_ENCODING_SLINEAR_BE:
662 			if (play->precision == 16)
663 				play->sw_code = swap_bytes;
664 			else
665 				play->sw_code = change_sign8;
666 			break;
667 		case AUDIO_ENCODING_ULINEAR_BE:
668 			if (play->precision == 16)
669 				play->sw_code = swap_bytes_change_sign16_le;
670 			break;
671 		default:
672 			return EINVAL;
673 		}
674 		for (i = 0; i < 10 && rec->sample_rate > fms_rates[i].limit;
675 		     i++)
676 			;
677 		rec->sample_rate = fms_rates[i].rate;
678 		sc->sc_rec_reg =
679 		    (rec->channels == 2 ? FM_REC_STEREO : 0) |
680 		    (rec->precision * rec->factor == 16 ? FM_REC_16BIT : 0) |
681 		    (i << 8);
682 	}
683 
684 	return 0;
685 }
686 
687 int
688 fms_round_blocksize(addr, blk)
689 	void *addr;
690 	int blk;
691 {
692 	return blk & ~0xf;
693 }
694 
695 int
696 fms_halt_output(addr)
697 	void *addr;
698 {
699 	struct fms_softc *sc = addr;
700 	u_int16_t k1;
701 
702 	k1 = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL);
703 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL,
704 			  (k1 & ~(FM_PLAY_STOPNOW | FM_PLAY_START)) |
705 			  FM_PLAY_BUF1_LAST | FM_PLAY_BUF2_LAST);
706 
707 	return 0;
708 }
709 
710 int
711 fms_halt_input(addr)
712 	void *addr;
713 {
714 	struct fms_softc *sc = addr;
715 	u_int16_t k1;
716 
717 	k1 = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL);
718 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL,
719 			  (k1 & ~(FM_REC_STOPNOW | FM_REC_START)) |
720 			  FM_REC_BUF1_LAST | FM_REC_BUF2_LAST);
721 
722 	return 0;
723 }
724 
725 int
726 fms_getdev(addr, retp)
727 	void *addr;
728 	struct audio_device *retp;
729 {
730 	*retp = fms_device;
731 	return 0;
732 }
733 
734 int
735 fms_set_port(addr, cp)
736 	void *addr;
737 	mixer_ctrl_t *cp;
738 {
739 	struct fms_softc *sc = addr;
740 
741 	return (sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp));
742 }
743 
744 int
745 fms_get_port(addr, cp)
746 	void *addr;
747 	mixer_ctrl_t *cp;
748 {
749 	struct fms_softc *sc = addr;
750 
751 	return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp));
752 }
753 
754 void *
755 fms_malloc(addr, direction, size, pool, flags)
756 	void *addr;
757 	int direction;
758 	size_t size;
759 	int pool, flags;
760 {
761 	struct fms_softc *sc = addr;
762 	struct fms_dma *p;
763 	int error;
764 	int rseg;
765 
766 	p = malloc(sizeof(*p), pool, flags);
767 	if (!p)
768 		return 0;
769 
770 	p->size = size;
771 	if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &p->seg,
772 				      1, &rseg, BUS_DMA_NOWAIT)) != 0) {
773 		printf("%s: unable to allocate dma, error = %d\n",
774 		       sc->sc_dev.dv_xname, error);
775 		goto fail_alloc;
776 	}
777 
778 	if ((error = bus_dmamem_map(sc->sc_dmat, &p->seg, rseg, size, &p->addr,
779 				    BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
780 		printf("%s: unable to map dma, error = %d\n",
781 		       sc->sc_dev.dv_xname, error);
782 		goto fail_map;
783 	}
784 
785 	if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
786 				       BUS_DMA_NOWAIT, &p->map)) != 0) {
787 		printf("%s: unable to create dma map, error = %d\n",
788 		       sc->sc_dev.dv_xname, error);
789 		goto fail_create;
790 	}
791 
792 	if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, size, NULL,
793 				     BUS_DMA_NOWAIT)) != 0) {
794 		printf("%s: unable to load dma map, error = %d\n",
795 		       sc->sc_dev.dv_xname, error);
796 		goto fail_load;
797 	}
798 
799 	p->next = sc->sc_dmas;
800 	sc->sc_dmas = p;
801 
802 	return p->addr;
803 
804 
805 fail_load:
806 	bus_dmamap_destroy(sc->sc_dmat, p->map);
807 fail_create:
808 	bus_dmamem_unmap(sc->sc_dmat, p->addr, size);
809 fail_map:
810 	bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
811 fail_alloc:
812 	free(p, pool);
813 	return 0;
814 }
815 
816 void
817 fms_free(addr, ptr, pool)
818 	void *addr;
819 	void *ptr;
820 	int pool;
821 {
822 	struct fms_softc *sc = addr;
823 	struct fms_dma **pp, *p;
824 
825 	for (pp = &(sc->sc_dmas); (p = *pp) != NULL; pp = &p->next)
826 		if (p->addr == ptr) {
827 			bus_dmamap_unload(sc->sc_dmat, p->map);
828 			bus_dmamap_destroy(sc->sc_dmat, p->map);
829 			bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size);
830 			bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
831 
832 			*pp = p->next;
833 			free(p, pool);
834 			return;
835 		}
836 
837 	panic("fms_free: trying to free unallocated memory");
838 }
839 
840 size_t
841 fms_round_buffersize(addr, direction, size)
842 	void *addr;
843 	int direction;
844 	size_t size;
845 {
846 	return size;
847 }
848 
849 paddr_t
850 fms_mappage(addr, mem, off, prot)
851 	void *addr;
852 	void *mem;
853 	off_t off;
854 	int prot;
855 {
856 	struct fms_softc *sc = addr;
857 	struct fms_dma *p;
858 
859 	if (off < 0)
860 		return -1;
861 
862 	for (p = sc->sc_dmas; p && p->addr != mem; p = p->next)
863 		;
864 	if (!p)
865 		return -1;
866 
867 	return bus_dmamem_mmap(sc->sc_dmat, &p->seg, 1, off, prot,
868 			       BUS_DMA_WAITOK);
869 }
870 
871 int
872 fms_get_props(addr)
873 	void *addr;
874 {
875 	return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT |
876 	       AUDIO_PROP_FULLDUPLEX;
877 }
878 
879 int
880 fms_query_devinfo(addr, dip)
881 	void *addr;
882 	mixer_devinfo_t *dip;
883 {
884 	struct fms_softc *sc = addr;
885 
886 	return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, dip));
887 }
888 
889 int
890 fms_trigger_output(addr, start, end, blksize, intr, arg, param)
891 	void *addr;
892 	void *start, *end;
893 	int blksize;
894 	void (*intr) __P((void *));
895 	void *arg;
896 	struct audio_params *param;
897 {
898 	struct fms_softc *sc = addr;
899 	struct fms_dma *p;
900 
901 	sc->sc_pintr = intr;
902 	sc->sc_parg = arg;
903 
904 	for (p = sc->sc_dmas; p && p->addr != start; p = p->next)
905 		;
906 
907 	if (!p)
908 		panic("fms_trigger_output: request with bad start "
909 		      "address (%p)\n", start);
910 
911 	sc->sc_play_start = p->map->dm_segs[0].ds_addr;
912 	sc->sc_play_end = sc->sc_play_start + ((char *)end - (char *)start);
913 	sc->sc_play_blksize = blksize;
914 	sc->sc_play_nextblk = sc->sc_play_start + sc->sc_play_blksize;
915 	sc->sc_play_flip = 0;
916 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_DMALEN, blksize - 1);
917 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_PLAY_DMABUF1,
918 			  sc->sc_play_start);
919 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_PLAY_DMABUF2,
920 			  sc->sc_play_nextblk);
921 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL,
922 			  FM_PLAY_START | FM_PLAY_STOPNOW | sc->sc_play_reg);
923 	return 0;
924 }
925 
926 
927 int
928 fms_trigger_input(addr, start, end, blksize, intr, arg, param)
929 	void *addr;
930 	void *start, *end;
931 	int blksize;
932 	void (*intr) __P((void *));
933 	void *arg;
934 	struct audio_params *param;
935 {
936 	struct fms_softc *sc = addr;
937 	struct fms_dma *p;
938 
939 	sc->sc_rintr = intr;
940 	sc->sc_rarg = arg;
941 
942 	for (p = sc->sc_dmas; p && p->addr != start; p = p->next)
943 		;
944 
945 	if (!p)
946 		panic("fms_trigger_input: request with bad start "
947 		      "address (%p)\n", start);
948 
949 	sc->sc_rec_start = p->map->dm_segs[0].ds_addr;
950 	sc->sc_rec_end = sc->sc_rec_start + ((char *)end - (char *)start);
951 	sc->sc_rec_blksize = blksize;
952 	sc->sc_rec_nextblk = sc->sc_rec_start + sc->sc_rec_blksize;
953 	sc->sc_rec_flip = 0;
954 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_DMALEN, blksize - 1);
955 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_REC_DMABUF1,
956 			  sc->sc_rec_start);
957 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_REC_DMABUF2,
958 			  sc->sc_rec_nextblk);
959 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL,
960 			  FM_REC_START | FM_REC_STOPNOW | sc->sc_rec_reg);
961 	return 0;
962 }
963 
964 
965