Annotation of sys/dev/pci/fms.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: fms.c,v 1.17 2005/04/16 21:57:23 mickey Exp $ */
! 2: /* $NetBSD: fms.c,v 1.5.4.1 2000/06/30 16:27:50 simonb Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1999 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Witold J. Wnuk.
! 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: * Forte Media FM801 Audio Device Driver
! 42: */
! 43:
! 44: #include "radio.h"
! 45:
! 46: #include <sys/param.h>
! 47: #include <sys/systm.h>
! 48: #include <sys/kernel.h>
! 49: #include <sys/malloc.h>
! 50: #include <sys/device.h>
! 51: #include <sys/audioio.h>
! 52:
! 53: #include <machine/bus.h>
! 54: #include <machine/cpu.h>
! 55:
! 56: #include <dev/pci/pcidevs.h>
! 57: #include <dev/pci/pcivar.h>
! 58:
! 59: #include <dev/audio_if.h>
! 60: #include <dev/mulaw.h>
! 61: #include <dev/auconv.h>
! 62:
! 63: #include <dev/ic/ac97.h>
! 64: #if 0
! 65: #include <dev/ic/mpuvar.h>
! 66: #endif
! 67:
! 68: #include <dev/pci/fmsreg.h>
! 69: #include <dev/pci/fmsvar.h>
! 70:
! 71:
! 72: struct fms_dma {
! 73: struct fms_dma *next;
! 74: caddr_t addr;
! 75: size_t size;
! 76: bus_dmamap_t map;
! 77: bus_dma_segment_t seg;
! 78: };
! 79:
! 80:
! 81:
! 82: int fms_match(struct device *, void *, void *);
! 83: void fms_attach(struct device *, struct device *, void *);
! 84: int fms_intr(void *);
! 85:
! 86: int fms_open(void *, int);
! 87: void fms_close(void *);
! 88: int fms_query_encoding(void *, struct audio_encoding *);
! 89: int fms_set_params(void *, int, int, struct audio_params *,
! 90: struct audio_params *);
! 91: int fms_round_blocksize(void *, int);
! 92: int fms_halt_output(void *);
! 93: int fms_halt_input(void *);
! 94: int fms_getdev(void *, struct audio_device *);
! 95: int fms_set_port(void *, mixer_ctrl_t *);
! 96: int fms_get_port(void *, mixer_ctrl_t *);
! 97: int fms_query_devinfo(void *, mixer_devinfo_t *);
! 98: void *fms_malloc(void *, int, size_t, int, int);
! 99: void fms_free(void *, void *, int);
! 100: paddr_t fms_mappage(void *, void *, off_t, int);
! 101: int fms_get_props(void *);
! 102: int fms_trigger_output(void *, void *, void *, int, void (*)(void *),
! 103: void *, struct audio_params *);
! 104: int fms_trigger_input(void *, void *, void *, int, void (*)(void *),
! 105: void *, struct audio_params *);
! 106:
! 107: struct cfdriver fms_cd = {
! 108: NULL, "fms", DV_DULL
! 109: };
! 110:
! 111: struct cfattach fms_ca = {
! 112: sizeof (struct fms_softc), fms_match, fms_attach
! 113: };
! 114:
! 115: struct audio_device fms_device = {
! 116: "Forte Media 801",
! 117: "1.0",
! 118: "fms"
! 119: };
! 120:
! 121:
! 122: struct audio_hw_if fms_hw_if = {
! 123: fms_open,
! 124: fms_close,
! 125: NULL,
! 126: fms_query_encoding,
! 127: fms_set_params,
! 128: fms_round_blocksize,
! 129: NULL,
! 130: NULL,
! 131: NULL,
! 132: NULL,
! 133: NULL,
! 134: fms_halt_output,
! 135: fms_halt_input,
! 136: NULL,
! 137: fms_getdev,
! 138: NULL,
! 139: fms_set_port,
! 140: fms_get_port,
! 141: fms_query_devinfo,
! 142: fms_malloc,
! 143: fms_free,
! 144: NULL,
! 145: fms_mappage,
! 146: fms_get_props,
! 147: fms_trigger_output,
! 148: fms_trigger_input
! 149: };
! 150:
! 151: int fms_attach_codec(void *, struct ac97_codec_if *);
! 152: int fms_read_codec(void *, u_int8_t, u_int16_t *);
! 153: int fms_write_codec(void *, u_int8_t, u_int16_t);
! 154: void fms_reset_codec(void *);
! 155:
! 156: int fms_allocmem(struct fms_softc *, size_t, size_t,
! 157: struct fms_dma *);
! 158: int fms_freemem(struct fms_softc *, struct fms_dma *);
! 159:
! 160: int
! 161: fms_match(parent, match, aux)
! 162: struct device *parent;
! 163: void *match;
! 164: void *aux;
! 165: {
! 166: struct pci_attach_args *pa = (struct pci_attach_args *) aux;
! 167:
! 168: if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_FORTEMEDIA &&
! 169: PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_FORTEMEDIA_FM801)
! 170: return (1);
! 171: return (0);
! 172: }
! 173:
! 174: void
! 175: fms_attach(parent, self, aux)
! 176: struct device *parent;
! 177: struct device *self;
! 178: void *aux;
! 179: {
! 180: struct pci_attach_args *pa = aux;
! 181: struct fms_softc *sc = (struct fms_softc *) self;
! 182: struct audio_attach_args aa;
! 183: pci_chipset_tag_t pc = pa->pa_pc;
! 184: pcitag_t pt = pa->pa_tag;
! 185: pci_intr_handle_t ih;
! 186: bus_size_t iosize;
! 187: const char *intrstr;
! 188: u_int16_t k1;
! 189: int i;
! 190:
! 191: if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_IO, 0, &sc->sc_iot,
! 192: &sc->sc_ioh, NULL, &iosize, 0)) {
! 193: printf(": can't map i/o space\n");
! 194: return;
! 195: }
! 196:
! 197: if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, 0x30, 2,
! 198: &sc->sc_mpu_ioh)) {
! 199: printf(": can't get mpu subregion handle\n");
! 200: bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
! 201: return;
! 202: }
! 203:
! 204: if (bus_space_subregion(sc->sc_iot, sc->sc_ioh, 0x68, 4,
! 205: &sc->sc_opl_ioh)) {
! 206: printf(": can't get opl subregion handle\n");
! 207: bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
! 208: return;
! 209: }
! 210:
! 211: if (pci_intr_map(pa, &ih)) {
! 212: printf(": couldn't map interrupt\n");
! 213: bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
! 214: return;
! 215: }
! 216: intrstr = pci_intr_string(pc, ih);
! 217:
! 218: sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, fms_intr, sc,
! 219: sc->sc_dev.dv_xname);
! 220: if (sc->sc_ih == NULL) {
! 221: printf(": couldn't establish interrupt");
! 222: if (intrstr != NULL)
! 223: printf(" at %s", intrstr);
! 224: printf("\n");
! 225: bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
! 226: return;
! 227: }
! 228:
! 229: printf(": %s\n", intrstr);
! 230:
! 231: sc->sc_dmat = pa->pa_dmat;
! 232:
! 233: /* Disable legacy audio (SBPro compatibility) */
! 234: pci_conf_write(pc, pt, 0x40, 0);
! 235:
! 236: /* Reset codec and AC'97 */
! 237: bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0020);
! 238: delay(2); /* > 1us according to AC'97 documentation */
! 239: bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0000);
! 240: delay(1); /* > 168.2ns according to AC'97 documentation */
! 241:
! 242: /* Set up volume */
! 243: bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PCM_VOLUME, 0x0808);
! 244: bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_FM_VOLUME, 0x0808);
! 245: bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_I2S_VOLUME, 0x0808);
! 246:
! 247: bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_RECORD_SOURCE, 0x0000);
! 248:
! 249: /* Unmask playback, record and mpu interrupts, mask the rest */
! 250: k1 = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_INTMASK);
! 251: bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_INTMASK,
! 252: (k1 & ~(FM_INTMASK_PLAY | FM_INTMASK_REC | FM_INTMASK_MPU)) |
! 253: FM_INTMASK_VOL);
! 254: bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS,
! 255: FM_INTSTATUS_PLAY | FM_INTSTATUS_REC | FM_INTSTATUS_MPU |
! 256: FM_INTSTATUS_VOL);
! 257:
! 258: #if NRADIO > 0
! 259: fmsradio_attach(sc);
! 260: #endif /* NRADIO > 0 */
! 261:
! 262: sc->host_if.arg = sc;
! 263: sc->host_if.attach = fms_attach_codec;
! 264: sc->host_if.read = fms_read_codec;
! 265: sc->host_if.write = fms_write_codec;
! 266: sc->host_if.reset = fms_reset_codec;
! 267:
! 268: if (ac97_attach(&sc->host_if) != 0)
! 269: return;
! 270:
! 271: /* Turn mute off */
! 272: for (i = 0; i < 3; i++) {
! 273: static struct {
! 274: char *class, *device;
! 275: } d[] = {
! 276: { AudioCoutputs, AudioNmaster },
! 277: { AudioCinputs, AudioNdac },
! 278: { AudioCrecord, AudioNvolume }
! 279: };
! 280: struct mixer_ctrl ctl;
! 281:
! 282: ctl.type = AUDIO_MIXER_ENUM;
! 283: ctl.un.ord = 0;
! 284: ctl.dev = sc->codec_if->vtbl->get_portnum_by_name(sc->codec_if,
! 285: d[i].class, d[i].device, AudioNmute);
! 286: fms_set_port(sc, &ctl);
! 287: }
! 288:
! 289: audio_attach_mi(&fms_hw_if, sc, &sc->sc_dev);
! 290:
! 291: aa.type = AUDIODEV_TYPE_OPL;
! 292: aa.hwif = NULL;
! 293: aa.hdl = NULL;
! 294: config_found(&sc->sc_dev, &aa, audioprint);
! 295:
! 296: aa.type = AUDIODEV_TYPE_MPU;
! 297: aa.hwif = NULL;
! 298: aa.hdl = NULL;
! 299: sc->sc_mpu_dev = config_found(&sc->sc_dev, &aa, audioprint);
! 300: }
! 301:
! 302: /*
! 303: * Each AC-link frame takes 20.8us, data should be ready in next frame,
! 304: * we allow more than two.
! 305: */
! 306: #define TIMO 50
! 307: int
! 308: fms_read_codec(addr, reg, val)
! 309: void *addr;
! 310: u_int8_t reg;
! 311: u_int16_t *val;
! 312: {
! 313: struct fms_softc *sc = addr;
! 314: int i;
! 315:
! 316: /* Poll until codec is ready */
! 317: for (i = 0; i < TIMO && bus_space_read_2(sc->sc_iot, sc->sc_ioh,
! 318: FM_CODEC_CMD) & FM_CODEC_CMD_BUSY; i++)
! 319: delay(1);
! 320: if (i >= TIMO) {
! 321: printf("fms: codec busy\n");
! 322: return 1;
! 323: }
! 324:
! 325: /* Write register index, read access */
! 326: bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CMD,
! 327: reg | FM_CODEC_CMD_READ);
! 328:
! 329: /* Poll until we have valid data */
! 330: for (i = 0; i < TIMO && !(bus_space_read_2(sc->sc_iot, sc->sc_ioh,
! 331: FM_CODEC_CMD) & FM_CODEC_CMD_VALID); i++)
! 332: delay(1);
! 333: if (i >= TIMO) {
! 334: printf("fms: no data from codec\n");
! 335: return 1;
! 336: }
! 337:
! 338: /* Read data */
! 339: *val = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_DATA);
! 340: return 0;
! 341: }
! 342:
! 343: int
! 344: fms_write_codec(addr, reg, val)
! 345: void *addr;
! 346: u_int8_t reg;
! 347: u_int16_t val;
! 348: {
! 349: struct fms_softc *sc = addr;
! 350: int i;
! 351:
! 352: /* Poll until codec is ready */
! 353: for (i = 0; i < TIMO && bus_space_read_2(sc->sc_iot, sc->sc_ioh,
! 354: FM_CODEC_CMD) & FM_CODEC_CMD_BUSY; i++)
! 355: delay(1);
! 356: if (i >= TIMO) {
! 357: printf("fms: codec busy\n");
! 358: return 1;
! 359: }
! 360:
! 361: /* Write data */
! 362: bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_DATA, val);
! 363: /* Write index register, write access */
! 364: bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CMD, reg);
! 365: return 0;
! 366: }
! 367: #undef TIMO
! 368:
! 369: int
! 370: fms_attach_codec(addr, cif)
! 371: void *addr;
! 372: struct ac97_codec_if *cif;
! 373: {
! 374: struct fms_softc *sc = addr;
! 375:
! 376: sc->codec_if = cif;
! 377: return 0;
! 378: }
! 379:
! 380: /* Cold Reset */
! 381: void
! 382: fms_reset_codec(addr)
! 383: void *addr;
! 384: {
! 385: struct fms_softc *sc = addr;
! 386: bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0020);
! 387: delay(2);
! 388: bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_CODEC_CTL, 0x0000);
! 389: delay(1);
! 390: }
! 391:
! 392: int
! 393: fms_intr(arg)
! 394: void *arg;
! 395: {
! 396: struct fms_softc *sc = arg;
! 397: u_int16_t istat;
! 398:
! 399: istat = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS);
! 400:
! 401: if (istat & FM_INTSTATUS_PLAY) {
! 402: if ((sc->sc_play_nextblk += sc->sc_play_blksize) >=
! 403: sc->sc_play_end)
! 404: sc->sc_play_nextblk = sc->sc_play_start;
! 405:
! 406: bus_space_write_4(sc->sc_iot, sc->sc_ioh,
! 407: sc->sc_play_flip++ & 1 ?
! 408: FM_PLAY_DMABUF2 : FM_PLAY_DMABUF1, sc->sc_play_nextblk);
! 409:
! 410: if (sc->sc_pintr)
! 411: sc->sc_pintr(sc->sc_parg);
! 412: else
! 413: printf("unexpected play intr\n");
! 414: }
! 415:
! 416: if (istat & FM_INTSTATUS_REC) {
! 417: if ((sc->sc_rec_nextblk += sc->sc_rec_blksize) >=
! 418: sc->sc_rec_end)
! 419: sc->sc_rec_nextblk = sc->sc_rec_start;
! 420:
! 421: bus_space_write_4(sc->sc_iot, sc->sc_ioh,
! 422: sc->sc_rec_flip++ & 1 ?
! 423: FM_REC_DMABUF2 : FM_REC_DMABUF1, sc->sc_rec_nextblk);
! 424:
! 425: if (sc->sc_rintr)
! 426: sc->sc_rintr(sc->sc_rarg);
! 427: else
! 428: printf("unexpected rec intr\n");
! 429: }
! 430:
! 431: #if 0
! 432: if (istat & FM_INTSTATUS_MPU)
! 433: mpu_intr(sc->sc_mpu_dev);
! 434: #endif
! 435:
! 436: bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_INTSTATUS,
! 437: istat & (FM_INTSTATUS_PLAY | FM_INTSTATUS_REC));
! 438:
! 439: return 1;
! 440: }
! 441:
! 442: int
! 443: fms_open(addr, flags)
! 444: void *addr;
! 445: int flags;
! 446: {
! 447: /* UNUSED struct fms_softc *sc = addr;*/
! 448:
! 449: return 0;
! 450: }
! 451:
! 452: void
! 453: fms_close(addr)
! 454: void *addr;
! 455: {
! 456: /* UNUSED struct fms_softc *sc = addr;*/
! 457: }
! 458:
! 459: int
! 460: fms_query_encoding(addr, fp)
! 461: void *addr;
! 462: struct audio_encoding *fp;
! 463: {
! 464:
! 465: switch (fp->index) {
! 466: case 0:
! 467: strlcpy(fp->name, AudioEmulaw, sizeof fp->name);
! 468: fp->encoding = AUDIO_ENCODING_ULAW;
! 469: fp->precision = 8;
! 470: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 471: return 0;
! 472: case 1:
! 473: strlcpy(fp->name, AudioEslinear_le, sizeof fp->name);
! 474: fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
! 475: fp->precision = 16;
! 476: fp->flags = 0;
! 477: return 0;
! 478: case 2:
! 479: strlcpy(fp->name, AudioEulinear, sizeof fp->name);
! 480: fp->encoding = AUDIO_ENCODING_ULINEAR;
! 481: fp->precision = 8;
! 482: fp->flags = 0;
! 483: return 0;
! 484: case 3:
! 485: strlcpy(fp->name, AudioEalaw, sizeof fp->name);
! 486: fp->encoding = AUDIO_ENCODING_ALAW;
! 487: fp->precision = 8;
! 488: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 489: return 0;
! 490: case 4:
! 491: strlcpy(fp->name, AudioEulinear_le, sizeof fp->name);
! 492: fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
! 493: fp->precision = 16;
! 494: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 495: return 0;
! 496: case 5:
! 497: strlcpy(fp->name, AudioEslinear, sizeof fp->name);
! 498: fp->encoding = AUDIO_ENCODING_SLINEAR;
! 499: fp->precision = 8;
! 500: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 501: return 0;
! 502: case 6:
! 503: strlcpy(fp->name, AudioEulinear_be, sizeof fp->name);
! 504: fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
! 505: fp->precision = 16;
! 506: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 507: return 0;
! 508: case 7:
! 509: strlcpy(fp->name, AudioEslinear_be, sizeof fp->name);
! 510: fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
! 511: fp->precision = 16;
! 512: fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 513: return 0;
! 514: default:
! 515: return EINVAL;
! 516: }
! 517: }
! 518:
! 519: /*
! 520: * Range below -limit- is set to -rate-
! 521: * What a pity FM801 does not have 24000
! 522: * 24000 -> 22050 sounds rather poor
! 523: */
! 524: struct {
! 525: int limit;
! 526: int rate;
! 527: } fms_rates[11] = {
! 528: { 6600, 5500 },
! 529: { 8750, 8000 },
! 530: { 10250, 9600 },
! 531: { 13200, 11025 },
! 532: { 17500, 16000 },
! 533: { 20500, 19200 },
! 534: { 26500, 22050 },
! 535: { 35000, 32000 },
! 536: { 41000, 38400 },
! 537: { 46000, 44100 },
! 538: { 48000, 48000 },
! 539: /* anything above -> 48000 */
! 540: };
! 541:
! 542: int
! 543: fms_set_params(addr, setmode, usemode, play, rec)
! 544: void *addr;
! 545: int setmode, usemode;
! 546: struct audio_params *play, *rec;
! 547: {
! 548: struct fms_softc *sc = addr;
! 549: int i;
! 550:
! 551: if (setmode & AUMODE_PLAY) {
! 552: play->factor = 1;
! 553: play->sw_code = 0;
! 554: switch(play->encoding) {
! 555: case AUDIO_ENCODING_ULAW:
! 556: play->factor = 2;
! 557: play->sw_code = mulaw_to_slinear16_le;
! 558: break;
! 559: case AUDIO_ENCODING_SLINEAR_LE:
! 560: if (play->precision == 8)
! 561: play->sw_code = change_sign8;
! 562: break;
! 563: case AUDIO_ENCODING_ULINEAR_LE:
! 564: if (play->precision == 16)
! 565: play->sw_code = change_sign16_le;
! 566: break;
! 567: case AUDIO_ENCODING_ALAW:
! 568: play->factor = 2;
! 569: play->sw_code = alaw_to_slinear16_le;
! 570: break;
! 571: case AUDIO_ENCODING_SLINEAR_BE:
! 572: if (play->precision == 16)
! 573: play->sw_code = swap_bytes;
! 574: else
! 575: play->sw_code = change_sign8;
! 576: break;
! 577: case AUDIO_ENCODING_ULINEAR_BE:
! 578: if (play->precision == 16)
! 579: play->sw_code = change_sign16_swap_bytes_le;
! 580: break;
! 581: default:
! 582: return EINVAL;
! 583: }
! 584: for (i = 0; i < 10 && play->sample_rate > fms_rates[i].limit;
! 585: i++)
! 586: ;
! 587: play->sample_rate = fms_rates[i].rate;
! 588: sc->sc_play_reg = (play->channels == 2 ? FM_PLAY_STEREO : 0) |
! 589: (play->precision * play->factor == 16 ? FM_PLAY_16BIT : 0) |
! 590: (i << 8);
! 591: }
! 592:
! 593: if (setmode & AUMODE_RECORD) {
! 594:
! 595: rec->factor = 1;
! 596: rec->sw_code = 0;
! 597: switch(rec->encoding) {
! 598: case AUDIO_ENCODING_ULAW:
! 599: rec->sw_code = ulinear8_to_mulaw;
! 600: break;
! 601: case AUDIO_ENCODING_SLINEAR_LE:
! 602: if (rec->precision == 8)
! 603: rec->sw_code = change_sign8;
! 604: break;
! 605: case AUDIO_ENCODING_ULINEAR_LE:
! 606: if (rec->precision == 16)
! 607: rec->sw_code = change_sign16_le;
! 608: break;
! 609: case AUDIO_ENCODING_ALAW:
! 610: rec->sw_code = ulinear8_to_alaw;
! 611: break;
! 612: case AUDIO_ENCODING_SLINEAR_BE:
! 613: if (play->precision == 16)
! 614: play->sw_code = swap_bytes;
! 615: else
! 616: play->sw_code = change_sign8;
! 617: break;
! 618: case AUDIO_ENCODING_ULINEAR_BE:
! 619: if (play->precision == 16)
! 620: play->sw_code = swap_bytes_change_sign16_le;
! 621: break;
! 622: default:
! 623: return EINVAL;
! 624: }
! 625: for (i = 0; i < 10 && rec->sample_rate > fms_rates[i].limit;
! 626: i++)
! 627: ;
! 628: rec->sample_rate = fms_rates[i].rate;
! 629: sc->sc_rec_reg =
! 630: (rec->channels == 2 ? FM_REC_STEREO : 0) |
! 631: (rec->precision * rec->factor == 16 ? FM_REC_16BIT : 0) |
! 632: (i << 8);
! 633: }
! 634:
! 635: return 0;
! 636: }
! 637:
! 638: int
! 639: fms_round_blocksize(addr, blk)
! 640: void *addr;
! 641: int blk;
! 642: {
! 643: return (blk + 0xf) & ~0xf;
! 644: }
! 645:
! 646: int
! 647: fms_halt_output(addr)
! 648: void *addr;
! 649: {
! 650: struct fms_softc *sc = addr;
! 651: u_int16_t k1;
! 652:
! 653: k1 = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL);
! 654: bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL,
! 655: (k1 & ~(FM_PLAY_STOPNOW | FM_PLAY_START)) |
! 656: FM_PLAY_BUF1_LAST | FM_PLAY_BUF2_LAST);
! 657:
! 658: return 0;
! 659: }
! 660:
! 661: int
! 662: fms_halt_input(addr)
! 663: void *addr;
! 664: {
! 665: struct fms_softc *sc = addr;
! 666: u_int16_t k1;
! 667:
! 668: k1 = bus_space_read_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL);
! 669: bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL,
! 670: (k1 & ~(FM_REC_STOPNOW | FM_REC_START)) |
! 671: FM_REC_BUF1_LAST | FM_REC_BUF2_LAST);
! 672:
! 673: return 0;
! 674: }
! 675:
! 676: int
! 677: fms_getdev(addr, retp)
! 678: void *addr;
! 679: struct audio_device *retp;
! 680: {
! 681: *retp = fms_device;
! 682: return 0;
! 683: }
! 684:
! 685: int
! 686: fms_set_port(addr, cp)
! 687: void *addr;
! 688: mixer_ctrl_t *cp;
! 689: {
! 690: struct fms_softc *sc = addr;
! 691:
! 692: return (sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp));
! 693: }
! 694:
! 695: int
! 696: fms_get_port(addr, cp)
! 697: void *addr;
! 698: mixer_ctrl_t *cp;
! 699: {
! 700: struct fms_softc *sc = addr;
! 701:
! 702: return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp));
! 703: }
! 704:
! 705: void *
! 706: fms_malloc(addr, direction, size, pool, flags)
! 707: void *addr;
! 708: int direction;
! 709: size_t size;
! 710: int pool, flags;
! 711: {
! 712: struct fms_softc *sc = addr;
! 713: struct fms_dma *p;
! 714: int error;
! 715: int rseg;
! 716:
! 717: p = malloc(sizeof(*p), pool, flags);
! 718: if (!p)
! 719: return 0;
! 720:
! 721: p->size = size;
! 722: if ((error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, 0, &p->seg, 1,
! 723: &rseg, BUS_DMA_NOWAIT)) != 0) {
! 724: printf("%s: unable to allocate dma, error = %d\n",
! 725: sc->sc_dev.dv_xname, error);
! 726: goto fail_alloc;
! 727: }
! 728:
! 729: if ((error = bus_dmamem_map(sc->sc_dmat, &p->seg, rseg, size, &p->addr,
! 730: BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
! 731: printf("%s: unable to map dma, error = %d\n",
! 732: sc->sc_dev.dv_xname, error);
! 733: goto fail_map;
! 734: }
! 735:
! 736: if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
! 737: BUS_DMA_NOWAIT, &p->map)) != 0) {
! 738: printf("%s: unable to create dma map, error = %d\n",
! 739: sc->sc_dev.dv_xname, error);
! 740: goto fail_create;
! 741: }
! 742:
! 743: if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, size, NULL,
! 744: BUS_DMA_NOWAIT)) != 0) {
! 745: printf("%s: unable to load dma map, error = %d\n",
! 746: sc->sc_dev.dv_xname, error);
! 747: goto fail_load;
! 748: }
! 749:
! 750: p->next = sc->sc_dmas;
! 751: sc->sc_dmas = p;
! 752:
! 753: return p->addr;
! 754:
! 755:
! 756: fail_load:
! 757: bus_dmamap_destroy(sc->sc_dmat, p->map);
! 758: fail_create:
! 759: bus_dmamem_unmap(sc->sc_dmat, p->addr, size);
! 760: fail_map:
! 761: bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
! 762: fail_alloc:
! 763: free(p, pool);
! 764: return 0;
! 765: }
! 766:
! 767: void
! 768: fms_free(addr, ptr, pool)
! 769: void *addr;
! 770: void *ptr;
! 771: int pool;
! 772: {
! 773: struct fms_softc *sc = addr;
! 774: struct fms_dma **pp, *p;
! 775:
! 776: for (pp = &(sc->sc_dmas); (p = *pp) != NULL; pp = &p->next)
! 777: if (p->addr == ptr) {
! 778: bus_dmamap_unload(sc->sc_dmat, p->map);
! 779: bus_dmamap_destroy(sc->sc_dmat, p->map);
! 780: bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size);
! 781: bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
! 782:
! 783: *pp = p->next;
! 784: free(p, pool);
! 785: return;
! 786: }
! 787:
! 788: panic("fms_free: trying to free unallocated memory");
! 789: }
! 790:
! 791: paddr_t
! 792: fms_mappage(addr, mem, off, prot)
! 793: void *addr;
! 794: void *mem;
! 795: off_t off;
! 796: int prot;
! 797: {
! 798: struct fms_softc *sc = addr;
! 799: struct fms_dma *p;
! 800:
! 801: if (off < 0)
! 802: return -1;
! 803:
! 804: for (p = sc->sc_dmas; p && p->addr != mem; p = p->next)
! 805: ;
! 806: if (!p)
! 807: return -1;
! 808:
! 809: return bus_dmamem_mmap(sc->sc_dmat, &p->seg, 1, off, prot,
! 810: BUS_DMA_WAITOK);
! 811: }
! 812:
! 813: int
! 814: fms_get_props(addr)
! 815: void *addr;
! 816: {
! 817: return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT |
! 818: AUDIO_PROP_FULLDUPLEX;
! 819: }
! 820:
! 821: int
! 822: fms_query_devinfo(addr, dip)
! 823: void *addr;
! 824: mixer_devinfo_t *dip;
! 825: {
! 826: struct fms_softc *sc = addr;
! 827:
! 828: return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, dip));
! 829: }
! 830:
! 831: int
! 832: fms_trigger_output(addr, start, end, blksize, intr, arg, param)
! 833: void *addr;
! 834: void *start, *end;
! 835: int blksize;
! 836: void (*intr)(void *);
! 837: void *arg;
! 838: struct audio_params *param;
! 839: {
! 840: struct fms_softc *sc = addr;
! 841: struct fms_dma *p;
! 842:
! 843: sc->sc_pintr = intr;
! 844: sc->sc_parg = arg;
! 845:
! 846: for (p = sc->sc_dmas; p && p->addr != start; p = p->next)
! 847: ;
! 848:
! 849: if (!p)
! 850: panic("fms_trigger_output: request with bad start "
! 851: "address (%p)", start);
! 852:
! 853: sc->sc_play_start = p->map->dm_segs[0].ds_addr;
! 854: sc->sc_play_end = sc->sc_play_start + ((char *)end - (char *)start);
! 855: sc->sc_play_blksize = blksize;
! 856: sc->sc_play_nextblk = sc->sc_play_start + sc->sc_play_blksize;
! 857: sc->sc_play_flip = 0;
! 858: bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_DMALEN, blksize - 1);
! 859: bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_PLAY_DMABUF1,
! 860: sc->sc_play_start);
! 861: bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_PLAY_DMABUF2,
! 862: sc->sc_play_nextblk);
! 863: bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_PLAY_CTL,
! 864: FM_PLAY_START | FM_PLAY_STOPNOW | sc->sc_play_reg);
! 865: return 0;
! 866: }
! 867:
! 868:
! 869: int
! 870: fms_trigger_input(addr, start, end, blksize, intr, arg, param)
! 871: void *addr;
! 872: void *start, *end;
! 873: int blksize;
! 874: void (*intr)(void *);
! 875: void *arg;
! 876: struct audio_params *param;
! 877: {
! 878: struct fms_softc *sc = addr;
! 879: struct fms_dma *p;
! 880:
! 881: sc->sc_rintr = intr;
! 882: sc->sc_rarg = arg;
! 883:
! 884: for (p = sc->sc_dmas; p && p->addr != start; p = p->next)
! 885: ;
! 886:
! 887: if (!p)
! 888: panic("fms_trigger_input: request with bad start "
! 889: "address (%p)", start);
! 890:
! 891: sc->sc_rec_start = p->map->dm_segs[0].ds_addr;
! 892: sc->sc_rec_end = sc->sc_rec_start + ((char *)end - (char *)start);
! 893: sc->sc_rec_blksize = blksize;
! 894: sc->sc_rec_nextblk = sc->sc_rec_start + sc->sc_rec_blksize;
! 895: sc->sc_rec_flip = 0;
! 896: bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_DMALEN, blksize - 1);
! 897: bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_REC_DMABUF1,
! 898: sc->sc_rec_start);
! 899: bus_space_write_4(sc->sc_iot, sc->sc_ioh, FM_REC_DMABUF2,
! 900: sc->sc_rec_nextblk);
! 901: bus_space_write_2(sc->sc_iot, sc->sc_ioh, FM_REC_CTL,
! 902: FM_REC_START | FM_REC_STOPNOW | sc->sc_rec_reg);
! 903: return 0;
! 904: }
! 905:
! 906:
CVSweb