Merge branch 'topic/section-fix' into for-linus
[pandora-kernel.git] / sound / pci / hda / hda_codec.c
index b91f6ed..562403a 100644 (file)
@@ -158,6 +158,39 @@ make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
        return val;
 }
 
+/*
+ * Send and receive a verb
+ */
+static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
+                          unsigned int *res)
+{
+       struct hda_bus *bus = codec->bus;
+       int err;
+
+       if (res)
+               *res = -1;
+ again:
+       snd_hda_power_up(codec);
+       mutex_lock(&bus->cmd_mutex);
+       err = bus->ops.command(bus, cmd);
+       if (!err && res)
+               *res = bus->ops.get_response(bus);
+       mutex_unlock(&bus->cmd_mutex);
+       snd_hda_power_down(codec);
+       if (res && *res == -1 && bus->rirb_error) {
+               if (bus->response_reset) {
+                       snd_printd("hda_codec: resetting BUS due to "
+                                  "fatal communication error\n");
+                       bus->ops.bus_reset(bus);
+               }
+               goto again;
+       }
+       /* clear reset-flag when the communication gets recovered */
+       if (!err)
+               bus->response_reset = 0;
+       return err;
+}
+
 /**
  * snd_hda_codec_read - send a command and get the response
  * @codec: the HDA codec
@@ -174,27 +207,9 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid,
                                int direct,
                                unsigned int verb, unsigned int parm)
 {
-       struct hda_bus *bus = codec->bus;
-       unsigned int cmd, res;
-       int repeated = 0;
-
-       cmd = make_codec_cmd(codec, nid, direct, verb, parm);
-       snd_hda_power_up(codec);
-       mutex_lock(&bus->cmd_mutex);
- again:
-       if (!bus->ops.command(bus, cmd)) {
-               res = bus->ops.get_response(bus);
-               if (res == -1 && bus->rirb_error) {
-                       if (repeated++ < 1) {
-                               snd_printd(KERN_WARNING "hda_codec: "
-                                          "Trying verb 0x%08x again\n", cmd);
-                               goto again;
-                       }
-               }
-       } else
-               res = (unsigned int)-1;
-       mutex_unlock(&bus->cmd_mutex);
-       snd_hda_power_down(codec);
+       unsigned cmd = make_codec_cmd(codec, nid, direct, verb, parm);
+       unsigned int res;
+       codec_exec_verb(codec, cmd, &res);
        return res;
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_read);
@@ -214,17 +229,10 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_read);
 int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct,
                         unsigned int verb, unsigned int parm)
 {
-       struct hda_bus *bus = codec->bus;
+       unsigned int cmd = make_codec_cmd(codec, nid, direct, verb, parm);
        unsigned int res;
-       int err;
-
-       res = make_codec_cmd(codec, nid, direct, verb, parm);
-       snd_hda_power_up(codec);
-       mutex_lock(&bus->cmd_mutex);
-       err = bus->ops.command(bus, res);
-       mutex_unlock(&bus->cmd_mutex);
-       snd_hda_power_down(codec);
-       return err;
+       return codec_exec_verb(codec, cmd,
+                              codec->bus->sync_write ? &res : NULL);
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_write);
 
@@ -623,7 +631,10 @@ static int get_codec_name(struct hda_codec *codec)
        const struct hda_vendor_id *c;
        const char *vendor = NULL;
        u16 vendor_id = codec->vendor_id >> 16;
-       char tmp[16], name[32];
+       char tmp[16];
+
+       if (codec->vendor_name)
+               goto get_chip_name;
 
        for (c = hda_vendor_ids; c->id; c++) {
                if (c->id == vendor_id) {
@@ -635,14 +646,21 @@ static int get_codec_name(struct hda_codec *codec)
                sprintf(tmp, "Generic %04x", vendor_id);
                vendor = tmp;
        }
+       codec->vendor_name = kstrdup(vendor, GFP_KERNEL);
+       if (!codec->vendor_name)
+               return -ENOMEM;
+
+ get_chip_name:
+       if (codec->chip_name)
+               return 0;
+
        if (codec->preset && codec->preset->name)
-               snprintf(name, sizeof(name), "%s %s", vendor,
-                        codec->preset->name);
-       else
-               snprintf(name, sizeof(name), "%s ID %x", vendor,
-                        codec->vendor_id & 0xffff);
-       codec->name = kstrdup(name, GFP_KERNEL);
-       if (!codec->name)
+               codec->chip_name = kstrdup(codec->preset->name, GFP_KERNEL);
+       else {
+               sprintf(tmp, "ID %x", codec->vendor_id & 0xffff);
+               codec->chip_name = kstrdup(tmp, GFP_KERNEL);
+       }
+       if (!codec->chip_name)
                return -ENOMEM;
        return 0;
 }
@@ -848,7 +866,8 @@ static void snd_hda_codec_free(struct hda_codec *codec)
        module_put(codec->owner);
        free_hda_cache(&codec->amp_cache);
        free_hda_cache(&codec->cmd_cache);
-       kfree(codec->name);
+       kfree(codec->vendor_name);
+       kfree(codec->chip_name);
        kfree(codec->modelname);
        kfree(codec->wcaps);
        kfree(codec);
@@ -989,15 +1008,16 @@ int snd_hda_codec_configure(struct hda_codec *codec)
        int err;
 
        codec->preset = find_codec_preset(codec);
-       if (!codec->name) {
+       if (!codec->vendor_name || !codec->chip_name) {
                err = get_codec_name(codec);
                if (err < 0)
                        return err;
        }
        /* audio codec should override the mixer name */
        if (codec->afg || !*codec->bus->card->mixername)
-               strlcpy(codec->bus->card->mixername, codec->name,
-                       sizeof(codec->bus->card->mixername));
+               snprintf(codec->bus->card->mixername,
+                        sizeof(codec->bus->card->mixername),
+                        "%s %s", codec->vendor_name, codec->chip_name);
 
        if (is_generic_config(codec)) {
                err = snd_hda_parse_generic_codec(codec);
@@ -2269,28 +2289,22 @@ EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls);
 int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
                              int direct, unsigned int verb, unsigned int parm)
 {
-       struct hda_bus *bus = codec->bus;
-       unsigned int res;
-       int err;
+       int err = snd_hda_codec_write(codec, nid, direct, verb, parm);
+       struct hda_cache_head *c;
+       u32 key;
 
-       res = make_codec_cmd(codec, nid, direct, verb, parm);
-       snd_hda_power_up(codec);
-       mutex_lock(&bus->cmd_mutex);
-       err = bus->ops.command(bus, res);
-       if (!err) {
-               struct hda_cache_head *c;
-               u32 key;
-               /* parm may contain the verb stuff for get/set amp */
-               verb = verb | (parm >> 8);
-               parm &= 0xff;
-               key = build_cmd_cache_key(nid, verb);
-               c = get_alloc_hash(&codec->cmd_cache, key);
-               if (c)
-                       c->val = parm;
-       }
-       mutex_unlock(&bus->cmd_mutex);
-       snd_hda_power_down(codec);
-       return err;
+       if (err < 0)
+               return err;
+       /* parm may contain the verb stuff for get/set amp */
+       verb = verb | (parm >> 8);
+       parm &= 0xff;
+       key = build_cmd_cache_key(nid, verb);
+       mutex_lock(&codec->bus->cmd_mutex);
+       c = get_alloc_hash(&codec->cmd_cache, key);
+       if (c)
+               c->val = parm;
+       mutex_unlock(&codec->bus->cmd_mutex);
+       return 0;
 }
 EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache);
 
@@ -3873,11 +3887,10 @@ EXPORT_SYMBOL_HDA(auto_pin_cfg_labels);
 /**
  * snd_hda_suspend - suspend the codecs
  * @bus: the HDA bus
- * @state: suspsend state
  *
  * Returns 0 if successful.
  */
-int snd_hda_suspend(struct hda_bus *bus, pm_message_t state)
+int snd_hda_suspend(struct hda_bus *bus)
 {
        struct hda_codec *codec;