fms.c revision 1.25 1 /* $NetBSD: fms.c,v 1.25 2005/12/11 12:22:49 christos 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/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: fms.c,v 1.25 2005/12/11 12:22:49 christos Exp $");
45
46 #include "mpu.h"
47
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/kernel.h>
51 #include <sys/malloc.h>
52 #include <sys/device.h>
53 #include <sys/audioio.h>
54
55 #include <uvm/uvm_extern.h>
56
57 #include <machine/bus.h>
58 #include <machine/cpu.h>
59
60 #include <dev/pci/pcidevs.h>
61 #include <dev/pci/pcivar.h>
62
63 #include <dev/audio_if.h>
64 #include <dev/mulaw.h>
65 #include <dev/auconv.h>
66
67 #include <dev/ic/ac97var.h>
68 #include <dev/ic/mpuvar.h>
69
70 #include <dev/pci/fmsvar.h>
71
72
73 struct fms_dma {
74 struct fms_dma *next;
75 caddr_t addr;
76 size_t size;
77 bus_dmamap_t map;
78 bus_dma_segment_t seg;
79 };
80
81
82
83 static int fms_match(struct device *, struct cfdata *, void *);
84 static void fms_attach(struct device *, struct device *, void *);
85 static int fms_intr(void *);
86
87 static int fms_query_encoding(void *, struct audio_encoding *);
88 static int fms_set_params(void *, int, int, audio_params_t *,
89 audio_params_t *, stream_filter_list_t *,
90 stream_filter_list_t *);
91 static int fms_round_blocksize(void *, int, int, const audio_params_t *);
92 static int fms_halt_output(void *);
93 static int fms_halt_input(void *);
94 static int fms_getdev(void *, struct audio_device *);
95 static int fms_set_port(void *, mixer_ctrl_t *);
96 static int fms_get_port(void *, mixer_ctrl_t *);
97 static int fms_query_devinfo(void *, mixer_devinfo_t *);
98 static void *fms_malloc(void *, int, size_t, struct malloc_type *, int);
99 static void fms_free(void *, void *, struct malloc_type *);
100 static size_t fms_round_buffersize(void *, int, size_t);
101 static paddr_t fms_mappage(void *, void *, off_t, int);
102 static int fms_get_props(void *);
103 static int fms_trigger_output(void *, void *, void *, int,
104 void (*)(void *), void *,
105 const audio_params_t *);
106 static int fms_trigger_input(void *, void *, void *, int,
107 void (*)(void *), void *,
108 const audio_params_t *);
109
110 CFATTACH_DECL(fms, sizeof (struct fms_softc),
111 fms_match, fms_attach, NULL, NULL);
112
113 static struct audio_device fms_device = {
114 "Forte Media 801",
115 "1.0",
116 "fms"
117 };
118
119
120 static const struct audio_hw_if fms_hw_if = {
121 NULL, /* open */
122 NULL, /* close */
123 NULL,
124 fms_query_encoding,
125 fms_set_params,
126 fms_round_blocksize,
127 NULL,
128 NULL,
129 NULL,
130 NULL,
131 NULL,
132 fms_halt_output,
133 fms_halt_input,
134 NULL,
135 fms_getdev,
136 NULL,
137 fms_set_port,
138 fms_get_port,
139 fms_query_devinfo,
140 fms_malloc,
141 fms_free,
142 fms_round_buffersize,
143 fms_mappage,
144 fms_get_props,
145 fms_trigger_output,
146 fms_trigger_input,
147 NULL,
148 };
149
150 static int fms_attach_codec(void *, struct ac97_codec_if *);
151 static int fms_read_codec(void *, uint8_t, uint16_t *);
152 static int fms_write_codec(void *, uint8_t, uint16_t);
153 static int fms_reset_codec(void *);
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 static int
218 fms_match(struct device *parent, struct cfdata *match, void *aux)
219 {
220 struct pci_attach_args *pa;
221
222 pa = (struct pci_attach_args *)aux;
223 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_FORTEMEDIA)
224 return 0;
225 if (PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_FORTEMEDIA_FM801)
226 return 0;
227
228 return 1;
229 }
230
231 static void
232 fms_attach(struct device *parent, struct device *self, void *aux)
233 {
234 struct pci_attach_args *pa;
235 struct fms_softc *sc;
236 struct audio_attach_args aa;
237 const char *intrstr;
238 pci_chipset_tag_t pc;
239 pcitag_t pt;
240 pci_intr_handle_t ih;
241 uint16_t k1;
242
243 pa = aux;
244 sc = (struct fms_softc *)self;
245 intrstr = NULL;
246 pc = pa->pa_pc;
247 pt = pa->pa_tag;
248 aprint_naive(": Audio controller\n");
249 aprint_normal(": Forte Media FM-801\n");
250
251 if (pci_intr_map(pa, &ih)) {
252 aprint_error("%s: couldn't map interrupt\n",
253 sc->sc_dev.dv_xname);
254 return;
255 }
256 intrstr = pci_intr_string(pc, ih);
257
258 sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, fms_intr, sc);
259 if (sc->sc_ih == NULL) {
260 aprint_error("%s: couldn't establish interrupt",
261 sc->sc_dev.dv_xname);
262 if (intrstr != NULL)
263 aprint_normal(" at %s", intrstr);
264 aprint_normal("\n");
265 return;
266 }
267
268 sc->sc_dmat = pa->pa_dmat;
269
270 aprint_normal("%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 aprint_error("%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, self) != 0)
318 return;
319
320 audio_attach_mi(&fms_hw_if, sc, &sc->sc_dev);
321
322 aa.type = AUDIODEV_TYPE_OPL;
323 aa.hwif = NULL;
324 aa.hdl = NULL;
325 config_found(&sc->sc_dev, &aa, audioprint);
326
327 aa.type = AUDIODEV_TYPE_MPU;
328 aa.hwif = NULL;
329 aa.hdl = NULL;
330 sc->sc_mpu_dev = config_found(&sc->sc_dev, &aa, audioprint);
331 }
332
333 /*
334 * Each AC-link frame takes 20.8us, data should be ready in next frame,
335 * we allow more than two.
336 */
337 #define TIMO 50
338 static int
339 fms_read_codec(void *addr, uint8_t reg, uint16_t *val)
340 {
341 struct fms_softc *sc;
342 int i;
343
344 sc = addr;
345 /* Poll until codec is ready */
346 for (i = 0; i < TIMO && bus_space_read_2(sc->sc_iot, sc->sc_ioh,
347 FM_CODEC_CMD) & FM_CODEC_CMD_BUSY; i++)
348 delay(1);
349 if (i >= TIMO) {
350 printf("fms: codec busy\n");
351 return 1;
352 }
353
354 /* Write register index, read access */
355 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CMD,
356 reg | FM_CODEC_CMD_READ);
357
358 /* Poll until we have valid data */
359 for (i = 0; i < TIMO && !(bus_space_read_2(sc->sc_iot, sc->sc_ioh,
360 FM_CODEC_CMD) & FM_CODEC_CMD_VALID); i++)
361 delay(1);
362 if (i >= TIMO) {
363 printf("fms: no data from codec\n");
364 return 1;
365 }
366
367 /* Read data */
368 *val = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_DATA);
369 return 0;
370 }
371
372 static int
373 fms_write_codec(void *addr, uint8_t reg, uint16_t val)
374 {
375 struct fms_softc *sc = addr;
376 int i;
377
378 /* Poll until codec is ready */
379 for (i = 0; i < TIMO && bus_space_read_2(sc->sc_iot, sc->sc_ioh,
380 FM_CODEC_CMD) & FM_CODEC_CMD_BUSY; i++)
381 delay(1);
382 if (i >= TIMO) {
383 printf("fms: codec busy\n");
384 return 1;
385 }
386
387 /* Write data */
388 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_DATA, val);
389 /* Write index register, write access */
390 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CMD, reg);
391 return 0;
392 }
393 #undef TIMO
394
395 static int
396 fms_attach_codec(void *addr, struct ac97_codec_if *cif)
397 {
398 struct fms_softc *sc;
399
400 sc = addr;
401 sc->codec_if = cif;
402 return 0;
403 }
404
405 /* Cold Reset */
406 static int
407 fms_reset_codec(void *addr)
408 {
409 struct fms_softc *sc;
410
411 sc = addr;
412 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0020);
413 delay(2);
414 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0000);
415 delay(1);
416 return 0;
417 }
418
419 static int
420 fms_intr(void *arg)
421 {
422 struct fms_softc *sc;
423 uint16_t istat;
424
425 sc = arg;
426 istat = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS);
427
428 if (istat & FM_INTSTATUS_PLAY) {
429 if ((sc->sc_play_nextblk += sc->sc_play_blksize) >=
430 sc->sc_play_end)
431 sc->sc_play_nextblk = sc->sc_play_start;
432
433 bus_space_write_4(sc->sc_iot, sc->sc_ioh,
434 sc->sc_play_flip++ & 1 ?
435 FM_PLAY_DMABUF2 : FM_PLAY_DMABUF1, sc->sc_play_nextblk);
436
437 if (sc->sc_pintr)
438 sc->sc_pintr(sc->sc_parg);
439 else
440 printf("unexpected play intr\n");
441 }
442
443 if (istat & FM_INTSTATUS_REC) {
444 if ((sc->sc_rec_nextblk += sc->sc_rec_blksize) >=
445 sc->sc_rec_end)
446 sc->sc_rec_nextblk = sc->sc_rec_start;
447
448 bus_space_write_4(sc->sc_iot, sc->sc_ioh,
449 sc->sc_rec_flip++ & 1 ?
450 FM_REC_DMABUF2 : FM_REC_DMABUF1, sc->sc_rec_nextblk);
451
452 if (sc->sc_rintr)
453 sc->sc_rintr(sc->sc_rarg);
454 else
455 printf("unexpected rec intr\n");
456 }
457
458 #if NMPU > 0
459 if (istat & FM_INTSTATUS_MPU)
460 mpu_intr(sc->sc_mpu_dev);
461 #endif
462
463 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS,
464 istat & (FM_INTSTATUS_PLAY | FM_INTSTATUS_REC));
465
466 return 1;
467 }
468
469 static int
470 fms_query_encoding(void *addr, struct audio_encoding *fp)
471 {
472
473 switch (fp->index) {
474 case 0:
475 strcpy(fp->name, AudioEmulaw);
476 fp->encoding = AUDIO_ENCODING_ULAW;
477 fp->precision = 8;
478 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
479 return 0;
480 case 1:
481 strcpy(fp->name, AudioEslinear_le);
482 fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
483 fp->precision = 16;
484 fp->flags = 0;
485 return 0;
486 case 2:
487 strcpy(fp->name, AudioEulinear);
488 fp->encoding = AUDIO_ENCODING_ULINEAR;
489 fp->precision = 8;
490 fp->flags = 0;
491 return 0;
492 case 3:
493 strcpy(fp->name, AudioEalaw);
494 fp->encoding = AUDIO_ENCODING_ALAW;
495 fp->precision = 8;
496 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
497 return 0;
498 case 4:
499 strcpy(fp->name, AudioEulinear_le);
500 fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
501 fp->precision = 16;
502 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
503 return 0;
504 case 5:
505 strcpy(fp->name, AudioEslinear);
506 fp->encoding = AUDIO_ENCODING_SLINEAR;
507 fp->precision = 8;
508 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
509 return 0;
510 case 6:
511 strcpy(fp->name, AudioEulinear_be);
512 fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
513 fp->precision = 16;
514 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
515 return 0;
516 case 7:
517 strcpy(fp->name, AudioEslinear_be);
518 fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
519 fp->precision = 16;
520 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
521 return 0;
522 default:
523 return EINVAL;
524 }
525 }
526
527 /*
528 * Range below -limit- is set to -rate-
529 * What a pity FM801 does not have 24000
530 * 24000 -> 22050 sounds rather poor
531 */
532 struct {
533 int limit;
534 int rate;
535 } static const fms_rates[11] = {
536 { 6600, 5500 },
537 { 8750, 8000 },
538 { 10250, 9600 },
539 { 13200, 11025 },
540 { 17500, 16000 },
541 { 20500, 19200 },
542 { 26500, 22050 },
543 { 35000, 32000 },
544 { 41000, 38400 },
545 { 46000, 44100 },
546 { 48000, 48000 },
547 /* anything above -> 48000 */
548 };
549
550 #define FMS_NFORMATS 4
551 static const struct audio_format fms_formats[FMS_NFORMATS] = {
552 {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_LE, 16, 16,
553 2, AUFMT_STEREO, 11, {5500, 8000, 9600, 11025, 16000, 19200, 22050,
554 32000, 38400, 44100, 48000}},
555 {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_LE, 16, 16,
556 1, AUFMT_MONAURAL, 11, {5500, 8000, 9600, 11025, 16000, 19200, 22050,
557 32000, 38400, 44100, 48000}},
558 {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_ULINEAR_LE, 8, 8,
559 2, AUFMT_STEREO, 11, {5500, 8000, 9600, 11025, 16000, 19200, 22050,
560 32000, 38400, 44100, 48000}},
561 {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_ULINEAR_LE, 8, 8,
562 1, AUFMT_MONAURAL, 11, {5500, 8000, 9600, 11025, 16000, 19200, 22050,
563 32000, 38400, 44100, 48000}},
564 };
565
566 static int
567 fms_set_params(void *addr, int setmode, int usemode,
568 audio_params_t *play, audio_params_t *rec,
569 stream_filter_list_t *pfil, stream_filter_list_t *rfil)
570 {
571 struct fms_softc *sc;
572 int i, index;
573
574 sc = addr;
575 if (setmode & AUMODE_PLAY) {
576 for (i = 0; i < 10 && play->sample_rate > fms_rates[i].limit;
577 i++)
578 continue;
579 play->sample_rate = fms_rates[i].rate;
580 index = auconv_set_converter(fms_formats, FMS_NFORMATS,
581 AUMODE_PLAY, play, FALSE, pfil);
582 if (index < 0)
583 return EINVAL;
584 sc->sc_play_reg = i << 8;
585 if (fms_formats[index].channels == 2)
586 sc->sc_play_reg |= FM_PLAY_STEREO;
587 if (fms_formats[index].precision == 16)
588 sc->sc_play_reg |= FM_PLAY_16BIT;
589 }
590
591 if (setmode & AUMODE_RECORD) {
592 for (i = 0; i < 10 && rec->sample_rate > fms_rates[i].limit;
593 i++)
594 continue;
595 rec->sample_rate = fms_rates[i].rate;
596 index = auconv_set_converter(fms_formats, FMS_NFORMATS,
597 AUMODE_RECORD, rec, FALSE, rfil);
598 if (index < 0)
599 return EINVAL;
600 sc->sc_rec_reg = i << 8;
601 if (fms_formats[index].channels == 2)
602 sc->sc_rec_reg |= FM_REC_STEREO;
603 if (fms_formats[index].precision == 16)
604 sc->sc_rec_reg |= FM_REC_16BIT;
605 }
606
607 return 0;
608 }
609
610 static int
611 fms_round_blocksize(void *addr, int blk, int mode, const audio_params_t *param)
612 {
613
614 return blk & ~0xf;
615 }
616
617 static int
618 fms_halt_output(void *addr)
619 {
620 struct fms_softc *sc;
621 uint16_t k1;
622
623 sc = addr;
624 k1 = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL);
625 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL,
626 (k1 & ~(FM_PLAY_STOPNOW | FM_PLAY_START)) |
627 FM_PLAY_BUF1_LAST | FM_PLAY_BUF2_LAST);
628
629 return 0;
630 }
631
632 static int
633 fms_halt_input(void *addr)
634 {
635 struct fms_softc *sc;
636 uint16_t k1;
637
638 sc = addr;
639 k1 = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL);
640 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL,
641 (k1 & ~(FM_REC_STOPNOW | FM_REC_START)) |
642 FM_REC_BUF1_LAST | FM_REC_BUF2_LAST);
643
644 return 0;
645 }
646
647 static int
648 fms_getdev(void *addr, struct audio_device *retp)
649 {
650
651 *retp = fms_device;
652 return 0;
653 }
654
655 static int
656 fms_set_port(void *addr, mixer_ctrl_t *cp)
657 {
658 struct fms_softc *sc;
659
660 sc = addr;
661 return sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp);
662 }
663
664 static int
665 fms_get_port(void *addr, mixer_ctrl_t *cp)
666 {
667 struct fms_softc *sc;
668
669 sc = addr;
670 return sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp);
671 }
672
673 static void *
674 fms_malloc(void *addr, int direction, size_t size,
675 struct malloc_type *pool, int flags)
676 {
677 struct fms_softc *sc;
678 struct fms_dma *p;
679 int error;
680 int rseg;
681
682 sc = addr;
683 p = malloc(sizeof(*p), pool, flags);
684 if (p == NULL)
685 return NULL;
686
687 p->size = size;
688 if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &p->seg,
689 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
690 printf("%s: unable to allocate DMA, error = %d\n",
691 sc->sc_dev.dv_xname, error);
692 goto fail_alloc;
693 }
694
695 if ((error = bus_dmamem_map(sc->sc_dmat, &p->seg, rseg, size, &p->addr,
696 BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
697 printf("%s: unable to map DMA, error = %d\n",
698 sc->sc_dev.dv_xname, error);
699 goto fail_map;
700 }
701
702 if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
703 BUS_DMA_NOWAIT, &p->map)) != 0) {
704 printf("%s: unable to create DMA map, error = %d\n",
705 sc->sc_dev.dv_xname, error);
706 goto fail_create;
707 }
708
709 if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, size, NULL,
710 BUS_DMA_NOWAIT)) != 0) {
711 printf("%s: unable to load DMA map, error = %d\n",
712 sc->sc_dev.dv_xname, error);
713 goto fail_load;
714 }
715
716 p->next = sc->sc_dmas;
717 sc->sc_dmas = p;
718
719 return p->addr;
720
721
722 fail_load:
723 bus_dmamap_destroy(sc->sc_dmat, p->map);
724 fail_create:
725 bus_dmamem_unmap(sc->sc_dmat, p->addr, size);
726 fail_map:
727 bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
728 fail_alloc:
729 free(p, pool);
730 return NULL;
731 }
732
733 static void
734 fms_free(void *addr, void *ptr, struct malloc_type *pool)
735 {
736 struct fms_softc *sc;
737 struct fms_dma **pp, *p;
738
739 sc = addr;
740 for (pp = &(sc->sc_dmas); (p = *pp) != NULL; pp = &p->next)
741 if (p->addr == ptr) {
742 bus_dmamap_unload(sc->sc_dmat, p->map);
743 bus_dmamap_destroy(sc->sc_dmat, p->map);
744 bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size);
745 bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
746
747 *pp = p->next;
748 free(p, pool);
749 return;
750 }
751
752 panic("fms_free: trying to free unallocated memory");
753 }
754
755 static size_t
756 fms_round_buffersize(void *addr, int direction, size_t size)
757 {
758
759 return size;
760 }
761
762 static paddr_t
763 fms_mappage(void *addr, void *mem, off_t off, int prot)
764 {
765 struct fms_softc *sc;
766 struct fms_dma *p;
767
768 sc = addr;
769 if (off < 0)
770 return -1;
771
772 for (p = sc->sc_dmas; p && p->addr != mem; p = p->next)
773 continue;
774 if (p == NULL)
775 return -1;
776
777 return bus_dmamem_mmap(sc->sc_dmat, &p->seg, 1, off, prot,
778 BUS_DMA_WAITOK);
779 }
780
781 static int
782 fms_get_props(void *addr)
783 {
784 return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT |
785 AUDIO_PROP_FULLDUPLEX;
786 }
787
788 static int
789 fms_query_devinfo(void *addr, mixer_devinfo_t *dip)
790 {
791 struct fms_softc *sc;
792
793 sc = addr;
794 return sc->codec_if->vtbl->query_devinfo(sc->codec_if, dip);
795 }
796
797 static int
798 fms_trigger_output(void *addr, void *start, void *end, int blksize,
799 void (*intr)(void *), void *arg,
800 const audio_params_t *param)
801 {
802 struct fms_softc *sc;
803 struct fms_dma *p;
804
805 sc = addr;
806 sc->sc_pintr = intr;
807 sc->sc_parg = arg;
808
809 for (p = sc->sc_dmas; p && p->addr != start; p = p->next)
810 continue;
811
812 if (p == NULL)
813 panic("fms_trigger_output: request with bad start "
814 "address (%p)", start);
815
816 sc->sc_play_start = p->map->dm_segs[0].ds_addr;
817 sc->sc_play_end = sc->sc_play_start + ((char *)end - (char *)start);
818 sc->sc_play_blksize = blksize;
819 sc->sc_play_nextblk = sc->sc_play_start + sc->sc_play_blksize;
820 sc->sc_play_flip = 0;
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 return 0;
829 }
830
831
832 static int
833 fms_trigger_input(void *addr, void *start, void *end, int blksize,
834 void (*intr)(void *), void *arg, const audio_params_t *param)
835 {
836 struct fms_softc *sc;
837 struct fms_dma *p;
838
839 sc = addr;
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 continue;
845
846 if (p == NULL)
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 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_DMALEN, blksize - 1);
856 bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_REC_DMABUF1,
857 sc->sc_rec_start);
858 bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_REC_DMABUF2,
859 sc->sc_rec_nextblk);
860 bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL,
861 FM_REC_START | FM_REC_STOPNOW | sc->sc_rec_reg);
862 return 0;
863 }
864