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