root/sys/dev/sound/pci/hda/hdaa.h
/*-
 * SPDX-License-Identifier: BSD-2-Clause
 *
 * Copyright (c) 2006 Stephane E. Potvin <sepotvin@videotron.ca>
 * Copyright (c) 2006 Ariff Abdullah <ariff@FreeBSD.org>
 * Copyright (c) 2008-2012 Alexander Motin <mav@FreeBSD.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * Intel High Definition Audio (Audio function quirks) driver for FreeBSD.
 */

#ifndef _HDAA_QUIRKS_H_
#define _HDAA_QUIRKS_H_

#define HDAA_GPIO_SHIFT(n)      (n * 3)
#define HDAA_GPIO_MASK(n)       (0x7 << (n * 3))
#define HDAA_GPIO_KEEP(n)       (0x0 << (n * 3))
#define HDAA_GPIO_SET(n)        (0x1 << (n * 3))
#define HDAA_GPIO_CLEAR(n)      (0x2 << (n * 3))
#define HDAA_GPIO_DISABLE(n)    (0x3 << (n * 3))
#define HDAA_GPIO_INPUT(n)      (0x4 << (n * 3))

/* 9 - 25 = anything else */
#define HDAA_QUIRK_SOFTPCMVOL   (1 << 9)
#define HDAA_QUIRK_FIXEDRATE    (1 << 10)
#define HDAA_QUIRK_FORCESTEREO  (1 << 11)
#define HDAA_QUIRK_EAPDINV      (1 << 12)
#define HDAA_QUIRK_SENSEINV     (1 << 14)

/* 26 - 31 = vrefs */
#define HDAA_QUIRK_IVREF50      (1 << 26)
#define HDAA_QUIRK_IVREF80      (1 << 27)
#define HDAA_QUIRK_IVREF100     (1 << 28)
#define HDAA_QUIRK_OVREF50      (1 << 29)
#define HDAA_QUIRK_OVREF80      (1 << 30)
#define HDAA_QUIRK_OVREF100     (1U << 31)

#define HDAA_QUIRK_IVREF        (HDAA_QUIRK_IVREF50 | HDAA_QUIRK_IVREF80 | \
                                                HDAA_QUIRK_IVREF100)
#define HDAA_QUIRK_OVREF        (HDAA_QUIRK_OVREF50 | HDAA_QUIRK_OVREF80 | \
                                                HDAA_QUIRK_OVREF100)
#define HDAA_QUIRK_VREF         (HDAA_QUIRK_IVREF | HDAA_QUIRK_OVREF)

#define HDAA_AMP_VOL_DEFAULT    (-1)
#define HDAA_AMP_MUTE_DEFAULT   (0xffffffff)
#define HDAA_AMP_MUTE_NONE      (0)
#define HDAA_AMP_MUTE_LEFT      (1 << 0)
#define HDAA_AMP_MUTE_RIGHT     (1 << 1)
#define HDAA_AMP_MUTE_ALL       (HDAA_AMP_MUTE_LEFT | HDAA_AMP_MUTE_RIGHT)

#define HDAA_AMP_LEFT_MUTED(v)  ((v) & (HDAA_AMP_MUTE_LEFT))
#define HDAA_AMP_RIGHT_MUTED(v) (((v) & HDAA_AMP_MUTE_RIGHT) >> 1)

/* Widget in playback receiving signal from recording. */
#define HDAA_ADC_MONITOR                (1 << 0)
/* Input mixer widget needs volume control as destination. */
#define HDAA_IMIX_AS_DST                (2 << 0)

#define HDAA_CTL_OUT            1
#define HDAA_CTL_IN             2

#define HDA_MAX_CONNS   32
#define HDA_MAX_NAMELEN 32

struct hdaa_audio_as;
struct hdaa_audio_ctl;
struct hdaa_chan;
struct hdaa_devinfo;
struct hdaa_pcm_devinfo;
struct hdaa_widget;

struct hdaa_widget {
        nid_t nid;
        int type;
        int enable;
        int nconns, selconn;
        int waspin;
        uint32_t pflags;
        int bindas;
        int bindseqmask;
        int ossdev;
        uint32_t ossmask;
        int unsol;
        nid_t conns[HDA_MAX_CONNS];
        u_char connsenable[HDA_MAX_CONNS];
        char name[HDA_MAX_NAMELEN];
        uint8_t *eld;
        int     eld_len;
        struct hdaa_devinfo *devinfo;
        struct {
                uint32_t widget_cap;
                uint32_t outamp_cap;
                uint32_t inamp_cap;
                uint32_t supp_stream_formats;
                uint32_t supp_pcm_size_rate;
                uint32_t eapdbtl;
        } param;
        union {
                struct {
                        uint32_t config;
                        uint32_t original;
                        uint32_t newconf;
                        uint32_t cap;
                        uint32_t ctrl;
                        int     connected;
                } pin;
                struct {
                        uint8_t stripecap;
                } conv;
        } wclass;
};

struct hdaa_audio_ctl {
        struct hdaa_widget *widget, *childwidget;
        int enable;
        int index, dir, ndir;
        int mute, step, size, offset;
        int left, right, forcemute;
        uint32_t muted;
        uint32_t ossmask;       /* OSS devices that may affect control. */
        int     devleft[SOUND_MIXER_NRDEVICES]; /* Left ampl in 1/4dB. */
        int     devright[SOUND_MIXER_NRDEVICES]; /* Right ampl in 1/4dB. */
        int     devmute[SOUND_MIXER_NRDEVICES]; /* Mutes per OSS device. */
};

/* Association is a group of pins bound for some special function. */
struct hdaa_audio_as {
        u_char enable;
        u_char index;
        u_char dir;
        u_char pincnt;
        u_char fakeredir;
        u_char digital;
        uint16_t pinset;
        nid_t hpredir;
        nid_t pins[16];
        nid_t dacs[2][16];
        int num_chans;
        int chans[2];
        int location;   /* Pins location, if all have the same */
        int mixed;      /* Mixed/multiplexed recording, not multichannel. */
        struct hdaa_pcm_devinfo *pdevinfo;
};

struct hdaa_pcm_devinfo {
        device_t dev;
        struct hdaa_devinfo *devinfo;
        struct  snd_mixer *mixer;
        int     index;
        int     registered;
        int     playas, recas;
        u_char  left[SOUND_MIXER_NRDEVICES];
        u_char  right[SOUND_MIXER_NRDEVICES];
        int     minamp[SOUND_MIXER_NRDEVICES]; /* Minimal amps in 1/4dB. */
        int     maxamp[SOUND_MIXER_NRDEVICES]; /* Maximal amps in 1/4dB. */
        int     chan_size;
        int     chan_blkcnt;
        u_char  digital;
        uint32_t        ossmask;        /* Mask of supported OSS devices. */
        uint32_t        recsrc;         /* Mask of supported OSS sources. */
        int             autorecsrc;
};

struct hdaa_devinfo {
        device_t                dev;
        struct mtx              *lock;
        nid_t                   nid;
        nid_t                   startnode, endnode;
        uint32_t                outamp_cap;
        uint32_t                inamp_cap;
        uint32_t                supp_stream_formats;
        uint32_t                supp_pcm_size_rate;
        uint32_t                gpio_cap;
        uint32_t                quirks;
        uint32_t                newquirks;
        uint32_t                gpio;
        uint32_t                newgpio;
        uint32_t                gpo;
        uint32_t                newgpo;
        int                     nodecnt;
        int                     ctlcnt;
        int                     ascnt;
        int                     num_devs;
        int                     num_chans;
        struct hdaa_widget      *widget;
        struct hdaa_audio_ctl   *ctl;
        struct hdaa_audio_as    *as;
        struct hdaa_pcm_devinfo *devs;
        struct hdaa_chan        *chans;
        struct callout          poll_jack;
        int                     poll_ival;
        uint32_t                init_clear;
};

#define HDAA_CHN_RUNNING        0x00000001
#define HDAA_CHN_SUSPEND        0x00000002

struct hdaa_chan {
        struct snd_dbuf *b;
        struct pcm_channel *c;
        struct pcmchan_caps caps;
        struct hdaa_devinfo *devinfo;
        struct hdaa_pcm_devinfo *pdevinfo;
        uint32_t spd, fmt, fmtlist[32], pcmrates[16];
        uint32_t supp_stream_formats, supp_pcm_size_rate;
        uint32_t blkcnt, blksz;
        uint32_t *dmapos;
        uint32_t flags;
        int dir;
        int off;
        int sid;
        int bit16, bit32;
        int channels;   /* Number of audio channels. */
        int as;         /* Number of association. */
        int asindex;    /* Index within association. */
        nid_t io[16];
        uint8_t stripecap;      /* AND of stripecap of all ios. */
        uint8_t stripectl;      /* stripe to use to all ios. */
};

#define MINQDB(ctl)                                                     \
        ((0 - (ctl)->offset) * ((ctl)->size + 1))

#define MAXQDB(ctl)                                                     \
        (((ctl)->step - (ctl)->offset) * ((ctl)->size + 1))

#define RANGEQDB(ctl)                                                   \
        ((ctl)->step * ((ctl)->size + 1))

#define VAL2QDB(ctl, val)                                               \
        (((ctl)->size + 1) * ((int)(val) - (ctl)->offset))

#define QDB2VAL(ctl, qdb)                                               \
        imax(imin((((qdb) + (ctl)->size / 2 * ((qdb) > 0 ? 1 : -1)) /   \
         ((ctl)->size + 1) + (ctl)->offset), (ctl)->step), 0)

#define hdaa_codec_id(devinfo)                                          \
                (((uint32_t)hda_get_vendor_id(devinfo->dev) << 16) +    \
                hda_get_device_id(devinfo->dev))

#define hdaa_card_id(devinfo)                                   \
                (((uint32_t)hda_get_subdevice_id(devinfo->dev) << 16) + \
                hda_get_subvendor_id(devinfo->dev))

struct hdaa_widget      *hdaa_widget_get(struct hdaa_devinfo *, nid_t);
uint32_t                hdaa_widget_pin_patch(uint32_t config, const char *str);
uint32_t                hdaa_gpio_patch(uint32_t gpio, const char *str);

void                    hdaa_patch(struct hdaa_devinfo *devinfo);
void                    hdaa_patch_direct(struct hdaa_devinfo *devinfo);

#endif