48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * CDDL HEADER START
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * The contents of this file are subject to the terms of the
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * Common Development and Distribution License (the "License").
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * You may not use this file except in compliance with the License.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * or http://www.opensolaris.org/os/licensing.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * See the License for the specific language governing permissions
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * and limitations under the License.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * If applicable, add the following below this CDDL HEADER, with the
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner]
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * CDDL HEADER END
2c30fa4582c5d6c659e059e719c5f6163f7ef1e3Garrett D'Amore * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * Purpose: Driver for the Creative Audigy LS sound card
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * Copyright (C) 4Front Technologies 1996-2009.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic struct ddi_device_acc_attr dev_attr = {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic struct ddi_device_acc_attr buf_attr = {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore 0x000fffff, /* DMA counter (16 bits only in Audigy LS) */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore 0 /* Bus specific DMA flags */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic int audigyls_detach(audigyls_dev_t *);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic int audigyls_suspend(audigyls_dev_t *);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amorestatic int audigyls_open(void *, int, unsigned *, caddr_t *);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic void audigyls_close(void *);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic int audigyls_start(void *);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic void audigyls_stop(void *);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic int audigyls_format(void *);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic int audigyls_channels(void *);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic int audigyls_rate(void *);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic void audigyls_sync(void *, unsigned);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic void audigyls_chinfo(void *, int, unsigned *, unsigned *);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic uint16_t audigyls_read_ac97(void *, uint8_t);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic void audigyls_write_ac97(void *, uint8_t, uint16_t);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic int audigyls_alloc_port(audigyls_dev_t *, int);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic void audigyls_destroy(audigyls_dev_t *);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic void audigyls_hwinit(audigyls_dev_t *);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic void audigyls_configure_mixer(audigyls_dev_t *dev);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic audio_engine_ops_t audigyls_engine_ops = {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * Audigy LS uses AC'97 strictly for the recording side of things.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * While the chip can supposedly route output to AC'97 for playback,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * the PCI devices use a separate I2S DAC instead. As a result we
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * need to suppress controls that the AC'97 codec registers.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * Furthermore, even then the AC'97 codec offers inputs that we just
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * aren't interested in.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * AC'97 sources we don't want to expose.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic unsigned int
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreread_chan(audigyls_dev_t *dev, int reg, int chn)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* Pointer */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore OUTL(dev, PR, (reg << 16) | (chn & 0xffff));
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorewrite_chan(audigyls_dev_t *dev, int reg, int chn, uint32_t value)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* Pointer */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic unsigned int
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorewrite_reg(audigyls_dev_t *dev, int reg, uint32_t value)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore for (i = 0; i < 10000; i++) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (0xffff);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_write_ac97(void *arg, uint8_t index, uint16_t data)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore for (i = 0; i < 50000; i++) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (i == 50000) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreselect_digital_enable(audigyls_dev_t *dev, int mode)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * Set the out3/spdif combo jack format.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * mode0=analog rear/center, 1=spdif
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore/* only for SBLive 7.1 */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_i2c_write(audigyls_dev_t *dev, int reg, int data)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore tmp = (reg << 9 | data) << 16; /* set the upper 16 bits */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* first write the command to the data reg */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore for (i = 0; i < 20; i++) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* see audigyls.pdf for bits */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* now wait till controller sets valid bit (0x100) to 0 */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* transaction aborted */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_spi_write(audigyls_dev_t *dev, int data)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* Wait for status bit to return to 0 */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore for (i = 0; i < 1000; i++) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * Audio routines
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amoreaudigyls_open(void *arg, int flag, unsigned *nframesp, caddr_t *bufp)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore return (48000);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore (void) ddi_dma_sync(port->buf_dmah, 0, 0, port->syncdir);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore if (port->direction == AUDIGYLS_PLAY_PORT) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore /* get the offset, and switch to frames */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore n = offset + (port->buf_frames - port->offset);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_chinfo(void *arg, int chan, unsigned *offset, unsigned *incr)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (port->direction == AUDIGYLS_PLAY_PORT) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore *offset = (port->buf_frames * 2 * (chan / 2)) + (chan % 2);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore/* private implementation bits */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_alloc_port(audigyls_dev_t *dev, int num)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore port = kmem_zalloc(sizeof (*port), KM_SLEEP);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore port->buf_size = port->buf_frames * port->nchan * sizeof (int16_t);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* Alloc buffers */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (ddi_dma_alloc_handle(dev->dip, &dma_attr_buf, DDI_DMA_SLEEP, NULL,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_dev_warn(adev, "failed to allocate BUF handle");
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (ddi_dma_mem_alloc(port->buf_dmah, port->buf_size,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore &buf_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore &port->buf_kaddr, &len, &port->buf_acch) != DDI_SUCCESS) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_dev_warn(adev, "failed to allocate BUF memory");
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (ddi_dma_addr_bind_handle(port->buf_dmah, NULL, port->buf_kaddr,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore len, DDI_DMA_CONSISTENT | dir, DDI_DMA_SLEEP, NULL, &cookie,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_dev_warn(adev, "failed binding BUF DMA handle");
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore port->engine = audio_engine_alloc(&audigyls_engine_ops, caps);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_dev_warn(adev, "audio_engine_alloc failed");
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_engine_set_private(port->engine, port);
4a20ca87c19352fb04bb75918ba0231663faa6a8Garrett D'Amore for (int i = 0; i < CTL_NUM; i++) {
4a20ca87c19352fb04bb75918ba0231663faa6a8Garrett D'Amore audio_dev_del_control(dev->controls[i].ctrl);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore for (int i = 0; i < AUDIGYLS_NUM_PORT; i++) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_dev_remove_engine(dev->adev, port->engine);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore (void) ddi_dma_unbind_handle(port->buf_dmah);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore 0x00ff, 0x02ff, 0x0400, 0x520, 0x0620, 0x08ff, 0x0aff, 0x0cff,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore 0x0eff, 0x10ff, 0x1200, 0x1400, 0x1800, 0x1aff, 0x1cff,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* Set the orange jack to be analog out or S/PDIF */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore select_digital_enable(dev, dev->digital_enable);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * In P17, there's 8 GPIO pins.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * GPIO register: 0x00XXYYZZ
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * XX: Configure GPIO to be either GPI (0) or GPO (1).
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * YY: GPO values, applicable if the pin is configure to be GPO.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * ZZ: GPI values, applicable if the pin is configure to be GPI.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * in SB570, pin 0-4 and 6 is used as GPO and pin 5 and 7 is
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * used as GPI.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * 1 ==> Analog output
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * 0 ==> Digital output
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * 1 ==> Enable output on card
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * 0 ==> Disable output on card
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * 1 ==> Enable Mic Bias and Mic Path
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * 0 ==> Disable Mic Bias and Mic Path
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * 1 ==> Disable SPDIF-IO output
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * 0 ==> Enable SPDIF-IO output
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * GPO4 and GPO6:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * DAC sampling rate selection:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * Not applicable to SB570 since DAC is controlled through SPI
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * 1 ==> Front Panel is not connected
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * 0 ==> Front Panel is connected
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * 1 ==> Front Panel Headphone is not connected
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * 0 ==> Front Panel Headphone is connected
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* for SBLive 7.1 */
2a7bf89ee47466b3389ff63ab2831d3b73e0b8deGarrett D'Amore for (i = 0; i < (sizeof (spi_dac) / sizeof (spi_dac[0])); i++) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore OUTL(dev, HC, 0x00000009); /* Enable audio, use 48 kHz */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore tmp |= 0xf0c81000; /* Record src0/src1 from ac97 */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore tmp |= 0x50c81000; /* Record src0/src1 from I2SIN */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore tmp &= ~0x0303c00f; /* Set sample rates to 48 kHz */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, HMIXMAP_I2S, 0x76543210); /* Default out route */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, AUDCTL, 0x0f0f003f); /* Enable all outputs */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* All audio stopped! */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore for (i = 0; i < 4; i++) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * Reset DMA pointers and counters. Note that we do
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * The 5.1 play port made up channels 0, 1, and 3. The record
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * port is channel 2.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* Set sample rates to 48 kHz. */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore tmp = read_chan(dev, SRCTL, 0) & ~0x0303c00f;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, SCS0, 0x02108004); /* Audio */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, SCS1, 0x02108004); /* Audio */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, SCS2, 0x02108004); /* Audio */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, SCS3, 0x02108004); /* Audio */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore#define PLAYCTL (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_PLAY)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore#define RECCTL (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_REC)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore#define MONCTL (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_MONITOR)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore#define PCMVOL (PLAYCTL | AUDIO_CTRL_FLAG_PCMVOL)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore#define MAINVOL (PLAYCTL | AUDIO_CTRL_FLAG_MAINVOL)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore#define RECVOL (RECCTL | AUDIO_CTRL_FLAG_RECVOL)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore#define MONVOL (MONCTL | AUDIO_CTRL_FLAG_MONVOL)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore ((uint8_t)((((val) * MASK(nbits)) / 100)) << (8 - (nbits)))
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_stereo_scale(uint32_t value, uint8_t bits)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore val = (((left * ((1 << bits) - 1) / 100) << 8) |
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_configure_mixer(audigyls_dev_t *dev)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* output items */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore r = 0xffff - audigyls_stereo_scale(dev->controls[CTL_FRONT].val, 8);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore r = (r << 16) | r;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* surround */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore r = 0xffff - audigyls_stereo_scale(dev->controls[CTL_SURROUND].val, 8);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore r = (r << 16) | r;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore v1 = 255 - SCALE(dev->controls[CTL_CENTER].val, 8);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore v2 = 255 - SCALE(dev->controls[CTL_LFE].val, 8);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore r = (r << 16) | r;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore r = dev->controls[CTL_SPREAD].val ? 0x10101010 : 0x76543210;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* input items */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* recgain */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (dev->ac97_recgain && !dev->controls[CTL_LOOP].val) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * For AC'97, we use the AC'97 record gain, unless we are
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * in loopback.
a60cc674f1dd8c4fd3fb0e319c3d8b6b26524067Garrett D'Amore (void) ac97_control_set(dev->ac97_recgain, v1);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * Otherwise we set the P17 gain.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore r = r << 16 | r;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* monitor gain */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* AC'97 monitor gain is done by the AC'97 codec */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* For non-AC'97 devices, just a single master monitor gain */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore r = 255 - SCALE(dev->controls[CTL_MONGAIN].val, 8);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_chan(dev, SRCTL, 1, 0xffff0000 | r << 8 | r);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (r != 0xff) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* record source */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_i2c_write(dev, 0x15, 0x2); /* Mic */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_i2c_write(dev, 0x15, 0x4); /* Line */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* If loopback, record what you hear instead */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore r |= (v1 << 28) | (v1 << 24) | (v1 << 20) | (v1 << 16) | v1;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * You'd think this would be the same as the logic
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * above, but experience shows that what you need for
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * loopback is different. This whole thing looks
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * particularly fishy to me. I suspect someone has
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * made a mistake somewhere. But I can't seem to
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * figure out where it lies.
e7437094ebbbd4d60375f3927c017ff00cbab1deGarrett D'Amore for (int i = 0; i < 4; i++)
e7437094ebbbd4d60375f3927c017ff00cbab1deGarrett D'Amore r = (v1 << 28) | (v1 << 24) | (v1 << 20) | (v1 << 16) |
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_set_control(void *arg, uint64_t val)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_get_control(void *arg, uint64_t *val)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_alloc_ctrl(audigyls_dev_t *dev, uint32_t num, uint64_t val)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * For AC'97 devices, we want to expose the reasonable
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * AC'97 input sources, but suppress the stereomix,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * because we use loopback instead.
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore const char *n;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore for (i = 0; i < 64; i++) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (((adp->acd_minvalue & (1 << i)) == 0) ||
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore for (j = 0; audigyls_badsrcs[j]; j++) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore desc.acd_minvalue = desc.acd_maxvalue = dev->recmask;
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore pc->ctrl = audio_dev_add_control(dev->adev, &desc,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_get_control, audigyls_set_control, pc);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_alloc_ctrl(dev, CTL_FRONT, 75 | (75 << 8));
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_alloc_ctrl(dev, CTL_SURROUND, 75 | (75 << 8));
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_alloc_ctrl(dev, CTL_RECORDVOL, 75 | (75 << 8));
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, NULL);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore mutex_init(&dev->low_mutex, NULL, MUTEX_DRIVER, NULL);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if ((dev->adev = audio_dev_alloc(dip, 0)) == NULL) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (pci_config_setup(dip, &pcih) != DDI_SUCCESS) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_dev_warn(dev->adev, "pci_config_setup failed");
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore vendor = pci_config_get16(pcih, PCI_CONF_VENID);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore device = pci_config_get16(pcih, PCI_CONF_DEVID);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore subdevice = pci_config_get16(pcih, PCI_CONF_SUBVENID);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore subdevice |= pci_config_get16(pcih, PCI_CONF_SUBSYSID);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore device != PCI_DEVICE_ID_CREATIVE_AUDIGYLS) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_dev_warn(dev->adev, "Hardware not recognized "
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore pci_command = pci_config_get16(pcih, PCI_CONF_COMM);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore pci_config_put16(pcih, PCI_CONF_COMM, pci_command);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if ((ddi_regs_map_setup(dip, 1, &dev->base, 0, 0, &dev_attr,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_dev_warn(dev->adev, "failed to map registers");
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* Function of the orange jack: 0=analog, 1=digital */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore dev->digital_enable = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore version = "SB0310"; /* could also be SB0312 */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case 0x11021006:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore name = "Creative Sound Blaster Live! 24 bit";
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore name = "Creative Sound Blaster Live! 24 bit";
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case 0x1102100a:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case 0x11021011:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case 0x11021012:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case 0x14621009:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case 0x12973038:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore case 0x12973041:
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* Original Audigy LS revision (AC97 based) */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audigyls_read_ac97, audigyls_write_ac97, dev);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore "failed to allocate ac97 handle");
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* remove the AC'97 controls we don't want to expose */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore for (int i = 0; audigyls_remove_ac97[i]; i++) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore dev->ac97_recgain = ac97_control_find(dev->ac97,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore dev->ac97_recsrc = ac97_control_find(dev->ac97,
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (audigyls_alloc_port(dev, AUDIGYLS_PLAY_PORT) != DDI_SUCCESS)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (audigyls_alloc_port(dev, AUDIGYLS_REC_PORT) != DDI_SUCCESS)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (audio_dev_register(dev->adev) != DDI_SUCCESS) {
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_dev_warn(dev->adev, "unable to register with framework");
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore /* allow ac97 operations again */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore if (audio_dev_unregister(dev->adev) != DDI_SUCCESS)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic int audigyls_ddi_attach(dev_info_t *, ddi_attach_cmd_t);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic int audigyls_ddi_detach(dev_info_t *, ddi_detach_cmd_t);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amorestatic int audigyls_ddi_quiesce(dev_info_t *);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore 0, /* refcnt */
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore audio_init_ops(&audigyls_dev_ops, AUDIGYLS_NAME);
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amoreaudigyls_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore * Turn off the hardware
48722b5f422aa5e059f333d8c7384ffd184fe739Garrett D'Amore write_reg(dev, AIE, 0); /* Disable audio interrupts */