Merge branch 'topic/hda-cirrus' into topic/hda
[pandora-kernel.git] / sound / pci / hda / hda_codec.c
index d9d3262..a23c27d 100644 (file)
@@ -44,6 +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,8 +151,8 @@ make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
 {
        u32 val;
 
-       if ((codec->addr & ~0xf) | (direct & ~1) | (nid & ~0x7f) |
-           (verb & ~0xfff) | (parm & ~0xff)) {
+       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;
@@ -301,11 +302,20 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
        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 */
@@ -347,6 +357,12 @@ int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
                }
                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 */
@@ -736,8 +752,7 @@ static int read_pin_defaults(struct hda_codec *codec)
        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);
@@ -2361,16 +2376,20 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg,
        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;
@@ -3661,8 +3680,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec,
        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;