Annotation of sys/dev/pci/azalia.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: azalia.c,v 1.29 2007/08/02 17:13:31 reyk Exp $ */
! 2: /* $NetBSD: azalia.c,v 1.20 2006/05/07 08:31:44 kent Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 2005 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by TAMURA Kent
! 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: * High Definition Audio Specification
! 42: * ftp://download.intel.com/standards/hdaudio/pdf/HDAudio_03.pdf
! 43: *
! 44: *
! 45: * TO DO:
! 46: * - S/PDIF
! 47: * - power hook
! 48: * - multiple codecs (needed?)
! 49: * - multiple streams (needed?)
! 50: */
! 51:
! 52: #include <sys/cdefs.h>
! 53: #ifdef NETBSD_GOOP
! 54: __KERNEL_RCSID(0, "$NetBSD: azalia.c,v 1.15 2005/09/29 04:14:03 kent Exp $");
! 55: #endif
! 56:
! 57: #include <sys/param.h>
! 58: #include <sys/device.h>
! 59: #include <sys/malloc.h>
! 60: #include <sys/systm.h>
! 61: #include <uvm/uvm_param.h>
! 62: #include <dev/audio_if.h>
! 63: #include <dev/auconv.h>
! 64: #include <dev/pci/pcidevs.h>
! 65: #include <dev/pci/pcivar.h>
! 66:
! 67: #include <dev/pci/azalia.h>
! 68:
! 69: typedef struct audio_params audio_params_t;
! 70: #ifndef BUS_DMA_NOCACHE
! 71: #define BUS_DMA_NOCACHE 0
! 72: #endif
! 73: #define auconv_delete_encodings(x...)
! 74: #define auconv_query_encoding(x...) (EINVAL)
! 75: #define auconv_create_encodings(x...) (0)
! 76:
! 77: struct audio_format {
! 78: void *driver_data;
! 79: int32_t mode;
! 80: u_int encoding;
! 81: u_int validbits;
! 82: u_int precision;
! 83: u_int channels;
! 84: u_int channel_mask;
! 85: #define AUFMT_UNKNOWN_POSITION 0U
! 86: #define AUFMT_FRONT_LEFT 0x00001U /* USB audio compatible */
! 87: #define AUFMT_FRONT_RIGHT 0x00002U /* USB audio compatible */
! 88: #define AUFMT_FRONT_CENTER 0x00004U /* USB audio compatible */
! 89: #define AUFMT_LOW_FREQUENCY 0x00008U /* USB audio compatible */
! 90: #define AUFMT_BACK_LEFT 0x00010U /* USB audio compatible */
! 91: #define AUFMT_BACK_RIGHT 0x00020U /* USB audio compatible */
! 92: #define AUFMT_FRONT_LEFT_OF_CENTER 0x00040U /* USB audio compatible */
! 93: #define AUFMT_FRONT_RIGHT_OF_CENTER 0x00080U /* USB audio compatible */
! 94: #define AUFMT_BACK_CENTER 0x00100U /* USB audio compatible */
! 95: #define AUFMT_SIDE_LEFT 0x00200U /* USB audio compatible */
! 96: #define AUFMT_SIDE_RIGHT 0x00400U /* USB audio compatible */
! 97: #define AUFMT_TOP_CENTER 0x00800U /* USB audio compatible */
! 98: #define AUFMT_TOP_FRONT_LEFT 0x01000U
! 99: #define AUFMT_TOP_FRONT_CENTER 0x02000U
! 100: #define AUFMT_TOP_FRONT_RIGHT 0x04000U
! 101: #define AUFMT_TOP_BACK_LEFT 0x08000U
! 102: #define AUFMT_TOP_BACK_CENTER 0x10000U
! 103: #define AUFMT_TOP_BACK_RIGHT 0x20000U
! 104:
! 105: #define AUFMT_MONAURAL AUFMT_FRONT_CENTER
! 106: #define AUFMT_STEREO (AUFMT_FRONT_LEFT | AUFMT_FRONT_RIGHT)
! 107: #define AUFMT_SURROUND4 (AUFMT_STEREO | AUFMT_BACK_LEFT \
! 108: | AUFMT_BACK_RIGHT)
! 109: #define AUFMT_DOLBY_5_1 (AUFMT_SURROUND4 | AUFMT_FRONT_CENTER \
! 110: | AUFMT_LOW_FREQUENCY)
! 111:
! 112: /**
! 113: * 0: frequency[0] is lower limit, and frequency[1] is higher limit.
! 114: * 1-16: frequency[0] to frequency[frequency_type-1] are valid.
! 115: */
! 116: u_int frequency_type;
! 117:
! 118: #define AUFMT_MAX_FREQUENCIES 16
! 119: /**
! 120: * sampling rates
! 121: */
! 122: u_int frequency[AUFMT_MAX_FREQUENCIES];
! 123: };
! 124:
! 125: #define AUFMT_INVALIDATE(fmt) (fmt)->mode |= 0x80000000
! 126: #define AUFMT_VALIDATE(fmt) (fmt)->mode &= 0x7fffffff
! 127: #define AUFMT_IS_VALID(fmt) (((fmt)->mode & 0x80000000) == 0)
! 128:
! 129: /* ----------------------------------------------------------------
! 130: * ICH6/ICH7 constant values
! 131: * ---------------------------------------------------------------- */
! 132:
! 133: /* PCI registers */
! 134: #define ICH_PCI_HDBARL 0x10
! 135: #define ICH_PCI_HDBARU 0x14
! 136: #define ICH_PCI_HDCTL 0x40
! 137: #define ICH_PCI_HDCTL_CLKDETCLR 0x08
! 138: #define ICH_PCI_HDCTL_CLKDETEN 0x04
! 139: #define ICH_PCI_HDCTL_CLKDETINV 0x02
! 140: #define ICH_PCI_HDCTL_SIGNALMODE 0x01
! 141:
! 142: /* internal types */
! 143:
! 144: typedef struct {
! 145: bus_dmamap_t map;
! 146: caddr_t addr; /* kernel virtual address */
! 147: bus_dma_segment_t segments[1];
! 148: size_t size;
! 149: } azalia_dma_t;
! 150: #define AZALIA_DMA_DMAADDR(p) ((p)->map->dm_segs[0].ds_addr)
! 151:
! 152: typedef struct {
! 153: struct azalia_t *az;
! 154: int regbase;
! 155: int number;
! 156: int dir; /* AUMODE_PLAY or AUMODE_RECORD */
! 157: uint32_t intr_bit;
! 158: azalia_dma_t bdlist;
! 159: azalia_dma_t buffer;
! 160: void (*intr)(void*);
! 161: void *intr_arg;
! 162: } stream_t;
! 163: #define STR_READ_1(s, r) \
! 164: bus_space_read_1((s)->az->iot, (s)->az->ioh, (s)->regbase + HDA_SD_##r)
! 165: #define STR_READ_2(s, r) \
! 166: bus_space_read_2((s)->az->iot, (s)->az->ioh, (s)->regbase + HDA_SD_##r)
! 167: #define STR_READ_4(s, r) \
! 168: bus_space_read_4((s)->az->iot, (s)->az->ioh, (s)->regbase + HDA_SD_##r)
! 169: #define STR_WRITE_1(s, r, v) \
! 170: bus_space_write_1((s)->az->iot, (s)->az->ioh, (s)->regbase + HDA_SD_##r, v)
! 171: #define STR_WRITE_2(s, r, v) \
! 172: bus_space_write_2((s)->az->iot, (s)->az->ioh, (s)->regbase + HDA_SD_##r, v)
! 173: #define STR_WRITE_4(s, r, v) \
! 174: bus_space_write_4((s)->az->iot, (s)->az->ioh, (s)->regbase + HDA_SD_##r, v)
! 175:
! 176: typedef struct azalia_t {
! 177: struct device dev;
! 178: struct device *audiodev;
! 179:
! 180: pci_chipset_tag_t pc;
! 181: void *ih;
! 182: bus_space_tag_t iot;
! 183: bus_space_handle_t ioh;
! 184: bus_size_t map_size;
! 185: bus_dma_tag_t dmat;
! 186: pcireg_t pciid;
! 187: uint32_t subid;
! 188:
! 189: codec_t codecs[15];
! 190: int ncodecs; /* number of codecs */
! 191: int codecno; /* index of the using codec */
! 192:
! 193: azalia_dma_t corb_dma;
! 194: int corb_size;
! 195: azalia_dma_t rirb_dma;
! 196: int rirb_size;
! 197: int rirb_rp;
! 198: #define UNSOLQ_SIZE 256
! 199: rirb_entry_t *unsolq;
! 200: int unsolq_wp;
! 201: int unsolq_rp;
! 202: boolean_t unsolq_kick;
! 203:
! 204: boolean_t ok64;
! 205: int nistreams, nostreams, nbstreams;
! 206: stream_t pstream;
! 207: stream_t rstream;
! 208: } azalia_t;
! 209: #define XNAME(sc) ((sc)->dev.dv_xname)
! 210: #define AZ_READ_1(z, r) bus_space_read_1((z)->iot, (z)->ioh, HDA_##r)
! 211: #define AZ_READ_2(z, r) bus_space_read_2((z)->iot, (z)->ioh, HDA_##r)
! 212: #define AZ_READ_4(z, r) bus_space_read_4((z)->iot, (z)->ioh, HDA_##r)
! 213: #define AZ_WRITE_1(z, r, v) bus_space_write_1((z)->iot, (z)->ioh, HDA_##r, v)
! 214: #define AZ_WRITE_2(z, r, v) bus_space_write_2((z)->iot, (z)->ioh, HDA_##r, v)
! 215: #define AZ_WRITE_4(z, r, v) bus_space_write_4((z)->iot, (z)->ioh, HDA_##r, v)
! 216:
! 217:
! 218: /* prototypes */
! 219: int azalia_pci_match(struct device *, void *, void *);
! 220: void azalia_pci_attach(struct device *, struct device *, void *);
! 221: int azalia_pci_activate(struct device *, enum devact);
! 222: int azalia_pci_detach(struct device *, int);
! 223: int azalia_intr(void *);
! 224: int azalia_attach(azalia_t *);
! 225: void azalia_attach_intr(struct device *);
! 226: int azalia_init_corb(azalia_t *);
! 227: int azalia_delete_corb(azalia_t *);
! 228: int azalia_init_rirb(azalia_t *);
! 229: int azalia_delete_rirb(azalia_t *);
! 230: int azalia_set_command(azalia_t *, nid_t, int, uint32_t,
! 231: uint32_t);
! 232: int azalia_get_response(azalia_t *, uint32_t *);
! 233: void azalia_rirb_kick_unsol_events(azalia_t *);
! 234: void azalia_rirb_intr(azalia_t *);
! 235: int azalia_alloc_dmamem(azalia_t *, size_t, size_t, azalia_dma_t *);
! 236: int azalia_free_dmamem(const azalia_t *, azalia_dma_t*);
! 237:
! 238: int azalia_codec_init(codec_t *);
! 239: int azalia_codec_delete(codec_t *);
! 240: void azalia_codec_add_bits(codec_t *, int, uint32_t, int);
! 241: void azalia_codec_add_format(codec_t *, int, int, int, uint32_t,
! 242: int32_t);
! 243: int azalia_codec_comresp(const codec_t *, nid_t, uint32_t,
! 244: uint32_t, uint32_t *);
! 245: int azalia_codec_connect_stream(codec_t *, int, uint16_t, int);
! 246:
! 247: int azalia_widget_init(widget_t *, const codec_t *, int);
! 248: int azalia_widget_init_audio(widget_t *, const codec_t *);
! 249: int azalia_widget_print_audio(const widget_t *, const char *);
! 250: int azalia_widget_init_pin(widget_t *, const codec_t *);
! 251: int azalia_widget_print_pin(const widget_t *);
! 252: int azalia_widget_init_connection(widget_t *, const codec_t *);
! 253:
! 254: int azalia_stream_init(stream_t *, azalia_t *, int, int, int);
! 255: int azalia_stream_delete(stream_t *, azalia_t *);
! 256: int azalia_stream_reset(stream_t *);
! 257: int azalia_stream_start(stream_t *, void *, void *, int,
! 258: void (*)(void *), void *, uint16_t);
! 259: int azalia_stream_halt(stream_t *);
! 260: int azalia_stream_intr(stream_t *, uint32_t);
! 261:
! 262: int azalia_open(void *, int);
! 263: void azalia_close(void *);
! 264: int azalia_query_encoding(void *, audio_encoding_t *);
! 265: int azalia_set_params(void *, int, int, audio_params_t *,
! 266: audio_params_t *);
! 267: int azalia_round_blocksize(void *, int);
! 268: int azalia_halt_output(void *);
! 269: int azalia_halt_input(void *);
! 270: int azalia_getdev(void *, struct audio_device *);
! 271: int azalia_set_port(void *, mixer_ctrl_t *);
! 272: int azalia_get_port(void *, mixer_ctrl_t *);
! 273: int azalia_query_devinfo(void *, mixer_devinfo_t *);
! 274: void *azalia_allocm(void *, int, size_t, int, int);
! 275: void azalia_freem(void *, void *, int);
! 276: size_t azalia_round_buffersize(void *, int, size_t);
! 277: int azalia_get_props(void *);
! 278: int azalia_trigger_output(void *, void *, void *, int,
! 279: void (*)(void *), void *, audio_params_t *);
! 280: int azalia_trigger_input(void *, void *, void *, int,
! 281: void (*)(void *), void *, audio_params_t *);
! 282:
! 283: int azalia_params2fmt(const audio_params_t *, uint16_t *);
! 284: int azalia_create_encodings(struct audio_format *, int,
! 285: struct audio_encoding_set **);
! 286:
! 287: /* variables */
! 288: struct cfattach azalia_ca = {
! 289: sizeof(azalia_t), azalia_pci_match, azalia_pci_attach,
! 290: azalia_pci_detach, azalia_pci_activate
! 291: };
! 292:
! 293: struct cfdriver azalia_cd = {
! 294: NULL, "azalia", DV_DULL
! 295: };
! 296:
! 297: struct audio_hw_if azalia_hw_if = {
! 298: azalia_open,
! 299: azalia_close,
! 300: NULL, /* drain */
! 301: azalia_query_encoding,
! 302: azalia_set_params,
! 303: azalia_round_blocksize,
! 304: NULL, /* commit_settings */
! 305: NULL, /* init_output */
! 306: NULL, /* init_input */
! 307: NULL, /* start_output */
! 308: NULL, /* start_input */
! 309: azalia_halt_output,
! 310: azalia_halt_input,
! 311: NULL, /* speaker_ctl */
! 312: azalia_getdev,
! 313: NULL, /* setfd */
! 314: azalia_set_port,
! 315: azalia_get_port,
! 316: azalia_query_devinfo,
! 317: azalia_allocm,
! 318: azalia_freem,
! 319: azalia_round_buffersize,
! 320: NULL, /* mappage */
! 321: azalia_get_props,
! 322: azalia_trigger_output,
! 323: azalia_trigger_input,
! 324: };
! 325:
! 326: static const char *pin_colors[16] = {
! 327: "unknown", "black", "gray", "blue",
! 328: "green", "red", "orange", "yellow",
! 329: "purple", "pink", "col0a", "col0b",
! 330: "col0c", "col0d", "white", "other"};
! 331: #ifdef AZALIA_DEBUG
! 332: static const char *pin_devices[16] = {
! 333: "line-out", AudioNspeaker, AudioNheadphone, AudioNcd,
! 334: "SPDIF-out", "digital-out", "modem-line", "modem-handset",
! 335: "line-in", AudioNaux, AudioNmicrophone, "telephony",
! 336: "SPDIF-in", "digital-in", "dev0e", "other"};
! 337: #endif
! 338:
! 339: /* ================================================================
! 340: * PCI functions
! 341: * ================================================================ */
! 342:
! 343: #define PCI_ID_CODE0(v, p) PCI_ID_CODE(PCI_VENDOR_##v, PCI_PRODUCT_##v##_##p)
! 344: #define PCIID_NVIDIA_MCP51 PCI_ID_CODE0(NVIDIA, MCP51_HDA)
! 345: #define PCIID_NVIDIA_MCP55 PCI_ID_CODE0(NVIDIA, MCP55_HDA)
! 346: #define PCIID_ALI_M5461 PCI_ID_CODE0(ALI, M5461)
! 347: #define PCIID_VIATECH_HDA PCI_ID_CODE0(VIATECH, HDA)
! 348:
! 349: int
! 350: azalia_pci_match(struct device *parent, void *match, void *aux)
! 351: {
! 352: struct pci_attach_args *pa;
! 353:
! 354: pa = aux;
! 355: if (PCI_CLASS(pa->pa_class) == PCI_CLASS_MULTIMEDIA
! 356: && PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MULTIMEDIA_HDAUDIO)
! 357: return 1;
! 358: return 0;
! 359: }
! 360:
! 361: void
! 362: azalia_pci_attach(struct device *parent, struct device *self, void *aux)
! 363: {
! 364: azalia_t *sc;
! 365: struct pci_attach_args *pa;
! 366: pcireg_t v;
! 367: pci_intr_handle_t ih;
! 368: const char *intrrupt_str;
! 369:
! 370: sc = (azalia_t*)self;
! 371: pa = aux;
! 372:
! 373: sc->dmat = pa->pa_dmat;
! 374:
! 375: v = pci_conf_read(pa->pa_pc, pa->pa_tag, ICH_PCI_HDBARL);
! 376: v &= PCI_MAPREG_TYPE_MASK | PCI_MAPREG_MEM_TYPE_MASK;
! 377: if (pci_mapreg_map(pa, ICH_PCI_HDBARL, v, 0,
! 378: &sc->iot, &sc->ioh, NULL, &sc->map_size, 0)) {
! 379: printf(": can't map device i/o space\n");
! 380: return;
! 381: }
! 382:
! 383: /* enable back-to-back */
! 384: v = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
! 385: pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
! 386: v | PCI_COMMAND_BACKTOBACK_ENABLE);
! 387:
! 388: v = pci_conf_read(pa->pa_pc, pa->pa_tag, 0x44);
! 389: pci_conf_write(pa->pa_pc, pa->pa_tag, 0x44, v & (~0x7));
! 390:
! 391: /* interrupt */
! 392: if (pci_intr_map(pa, &ih)) {
! 393: printf(": can't map interrupt\n");
! 394: return;
! 395: }
! 396: sc->pc = pa->pa_pc;
! 397: intrrupt_str = pci_intr_string(pa->pa_pc, ih);
! 398: sc->ih = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO, azalia_intr,
! 399: sc, sc->dev.dv_xname);
! 400: if (sc->ih == NULL) {
! 401: printf(": can't establish interrupt");
! 402: if (intrrupt_str != NULL)
! 403: printf(" at %s", intrrupt_str);
! 404: printf("\n");
! 405: return;
! 406: }
! 407: printf(": %s\n", intrrupt_str);
! 408:
! 409: sc->pciid = pa->pa_id;
! 410:
! 411: if (azalia_attach(sc)) {
! 412: printf("%s: initialization failure\n", XNAME(sc));
! 413: azalia_pci_detach(self, 0);
! 414: return;
! 415: }
! 416: sc->subid = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
! 417:
! 418: azalia_attach_intr(self);
! 419: }
! 420:
! 421: int
! 422: azalia_pci_activate(struct device *self, enum devact act)
! 423: {
! 424: azalia_t *sc;
! 425: int ret;
! 426:
! 427: sc = (azalia_t*)self;
! 428: ret = 0;
! 429: switch (act) {
! 430: case DVACT_ACTIVATE:
! 431: return ret;
! 432: case DVACT_DEACTIVATE:
! 433: if (sc->audiodev != NULL)
! 434: ret = config_deactivate(sc->audiodev);
! 435: return ret;
! 436: }
! 437: return EOPNOTSUPP;
! 438: }
! 439:
! 440: int
! 441: azalia_pci_detach(struct device *self, int flags)
! 442: {
! 443: azalia_t *az;
! 444: int i;
! 445:
! 446: DPRINTF(("%s\n", __func__));
! 447: az = (azalia_t*)self;
! 448: if (az->audiodev != NULL) {
! 449: config_detach(az->audiodev, flags);
! 450: az->audiodev = NULL;
! 451: }
! 452:
! 453: DPRINTF(("%s: delete streams\n", __func__));
! 454: azalia_stream_delete(&az->rstream, az);
! 455: azalia_stream_delete(&az->pstream, az);
! 456:
! 457: DPRINTF(("%s: delete codecs\n", __func__));
! 458: for (i = 0; i < az->ncodecs; i++) {
! 459: azalia_codec_delete(&az->codecs[i]);
! 460: }
! 461: az->ncodecs = 0;
! 462:
! 463: DPRINTF(("%s: delete CORB and RIRB\n", __func__));
! 464: azalia_delete_corb(az);
! 465: azalia_delete_rirb(az);
! 466:
! 467: DPRINTF(("%s: delete PCI resources\n", __func__));
! 468: if (az->ih != NULL) {
! 469: pci_intr_disestablish(az->pc, az->ih);
! 470: az->ih = NULL;
! 471: }
! 472: if (az->map_size != 0) {
! 473: bus_space_unmap(az->iot, az->ioh, az->map_size);
! 474: az->map_size = 0;
! 475: }
! 476: return 0;
! 477: }
! 478:
! 479: int
! 480: azalia_intr(void *v)
! 481: {
! 482: azalia_t *az = v;
! 483: int ret = 0;
! 484: uint32_t intsts;
! 485: uint8_t rirbsts, rirbctl;
! 486:
! 487: intsts = AZ_READ_4(az, INTSTS);
! 488: if (intsts == 0)
! 489: return (0);
! 490:
! 491: AZ_WRITE_4(az, INTSTS, intsts);
! 492:
! 493: ret += azalia_stream_intr(&az->pstream, intsts);
! 494: ret += azalia_stream_intr(&az->rstream, intsts);
! 495:
! 496: rirbctl = AZ_READ_1(az, RIRBCTL);
! 497: rirbsts = AZ_READ_1(az, RIRBSTS);
! 498:
! 499: if (intsts & HDA_INTCTL_CIE) {
! 500: if (rirbctl & HDA_RIRBCTL_RINTCTL) {
! 501: if (rirbsts & HDA_RIRBSTS_RINTFL)
! 502: azalia_rirb_intr(az);
! 503: }
! 504: }
! 505:
! 506: return (1);
! 507: }
! 508:
! 509: /* ================================================================
! 510: * HDA controller functions
! 511: * ================================================================ */
! 512:
! 513: int
! 514: azalia_attach(azalia_t *az)
! 515: {
! 516: int i, n;
! 517: uint32_t gctl;
! 518: uint16_t gcap;
! 519: uint16_t statests;
! 520:
! 521: printf("%s: host: High Definition Audio rev. %d.%d\n",
! 522: XNAME(az), AZ_READ_1(az, VMAJ), AZ_READ_1(az, VMIN));
! 523: gcap = AZ_READ_2(az, GCAP);
! 524: az->nistreams = HDA_GCAP_ISS(gcap);
! 525: az->nostreams = HDA_GCAP_OSS(gcap);
! 526: az->nbstreams = HDA_GCAP_BSS(gcap);
! 527: az->ok64 = (gcap & HDA_GCAP_64OK) != 0;
! 528: DPRINTF(("%s: host: %d output, %d input, and %d bidi streams\n",
! 529: XNAME(az), az->nostreams, az->nistreams, az->nbstreams));
! 530:
! 531: /* 4.2.2 Starting the High Definition Audio Controller */
! 532: DPRINTF(("%s: resetting\n", __func__));
! 533: gctl = AZ_READ_4(az, GCTL);
! 534: AZ_WRITE_4(az, GCTL, gctl & ~HDA_GCTL_CRST);
! 535: for (i = 5000; i >= 0; i--) {
! 536: DELAY(10);
! 537: if ((AZ_READ_4(az, GCTL) & HDA_GCTL_CRST) == 0)
! 538: break;
! 539: }
! 540: DPRINTF(("%s: reset counter = %d\n", __func__, i));
! 541: if (i <= 0) {
! 542: printf("%s: reset failure\n", XNAME(az));
! 543: return ETIMEDOUT;
! 544: }
! 545: DELAY(1000);
! 546: gctl = AZ_READ_4(az, GCTL);
! 547: AZ_WRITE_4(az, GCTL, gctl | HDA_GCTL_CRST);
! 548: for (i = 5000; i >= 0; i--) {
! 549: DELAY(10);
! 550: if (AZ_READ_4(az, GCTL) & HDA_GCTL_CRST)
! 551: break;
! 552: }
! 553: DPRINTF(("%s: reset counter = %d\n", __func__, i));
! 554: if (i <= 0) {
! 555: printf("%s: reset-exit failure\n", XNAME(az));
! 556: return ETIMEDOUT;
! 557: }
! 558:
! 559: /* enable unsolicited response */
! 560: gctl = AZ_READ_4(az, GCTL);
! 561: AZ_WRITE_4(az, GCTL, gctl | HDA_GCTL_UNSOL);
! 562:
! 563: /* 4.3 Codec discovery */
! 564: DELAY(1000);
! 565: statests = AZ_READ_2(az, STATESTS);
! 566: for (i = 0, n = 0; i < 15; i++) {
! 567: if ((statests >> i) & 1) {
! 568: DPRINTF(("%s: found a codec at #%d\n", XNAME(az), i));
! 569: az->codecs[n].address = i;
! 570: az->codecs[n++].az = az;
! 571: }
! 572: }
! 573: az->ncodecs = n;
! 574: if (az->ncodecs < 1) {
! 575: printf("%s: No HD-Audio codecs\n", XNAME(az));
! 576: return -1;
! 577: }
! 578: return 0;
! 579: }
! 580:
! 581: void
! 582: azalia_attach_intr(struct device *self)
! 583: {
! 584: azalia_t *az;
! 585: int err, i, c;
! 586:
! 587: az = (azalia_t*)self;
! 588:
! 589: AZ_WRITE_2(az, STATESTS, HDA_STATESTS_SDIWAKE);
! 590: AZ_WRITE_1(az, RIRBSTS, HDA_RIRBSTS_RINTFL | HDA_RIRBSTS_RIRBOIS);
! 591: AZ_WRITE_4(az, INTSTS, HDA_INTSTS_CIS | HDA_INTSTS_GIS);
! 592: AZ_WRITE_4(az, DPLBASE, 0);
! 593: AZ_WRITE_4(az, DPUBASE, 0);
! 594:
! 595: /* 4.4.1 Command Outbound Ring Buffer */
! 596: if (azalia_init_corb(az))
! 597: goto err_exit;
! 598: /* 4.4.2 Response Inbound Ring Buffer */
! 599: if (azalia_init_rirb(az))
! 600: goto err_exit;
! 601:
! 602: AZ_WRITE_4(az, INTCTL,
! 603: AZ_READ_4(az, INTCTL) | HDA_INTCTL_CIE | HDA_INTCTL_GIE);
! 604:
! 605: c = -1;
! 606: for (i = 0; i < az->ncodecs; i++) {
! 607: err = azalia_codec_init(&az->codecs[i]);
! 608: if (!err && c < 0)
! 609: c = i;
! 610: }
! 611: if (c < 0)
! 612: goto err_exit;
! 613: /* Use the first audio codec */
! 614: az->codecno = c;
! 615: DPRINTF(("%s: using the #%d codec\n", XNAME(az), az->codecno));
! 616:
! 617: if (azalia_stream_init(&az->pstream, az, az->nistreams + 0,
! 618: 1, AUMODE_PLAY))
! 619: goto err_exit;
! 620: if (azalia_stream_init(&az->rstream, az, 0, 2, AUMODE_RECORD))
! 621: goto err_exit;
! 622:
! 623: az->audiodev = audio_attach_mi(&azalia_hw_if, az, &az->dev);
! 624: return;
! 625: err_exit:
! 626: azalia_pci_detach(self, 0);
! 627: return;
! 628: }
! 629:
! 630: int
! 631: azalia_init_corb(azalia_t *az)
! 632: {
! 633: int entries, err, i;
! 634: uint16_t corbrp, corbwp;
! 635: uint8_t corbsize, cap, corbctl;
! 636:
! 637: /* stop the CORB */
! 638: corbctl = AZ_READ_1(az, CORBCTL);
! 639: if (corbctl & HDA_CORBCTL_CORBRUN) { /* running? */
! 640: AZ_WRITE_1(az, CORBCTL, corbctl & ~HDA_CORBCTL_CORBRUN);
! 641: for (i = 5000; i >= 0; i--) {
! 642: DELAY(10);
! 643: corbctl = AZ_READ_1(az, CORBCTL);
! 644: if ((corbctl & HDA_CORBCTL_CORBRUN) == 0)
! 645: break;
! 646: }
! 647: if (i <= 0) {
! 648: printf("%s: CORB is running\n", XNAME(az));
! 649: return EBUSY;
! 650: }
! 651: }
! 652:
! 653: /* determine CORB size */
! 654: corbsize = AZ_READ_1(az, CORBSIZE);
! 655: cap = corbsize & HDA_CORBSIZE_CORBSZCAP_MASK;
! 656: corbsize &= ~HDA_CORBSIZE_CORBSIZE_MASK;
! 657: if (cap & HDA_CORBSIZE_CORBSZCAP_256) {
! 658: entries = 256;
! 659: corbsize |= HDA_CORBSIZE_CORBSIZE_256;
! 660: } else if (cap & HDA_CORBSIZE_CORBSZCAP_16) {
! 661: entries = 16;
! 662: corbsize |= HDA_CORBSIZE_CORBSIZE_16;
! 663: } else if (cap & HDA_CORBSIZE_CORBSZCAP_2) {
! 664: entries = 2;
! 665: corbsize |= HDA_CORBSIZE_CORBSIZE_2;
! 666: } else {
! 667: printf("%s: Invalid CORBSZCAP: 0x%2x\n", XNAME(az), cap);
! 668: return -1;
! 669: }
! 670:
! 671: err = azalia_alloc_dmamem(az, entries * sizeof(corb_entry_t),
! 672: 128, &az->corb_dma);
! 673: if (err) {
! 674: printf("%s: can't allocate CORB buffer\n", XNAME(az));
! 675: return err;
! 676: }
! 677: AZ_WRITE_4(az, CORBLBASE, (uint32_t)AZALIA_DMA_DMAADDR(&az->corb_dma));
! 678: AZ_WRITE_4(az, CORBUBASE, PTR_UPPER32(AZALIA_DMA_DMAADDR(&az->corb_dma)));
! 679: AZ_WRITE_1(az, CORBSIZE, corbsize);
! 680: az->corb_size = entries;
! 681:
! 682: DPRINTF(("%s: CORB allocation succeeded.\n", __func__));
! 683:
! 684: /* reset CORBRP */
! 685: corbrp = AZ_READ_2(az, CORBRP);
! 686: AZ_WRITE_2(az, CORBRP, corbrp | HDA_CORBRP_CORBRPRST);
! 687: AZ_WRITE_2(az, CORBRP, corbrp & ~HDA_CORBRP_CORBRPRST);
! 688: for (i = 5000; i >= 0; i--) {
! 689: DELAY(10);
! 690: corbrp = AZ_READ_2(az, CORBRP);
! 691: if ((corbrp & HDA_CORBRP_CORBRPRST) == 0)
! 692: break;
! 693: }
! 694: if (i <= 0) {
! 695: printf("%s: CORBRP reset failure\n", XNAME(az));
! 696: return -1;
! 697: }
! 698: DPRINTF(("%s: CORBWP=%d; size=%d\n", __func__,
! 699: AZ_READ_2(az, CORBRP) & HDA_CORBRP_CORBRP, az->corb_size));
! 700:
! 701: /* clear CORBWP */
! 702: corbwp = AZ_READ_2(az, CORBWP);
! 703: AZ_WRITE_2(az, CORBWP, corbwp & ~HDA_CORBWP_CORBWP);
! 704:
! 705: /* Run! */
! 706: corbctl = AZ_READ_1(az, CORBCTL);
! 707: AZ_WRITE_1(az, CORBCTL, corbctl | HDA_CORBCTL_CORBRUN);
! 708: return 0;
! 709: }
! 710:
! 711: int
! 712: azalia_delete_corb(azalia_t *az)
! 713: {
! 714: int i;
! 715: uint8_t corbctl;
! 716:
! 717: if (az->corb_dma.addr == NULL)
! 718: return 0;
! 719: /* stop the CORB */
! 720: corbctl = AZ_READ_1(az, CORBCTL);
! 721: AZ_WRITE_1(az, CORBCTL, corbctl & ~HDA_CORBCTL_CORBRUN);
! 722: for (i = 5000; i >= 0; i--) {
! 723: DELAY(10);
! 724: corbctl = AZ_READ_1(az, CORBCTL);
! 725: if ((corbctl & HDA_CORBCTL_CORBRUN) == 0)
! 726: break;
! 727: }
! 728: azalia_free_dmamem(az, &az->corb_dma);
! 729: return 0;
! 730: }
! 731:
! 732: int
! 733: azalia_init_rirb(azalia_t *az)
! 734: {
! 735: int entries, err, i;
! 736: uint16_t rirbwp;
! 737: uint8_t rirbsize, cap, rirbctl;
! 738:
! 739: /* stop the RIRB */
! 740: rirbctl = AZ_READ_1(az, RIRBCTL);
! 741: if (rirbctl & HDA_RIRBCTL_RIRBDMAEN) { /* running? */
! 742: AZ_WRITE_1(az, RIRBCTL, rirbctl & ~HDA_RIRBCTL_RIRBDMAEN);
! 743: for (i = 5000; i >= 0; i--) {
! 744: DELAY(10);
! 745: rirbctl = AZ_READ_1(az, RIRBCTL);
! 746: if ((rirbctl & HDA_RIRBCTL_RIRBDMAEN) == 0)
! 747: break;
! 748: }
! 749: if (i <= 0) {
! 750: printf("%s: RIRB is running\n", XNAME(az));
! 751: return EBUSY;
! 752: }
! 753: }
! 754:
! 755: /* determine RIRB size */
! 756: rirbsize = AZ_READ_1(az, RIRBSIZE);
! 757: cap = rirbsize & HDA_RIRBSIZE_RIRBSZCAP_MASK;
! 758: rirbsize &= ~HDA_RIRBSIZE_RIRBSIZE_MASK;
! 759: if (cap & HDA_RIRBSIZE_RIRBSZCAP_256) {
! 760: entries = 256;
! 761: rirbsize |= HDA_RIRBSIZE_RIRBSIZE_256;
! 762: } else if (cap & HDA_RIRBSIZE_RIRBSZCAP_16) {
! 763: entries = 16;
! 764: rirbsize |= HDA_RIRBSIZE_RIRBSIZE_16;
! 765: } else if (cap & HDA_RIRBSIZE_RIRBSZCAP_2) {
! 766: entries = 2;
! 767: rirbsize |= HDA_RIRBSIZE_RIRBSIZE_2;
! 768: } else {
! 769: printf("%s: Invalid RIRBSZCAP: 0x%2x\n", XNAME(az), cap);
! 770: return -1;
! 771: }
! 772:
! 773: err = azalia_alloc_dmamem(az, entries * sizeof(rirb_entry_t),
! 774: 128, &az->rirb_dma);
! 775: if (err) {
! 776: printf("%s: can't allocate RIRB buffer\n", XNAME(az));
! 777: return err;
! 778: }
! 779: AZ_WRITE_4(az, RIRBLBASE, (uint32_t)AZALIA_DMA_DMAADDR(&az->rirb_dma));
! 780: AZ_WRITE_4(az, RIRBUBASE, PTR_UPPER32(AZALIA_DMA_DMAADDR(&az->rirb_dma)));
! 781: AZ_WRITE_1(az, RIRBSIZE, rirbsize);
! 782: az->rirb_size = entries;
! 783:
! 784: DPRINTF(("%s: RIRB allocation succeeded.\n", __func__));
! 785:
! 786: /* setup the unsolicited response queue */
! 787: az->unsolq_rp = 0;
! 788: az->unsolq_wp = 0;
! 789: az->unsolq_kick = FALSE;
! 790: az->unsolq = malloc(sizeof(rirb_entry_t) * UNSOLQ_SIZE,
! 791: M_DEVBUF, M_NOWAIT);
! 792: if (az->unsolq == NULL) {
! 793: DPRINTF(("%s: can't allocate unsolicited response queue.\n",
! 794: XNAME(az)));
! 795: azalia_free_dmamem(az, &az->rirb_dma);
! 796: return ENOMEM;
! 797: }
! 798: bzero(az->unsolq, sizeof(rirb_entry_t) * UNSOLQ_SIZE);
! 799:
! 800: /* reset the write pointer */
! 801: rirbwp = AZ_READ_2(az, RIRBWP);
! 802: AZ_WRITE_2(az, RIRBWP, rirbwp | HDA_RIRBWP_RIRBWPRST);
! 803:
! 804: /* clear the read pointer */
! 805: az->rirb_rp = AZ_READ_2(az, RIRBWP) & HDA_RIRBWP_RIRBWP;
! 806: DPRINTF(("%s: RIRBRP=%d, size=%d\n", __func__, az->rirb_rp, az->rirb_size));
! 807:
! 808: AZ_WRITE_2(az, RINTCNT, 1);
! 809:
! 810: /* Run! */
! 811: rirbctl = AZ_READ_1(az, RIRBCTL);
! 812: AZ_WRITE_1(az, RIRBCTL, rirbctl |
! 813: HDA_RIRBCTL_RIRBDMAEN | HDA_RIRBCTL_RINTCTL);
! 814:
! 815: return (0);
! 816: }
! 817:
! 818: int
! 819: azalia_delete_rirb(azalia_t *az)
! 820: {
! 821: int i;
! 822: uint8_t rirbctl;
! 823:
! 824: if (az->unsolq != NULL) {
! 825: free(az->unsolq, M_DEVBUF);
! 826: az->unsolq = NULL;
! 827: }
! 828: if (az->rirb_dma.addr == NULL)
! 829: return 0;
! 830: /* stop the RIRB */
! 831: rirbctl = AZ_READ_1(az, RIRBCTL);
! 832: AZ_WRITE_1(az, RIRBCTL, rirbctl & ~HDA_RIRBCTL_RIRBDMAEN);
! 833: for (i = 5000; i >= 0; i--) {
! 834: DELAY(10);
! 835: rirbctl = AZ_READ_1(az, RIRBCTL);
! 836: if ((rirbctl & HDA_RIRBCTL_RIRBDMAEN) == 0)
! 837: break;
! 838: }
! 839: azalia_free_dmamem(az, &az->rirb_dma);
! 840: return 0;
! 841: }
! 842:
! 843: int
! 844: azalia_set_command(azalia_t *az, int caddr, nid_t nid, uint32_t control,
! 845: uint32_t param)
! 846: {
! 847: corb_entry_t *corb;
! 848: int wp;
! 849: uint32_t verb;
! 850: uint16_t corbwp;
! 851: uint8_t rirbctl;
! 852:
! 853: #ifdef DIAGNOSTIC
! 854: if ((AZ_READ_1(az, CORBCTL) & HDA_CORBCTL_CORBRUN) == 0) {
! 855: printf("%s: CORB is not running.\n", XNAME(az));
! 856: return -1;
! 857: }
! 858: #endif
! 859: verb = (caddr << 28) | (nid << 20) | (control << 8) | param;
! 860: corbwp = AZ_READ_2(az, CORBWP);
! 861: wp = corbwp & HDA_CORBWP_CORBWP;
! 862: corb = (corb_entry_t*)az->corb_dma.addr;
! 863: if (++wp >= az->corb_size)
! 864: wp = 0;
! 865: corb[wp] = verb;
! 866:
! 867: /* disable RIRB interrupts */
! 868: rirbctl = AZ_READ_1(az, RIRBCTL);
! 869: if (rirbctl & HDA_RIRBCTL_RINTCTL) {
! 870: AZ_WRITE_1(az, RIRBCTL, rirbctl & ~HDA_RIRBCTL_RINTCTL);
! 871: azalia_rirb_intr(az);
! 872: }
! 873:
! 874: AZ_WRITE_2(az, CORBWP, (corbwp & ~HDA_CORBWP_CORBWP) | wp);
! 875: #if 0
! 876: DPRINTF(("%s: caddr=%d nid=%d control=0x%x param=0x%x verb=0x%8.8x wp=%d\n",
! 877: __func__, caddr, nid, control, param, verb, wp));
! 878: #endif
! 879: return 0;
! 880: }
! 881:
! 882: int
! 883: azalia_get_response(azalia_t *az, uint32_t *result)
! 884: {
! 885: const rirb_entry_t *rirb;
! 886: int i;
! 887: uint16_t wp;
! 888: uint8_t rirbctl;
! 889:
! 890: #ifdef DIAGNOSTIC
! 891: if ((AZ_READ_1(az, RIRBCTL) & HDA_RIRBCTL_RIRBDMAEN) == 0) {
! 892: printf("%s: RIRB is not running.\n", XNAME(az));
! 893: return -1;
! 894: }
! 895: #endif
! 896: for (i = 5000; i >= 0; i--) {
! 897: wp = AZ_READ_2(az, RIRBWP) & HDA_RIRBWP_RIRBWP;
! 898: if (az->rirb_rp != wp)
! 899: break;
! 900: DELAY(10);
! 901: }
! 902: if (i <= 0) {
! 903: printf("%s: RIRB time out\n", XNAME(az));
! 904: return ETIMEDOUT;
! 905: }
! 906: rirb = (rirb_entry_t*)az->rirb_dma.addr;
! 907: for (;;) {
! 908: if (++az->rirb_rp >= az->rirb_size)
! 909: az->rirb_rp = 0;
! 910: if (rirb[az->rirb_rp].resp_ex & RIRB_RESP_UNSOL) {
! 911: az->unsolq[az->unsolq_wp].resp = rirb[az->rirb_rp].resp;
! 912: az->unsolq[az->unsolq_wp++].resp_ex = rirb[az->rirb_rp].resp_ex;
! 913: az->unsolq_wp %= UNSOLQ_SIZE;
! 914: } else
! 915: break;
! 916: }
! 917: if (result != NULL)
! 918: *result = rirb[az->rirb_rp].resp;
! 919:
! 920: azalia_rirb_kick_unsol_events(az);
! 921: #if 0
! 922: for (i = 0; i < 16 /*az->rirb_size*/; i++) {
! 923: DPRINTF(("rirb[%d] 0x%8.8x:0x%8.8x ", i, rirb[i].resp, rirb[i].resp_ex));
! 924: if ((i % 2) == 1)
! 925: DPRINTF(("\n"));
! 926: }
! 927: #endif
! 928:
! 929: /* re-enable RIRB interrupts */
! 930: rirbctl = AZ_READ_1(az, RIRBCTL);
! 931: AZ_WRITE_1(az, RIRBCTL, rirbctl | HDA_RIRBCTL_RINTCTL);
! 932:
! 933: return 0;
! 934: }
! 935:
! 936: void
! 937: azalia_rirb_kick_unsol_events(azalia_t *az)
! 938: {
! 939: if (az->unsolq_kick)
! 940: return;
! 941: az->unsolq_kick = TRUE;
! 942: while (az->unsolq_rp != az->unsolq_wp) {
! 943: int i;
! 944: int tag;
! 945: codec_t *codec;
! 946: i = RIRB_RESP_CODEC(az->unsolq[az->unsolq_rp].resp_ex);
! 947: tag = RIRB_UNSOL_TAG(az->unsolq[az->unsolq_rp].resp);
! 948: codec = &az->codecs[i];
! 949: DPRINTF(("%s: codec#=%d tag=%d\n", __func__, i, tag));
! 950: az->unsolq_rp++;
! 951: az->unsolq_rp %= UNSOLQ_SIZE;
! 952: if (codec->unsol_event != NULL)
! 953: codec->unsol_event(codec, tag);
! 954: }
! 955: az->unsolq_kick = FALSE;
! 956: }
! 957:
! 958: void
! 959: azalia_rirb_intr(azalia_t *az)
! 960: {
! 961: const rirb_entry_t *rirb;
! 962: uint16_t wp, rp;
! 963: uint8_t rirbsts;
! 964:
! 965: rirbsts = AZ_READ_1(az, RIRBSTS);
! 966:
! 967: wp = AZ_READ_2(az, RIRBWP) & HDA_RIRBWP_RIRBWP;
! 968: if (rp == wp)
! 969: return; /* interrupted but no data in RIRB */
! 970: rirb = (rirb_entry_t*)az->rirb_dma.addr;
! 971: while (az->rirb_rp != wp) {
! 972: if (++az->rirb_rp >= az->rirb_size)
! 973: az->rirb_rp = 0;
! 974: if (rirb[az->rirb_rp].resp_ex & RIRB_RESP_UNSOL) {
! 975: az->unsolq[az->unsolq_wp].resp = rirb[az->rirb_rp].resp;
! 976: az->unsolq[az->unsolq_wp++].resp_ex = rirb[az->rirb_rp].resp_ex;
! 977: az->unsolq_wp %= UNSOLQ_SIZE;
! 978: } else {
! 979: break;
! 980: }
! 981: }
! 982:
! 983: azalia_rirb_kick_unsol_events(az);
! 984:
! 985: AZ_WRITE_1(az, RIRBSTS,
! 986: rirbsts | HDA_RIRBSTS_RIRBOIS | HDA_RIRBSTS_RINTFL);
! 987: }
! 988:
! 989: int
! 990: azalia_alloc_dmamem(azalia_t *az, size_t size, size_t align, azalia_dma_t *d)
! 991: {
! 992: int err;
! 993: int nsegs;
! 994:
! 995: d->size = size;
! 996: err = bus_dmamem_alloc(az->dmat, size, align, 0, d->segments, 1,
! 997: &nsegs, BUS_DMA_NOWAIT);
! 998: if (err)
! 999: return err;
! 1000: if (nsegs != 1)
! 1001: goto free;
! 1002: err = bus_dmamem_map(az->dmat, d->segments, 1, size,
! 1003: &d->addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT | BUS_DMA_NOCACHE);
! 1004: if (err)
! 1005: goto free;
! 1006: err = bus_dmamap_create(az->dmat, size, 1, size, 0,
! 1007: BUS_DMA_NOWAIT, &d->map);
! 1008: if (err)
! 1009: goto unmap;
! 1010: err = bus_dmamap_load(az->dmat, d->map, d->addr, size,
! 1011: NULL, BUS_DMA_NOWAIT);
! 1012: if (err)
! 1013: goto destroy;
! 1014:
! 1015: if (!az->ok64 && PTR_UPPER32(AZALIA_DMA_DMAADDR(d)) != 0) {
! 1016: azalia_free_dmamem(az, d);
! 1017: return -1;
! 1018: }
! 1019: return 0;
! 1020:
! 1021: destroy:
! 1022: bus_dmamap_destroy(az->dmat, d->map);
! 1023: unmap:
! 1024: bus_dmamem_unmap(az->dmat, d->addr, size);
! 1025: free:
! 1026: bus_dmamem_free(az->dmat, d->segments, 1);
! 1027: d->addr = NULL;
! 1028: return err;
! 1029: }
! 1030:
! 1031: int
! 1032: azalia_free_dmamem(const azalia_t *az, azalia_dma_t* d)
! 1033: {
! 1034: if (d->addr == NULL)
! 1035: return 0;
! 1036: bus_dmamap_unload(az->dmat, d->map);
! 1037: bus_dmamap_destroy(az->dmat, d->map);
! 1038: bus_dmamem_unmap(az->dmat, d->addr, d->size);
! 1039: bus_dmamem_free(az->dmat, d->segments, 1);
! 1040: d->addr = NULL;
! 1041: return 0;
! 1042: }
! 1043:
! 1044: /* ================================================================
! 1045: * HDA codec functions
! 1046: * ================================================================ */
! 1047:
! 1048: int
! 1049: azalia_codec_init(codec_t *this)
! 1050: {
! 1051: uint32_t rev, id, result;
! 1052: int err, addr, n, i;
! 1053: const char *vendor;
! 1054:
! 1055: this->comresp = azalia_codec_comresp;
! 1056: addr = this->address;
! 1057: DPRINTF(("%s: information of codec[%d] follows:\n",
! 1058: XNAME(this->az), addr));
! 1059: /* codec vendor/device/revision */
! 1060: err = this->comresp(this, CORB_NID_ROOT, CORB_GET_PARAMETER,
! 1061: COP_REVISION_ID, &rev);
! 1062: if (err)
! 1063: return err;
! 1064: err = this->comresp(this, CORB_NID_ROOT, CORB_GET_PARAMETER,
! 1065: COP_VENDOR_ID, &id);
! 1066: if (err)
! 1067: return err;
! 1068: this->vid = id;
! 1069: this->subid = this->az->subid;
! 1070: azalia_codec_init_vtbl(this);
! 1071:
! 1072: printf("%s: codec:", XNAME(this->az));
! 1073: if (this->name == NULL) {
! 1074: vendor = pci_findvendor(id >> 16);
! 1075: if (vendor == NULL)
! 1076: printf(" 0x%04x/0x%04x", id >> 16, id & 0xffff);
! 1077: else
! 1078: printf(" %s/0x%04x", vendor, id & 0xffff);
! 1079: } else
! 1080: printf(" %s", this->name);
! 1081: printf(" (rev. %u.%u), HDA version %u.%u\n",
! 1082: COP_RID_REVISION(rev), COP_RID_STEPPING(rev),
! 1083: COP_RID_MAJ(rev), COP_RID_MIN(rev));
! 1084:
! 1085: /* identify function nodes */
! 1086: err = this->comresp(this, CORB_NID_ROOT, CORB_GET_PARAMETER,
! 1087: COP_SUBORDINATE_NODE_COUNT, &result);
! 1088: if (err)
! 1089: return err;
! 1090: this->nfunctions = COP_NSUBNODES(result);
! 1091: if (COP_NSUBNODES(result) <= 0) {
! 1092: printf("%s: No function groups\n", XNAME(this->az));
! 1093: return -1;
! 1094: }
! 1095: /* iterate function nodes and find an audio function */
! 1096: n = COP_START_NID(result);
! 1097: DPRINTF(("%s: nidstart=%d #functions=%d\n",
! 1098: __func__, n, this->nfunctions));
! 1099: this->audiofunc = -1;
! 1100: for (i = 0; i < this->nfunctions; i++) {
! 1101: err = this->comresp(this, n + i, CORB_GET_PARAMETER,
! 1102: COP_FUNCTION_GROUP_TYPE, &result);
! 1103: if (err)
! 1104: continue;
! 1105: DPRINTF(("%s: FTYPE result = 0x%8.8x\n", __func__, result));
! 1106: if (COP_FTYPE(result) == COP_FTYPE_AUDIO) {
! 1107: this->audiofunc = n + i;
! 1108: break; /* XXX multiple audio functions? */
! 1109: } else if (COP_FTYPE(result) == COP_FTYPE_MODEM) {
! 1110: printf("%s: codec[%d]: No support for modem function groups\n",
! 1111: XNAME(this->az), addr);
! 1112: }
! 1113: }
! 1114: if (this->audiofunc < 0) {
! 1115: printf("%s: codec[%d]: No audio function groups\n",
! 1116: XNAME(this->az), addr);
! 1117: return -1;
! 1118: }
! 1119:
! 1120: /* power the audio function */
! 1121: this->comresp(this, this->audiofunc, CORB_SET_POWER_STATE, CORB_PS_D0, &result);
! 1122: DELAY(100);
! 1123:
! 1124: /* check widgets in the audio function */
! 1125: err = this->comresp(this, this->audiofunc,
! 1126: CORB_GET_PARAMETER, COP_SUBORDINATE_NODE_COUNT, &result);
! 1127: if (err)
! 1128: return err;
! 1129: DPRINTF(("%s: There are %d widgets in the audio function.\n",
! 1130: __func__, COP_NSUBNODES(result)));
! 1131: this->wstart = COP_START_NID(result);
! 1132: if (this->wstart < 2) {
! 1133: printf("%s: invalid node structure\n", XNAME(this->az));
! 1134: return -1;
! 1135: }
! 1136: this->wend = this->wstart + COP_NSUBNODES(result);
! 1137: this->w = malloc(sizeof(widget_t) * this->wend, M_DEVBUF, M_NOWAIT);
! 1138: if (this->w == NULL) {
! 1139: printf("%s: out of memory\n", XNAME(this->az));
! 1140: return ENOMEM;
! 1141: }
! 1142: bzero(this->w, sizeof(widget_t) * this->wend);
! 1143:
! 1144: /* query the base parameters */
! 1145: this->comresp(this, this->audiofunc, CORB_GET_PARAMETER,
! 1146: COP_STREAM_FORMATS, &result);
! 1147: this->w[this->audiofunc].d.audio.encodings = result;
! 1148: this->comresp(this, this->audiofunc, CORB_GET_PARAMETER,
! 1149: COP_PCM, &result);
! 1150: this->w[this->audiofunc].d.audio.bits_rates = result;
! 1151: this->comresp(this, this->audiofunc, CORB_GET_PARAMETER,
! 1152: COP_INPUT_AMPCAP, &result);
! 1153: this->w[this->audiofunc].inamp_cap = result;
! 1154: this->comresp(this, this->audiofunc, CORB_GET_PARAMETER,
! 1155: COP_OUTPUT_AMPCAP, &result);
! 1156: this->w[this->audiofunc].outamp_cap = result;
! 1157: #ifdef AZALIA_DEBUG
! 1158: azalia_widget_print_audio(&this->w[this->audiofunc], "\t");
! 1159: result = this->w[this->audiofunc].inamp_cap;
! 1160: DPRINTF(("\tinamp: mute=%u size=%u steps=%u offset=%u\n",
! 1161: (result & COP_AMPCAP_MUTE) != 0, COP_AMPCAP_STEPSIZE(result),
! 1162: COP_AMPCAP_NUMSTEPS(result), COP_AMPCAP_OFFSET(result)));
! 1163: result = this->w[this->audiofunc].outamp_cap;
! 1164: DPRINTF(("\toutamp: mute=%u size=%u steps=%u offset=%u\n",
! 1165: (result & COP_AMPCAP_MUTE) != 0, COP_AMPCAP_STEPSIZE(result),
! 1166: COP_AMPCAP_NUMSTEPS(result), COP_AMPCAP_OFFSET(result)));
! 1167: #endif
! 1168:
! 1169: strlcpy(this->w[CORB_NID_ROOT].name, "root",
! 1170: sizeof(this->w[CORB_NID_ROOT].name));
! 1171: strlcpy(this->w[this->audiofunc].name, "hdaudio",
! 1172: sizeof(this->w[this->audiofunc].name));
! 1173: FOR_EACH_WIDGET(this, i) {
! 1174: err = azalia_widget_init(&this->w[i], this, i);
! 1175: if (err)
! 1176: return err;
! 1177: }
! 1178:
! 1179: err = this->init_dacgroup(this);
! 1180: if (err)
! 1181: return err;
! 1182: #ifdef AZALIA_DEBUG
! 1183: for (i = 0; i < this->dacs.ngroups; i++) {
! 1184: DPRINTF(("%s: dacgroup[%d]:", __func__, i));
! 1185: for (n = 0; n < this->dacs.groups[i].nconv; n++) {
! 1186: DPRINTF((" %2.2x", this->dacs.groups[i].conv[n]));
! 1187: }
! 1188: DPRINTF(("\n"));
! 1189: }
! 1190: #endif
! 1191:
! 1192: /* set invalid values for azalia_codec_construct_format() to work */
! 1193: this->dacs.cur = -1;
! 1194: this->adcs.cur = -1;
! 1195: err = azalia_codec_construct_format(this, 0, 0);
! 1196: if (err)
! 1197: return err;
! 1198:
! 1199: return this->mixer_init(this);
! 1200: }
! 1201:
! 1202: int
! 1203: azalia_codec_delete(codec_t *this)
! 1204: {
! 1205: if (this->mixer_delete != NULL)
! 1206: this->mixer_delete(this);
! 1207: if (this->formats != NULL) {
! 1208: free(this->formats, M_DEVBUF);
! 1209: this->formats = NULL;
! 1210: }
! 1211: printf("delete_encodings...\n");
! 1212: auconv_delete_encodings(this->encodings);
! 1213: this->encodings = NULL;
! 1214: return 0;
! 1215: }
! 1216:
! 1217: int
! 1218: azalia_codec_construct_format(codec_t *this, int newdac, int newadc)
! 1219: {
! 1220: const convgroup_t *group;
! 1221: uint32_t bits_rates;
! 1222: int prev_dac, prev_adc;
! 1223: int pvariation, rvariation;
! 1224: int nbits, c, chan, i, err;
! 1225: nid_t nid;
! 1226:
! 1227: prev_dac = this->dacs.cur;
! 1228: this->dacs.cur = newdac;
! 1229: group = &this->dacs.groups[this->dacs.cur];
! 1230: bits_rates = this->w[group->conv[0]].d.audio.bits_rates;
! 1231: nbits = 0;
! 1232: if (bits_rates & COP_PCM_B8)
! 1233: nbits++;
! 1234: if (bits_rates & COP_PCM_B16)
! 1235: nbits++;
! 1236: if (bits_rates & COP_PCM_B20)
! 1237: nbits++;
! 1238: if (bits_rates & COP_PCM_B24)
! 1239: nbits++;
! 1240: if (bits_rates & COP_PCM_B32)
! 1241: nbits++;
! 1242: if (nbits == 0) {
! 1243: printf("%s: %s/%d invalid PCM format: 0x%8.8x\n",
! 1244: XNAME(this->az), __FILE__, __LINE__, bits_rates);
! 1245: return -1;
! 1246: }
! 1247: pvariation = group->nconv * nbits;
! 1248:
! 1249: prev_adc = this->adcs.cur;
! 1250: this->adcs.cur = newadc;
! 1251: group = &this->adcs.groups[this->adcs.cur];
! 1252: bits_rates = this->w[group->conv[0]].d.audio.bits_rates;
! 1253: nbits = 0;
! 1254: if (bits_rates & COP_PCM_B8)
! 1255: nbits++;
! 1256: if (bits_rates & COP_PCM_B16)
! 1257: nbits++;
! 1258: if (bits_rates & COP_PCM_B20)
! 1259: nbits++;
! 1260: if (bits_rates & COP_PCM_B24)
! 1261: nbits++;
! 1262: if (bits_rates & COP_PCM_B32)
! 1263: nbits++;
! 1264: if (nbits == 0) {
! 1265: printf("%s: %s/%d invalid PCM format: 0x%8.8x\n",
! 1266: XNAME(this->az), __FILE__, __LINE__, bits_rates);
! 1267: return -1;
! 1268: }
! 1269: rvariation = group->nconv * nbits;
! 1270:
! 1271: if (this->formats != NULL)
! 1272: free(this->formats, M_DEVBUF);
! 1273: this->nformats = 0;
! 1274: this->formats = malloc(sizeof(struct audio_format) *
! 1275: (pvariation + rvariation), M_DEVBUF, M_NOWAIT);
! 1276: if (this->formats == NULL) {
! 1277: printf("%s: out of memory in %s\n",
! 1278: XNAME(this->az), __func__);
! 1279: return ENOMEM;
! 1280: }
! 1281: bzero(this->formats, sizeof(struct audio_format) *
! 1282: (pvariation + rvariation));
! 1283:
! 1284: /* register formats for playback */
! 1285: group = &this->dacs.groups[this->dacs.cur];
! 1286: nid = group->conv[0];
! 1287: chan = 0;
! 1288: bits_rates = this->w[nid].d.audio.bits_rates;
! 1289: for (c = 0; c < group->nconv; c++) {
! 1290: for (chan = 0, i = 0; i <= c; i++)
! 1291: chan += WIDGET_CHANNELS(&this->w[group->conv[c]]);
! 1292: azalia_codec_add_bits(this, chan, bits_rates, AUMODE_PLAY);
! 1293: }
! 1294:
! 1295: /* register formats for recording */
! 1296: group = &this->adcs.groups[this->adcs.cur];
! 1297: nid = group->conv[0];
! 1298: chan = 0;
! 1299: bits_rates = this->w[nid].d.audio.bits_rates;
! 1300: for (c = 0; c < group->nconv; c++) {
! 1301: for (chan = 0, i = 0; i <= c; i++)
! 1302: chan += WIDGET_CHANNELS(&this->w[group->conv[c]]);
! 1303: azalia_codec_add_bits(this, chan, bits_rates, AUMODE_RECORD);
! 1304: }
! 1305:
! 1306: err = azalia_create_encodings(this->formats, this->nformats,
! 1307: &this->encodings);
! 1308: if (err)
! 1309: return err;
! 1310: return 0;
! 1311: }
! 1312:
! 1313: void
! 1314: azalia_codec_add_bits(codec_t *this, int chan, uint32_t bits_rates, int mode)
! 1315: {
! 1316: if (bits_rates & COP_PCM_B8)
! 1317: azalia_codec_add_format(this, chan, 8, 16, bits_rates, mode);
! 1318: if (bits_rates & COP_PCM_B16)
! 1319: azalia_codec_add_format(this, chan, 16, 16, bits_rates, mode);
! 1320: if (bits_rates & COP_PCM_B20)
! 1321: azalia_codec_add_format(this, chan, 20, 32, bits_rates, mode);
! 1322: if (bits_rates & COP_PCM_B24)
! 1323: azalia_codec_add_format(this, chan, 24, 32, bits_rates, mode);
! 1324: if (bits_rates & COP_PCM_B32)
! 1325: azalia_codec_add_format(this, chan, 32, 32, bits_rates, mode);
! 1326: }
! 1327:
! 1328: void
! 1329: azalia_codec_add_format(codec_t *this, int chan, int valid, int prec,
! 1330: uint32_t rates, int32_t mode)
! 1331: {
! 1332: struct audio_format *f;
! 1333:
! 1334: f = &this->formats[this->nformats++];
! 1335: f->mode = mode;
! 1336: f->encoding = AUDIO_ENCODING_SLINEAR_LE;
! 1337: if (valid == 8 && prec == 8)
! 1338: f->encoding = AUDIO_ENCODING_ULINEAR_LE;
! 1339: f->validbits = valid;
! 1340: f->precision = prec;
! 1341: f->channels = chan;
! 1342: switch (chan) {
! 1343: case 1:
! 1344: f->channel_mask = AUFMT_MONAURAL;
! 1345: break;
! 1346: case 2:
! 1347: f->channel_mask = AUFMT_STEREO;
! 1348: break;
! 1349: case 4:
! 1350: f->channel_mask = AUFMT_SURROUND4;
! 1351: break;
! 1352: case 6:
! 1353: f->channel_mask = AUFMT_DOLBY_5_1;
! 1354: break;
! 1355: case 8:
! 1356: f->channel_mask = AUFMT_DOLBY_5_1
! 1357: | AUFMT_SIDE_LEFT | AUFMT_SIDE_RIGHT;
! 1358: break;
! 1359: default:
! 1360: f->channel_mask = 0;
! 1361: }
! 1362: if (rates & COP_PCM_R80)
! 1363: f->frequency[f->frequency_type++] = 8000;
! 1364: if (rates & COP_PCM_R110)
! 1365: f->frequency[f->frequency_type++] = 11025;
! 1366: if (rates & COP_PCM_R160)
! 1367: f->frequency[f->frequency_type++] = 16000;
! 1368: if (rates & COP_PCM_R220)
! 1369: f->frequency[f->frequency_type++] = 22050;
! 1370: if (rates & COP_PCM_R320)
! 1371: f->frequency[f->frequency_type++] = 32000;
! 1372: if (rates & COP_PCM_R441)
! 1373: f->frequency[f->frequency_type++] = 44100;
! 1374: if (rates & COP_PCM_R480)
! 1375: f->frequency[f->frequency_type++] = 48000;
! 1376: if (rates & COP_PCM_R882)
! 1377: f->frequency[f->frequency_type++] = 88200;
! 1378: if (rates & COP_PCM_R960)
! 1379: f->frequency[f->frequency_type++] = 96000;
! 1380: if (rates & COP_PCM_R1764)
! 1381: f->frequency[f->frequency_type++] = 176400;
! 1382: if (rates & COP_PCM_R1920)
! 1383: f->frequency[f->frequency_type++] = 192000;
! 1384: if (rates & COP_PCM_R3840)
! 1385: f->frequency[f->frequency_type++] = 384000;
! 1386: }
! 1387:
! 1388: int
! 1389: azalia_codec_comresp(const codec_t *codec, nid_t nid, uint32_t control,
! 1390: uint32_t param, uint32_t* result)
! 1391: {
! 1392: int err;
! 1393:
! 1394: err = azalia_set_command(codec->az, codec->address, nid, control, param);
! 1395: if (err)
! 1396: return err;
! 1397: return azalia_get_response(codec->az, result);
! 1398: }
! 1399:
! 1400: int
! 1401: azalia_codec_connect_stream(codec_t *this, int dir, uint16_t fmt, int number)
! 1402: {
! 1403: const convgroup_t *group;
! 1404: int i, err, startchan, nchan;
! 1405: nid_t nid;
! 1406: boolean_t flag222;
! 1407:
! 1408: DPRINTF(("%s: fmt=0x%4.4x number=%d\n", __func__, fmt, number));
! 1409: err = 0;
! 1410: if (dir == AUMODE_RECORD)
! 1411: group = &this->adcs.groups[this->adcs.cur];
! 1412: else
! 1413: group = &this->dacs.groups[this->dacs.cur];
! 1414: flag222 = group->nconv >= 3 &&
! 1415: (WIDGET_CHANNELS(&this->w[group->conv[0]]) == 2) &&
! 1416: (WIDGET_CHANNELS(&this->w[group->conv[1]]) == 2) &&
! 1417: (WIDGET_CHANNELS(&this->w[group->conv[2]]) == 2);
! 1418: nchan = (fmt & HDA_SD_FMT_CHAN) + 1;
! 1419: startchan = 0;
! 1420: for (i = 0; i < group->nconv; i++) {
! 1421: nid = group->conv[i];
! 1422:
! 1423: /* surround and c/lfe handling */
! 1424: if (nchan >= 6 && flag222 && i == 1) {
! 1425: nid = group->conv[2];
! 1426: } else if (nchan >= 6 && flag222 && i == 2) {
! 1427: nid = group->conv[1];
! 1428: }
! 1429:
! 1430: err = this->comresp(this, nid, CORB_SET_CONVERTER_FORMAT, fmt, NULL);
! 1431: if (err)
! 1432: goto exit;
! 1433: err = this->comresp(this, nid, CORB_SET_CONVERTER_STREAM_CHANNEL,
! 1434: (number << 4) | startchan, NULL);
! 1435: if (err)
! 1436: goto exit;
! 1437: if (nchan > 2)
! 1438: startchan += WIDGET_CHANNELS(&this->w[nid]);
! 1439: }
! 1440:
! 1441: exit:
! 1442: DPRINTF(("%s: leave with %d\n", __func__, err));
! 1443: return err;
! 1444: }
! 1445:
! 1446: /* ================================================================
! 1447: * HDA widget functions
! 1448: * ================================================================ */
! 1449:
! 1450: #define WIDGETCAP_BITS \
! 1451: "\20\014LRSWAP\013POWER\012DIGITAL" \
! 1452: "\011CONNLIST\010UNSOL\07PROC\06STRIPE\05FORMATOV\04AMPOV\03OUTAMP" \
! 1453: "\02INAMP\01STEREO"
! 1454:
! 1455: int
! 1456: azalia_widget_init(widget_t *this, const codec_t *codec, nid_t nid)
! 1457: {
! 1458: uint32_t result;
! 1459: int err;
! 1460:
! 1461: err = codec->comresp(codec, nid, CORB_GET_PARAMETER,
! 1462: COP_AUDIO_WIDGET_CAP, &result);
! 1463: if (err)
! 1464: return err;
! 1465: this->nid = nid;
! 1466: this->widgetcap = result;
! 1467: this->type = COP_AWCAP_TYPE(result);
! 1468: DPRINTF(("%s: ", XNAME(codec->az)));
! 1469: if (this->widgetcap & COP_AWCAP_POWER) {
! 1470: codec->comresp(codec, nid, CORB_SET_POWER_STATE, CORB_PS_D0, &result);
! 1471: DELAY(100);
! 1472: }
! 1473: switch (this->type) {
! 1474: case COP_AWTYPE_AUDIO_OUTPUT:
! 1475: snprintf(this->name, sizeof(this->name), "dac%2.2x", nid);
! 1476: DPRINTF(("%s wcap=%b\n", this->name,
! 1477: this->widgetcap, WIDGETCAP_BITS));
! 1478: azalia_widget_init_audio(this, codec);
! 1479: break;
! 1480: case COP_AWTYPE_AUDIO_INPUT:
! 1481: snprintf(this->name, sizeof(this->name), "adc%2.2x", nid);
! 1482: DPRINTF(("%s wcap=%b\n", this->name,
! 1483: this->widgetcap, WIDGETCAP_BITS));
! 1484: azalia_widget_init_audio(this, codec);
! 1485: break;
! 1486: case COP_AWTYPE_AUDIO_MIXER:
! 1487: snprintf(this->name, sizeof(this->name), "mix%2.2x", nid);
! 1488: DPRINTF(("%s wcap=%b\n", this->name,
! 1489: this->widgetcap, WIDGETCAP_BITS));
! 1490: break;
! 1491: case COP_AWTYPE_AUDIO_SELECTOR:
! 1492: snprintf(this->name, sizeof(this->name), "sel%2.2x", nid);
! 1493: DPRINTF(("%s wcap=%b\n", this->name,
! 1494: this->widgetcap, WIDGETCAP_BITS));
! 1495: break;
! 1496: case COP_AWTYPE_PIN_COMPLEX:
! 1497: azalia_widget_init_pin(this, codec);
! 1498: snprintf(this->name, sizeof(this->name), "%s%2.2x",
! 1499: pin_colors[this->d.pin.color], nid);
! 1500: DPRINTF(("%s wcap=%b\n", this->name,
! 1501: this->widgetcap, WIDGETCAP_BITS));
! 1502: azalia_widget_print_pin(this);
! 1503: break;
! 1504: case COP_AWTYPE_POWER:
! 1505: snprintf(this->name, sizeof(this->name), "pow%2.2x", nid);
! 1506: DPRINTF(("%s wcap=%b\n", this->name,
! 1507: this->widgetcap, WIDGETCAP_BITS));
! 1508: break;
! 1509: case COP_AWTYPE_VOLUME_KNOB:
! 1510: snprintf(this->name, sizeof(this->name), "volume%2.2x", nid);
! 1511: DPRINTF(("%s wcap=%b\n", this->name,
! 1512: this->widgetcap, WIDGETCAP_BITS));
! 1513: err = codec->comresp(codec, nid, CORB_GET_PARAMETER,
! 1514: COP_VOLUME_KNOB_CAPABILITIES, &result);
! 1515: if (!err) {
! 1516: this->d.volume.cap = result;
! 1517: DPRINTF(("\tdelta=%d steps=%d\n",
! 1518: !!(result & COP_VKCAP_DELTA),
! 1519: COP_VKCAP_NUMSTEPS(result)));
! 1520: }
! 1521: break;
! 1522: case COP_AWTYPE_BEEP_GENERATOR:
! 1523: snprintf(this->name, sizeof(this->name), "beep%2.2x", nid);
! 1524: DPRINTF(("%s wcap=%b\n", this->name,
! 1525: this->widgetcap, WIDGETCAP_BITS));
! 1526: break;
! 1527: default:
! 1528: snprintf(this->name, sizeof(this->name), "widget%2.2x", nid);
! 1529: DPRINTF(("%s wcap=%b\n", this->name,
! 1530: this->widgetcap, WIDGETCAP_BITS));
! 1531: break;
! 1532: }
! 1533: azalia_widget_init_connection(this, codec);
! 1534:
! 1535: /* amplifier information */
! 1536: if (this->widgetcap & COP_AWCAP_INAMP) {
! 1537: if (this->widgetcap & COP_AWCAP_AMPOV)
! 1538: codec->comresp(codec, nid, CORB_GET_PARAMETER,
! 1539: COP_INPUT_AMPCAP, &this->inamp_cap);
! 1540: else
! 1541: this->inamp_cap = codec->w[codec->audiofunc].inamp_cap;
! 1542: DPRINTF(("\tinamp: mute=%u size=%u steps=%u offset=%u\n",
! 1543: (this->inamp_cap & COP_AMPCAP_MUTE) != 0,
! 1544: COP_AMPCAP_STEPSIZE(this->inamp_cap),
! 1545: COP_AMPCAP_NUMSTEPS(this->inamp_cap),
! 1546: COP_AMPCAP_OFFSET(this->inamp_cap)));
! 1547: }
! 1548: if (this->widgetcap & COP_AWCAP_OUTAMP) {
! 1549: if (this->widgetcap & COP_AWCAP_AMPOV)
! 1550: codec->comresp(codec, nid, CORB_GET_PARAMETER,
! 1551: COP_OUTPUT_AMPCAP, &this->outamp_cap);
! 1552: else
! 1553: this->outamp_cap = codec->w[codec->audiofunc].outamp_cap;
! 1554: DPRINTF(("\toutamp: mute=%u size=%u steps=%u offset=%u\n",
! 1555: (this->outamp_cap & COP_AMPCAP_MUTE) != 0,
! 1556: COP_AMPCAP_STEPSIZE(this->outamp_cap),
! 1557: COP_AMPCAP_NUMSTEPS(this->outamp_cap),
! 1558: COP_AMPCAP_OFFSET(this->outamp_cap)));
! 1559: }
! 1560: if (codec->init_widget != NULL)
! 1561: codec->init_widget(codec, this, nid);
! 1562: return 0;
! 1563: }
! 1564:
! 1565: int
! 1566: azalia_widget_init_audio(widget_t *this, const codec_t *codec)
! 1567: {
! 1568: uint32_t result;
! 1569: int err;
! 1570:
! 1571: /* check audio format */
! 1572: if (this->widgetcap & COP_AWCAP_FORMATOV) {
! 1573: err = codec->comresp(codec, this->nid,
! 1574: CORB_GET_PARAMETER, COP_STREAM_FORMATS, &result);
! 1575: if (err)
! 1576: return err;
! 1577: this->d.audio.encodings = result;
! 1578: if (result == 0) { /* quirk for CMI9880.
! 1579: * This must not occuur usually... */
! 1580: this->d.audio.encodings =
! 1581: codec->w[codec->audiofunc].d.audio.encodings;
! 1582: this->d.audio.bits_rates =
! 1583: codec->w[codec->audiofunc].d.audio.bits_rates;
! 1584: } else {
! 1585: if ((result & COP_STREAM_FORMAT_PCM) == 0) {
! 1586: printf("%s: %s: No PCM support: %x\n",
! 1587: XNAME(codec->az), this->name, result);
! 1588: return -1;
! 1589: }
! 1590: err = codec->comresp(codec, this->nid, CORB_GET_PARAMETER,
! 1591: COP_PCM, &result);
! 1592: if (err)
! 1593: return err;
! 1594: this->d.audio.bits_rates = result;
! 1595: }
! 1596: this->d.audio.bits_rates = result;
! 1597: } else {
! 1598: this->d.audio.encodings =
! 1599: codec->w[codec->audiofunc].d.audio.encodings;
! 1600: this->d.audio.bits_rates =
! 1601: codec->w[codec->audiofunc].d.audio.bits_rates;
! 1602: }
! 1603: #ifdef AZALIA_DEBUG
! 1604: azalia_widget_print_audio(this, "\t");
! 1605: #endif
! 1606: return 0;
! 1607: }
! 1608:
! 1609: #define ENCODING_BITS "\20\3AC3\2FLOAT32\1PCM"
! 1610: #define BITSRATES_BITS "\20\x15""32bit\x14""24bit\x13""20bit" \
! 1611: "\x12""16bit\x11""8bit""\x0c""384kHz\x0b""192kHz\x0a""176.4kHz" \
! 1612: "\x09""96kHz\x08""88.2kHz\x07""48kHz\x06""44.1kHz\x05""32kHz\x04" \
! 1613: "22.05kHz\x03""16kHz\x02""11.025kHz\x01""8kHz"
! 1614:
! 1615: int
! 1616: azalia_widget_print_audio(const widget_t *this, const char *lead)
! 1617: {
! 1618: printf("%sencodings=%b\n", lead, this->d.audio.encodings,
! 1619: ENCODING_BITS);
! 1620: printf("%sPCM formats=%b\n", lead, this->d.audio.bits_rates,
! 1621: BITSRATES_BITS);
! 1622: return 0;
! 1623: }
! 1624:
! 1625: int
! 1626: azalia_widget_init_pin(widget_t *this, const codec_t *codec)
! 1627: {
! 1628: uint32_t result;
! 1629: int err;
! 1630:
! 1631: err = codec->comresp(codec, this->nid, CORB_GET_CONFIGURATION_DEFAULT,
! 1632: 0, &result);
! 1633: if (err)
! 1634: return err;
! 1635: this->d.pin.config = result;
! 1636: this->d.pin.sequence = CORB_CD_SEQUENCE(result);
! 1637: this->d.pin.association = CORB_CD_ASSOCIATION(result);
! 1638: this->d.pin.color = CORB_CD_COLOR(result);
! 1639: this->d.pin.device = CORB_CD_DEVICE(result);
! 1640:
! 1641: err = codec->comresp(codec, this->nid, CORB_GET_PARAMETER,
! 1642: COP_PINCAP, &result);
! 1643: if (err)
! 1644: return err;
! 1645: this->d.pin.cap = result;
! 1646: return 0;
! 1647: }
! 1648:
! 1649: #define PINCAP_BITS "\20\021EAPD\07BALANCE\06INPUT" \
! 1650: "\05OUTPUT\04HEADPHONE\03PRESENCE\02TRIGGER\01IMPEDANCE"
! 1651:
! 1652: int
! 1653: azalia_widget_print_pin(const widget_t *this)
! 1654: {
! 1655: DPRINTF(("\tpin config; device=%s color=%s assoc=%d seq=%d",
! 1656: pin_devices[this->d.pin.device], pin_colors[this->d.pin.color],
! 1657: this->d.pin.association, this->d.pin.sequence));
! 1658: DPRINTF((" cap=%b\n", this->d.pin.cap, PINCAP_BITS));
! 1659: return 0;
! 1660: }
! 1661:
! 1662: int
! 1663: azalia_widget_init_connection(widget_t *this, const codec_t *codec)
! 1664: {
! 1665: uint32_t result;
! 1666: int err;
! 1667: boolean_t longform;
! 1668: int length, i;
! 1669:
! 1670: this->selected = -1;
! 1671: if ((this->widgetcap & COP_AWCAP_CONNLIST) == 0)
! 1672: return 0;
! 1673:
! 1674: err = codec->comresp(codec, this->nid, CORB_GET_PARAMETER,
! 1675: COP_CONNECTION_LIST_LENGTH, &result);
! 1676: if (err)
! 1677: return err;
! 1678: longform = (result & COP_CLL_LONG) != 0;
! 1679: length = COP_CLL_LENGTH(result);
! 1680: if (length == 0)
! 1681: return 0;
! 1682: this->nconnections = length;
! 1683: this->connections = malloc(sizeof(nid_t) * (length + 3),
! 1684: M_DEVBUF, M_NOWAIT);
! 1685: if (this->connections == NULL) {
! 1686: printf("%s: out of memory\n", XNAME(codec->az));
! 1687: return ENOMEM;
! 1688: }
! 1689: if (longform) {
! 1690: for (i = 0; i < length;) {
! 1691: err = codec->comresp(codec, this->nid,
! 1692: CORB_GET_CONNECTION_LIST_ENTRY, i, &result);
! 1693: if (err)
! 1694: return err;
! 1695: this->connections[i++] = CORB_CLE_LONG_0(result);
! 1696: this->connections[i++] = CORB_CLE_LONG_1(result);
! 1697: }
! 1698: } else {
! 1699: for (i = 0; i < length;) {
! 1700: err = codec->comresp(codec, this->nid,
! 1701: CORB_GET_CONNECTION_LIST_ENTRY, i, &result);
! 1702: if (err)
! 1703: return err;
! 1704: this->connections[i++] = CORB_CLE_SHORT_0(result);
! 1705: this->connections[i++] = CORB_CLE_SHORT_1(result);
! 1706: this->connections[i++] = CORB_CLE_SHORT_2(result);
! 1707: this->connections[i++] = CORB_CLE_SHORT_3(result);
! 1708: }
! 1709: }
! 1710: if (length > 0) {
! 1711: DPRINTF(("\tconnections=0x%x", this->connections[0]));
! 1712: for (i = 1; i < length; i++) {
! 1713: DPRINTF((",0x%x", this->connections[i]));
! 1714: }
! 1715:
! 1716: err = codec->comresp(codec, this->nid,
! 1717: CORB_GET_CONNECTION_SELECT_CONTROL, 0, &result);
! 1718: if (err)
! 1719: return err;
! 1720: this->selected = CORB_CSC_INDEX(result);
! 1721: DPRINTF(("; selected=0x%x\n", this->connections[result]));
! 1722: }
! 1723: return 0;
! 1724: }
! 1725:
! 1726: /* ================================================================
! 1727: * Stream functions
! 1728: * ================================================================ */
! 1729:
! 1730: int
! 1731: azalia_stream_init(stream_t *this, azalia_t *az, int regindex, int strnum, int dir)
! 1732: {
! 1733: int err;
! 1734:
! 1735: this->az = az;
! 1736: this->regbase = HDA_SD_BASE + regindex * HDA_SD_SIZE;
! 1737: this->intr_bit = 1 << regindex;
! 1738: this->number = strnum;
! 1739: this->dir = dir;
! 1740:
! 1741: /* setup BDL buffers */
! 1742: err = azalia_alloc_dmamem(az, sizeof(bdlist_entry_t) * HDA_BDL_MAX,
! 1743: 128, &this->bdlist);
! 1744: if (err) {
! 1745: printf("%s: can't allocate a BDL buffer\n", XNAME(az));
! 1746: return err;
! 1747: }
! 1748: return 0;
! 1749: }
! 1750:
! 1751: int
! 1752: azalia_stream_delete(stream_t *this, azalia_t *az)
! 1753: {
! 1754: if (this->bdlist.addr == NULL)
! 1755: return 0;
! 1756: azalia_free_dmamem(az, &this->bdlist);
! 1757: return 0;
! 1758: }
! 1759:
! 1760: int
! 1761: azalia_stream_reset(stream_t *this)
! 1762: {
! 1763: int i;
! 1764: uint16_t ctl;
! 1765: uint8_t sts;
! 1766:
! 1767: /* Make sure RUN bit is zero before resetting */
! 1768: ctl = STR_READ_2(this, CTL);
! 1769: ctl &= ~HDA_SD_CTL_RUN;
! 1770: STR_WRITE_2(this, CTL, ctl);
! 1771:
! 1772: /* Start reset and wait for chip to enter. */
! 1773: ctl = STR_READ_2(this, CTL);
! 1774: STR_WRITE_2(this, CTL, ctl | HDA_SD_CTL_SRST);
! 1775: for (i = 5000; i >= 0; i--) {
! 1776: DELAY(10);
! 1777: ctl = STR_READ_2(this, CTL);
! 1778: if (ctl & HDA_SD_CTL_SRST)
! 1779: break;
! 1780: }
! 1781: if (i <= 0) {
! 1782: printf("%s: stream reset failure 1\n", XNAME(this->az));
! 1783: return -1;
! 1784: }
! 1785:
! 1786: /* Clear reset and wait for chip to finish */
! 1787: STR_WRITE_2(this, CTL, ctl & ~HDA_SD_CTL_SRST);
! 1788: for (i = 5000; i >= 0; i--) {
! 1789: DELAY(10);
! 1790: ctl = STR_READ_2(this, CTL);
! 1791: if ((ctl & HDA_SD_CTL_SRST) == 0)
! 1792: break;
! 1793: }
! 1794: if (i <= 0) {
! 1795: printf("%s: stream reset failure 2\n", XNAME(this->az));
! 1796: return -1;
! 1797: }
! 1798:
! 1799: sts = STR_READ_1(this, STS);
! 1800: sts |= HDA_SD_STS_DESE | HDA_SD_STS_FIFOE | HDA_SD_STS_BCIS;
! 1801: STR_WRITE_1(this, STS, sts);
! 1802:
! 1803: return (0);
! 1804: }
! 1805:
! 1806: int
! 1807: azalia_stream_start(stream_t *this, void *start, void *end, int blk,
! 1808: void (*intr)(void *), void *arg, uint16_t fmt)
! 1809: {
! 1810: bdlist_entry_t *bdlist;
! 1811: bus_addr_t dmaaddr, dmaend;
! 1812: int err, index;
! 1813: uint32_t intctl;
! 1814: uint8_t ctl2;
! 1815:
! 1816: this->intr = intr;
! 1817: this->intr_arg = arg;
! 1818:
! 1819: err = azalia_stream_reset(this);
! 1820: if (err) {
! 1821: printf("%s: stream reset failed\n", "azalia");
! 1822: return err;
! 1823: }
! 1824:
! 1825: STR_WRITE_4(this, BDPL, 0);
! 1826: STR_WRITE_4(this, BDPU, 0);
! 1827:
! 1828: /* setup BDL */
! 1829: dmaaddr = AZALIA_DMA_DMAADDR(&this->buffer);
! 1830: dmaend = dmaaddr + ((caddr_t)end - (caddr_t)start);
! 1831: bdlist = (bdlist_entry_t*)this->bdlist.addr;
! 1832: for (index = 0; index < HDA_BDL_MAX; index++) {
! 1833: bdlist[index].low = htole32(dmaaddr);
! 1834: bdlist[index].high = htole32(PTR_UPPER32(dmaaddr));
! 1835: bdlist[index].length = htole32(blk);
! 1836: bdlist[index].flags = htole32(BDLIST_ENTRY_IOC);
! 1837: dmaaddr += blk;
! 1838: if (dmaaddr >= dmaend) {
! 1839: index++;
! 1840: break;
! 1841: }
! 1842: }
! 1843:
! 1844: dmaaddr = AZALIA_DMA_DMAADDR(&this->bdlist);
! 1845: STR_WRITE_4(this, BDPL, dmaaddr);
! 1846: STR_WRITE_4(this, BDPU, PTR_UPPER32(dmaaddr));
! 1847: STR_WRITE_2(this, LVI, (index - 1) & HDA_SD_LVI_LVI);
! 1848: ctl2 = STR_READ_1(this, CTL2);
! 1849: STR_WRITE_1(this, CTL2,
! 1850: (ctl2 & ~HDA_SD_CTL2_STRM) | (this->number << HDA_SD_CTL2_STRM_SHIFT));
! 1851: STR_WRITE_4(this, CBL, ((caddr_t)end - (caddr_t)start));
! 1852: STR_WRITE_2(this, FMT, fmt);
! 1853:
! 1854: err = azalia_codec_connect_stream(&this->az->codecs[this->az->codecno],
! 1855: this->dir, fmt, this->number);
! 1856: if (err)
! 1857: return EINVAL;
! 1858:
! 1859: intctl = AZ_READ_4(this->az, INTCTL);
! 1860: intctl |= this->intr_bit;
! 1861: AZ_WRITE_4(this->az, INTCTL, intctl);
! 1862:
! 1863: STR_WRITE_1(this, CTL, STR_READ_1(this, CTL) |
! 1864: HDA_SD_CTL_DEIE | HDA_SD_CTL_FEIE | HDA_SD_CTL_IOCE |
! 1865: HDA_SD_CTL_RUN);
! 1866:
! 1867: return (0);
! 1868: }
! 1869:
! 1870: int
! 1871: azalia_stream_halt(stream_t *this)
! 1872: {
! 1873: uint16_t ctl;
! 1874:
! 1875: ctl = STR_READ_2(this, CTL);
! 1876: ctl &= ~(HDA_SD_CTL_DEIE | HDA_SD_CTL_FEIE | HDA_SD_CTL_IOCE | HDA_SD_CTL_RUN);
! 1877: STR_WRITE_2(this, CTL, ctl);
! 1878: AZ_WRITE_4(this->az, INTCTL,
! 1879: AZ_READ_4(this->az, INTCTL) & ~this->intr_bit);
! 1880: return (0);
! 1881: }
! 1882:
! 1883: #define HDA_SD_STS_BITS "\20\3BCIS\4FIFOE\5DESE\6FIFORDY"
! 1884:
! 1885: int
! 1886: azalia_stream_intr(stream_t *this, uint32_t intsts)
! 1887: {
! 1888: u_int8_t sts;
! 1889:
! 1890: if ((intsts & this->intr_bit) == 0)
! 1891: return (0);
! 1892:
! 1893: sts = STR_READ_1(this, STS);
! 1894: STR_WRITE_1(this, STS, sts |
! 1895: HDA_SD_STS_DESE | HDA_SD_STS_FIFOE | HDA_SD_STS_BCIS);
! 1896:
! 1897: if (sts & (HDA_SD_STS_DESE | HDA_SD_STS_FIFOE))
! 1898: printf("%s: stream %d: sts=%b\n", XNAME(this->az),
! 1899: this->number, sts, HDA_SD_STS_BITS);
! 1900: if (sts & HDA_SD_STS_BCIS)
! 1901: this->intr(this->intr_arg);
! 1902: return (1);
! 1903: }
! 1904:
! 1905: /* ================================================================
! 1906: * MI audio entries
! 1907: * ================================================================ */
! 1908:
! 1909: int
! 1910: azalia_open(void *v, int flags)
! 1911: {
! 1912: azalia_t *az;
! 1913: codec_t *codec;
! 1914:
! 1915: DPRINTF(("%s: flags=0x%x\n", __func__, flags));
! 1916: az = v;
! 1917: codec = &az->codecs[az->codecno];
! 1918: codec->running++;
! 1919: return 0;
! 1920: }
! 1921:
! 1922: void
! 1923: azalia_close(void *v)
! 1924: {
! 1925: azalia_t *az;
! 1926: codec_t *codec;
! 1927:
! 1928: DPRINTF(("%s\n", __func__));
! 1929: az = v;
! 1930: codec = &az->codecs[az->codecno];
! 1931: codec->running--;
! 1932: }
! 1933:
! 1934: int
! 1935: azalia_query_encoding(void *v, audio_encoding_t *enc)
! 1936: {
! 1937: azalia_t *az;
! 1938: codec_t *codec;
! 1939: int i, j;
! 1940:
! 1941: az = v;
! 1942: codec = &az->codecs[az->codecno];
! 1943: for (j = 0, i = 0; j < codec->nformats; j++) {
! 1944: if (codec->formats[j].validbits !=
! 1945: codec->formats[j].precision)
! 1946: continue;
! 1947: if (i == enc->index) {
! 1948: enc->encoding = codec->formats[j].encoding;
! 1949: enc->precision = codec->formats[j].precision;
! 1950: switch (enc->encoding) {
! 1951: case AUDIO_ENCODING_SLINEAR_LE:
! 1952: strlcpy(enc->name, enc->precision == 8 ?
! 1953: AudioEslinear : AudioEslinear_le,
! 1954: sizeof enc->name);
! 1955: break;
! 1956: case AUDIO_ENCODING_ULINEAR_LE:
! 1957: strlcpy(enc->name, enc->precision == 8 ?
! 1958: AudioEulinear : AudioEulinear_le,
! 1959: sizeof enc->name);
! 1960: break;
! 1961: default:
! 1962: strlcpy(enc->name, "unknown", sizeof enc->name);
! 1963: break;
! 1964: }
! 1965: return (0);
! 1966: }
! 1967: i++;
! 1968: }
! 1969: return (EINVAL);
! 1970: }
! 1971:
! 1972: int
! 1973: azalia_set_params(void *v, int smode, int umode, audio_params_t *p,
! 1974: audio_params_t *r)
! 1975: {
! 1976: azalia_t *az;
! 1977: codec_t *codec;
! 1978: void (*pswcode)(void *, u_char *, int) = NULL;
! 1979: void (*rswcode)(void *, u_char *, int) = NULL;
! 1980: int i, j;
! 1981:
! 1982: az = v;
! 1983: codec = &az->codecs[az->codecno];
! 1984: if (smode & AUMODE_RECORD && r != NULL) {
! 1985: if (r->encoding == AUDIO_ENCODING_ULAW) { /*XXX*/
! 1986: r->encoding = AUDIO_ENCODING_SLINEAR_LE;
! 1987: r->precision = 16;
! 1988: r->channels = 2;
! 1989: r->sample_rate = 44100;
! 1990: }
! 1991: for (i = 0; i < codec->nformats; i++) {
! 1992: if (r->encoding != codec->formats[i].encoding)
! 1993: continue;
! 1994: if (r->precision != codec->formats[i].precision)
! 1995: continue;
! 1996: if (r->channels != codec->formats[i].channels)
! 1997: continue;
! 1998: break;
! 1999: }
! 2000: if (i == codec->nformats) {
! 2001: printf("didn't find Record format %u/%u/%u\n",
! 2002: r->encoding, r->precision, r->channels);
! 2003: return (EINVAL);
! 2004: }
! 2005: for (j = 0; j < codec->formats[i].frequency_type; j++) {
! 2006: if (r->sample_rate != codec->formats[i].frequency[j])
! 2007: continue;
! 2008: break;
! 2009: }
! 2010: if (j == codec->formats[i].frequency_type) {
! 2011: printf("didn't find Record rate %u\n",
! 2012: r->sample_rate);
! 2013: return (EINVAL);
! 2014: }
! 2015: r->sw_code = rswcode;
! 2016: }
! 2017: if (smode & AUMODE_PLAY && p != NULL) {
! 2018: if (p->encoding == AUDIO_ENCODING_ULAW) { /*XXX*/
! 2019: p->encoding = AUDIO_ENCODING_SLINEAR_LE;
! 2020: p->precision = 16;
! 2021: p->channels = 2;
! 2022: p->sample_rate = 44100;
! 2023: }
! 2024: for (i = 0; i < codec->nformats; i++) {
! 2025: if (p->encoding != codec->formats[i].encoding)
! 2026: continue;
! 2027: if (p->precision != codec->formats[i].precision)
! 2028: continue;
! 2029: if (p->channels != codec->formats[i].channels)
! 2030: continue;
! 2031: break;
! 2032: }
! 2033: if (i == codec->nformats) {
! 2034: printf("can't find playback format %u/%u/%u\n",
! 2035: r->encoding, r->precision, r->channels);
! 2036: return (EINVAL);
! 2037: }
! 2038: for (j = 0; j < codec->formats[i].frequency_type; j++) {
! 2039: if (p->sample_rate != codec->formats[i].frequency[j])
! 2040: continue;
! 2041: break;
! 2042: }
! 2043: if (j == codec->formats[i].frequency_type) {
! 2044: printf("can't find playback rate %u\n",
! 2045: p->sample_rate);
! 2046: return (EINVAL);
! 2047: }
! 2048: p->sw_code = pswcode;
! 2049: }
! 2050:
! 2051: return (0);
! 2052: }
! 2053:
! 2054: int
! 2055: azalia_round_blocksize(void *v, int blk)
! 2056: {
! 2057: azalia_t *az;
! 2058: size_t size;
! 2059:
! 2060: blk &= ~0x7f; /* must be multiple of 128 */
! 2061: if (blk <= 0)
! 2062: blk = 128;
! 2063: /* number of blocks must be <= HDA_BDL_MAX */
! 2064: az = v;
! 2065: size = az->pstream.buffer.size;
! 2066: #ifdef DIAGNOSTIC
! 2067: if (size <= 0) {
! 2068: printf("%s: size is 0", __func__);
! 2069: return 256;
! 2070: }
! 2071: #endif
! 2072: if (size > HDA_BDL_MAX * blk) {
! 2073: blk = size / HDA_BDL_MAX;
! 2074: if (blk & 0x7f)
! 2075: blk = (blk + 0x7f) & ~0x7f;
! 2076: }
! 2077: DPRINTF(("%s: resultant block size = %d\n", __func__, blk));
! 2078: return blk;
! 2079: }
! 2080:
! 2081: int
! 2082: azalia_halt_output(void *v)
! 2083: {
! 2084: azalia_t *az;
! 2085:
! 2086: DPRINTF(("%s\n", __func__));
! 2087: az = v;
! 2088: return azalia_stream_halt(&az->pstream);
! 2089: }
! 2090:
! 2091: int
! 2092: azalia_halt_input(void *v)
! 2093: {
! 2094: azalia_t *az;
! 2095:
! 2096: DPRINTF(("%s\n", __func__));
! 2097: az = v;
! 2098: return azalia_stream_halt(&az->rstream);
! 2099: }
! 2100:
! 2101: int
! 2102: azalia_getdev(void *v, struct audio_device *dev)
! 2103: {
! 2104: azalia_t *az;
! 2105:
! 2106: az = v;
! 2107: strlcpy(dev->name, "HD-Audio", MAX_AUDIO_DEV_LEN);
! 2108: snprintf(dev->version, MAX_AUDIO_DEV_LEN,
! 2109: "%d.%d", AZ_READ_1(az, VMAJ), AZ_READ_1(az, VMIN));
! 2110: strlcpy(dev->config, XNAME(az), MAX_AUDIO_DEV_LEN);
! 2111: return 0;
! 2112: }
! 2113:
! 2114: int
! 2115: azalia_set_port(void *v, mixer_ctrl_t *mc)
! 2116: {
! 2117: azalia_t *az;
! 2118: codec_t *co;
! 2119:
! 2120: az = v;
! 2121: co = &az->codecs[az->codecno];
! 2122: return co->set_port(co, mc);
! 2123: }
! 2124:
! 2125: int
! 2126: azalia_get_port(void *v, mixer_ctrl_t *mc)
! 2127: {
! 2128: azalia_t *az;
! 2129: codec_t *co;
! 2130:
! 2131: az = v;
! 2132: co = &az->codecs[az->codecno];
! 2133: return co->get_port(co, mc);
! 2134: }
! 2135:
! 2136: int
! 2137: azalia_query_devinfo(void *v, mixer_devinfo_t *mdev)
! 2138: {
! 2139: azalia_t *az;
! 2140: const codec_t *co;
! 2141:
! 2142: az = v;
! 2143: co = &az->codecs[az->codecno];
! 2144: if (mdev->index >= co->nmixers)
! 2145: return ENXIO;
! 2146: *mdev = co->mixers[mdev->index].devinfo;
! 2147: return 0;
! 2148: }
! 2149:
! 2150: void *
! 2151: azalia_allocm(void *v, int dir, size_t size, int pool, int flags)
! 2152: {
! 2153: azalia_t *az;
! 2154: stream_t *stream;
! 2155: int err;
! 2156:
! 2157: az = v;
! 2158: stream = dir == AUMODE_PLAY ? &az->pstream : &az->rstream;
! 2159: err = azalia_alloc_dmamem(az, size, 128, &stream->buffer);
! 2160: if (err) {
! 2161: printf("%s: allocm failed\n", az->dev.dv_xname);
! 2162: return NULL;
! 2163: }
! 2164: return stream->buffer.addr;
! 2165: }
! 2166:
! 2167: void
! 2168: azalia_freem(void *v, void *addr, int pool)
! 2169: {
! 2170: azalia_t *az;
! 2171: stream_t *stream;
! 2172:
! 2173: az = v;
! 2174: if (addr == az->pstream.buffer.addr) {
! 2175: stream = &az->pstream;
! 2176: } else if (addr == az->rstream.buffer.addr) {
! 2177: stream = &az->rstream;
! 2178: } else {
! 2179: return;
! 2180: }
! 2181: azalia_free_dmamem(az, &stream->buffer);
! 2182: }
! 2183:
! 2184: size_t
! 2185: azalia_round_buffersize(void *v, int dir, size_t size)
! 2186: {
! 2187: size &= ~0x7f; /* must be multiple of 128 */
! 2188: if (size <= 0)
! 2189: size = 128;
! 2190: return size;
! 2191: }
! 2192:
! 2193: int
! 2194: azalia_get_props(void *v)
! 2195: {
! 2196: return AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX;
! 2197: }
! 2198:
! 2199: int
! 2200: azalia_trigger_output(void *v, void *start, void *end, int blk,
! 2201: void (*intr)(void *), void *arg, audio_params_t *param)
! 2202: {
! 2203: azalia_t *az;
! 2204: int err;
! 2205: uint16_t fmt;
! 2206:
! 2207: err = azalia_params2fmt(param, &fmt);
! 2208: if (err)
! 2209: return EINVAL;
! 2210:
! 2211: az = v;
! 2212: return azalia_stream_start(&az->pstream, start, end, blk, intr, arg, fmt);
! 2213: }
! 2214:
! 2215: int
! 2216: azalia_trigger_input(void *v, void *start, void *end, int blk,
! 2217: void (*intr)(void *), void *arg, audio_params_t *param)
! 2218: {
! 2219: azalia_t *az;
! 2220: int err;
! 2221: uint16_t fmt;
! 2222:
! 2223: DPRINTF(("%s: this=%p start=%p end=%p blk=%d {enc=%u %uch %u/%ubit %uHz}\n",
! 2224: __func__, v, start, end, blk, param->encoding, param->channels,
! 2225: param->precision, param->precision, param->sample_rate));
! 2226:
! 2227: err = azalia_params2fmt(param, &fmt);
! 2228: if (err)
! 2229: return EINVAL;
! 2230:
! 2231: az = v;
! 2232: return azalia_stream_start(&az->rstream, start, end, blk, intr, arg, fmt);
! 2233: }
! 2234:
! 2235: /* --------------------------------
! 2236: * helpers for MI audio functions
! 2237: * -------------------------------- */
! 2238: int
! 2239: azalia_params2fmt(const audio_params_t *param, uint16_t *fmt)
! 2240: {
! 2241: uint16_t ret;
! 2242:
! 2243: ret = 0;
! 2244: #ifdef DIAGNOSTIC
! 2245: if (param->channels > HDA_MAX_CHANNELS) {
! 2246: printf("%s: too many channels: %u\n", __func__,
! 2247: param->channels);
! 2248: return EINVAL;
! 2249: }
! 2250: #endif
! 2251: ret |= param->channels - 1;
! 2252:
! 2253: switch (param->precision) {
! 2254: case 8:
! 2255: ret |= HDA_SD_FMT_BITS_8_16;
! 2256: break;
! 2257: case 16:
! 2258: ret |= HDA_SD_FMT_BITS_16_16;
! 2259: break;
! 2260: case 32:
! 2261: ret |= HDA_SD_FMT_BITS_32_32;
! 2262: break;
! 2263: }
! 2264:
! 2265: #if 0
! 2266: switch (param->validbits) {
! 2267: case 8:
! 2268: ret |= HDA_SD_FMT_BITS_8_16;
! 2269: break;
! 2270: case 16:
! 2271: ret |= HDA_SD_FMT_BITS_16_16;
! 2272: break;
! 2273: case 20:
! 2274: ret |= HDA_SD_FMT_BITS_20_32;
! 2275: break;
! 2276: case 24:
! 2277: ret |= HDA_SD_FMT_BITS_24_32;
! 2278: break;
! 2279: case 32:
! 2280: ret |= HDA_SD_FMT_BITS_32_32;
! 2281: break;
! 2282: default:
! 2283: printf("%s: invalid validbits: %u\n", __func__,
! 2284: param->validbits);
! 2285: }
! 2286: #endif
! 2287:
! 2288: if (param->sample_rate == 384000) {
! 2289: printf("%s: invalid sample_rate: %u\n", __func__,
! 2290: param->sample_rate);
! 2291: return EINVAL;
! 2292: } else if (param->sample_rate == 192000) {
! 2293: ret |= HDA_SD_FMT_BASE_48 | HDA_SD_FMT_MULT_X4 | HDA_SD_FMT_DIV_BY1;
! 2294: } else if (param->sample_rate == 176400) {
! 2295: ret |= HDA_SD_FMT_BASE_44 | HDA_SD_FMT_MULT_X4 | HDA_SD_FMT_DIV_BY1;
! 2296: } else if (param->sample_rate == 96000) {
! 2297: ret |= HDA_SD_FMT_BASE_48 | HDA_SD_FMT_MULT_X2 | HDA_SD_FMT_DIV_BY1;
! 2298: } else if (param->sample_rate == 88200) {
! 2299: ret |= HDA_SD_FMT_BASE_44 | HDA_SD_FMT_MULT_X2 | HDA_SD_FMT_DIV_BY1;
! 2300: } else if (param->sample_rate == 48000) {
! 2301: ret |= HDA_SD_FMT_BASE_48 | HDA_SD_FMT_MULT_X1 | HDA_SD_FMT_DIV_BY1;
! 2302: } else if (param->sample_rate == 44100) {
! 2303: ret |= HDA_SD_FMT_BASE_44 | HDA_SD_FMT_MULT_X1 | HDA_SD_FMT_DIV_BY1;
! 2304: } else if (param->sample_rate == 32000) {
! 2305: ret |= HDA_SD_FMT_BASE_48 | HDA_SD_FMT_MULT_X2 | HDA_SD_FMT_DIV_BY3;
! 2306: } else if (param->sample_rate == 22050) {
! 2307: ret |= HDA_SD_FMT_BASE_44 | HDA_SD_FMT_MULT_X1 | HDA_SD_FMT_DIV_BY2;
! 2308: } else if (param->sample_rate == 16000) {
! 2309: ret |= HDA_SD_FMT_BASE_48 | HDA_SD_FMT_MULT_X1 | HDA_SD_FMT_DIV_BY3;
! 2310: } else if (param->sample_rate == 11025) {
! 2311: ret |= HDA_SD_FMT_BASE_44 | HDA_SD_FMT_MULT_X1 | HDA_SD_FMT_DIV_BY4;
! 2312: } else if (param->sample_rate == 8000) {
! 2313: ret |= HDA_SD_FMT_BASE_48 | HDA_SD_FMT_MULT_X1 | HDA_SD_FMT_DIV_BY6;
! 2314: } else {
! 2315: printf("%s: invalid sample_rate: %u\n", __func__,
! 2316: param->sample_rate);
! 2317: return EINVAL;
! 2318: }
! 2319: *fmt = ret;
! 2320: return 0;
! 2321: }
! 2322:
! 2323: int
! 2324: azalia_create_encodings(struct audio_format *formats, int nformats,
! 2325: struct audio_encoding_set **encodings)
! 2326: {
! 2327: #if 0
! 2328: int i;
! 2329: u_int j;
! 2330:
! 2331: for (i = 0; i < nformats; i++) {
! 2332: printf("format(%d): encoding %u vbits %u prec %u chans %u cmask 0x%x\n",
! 2333: i, formats[i].encoding, formats[i].validbits,
! 2334: formats[i].precision, formats[i].channels,
! 2335: formats[i].channel_mask);
! 2336: printf("format(%d) rates:", i);
! 2337: for (j = 0; j < formats[i].frequency_type; j++) {
! 2338: printf(" %u", formats[i].frequency[j]);
! 2339: }
! 2340: printf("\n");
! 2341: }
! 2342: #endif
! 2343: return (0);
! 2344: }
CVSweb