Merge branch 'topic/hda-cirrus' into topic/hda
authorTakashi Iwai <tiwai@suse.de>
Thu, 30 Jul 2009 16:09:04 +0000 (18:09 +0200)
committerTakashi Iwai <tiwai@suse.de>
Thu, 30 Jul 2009 16:09:04 +0000 (18:09 +0200)
1  2 
Documentation/sound/alsa/HD-Audio-Models.txt
sound/pci/hda/hda_codec.c

@@@ -155,8 -155,6 +155,8 @@@ ALC882/883/885/888/88
    fujitsu-pi2515 Fujitsu AMILO Pi2515
    fujitsu-xa3530 Fujitsu AMILO XA3530
    3stack-6ch-intel Intel DG33* boards
 +  intel-alc889a       Intel IbexPeak with ALC889A
 +  intel-x58   Intel DX58 with ALC889
    asus-p5q    ASUS P5Q-EM boards
    mb31                MacBook 3,1
    sony-vaio-tt  Sony VAIO TT
@@@ -383,3 -381,7 +383,7 @@@ STAC987
  ========
    vaio                VAIO laptop without SPDIF
    auto                BIOS setup (default)
+ Cirrus Logic CS4206/4207
+ ========================
+   mbp55               MacBook Pro 5,5
@@@ -44,6 -44,7 +44,7 @@@ struct hda_vendor_id 
  /* codec vendor labels */
  static struct hda_vendor_id hda_vendor_ids[] = {
        { 0x1002, "ATI" },
+       { 0x1013, "Cirrus Logic" },
        { 0x1057, "Motorola" },
        { 0x1095, "Silicon Image" },
        { 0x10de, "Nvidia" },
@@@ -150,14 -151,7 +151,14 @@@ make_codec_cmd(struct hda_codec *codec
  {
        u32 val;
  
 -      val = (u32)(codec->addr & 0x0f) << 28;
 +      if ((codec->addr & ~0xf) || (direct & ~1) || (nid & ~0x7f) ||
 +          (verb & ~0xfff) || (parm & ~0xffff)) {
 +              printk(KERN_ERR "hda-codec: out of range cmd %x:%x:%x:%x:%x\n",
 +                     codec->addr, direct, nid, verb, parm);
 +              return ~0;
 +      }
 +
 +      val = (u32)codec->addr << 28;
        val |= (u32)direct << 27;
        val |= (u32)nid << 20;
        val |= verb << 8;
@@@ -174,9 -168,6 +175,9 @@@ static int codec_exec_verb(struct hda_c
        struct hda_bus *bus = codec->bus;
        int err;
  
 +      if (cmd == ~0)
 +              return -1;
 +
        if (res)
                *res = -1;
   again:
@@@ -301,20 -292,11 +302,20 @@@ int snd_hda_get_connections(struct hda_
        unsigned int parm;
        int i, conn_len, conns;
        unsigned int shift, num_elems, mask;
 +      unsigned int wcaps;
        hda_nid_t prev_nid;
  
        if (snd_BUG_ON(!conn_list || max_conns <= 0))
                return -EINVAL;
  
 +      wcaps = get_wcaps(codec, nid);
 +      if (!(wcaps & AC_WCAP_CONN_LIST) &&
 +          get_wcaps_type(wcaps) != AC_WID_VOL_KNB) {
 +              snd_printk(KERN_WARNING "hda_codec: "
 +                         "connection list not available for 0x%x\n", nid);
 +              return -EINVAL;
 +      }
 +
        parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN);
        if (parm & AC_CLIST_LONG) {
                /* long form */
                /* single connection */
                parm = snd_hda_codec_read(codec, nid, 0,
                                          AC_VERB_GET_CONNECT_LIST, 0);
 +              if (parm == -1 && codec->bus->rirb_error)
 +                      return -EIO;
                conn_list[0] = parm & mask;
                return 1;
        }
                int range_val;
                hda_nid_t val, n;
  
 -              if (i % num_elems == 0)
 +              if (i % num_elems == 0) {
                        parm = snd_hda_codec_read(codec, nid, 0,
                                                  AC_VERB_GET_CONNECT_LIST, i);
 +                      if (parm == -1 && codec->bus->rirb_error)
 +                              return -EIO;
 +              }
                range_val = !!(parm & (1 << (shift-1))); /* ranges */
                val = parm & mask;
 +              if (val == 0) {
 +                      snd_printk(KERN_WARNING "hda_codec: "
 +                                 "invalid CONNECT_LIST verb %x[%i]:%x\n",
 +                                  nid, i, parm);
 +                      return 0;
 +              }
                parm >>= shift;
                if (range_val) {
                        /* ranges between the previous and this one */
@@@ -751,7 -722,8 +752,7 @@@ static int read_pin_defaults(struct hda
        for (i = 0; i < codec->num_nodes; i++, nid++) {
                struct hda_pincfg *pin;
                unsigned int wcaps = get_wcaps(codec, nid);
 -              unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >>
 -                              AC_WCAP_TYPE_SHIFT;
 +              unsigned int wid_type = get_wcaps_type(wcaps);
                if (wid_type != AC_WID_PIN)
                        continue;
                pin = snd_array_new(&codec->init_pins);
@@@ -2375,20 -2347,16 +2376,20 @@@ static void hda_set_power_state(struct 
        hda_nid_t nid;
        int i;
  
 -      snd_hda_codec_write(codec, fg, 0, AC_VERB_SET_POWER_STATE,
 +      /* this delay seems necessary to avoid click noise at power-down */
 +      if (power_state == AC_PWRST_D3)
 +              msleep(100);
 +      snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE,
                            power_state);
 -      msleep(10); /* partial workaround for "azx_get_response timeout" */
 +      /* partial workaround for "azx_get_response timeout" */
 +      if (power_state == AC_PWRST_D0)
 +              msleep(10);
  
        nid = codec->start_nid;
        for (i = 0; i < codec->num_nodes; i++, nid++) {
                unsigned int wcaps = get_wcaps(codec, nid);
                if (wcaps & AC_WCAP_POWER) {
 -                      unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >>
 -                              AC_WCAP_TYPE_SHIFT;
 +                      unsigned int wid_type = get_wcaps_type(wcaps);
                        if (power_state == AC_PWRST_D3 &&
                            wid_type == AC_WID_PIN) {
                                unsigned int pincap;
@@@ -2596,7 -2564,7 +2597,7 @@@ unsigned int snd_hda_calc_stream_format
        case 20:
        case 24:
        case 32:
 -              if (maxbps >= 32)
 +              if (maxbps >= 32 || format == SNDRV_PCM_FORMAT_FLOAT_LE)
                        val |= 0x40;
                else if (maxbps >= 24)
                        val |= 0x30;
@@@ -2725,8 -2693,7 +2726,8 @@@ static int snd_hda_query_supported_pcm(
                }
                if (streams & AC_SUPFMT_FLOAT32) {
                        formats |= SNDRV_PCM_FMTBIT_FLOAT_LE;
 -                      bps = 32;
 +                      if (!bps)
 +                              bps = 32;
                }
                if (streams == AC_SUPFMT_AC3) {
                        /* should be exclusive */
@@@ -3500,16 -3467,10 +3501,16 @@@ int snd_hda_multi_out_analog_open(struc
                }
                mutex_lock(&codec->spdif_mutex);
                if (mout->share_spdif) {
 -                      runtime->hw.rates &= mout->spdif_rates;
 -                      runtime->hw.formats &= mout->spdif_formats;
 -                      if (mout->spdif_maxbps < hinfo->maxbps)
 -                              hinfo->maxbps = mout->spdif_maxbps;
 +                      if ((runtime->hw.rates & mout->spdif_rates) &&
 +                          (runtime->hw.formats & mout->spdif_formats)) {
 +                              runtime->hw.rates &= mout->spdif_rates;
 +                              runtime->hw.formats &= mout->spdif_formats;
 +                              if (mout->spdif_maxbps < hinfo->maxbps)
 +                                      hinfo->maxbps = mout->spdif_maxbps;
 +                      } else {
 +                              mout->share_spdif = 0;
 +                              /* FIXME: need notify? */
 +                      }
                }
                mutex_unlock(&codec->spdif_mutex);
        }
@@@ -3679,7 -3640,8 +3680,7 @@@ int snd_hda_parse_pin_def_config(struc
        end_nid = codec->start_nid + codec->num_nodes;
        for (nid = codec->start_nid; nid < end_nid; nid++) {
                unsigned int wid_caps = get_wcaps(codec, nid);
 -              unsigned int wid_type =
 -                      (wid_caps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
 +              unsigned int wid_type = get_wcaps_type(wid_caps);
                unsigned int def_conf;
                short assoc, loc;