Annotation of sys/dev/pci/yds.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: yds.c,v 1.28 2007/01/06 02:48:40 deraadt Exp $ */
! 2: /* $NetBSD: yds.c,v 1.5 2001/05/21 23:55:04 minoura Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 2000, 2001 Kazuki Sakamoto and Minoura Makoto.
! 6: * All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 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, BUT
! 22: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 23: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 24: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 25: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 26: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 27: */
! 28:
! 29: /*
! 30: * Yamaha YMF724[B-F]/740[B-C]/744/754
! 31: *
! 32: * Documentation links:
! 33: * - ftp://ftp.alsa-project.org/pub/manuals/yamaha/
! 34: * - ftp://ftp.alsa-project.org/pub/manuals/yamaha/pci/
! 35: *
! 36: * TODO:
! 37: * - FM synth volume (difficult: mixed before ac97)
! 38: * - Digital in/out (SPDIF) support
! 39: * - Effect??
! 40: */
! 41:
! 42: #include <sys/param.h>
! 43: #include <sys/systm.h>
! 44: #include <sys/kernel.h>
! 45: #include <sys/fcntl.h>
! 46: #include <sys/malloc.h>
! 47: #include <sys/device.h>
! 48: #include <sys/proc.h>
! 49: #include <sys/queue.h>
! 50: #include <sys/fcntl.h>
! 51:
! 52: #include <dev/pci/pcidevs.h>
! 53: #include <dev/pci/pcireg.h>
! 54: #include <dev/pci/pcivar.h>
! 55:
! 56: #include <sys/audioio.h>
! 57: #include <dev/audio_if.h>
! 58: #include <dev/midi_if.h>
! 59: #include <dev/mulaw.h>
! 60: #include <dev/auconv.h>
! 61: #include <dev/ic/ac97.h>
! 62: #include <dev/ic/mpuvar.h>
! 63:
! 64: #include <machine/bus.h>
! 65: #include <machine/intr.h>
! 66:
! 67: #include <dev/pci/ydsreg.h>
! 68: #include <dev/pci/ydsvar.h>
! 69:
! 70: /* Debug */
! 71: #undef YDS_USE_REC_SLOT
! 72: #define YDS_USE_P44
! 73:
! 74: #ifdef AUDIO_DEBUG
! 75: # define DPRINTF(x) if (ydsdebug) printf x
! 76: # define DPRINTFN(n,x) if (ydsdebug>(n)) printf x
! 77: int ydsdebug = 0;
! 78: #else
! 79: # define DPRINTF(x)
! 80: # define DPRINTFN(n,x)
! 81: #endif
! 82: #ifdef YDS_USE_REC_SLOT
! 83: # define YDS_INPUT_SLOT 0 /* REC slot = ADC + loopbacks */
! 84: #else
! 85: # define YDS_INPUT_SLOT 1 /* ADC slot */
! 86: #endif
! 87:
! 88: static int ac97_id2;
! 89:
! 90: int yds_match(struct device *, void *, void *);
! 91: void yds_attach(struct device *, struct device *, void *);
! 92: int yds_intr(void *);
! 93:
! 94: static void nswaph(u_int32_t *p, int wcount);
! 95:
! 96: #define DMAADDR(p) ((p)->map->dm_segs[0].ds_addr)
! 97: #define KERNADDR(p) ((void *)((p)->addr))
! 98:
! 99: int yds_allocmem(struct yds_softc *, size_t, size_t,
! 100: struct yds_dma *);
! 101: int yds_freemem(struct yds_softc *, struct yds_dma *);
! 102:
! 103: #ifndef AUDIO_DEBUG
! 104: #define YWRITE1(sc, r, x) bus_space_write_1((sc)->memt, (sc)->memh, (r), (x))
! 105: #define YWRITE2(sc, r, x) bus_space_write_2((sc)->memt, (sc)->memh, (r), (x))
! 106: #define YWRITE4(sc, r, x) bus_space_write_4((sc)->memt, (sc)->memh, (r), (x))
! 107: #define YREAD1(sc, r) bus_space_read_1((sc)->memt, (sc)->memh, (r))
! 108: #define YREAD2(sc, r) bus_space_read_2((sc)->memt, (sc)->memh, (r))
! 109: #define YREAD4(sc, r) bus_space_read_4((sc)->memt, (sc)->memh, (r))
! 110: #else
! 111:
! 112: u_int16_t YREAD2(struct yds_softc *sc,bus_size_t r);
! 113: u_int32_t YREAD4(struct yds_softc *sc,bus_size_t r);
! 114: void YWRITE1(struct yds_softc *sc,bus_size_t r,u_int8_t x);
! 115: void YWRITE2(struct yds_softc *sc,bus_size_t r,u_int16_t x);
! 116: void YWRITE4(struct yds_softc *sc,bus_size_t r,u_int32_t x);
! 117:
! 118: u_int16_t YREAD2(struct yds_softc *sc,bus_size_t r)
! 119: {
! 120: DPRINTFN(5, (" YREAD2(0x%lX)\n",(unsigned long)r));
! 121: return bus_space_read_2(sc->memt,sc->memh,r);
! 122: }
! 123: u_int32_t YREAD4(struct yds_softc *sc,bus_size_t r)
! 124: {
! 125: DPRINTFN(5, (" YREAD4(0x%lX)\n",(unsigned long)r));
! 126: return bus_space_read_4(sc->memt,sc->memh,r);
! 127: }
! 128: void YWRITE1(struct yds_softc *sc,bus_size_t r,u_int8_t x)
! 129: {
! 130: DPRINTFN(5, (" YWRITE1(0x%lX,0x%lX)\n",(unsigned long)r,(unsigned long)x));
! 131: bus_space_write_1(sc->memt,sc->memh,r,x);
! 132: }
! 133: void YWRITE2(struct yds_softc *sc,bus_size_t r,u_int16_t x)
! 134: {
! 135: DPRINTFN(5, (" YWRITE2(0x%lX,0x%lX)\n",(unsigned long)r,(unsigned long)x));
! 136: bus_space_write_2(sc->memt,sc->memh,r,x);
! 137: }
! 138: void YWRITE4(struct yds_softc *sc,bus_size_t r,u_int32_t x)
! 139: {
! 140: DPRINTFN(5, (" YWRITE4(0x%lX,0x%lX)\n",(unsigned long)r,(unsigned long)x));
! 141: bus_space_write_4(sc->memt,sc->memh,r,x);
! 142: }
! 143: #endif
! 144:
! 145: #define YWRITEREGION4(sc, r, x, c) \
! 146: bus_space_write_region_4((sc)->memt, (sc)->memh, (r), (x), (c) / 4)
! 147:
! 148: struct cfattach yds_ca = {
! 149: sizeof(struct yds_softc), yds_match, yds_attach
! 150: };
! 151:
! 152: struct cfdriver yds_cd = {
! 153: NULL, "yds", DV_DULL
! 154: };
! 155:
! 156: int yds_open(void *, int);
! 157: void yds_close(void *);
! 158: int yds_query_encoding(void *, struct audio_encoding *);
! 159: int yds_set_params(void *, int, int,
! 160: struct audio_params *, struct audio_params *);
! 161: int yds_round_blocksize(void *, int);
! 162: int yds_trigger_output(void *, void *, void *, int, void (*)(void *),
! 163: void *, struct audio_params *);
! 164: int yds_trigger_input(void *, void *, void *, int, void (*)(void *),
! 165: void *, struct audio_params *);
! 166: int yds_halt_output(void *);
! 167: int yds_halt_input(void *);
! 168: int yds_getdev(void *, struct audio_device *);
! 169: int yds_mixer_set_port(void *, mixer_ctrl_t *);
! 170: int yds_mixer_get_port(void *, mixer_ctrl_t *);
! 171: void *yds_malloc(void *, int, size_t, int, int);
! 172: void yds_free(void *, void *, int);
! 173: size_t yds_round_buffersize(void *, int, size_t);
! 174: paddr_t yds_mappage(void *, void *, off_t, int);
! 175: int yds_get_props(void *);
! 176: int yds_query_devinfo(void *addr, mixer_devinfo_t *dip);
! 177:
! 178: int yds_attach_codec(void *sc, struct ac97_codec_if *);
! 179: int yds_read_codec(void *sc, u_int8_t a, u_int16_t *d);
! 180: int yds_write_codec(void *sc, u_int8_t a, u_int16_t d);
! 181: void yds_reset_codec(void *sc);
! 182: int yds_get_portnum_by_name(struct yds_softc *, char *, char *,
! 183: char *);
! 184:
! 185: static u_int yds_get_dstype(int);
! 186: static int yds_download_mcode(struct yds_softc *);
! 187: static int yds_allocate_slots(struct yds_softc *);
! 188: static void yds_configure_legacy(struct yds_softc *arg);
! 189: static void yds_enable_dsp(struct yds_softc *);
! 190: static int yds_disable_dsp(struct yds_softc *);
! 191: static int yds_ready_codec(struct yds_codec_softc *);
! 192: static int yds_halt(struct yds_softc *);
! 193: static u_int32_t yds_get_lpfq(u_int);
! 194: static u_int32_t yds_get_lpfk(u_int);
! 195: static struct yds_dma *yds_find_dma(struct yds_softc *, void *);
! 196:
! 197: void yds_powerhook(int, void *);
! 198: int yds_init(void *sc);
! 199: void yds_attachhook(void *);
! 200:
! 201: #ifdef AUDIO_DEBUG
! 202: static void yds_dump_play_slot(struct yds_softc *, int);
! 203: #define YDS_DUMP_PLAY_SLOT(n,sc,bank) \
! 204: if (ydsdebug > (n)) yds_dump_play_slot(sc, bank)
! 205: #else
! 206: #define YDS_DUMP_PLAY_SLOT(n,sc,bank)
! 207: #endif /* AUDIO_DEBUG */
! 208:
! 209: static struct audio_hw_if yds_hw_if = {
! 210: yds_open,
! 211: yds_close,
! 212: NULL,
! 213: yds_query_encoding,
! 214: yds_set_params,
! 215: yds_round_blocksize,
! 216: NULL,
! 217: NULL,
! 218: NULL,
! 219: NULL,
! 220: NULL,
! 221: yds_halt_output,
! 222: yds_halt_input,
! 223: NULL,
! 224: yds_getdev,
! 225: NULL,
! 226: yds_mixer_set_port,
! 227: yds_mixer_get_port,
! 228: yds_query_devinfo,
! 229: yds_malloc,
! 230: yds_free,
! 231: yds_round_buffersize,
! 232: yds_mappage,
! 233: yds_get_props,
! 234: yds_trigger_output,
! 235: yds_trigger_input
! 236: };
! 237:
! 238: struct audio_device yds_device = {
! 239: "Yamaha DS-1",
! 240: "",
! 241: "yds"
! 242: };
! 243:
! 244: const static struct {
! 245: u_int id;
! 246: u_int flags;
! 247: #define YDS_CAP_MCODE_1 0x0001
! 248: #define YDS_CAP_MCODE_1E 0x0002
! 249: #define YDS_CAP_LEGACY_SELECTABLE 0x0004
! 250: #define YDS_CAP_LEGACY_FLEXIBLE 0x0008
! 251: #define YDS_CAP_HAS_P44 0x0010
! 252: #define YDS_CAP_LEGACY_SMOD_DISABLE 0x1000
! 253: } yds_chip_capability_list[] = {
! 254: { PCI_PRODUCT_YAMAHA_YMF724,
! 255: YDS_CAP_MCODE_1|YDS_CAP_LEGACY_SELECTABLE },
! 256: /* 740[C] has only 32 slots. But anyway we use only 2 */
! 257: { PCI_PRODUCT_YAMAHA_YMF740,
! 258: YDS_CAP_MCODE_1|YDS_CAP_LEGACY_SELECTABLE }, /* XXX NOT TESTED */
! 259: { PCI_PRODUCT_YAMAHA_YMF740C,
! 260: YDS_CAP_MCODE_1E|YDS_CAP_LEGACY_SELECTABLE },
! 261: { PCI_PRODUCT_YAMAHA_YMF724F,
! 262: YDS_CAP_MCODE_1E|YDS_CAP_LEGACY_SELECTABLE },
! 263: { PCI_PRODUCT_YAMAHA_YMF744,
! 264: YDS_CAP_MCODE_1E|YDS_CAP_LEGACY_FLEXIBLE },
! 265: { PCI_PRODUCT_YAMAHA_YMF754,
! 266: YDS_CAP_MCODE_1E|YDS_CAP_LEGACY_FLEXIBLE|YDS_CAP_HAS_P44 },
! 267: /* How about 734/737/738?? */
! 268: { 0, 0 }
! 269: };
! 270: #ifdef AUDIO_DEBUG
! 271: #define YDS_CAP_BITS "\020\005P44\004LEGFLEX\003LEGSEL\002MCODE1E\001MCODE1"
! 272: #endif
! 273:
! 274: #ifdef AUDIO_DEBUG
! 275: static void
! 276: yds_dump_play_slot(sc, bank)
! 277: struct yds_softc *sc;
! 278: int bank;
! 279: {
! 280: int i, j;
! 281: u_int32_t *p;
! 282: u_int32_t num;
! 283: struct yds_dma *dma;
! 284:
! 285: for (i = 0; i < N_PLAY_SLOTS; i++) {
! 286: printf("pbankp[%d] = %p,", i*2, sc->pbankp[i*2]);
! 287: printf("pbankp[%d] = %p\n", i*2+1, sc->pbankp[i*2+1]);
! 288: }
! 289:
! 290: p = (u_int32_t*)sc->ptbl;
! 291: for (i = 0; i < N_PLAY_SLOTS+1; i++) {
! 292: printf("ptbl + %d:0x%x\n", i, *p);
! 293: p++;
! 294: }
! 295:
! 296: num = *(u_int32_t*)sc->ptbl;
! 297: printf("num = %d\n", num);
! 298:
! 299: for (i = 0; i < num; i++) {
! 300:
! 301: p = (u_int32_t *)sc->pbankp[i];
! 302:
! 303: dma = yds_find_dma(sc,(void *)p);
! 304:
! 305: for (j = 0; j < sizeof(struct play_slot_ctrl_bank) /
! 306: sizeof(u_int32_t); j++) {
! 307: printf(" 0x%02x: 0x%08x\n",
! 308: (unsigned) (j * sizeof(u_int32_t)),
! 309: (unsigned) *p++);
! 310: }
! 311: /*
! 312: p = (u_int32_t *)sc->pbankp[i*2 + 1];
! 313: printf(" pbankp[%d] : %p\n", i*2 + 1, p);
! 314: for (j = 0; j < sizeof(struct play_slot_ctrl_bank) /
! 315: sizeof(u_int32_t); j++) {
! 316: printf(" 0x%02x: 0x%08x\n",
! 317: j * sizeof(u_int32_t), *p++);
! 318: delay(1);
! 319: }
! 320: */
! 321: }
! 322: }
! 323: #endif /* AUDIO_DEBUG */
! 324:
! 325: static u_int
! 326: yds_get_dstype(id)
! 327: int id;
! 328: {
! 329: int i;
! 330:
! 331: for (i = 0; yds_chip_capability_list[i].id; i++) {
! 332: if (PCI_PRODUCT(id) == yds_chip_capability_list[i].id)
! 333: return yds_chip_capability_list[i].flags;
! 334: }
! 335:
! 336: return -1;
! 337: }
! 338:
! 339: static void
! 340: nswaph(u_int32_t *p, int wcount)
! 341: {
! 342: for (; wcount; wcount -=4) {
! 343: *p = ntohl(*p);
! 344: p++;
! 345: }
! 346: }
! 347:
! 348: static int
! 349: yds_download_mcode(sc)
! 350: struct yds_softc *sc;
! 351: {
! 352: u_int ctrl;
! 353: const u_int32_t *p;
! 354: size_t size;
! 355: u_char *buf;
! 356: size_t buflen;
! 357: int error;
! 358: struct yds_firmware *yf;
! 359:
! 360: error = loadfirmware("yds", &buf, &buflen);
! 361: if (error)
! 362: return 1;
! 363: yf = (struct yds_firmware *)buf;
! 364:
! 365: if (sc->sc_flags & YDS_CAP_MCODE_1) {
! 366: p = (u_int32_t *)&yf->data[ntohl(yf->dsplen)];
! 367: size = ntohl(yf->ds1len);
! 368: } else if (sc->sc_flags & YDS_CAP_MCODE_1E) {
! 369: p = (u_int32_t *)&yf->data[ntohl(yf->dsplen) + ntohl(yf->ds1len)];
! 370: size = ntohl(yf->ds1elen);
! 371: } else {
! 372: free(buf, M_DEVBUF);
! 373: return 1; /* unknown */
! 374: }
! 375:
! 376: if (size > buflen) {
! 377: printf("%s: old firmware file, update please\n",
! 378: sc->sc_dev.dv_xname);
! 379: free(buf, M_DEVBUF);
! 380: return 1;
! 381: }
! 382:
! 383: if (yds_disable_dsp(sc)) {
! 384: free(buf, M_DEVBUF);
! 385: return 1;
! 386: }
! 387:
! 388: /* Software reset */
! 389: YWRITE4(sc, YDS_MODE, YDS_MODE_RESET);
! 390: YWRITE4(sc, YDS_MODE, 0);
! 391:
! 392: YWRITE4(sc, YDS_MAPOF_REC, 0);
! 393: YWRITE4(sc, YDS_MAPOF_EFFECT, 0);
! 394: YWRITE4(sc, YDS_PLAY_CTRLBASE, 0);
! 395: YWRITE4(sc, YDS_REC_CTRLBASE, 0);
! 396: YWRITE4(sc, YDS_EFFECT_CTRLBASE, 0);
! 397: YWRITE4(sc, YDS_WORK_BASE, 0);
! 398:
! 399: ctrl = YREAD2(sc, YDS_GLOBAL_CONTROL);
! 400: YWRITE2(sc, YDS_GLOBAL_CONTROL, ctrl & ~0x0007);
! 401:
! 402: /* Download DSP microcode. */
! 403: nswaph((u_int32_t *)&yf->data[0], ntohl(yf->dsplen));
! 404: YWRITEREGION4(sc, YDS_DSP_INSTRAM, (u_int32_t *)&yf->data[0],
! 405: ntohl(yf->dsplen));
! 406:
! 407: /* Download CONTROL microcode. */
! 408: nswaph((u_int32_t *)p, size);
! 409: YWRITEREGION4(sc, YDS_CTRL_INSTRAM, p, size);
! 410:
! 411: yds_enable_dsp(sc);
! 412: delay(10*1000); /* neccesary on my 724F (??) */
! 413:
! 414: free(buf, M_DEVBUF);
! 415: return 0;
! 416: }
! 417:
! 418: static int
! 419: yds_allocate_slots(sc)
! 420: struct yds_softc *sc;
! 421: {
! 422: size_t pcs, rcs, ecs, ws, memsize;
! 423: void *mp;
! 424: u_int32_t da; /* DMA address */
! 425: char *va; /* KVA */
! 426: off_t cb;
! 427: int i;
! 428: struct yds_dma *p;
! 429:
! 430: /* Alloc DSP Control Data */
! 431: pcs = YREAD4(sc, YDS_PLAY_CTRLSIZE) * sizeof(u_int32_t);
! 432: rcs = YREAD4(sc, YDS_REC_CTRLSIZE) * sizeof(u_int32_t);
! 433: ecs = YREAD4(sc, YDS_EFFECT_CTRLSIZE) * sizeof(u_int32_t);
! 434: ws = WORK_SIZE;
! 435: YWRITE4(sc, YDS_WORK_SIZE, ws / sizeof(u_int32_t));
! 436:
! 437: DPRINTF(("play control size : %d\n", (unsigned int)pcs));
! 438: DPRINTF(("rec control size : %d\n", (unsigned int)rcs));
! 439: DPRINTF(("eff control size : %d\n", (unsigned int)ecs));
! 440: DPRINTF(("work size : %d\n", (unsigned int)ws));
! 441: #ifdef DIAGNOSTIC
! 442: if (pcs != sizeof(struct play_slot_ctrl_bank)) {
! 443: printf("%s: invalid play slot ctrldata %d != %d\n",
! 444: sc->sc_dev.dv_xname, (unsigned int)pcs,
! 445: (unsigned int)sizeof(struct play_slot_ctrl_bank));
! 446: }
! 447: if (rcs != sizeof(struct rec_slot_ctrl_bank)) {
! 448: printf("%s: invalid rec slot ctrldata %d != %d\n",
! 449: sc->sc_dev.dv_xname, (unsigned int)rcs,
! 450: (unsigned int)sizeof(struct rec_slot_ctrl_bank));
! 451: }
! 452: #endif
! 453:
! 454: memsize = N_PLAY_SLOTS*N_PLAY_SLOT_CTRL_BANK*pcs +
! 455: N_REC_SLOT_CTRL*N_REC_SLOT_CTRL_BANK*rcs + ws;
! 456: memsize += (N_PLAY_SLOTS+1)*sizeof(u_int32_t);
! 457:
! 458: p = &sc->sc_ctrldata;
! 459: i = yds_allocmem(sc, memsize, 16, p);
! 460: if (i) {
! 461: printf("%s: couldn't alloc/map DSP DMA buffer, reason %d\n",
! 462: sc->sc_dev.dv_xname, i);
! 463: free(p, M_DEVBUF);
! 464: return 1;
! 465: }
! 466: mp = KERNADDR(p);
! 467: da = DMAADDR(p);
! 468:
! 469: DPRINTF(("mp:%p, DMA addr:%p\n",
! 470: mp, (void *) sc->sc_ctrldata.map->dm_segs[0].ds_addr));
! 471:
! 472: bzero(mp, memsize);
! 473:
! 474: /* Work space */
! 475: cb = 0;
! 476: va = (u_int8_t*)mp;
! 477: YWRITE4(sc, YDS_WORK_BASE, da + cb);
! 478: cb += ws;
! 479:
! 480: /* Play control data table */
! 481: sc->ptbl = (u_int32_t *)(va + cb);
! 482: sc->ptbloff = cb;
! 483: YWRITE4(sc, YDS_PLAY_CTRLBASE, da + cb);
! 484: cb += (N_PLAY_SLOT_CTRL + 1) * sizeof(u_int32_t);
! 485:
! 486: /* Record slot control data */
! 487: sc->rbank = (struct rec_slot_ctrl_bank *)(va + cb);
! 488: YWRITE4(sc, YDS_REC_CTRLBASE, da + cb);
! 489: sc->rbankoff = cb;
! 490: cb += N_REC_SLOT_CTRL * N_REC_SLOT_CTRL_BANK * rcs;
! 491:
! 492: #if 0
! 493: /* Effect slot control data -- unused */
! 494: YWRITE4(sc, YDS_EFFECT_CTRLBASE, da + cb);
! 495: cb += N_EFFECT_SLOT_CTRL * N_EFFECT_SLOT_CTRL_BANK * ecs;
! 496: #endif
! 497:
! 498: /* Play slot control data */
! 499: sc->pbankoff = da + cb;
! 500: for (i=0; i<N_PLAY_SLOT_CTRL; i++) {
! 501: sc->pbankp[i*2] = (struct play_slot_ctrl_bank *)(va + cb);
! 502: *(sc->ptbl + i+1) = da + cb;
! 503: cb += pcs;
! 504:
! 505: sc->pbankp[i*2+1] = (struct play_slot_ctrl_bank *)(va + cb);
! 506: cb += pcs;
! 507: }
! 508: /* Sync play control data table */
! 509: bus_dmamap_sync(sc->sc_dmatag, p->map,
! 510: sc->ptbloff, (N_PLAY_SLOT_CTRL+1) * sizeof(u_int32_t),
! 511: BUS_DMASYNC_PREWRITE);
! 512:
! 513: return 0;
! 514: }
! 515:
! 516: static void
! 517: yds_enable_dsp(sc)
! 518: struct yds_softc *sc;
! 519: {
! 520: YWRITE4(sc, YDS_CONFIG, YDS_DSP_SETUP);
! 521: }
! 522:
! 523: static int
! 524: yds_disable_dsp(sc)
! 525: struct yds_softc *sc;
! 526: {
! 527: int to;
! 528: u_int32_t data;
! 529:
! 530: data = YREAD4(sc, YDS_CONFIG);
! 531: if (data)
! 532: YWRITE4(sc, YDS_CONFIG, YDS_DSP_DISABLE);
! 533:
! 534: for (to = 0; to < YDS_WORK_TIMEOUT; to++) {
! 535: if ((YREAD4(sc, YDS_STATUS) & YDS_STAT_WORK) == 0)
! 536: return 0;
! 537: delay(1);
! 538: }
! 539:
! 540: return 1;
! 541: }
! 542:
! 543: int
! 544: yds_match(parent, match, aux)
! 545: struct device *parent;
! 546: void *match;
! 547: void *aux;
! 548: {
! 549: struct pci_attach_args *pa = (struct pci_attach_args *) aux;
! 550:
! 551: switch (PCI_VENDOR(pa->pa_id)) {
! 552: case PCI_VENDOR_YAMAHA:
! 553: switch (PCI_PRODUCT(pa->pa_id)) {
! 554: case PCI_PRODUCT_YAMAHA_YMF724:
! 555: case PCI_PRODUCT_YAMAHA_YMF740:
! 556: case PCI_PRODUCT_YAMAHA_YMF740C:
! 557: case PCI_PRODUCT_YAMAHA_YMF724F:
! 558: case PCI_PRODUCT_YAMAHA_YMF744:
! 559: case PCI_PRODUCT_YAMAHA_YMF754:
! 560: /* 734, 737, 738?? */
! 561: return (1);
! 562: }
! 563: break;
! 564: }
! 565:
! 566: return (0);
! 567: }
! 568:
! 569: /*
! 570: * This routine is called after all the ISA devices are configured,
! 571: * to avoid conflict.
! 572: */
! 573: static void
! 574: yds_configure_legacy (sc)
! 575: struct yds_softc *sc;
! 576: #define FLEXIBLE (sc->sc_flags & YDS_CAP_LEGACY_FLEXIBLE)
! 577: #define SELECTABLE (sc->sc_flags & YDS_CAP_LEGACY_SELECTABLE)
! 578: {
! 579: pcireg_t reg;
! 580: struct device *dev;
! 581: int i;
! 582: bus_addr_t opl_addrs[] = {0x388, 0x398, 0x3A0, 0x3A8};
! 583: bus_addr_t mpu_addrs[] = {0x330, 0x300, 0x332, 0x334};
! 584:
! 585: if (!FLEXIBLE && !SELECTABLE)
! 586: return;
! 587:
! 588: reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, YDS_PCI_LEGACY);
! 589: reg &= ~0x8133c03f; /* these bits are out of interest */
! 590: reg |= (YDS_PCI_EX_LEGACY_IMOD | YDS_PCI_LEGACY_FMEN |
! 591: YDS_PCI_LEGACY_MEN /*| YDS_PCI_LEGACY_MIEN*/);
! 592: if (sc->sc_flags & YDS_CAP_LEGACY_SMOD_DISABLE)
! 593: reg |= YDS_PCI_EX_LEGACY_SMOD_DISABLE;
! 594: if (FLEXIBLE) {
! 595: pci_conf_write(sc->sc_pc, sc->sc_pcitag, YDS_PCI_LEGACY, reg);
! 596: delay(100*1000);
! 597: }
! 598:
! 599: /* Look for OPL */
! 600: dev = 0;
! 601: for (i = 0; i < sizeof(opl_addrs) / sizeof (bus_addr_t); i++) {
! 602: if (SELECTABLE) {
! 603: pci_conf_write(sc->sc_pc, sc->sc_pcitag,
! 604: YDS_PCI_LEGACY, reg | (i << (0+16)));
! 605: delay(100*1000); /* wait 100ms */
! 606: } else
! 607: pci_conf_write(sc->sc_pc, sc->sc_pcitag,
! 608: YDS_PCI_FM_BA, opl_addrs[i]);
! 609: if (bus_space_map(sc->sc_opl_iot,
! 610: opl_addrs[i], 4, 0, &sc->sc_opl_ioh) == 0) {
! 611: struct audio_attach_args aa;
! 612:
! 613: aa.type = AUDIODEV_TYPE_OPL;
! 614: aa.hwif = aa.hdl = NULL;
! 615: dev = config_found(&sc->sc_dev, &aa, audioprint);
! 616: if (dev == 0)
! 617: bus_space_unmap(sc->sc_opl_iot,
! 618: sc->sc_opl_ioh, 4);
! 619: else {
! 620: if (SELECTABLE)
! 621: reg |= (i << (0+16));
! 622: break;
! 623: }
! 624: }
! 625: }
! 626: if (dev == 0) {
! 627: reg &= ~YDS_PCI_LEGACY_FMEN;
! 628: pci_conf_write(sc->sc_pc, sc->sc_pcitag,
! 629: YDS_PCI_LEGACY, reg);
! 630: } else {
! 631: /* Max. volume */
! 632: YWRITE4(sc, YDS_LEGACY_OUT_VOLUME, 0x3fff3fff);
! 633: YWRITE4(sc, YDS_LEGACY_REC_VOLUME, 0x3fff3fff);
! 634: }
! 635:
! 636: /* Look for MPU */
! 637: dev = 0;
! 638: for (i = 0; i < sizeof(mpu_addrs) / sizeof (bus_addr_t); i++) {
! 639: if (SELECTABLE)
! 640: pci_conf_write(sc->sc_pc, sc->sc_pcitag,
! 641: YDS_PCI_LEGACY, reg | (i << (4+16)));
! 642: else
! 643: pci_conf_write(sc->sc_pc, sc->sc_pcitag,
! 644: YDS_PCI_MPU_BA, mpu_addrs[i]);
! 645: if (bus_space_map(sc->sc_mpu_iot,
! 646: mpu_addrs[i], 2, 0, &sc->sc_mpu_ioh) == 0) {
! 647: struct audio_attach_args aa;
! 648:
! 649: aa.type = AUDIODEV_TYPE_MPU;
! 650: aa.hwif = aa.hdl = NULL;
! 651: dev = config_found(&sc->sc_dev, &aa, audioprint);
! 652: if (dev == 0)
! 653: bus_space_unmap(sc->sc_mpu_iot,
! 654: sc->sc_mpu_ioh, 2);
! 655: else {
! 656: if (SELECTABLE)
! 657: reg |= (i << (4+16));
! 658: break;
! 659: }
! 660: }
! 661: }
! 662: if (dev == 0) {
! 663: reg &= ~(YDS_PCI_LEGACY_MEN | YDS_PCI_LEGACY_MIEN);
! 664: pci_conf_write(sc->sc_pc, sc->sc_pcitag,
! 665: YDS_PCI_LEGACY, reg);
! 666: }
! 667: sc->sc_mpu = dev;
! 668: }
! 669: #undef FLEXIBLE
! 670: #undef SELECTABLE
! 671:
! 672: void
! 673: yds_attach(parent, self, aux)
! 674: struct device *parent;
! 675: struct device *self;
! 676: void *aux;
! 677: {
! 678: struct yds_softc *sc = (struct yds_softc *)self;
! 679: struct pci_attach_args *pa = (struct pci_attach_args *)aux;
! 680: pci_chipset_tag_t pc = pa->pa_pc;
! 681: char const *intrstr;
! 682: pci_intr_handle_t ih;
! 683: bus_size_t size;
! 684: pcireg_t reg;
! 685: int i;
! 686:
! 687: /* Map register to memory */
! 688: if (pci_mapreg_map(pa, YDS_PCI_MBA, PCI_MAPREG_TYPE_MEM, 0,
! 689: &sc->memt, &sc->memh, NULL, &size, 0)) {
! 690: printf("%s: can't map memory space\n", sc->sc_dev.dv_xname);
! 691: return;
! 692: }
! 693:
! 694: /* Map and establish the interrupt. */
! 695: if (pci_intr_map(pa, &ih)) {
! 696: printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname);
! 697: bus_space_unmap(sc->memt, sc->memh, size);
! 698: return;
! 699: }
! 700: intrstr = pci_intr_string(pc, ih);
! 701: sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, yds_intr, sc,
! 702: self->dv_xname);
! 703: if (sc->sc_ih == NULL) {
! 704: printf("%s: couldn't establish interrupt",
! 705: sc->sc_dev.dv_xname);
! 706: if (intrstr != NULL)
! 707: printf(" at %s", intrstr);
! 708: printf("\n");
! 709: bus_space_unmap(sc->memt, sc->memh, size);
! 710: return;
! 711: }
! 712: printf(": %s\n", intrstr);
! 713:
! 714: sc->sc_dmatag = pa->pa_dmat;
! 715: sc->sc_pc = pc;
! 716: sc->sc_pcitag = pa->pa_tag;
! 717: sc->sc_id = pa->pa_id;
! 718: sc->sc_revision = PCI_REVISION(pa->pa_class);
! 719: sc->sc_flags = yds_get_dstype(sc->sc_id);
! 720: if (sc->sc_dev.dv_cfdata->cf_flags & YDS_CAP_LEGACY_SMOD_DISABLE)
! 721: sc->sc_flags |= YDS_CAP_LEGACY_SMOD_DISABLE;
! 722: #ifdef AUDIO_DEBUG
! 723: if (ydsdebug)
! 724: printf("%s: chip has %b\n", sc->sc_dev.dv_xname,
! 725: YDS_CAP_BITS, sc->sc_flags);
! 726: #endif
! 727:
! 728: /* Disable legacy mode */
! 729: reg = pci_conf_read(pc, pa->pa_tag, YDS_PCI_LEGACY);
! 730: pci_conf_write(pc, pa->pa_tag, YDS_PCI_LEGACY,
! 731: reg & YDS_PCI_LEGACY_LAD);
! 732:
! 733: /* Mute all volumes */
! 734: for (i = 0x80; i < 0xc0; i += 2)
! 735: YWRITE2(sc, i, 0);
! 736:
! 737: sc->sc_legacy_iot = pa->pa_iot;
! 738: mountroothook_establish(yds_attachhook, sc);
! 739: }
! 740:
! 741: void
! 742: yds_attachhook(void *xsc)
! 743: {
! 744: struct yds_softc *sc = xsc;
! 745: struct yds_codec_softc *codec;
! 746: mixer_ctrl_t ctl;
! 747: int r, i;
! 748:
! 749: /* Initialize the device */
! 750: if (yds_init(sc) == -1)
! 751: return;
! 752:
! 753: /*
! 754: * Attach ac97 codec
! 755: */
! 756: for (i = 0; i < 2; i++) {
! 757: static struct {
! 758: int data;
! 759: int addr;
! 760: } statregs[] = {
! 761: {AC97_STAT_DATA1, AC97_STAT_ADDR1},
! 762: {AC97_STAT_DATA2, AC97_STAT_ADDR2},
! 763: };
! 764:
! 765: if (i == 1 && ac97_id2 == -1)
! 766: break; /* secondary ac97 not available */
! 767:
! 768: codec = &sc->sc_codec[i];
! 769: memcpy(&codec->sc_dev, &sc->sc_dev, sizeof(codec->sc_dev));
! 770: codec->sc = sc;
! 771: codec->id = i == 1 ? ac97_id2 : 0;
! 772: codec->status_data = statregs[i].data;
! 773: codec->status_addr = statregs[i].addr;
! 774: codec->host_if.arg = codec;
! 775: codec->host_if.attach = yds_attach_codec;
! 776: codec->host_if.read = yds_read_codec;
! 777: codec->host_if.write = yds_write_codec;
! 778: codec->host_if.reset = yds_reset_codec;
! 779:
! 780: if ((r = ac97_attach(&codec->host_if)) != 0) {
! 781: printf("%s: can't attach codec (error 0x%X)\n",
! 782: sc->sc_dev.dv_xname, r);
! 783: return;
! 784: }
! 785: }
! 786:
! 787: /* Just enable the DAC and master volumes by default */
! 788: ctl.type = AUDIO_MIXER_ENUM;
! 789: ctl.un.ord = 0; /* off */
! 790: ctl.dev = yds_get_portnum_by_name(sc, AudioCoutputs,
! 791: AudioNmaster, AudioNmute);
! 792: yds_mixer_set_port(sc, &ctl);
! 793: ctl.dev = yds_get_portnum_by_name(sc, AudioCinputs,
! 794: AudioNdac, AudioNmute);
! 795: yds_mixer_set_port(sc, &ctl);
! 796: ctl.dev = yds_get_portnum_by_name(sc, AudioCinputs,
! 797: AudioNcd, AudioNmute);
! 798: yds_mixer_set_port(sc, &ctl);
! 799: ctl.dev = yds_get_portnum_by_name(sc, AudioCrecord,
! 800: AudioNvolume, AudioNmute);
! 801: yds_mixer_set_port(sc, &ctl);
! 802:
! 803: ctl.dev = yds_get_portnum_by_name(sc, AudioCrecord,
! 804: AudioNsource, NULL);
! 805: ctl.type = AUDIO_MIXER_ENUM;
! 806: ctl.un.ord = 0;
! 807: yds_mixer_set_port(sc, &ctl);
! 808:
! 809: /* Set a reasonable default volume */
! 810: ctl.type = AUDIO_MIXER_VALUE;
! 811: ctl.un.value.num_channels = 2;
! 812: ctl.un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
! 813: ctl.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 127;
! 814:
! 815: ctl.dev = sc->sc_codec[0].codec_if->vtbl->get_portnum_by_name(
! 816: sc->sc_codec[0].codec_if, AudioCoutputs, AudioNmaster, NULL);
! 817: yds_mixer_set_port(sc, &ctl);
! 818:
! 819: audio_attach_mi(&yds_hw_if, sc, &sc->sc_dev);
! 820:
! 821: /* Watch for power changes */
! 822: sc->suspend = PWR_RESUME;
! 823: sc->powerhook = powerhook_establish(yds_powerhook, sc);
! 824:
! 825: yds_configure_legacy(sc);
! 826: }
! 827:
! 828: int
! 829: yds_attach_codec(sc_, codec_if)
! 830: void *sc_;
! 831: struct ac97_codec_if *codec_if;
! 832: {
! 833: struct yds_codec_softc *sc = sc_;
! 834:
! 835: sc->codec_if = codec_if;
! 836: return 0;
! 837: }
! 838:
! 839: static int
! 840: yds_ready_codec(sc)
! 841: struct yds_codec_softc *sc;
! 842: {
! 843: int to;
! 844:
! 845: for (to = 0; to < AC97_TIMEOUT; to++) {
! 846: if ((YREAD2(sc->sc, sc->status_addr) & AC97_BUSY) == 0)
! 847: return 0;
! 848: delay(1);
! 849: }
! 850:
! 851: return 1;
! 852: }
! 853:
! 854: int
! 855: yds_read_codec(sc_, reg, data)
! 856: void *sc_;
! 857: u_int8_t reg;
! 858: u_int16_t *data;
! 859: {
! 860: struct yds_codec_softc *sc = sc_;
! 861:
! 862: YWRITE2(sc->sc, AC97_CMD_ADDR, AC97_CMD_READ | AC97_ID(sc->id) | reg);
! 863:
! 864: if (yds_ready_codec(sc)) {
! 865: printf("%s: yds_read_codec timeout\n",
! 866: sc->sc->sc_dev.dv_xname);
! 867: return EIO;
! 868: }
! 869:
! 870: if (PCI_PRODUCT(sc->sc->sc_id) == PCI_PRODUCT_YAMAHA_YMF744 &&
! 871: sc->sc->sc_revision < 2) {
! 872: int i;
! 873:
! 874: for (i = 0; i < 600; i++)
! 875: YREAD2(sc->sc, sc->status_data);
! 876: }
! 877: *data = YREAD2(sc->sc, sc->status_data);
! 878:
! 879: return 0;
! 880: }
! 881:
! 882: int
! 883: yds_write_codec(sc_, reg, data)
! 884: void *sc_;
! 885: u_int8_t reg;
! 886: u_int16_t data;
! 887: {
! 888: struct yds_codec_softc *sc = sc_;
! 889:
! 890: YWRITE2(sc->sc, AC97_CMD_ADDR, AC97_CMD_WRITE | AC97_ID(sc->id) | reg);
! 891: YWRITE2(sc->sc, AC97_CMD_DATA, data);
! 892:
! 893: if (yds_ready_codec(sc)) {
! 894: printf("%s: yds_write_codec timeout\n",
! 895: sc->sc->sc_dev.dv_xname);
! 896: return EIO;
! 897: }
! 898:
! 899: return 0;
! 900: }
! 901:
! 902: /*
! 903: * XXX: Must handle the secondary differntly!!
! 904: */
! 905: void
! 906: yds_reset_codec(sc_)
! 907: void *sc_;
! 908: {
! 909: struct yds_codec_softc *codec = sc_;
! 910: struct yds_softc *sc = codec->sc;
! 911: pcireg_t reg;
! 912:
! 913: /* reset AC97 codec */
! 914: reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, YDS_PCI_DSCTRL);
! 915: if (reg & 0x03) {
! 916: pci_conf_write(sc->sc_pc, sc->sc_pcitag,
! 917: YDS_PCI_DSCTRL, reg & ~0x03);
! 918: pci_conf_write(sc->sc_pc, sc->sc_pcitag,
! 919: YDS_PCI_DSCTRL, reg | 0x03);
! 920: pci_conf_write(sc->sc_pc, sc->sc_pcitag,
! 921: YDS_PCI_DSCTRL, reg & ~0x03);
! 922: delay(50000);
! 923: }
! 924:
! 925: yds_ready_codec(sc_);
! 926: }
! 927:
! 928: int
! 929: yds_intr(p)
! 930: void *p;
! 931: {
! 932: struct yds_softc *sc = p;
! 933: u_int status;
! 934:
! 935: status = YREAD4(sc, YDS_STATUS);
! 936: DPRINTFN(1, ("yds_intr: status=%08x\n", status));
! 937: if ((status & (YDS_STAT_INT|YDS_STAT_TINT)) == 0) {
! 938: #if 0
! 939: if (sc->sc_mpu)
! 940: return mpu_intr(sc->sc_mpu);
! 941: #endif
! 942: return 0;
! 943: }
! 944:
! 945: if (status & YDS_STAT_TINT) {
! 946: YWRITE4(sc, YDS_STATUS, YDS_STAT_TINT);
! 947: printf ("yds_intr: timeout!\n");
! 948: }
! 949:
! 950: if (status & YDS_STAT_INT) {
! 951: int nbank = (YREAD4(sc, YDS_CONTROL_SELECT) == 0);
! 952:
! 953: /* Clear interrupt flag */
! 954: YWRITE4(sc, YDS_STATUS, YDS_STAT_INT);
! 955:
! 956: /* Buffer for the next frame is always ready. */
! 957: YWRITE4(sc, YDS_MODE, YREAD4(sc, YDS_MODE) | YDS_MODE_ACTV2);
! 958:
! 959: if (sc->sc_play.intr) {
! 960: u_int dma, cpu, blk, len;
! 961:
! 962: /* Sync play slot control data */
! 963: bus_dmamap_sync(sc->sc_dmatag, sc->sc_ctrldata.map,
! 964: sc->pbankoff,
! 965: sizeof(struct play_slot_ctrl_bank)*
! 966: (*sc->ptbl)*
! 967: N_PLAY_SLOT_CTRL_BANK,
! 968: BUS_DMASYNC_POSTWRITE|
! 969: BUS_DMASYNC_POSTREAD);
! 970: dma = sc->pbankp[nbank]->pgstart * sc->sc_play.factor;
! 971: cpu = sc->sc_play.offset;
! 972: blk = sc->sc_play.blksize;
! 973: len = sc->sc_play.length;
! 974:
! 975: if (((dma > cpu) && (dma - cpu > blk * 2)) ||
! 976: ((cpu > dma) && (dma + len - cpu > blk * 2))) {
! 977: /* We can fill the next block */
! 978: /* Sync ring buffer for previous write */
! 979: bus_dmamap_sync(sc->sc_dmatag,
! 980: sc->sc_play.dma->map,
! 981: cpu, blk,
! 982: BUS_DMASYNC_POSTWRITE);
! 983: sc->sc_play.intr(sc->sc_play.intr_arg);
! 984: sc->sc_play.offset += blk;
! 985: if (sc->sc_play.offset >= len) {
! 986: sc->sc_play.offset -= len;
! 987: #ifdef DIAGNOSTIC
! 988: if (sc->sc_play.offset != 0)
! 989: printf ("Audio ringbuffer botch\n");
! 990: #endif
! 991: }
! 992: /* Sync ring buffer for next write */
! 993: bus_dmamap_sync(sc->sc_dmatag,
! 994: sc->sc_play.dma->map,
! 995: cpu, blk,
! 996: BUS_DMASYNC_PREWRITE);
! 997: }
! 998: }
! 999: if (sc->sc_rec.intr) {
! 1000: u_int dma, cpu, blk, len;
! 1001:
! 1002: /* Sync rec slot control data */
! 1003: bus_dmamap_sync(sc->sc_dmatag, sc->sc_ctrldata.map,
! 1004: sc->rbankoff,
! 1005: sizeof(struct rec_slot_ctrl_bank)*
! 1006: N_REC_SLOT_CTRL*
! 1007: N_REC_SLOT_CTRL_BANK,
! 1008: BUS_DMASYNC_POSTWRITE|
! 1009: BUS_DMASYNC_POSTREAD);
! 1010: dma = sc->rbank[YDS_INPUT_SLOT*2 + nbank].pgstartadr;
! 1011: cpu = sc->sc_rec.offset;
! 1012: blk = sc->sc_rec.blksize;
! 1013: len = sc->sc_rec.length;
! 1014:
! 1015: if (((dma > cpu) && (dma - cpu > blk * 2)) ||
! 1016: ((cpu > dma) && (dma + len - cpu > blk * 2))) {
! 1017: /* We can drain the current block */
! 1018: /* Sync ring buffer first */
! 1019: bus_dmamap_sync(sc->sc_dmatag,
! 1020: sc->sc_rec.dma->map,
! 1021: cpu, blk,
! 1022: BUS_DMASYNC_POSTREAD);
! 1023: sc->sc_rec.intr(sc->sc_rec.intr_arg);
! 1024: sc->sc_rec.offset += blk;
! 1025: if (sc->sc_rec.offset >= len) {
! 1026: sc->sc_rec.offset -= len;
! 1027: #ifdef DIAGNOSTIC
! 1028: if (sc->sc_rec.offset != 0)
! 1029: printf ("Audio ringbuffer botch\n");
! 1030: #endif
! 1031: }
! 1032: /* Sync ring buffer for next read */
! 1033: bus_dmamap_sync(sc->sc_dmatag,
! 1034: sc->sc_rec.dma->map,
! 1035: cpu, blk,
! 1036: BUS_DMASYNC_PREREAD);
! 1037: }
! 1038: }
! 1039: }
! 1040:
! 1041: return 1;
! 1042: }
! 1043:
! 1044: int
! 1045: yds_allocmem(sc, size, align, p)
! 1046: struct yds_softc *sc;
! 1047: size_t size;
! 1048: size_t align;
! 1049: struct yds_dma *p;
! 1050: {
! 1051: int error;
! 1052:
! 1053: p->size = size;
! 1054: error = bus_dmamem_alloc(sc->sc_dmatag, p->size, align, 0,
! 1055: p->segs, sizeof(p->segs)/sizeof(p->segs[0]),
! 1056: &p->nsegs, BUS_DMA_NOWAIT);
! 1057: if (error)
! 1058: return (error);
! 1059:
! 1060: error = bus_dmamem_map(sc->sc_dmatag, p->segs, p->nsegs, p->size,
! 1061: &p->addr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
! 1062: if (error)
! 1063: goto free;
! 1064:
! 1065: error = bus_dmamap_create(sc->sc_dmatag, p->size, 1, p->size,
! 1066: 0, BUS_DMA_NOWAIT, &p->map);
! 1067: if (error)
! 1068: goto unmap;
! 1069:
! 1070: error = bus_dmamap_load(sc->sc_dmatag, p->map, p->addr, p->size, NULL,
! 1071: BUS_DMA_NOWAIT);
! 1072: if (error)
! 1073: goto destroy;
! 1074: return (0);
! 1075:
! 1076: destroy:
! 1077: bus_dmamap_destroy(sc->sc_dmatag, p->map);
! 1078: unmap:
! 1079: bus_dmamem_unmap(sc->sc_dmatag, p->addr, p->size);
! 1080: free:
! 1081: bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs);
! 1082: return (error);
! 1083: }
! 1084:
! 1085: int
! 1086: yds_freemem(sc, p)
! 1087: struct yds_softc *sc;
! 1088: struct yds_dma *p;
! 1089: {
! 1090: bus_dmamap_unload(sc->sc_dmatag, p->map);
! 1091: bus_dmamap_destroy(sc->sc_dmatag, p->map);
! 1092: bus_dmamem_unmap(sc->sc_dmatag, p->addr, p->size);
! 1093: bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs);
! 1094: return 0;
! 1095: }
! 1096:
! 1097: int
! 1098: yds_open(addr, flags)
! 1099: void *addr;
! 1100: int flags;
! 1101: {
! 1102: struct yds_softc *sc = addr;
! 1103: int mode;
! 1104:
! 1105: /* Select bank 0. */
! 1106: YWRITE4(sc, YDS_CONTROL_SELECT, 0);
! 1107:
! 1108: /* Start the DSP operation. */
! 1109: mode = YREAD4(sc, YDS_MODE);
! 1110: mode |= YDS_MODE_ACTV;
! 1111: mode &= ~YDS_MODE_ACTV2;
! 1112: YWRITE4(sc, YDS_MODE, mode);
! 1113:
! 1114: return 0;
! 1115: }
! 1116:
! 1117: /*
! 1118: * Close function is called at splaudio().
! 1119: */
! 1120: void
! 1121: yds_close(addr)
! 1122: void *addr;
! 1123: {
! 1124: struct yds_softc *sc = addr;
! 1125:
! 1126: yds_halt_output(sc);
! 1127: yds_halt_input(sc);
! 1128: yds_halt(sc);
! 1129: }
! 1130:
! 1131: int
! 1132: yds_query_encoding(addr, fp)
! 1133: void *addr;
! 1134: struct audio_encoding *fp;
! 1135: {
! 1136: switch (fp->index) {
! 1137: case 0:
! 1138: strlcpy(fp->name, AudioEulinear, sizeof fp->name);
! 1139: fp->encoding = AUDIO_ENCODING_ULINEAR;
! 1140: fp->precision = 8;
! 1141: fp->flags = 0;
! 1142: return (0);
! 1143: case 1:
! 1144: strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
! 1145: fp->encoding = AUDIO_ENCODING_ULAW;
! 1146: fp->precision = 8;
! 1147: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 1148: return (0);
! 1149: case 2:
! 1150: strlcpy(fp->name, AudioEalaw, sizeof fp->name);
! 1151: fp->encoding = AUDIO_ENCODING_ALAW;
! 1152: fp->precision = 8;
! 1153: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 1154: return (0);
! 1155: case 3:
! 1156: strlcpy(fp->name, AudioEslinear, sizeof fp->name);
! 1157: fp->encoding = AUDIO_ENCODING_SLINEAR;
! 1158: fp->precision = 8;
! 1159: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 1160: return (0);
! 1161: case 4:
! 1162: strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
! 1163: fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
! 1164: fp->precision = 16;
! 1165: fp->flags = 0;
! 1166: return (0);
! 1167: case 5:
! 1168: strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
! 1169: fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
! 1170: fp->precision = 16;
! 1171: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 1172: return (0);
! 1173: case 6:
! 1174: strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
! 1175: fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
! 1176: fp->precision = 16;
! 1177: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 1178: return (0);
! 1179: case 7:
! 1180: strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
! 1181: fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
! 1182: fp->precision = 16;
! 1183: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 1184: return (0);
! 1185: default:
! 1186: return (EINVAL);
! 1187: }
! 1188: }
! 1189:
! 1190: int
! 1191: yds_set_params(addr, setmode, usemode, play, rec)
! 1192: void *addr;
! 1193: int setmode, usemode;
! 1194: struct audio_params *play, *rec;
! 1195: {
! 1196: struct audio_params *p;
! 1197: int mode;
! 1198:
! 1199: for (mode = AUMODE_RECORD; mode != -1;
! 1200: mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
! 1201: if ((setmode & mode) == 0)
! 1202: continue;
! 1203:
! 1204: p = mode == AUMODE_PLAY ? play : rec;
! 1205:
! 1206: if (p->sample_rate < 4000 || p->sample_rate > 48000 ||
! 1207: (p->precision != 8 && p->precision != 16) ||
! 1208: (p->channels != 1 && p->channels != 2))
! 1209: return (EINVAL);
! 1210:
! 1211: p->factor = 1;
! 1212: p->sw_code = 0;
! 1213: switch (p->encoding) {
! 1214: case AUDIO_ENCODING_SLINEAR_BE:
! 1215: if (p->precision == 16)
! 1216: p->sw_code = swap_bytes;
! 1217: else
! 1218: p->sw_code = change_sign8;
! 1219: break;
! 1220: case AUDIO_ENCODING_SLINEAR_LE:
! 1221: if (p->precision != 16)
! 1222: p->sw_code = change_sign8;
! 1223: break;
! 1224: case AUDIO_ENCODING_ULINEAR_BE:
! 1225: if (p->precision == 16) {
! 1226: if (mode == AUMODE_PLAY)
! 1227: p->sw_code = swap_bytes_change_sign16_le;
! 1228: else
! 1229: p->sw_code = change_sign16_swap_bytes_le;
! 1230: }
! 1231: break;
! 1232: case AUDIO_ENCODING_ULINEAR_LE:
! 1233: if (p->precision == 16)
! 1234: p->sw_code = change_sign16_le;
! 1235: break;
! 1236: case AUDIO_ENCODING_ULAW:
! 1237: if (mode == AUMODE_PLAY) {
! 1238: p->factor = 2;
! 1239: p->precision = 16;
! 1240: p->sw_code = mulaw_to_slinear16_le;
! 1241: } else
! 1242: p->sw_code = ulinear8_to_mulaw;
! 1243: break;
! 1244: case AUDIO_ENCODING_ALAW:
! 1245: if (mode == AUMODE_PLAY) {
! 1246: p->factor = 2;
! 1247: p->precision = 16;
! 1248: p->sw_code = alaw_to_slinear16_le;
! 1249: } else
! 1250: p->sw_code = ulinear8_to_alaw;
! 1251: break;
! 1252: default:
! 1253: return (EINVAL);
! 1254: }
! 1255: }
! 1256:
! 1257: return 0;
! 1258: }
! 1259:
! 1260: int
! 1261: yds_round_blocksize(addr, blk)
! 1262: void *addr;
! 1263: int blk;
! 1264: {
! 1265: /*
! 1266: * Block size must be bigger than a frame.
! 1267: * That is 1024bytes at most, i.e. for 48000Hz, 16bit, 2ch.
! 1268: */
! 1269: if (blk < 1024)
! 1270: blk = 1024;
! 1271:
! 1272: return blk & ~4;
! 1273: }
! 1274:
! 1275: static u_int32_t
! 1276: yds_get_lpfq(sample_rate)
! 1277: u_int sample_rate;
! 1278: {
! 1279: int i;
! 1280: static struct lpfqt {
! 1281: u_int rate;
! 1282: u_int32_t lpfq;
! 1283: } lpfqt[] = {
! 1284: {8000, 0x32020000},
! 1285: {11025, 0x31770000},
! 1286: {16000, 0x31390000},
! 1287: {22050, 0x31c90000},
! 1288: {32000, 0x33d00000},
! 1289: {48000, 0x40000000},
! 1290: {0, 0}
! 1291: };
! 1292:
! 1293: if (sample_rate == 44100) /* for P44 slot? */
! 1294: return 0x370A0000;
! 1295:
! 1296: for (i = 0; lpfqt[i].rate != 0; i++)
! 1297: if (sample_rate <= lpfqt[i].rate)
! 1298: break;
! 1299:
! 1300: return lpfqt[i].lpfq;
! 1301: }
! 1302:
! 1303: static u_int32_t
! 1304: yds_get_lpfk(sample_rate)
! 1305: u_int sample_rate;
! 1306: {
! 1307: int i;
! 1308: static struct lpfkt {
! 1309: u_int rate;
! 1310: u_int32_t lpfk;
! 1311: } lpfkt[] = {
! 1312: {8000, 0x18b20000},
! 1313: {11025, 0x20930000},
! 1314: {16000, 0x2b9a0000},
! 1315: {22050, 0x35a10000},
! 1316: {32000, 0x3eaa0000},
! 1317: {48000, 0x40000000},
! 1318: {0, 0}
! 1319: };
! 1320:
! 1321: if (sample_rate == 44100) /* for P44 slot? */
! 1322: return 0x46460000;
! 1323:
! 1324: for (i = 0; lpfkt[i].rate != 0; i++)
! 1325: if (sample_rate <= lpfkt[i].rate)
! 1326: break;
! 1327:
! 1328: return lpfkt[i].lpfk;
! 1329: }
! 1330:
! 1331: int
! 1332: yds_trigger_output(addr, start, end, blksize, intr, arg, param)
! 1333: void *addr;
! 1334: void *start, *end;
! 1335: int blksize;
! 1336: void (*intr)(void *);
! 1337: void *arg;
! 1338: struct audio_params *param;
! 1339: #define P44 (sc->sc_flags & YDS_CAP_HAS_P44)
! 1340: {
! 1341: struct yds_softc *sc = addr;
! 1342: struct yds_dma *p;
! 1343: struct play_slot_ctrl_bank *psb;
! 1344: const u_int gain = 0x40000000;
! 1345: bus_addr_t s;
! 1346: size_t l;
! 1347: int i;
! 1348: int p44, channels;
! 1349:
! 1350: #ifdef DIAGNOSTIC
! 1351: if (sc->sc_play.intr)
! 1352: panic("yds_trigger_output: already running");
! 1353: #endif
! 1354:
! 1355: sc->sc_play.intr = intr;
! 1356: sc->sc_play.intr_arg = arg;
! 1357: sc->sc_play.offset = 0;
! 1358: sc->sc_play.blksize = blksize;
! 1359:
! 1360: DPRINTFN(1, ("yds_trigger_output: sc=%p start=%p end=%p "
! 1361: "blksize=%d intr=%p(%p)\n", addr, start, end, blksize, intr, arg));
! 1362:
! 1363: p = yds_find_dma(sc, start);
! 1364: if (!p) {
! 1365: printf("yds_trigger_output: bad addr %p\n", start);
! 1366: return (EINVAL);
! 1367: }
! 1368: sc->sc_play.dma = p;
! 1369:
! 1370: #ifdef DIAGNOSTIC
! 1371: {
! 1372: u_int32_t ctrlsize;
! 1373: if ((ctrlsize = YREAD4(sc, YDS_PLAY_CTRLSIZE)) !=
! 1374: sizeof(struct play_slot_ctrl_bank) / sizeof(u_int32_t))
! 1375: panic("%s: invalid play slot ctrldata %d %d",
! 1376: sc->sc_dev.dv_xname, ctrlsize,
! 1377: sizeof(struct play_slot_ctrl_bank));
! 1378: }
! 1379: #endif
! 1380:
! 1381: #ifdef YDS_USE_P44
! 1382: /* The document says the P44 SRC supports only stereo, 16bit PCM. */
! 1383: if (P44)
! 1384: p44 = ((param->sample_rate == 44100) &&
! 1385: (param->channels == 2) &&
! 1386: (param->precision == 16));
! 1387: else
! 1388: #endif
! 1389: p44 = 0;
! 1390: channels = p44 ? 1 : param->channels;
! 1391:
! 1392: s = DMAADDR(p);
! 1393: l = ((char *)end - (char *)start);
! 1394: sc->sc_play.length = l;
! 1395:
! 1396: *sc->ptbl = channels; /* Num of play */
! 1397:
! 1398: sc->sc_play.factor = 1;
! 1399: if (param->channels == 2)
! 1400: sc->sc_play.factor *= 2;
! 1401: if (param->precision != 8)
! 1402: sc->sc_play.factor *= 2;
! 1403: l /= sc->sc_play.factor;
! 1404:
! 1405: psb = sc->pbankp[0];
! 1406: memset(psb, 0, sizeof(*psb));
! 1407: psb->format = ((channels == 2 ? PSLT_FORMAT_STEREO : 0) |
! 1408: (param->precision == 8 ? PSLT_FORMAT_8BIT : 0) |
! 1409: (p44 ? PSLT_FORMAT_SRC441 : 0));
! 1410: psb->pgbase = s;
! 1411: psb->pgloopend = l;
! 1412: if (!p44) {
! 1413: psb->pgdeltaend = (param->sample_rate * 65536 / 48000) << 12;
! 1414: psb->lpfkend = yds_get_lpfk(param->sample_rate);
! 1415: psb->eggainend = gain;
! 1416: psb->lpfq = yds_get_lpfq(param->sample_rate);
! 1417: psb->pgdelta = psb->pgdeltaend;
! 1418: psb->lpfk = yds_get_lpfk(param->sample_rate);
! 1419: psb->eggain = gain;
! 1420: }
! 1421:
! 1422: for (i = 0; i < channels; i++) {
! 1423: /* i == 0: left or mono, i == 1: right */
! 1424: psb = sc->pbankp[i*2];
! 1425: if (i)
! 1426: /* copy from left */
! 1427: *psb = *(sc->pbankp[0]);
! 1428: if (channels == 2) {
! 1429: /* stereo */
! 1430: if (i == 0) {
! 1431: psb->lchgain = psb->lchgainend = gain;
! 1432: } else {
! 1433: psb->lchgain = psb->lchgainend = 0;
! 1434: psb->rchgain = psb->rchgainend = gain;
! 1435: psb->format |= PSLT_FORMAT_RCH;
! 1436: }
! 1437: } else if (!p44) {
! 1438: /* mono */
! 1439: psb->lchgain = psb->rchgain = gain;
! 1440: psb->lchgainend = psb->rchgainend = gain;
! 1441: }
! 1442: /* copy to the other bank */
! 1443: *(sc->pbankp[i*2+1]) = *psb;
! 1444: }
! 1445:
! 1446: YDS_DUMP_PLAY_SLOT(5, sc, 0);
! 1447: YDS_DUMP_PLAY_SLOT(5, sc, 1);
! 1448:
! 1449: if (p44)
! 1450: YWRITE4(sc, YDS_P44_OUT_VOLUME, 0x3fff3fff);
! 1451: else
! 1452: YWRITE4(sc, YDS_DAC_OUT_VOLUME, 0x3fff3fff);
! 1453:
! 1454: /* Now the play slot for the next frame is set up!! */
! 1455: /* Sync play slot control data for both directions */
! 1456: bus_dmamap_sync(sc->sc_dmatag, sc->sc_ctrldata.map,
! 1457: sc->ptbloff,
! 1458: sizeof(struct play_slot_ctrl_bank) *
! 1459: channels * N_PLAY_SLOT_CTRL_BANK,
! 1460: BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
! 1461: /* Sync ring buffer */
! 1462: bus_dmamap_sync(sc->sc_dmatag, p->map, 0, blksize,
! 1463: BUS_DMASYNC_PREWRITE);
! 1464: /* HERE WE GO!! */
! 1465: YWRITE4(sc, YDS_MODE,
! 1466: YREAD4(sc, YDS_MODE) | YDS_MODE_ACTV | YDS_MODE_ACTV2);
! 1467:
! 1468: return 0;
! 1469: }
! 1470: #undef P44
! 1471:
! 1472: int
! 1473: yds_trigger_input(addr, start, end, blksize, intr, arg, param)
! 1474: void *addr;
! 1475: void *start, *end;
! 1476: int blksize;
! 1477: void (*intr)(void *);
! 1478: void *arg;
! 1479: struct audio_params *param;
! 1480: {
! 1481: struct yds_softc *sc = addr;
! 1482: struct yds_dma *p;
! 1483: u_int srate, format;
! 1484: struct rec_slot_ctrl_bank *rsb;
! 1485: bus_addr_t s;
! 1486: size_t l;
! 1487:
! 1488: #ifdef DIAGNOSTIC
! 1489: if (sc->sc_rec.intr)
! 1490: panic("yds_trigger_input: already running");
! 1491: #endif
! 1492: sc->sc_rec.intr = intr;
! 1493: sc->sc_rec.intr_arg = arg;
! 1494: sc->sc_rec.offset = 0;
! 1495: sc->sc_rec.blksize = blksize;
! 1496:
! 1497: DPRINTFN(1, ("yds_trigger_input: "
! 1498: "sc=%p start=%p end=%p blksize=%d intr=%p(%p)\n",
! 1499: addr, start, end, blksize, intr, arg));
! 1500: DPRINTFN(1, (" parameters: rate=%lu, precision=%u, channels=%u\n",
! 1501: param->sample_rate, param->precision, param->channels));
! 1502:
! 1503: p = yds_find_dma(sc, start);
! 1504: if (!p) {
! 1505: printf("yds_trigger_input: bad addr %p\n", start);
! 1506: return (EINVAL);
! 1507: }
! 1508: sc->sc_rec.dma = p;
! 1509:
! 1510: s = DMAADDR(p);
! 1511: l = ((char *)end - (char *)start);
! 1512: sc->sc_rec.length = l;
! 1513:
! 1514: sc->sc_rec.factor = 1;
! 1515: if (param->channels == 2)
! 1516: sc->sc_rec.factor *= 2;
! 1517: if (param->precision != 8)
! 1518: sc->sc_rec.factor *= 2;
! 1519:
! 1520: rsb = &sc->rbank[0];
! 1521: memset(rsb, 0, sizeof(*rsb));
! 1522: rsb->pgbase = s;
! 1523: rsb->pgloopendadr = l;
! 1524: /* Seems all 4 banks must be set up... */
! 1525: sc->rbank[1] = *rsb;
! 1526: sc->rbank[2] = *rsb;
! 1527: sc->rbank[3] = *rsb;
! 1528:
! 1529: YWRITE4(sc, YDS_ADC_IN_VOLUME, 0x3fff3fff);
! 1530: YWRITE4(sc, YDS_REC_IN_VOLUME, 0x3fff3fff);
! 1531: srate = 48000 * 4096 / param->sample_rate - 1;
! 1532: format = ((param->precision == 8 ? YDS_FORMAT_8BIT : 0) |
! 1533: (param->channels == 2 ? YDS_FORMAT_STEREO : 0));
! 1534: DPRINTF(("srate=%d, format=%08x\n", srate, format));
! 1535: #ifdef YDS_USE_REC_SLOT
! 1536: YWRITE4(sc, YDS_DAC_REC_VOLUME, 0x3fff3fff);
! 1537: YWRITE4(sc, YDS_P44_REC_VOLUME, 0x3fff3fff);
! 1538: YWRITE4(sc, YDS_MAPOF_REC, YDS_RECSLOT_VALID);
! 1539: YWRITE4(sc, YDS_REC_SAMPLE_RATE, srate);
! 1540: YWRITE4(sc, YDS_REC_FORMAT, format);
! 1541: #else
! 1542: YWRITE4(sc, YDS_MAPOF_REC, YDS_ADCSLOT_VALID);
! 1543: YWRITE4(sc, YDS_ADC_SAMPLE_RATE, srate);
! 1544: YWRITE4(sc, YDS_ADC_FORMAT, format);
! 1545: #endif
! 1546: /* Now the rec slot for the next frame is set up!! */
! 1547: /* Sync record slot control data */
! 1548: bus_dmamap_sync(sc->sc_dmatag, sc->sc_ctrldata.map,
! 1549: sc->rbankoff,
! 1550: sizeof(struct rec_slot_ctrl_bank)*
! 1551: N_REC_SLOT_CTRL*
! 1552: N_REC_SLOT_CTRL_BANK,
! 1553: BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
! 1554: /* Sync ring buffer */
! 1555: bus_dmamap_sync(sc->sc_dmatag, p->map, 0, blksize,
! 1556: BUS_DMASYNC_PREREAD);
! 1557: /* HERE WE GO!! */
! 1558: YWRITE4(sc, YDS_MODE,
! 1559: YREAD4(sc, YDS_MODE) | YDS_MODE_ACTV | YDS_MODE_ACTV2);
! 1560:
! 1561: return 0;
! 1562: }
! 1563:
! 1564: static int
! 1565: yds_halt(sc)
! 1566: struct yds_softc *sc;
! 1567: {
! 1568: u_int32_t mode;
! 1569:
! 1570: /* Stop the DSP operation. */
! 1571: mode = YREAD4(sc, YDS_MODE);
! 1572: YWRITE4(sc, YDS_MODE, mode & ~(YDS_MODE_ACTV|YDS_MODE_ACTV2));
! 1573:
! 1574: /* Paranoia... mute all */
! 1575: YWRITE4(sc, YDS_P44_OUT_VOLUME, 0);
! 1576: YWRITE4(sc, YDS_DAC_OUT_VOLUME, 0);
! 1577: YWRITE4(sc, YDS_ADC_IN_VOLUME, 0);
! 1578: YWRITE4(sc, YDS_REC_IN_VOLUME, 0);
! 1579: YWRITE4(sc, YDS_DAC_REC_VOLUME, 0);
! 1580: YWRITE4(sc, YDS_P44_REC_VOLUME, 0);
! 1581:
! 1582: return 0;
! 1583: }
! 1584:
! 1585: int
! 1586: yds_halt_output(addr)
! 1587: void *addr;
! 1588: {
! 1589: struct yds_softc *sc = addr;
! 1590:
! 1591: DPRINTF(("yds: yds_halt_output\n"));
! 1592: if (sc->sc_play.intr) {
! 1593: sc->sc_play.intr = 0;
! 1594: /* Sync play slot control data */
! 1595: bus_dmamap_sync(sc->sc_dmatag, sc->sc_ctrldata.map,
! 1596: sc->pbankoff,
! 1597: sizeof(struct play_slot_ctrl_bank)*
! 1598: (*sc->ptbl)*N_PLAY_SLOT_CTRL_BANK,
! 1599: BUS_DMASYNC_POSTWRITE|BUS_DMASYNC_POSTREAD);
! 1600: /* Stop the play slot operation */
! 1601: sc->pbankp[0]->status =
! 1602: sc->pbankp[1]->status =
! 1603: sc->pbankp[2]->status =
! 1604: sc->pbankp[3]->status = 1;
! 1605: /* Sync ring buffer */
! 1606: bus_dmamap_sync(sc->sc_dmatag, sc->sc_play.dma->map,
! 1607: 0, sc->sc_play.length, BUS_DMASYNC_POSTWRITE);
! 1608: }
! 1609:
! 1610: return 0;
! 1611: }
! 1612:
! 1613: int
! 1614: yds_halt_input(addr)
! 1615: void *addr;
! 1616: {
! 1617: struct yds_softc *sc = addr;
! 1618:
! 1619: DPRINTF(("yds: yds_halt_input\n"));
! 1620: if (sc->sc_rec.intr) {
! 1621: /* Stop the rec slot operation */
! 1622: YWRITE4(sc, YDS_MAPOF_REC, 0);
! 1623: sc->sc_rec.intr = 0;
! 1624: /* Sync rec slot control data */
! 1625: bus_dmamap_sync(sc->sc_dmatag, sc->sc_ctrldata.map,
! 1626: sc->rbankoff,
! 1627: sizeof(struct rec_slot_ctrl_bank)*
! 1628: N_REC_SLOT_CTRL*N_REC_SLOT_CTRL_BANK,
! 1629: BUS_DMASYNC_POSTWRITE|BUS_DMASYNC_POSTREAD);
! 1630: /* Sync ring buffer */
! 1631: bus_dmamap_sync(sc->sc_dmatag, sc->sc_rec.dma->map,
! 1632: 0, sc->sc_rec.length, BUS_DMASYNC_POSTREAD);
! 1633: }
! 1634: sc->sc_rec.intr = NULL;
! 1635:
! 1636: return 0;
! 1637: }
! 1638:
! 1639: int
! 1640: yds_getdev(addr, retp)
! 1641: void *addr;
! 1642: struct audio_device *retp;
! 1643: {
! 1644: *retp = yds_device;
! 1645:
! 1646: return 0;
! 1647: }
! 1648:
! 1649: int
! 1650: yds_mixer_set_port(addr, cp)
! 1651: void *addr;
! 1652: mixer_ctrl_t *cp;
! 1653: {
! 1654: struct yds_softc *sc = addr;
! 1655:
! 1656: return (sc->sc_codec[0].codec_if->vtbl->mixer_set_port(
! 1657: sc->sc_codec[0].codec_if, cp));
! 1658: }
! 1659:
! 1660: int
! 1661: yds_mixer_get_port(addr, cp)
! 1662: void *addr;
! 1663: mixer_ctrl_t *cp;
! 1664: {
! 1665: struct yds_softc *sc = addr;
! 1666:
! 1667: return (sc->sc_codec[0].codec_if->vtbl->mixer_get_port(
! 1668: sc->sc_codec[0].codec_if, cp));
! 1669: }
! 1670:
! 1671: int
! 1672: yds_query_devinfo(addr, dip)
! 1673: void *addr;
! 1674: mixer_devinfo_t *dip;
! 1675: {
! 1676: struct yds_softc *sc = addr;
! 1677:
! 1678: return (sc->sc_codec[0].codec_if->vtbl->query_devinfo(
! 1679: sc->sc_codec[0].codec_if, dip));
! 1680: }
! 1681:
! 1682: int
! 1683: yds_get_portnum_by_name(sc, class, device, qualifier)
! 1684: struct yds_softc *sc;
! 1685: char *class, *device, *qualifier;
! 1686: {
! 1687: return (sc->sc_codec[0].codec_if->vtbl->get_portnum_by_name(
! 1688: sc->sc_codec[0].codec_if, class, device, qualifier));
! 1689: }
! 1690:
! 1691: void *
! 1692: yds_malloc(addr, direction, size, pool, flags)
! 1693: void *addr;
! 1694: int direction;
! 1695: size_t size;
! 1696: int pool, flags;
! 1697: {
! 1698: struct yds_softc *sc = addr;
! 1699: struct yds_dma *p;
! 1700: int error;
! 1701:
! 1702: p = malloc(sizeof(*p), pool, flags);
! 1703: if (!p)
! 1704: return (0);
! 1705: error = yds_allocmem(sc, size, 16, p);
! 1706: if (error) {
! 1707: free(p, pool);
! 1708: return (0);
! 1709: }
! 1710: p->next = sc->sc_dmas;
! 1711: sc->sc_dmas = p;
! 1712: return (KERNADDR(p));
! 1713: }
! 1714:
! 1715: void
! 1716: yds_free(addr, ptr, pool)
! 1717: void *addr;
! 1718: void *ptr;
! 1719: int pool;
! 1720: {
! 1721: struct yds_softc *sc = addr;
! 1722: struct yds_dma **pp, *p;
! 1723:
! 1724: for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->next) {
! 1725: if (KERNADDR(p) == ptr) {
! 1726: yds_freemem(sc, p);
! 1727: *pp = p->next;
! 1728: free(p, pool);
! 1729: return;
! 1730: }
! 1731: }
! 1732: }
! 1733:
! 1734: static struct yds_dma *
! 1735: yds_find_dma(sc, addr)
! 1736: struct yds_softc *sc;
! 1737: void *addr;
! 1738: {
! 1739: struct yds_dma *p;
! 1740:
! 1741: for (p = sc->sc_dmas; p && KERNADDR(p) != addr; p = p->next)
! 1742: ;
! 1743:
! 1744: return p;
! 1745: }
! 1746:
! 1747: size_t
! 1748: yds_round_buffersize(addr, direction, size)
! 1749: void *addr;
! 1750: int direction;
! 1751: size_t size;
! 1752: {
! 1753: /*
! 1754: * Buffer size should be at least twice as bigger as a frame.
! 1755: */
! 1756: if (size < 1024 * 3)
! 1757: size = 1024 * 3;
! 1758: return (size);
! 1759: }
! 1760:
! 1761: paddr_t
! 1762: yds_mappage(addr, mem, off, prot)
! 1763: void *addr;
! 1764: void *mem;
! 1765: off_t off;
! 1766: int prot;
! 1767: {
! 1768: struct yds_softc *sc = addr;
! 1769: struct yds_dma *p;
! 1770:
! 1771: if (off < 0)
! 1772: return (-1);
! 1773: p = yds_find_dma(sc, mem);
! 1774: if (!p)
! 1775: return (-1);
! 1776: return (bus_dmamem_mmap(sc->sc_dmatag, p->segs, p->nsegs,
! 1777: off, prot, BUS_DMA_WAITOK));
! 1778: }
! 1779:
! 1780: int
! 1781: yds_get_props(addr)
! 1782: void *addr;
! 1783: {
! 1784: return (AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT |
! 1785: AUDIO_PROP_FULLDUPLEX);
! 1786: }
! 1787:
! 1788: void
! 1789: yds_powerhook(why, self)
! 1790: int why;
! 1791: void *self;
! 1792: {
! 1793: struct yds_softc *sc = (struct yds_softc *)self;
! 1794:
! 1795: if (why != PWR_RESUME) {
! 1796: /* Power down */
! 1797: DPRINTF(("yds: power down\n"));
! 1798: sc->suspend = why;
! 1799:
! 1800: } else {
! 1801: /* Wake up */
! 1802: DPRINTF(("yds: power resume\n"));
! 1803: if (sc->suspend == PWR_RESUME) {
! 1804: printf("%s: resume without suspend?\n",
! 1805: sc->sc_dev.dv_xname);
! 1806: sc->suspend = why;
! 1807: return;
! 1808: }
! 1809: sc->suspend = why;
! 1810: yds_init(sc);
! 1811: (sc->sc_codec[0].codec_if->vtbl->restore_ports)(sc->sc_codec[0].codec_if);
! 1812: }
! 1813: }
! 1814:
! 1815: int
! 1816: yds_init(sc_)
! 1817: void *sc_;
! 1818: {
! 1819: struct yds_softc *sc = sc_;
! 1820: u_int32_t reg;
! 1821:
! 1822: pci_chipset_tag_t pc = sc->sc_pc;
! 1823:
! 1824: int to;
! 1825:
! 1826: DPRINTF(("in yds_init()\n"));
! 1827:
! 1828: /* Download microcode */
! 1829: if (yds_download_mcode(sc)) {
! 1830: printf("%s: download microcode failed\n", sc->sc_dev.dv_xname);
! 1831: return -1;
CVSweb