1 /* $NetBSD: fms.c,v 1.36 2009/05/12 08:23:00 cegger Exp $ */
4 * Copyright (c) 1999 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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.
33 * Forte Media FM801 Audio Device Driver
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: fms.c,v 1.36 2009/05/12 08:23:00 cegger Exp $");
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
44 #include <sys/malloc.h>
45 #include <sys/device.h>
46 #include <sys/audioio.h>
48 #include <uvm/uvm_extern.h>
53 #include <dev/pci/pcidevs.h>
54 #include <dev/pci/pcivar.h>
56 #include <dev/audio_if.h>
57 #include <dev/mulaw.h>
58 #include <dev/auconv.h>
60 #include <dev/ic/ac97var.h>
61 #include <dev/ic/mpuvar.h>
63 #include <dev/pci/fmsvar.h>
71 bus_dma_segment_t seg
;
76 static int fms_match(device_t
, cfdata_t
, void *);
77 static void fms_attach(device_t
, device_t
, void *);
78 static int fms_intr(void *);
80 static int fms_query_encoding(void *, struct audio_encoding
*);
81 static int fms_set_params(void *, int, int, audio_params_t
*,
82 audio_params_t
*, stream_filter_list_t
*,
83 stream_filter_list_t
*);
84 static int fms_round_blocksize(void *, int, int, const audio_params_t
*);
85 static int fms_halt_output(void *);
86 static int fms_halt_input(void *);
87 static int fms_getdev(void *, struct audio_device
*);
88 static int fms_set_port(void *, mixer_ctrl_t
*);
89 static int fms_get_port(void *, mixer_ctrl_t
*);
90 static int fms_query_devinfo(void *, mixer_devinfo_t
*);
91 static void *fms_malloc(void *, int, size_t, struct malloc_type
*, int);
92 static void fms_free(void *, void *, struct malloc_type
*);
93 static size_t fms_round_buffersize(void *, int, size_t);
94 static paddr_t
fms_mappage(void *, void *, off_t
, int);
95 static int fms_get_props(void *);
96 static int fms_trigger_output(void *, void *, void *, int,
97 void (*)(void *), void *,
98 const audio_params_t
*);
99 static int fms_trigger_input(void *, void *, void *, int,
100 void (*)(void *), void *,
101 const audio_params_t
*);
103 CFATTACH_DECL(fms
, sizeof (struct fms_softc
),
104 fms_match
, fms_attach
, NULL
, NULL
);
106 static struct audio_device fms_device
= {
113 static const struct audio_hw_if fms_hw_if
= {
135 fms_round_buffersize
,
144 static int fms_attach_codec(void *, struct ac97_codec_if
*);
145 static int fms_read_codec(void *, uint8_t, uint16_t *);
146 static int fms_write_codec(void *, uint8_t, uint16_t);
147 static int fms_reset_codec(void *);
149 #define FM_PCM_VOLUME 0x00
150 #define FM_FM_VOLUME 0x02
151 #define FM_I2S_VOLUME 0x04
152 #define FM_RECORD_SOURCE 0x06
154 #define FM_PLAY_CTL 0x08
155 #define FM_PLAY_RATE_MASK 0x0f00
156 #define FM_PLAY_BUF1_LAST 0x0001
157 #define FM_PLAY_BUF2_LAST 0x0002
158 #define FM_PLAY_START 0x0020
159 #define FM_PLAY_PAUSE 0x0040
160 #define FM_PLAY_STOPNOW 0x0080
161 #define FM_PLAY_16BIT 0x4000
162 #define FM_PLAY_STEREO 0x8000
164 #define FM_PLAY_DMALEN 0x0a
165 #define FM_PLAY_DMABUF1 0x0c
166 #define FM_PLAY_DMABUF2 0x10
169 #define FM_REC_CTL 0x14
170 #define FM_REC_RATE_MASK 0x0f00
171 #define FM_REC_BUF1_LAST 0x0001
172 #define FM_REC_BUF2_LAST 0x0002
173 #define FM_REC_START 0x0020
174 #define FM_REC_PAUSE 0x0040
175 #define FM_REC_STOPNOW 0x0080
176 #define FM_REC_16BIT 0x4000
177 #define FM_REC_STEREO 0x8000
180 #define FM_REC_DMALEN 0x16
181 #define FM_REC_DMABUF1 0x18
182 #define FM_REC_DMABUF2 0x1c
184 #define FM_CODEC_CTL 0x22
185 #define FM_VOLUME 0x26
186 #define FM_VOLUME_MUTE 0x8000
188 #define FM_CODEC_CMD 0x2a
189 #define FM_CODEC_CMD_READ 0x0080
190 #define FM_CODEC_CMD_VALID 0x0100
191 #define FM_CODEC_CMD_BUSY 0x0200
193 #define FM_CODEC_DATA 0x2c
195 #define FM_IO_CTL 0x52
196 #define FM_CARD_CTL 0x54
198 #define FM_INTMASK 0x56
199 #define FM_INTMASK_PLAY 0x0001
200 #define FM_INTMASK_REC 0x0002
201 #define FM_INTMASK_VOL 0x0040
202 #define FM_INTMASK_MPU 0x0080
204 #define FM_INTSTATUS 0x5a
205 #define FM_INTSTATUS_PLAY 0x0100
206 #define FM_INTSTATUS_REC 0x0200
207 #define FM_INTSTATUS_VOL 0x4000
208 #define FM_INTSTATUS_MPU 0x8000
212 fms_match(device_t parent
, cfdata_t match
, void *aux
)
214 struct pci_attach_args
*pa
;
216 pa
= (struct pci_attach_args
*)aux
;
217 if (PCI_VENDOR(pa
->pa_id
) != PCI_VENDOR_FORTEMEDIA
)
219 if (PCI_PRODUCT(pa
->pa_id
) != PCI_PRODUCT_FORTEMEDIA_FM801
)
226 fms_attach(device_t parent
, device_t self
, void *aux
)
228 struct pci_attach_args
*pa
;
229 struct fms_softc
*sc
;
230 struct audio_attach_args aa
;
232 pci_chipset_tag_t pc
;
234 pci_intr_handle_t ih
;
238 sc
= device_private(self
);
242 aprint_naive(": Audio controller\n");
243 aprint_normal(": Forte Media FM-801\n");
245 if (pci_intr_map(pa
, &ih
)) {
246 aprint_error_dev(&sc
->sc_dev
, "couldn't map interrupt\n");
249 intrstr
= pci_intr_string(pc
, ih
);
251 sc
->sc_ih
= pci_intr_establish(pc
, ih
, IPL_AUDIO
, fms_intr
, sc
);
252 if (sc
->sc_ih
== NULL
) {
253 aprint_error_dev(&sc
->sc_dev
, "couldn't establish interrupt");
255 aprint_error(" at %s", intrstr
);
260 sc
->sc_dmat
= pa
->pa_dmat
;
262 aprint_normal_dev(&sc
->sc_dev
, "interrupting at %s\n", intrstr
);
264 if (pci_mapreg_map(pa
, 0x10, PCI_MAPREG_TYPE_IO
, 0, &sc
->sc_iot
,
265 &sc
->sc_ioh
, &sc
->sc_ioaddr
, &sc
->sc_iosize
)) {
266 aprint_error_dev(&sc
->sc_dev
, "can't map i/o space\n");
270 if (bus_space_subregion(sc
->sc_iot
, sc
->sc_ioh
, 0x30, 2,
272 panic("fms_attach: can't get mpu subregion handle");
274 if (bus_space_subregion(sc
->sc_iot
, sc
->sc_ioh
, 0x68, 4,
276 panic("fms_attach: can't get opl subregion handle");
278 /* Disable legacy audio (SBPro compatibility) */
279 pci_conf_write(pc
, pt
, 0x40, 0);
281 /* Reset codec and AC'97 */
282 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, FM_CODEC_CTL
, 0x0020);
283 delay(2); /* > 1us according to AC'97 documentation */
284 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, FM_CODEC_CTL
, 0x0000);
285 delay(1); /* > 168.2ns according to AC'97 documentation */
288 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, FM_PCM_VOLUME
, 0x0808);
289 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, FM_FM_VOLUME
, 0x0808);
290 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, FM_I2S_VOLUME
, 0x0808);
292 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, FM_RECORD_SOURCE
, 0x0000);
294 /* Unmask playback, record and mpu interrupts, mask the rest */
295 k1
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, FM_INTMASK
);
296 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, FM_INTMASK
,
297 (k1
& ~(FM_INTMASK_PLAY
| FM_INTMASK_REC
| FM_INTMASK_MPU
)) |
299 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, FM_INTSTATUS
,
300 FM_INTSTATUS_PLAY
| FM_INTSTATUS_REC
| FM_INTSTATUS_MPU
|
303 sc
->host_if
.arg
= sc
;
304 sc
->host_if
.attach
= fms_attach_codec
;
305 sc
->host_if
.read
= fms_read_codec
;
306 sc
->host_if
.write
= fms_write_codec
;
307 sc
->host_if
.reset
= fms_reset_codec
;
309 if (ac97_attach(&sc
->host_if
, self
) != 0)
312 audio_attach_mi(&fms_hw_if
, sc
, &sc
->sc_dev
);
314 aa
.type
= AUDIODEV_TYPE_OPL
;
317 config_found(&sc
->sc_dev
, &aa
, audioprint
);
319 aa
.type
= AUDIODEV_TYPE_MPU
;
322 sc
->sc_mpu_dev
= config_found(&sc
->sc_dev
, &aa
, audioprint
);
326 * Each AC-link frame takes 20.8us, data should be ready in next frame,
327 * we allow more than two.
331 fms_read_codec(void *addr
, uint8_t reg
, uint16_t *val
)
333 struct fms_softc
*sc
;
337 /* Poll until codec is ready */
338 for (i
= 0; i
< TIMO
&& bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
,
339 FM_CODEC_CMD
) & FM_CODEC_CMD_BUSY
; i
++)
342 printf("fms: codec busy\n");
346 /* Write register index, read access */
347 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, FM_CODEC_CMD
,
348 reg
| FM_CODEC_CMD_READ
);
350 /* Poll until we have valid data */
351 for (i
= 0; i
< TIMO
&& !(bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
,
352 FM_CODEC_CMD
) & FM_CODEC_CMD_VALID
); i
++)
355 printf("fms: no data from codec\n");
360 *val
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, FM_CODEC_DATA
);
365 fms_write_codec(void *addr
, uint8_t reg
, uint16_t val
)
367 struct fms_softc
*sc
= addr
;
370 /* Poll until codec is ready */
371 for (i
= 0; i
< TIMO
&& bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
,
372 FM_CODEC_CMD
) & FM_CODEC_CMD_BUSY
; i
++)
375 printf("fms: codec busy\n");
380 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, FM_CODEC_DATA
, val
);
381 /* Write index register, write access */
382 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, FM_CODEC_CMD
, reg
);
388 fms_attach_codec(void *addr
, struct ac97_codec_if
*cif
)
390 struct fms_softc
*sc
;
399 fms_reset_codec(void *addr
)
401 struct fms_softc
*sc
;
404 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, FM_CODEC_CTL
, 0x0020);
406 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, FM_CODEC_CTL
, 0x0000);
414 struct fms_softc
*sc
= arg
;
416 struct mpu_softc
*sc_mpu
= device_private(sc
->sc_mpu_dev
);
420 istat
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, FM_INTSTATUS
);
422 if (istat
& FM_INTSTATUS_PLAY
) {
423 if ((sc
->sc_play_nextblk
+= sc
->sc_play_blksize
) >=
425 sc
->sc_play_nextblk
= sc
->sc_play_start
;
427 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
,
428 sc
->sc_play_flip
++ & 1 ?
429 FM_PLAY_DMABUF2
: FM_PLAY_DMABUF1
, sc
->sc_play_nextblk
);
432 sc
->sc_pintr(sc
->sc_parg
);
434 printf("unexpected play intr\n");
437 if (istat
& FM_INTSTATUS_REC
) {
438 if ((sc
->sc_rec_nextblk
+= sc
->sc_rec_blksize
) >=
440 sc
->sc_rec_nextblk
= sc
->sc_rec_start
;
442 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
,
443 sc
->sc_rec_flip
++ & 1 ?
444 FM_REC_DMABUF2
: FM_REC_DMABUF1
, sc
->sc_rec_nextblk
);
447 sc
->sc_rintr(sc
->sc_rarg
);
449 printf("unexpected rec intr\n");
453 if (istat
& FM_INTSTATUS_MPU
)
457 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, FM_INTSTATUS
,
458 istat
& (FM_INTSTATUS_PLAY
| FM_INTSTATUS_REC
));
464 fms_query_encoding(void *addr
, struct audio_encoding
*fp
)
469 strcpy(fp
->name
, AudioEmulaw
);
470 fp
->encoding
= AUDIO_ENCODING_ULAW
;
472 fp
->flags
= AUDIO_ENCODINGFLAG_EMULATED
;
475 strcpy(fp
->name
, AudioEslinear_le
);
476 fp
->encoding
= AUDIO_ENCODING_SLINEAR_LE
;
481 strcpy(fp
->name
, AudioEulinear
);
482 fp
->encoding
= AUDIO_ENCODING_ULINEAR
;
487 strcpy(fp
->name
, AudioEalaw
);
488 fp
->encoding
= AUDIO_ENCODING_ALAW
;
490 fp
->flags
= AUDIO_ENCODINGFLAG_EMULATED
;
493 strcpy(fp
->name
, AudioEulinear_le
);
494 fp
->encoding
= AUDIO_ENCODING_ULINEAR_LE
;
496 fp
->flags
= AUDIO_ENCODINGFLAG_EMULATED
;
499 strcpy(fp
->name
, AudioEslinear
);
500 fp
->encoding
= AUDIO_ENCODING_SLINEAR
;
502 fp
->flags
= AUDIO_ENCODINGFLAG_EMULATED
;
505 strcpy(fp
->name
, AudioEulinear_be
);
506 fp
->encoding
= AUDIO_ENCODING_ULINEAR_BE
;
508 fp
->flags
= AUDIO_ENCODINGFLAG_EMULATED
;
511 strcpy(fp
->name
, AudioEslinear_be
);
512 fp
->encoding
= AUDIO_ENCODING_SLINEAR_BE
;
514 fp
->flags
= AUDIO_ENCODINGFLAG_EMULATED
;
522 * Range below -limit- is set to -rate-
523 * What a pity FM801 does not have 24000
524 * 24000 -> 22050 sounds rather poor
529 } const fms_rates
[11] = {
541 /* anything above -> 48000 */
544 #define FMS_NFORMATS 4
545 static const struct audio_format fms_formats
[FMS_NFORMATS
] = {
546 {NULL
, AUMODE_PLAY
| AUMODE_RECORD
, AUDIO_ENCODING_SLINEAR_LE
, 16, 16,
547 2, AUFMT_STEREO
, 11, {5500, 8000, 9600, 11025, 16000, 19200, 22050,
548 32000, 38400, 44100, 48000}},
549 {NULL
, AUMODE_PLAY
| AUMODE_RECORD
, AUDIO_ENCODING_SLINEAR_LE
, 16, 16,
550 1, AUFMT_MONAURAL
, 11, {5500, 8000, 9600, 11025, 16000, 19200, 22050,
551 32000, 38400, 44100, 48000}},
552 {NULL
, AUMODE_PLAY
| AUMODE_RECORD
, AUDIO_ENCODING_ULINEAR_LE
, 8, 8,
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_ULINEAR_LE
, 8, 8,
556 1, AUFMT_MONAURAL
, 11, {5500, 8000, 9600, 11025, 16000, 19200, 22050,
557 32000, 38400, 44100, 48000}},
561 fms_set_params(void *addr
, int setmode
, int usemode
,
562 audio_params_t
*play
, audio_params_t
*rec
, stream_filter_list_t
*pfil
,
563 stream_filter_list_t
*rfil
)
565 struct fms_softc
*sc
;
569 if (setmode
& AUMODE_PLAY
) {
570 for (i
= 0; i
< 10 && play
->sample_rate
> fms_rates
[i
].limit
;
573 play
->sample_rate
= fms_rates
[i
].rate
;
574 index
= auconv_set_converter(fms_formats
, FMS_NFORMATS
,
575 AUMODE_PLAY
, play
, FALSE
, pfil
);
578 sc
->sc_play_reg
= i
<< 8;
579 if (fms_formats
[index
].channels
== 2)
580 sc
->sc_play_reg
|= FM_PLAY_STEREO
;
581 if (fms_formats
[index
].precision
== 16)
582 sc
->sc_play_reg
|= FM_PLAY_16BIT
;
585 if (setmode
& AUMODE_RECORD
) {
586 for (i
= 0; i
< 10 && rec
->sample_rate
> fms_rates
[i
].limit
;
589 rec
->sample_rate
= fms_rates
[i
].rate
;
590 index
= auconv_set_converter(fms_formats
, FMS_NFORMATS
,
591 AUMODE_RECORD
, rec
, FALSE
, rfil
);
594 sc
->sc_rec_reg
= i
<< 8;
595 if (fms_formats
[index
].channels
== 2)
596 sc
->sc_rec_reg
|= FM_REC_STEREO
;
597 if (fms_formats
[index
].precision
== 16)
598 sc
->sc_rec_reg
|= FM_REC_16BIT
;
605 fms_round_blocksize(void *addr
, int blk
, int mode
,
606 const audio_params_t
*param
)
613 fms_halt_output(void *addr
)
615 struct fms_softc
*sc
;
619 k1
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, FM_PLAY_CTL
);
620 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, FM_PLAY_CTL
,
621 (k1
& ~(FM_PLAY_STOPNOW
| FM_PLAY_START
)) |
622 FM_PLAY_BUF1_LAST
| FM_PLAY_BUF2_LAST
);
628 fms_halt_input(void *addr
)
630 struct fms_softc
*sc
;
634 k1
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, FM_REC_CTL
);
635 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, FM_REC_CTL
,
636 (k1
& ~(FM_REC_STOPNOW
| FM_REC_START
)) |
637 FM_REC_BUF1_LAST
| FM_REC_BUF2_LAST
);
643 fms_getdev(void *addr
, struct audio_device
*retp
)
651 fms_set_port(void *addr
, mixer_ctrl_t
*cp
)
653 struct fms_softc
*sc
;
656 return sc
->codec_if
->vtbl
->mixer_set_port(sc
->codec_if
, cp
);
660 fms_get_port(void *addr
, mixer_ctrl_t
*cp
)
662 struct fms_softc
*sc
;
665 return sc
->codec_if
->vtbl
->mixer_get_port(sc
->codec_if
, cp
);
669 fms_malloc(void *addr
, int direction
, size_t size
,
670 struct malloc_type
*pool
, int flags
)
672 struct fms_softc
*sc
;
678 p
= malloc(sizeof(*p
), pool
, flags
);
683 if ((error
= bus_dmamem_alloc(sc
->sc_dmat
, size
, PAGE_SIZE
, 0, &p
->seg
,
684 1, &rseg
, BUS_DMA_NOWAIT
)) != 0) {
685 aprint_error_dev(&sc
->sc_dev
, "unable to allocate DMA, error = %d\n", error
);
689 if ((error
= bus_dmamem_map(sc
->sc_dmat
, &p
->seg
, rseg
, size
, &p
->addr
,
690 BUS_DMA_NOWAIT
| BUS_DMA_COHERENT
)) != 0) {
691 aprint_error_dev(&sc
->sc_dev
, "unable to map DMA, error = %d\n",
696 if ((error
= bus_dmamap_create(sc
->sc_dmat
, size
, 1, size
, 0,
697 BUS_DMA_NOWAIT
, &p
->map
)) != 0) {
698 aprint_error_dev(&sc
->sc_dev
, "unable to create DMA map, error = %d\n",
703 if ((error
= bus_dmamap_load(sc
->sc_dmat
, p
->map
, p
->addr
, size
, NULL
,
704 BUS_DMA_NOWAIT
)) != 0) {
705 aprint_error_dev(&sc
->sc_dev
, "unable to load DMA map, error = %d\n",
710 p
->next
= sc
->sc_dmas
;
717 bus_dmamap_destroy(sc
->sc_dmat
, p
->map
);
719 bus_dmamem_unmap(sc
->sc_dmat
, p
->addr
, size
);
721 bus_dmamem_free(sc
->sc_dmat
, &p
->seg
, 1);
728 fms_free(void *addr
, void *ptr
, struct malloc_type
*pool
)
730 struct fms_softc
*sc
;
731 struct fms_dma
**pp
, *p
;
734 for (pp
= &(sc
->sc_dmas
); (p
= *pp
) != NULL
; pp
= &p
->next
)
735 if (p
->addr
== ptr
) {
736 bus_dmamap_unload(sc
->sc_dmat
, p
->map
);
737 bus_dmamap_destroy(sc
->sc_dmat
, p
->map
);
738 bus_dmamem_unmap(sc
->sc_dmat
, p
->addr
, p
->size
);
739 bus_dmamem_free(sc
->sc_dmat
, &p
->seg
, 1);
746 panic("fms_free: trying to free unallocated memory");
750 fms_round_buffersize(void *addr
, int direction
, size_t size
)
757 fms_mappage(void *addr
, void *mem
, off_t off
, int prot
)
759 struct fms_softc
*sc
;
766 for (p
= sc
->sc_dmas
; p
&& p
->addr
!= mem
; p
= p
->next
)
771 return bus_dmamem_mmap(sc
->sc_dmat
, &p
->seg
, 1, off
, prot
,
776 fms_get_props(void *addr
)
778 return AUDIO_PROP_MMAP
| AUDIO_PROP_INDEPENDENT
|
779 AUDIO_PROP_FULLDUPLEX
;
783 fms_query_devinfo(void *addr
, mixer_devinfo_t
*dip
)
785 struct fms_softc
*sc
;
788 return sc
->codec_if
->vtbl
->query_devinfo(sc
->codec_if
, dip
);
792 fms_trigger_output(void *addr
, void *start
, void *end
, int blksize
,
793 void (*intr
)(void *), void *arg
, const audio_params_t
*param
)
795 struct fms_softc
*sc
;
802 for (p
= sc
->sc_dmas
; p
&& p
->addr
!= start
; p
= p
->next
)
806 panic("fms_trigger_output: request with bad start "
807 "address (%p)", start
);
809 sc
->sc_play_start
= p
->map
->dm_segs
[0].ds_addr
;
810 sc
->sc_play_end
= sc
->sc_play_start
+ ((char *)end
- (char *)start
);
811 sc
->sc_play_blksize
= blksize
;
812 sc
->sc_play_nextblk
= sc
->sc_play_start
+ sc
->sc_play_blksize
;
813 sc
->sc_play_flip
= 0;
814 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, FM_PLAY_DMALEN
, blksize
- 1);
815 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
, FM_PLAY_DMABUF1
,
817 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
, FM_PLAY_DMABUF2
,
818 sc
->sc_play_nextblk
);
819 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, FM_PLAY_CTL
,
820 FM_PLAY_START
| FM_PLAY_STOPNOW
| sc
->sc_play_reg
);
826 fms_trigger_input(void *addr
, void *start
, void *end
, int blksize
,
827 void (*intr
)(void *), void *arg
, const audio_params_t
*param
)
829 struct fms_softc
*sc
;
836 for (p
= sc
->sc_dmas
; p
&& p
->addr
!= start
; p
= p
->next
)
840 panic("fms_trigger_input: request with bad start "
841 "address (%p)", start
);
843 sc
->sc_rec_start
= p
->map
->dm_segs
[0].ds_addr
;
844 sc
->sc_rec_end
= sc
->sc_rec_start
+ ((char *)end
- (char *)start
);
845 sc
->sc_rec_blksize
= blksize
;
846 sc
->sc_rec_nextblk
= sc
->sc_rec_start
+ sc
->sc_rec_blksize
;
848 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, FM_REC_DMALEN
, blksize
- 1);
849 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
, FM_REC_DMABUF1
,
851 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
, FM_REC_DMABUF2
,
853 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, FM_REC_CTL
,
854 FM_REC_START
| FM_REC_STOPNOW
| sc
->sc_rec_reg
);