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