Annotation of sys/dev/pci/emuxki.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: emuxki.c,v 1.24 2007/07/10 22:04:28 jakemsr Exp $ */
! 2: /* $NetBSD: emuxki.c,v 1.1 2001/10/17 18:39:41 jdolecek Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 2001 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Yannick Montulet.
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by the NetBSD
! 22: * Foundation, Inc. and its contributors.
! 23: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 24: * contributors may be used to endorse or promote products derived
! 25: * from this software without specific prior written permission.
! 26: *
! 27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 37: * POSSIBILITY OF SUCH DAMAGE.
! 38: */
! 39:
! 40: /*
! 41: * Driver for Creative Labs SBLive! series and probably PCI512.
! 42: *
! 43: * Known bugs:
! 44: * - inversed stereo at ac97 codec level
! 45: * (XXX jdolecek - don't see the problem? maybe because auvia(4) has
! 46: * it swapped too?)
! 47: * - bass disappear when you plug rear jack-in on Cambridge FPS2000 speakers
! 48: * (and presumably all speakers that support front and rear jack-in)
! 49: *
! 50: * TODO:
! 51: * - Digital Outputs
! 52: * - (midi/mpu),joystick support
! 53: * - Multiple voices play (problem with /dev/audio architecture)
! 54: * - Multiple sources recording (Pb with audio(4))
! 55: * - Independent modification of each channel's parameters (via mixer ?)
! 56: * - DSP FX patches (to make fx like chipmunk)
! 57: */
! 58:
! 59: #include <sys/types.h>
! 60: #include <sys/device.h>
! 61: #include <sys/errno.h>
! 62: #include <sys/malloc.h>
! 63: #include <sys/systm.h>
! 64: #include <sys/param.h>
! 65: #include <sys/audioio.h>
! 66: #include <sys/selinfo.h>
! 67:
! 68: #include <dev/pci/pcireg.h>
! 69: #include <dev/pci/pcivar.h>
! 70: #include <dev/pci/pcidevs.h>
! 71:
! 72: #include <dev/audio_if.h>
! 73: #include <dev/audiovar.h>
! 74: #include <dev/auconv.h>
! 75: #include <dev/mulaw.h>
! 76: #include <dev/ic/ac97.h>
! 77:
! 78: #include <dev/pci/emuxkireg.h>
! 79: #include <dev/pci/emuxkivar.h>
! 80:
! 81: #define slinear16_to_ulinear8_le linear16_to_ulinear8_le;
! 82:
! 83: /* autconf goo */
! 84: int emuxki_match(struct device *, void *, void *);
! 85: void emuxki_attach(struct device *, struct device *, void *);
! 86: int emuxki_detach(struct device *, int);
! 87: int emuxki_scinit(struct emuxki_softc *sc);
! 88: void emuxki_pci_shutdown(struct emuxki_softc *sc);
! 89:
! 90: /* dma mem mgmt */
! 91: struct dmamem *emuxki_dmamem_alloc(bus_dma_tag_t, size_t, bus_size_t,
! 92: int, int, int);
! 93: void emuxki_dmamem_free(struct dmamem *, int);
! 94: void emuxki_dmamem_delete(struct dmamem *mem, int type);
! 95:
! 96: struct emuxki_mem *emuxki_mem_new(struct emuxki_softc *sc, int ptbidx,
! 97: size_t size, int type, int flags);
! 98: void emuxki_mem_delete(struct emuxki_mem *mem, int type);
! 99:
! 100: /* Emu10k1 init & shutdown */
! 101: int emuxki_init(struct emuxki_softc *);
! 102: void emuxki_shutdown(struct emuxki_softc *);
! 103:
! 104: /* Emu10k1 mem mgmt */
! 105: void *emuxki_pmem_alloc(struct emuxki_softc *, size_t,int,int);
! 106: void *emuxki_rmem_alloc(struct emuxki_softc *, size_t,int,int);
! 107:
! 108: /*
! 109: * Emu10k1 channels funcs : There is no direct access to channels, everything
! 110: * is done through voices I will at least provide channel based fx params
! 111: * modification, later...
! 112: */
! 113:
! 114: /* Emu10k1 voice mgmt */
! 115: struct emuxki_voice *emuxki_voice_new(struct emuxki_softc *, u_int8_t);
! 116: void emuxki_voice_delete(struct emuxki_voice *);
! 117: int emuxki_voice_set_audioparms(struct emuxki_voice *, u_int8_t, u_int8_t, u_int32_t);
! 118: /* emuxki_voice_set_fxparms will come later, it'll need channel distinction */
! 119: int emuxki_voice_set_bufparms(struct emuxki_voice *, void *, u_int32_t, u_int16_t);
! 120: int emuxki_voice_set_stereo(struct emuxki_voice *voice, u_int8_t stereo);
! 121: int emuxki_voice_dataloc_create(struct emuxki_voice *voice);
! 122: void emuxki_voice_dataloc_destroy(struct emuxki_voice *voice);
! 123: void emuxki_voice_commit_parms(struct emuxki_voice *);
! 124: void emuxki_voice_recsrc_release(struct emuxki_softc *sc, emuxki_recsrc_t source);
! 125: int emuxki_recsrc_reserve(struct emuxki_voice *voice, emuxki_recsrc_t source);
! 126: int emuxki_voice_adc_rate(struct emuxki_voice *);
! 127: u_int32_t emuxki_voice_curaddr(struct emuxki_voice *);
! 128: int emuxki_set_vparms(struct emuxki_voice *voice, struct audio_params *p);
! 129: int emuxki_voice_set_srate(struct emuxki_voice *voice, u_int32_t srate);
! 130: void emuxki_voice_start(struct emuxki_voice *, void (*) (void *), void *);
! 131: void emuxki_voice_halt(struct emuxki_voice *);
! 132: int emuxki_voice_channel_create(struct emuxki_voice *voice);
! 133: void emuxki_voice_channel_destroy(struct emuxki_voice *voice);
! 134:
! 135: struct emuxki_channel *emuxki_channel_new(struct emuxki_voice *voice, u_int8_t num);
! 136: void emuxki_channel_delete(struct emuxki_channel *chan);
! 137: void emuxki_channel_start(struct emuxki_channel *chan);
! 138: void emuxki_channel_stop(struct emuxki_channel *chan);
! 139: void emuxki_channel_commit_fx(struct emuxki_channel *chan);
! 140: void emuxki_channel_commit_parms(struct emuxki_channel *chan);
! 141: void emuxki_channel_set_bufparms(struct emuxki_channel *chan, u_int32_t start, u_int32_t end);
! 142: void emuxki_channel_set_srate(struct emuxki_channel *chan, u_int32_t srate);
! 143: void emuxki_channel_set_fxsend(struct emuxki_channel *chan,
! 144: struct emuxki_chanparms_fxsend *fxsend);
! 145: void emuxki_chanparms_set_defaults(struct emuxki_channel *chan);
! 146:
! 147: void emuxki_resched_timer(struct emuxki_softc *sc);
! 148:
! 149: /*
! 150: * Emu10k1 stream mgmt : not done yet
! 151: */
! 152: #if 0
! 153: struct emuxki_stream *emuxki_stream_new(struct emu10k1 *);
! 154: void emuxki_stream_delete(struct emuxki_stream *);
! 155: int emuxki_stream_set_audio_params(struct emuxki_stream *, u_int8_t,
! 156: u_int8_t, u_int8_t, u_int16_t);
! 157: void emuxki_stream_start(struct emuxki_stream *);
! 158: void emuxki_stream_halt(struct emuxki_stream *);
! 159: #endif
! 160:
! 161: /* fx interface */
! 162: void emuxki_initfx(struct emuxki_softc *sc);
! 163: void emuxki_dsp_addop(struct emuxki_softc *sc, u_int16_t *pc, u_int8_t op,
! 164: u_int16_t r, u_int16_t a, u_int16_t x, u_int16_t y);
! 165: void emuxki_write_micro(struct emuxki_softc *sc, u_int32_t pc, u_int32_t data);
! 166:
! 167: /* audio interface callbacks */
! 168:
! 169: int emuxki_open(void *, int);
! 170: void emuxki_close(void *);
! 171:
! 172: int emuxki_query_encoding(void *, struct audio_encoding *);
! 173: int emuxki_set_params(void *, int, int,
! 174: struct audio_params *,
! 175: struct audio_params *);
! 176:
! 177: int emuxki_round_blocksize(void *, int);
! 178: size_t emuxki_round_buffersize(void *, int, size_t);
! 179:
! 180: int emuxki_trigger_output(void *, void *, void *, int, void (*)(void *),
! 181: void *, struct audio_params *);
! 182: int emuxki_trigger_input(void *, void *, void *, int, void (*) (void *),
! 183: void *, struct audio_params *);
! 184: int emuxki_halt_output(void *);
! 185: int emuxki_halt_input(void *);
! 186:
! 187: int emuxki_getdev(void *, struct audio_device *);
! 188: int emuxki_set_port(void *, mixer_ctrl_t *);
! 189: int emuxki_get_port(void *, mixer_ctrl_t *);
! 190: int emuxki_query_devinfo(void *, mixer_devinfo_t *);
! 191:
! 192: void *emuxki_allocm(void *, int, size_t, int, int);
! 193: void emuxki_freem(void *, void *, int);
! 194:
! 195: paddr_t emuxki_mappage(void *, void *, off_t, int);
! 196: int emuxki_get_props(void *);
! 197:
! 198: /* Interrupt handler */
! 199: int emuxki_intr(void *);
! 200:
! 201: /* Emu10k1 AC97 interface callbacks */
! 202: int emuxki_ac97_init(struct emuxki_softc *sc);
! 203: int emuxki_ac97_attach(void *, struct ac97_codec_if *);
! 204: int emuxki_ac97_read(void *, u_int8_t, u_int16_t *);
! 205: int emuxki_ac97_write(void *, u_int8_t, u_int16_t);
! 206: void emuxki_ac97_reset(void *);
! 207:
! 208: const struct pci_matchid emuxki_devices[] = {
! 209: { PCI_VENDOR_CREATIVELABS, PCI_PRODUCT_CREATIVELABS_SBLIVE },
! 210: { PCI_VENDOR_CREATIVELABS, PCI_PRODUCT_CREATIVELABS_SBLIVE2 },
! 211: { PCI_VENDOR_CREATIVELABS, PCI_PRODUCT_CREATIVELABS_AUDIGY },
! 212: { PCI_VENDOR_CREATIVELABS, PCI_PRODUCT_CREATIVELABS_AUDIGY2 },
! 213: };
! 214:
! 215: /*
! 216: * Autoconfig goo.
! 217: */
! 218: struct cfdriver emu_cd = {
! 219: NULL, "emu", DV_DULL
! 220: };
! 221:
! 222: struct cfattach emu_ca = {
! 223: sizeof(struct emuxki_softc),
! 224: emuxki_match,
! 225: emuxki_attach,
! 226: emuxki_detach,
! 227: NULL /* config activate */
! 228: };
! 229:
! 230: struct audio_hw_if emuxki_hw_if = {
! 231: emuxki_open,
! 232: emuxki_close,
! 233: NULL, /* drain */
! 234: emuxki_query_encoding,
! 235: emuxki_set_params,
! 236: emuxki_round_blocksize,
! 237: NULL, /* commit settings */
! 238: NULL, /* init_output */
! 239: NULL, /* init_input */
! 240: NULL, /* start_output */
! 241: NULL, /* start_input */
! 242: emuxki_halt_output,
! 243: emuxki_halt_input,
! 244: NULL, /* speaker_ctl */
! 245: emuxki_getdev,
! 246: NULL, /* setfd */
! 247: emuxki_set_port,
! 248: emuxki_get_port,
! 249: emuxki_query_devinfo,
! 250: emuxki_allocm,
! 251: emuxki_freem,
! 252: emuxki_round_buffersize,
! 253: emuxki_mappage,
! 254: emuxki_get_props,
! 255: emuxki_trigger_output,
! 256: emuxki_trigger_input,
! 257: };
! 258:
! 259: #if 0
! 260: static const int emuxki_recsrc_intrmasks[EMU_NUMRECSRCS] =
! 261: { EMU_INTE_MICBUFENABLE, EMU_INTE_ADCBUFENABLE, EMU_INTE_EFXBUFENABLE };
! 262: #endif
! 263: static const u_int32_t emuxki_recsrc_bufaddrreg[EMU_NUMRECSRCS] =
! 264: { EMU_MICBA, EMU_ADCBA, EMU_FXBA };
! 265: static const u_int32_t emuxki_recsrc_szreg[EMU_NUMRECSRCS] =
! 266: { EMU_MICBS, EMU_ADCBS, EMU_FXBS };
! 267: static const int emuxki_recbuf_sz[] = {
! 268: 0, 384, 448, 512, 640, 768, 896, 1024, 1280, 1536, 1792,
! 269: 2048, 2560, 3072, 3584, 4096, 5120, 6144, 7168, 8192, 10240,
! 270: 12288, 14366, 16384, 20480, 24576, 28672, 32768, 40960, 49152,
! 271: 57344, 65536
! 272: };
! 273:
! 274: /*
! 275: * DMA memory mgmt
! 276: */
! 277:
! 278: void
! 279: emuxki_dmamem_delete(struct dmamem *mem, int type)
! 280: {
! 281: free(mem->segs, type);
! 282: free(mem, type);
! 283: }
! 284:
! 285: struct dmamem *
! 286: emuxki_dmamem_alloc(bus_dma_tag_t dmat, size_t size, bus_size_t align,
! 287: int nsegs, int type, int flags)
! 288: {
! 289: struct dmamem *mem;
! 290: int bus_dma_flags;
! 291:
! 292: /* Allocate memory for structure */
! 293: if ((mem = malloc(sizeof(*mem), type, flags)) == NULL)
! 294: return (NULL);
! 295: mem->dmat = dmat;
! 296: mem->size = size;
! 297: mem->align = align;
! 298: mem->nsegs = nsegs;
! 299: mem->bound = 0;
! 300:
! 301: mem->segs = malloc(mem->nsegs * sizeof(*(mem->segs)), type, flags);
! 302: if (mem->segs == NULL) {
! 303: free(mem, type);
! 304: return (NULL);
! 305: }
! 306:
! 307: bus_dma_flags = (flags & M_NOWAIT) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK;
! 308: if (bus_dmamem_alloc(dmat, mem->size, mem->align, mem->bound,
! 309: mem->segs, mem->nsegs, &(mem->rsegs),
! 310: bus_dma_flags)) {
! 311: emuxki_dmamem_delete(mem, type);
! 312: return (NULL);
! 313: }
! 314:
! 315: if (bus_dmamem_map(dmat, mem->segs, mem->nsegs, mem->size,
! 316: &(mem->kaddr), bus_dma_flags | BUS_DMA_COHERENT)) {
! 317: bus_dmamem_free(dmat, mem->segs, mem->nsegs);
! 318: emuxki_dmamem_delete(mem, type);
! 319: return (NULL);
! 320: }
! 321:
! 322: if (bus_dmamap_create(dmat, mem->size, mem->nsegs, mem->size,
! 323: mem->bound, bus_dma_flags, &(mem->map))) {
! 324: bus_dmamem_unmap(dmat, mem->kaddr, mem->size);
! 325: bus_dmamem_free(dmat, mem->segs, mem->nsegs);
! 326: emuxki_dmamem_delete(mem, type);
! 327: return (NULL);
! 328: }
! 329:
! 330: if (bus_dmamap_load(dmat, mem->map, mem->kaddr,
! 331: mem->size, NULL, bus_dma_flags)) {
! 332: bus_dmamap_destroy(dmat, mem->map);
! 333: bus_dmamem_unmap(dmat, mem->kaddr, mem->size);
! 334: bus_dmamem_free(dmat, mem->segs, mem->nsegs);
! 335: emuxki_dmamem_delete(mem, type);
! 336: return (NULL);
! 337: }
! 338:
! 339: return (mem);
! 340: }
! 341:
! 342: void
! 343: emuxki_dmamem_free(struct dmamem *mem, int type)
! 344: {
! 345: bus_dmamap_unload(mem->dmat, mem->map);
! 346: bus_dmamap_destroy(mem->dmat, mem->map);
! 347: bus_dmamem_unmap(mem->dmat, mem->kaddr, mem->size);
! 348: bus_dmamem_free(mem->dmat, mem->segs, mem->nsegs);
! 349: emuxki_dmamem_delete(mem, type);
! 350: }
! 351:
! 352:
! 353: /*
! 354: * Autoconf device callbacks : attach and detach
! 355: */
! 356:
! 357: void
! 358: emuxki_pci_shutdown(struct emuxki_softc *sc)
! 359: {
! 360: if (sc->sc_ih != NULL)
! 361: pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
! 362: if (sc->sc_ios)
! 363: bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
! 364: }
! 365:
! 366: int
! 367: emuxki_scinit(struct emuxki_softc *sc)
! 368: {
! 369: int err;
! 370:
! 371: bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_HCFG,
! 372: /* enable spdif(?) output on non-APS */
! 373: (sc->sc_type == EMUXKI_APS? 0 : EMU_HCFG_GPOUTPUT0) |
! 374: EMU_HCFG_LOCKSOUNDCACHE | EMU_HCFG_LOCKTANKCACHE_MASK |
! 375: EMU_HCFG_MUTEBUTTONENABLE);
! 376: bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_INTE,
! 377: EMU_INTE_SAMPLERATER | EMU_INTE_PCIERRENABLE);
! 378:
! 379: if ((err = emuxki_init(sc)))
! 380: return (err);
! 381:
! 382: if (sc->sc_type & EMUXKI_AUDIGY2) {
! 383: bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_HCFG,
! 384: EMU_HCFG_AUDIOENABLE | EMU_HCFG_AC3ENABLE_CDSPDIF |
! 385: EMU_HCFG_AC3ENABLE_GPSPDIF | EMU_HCFG_AUTOMUTE);
! 386: } else if (sc->sc_type & EMUXKI_AUDIGY) {
! 387: bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_HCFG,
! 388: EMU_HCFG_AUDIOENABLE | EMU_HCFG_AUTOMUTE);
! 389: } else {
! 390: bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_HCFG,
! 391: EMU_HCFG_AUDIOENABLE | EMU_HCFG_JOYENABLE |
! 392: EMU_HCFG_LOCKTANKCACHE_MASK | EMU_HCFG_AUTOMUTE);
! 393: }
! 394: bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_INTE,
! 395: bus_space_read_4(sc->sc_iot, sc->sc_ioh, EMU_INTE) |
! 396: EMU_INTE_VOLINCRENABLE | EMU_INTE_VOLDECRENABLE |
! 397: EMU_INTE_MUTEENABLE);
! 398:
! 399: if (sc->sc_type & EMUXKI_AUDIGY2) {
! 400: bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_A_IOCFG,
! 401: EMU_A_IOCFG_GPOUT0 |
! 402: bus_space_read_4(sc->sc_iot, sc->sc_ioh, EMU_A_IOCFG));
! 403: }
! 404:
! 405: /* No multiple voice support for now */
! 406: sc->pvoice = sc->rvoice = NULL;
! 407:
! 408: return (0);
! 409: }
! 410:
! 411: int
! 412: emuxki_ac97_init(struct emuxki_softc *sc)
! 413: {
! 414: sc->hostif.arg = sc;
! 415: sc->hostif.attach = emuxki_ac97_attach;
! 416: sc->hostif.read = emuxki_ac97_read;
! 417: sc->hostif.write = emuxki_ac97_write;
! 418: sc->hostif.reset = emuxki_ac97_reset;
! 419: sc->hostif.flags = NULL;
! 420: return (ac97_attach(&(sc->hostif)));
! 421: }
! 422:
! 423: int
! 424: emuxki_match(struct device *parent, void *match, void *aux)
! 425: {
! 426: return (pci_matchbyid((struct pci_attach_args *)aux, emuxki_devices,
! 427: sizeof(emuxki_devices)/sizeof(emuxki_devices[0])));
! 428: }
! 429:
! 430: void
! 431: emuxki_attach(struct device *parent, struct device *self, void *aux)
! 432: {
! 433: struct emuxki_softc *sc = (struct emuxki_softc *) self;
! 434: struct pci_attach_args *pa = aux;
! 435: pci_intr_handle_t ih;
! 436: const char *intrstr;
! 437:
! 438: if (pci_mapreg_map(pa, EMU_PCI_CBIO, PCI_MAPREG_TYPE_IO, 0,
! 439: &(sc->sc_iot), &(sc->sc_ioh), &(sc->sc_iob), &(sc->sc_ios), 0)) {
! 440: printf(": can't map iospace\n");
! 441: return;
! 442: }
! 443:
! 444: sc->sc_pc = pa->pa_pc;
! 445: sc->sc_dmat = pa->pa_dmat;
! 446:
! 447: if (pci_intr_map(pa, &ih)) {
! 448: printf(": couldn't map interrupt\n");
! 449: bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
! 450: return;
! 451: }
! 452:
! 453: intrstr = pci_intr_string(pa->pa_pc, ih);
! 454: sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO, emuxki_intr,
! 455: sc, sc->sc_dev.dv_xname);
! 456: if (sc->sc_ih == NULL) {
! 457: printf(": couldn't establish interrupt");
! 458: if (intrstr != NULL)
! 459: printf(" at %s", intrstr);
! 460: printf("\n");
! 461: bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
! 462: return;
! 463: }
! 464: printf(": %s\n", intrstr);
! 465:
! 466: /* XXX it's unknown whether APS is made from Audigy as well */
! 467: if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_CREATIVELABS_AUDIGY) {
! 468: sc->sc_type = EMUXKI_AUDIGY;
! 469: if (PCI_REVISION(pa->pa_class) == 0x04 ||
! 470: PCI_REVISION(pa->pa_class) == 0x08) {
! 471: sc->sc_type |= EMUXKI_AUDIGY2;
! 472: strlcpy(sc->sc_audv.name, "Audigy2", sizeof sc->sc_audv.name);
! 473: } else {
! 474: strlcpy(sc->sc_audv.name, "Audigy", sizeof sc->sc_audv.name);
! 475: }
! 476: } else if (pci_conf_read(pa->pa_pc, pa->pa_tag,
! 477: PCI_SUBSYS_ID_REG) == EMU_SUBSYS_APS) {
! 478: sc->sc_type = EMUXKI_APS;
! 479: strlcpy(sc->sc_audv.name, "E-mu APS", sizeof sc->sc_audv.name);
! 480: } else {
! 481: sc->sc_type = EMUXKI_SBLIVE;
! 482: strlcpy(sc->sc_audv.name, "SB Live!", sizeof sc->sc_audv.name);
! 483: }
! 484: snprintf(sc->sc_audv.version, sizeof sc->sc_audv.version, "0x%02x",
! 485: PCI_REVISION(pa->pa_class));
! 486: strlcpy(sc->sc_audv.config, "emuxki", sizeof sc->sc_audv.config);
! 487:
! 488: if (emuxki_scinit(sc) ||
! 489: /* APS has no ac97 XXX */
! 490: (sc->sc_type == EMUXKI_APS || emuxki_ac97_init(sc)) ||
! 491: (sc->sc_audev = audio_attach_mi(&emuxki_hw_if, sc, self)) == NULL) {
! 492: emuxki_pci_shutdown(sc);
! 493: return;
! 494: }
! 495: }
! 496:
! 497: int
! 498: emuxki_detach(struct device *self, int flags)
! 499: {
! 500: struct emuxki_softc *sc = (struct emuxki_softc *) self;
! 501:
! 502: if (sc->sc_audev != NULL) /* Test in case audio didn't attach */
! 503: config_detach(sc->sc_audev, 0);
! 504:
! 505: /* All voices should be stopped now but add some code here if not */
! 506:
! 507: bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_HCFG,
! 508: EMU_HCFG_LOCKSOUNDCACHE | EMU_HCFG_LOCKTANKCACHE_MASK |
! 509: EMU_HCFG_MUTEBUTTONENABLE);
! 510: bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_INTE, 0);
! 511:
! 512: emuxki_shutdown(sc);
! 513:
! 514: emuxki_pci_shutdown(sc);
! 515:
! 516: return (0);
! 517: }
! 518:
! 519:
! 520: /* Misc stuff relative to emu10k1 */
! 521:
! 522: static __inline u_int32_t
! 523: emuxki_rate_to_pitch(u_int32_t rate)
! 524: {
! 525: static const u_int32_t logMagTable[128] = {
! 526: 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3,
! 527: 0x13aa2, 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a,
! 528: 0x2655d, 0x28ed5, 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb,
! 529: 0x381b6, 0x3a93d, 0x3d081, 0x3f782, 0x41e42, 0x444c1, 0x46b01,
! 530: 0x49101, 0x4b6c4, 0x4dc49, 0x50191, 0x5269e, 0x54b6f, 0x57006,
! 531: 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7, 0x646ee, 0x66a00,
! 532: 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829, 0x759d4,
! 533: 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
! 534: 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20,
! 535: 0x93d26, 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec,
! 536: 0xa11d8, 0xa2f9d, 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241,
! 537: 0xadf26, 0xafbe7, 0xb1885, 0xb3500, 0xb5157, 0xb6d8c, 0xb899f,
! 538: 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899, 0xc1404, 0xc2f50, 0xc4a7b,
! 539: 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c, 0xceaec, 0xd053f,
! 540: 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3, 0xdba4a,
! 541: 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
! 542: 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a,
! 543: 0xf2c83, 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57,
! 544: 0xfd1a7, 0xfe8df
! 545: };
! 546: static const u_int8_t logSlopeTable[128] = {
! 547: 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
! 548: 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
! 549: 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
! 550: 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
! 551: 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
! 552: 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
! 553: 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
! 554: 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
! 555: 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
! 556: 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
! 557: 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
! 558: 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
! 559: 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
! 560: 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
! 561: 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
! 562: 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
! 563: };
! 564: int8_t i;
! 565:
! 566: if (rate == 0)
! 567: return 0; /* Bail out if no leading "1" */
! 568: rate *= 11185; /* Scale 48000 to 0x20002380 */
! 569: for (i = 31; i > 0; i--) {
! 570: if (rate & 0x80000000) { /* Detect leading "1" */
! 571: return (((u_int32_t) (i - 15) << 20) +
! 572: logMagTable[0x7f & (rate >> 24)] +
! 573: (0x7f & (rate >> 17)) *
! 574: logSlopeTable[0x7f & (rate >> 24)]);
! 575: }
! 576: rate <<= 1;
! 577: }
! 578:
! 579: return 0; /* Should never reach this point */
! 580: }
! 581:
! 582: /* Emu10k1 Low level */
! 583:
! 584: static __inline u_int32_t
! 585: emuxki_read(struct emuxki_softc *sc, u_int16_t chano, u_int32_t reg)
! 586: {
! 587: u_int32_t ptr, mask = 0xffffffff;
! 588: u_int8_t size, offset = 0;
! 589: int s;
! 590:
! 591: ptr = ((((u_int32_t) reg) << 16) &
! 592: (sc->sc_type & EMUXKI_AUDIGY ?
! 593: EMU_A_PTR_ADDR_MASK : EMU_PTR_ADDR_MASK)) |
! 594: (chano & EMU_PTR_CHNO_MASK);
! 595: if (reg & 0xff000000) {
! 596: size = (reg >> 24) & 0x3f;
! 597: offset = (reg >> 16) & 0x1f;
! 598: mask = ((1 << size) - 1) << offset;
! 599: }
! 600:
! 601: s = splaudio();
! 602: bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_PTR, ptr);
! 603: ptr = (bus_space_read_4(sc->sc_iot, sc->sc_ioh, EMU_DATA) & mask)
! 604: >> offset;
! 605: splx(s);
! 606:
! 607: return (ptr);
! 608: }
! 609:
! 610: static __inline void
! 611: emuxki_write(struct emuxki_softc *sc, u_int16_t chano,
! 612: u_int32_t reg, u_int32_t data)
! 613: {
! 614: u_int32_t ptr, mask;
! 615: u_int8_t size, offset;
! 616: int s;
! 617:
! 618: ptr = ((((u_int32_t) reg) << 16) &
! 619: (sc->sc_type & EMUXKI_AUDIGY ?
! 620: EMU_A_PTR_ADDR_MASK : EMU_PTR_ADDR_MASK)) |
! 621: (chano & EMU_PTR_CHNO_MASK);
! 622:
! 623: /* BE CAREFUL WITH THAT AXE, EUGENE */
! 624: if (ptr == 0x52 || ptr == 0x53)
! 625: return;
! 626:
! 627: if (reg & 0xff000000) {
! 628: size = (reg >> 24) & 0x3f;
! 629: offset = (reg >> 16) & 0x1f;
! 630: mask = ((1 << size) - 1) << offset;
! 631: data = ((data << offset) & mask) |
! 632: (emuxki_read(sc, chano, reg & 0xffff) & ~mask);
! 633: }
! 634:
! 635: s = splaudio();
! 636: bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_PTR, ptr);
! 637: bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_DATA, data);
! 638: splx(s);
! 639: }
! 640:
! 641: /* Microcode should this go in /sys/dev/microcode ? */
! 642:
! 643: void
! 644: emuxki_write_micro(struct emuxki_softc *sc, u_int32_t pc, u_int32_t data)
! 645: {
! 646: emuxki_write(sc, 0,
! 647: (sc->sc_type & EMUXKI_AUDIGY ?
! 648: EMU_A_MICROCODEBASE : EMU_MICROCODEBASE) + pc,
! 649: data);
! 650: }
! 651:
! 652: void
! 653: emuxki_dsp_addop(struct emuxki_softc *sc, u_int16_t *pc, u_int8_t op,
! 654: u_int16_t r, u_int16_t a, u_int16_t x, u_int16_t y)
! 655: {
! 656: if (sc->sc_type & EMUXKI_AUDIGY) {
! 657: emuxki_write_micro(sc, *pc << 1,
! 658: ((x << 12) & EMU_A_DSP_LOWORD_OPX_MASK) |
! 659: (y & EMU_A_DSP_LOWORD_OPY_MASK));
! 660: emuxki_write_micro(sc, (*pc << 1) + 1,
! 661: ((op << 24) & EMU_A_DSP_HIWORD_OPCODE_MASK) |
! 662: ((r << 12) & EMU_A_DSP_HIWORD_RESULT_MASK) |
! 663: (a & EMU_A_DSP_HIWORD_OPA_MASK));
! 664: } else {
! 665: emuxki_write_micro(sc, *pc << 1,
! 666: ((x << 10) & EMU_DSP_LOWORD_OPX_MASK) |
! 667: (y & EMU_DSP_LOWORD_OPY_MASK));
! 668: emuxki_write_micro(sc, (*pc << 1) + 1,
! 669: ((op << 20) & EMU_DSP_HIWORD_OPCODE_MASK) |
! 670: ((r << 10) & EMU_DSP_HIWORD_RESULT_MASK) |
! 671: (a & EMU_DSP_HIWORD_OPA_MASK));
! 672: }
! 673: (*pc)++;
! 674: }
! 675:
! 676: /* init and shutdown */
! 677:
! 678: void
! 679: emuxki_initfx(struct emuxki_softc *sc)
! 680: {
! 681: u_int16_t pc;
! 682:
! 683: /* Set all GPRs to 0 */
! 684: for (pc = 0; pc < 256; pc++)
! 685: emuxki_write(sc, 0, EMU_DSP_GPR(pc), 0);
! 686: for (pc = 0; pc < 160; pc++) {
! 687: emuxki_write(sc, 0, EMU_TANKMEMDATAREGBASE + pc, 0);
! 688: emuxki_write(sc, 0, EMU_TANKMEMADDRREGBASE + pc, 0);
! 689: }
! 690: pc = 0;
! 691:
! 692: if (sc->sc_type & EMUXKI_AUDIGY) {
! 693: /* AC97 Out (l/r) = AC97 In (l/r) + FX[0/1] * 4 */
! 694: emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_MACINTS,
! 695: EMU_A_DSP_OUTL(EMU_A_DSP_OUT_A_FRONT),
! 696: EMU_A_DSP_CST(0),
! 697: EMU_DSP_FX(0), EMU_A_DSP_CST(4));
! 698: emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_MACINTS,
! 699: EMU_A_DSP_OUTR(EMU_A_DSP_OUT_A_FRONT),
! 700: EMU_A_DSP_CST(0),
! 701: EMU_DSP_FX(1), EMU_A_DSP_CST(4));
! 702:
! 703: /* Rear channel OUT (l/r) = FX[2/3] * 4 */
! 704: #if 0
! 705: emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_MACINTS,
! 706: EMU_A_DSP_OUTL(EMU_A_DSP_OUT_A_REAR),
! 707: EMU_A_DSP_OUTL(EMU_A_DSP_OUT_A_FRONT),
! 708: EMU_DSP_FX(0), EMU_A_DSP_CST(4));
! 709: emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_MACINTS,
! 710: EMU_A_DSP_OUTR(EMU_A_DSP_OUT_A_REAR),
! 711: EMU_A_DSP_OUTR(EMU_A_DSP_OUT_A_FRONT),
! 712: EMU_DSP_FX(1), EMU_A_DSP_CST(4));
! 713: #endif
! 714: /* ADC recording (l/r) = AC97 In (l/r) */
! 715: emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_ACC3,
! 716: EMU_A_DSP_OUTL(EMU_A_DSP_OUT_ADC),
! 717: EMU_A_DSP_INL(EMU_DSP_IN_AC97),
! 718: EMU_A_DSP_CST(0), EMU_A_DSP_CST(0));
! 719: emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_ACC3,
! 720: EMU_A_DSP_OUTR(EMU_A_DSP_OUT_ADC),
! 721: EMU_A_DSP_INR(EMU_DSP_IN_AC97),
! 722: EMU_A_DSP_CST(0), EMU_A_DSP_CST(0));
! 723:
! 724: /* zero out the rest of the microcode */
! 725: while (pc < 512)
! 726: emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_ACC3,
! 727: EMU_A_DSP_CST(0), EMU_A_DSP_CST(0),
! 728: EMU_A_DSP_CST(0), EMU_A_DSP_CST(0));
! 729:
! 730: emuxki_write(sc, 0, EMU_A_DBG, 0); /* Is it really necessary ? */
! 731: } else {
! 732: /* AC97 Out (l/r) = AC97 In (l/r) + FX[0/1] * 4 */
! 733: emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_MACINTS,
! 734: EMU_DSP_OUTL(EMU_DSP_OUT_A_FRONT),
! 735: EMU_DSP_CST(0),
! 736: EMU_DSP_FX(0), EMU_DSP_CST(4));
! 737: emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_MACINTS,
! 738: EMU_DSP_OUTR(EMU_DSP_OUT_A_FRONT),
! 739: EMU_DSP_CST(0),
! 740: EMU_DSP_FX(1), EMU_DSP_CST(4));
! 741:
! 742: /* Rear channel OUT (l/r) = FX[2/3] * 4 */
! 743: #if 0
! 744: emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_MACINTS,
! 745: EMU_DSP_OUTL(EMU_DSP_OUT_AD_REAR),
! 746: EMU_DSP_OUTL(EMU_DSP_OUT_A_FRONT),
! 747: EMU_DSP_FX(0), EMU_DSP_CST(4));
! 748: emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_MACINTS,
! 749: EMU_DSP_OUTR(EMU_DSP_OUT_AD_REAR),
! 750: EMU_DSP_OUTR(EMU_DSP_OUT_A_FRONT),
! 751: EMU_DSP_FX(1), EMU_DSP_CST(4));
! 752: #endif
! 753: /* ADC recording (l/r) = AC97 In (l/r) */
! 754: emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_ACC3,
! 755: EMU_DSP_OUTL(EMU_DSP_OUT_ADC),
! 756: EMU_DSP_INL(EMU_DSP_IN_AC97),
! 757: EMU_DSP_CST(0), EMU_DSP_CST(0));
! 758: emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_ACC3,
! 759: EMU_DSP_OUTR(EMU_DSP_OUT_ADC),
! 760: EMU_DSP_INR(EMU_DSP_IN_AC97),
! 761: EMU_DSP_CST(0), EMU_DSP_CST(0));
! 762:
! 763: /* zero out the rest of the microcode */
! 764: while (pc < 512)
! 765: emuxki_dsp_addop(sc, &pc, EMU_DSP_OP_ACC3,
! 766: EMU_DSP_CST(0), EMU_DSP_CST(0),
! 767: EMU_DSP_CST(0), EMU_DSP_CST(0));
! 768:
! 769: emuxki_write(sc, 0, EMU_DBG, 0); /* Is it really necessary ? */
! 770: }
! 771: }
! 772:
! 773: int
! 774: emuxki_init(struct emuxki_softc *sc)
! 775: {
! 776: u_int16_t i;
! 777: u_int32_t spcs, *ptb;
! 778: bus_addr_t silentpage;
! 779:
! 780: /* disable any channel interrupt */
! 781: emuxki_write(sc, 0, EMU_CLIEL, 0);
! 782: emuxki_write(sc, 0, EMU_CLIEH, 0);
! 783: emuxki_write(sc, 0, EMU_SOLEL, 0);
! 784: emuxki_write(sc, 0, EMU_SOLEH, 0);
! 785:
! 786: /* Set recording buffers sizes to zero */
! 787: emuxki_write(sc, 0, EMU_MICBS, EMU_RECBS_BUFSIZE_NONE);
! 788: emuxki_write(sc, 0, EMU_MICBA, 0);
! 789: emuxki_write(sc, 0, EMU_FXBS, EMU_RECBS_BUFSIZE_NONE);
! 790: emuxki_write(sc, 0, EMU_FXBA, 0);
! 791: emuxki_write(sc, 0, EMU_ADCBS, EMU_RECBS_BUFSIZE_NONE);
! 792: emuxki_write(sc, 0, EMU_ADCBA, 0);
! 793:
! 794: if(sc->sc_type & EMUXKI_AUDIGY) {
! 795: emuxki_write(sc, 0, EMU_SPBYPASS, EMU_SPBYPASS_24_BITS);
! 796: emuxki_write(sc, 0, EMU_AC97SLOT, EMU_AC97SLOT_CENTER | EMU_AC97SLOT_LFE);
! 797: }
! 798:
! 799: /* Initialize all channels to stopped and no effects */
! 800: for (i = 0; i < EMU_NUMCHAN; i++) {
! 801: emuxki_write(sc, i, EMU_CHAN_DCYSUSV, 0);
! 802: emuxki_write(sc, i, EMU_CHAN_IP, 0);
! 803: emuxki_write(sc, i, EMU_CHAN_VTFT, 0xffff);
! 804: emuxki_write(sc, i, EMU_CHAN_CVCF, 0xffff);
! 805: emuxki_write(sc, i, EMU_CHAN_PTRX, 0);
! 806: emuxki_write(sc, i, EMU_CHAN_CPF, 0);
! 807: emuxki_write(sc, i, EMU_CHAN_CCR, 0);
! 808: emuxki_write(sc, i, EMU_CHAN_PSST, 0);
! 809: emuxki_write(sc, i, EMU_CHAN_DSL, 0x10); /* Why 16 ? */
! 810: emuxki_write(sc, i, EMU_CHAN_CCCA, 0);
! 811: emuxki_write(sc, i, EMU_CHAN_Z1, 0);
! 812: emuxki_write(sc, i, EMU_CHAN_Z2, 0);
! 813: emuxki_write(sc, i, EMU_CHAN_FXRT, 0x32100000);
! 814: emuxki_write(sc, i, EMU_CHAN_ATKHLDM, 0);
! 815: emuxki_write(sc, i, EMU_CHAN_DCYSUSM, 0);
! 816: emuxki_write(sc, i, EMU_CHAN_IFATN, 0xffff);
! 817: emuxki_write(sc, i, EMU_CHAN_PEFE, 0);
! 818: emuxki_write(sc, i, EMU_CHAN_FMMOD, 0);
! 819: emuxki_write(sc, i, EMU_CHAN_TREMFRQ, 24);
! 820: emuxki_write(sc, i, EMU_CHAN_FM2FRQ2, 24);
! 821: emuxki_write(sc, i, EMU_CHAN_TEMPENV, 0);
! 822:
! 823: /* these are last so OFF prevents writing */
! 824: emuxki_write(sc, i, EMU_CHAN_LFOVAL2, 0);
! 825: emuxki_write(sc, i, EMU_CHAN_LFOVAL1, 0);
! 826: emuxki_write(sc, i, EMU_CHAN_ATKHLDV, 0);
! 827: emuxki_write(sc, i, EMU_CHAN_ENVVOL, 0);
! 828: emuxki_write(sc, i, EMU_CHAN_ENVVAL, 0);
! 829: }
! 830:
! 831: /* set digital outputs format */
! 832: spcs = (EMU_SPCS_CLKACCY_1000PPM | EMU_SPCS_SAMPLERATE_48 |
! 833: EMU_SPCS_CHANNELNUM_LEFT | EMU_SPCS_SOURCENUM_UNSPEC |
! 834: EMU_SPCS_GENERATIONSTATUS | 0x00001200 /* Cat code. */ |
! 835: 0x00000000 /* IEC-958 Mode */ | EMU_SPCS_EMPHASIS_NONE |
! 836: EMU_SPCS_COPYRIGHT);
! 837: emuxki_write(sc, 0, EMU_SPCS0, spcs);
! 838: emuxki_write(sc, 0, EMU_SPCS1, spcs);
! 839: emuxki_write(sc, 0, EMU_SPCS2, spcs);
! 840:
! 841: if(sc->sc_type & EMUXKI_AUDIGY2) {
! 842: emuxki_write(sc, 0, EMU_A2_SPDIF_SAMPLERATE, EMU_A2_SPDIF_UNKNOWN);
! 843:
! 844: bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_A2_PTR, EMU_A2_SRCSEL);
! 845: bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_A2_DATA,
! 846: EMU_A2_SRCSEL_ENABLE_SPDIF | EMU_A2_SRCSEL_ENABLE_SRCMULTI);
! 847:
! 848: bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_A2_PTR, EMU_A2_SRCMULTI);
! 849: bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_A2_DATA, EMU_A2_SRCMULTI_ENABLE_INPUT);
! 850: }
! 851:
! 852:
! 853: /* Let's play with sound processor */
! 854: emuxki_initfx(sc);
! 855:
! 856: /* Here is our Page Table */
! 857: if ((sc->ptb = emuxki_dmamem_alloc(sc->sc_dmat,
! 858: EMU_MAXPTE * sizeof(u_int32_t),
! 859: EMU_DMA_ALIGN, EMU_DMAMEM_NSEG,
! 860: M_DEVBUF, M_WAITOK)) == NULL)
! 861: return (ENOMEM);
! 862:
! 863: /* This is necessary unless you like Metallic noise... */
! 864: if ((sc->silentpage = emuxki_dmamem_alloc(sc->sc_dmat, EMU_PTESIZE,
! 865: EMU_DMA_ALIGN, EMU_DMAMEM_NSEG, M_DEVBUF, M_WAITOK))==NULL){
! 866: emuxki_dmamem_free(sc->ptb, M_DEVBUF);
! 867: return (ENOMEM);
! 868: }
! 869:
! 870: /* Zero out the silent page */
! 871: /* This might not be always true, it might be 128 for 8bit channels */
! 872: memset(KERNADDR(sc->silentpage), 0, DMASIZE(sc->silentpage));
! 873:
! 874: /*
! 875: * Set all the PTB Entries to the silent page We shift the physical
! 876: * address by one and OR it with the page number. I don't know what
! 877: * the ORed index is for, might be a very useful unused feature...
! 878: */
! 879: silentpage = DMAADDR(sc->silentpage) << 1;
! 880: ptb = KERNADDR(sc->ptb);
! 881: for (i = 0; i < EMU_MAXPTE; i++)
! 882: ptb[i] = htole32(silentpage | i);
! 883:
! 884: /* Write PTB address and set TCB to none */
! 885: emuxki_write(sc, 0, EMU_PTB, DMAADDR(sc->ptb));
! 886: emuxki_write(sc, 0, EMU_TCBS, 0); /* This means 16K TCB */
! 887: emuxki_write(sc, 0, EMU_TCB, 0); /* No TCB use for now */
! 888:
! 889: /*
! 890: * Set channels MAPs to the silent page.
! 891: * I don't know what MAPs are for.
! 892: */
! 893: silentpage |= EMU_CHAN_MAP_PTI_MASK;
! 894: for (i = 0; i < EMU_NUMCHAN; i++) {
! 895: emuxki_write(sc, i, EMU_CHAN_MAPA, silentpage);
! 896: emuxki_write(sc, i, EMU_CHAN_MAPB, silentpage);
! 897: sc->channel[i] = NULL;
! 898: }
! 899:
! 900: /* Init voices list */
! 901: LIST_INIT(&(sc->voices));
! 902:
! 903: /* Timer is stopped */
! 904: sc->timerstate &= ~EMU_TIMER_STATE_ENABLED;
! 905: return (0);
! 906: }
! 907:
! 908: void
! 909: emuxki_shutdown(struct emuxki_softc *sc)
! 910: {
! 911: u_int32_t i;
! 912:
! 913: /* Disable any Channels interrupts */
! 914: emuxki_write(sc, 0, EMU_CLIEL, 0);
! 915: emuxki_write(sc, 0, EMU_CLIEH, 0);
! 916: emuxki_write(sc, 0, EMU_SOLEL, 0);
! 917: emuxki_write(sc, 0, EMU_SOLEH, 0);
! 918:
! 919: /*
! 920: * Should do some voice(stream) stopping stuff here, that's what will
! 921: * stop and deallocate all channels.
! 922: */
! 923:
! 924: /* Stop all channels */
! 925: /* XXX This shouldn't be necessary, I'll remove once everything works */
! 926: for (i = 0; i < EMU_NUMCHAN; i++)
! 927: emuxki_write(sc, i, EMU_CHAN_DCYSUSV, 0);
! 928: for (i = 0; i < EMU_NUMCHAN; i++) {
! 929: emuxki_write(sc, i, EMU_CHAN_VTFT, 0);
! 930: emuxki_write(sc, i, EMU_CHAN_CVCF, 0);
! 931: emuxki_write(sc, i, EMU_CHAN_PTRX, 0);
! 932: emuxki_write(sc, i, EMU_CHAN_CPF, 0);
! 933: }
! 934:
! 935: /*
! 936: * Deallocate Emu10k1 caches and recording buffers. Again it will be
! 937: * removed because it will be done in voice shutdown.
! 938: */
! 939: emuxki_write(sc, 0, EMU_MICBS, EMU_RECBS_BUFSIZE_NONE);
! 940: emuxki_write(sc, 0, EMU_MICBA, 0);
! 941: emuxki_write(sc, 0, EMU_FXBS, EMU_RECBS_BUFSIZE_NONE);
! 942: emuxki_write(sc, 0, EMU_FXBA, 0);
! 943: if(sc->sc_type & EMUXKI_AUDIGY) {
! 944: emuxki_write(sc, 0, EMU_A_FXWC1, 0);
! 945: emuxki_write(sc, 0, EMU_A_FXWC2, 0);
! 946: } else {
! 947: emuxki_write(sc, 0, EMU_FXWC, 0);
! 948: }
! 949: emuxki_write(sc, 0, EMU_ADCBS, EMU_RECBS_BUFSIZE_NONE);
! 950: emuxki_write(sc, 0, EMU_ADCBA, 0);
! 951:
! 952: /*
! 953: * XXX I don't know yet how I will handle tank cache buffer,
! 954: * I don't even clearly know what it is for.
! 955: */
! 956: emuxki_write(sc, 0, EMU_TCB, 0); /* 16K again */
! 957: emuxki_write(sc, 0, EMU_TCBS, 0);
! 958:
! 959: emuxki_write(sc, 0, EMU_DBG, 0x8000); /* necessary ? */
! 960:
! 961: emuxki_dmamem_free(sc->silentpage, M_DEVBUF);
! 962: emuxki_dmamem_free(sc->ptb, M_DEVBUF);
! 963: }
! 964:
! 965: /* Emu10k1 Memory management */
! 966:
! 967: struct emuxki_mem *
! 968: emuxki_mem_new(struct emuxki_softc *sc, int ptbidx,
! 969: size_t size, int type, int flags)
! 970: {
! 971: struct emuxki_mem *mem;
! 972:
! 973: if ((mem = malloc(sizeof(*mem), type, flags)) == NULL)
! 974: return (NULL);
! 975:
! 976: mem->ptbidx = ptbidx;
! 977: if ((mem->dmamem = emuxki_dmamem_alloc(sc->sc_dmat, size,
! 978: EMU_DMA_ALIGN, EMU_DMAMEM_NSEG, type, flags)) == NULL) {
! 979: free(mem, type);
! 980: return (NULL);
! 981: }
! 982: return (mem);
! 983: }
! 984:
! 985: void
! 986: emuxki_mem_delete(struct emuxki_mem *mem, int type)
! 987: {
! 988: emuxki_dmamem_free(mem->dmamem, type);
! 989: free(mem, type);
! 990: }
! 991:
! 992: void *
! 993: emuxki_pmem_alloc(struct emuxki_softc *sc, size_t size, int type, int flags)
! 994: {
! 995: int i, j, s;
! 996: size_t numblocks;
! 997: struct emuxki_mem *mem;
! 998: u_int32_t *ptb, silentpage;
! 999:
! 1000: ptb = KERNADDR(sc->ptb);
! 1001: silentpage = DMAADDR(sc->silentpage) << 1;
! 1002: numblocks = size / EMU_PTESIZE;
! 1003: if (size % EMU_PTESIZE)
! 1004: numblocks++;
! 1005:
! 1006: for (i = 0; i < EMU_MAXPTE; i++)
! 1007: if ((letoh32(ptb[i]) & EMU_CHAN_MAP_PTE_MASK) == silentpage) {
! 1008: /* We look for a free PTE */
! 1009: s = splaudio();
! 1010: for (j = 0; j < numblocks; j++)
! 1011: if ((letoh32(ptb[i + j])
! 1012: & EMU_CHAN_MAP_PTE_MASK)
! 1013: != silentpage)
! 1014: break;
! 1015: if (j == numblocks) {
! 1016: if ((mem = emuxki_mem_new(sc, i,
! 1017: size, type, flags)) == NULL) {
! 1018: splx(s);
! 1019: return (NULL);
! 1020: }
! 1021: for (j = 0; j < numblocks; j++)
! 1022: ptb[i + j] =
! 1023: htole32((((DMAADDR(mem->dmamem) +
! 1024: j * EMU_PTESIZE)) << 1) | (i + j));
! 1025: LIST_INSERT_HEAD(&(sc->mem), mem, next);
! 1026: splx(s);
! 1027: return (KERNADDR(mem->dmamem));
! 1028: } else
! 1029: i += j;
! 1030: splx(s);
! 1031: }
! 1032: return (NULL);
! 1033: }
! 1034:
! 1035: void *
! 1036: emuxki_rmem_alloc(struct emuxki_softc *sc, size_t size, int type, int flags)
! 1037: {
! 1038: struct emuxki_mem *mem;
! 1039: int s;
! 1040:
! 1041: mem = emuxki_mem_new(sc, EMU_RMEM, size, type, flags);
! 1042: if (mem == NULL)
! 1043: return (NULL);
! 1044:
! 1045: s = splaudio();
! 1046: LIST_INSERT_HEAD(&(sc->mem), mem, next);
! 1047: splx(s);
! 1048:
! 1049: return (KERNADDR(mem->dmamem));
! 1050: }
! 1051:
! 1052: /*
! 1053: * emuxki_channel_* : Channel management functions
! 1054: * emuxki_chanparms_* : Channel parameters modification functions
! 1055: */
! 1056:
! 1057: /*
! 1058: * is splaudio necessary here, can the same voice be manipulated by two
! 1059: * different threads at a time ?
! 1060: */
! 1061: void
! 1062: emuxki_chanparms_set_defaults(struct emuxki_channel *chan)
! 1063: {
! 1064: chan->fxsend.a.level = chan->fxsend.b.level =
! 1065: chan->fxsend.c.level = chan->fxsend.d.level =
! 1066: /* for audigy */
! 1067: chan->fxsend.e.level = chan->fxsend.f.level =
! 1068: chan->fxsend.g.level = chan->fxsend.h.level =
! 1069: chan->voice->sc->sc_type & EMUXKI_AUDIGY ?
! 1070: 0xc0 : 0xff; /* not max */
! 1071:
! 1072: chan->fxsend.a.dest = 0x0;
! 1073: chan->fxsend.b.dest = 0x1;
! 1074: chan->fxsend.c.dest = 0x2;
! 1075: chan->fxsend.d.dest = 0x3;
! 1076: /* for audigy */
! 1077: chan->fxsend.e.dest = 0x4;
! 1078: chan->fxsend.f.dest = 0x5;
! 1079: chan->fxsend.g.dest = 0x6;
! 1080: chan->fxsend.h.dest = 0x7;
! 1081:
! 1082: chan->pitch.initial = 0x0000; /* shouldn't it be 0xE000 ? */
! 1083: chan->pitch.current = 0x0000; /* should it be 0x0400 */
! 1084: chan->pitch.target = 0x0000; /* the unity pitch shift ? */
! 1085: chan->pitch.envelope_amount = 0x00; /* none */
! 1086:
! 1087: chan->initial_attenuation = 0x00; /* no attenuation */
! 1088: chan->volume.current = 0x0000; /* no volume */
! 1089: chan->volume.target = 0xffff;
! 1090: chan->volume.envelope.current_state = 0x8000; /* 0 msec delay */
! 1091: chan->volume.envelope.hold_time = 0x7f; /* 0 msec */
! 1092: chan->volume.envelope.attack_time = 0x7F; /* 5.5msec */
! 1093: chan->volume.envelope.sustain_level = 0x7F; /* full */
! 1094: chan->volume.envelope.decay_time = 0x7F; /* 22msec */
! 1095:
! 1096: chan->filter.initial_cutoff_frequency = 0xff; /* no filter */
! 1097: chan->filter.current_cutoff_frequency = 0xffff; /* no filtering */
! 1098: chan->filter.target_cutoff_frequency = 0xffff; /* no filtering */
! 1099: chan->filter.lowpass_resonance_height = 0x0;
! 1100: chan->filter.interpolation_ROM = 0x1; /* full band */
! 1101: chan->filter.envelope_amount = 0x7f; /* none */
! 1102: chan->filter.LFO_modulation_depth = 0x00; /* none */
! 1103:
! 1104: chan->loop.start = 0x000000;
! 1105: chan->loop.end = 0x000010; /* Why ? */
! 1106:
! 1107: chan->modulation.envelope.current_state = 0x8000;
! 1108: chan->modulation.envelope.hold_time = 0x00; /* 127 better ? */
! 1109: chan->modulation.envelope.attack_time = 0x00; /* infinite */
! 1110: chan->modulation.envelope.sustain_level = 0x00; /* off */
! 1111: chan->modulation.envelope.decay_time = 0x7f; /* 22 msec */
! 1112: chan->modulation.LFO_state = 0x8000;
! 1113:
! 1114: chan->vibrato_LFO.state = 0x8000;
! 1115: chan->vibrato_LFO.modulation_depth = 0x00; /* none */
! 1116: chan->vibrato_LFO.vibrato_depth = 0x00;
! 1117: chan->vibrato_LFO.frequency = 0x00; /* Why set to 24 when
! 1118: * initialized ? */
! 1119:
! 1120: chan->tremolo_depth = 0x00;
! 1121: }
! 1122:
! 1123: /* only call it at splaudio */
! 1124: struct emuxki_channel *
! 1125: emuxki_channel_new(struct emuxki_voice *voice, u_int8_t num)
! 1126: {
! 1127: struct emuxki_channel *chan;
! 1128:
! 1129: chan = malloc(sizeof(struct emuxki_channel), M_DEVBUF, M_WAITOK);
! 1130: if (chan == NULL)
! 1131: return (NULL);
! 1132:
! 1133: chan->voice = voice;
! 1134: chan->num = num;
! 1135: emuxki_chanparms_set_defaults(chan);
! 1136: chan->voice->sc->channel[num] = chan;
! 1137: return (chan);
! 1138: }
! 1139:
! 1140: /* only call it at splaudio */
! 1141: void
! 1142: emuxki_channel_delete(struct emuxki_channel *chan)
! 1143: {
! 1144: chan->voice->sc->channel[chan->num] = NULL;
! 1145: free(chan, M_DEVBUF);
! 1146: }
! 1147:
! 1148: void
! 1149: emuxki_channel_set_fxsend(struct emuxki_channel *chan,
! 1150: struct emuxki_chanparms_fxsend *fxsend)
! 1151: {
! 1152: /* Could do a memcpy ...*/
! 1153: chan->fxsend.a.level = fxsend->a.level;
! 1154: chan->fxsend.b.level = fxsend->b.level;
! 1155: chan->fxsend.c.level = fxsend->c.level;
! 1156: chan->fxsend.d.level = fxsend->d.level;
! 1157: chan->fxsend.a.dest = fxsend->a.dest;
! 1158: chan->fxsend.b.dest = fxsend->b.dest;
! 1159: chan->fxsend.c.dest = fxsend->c.dest;
! 1160: chan->fxsend.d.dest = fxsend->d.dest;
! 1161:
! 1162: /* for audigy */
! 1163: chan->fxsend.e.level = fxsend->e.level;
! 1164: chan->fxsend.f.level = fxsend->f.level;
! 1165: chan->fxsend.g.level = fxsend->g.level;
! 1166: chan->fxsend.h.level = fxsend->h.level;
! 1167: chan->fxsend.e.dest = fxsend->e.dest;
! 1168: chan->fxsend.f.dest = fxsend->f.dest;
! 1169: chan->fxsend.g.dest = fxsend->g.dest;
! 1170: chan->fxsend.h.dest = fxsend->h.dest;
! 1171: }
! 1172:
! 1173: void
! 1174: emuxki_channel_set_srate(struct emuxki_channel *chan, u_int32_t srate)
! 1175: {
! 1176: chan->pitch.target = (srate << 8) / 375;
! 1177: chan->pitch.target = (chan->pitch.target >> 1) +
! 1178: (chan->pitch.target & 1);
! 1179: chan->pitch.target &= 0xffff;
! 1180: chan->pitch.current = chan->pitch.target;
! 1181: chan->pitch.initial =
! 1182: (emuxki_rate_to_pitch(srate) >> 8) & EMU_CHAN_IP_MASK;
! 1183: }
! 1184:
! 1185: /* voice params must be set before calling this */
! 1186: void
! 1187: emuxki_channel_set_bufparms(struct emuxki_channel *chan,
! 1188: u_int32_t start, u_int32_t end)
! 1189: {
! 1190: chan->loop.start = start & EMU_CHAN_PSST_LOOPSTARTADDR_MASK;
! 1191: chan->loop.end = end & EMU_CHAN_DSL_LOOPENDADDR_MASK;
! 1192: }
! 1193:
! 1194: void
! 1195: emuxki_channel_commit_fx(struct emuxki_channel *chan)
! 1196: {
! 1197: struct emuxki_softc *sc = chan->voice->sc;
! 1198: u_int8_t chano = chan->num;
! 1199:
! 1200: if(sc->sc_type & EMUXKI_AUDIGY) {
! 1201: emuxki_write(sc, chano, EMU_A_CHAN_FXRT1,
! 1202: (chan->fxsend.d.dest << 24) |
! 1203: (chan->fxsend.c.dest << 16) |
! 1204: (chan->fxsend.b.dest << 8) |
! 1205: (chan->fxsend.a.dest));
! 1206: emuxki_write(sc, chano, EMU_A_CHAN_FXRT2,
! 1207: (chan->fxsend.h.dest << 24) |
! 1208: (chan->fxsend.g.dest << 16) |
! 1209: (chan->fxsend.f.dest << 8) |
! 1210: (chan->fxsend.e.dest));
! 1211: emuxki_write(sc, chano, EMU_A_CHAN_SENDAMOUNTS,
! 1212: (chan->fxsend.e.level << 24) |
! 1213: (chan->fxsend.f.level << 16) |
! 1214: (chan->fxsend.g.level << 8) |
! 1215: (chan->fxsend.h.level));
! 1216: } else {
! 1217: emuxki_write(sc, chano, EMU_CHAN_FXRT,
! 1218: (chan->fxsend.d.dest << 28) |
! 1219: (chan->fxsend.c.dest << 24) |
! 1220: (chan->fxsend.b.dest << 20) |
! 1221: (chan->fxsend.a.dest << 16));
! 1222: }
! 1223:
! 1224: emuxki_write(sc, chano, 0x10000000 | EMU_CHAN_PTRX,
! 1225: (chan->fxsend.a.level << 8) | chan->fxsend.b.level);
! 1226: emuxki_write(sc, chano, EMU_CHAN_DSL,
! 1227: (chan->fxsend.d.level << 24) | chan->loop.end);
! 1228: emuxki_write(sc, chano, EMU_CHAN_PSST,
! 1229: (chan->fxsend.c.level << 24) | chan->loop.start);
! 1230: }
! 1231:
! 1232: void
! 1233: emuxki_channel_commit_parms(struct emuxki_channel *chan)
! 1234: {
! 1235: struct emuxki_voice *voice = chan->voice;
! 1236: struct emuxki_softc *sc = voice->sc;
! 1237: u_int32_t start, mapval;
! 1238: u_int8_t chano = chan->num;
! 1239: int s;
! 1240:
! 1241: start = chan->loop.start +
! 1242: (voice->stereo ? 28 : 30) * (voice->b16 + 1);
! 1243: mapval = DMAADDR(sc->silentpage) << 1 | EMU_CHAN_MAP_PTI_MASK;
! 1244:
! 1245: s = splaudio();
! 1246: emuxki_write(sc, chano, EMU_CHAN_CPF_STEREO, voice->stereo);
! 1247:
! 1248: emuxki_channel_commit_fx(chan);
! 1249:
! 1250: emuxki_write(sc, chano, EMU_CHAN_CCCA,
! 1251: (chan->filter.lowpass_resonance_height << 28) |
! 1252: (chan->filter.interpolation_ROM << 25) |
! 1253: (voice->b16 ? 0 : EMU_CHAN_CCCA_8BITSELECT) | start);
! 1254: emuxki_write(sc, chano, EMU_CHAN_Z1, 0);
! 1255: emuxki_write(sc, chano, EMU_CHAN_Z2, 0);
! 1256: emuxki_write(sc, chano, EMU_CHAN_MAPA, mapval);
! 1257: emuxki_write(sc, chano, EMU_CHAN_MAPB, mapval);
! 1258: emuxki_write(sc, chano, EMU_CHAN_CVCF_CURRFILTER,
! 1259: chan->filter.current_cutoff_frequency);
! 1260: emuxki_write(sc, chano, EMU_CHAN_VTFT_FILTERTARGET,
! 1261: chan->filter.target_cutoff_frequency);
! 1262: emuxki_write(sc, chano, EMU_CHAN_ATKHLDM,
! 1263: (chan->modulation.envelope.hold_time << 8) |
! 1264: chan->modulation.envelope.attack_time);
! 1265: emuxki_write(sc, chano, EMU_CHAN_DCYSUSM,
! 1266: (chan->modulation.envelope.sustain_level << 8) |
! 1267: chan->modulation.envelope.decay_time);
! 1268: emuxki_write(sc, chano, EMU_CHAN_LFOVAL1,
! 1269: chan->modulation.LFO_state);
! 1270: emuxki_write(sc, chano, EMU_CHAN_LFOVAL2,
! 1271: chan->vibrato_LFO.state);
! 1272: emuxki_write(sc, chano, EMU_CHAN_FMMOD,
! 1273: (chan->vibrato_LFO.modulation_depth << 8) |
! 1274: chan->filter.LFO_modulation_depth);
! 1275: emuxki_write(sc, chano, EMU_CHAN_TREMFRQ,
! 1276: (chan->tremolo_depth << 8));
! 1277: emuxki_write(sc, chano, EMU_CHAN_FM2FRQ2,
! 1278: (chan->vibrato_LFO.vibrato_depth << 8) |
! 1279: chan->vibrato_LFO.frequency);
! 1280: emuxki_write(sc, chano, EMU_CHAN_ENVVAL,
! 1281: chan->modulation.envelope.current_state);
! 1282: emuxki_write(sc, chano, EMU_CHAN_ATKHLDV,
! 1283: (chan->volume.envelope.hold_time << 8) |
! 1284: chan->volume.envelope.attack_time);
! 1285: emuxki_write(sc, chano, EMU_CHAN_ENVVOL,
! 1286: chan->volume.envelope.current_state);
! 1287: emuxki_write(sc, chano, EMU_CHAN_PEFE,
! 1288: (chan->pitch.envelope_amount << 8) |
! 1289: chan->filter.envelope_amount);
! 1290: splx(s);
! 1291: }
! 1292:
! 1293: void
! 1294: emuxki_channel_start(struct emuxki_channel *chan)
! 1295: {
! 1296: struct emuxki_voice *voice = chan->voice;
! 1297: struct emuxki_softc *sc = voice->sc;
! 1298: u_int8_t cache_sample, cache_invalid_size, chano = chan->num;
! 1299: u_int32_t sample;
! 1300: int s;
! 1301:
! 1302: cache_sample = voice->stereo ? 4 : 2;
! 1303: sample = voice->b16 ? 0x00000000 : 0x80808080;
! 1304: cache_invalid_size = (voice->stereo ? 28 : 30) * (voice->b16 + 1);
! 1305:
! 1306: s = splaudio();
! 1307: while (cache_sample--) {
! 1308: emuxki_write(sc, chano, EMU_CHAN_CD0 + cache_sample,
! 1309: sample);
! 1310: }
! 1311: emuxki_write(sc, chano, EMU_CHAN_CCR_CACHEINVALIDSIZE, 0);
! 1312: emuxki_write(sc, chano, EMU_CHAN_CCR_READADDRESS, 64);
! 1313: emuxki_write(sc, chano, EMU_CHAN_CCR_CACHEINVALIDSIZE,
! 1314: cache_invalid_size);
! 1315: emuxki_write(sc, chano, EMU_CHAN_IFATN,
! 1316: (chan->filter.target_cutoff_frequency << 8) |
! 1317: chan->initial_attenuation);
! 1318: emuxki_write(sc, chano, EMU_CHAN_VTFT_VOLUMETARGET,
! 1319: chan->volume.target);
! 1320: emuxki_write(sc, chano, EMU_CHAN_CVCF_CURRVOL,
! 1321: chan->volume.current);
! 1322: emuxki_write(sc, 0,
! 1323: EMU_MKSUBREG(1, chano, EMU_SOLEL + (chano >> 5)),
! 1324: 0); /* Clear stop on loop */
! 1325: emuxki_write(sc, 0,
! 1326: EMU_MKSUBREG(1, chano, EMU_CLIEL + (chano >> 5)),
! 1327: 0); /* Clear loop interrupt */
! 1328: emuxki_write(sc, chano, EMU_CHAN_DCYSUSV,
! 1329: (chan->volume.envelope.sustain_level << 8) |
! 1330: chan->volume.envelope.decay_time);
! 1331: emuxki_write(sc, chano, EMU_CHAN_PTRX_PITCHTARGET,
! 1332: chan->pitch.target);
! 1333: emuxki_write(sc, chano, EMU_CHAN_CPF_PITCH,
! 1334: chan->pitch.current);
! 1335: emuxki_write(sc, chano, EMU_CHAN_IP, chan->pitch.initial);
! 1336:
! 1337: splx(s);
! 1338: }
! 1339:
! 1340: void
! 1341: emuxki_channel_stop(struct emuxki_channel *chan)
! 1342: {
! 1343: int s;
! 1344: u_int8_t chano = chan->num;
! 1345: struct emuxki_softc *sc = chan->voice->sc;
! 1346:
! 1347: s = splaudio();
! 1348: emuxki_write(sc, chano, EMU_CHAN_PTRX_PITCHTARGET, 0);
! 1349: emuxki_write(sc, chano, EMU_CHAN_CPF_PITCH, 0);
! 1350: emuxki_write(sc, chano, EMU_CHAN_IFATN_ATTENUATION, 0xff);
! 1351: emuxki_write(sc, chano, EMU_CHAN_VTFT_VOLUMETARGET, 0);
! 1352: emuxki_write(sc, chano, EMU_CHAN_CVCF_CURRVOL, 0);
! 1353: emuxki_write(sc, chano, EMU_CHAN_IP, 0);
! 1354: splx(s);
! 1355: }
! 1356:
! 1357: /*
! 1358: * Voices management
! 1359: * emuxki_voice_dataloc : use(play or rec) independent dataloc union helpers
! 1360: * emuxki_voice_channel_* : play part of dataloc union helpers
! 1361: * emuxki_voice_recsrc_* : rec part of dataloc union helpers
! 1362: */
! 1363:
! 1364: /* Allocate channels for voice in case of play voice */
! 1365: int
! 1366: emuxki_voice_channel_create(struct emuxki_voice *voice)
! 1367: {
! 1368: struct emuxki_channel **channel = voice->sc->channel;
! 1369: u_int8_t i, stereo = voice->stereo;
! 1370: int s;
! 1371:
! 1372: for (i = 0; i < EMU_NUMCHAN; i += stereo + 1) {
! 1373: if ((stereo && (channel[i + 1] != NULL)) ||
! 1374: (channel[i] != NULL)) /* Looking for free channels */
! 1375: continue;
! 1376: s = splaudio();
! 1377: if (stereo) {
! 1378: voice->dataloc.chan[1] =
! 1379: emuxki_channel_new(voice, i + 1);
! 1380: if (voice->dataloc.chan[1] == NULL) {
! 1381: splx(s);
! 1382: return (ENOMEM);
! 1383: }
! 1384: }
! 1385: voice->dataloc.chan[0] = emuxki_channel_new(voice, i);
! 1386: if (voice->dataloc.chan[0] == NULL) {
! 1387: if (stereo) {
! 1388: emuxki_channel_delete(voice->dataloc.chan[1]);
! 1389: voice->dataloc.chan[1] = NULL;
! 1390: }
! 1391: splx(s);
! 1392: return (ENOMEM);
! 1393: }
! 1394: splx(s);
! 1395: return (0);
! 1396: }
! 1397: return (EAGAIN);
! 1398: }
! 1399:
! 1400: /* When calling this function we assume no one can access the voice */
! 1401: void
! 1402: emuxki_voice_channel_destroy(struct emuxki_voice *voice)
! 1403: {
! 1404: emuxki_channel_delete(voice->dataloc.chan[0]);
! 1405: voice->dataloc.chan[0] = NULL;
! 1406: if (voice->stereo)
! 1407: emuxki_channel_delete(voice->dataloc.chan[1]);
! 1408: voice->dataloc.chan[1] = NULL;
! 1409: }
! 1410:
! 1411: /*
! 1412: * Will come back when used in voice_dataloc_create
! 1413: */
! 1414: int
! 1415: emuxki_recsrc_reserve(struct emuxki_voice *voice, emuxki_recsrc_t source)
! 1416: {
! 1417: if (source < 0 || source >= EMU_NUMRECSRCS) {
! 1418: #ifdef EMUXKI_DEBUG
! 1419: printf("Tried to reserve invalid source: %d\n", source);
! 1420: #endif
! 1421: return (EINVAL);
! 1422: }
! 1423: if (voice->sc->recsrc[source] == voice)
! 1424: return (0); /* XXX */
! 1425: if (voice->sc->recsrc[source] != NULL)
! 1426: return (EBUSY);
! 1427: voice->sc->recsrc[source] = voice;
! 1428: return (0);
! 1429: }
! 1430:
! 1431: /* When calling this function we assume the voice is stopped */
! 1432: void
! 1433: emuxki_voice_recsrc_release(struct emuxki_softc *sc, emuxki_recsrc_t source)
! 1434: {
! 1435: sc->recsrc[source] = NULL;
! 1436: }
! 1437:
! 1438: int
! 1439: emuxki_voice_dataloc_create(struct emuxki_voice *voice)
! 1440: {
! 1441: int error;
! 1442:
! 1443: if (voice->use & EMU_VOICE_USE_PLAY) {
! 1444: if ((error = emuxki_voice_channel_create(voice)))
! 1445: return (error);
! 1446: } else {
! 1447: if ((error =
! 1448: emuxki_recsrc_reserve(voice, voice->dataloc.source)))
! 1449: return (error);
! 1450: }
! 1451: return (0);
! 1452: }
! 1453:
! 1454: void
! 1455: emuxki_voice_dataloc_destroy(struct emuxki_voice *voice)
! 1456: {
! 1457: if (voice->use & EMU_VOICE_USE_PLAY) {
! 1458: if (voice->dataloc.chan[0] != NULL)
! 1459: emuxki_voice_channel_destroy(voice);
! 1460: } else {
! 1461: if (voice->dataloc.source != EMU_RECSRC_NOTSET) {
! 1462: emuxki_voice_recsrc_release(voice->sc,
! 1463: voice->dataloc.source);
! 1464: voice->dataloc.source = EMU_RECSRC_NOTSET;
! 1465: }
! 1466: }
! 1467: }
! 1468:
! 1469: struct emuxki_voice *
! 1470: emuxki_voice_new(struct emuxki_softc *sc, u_int8_t use)
! 1471: {
! 1472: struct emuxki_voice *voice;
! 1473: int s;
! 1474:
! 1475: s = splaudio();
! 1476: voice = sc->lvoice;
! 1477: sc->lvoice = NULL;
! 1478: splx(s);
! 1479:
! 1480: if (!voice) {
! 1481: if (!(voice = malloc(sizeof(*voice), M_DEVBUF, M_WAITOK)))
! 1482: return (NULL);
! 1483: } else if (voice->use != use)
! 1484: emuxki_voice_dataloc_destroy(voice);
! 1485: else
! 1486: goto skip_initialize;
! 1487:
! 1488: voice->sc = sc;
! 1489: voice->state = !EMU_VOICE_STATE_STARTED;
! 1490: voice->stereo = EMU_VOICE_STEREO_NOTSET;
! 1491: voice->b16 = 0;
! 1492: voice->sample_rate = 0;
! 1493: if (use & EMU_VOICE_USE_PLAY)
! 1494: voice->dataloc.chan[0] = voice->dataloc.chan[1] = NULL;
! 1495: else
! 1496: voice->dataloc.source = EMU_RECSRC_NOTSET;
! 1497: voice->buffer = NULL;
! 1498: voice->blksize = 0;
! 1499: voice->trigblk = 0;
! 1500: voice->blkmod = 0;
! 1501: voice->inth = NULL;
! 1502: voice->inthparam = NULL;
! 1503: voice->use = use;
! 1504:
! 1505: skip_initialize:
! 1506: s = splaudio();
! 1507: LIST_INSERT_HEAD((&sc->voices), voice, next);
! 1508: splx(s);
! 1509:
! 1510: return (voice);
! 1511: }
! 1512:
! 1513: void
! 1514: emuxki_voice_delete(struct emuxki_voice *voice)
! 1515: {
! 1516: struct emuxki_softc *sc = voice->sc;
! 1517: struct emuxki_voice *lvoice;
! 1518: int s;
! 1519:
! 1520: if (voice->state & EMU_VOICE_STATE_STARTED)
! 1521: emuxki_voice_halt(voice);
! 1522:
! 1523: s = splaudio();
! 1524: LIST_REMOVE(voice, next);
! 1525: lvoice = sc->lvoice;
! 1526: sc->lvoice = voice;
! 1527: splx(s);
! 1528:
! 1529: if (lvoice) {
! 1530: emuxki_voice_dataloc_destroy(lvoice);
! 1531: free(lvoice, M_DEVBUF);
! 1532: }
! 1533: }
! 1534:
! 1535: int
! 1536: emuxki_voice_set_stereo(struct emuxki_voice *voice, u_int8_t stereo)
! 1537: {
! 1538: int error;
! 1539: emuxki_recsrc_t source = 0; /* XXX: gcc */
! 1540: struct emuxki_chanparms_fxsend fxsend;
! 1541:
! 1542: if (! (voice->use & EMU_VOICE_USE_PLAY))
! 1543: source = voice->dataloc.source;
! 1544: emuxki_voice_dataloc_destroy(voice);
! 1545: if (! (voice->use & EMU_VOICE_USE_PLAY))
! 1546: voice->dataloc.source = source;
! 1547: voice->stereo = stereo;
! 1548: if ((error = emuxki_voice_dataloc_create(voice)))
! 1549: return (error);
! 1550: if (voice->use & EMU_VOICE_USE_PLAY) {
! 1551: fxsend.a.dest = 0x0;
! 1552: fxsend.b.dest = 0x1;
! 1553: fxsend.c.dest = 0x2;
! 1554: fxsend.d.dest = 0x3;
! 1555: /* for audigy */
! 1556: fxsend.e.dest = 0x4;
! 1557: fxsend.f.dest = 0x5;
! 1558: fxsend.g.dest = 0x6;
! 1559: fxsend.h.dest = 0x7;
! 1560: if (voice->stereo) {
! 1561: fxsend.a.level = fxsend.c.level = 0xc0;
! 1562: fxsend.b.level = fxsend.d.level = 0x00;
! 1563: fxsend.e.level = fxsend.g.level = 0xc0;
! 1564: fxsend.f.level = fxsend.h.level = 0x00;
! 1565: emuxki_channel_set_fxsend(voice->dataloc.chan[0],
! 1566: &fxsend);
! 1567: fxsend.a.level = fxsend.c.level = 0x00;
! 1568: fxsend.b.level = fxsend.d.level = 0xc0;
! 1569: fxsend.e.level = fxsend.g.level = 0x00;
! 1570: fxsend.f.level = fxsend.h.level = 0xc0;
! 1571: emuxki_channel_set_fxsend(voice->dataloc.chan[1],
! 1572: &fxsend);
! 1573: } /* No else : default is good for mono */
! 1574: }
! 1575: return (0);
! 1576: }
! 1577:
! 1578: int
! 1579: emuxki_voice_set_srate(struct emuxki_voice *voice, u_int32_t srate)
! 1580: {
! 1581: if (voice->use & EMU_VOICE_USE_PLAY) {
! 1582: if ((srate < 4000) || (srate > 48000))
! 1583: return (EINVAL);
! 1584: voice->sample_rate = srate;
! 1585: emuxki_channel_set_srate(voice->dataloc.chan[0], srate);
! 1586: if (voice->stereo)
! 1587: emuxki_channel_set_srate(voice->dataloc.chan[1],
! 1588: srate);
! 1589: } else {
! 1590: if ((srate < 8000) || (srate > 48000))
! 1591: return (EINVAL);
! 1592: voice->sample_rate = srate;
! 1593: if (emuxki_voice_adc_rate(voice) < 0) {
! 1594: voice->sample_rate = 0;
! 1595: return (EINVAL);
! 1596: }
! 1597: }
! 1598: return (0);
! 1599: }
! 1600:
! 1601: int
! 1602: emuxki_voice_set_audioparms(struct emuxki_voice *voice, u_int8_t stereo,
! 1603: u_int8_t b16, u_int32_t srate)
! 1604: {
! 1605: int error = 0;
! 1606:
! 1607: /*
! 1608: * Audio driver tried to set recording AND playing params even if
! 1609: * device opened in play or record only mode ==>
! 1610: * modified emuxki_set_params.
! 1611: * Stays here for now just in case ...
! 1612: */
! 1613: if (voice == NULL) {
! 1614: #ifdef EMUXKI_DEBUG
! 1615: printf("warning: tried to set unallocated voice params !!\n");
! 1616: #endif
! 1617: return (0);
! 1618: }
! 1619:
! 1620: if (voice->stereo == stereo && voice->b16 == b16 &&
! 1621: voice->sample_rate == srate)
! 1622: return (0);
! 1623:
! 1624: #ifdef EMUXKI_DEBUG
! 1625: printf("Setting %s voice params : %s, %u bits, %u hz\n",
! 1626: (voice->use & EMU_VOICE_USE_PLAY) ? "play" : "record",
! 1627: stereo ? "stereo" : "mono", (b16 + 1) * 8, srate);
! 1628: #endif
! 1629:
! 1630: if (voice->stereo != stereo) {
! 1631: if ((error = emuxki_voice_set_stereo(voice, stereo)))
! 1632: return (error);
! 1633: }
! 1634: voice->b16 = b16;
! 1635: if (voice->sample_rate != srate)
! 1636: error = emuxki_voice_set_srate(voice, srate);
! 1637: return error;
! 1638: }
! 1639:
! 1640: /* voice audio parms (see just before) must be set prior to this */
! 1641: int
! 1642: emuxki_voice_set_bufparms(struct emuxki_voice *voice, void *ptr,
! 1643: u_int32_t bufsize, u_int16_t blksize)
! 1644: {
! 1645: struct emuxki_mem *mem;
! 1646: struct emuxki_channel **chan;
! 1647: u_int32_t start, end;
! 1648: u_int8_t sample_size;
! 1649: int idx;
! 1650: int error = EFAULT;
! 1651:
! 1652: LIST_FOREACH(mem, &voice->sc->mem, next) {
! 1653: if (KERNADDR(mem->dmamem) != ptr)
! 1654: continue;
! 1655:
! 1656: voice->buffer = mem;
! 1657: sample_size = (voice->b16 + 1) * (voice->stereo + 1);
! 1658: voice->trigblk = 0; /* This shouldn't be needed */
! 1659: voice->blkmod = bufsize / blksize;
! 1660: if (bufsize % blksize) /* This should not happen */
! 1661: voice->blkmod++;
! 1662: error = 0;
! 1663:
! 1664: if (voice->use & EMU_VOICE_USE_PLAY) {
! 1665: voice->blksize = blksize / sample_size;
! 1666: chan = voice->dataloc.chan;
! 1667: start = (mem->ptbidx << 12) / sample_size;
! 1668: end = start + bufsize / sample_size;
! 1669: emuxki_channel_set_bufparms(chan[0],
! 1670: start, end);
! 1671: if (voice->stereo)
! 1672: emuxki_channel_set_bufparms(chan[1],
! 1673: start, end);
! 1674: voice->timerate = (u_int32_t) 48000 *
! 1675: voice->blksize / voice->sample_rate;
! 1676: if (voice->timerate < 5)
! 1677: error = EINVAL;
! 1678: } else {
! 1679: voice->blksize = blksize;
! 1680: for(idx = sizeof(emuxki_recbuf_sz) /
! 1681: sizeof(emuxki_recbuf_sz[0]); --idx >= 0;)
! 1682: if (emuxki_recbuf_sz[idx] == bufsize)
! 1683: break;
! 1684: if (idx < 0) {
! 1685: #ifdef EMUXKI_DEBUG
! 1686: printf("Invalid bufsize: %d\n", bufsize);
! 1687: #endif
! 1688: return (EINVAL);
! 1689: }
! 1690: emuxki_write(voice->sc, 0,
! 1691: emuxki_recsrc_szreg[voice->dataloc.source], idx);
! 1692: emuxki_write(voice->sc, 0,
! 1693: emuxki_recsrc_bufaddrreg[voice->dataloc.source],
! 1694: DMAADDR(mem->dmamem));
! 1695:
! 1696: /* Use timer to emulate DMA completion interrupt */
! 1697: voice->timerate = (u_int32_t) 48000 * blksize /
! 1698: (voice->sample_rate * sample_size);
! 1699: if (voice->timerate < 5) {
! 1700: #ifdef EMUXKI_DEBUG
! 1701: printf("Invalid timerate: %d, blksize %d\n",
! 1702: voice->timerate, blksize);
! 1703: #endif
! 1704: error = EINVAL;
! 1705: }
! 1706: }
! 1707:
! 1708: break;
! 1709: }
! 1710:
! 1711: return (error);
! 1712: }
! 1713:
! 1714: void
! 1715: emuxki_voice_commit_parms(struct emuxki_voice *voice)
! 1716: {
! 1717: if (voice->use & EMU_VOICE_USE_PLAY) {
! 1718: emuxki_channel_commit_parms(voice->dataloc.chan[0]);
! 1719: if (voice->stereo)
! 1720: emuxki_channel_commit_parms(voice->dataloc.chan[1]);
! 1721: }
! 1722: }
! 1723:
! 1724: u_int32_t
! 1725: emuxki_voice_curaddr(struct emuxki_voice *voice)
! 1726: {
! 1727: int idxreg = 0;
! 1728:
! 1729: /* XXX different semantics in these cases */
! 1730: if (voice->use & EMU_VOICE_USE_PLAY) {
! 1731: /* returns number of samples (an l/r pair counts 1) */
! 1732: return (emuxki_read(voice->sc,
! 1733: voice->dataloc.chan[0]->num,
! 1734: EMU_CHAN_CCCA_CURRADDR) -
! 1735: voice->dataloc.chan[0]->loop.start);
! 1736: } else {
! 1737: /* returns number of bytes */
! 1738: switch (voice->dataloc.source) {
! 1739: case EMU_RECSRC_MIC:
! 1740: idxreg = (voice->sc->sc_type & EMUXKI_AUDIGY) ?
! 1741: EMU_A_MICIDX : EMU_MICIDX;
! 1742: break;
! 1743: case EMU_RECSRC_ADC:
! 1744: idxreg = (voice->sc->sc_type & EMUXKI_AUDIGY) ?
! 1745: EMU_A_ADCIDX : EMU_ADCIDX;
! 1746: break;
! 1747: case EMU_RECSRC_FX:
! 1748: idxreg = EMU_FXIDX;
! 1749: break;
! 1750: default:
! 1751: #ifdef EMUXKI_DEBUG
! 1752: printf("emu: bad recording source!\n");
! 1753: #endif
! 1754: break;
! 1755: }
! 1756: return (emuxki_read(voice->sc, 0, EMU_RECIDX(idxreg))
! 1757: & EMU_RECIDX_MASK);
! 1758: }
! 1759: return (0);
! 1760: }
! 1761:
! 1762: void
! 1763: emuxki_resched_timer(struct emuxki_softc *sc)
! 1764: {
! 1765: struct emuxki_voice *voice;
! 1766: u_int16_t timerate = 1024;
! 1767: u_int8_t active = 0;
! 1768: int s;
! 1769:
! 1770: s = splaudio();
! 1771: LIST_FOREACH(voice, &sc->voices, next) {
! 1772: if ((voice->state & EMU_VOICE_STATE_STARTED) == 0)
! 1773: continue;
! 1774: active = 1;
! 1775: if (voice->timerate < timerate)
! 1776: timerate = voice->timerate;
! 1777: }
! 1778:
! 1779: if (timerate & ~EMU_TIMER_RATE_MASK)
! 1780: timerate = 0;
! 1781: bus_space_write_2(sc->sc_iot, sc->sc_ioh, EMU_TIMER, timerate);
! 1782: if (!active && (sc->timerstate & EMU_TIMER_STATE_ENABLED)) {
! 1783: bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_INTE,
! 1784: bus_space_read_4(sc->sc_iot, sc->sc_ioh, EMU_INTE) &
! 1785: ~EMU_INTE_INTERTIMERENB);
! 1786: sc->timerstate &= ~EMU_TIMER_STATE_ENABLED;
! 1787: } else if (active && !(sc->timerstate & EMU_TIMER_STATE_ENABLED)) {
! 1788: bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_INTE,
! 1789: bus_space_read_4(sc->sc_iot, sc->sc_ioh, EMU_INTE) |
! 1790: EMU_INTE_INTERTIMERENB);
! 1791: sc->timerstate |= EMU_TIMER_STATE_ENABLED;
! 1792: }
! 1793: splx(s);
! 1794: }
! 1795:
! 1796: int
! 1797: emuxki_voice_adc_rate(struct emuxki_voice *voice)
! 1798: {
! 1799: switch(voice->sample_rate) {
! 1800: case 48000:
! 1801: return EMU_ADCCR_SAMPLERATE_48;
! 1802: break;
! 1803: case 44100:
! 1804: return EMU_ADCCR_SAMPLERATE_44;
! 1805: break;
! 1806: case 32000:
! 1807: return EMU_ADCCR_SAMPLERATE_32;
! 1808: break;
! 1809: case 24000:
! 1810: return EMU_ADCCR_SAMPLERATE_24;
! 1811: break;
! 1812: case 22050:
! 1813: return EMU_ADCCR_SAMPLERATE_22;
! 1814: break;
! 1815: case 16000:
! 1816: return EMU_ADCCR_SAMPLERATE_16;
! 1817: break;
! 1818: case 12000:
! 1819: if(voice->sc->sc_type & EMUXKI_AUDIGY)
! 1820: return EMU_A_ADCCR_SAMPLERATE_12;
! 1821: else {
! 1822: #ifdef EMUXKI_DEBUG
! 1823: printf("recording sample_rate not supported : %u\n", voice->sample_rate);
! 1824: #endif
! 1825: return (-1);
! 1826: }
! 1827: break;
! 1828: case 11000:
! 1829: if(voice->sc->sc_type & EMUXKI_AUDIGY)
! 1830: return EMU_A_ADCCR_SAMPLERATE_11;
! 1831: else
! 1832: return EMU_ADCCR_SAMPLERATE_11;
! 1833: break;
! 1834: case 8000:
! 1835: if(voice->sc->sc_type & EMUXKI_AUDIGY)
! 1836: return EMU_A_ADCCR_SAMPLERATE_8;
! 1837: else
! 1838: return EMU_ADCCR_SAMPLERATE_8;
! 1839: break;
! 1840: default:
! 1841: #ifdef EMUXKI_DEBUG
! 1842: printf("recording sample_rate not supported : %u\n", voice->sample_rate);
! 1843: #endif
! 1844: return (-1);
! 1845: }
! 1846: return (-1); /* shouldn't get here */
! 1847: }
! 1848:
! 1849: void
! 1850: emuxki_voice_start(struct emuxki_voice *voice,
! 1851: void (*inth) (void *), void *inthparam)
! 1852: {
! 1853: u_int32_t val;
! 1854:
! 1855: voice->inth = inth;
! 1856: voice->inthparam = inthparam;
! 1857: if (voice->use & EMU_VOICE_USE_PLAY) {
! 1858: voice->trigblk = 1;
! 1859: emuxki_channel_start(voice->dataloc.chan[0]);
! 1860: if (voice->stereo)
! 1861: emuxki_channel_start(voice->dataloc.chan[1]);
! 1862: } else {
! 1863: voice->trigblk = 1;
! 1864: switch (voice->dataloc.source) {
! 1865: case EMU_RECSRC_ADC:
! 1866: /* XXX need to program DSP to output L+R
! 1867: * XXX in monaural case? */
! 1868: if (voice->sc->sc_type & EMUXKI_AUDIGY) {
! 1869: val = EMU_A_ADCCR_LCHANENABLE;
! 1870: if (voice->stereo)
! 1871: val |= EMU_A_ADCCR_RCHANENABLE;
! 1872: } else {
! 1873: val = EMU_ADCCR_LCHANENABLE;
! 1874: if (voice->stereo)
! 1875: val |= EMU_ADCCR_RCHANENABLE;
! 1876: }
! 1877: val |= emuxki_voice_adc_rate(voice);
! 1878: emuxki_write(voice->sc, 0, EMU_ADCCR, 0);
! 1879: emuxki_write(voice->sc, 0, EMU_ADCCR, val);
! 1880: break;
! 1881: case EMU_RECSRC_MIC:
! 1882: case EMU_RECSRC_FX:
! 1883: printf("unimplemented\n");
! 1884: break;
! 1885: case EMU_RECSRC_NOTSET:
! 1886: default:
! 1887: break;
! 1888: }
! 1889: #if 0
! 1890: /* DMA completion interrupt is useless; use timer */
! 1891: int s;
! 1892: s = splaudio();
! 1893: val = emu_rd(sc, INTE, 4);
! 1894: val |= emuxki_recsrc_intrmasks[voice->dataloc.source];
! 1895: emu_wr(sc, INTE, val, 4);
! 1896: splx(s);
! 1897: #endif
! 1898: }
! 1899: voice->state |= EMU_VOICE_STATE_STARTED;
! 1900: emuxki_resched_timer(voice->sc);
! 1901: }
! 1902:
! 1903: void
! 1904: emuxki_voice_halt(struct emuxki_voice *voice)
! 1905: {
! 1906: if (voice->use & EMU_VOICE_USE_PLAY) {
! 1907: emuxki_channel_stop(voice->dataloc.chan[0]);
! 1908: if (voice->stereo)
! 1909: emuxki_channel_stop(voice->dataloc.chan[1]);
! 1910: } else {
! 1911: switch (voice->dataloc.source) {
! 1912: case EMU_RECSRC_ADC:
! 1913: emuxki_write(voice->sc, 0, EMU_ADCCR, 0);
! 1914: break;
! 1915: case EMU_RECSRC_FX:
! 1916: case EMU_RECSRC_MIC:
! 1917: printf("unimplemented\n");
! 1918: break;
! 1919: case EMU_RECSRC_NOTSET:
! 1920: printf("Bad dataloc.source\n");
! 1921: }
! 1922: /* This should reset buffer pointer */
! 1923: emuxki_write(voice->sc, 0,
! 1924: emuxki_recsrc_szreg[voice->dataloc.source],
! 1925: EMU_RECBS_BUFSIZE_NONE);
! 1926: #if 0
! 1927: int s;
! 1928: s = splaudio();
! 1929: val = emu_rd(sc, INTE, 4);
! 1930: val &= ~emuxki_recsrc_intrmasks[voice->dataloc.source];
! 1931: emu_wr(sc, INTE, val, 4);
! 1932: splx(s);
! 1933: #endif
! 1934: }
! 1935: voice->state &= ~EMU_VOICE_STATE_STARTED;
! 1936: emuxki_resched_timer(voice->sc);
! 1937: }
! 1938:
! 1939: /*
! 1940: * The interrupt handler
! 1941: */
! 1942: int
! 1943: emuxki_intr(void *arg)
! 1944: {
! 1945: struct emuxki_softc *sc = arg;
! 1946: u_int32_t ipr, curblk, us = 0;
! 1947: struct emuxki_voice *voice;
! 1948:
! 1949: while ((ipr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, EMU_IPR))) {
! 1950: if (ipr & EMU_IPR_INTERVALTIMER) {
! 1951: LIST_FOREACH(voice, &sc->voices, next) {
! 1952: if ((voice->state &
! 1953: EMU_VOICE_STATE_STARTED) == 0)
! 1954: continue;
! 1955:
! 1956: curblk = emuxki_voice_curaddr(voice) /
! 1957: voice->blksize;
! 1958: #if 0
! 1959: if (curblk == voice->trigblk) {
! 1960: voice->inth(voice->inthparam);
! 1961: voice->trigblk++;
! 1962: voice->trigblk %= voice->blkmod;
! 1963: }
! 1964: #else
! 1965: while ((curblk >= voice->trigblk &&
! 1966: curblk < (voice->trigblk + voice->blkmod / 2)) ||
! 1967: ((int)voice->trigblk - (int)curblk) >
! 1968: (voice->blkmod / 2 + 1)) {
! 1969: voice->inth(voice->inthparam);
! 1970: voice->trigblk++;
! 1971: voice->trigblk %= voice->blkmod;
! 1972: }
! 1973: #endif
! 1974: }
! 1975: us = 1;
! 1976: }
! 1977:
! 1978: /* Got interrupt */
! 1979: bus_space_write_4(sc->sc_iot, sc->sc_ioh, EMU_IPR, ipr);
! 1980: }
! 1981:
! 1982: return (us);
! 1983: }
! 1984:
! 1985:
! 1986: /*
! 1987: * Audio Architecture callbacks
! 1988: */
! 1989:
! 1990: int
! 1991: emuxki_open(void *addr, int flags)
! 1992: {
! 1993: struct emuxki_softc *sc = addr;
! 1994:
! 1995: #ifdef EMUXKI_DEBUG
! 1996: printf("%s: emuxki_open called\n", sc->sc_dev.dv_xname);
! 1997: #endif
! 1998:
! 1999: /*
! 2000: * Multiple voice support would be added as soon as I find a way to
! 2001: * trick the audio arch into supporting multiple voices.
! 2002: * Or I might integrate a modified audio arch supporting
! 2003: * multiple voices.
! 2004: */
! 2005:
! 2006: /*
! 2007: * I did this because i have problems identifying the selected
! 2008: * recording source(s) which is necessary when setting recording
! 2009: * params. This will be addressed very soon.
! 2010: */
! 2011: if (flags & AUOPEN_READ) {
! 2012: sc->rvoice = emuxki_voice_new(sc, 0 /* EMU_VOICE_USE_RECORD */);
! 2013: if (sc->rvoice == NULL)
! 2014: return (EBUSY);
! 2015:
! 2016: /* XXX Hardcode RECSRC_ADC for now */
! 2017: sc->rvoice->dataloc.source = EMU_RECSRC_ADC;
! 2018: }
! 2019:
! 2020: if (flags & AUOPEN_WRITE) {
! 2021: sc->pvoice = emuxki_voice_new(sc, EMU_VOICE_USE_PLAY);
! 2022: if (sc->pvoice == NULL) {
! 2023: if (flags & AUOPEN_READ)
! 2024: emuxki_voice_delete(sc->rvoice);
! 2025: return (EBUSY);
! 2026: }
! 2027: }
! 2028:
! 2029: return (0);
! 2030: }
! 2031:
! 2032: void
! 2033: emuxki_close(void *addr)
! 2034: {
! 2035: struct emuxki_softc *sc = addr;
! 2036:
! 2037: #ifdef EMUXKI_DEBUG
! 2038: printf("%s: emu10K1_close called\n", sc->sc_dev.dv_xname);
! 2039: #endif
! 2040:
! 2041: /* No multiple voice support for now */
! 2042: if (sc->rvoice != NULL)
! 2043: emuxki_voice_delete(sc->rvoice);
! 2044: sc->rvoice = NULL;
! 2045: if (sc->pvoice != NULL)
! 2046: emuxki_voice_delete(sc->pvoice);
! 2047: sc->pvoice = NULL;
! 2048: }
! 2049:
! 2050: int
! 2051: emuxki_query_encoding(void *addr, struct audio_encoding *fp)
! 2052: {
! 2053: #ifdef EMUXKI_DEBUG
! 2054: struct emuxki_softc *sc = addr;
! 2055:
! 2056: printf("%s: emuxki_query_encoding called\n", sc->sc_dev.dv_xname);
! 2057: #endif
! 2058:
! 2059: switch (fp->index) {
! 2060: case 0:
! 2061: strlcpy(fp->name, AudioEulinear, sizeof fp->name);
! 2062: fp->encoding = AUDIO_ENCODING_ULINEAR;
! 2063: fp->precision = 8;
! 2064: fp->flags = 0;
! 2065: break;
! 2066: case 1:
! 2067: strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
! 2068: fp->encoding = AUDIO_ENCODING_ULAW;
! 2069: fp->precision = 8;
! 2070: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 2071: break;
! 2072: case 2:
! 2073: strlcpy(fp->name, AudioEalaw, sizeof fp->name);
! 2074: fp->encoding = AUDIO_ENCODING_ALAW;
! 2075: fp->precision = 8;
! 2076: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 2077: break;
! 2078: case 3:
! 2079: strlcpy(fp->name, AudioEslinear, sizeof fp->name);
! 2080: fp->encoding = AUDIO_ENCODING_SLINEAR;
! 2081: fp->precision = 8;
! 2082: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 2083: break;
! 2084: case 4:
! 2085: strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
! 2086: fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
! 2087: fp->precision = 16;
! 2088: fp->flags = 0;
! 2089: break;
! 2090: case 5:
! 2091: strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
! 2092: fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
! 2093: fp->precision = 16;
! 2094: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 2095: break;
! 2096: case 6:
! 2097: strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
! 2098: fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
! 2099: fp->precision = 16;
! 2100: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 2101: break;
! 2102: case 7:
! 2103: strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
! 2104: fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
! 2105: fp->precision = 16;
! 2106: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 2107: break;
! 2108: default:
! 2109: return (EINVAL);
! 2110: }
! 2111: return (0);
! 2112: }
! 2113:
! 2114: int
! 2115: emuxki_set_vparms(struct emuxki_voice *voice, struct audio_params *p)
! 2116: {
! 2117: u_int8_t b16, mode;
! 2118:
! 2119: mode = (voice->use & EMU_VOICE_USE_PLAY) ?
! 2120: AUMODE_PLAY : AUMODE_RECORD;
! 2121: p->factor = 1;
! 2122: p->sw_code = NULL;
! 2123: if (p->channels != 1 && p->channels != 2)
! 2124: return (EINVAL);/* Will change when streams come in use */
! 2125:
! 2126: /*
! 2127: * Always use slinear_le for recording, as how to set otherwise
! 2128: * isn't known.
! 2129: */
! 2130: if (mode == AUMODE_PLAY)
! 2131: b16 = (p->precision == 16);
! 2132: else {
! 2133: b16 = 1;
! 2134: if (p->precision == 8)
! 2135: p->factor *= 2;
! 2136: }
! 2137:
! 2138: switch (p->encoding) {
! 2139: case AUDIO_ENCODING_ULAW:
! 2140: if (mode == AUMODE_PLAY) {
! 2141: p->factor = 2;
! 2142: p->sw_code = mulaw_to_slinear16_le;
! 2143: b16 = 1;
! 2144: } else
! 2145: p->sw_code = slinear16_to_mulaw_le;
! 2146: break;
! 2147:
! 2148: case AUDIO_ENCODING_ALAW:
! 2149: if (mode == AUMODE_PLAY) {
! 2150: p->factor = 2;
! 2151: p->sw_code = alaw_to_slinear16_le;
! 2152: b16 = 1;
! 2153: } else
! 2154: p->sw_code = slinear16_to_alaw_le;
! 2155: break;
! 2156:
! 2157: case AUDIO_ENCODING_SLINEAR_LE:
! 2158: if (p->precision == 8) {
! 2159: if (mode == AUMODE_PLAY)
! 2160: p->sw_code = change_sign8;
! 2161: else
! 2162: p->sw_code = linear16_to_linear8_le;
! 2163: }
! 2164: break;
! 2165:
! 2166: case AUDIO_ENCODING_ULINEAR_LE:
! 2167: if (p->precision == 16)
! 2168: p->sw_code = change_sign16_le;
! 2169: else if (mode == AUMODE_RECORD)
! 2170: p->sw_code = slinear16_to_ulinear8_le;
! 2171: break;
! 2172:
! 2173: case AUDIO_ENCODING_SLINEAR_BE:
! 2174: if (p->precision == 16)
! 2175: p->sw_code = swap_bytes;
! 2176: else {
! 2177: if (mode == AUMODE_PLAY)
! 2178: p->sw_code = change_sign8;
! 2179: else
! 2180: p->sw_code = linear16_to_linear8_le;
! 2181: }
! 2182: break;
! 2183:
! 2184: case AUDIO_ENCODING_ULINEAR_BE:
! 2185: if (p->precision == 16) {
! 2186: if (mode == AUMODE_PLAY)
! 2187: p->sw_code = swap_bytes_change_sign16_le;
! 2188: else
! 2189: p->sw_code = change_sign16_swap_bytes_le;
! 2190: } else if (mode == AUMODE_RECORD)
! 2191: p->sw_code = slinear16_to_ulinear8_le;
! 2192: break;
! 2193:
! 2194: default:
! 2195: return (EINVAL);
! 2196: }
! 2197:
! 2198: return (emuxki_voice_set_audioparms(voice, p->channels == 2,
! 2199: b16, p->sample_rate));
! 2200: }
! 2201:
! 2202: int
! 2203: emuxki_set_params(void *addr, int setmode, int usemode,
! 2204: struct audio_params *play, struct audio_params *rec)
! 2205: {
! 2206: struct emuxki_softc *sc = addr;
! 2207: int mode, error;
! 2208: struct audio_params *p;
! 2209:
! 2210: for (mode = AUMODE_RECORD; mode != -1;
! 2211: mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
! 2212: if ((usemode & setmode & mode) == 0)
! 2213: continue;
! 2214:
! 2215: p = (mode == AUMODE_PLAY) ? play : rec;
! 2216:
! 2217: /* No multiple voice support for now */
! 2218: if ((error = emuxki_set_vparms((mode == AUMODE_PLAY) ?
! 2219: sc->pvoice : sc->rvoice, p)))
! 2220: return (error);
! 2221: }
! 2222:
! 2223: return (0);
! 2224: }
! 2225:
! 2226: int
! 2227: emuxki_halt_output(void *addr)
! 2228: {
! 2229: struct emuxki_softc *sc = addr;
! 2230:
! 2231: /* No multiple voice support for now */
! 2232: if (sc->pvoice == NULL)
! 2233: return (ENXIO);
! 2234:
! 2235: emuxki_voice_halt(sc->pvoice);
! 2236: return (0);
! 2237: }
! 2238:
! 2239: int
! 2240: emuxki_halt_input(void *addr)
! 2241: {
! 2242: struct emuxki_softc *sc = addr;
! 2243:
! 2244: #ifdef EMUXKI_DEBUG
! 2245: printf("%s: emuxki_halt_input called\n", sc->sc_dev.dv_xname);
! 2246: #endif
! 2247:
! 2248: /* No multiple voice support for now */
! 2249: if (sc->rvoice == NULL)
! 2250: return (ENXIO);
! 2251: emuxki_voice_halt(sc->rvoice);
! 2252: return (0);
! 2253: }
! 2254:
! 2255: int
! 2256: emuxki_getdev(void *v, struct audio_device *adp)
! 2257: {
! 2258: struct emuxki_softc *sc = v;
! 2259: *adp = sc->sc_audv;
! 2260: return 0;
! 2261: }
! 2262:
! 2263: int
! 2264: emuxki_set_port(void *addr, mixer_ctrl_t *mctl)
! 2265: {
! 2266: struct emuxki_softc *sc = addr;
! 2267:
! 2268: return sc->codecif->vtbl->mixer_set_port(sc->codecif, mctl);
! 2269: }
! 2270:
! 2271: int
! 2272: emuxki_get_port(void *addr, mixer_ctrl_t *mctl)
! 2273: {
! 2274: struct emuxki_softc *sc = addr;
! 2275:
! 2276: return sc->codecif->vtbl->mixer_get_port(sc->codecif, mctl);
! 2277: }
! 2278:
! 2279: int
! 2280: emuxki_query_devinfo(void *addr, mixer_devinfo_t *minfo)
! 2281: {
! 2282: struct emuxki_softc *sc = addr;
! 2283:
! 2284: return sc->codecif->vtbl->query_devinfo(sc->codecif, minfo);
! 2285: }
! 2286:
! 2287: void *
! 2288: emuxki_allocm(void *addr, int direction, size_t size, int type, int flags)
! 2289: {
! 2290: struct emuxki_softc *sc = addr;
! 2291:
! 2292: if (direction == AUMODE_PLAY)
! 2293: return emuxki_pmem_alloc(sc, size, type, flags);
! 2294: else
! 2295: return emuxki_rmem_alloc(sc, size, type, flags);
! 2296: }
! 2297:
! 2298: void
! 2299: emuxki_freem(void *addr, void *ptr, int type)
! 2300: {
! 2301: struct emuxki_softc *sc = addr;
! 2302: int i, s;
! 2303: struct emuxki_mem *mem;
! 2304: size_t numblocks;
! 2305: u_int32_t *ptb, silentpage;
! 2306:
! 2307: ptb = KERNADDR(sc->ptb);
! 2308: silentpage = DMAADDR(sc->silentpage) << 1;
! 2309: LIST_FOREACH(mem, &sc->mem, next) {
! 2310: if (KERNADDR(mem->dmamem) != ptr)
! 2311: continue;
! 2312:
! 2313: s = splaudio();
! 2314: if (mem->ptbidx != EMU_RMEM) {
! 2315: numblocks = DMASIZE(mem->dmamem) / EMU_PTESIZE;
! 2316: if (DMASIZE(mem->dmamem) % EMU_PTESIZE)
! 2317: numblocks++;
! 2318: for (i = 0; i < numblocks; i++)
! 2319: ptb[mem->ptbidx + i] =
! 2320: htole32(silentpage | (mem->ptbidx + i));
! 2321: }
! 2322: LIST_REMOVE(mem, next);
! 2323: splx(s);
! 2324:
! 2325: emuxki_mem_delete(mem, type);
! 2326: break;
! 2327: }
! 2328: }
! 2329:
! 2330: /* blocksize should be a divisor of allowable buffersize */
! 2331: /* XXX probably this could be done better */
! 2332: int
! 2333: emuxki_round_blocksize(void *addr, int blksize)
! 2334: {
! 2335: int bufsize = 65536;
! 2336:
! 2337: while (bufsize > blksize)
! 2338: bufsize /= 2;
! 2339:
! 2340: return bufsize;
! 2341: }
! 2342:
! 2343: size_t
! 2344: emuxki_round_buffersize(void *addr, int direction, size_t bsize)
! 2345: {
! 2346:
! 2347: if (direction == AUMODE_PLAY) {
! 2348: if (bsize < EMU_PTESIZE)
! 2349: bsize = EMU_PTESIZE;
! 2350: else if (bsize > (EMU_PTESIZE * EMU_MAXPTE))
! 2351: bsize = EMU_PTESIZE * EMU_MAXPTE;
! 2352: /* Would be better if set to max available */
! 2353: else if (bsize % EMU_PTESIZE)
! 2354: bsize = bsize -
! 2355: (bsize % EMU_PTESIZE) +
! 2356: EMU_PTESIZE;
! 2357: } else {
! 2358: int idx;
! 2359:
! 2360: /* find nearest lower recbuf size */
! 2361: for(idx = sizeof(emuxki_recbuf_sz) /
! 2362: sizeof(emuxki_recbuf_sz[0]); --idx >= 0; ) {
! 2363: if (bsize >= emuxki_recbuf_sz[idx]) {
! 2364: bsize = emuxki_recbuf_sz[idx];
! 2365: break;
! 2366: }
! 2367: }
! 2368:
! 2369: if (bsize == 0)
! 2370: bsize = 384;
! 2371: }
! 2372:
! 2373: return (bsize);
! 2374: }
! 2375:
! 2376: paddr_t
! 2377: emuxki_mappage(void *addr, void *ptr, off_t off, int prot)
! 2378: {
! 2379: struct emuxki_softc *sc = addr;
! 2380: struct emuxki_mem *mem;
! 2381:
! 2382: LIST_FOREACH(mem, &sc->mem, next) {
! 2383: if (KERNADDR(mem->dmamem) == ptr) {
! 2384: struct dmamem *dm = mem->dmamem;
! 2385:
! 2386: return bus_dmamem_mmap(dm->dmat, dm->segs, dm->nsegs,
! 2387: off, prot, BUS_DMA_WAITOK);
! 2388: }
! 2389: }
! 2390:
! 2391: return (-1);
! 2392: }
! 2393:
! 2394: int
! 2395: emuxki_get_props(void *addr)
! 2396: {
! 2397: return (AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT |
! 2398: AUDIO_PROP_FULLDUPLEX);
! 2399: }
! 2400:
! 2401: int
! 2402: emuxki_trigger_output(void *addr, void *start, void *end, int blksize,
! 2403: void (*inth) (void *), void *inthparam,
! 2404: struct audio_params *params)
! 2405: {
! 2406: struct emuxki_softc *sc = addr;
! 2407: /* No multiple voice support for now */
! 2408: struct emuxki_voice *voice = sc->pvoice;
! 2409: int error;
! 2410:
! 2411: if (voice == NULL)
! 2412: return (ENXIO);
! 2413: if ((error = emuxki_set_vparms(voice, params)))
! 2414: return (error);
! 2415: if ((error = emuxki_voice_set_bufparms(voice, start,
! 2416: (caddr_t)end - (caddr_t)start, blksize)))
! 2417: return (error);
! 2418: emuxki_voice_commit_parms(voice);
! 2419: emuxki_voice_start(voice, inth, inthparam);
! 2420:
! 2421: return (0);
! 2422: }
! 2423:
! 2424: int
! 2425: emuxki_trigger_input(void *addr, void *start, void *end, int blksize,
! 2426: void (*inth) (void *), void *inthparam,
! 2427: struct audio_params *params)
! 2428: {
! 2429: struct emuxki_softc *sc = addr;
! 2430: /* No multiple voice support for now */
! 2431: struct emuxki_voice *voice = sc->rvoice;
! 2432: int error;
! 2433:
! 2434: if (voice == NULL)
! 2435: return (ENXIO);
! 2436: if ((error = emuxki_set_vparms(voice, params)))
! 2437: return (error);
! 2438: if ((error = emuxki_voice_set_bufparms(voice, start,
! 2439: (caddr_t)end - (caddr_t)start,
! 2440: blksize)))
! 2441: return (error);
! 2442: emuxki_voice_start(voice, inth, inthparam);
! 2443:
! 2444: return (0);
! 2445: }
! 2446:
! 2447:
! 2448: /*
! 2449: * AC97 callbacks
! 2450: */
! 2451:
! 2452: int
! 2453: emuxki_ac97_attach(void *arg, struct ac97_codec_if *codecif)
! 2454: {
! 2455: struct emuxki_softc *sc = arg;
! 2456:
! 2457: sc->codecif = codecif;
! 2458: return (0);
! 2459: }
! 2460:
! 2461: int
! 2462: emuxki_ac97_read(void *arg, u_int8_t reg, u_int16_t *val)
! 2463: {
! 2464: struct emuxki_softc *sc = arg;
! 2465: int s;
! 2466:
! 2467: s = splaudio();
! 2468: bus_space_write_1(sc->sc_iot, sc->sc_ioh, EMU_AC97ADDR, reg);
! 2469: *val = bus_space_read_2(sc->sc_iot, sc->sc_ioh, EMU_AC97DATA);
! 2470: splx(s);
! 2471:
! 2472: return (0);
! 2473: }
! 2474:
! 2475: int
! 2476: emuxki_ac97_write(void *arg, u_int8_t reg, u_int16_t val)
! 2477: {
! 2478: struct emuxki_softc *sc = arg;
! 2479: int s;
! 2480:
! 2481: s = splaudio();
! 2482: bus_space_write_1(sc->sc_iot, sc->sc_ioh, EMU_AC97ADDR, reg);
! 2483: bus_space_write_2(sc->sc_iot, sc->sc_ioh, EMU_AC97DATA, val);
! 2484: splx(s);
! 2485:
! 2486: return (0);
! 2487: }
! 2488:
! 2489: void
! 2490: emuxki_ac97_reset(void *arg)
! 2491: {
! 2492: }
CVSweb