#include "hda_patch.h"
 #include "hda_beep.h"
 
-#define STAC_VREF_EVENT                0x00
-#define STAC_INSERT_EVENT      0x10
-#define STAC_PWR_EVENT         0x20
-#define STAC_HP_EVENT          0x30
+enum {
+       STAC_VREF_EVENT = 1,
+       STAC_INSERT_EVENT,
+       STAC_PWR_EVENT,
+       STAC_HP_EVENT,
+};
 
 enum {
        STAC_REF,
 
 struct sigmatel_event {
        hda_nid_t nid;
+       unsigned char type;
+       unsigned char tag;
        int data;
 };
 
        return 0;
 }
 
+static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid,
+                                  unsigned char type);
+
 static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
                        struct snd_ctl_elem_value *ucontrol)
 {
        /* check to be sure that the ports are upto date with
         * switch changes
         */
-       codec->patch_ops.unsol_event(codec, (STAC_HP_EVENT | nid) << 26);
+       stac_issue_unsol_event(codec, nid, STAC_HP_EVENT);
 
        return 1;
 }
         * appropriately according to the pin direction
         */
        if (spec->hp_detect)
-               codec->patch_ops.unsol_event(codec,
-                       (STAC_HP_EVENT | nid) << 26);
+               stac_issue_unsol_event(codec, nid, STAC_HP_EVENT);
 
         return 1;
 }
 #endif
 }
 
-static int stac92xx_add_event(struct sigmatel_spec *spec, hda_nid_t nid,
-                            int data)
+static int stac_add_event(struct sigmatel_spec *spec, hda_nid_t nid,
+                         unsigned char type, int data)
 {
        struct sigmatel_event *event;
 
        if (!event)
                return -ENOMEM;
        event->nid = nid;
+       event->type = type;
+       event->tag = spec->events.used;
        event->data = data;
 
-       return 0;
+       return event->tag;
 }
 
-static int stac92xx_event_data(struct hda_codec *codec, hda_nid_t nid)
+static struct sigmatel_event *stac_get_event(struct hda_codec *codec,
+                                            hda_nid_t nid, unsigned char type)
 {
        struct sigmatel_spec *spec = codec->spec;
-       struct sigmatel_event *events = spec->events.list;
-       if (events) {
-               int i;
-               for (i = 0; i < spec->events.used; i++)
-                       if (events[i].nid == nid)
-                               return events[i].data;
+       struct sigmatel_event *event = spec->events.list;
+       int i;
+
+       for (i = 0; i < spec->events.used; i++, event++) {
+               if (event->nid == nid && event->type == type)
+                       return event;
        }
-       return 0;
+       return NULL;
 }
 
-static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
-                             unsigned int event)
+static struct sigmatel_event *stac_get_event_from_tag(struct hda_codec *codec,
+                                                     unsigned char tag)
 {
-       if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
-               snd_hda_codec_write_cache(codec, nid, 0,
-                                         AC_VERB_SET_UNSOLICITED_ENABLE,
-                                         (AC_USRSP_EN | event | nid));
+       struct sigmatel_spec *spec = codec->spec;
+       struct sigmatel_event *event = spec->events.list;
+       int i;
+
+       for (i = 0; i < spec->events.used; i++, event++) {
+               if (event->tag == tag)
+                       return event;
        }
+       return NULL;
+}
+
+static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
+                             unsigned int type)
+{
+       struct sigmatel_event *event;
+       int tag;
+
+       if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP))
+               return;
+       event = stac_get_event(codec, nid, type);
+       if (event)
+               tag = event->tag;
+       else
+               tag = stac_add_event(codec->spec, nid, type, 0);
+       if (tag < 0)
+               return;
+       snd_hda_codec_write_cache(codec, nid, 0,
+                                 AC_VERB_SET_UNSOLICITED_ENABLE,
+                                 AC_USRSP_EN | tag);
 }
 
 static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
                /* Enable unsolicited responses on the HP widget */
                for (i = 0; i < cfg->hp_outs; i++) {
                        hda_nid_t nid = cfg->hp_pins[i];
-                       enable_pin_detect(codec, nid, STAC_HP_EVENT | nid);
+                       enable_pin_detect(codec, nid, STAC_HP_EVENT);
                }
                /* force to enable the first line-out; the others are set up
                 * in unsol_event
                stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
                                AC_PINCTL_OUT_EN);
                /* fake event to set up pins */
-               codec->patch_ops.unsol_event(codec,
-                       (STAC_HP_EVENT | spec->autocfg.hp_pins[0]) << 26);
+               stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0],
+                                      STAC_HP_EVENT);
        } else {
                stac92xx_auto_init_multi_out(codec);
                stac92xx_auto_init_hp_out(codec);
                        }
                        pinctl |= AC_PINCTL_IN_EN;
                        stac92xx_auto_set_pinctl(codec, nid, pinctl);
-                       enable_pin_detect(codec, nid, STAC_INSERT_EVENT | nid);
+                       enable_pin_detect(codec, nid, STAC_INSERT_EVENT);
                }
        }
        for (i = 0; i < spec->num_dmics; i++)
        for (i = 0; i < spec->num_pwrs; i++)  {
                hda_nid_t nid = spec->pwr_nids[i];
                int pinctl, def_conf;
-               int event = STAC_PWR_EVENT;
 
                if (is_nid_hp_pin(cfg, nid) && spec->hp_detect)
                        continue; /* already has an unsol event */
                                stac_toggle_power_map(codec, nid, 1);
                        continue;
                }
-               enable_pin_detect(codec, spec->pwr_nids[i], event | i);
-               codec->patch_ops.unsol_event(codec, (event | i) << 26);
+               enable_pin_detect(codec, nid, STAC_PWR_EVENT);
+               stac_issue_unsol_event(codec, nid, STAC_PWR_EVENT);
        }
        if (spec->dac_list)
                stac92xx_power_down(codec);
        return 0;
 }
 
-static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
+static void stac92xx_hp_detect(struct hda_codec *codec)
 {
        struct sigmatel_spec *spec = codec->spec;
        struct auto_pin_cfg *cfg = &spec->autocfg;
        }
 }
 
+static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid,
+                                  unsigned char type)
+{
+       struct sigmatel_event *event = stac_get_event(codec, nid, type);
+       if (!event)
+               return;
+       codec->patch_ops.unsol_event(codec, (unsigned)event->tag << 26);
+}
+
 static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
 {
        struct sigmatel_spec *spec = codec->spec;
-       int event = (res >> 26) & 0x70;
-       int nid = res >> 26 & 0x0f;
+       struct sigmatel_event *event;
+       int tag, data;
 
-       switch (event) {
+       tag = (res >> 26) & 0x7f;
+       event = stac_get_event_from_tag(codec, tag);
+       if (!event)
+               return;
+
+       switch (event->type) {
        case STAC_HP_EVENT:
-               stac92xx_hp_detect(codec, res);
+               stac92xx_hp_detect(codec);
                /* fallthru */
        case STAC_INSERT_EVENT:
        case STAC_PWR_EVENT:
-               if (nid) {
-                       if (spec->num_pwrs > 0)
-                               stac92xx_pin_sense(codec, nid);
-                       stac92xx_report_jack(codec, nid);
-               }
+               if (spec->num_pwrs > 0)
+                       stac92xx_pin_sense(codec, event->nid);
+               stac92xx_report_jack(codec, event->nid);
                break;
-       case STAC_VREF_EVENT: {
-               int data = snd_hda_codec_read(codec, codec->afg, 0,
-                       AC_VERB_GET_GPIO_DATA, 0);
-               int idx = stac92xx_event_data(codec, nid);
+       case STAC_VREF_EVENT:
+               data = snd_hda_codec_read(codec, codec->afg, 0,
+                                         AC_VERB_GET_GPIO_DATA, 0);
                /* toggle VREF state based on GPIOx status */
                snd_hda_codec_write(codec, codec->afg, 0, 0x7e0,
-                       !!(data & (1 << idx)));
+                                   !!(data & (1 << event->data)));
                break;
-               }
        }
 }
 
        snd_hda_codec_resume_cache(codec);
        /* fake event to set up pins again to override cached values */
        if (spec->hp_detect)
-               codec->patch_ops.unsol_event(codec,
-                       (STAC_HP_EVENT | spec->autocfg.hp_pins[0]) << 26);
+               stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0],
+                                      STAC_HP_EVENT);
        return 0;
 }
 
                switch (spec->board_config) {
                case STAC_HP_M4:
                        /* Enable VREF power saving on GPIO1 detect */
+                       err = stac_add_event(spec, codec->afg,
+                                            STAC_VREF_EVENT, 0x02);
+                       if (err < 0)
+                               return err;
                        snd_hda_codec_write_cache(codec, codec->afg, 0,
                                AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02);
                        snd_hda_codec_write_cache(codec, codec->afg, 0,
                                AC_VERB_SET_UNSOLICITED_ENABLE,
-                               (AC_USRSP_EN | STAC_VREF_EVENT | codec->afg));
-                       err = stac92xx_add_event(spec, codec->afg, 0x02);
-                       if (err < 0)
-                               return err;
+                               AC_USRSP_EN | err);
                        spec->gpio_mask |= 0x02;
                        break;
                }
                stac_change_pin_config(codec, 0x20, 0x1c410030);
 
                /* Enable unsol response for GPIO4/Dock HP connection */
+               err = stac_add_event(spec, codec->afg, STAC_VREF_EVENT, 0x01);
+               if (err < 0)
+                       return err;
                snd_hda_codec_write_cache(codec, codec->afg, 0,
                        AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
                snd_hda_codec_write_cache(codec, codec->afg, 0,
-                       AC_VERB_SET_UNSOLICITED_ENABLE,
-                       (AC_USRSP_EN | STAC_VREF_EVENT | codec->afg));
-               err = stac92xx_add_event(spec, codec->afg, 0x01);
-               if (err < 0)
-                       return err;
+                                         AC_VERB_SET_UNSOLICITED_ENABLE,
+                                         AC_USRSP_EN | err);
 
                spec->gpio_dir = 0x0b;
                spec->eapd_mask = 0x01;