+static struct work_struct device_change;
+static struct snd_pmac *device_change_chip;
+
+static void device_change_handler(struct work_struct *work)
+{
+ struct snd_pmac *chip = device_change_chip;
+ struct pmac_tumbler *mix;
+ int headphone, lineout;
+
+ if (!chip)
+ return;
+
+ mix = chip->mixer_data;
+ snd_assert(mix, return);
+
+ headphone = tumbler_detect_headphone(chip);
+ lineout = tumbler_detect_lineout(chip);
+
+ DBG("headphone: %d, lineout: %d\n", headphone, lineout);
+
+ if (headphone || lineout) {
+ /* unmute headphone/lineout & mute speaker */
+ if (headphone)
+ check_mute(chip, &mix->hp_mute, 0, mix->auto_mute_notify,
+ chip->master_sw_ctl);
+ if (lineout && mix->line_mute.addr != 0)
+ check_mute(chip, &mix->line_mute, 0, mix->auto_mute_notify,
+ chip->lineout_sw_ctl);
+ if (mix->anded_reset)
+ msleep(10);
+ check_mute(chip, &mix->amp_mute, 1, mix->auto_mute_notify,
+ chip->speaker_sw_ctl);
+ } else {
+ /* unmute speaker, mute others */
+ check_mute(chip, &mix->amp_mute, 0, mix->auto_mute_notify,
+ chip->speaker_sw_ctl);
+ if (mix->anded_reset)
+ msleep(10);
+ check_mute(chip, &mix->hp_mute, 1, mix->auto_mute_notify,
+ chip->master_sw_ctl);
+ if (mix->line_mute.addr != 0)
+ check_mute(chip, &mix->line_mute, 1, mix->auto_mute_notify,
+ chip->lineout_sw_ctl);
+ }
+ if (mix->auto_mute_notify)
+ snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &chip->hp_detect_ctl->id);
+
+#ifdef CONFIG_SND_POWERMAC_AUTO_DRC
+ mix->drc_enable = ! (headphone || lineout);
+ if (mix->auto_mute_notify)
+ snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
+ &chip->drc_sw_ctl->id);
+ if (chip->model == PMAC_TUMBLER)
+ tumbler_set_drc(mix);
+ else
+ snapper_set_drc(mix);
+#endif
+
+ /* reset the master volume so the correct amplification is applied */
+ tumbler_set_master_volume(mix);
+}
+
+static void tumbler_update_automute(struct snd_pmac *chip, int do_notify)