Skip to content

Commit

Permalink
ALSA: hda - Make common input-jack helper functions
Browse files Browse the repository at this point in the history
Since multiple codec drivers already use the input-jack stuff, let's
make common helper functions to reduce the duplicated codes.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
  • Loading branch information
Takashi Iwai committed Mar 3, 2011
1 parent d207df2 commit cd372fb
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 272 deletions.
105 changes: 105 additions & 0 deletions sound/pci/hda/hda_codec.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <sound/asoundef.h>
#include <sound/tlv.h>
#include <sound/initval.h>
#include <sound/jack.h>
#include "hda_local.h"
#include "hda_beep.h"
#include <sound/hda_hwdep.h>
Expand Down Expand Up @@ -4959,5 +4960,109 @@ void snd_print_pcm_bits(int pcm, char *buf, int buflen)
}
EXPORT_SYMBOL_HDA(snd_print_pcm_bits);

#ifdef CONFIG_SND_HDA_INPUT_JACK
/*
* Input-jack notification support
*/
struct hda_jack_item {
hda_nid_t nid;
int type;
struct snd_jack *jack;
};

static const char *get_jack_default_name(struct hda_codec *codec, hda_nid_t nid,
int type)
{
switch (type) {
case SND_JACK_HEADPHONE:
return "Headphone";
case SND_JACK_MICROPHONE:
return "Mic";
case SND_JACK_LINEOUT:
return "Line-out";
case SND_JACK_HEADSET:
return "Headset";
default:
return "Misc";
}
}

static void hda_free_jack_priv(struct snd_jack *jack)
{
struct hda_jack_item *jacks = jack->private_data;
jacks->nid = 0;
jacks->jack = NULL;
}

int snd_hda_input_jack_add(struct hda_codec *codec, hda_nid_t nid, int type,
const char *name)
{
struct hda_jack_item *jack;
int err;

snd_array_init(&codec->jacks, sizeof(*jack), 32);
jack = snd_array_new(&codec->jacks);
if (!jack)
return -ENOMEM;

jack->nid = nid;
jack->type = type;
if (!name)
name = get_jack_default_name(codec, nid, type);
err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
if (err < 0) {
jack->nid = 0;
return err;
}
jack->jack->private_data = jack;
jack->jack->private_free = hda_free_jack_priv;
return 0;
}
EXPORT_SYMBOL_HDA(snd_hda_input_jack_add);

void snd_hda_input_jack_report(struct hda_codec *codec, hda_nid_t nid)
{
struct hda_jack_item *jacks = codec->jacks.list;
int i;

if (!jacks)
return;

for (i = 0; i < codec->jacks.used; i++, jacks++) {
unsigned int pin_ctl;
unsigned int present;
int type;

if (jacks->nid != nid)
continue;
present = snd_hda_jack_detect(codec, nid);
type = jacks->type;
if (type == (SND_JACK_HEADPHONE | SND_JACK_LINEOUT)) {
pin_ctl = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
type = (pin_ctl & AC_PINCTL_HP_EN) ?
SND_JACK_HEADPHONE : SND_JACK_LINEOUT;
}
snd_jack_report(jacks->jack, present ? type : 0);
}
}
EXPORT_SYMBOL_HDA(snd_hda_input_jack_report);

/* free jack instances manually when clearing/reconfiguring */
void snd_hda_input_jack_free(struct hda_codec *codec)
{
if (!codec->bus->shutdown && codec->jacks.list) {
struct hda_jack_item *jacks = codec->jacks.list;
int i;
for (i = 0; i < codec->jacks.used; i++, jacks++) {
if (jacks->jack)
snd_device_free(codec->bus->card, jacks->jack);
}
}
snd_array_free(&codec->jacks);
}
EXPORT_SYMBOL_HDA(snd_hda_input_jack_free);
#endif /* CONFIG_SND_HDA_INPUT_JACK */

MODULE_DESCRIPTION("HDA codec core");
MODULE_LICENSE("GPL");
5 changes: 5 additions & 0 deletions sound/pci/hda/hda_codec.h
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,11 @@ struct hda_codec {
/* codec-specific additional proc output */
void (*proc_widget_hook)(struct snd_info_buffer *buffer,
struct hda_codec *codec, hda_nid_t nid);

#ifdef CONFIG_SND_HDA_INPUT_JACK
/* jack detection */
struct snd_array jacks;
#endif
};

/* direction */
Expand Down
24 changes: 24 additions & 0 deletions sound/pci/hda/hda_local.h
Original file line number Diff line number Diff line change
Expand Up @@ -656,4 +656,28 @@ static inline void snd_hda_eld_proc_free(struct hda_codec *codec,
#define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80
void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen);

/*
* Input-jack notification support
*/
#ifdef CONFIG_SND_HDA_INPUT_JACK
int snd_hda_input_jack_add(struct hda_codec *codec, hda_nid_t nid, int type,
const char *name);
void snd_hda_input_jack_report(struct hda_codec *codec, hda_nid_t nid);
void snd_hda_input_jack_free(struct hda_codec *codec);
#else /* CONFIG_SND_HDA_INPUT_JACK */
static inline int snd_hda_input_jack_add(struct hda_codec *codec,
hda_nid_t nid, int type,
const char *name)
{
return 0;
}
static inline void snd_hda_input_jack_report(struct hda_codec *codec,
hda_nid_t nid)
{
}
static inline void snd_hda_input_jack_free(struct hda_codec *codec)
{
}
#endif /* CONFIG_SND_HDA_INPUT_JACK */

#endif /* __SOUND_HDA_LOCAL_H */
124 changes: 14 additions & 110 deletions sound/pci/hda/patch_conexant.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,6 @@
#define AUTO_MIC_PORTB (1 << 1)
#define AUTO_MIC_PORTC (1 << 2)

struct conexant_jack {

hda_nid_t nid;
int type;
struct snd_jack *jack;

};

struct pin_dac_pair {
hda_nid_t pin;
hda_nid_t dac;
Expand Down Expand Up @@ -111,9 +103,6 @@ struct conexant_spec {

unsigned int spdif_route;

/* jack detection */
struct snd_array jacks;

/* dynamic controls, init_verbs and input_mux */
struct auto_pin_cfg autocfg;
struct hda_input_mux private_imux;
Expand Down Expand Up @@ -393,71 +382,9 @@ static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol,
&spec->cur_mux[adc_idx]);
}

#ifdef CONFIG_SND_HDA_INPUT_JACK
static void conexant_free_jack_priv(struct snd_jack *jack)
{
struct conexant_jack *jacks = jack->private_data;
jacks->nid = 0;
jacks->jack = NULL;
}

static int conexant_add_jack(struct hda_codec *codec,
hda_nid_t nid, int type)
{
struct conexant_spec *spec;
struct conexant_jack *jack;
const char *name;
int i, err;

spec = codec->spec;
snd_array_init(&spec->jacks, sizeof(*jack), 32);

jack = spec->jacks.list;
for (i = 0; i < spec->jacks.used; i++, jack++)
if (jack->nid == nid)
return 0 ; /* already present */

jack = snd_array_new(&spec->jacks);
name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ;

if (!jack)
return -ENOMEM;

jack->nid = nid;
jack->type = type;

err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
if (err < 0)
return err;
jack->jack->private_data = jack;
jack->jack->private_free = conexant_free_jack_priv;
return 0;
}

static void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid)
{
struct conexant_spec *spec = codec->spec;
struct conexant_jack *jacks = spec->jacks.list;

if (jacks) {
int i;
for (i = 0; i < spec->jacks.used; i++) {
if (jacks->nid == nid) {
unsigned int present;
present = snd_hda_jack_detect(codec, nid);

present = (present) ? jacks->type : 0 ;

snd_jack_report(jacks->jack,
present);
}
jacks++;
}
}
}

static int conexant_init_jacks(struct hda_codec *codec)
{
#ifdef CONFIG_SND_HDA_INPUT_JACK
struct conexant_spec *spec = codec->spec;
int i;

Expand All @@ -469,35 +396,25 @@ static int conexant_init_jacks(struct hda_codec *codec)
int err = 0;
switch (hv->param ^ AC_USRSP_EN) {
case CONEXANT_HP_EVENT:
err = conexant_add_jack(codec, hv->nid,
SND_JACK_HEADPHONE);
conexant_report_jack(codec, hv->nid);
err = snd_hda_input_jack_add(codec, hv->nid,
SND_JACK_HEADPHONE, NULL);
snd_hda_input_jack_report(codec, hv->nid);
break;
case CXT5051_PORTC_EVENT:
case CONEXANT_MIC_EVENT:
err = conexant_add_jack(codec, hv->nid,
SND_JACK_MICROPHONE);
conexant_report_jack(codec, hv->nid);
err = snd_hda_input_jack_add(codec, hv->nid,
SND_JACK_MICROPHONE, NULL);
snd_hda_input_jack_report(codec, hv->nid);
break;
}
if (err < 0)
return err;
++hv;
}
}
return 0;

}
#else
static inline void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid)
{
}

static inline int conexant_init_jacks(struct hda_codec *codec)
{
#endif /* CONFIG_SND_HDA_INPUT_JACK */
return 0;
}
#endif

static int conexant_init(struct hda_codec *codec)
{
Expand All @@ -511,18 +428,7 @@ static int conexant_init(struct hda_codec *codec)

static void conexant_free(struct hda_codec *codec)
{
#ifdef CONFIG_SND_HDA_INPUT_JACK
struct conexant_spec *spec = codec->spec;
if (spec->jacks.list) {
struct conexant_jack *jacks = spec->jacks.list;
int i;
for (i = 0; i < spec->jacks.used; i++, jacks++) {
if (jacks->jack)
snd_device_free(codec->bus->card, jacks->jack);
}
snd_array_free(&spec->jacks);
}
#endif
snd_hda_input_jack_free(codec);
snd_hda_detach_beep_device(codec);
kfree(codec->spec);
}
Expand Down Expand Up @@ -1787,7 +1693,7 @@ static void cxt5051_hp_unsol_event(struct hda_codec *codec,
cxt5051_portc_automic(codec);
break;
}
conexant_report_jack(codec, nid);
snd_hda_input_jack_report(codec, nid);
}

static struct snd_kcontrol_new cxt5051_playback_mixers[] = {
Expand Down Expand Up @@ -1959,10 +1865,8 @@ static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid,
snd_hda_codec_write(codec, nid, 0,
AC_VERB_SET_UNSOLICITED_ENABLE,
AC_USRSP_EN | event);
#ifdef CONFIG_SND_HDA_INPUT_JACK
conexant_add_jack(codec, nid, SND_JACK_MICROPHONE);
conexant_report_jack(codec, nid);
#endif
snd_hda_input_jack_add(codec, nid, SND_JACK_MICROPHONE, NULL);
snd_hda_input_jack_report(codec, nid);
}

static struct hda_verb cxt5051_ideapad_init_verbs[] = {
Expand Down Expand Up @@ -3477,11 +3381,11 @@ static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
switch (res >> 26) {
case CONEXANT_HP_EVENT:
cx_auto_hp_automute(codec);
conexant_report_jack(codec, nid);
snd_hda_input_jack_report(codec, nid);
break;
case CONEXANT_MIC_EVENT:
cx_auto_automic(codec);
conexant_report_jack(codec, nid);
snd_hda_input_jack_report(codec, nid);
break;
}
}
Expand Down
Loading

0 comments on commit cd372fb

Please sign in to comment.