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