1 /* $NetBSD: vs.c,v 1.15 2002/04/07 14:52:27 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 * 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(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 __P((struct device *, struct cfdata *, void *)); 70 static void vs_attach __P((struct device *, struct device *, void *)); 71 72 static int vs_dmaintr __P((void *)); 73 static int vs_dmaerrintr __P((void *)); 74 75 /* MI audio layer interface */ 76 static int vs_open __P((void *, int)); 77 static void vs_close __P((void *)); 78 static int vs_query_encoding __P((void *, struct audio_encoding *)); 79 static int vs_set_params __P((void *, int, int, struct audio_params *, 80 struct audio_params *)); 81 static int vs_trigger_output __P((void *, void *, void *, int, 82 void (*)(void *), void *, 83 struct audio_params *)); 84 static int vs_trigger_input __P((void *, void *, void *, int, 85 void (*)(void *), void *, 86 struct audio_params *)); 87 static int vs_halt_output __P((void *)); 88 static int vs_halt_input __P((void *)); 89 static int vs_allocmem __P((struct vs_softc *, size_t, size_t, size_t, int, 90 struct vs_dma *)); 91 static void vs_freemem __P((struct vs_dma *)); 92 static int vs_getdev __P((void *, struct audio_device *)); 93 static int vs_set_port __P((void *, mixer_ctrl_t *)); 94 static int vs_get_port __P((void *, mixer_ctrl_t *)); 95 static int vs_query_devinfo __P((void *, mixer_devinfo_t *)); 96 static void *vs_allocm __P((void *, int, size_t, int, int)); 97 static void vs_freem __P((void *, void *, int)); 98 static size_t vs_round_buffersize __P((void *, int, size_t)); 99 static int vs_get_props __P((void *)); 100 101 /* lower functions */ 102 static int vs_round_sr(u_long); 103 static void vs_set_sr(struct vs_softc *sc, int); 104 static inline void vs_set_po(struct vs_softc *sc, u_long); 105 106 extern struct cfdata vs_cd; 107 108 struct cfattach vs_ca = { 109 sizeof(struct vs_softc), vs_match, vs_attach 110 }; 111 112 static struct audio_hw_if vs_hw_if = { 113 vs_open, 114 vs_close, 115 NULL, /* drain */ 116 117 vs_query_encoding, 118 vs_set_params, 119 NULL, /* round_blocksize */ 120 NULL, /* commit_settings */ 121 122 NULL, /* init_output */ 123 NULL, /* init_input */ 124 NULL, /* start_output */ 125 NULL, /* start_input */ 126 127 vs_halt_output, 128 vs_halt_input, 129 NULL, /* speaker_ctl */ 130 131 vs_getdev, 132 NULL, /* setfd */ 133 134 vs_set_port, 135 vs_get_port, 136 vs_query_devinfo, 137 138 vs_allocm, 139 vs_freem, 140 vs_round_buffersize, 141 NULL, /* mappage */ 142 143 vs_get_props, 144 145 vs_trigger_output, 146 vs_trigger_input, 147 148 NULL, 149 }; 150 151 static struct audio_device vs_device = { 152 "OKI MSM6258", 153 "", 154 "vs" 155 }; 156 157 struct { 158 u_long rate; 159 u_char clk; 160 u_char den; 161 } vs_l2r[] = { 162 { VS_RATE_15K, VS_CLK_8MHZ, VS_SRATE_512 }, 163 { VS_RATE_10K, VS_CLK_8MHZ, VS_SRATE_768 }, 164 { VS_RATE_7K, VS_CLK_8MHZ, VS_SRATE_1024}, 165 { VS_RATE_5K, VS_CLK_4MHZ, VS_SRATE_768 }, 166 { VS_RATE_3K, VS_CLK_4MHZ, VS_SRATE_1024} 167 }; 168 169 #define NUM_RATE (sizeof(vs_l2r)/sizeof(vs_l2r[0])) 170 171 struct { 172 char *name; 173 int encoding; 174 int precision; 175 } vs_encodings[] = { 176 {AudioEadpcm, AUDIO_ENCODING_ADPCM, 4}, 177 {AudioEslinear, AUDIO_ENCODING_SLINEAR, 8}, 178 {AudioEulinear, AUDIO_ENCODING_ULINEAR, 8}, 179 {AudioEmulaw, AUDIO_ENCODING_ULAW, 8}, 180 {AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE, 16}, 181 {AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE, 16}, 182 }; 183 184 static int 185 vs_match(struct device *parent, struct cfdata *cf, void *aux) 186 { 187 struct intio_attach_args *ia = aux; 188 189 if (strcmp(ia->ia_name, "vs") || cf->cf_unit > 0) 190 return 0; 191 192 if (ia->ia_addr == INTIOCF_ADDR_DEFAULT) 193 ia->ia_addr = VS_ADDR; 194 if (ia->ia_dma == INTIOCF_DMA_DEFAULT) 195 ia->ia_dma = VS_DMA; 196 if (ia->ia_dmaintr == INTIOCF_DMAINTR_DEFAULT) 197 ia->ia_dmaintr = VS_DMAINTR; 198 199 /* fixed parameters */ 200 if (ia->ia_addr != VS_ADDR) 201 return 0; 202 if (ia->ia_dma != VS_DMA) 203 return 0; 204 if (ia->ia_dmaintr != VS_DMAINTR) 205 return 0; 206 207 #ifdef VS_DEBUG 208 vs_debug = 1; 209 #ifdef AUDIO_DEBUG 210 audiodebug = 2; 211 #endif 212 #endif 213 214 return 1; 215 } 216 217 static void 218 vs_attach(struct device *parent, struct device *self, void *aux) 219 { 220 struct vs_softc *sc = (struct vs_softc *)self; 221 bus_space_tag_t iot; 222 bus_space_handle_t ioh; 223 struct intio_attach_args *ia = aux; 224 225 printf("\n"); 226 227 /* Re-map the I/O space */ 228 iot = ia->ia_bst; 229 bus_space_map(iot, ia->ia_addr, 0x2000, BUS_SPACE_MAP_SHIFTED, &ioh); 230 231 /* Initialize sc */ 232 sc->sc_iot = iot; 233 sc->sc_ioh = ioh; 234 sc->sc_hw_if = &vs_hw_if; 235 sc->sc_addr = (caddr_t) ia->ia_addr; 236 sc->sc_dmas = NULL; 237 238 /* Initialize codec */ 239 sc->sc_codec = msm6258_codec_init(); 240 if (sc->sc_codec == NULL) { 241 printf ("Could not init codec\n"); 242 return; 243 } 244 245 /* XXX */ 246 bus_space_map(iot, PPI_ADDR, PPI_MAPSIZE, BUS_SPACE_MAP_SHIFTED, 247 &sc->sc_ppi); 248 249 /* Initialize DMAC */ 250 sc->sc_dmat = ia->ia_dmat; 251 sc->sc_dma_ch = dmac_alloc_channel(parent, ia->ia_dma, "vs", 252 ia->ia_dmaintr, vs_dmaintr, sc, 253 ia->ia_dmaintr+1, vs_dmaerrintr, sc); 254 255 printf("%s: MSM6258V ADPCM voice synthesizer\n", sc->sc_dev.dv_xname); 256 257 audio_attach_mi(&vs_hw_if, sc, &sc->sc_dev); 258 } 259 260 /* 261 * vs interrupt handler 262 */ 263 static int 264 vs_dmaintr(void *hdl) 265 { 266 struct vs_softc *sc = hdl; 267 268 DPRINTF(2, ("vs_dmaintr\n")); 269 270 if (sc->sc_pintr) { 271 /* start next transfer */ 272 sc->sc_current.dmap += sc->sc_current.blksize; 273 if (sc->sc_current.dmap + sc->sc_current.blksize 274 > sc->sc_current.bufsize) 275 sc->sc_current.dmap -= sc->sc_current.bufsize; 276 dmac_start_xfer_offset (sc->sc_dma_ch->ch_softc, 277 sc->sc_current.xfer, 278 sc->sc_current.dmap, 279 sc->sc_current.blksize); 280 sc->sc_pintr(sc->sc_parg); 281 } else if (sc->sc_rintr) { 282 /* start next transfer */ 283 sc->sc_current.dmap += sc->sc_current.blksize; 284 if (sc->sc_current.dmap + sc->sc_current.blksize 285 > sc->sc_current.bufsize) 286 sc->sc_current.dmap -= sc->sc_current.bufsize; 287 dmac_start_xfer_offset (sc->sc_dma_ch->ch_softc, 288 sc->sc_current.xfer, 289 sc->sc_current.dmap, 290 sc->sc_current.blksize); 291 sc->sc_rintr(sc->sc_rarg); 292 } else { 293 printf ("vs_dmaintr: spurious interrupt\n"); 294 } 295 296 return 1; 297 } 298 299 static int 300 vs_dmaerrintr(void *hdl) 301 { 302 struct vs_softc *sc = hdl; 303 304 DPRINTF(1, ("%s: DMA transfer error.\n", sc->sc_dev.dv_xname)); 305 /* XXX */ 306 vs_dmaintr(sc); 307 308 return 1; 309 } 310 311 312 /* 313 * audio MD layer interfaces 314 */ 315 316 static int 317 vs_open(void *hdl, int flags) 318 { 319 struct vs_softc *sc = hdl; 320 321 DPRINTF(1, ("vs_open: flags=%d\n", flags)); 322 323 sc->sc_pintr = NULL; 324 sc->sc_rintr = NULL; 325 326 msm6258_codec_open(sc); 327 328 return 0; 329 } 330 331 static void 332 vs_close(void *hdl) 333 { 334 DPRINTF(1, ("vs_close\n")); 335 } 336 337 static int 338 vs_query_encoding(void *hdl, struct audio_encoding *fp) 339 { 340 DPRINTF(1, ("vs_query_encoding\n")); 341 342 if (fp->index >= sizeof(vs_encodings) / sizeof(vs_encodings[0])) 343 return EINVAL; 344 345 strcpy(fp->name, vs_encodings[fp->index].name); 346 fp->encoding = vs_encodings[fp->index].encoding; 347 fp->precision = vs_encodings[fp->index].precision; 348 if (fp->encoding == AUDIO_ENCODING_ADPCM) 349 fp->flags = 0; 350 else 351 fp->flags = AUDIO_ENCODINGFLAG_EMULATED; 352 return 0; 353 } 354 355 static int 356 vs_round_sr(u_long rate) 357 { 358 int i; 359 int diff = rate; 360 int nearest = 0; 361 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 struct audio_params *play, struct audio_params *rec) 384 { 385 struct vs_softc *sc = hdl; 386 struct audio_params *p; 387 int mode; 388 int rate; 389 void (*pswcode)(void *, u_char *, int); 390 void (*rswcode)(void *, u_char *, int); 391 392 DPRINTF(1, ("vs_set_params: setmode=%d, usemode=%d\n", setmode, usemode)); 393 394 /* set first record info, then play info */ 395 for (mode = AUMODE_RECORD; mode != -1; 396 mode = (mode == AUMODE_RECORD) ? AUMODE_PLAY : -1) { 397 if ((setmode & mode) == 0) 398 continue; 399 400 p = (mode == AUMODE_PLAY) ? play : rec; 401 402 if (p->channels != 1) 403 return (EINVAL); 404 405 rate = p->sample_rate; 406 pswcode = NULL; 407 rswcode = NULL; 408 p->factor = 1; 409 p->factor_denom = 0; 410 p->hw_precision = 4; 411 p->hw_encoding = AUDIO_ENCODING_ADPCM; 412 DPRINTF(1, ("vs_set_params: encoding=%d, precision=%d\n", 413 p->encoding, p->precision)); 414 switch (p->precision) { 415 case 4: 416 if (p->encoding == AUDIO_ENCODING_ADPCM) 417 p->factor_denom = 1; 418 break; 419 case 8: 420 switch (p->encoding) { 421 case AUDIO_ENCODING_ULAW: 422 p->factor_denom = 2; 423 pswcode = msm6258_mulaw_to_adpcm; 424 rswcode = msm6258_adpcm_to_mulaw; 425 break; 426 case AUDIO_ENCODING_SLINEAR: 427 case AUDIO_ENCODING_SLINEAR_LE: 428 case AUDIO_ENCODING_SLINEAR_BE: 429 p->factor_denom = 2; 430 pswcode = msm6258_slinear8_to_adpcm; 431 rswcode = msm6258_adpcm_to_slinear8; 432 break; 433 case AUDIO_ENCODING_ULINEAR: 434 case AUDIO_ENCODING_ULINEAR_LE: 435 case AUDIO_ENCODING_ULINEAR_BE: 436 p->factor_denom = 2; 437 pswcode = msm6258_ulinear8_to_adpcm; 438 rswcode = msm6258_adpcm_to_ulinear8; 439 break; 440 } 441 break; 442 case 16: 443 switch (p->encoding) { 444 case AUDIO_ENCODING_SLINEAR_LE: 445 p->factor_denom = 4; 446 pswcode = msm6258_slinear16_le_to_adpcm; 447 rswcode = msm6258_adpcm_to_slinear16_le; 448 break; 449 case AUDIO_ENCODING_SLINEAR_BE: 450 p->factor_denom = 4; 451 pswcode = msm6258_slinear16_be_to_adpcm; 452 rswcode = msm6258_adpcm_to_slinear16_be; 453 break; 454 } 455 break; 456 } 457 if (p->factor_denom == 0) { 458 DPRINTF(1, ("vs_set_params: mode=%d, encoding=%d\n", 459 mode, p->encoding)); 460 return EINVAL; 461 } 462 463 DPRINTF(1, ("vs_set_params: rate=%d -> ", rate)); 464 rate = vs_round_sr(rate); 465 DPRINTF(1, ("%d\n", rate)); 466 if (rate < 0) 467 return (EINVAL); 468 if (mode == AUMODE_PLAY) { 469 p->sw_code = pswcode; 470 sc->sc_current.prate = rate; 471 } else { 472 p->sw_code = rswcode; 473 sc->sc_current.rrate = rate; 474 } 475 } 476 477 return 0; 478 } 479 480 static void 481 vs_set_sr(struct vs_softc *sc, int rate) 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 struct audio_params *p) 504 { 505 struct vs_softc *sc = hdl; 506 struct vs_dma *vd; 507 struct dmac_dma_xfer *xf; 508 struct dmac_channel_stat *chan = sc->sc_dma_ch; 509 510 DPRINTF(2, ("vs_trigger_output: start=%p, bsize=%d, intr=%p, arg=%p\n", 511 start, bsize, intr, arg)); 512 513 sc->sc_pintr = intr; 514 sc->sc_parg = arg; 515 sc->sc_current.blksize = bsize; 516 sc->sc_current.bufsize = (char*)end - (char*)start; 517 sc->sc_current.dmap = 0; 518 519 /* Find DMA buffer. */ 520 for (vd = sc->sc_dmas; vd != NULL && KVADDR(vd) != start; 521 vd = vd->vd_next) 522 ; 523 if (vd == NULL) { 524 printf("%s: trigger_output: bad addr %p\n", 525 sc->sc_dev.dv_xname, start); 526 return (EINVAL); 527 } 528 529 vs_set_sr(sc, sc->sc_current.prate); 530 vs_set_po(sc, VS_PANOUT_LR); 531 532 xf = dmac_alloc_xfer (chan, sc->sc_dmat, vd->vd_map); 533 sc->sc_current.xfer = xf; 534 chan->ch_dcr = (DMAC_DCR_XRM_CSWOH | DMAC_DCR_OTYP_EASYNC | 535 DMAC_DCR_OPS_8BIT); 536 chan->ch_ocr = DMAC_OCR_REQG_EXTERNAL; 537 xf->dx_ocr = DMAC_OCR_DIR_MTD; 538 xf->dx_scr = DMAC_SCR_MAC_COUNT_UP | DMAC_SCR_DAC_NO_COUNT; 539 xf->dx_device = sc->sc_addr + MSM6258_DATA*2 + 1; 540 541 dmac_load_xfer (chan->ch_softc, xf); 542 dmac_start_xfer_offset (chan->ch_softc, xf, 0, sc->sc_current.blksize); 543 bus_space_write_1 (sc->sc_iot, sc->sc_ioh, MSM6258_STAT, 2); 544 545 return 0; 546 } 547 548 static int 549 vs_trigger_input(void *hdl, void *start, void *end, int bsize, 550 void (*intr)(void *), void *arg, 551 struct audio_params *p) 552 { 553 struct vs_softc *sc = hdl; 554 struct vs_dma *vd; 555 struct dmac_dma_xfer *xf; 556 struct dmac_channel_stat *chan = sc->sc_dma_ch; 557 558 DPRINTF(2, ("vs_trigger_input: start=%p, bsize=%d, intr=%p, arg=%p\n", 559 start, bsize, intr, arg)); 560 561 sc->sc_rintr = intr; 562 sc->sc_rarg = arg; 563 sc->sc_current.blksize = bsize; 564 sc->sc_current.bufsize = (char*)end - (char*)start; 565 sc->sc_current.dmap = 0; 566 567 /* Find DMA buffer. */ 568 for (vd = sc->sc_dmas; vd != NULL && KVADDR(vd) != start; 569 vd = vd->vd_next) 570 ; 571 if (vd == NULL) { 572 printf("%s: trigger_output: bad addr %p\n", 573 sc->sc_dev.dv_xname, start); 574 return (EINVAL); 575 } 576 577 vs_set_sr(sc, sc->sc_current.rrate); 578 xf = dmac_alloc_xfer (chan, sc->sc_dmat, vd->vd_map); 579 sc->sc_current.xfer = xf; 580 chan->ch_dcr = (DMAC_DCR_XRM_CSWOH | DMAC_DCR_OTYP_EASYNC | 581 DMAC_DCR_OPS_8BIT); 582 chan->ch_ocr = DMAC_OCR_REQG_EXTERNAL; 583 xf->dx_ocr = DMAC_OCR_DIR_DTM; 584 xf->dx_scr = DMAC_SCR_MAC_COUNT_UP | DMAC_SCR_DAC_NO_COUNT; 585 xf->dx_device = sc->sc_addr + MSM6258_DATA*2 + 1; 586 587 dmac_load_xfer (chan->ch_softc, xf); 588 dmac_start_xfer_offset (chan->ch_softc, xf, 0, sc->sc_current.blksize); 589 bus_space_write_1 (sc->sc_iot, sc->sc_ioh, MSM6258_STAT, 4); 590 591 return 0; 592 } 593 594 static int 595 vs_halt_output(void *hdl) 596 { 597 struct vs_softc *sc = hdl; 598 599 DPRINTF(1, ("vs_halt_output\n")); 600 601 /* stop ADPCM play */ 602 dmac_abort_xfer(sc->sc_dma_ch->ch_softc, sc->sc_current.xfer); 603 bus_space_write_1 (sc->sc_iot, sc->sc_ioh, MSM6258_STAT, 1); 604 605 return 0; 606 } 607 608 static int 609 vs_halt_input(void *hdl) 610 { 611 struct vs_softc *sc = hdl; 612 613 DPRINTF(1, ("vs_halt_input\n")); 614 615 /* stop ADPCM recoding */ 616 dmac_abort_xfer(sc->sc_dma_ch->ch_softc, sc->sc_current.xfer); 617 bus_space_write_1 (sc->sc_iot, sc->sc_ioh, MSM6258_STAT, 1); 618 619 return 0; 620 } 621 622 static int 623 vs_allocmem(sc, size, align, boundary, flags, vd) 624 struct vs_softc *sc; 625 size_t size; 626 size_t align; 627 size_t boundary; 628 int flags; 629 struct vs_dma *vd; 630 { 631 int error, wait; 632 633 #ifdef DIAGNOSTIC 634 if (size > DMAC_MAXSEGSZ) 635 panic ("vs_allocmem: maximum size exceeded, %d", (int) size); 636 #endif 637 638 wait = (flags & M_NOWAIT) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK; 639 vd->vd_size = size; 640 641 error = bus_dmamem_alloc(vd->vd_dmat, vd->vd_size, align, boundary, 642 vd->vd_segs, 643 sizeof (vd->vd_segs) / sizeof (vd->vd_segs[0]), 644 &vd->vd_nsegs, wait); 645 if (error) 646 goto out; 647 648 error = bus_dmamem_map(vd->vd_dmat, vd->vd_segs, vd->vd_nsegs, 649 vd->vd_size, &vd->vd_addr, 650 wait | BUS_DMA_COHERENT); 651 if (error) 652 goto free; 653 654 error = bus_dmamap_create(vd->vd_dmat, vd->vd_size, 1, DMAC_MAXSEGSZ, 655 0, wait, &vd->vd_map); 656 if (error) 657 goto unmap; 658 659 error = bus_dmamap_load(vd->vd_dmat, vd->vd_map, vd->vd_addr, 660 vd->vd_size, NULL, wait); 661 if (error) 662 goto destroy; 663 664 return (0); 665 666 destroy: 667 bus_dmamap_destroy(vd->vd_dmat, vd->vd_map); 668 unmap: 669 bus_dmamem_unmap(vd->vd_dmat, vd->vd_addr, vd->vd_size); 670 free: 671 bus_dmamem_free(vd->vd_dmat, vd->vd_segs, vd->vd_nsegs); 672 out: 673 return (error); 674 } 675 676 static void 677 vs_freemem(vd) 678 struct vs_dma *vd; 679 { 680 681 bus_dmamap_unload(vd->vd_dmat, vd->vd_map); 682 bus_dmamap_destroy(vd->vd_dmat, vd->vd_map); 683 bus_dmamem_unmap(vd->vd_dmat, vd->vd_addr, vd->vd_size); 684 bus_dmamem_free(vd->vd_dmat, vd->vd_segs, vd->vd_nsegs); 685 } 686 687 static int 688 vs_getdev(void *hdl, struct audio_device *retp) 689 { 690 DPRINTF(1, ("vs_getdev\n")); 691 692 *retp = vs_device; 693 return 0; 694 } 695 696 static int 697 vs_set_port(void *hdl, mixer_ctrl_t *cp) 698 { 699 DPRINTF(1, ("vs_set_port\n")); 700 return 0; 701 } 702 703 static int 704 vs_get_port(void *hdl, mixer_ctrl_t *cp) 705 { 706 DPRINTF(1, ("vs_get_port\n")); 707 return 0; 708 } 709 710 static int 711 vs_query_devinfo(void *hdl, mixer_devinfo_t *mi) 712 { 713 DPRINTF(1, ("vs_query_devinfo\n")); 714 switch (mi->index) { 715 default: 716 return EINVAL; 717 } 718 return 0; 719 } 720 721 static void * 722 vs_allocm(hdl, direction, size, type, flags) 723 void *hdl; 724 int direction; 725 size_t size; 726 int type, flags; 727 { 728 struct vs_softc *sc = hdl; 729 struct vs_dma *vd; 730 int error; 731 732 if ((vd = malloc(size, type, flags)) == NULL) 733 return (NULL); 734 735 vd->vd_dmat = sc->sc_dmat; 736 737 error = vs_allocmem(sc, size, 32, 0, flags, vd); 738 if (error) { 739 free(vd, type); 740 return (NULL); 741 } 742 vd->vd_next = sc->sc_dmas; 743 sc->sc_dmas = vd; 744 745 return (KVADDR(vd)); 746 } 747 748 static void 749 vs_freem(hdl, addr, type) 750 void *hdl; 751 void *addr; 752 int type; 753 { 754 struct vs_softc *sc = hdl; 755 struct vs_dma *p, **pp; 756 757 for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->vd_next) { 758 if (KVADDR(p) == addr) { 759 vs_freemem(p); 760 *pp = p->vd_next; 761 free(p, type); 762 return; 763 } 764 } 765 } 766 767 static size_t 768 vs_round_buffersize(void *hdl, int direction, size_t bufsize) 769 { 770 if (bufsize > DMAC_MAXSEGSZ) 771 bufsize = DMAC_MAXSEGSZ; 772 773 return bufsize; 774 } 775 776 #if 0 777 paddr_t 778 vs_mappage(addr, mem, off, prot) 779 void *addr; 780 void *mem; 781 off_t off; 782 int prot; 783 { 784 struct vs_softc *sc = addr; 785 struct vs_dma *p; 786 787 if (off < 0) 788 return (-1); 789 for (p = sc->sc_dmas; p != NULL && KVADDR(p) != mem; 790 p = p->vd_next) 791 ; 792 if (p == NULL) { 793 printf("%s: mappage: bad addr %p\n", 794 sc->sc_dev.dv_xname, start); 795 return (-1); 796 } 797 798 return (bus_dmamem_mmap(sc->sc_dmat, p->vd_segs, p->vd_nsegs, 799 off, prot, BUS_DMA_WAITOK)); 800 } 801 #endif 802 803 static int 804 vs_get_props(void *hdl) 805 { 806 DPRINTF(1, ("vs_get_props\n")); 807 return 0 /* | dependent | half duplex | no mmap */; 808 } 809 #endif /* NAUDIO > 0 && NVS > 0*/ 810