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