1 /* $NetBSD: vs.c,v 1.36 2014/03/26 08:17:59 christos Exp $ */ 2 3 /* 4 * Copyright (c) 2001 Tetsuya Isaki. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 /* 29 * VS - OKI MSM6258 ADPCM voice synthesizer device driver. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: vs.c,v 1.36 2014/03/26 08:17:59 christos Exp $"); 34 35 #include "audio.h" 36 #include "vs.h" 37 #if NAUDIO > 0 && NVS > 0 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/device.h> 42 #include <sys/kmem.h> 43 44 #include <sys/audioio.h> 45 #include <dev/audio_if.h> 46 #include <dev/mulaw.h> 47 48 #include <machine/bus.h> 49 #include <machine/cpu.h> 50 51 #include <dev/ic/msm6258var.h> 52 53 #include <arch/x68k/dev/dmacvar.h> 54 #include <arch/x68k/dev/intiovar.h> 55 #include <arch/x68k/dev/opmvar.h> 56 57 #include <arch/x68k/dev/vsvar.h> 58 59 #ifdef VS_DEBUG 60 #define DPRINTF(y,x) if (vs_debug >= (y)) printf x 61 static int vs_debug; 62 #ifdef AUDIO_DEBUG 63 extern int audiodebug; 64 #endif 65 #else 66 #define DPRINTF(y,x) 67 #endif 68 69 static int vs_match(device_t, cfdata_t, void *); 70 static void vs_attach(device_t, device_t, void *); 71 72 static int vs_dmaintr(void *); 73 static int vs_dmaerrintr(void *); 74 75 /* MI audio layer interface */ 76 static int vs_open(void *, int); 77 static void vs_close(void *); 78 static int vs_query_encoding(void *, struct audio_encoding *); 79 static int vs_set_params(void *, int, int, audio_params_t *, 80 audio_params_t *, stream_filter_list_t *, stream_filter_list_t *); 81 static int vs_trigger_output(void *, void *, void *, int, 82 void (*)(void *), void *, const audio_params_t *); 83 static int vs_trigger_input(void *, void *, void *, int, 84 void (*)(void *), void *, const audio_params_t *); 85 static int vs_halt_output(void *); 86 static int vs_halt_input(void *); 87 static int vs_allocmem(struct vs_softc *, size_t, size_t, size_t, 88 struct vs_dma *); 89 static void vs_freemem(struct vs_dma *); 90 static int vs_getdev(void *, struct audio_device *); 91 static int vs_set_port(void *, mixer_ctrl_t *); 92 static int vs_get_port(void *, mixer_ctrl_t *); 93 static int vs_query_devinfo(void *, mixer_devinfo_t *); 94 static void *vs_allocm(void *, int, size_t); 95 static void vs_freem(void *, void *, size_t); 96 static size_t vs_round_buffersize(void *, int, size_t); 97 static int vs_get_props(void *); 98 static void vs_get_locks(void *, kmutex_t **, kmutex_t **); 99 100 /* lower functions */ 101 static int vs_round_sr(u_long); 102 static void vs_set_sr(struct vs_softc *, int); 103 static inline void vs_set_po(struct vs_softc *, u_long); 104 105 extern struct cfdriver vs_cd; 106 107 CFATTACH_DECL_NEW(vs, sizeof(struct vs_softc), 108 vs_match, vs_attach, NULL, NULL); 109 110 static int vs_attached; 111 112 static const struct audio_hw_if vs_hw_if = { 113 vs_open, 114 vs_close, 115 NULL, /* drain */ 116 vs_query_encoding, 117 vs_set_params, 118 NULL, /* round_blocksize */ 119 NULL, /* commit_settings */ 120 NULL, /* init_output */ 121 NULL, /* init_input */ 122 NULL, /* start_output */ 123 NULL, /* start_input */ 124 vs_halt_output, 125 vs_halt_input, 126 NULL, /* speaker_ctl */ 127 vs_getdev, 128 NULL, /* setfd */ 129 vs_set_port, 130 vs_get_port, 131 vs_query_devinfo, 132 vs_allocm, 133 vs_freem, 134 vs_round_buffersize, 135 NULL, /* mappage */ 136 vs_get_props, 137 vs_trigger_output, 138 vs_trigger_input, 139 NULL, 140 vs_get_locks, 141 }; 142 143 static struct audio_device vs_device = { 144 "OKI MSM6258", 145 "", 146 "vs" 147 }; 148 149 struct { 150 u_long rate; 151 u_char clk; 152 u_char den; 153 } vs_l2r[] = { 154 { VS_RATE_15K, VS_CLK_8MHZ, VS_SRATE_512 }, 155 { VS_RATE_10K, VS_CLK_8MHZ, VS_SRATE_768 }, 156 { VS_RATE_7K, VS_CLK_8MHZ, VS_SRATE_1024}, 157 { VS_RATE_5K, VS_CLK_4MHZ, VS_SRATE_768 }, 158 { VS_RATE_3K, VS_CLK_4MHZ, VS_SRATE_1024} 159 }; 160 161 #define NUM_RATE (sizeof(vs_l2r)/sizeof(vs_l2r[0])) 162 163 struct { 164 const char *name; 165 int encoding; 166 int precision; 167 } vs_encodings[] = { 168 {AudioEadpcm, AUDIO_ENCODING_ADPCM, 4}, 169 {AudioEslinear, AUDIO_ENCODING_SLINEAR, 8}, 170 {AudioEulinear, AUDIO_ENCODING_ULINEAR, 8}, 171 {AudioEmulaw, AUDIO_ENCODING_ULAW, 8}, 172 {AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE, 16}, 173 {AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE, 16}, 174 }; 175 176 static int 177 vs_match(device_t parent, cfdata_t cf, void *aux) 178 { 179 struct intio_attach_args *ia; 180 181 ia = aux; 182 if (strcmp(ia->ia_name, "vs") || vs_attached) 183 return 0; 184 185 if (ia->ia_addr == INTIOCF_ADDR_DEFAULT) 186 ia->ia_addr = VS_ADDR; 187 if (ia->ia_dma == INTIOCF_DMA_DEFAULT) 188 ia->ia_dma = VS_DMA; 189 if (ia->ia_dmaintr == INTIOCF_DMAINTR_DEFAULT) 190 ia->ia_dmaintr = VS_DMAINTR; 191 192 /* fixed parameters */ 193 if (ia->ia_addr != VS_ADDR) 194 return 0; 195 if (ia->ia_dma != VS_DMA) 196 return 0; 197 if (ia->ia_dmaintr != VS_DMAINTR) 198 return 0; 199 200 #ifdef VS_DEBUG 201 vs_debug = 1; 202 #ifdef AUDIO_DEBUG 203 audiodebug = 2; 204 #endif 205 #endif 206 207 return 1; 208 } 209 210 static void 211 vs_attach(device_t parent, device_t self, void *aux) 212 { 213 struct vs_softc *sc; 214 bus_space_tag_t iot; 215 bus_space_handle_t ioh; 216 struct intio_attach_args *ia; 217 218 sc = device_private(self); 219 sc->sc_dev = self; 220 ia = aux; 221 vs_attached = 1; 222 223 printf("\n"); 224 225 /* Re-map the I/O space */ 226 iot = ia->ia_bst; 227 bus_space_map(iot, ia->ia_addr, 0x2000, BUS_SPACE_MAP_SHIFTED, &ioh); 228 229 /* Initialize sc */ 230 sc->sc_iot = iot; 231 sc->sc_ioh = ioh; 232 sc->sc_hw_if = &vs_hw_if; 233 sc->sc_addr = (void *) ia->ia_addr; 234 sc->sc_dmas = NULL; 235 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 236 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED); 237 238 /* XXX */ 239 bus_space_map(iot, PPI_ADDR, PPI_MAPSIZE, BUS_SPACE_MAP_SHIFTED, 240 &sc->sc_ppi); 241 242 /* Initialize DMAC */ 243 sc->sc_dmat = ia->ia_dmat; 244 sc->sc_dma_ch = dmac_alloc_channel(parent, ia->ia_dma, "vs", 245 ia->ia_dmaintr, vs_dmaintr, sc, 246 ia->ia_dmaintr+1, vs_dmaerrintr, sc); 247 248 aprint_normal_dev(self, "MSM6258V ADPCM voice synthesizer\n"); 249 250 audio_attach_mi(&vs_hw_if, sc, sc->sc_dev); 251 } 252 253 /* 254 * vs interrupt handler 255 */ 256 static int 257 vs_dmaintr(void *hdl) 258 { 259 struct vs_softc *sc; 260 261 DPRINTF(2, ("vs_dmaintr\n")); 262 sc = hdl; 263 264 mutex_spin_enter(&sc->sc_intr_lock); 265 266 if (sc->sc_pintr) { 267 /* start next transfer */ 268 sc->sc_current.dmap += sc->sc_current.blksize; 269 if (sc->sc_current.dmap + sc->sc_current.blksize 270 > sc->sc_current.bufsize) 271 sc->sc_current.dmap -= sc->sc_current.bufsize; 272 dmac_start_xfer_offset(sc->sc_dma_ch->ch_softc, 273 sc->sc_current.xfer, 274 sc->sc_current.dmap, 275 sc->sc_current.blksize); 276 sc->sc_pintr(sc->sc_parg); 277 } else if (sc->sc_rintr) { 278 /* start next transfer */ 279 sc->sc_current.dmap += sc->sc_current.blksize; 280 if (sc->sc_current.dmap + sc->sc_current.blksize 281 > sc->sc_current.bufsize) 282 sc->sc_current.dmap -= sc->sc_current.bufsize; 283 dmac_start_xfer_offset(sc->sc_dma_ch->ch_softc, 284 sc->sc_current.xfer, 285 sc->sc_current.dmap, 286 sc->sc_current.blksize); 287 sc->sc_rintr(sc->sc_rarg); 288 } else { 289 printf("vs_dmaintr: spurious interrupt\n"); 290 } 291 292 mutex_spin_exit(&sc->sc_intr_lock); 293 294 return 1; 295 } 296 297 static int 298 vs_dmaerrintr(void *hdl) 299 { 300 struct vs_softc *sc; 301 302 sc = hdl; 303 DPRINTF(1, ("%s: DMA transfer error.\n", device_xname(sc->sc_dev))); 304 /* XXX */ 305 vs_dmaintr(sc); 306 307 return 1; 308 } 309 310 311 /* 312 * audio MD layer interfaces 313 */ 314 315 static int 316 vs_open(void *hdl, int flags) 317 { 318 struct vs_softc *sc; 319 320 DPRINTF(1, ("vs_open: flags=%d\n", flags)); 321 sc = hdl; 322 sc->sc_pintr = NULL; 323 sc->sc_rintr = NULL; 324 325 return 0; 326 } 327 328 static void 329 vs_close(void *hdl) 330 { 331 332 DPRINTF(1, ("vs_close\n")); 333 } 334 335 static int 336 vs_query_encoding(void *hdl, struct audio_encoding *fp) 337 { 338 339 DPRINTF(1, ("vs_query_encoding\n")); 340 if (fp->index >= sizeof(vs_encodings) / sizeof(vs_encodings[0])) 341 return EINVAL; 342 343 strcpy(fp->name, vs_encodings[fp->index].name); 344 fp->encoding = vs_encodings[fp->index].encoding; 345 fp->precision = vs_encodings[fp->index].precision; 346 if (fp->encoding == AUDIO_ENCODING_ADPCM) 347 fp->flags = 0; 348 else 349 fp->flags = AUDIO_ENCODINGFLAG_EMULATED; 350 return 0; 351 } 352 353 static int 354 vs_round_sr(u_long rate) 355 { 356 int i; 357 int diff; 358 int nearest; 359 360 diff = rate; 361 nearest = 0; 362 for (i = 0; i < NUM_RATE; i++) { 363 if (rate >= vs_l2r[i].rate) { 364 if (rate - vs_l2r[i].rate < diff) { 365 diff = rate - vs_l2r[i].rate; 366 nearest = i; 367 } 368 } else { 369 if (vs_l2r[i].rate - rate < diff) { 370 diff = vs_l2r[i].rate - rate; 371 nearest = i; 372 } 373 } 374 } 375 if (diff * 100 / rate > 15) 376 return -1; 377 else 378 return nearest; 379 } 380 381 static int 382 vs_set_params(void *hdl, int setmode, int usemode, 383 audio_params_t *play, audio_params_t *rec, 384 stream_filter_list_t *pfil, stream_filter_list_t *rfil) 385 { 386 struct vs_softc *sc; 387 struct audio_params *p; 388 int mode; 389 int rate; 390 audio_params_t hw; 391 int matched; 392 393 DPRINTF(1, ("vs_set_params: setmode=%d, usemode=%d\n", 394 setmode, usemode)); 395 396 sc = hdl; 397 /* set first record info, then play info */ 398 for (mode = AUMODE_RECORD; mode != -1; 399 mode = (mode == AUMODE_RECORD) ? AUMODE_PLAY : -1) { 400 if ((setmode & mode) == 0) 401 continue; 402 403 p = (mode == AUMODE_PLAY) ? play : rec; 404 405 if (p->channels != 1) 406 return EINVAL; 407 408 rate = p->sample_rate; 409 hw = *p; 410 hw.encoding = AUDIO_ENCODING_ADPCM; 411 hw.precision = hw.validbits = 4; 412 DPRINTF(1, ("vs_set_params: encoding=%d, precision=%d\n", 413 p->encoding, p->precision)); 414 matched = 0; 415 switch (p->precision) { 416 case 4: 417 if (p->encoding == AUDIO_ENCODING_ADPCM) 418 matched = 1; 419 break; 420 case 8: 421 switch (p->encoding) { 422 case AUDIO_ENCODING_ULAW: 423 matched = 1; 424 hw.encoding = AUDIO_ENCODING_ULINEAR_LE; 425 hw.precision = hw.validbits = 8; 426 pfil->prepend(pfil, mulaw_to_linear8, &hw); 427 hw.encoding = AUDIO_ENCODING_ADPCM; 428 hw.precision = hw.validbits = 4; 429 pfil->prepend(pfil, msm6258_linear8_to_adpcm, &hw); 430 rfil->append(rfil, msm6258_adpcm_to_linear8, &hw); 431 hw.encoding = AUDIO_ENCODING_ULINEAR_LE; 432 hw.precision = hw.validbits = 8; 433 rfil->append(rfil, linear8_to_mulaw, &hw); 434 break; 435 case AUDIO_ENCODING_SLINEAR: 436 case AUDIO_ENCODING_SLINEAR_LE: 437 case AUDIO_ENCODING_SLINEAR_BE: 438 case AUDIO_ENCODING_ULINEAR: 439 case AUDIO_ENCODING_ULINEAR_LE: 440 case AUDIO_ENCODING_ULINEAR_BE: 441 matched = 1; 442 pfil->append(pfil, msm6258_linear8_to_adpcm, &hw); 443 rfil->append(rfil, msm6258_adpcm_to_linear8, &hw); 444 break; 445 } 446 break; 447 case 16: 448 switch (p->encoding) { 449 case AUDIO_ENCODING_SLINEAR_LE: 450 case AUDIO_ENCODING_SLINEAR_BE: 451 matched = 1; 452 pfil->append(pfil, msm6258_slinear16_to_adpcm, &hw); 453 rfil->append(rfil, msm6258_adpcm_to_slinear16, &hw); 454 break; 455 } 456 break; 457 } 458 if (matched == 0) { 459 DPRINTF(1, ("vs_set_params: mode=%d, encoding=%d\n", 460 mode, p->encoding)); 461 return EINVAL; 462 } 463 464 DPRINTF(1, ("vs_set_params: rate=%d -> ", rate)); 465 rate = vs_round_sr(rate); 466 DPRINTF(1, ("%d\n", rate)); 467 if (rate < 0) 468 return EINVAL; 469 if (mode == AUMODE_PLAY) { 470 sc->sc_current.prate = rate; 471 } else { 472 sc->sc_current.rrate = rate; 473 } 474 } 475 476 return 0; 477 } 478 479 static void 480 vs_set_sr(struct vs_softc *sc, int rate) 481 { 482 483 DPRINTF(1, ("setting sample rate to %d, %d\n", 484 rate, (int)vs_l2r[rate].rate)); 485 bus_space_write_1(sc->sc_iot, sc->sc_ppi, PPI_PORTC, 486 (bus_space_read_1 (sc->sc_iot, sc->sc_ppi, 487 PPI_PORTC) & 0xf0) 488 | vs_l2r[rate].den); 489 adpcm_chgclk(vs_l2r[rate].clk); 490 } 491 492 static inline void 493 vs_set_po(struct vs_softc *sc, u_long po) 494 { 495 bus_space_write_1(sc->sc_iot, sc->sc_ppi, PPI_PORTC, 496 (bus_space_read_1(sc->sc_iot, sc->sc_ppi, PPI_PORTC) 497 & 0xfc) | po); 498 } 499 500 static int 501 vs_trigger_output(void *hdl, void *start, void *end, int bsize, 502 void (*intr)(void *), void *arg, 503 const audio_params_t *p) 504 { 505 struct vs_softc *sc; 506 struct vs_dma *vd; 507 struct dmac_dma_xfer *xf; 508 struct dmac_channel_stat *chan; 509 510 DPRINTF(2, ("vs_trigger_output: start=%p, bsize=%d, intr=%p, arg=%p\n", 511 start, bsize, intr, arg)); 512 sc = hdl; 513 chan = sc->sc_dma_ch; 514 sc->sc_pintr = intr; 515 sc->sc_parg = arg; 516 sc->sc_current.blksize = bsize; 517 sc->sc_current.bufsize = (char *)end - (char *)start; 518 sc->sc_current.dmap = 0; 519 520 /* Find DMA buffer. */ 521 for (vd = sc->sc_dmas; vd != NULL && KVADDR(vd) != start; 522 vd = vd->vd_next) 523 continue; 524 if (vd == NULL) { 525 printf("%s: trigger_output: bad addr %p\n", 526 device_xname(sc->sc_dev), start); 527 return EINVAL; 528 } 529 530 vs_set_sr(sc, sc->sc_current.prate); 531 vs_set_po(sc, VS_PANOUT_LR); 532 533 xf = dmac_alloc_xfer(chan, sc->sc_dmat, vd->vd_map); 534 sc->sc_current.xfer = xf; 535 chan->ch_dcr = (DMAC_DCR_XRM_CSWOH | DMAC_DCR_OTYP_EASYNC | 536 DMAC_DCR_OPS_8BIT); 537 chan->ch_ocr = DMAC_OCR_REQG_EXTERNAL; 538 xf->dx_ocr = DMAC_OCR_DIR_MTD; 539 xf->dx_scr = DMAC_SCR_MAC_COUNT_UP | DMAC_SCR_DAC_NO_COUNT; 540 xf->dx_device = sc->sc_addr + MSM6258_DATA*2 + 1; 541 542 dmac_load_xfer(chan->ch_softc, xf); 543 dmac_start_xfer_offset(chan->ch_softc, xf, 0, sc->sc_current.blksize); 544 bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSM6258_STAT, 2); 545 546 return 0; 547 } 548 549 static int 550 vs_trigger_input(void *hdl, void *start, void *end, int bsize, 551 void (*intr)(void *), void *arg, 552 const audio_params_t *p) 553 { 554 struct vs_softc *sc; 555 struct vs_dma *vd; 556 struct dmac_dma_xfer *xf; 557 struct dmac_channel_stat *chan; 558 559 DPRINTF(2, ("vs_trigger_input: start=%p, bsize=%d, intr=%p, arg=%p\n", 560 start, bsize, intr, arg)); 561 sc = hdl; 562 chan = sc->sc_dma_ch; 563 sc->sc_rintr = intr; 564 sc->sc_rarg = arg; 565 sc->sc_current.blksize = bsize; 566 sc->sc_current.bufsize = (char *)end - (char *)start; 567 sc->sc_current.dmap = 0; 568 569 /* Find DMA buffer. */ 570 for (vd = sc->sc_dmas; vd != NULL && KVADDR(vd) != start; 571 vd = vd->vd_next) 572 continue; 573 if (vd == NULL) { 574 printf("%s: trigger_output: bad addr %p\n", 575 device_xname(sc->sc_dev), start); 576 return EINVAL; 577 } 578 579 vs_set_sr(sc, sc->sc_current.rrate); 580 xf = dmac_alloc_xfer(chan, sc->sc_dmat, vd->vd_map); 581 sc->sc_current.xfer = xf; 582 chan->ch_dcr = (DMAC_DCR_XRM_CSWOH | DMAC_DCR_OTYP_EASYNC | 583 DMAC_DCR_OPS_8BIT); 584 chan->ch_ocr = DMAC_OCR_REQG_EXTERNAL; 585 xf->dx_ocr = DMAC_OCR_DIR_DTM; 586 xf->dx_scr = DMAC_SCR_MAC_COUNT_UP | DMAC_SCR_DAC_NO_COUNT; 587 xf->dx_device = sc->sc_addr + MSM6258_DATA*2 + 1; 588 589 dmac_load_xfer(chan->ch_softc, xf); 590 dmac_start_xfer_offset(chan->ch_softc, xf, 0, sc->sc_current.blksize); 591 bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSM6258_STAT, 4); 592 593 return 0; 594 } 595 596 static int 597 vs_halt_output(void *hdl) 598 { 599 struct vs_softc *sc; 600 601 DPRINTF(1, ("vs_halt_output\n")); 602 sc = hdl; 603 /* stop ADPCM play */ 604 dmac_abort_xfer(sc->sc_dma_ch->ch_softc, sc->sc_current.xfer); 605 bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSM6258_STAT, 1); 606 607 return 0; 608 } 609 610 static int 611 vs_halt_input(void *hdl) 612 { 613 struct vs_softc *sc; 614 615 DPRINTF(1, ("vs_halt_input\n")); 616 sc = hdl; 617 /* stop ADPCM recoding */ 618 dmac_abort_xfer(sc->sc_dma_ch->ch_softc, sc->sc_current.xfer); 619 bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSM6258_STAT, 1); 620 621 return 0; 622 } 623 624 static int 625 vs_allocmem(struct vs_softc *sc, size_t size, size_t align, size_t boundary, 626 struct vs_dma *vd) 627 { 628 int error; 629 630 #ifdef DIAGNOSTIC 631 if (size > DMAC_MAXSEGSZ) 632 panic ("vs_allocmem: maximum size exceeded, %d", (int) size); 633 #endif 634 635 vd->vd_size = size; 636 637 error = bus_dmamem_alloc(vd->vd_dmat, vd->vd_size, align, boundary, 638 vd->vd_segs, 639 sizeof (vd->vd_segs) / sizeof (vd->vd_segs[0]), 640 &vd->vd_nsegs, BUS_DMA_WAITOK); 641 if (error) 642 goto out; 643 644 error = bus_dmamem_map(vd->vd_dmat, vd->vd_segs, vd->vd_nsegs, 645 vd->vd_size, &vd->vd_addr, 646 BUS_DMA_WAITOK | BUS_DMA_COHERENT); 647 if (error) 648 goto free; 649 650 error = bus_dmamap_create(vd->vd_dmat, vd->vd_size, 1, DMAC_MAXSEGSZ, 651 0, BUS_DMA_WAITOK, &vd->vd_map); 652 if (error) 653 goto unmap; 654 655 error = bus_dmamap_load(vd->vd_dmat, vd->vd_map, vd->vd_addr, 656 vd->vd_size, NULL, BUS_DMA_WAITOK); 657 if (error) 658 goto destroy; 659 660 return 0; 661 662 destroy: 663 bus_dmamap_destroy(vd->vd_dmat, vd->vd_map); 664 unmap: 665 bus_dmamem_unmap(vd->vd_dmat, vd->vd_addr, vd->vd_size); 666 free: 667 bus_dmamem_free(vd->vd_dmat, vd->vd_segs, vd->vd_nsegs); 668 out: 669 return error; 670 } 671 672 static void 673 vs_freemem(struct vs_dma *vd) 674 { 675 676 bus_dmamap_unload(vd->vd_dmat, vd->vd_map); 677 bus_dmamap_destroy(vd->vd_dmat, vd->vd_map); 678 bus_dmamem_unmap(vd->vd_dmat, vd->vd_addr, vd->vd_size); 679 bus_dmamem_free(vd->vd_dmat, vd->vd_segs, vd->vd_nsegs); 680 } 681 682 static int 683 vs_getdev(void *hdl, struct audio_device *retp) 684 { 685 686 DPRINTF(1, ("vs_getdev\n")); 687 *retp = vs_device; 688 return 0; 689 } 690 691 static int 692 vs_set_port(void *hdl, mixer_ctrl_t *cp) 693 { 694 695 DPRINTF(1, ("vs_set_port\n")); 696 return 0; 697 } 698 699 static int 700 vs_get_port(void *hdl, mixer_ctrl_t *cp) 701 { 702 703 DPRINTF(1, ("vs_get_port\n")); 704 return 0; 705 } 706 707 static int 708 vs_query_devinfo(void *hdl, mixer_devinfo_t *mi) 709 { 710 711 DPRINTF(1, ("vs_query_devinfo\n")); 712 switch (mi->index) { 713 default: 714 return EINVAL; 715 } 716 return 0; 717 } 718 719 static void * 720 vs_allocm(void *hdl, int direction, size_t size) 721 { 722 struct vs_softc *sc; 723 struct vs_dma *vd; 724 int error; 725 726 if ((vd = kmem_alloc(sizeof(*vd), KM_SLEEP)) == NULL) 727 return NULL; 728 sc = hdl; 729 vd->vd_dmat = sc->sc_dmat; 730 731 error = vs_allocmem(sc, size, 32, 0, vd); 732 if (error) { 733 kmem_free(vd, sizeof(*vd)); 734 return NULL; 735 } 736 vd->vd_next = sc->sc_dmas; 737 sc->sc_dmas = vd; 738 739 return KVADDR(vd); 740 } 741 742 static void 743 vs_freem(void *hdl, void *addr, size_t size) 744 { 745 struct vs_softc *sc; 746 struct vs_dma *p, **pp; 747 748 sc = hdl; 749 for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->vd_next) { 750 if (KVADDR(p) == addr) { 751 vs_freemem(p); 752 *pp = p->vd_next; 753 kmem_free(p, sizeof(*p)); 754 return; 755 } 756 } 757 } 758 759 static size_t 760 vs_round_buffersize(void *hdl, int direction, size_t bufsize) 761 { 762 763 if (bufsize > DMAC_MAXSEGSZ) 764 bufsize = DMAC_MAXSEGSZ; 765 return bufsize; 766 } 767 768 #if 0 769 paddr_t 770 vs_mappage(void *addr, void *mem, off_t off, int prot) 771 { 772 struct vs_softc *sc; 773 struct vs_dma *p; 774 775 if (off < 0) 776 return -1; 777 sc = addr; 778 for (p = sc->sc_dmas; p != NULL && KVADDR(p) != mem; 779 p = p->vd_next) 780 continue; 781 if (p == NULL) { 782 printf("%s: mappage: bad addr %p\n", 783 device_xname(sc->sc_dev), start); 784 return -1; 785 } 786 787 return bus_dmamem_mmap(sc->sc_dmat, p->vd_segs, p->vd_nsegs, 788 off, prot, BUS_DMA_WAITOK); 789 } 790 #endif 791 792 static int 793 vs_get_props(void *hdl) 794 { 795 796 DPRINTF(1, ("vs_get_props\n")); 797 return 0 /* | dependent | half duplex | no mmap */; 798 } 799 800 static void 801 vs_get_locks(void *hdl, kmutex_t **intr, kmutex_t **thread) 802 { 803 struct vs_softc *sc; 804 805 DPRINTF(1, ("vs_get_locks\n")); 806 sc = hdl; 807 *intr = &sc->sc_intr_lock; 808 *thread = &sc->sc_lock; 809 } 810 811 #endif /* NAUDIO > 0 && NVS > 0*/ 812