VT1708 HW doesn't support unsolicited response, so we polling with jack detect function instead. As you describe, we implement it with self-reschedule workqueue, acting like a timer. Is there some advice to implement timer-like task, I tested with timer and it will crash the driver. On Mon, Oct 5, 2009 at 11:12 PM, Takashi Iwai <tiwai@xxxxxxx> wrote: > At Mon, 5 Oct 2009 22:27:20 +0800, > Li Bo wrote: >> >> [ALSA] HDA VIA: Add Jack detect feature for VT1708. > > Why is it needed? Isn't the unsolicited event handled properly at > HP plugging? > > Also, this implementation doesn't look good. If I understand > correctly, it invokes a workqueue which re-schedules itself at each > 100ms... > > > Takashi > >> Signed-off-by: Lydia Wang <lydiawang@xxxxxxxxxxxxxx> >> >> Index: sound-2.6/sound/pci/hda/patch_via.c >> =================================================================== >> --- sound-2.6.orig/sound/pci/hda/patch_via.c 2009-10-05 15:10:22.000000000 +0800 >> +++ sound-2.6/sound/pci/hda/patch_via.c 2009-10-05 15:10:36.000000000 +0800 >> @@ -257,6 +257,11 @@ >> unsigned int smart51_enabled; >> enum VIA_HDA_CODEC codec_type; >> >> + /* work to check hp jack state */ >> + struct hda_codec *codec; >> + struct delayed_work hp_jack_work; >> + int vt1708_jack_detectect; >> + >> #ifdef CONFIG_SND_HDA_POWER_SAVE >> struct hda_loopback_check loopback; >> #endif >> @@ -966,6 +971,8 @@ >> {0x20, AC_VERB_SET_CONNECT_SEL, 0x1}, >> /* PW9 Output enable */ >> {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, >> + /* power down jack detect function */ >> + {0x1, 0xf81, 0x1}, >> { } >> }; >> >> @@ -1340,6 +1347,10 @@ >> return; >> >> via_free_kctls(codec); >> + if (spec->codec_type == VT1708) { >> + cancel_delayed_work(&spec->hp_jack_work); >> + flush_scheduled_work(); >> + } >> kfree(codec->spec); >> } >> >> @@ -1724,6 +1735,52 @@ >> return; >> } >> >> +static int vt1708_jack_detectect_get(struct snd_kcontrol *kcontrol, >> + struct snd_ctl_elem_value *ucontrol) >> +{ >> + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); >> + struct via_spec *spec = codec->spec; >> + >> + if (spec->codec_type != VT1708) >> + return 0; >> + spec->vt1708_jack_detectect = >> + !((snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8) & 0x1); >> + ucontrol->value.integer.value[0] = spec->vt1708_jack_detectect; >> + return 0; >> +} >> + >> +static int vt1708_jack_detectect_put(struct snd_kcontrol *kcontrol, >> + struct snd_ctl_elem_value *ucontrol) >> +{ >> + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); >> + struct via_spec *spec = codec->spec; >> + int change; >> + >> + if (spec->codec_type != VT1708) >> + return 0; >> + spec->vt1708_jack_detectect = ucontrol->value.integer.value[0]; >> + snd_hda_codec_write(codec, 0x1, 0, 0xf81, !spec->vt1708_jack_detectect); >> + change = (0x1 & (snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8)) >> + == !spec->vt1708_jack_detectect; >> + if (spec->vt1708_jack_detectect) { >> + mute_aa_path(codec, 1); >> + notify_aa_path_ctls(codec); >> + } >> + return change; >> +} >> + >> +static struct snd_kcontrol_new vt1708_jack_detectect[] = { >> + { >> + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, >> + .name = "Jack Detect", >> + .count = 1, >> + .info = snd_ctl_boolean_mono_info, >> + .get = vt1708_jack_detectect_get, >> + .put = vt1708_jack_detectect_put, >> + }, >> + {} /* end */ >> +}; >> + >> static int vt1708_parse_auto_config(struct hda_codec *codec) >> { >> struct via_spec *spec = codec->spec; >> @@ -1751,6 +1808,10 @@ >> err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg); >> if (err < 0) >> return err; >> + /* add jack detect on/off control */ >> + err = snd_hda_add_new_ctls(codec, vt1708_jack_detectect); >> + if (err < 0) >> + return err; >> >> spec->multiout.max_channels = spec->multiout.num_dacs * 2; >> >> @@ -1784,6 +1845,24 @@ >> return 0; >> } >> >> +static void update_hp_jack_state(struct work_struct *work) >> +{ >> + struct via_spec *spec = container_of(work, struct via_spec, >> + hp_jack_work.work); >> + static int present = 1; >> + >> + if (spec->codec_type != VT1708) >> + return; >> + /* if jack state toggled */ >> + if (present >> + != (snd_hda_codec_read(spec->codec, spec->autocfg.hp_pins[0], 0, >> + AC_VERB_GET_PIN_SENSE, 0) >> 31)) { >> + present ^= 1; >> + via_hp_automute(spec->codec); >> + } >> + schedule_delayed_work(&spec->hp_jack_work, msecs_to_jiffies(100)); >> +} >> + >> static int get_mux_nids(struct hda_codec *codec) >> { >> struct via_spec *spec = codec->spec; >> @@ -1860,7 +1939,9 @@ >> #ifdef CONFIG_SND_HDA_POWER_SAVE >> spec->loopback.amplist = vt1708_loopbacks; >> #endif >> - >> + spec->codec = codec; >> + INIT_DELAYED_WORK(&spec->hp_jack_work, update_hp_jack_state); >> + schedule_delayed_work(&spec->hp_jack_work, msecs_to_jiffies(100)); >> return 0; >> } >> > _______________________________________________ Alsa-devel mailing list Alsa-devel@xxxxxxxxxxxxxxxx http://mailman.alsa-project.org/mailman/listinfo/alsa-devel