Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  atihdmi.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * ATI/AMD codec support
 */


#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/unaligned.h>
#include <sound/core.h>
#include <sound/tlv.h>
#include <sound/hdaudio.h>
#include <sound/hda_codec.h>
#include "hda_local.h"
#include "hdmi_local.h"

#define is_amdhdmi_rev3_or_later(codec) \
 ((codec)->core.vendor_id == 0x1002aa01 && \
  ((codec)->core.revision_id & 0xff00) >= 0x0300)
#define has_amd_full_remap_support(codec) is_amdhdmi_rev3_or_later(codec)

/* ATI/AMD specific HDA pin verbs, see the AMD HDA Verbs specification */
#define ATI_VERB_SET_CHANNEL_ALLOCATION 0x771
#define ATI_VERB_SET_DOWNMIX_INFO 0x772
#define ATI_VERB_SET_MULTICHANNEL_01 0x777
#define ATI_VERB_SET_MULTICHANNEL_23 0x778
#define ATI_VERB_SET_MULTICHANNEL_45 0x779
#define ATI_VERB_SET_MULTICHANNEL_67 0x77a
#define ATI_VERB_SET_HBR_CONTROL 0x77c
#define ATI_VERB_SET_MULTICHANNEL_1 0x785
#define ATI_VERB_SET_MULTICHANNEL_3 0x786
#define ATI_VERB_SET_MULTICHANNEL_5 0x787
#define ATI_VERB_SET_MULTICHANNEL_7 0x788
#define ATI_VERB_SET_MULTICHANNEL_MODE 0x789
#define ATI_VERB_GET_CHANNEL_ALLOCATION 0xf71
#define ATI_VERB_GET_DOWNMIX_INFO 0xf72
#define ATI_VERB_GET_MULTICHANNEL_01 0xf77
#define ATI_VERB_GET_MULTICHANNEL_23 0xf78
#define ATI_VERB_GET_MULTICHANNEL_45 0xf79
#define ATI_VERB_GET_MULTICHANNEL_67 0xf7a
#define ATI_VERB_GET_HBR_CONTROL 0xf7c
#define ATI_VERB_GET_MULTICHANNEL_1 0xf85
#define ATI_VERB_GET_MULTICHANNEL_3 0xf86
#define ATI_VERB_GET_MULTICHANNEL_5 0xf87
#define ATI_VERB_GET_MULTICHANNEL_7 0xf88
#define ATI_VERB_GET_MULTICHANNEL_MODE 0xf89

/* AMD specific HDA cvt verbs */
#define ATI_VERB_SET_RAMP_RATE  0x770
#define ATI_VERB_GET_RAMP_RATE  0xf70

#define ATI_OUT_ENABLE 0x1

#define ATI_MULTICHANNEL_MODE_PAIRED 0
#define ATI_MULTICHANNEL_MODE_SINGLE 1

#define ATI_HBR_CAPABLE 0x01
#define ATI_HBR_ENABLE 0x10

/* ATI/AMD specific ELD emulation */

#define ATI_VERB_SET_AUDIO_DESCRIPTOR 0x776
#define ATI_VERB_SET_SINK_INFO_INDEX 0x780
#define ATI_VERB_GET_SPEAKER_ALLOCATION 0xf70
#define ATI_VERB_GET_AUDIO_DESCRIPTOR 0xf76
#define ATI_VERB_GET_AUDIO_VIDEO_DELAY 0xf7b
#define ATI_VERB_GET_SINK_INFO_INDEX 0xf80
#define ATI_VERB_GET_SINK_INFO_DATA 0xf81

#define ATI_SPKALLOC_SPKALLOC  0x007f
#define ATI_SPKALLOC_TYPE_HDMI  0x0100
#define ATI_SPKALLOC_TYPE_DISPLAYPORT 0x0200

/* first three bytes are just standard SAD */
#define ATI_AUDIODESC_CHANNELS  0x00000007
#define ATI_AUDIODESC_RATES  0x0000ff00
#define ATI_AUDIODESC_LPCM_STEREO_RATES 0xff000000

/* in standard HDMI VSDB format */
#define ATI_DELAY_VIDEO_LATENCY  0x000000ff
#define ATI_DELAY_AUDIO_LATENCY  0x0000ff00

enum ati_sink_info_idx {
 ATI_INFO_IDX_MANUFACTURER_ID = 0,
 ATI_INFO_IDX_PRODUCT_ID  = 1,
 ATI_INFO_IDX_SINK_DESC_LEN = 2,
 ATI_INFO_IDX_PORT_ID_LOW = 3,
 ATI_INFO_IDX_PORT_ID_HIGH = 4,
 ATI_INFO_IDX_SINK_DESC_FIRST = 5,
 ATI_INFO_IDX_SINK_DESC_LAST = 22, /* max len 18 bytes */
};

static int get_eld_ati(struct hda_codec *codec, hda_nid_t nid,
         unsigned char *buf, int *eld_size, bool rev3_or_later)
{
 int spkalloc, ati_sad, aud_synch;
 int sink_desc_len = 0;
 int pos, i;

 /* ATI/AMD does not have ELD, emulate it */

 spkalloc = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SPEAKER_ALLOCATION, 0);

 if (spkalloc <= 0) {
  codec_info(codec, "HDMI ATI/AMD: no speaker allocation for ELD\n");
  return -EINVAL;
 }

 memset(buf, 0, ELD_FIXED_BYTES + ELD_MAX_MNL + ELD_MAX_SAD * 3);

 /* version */
 buf[0] = ELD_VER_CEA_861D << 3;

 /* speaker allocation from EDID */
 buf[7] = spkalloc & ATI_SPKALLOC_SPKALLOC;

 /* is DisplayPort? */
 if (spkalloc & ATI_SPKALLOC_TYPE_DISPLAYPORT)
  buf[5] |= 0x04;

 pos = ELD_FIXED_BYTES;

 if (rev3_or_later) {
  int sink_info;

  snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PORT_ID_LOW);
  sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
  put_unaligned_le32(sink_info, buf + 8);

  snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PORT_ID_HIGH);
  sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
  put_unaligned_le32(sink_info, buf + 12);

  snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_MANUFACTURER_ID);
  sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
  put_unaligned_le16(sink_info, buf + 16);

  snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PRODUCT_ID);
  sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
  put_unaligned_le16(sink_info, buf + 18);

  snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_SINK_DESC_LEN);
  sink_desc_len = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);

  if (sink_desc_len > ELD_MAX_MNL) {
   codec_info(codec, "HDMI ATI/AMD: Truncating HDMI sink description with length %d\n",
       sink_desc_len);
   sink_desc_len = ELD_MAX_MNL;
  }

  buf[4] |= sink_desc_len;

  for (i = 0; i < sink_desc_len; i++) {
   snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_SINK_DESC_FIRST + i);
   buf[pos++] = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
  }
 }

 for (i = AUDIO_CODING_TYPE_LPCM; i <= AUDIO_CODING_TYPE_WMAPRO; i++) {
  if (i == AUDIO_CODING_TYPE_SACD || i == AUDIO_CODING_TYPE_DST)
   continue/* not handled by ATI/AMD */

  snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_AUDIO_DESCRIPTOR, i << 3);
  ati_sad = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_AUDIO_DESCRIPTOR, 0);

  if (ati_sad <= 0)
   continue;

  if (ati_sad & ATI_AUDIODESC_RATES) {
   /* format is supported, copy SAD as-is */
   buf[pos++] = (ati_sad & 0x0000ff) >> 0;
   buf[pos++] = (ati_sad & 0x00ff00) >> 8;
   buf[pos++] = (ati_sad & 0xff0000) >> 16;
  }

  if (i == AUDIO_CODING_TYPE_LPCM
      && (ati_sad & ATI_AUDIODESC_LPCM_STEREO_RATES)
      && (ati_sad & ATI_AUDIODESC_LPCM_STEREO_RATES) >> 16 != (ati_sad & ATI_AUDIODESC_RATES)) {
   /* for PCM there is a separate stereo rate mask */
   buf[pos++] = ((ati_sad & 0x000000ff) & ~ATI_AUDIODESC_CHANNELS) | 0x1;
   /* rates from the extra byte */
   buf[pos++] = (ati_sad & 0xff000000) >> 24;
   buf[pos++] = (ati_sad & 0x00ff0000) >> 16;
  }
 }

 if (pos == ELD_FIXED_BYTES + sink_desc_len) {
  codec_info(codec, "HDMI ATI/AMD: no audio descriptors for ELD\n");
  return -EINVAL;
 }

 /*
 * HDMI VSDB latency format:
 * separately for both audio and video:
 *  0          field not valid or unknown latency
 *  [1..251]   msecs = (x-1)*2  (max 500ms with x = 251 = 0xfb)
 *  255        audio/video not supported
 *
 * HDA latency format:
 * single value indicating video latency relative to audio:
 *  0          unknown or 0ms
 *  [1..250]   msecs = x*2  (max 500ms with x = 250 = 0xfa)
 *  [251..255] reserved
 */

 aud_synch = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_AUDIO_VIDEO_DELAY, 0);
 if ((aud_synch & ATI_DELAY_VIDEO_LATENCY) && (aud_synch & ATI_DELAY_AUDIO_LATENCY)) {
  int video_latency_hdmi = (aud_synch & ATI_DELAY_VIDEO_LATENCY);
  int audio_latency_hdmi = (aud_synch & ATI_DELAY_AUDIO_LATENCY) >> 8;

  if (video_latency_hdmi <= 0xfb && audio_latency_hdmi <= 0xfb &&
      video_latency_hdmi > audio_latency_hdmi)
   buf[6] = video_latency_hdmi - audio_latency_hdmi;
  /* else unknown/invalid or 0ms or video ahead of audio, so use zero */
 }

 /* SAD count */
 buf[5] |= ((pos - ELD_FIXED_BYTES - sink_desc_len) / 3) << 4;

 /* Baseline ELD block length is 4-byte aligned */
 pos = round_up(pos, 4);

 /* Baseline ELD length (4-byte header is not counted in) */
 buf[2] = (pos - 4) / 4;

 *eld_size = pos;

 return 0;
}

static int atihdmi_pin_get_eld(struct hda_codec *codec, hda_nid_t nid,
          int dev_id, unsigned char *buf, int *eld_size)
{
 WARN_ON(dev_id != 0);
 /* call hda_eld.c ATI/AMD-specific function */
 return get_eld_ati(codec, nid, buf, eld_size,
      is_amdhdmi_rev3_or_later(codec));
}

static void atihdmi_pin_setup_infoframe(struct hda_codec *codec,
     hda_nid_t pin_nid, int dev_id, int ca,
     int active_channels, int conn_type)
{
 WARN_ON(dev_id != 0);
 snd_hda_codec_write(codec, pin_nid, 0, ATI_VERB_SET_CHANNEL_ALLOCATION, ca);
}

static int atihdmi_paired_swap_fc_lfe(int pos)
{
 /*
 * ATI/AMD have automatic FC/LFE swap built-in
 * when in pairwise mapping mode.
 */


 switch (pos) {
 /* see channel_allocations[].speakers[] */
 case 2: return 3;
 case 3: return 2;
 defaultreturn pos;
 }
}

static int atihdmi_paired_chmap_validate(struct hdac_chmap *chmap,
   int ca, int chs, unsigned char *map)
{
 struct hdac_cea_channel_speaker_allocation *cap;
 int i, j;

 /* check that only channel pairs need to be remapped on old pre-rev3 ATI/AMD */

 cap = snd_hdac_get_ch_alloc_from_ca(ca);
 for (i = 0; i < chs; ++i) {
  int mask = snd_hdac_chmap_to_spk_mask(map[i]);
  bool ok = false;
  bool companion_ok = false;

  if (!mask)
   continue;

  for (j = 0 + i % 2; j < 8; j += 2) {
   int chan_idx = 7 - atihdmi_paired_swap_fc_lfe(j);

   if (cap->speakers[chan_idx] == mask) {
    /* channel is in a supported position */
    ok = true;

    if (i % 2 == 0 && i + 1 < chs) {
     /* even channel, check the odd companion */
     int comp_chan_idx = 7 - atihdmi_paired_swap_fc_lfe(j + 1);
     int comp_mask_req = snd_hdac_chmap_to_spk_mask(map[i+1]);
     int comp_mask_act = cap->speakers[comp_chan_idx];

     if (comp_mask_req == comp_mask_act)
      companion_ok = true;
     else
      return -EINVAL;
    }
    break;
   }
  }

  if (!ok)
   return -EINVAL;

  if (companion_ok)
   i++; /* companion channel already checked */
 }

 return 0;
}

static int atihdmi_pin_set_slot_channel(struct hdac_device *hdac,
  hda_nid_t pin_nid, int hdmi_slot, int stream_channel)
{
 struct hda_codec *codec = hdac_to_hda_codec(hdac);
 int verb;
 int ati_channel_setup = 0;

 if (hdmi_slot > 7)
  return -EINVAL;

 if (!has_amd_full_remap_support(codec)) {
  hdmi_slot = atihdmi_paired_swap_fc_lfe(hdmi_slot);

  /* In case this is an odd slot but without stream channel, do not
 * disable the slot since the corresponding even slot could have a
 * channel. In case neither have a channel, the slot pair will be
 * disabled when this function is called for the even slot.
 */

  if (hdmi_slot % 2 != 0 && stream_channel == 0xf)
   return 0;

  hdmi_slot -= hdmi_slot % 2;

  if (stream_channel != 0xf)
   stream_channel -= stream_channel % 2;
 }

 verb = ATI_VERB_SET_MULTICHANNEL_01 + hdmi_slot/2 + (hdmi_slot % 2) * 0x00e;

 /* ati_channel_setup format: [7..4] = stream_channel_id, [1] = mute, [0] = enable */

 if (stream_channel != 0xf)
  ati_channel_setup = (stream_channel << 4) | ATI_OUT_ENABLE;

 return snd_hda_codec_write(codec, pin_nid, 0, verb, ati_channel_setup);
}

static int atihdmi_pin_get_slot_channel(struct hdac_device *hdac,
    hda_nid_t pin_nid, int asp_slot)
{
 struct hda_codec *codec = hdac_to_hda_codec(hdac);
 bool was_odd = false;
 int ati_asp_slot = asp_slot;
 int verb;
 int ati_channel_setup;

 if (asp_slot > 7)
  return -EINVAL;

 if (!has_amd_full_remap_support(codec)) {
  ati_asp_slot = atihdmi_paired_swap_fc_lfe(asp_slot);
  if (ati_asp_slot % 2 != 0) {
   ati_asp_slot -= 1;
   was_odd = true;
  }
 }

 verb = ATI_VERB_GET_MULTICHANNEL_01 + ati_asp_slot/2 + (ati_asp_slot % 2) * 0x00e;

 ati_channel_setup = snd_hda_codec_read(codec, pin_nid, 0, verb, 0);

 if (!(ati_channel_setup & ATI_OUT_ENABLE))
  return 0xf;

 return ((ati_channel_setup & 0xf0) >> 4) + !!was_odd;
}

static int atihdmi_paired_chmap_cea_alloc_validate_get_type(
  struct hdac_chmap *chmap,
  struct hdac_cea_channel_speaker_allocation *cap,
  int channels)
{
 int c;

 /*
 * Pre-rev3 ATI/AMD codecs operate in a paired channel mode, so
 * we need to take that into account (a single channel may take 2
 * channel slots if we need to carry a silent channel next to it).
 * On Rev3+ AMD codecs this function is not used.
 */

 int chanpairs = 0;

 /* We only produce even-numbered channel count TLVs */
 if ((channels % 2) != 0)
  return -1;

 for (c = 0; c < 7; c += 2) {
  if (cap->speakers[c] || cap->speakers[c+1])
   chanpairs++;
 }

 if (chanpairs * 2 != channels)
  return -1;

 return SNDRV_CTL_TLVT_CHMAP_PAIRED;
}

static void atihdmi_paired_cea_alloc_to_tlv_chmap(struct hdac_chmap *hchmap,
  struct hdac_cea_channel_speaker_allocation *cap,
  unsigned int *chmap, int channels)
{
 /* produce paired maps for pre-rev3 ATI/AMD codecs */
 int count = 0;
 int c;

 for (c = 7; c >= 0; c--) {
  int chan = 7 - atihdmi_paired_swap_fc_lfe(7 - c);
  int spk = cap->speakers[chan];

  if (!spk) {
   /* add N/A channel if the companion channel is occupied */
   if (cap->speakers[chan + (chan % 2 ? -1 : 1)])
    chmap[count++] = SNDRV_CHMAP_NA;

   continue;
  }

  chmap[count++] = snd_hdac_spk_to_chmap(spk);
 }

 WARN_ON(count != channels);
}

static int atihdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid,
     int dev_id, bool hbr)
{
 int hbr_ctl, hbr_ctl_new;

 WARN_ON(dev_id != 0);

 hbr_ctl = snd_hda_codec_read(codec, pin_nid, 0, ATI_VERB_GET_HBR_CONTROL, 0);
 if (hbr_ctl >= 0 && (hbr_ctl & ATI_HBR_CAPABLE)) {
  if (hbr)
   hbr_ctl_new = hbr_ctl | ATI_HBR_ENABLE;
  else
   hbr_ctl_new = hbr_ctl & ~ATI_HBR_ENABLE;

  codec_dbg(codec,
     "%s: NID=0x%x, %shbr-ctl=0x%x\n",
     __func__,
     pin_nid,
     hbr_ctl == hbr_ctl_new ? "" : "new-",
     hbr_ctl_new);

  if (hbr_ctl != hbr_ctl_new)
   snd_hda_codec_write(codec, pin_nid, 0,
      ATI_VERB_SET_HBR_CONTROL,
      hbr_ctl_new);

 } else if (hbr)
  return -EINVAL;

 return 0;
}

static int atihdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
    hda_nid_t pin_nid, int dev_id,
    u32 stream_tag, int format)
{
 if (is_amdhdmi_rev3_or_later(codec)) {
  int ramp_rate = 180; /* default as per AMD spec */
  /* disable ramp-up/down for non-pcm as per AMD spec */
  if (format & AC_FMT_TYPE_NON_PCM)
   ramp_rate = 0;

  snd_hda_codec_write(codec, cvt_nid, 0, ATI_VERB_SET_RAMP_RATE, ramp_rate);
 }

 return snd_hda_hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id,
      stream_tag, format);
}


static int atihdmi_init(struct hda_codec *codec)
{
 struct hdmi_spec *spec = codec->spec;
 int pin_idx, err;

 err = snd_hda_hdmi_generic_init(codec);

 if (err)
  return err;

 for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
  struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);

  /* make sure downmix information in infoframe is zero */
  snd_hda_codec_write(codec, per_pin->pin_nid, 0, ATI_VERB_SET_DOWNMIX_INFO, 0);

  /* enable channel-wise remap mode if supported */
  if (has_amd_full_remap_support(codec))
   snd_hda_codec_write(codec, per_pin->pin_nid, 0,
         ATI_VERB_SET_MULTICHANNEL_MODE,
         ATI_MULTICHANNEL_MODE_SINGLE);
 }
 codec->auto_runtime_pm = 1;

 return 0;
}

/* map from pin NID to port; port is 0-based */
/* for AMD: assume widget NID starting from 3, with step 2 (3, 5, 7, ...) */
static int atihdmi_pin2port(void *audio_ptr, int pin_nid)
{
 return pin_nid / 2 - 1;
}

/* reverse-map from port to pin NID: see above */
static int atihdmi_port2pin(struct hda_codec *codec, int port)
{
 return port * 2 + 3;
}

static const struct drm_audio_component_audio_ops atihdmi_audio_ops = {
 .pin2port = atihdmi_pin2port,
 .pin_eld_notify = snd_hda_hdmi_acomp_pin_eld_notify,
 .master_bind = snd_hda_hdmi_acomp_master_bind,
 .master_unbind = snd_hda_hdmi_acomp_master_unbind,
};

static int atihdmi_probe(struct hda_codec *codec, const struct hda_device_id *id)
{
 struct hdmi_spec *spec;
 struct hdmi_spec_per_cvt *per_cvt;
 int err, cvt_idx;

 err = snd_hda_hdmi_generic_probe(codec);
 if (err)
  return err;

 spec = codec->spec;

 spec->static_pcm_mapping = true;

 spec->ops.pin_get_eld = atihdmi_pin_get_eld;
 spec->ops.pin_setup_infoframe = atihdmi_pin_setup_infoframe;
 spec->ops.pin_hbr_setup = atihdmi_pin_hbr_setup;
 spec->ops.setup_stream = atihdmi_setup_stream;

 spec->chmap.ops.pin_get_slot_channel = atihdmi_pin_get_slot_channel;
 spec->chmap.ops.pin_set_slot_channel = atihdmi_pin_set_slot_channel;

 if (!has_amd_full_remap_support(codec)) {
  /* override to ATI/AMD-specific versions with pairwise mapping */
  spec->chmap.ops.chmap_cea_alloc_validate_get_type =
   atihdmi_paired_chmap_cea_alloc_validate_get_type;
  spec->chmap.ops.cea_alloc_to_tlv_chmap =
    atihdmi_paired_cea_alloc_to_tlv_chmap;
  spec->chmap.ops.chmap_validate = atihdmi_paired_chmap_validate;
 }

 /* ATI/AMD converters do not advertise all of their capabilities */
 for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
  per_cvt = get_cvt(spec, cvt_idx);
  per_cvt->channels_max = max(per_cvt->channels_max, 8u);
  per_cvt->rates |= SUPPORTED_RATES;
  per_cvt->formats |= SUPPORTED_FORMATS;
  per_cvt->maxbps = max(per_cvt->maxbps, 24u);
 }

 spec->chmap.channels_max = max(spec->chmap.channels_max, 8u);

 /* AMD GPUs have neither EPSS nor CLKSTOP bits, hence preventing
 * the link-down as is.  Tell the core to allow it.
 */

 codec->link_down_at_suspend = 1;

 snd_hda_hdmi_acomp_init(codec, &atihdmi_audio_ops, atihdmi_port2pin);

 return 0;
}

static const struct hda_codec_ops atihdmi_codec_ops = {
 .probe = atihdmi_probe,
 .remove = snd_hda_hdmi_generic_remove,
 .init = atihdmi_init,
 .build_pcms = snd_hda_hdmi_generic_build_pcms,
 .build_controls = snd_hda_hdmi_generic_build_controls,
 .unsol_event = snd_hda_hdmi_generic_unsol_event,
 .suspend = snd_hda_hdmi_generic_suspend,
 .resume  = snd_hda_hdmi_generic_resume,
};

/*
 * driver entries
 */

static const struct hda_device_id snd_hda_id_atihdmi[] = {
 HDA_CODEC_ID(0x1002793c, "RS600 HDMI"),
 HDA_CODEC_ID(0x10027919, "RS600 HDMI"),
 HDA_CODEC_ID(0x1002791a, "RS690/780 HDMI"),
 HDA_CODEC_ID(0x1002aa01, "R6xx HDMI"),
 {} /* terminator */
};
MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_atihdmi);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("AMD/ATI HDMI HD-audio codec");
MODULE_IMPORT_NS("SND_HDA_CODEC_HDMI");

static struct hda_codec_driver atihdmi_driver = {
 .id = snd_hda_id_atihdmi,
 .ops = &atihdmi_codec_ops,
};

module_hda_codec_driver(atihdmi_driver);

Messung V0.5
C=93 H=93 G=92

¤ Dauer der Verarbeitung: 0.11 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge