Annotation of sys/dev/pci/esa.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: esa.c,v 1.11 2006/01/25 23:54:21 brad Exp $ */
! 2: /* $NetBSD: esa.c,v 1.12 2002/03/24 14:17:35 jmcneill Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 2001, 2002 Jared D. McNeill <jmcneill@invisible.ca>
! 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. The name of the author may not be used to endorse or promote products
! 14: * derived from this software without specific prior written permission.
! 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,
! 21: * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
! 22: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
! 23: * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
! 24: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 25: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 26: * SUCH DAMAGE.
! 27: */
! 28:
! 29: /*
! 30: * Shamelessly stolen from NetBSD who based it on FreeBSD's who in turn
! 31: * based it on Linux's driver. What a wonderful world.
! 32: *
! 33: *
! 34: * ESS Allegro-1 / Maestro3 Audio Driver
! 35: *
! 36: * Based on the FreeBSD maestro3 driver and the NetBSD eap driver.
! 37: * Original driver by Don Kim.
! 38: *
! 39: * The list management code could possibly be written better, but what
! 40: * we have right now does the job nicely. Thanks to Zach Brown <zab@zabbo.net>
! 41: * and Andrew MacDonald <amac@epsilon.yi.org> for helping me debug the
! 42: * problems with the original list management code present in the Linux
! 43: * driver.
! 44: */
! 45:
! 46: #include <sys/types.h>
! 47: #include <sys/errno.h>
! 48: #include <sys/param.h>
! 49: #include <sys/systm.h>
! 50: #include <sys/malloc.h>
! 51: #include <sys/device.h>
! 52: #include <sys/conf.h>
! 53: #include <sys/exec.h>
! 54: #include <sys/selinfo.h>
! 55: #include <sys/audioio.h>
! 56:
! 57: #include <machine/bus.h>
! 58: #include <machine/intr.h>
! 59:
! 60: #include <dev/pci/pcidevs.h>
! 61: #include <dev/pci/pcivar.h>
! 62:
! 63: #include <dev/audio_if.h>
! 64: #include <dev/mulaw.h>
! 65: #include <dev/auconv.h>
! 66: #include <dev/ic/ac97.h>
! 67:
! 68: #include <dev/pci/esareg.h>
! 69: #include <dev/pci/esavar.h>
! 70: #include <dev/microcode/esa/esadsp.h>
! 71:
! 72: #define PCI_CBIO 0x10
! 73:
! 74: #define ESA_DAC_DATA 0x1100
! 75:
! 76: enum {
! 77: ESS_ALLEGRO1,
! 78: ESS_MAESTRO3
! 79: };
! 80:
! 81: static struct esa_card_type {
! 82: u_int16_t pci_vendor_id;
! 83: u_int16_t pci_product_id;
! 84: int type;
! 85: int delay1, delay2;
! 86: } esa_card_types[] = {
! 87: { PCI_VENDOR_ESSTECH, PCI_PRODUCT_ESSTECH_ES1989,
! 88: ESS_ALLEGRO1, 50, 800 },
! 89: { PCI_VENDOR_ESSTECH, PCI_PRODUCT_ESSTECH_MAESTRO3,
! 90: ESS_MAESTRO3, 20, 500 },
! 91: { PCI_VENDOR_ESSTECH, PCI_PRODUCT_ESSTECH_MAESTRO3_2,
! 92: ESS_MAESTRO3, 20, 500 },
! 93: { 0, 0, 0, 0, 0 }
! 94: };
! 95:
! 96: struct audio_device esa_device = {
! 97: "ESS Allegro",
! 98: "",
! 99: "esa"
! 100: };
! 101:
! 102: int esa_match(struct device *, void *, void *);
! 103: void esa_attach(struct device *, struct device *, void *);
! 104: int esa_detach(struct device *, int);
! 105:
! 106: /* audio(9) functions */
! 107: int esa_open(void *, int);
! 108: void esa_close(void *);
! 109: int esa_query_encoding(void *, struct audio_encoding *);
! 110: int esa_set_params(void *, int, int, struct audio_params *,
! 111: struct audio_params *);
! 112: int esa_round_blocksize(void *, int);
! 113: int esa_commit_settings(void *);
! 114: int esa_halt_output(void *);
! 115: int esa_halt_input(void *);
! 116: int esa_set_port(void *, mixer_ctrl_t *);
! 117: int esa_get_port(void *, mixer_ctrl_t *);
! 118: int esa_query_devinfo(void *, mixer_devinfo_t *);
! 119: void * esa_malloc(void *, int, size_t, int, int);
! 120: void esa_free(void *, void *, int);
! 121: int esa_getdev(void *, struct audio_device *);
! 122: size_t esa_round_buffersize(void *, int, size_t);
! 123: int esa_get_props(void *);
! 124: int esa_trigger_output(void *, void *, void *, int,
! 125: void (*)(void *), void *,
! 126: struct audio_params *);
! 127: int esa_trigger_input(void *, void *, void *, int,
! 128: void (*)(void *), void *,
! 129: struct audio_params *);
! 130:
! 131: int esa_intr(void *);
! 132: int esa_allocmem(struct esa_softc *, size_t, size_t,
! 133: struct esa_dma *);
! 134: int esa_freemem(struct esa_softc *, struct esa_dma *);
! 135: paddr_t esa_mappage(void *addr, void *mem, off_t off, int prot);
! 136:
! 137: /* Supporting subroutines */
! 138: u_int16_t esa_read_assp(struct esa_softc *, u_int16_t, u_int16_t);
! 139: void esa_write_assp(struct esa_softc *, u_int16_t, u_int16_t,
! 140: u_int16_t);
! 141: int esa_init_codec(struct esa_softc *);
! 142: int esa_attach_codec(void *, struct ac97_codec_if *);
! 143: int esa_read_codec(void *, u_int8_t, u_int16_t *);
! 144: int esa_write_codec(void *, u_int8_t, u_int16_t);
! 145: void esa_reset_codec(void *);
! 146: enum ac97_host_flags esa_flags_codec(void *);
! 147: int esa_wait(struct esa_softc *);
! 148: int esa_init(struct esa_softc *);
! 149: void esa_config(struct esa_softc *);
! 150: u_int8_t esa_assp_halt(struct esa_softc *);
! 151: void esa_codec_reset(struct esa_softc *);
! 152: int esa_amp_enable(struct esa_softc *);
! 153: void esa_enable_interrupts(struct esa_softc *);
! 154: u_int32_t esa_get_pointer(struct esa_softc *, struct esa_channel *);
! 155:
! 156: /* list management */
! 157: int esa_add_list(struct esa_voice *, struct esa_list *, u_int16_t,
! 158: int);
! 159: void esa_remove_list(struct esa_voice *, struct esa_list *, int);
! 160:
! 161: /* power management */
! 162: int esa_power(struct esa_softc *, int);
! 163: void esa_powerhook(int, void *);
! 164: int esa_suspend(struct esa_softc *);
! 165: int esa_resume(struct esa_softc *);
! 166:
! 167: static audio_encoding_t esa_encoding[] = {
! 168: { 0, AudioEulinear, AUDIO_ENCODING_ULINEAR, 8, 0 },
! 169: { 1, AudioEmulaw, AUDIO_ENCODING_ULAW, 8,
! 170: AUDIO_ENCODINGFLAG_EMULATED },
! 171: { 2, AudioEalaw, AUDIO_ENCODING_ALAW, 8, AUDIO_ENCODINGFLAG_EMULATED },
! 172: { 3, AudioEslinear, AUDIO_ENCODING_SLINEAR, 8,
! 173: AUDIO_ENCODINGFLAG_EMULATED }, /* XXX: Are you sure? */
! 174: { 4, AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE, 16, 0 },
! 175: { 5, AudioEulinear_le, AUDIO_ENCODING_ULINEAR_LE, 16,
! 176: AUDIO_ENCODINGFLAG_EMULATED },
! 177: { 6, AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE, 16,
! 178: AUDIO_ENCODINGFLAG_EMULATED },
! 179: { 7, AudioEulinear_be, AUDIO_ENCODING_ULINEAR_BE, 16,
! 180: AUDIO_ENCODINGFLAG_EMULATED }
! 181: };
! 182:
! 183: #define ESA_NENCODINGS 8
! 184:
! 185: struct audio_hw_if esa_hw_if = {
! 186: esa_open,
! 187: esa_close,
! 188: NULL, /* drain */
! 189: esa_query_encoding,
! 190: esa_set_params,
! 191: esa_round_blocksize,
! 192: esa_commit_settings,
! 193: NULL, /* init_output */
! 194: NULL, /* init_input */
! 195: NULL, /* start_output */
! 196: NULL, /* start_input */
! 197: esa_halt_output,
! 198: esa_halt_input,
! 199: NULL, /* speaker_ctl */
! 200: esa_getdev,
! 201: NULL, /* getfd */
! 202: esa_set_port,
! 203: esa_get_port,
! 204: esa_query_devinfo,
! 205: esa_malloc,
! 206: esa_free,
! 207: esa_round_buffersize,
! 208: esa_mappage,
! 209: esa_get_props,
! 210: esa_trigger_output,
! 211: esa_trigger_input
! 212: };
! 213:
! 214: struct cfdriver esa_cd = {
! 215: NULL, "esa", DV_DULL
! 216: };
! 217:
! 218: struct cfattach esa_ca = {
! 219: sizeof(struct esa_softc), esa_match, esa_attach,
! 220: esa_detach, /*esa_activate*/ NULL
! 221: };
! 222:
! 223: /*
! 224: * audio(9) functions
! 225: */
! 226:
! 227: int
! 228: esa_open(void *hdl, int flags)
! 229: {
! 230:
! 231: return (0);
! 232: }
! 233:
! 234: void
! 235: esa_close(void *hdl)
! 236: {
! 237:
! 238: return;
! 239: }
! 240:
! 241: int
! 242: esa_query_encoding(void *hdl, struct audio_encoding *ae)
! 243: {
! 244:
! 245: if (ae->index < 0 || ae->index >= ESA_NENCODINGS)
! 246: return (EINVAL);
! 247: *ae = esa_encoding[ae->index];
! 248:
! 249: return (0);
! 250: }
! 251:
! 252: int
! 253: esa_set_params(void *hdl, int setmode, int usemode, struct audio_params *play,
! 254: struct audio_params *rec)
! 255: {
! 256: struct esa_voice *vc = hdl;
! 257: //struct esa_softc *sc = (struct esa_softc *)vc->parent;
! 258: struct esa_channel *ch;
! 259: struct audio_params *p;
! 260: int mode;
! 261:
! 262: for (mode = AUMODE_RECORD; mode != -1;
! 263: mode = (mode == AUMODE_RECORD) ? AUMODE_PLAY : -1) {
! 264: if ((setmode & mode) == 0)
! 265: continue;
! 266:
! 267: switch (mode) {
! 268: case AUMODE_PLAY:
! 269: p = play;
! 270: ch = &vc->play;
! 271: break;
! 272: case AUMODE_RECORD:
! 273: p = rec;
! 274: ch = &vc->rec;
! 275: break;
! 276: }
! 277:
! 278: if (p->sample_rate < ESA_MINRATE ||
! 279: p->sample_rate > ESA_MAXRATE ||
! 280: (p->precision != 8 && p->precision != 16) ||
! 281: (p->channels < 1 || p->channels > 2))
! 282: return (EINVAL);
! 283:
! 284: p->factor = 1;
! 285: p->sw_code = 0;
! 286:
! 287: switch(p->encoding) {
! 288: case AUDIO_ENCODING_SLINEAR_BE:
! 289: if (p->precision == 16)
! 290: p->sw_code = swap_bytes;
! 291: else
! 292: p->sw_code = change_sign8;
! 293: break;
! 294: case AUDIO_ENCODING_SLINEAR_LE:
! 295: if (p->precision != 16)
! 296: p->sw_code = change_sign8;
! 297: break;
! 298: case AUDIO_ENCODING_ULINEAR_BE:
! 299: if (p->precision == 16) {
! 300: if (mode == AUMODE_PLAY)
! 301: p->sw_code =
! 302: swap_bytes_change_sign16_le;
! 303: else
! 304: p->sw_code =
! 305: change_sign16_swap_bytes_le;
! 306: }
! 307: break;
! 308: case AUDIO_ENCODING_ULINEAR_LE:
! 309: if (p->precision == 16)
! 310: p->sw_code = change_sign16_le;
! 311: break;
! 312: case AUDIO_ENCODING_ULAW:
! 313: if (mode == AUMODE_PLAY) {
! 314: p->factor = 2;
! 315: p->sw_code = mulaw_to_slinear16_le;
! 316: } else
! 317: p->sw_code = ulinear8_to_mulaw;
! 318: break;
! 319: case AUDIO_ENCODING_ALAW:
! 320: if (mode == AUMODE_PLAY) {
! 321: p->factor = 2;
! 322: p->sw_code = alaw_to_slinear16_le;
! 323: } else
! 324: p->sw_code = ulinear8_to_alaw;
! 325: break;
! 326: default:
! 327: return (EINVAL);
! 328: }
! 329:
! 330: ch->mode = *p;
! 331: }
! 332:
! 333: return (0);
! 334: }
! 335:
! 336: int
! 337: esa_commit_settings(void *hdl)
! 338: {
! 339: struct esa_voice *vc = hdl;
! 340: struct esa_softc *sc = (struct esa_softc *)vc->parent;
! 341: struct audio_params *p = &vc->play.mode;
! 342: struct audio_params *r = &vc->rec.mode;
! 343: u_int32_t data;
! 344: u_int32_t freq;
! 345: int data_bytes = (((ESA_MINISRC_TMP_BUFFER_SIZE & ~1) +
! 346: (ESA_MINISRC_IN_BUFFER_SIZE & ~1) +
! 347: (ESA_MINISRC_OUT_BUFFER_SIZE & ~1) + 4) + 255)
! 348: &~ 255;
! 349:
! 350: /* playback */
! 351: vc->play.data_offset = ESA_DAC_DATA + (data_bytes * vc->index);
! 352: if (p->channels == 1)
! 353: data = 1;
! 354: else
! 355: data = 0;
! 356: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
! 357: vc->play.data_offset + ESA_SRC3_MODE_OFFSET,
! 358: data);
! 359: if (p->precision * p->factor == 8)
! 360: data = 1;
! 361: else
! 362: data = 0;
! 363: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
! 364: vc->play.data_offset + ESA_SRC3_WORD_LENGTH_OFFSET,
! 365: data);
! 366: if ((freq = ((p->sample_rate << 15) + 24000) / 48000) != 0) {
! 367: freq--;
! 368: }
! 369: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
! 370: vc->play.data_offset + ESA_CDATA_FREQUENCY, freq);
! 371:
! 372: /* recording */
! 373: vc->rec.data_offset = ESA_DAC_DATA + (data_bytes * vc->index) +
! 374: (data_bytes / 2);
! 375: if (r->channels == 1)
! 376: data = 1;
! 377: else
! 378: data = 0;
! 379: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
! 380: vc->rec.data_offset + ESA_SRC3_MODE_OFFSET,
! 381: data);
! 382: if (r->precision * r->factor == 8)
! 383: data = 1;
! 384: else
! 385: data = 0;
! 386: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
! 387: vc->rec.data_offset + ESA_SRC3_WORD_LENGTH_OFFSET,
! 388: data);
! 389: if ((freq = ((r->sample_rate << 15) + 24000) / 48000) != 0) {
! 390: freq--;
! 391: }
! 392: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
! 393: vc->rec.data_offset + ESA_CDATA_FREQUENCY, freq);
! 394:
! 395: return (0);
! 396: };
! 397:
! 398: int
! 399: esa_round_blocksize(void *hdl, int bs)
! 400: {
! 401: struct esa_voice *vc = hdl;
! 402:
! 403: /*
! 404: * Surely there has to be a better solution...
! 405: */
! 406: vc->play.blksize = vc->rec.blksize = 4096;
! 407:
! 408: return (vc->play.blksize);
! 409: }
! 410:
! 411: int
! 412: esa_halt_output(void *hdl)
! 413: {
! 414: struct esa_voice *vc = hdl;
! 415: struct esa_softc *sc = (struct esa_softc *)vc->parent;
! 416: bus_space_tag_t iot = sc->sc_iot;
! 417: bus_space_handle_t ioh = sc->sc_ioh;
! 418: u_int16_t data;
! 419:
! 420: if (vc->play.active == 0)
! 421: return (0);
! 422:
! 423: vc->play.active = 0;
! 424:
! 425: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
! 426: ESA_CDATA_INSTANCE_READY + vc->play.data_offset, 0);
! 427:
! 428: sc->sc_ntimers--;
! 429: if (sc->sc_ntimers == 0) {
! 430: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
! 431: ESA_KDATA_TIMER_COUNT_RELOAD, 0);
! 432: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
! 433: ESA_KDATA_TIMER_COUNT_CURRENT, 0);
! 434: data = bus_space_read_2(iot, ioh, ESA_HOST_INT_CTRL);
! 435: bus_space_write_2(iot, ioh, ESA_HOST_INT_CTRL,
! 436: data & ~ESA_CLKRUN_GEN_ENABLE);
! 437: }
! 438:
! 439: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
! 440: ESA_KDATA_MIXER_TASK_NUMBER,
! 441: sc->mixer_list.indexmap[vc->index]);
! 442: /* remove ourselves from the packed lists */
! 443: esa_remove_list(vc, &sc->mixer_list, vc->index);
! 444: esa_remove_list(vc, &sc->dma_list, vc->index);
! 445: esa_remove_list(vc, &sc->msrc_list, vc->index);
! 446:
! 447: return (0);
! 448: }
! 449:
! 450: int
! 451: esa_halt_input(void *hdl)
! 452: {
! 453: struct esa_voice *vc = hdl;
! 454: struct esa_softc *sc = (struct esa_softc *)vc->parent;
! 455: bus_space_tag_t iot = sc->sc_iot;
! 456: bus_space_handle_t ioh = sc->sc_ioh;
! 457: u_int32_t data;
! 458:
! 459: if (vc->rec.active == 0)
! 460: return (0);
! 461:
! 462: vc->rec.active = 0;
! 463:
! 464: sc->sc_ntimers--;
! 465: if (sc->sc_ntimers == 0) {
! 466: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
! 467: ESA_KDATA_TIMER_COUNT_RELOAD, 0);
! 468: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
! 469: ESA_KDATA_TIMER_COUNT_CURRENT, 0);
! 470: data = bus_space_read_2(iot, ioh, ESA_HOST_INT_CTRL);
! 471: bus_space_write_2(iot, ioh, ESA_HOST_INT_CTRL,
! 472: data & ~ESA_CLKRUN_GEN_ENABLE);
! 473: }
! 474:
! 475: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, vc->rec.data_offset +
! 476: ESA_CDATA_INSTANCE_READY, 0);
! 477: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, ESA_KDATA_ADC1_REQUEST,
! 478: 0);
! 479:
! 480: /* remove ourselves from the packed lists */
! 481: esa_remove_list(vc, &sc->adc1_list, vc->index + ESA_NUM_VOICES);
! 482: esa_remove_list(vc, &sc->dma_list, vc->index + ESA_NUM_VOICES);
! 483: esa_remove_list(vc, &sc->msrc_list, vc->index + ESA_NUM_VOICES);
! 484:
! 485: return (0);
! 486: }
! 487:
! 488: void *
! 489: esa_malloc(void *hdl, int direction, size_t size, int type, int flags)
! 490: {
! 491: struct esa_voice *vc = hdl;
! 492: struct esa_softc *sc = (struct esa_softc *)vc->parent;
! 493: struct esa_dma *p;
! 494: int error;
! 495:
! 496: p = malloc(sizeof(*p), type, flags);
! 497: if (!p)
! 498: return (0);
! 499: error = esa_allocmem(sc, size, 16, p);
! 500: if (error) {
! 501: free(p, type);
! 502: printf("%s: esa_malloc: not enough memory\n",
! 503: sc->sc_dev.dv_xname);
! 504: return (0);
! 505: }
! 506: p->next = vc->dma;
! 507: vc->dma = p;
! 508:
! 509: return (KERNADDR(p));
! 510: }
! 511:
! 512: void
! 513: esa_free(void *hdl, void *addr, int type)
! 514: {
! 515: struct esa_voice *vc = hdl;
! 516: struct esa_softc *sc = (struct esa_softc *)vc->parent;
! 517: struct esa_dma *p;
! 518: struct esa_dma **pp;
! 519:
! 520: for (pp = &vc->dma; (p = *pp) != NULL; pp = &p->next)
! 521: if (KERNADDR(p) == addr) {
! 522: esa_freemem(sc, p);
! 523: *pp = p->next;
! 524: free(p, type);
! 525: return;
! 526: }
! 527: }
! 528:
! 529: int
! 530: esa_getdev(void *hdl, struct audio_device *ret)
! 531: {
! 532:
! 533: *ret = esa_device;
! 534:
! 535: return (0);
! 536: }
! 537:
! 538: int
! 539: esa_set_port(void *hdl, mixer_ctrl_t *mc)
! 540: {
! 541: struct esa_voice *vc = hdl;
! 542: struct esa_softc *sc = (struct esa_softc *)vc->parent;
! 543:
! 544: return (sc->codec_if->vtbl->mixer_set_port(sc->codec_if, mc));
! 545: }
! 546:
! 547: int
! 548: esa_get_port(void *hdl, mixer_ctrl_t *mc)
! 549: {
! 550: struct esa_voice *vc = hdl;
! 551: struct esa_softc *sc = (struct esa_softc *)vc->parent;
! 552:
! 553: return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, mc));
! 554: }
! 555:
! 556: int
! 557: esa_query_devinfo(void *hdl, mixer_devinfo_t *di)
! 558: {
! 559: struct esa_voice *vc = hdl;
! 560: struct esa_softc *sc = (struct esa_softc *)vc->parent;
! 561:
! 562: return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, di));
! 563: }
! 564:
! 565: size_t
! 566: esa_round_buffersize(void *hdl, int direction, size_t bufsize)
! 567: {
! 568: struct esa_voice *vc = hdl;
! 569:
! 570: /*
! 571: * We must be able to do better than this...
! 572: */
! 573: vc->play.bufsize = vc->rec.bufsize = 65536;
! 574:
! 575: return (vc->play.bufsize);
! 576: }
! 577:
! 578: int
! 579: esa_get_props(void *hdl)
! 580: {
! 581:
! 582: return (AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX);
! 583: }
! 584:
! 585: int
! 586: esa_trigger_output(void *hdl, void *start, void *end, int blksize,
! 587: void (*intr)(void *), void *intrarg,
! 588: struct audio_params *param)
! 589: {
! 590: struct esa_voice *vc = hdl;
! 591: struct esa_softc *sc = (struct esa_softc *)vc->parent;
! 592: struct esa_dma *p;
! 593: bus_space_tag_t iot = sc->sc_iot;
! 594: bus_space_handle_t ioh = sc->sc_ioh;
! 595: u_int32_t data;
! 596: u_int32_t bufaddr;
! 597: u_int32_t i;
! 598: size_t size;
! 599:
! 600: int data_bytes = (((ESA_MINISRC_TMP_BUFFER_SIZE & ~1) +
! 601: (ESA_MINISRC_IN_BUFFER_SIZE & ~1) +
! 602: (ESA_MINISRC_OUT_BUFFER_SIZE & ~1) + 4) + 255)
! 603: &~ 255;
! 604: int dac_data = ESA_DAC_DATA + (data_bytes * vc->index);
! 605: int dsp_in_size = ESA_MINISRC_IN_BUFFER_SIZE - (0x20 * 2);
! 606: int dsp_out_size = ESA_MINISRC_OUT_BUFFER_SIZE - (0x20 * 2);
! 607: int dsp_in_buf = dac_data + (ESA_MINISRC_TMP_BUFFER_SIZE / 2);
! 608: int dsp_out_buf = dsp_in_buf + (dsp_in_size / 2) + 1;
! 609:
! 610: if (vc->play.active)
! 611: return (EINVAL);
! 612:
! 613: for (p = vc->dma; p && KERNADDR(p) != start; p = p->next)
! 614: ;
! 615: if (!p) {
! 616: printf("%s: esa_trigger_output: bad addr %p\n",
! 617: sc->sc_dev.dv_xname, start);
! 618: return (EINVAL);
! 619: }
! 620:
! 621: vc->play.active = 1;
! 622: vc->play.intr = intr;
! 623: vc->play.arg = intrarg;
! 624: vc->play.pos = 0;
! 625: vc->play.count = 0;
! 626: vc->play.buf = start;
! 627: size = (size_t)(((caddr_t)end - (caddr_t)start));
! 628: bufaddr = DMAADDR(p);
! 629: vc->play.start = bufaddr;
! 630:
! 631: #define LO(x) ((x) & 0x0000ffff)
! 632: #define HI(x) ((x) >> 16)
! 633:
! 634: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, dac_data +
! 635: ESA_CDATA_HOST_SRC_ADDRL, LO(bufaddr));
! 636: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, dac_data +
! 637: ESA_CDATA_HOST_SRC_ADDRH, HI(bufaddr));
! 638: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, dac_data +
! 639: ESA_CDATA_HOST_SRC_END_PLUS_1L, LO(bufaddr + size));
! 640: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, dac_data +
! 641: ESA_CDATA_HOST_SRC_END_PLUS_1H, HI(bufaddr + size));
! 642: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, dac_data +
! 643: ESA_CDATA_HOST_SRC_CURRENTL, LO(bufaddr));
! 644: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, dac_data +
! 645: ESA_CDATA_HOST_SRC_CURRENTH, HI(bufaddr));
! 646:
! 647: /* DSP buffers */
! 648: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, dac_data +
! 649: ESA_CDATA_IN_BUF_BEGIN, dsp_in_buf);
! 650: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, dac_data +
! 651: ESA_CDATA_IN_BUF_END_PLUS_1, dsp_in_buf + (dsp_in_size / 2));
! 652: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, dac_data +
! 653: ESA_CDATA_IN_BUF_HEAD, dsp_in_buf);
! 654: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, dac_data +
! 655: ESA_CDATA_IN_BUF_TAIL, dsp_in_buf);
! 656: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, dac_data +
! 657: ESA_CDATA_OUT_BUF_BEGIN, dsp_out_buf);
! 658: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, dac_data +
! 659: ESA_CDATA_OUT_BUF_END_PLUS_1, dsp_out_buf + (dsp_out_size / 2));
! 660: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, dac_data +
! 661: ESA_CDATA_OUT_BUF_HEAD, dsp_out_buf);
! 662: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, dac_data +
! 663: ESA_CDATA_OUT_BUF_TAIL, dsp_out_buf);
! 664:
! 665: /* Some per-client initializers */
! 666: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, dac_data +
! 667: ESA_SRC3_DIRECTION_OFFSET + 12, dac_data + 40 + 8);
! 668: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, dac_data +
! 669: ESA_SRC3_DIRECTION_OFFSET + 19, 0x400 + ESA_MINISRC_COEF_LOC);
! 670: /* Enable or disable low-pass filter? (0xff if rate > 45000) */
! 671: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, dac_data +
! 672: ESA_SRC3_DIRECTION_OFFSET + 22,
! 673: vc->play.mode.sample_rate > 45000 ? 0xff : 0);
! 674: /* Tell it which way DMA is going */
! 675: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, dac_data +
! 676: ESA_CDATA_DMA_CONTROL,
! 677: ESA_DMACONTROL_AUTOREPEAT + ESA_DMAC_PAGE3_SELECTOR +
! 678: ESA_DMAC_BLOCKF_SELECTOR);
! 679:
! 680: /* Set an armload of static initializers */
! 681: for (i = 0; i < (sizeof(esa_playvals) / sizeof(esa_playvals[0])); i++)
! 682: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, dac_data +
! 683: esa_playvals[i].addr, esa_playvals[i].val);
! 684:
! 685: /* Put us in the packed task lists */
! 686: esa_add_list(vc, &sc->msrc_list, dac_data >> ESA_DP_SHIFT_COUNT,
! 687: vc->index);
! 688: esa_add_list(vc, &sc->dma_list, dac_data >> ESA_DP_SHIFT_COUNT,
! 689: vc->index);
! 690: esa_add_list(vc, &sc->mixer_list, dac_data >> ESA_DP_SHIFT_COUNT,
! 691: vc->index);
! 692: #undef LO
! 693: #undef HI
! 694:
! 695: /* XXX */
! 696: //esa_commit_settings(vc);
! 697:
! 698: sc->sc_ntimers++;
! 699:
! 700: if (sc->sc_ntimers == 1) {
! 701: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
! 702: ESA_KDATA_TIMER_COUNT_RELOAD, 240);
! 703: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
! 704: ESA_KDATA_TIMER_COUNT_CURRENT, 240);
! 705: data = bus_space_read_2(iot, ioh, ESA_HOST_INT_CTRL);
! 706: bus_space_write_2(iot, ioh, ESA_HOST_INT_CTRL,
! 707: data | ESA_CLKRUN_GEN_ENABLE);
! 708: }
! 709:
! 710: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, dac_data +
! 711: ESA_CDATA_INSTANCE_READY, 1);
! 712: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
! 713: ESA_KDATA_MIXER_TASK_NUMBER,
! 714: sc->mixer_list.indexmap[vc->index]);
! 715:
! 716: return (0);
! 717: }
! 718:
! 719: int
! 720: esa_trigger_input(void *hdl, void *start, void *end, int blksize,
! 721: void (*intr)(void *), void *intrarg,
! 722: struct audio_params *param)
! 723: {
! 724: struct esa_voice *vc = hdl;
! 725: struct esa_softc *sc = (struct esa_softc *)vc->parent;
! 726: struct esa_dma *p;
! 727: bus_space_tag_t iot = sc->sc_iot;
! 728: bus_space_handle_t ioh = sc->sc_ioh;
! 729: u_int32_t data;
! 730: u_int32_t bufaddr;
! 731: u_int32_t i;
! 732: size_t size;
! 733: int data_bytes = (((ESA_MINISRC_TMP_BUFFER_SIZE & ~1) +
! 734: (ESA_MINISRC_IN_BUFFER_SIZE & ~1) +
! 735: (ESA_MINISRC_OUT_BUFFER_SIZE & ~1) + 4) + 255)
! 736: &~ 255;
! 737: int adc_data = ESA_DAC_DATA + (data_bytes * vc->index) +
! 738: (data_bytes / 2);
! 739: int dsp_in_size = ESA_MINISRC_IN_BUFFER_SIZE - (0x10 * 2);
! 740: int dsp_out_size = ESA_MINISRC_OUT_BUFFER_SIZE - (0x10 * 2);
! 741: int dsp_in_buf = adc_data + (ESA_MINISRC_TMP_BUFFER_SIZE / 2);
! 742: int dsp_out_buf = dsp_in_buf + (dsp_in_size / 2) + 1;
! 743: vc->rec.data_offset = adc_data;
! 744:
! 745: /* We only support 1 recording channel */
! 746: if (vc->index > 0)
! 747: return (ENODEV);
! 748:
! 749: if (vc->rec.active)
! 750: return (EINVAL);
! 751:
! 752: for (p = vc->dma; p && KERNADDR(p) != start; p = p->next)
! 753: ;
! 754: if (!p) {
! 755: printf("%s: esa_trigger_input: bad addr %p\n",
! 756: sc->sc_dev.dv_xname, start);
! 757: return (EINVAL);
! 758: }
! 759:
! 760: vc->rec.active = 1;
! 761: vc->rec.intr = intr;
! 762: vc->rec.arg = intrarg;
! 763: vc->rec.pos = 0;
! 764: vc->rec.count = 0;
! 765: vc->rec.buf = start;
! 766: size = (size_t)(((caddr_t)end - (caddr_t)start));
! 767: bufaddr = DMAADDR(p);
! 768: vc->rec.start = bufaddr;
! 769:
! 770: #define LO(x) ((x) & 0x0000ffff)
! 771: #define HI(x) ((x) >> 16)
! 772:
! 773: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, adc_data +
! 774: ESA_CDATA_HOST_SRC_ADDRL, LO(bufaddr));
! 775: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, adc_data +
! 776: ESA_CDATA_HOST_SRC_ADDRH, HI(bufaddr));
! 777: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, adc_data +
! 778: ESA_CDATA_HOST_SRC_END_PLUS_1L, LO(bufaddr + size));
! 779: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, adc_data +
! 780: ESA_CDATA_HOST_SRC_END_PLUS_1H, HI(bufaddr + size));
! 781: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, adc_data +
! 782: ESA_CDATA_HOST_SRC_CURRENTL, LO(bufaddr));
! 783: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, adc_data +
! 784: ESA_CDATA_HOST_SRC_CURRENTH, HI(bufaddr));
! 785:
! 786: /* DSP buffers */
! 787: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, adc_data +
! 788: ESA_CDATA_IN_BUF_BEGIN, dsp_in_buf);
! 789: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, adc_data +
! 790: ESA_CDATA_IN_BUF_END_PLUS_1, dsp_in_buf + (dsp_in_size / 2));
! 791: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, adc_data +
! 792: ESA_CDATA_IN_BUF_HEAD, dsp_in_buf);
! 793: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, adc_data +
! 794: ESA_CDATA_IN_BUF_TAIL, dsp_in_buf);
! 795: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, adc_data +
! 796: ESA_CDATA_OUT_BUF_BEGIN, dsp_out_buf);
! 797: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, adc_data +
! 798: ESA_CDATA_OUT_BUF_END_PLUS_1, dsp_out_buf + (dsp_out_size / 2));
! 799: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, adc_data +
! 800: ESA_CDATA_OUT_BUF_HEAD, dsp_out_buf);
! 801: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, adc_data +
! 802: ESA_CDATA_OUT_BUF_TAIL, dsp_out_buf);
! 803:
! 804: /* Some per-client initializers */
! 805: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, adc_data +
! 806: ESA_SRC3_DIRECTION_OFFSET + 12, adc_data + 40 + 8);
! 807: /* Tell it which way DMA is going */
! 808: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, adc_data +
! 809: ESA_CDATA_DMA_CONTROL,
! 810: ESA_DMACONTROL_DIRECTION + ESA_DMACONTROL_AUTOREPEAT +
! 811: ESA_DMAC_PAGE3_SELECTOR + ESA_DMAC_BLOCKF_SELECTOR);
! 812:
! 813: /* Set an armload of static initializers */
! 814: for (i = 0; i < (sizeof(esa_recvals) / sizeof(esa_recvals[0])); i++)
! 815: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, adc_data +
! 816: esa_recvals[i].addr, esa_recvals[i].val);
! 817:
! 818: /* Put us in the packed task lists */
! 819: esa_add_list(vc, &sc->adc1_list, adc_data >> ESA_DP_SHIFT_COUNT,
! 820: vc->index + ESA_NUM_VOICES);
! 821: esa_add_list(vc, &sc->msrc_list, adc_data >> ESA_DP_SHIFT_COUNT,
! 822: vc->index + ESA_NUM_VOICES);
! 823: esa_add_list(vc, &sc->dma_list, adc_data >> ESA_DP_SHIFT_COUNT,
! 824: vc->index + ESA_NUM_VOICES);
! 825: #undef LO
! 826: #undef HI
! 827:
! 828: /* XXX */
! 829: //esa_commit_settings(vc);
! 830:
! 831: sc->sc_ntimers++;
! 832: if (sc->sc_ntimers == 1) {
! 833: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
! 834: ESA_KDATA_TIMER_COUNT_RELOAD, 240);
! 835: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
! 836: ESA_KDATA_TIMER_COUNT_CURRENT, 240);
! 837: data = bus_space_read_2(iot, ioh, ESA_HOST_INT_CTRL);
! 838: bus_space_write_2(iot, ioh, ESA_HOST_INT_CTRL,
! 839: data | ESA_CLKRUN_GEN_ENABLE);
! 840: }
! 841:
! 842: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, adc_data +
! 843: ESA_CDATA_INSTANCE_READY, 1);
! 844: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, ESA_KDATA_ADC1_REQUEST,
! 845: 1);
! 846:
! 847: return (0);
! 848: }
! 849:
! 850: /* Interrupt handler */
! 851:
! 852: int
! 853: esa_intr(void *hdl)
! 854: {
! 855: struct esa_softc *sc = hdl;
! 856: struct esa_voice *vc;
! 857: bus_space_tag_t iot = sc->sc_iot;
! 858: bus_space_handle_t ioh = sc->sc_ioh;
! 859: u_int8_t status, ctl;
! 860: u_int32_t pos;
! 861: u_int32_t diff;
! 862: u_int32_t play_blksize, play_bufsize;
! 863: u_int32_t rec_blksize, rec_bufsize;
! 864: int i;
! 865:
! 866: status = bus_space_read_1(iot, ioh, ESA_HOST_INT_STATUS);
! 867: if (status == 0xff)
! 868: return (0);
! 869:
! 870: /* ack the interrupt */
! 871: bus_space_write_1(iot, ioh, ESA_HOST_INT_STATUS, status);
! 872:
! 873: if (status & ESA_HV_INT_PENDING) {
! 874: u_int8_t event;
! 875:
! 876: printf("%s: hardware volume interrupt\n", sc->sc_dev.dv_xname);
! 877: event = bus_space_read_1(iot, ioh, ESA_HW_VOL_COUNTER_MASTER);
! 878: switch(event) {
! 879: case 0x99:
! 880: case 0xaa:
! 881: case 0x66:
! 882: case 0x88:
! 883: printf("%s: esa_intr: FIXME\n", sc->sc_dev.dv_xname);
! 884: break;
! 885: default:
! 886: printf("%s: unknown hwvol event 0x%02x\n",
! 887: sc->sc_dev.dv_xname, event);
! 888: break;
! 889: }
! 890: bus_space_write_1(iot, ioh, ESA_HW_VOL_COUNTER_MASTER, 0x88);
! 891: }
! 892:
! 893: if (status & ESA_ASSP_INT_PENDING) {
! 894: ctl = bus_space_read_1(iot, ioh, ESA_ASSP_CONTROL_B);
! 895: if (!(ctl & ESA_STOP_ASSP_CLOCK)) {
! 896: ctl = bus_space_read_1(iot, ioh,
! 897: ESA_ASSP_HOST_INT_STATUS);
! 898: if (ctl & ESA_DSP2HOST_REQ_TIMER) {
! 899: bus_space_write_1(iot, ioh,
! 900: ESA_ASSP_HOST_INT_STATUS,
! 901: ESA_DSP2HOST_REQ_TIMER);
! 902: for (i = 0; i < ESA_NUM_VOICES; i++) {
! 903: vc = &sc->voice[i];
! 904: if (vc->play.active) {
! 905: play_blksize = vc->play.blksize;
! 906: play_bufsize = vc->play.bufsize;
! 907: pos = esa_get_pointer(sc, &vc->play)
! 908: % play_bufsize;
! 909: diff = (play_bufsize + pos - vc->play.pos)
! 910: % play_bufsize;
! 911: vc->play.pos = pos;
! 912: vc->play.count += diff;
! 913: while(vc->play.count >= play_blksize) {
! 914: vc->play.count -= play_blksize;
! 915: (*vc->play.intr)(vc->play.arg);
! 916: }
! 917: }
! 918: if (vc->rec.active) {
! 919: rec_blksize = vc->rec.blksize;
! 920: rec_bufsize = vc->rec.bufsize;
! 921: pos = esa_get_pointer(sc, &vc->rec)
! 922: % rec_bufsize;
! 923: diff = (rec_bufsize + pos - vc->rec.pos)
! 924: % rec_bufsize;
! 925: vc->rec.pos = pos;
! 926: vc->rec.count += diff;
! 927: while(vc->rec.count >= rec_blksize) {
! 928: vc->rec.count -= rec_blksize;
! 929: (*vc->rec.intr)(vc->rec.arg);
! 930: }
! 931: }
! 932: }
! 933: }
! 934: }
! 935: }
! 936:
! 937: return (1);
! 938: }
! 939:
! 940: int
! 941: esa_allocmem(struct esa_softc *sc, size_t size, size_t align,
! 942: struct esa_dma *p)
! 943: {
! 944: int error;
! 945:
! 946: p->size = size;
! 947: error = bus_dmamem_alloc(sc->sc_dmat, p->size, align, 0,
! 948: p->segs, sizeof(p->segs) / sizeof(p->segs[0]),
! 949: &p->nsegs, BUS_DMA_NOWAIT);
! 950: if (error)
! 951: return (error);
! 952:
! 953: error = bus_dmamem_map(sc->sc_dmat, p->segs, p->nsegs, p->size,
! 954: &p->addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
! 955: if (error)
! 956: goto free;
! 957:
! 958: error = bus_dmamap_create(sc->sc_dmat, p->size, 1, p->size, 0,
! 959: BUS_DMA_NOWAIT, &p->map);
! 960: if (error)
! 961: goto unmap;
! 962:
! 963: error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, p->size, NULL,
! 964: BUS_DMA_NOWAIT);
! 965: if (error)
! 966: goto destroy;
! 967:
! 968: return (0);
! 969:
! 970: destroy:
! 971: bus_dmamap_destroy(sc->sc_dmat, p->map);
! 972: unmap:
! 973: bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size);
! 974: free:
! 975: bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs);
! 976:
! 977: return (error);
! 978: }
! 979:
! 980: int
! 981: esa_freemem(struct esa_softc *sc, struct esa_dma *p)
! 982: {
! 983:
! 984: bus_dmamap_unload(sc->sc_dmat, p->map);
! 985: bus_dmamap_destroy(sc->sc_dmat, p->map);
! 986: bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size);
! 987: bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs);
! 988:
! 989: return (0);
! 990: }
! 991:
! 992: /*
! 993: * Supporting Subroutines
! 994: */
! 995: const struct pci_matchid esa_devices[] = {
! 996: { PCI_VENDOR_ESSTECH, PCI_PRODUCT_ESSTECH_ES1989 },
! 997: { PCI_VENDOR_ESSTECH, PCI_PRODUCT_ESSTECH_MAESTRO3 },
! 998: { PCI_VENDOR_ESSTECH, PCI_PRODUCT_ESSTECH_MAESTRO3_2 },
! 999: };
! 1000:
! 1001: int
! 1002: esa_match(struct device *dev, void *match, void *aux)
! 1003: {
! 1004: return (pci_matchbyid((struct pci_attach_args *)aux, esa_devices,
! 1005: sizeof(esa_devices)/sizeof(esa_devices[0])));
! 1006: }
! 1007:
! 1008: void
! 1009: esa_attach(struct device *parent, struct device *self, void *aux)
! 1010: {
! 1011: struct esa_softc *sc = (struct esa_softc *)self;
! 1012: struct pci_attach_args *pa = (struct pci_attach_args *)aux;
! 1013: pcitag_t tag = pa->pa_tag;
! 1014: pci_chipset_tag_t pc = pa->pa_pc;
! 1015: pci_intr_handle_t ih;
! 1016: struct esa_card_type *card;
! 1017: const char *intrstr;
! 1018: int i, len;
! 1019:
! 1020: for (card = esa_card_types; card->pci_vendor_id; card++)
! 1021: if (PCI_VENDOR(pa->pa_id) == card->pci_vendor_id &&
! 1022: PCI_PRODUCT(pa->pa_id) == card->pci_product_id) {
! 1023: sc->type = card->type;
! 1024: sc->delay1 = card->delay1;
! 1025: sc->delay2 = card->delay2;
! 1026: break;
! 1027: }
! 1028:
! 1029: /* Map I/O register */
! 1030: if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0,
! 1031: &sc->sc_iot, &sc->sc_ioh, &sc->sc_iob, &sc->sc_ios, 0)) {
! 1032: printf(": can't map i/o space\n");
! 1033: return;
! 1034: }
! 1035:
! 1036: /* Initialize softc */
! 1037: sc->sc_tag = tag;
! 1038: sc->sc_pct = pc;
! 1039: sc->sc_dmat = pa->pa_dmat;
! 1040:
! 1041: /* Map and establish an interrupt */
! 1042: if (pci_intr_map(pa, &ih)) {
! 1043: printf(": can't map interrupt\n");
! 1044: bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
! 1045: return;
! 1046: }
! 1047: intrstr = pci_intr_string(pc, ih);
! 1048: sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, esa_intr, self,
! 1049: sc->sc_dev.dv_xname);
! 1050: if (sc->sc_ih == NULL) {
! 1051: printf(": can't establish interrupt");
! 1052: if (intrstr != NULL)
! 1053: printf(" at %s", intrstr);
! 1054: printf("\n");
! 1055: bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
! 1056: return;
! 1057: }
! 1058: printf(": %s\n", intrstr);
! 1059:
! 1060: /* Power up chip */
! 1061: esa_power(sc, PCI_PMCSR_STATE_D0);
! 1062:
! 1063: /* Init chip */
! 1064: if (esa_init(sc) == -1) {
! 1065: printf("%s: esa_attach: unable to initialize the card\n",
! 1066: sc->sc_dev.dv_xname);
! 1067: pci_intr_disestablish(pc, sc->sc_ih);
! 1068: bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
! 1069: return;
! 1070: }
! 1071:
! 1072: /* create suspend save area */
! 1073: len = sizeof(u_int16_t) * (ESA_REV_B_CODE_MEMORY_LENGTH
! 1074: + ESA_REV_B_DATA_MEMORY_LENGTH + 1);
! 1075: sc->savemem = (u_int16_t *)malloc(len, M_DEVBUF, M_NOWAIT);
! 1076: if (sc->savemem == NULL) {
! 1077: printf("%s: unable to allocate suspend buffer\n",
! 1078: sc->sc_dev.dv_xname);
! 1079: pci_intr_disestablish(pc, sc->sc_ih);
! 1080: bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
! 1081: return;
! 1082: }
! 1083: bzero(sc->savemem, len);
! 1084:
! 1085: /*
! 1086: * Every card I've seen has had their channels swapped with respect
! 1087: * to the mixer. Ie:
! 1088: * $ mixerctl -w outputs.master=0,191
! 1089: * Would result in the _right_ speaker being turned off.
! 1090: *
! 1091: * So, we will swap the left and right mixer channels to compensate
! 1092: * for this.
! 1093: */
! 1094: sc->codec_flags |= AC97_HOST_SWAPPED_CHANNELS;
! 1095: sc->codec_flags |= AC97_HOST_DONT_READ;
! 1096:
! 1097: /* Attach AC97 host interface */
! 1098: sc->host_if.arg = self;
! 1099: sc->host_if.attach = esa_attach_codec;
! 1100: sc->host_if.read = esa_read_codec;
! 1101: sc->host_if.write = esa_write_codec;
! 1102: sc->host_if.reset = esa_reset_codec;
! 1103: sc->host_if.flags = esa_flags_codec;
! 1104:
! 1105: if (ac97_attach(&sc->host_if) != 0) {
! 1106: pci_intr_disestablish(pc, sc->sc_ih);
! 1107: bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
! 1108: free(sc->savemem, M_DEVBUF);
! 1109: return;
! 1110: }
! 1111:
! 1112: /* initialize list management structures */
! 1113: sc->mixer_list.mem_addr = ESA_KDATA_MIXER_XFER0;
! 1114: sc->mixer_list.max = ESA_MAX_VIRTUAL_MIXER_CHANNELS;
! 1115: sc->adc1_list.mem_addr = ESA_KDATA_ADC1_XFER0;
! 1116: sc->adc1_list.max = ESA_MAX_VIRTUAL_ADC1_CHANNELS;
! 1117: sc->dma_list.mem_addr = ESA_KDATA_DMA_XFER0;
! 1118: sc->dma_list.max = ESA_MAX_VIRTUAL_DMA_CHANNELS;
! 1119: sc->msrc_list.mem_addr = ESA_KDATA_INSTANCE0_MINISRC;
! 1120: sc->msrc_list.max = ESA_MAX_INSTANCE_MINISRC;
! 1121:
! 1122: /* initialize index maps */
! 1123: for (i = 0; i < ESA_NUM_VOICES * 2; i++) {
! 1124: sc->mixer_list.indexmap[i] = -1;
! 1125: sc->msrc_list.indexmap[i] = -1;
! 1126: sc->dma_list.indexmap[i] = -1;
! 1127: sc->adc1_list.indexmap[i] = -1;
! 1128: }
! 1129: for (i = 0; i < ESA_NUM_VOICES; i++) {
! 1130: sc->voice[i].parent = (struct device *)sc;
! 1131: sc->voice[i].index = i;
! 1132: sc->sc_audiodev[i] =
! 1133: audio_attach_mi(&esa_hw_if, &sc->voice[i], &sc->sc_dev);
! 1134: }
! 1135:
! 1136: sc->powerhook = powerhook_establish(esa_powerhook, sc);
! 1137: if (sc->powerhook == NULL)
! 1138: printf("%s: WARNING: unable to establish powerhook\n",
! 1139: sc->sc_dev.dv_xname);
! 1140:
! 1141: return;
! 1142: }
! 1143:
! 1144: int
! 1145: esa_detach(struct device *self, int flags)
! 1146: {
! 1147: struct esa_softc *sc = (struct esa_softc *)self;
! 1148: int i;
! 1149:
! 1150: for (i = 0; i < ESA_NUM_VOICES; i++) {
! 1151: if (sc->sc_audiodev[i] != NULL)
! 1152: config_detach(sc->sc_audiodev[i], flags);
! 1153: }
! 1154:
! 1155: if (sc->sc_ih != NULL)
! 1156: pci_intr_disestablish(sc->sc_pct, sc->sc_ih);
! 1157: if (sc->sc_ios)
! 1158: bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
! 1159:
! 1160: free(sc->savemem, M_DEVBUF);
! 1161:
! 1162: return (0);
! 1163: }
! 1164:
! 1165: u_int16_t
! 1166: esa_read_assp(struct esa_softc *sc, u_int16_t region, u_int16_t index)
! 1167: {
! 1168: u_int16_t data;
! 1169: bus_space_tag_t iot = sc->sc_iot;
! 1170: bus_space_handle_t ioh = sc->sc_ioh;
! 1171:
! 1172: bus_space_write_2(iot, ioh, ESA_DSP_PORT_MEMORY_TYPE,
! 1173: region & ESA_MEMTYPE_MASK);
! 1174: bus_space_write_2(iot, ioh, ESA_DSP_PORT_MEMORY_INDEX, index);
! 1175: data = bus_space_read_2(iot, ioh, ESA_DSP_PORT_MEMORY_DATA);
! 1176:
! 1177: return (data);
! 1178: }
! 1179:
! 1180: void
! 1181: esa_write_assp(struct esa_softc *sc, u_int16_t region, u_int16_t index,
! 1182: u_int16_t data)
! 1183: {
! 1184: bus_space_tag_t iot = sc->sc_iot;
! 1185: bus_space_handle_t ioh = sc->sc_ioh;
! 1186:
! 1187: bus_space_write_2(iot, ioh, ESA_DSP_PORT_MEMORY_TYPE,
! 1188: region & ESA_MEMTYPE_MASK);
! 1189: bus_space_write_2(iot, ioh, ESA_DSP_PORT_MEMORY_INDEX, index);
! 1190: bus_space_write_2(iot, ioh, ESA_DSP_PORT_MEMORY_DATA, data);
! 1191:
! 1192: return;
! 1193: }
! 1194:
! 1195: int
! 1196: esa_init_codec(struct esa_softc *sc)
! 1197: {
! 1198: bus_space_tag_t iot = sc->sc_iot;
! 1199: bus_space_handle_t ioh = sc->sc_ioh;
! 1200: u_int32_t data;
! 1201:
! 1202: data = bus_space_read_1(iot, ioh, ESA_CODEC_COMMAND);
! 1203:
! 1204: return ((data & 0x1) ? 0 : 1);
! 1205: }
! 1206:
! 1207: int
! 1208: esa_attach_codec(void *aux, struct ac97_codec_if *codec_if)
! 1209: {
! 1210: struct esa_softc *sc = aux;
! 1211:
! 1212: sc->codec_if = codec_if;
! 1213:
! 1214: return (0);
! 1215: }
! 1216:
! 1217: int
! 1218: esa_read_codec(void *aux, u_int8_t reg, u_int16_t *result)
! 1219: {
! 1220: struct esa_softc *sc = aux;
! 1221: bus_space_tag_t iot = sc->sc_iot;
! 1222: bus_space_handle_t ioh = sc->sc_ioh;
! 1223:
! 1224: if (esa_wait(sc))
! 1225: printf("%s: esa_read_codec: timed out\n", sc->sc_dev.dv_xname);
! 1226: bus_space_write_1(iot, ioh, ESA_CODEC_COMMAND, (reg & 0x7f) | 0x80);
! 1227: delay(50);
! 1228: if (esa_wait(sc))
! 1229: printf("%s: esa_read_codec: timed out\n", sc->sc_dev.dv_xname);
! 1230: *result = bus_space_read_2(iot, ioh, ESA_CODEC_DATA);
! 1231:
! 1232: return (0);
! 1233: }
! 1234:
! 1235: int
! 1236: esa_write_codec(void *aux, u_int8_t reg, u_int16_t data)
! 1237: {
! 1238: struct esa_softc *sc = aux;
! 1239: bus_space_tag_t iot = sc->sc_iot;
! 1240: bus_space_handle_t ioh = sc->sc_ioh;
! 1241:
! 1242: if (esa_wait(sc)) {
! 1243: printf("%s: esa_write_codec: timed out\n", sc->sc_dev.dv_xname);
! 1244: return (-1);
! 1245: }
! 1246: bus_space_write_2(iot, ioh, ESA_CODEC_DATA, data);
! 1247: bus_space_write_1(iot, ioh, ESA_CODEC_COMMAND, reg & 0x7f);
! 1248: delay(50);
! 1249:
! 1250: return (0);
! 1251: }
! 1252:
! 1253: void
! 1254: esa_reset_codec(void *aux)
! 1255: {
! 1256:
! 1257: return;
! 1258: }
! 1259:
! 1260: enum ac97_host_flags
! 1261: esa_flags_codec(void *aux)
! 1262: {
! 1263: struct esa_softc *sc = aux;
! 1264:
! 1265: return (sc->codec_flags);
! 1266: }
! 1267:
! 1268: int
! 1269: esa_wait(struct esa_softc *sc)
! 1270: {
! 1271: int i, val;
! 1272: bus_space_tag_t iot = sc->sc_iot;
! 1273: bus_space_handle_t ioh = sc->sc_ioh;
! 1274:
! 1275: for (i = 0; i < 20; i++) {
! 1276: val = bus_space_read_1(iot, ioh, ESA_CODEC_STATUS);
! 1277: if ((val & 1) == 0)
! 1278: return (0);
! 1279: delay(2);
! 1280: }
! 1281:
! 1282: return (-1);
! 1283: }
! 1284:
! 1285: int
! 1286: esa_init(struct esa_softc *sc)
! 1287: {
! 1288: struct esa_voice *vc;
! 1289: bus_space_tag_t iot = sc->sc_iot;
! 1290: bus_space_handle_t ioh = sc->sc_ioh;
! 1291: pcitag_t tag = sc->sc_tag;
! 1292: pci_chipset_tag_t pc = sc->sc_pct;
! 1293: u_int32_t data, i, size;
! 1294: u_int8_t reset_state;
! 1295: int data_bytes = (((ESA_MINISRC_TMP_BUFFER_SIZE & ~1) +
! 1296: (ESA_MINISRC_IN_BUFFER_SIZE & ~1) +
! 1297: (ESA_MINISRC_OUT_BUFFER_SIZE & ~1) + 4) + 255)
! 1298: &~ 255;
! 1299:
! 1300: /* Disable legacy emulation */
! 1301: data = pci_conf_read(pc, tag, PCI_LEGACY_AUDIO_CTRL);
! 1302: data |= DISABLE_LEGACY;
! 1303: pci_conf_write(pc, tag, PCI_LEGACY_AUDIO_CTRL, data);
! 1304:
! 1305: esa_config(sc);
! 1306:
! 1307: reset_state = esa_assp_halt(sc);
! 1308:
! 1309: esa_init_codec(sc);
! 1310: esa_codec_reset(sc);
! 1311:
! 1312: /* Zero kernel and mixer data */
! 1313: size = ESA_REV_B_DATA_MEMORY_UNIT_LENGTH * ESA_NUM_UNITS_KERNEL_DATA;
! 1314: for (i = 0; i < size / 2; i++) {
! 1315: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
! 1316: ESA_KDATA_BASE_ADDR + i, 0);
! 1317: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
! 1318: ESA_KDATA_BASE_ADDR2 + i, 0);
! 1319: }
! 1320:
! 1321: /* Init DMA pointer */
! 1322: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, ESA_KDATA_CURRENT_DMA,
! 1323: ESA_KDATA_DMA_XFER0);
! 1324:
! 1325: /* Write kernel code into memory */
! 1326: size = sizeof(esa_assp_kernel_image);
! 1327: for (i = 0; i < size / 2; i++)
! 1328: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_CODE,
! 1329: ESA_REV_B_CODE_MEMORY_BEGIN + i, esa_assp_kernel_image[i]);
! 1330:
! 1331: size = sizeof(esa_assp_minisrc_image);
! 1332: for (i = 0; i < size / 2; i++)
! 1333: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_CODE, 0x400 + i,
! 1334: esa_assp_minisrc_image[i]);
! 1335:
! 1336: /* Write the coefficients for the low pass filter */
! 1337: size = sizeof(esa_minisrc_lpf_image);
! 1338: for (i = 0; i < size / 2; i++)
! 1339: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_CODE,
! 1340: 0x400 + ESA_MINISRC_COEF_LOC + i, esa_minisrc_lpf_image[i]);
! 1341: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_CODE,
! 1342: 0x400 + ESA_MINISRC_COEF_LOC + size, 0x8000);
! 1343: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, ESA_KDATA_TASK0, 0x400);
! 1344: /* Init the mixer number */
! 1345: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
! 1346: ESA_KDATA_MIXER_TASK_NUMBER, 0);
! 1347: /* Extreme kernel master volume */
! 1348: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
! 1349: ESA_KDATA_DAC_LEFT_VOLUME, ESA_ARB_VOLUME);
! 1350: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
! 1351: ESA_KDATA_DAC_RIGHT_VOLUME, ESA_ARB_VOLUME);
! 1352:
! 1353: if (esa_amp_enable(sc))
! 1354: return (-1);
! 1355:
! 1356: /* Zero entire DAC/ADC area */
! 1357: for (i = 0x1100; i < 0x1c00; i++)
! 1358: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, i, 0);
! 1359:
! 1360: /* set some sane defaults */
! 1361: for (i = 0; i < ESA_NUM_VOICES; i++) {
! 1362: vc = &sc->voice[i];
! 1363: vc->play.data_offset = ESA_DAC_DATA + (data_bytes * i);
! 1364: vc->rec.data_offset = ESA_DAC_DATA + (data_bytes * i * 2);
! 1365: }
! 1366:
! 1367: esa_enable_interrupts(sc);
! 1368:
! 1369: bus_space_write_1(iot, ioh, ESA_DSP_PORT_CONTROL_REG_B,
! 1370: reset_state | ESA_REGB_ENABLE_RESET);
! 1371:
! 1372: return (0);
! 1373: }
! 1374:
! 1375: void
! 1376: esa_config(struct esa_softc *sc)
! 1377: {
! 1378: bus_space_tag_t iot = sc->sc_iot;
! 1379: bus_space_handle_t ioh = sc->sc_ioh;
! 1380: pcitag_t tag = sc->sc_tag;
! 1381: pci_chipset_tag_t pc = sc->sc_pct;
! 1382: u_int32_t data;
! 1383:
! 1384: data = pci_conf_read(pc, tag, ESA_PCI_ALLEGRO_CONFIG);
! 1385: data &= ESA_REDUCED_DEBOUNCE;
! 1386: data |= ESA_PM_CTRL_ENABLE | ESA_CLK_DIV_BY_49 | ESA_USE_PCI_TIMING;
! 1387: pci_conf_write(pc, tag, ESA_PCI_ALLEGRO_CONFIG, data);
! 1388:
! 1389: bus_space_write_1(iot, ioh, ESA_ASSP_CONTROL_B, ESA_RESET_ASSP);
! 1390: data = pci_conf_read(pc, tag, ESA_PCI_ALLEGRO_CONFIG);
! 1391: data &= ~ESA_INT_CLK_SELECT;
! 1392: if (sc->type == ESS_MAESTRO3) {
! 1393: data &= ~ESA_INT_CLK_MULT_ENABLE;
! 1394: data |= ESA_INT_CLK_SRC_NOT_PCI;
! 1395: }
! 1396: data &= ~(ESA_CLK_MULT_MODE_SELECT | ESA_CLK_MULT_MODE_SELECT_2);
! 1397: pci_conf_write(pc, tag, ESA_PCI_ALLEGRO_CONFIG, data);
! 1398:
! 1399: if (sc->type == ESS_ALLEGRO1) {
! 1400: data = pci_conf_read(pc, tag, ESA_PCI_USER_CONFIG);
! 1401: data |= ESA_IN_CLK_12MHZ_SELECT;
! 1402: pci_conf_write(pc, tag, ESA_PCI_USER_CONFIG, data);
! 1403: }
! 1404:
! 1405: data = bus_space_read_1(iot, ioh, ESA_ASSP_CONTROL_A);
! 1406: data &= ~(ESA_DSP_CLK_36MHZ_SELECT | ESA_ASSP_CLK_49MHZ_SELECT);
! 1407: data |= ESA_ASSP_CLK_49MHZ_SELECT; /* XXX: Assumes 49MHz DSP */
! 1408: data |= ESA_ASSP_0_WS_ENABLE;
! 1409: bus_space_write_1(iot, ioh, ESA_ASSP_CONTROL_A, data);
! 1410:
! 1411: bus_space_write_1(iot, ioh, ESA_ASSP_CONTROL_B, ESA_RUN_ASSP);
! 1412:
! 1413: return;
! 1414: }
! 1415:
! 1416: u_int8_t
! 1417: esa_assp_halt(struct esa_softc *sc)
! 1418: {
! 1419: bus_space_tag_t iot = sc->sc_iot;
! 1420: bus_space_handle_t ioh = sc->sc_ioh;
! 1421: u_int8_t data, reset_state;
! 1422:
! 1423: data = bus_space_read_1(iot, ioh, ESA_DSP_PORT_CONTROL_REG_B);
! 1424: reset_state = data & ~ESA_REGB_STOP_CLOCK;
! 1425: delay(10000); /* XXX use tsleep */
! 1426: bus_space_write_1(iot, ioh, ESA_DSP_PORT_CONTROL_REG_B,
! 1427: reset_state & ~ESA_REGB_ENABLE_RESET);
! 1428: delay(10000); /* XXX use tsleep */
! 1429:
! 1430: return (reset_state);
! 1431: }
! 1432:
! 1433: void
! 1434: esa_codec_reset(struct esa_softc *sc)
! 1435: {
! 1436: bus_space_tag_t iot = sc->sc_iot;
! 1437: bus_space_handle_t ioh = sc->sc_ioh;
! 1438: u_int16_t data, dir;
! 1439: int retry = 0;
! 1440:
! 1441: do {
! 1442: data = bus_space_read_2(iot, ioh, ESA_GPIO_DIRECTION);
! 1443: dir = data | 0x10; /* assuming pci bus master? */
! 1444:
! 1445: /* remote codec config */
! 1446: data = bus_space_read_2(iot, ioh, ESA_RING_BUS_CTRL_B);
! 1447: bus_space_write_2(iot, ioh, ESA_RING_BUS_CTRL_B,
! 1448: data & ~ESA_SECOND_CODEC_ID_MASK);
! 1449: data = bus_space_read_2(iot, ioh, ESA_SDO_OUT_DEST_CTRL);
! 1450: bus_space_write_2(iot, ioh, ESA_SDO_OUT_DEST_CTRL,
! 1451: data & ~ESA_COMMAND_ADDR_OUT);
! 1452: data = bus_space_read_2(iot, ioh, ESA_SDO_IN_DEST_CTRL);
! 1453: bus_space_write_2(iot, ioh, ESA_SDO_IN_DEST_CTRL,
! 1454: data & ~ESA_STATUS_ADDR_IN);
! 1455:
! 1456: bus_space_write_2(iot, ioh, ESA_RING_BUS_CTRL_A,
! 1457: ESA_IO_SRAM_ENABLE);
! 1458: delay(20);
! 1459:
! 1460: bus_space_write_2(iot, ioh, ESA_GPIO_DIRECTION,
! 1461: dir & ~ESA_GPO_PRIMARY_AC97);
! 1462: bus_space_write_2(iot, ioh, ESA_GPIO_MASK,
! 1463: ~ESA_GPO_PRIMARY_AC97);
! 1464: bus_space_write_2(iot, ioh, ESA_GPIO_DATA, 0);
! 1465: bus_space_write_2(iot, ioh, ESA_GPIO_DIRECTION,
! 1466: dir | ESA_GPO_PRIMARY_AC97);
! 1467: delay(sc->delay1 * 1000);
! 1468: bus_space_write_2(iot, ioh, ESA_GPIO_DATA,
! 1469: ESA_GPO_PRIMARY_AC97);
! 1470: delay(5);
! 1471: bus_space_write_2(iot, ioh, ESA_RING_BUS_CTRL_A,
! 1472: ESA_IO_SRAM_ENABLE | ESA_SERIAL_AC_LINK_ENABLE);
! 1473: bus_space_write_2(iot, ioh, ESA_GPIO_MASK, ~0);
! 1474: delay(sc->delay2 * 1000);
! 1475:
! 1476: esa_read_codec(sc, 0x7c, &data);
! 1477: if ((data == 0) || (data == 0xffff)) {
! 1478: retry++;
! 1479: if (retry > 3) {
! 1480: printf("%s: esa_codec_reset: failed\n",
! 1481: sc->sc_dev.dv_xname);
! 1482: break;
! 1483: }
! 1484: printf("%s: esa_codec_reset: retrying\n",
! 1485: sc->sc_dev.dv_xname);
! 1486: } else
! 1487: retry = 0;
! 1488: } while (retry);
! 1489:
! 1490: return;
! 1491: }
! 1492:
! 1493: int
! 1494: esa_amp_enable(struct esa_softc *sc)
! 1495: {
! 1496: bus_space_tag_t iot = sc->sc_iot;
! 1497: bus_space_handle_t ioh = sc->sc_ioh;
! 1498: u_int32_t gpo, polarity_port, polarity;
! 1499: u_int16_t data;
! 1500:
! 1501: switch (sc->type) {
! 1502: case ESS_ALLEGRO1:
! 1503: polarity_port = 0x1800;
! 1504: break;
! 1505: case ESS_MAESTRO3:
! 1506: polarity_port = 0x1100;
! 1507: break;
! 1508: default:
! 1509: printf("%s: esa_amp_enable: Unknown chip type!!!\n",
! 1510: sc->sc_dev.dv_xname);
! 1511: return (1);
! 1512: }
! 1513:
! 1514: gpo = (polarity_port >> 8) & 0x0f;
! 1515: polarity = polarity_port >> 12;
! 1516: polarity = !polarity; /* Enable */
! 1517: polarity = polarity << gpo;
! 1518: gpo = 1 << gpo;
! 1519: bus_space_write_2(iot, ioh, ESA_GPIO_MASK, ~gpo);
! 1520: data = bus_space_read_2(iot, ioh, ESA_GPIO_DIRECTION);
! 1521: bus_space_write_2(iot, ioh, ESA_GPIO_DIRECTION, data | gpo);
! 1522: data = ESA_GPO_SECONDARY_AC97 | ESA_GPO_PRIMARY_AC97 | polarity;
! 1523: bus_space_write_2(iot, ioh, ESA_GPIO_DATA, data);
! 1524: bus_space_write_2(iot, ioh, ESA_GPIO_MASK, ~0);
! 1525:
! 1526: return (0);
! 1527: }
! 1528:
! 1529: void
! 1530: esa_enable_interrupts(struct esa_softc *sc)
! 1531: {
! 1532: bus_space_tag_t iot = sc->sc_iot;
! 1533: bus_space_handle_t ioh = sc->sc_ioh;
! 1534: u_int8_t data;
! 1535:
! 1536: bus_space_write_2(iot, ioh, ESA_HOST_INT_CTRL,
! 1537: ESA_ASSP_INT_ENABLE | ESA_HV_INT_ENABLE);
! 1538: data = bus_space_read_1(iot, ioh, ESA_ASSP_CONTROL_C);
! 1539: bus_space_write_1(iot, ioh, ESA_ASSP_CONTROL_C,
! 1540: data | ESA_ASSP_HOST_INT_ENABLE);
! 1541: }
! 1542:
! 1543: /*
! 1544: * List management
! 1545: */
! 1546: int
! 1547: esa_add_list(struct esa_voice *vc, struct esa_list *el,
! 1548: u_int16_t val, int index)
! 1549: {
! 1550: struct esa_softc *sc = (struct esa_softc *)vc->parent;
! 1551:
! 1552: el->indexmap[index] = el->currlen;
! 1553: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
! 1554: el->mem_addr + el->currlen,
! 1555: val);
! 1556:
! 1557: return (el->currlen++);
! 1558: }
! 1559:
! 1560: void
! 1561: esa_remove_list(struct esa_voice *vc, struct esa_list *el, int index)
! 1562: {
! 1563: struct esa_softc *sc = (struct esa_softc *)vc->parent;
! 1564: u_int16_t val;
! 1565: int lastindex = el->currlen - 1;
! 1566: int vindex = el->indexmap[index];
! 1567: int i;
! 1568:
! 1569: /* reset our virtual index */
! 1570: el->indexmap[index] = -1;
! 1571:
! 1572: if (vindex != lastindex) {
! 1573: val = esa_read_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
! 1574: el->mem_addr + lastindex);
! 1575: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
! 1576: el->mem_addr + vindex,
! 1577: val);
! 1578: for (i = 0; i < ESA_NUM_VOICES * 2; i++)
! 1579: if (el->indexmap[i] == lastindex)
! 1580: break;
! 1581: if (i >= ESA_NUM_VOICES * 2)
! 1582: printf("%s: esa_remove_list: invalid task index\n",
! 1583: sc->sc_dev.dv_xname);
! 1584: else
! 1585: el->indexmap[i] = vindex;
! 1586: }
! 1587:
! 1588: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA,
! 1589: el->mem_addr + lastindex, 0);
! 1590: el->currlen--;
! 1591:
! 1592: return;
! 1593: }
! 1594:
! 1595: int
! 1596: esa_power(struct esa_softc *sc, int state)
! 1597: {
! 1598: pcitag_t tag = sc->sc_tag;
! 1599: pci_chipset_tag_t pc = sc->sc_pct;
! 1600: pcireg_t data;
! 1601: int pmcapreg;
! 1602:
! 1603: if (pci_get_capability(pc, tag, PCI_CAP_PWRMGMT, &pmcapreg, 0)) {
! 1604: data = pci_conf_read(pc, tag, pmcapreg + PCI_PMCSR);
! 1605: if ((data & PCI_PMCSR_STATE_MASK) != state)
! 1606: pci_conf_write(pc, tag, pmcapreg + PCI_PMCSR, state);
! 1607: }
! 1608:
! 1609: return (0);
! 1610: }
! 1611:
! 1612: void
! 1613: esa_powerhook(int why, void *hdl)
! 1614: {
! 1615: struct esa_softc *sc = (struct esa_softc *)hdl;
! 1616:
! 1617: switch (why) {
! 1618: case PWR_SUSPEND:
! 1619: case PWR_STANDBY:
! 1620: esa_suspend(sc);
! 1621: break;
! 1622: case PWR_RESUME:
! 1623: esa_resume(sc);
! 1624: (sc->codec_if->vtbl->restore_ports)(sc->codec_if);
! 1625: break;
! 1626: }
! 1627: }
! 1628:
! 1629: int
! 1630: esa_suspend(struct esa_softc *sc)
! 1631: {
! 1632: bus_space_tag_t iot = sc->sc_iot;
! 1633: bus_space_handle_t ioh = sc->sc_ioh;
! 1634: int i, index;
! 1635:
! 1636: index = 0;
! 1637:
! 1638: bus_space_write_2(iot, ioh, ESA_HOST_INT_CTRL, 0);
! 1639: bus_space_write_1(iot, ioh, ESA_ASSP_CONTROL_C, 0);
! 1640:
! 1641: esa_assp_halt(sc);
! 1642:
! 1643: /* Save ASSP state */
! 1644: for (i = ESA_REV_B_CODE_MEMORY_BEGIN; i <= ESA_REV_B_CODE_MEMORY_END;
! 1645: i++)
! 1646: sc->savemem[index++] = esa_read_assp(sc,
! 1647: ESA_MEMTYPE_INTERNAL_CODE, i);
! 1648: for (i = ESA_REV_B_DATA_MEMORY_BEGIN; i <= ESA_REV_B_DATA_MEMORY_END;
! 1649: i++)
! 1650: sc->savemem[index++] = esa_read_assp(sc,
! 1651: ESA_MEMTYPE_INTERNAL_DATA, i);
! 1652:
! 1653: esa_power(sc, PCI_PMCSR_STATE_D3);
! 1654:
! 1655: return (0);
! 1656: }
! 1657:
! 1658: int
! 1659: esa_resume(struct esa_softc *sc) {
! 1660: bus_space_tag_t iot = sc->sc_iot;
! 1661: bus_space_handle_t ioh = sc->sc_ioh;
! 1662: int i, index;
! 1663: u_int8_t reset_state;
! 1664:
! 1665: index = 0;
! 1666:
! 1667: esa_power(sc, PCI_PMCSR_STATE_D0);
! 1668: delay(10000);
! 1669:
! 1670: esa_config(sc);
! 1671:
! 1672: reset_state = esa_assp_halt(sc);
! 1673:
! 1674: esa_codec_reset(sc);
! 1675:
! 1676: /* restore ASSP */
! 1677: for (i = ESA_REV_B_CODE_MEMORY_BEGIN; i <= ESA_REV_B_CODE_MEMORY_END;
! 1678: i++)
! 1679: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_CODE, i,
! 1680: sc->savemem[index++]);
! 1681: for (i = ESA_REV_B_DATA_MEMORY_BEGIN; i <= ESA_REV_B_DATA_MEMORY_END;
! 1682: i++)
! 1683: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, i,
! 1684: sc->savemem[index++]);
! 1685:
! 1686: esa_write_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, ESA_KDATA_DMA_ACTIVE, 0);
! 1687: bus_space_write_1(iot, ioh, ESA_DSP_PORT_CONTROL_REG_B,
! 1688: reset_state | ESA_REGB_ENABLE_RESET);
! 1689:
! 1690: esa_enable_interrupts(sc);
! 1691: esa_amp_enable(sc);
! 1692:
! 1693: return (0);
! 1694: }
! 1695:
! 1696: u_int32_t
! 1697: esa_get_pointer(struct esa_softc *sc, struct esa_channel *ch)
! 1698: {
! 1699: u_int16_t hi = 0, lo = 0;
! 1700: u_int32_t addr;
! 1701: int data_offset = ch->data_offset;
! 1702:
! 1703: hi = esa_read_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, data_offset +
! 1704: ESA_CDATA_HOST_SRC_CURRENTH);
! 1705: lo = esa_read_assp(sc, ESA_MEMTYPE_INTERNAL_DATA, data_offset +
! 1706: ESA_CDATA_HOST_SRC_CURRENTL);
! 1707:
! 1708: addr = lo | ((u_int32_t)hi << 16);
! 1709: return (addr - ch->start);
! 1710: }
! 1711:
! 1712: paddr_t
! 1713: esa_mappage(void *addr, void *mem, off_t off, int prot)
! 1714: {
! 1715: struct esa_voice *vc = addr;
! 1716: struct esa_softc *sc = (struct esa_softc *)vc->parent;
! 1717: struct esa_dma *p;
! 1718:
! 1719: if (off < 0)
! 1720: return (-1);
! 1721: for (p = vc->dma; p && KERNADDR(p) != mem; p = p->next)
! 1722: ;
! 1723: if (!p)
! 1724: return (-1);
! 1725: return (bus_dmamem_mmap(sc->sc_dmat, p->segs, p->nsegs,
! 1726: off, prot, BUS_DMA_WAITOK));
! 1727: }
CVSweb