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