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