1 /* $NetBSD: vs.c,v 1.49 2017/09/30 04:07:04 isaki 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.49 2017/09/30 04:07:04 isaki 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_init_output(void *, void *, int); 82 static int vs_init_input(void *, void *, int); 83 static int vs_start_input(void *, void *, int, void (*)(void *), void *); 84 static int vs_start_output(void *, void *, int, void (*)(void *), void *); 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 vs_init_output, 121 vs_init_input, 122 vs_start_output, 123 vs_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 NULL, /* trigger_output */ 138 NULL, /* 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 static int 164 vs_match(device_t parent, cfdata_t cf, void *aux) 165 { 166 struct intio_attach_args *ia; 167 168 ia = aux; 169 if (strcmp(ia->ia_name, "vs") || vs_attached) 170 return 0; 171 172 if (ia->ia_addr == INTIOCF_ADDR_DEFAULT) 173 ia->ia_addr = VS_ADDR; 174 if (ia->ia_dma == INTIOCF_DMA_DEFAULT) 175 ia->ia_dma = VS_DMA; 176 if (ia->ia_dmaintr == INTIOCF_DMAINTR_DEFAULT) 177 ia->ia_dmaintr = VS_DMAINTR; 178 179 /* fixed parameters */ 180 if (ia->ia_addr != VS_ADDR) 181 return 0; 182 if (ia->ia_dma != VS_DMA) 183 return 0; 184 if (ia->ia_dmaintr != VS_DMAINTR) 185 return 0; 186 187 #ifdef VS_DEBUG 188 vs_debug = 1; 189 #ifdef AUDIO_DEBUG 190 audiodebug = 2; 191 #endif 192 #endif 193 194 return 1; 195 } 196 197 static void 198 vs_attach(device_t parent, device_t self, void *aux) 199 { 200 struct vs_softc *sc; 201 bus_space_tag_t iot; 202 bus_space_handle_t ioh; 203 struct intio_attach_args *ia; 204 205 sc = device_private(self); 206 sc->sc_dev = self; 207 ia = aux; 208 vs_attached = 1; 209 210 printf("\n"); 211 212 /* Re-map the I/O space */ 213 iot = ia->ia_bst; 214 bus_space_map(iot, ia->ia_addr, 0x2000, BUS_SPACE_MAP_SHIFTED, &ioh); 215 216 /* Initialize sc */ 217 sc->sc_iot = iot; 218 sc->sc_ioh = ioh; 219 sc->sc_hw_if = &vs_hw_if; 220 sc->sc_addr = (void *) ia->ia_addr; 221 sc->sc_dmas = NULL; 222 sc->sc_prev_vd = NULL; 223 sc->sc_active = 0; 224 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 225 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED); 226 227 /* XXX */ 228 bus_space_map(iot, PPI_ADDR, PPI_MAPSIZE, BUS_SPACE_MAP_SHIFTED, 229 &sc->sc_ppi); 230 231 /* Initialize DMAC */ 232 sc->sc_dmat = ia->ia_dmat; 233 sc->sc_dma_ch = dmac_alloc_channel(parent, ia->ia_dma, "vs", 234 ia->ia_dmaintr, vs_dmaintr, sc, 235 ia->ia_dmaintr+1, vs_dmaerrintr, sc, 236 (DMAC_DCR_XRM_CSWOH | DMAC_DCR_OTYP_EASYNC | DMAC_DCR_OPS_8BIT), 237 (DMAC_OCR_SIZE_BYTE | DMAC_OCR_REQG_EXTERNAL)); 238 239 aprint_normal_dev(self, "MSM6258V ADPCM voice synthesizer\n"); 240 241 audio_attach_mi(&vs_hw_if, sc, sc->sc_dev); 242 } 243 244 /* 245 * vs interrupt handler 246 */ 247 static int 248 vs_dmaintr(void *hdl) 249 { 250 struct vs_softc *sc; 251 252 DPRINTF(2, ("vs_dmaintr\n")); 253 sc = hdl; 254 255 mutex_spin_enter(&sc->sc_intr_lock); 256 257 if (sc->sc_pintr) { 258 sc->sc_pintr(sc->sc_parg); 259 } else if (sc->sc_rintr) { 260 sc->sc_rintr(sc->sc_rarg); 261 } else { 262 printf("vs_dmaintr: spurious interrupt\n"); 263 } 264 265 mutex_spin_exit(&sc->sc_intr_lock); 266 267 return 1; 268 } 269 270 static int 271 vs_dmaerrintr(void *hdl) 272 { 273 struct vs_softc *sc; 274 275 sc = hdl; 276 DPRINTF(1, ("%s: DMA transfer error.\n", device_xname(sc->sc_dev))); 277 /* XXX */ 278 vs_dmaintr(sc); 279 280 return 1; 281 } 282 283 284 /* 285 * audio MD layer interfaces 286 */ 287 288 static int 289 vs_open(void *hdl, int flags) 290 { 291 struct vs_softc *sc; 292 293 DPRINTF(1, ("vs_open: flags=%d\n", flags)); 294 sc = hdl; 295 sc->sc_pintr = NULL; 296 sc->sc_rintr = NULL; 297 sc->sc_active = 0; 298 299 return 0; 300 } 301 302 static void 303 vs_close(void *hdl) 304 { 305 306 DPRINTF(1, ("vs_close\n")); 307 } 308 309 static int 310 vs_query_encoding(void *hdl, struct audio_encoding *fp) 311 { 312 313 DPRINTF(1, ("vs_query_encoding\n")); 314 315 if (fp->index == 0) { 316 strcpy(fp->name, AudioEslinear); 317 fp->encoding = AUDIO_ENCODING_SLINEAR; 318 fp->precision = 8; 319 fp->flags = 0; 320 return 0; 321 } 322 if (fp->index == 1) { 323 strcpy(fp->name, AudioEslinear_be); 324 fp->encoding = AUDIO_ENCODING_SLINEAR_BE; 325 fp->precision = 16; 326 fp->flags = 0; 327 return 0; 328 } 329 return EINVAL; 330 } 331 332 static int 333 vs_round_sr(u_long rate) 334 { 335 int i; 336 int diff; 337 int nearest; 338 339 diff = rate; 340 nearest = 0; 341 for (i = 0; i < NUM_RATE; i++) { 342 if (rate >= vs_l2r[i].rate) { 343 if (rate - vs_l2r[i].rate < diff) { 344 diff = rate - vs_l2r[i].rate; 345 nearest = i; 346 } 347 } else { 348 if (vs_l2r[i].rate - rate < diff) { 349 diff = vs_l2r[i].rate - rate; 350 nearest = i; 351 } 352 } 353 } 354 if (diff * 100 / rate > 15) 355 return -1; 356 else 357 return nearest; 358 } 359 360 static int 361 vs_set_params(void *hdl, int setmode, int usemode, 362 audio_params_t *play, audio_params_t *rec, 363 stream_filter_list_t *pfil, stream_filter_list_t *rfil) 364 { 365 struct vs_softc *sc; 366 audio_params_t hw; 367 stream_filter_factory_t *pconv; 368 stream_filter_factory_t *rconv; 369 int rate; 370 371 sc = hdl; 372 373 DPRINTF(1, ("vs_set_params: mode=%d enc=%d rate=%d prec=%d ch=%d: ", 374 setmode, play->encoding, play->sample_rate, 375 play->precision, play->channels)); 376 377 /* *play and *rec are identical because !AUDIO_PROP_INDEPENDENT */ 378 379 if (play->channels != 1) { 380 DPRINTF(1, ("channels not matched\n")); 381 return EINVAL; 382 } 383 384 rate = vs_round_sr(play->sample_rate); 385 if (rate < 0) { 386 DPRINTF(1, ("rate not matched\n")); 387 return EINVAL; 388 } 389 390 if (play->precision == 8 && play->encoding == AUDIO_ENCODING_SLINEAR) { 391 pconv = msm6258_linear8_to_adpcm; 392 rconv = msm6258_adpcm_to_linear8; 393 } else if (play->precision == 16 && 394 play->encoding == AUDIO_ENCODING_SLINEAR_BE) { 395 pconv = msm6258_slinear16_to_adpcm; 396 rconv = msm6258_adpcm_to_slinear16; 397 } else { 398 DPRINTF(1, ("prec/enc not matched\n")); 399 return EINVAL; 400 } 401 402 sc->sc_current.rate = rate; 403 404 /* pfil and rfil are independent even if !AUDIO_PROP_INDEPENDENT */ 405 406 if ((setmode & AUMODE_PLAY) != 0) { 407 hw = *play; 408 hw.encoding = AUDIO_ENCODING_ADPCM; 409 hw.precision = 4; 410 hw.validbits = 4; 411 pfil->prepend(pfil, pconv, &hw); 412 } 413 if ((setmode & AUMODE_RECORD) != 0) { 414 hw = *rec; 415 hw.encoding = AUDIO_ENCODING_ADPCM; 416 hw.precision = 4; 417 hw.validbits = 4; 418 rfil->prepend(rfil, rconv, &hw); 419 } 420 421 DPRINTF(1, ("accepted\n")); 422 return 0; 423 } 424 425 static void 426 vs_set_sr(struct vs_softc *sc, int rate) 427 { 428 429 DPRINTF(1, ("setting sample rate to %d, %d\n", 430 rate, (int)vs_l2r[rate].rate)); 431 bus_space_write_1(sc->sc_iot, sc->sc_ppi, PPI_PORTC, 432 (bus_space_read_1 (sc->sc_iot, sc->sc_ppi, 433 PPI_PORTC) & 0xf0) 434 | vs_l2r[rate].den); 435 adpcm_chgclk(vs_l2r[rate].clk); 436 } 437 438 static inline void 439 vs_set_po(struct vs_softc *sc, u_long po) 440 { 441 bus_space_write_1(sc->sc_iot, sc->sc_ppi, PPI_PORTC, 442 (bus_space_read_1(sc->sc_iot, sc->sc_ppi, PPI_PORTC) 443 & 0xfc) | po); 444 } 445 446 static int 447 vs_init_output(void *hdl, void *buffer, int size) 448 { 449 struct vs_softc *sc; 450 451 DPRINTF(1, ("%s\n", __func__)); 452 sc = hdl; 453 454 /* Set rate and pan */ 455 vs_set_sr(sc, sc->sc_current.rate); 456 vs_set_po(sc, VS_PANOUT_LR); 457 458 return 0; 459 } 460 461 static int 462 vs_init_input(void *hdl, void *buffer, int size) 463 { 464 struct vs_softc *sc; 465 466 DPRINTF(1, ("%s\n", __func__)); 467 sc = hdl; 468 469 /* Set rate */ 470 vs_set_sr(sc, sc->sc_current.rate); 471 472 return 0; 473 } 474 475 static int 476 vs_start_output(void *hdl, void *block, int blksize, void (*intr)(void *), 477 void *arg) 478 { 479 struct vs_softc *sc; 480 struct vs_dma *vd; 481 struct dmac_channel_stat *chan; 482 483 DPRINTF(2, ("%s: block=%p blksize=%d\n", __func__, block, blksize)); 484 sc = hdl; 485 486 sc->sc_pintr = intr; 487 sc->sc_parg = arg; 488 489 /* Find DMA buffer. */ 490 for (vd = sc->sc_dmas; vd != NULL; vd = vd->vd_next) { 491 if (KVADDR(vd) <= block && block < KVADDR_END(vd) 492 break; 493 } 494 if (vd == NULL) { 495 printf("%s: start_output: bad addr %p\n", 496 device_xname(sc->sc_dev), block); 497 return EINVAL; 498 } 499 500 chan = sc->sc_dma_ch; 501 502 if (vd != sc->sc_prev_vd) { 503 sc->sc_current.xfer = dmac_prepare_xfer(chan, sc->sc_dmat, 504 vd->vd_map, DMAC_OCR_DIR_MTD, 505 (DMAC_SCR_MAC_COUNT_UP | DMAC_SCR_DAC_NO_COUNT), 506 sc->sc_addr + MSM6258_DATA * 2 + 1); 507 sc->sc_prev_vd = vd; 508 } 509 dmac_start_xfer_offset(chan->ch_softc, sc->sc_current.xfer, 510 (int)block - (int)KVADDR(vd), blksize); 511 512 if (sc->sc_active == 0) { 513 bus_space_write_1(sc->sc_iot, sc->sc_ioh, 514 MSM6258_CMD, MSM6258_CMD_PLAY_START); 515 sc->sc_active = 1; 516 } 517 518 return 0; 519 } 520 521 static int 522 vs_start_input(void *hdl, void *block, int blksize, void (*intr)(void *), 523 void *arg) 524 { 525 struct vs_softc *sc; 526 struct vs_dma *vd; 527 struct dmac_channel_stat *chan; 528 529 DPRINTF(2, ("%s: block=%p blksize=%d\n", __func__, block, blksize)); 530 sc = hdl; 531 532 sc->sc_rintr = intr; 533 sc->sc_rarg = arg; 534 535 /* Find DMA buffer. */ 536 for (vd = sc->sc_dmas; vd != NULL; vd = vd->vd_next) { 537 if (KVADDR(vd) <= block && block < KVADDR_END(vd) 538 break; 539 } 540 if (vd == NULL) { 541 printf("%s: start_output: bad addr %p\n", 542 device_xname(sc->sc_dev), block); 543 return EINVAL; 544 } 545 546 chan = sc->sc_dma_ch; 547 548 if (vd != sc->sc_prev_vd) { 549 sc->sc_current.xfer = dmac_prepare_xfer(chan, sc->sc_dmat, 550 vd->vd_map, DMAC_OCR_DIR_DTM, 551 (DMAC_SCR_MAC_COUNT_UP | DMAC_SCR_DAC_NO_COUNT), 552 sc->sc_addr + MSM6258_DATA * 2 + 1); 553 sc->sc_prev_vd = vd; 554 } 555 dmac_start_xfer_offset(chan->ch_softc, sc->sc_current.xfer, 556 (int)block - (int)KVADDR(vd), blksize); 557 558 if (sc->sc_active == 0) { 559 bus_space_write_1(sc->sc_iot, sc->sc_ioh, 560 MSM6258_CMD, MSM6258_CMD_REC_START); 561 sc->sc_active = 1; 562 } 563 564 return 0; 565 } 566 567 static int 568 vs_halt_output(void *hdl) 569 { 570 struct vs_softc *sc; 571 572 DPRINTF(1, ("vs_halt_output\n")); 573 sc = hdl; 574 if (sc->sc_active) { 575 /* stop ADPCM play */ 576 dmac_abort_xfer(sc->sc_dma_ch->ch_softc, sc->sc_current.xfer); 577 bus_space_write_1(sc->sc_iot, sc->sc_ioh, 578 MSM6258_CMD, MSM6258_CMD_STOP); 579 sc->sc_active = 0; 580 } 581 582 return 0; 583 } 584 585 static int 586 vs_halt_input(void *hdl) 587 { 588 struct vs_softc *sc; 589 590 DPRINTF(1, ("vs_halt_input\n")); 591 sc = hdl; 592 if (sc->sc_active) { 593 /* stop ADPCM recoding */ 594 dmac_abort_xfer(sc->sc_dma_ch->ch_softc, sc->sc_current.xfer); 595 bus_space_write_1(sc->sc_iot, sc->sc_ioh, 596 MSM6258_CMD, MSM6258_CMD_STOP); 597 sc->sc_active = 0; 598 } 599 600 return 0; 601 } 602 603 static int 604 vs_allocmem(struct vs_softc *sc, size_t size, size_t align, size_t boundary, 605 struct vs_dma *vd) 606 { 607 int error; 608 609 #ifdef DIAGNOSTIC 610 if (size > DMAC_MAXSEGSZ) 611 panic ("vs_allocmem: maximum size exceeded, %d", (int) size); 612 #endif 613 614 vd->vd_size = size; 615 616 error = bus_dmamem_alloc(vd->vd_dmat, vd->vd_size, align, boundary, 617 vd->vd_segs, 618 sizeof (vd->vd_segs) / sizeof (vd->vd_segs[0]), 619 &vd->vd_nsegs, BUS_DMA_WAITOK); 620 if (error) 621 goto out; 622 623 error = bus_dmamem_map(vd->vd_dmat, vd->vd_segs, vd->vd_nsegs, 624 vd->vd_size, &vd->vd_addr, 625 BUS_DMA_WAITOK | BUS_DMA_COHERENT); 626 if (error) 627 goto free; 628 629 error = bus_dmamap_create(vd->vd_dmat, vd->vd_size, 1, DMAC_MAXSEGSZ, 630 0, BUS_DMA_WAITOK, &vd->vd_map); 631 if (error) 632 goto unmap; 633 634 error = bus_dmamap_load(vd->vd_dmat, vd->vd_map, vd->vd_addr, 635 vd->vd_size, NULL, BUS_DMA_WAITOK); 636 if (error) 637 goto destroy; 638 639 return 0; 640 641 destroy: 642 bus_dmamap_destroy(vd->vd_dmat, vd->vd_map); 643 unmap: 644 bus_dmamem_unmap(vd->vd_dmat, vd->vd_addr, vd->vd_size); 645 free: 646 bus_dmamem_free(vd->vd_dmat, vd->vd_segs, vd->vd_nsegs); 647 out: 648 return error; 649 } 650 651 static void 652 vs_freemem(struct vs_dma *vd) 653 { 654 655 bus_dmamap_unload(vd->vd_dmat, vd->vd_map); 656 bus_dmamap_destroy(vd->vd_dmat, vd->vd_map); 657 bus_dmamem_unmap(vd->vd_dmat, vd->vd_addr, vd->vd_size); 658 bus_dmamem_free(vd->vd_dmat, vd->vd_segs, vd->vd_nsegs); 659 } 660 661 static int 662 vs_getdev(void *hdl, struct audio_device *retp) 663 { 664 665 DPRINTF(1, ("vs_getdev\n")); 666 *retp = vs_device; 667 return 0; 668 } 669 670 static int 671 vs_set_port(void *hdl, mixer_ctrl_t *cp) 672 { 673 674 DPRINTF(1, ("vs_set_port\n")); 675 return 0; 676 } 677 678 static int 679 vs_get_port(void *hdl, mixer_ctrl_t *cp) 680 { 681 682 DPRINTF(1, ("vs_get_port\n")); 683 return 0; 684 } 685 686 static int 687 vs_query_devinfo(void *hdl, mixer_devinfo_t *mi) 688 { 689 690 DPRINTF(1, ("vs_query_devinfo\n")); 691 switch (mi->index) { 692 default: 693 return EINVAL; 694 } 695 return 0; 696 } 697 698 static void * 699 vs_allocm(void *hdl, int direction, size_t size) 700 { 701 struct vs_softc *sc; 702 struct vs_dma *vd; 703 int error; 704 705 vd = kmem_alloc(sizeof(*vd), KM_SLEEP); 706 sc = hdl; 707 vd->vd_dmat = sc->sc_dmat; 708 709 error = vs_allocmem(sc, size, 32, 0, vd); 710 if (error) { 711 kmem_free(vd, sizeof(*vd)); 712 return NULL; 713 } 714 vd->vd_next = sc->sc_dmas; 715 sc->sc_dmas = vd; 716 717 return KVADDR(vd); 718 } 719 720 static void 721 vs_freem(void *hdl, void *addr, size_t size) 722 { 723 struct vs_softc *sc; 724 struct vs_dma *p, **pp; 725 726 sc = hdl; 727 for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->vd_next) { 728 if (KVADDR(p) == addr) { 729 vs_freemem(p); 730 *pp = p->vd_next; 731 kmem_free(p, sizeof(*p)); 732 return; 733 } 734 } 735 } 736 737 static size_t 738 vs_round_buffersize(void *hdl, int direction, size_t bufsize) 739 { 740 741 if (bufsize > DMAC_MAXSEGSZ) 742 bufsize = DMAC_MAXSEGSZ; 743 return bufsize; 744 } 745 746 #if 0 747 paddr_t 748 vs_mappage(void *addr, void *mem, off_t off, int prot) 749 { 750 struct vs_softc *sc; 751 struct vs_dma *p; 752 753 if (off < 0) 754 return -1; 755 sc = addr; 756 for (p = sc->sc_dmas; p != NULL && KVADDR(p) != mem; 757 p = p->vd_next) 758 continue; 759 if (p == NULL) { 760 printf("%s: mappage: bad addr %p\n", 761 device_xname(sc->sc_dev), start); 762 return -1; 763 } 764 765 return bus_dmamem_mmap(sc->sc_dmat, p->vd_segs, p->vd_nsegs, 766 off, prot, BUS_DMA_WAITOK); 767 } 768 #endif 769 770 static int 771 vs_get_props(void *hdl) 772 { 773 774 DPRINTF(1, ("vs_get_props\n")); 775 return 0 /* | dependent | half duplex | no mmap */; 776 } 777 778 static void 779 vs_get_locks(void *hdl, kmutex_t **intr, kmutex_t **thread) 780 { 781 struct vs_softc *sc; 782 783 DPRINTF(1, ("vs_get_locks\n")); 784 sc = hdl; 785 *intr = &sc->sc_intr_lock; 786 *thread = &sc->sc_lock; 787 } 788 789 #endif /* NAUDIO > 0 && NVS > 0*/ 790