Annotation of sys/dev/pci/autri.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: autri.c,v 1.20 2007/05/26 00:36:03 krw Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2001 SOMEYA Yoshihiko and KUROSAWA Takahiro.
! 5: * All rights reserved.
! 6: *
! 7: * Redistribution and use in source and binary forms, with or without
! 8: * modification, are permitted provided that the following conditions
! 9: * are met:
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice, this list of conditions and the following disclaimer.
! 12: * 2. Redistributions in binary form must reproduce the above copyright
! 13: * notice, this list of conditions and the following disclaimer in the
! 14: * documentation and/or other materials provided with the distribution.
! 15: *
! 16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 17: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 18: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 19: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 20: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 21: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 22: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 23: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 24: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 25: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 26: */
! 27:
! 28: /*
! 29: * Trident 4DWAVE-DX/NX, SiS 7018, ALi M5451 Sound Driver
! 30: *
! 31: * The register information is taken from the ALSA driver.
! 32: *
! 33: * Documentation links:
! 34: * - ftp://ftp.alsa-project.org/pub/manuals/trident/
! 35: */
! 36:
! 37: #include "midi.h"
! 38:
! 39: #include <sys/param.h>
! 40: #include <sys/systm.h>
! 41: #include <sys/kernel.h>
! 42: #include <sys/fcntl.h>
! 43: #include <sys/malloc.h>
! 44: #include <sys/device.h>
! 45: #include <sys/proc.h>
! 46:
! 47: #include <dev/pci/pcidevs.h>
! 48: #include <dev/pci/pcireg.h>
! 49: #include <dev/pci/pcivar.h>
! 50:
! 51: #include <sys/audioio.h>
! 52: #include <dev/audio_if.h>
! 53: #include <dev/midi_if.h>
! 54: #include <dev/mulaw.h>
! 55: #include <dev/auconv.h>
! 56: #include <dev/ic/ac97.h>
! 57: #include <dev/ic/mpuvar.h>
! 58:
! 59: #include <machine/bus.h>
! 60: #include <machine/intr.h>
! 61:
! 62: #include <dev/pci/autrireg.h>
! 63: #include <dev/pci/autrivar.h>
! 64:
! 65: #ifdef AUDIO_DEBUG
! 66: # define DPRINTF(x) if (autridebug) printf x
! 67: # define DPRINTFN(n,x) if (autridebug > (n)) printf x
! 68: int autridebug = 0;
! 69: #else
! 70: # define DPRINTF(x)
! 71: # define DPRINTFN(n,x)
! 72: #endif
! 73:
! 74: int autri_match(struct device *, void *, void *);
! 75: void autri_attach(struct device *, struct device *, void *);
! 76: int autri_intr(void *);
! 77:
! 78: #define DMAADDR(p) ((p)->map->dm_segs[0].ds_addr)
! 79: #define KERNADDR(p) ((void *)((p)->addr))
! 80:
! 81: int autri_allocmem(struct autri_softc *, size_t, size_t, struct autri_dma *);
! 82: int autri_freemem(struct autri_softc *, struct autri_dma *);
! 83:
! 84: #define TWRITE1(sc, r, x) bus_space_write_1((sc)->memt, (sc)->memh, (r), (x))
! 85: #define TWRITE2(sc, r, x) bus_space_write_2((sc)->memt, (sc)->memh, (r), (x))
! 86: #define TWRITE4(sc, r, x) bus_space_write_4((sc)->memt, (sc)->memh, (r), (x))
! 87: #define TREAD1(sc, r) bus_space_read_1((sc)->memt, (sc)->memh, (r))
! 88: #define TREAD2(sc, r) bus_space_read_2((sc)->memt, (sc)->memh, (r))
! 89: #define TREAD4(sc, r) bus_space_read_4((sc)->memt, (sc)->memh, (r))
! 90:
! 91: static __inline void autri_reg_set_1(struct autri_softc *, int, uint8_t);
! 92: static __inline void autri_reg_clear_1(struct autri_softc *, int, uint8_t);
! 93: static __inline void autri_reg_set_4(struct autri_softc *, int, uint32_t);
! 94: static __inline void autri_reg_clear_4(struct autri_softc *, int, uint32_t);
! 95:
! 96: int autri_attach_codec(void *sc, struct ac97_codec_if *);
! 97: int autri_read_codec(void *sc, u_int8_t a, u_int16_t *d);
! 98: int autri_write_codec(void *sc, u_int8_t a, u_int16_t d);
! 99: void autri_reset_codec(void *sc);
! 100: enum ac97_host_flags autri_flags_codec(void *);
! 101:
! 102: void autri_powerhook(int why,void *addr);
! 103: int autri_init(void *sc);
! 104: struct autri_dma *autri_find_dma(struct autri_softc *, void *);
! 105: void autri_setup_channel(struct autri_softc *sc,int mode,
! 106: struct audio_params *param);
! 107: void autri_enable_interrupt(struct autri_softc *sc, int ch);
! 108: void autri_disable_interrupt(struct autri_softc *sc, int ch);
! 109: void autri_startch(struct autri_softc *sc, int ch, int ch_intr);
! 110: void autri_stopch(struct autri_softc *sc, int ch, int ch_intr);
! 111: void autri_enable_loop_interrupt(void *sc);
! 112: #if 0
! 113: void autri_disable_loop_interrupt(void *sc);
! 114: #endif
! 115:
! 116: struct cfdriver autri_cd = {
! 117: NULL, "autri", DV_DULL
! 118: };
! 119:
! 120: struct cfattach autri_ca = {
! 121: sizeof(struct autri_softc), autri_match, autri_attach
! 122: };
! 123:
! 124: int autri_open(void *, int);
! 125: void autri_close(void *);
! 126: int autri_query_encoding(void *, struct audio_encoding *);
! 127: int autri_set_params(void *, int, int, struct audio_params *,
! 128: struct audio_params *);
! 129: int autri_round_blocksize(void *, int);
! 130: int autri_trigger_output(void *, void *, void *, int, void (*)(void *),
! 131: void *, struct audio_params *);
! 132: int autri_trigger_input(void *, void *, void *, int, void (*)(void *),
! 133: void *, struct audio_params *);
! 134: int autri_halt_output(void *);
! 135: int autri_halt_input(void *);
! 136: int autri_getdev(void *, struct audio_device *);
! 137: int autri_mixer_set_port(void *, mixer_ctrl_t *);
! 138: int autri_mixer_get_port(void *, mixer_ctrl_t *);
! 139: void *autri_malloc(void *, int, size_t, int, int);
! 140: void autri_free(void *, void *, int);
! 141: paddr_t autri_mappage(void *, void *, off_t, int);
! 142: int autri_get_props(void *);
! 143: int autri_query_devinfo(void *addr, mixer_devinfo_t *dip);
! 144:
! 145: int autri_get_portnum_by_name(struct autri_softc *, char *, char *, char *);
! 146:
! 147: struct audio_hw_if autri_hw_if = {
! 148: autri_open,
! 149: autri_close,
! 150: NULL, /* drain */
! 151: autri_query_encoding,
! 152: autri_set_params,
! 153: autri_round_blocksize,
! 154: NULL, /* commit_settings */
! 155: NULL, /* init_output */
! 156: NULL, /* init_input */
! 157: NULL, /* start_output */
! 158: NULL, /* start_input */
! 159: autri_halt_output,
! 160: autri_halt_input,
! 161: NULL, /* speaker_ctl */
! 162: autri_getdev,
! 163: NULL, /* setfd */
! 164: autri_mixer_set_port,
! 165: autri_mixer_get_port,
! 166: autri_query_devinfo,
! 167: autri_malloc,
! 168: autri_free,
! 169: NULL,
! 170: autri_mappage,
! 171: autri_get_props,
! 172: autri_trigger_output,
! 173: autri_trigger_input,
! 174: };
! 175:
! 176: #if NMIDI > 0
! 177: void autri_midi_close(void *);
! 178: void autri_midi_getinfo(void *, struct midi_info *);
! 179: int autri_midi_open(void *, int, void (*)(void *, int),
! 180: void (*)(void *), void *);
! 181: int autri_midi_output(void *, int);
! 182:
! 183: struct midi_hw_if autri_midi_hw_if = {
! 184: autri_midi_open,
! 185: autri_midi_close,
! 186: autri_midi_output,
! 187: NULL, /* flush */
! 188: autri_midi_getinfo,
! 189: NULL, /* ioctl */
! 190: };
! 191: #endif
! 192:
! 193: /*
! 194: * register set/clear bit
! 195: */
! 196: static __inline void
! 197: autri_reg_set_1(sc, no, mask)
! 198: struct autri_softc *sc;
! 199: int no;
! 200: uint8_t mask;
! 201: {
! 202: bus_space_write_1(sc->memt, sc->memh, no,
! 203: (bus_space_read_1(sc->memt, sc->memh, no) | mask));
! 204: }
! 205:
! 206: static __inline void
! 207: autri_reg_clear_1(sc, no, mask)
! 208: struct autri_softc *sc;
! 209: int no;
! 210: uint8_t mask;
! 211: {
! 212: bus_space_write_1(sc->memt, sc->memh, no,
! 213: (bus_space_read_1(sc->memt, sc->memh, no) & ~mask));
! 214: }
! 215:
! 216: static __inline void
! 217: autri_reg_set_4(sc, no, mask)
! 218: struct autri_softc *sc;
! 219: int no;
! 220: uint32_t mask;
! 221: {
! 222: bus_space_write_4(sc->memt, sc->memh, no,
! 223: (bus_space_read_4(sc->memt, sc->memh, no) | mask));
! 224: }
! 225:
! 226: static __inline void
! 227: autri_reg_clear_4(sc, no, mask)
! 228: struct autri_softc *sc;
! 229: int no;
! 230: uint32_t mask;
! 231: {
! 232: bus_space_write_4(sc->memt, sc->memh, no,
! 233: (bus_space_read_4(sc->memt, sc->memh, no) & ~mask));
! 234: }
! 235:
! 236: /*
! 237: * AC97 codec
! 238: */
! 239: int
! 240: autri_attach_codec(sc_, codec_if)
! 241: void *sc_;
! 242: struct ac97_codec_if *codec_if;
! 243: {
! 244: struct autri_codec_softc *sc = sc_;
! 245:
! 246: DPRINTF(("autri_attach_codec()\n"));
! 247:
! 248: sc->codec_if = codec_if;
! 249: return 0;
! 250: }
! 251:
! 252: int
! 253: autri_read_codec(sc_, index, data)
! 254: void *sc_;
! 255: u_int8_t index;
! 256: u_int16_t *data;
! 257: {
! 258: struct autri_codec_softc *codec = sc_;
! 259: struct autri_softc *sc = codec->sc;
! 260: u_int32_t status, addr, cmd, busy;
! 261: u_int16_t count;
! 262:
! 263: /*DPRINTF(("sc->sc->type : 0x%X",sc->sc->type));*/
! 264:
! 265: switch (sc->sc_devid) {
! 266: case AUTRI_DEVICE_ID_4DWAVE_DX:
! 267: addr = AUTRI_DX_ACR1;
! 268: cmd = AUTRI_DX_ACR1_CMD_READ;
! 269: busy = AUTRI_DX_ACR1_BUSY_READ;
! 270: break;
! 271: case AUTRI_DEVICE_ID_4DWAVE_NX:
! 272: addr = AUTRI_NX_ACR2;
! 273: cmd = AUTRI_NX_ACR2_CMD_READ;
! 274: busy = AUTRI_NX_ACR2_BUSY_READ | AUTRI_NX_ACR2_RECV_WAIT;
! 275: break;
! 276: case AUTRI_DEVICE_ID_SIS_7018:
! 277: addr = AUTRI_SIS_ACRD;
! 278: cmd = AUTRI_SIS_ACRD_CMD_READ;
! 279: busy = AUTRI_SIS_ACRD_BUSY_READ | AUTRI_SIS_ACRD_AUDIO_BUSY;
! 280: break;
! 281: case AUTRI_DEVICE_ID_ALI_M5451:
! 282: if (sc->sc_revision > 0x01)
! 283: addr = AUTRI_ALI_ACWR;
! 284: else
! 285: addr = AUTRI_ALI_ACRD;
! 286: cmd = AUTRI_ALI_ACRD_CMD_READ;
! 287: busy = AUTRI_ALI_ACRD_BUSY_READ;
! 288: break;
! 289: default:
! 290: printf("%s: autri_read_codec : unknown device\n",
! 291: sc->sc_dev.dv_xname);
! 292: return -1;
! 293: }
! 294:
! 295: /* wait for 'Ready to Read' */
! 296: for (count=0; count < 0xffff; count++) {
! 297: if ((TREAD4(sc, addr) & busy) == 0)
! 298: break;
! 299: DELAY(1);
! 300: }
! 301:
! 302: if (count == 0xffff) {
! 303: printf("%s: Codec timeout. Busy reading AC97 codec.\n",
! 304: sc->sc_dev.dv_xname);
! 305: return -1;
! 306: }
! 307:
! 308: /* send Read Command to AC97 */
! 309: TWRITE4(sc, addr, (index & 0x7f) | cmd);
! 310:
! 311: /* wait for 'Returned data is available' */
! 312: for (count=0; count < 0xffff; count++) {
! 313: status = TREAD4(sc, addr);
! 314: if ((status & busy) == 0)
! 315: break;
! 316: DELAY(1);
! 317: }
! 318:
! 319: if (count == 0xffff) {
! 320: printf("%s: Codec timeout. Busy reading AC97 codec.\n",
! 321: sc->sc_dev.dv_xname);
! 322: return -1;
! 323: }
! 324:
! 325: *data = (status >> 16) & 0x0000ffff;
! 326: /*DPRINTF(("autri_read_codec(0x%X) return 0x%X\n",reg,*data));*/
! 327: return 0;
! 328: }
! 329:
! 330: int
! 331: autri_write_codec(sc_, index, data)
! 332: void *sc_;
! 333: u_int8_t index;
! 334: u_int16_t data;
! 335: {
! 336: struct autri_codec_softc *codec = sc_;
! 337: struct autri_softc *sc = codec->sc;
! 338: u_int32_t addr, cmd, busy;
! 339: u_int16_t count;
! 340:
! 341: /*DPRINTF(("autri_write_codec(0x%X,0x%X)\n",index,data));*/
! 342:
! 343: switch (sc->sc_devid) {
! 344: case AUTRI_DEVICE_ID_4DWAVE_DX:
! 345: addr = AUTRI_DX_ACR0;
! 346: cmd = AUTRI_DX_ACR0_CMD_WRITE;
! 347: busy = AUTRI_DX_ACR0_BUSY_WRITE;
! 348: break;
! 349: case AUTRI_DEVICE_ID_4DWAVE_NX:
! 350: addr = AUTRI_NX_ACR1;
! 351: cmd = AUTRI_NX_ACR1_CMD_WRITE;
! 352: busy = AUTRI_NX_ACR1_BUSY_WRITE;
! 353: break;
! 354: case AUTRI_DEVICE_ID_SIS_7018:
! 355: addr = AUTRI_SIS_ACWR;
! 356: cmd = AUTRI_SIS_ACWR_CMD_WRITE;
! 357: busy = AUTRI_SIS_ACWR_BUSY_WRITE | AUTRI_SIS_ACWR_AUDIO_BUSY;
! 358: break;
! 359: case AUTRI_DEVICE_ID_ALI_M5451:
! 360: addr = AUTRI_ALI_ACWR;
! 361: cmd = AUTRI_ALI_ACWR_CMD_WRITE;
! 362: if (sc->sc_revision > 0x01)
! 363: cmd |= 0x0100;
! 364: busy = AUTRI_ALI_ACWR_BUSY_WRITE;
! 365: break;
! 366: default:
! 367: printf("%s: autri_write_codec : unknown device.\n",
! 368: sc->sc_dev.dv_xname);
! 369: return -1;
! 370: }
! 371:
! 372: /* wait for 'Ready to Write' */
! 373: for (count=0; count < 0xffff; count++) {
! 374: if ((TREAD4(sc, addr) & busy) == 0)
! 375: break;
! 376: DELAY(1);
! 377: }
! 378:
! 379: if (count == 0xffff) {
! 380: printf("%s: Codec timeout. Busy writing AC97 codec\n",
! 381: sc->sc_dev.dv_xname);
! 382: return -1;
! 383: }
! 384:
! 385: /* send Write Command to AC97 */
! 386: TWRITE4(sc, addr, (data << 16) | (index & 0x7f) | cmd);
! 387:
! 388: return 0;
! 389: }
! 390:
! 391: void
! 392: autri_reset_codec(sc_)
! 393: void *sc_;
! 394: {
! 395: struct autri_codec_softc *codec = sc_;
! 396: struct autri_softc *sc = codec->sc;
! 397: u_int32_t reg, ready;
! 398: int addr, count = 200;
! 399:
! 400: DPRINTF(("autri_reset_codec(codec=%p,sc=%p)\n",codec,sc));
! 401: DPRINTF(("sc->sc_devid=%X\n",sc->sc_devid));
! 402:
! 403: switch (sc->sc_devid) {
! 404: case AUTRI_DEVICE_ID_4DWAVE_DX:
! 405: /* warm reset AC97 codec */
! 406: autri_reg_set_4(sc, AUTRI_DX_ACR2, 1);
! 407: delay(100);
! 408: /* release reset */
! 409: autri_reg_clear_4(sc, AUTRI_DX_ACR2, 1);
! 410: delay(100);
! 411:
! 412: addr = AUTRI_DX_ACR2;
! 413: ready = AUTRI_DX_ACR2_CODEC_READY;
! 414: break;
! 415: case AUTRI_DEVICE_ID_4DWAVE_NX:
! 416: /* warm reset AC97 codec */
! 417: autri_reg_set_4(sc, AUTRI_NX_ACR0, 1);
! 418: delay(100);
! 419: /* release reset */
! 420: autri_reg_clear_4(sc, AUTRI_NX_ACR0, 1);
! 421: delay(100);
! 422:
! 423: addr = AUTRI_NX_ACR0;
! 424: ready = AUTRI_NX_ACR0_CODEC_READY;
! 425: break;
! 426: case AUTRI_DEVICE_ID_SIS_7018:
! 427: /* warm reset AC97 codec */
! 428: autri_reg_set_4(sc, AUTRI_SIS_SCTRL, 2);
! 429: delay(1000);
! 430: /* release reset (warm & cold) */
! 431: autri_reg_clear_4(sc, AUTRI_SIS_SCTRL, 3);
! 432: delay(2000);
! 433:
! 434: addr = AUTRI_SIS_SCTRL;
! 435: ready = AUTRI_SIS_SCTRL_CODEC_READY;
! 436: break;
! 437: case AUTRI_DEVICE_ID_ALI_M5451:
! 438: /* warm reset AC97 codec */
! 439: autri_reg_set_4(sc, AUTRI_ALI_SCTRL, 1);
! 440: delay(100);
! 441: /* release reset (warm & cold) */
! 442: autri_reg_clear_4(sc, AUTRI_ALI_SCTRL, 3);
! 443: delay(100);
! 444:
! 445: addr = AUTRI_ALI_SCTRL;
! 446: ready = AUTRI_ALI_SCTRL_CODEC_READY;
! 447: break;
! 448: }
! 449:
! 450: /* wait for 'Codec Ready' */
! 451: while (count--) {
! 452: reg = TREAD4(sc, addr);
! 453: if (reg & ready)
! 454: break;
! 455: delay(1000);
! 456: }
! 457:
! 458: if (count == 0)
! 459: printf("%s: Codec timeout. AC97 is not ready for operation.\n",
! 460: sc->sc_dev.dv_xname);
! 461: }
! 462:
! 463: enum ac97_host_flags
! 464: autri_flags_codec(void *v)
! 465: {
! 466: struct autri_codec_softc *sc = v;
! 467:
! 468: return (sc->flags);
! 469: }
! 470:
! 471: /*
! 472: *
! 473: */
! 474: const struct pci_matchid autri_devices[] = {
! 475: { PCI_VENDOR_TRIDENT, PCI_PRODUCT_TRIDENT_4DWAVE_NX },
! 476: { PCI_VENDOR_SIS, PCI_PRODUCT_SIS_7018 },
! 477: { PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M5451 }
! 478: };
! 479:
! 480: int
! 481: autri_match(parent, match, aux)
! 482: struct device *parent;
! 483: void *match;
! 484: void *aux;
! 485: {
! 486: struct pci_attach_args *pa = aux;
! 487:
! 488: if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_TRIDENT &&
! 489: PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_TRIDENT_4DWAVE_DX) {
! 490: /*
! 491: * IBM makes a pcn network card and improperly
! 492: * sets the vendor and product ID's. Avoid matching.
! 493: */
! 494: if (PCI_CLASS(pa->pa_class) == PCI_CLASS_NETWORK)
! 495: return (0);
! 496: else
! 497: return (1);
! 498: }
! 499:
! 500: return (pci_matchbyid((struct pci_attach_args *)aux, autri_devices,
! 501: sizeof(autri_devices)/sizeof(autri_devices[0])));
! 502: }
! 503:
! 504: void
! 505: autri_attach(parent, self, aux)
! 506: struct device *parent;
! 507: struct device *self;
! 508: void *aux;
! 509: {
! 510: struct autri_softc *sc = (struct autri_softc *)self;
! 511: struct pci_attach_args *pa = (struct pci_attach_args *)aux;
! 512: pci_chipset_tag_t pc = pa->pa_pc;
! 513: struct autri_codec_softc *codec;
! 514: bus_size_t iosize;
! 515: pci_intr_handle_t ih;
! 516: char const *intrstr;
! 517: mixer_ctrl_t ctl;
! 518: int i, r;
! 519:
! 520: sc->sc_devid = pa->pa_id;
! 521: sc->sc_class = pa->pa_class;
! 522: sc->sc_revision = PCI_REVISION(pa->pa_class);
! 523:
! 524: /* map register to memory */
! 525: if (pci_mapreg_map(pa, AUTRI_PCI_MEMORY_BASE,
! 526: PCI_MAPREG_TYPE_MEM, 0, &sc->memt, &sc->memh, NULL, &iosize, 0)) {
! 527: printf("%s: can't map memory space\n", sc->sc_dev.dv_xname);
! 528: return;
! 529: }
! 530:
! 531: /* map and establish the interrupt */
! 532: if (pci_intr_map(pa, &ih)) {
! 533: printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname);
! 534: bus_space_unmap(sc->memt, sc->memh, iosize);
! 535: return;
! 536: }
! 537: intrstr = pci_intr_string(pc, ih);
! 538: sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, autri_intr, sc,
! 539: sc->sc_dev.dv_xname);
! 540: if (sc->sc_ih == NULL) {
! 541: printf("%s: couldn't establish interrupt",
! 542: sc->sc_dev.dv_xname);
! 543: if (intrstr != NULL)
! 544: printf(" at %s", intrstr);
! 545: printf("\n");
! 546: bus_space_unmap(sc->memt, sc->memh, iosize);
! 547: return;
! 548: }
! 549: printf(": %s\n", intrstr);
! 550:
! 551: sc->sc_dmatag = pa->pa_dmat;
! 552: sc->sc_pc = pc;
! 553: sc->sc_pt = pa->pa_tag;
! 554:
! 555: /* initialize the device */
! 556: autri_init(sc);
! 557:
! 558: /* attach AC97 codec */
! 559: codec = &sc->sc_codec;
! 560: memcpy(&codec->sc_dev, &sc->sc_dev, sizeof(codec->sc_dev));
! 561: codec->sc = sc;
! 562:
! 563: codec->host_if.arg = codec;
! 564: codec->host_if.attach = autri_attach_codec;
! 565: codec->host_if.reset = autri_reset_codec;
! 566: codec->host_if.read = autri_read_codec;
! 567: codec->host_if.write = autri_write_codec;
! 568: codec->host_if.flags = autri_flags_codec;
! 569: codec->flags = AC97_HOST_DONT_READ | AC97_HOST_SWAPPED_CHANNELS;
! 570: if (sc->sc_dev.dv_cfdata->cf_flags & 0x0001)
! 571: codec->flags &= ~AC97_HOST_SWAPPED_CHANNELS;
! 572:
! 573: if ((r = ac97_attach(&codec->host_if)) != 0) {
! 574: printf("%s: can't attach codec (error 0x%X)\n",
! 575: sc->sc_dev.dv_xname, r);
! 576: pci_intr_disestablish(pc, sc->sc_ih);
! 577: bus_space_unmap(sc->memt, sc->memh, iosize);
! 578: return;
! 579: }
! 580:
! 581: /* disable mutes */
! 582: for (i = 0; i < 4; i++) {
! 583: static struct {
! 584: char *class, *device;
! 585: } d[] = {
! 586: { AudioCoutputs, AudioNmaster},
! 587: { AudioCinputs, AudioNdac},
! 588: { AudioCinputs, AudioNcd},
! 589: { AudioCrecord, AudioNvolume},
! 590: };
! 591:
! 592: ctl.type = AUDIO_MIXER_ENUM;
! 593: ctl.un.ord = 0;
! 594:
! 595: #if 0
! 596: ctl.dev = sc->sc_codec.codec_if->vtbl->get_portnum_by_name(sc->sc_codec.codec_if,
! 597: d[i].class, d[i].device, AudioNmute);
! 598: #endif
! 599: ctl.dev = autri_get_portnum_by_name(sc,d[i].class,
! 600: d[i].device, AudioNmute);
! 601: autri_mixer_set_port(sc, &ctl);
! 602: }
! 603:
! 604: /* set a reasonable default volume */
! 605: ctl.type = AUDIO_MIXER_VALUE;
! 606: ctl.un.value.num_channels = 2;
! 607: ctl.un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
! 608: ctl.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 127;
! 609:
! 610: ctl.dev = autri_get_portnum_by_name(sc,AudioCoutputs,AudioNmaster,NULL);
! 611: autri_mixer_set_port(sc, &ctl);
! 612:
! 613: audio_attach_mi(&autri_hw_if, sc, &sc->sc_dev);
! 614:
! 615: #if NMIDI > 0
! 616: midi_attach_mi(&autri_midi_hw_if, sc, &sc->sc_dev);
! 617: #endif
! 618:
! 619: sc->sc_old_power = PWR_RESUME;
! 620: powerhook_establish(autri_powerhook, sc);
! 621: }
! 622:
! 623: void
! 624: autri_powerhook(int why,void *addr)
! 625: {
! 626: struct autri_softc *sc = addr;
! 627:
! 628: if (why == PWR_RESUME && sc->sc_old_power == PWR_SUSPEND) {
! 629: DPRINTF(("PWR_RESUME\n"));
! 630: autri_init(sc);
! 631: /*autri_reset_codec(&sc->sc_codec);*/
! 632: (sc->sc_codec.codec_if->vtbl->restore_ports)(sc->sc_codec.codec_if);
! 633: }
! 634: sc->sc_old_power = why;
! 635: }
! 636:
! 637: int
! 638: autri_init(sc_)
! 639: void *sc_;
! 640: {
! 641: struct autri_softc *sc = sc_;
! 642: pcireg_t reg;
! 643:
! 644: pci_chipset_tag_t pc = sc->sc_pc;
! 645: pcitag_t pt = sc->sc_pt;
! 646:
! 647: DPRINTF(("in autri_init()\n"));
! 648: DPRINTFN(5,("pci_conf_read(0x40) : 0x%X\n",pci_conf_read(pc,pt,0x40)));
! 649: DPRINTFN(5,("pci_conf_read(0x44) : 0x%X\n",pci_conf_read(pc,pt,0x44)));
! 650:
! 651: switch (sc->sc_devid) {
! 652: case AUTRI_DEVICE_ID_4DWAVE_DX:
! 653: /* disable Legacy Control */
! 654: pci_conf_write(pc, pt, AUTRI_PCI_DDMA_CFG,0);
! 655: reg = pci_conf_read(pc, pt, AUTRI_PCI_LEGACY_IOBASE);
! 656: pci_conf_write(pc, pt, AUTRI_PCI_LEGACY_IOBASE, reg & 0xffff0000);
! 657: delay(100);
! 658: /* audio engine reset */
! 659: reg = pci_conf_read(pc, pt, AUTRI_PCI_LEGACY_IOBASE);
! 660: pci_conf_write(pc, pt, AUTRI_PCI_LEGACY_IOBASE, reg | 0x00040000);
! 661: delay(100);
! 662: /* release reset */
! 663: reg = pci_conf_read(pc, pt, AUTRI_PCI_LEGACY_IOBASE);
! 664: pci_conf_write(pc, pt, AUTRI_PCI_LEGACY_IOBASE, reg & ~0x00040000);
! 665: delay(100);
! 666: /* DAC on */
! 667: autri_reg_set_4(sc,AUTRI_DX_ACR2,0x02);
! 668: break;
! 669: case AUTRI_DEVICE_ID_4DWAVE_NX:
! 670: /* disable Legacy Control */
! 671: pci_conf_write(pc, pt, AUTRI_PCI_DDMA_CFG,0);
! 672: reg = pci_conf_read(pc, pt, AUTRI_PCI_LEGACY_IOBASE);
! 673: pci_conf_write(pc, pt, AUTRI_PCI_LEGACY_IOBASE, reg & 0xffff0000);
! 674: delay(100);
! 675: /* audio engine reset */
! 676: reg = pci_conf_read(pc, pt, AUTRI_PCI_LEGACY_IOBASE);
! 677: pci_conf_write(pc, pt, AUTRI_PCI_LEGACY_IOBASE, reg | 0x00010000);
! 678: delay(100);
! 679: /* release reset */
! 680: reg = pci_conf_read(pc, pt, AUTRI_PCI_LEGACY_IOBASE);
! 681: pci_conf_write(pc, pt, AUTRI_PCI_LEGACY_IOBASE, reg & ~0x00010000);
! 682: delay(100);
! 683: /* DAC on */
! 684: autri_reg_set_4(sc,AUTRI_NX_ACR0,0x02);
! 685: break;
! 686: case AUTRI_DEVICE_ID_SIS_7018:
! 687: /* disable Legacy Control */
! 688: pci_conf_write(pc, pt, AUTRI_PCI_DDMA_CFG,0);
! 689: reg = pci_conf_read(pc, pt, AUTRI_PCI_LEGACY_IOBASE);
! 690: pci_conf_write(pc, pt, AUTRI_PCI_LEGACY_IOBASE, reg & 0xffff0000);
! 691: delay(100);
! 692: /* reset Digital Controller */
! 693: reg = pci_conf_read(pc, pt, AUTRI_PCI_LEGACY_IOBASE);
! 694: pci_conf_write(pc, pt, AUTRI_PCI_LEGACY_IOBASE, reg | 0x000c0000);
! 695: delay(100);
! 696: /* release reset */
! 697: reg = pci_conf_read(pc, pt, AUTRI_PCI_LEGACY_IOBASE);
! 698: pci_conf_write(pc, pt, AUTRI_PCI_LEGACY_IOBASE, reg & ~0x00040000);
! 699: delay(100);
! 700: /* disable AC97 GPIO interrupt */
! 701: TWRITE1(sc, AUTRI_SIS_ACGPIO, 0);
! 702: /* enable 64 channel mode */
! 703: autri_reg_set_4(sc, AUTRI_LFO_GC_CIR, BANK_B_EN);
! 704: break;
! 705: case AUTRI_DEVICE_ID_ALI_M5451:
! 706: /* disable Legacy Control */
! 707: pci_conf_write(pc, pt, AUTRI_PCI_DDMA_CFG,0);
! 708: reg = pci_conf_read(pc, pt, AUTRI_PCI_LEGACY_IOBASE);
! 709: pci_conf_write(pc, pt, AUTRI_PCI_LEGACY_IOBASE, reg & 0xffff0000);
! 710: delay(100);
! 711: /* reset Digital Controller */
! 712: reg = pci_conf_read(pc, pt, AUTRI_PCI_LEGACY_IOBASE);
! 713: pci_conf_write(pc, pt, AUTRI_PCI_LEGACY_IOBASE, reg | 0x000c0000);
! 714: delay(100);
! 715: /* release reset */
! 716: reg = pci_conf_read(pc, pt, AUTRI_PCI_LEGACY_IOBASE);
! 717: pci_conf_write(pc, pt, AUTRI_PCI_LEGACY_IOBASE, reg & ~0x00040000);
! 718: delay(100);
! 719: /* enable PCM input */
! 720: autri_reg_set_4(sc, AUTRI_ALI_GCONTROL, AUTRI_ALI_GCONTROL_PCM_IN);
! 721: break;
! 722: }
! 723:
! 724: if (sc->sc_devid == AUTRI_DEVICE_ID_ALI_M5451) {
! 725: sc->sc_play.ch = 0;
! 726: sc->sc_play.ch_intr = 1;
! 727: sc->sc_rec.ch = 31;
! 728: sc->sc_rec.ch_intr = 2;
! 729: } else {
! 730: sc->sc_play.ch = 0x20;
! 731: sc->sc_play.ch_intr = 0x21;
! 732: sc->sc_rec.ch = 0x22;
! 733: sc->sc_rec.ch_intr = 0x23;
! 734: }
! 735:
! 736: /* clear channel status */
! 737: TWRITE4(sc, AUTRI_STOP_A, 0xffffffff);
! 738: TWRITE4(sc, AUTRI_STOP_B, 0xffffffff);
! 739:
! 740: /* disable channel interrupt */
! 741: TWRITE4(sc, AUTRI_AINTEN_A, 0);
! 742: TWRITE4(sc, AUTRI_AINTEN_B, 0);
! 743:
! 744: #if 0
! 745: /* TLB */
! 746: if (sc->sc_devid == AUTRI_DEVICE_ID_4DWAVE_NX) {
! 747: TWRITE4(sc,AUTRI_NX_TLBC,0);
! 748: }
! 749: #endif
! 750:
! 751: autri_enable_loop_interrupt(sc);
! 752:
! 753: DPRINTF(("out autri_init()\n"));
! 754: return 0;
! 755: }
! 756:
! 757: void
! 758: autri_enable_loop_interrupt(sc_)
! 759: void *sc_;
! 760: {
! 761: struct autri_softc *sc = sc_;
! 762: u_int32_t reg;
! 763:
! 764: /*reg = (ENDLP_IE | MIDLP_IE);*/
! 765: reg = ENDLP_IE;
! 766: #if 0
! 767: if (sc->sc_devid == AUTRI_DEVICE_ID_SIS_7018)
! 768: reg |= BANK_B_EN;
! 769: #endif
! 770: autri_reg_set_4(sc,AUTRI_LFO_GC_CIR,reg);
! 771: }
! 772:
! 773: #if 0
! 774: void
! 775: autri_disable_loop_interrupt(sc_)
! 776: void *sc_;
! 777: {
! 778: struct autri_softc *sc = sc_;
! 779: u_int32_t reg;
! 780:
! 781: reg = (ENDLP_IE | MIDLP_IE);
! 782: autri_reg_clear_4(sc,AUTRI_LFO_GC_CIR,reg);
! 783: }
! 784: #endif
! 785:
! 786: int
! 787: autri_intr(p)
! 788: void *p;
! 789: {
! 790: struct autri_softc *sc = p;
! 791: u_int32_t intsrc;
! 792: u_int32_t mask, active[2];
! 793: int ch, endch;
! 794: /*
! 795: u_int32_t reg;
! 796: u_int32_t cso,eso;
! 797: */
! 798:
! 799: intsrc = TREAD4(sc,AUTRI_MISCINT);
! 800: if ((intsrc & (ADDRESS_IRQ|MPU401_IRQ)) == 0)
! 801: return 0;
! 802:
! 803: if (intsrc & ADDRESS_IRQ) {
! 804:
! 805: active[0] = TREAD4(sc,AUTRI_AIN_A);
! 806: active[1] = TREAD4(sc,AUTRI_AIN_B);
! 807:
! 808: if (sc->sc_devid == AUTRI_DEVICE_ID_ALI_M5451) {
! 809: endch = 32;
! 810: } else {
! 811: endch = 64;
! 812: }
! 813:
! 814: for (ch=0; ch<endch; ch++) {
! 815: mask = 1 << (ch & 0x1f);
! 816: if (active[(ch & 0x20) ? 1 : 0] & mask) {
! 817:
! 818: /* clear interrupt */
! 819: TWRITE4(sc, (ch & 0x20) ? AUTRI_AIN_B : AUTRI_AIN_A, mask);
! 820: /* disable interrupt */
! 821: autri_reg_clear_4(sc,(ch & 0x20) ? AUTRI_AINTEN_B : AUTRI_AINTEN_A, mask);
! 822: #if 0
! 823: reg = TREAD4(sc,AUTRI_LFO_GC_CIR) & ~0x0000003f;
! 824: TWRITE4(sc,AUTRI_LFO_GC_CIR, reg | ch);
! 825:
! 826: if (sc->sc_devid == AUTRI_DEVICE_ID_4DWAVE_NX) {
! 827: cso = TREAD4(sc, 0xe0) & 0x00ffffff;
! 828: eso = TREAD4(sc, 0xe8) & 0x00ffffff;
! 829: } else {
! 830: cso = (TREAD4(sc, 0xe0) >> 16) & 0x0000ffff;
! 831: eso = (TREAD4(sc, 0xe8) >> 16) & 0x0000ffff;
! 832: }
! 833: /*printf("cso=%d, eso=%d\n",cso,eso);*/
! 834: #endif
! 835: if (ch == sc->sc_play.ch_intr) {
! 836: if (sc->sc_play.intr)
! 837: sc->sc_play.intr(sc->sc_play.intr_arg);
! 838: }
! 839:
! 840: if (ch == sc->sc_rec.ch_intr) {
! 841: if (sc->sc_rec.intr)
! 842: sc->sc_rec.intr(sc->sc_rec.intr_arg);
! 843: }
! 844:
! 845: /* enable interrupt */
! 846: autri_reg_set_4(sc, (ch & 0x20) ? AUTRI_AINTEN_B : AUTRI_AINTEN_A, mask);
! 847: }
! 848: }
! 849: }
! 850:
! 851: if (intsrc & MPU401_IRQ) {
! 852: /* XXX */
! 853: }
! 854:
! 855: autri_reg_set_4(sc,AUTRI_MISCINT,
! 856: ST_TARGET_REACHED | MIXER_OVERFLOW | MIXER_UNDERFLOW);
! 857:
! 858: return 1;
! 859: }
! 860:
! 861: /*
! 862: *
! 863: */
! 864:
! 865: int
! 866: autri_allocmem(sc, size, align, p)
! 867: struct autri_softc *sc;
! 868: size_t size;
! 869: size_t align;
! 870: struct autri_dma *p;
! 871: {
! 872: int error;
! 873:
! 874: p->size = size;
! 875: error = bus_dmamem_alloc(sc->sc_dmatag, p->size, align, 0,
! 876: p->segs, sizeof(p->segs)/sizeof(p->segs[0]),
! 877: &p->nsegs, BUS_DMA_NOWAIT);
! 878: if (error)
! 879: return (error);
! 880:
! 881: error = bus_dmamem_map(sc->sc_dmatag, p->segs, p->nsegs, p->size,
! 882: &p->addr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
! 883: if (error)
! 884: goto free;
! 885:
! 886: error = bus_dmamap_create(sc->sc_dmatag, p->size, 1, p->size,
! 887: 0, BUS_DMA_NOWAIT, &p->map);
! 888: if (error)
! 889: goto unmap;
! 890:
! 891: error = bus_dmamap_load(sc->sc_dmatag, p->map, p->addr, p->size, NULL,
! 892: BUS_DMA_NOWAIT);
! 893: if (error)
! 894: goto destroy;
! 895: return (0);
! 896:
! 897: destroy:
! 898: bus_dmamap_destroy(sc->sc_dmatag, p->map);
! 899: unmap:
! 900: bus_dmamem_unmap(sc->sc_dmatag, p->addr, p->size);
! 901: free:
! 902: bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs);
! 903: return (error);
! 904: }
! 905:
! 906: int
! 907: autri_freemem(sc, p)
! 908: struct autri_softc *sc;
! 909: struct autri_dma *p;
! 910: {
! 911: bus_dmamap_unload(sc->sc_dmatag, p->map);
! 912: bus_dmamap_destroy(sc->sc_dmatag, p->map);
! 913: bus_dmamem_unmap(sc->sc_dmatag, p->addr, p->size);
! 914: bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs);
! 915: return 0;
! 916: }
! 917:
! 918: int
! 919: autri_open(addr, flags)
! 920: void *addr;
! 921: int flags;
! 922: {
! 923: DPRINTF(("autri_open()\n"));
! 924: DPRINTFN(5,("MISCINT : 0x%08X\n",
! 925: TREAD4((struct autri_softc *)addr, AUTRI_MISCINT)));
! 926: DPRINTFN(5,("LFO_GC_CIR : 0x%08X\n",
! 927: TREAD4((struct autri_softc *)addr, AUTRI_LFO_GC_CIR)));
! 928: return 0;
! 929: }
! 930:
! 931: void
! 932: autri_close(addr)
! 933: void *addr;
! 934: {
! 935: DPRINTF(("autri_close()\n"));
! 936: }
! 937:
! 938: int
! 939: autri_query_encoding(addr, fp)
! 940: void *addr;
! 941: struct audio_encoding *fp;
! 942: {
! 943: switch (fp->index) {
! 944: case 0:
! 945: strlcpy(fp->name, AudioEulinear, sizeof fp->name);
! 946: fp->encoding = AUDIO_ENCODING_ULINEAR;
! 947: fp->precision = 8;
! 948: fp->flags = 0;
! 949: break;
! 950: case 1:
! 951: strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
! 952: fp->encoding = AUDIO_ENCODING_ULAW;
! 953: fp->precision = 8;
! 954: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 955: break;
! 956: case 2:
! 957: strlcpy(fp->name, AudioEalaw, sizeof fp->name);
! 958: fp->encoding = AUDIO_ENCODING_ALAW;
! 959: fp->precision = 8;
! 960: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 961: break;
! 962: case 3:
! 963: strlcpy(fp->name, AudioEslinear, sizeof fp->name);
! 964: fp->encoding = AUDIO_ENCODING_SLINEAR;
! 965: fp->precision = 8;
! 966: fp->flags = 0;
! 967: break;
! 968: case 4:
! 969: strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
! 970: fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
! 971: fp->precision = 16;
! 972: fp->flags = 0;
! 973: break;
! 974: case 5:
! 975: strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
! 976: fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
! 977: fp->precision = 16;
! 978: fp->flags = 0;
! 979: break;
! 980: case 6:
! 981: strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
! 982: fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
! 983: fp->precision = 16;
! 984: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 985: break;
! 986: case 7:
! 987: strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
! 988: fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
! 989: fp->precision = 16;
! 990: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 991: break;
! 992: default:
! 993: return (EINVAL);
! 994: }
! 995:
! 996: return 0;
! 997: }
! 998:
! 999: int
! 1000: autri_set_params(addr, setmode, usemode, play, rec)
! 1001: void *addr;
! 1002: int setmode, usemode;
! 1003: struct audio_params *play, *rec;
! 1004: {
! 1005: struct audio_params *p;
! 1006: int mode;
! 1007:
! 1008: for (mode = AUMODE_RECORD; mode != -1;
! 1009: mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
! 1010: if ((setmode & mode) == 0)
! 1011: continue;
! 1012:
! 1013: p = mode == AUMODE_PLAY ? play : rec;
! 1014:
! 1015: if (p->sample_rate < 4000 || p->sample_rate > 48000 ||
! 1016: (p->precision != 8 && p->precision != 16) ||
! 1017: (p->channels != 1 && p->channels != 2))
! 1018: return (EINVAL);
! 1019:
! 1020: p->factor = 1;
! 1021: p->sw_code = 0;
! 1022: switch (p->encoding) {
! 1023: case AUDIO_ENCODING_SLINEAR_BE:
! 1024: case AUDIO_ENCODING_ULINEAR_BE:
! 1025: if (p->precision == 16)
! 1026: p->sw_code = swap_bytes;
! 1027: break;
! 1028: case AUDIO_ENCODING_SLINEAR_LE:
! 1029: case AUDIO_ENCODING_ULINEAR_LE:
! 1030: break;
! 1031: case AUDIO_ENCODING_ULAW:
! 1032: if (mode == AUMODE_PLAY)
! 1033: p->sw_code = mulaw_to_ulinear8;
! 1034: else
! 1035: p->sw_code = ulinear8_to_mulaw;
! 1036:
! 1037: break;
! 1038: case AUDIO_ENCODING_ALAW:
! 1039: if (mode == AUMODE_PLAY)
! 1040: p->sw_code = alaw_to_ulinear8;
! 1041: else
! 1042: p->sw_code = ulinear8_to_alaw;
! 1043:
! 1044: break;
! 1045: default:
! 1046: return (EINVAL);
! 1047: }
! 1048: }
! 1049:
! 1050: return 0;
! 1051: }
! 1052:
! 1053: int
! 1054: autri_round_blocksize(addr, block)
! 1055: void *addr;
! 1056: int block;
! 1057: {
! 1058: return ((block + 3) & -4);
! 1059: }
! 1060:
! 1061: int
! 1062: autri_halt_output(addr)
! 1063: void *addr;
! 1064: {
! 1065: struct autri_softc *sc = addr;
! 1066:
! 1067: DPRINTF(("autri_halt_output()\n"));
! 1068:
! 1069: sc->sc_play.intr = NULL;
! 1070: autri_stopch(sc, sc->sc_play.ch, sc->sc_play.ch_intr);
! 1071: autri_disable_interrupt(sc, sc->sc_play.ch_intr);
! 1072:
! 1073: return 0;
! 1074: }
! 1075:
! 1076: int
! 1077: autri_halt_input(addr)
! 1078: void *addr;
! 1079: {
! 1080: struct autri_softc *sc = addr;
! 1081:
! 1082: DPRINTF(("autri_halt_input()\n"));
! 1083:
! 1084: sc->sc_rec.intr = NULL;
! 1085: autri_stopch(sc, sc->sc_rec.ch, sc->sc_rec.ch_intr);
! 1086: autri_disable_interrupt(sc, sc->sc_rec.ch_intr);
! 1087:
! 1088: return 0;
! 1089: }
! 1090:
! 1091: int
! 1092: autri_getdev(addr, retp)
! 1093: void *addr;
! 1094: struct audio_device *retp;
! 1095: {
! 1096: struct autri_softc *sc = addr;
! 1097:
! 1098: DPRINTF(("autri_getdev().\n"));
! 1099:
! 1100: strncpy(retp->name, "Trident 4DWAVE", sizeof(retp->name));
! 1101: snprintf(retp->version, sizeof(retp->version), "0x%02x",
! 1102: PCI_REVISION(sc->sc_class));
! 1103:
! 1104: switch (sc->sc_devid) {
! 1105: case AUTRI_DEVICE_ID_4DWAVE_DX:
! 1106: strncpy(retp->config, "4DWAVE-DX", sizeof(retp->config));
! 1107: break;
! 1108: case AUTRI_DEVICE_ID_4DWAVE_NX:
! 1109: strncpy(retp->config, "4DWAVE-NX", sizeof(retp->config));
! 1110: break;
! 1111: case AUTRI_DEVICE_ID_SIS_7018:
! 1112: strncpy(retp->config, "SiS 7018", sizeof(retp->config));
! 1113: break;
! 1114: case AUTRI_DEVICE_ID_ALI_M5451:
! 1115: strncpy(retp->config, "ALi M5451", sizeof(retp->config));
! 1116: break;
! 1117: default:
! 1118: strncpy(retp->config, "unknown", sizeof(retp->config));
! 1119: }
! 1120:
! 1121: return 0;
! 1122: }
! 1123:
! 1124: int
! 1125: autri_mixer_set_port(addr, cp)
! 1126: void *addr;
! 1127: mixer_ctrl_t *cp;
! 1128: {
! 1129: struct autri_softc *sc = addr;
! 1130:
! 1131: return (sc->sc_codec.codec_if->vtbl->mixer_set_port(
! 1132: sc->sc_codec.codec_if, cp));
! 1133: }
! 1134:
! 1135: int
! 1136: autri_mixer_get_port(addr, cp)
! 1137: void *addr;
! 1138: mixer_ctrl_t *cp;
! 1139: {
! 1140: struct autri_softc *sc = addr;
! 1141:
! 1142: return (sc->sc_codec.codec_if->vtbl->mixer_get_port(
! 1143: sc->sc_codec.codec_if, cp));
! 1144: }
! 1145:
! 1146: int
! 1147: autri_query_devinfo(addr, dip)
! 1148: void *addr;
! 1149: mixer_devinfo_t *dip;
! 1150: {
! 1151: struct autri_softc *sc = addr;
! 1152:
! 1153: return (sc->sc_codec.codec_if->vtbl->query_devinfo(
! 1154: sc->sc_codec.codec_if, dip));
! 1155: }
! 1156:
! 1157: int
! 1158: autri_get_portnum_by_name(sc, class, device, qualifier)
! 1159: struct autri_softc *sc;
! 1160: char *class, *device, *qualifier;
! 1161: {
! 1162: return (sc->sc_codec.codec_if->vtbl->get_portnum_by_name(
! 1163: sc->sc_codec.codec_if, class, device, qualifier));
! 1164: }
! 1165:
! 1166: void *
! 1167: autri_malloc(addr, direction, size, pool, flags)
! 1168: void *addr;
! 1169: int direction;
! 1170: size_t size;
! 1171: int pool, flags;
! 1172: {
! 1173: struct autri_softc *sc = addr;
! 1174: struct autri_dma *p;
! 1175: int error;
! 1176:
! 1177: p = malloc(sizeof(*p), pool, flags);
! 1178: if (!p)
! 1179: return NULL;
! 1180:
! 1181: #if 0
! 1182: error = autri_allocmem(sc, size, 16, p);
! 1183: #endif
! 1184: error = autri_allocmem(sc, size, 0x10000, p);
! 1185: if (error) {
! 1186: free(p, pool);
! 1187: return NULL;
! 1188: }
! 1189:
! 1190: p->next = sc->sc_dmas;
! 1191: sc->sc_dmas = p;
! 1192: return KERNADDR(p);
! 1193: }
! 1194:
! 1195: void
! 1196: autri_free(addr, ptr, pool)
! 1197: void *addr;
! 1198: void *ptr;
! 1199: int pool;
! 1200: {
! 1201: struct autri_softc *sc = addr;
! 1202: struct autri_dma **pp, *p;
! 1203:
! 1204: for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->next) {
! 1205: if (KERNADDR(p) == ptr) {
! 1206: autri_freemem(sc, p);
! 1207: *pp = p->next;
! 1208: free(p, pool);
! 1209: return;
! 1210: }
! 1211: }
! 1212: }
! 1213:
! 1214: struct autri_dma *
! 1215: autri_find_dma(sc, addr)
! 1216: struct autri_softc *sc;
! 1217: void *addr;
! 1218: {
! 1219: struct autri_dma *p;
! 1220:
! 1221: for (p = sc->sc_dmas; p && KERNADDR(p) != addr; p = p->next)
! 1222: ;
! 1223:
! 1224: return p;
! 1225: }
! 1226:
! 1227: paddr_t
! 1228: autri_mappage(addr, mem, off, prot)
! 1229: void *addr;
! 1230: void *mem;
! 1231: off_t off;
! 1232: int prot;
! 1233: {
! 1234: struct autri_softc *sc = addr;
! 1235: struct autri_dma *p;
! 1236:
! 1237: if (off < 0)
! 1238: return (-1);
! 1239:
! 1240: p = autri_find_dma(sc, mem);
! 1241: if (!p)
! 1242: return (-1);
! 1243:
! 1244: return (bus_dmamem_mmap(sc->sc_dmatag, p->segs, p->nsegs,
! 1245: off, prot, BUS_DMA_WAITOK));
! 1246: }
! 1247:
! 1248: int
! 1249: autri_get_props(addr)
! 1250: void *addr;
! 1251: {
! 1252: return (AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT |
! 1253: AUDIO_PROP_FULLDUPLEX);
! 1254: }
! 1255:
! 1256: void
! 1257: autri_setup_channel(sc, mode, param)
! 1258: struct autri_softc *sc;
! 1259: int mode;
! 1260: struct audio_params *param;
! 1261: {
! 1262: int i, ch, channel;
! 1263: u_int32_t reg, cr[5];
! 1264: u_int32_t cso, eso;
! 1265: u_int32_t delta, dch[2], ctrl;
! 1266: u_int32_t alpha_fms, fm_vol, attribute;
! 1267:
! 1268: u_int32_t dmaaddr, dmalen;
! 1269: int factor, rvol, cvol;
! 1270: struct autri_chstatus *chst;
! 1271:
! 1272: ctrl = AUTRI_CTRL_LOOPMODE;
! 1273: switch (param->encoding) {
! 1274: case AUDIO_ENCODING_SLINEAR_BE:
! 1275: case AUDIO_ENCODING_SLINEAR_LE:
! 1276: ctrl |= AUTRI_CTRL_SIGNED;
! 1277: break;
! 1278: }
! 1279:
! 1280: factor = 0;
! 1281: if (param->precision == 16) {
! 1282: ctrl |= AUTRI_CTRL_16BIT;
! 1283: factor++;
! 1284: }
! 1285:
! 1286: if (param->channels == 2) {
! 1287: ctrl |= AUTRI_CTRL_STEREO;
! 1288: factor++;
! 1289: }
! 1290:
! 1291: delta = (u_int32_t)param->sample_rate;
! 1292: if (delta < 4000)
! 1293: delta = 4000;
! 1294: if (delta > 48000)
! 1295: delta = 48000;
! 1296:
! 1297: attribute = 0;
! 1298:
! 1299: dch[1] = ((delta << 12) / 48000) & 0x0000ffff;
! 1300: if (mode == AUMODE_PLAY) {
! 1301: chst = &sc->sc_play;
! 1302: dch[0] = ((delta << 12) / 48000) & 0x0000ffff;
! 1303: ctrl |= AUTRI_CTRL_WAVEVOL;
! 1304: /*
! 1305: if (sc->sc_devid == AUTRI_DEVICE_ID_ALI_M5451)
! 1306: ctrl |= 0x80000000;
! 1307: */
! 1308: } else {
! 1309: chst = &sc->sc_rec;
! 1310: dch[0] = ((48000 << 12) / delta) & 0x0000ffff;
! 1311: if (sc->sc_devid == AUTRI_DEVICE_ID_SIS_7018) {
! 1312: ctrl |= AUTRI_CTRL_MUTE_SIS;
! 1313: attribute = AUTRI_ATTR_PCMREC_SIS;
! 1314: if (delta != 48000)
! 1315: attribute |= AUTRI_ATTR_ENASRC_SIS;
! 1316: }
! 1317: ctrl |= AUTRI_CTRL_MUTE;
! 1318: }
! 1319:
! 1320: dmaaddr = DMAADDR(chst->dma);
! 1321: cso = alpha_fms = 0;
! 1322: rvol = cvol = 0x7f;
! 1323: fm_vol = 0x0 | ((rvol & 0x7f) << 7) | (cvol & 0x7f);
! 1324:
! 1325: for (ch=0; ch<2; ch++) {
! 1326:
! 1327: if (ch == 0)
! 1328: dmalen = (chst->length >> factor);
! 1329: else {
! 1330: /* channel for interrupt */
! 1331: dmalen = (chst->blksize >> factor);
! 1332: if (sc->sc_devid == AUTRI_DEVICE_ID_SIS_7018)
! 1333: ctrl |= AUTRI_CTRL_MUTE_SIS;
! 1334: else
! 1335: ctrl |= AUTRI_CTRL_MUTE;
! 1336: attribute = 0;
! 1337: }
! 1338:
! 1339: eso = dmalen - 1;
! 1340:
! 1341: switch (sc->sc_devid) {
! 1342: case AUTRI_DEVICE_ID_4DWAVE_DX:
! 1343: cr[0] = (cso << 16) | (alpha_fms & 0x0000ffff);
! 1344: cr[1] = dmaaddr;
! 1345: cr[2] = (eso << 16) | (dch[ch] & 0x0000ffff);
! 1346: cr[3] = fm_vol;
! 1347: cr[4] = ctrl;
! 1348: break;
! 1349: case AUTRI_DEVICE_ID_4DWAVE_NX:
! 1350: cr[0] = (dch[ch] << 24) | (cso & 0x00ffffff);
! 1351: cr[1] = dmaaddr;
! 1352: cr[2] = ((dch[ch] << 16) & 0xff000000) | (eso & 0x00ffffff);
! 1353: cr[3] = (alpha_fms << 16) | (fm_vol & 0x0000ffff);
! 1354: cr[4] = ctrl;
! 1355: break;
! 1356: case AUTRI_DEVICE_ID_SIS_7018:
! 1357: cr[0] = (cso << 16) | (alpha_fms & 0x0000ffff);
! 1358: cr[1] = dmaaddr;
! 1359: cr[2] = (eso << 16) | (dch[ch] & 0x0000ffff);
! 1360: cr[3] = attribute;
! 1361: cr[4] = ctrl;
! 1362: break;
! 1363: case AUTRI_DEVICE_ID_ALI_M5451:
! 1364: cr[0] = (cso << 16) | (alpha_fms & 0x0000ffff);
! 1365: cr[1] = dmaaddr;
! 1366: cr[2] = (eso << 16) | (dch[ch] & 0x0000ffff);
! 1367: cr[3] = 0;
! 1368: cr[4] = ctrl;
! 1369: break;
! 1370: }
! 1371:
! 1372: /* write channel data */
! 1373: channel = (ch == 0) ? chst->ch : chst->ch_intr;
! 1374:
! 1375: reg = TREAD4(sc,AUTRI_LFO_GC_CIR) & ~0x0000003f;
! 1376: TWRITE4(sc,AUTRI_LFO_GC_CIR, reg | channel);
! 1377:
! 1378: for (i=0; i<5; i++) {
! 1379: TWRITE4(sc, AUTRI_ARAM_CR + i*sizeof(cr[0]), cr[i]);
! 1380: DPRINTFN(5,("cr[%d] : 0x%08X\n", i, cr[i]));
! 1381: }
! 1382:
! 1383: /* Bank A only */
! 1384: if (channel < 0x20) {
! 1385: TWRITE4(sc, AUTRI_EBUF1, AUTRI_EMOD_STILL);
! 1386: TWRITE4(sc, AUTRI_EBUF2, AUTRI_EMOD_STILL);
! 1387: }
! 1388: }
! 1389:
! 1390: }
! 1391:
! 1392: int
! 1393: autri_trigger_output(addr, start, end, blksize, intr, arg, param)
! 1394: void *addr;
! 1395: void *start, *end;
! 1396: int blksize;
! 1397: void (*intr)(void *);
! 1398: void *arg;
! 1399: struct audio_params *param;
! 1400: {
! 1401: struct autri_softc *sc = addr;
! 1402: struct autri_dma *p;
! 1403:
! 1404: DPRINTFN(5,("autri_trigger_output: sc=%p start=%p end=%p "
! 1405: "blksize=%d intr=%p(%p)\n", addr, start, end, blksize, intr, arg));
! 1406:
! 1407: sc->sc_play.intr = intr;
! 1408: sc->sc_play.intr_arg = arg;
! 1409: sc->sc_play.offset = 0;
! 1410: sc->sc_play.blksize = blksize;
! 1411: sc->sc_play.length = (char *)end - (char *)start;
! 1412:
! 1413: p = autri_find_dma(sc, start);
! 1414: if (!p) {
! 1415: printf("autri_trigger_output: bad addr %p\n", start);
! 1416: return (EINVAL);
! 1417: }
! 1418:
! 1419: sc->sc_play.dma = p;
! 1420:
! 1421: /* */
! 1422: autri_setup_channel(sc, AUMODE_PLAY, param);
! 1423:
! 1424: /* volume set to no attenuation */
! 1425: TWRITE4(sc, AUTRI_MUSICVOL_WAVEVOL, 0);
! 1426:
! 1427: /* enable interrupt */
! 1428: autri_enable_interrupt(sc, sc->sc_play.ch_intr);
! 1429:
! 1430: /* start channel */
! 1431: autri_startch(sc, sc->sc_play.ch, sc->sc_play.ch_intr);
! 1432:
! 1433: return 0;
! 1434: }
! 1435:
! 1436: int
! 1437: autri_trigger_input(addr, start, end, blksize, intr, arg, param)
! 1438: void *addr;
! 1439: void *start, *end;
! 1440: int blksize;
! 1441: void (*intr)(void *);
! 1442: void *arg;
! 1443: struct audio_params *param;
! 1444: {
! 1445: struct autri_softc *sc = addr;
! 1446: struct autri_dma *p;
! 1447:
! 1448: DPRINTFN(5,("autri_trigger_input: sc=%p start=%p end=%p "
! 1449: "blksize=%d intr=%p(%p)\n", addr, start, end, blksize, intr, arg));
! 1450:
! 1451: sc->sc_rec.intr = intr;
! 1452: sc->sc_rec.intr_arg = arg;
! 1453: sc->sc_rec.offset = 0;
! 1454: sc->sc_rec.blksize = blksize;
! 1455: sc->sc_rec.length = (char *)end - (char *)start;
! 1456:
! 1457: /* */
! 1458: p = autri_find_dma(sc, start);
! 1459: if (!p) {
! 1460: printf("autri_trigger_input: bad addr %p\n", start);
! 1461: return (EINVAL);
! 1462: }
! 1463:
! 1464: sc->sc_rec.dma = p;
! 1465:
! 1466: /* */
! 1467: if (sc->sc_devid == AUTRI_DEVICE_ID_4DWAVE_NX) {
! 1468: autri_reg_set_4(sc, AUTRI_NX_ACR0, AUTRI_NX_ACR0_PSB_CAPTURE);
! 1469: TWRITE1(sc, AUTRI_NX_RCI3, AUTRI_NX_RCI3_ENABLE | sc->sc_rec.ch);
! 1470: }
! 1471:
! 1472: #if 0
! 1473: /* 4DWAVE only allows capturing at a 48KHz rate */
! 1474: if (sc->sc_devid == AUTRI_DEVICE_ID_4DWAVE_DX ||
! 1475: sc->sc_devid == AUTRI_DEVICE_ID_4DWAVE_NX)
! 1476: param->sample_rate = 48000;
! 1477: #endif
! 1478:
! 1479: autri_setup_channel(sc, AUMODE_RECORD, param);
! 1480:
! 1481: /* enable interrupt */
! 1482: autri_enable_interrupt(sc, sc->sc_rec.ch_intr);
! 1483:
! 1484: /* start channel */
! 1485: autri_startch(sc, sc->sc_rec.ch, sc->sc_rec.ch_intr);
! 1486:
! 1487: return 0;
! 1488: }
! 1489:
! 1490: #if 0
! 1491: int
! 1492: autri_halt(sc)
! 1493: struct autri_softc *sc;
! 1494: {
! 1495: DPRINTF(("autri_halt().\n"));
! 1496: /*autri_stopch(sc);*/
! 1497: autri_disable_interrupt(sc, sc->sc_play.channel);
! 1498: autri_disable_interrupt(sc, sc->sc_rec.channel);
! 1499: return 0;
! 1500: }
! 1501: #endif
! 1502:
! 1503: void
! 1504: autri_enable_interrupt(sc, ch)
! 1505: struct autri_softc *sc;
! 1506: int ch;
! 1507: {
! 1508: int reg;
! 1509:
! 1510: reg = (ch & 0x20) ? AUTRI_AINTEN_B : AUTRI_AINTEN_A;
! 1511: ch &= 0x1f;
! 1512:
! 1513: autri_reg_set_4(sc, reg, 1 << ch);
! 1514: }
! 1515:
! 1516: void
! 1517: autri_disable_interrupt(sc, ch)
! 1518: struct autri_softc *sc;
! 1519: int ch;
! 1520: {
! 1521: int reg;
! 1522:
! 1523: reg = (ch & 0x20) ? AUTRI_AINTEN_B : AUTRI_AINTEN_A;
! 1524: ch &= 0x1f;
! 1525:
! 1526: autri_reg_clear_4(sc, reg, 1 << ch);
! 1527: }
! 1528:
! 1529: void
! 1530: autri_startch(sc, ch, ch_intr)
! 1531: struct autri_softc *sc;
! 1532: int ch, ch_intr;
! 1533: {
! 1534: int reg;
! 1535: u_int32_t chmask;
! 1536:
! 1537: reg = (ch & 0x20) ? AUTRI_START_B : AUTRI_START_A;
! 1538: ch &= 0x1f;
! 1539: chmask = (1 << ch) | (1 << ch_intr);
! 1540:
! 1541: autri_reg_set_4(sc, reg, chmask);
! 1542: }
! 1543:
! 1544: void
! 1545: autri_stopch(sc, ch, ch_intr)
! 1546: struct autri_softc *sc;
! 1547: int ch, ch_intr;
! 1548: {
! 1549: int reg;
! 1550: u_int32_t chmask;
! 1551:
! 1552: reg = (ch & 0x20) ? AUTRI_STOP_B : AUTRI_STOP_A;
! 1553: ch &= 0x1f;
! 1554: chmask = (1 << ch) | (1 << ch_intr);
! 1555:
! 1556: autri_reg_set_4(sc, reg, chmask);
! 1557: }
! 1558:
! 1559: #if NMIDI > 0
! 1560: int
! 1561: autri_midi_open(void *addr, int flags,
! 1562: void (*iintr)(void *, int),
! 1563: void (*ointr)(void *),
! 1564: void *arg)
! 1565: {
! 1566: struct autri_softc *sc = addr;
! 1567:
! 1568: DPRINTF(("autri_midi_open()\n"));
! 1569:
! 1570: DPRINTFN(5,("MPUR1 : 0x%02X\n",TREAD1(sc,AUTRI_MPUR1)));
! 1571: DPRINTFN(5,("MPUR2 : 0x%02X\n",TREAD1(sc,AUTRI_MPUR2)));
! 1572:
! 1573: sc->sc_iintr = iintr;
! 1574: sc->sc_ointr = ointr;
! 1575: sc->sc_arg = arg;
! 1576:
! 1577: if (flags & FREAD)
! 1578: autri_reg_clear_1(sc, AUTRI_MPUR2, AUTRI_MIDIIN_ENABLE_INTR);
! 1579:
! 1580: if (flags & FWRITE)
! 1581: autri_reg_set_1(sc, AUTRI_MPUR2, AUTRI_MIDIOUT_CONNECT);
! 1582:
! 1583: return (0);
! 1584: }
! 1585:
! 1586: void
! 1587: autri_midi_close(void *addr)
! 1588: {
! 1589: struct autri_softc *sc = addr;
! 1590:
! 1591: DPRINTF(("autri_midi_close()\n"));
! 1592:
! 1593: tsleep(sc, PWAIT, "autri", hz/10); /* give uart a chance to drain */
! 1594:
! 1595: sc->sc_iintr = NULL;
! 1596: sc->sc_ointr = NULL;
! 1597: }
! 1598:
! 1599: int
! 1600: autri_midi_output(void *addr, int d)
! 1601: {
! 1602: struct autri_softc *sc = addr;
! 1603: int x;
! 1604:
! 1605: for (x = 0; x != MIDI_BUSY_WAIT; x++) {
! 1606: if ((TREAD1(sc, AUTRI_MPUR1) & AUTRI_MIDIOUT_READY) == 0) {
! 1607: TWRITE1(sc, AUTRI_MPUR0, d);
! 1608: return (0);
! 1609: }
! 1610: delay(MIDI_BUSY_DELAY);
! 1611: }
! 1612: return (EIO);
! 1613: }
! 1614:
! 1615: void
! 1616: autri_midi_getinfo(void *addr, struct midi_info *mi)
! 1617: {
! 1618: mi->name = "4DWAVE MIDI UART";
! 1619: mi->props = MIDI_PROP_CAN_INPUT;
! 1620: }
! 1621:
! 1622: #endif
CVSweb