1/*	$NetBSD: fms.c,v 1.50 2024/01/08 18:37:24 chs Exp $	*/
2
3/*-
4 * Copyright (c) 1999, 2008 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 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32/*
33 * Forte Media FM801 Audio Device Driver
34 */
35
36#include <sys/cdefs.h>
37__KERNEL_RCSID(0, "$NetBSD: fms.c,v 1.50 2024/01/08 18:37:24 chs Exp $");
38
39#include "mpu.h"
40
41#include <sys/param.h>
42#include <sys/systm.h>
43#include <sys/kernel.h>
44#include <sys/kmem.h>
45#include <sys/device.h>
46#include <sys/audioio.h>
47
48#include <sys/bus.h>
49#include <sys/cpu.h>
50
51#include <dev/pci/pcidevs.h>
52#include <dev/pci/pcivar.h>
53
54#include <dev/audio/audio_if.h>
55
56#include <dev/ic/ac97var.h>
57#include <dev/ic/mpuvar.h>
58
59#include <dev/pci/fmsvar.h>
60
61
62struct fms_dma {
63	struct fms_dma *next;
64	void *addr;
65	size_t size;
66	bus_dmamap_t map;
67	bus_dma_segment_t seg;
68};
69
70
71
72static int	fms_match(device_t, cfdata_t, void *);
73static void	fms_attach(device_t, device_t, void *);
74static int	fms_intr(void *);
75
76static int	fms_query_format(void *, audio_format_query_t *);
77static int	fms_set_format(void *, int,
78			       const audio_params_t *, const audio_params_t *,
79			       audio_filter_reg_t *, audio_filter_reg_t *);
80static int	fms_round_blocksize(void *, int, int, const audio_params_t *);
81static int	fms_halt_output(void *);
82static int	fms_halt_input(void *);
83static int	fms_getdev(void *, struct audio_device *);
84static int	fms_set_port(void *, mixer_ctrl_t *);
85static int	fms_get_port(void *, mixer_ctrl_t *);
86static int	fms_query_devinfo(void *, mixer_devinfo_t *);
87static void	*fms_malloc(void *, int, size_t);
88static void	fms_free(void *, void *, size_t);
89static int	fms_get_props(void *);
90static int	fms_trigger_output(void *, void *, void *, int,
91				   void (*)(void *), void *,
92				   const audio_params_t *);
93static int	fms_trigger_input(void *, void *, void *, int,
94				  void (*)(void *), void *,
95				  const audio_params_t *);
96static void	fms_get_locks(void *, kmutex_t **, kmutex_t **);
97
98CFATTACH_DECL_NEW(fms, sizeof (struct fms_softc),
99    fms_match, fms_attach, NULL, NULL);
100
101static struct audio_device fms_device = {
102	"Forte Media 801",
103	"1.0",
104	"fms"
105};
106
107/*
108 * The frequency list in this format is also referred from fms_rate2index().
109 * So don't rearrange or delete entries.
110 */
111static const struct audio_format fms_formats[] = {
112	{
113		.mode		= AUMODE_PLAY | AUMODE_RECORD,
114		.encoding	= AUDIO_ENCODING_SLINEAR_LE,
115		.validbits	= 16,
116		.precision	= 16,
117		.channels	= 2,
118		.channel_mask	= AUFMT_STEREO,
119		.frequency_type	= 11,
120		.frequency	= { 5500, 8000, 9600, 11025, 16000, 19200,
121		                    22050, 32000, 38400, 44100, 48000},
122	},
123};
124#define FMS_NFORMATS	__arraycount(fms_formats)
125
126
127static const struct audio_hw_if fms_hw_if = {
128	.query_format		= fms_query_format,
129	.set_format		= fms_set_format,
130	.round_blocksize	= fms_round_blocksize,
131	.halt_output		= fms_halt_output,
132	.halt_input		= fms_halt_input,
133	.getdev			= fms_getdev,
134	.set_port		= fms_set_port,
135	.get_port		= fms_get_port,
136	.query_devinfo		= fms_query_devinfo,
137	.allocm			= fms_malloc,
138	.freem			= fms_free,
139	.get_props		= fms_get_props,
140	.trigger_output		= fms_trigger_output,
141	.trigger_input		= fms_trigger_input,
142	.get_locks		= fms_get_locks,
143};
144
145static int	fms_attach_codec(void *, struct ac97_codec_if *);
146static int	fms_read_codec(void *, uint8_t, uint16_t *);
147static int	fms_write_codec(void *, uint8_t, uint16_t);
148static int	fms_reset_codec(void *);
149static int	fms_rate2index(u_int);
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
213static int
214fms_match(device_t parent, cfdata_t match, void *aux)
215{
216	struct pci_attach_args *pa;
217
218	pa = (struct pci_attach_args *)aux;
219	if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_FORTEMEDIA)
220		return 0;
221	if (PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_FORTEMEDIA_FM801)
222		return 0;
223
224	return 1;
225}
226
227static void
228fms_attach(device_t parent, device_t self, void *aux)
229{
230	struct pci_attach_args *pa;
231	struct fms_softc *sc;
232	struct audio_attach_args aa;
233	const char *intrstr;
234	pci_chipset_tag_t pc;
235	pcitag_t pt;
236	pci_intr_handle_t ih;
237	uint16_t k1;
238	char intrbuf[PCI_INTRSTR_LEN];
239
240	pa = aux;
241	sc = device_private(self);
242	sc->sc_dev = self;
243	intrstr = NULL;
244	pc = pa->pa_pc;
245	pt = pa->pa_tag;
246	aprint_naive(": Audio controller\n");
247	aprint_normal(": Forte Media FM-801\n");
248
249	if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_IO, 0, &sc->sc_iot,
250			   &sc->sc_ioh, &sc->sc_ioaddr, &sc->sc_iosize)) {
251		aprint_error_dev(sc->sc_dev, "can't map i/o space\n");
252		return;
253	}
254	if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, 0x30, 2,
255				&sc->sc_mpu_ioh))
256		panic("fms_attach: can't get mpu subregion handle");
257	if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, 0x68, 4,
258				&sc->sc_opl_ioh))
259		panic("fms_attach: can't get opl subregion handle");
260
261	if (pci_intr_map(pa, &ih)) {
262		aprint_error_dev(sc->sc_dev, "couldn't map interrupt\n");
263		return;
264	}
265	intrstr = pci_intr_string(pc, ih, intrbuf, sizeof(intrbuf));
266
267	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
268	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO);
269
270	sc->sc_ih = pci_intr_establish_xname(pc, ih, IPL_AUDIO, fms_intr, sc,
271	    device_xname(self));
272	if (sc->sc_ih == NULL) {
273		aprint_error_dev(sc->sc_dev, "couldn't establish interrupt");
274		if (intrstr != NULL)
275			aprint_error(" at %s", intrstr);
276		aprint_error("\n");
277		mutex_destroy(&sc->sc_lock);
278		mutex_destroy(&sc->sc_intr_lock);
279		return;
280	}
281
282	sc->sc_dmat = pa->pa_dmat;
283
284	aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr);
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, self, &sc->sc_lock) != 0) {
318		mutex_destroy(&sc->sc_intr_lock);
319		mutex_destroy(&sc->sc_lock);
320		return;
321	}
322
323	audio_attach_mi(&fms_hw_if, sc, sc->sc_dev);
324
325	aa.type = AUDIODEV_TYPE_OPL;
326	aa.hwif = NULL;
327	aa.hdl = NULL;
328	config_found(sc->sc_dev, &aa, audioprint, CFARGS(.iattr = "fms"));
329
330	aa.type = AUDIODEV_TYPE_MPU;
331	aa.hwif = NULL;
332	aa.hdl = NULL;
333	sc->sc_mpu_dev = config_found(sc->sc_dev, &aa, audioprint,
334	    CFARGS(.iattr = "fms"));
335}
336
337/*
338 * Each AC-link frame takes 20.8us, data should be ready in next frame,
339 * we allow more than two.
340 */
341#define TIMO 50
342static int
343fms_read_codec(void *addr, uint8_t reg, uint16_t *val)
344{
345	struct fms_softc *sc;
346	int i;
347
348	sc = addr;
349	/* Poll until codec is ready */
350	for (i = 0; i < TIMO && bus_space_read_2(sc->sc_iot, sc->sc_ioh,
351		 FM_CODEC_CMD) & FM_CODEC_CMD_BUSY; i++)
352		delay(1);
353	if (i >= TIMO) {
354		printf("fms: codec busy\n");
355		return 1;
356	}
357
358	/* Write register index, read access */
359	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CMD,
360			  reg | FM_CODEC_CMD_READ);
361
362	/* Poll until we have valid data */
363	for (i = 0; i < TIMO && !(bus_space_read_2(sc->sc_iot, sc->sc_ioh,
364		 FM_CODEC_CMD) & FM_CODEC_CMD_VALID); i++)
365		delay(1);
366	if (i >= TIMO) {
367		printf("fms: no data from codec\n");
368		return 1;
369	}
370
371	/* Read data */
372	*val = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_DATA);
373	return 0;
374}
375
376static int
377fms_write_codec(void *addr, uint8_t reg, uint16_t val)
378{
379	struct fms_softc *sc = addr;
380	int i;
381
382	/* Poll until codec is ready */
383	for (i = 0; i < TIMO && bus_space_read_2(sc->sc_iot, sc->sc_ioh,
384		 FM_CODEC_CMD) & FM_CODEC_CMD_BUSY; i++)
385		delay(1);
386	if (i >= TIMO) {
387		printf("fms: codec busy\n");
388		return 1;
389	}
390
391	/* Write data */
392	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_DATA, val);
393	/* Write index register, write access */
394	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CMD, reg);
395	return 0;
396}
397#undef TIMO
398
399static int
400fms_attach_codec(void *addr, struct ac97_codec_if *cif)
401{
402	struct fms_softc *sc;
403
404	sc = addr;
405	sc->codec_if = cif;
406	return 0;
407}
408
409/* Cold Reset */
410static int
411fms_reset_codec(void *addr)
412{
413	struct fms_softc *sc;
414
415	sc = addr;
416	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0020);
417	delay(2);
418	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0000);
419	delay(1);
420	return 0;
421}
422
423static int
424fms_intr(void *arg)
425{
426	struct fms_softc *sc = arg;
427#if NMPU > 0
428	struct mpu_softc *sc_mpu = device_private(sc->sc_mpu_dev);
429#endif
430	uint16_t istat;
431
432	mutex_spin_enter(&sc->sc_intr_lock);
433
434	istat = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS);
435
436	if (istat & FM_INTSTATUS_PLAY) {
437		if ((sc->sc_play_nextblk += sc->sc_play_blksize) >=
438		     sc->sc_play_end)
439			sc->sc_play_nextblk = sc->sc_play_start;
440
441		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
442		    sc->sc_play_flip++ & 1 ?
443		    FM_PLAY_DMABUF2 : FM_PLAY_DMABUF1, sc->sc_play_nextblk);
444
445		if (sc->sc_pintr)
446			sc->sc_pintr(sc->sc_parg);
447		else
448			printf("unexpected play intr\n");
449	}
450
451	if (istat & FM_INTSTATUS_REC) {
452		if ((sc->sc_rec_nextblk += sc->sc_rec_blksize) >=
453		     sc->sc_rec_end)
454			sc->sc_rec_nextblk = sc->sc_rec_start;
455
456		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
457		    sc->sc_rec_flip++ & 1 ?
458		    FM_REC_DMABUF2 : FM_REC_DMABUF1, sc->sc_rec_nextblk);
459
460		if (sc->sc_rintr)
461			sc->sc_rintr(sc->sc_rarg);
462		else
463			printf("unexpected rec intr\n");
464	}
465
466#if NMPU > 0
467	if (istat & FM_INTSTATUS_MPU)
468		mpu_intr(sc_mpu);
469#endif
470
471	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS,
472			  istat & (FM_INTSTATUS_PLAY | FM_INTSTATUS_REC));
473
474	mutex_spin_exit(&sc->sc_intr_lock);
475
476	return 1;
477}
478
479static int
480fms_query_format(void *addr, audio_format_query_t *afp)
481{
482
483	return audio_query_format(fms_formats, FMS_NFORMATS, afp);
484}
485
486/* Return index number of sample_rate */
487static int
488fms_rate2index(u_int sample_rate)
489{
490	int i;
491
492	for (i = 0; i < fms_formats[0].frequency_type; i++) {
493		if (sample_rate == fms_formats[0].frequency[i])
494			return i;
495	}
496
497	/* NOTREACHED */
498	panic("fms_format.frequency mismatch?\n");
499}
500
501static int
502fms_set_format(void *addr, int setmode,
503    const audio_params_t *play, const audio_params_t *rec,
504    audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
505{
506	struct fms_softc *sc;
507
508	sc = addr;
509	if (setmode & AUMODE_PLAY) {
510		sc->sc_play_reg = fms_rate2index(play->sample_rate) << 8;
511		sc->sc_play_reg |= FM_PLAY_STEREO;
512		sc->sc_play_reg |= FM_PLAY_16BIT;
513	}
514
515	if (setmode & AUMODE_RECORD) {
516		sc->sc_rec_reg = fms_rate2index(rec->sample_rate) << 8;
517		sc->sc_rec_reg |= FM_REC_STEREO;
518		sc->sc_rec_reg |= FM_REC_16BIT;
519	}
520
521	return 0;
522}
523
524static int
525fms_round_blocksize(void *addr, int blk, int mode,
526    const audio_params_t *param)
527{
528
529	return blk & ~0xf;
530}
531
532static int
533fms_halt_output(void *addr)
534{
535	struct fms_softc *sc;
536	uint16_t k1;
537
538	sc = addr;
539	k1 = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL);
540	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL,
541			  (k1 & ~(FM_PLAY_STOPNOW | FM_PLAY_START)) |
542			  FM_PLAY_BUF1_LAST | FM_PLAY_BUF2_LAST);
543
544	return 0;
545}
546
547static int
548fms_halt_input(void *addr)
549{
550	struct fms_softc *sc;
551	uint16_t k1;
552
553	sc = addr;
554	k1 = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL);
555	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL,
556			  (k1 & ~(FM_REC_STOPNOW | FM_REC_START)) |
557			  FM_REC_BUF1_LAST | FM_REC_BUF2_LAST);
558
559	return 0;
560}
561
562static int
563fms_getdev(void *addr, struct audio_device *retp)
564{
565
566	*retp = fms_device;
567	return 0;
568}
569
570static int
571fms_set_port(void *addr, mixer_ctrl_t *cp)
572{
573	struct fms_softc *sc;
574
575	sc = addr;
576	return sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp);
577}
578
579static int
580fms_get_port(void *addr, mixer_ctrl_t *cp)
581{
582	struct fms_softc *sc;
583
584	sc = addr;
585	return sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp);
586}
587
588static void *
589fms_malloc(void *addr, int direction, size_t size)
590{
591	struct fms_softc *sc;
592	struct fms_dma *p;
593	int error;
594	int rseg;
595
596	sc = addr;
597	p = kmem_alloc(sizeof(*p), KM_SLEEP);
598	p->size = size;
599
600	if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &p->seg,
601				      1, &rseg, BUS_DMA_WAITOK)) != 0) {
602		aprint_error_dev(sc->sc_dev, "unable to allocate DMA, error = %d\n", error);
603		goto fail_alloc;
604	}
605
606	if ((error = bus_dmamem_map(sc->sc_dmat, &p->seg, rseg, size, &p->addr,
607				    BUS_DMA_WAITOK | BUS_DMA_COHERENT)) != 0) {
608		aprint_error_dev(sc->sc_dev, "unable to map DMA, error = %d\n",
609		       error);
610		goto fail_map;
611	}
612
613	if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
614				       BUS_DMA_WAITOK, &p->map)) != 0) {
615		aprint_error_dev(sc->sc_dev, "unable to create DMA map, error = %d\n",
616		       error);
617		goto fail_create;
618	}
619
620	if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, size, NULL,
621				     BUS_DMA_WAITOK)) != 0) {
622		aprint_error_dev(sc->sc_dev, "unable to load DMA map, error = %d\n",
623		       error);
624		goto fail_load;
625	}
626
627	p->next = sc->sc_dmas;
628	sc->sc_dmas = p;
629
630	return p->addr;
631
632
633fail_load:
634	bus_dmamap_destroy(sc->sc_dmat, p->map);
635fail_create:
636	bus_dmamem_unmap(sc->sc_dmat, p->addr, size);
637fail_map:
638	bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
639fail_alloc:
640	kmem_free(p, sizeof(*p));
641	return NULL;
642}
643
644static void
645fms_free(void *addr, void *ptr, size_t size)
646{
647	struct fms_softc *sc;
648	struct fms_dma **pp, *p;
649
650	sc = addr;
651	for (pp = &(sc->sc_dmas); (p = *pp) != NULL; pp = &p->next)
652		if (p->addr == ptr) {
653			bus_dmamap_unload(sc->sc_dmat, p->map);
654			bus_dmamap_destroy(sc->sc_dmat, p->map);
655			bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size);
656			bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
657
658			*pp = p->next;
659			kmem_free(p, sizeof(*p));
660			return;
661		}
662
663	panic("fms_free: trying to free unallocated memory");
664}
665
666static int
667fms_get_props(void *addr)
668{
669
670	return AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE |
671	    AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX;
672}
673
674static int
675fms_query_devinfo(void *addr, mixer_devinfo_t *dip)
676{
677	struct fms_softc *sc;
678
679	sc = addr;
680	return sc->codec_if->vtbl->query_devinfo(sc->codec_if, dip);
681}
682
683static int
684fms_trigger_output(void *addr, void *start, void *end, int blksize,
685    void (*intr)(void *), void *arg, const audio_params_t *param)
686{
687	struct fms_softc *sc;
688	struct fms_dma *p;
689
690	sc = addr;
691	sc->sc_pintr = intr;
692	sc->sc_parg = arg;
693
694	for (p = sc->sc_dmas; p && p->addr != start; p = p->next)
695		continue;
696
697	if (p == NULL)
698		panic("fms_trigger_output: request with bad start "
699		      "address (%p)", start);
700
701	sc->sc_play_start = p->map->dm_segs[0].ds_addr;
702	sc->sc_play_end = sc->sc_play_start + ((char *)end - (char *)start);
703	sc->sc_play_blksize = blksize;
704	sc->sc_play_nextblk = sc->sc_play_start + sc->sc_play_blksize;
705	sc->sc_play_flip = 0;
706	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_DMALEN, blksize - 1);
707	bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_PLAY_DMABUF1,
708			  sc->sc_play_start);
709	bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_PLAY_DMABUF2,
710			  sc->sc_play_nextblk);
711	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL,
712			  FM_PLAY_START | FM_PLAY_STOPNOW | sc->sc_play_reg);
713	return 0;
714}
715
716
717static int
718fms_trigger_input(void *addr, void *start, void *end, int blksize,
719    void (*intr)(void *), void *arg, const audio_params_t *param)
720{
721	struct fms_softc *sc;
722	struct fms_dma *p;
723
724	sc = addr;
725	sc->sc_rintr = intr;
726	sc->sc_rarg = arg;
727
728	for (p = sc->sc_dmas; p && p->addr != start; p = p->next)
729		continue;
730
731	if (p == NULL)
732		panic("fms_trigger_input: request with bad start "
733		      "address (%p)", start);
734
735	sc->sc_rec_start = p->map->dm_segs[0].ds_addr;
736	sc->sc_rec_end = sc->sc_rec_start + ((char *)end - (char *)start);
737	sc->sc_rec_blksize = blksize;
738	sc->sc_rec_nextblk = sc->sc_rec_start + sc->sc_rec_blksize;
739	sc->sc_rec_flip = 0;
740	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_DMALEN, blksize - 1);
741	bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_REC_DMABUF1,
742			  sc->sc_rec_start);
743	bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_REC_DMABUF2,
744			  sc->sc_rec_nextblk);
745	bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL,
746			  FM_REC_START | FM_REC_STOPNOW | sc->sc_rec_reg);
747	return 0;
748}
749
750static void
751fms_get_locks(void *addr, kmutex_t **intr, kmutex_t **thread)
752{
753	struct fms_softc *sc;
754
755	sc = addr;
756	*intr = &sc->sc_intr_lock;
757	*thread = &sc->sc_lock;
758}
759