Subject: Re: kern/34071: azalia device driver doesn't support pin sensing
To: None <kent@NetBSD.org, gnats-admin@netbsd.org, netbsd-bugs@netbsd.org,>
From: TAMURA Kent <kent@NetBSD.org>
List: netbsd-bugs
Date: 02/05/2007 14:40:02
The following reply was made to PR kern/34071; it has been noted by GNATS.

From: "TAMURA Kent" <kent@NetBSD.org>
To: "Berndt Josef Wulf" <wulf@ping.net.au>
Cc: gnats-bugs@netbsd.org
Subject: Re: kern/34071: azalia device driver doesn't support pin sensing
Date: Mon, 5 Feb 2007 23:35:51 +0900

 Could you test the following patch and tell me the name of
 the machine or mainboard?
 
 ----------------------------------------------------------------
 Index: azalia_codec.c
 ===================================================================
 RCS file: /cvsroot/src/sys/dev/pci/azalia_codec.c,v
 retrieving revision 1.28
 diff -u -r1.28 azalia_codec.c
 --- azalia_codec.c	6 Jan 2007 18:35:35 -0000	1.28
 +++ azalia_codec.c	5 Feb 2007 14:32:42 -0000
 @@ -123,6 +123,9 @@
  static int	stac9221_init_dacgroup(codec_t *);
  static int	stac9221_mixer_init(codec_t *);
  static int	stac9220_mixer_init(codec_t *);
 +static int	stac9220_set_port(codec_t *, mixer_ctrl_t *);
 +static int	stac9220_get_port(codec_t *, mixer_ctrl_t *);
 +static int	stac9220_unsol_event(codec_t *, int);
 
 
  int
 @@ -190,6 +193,9 @@
  	case 0x83847690:
  		this->name = "Sigmatel STAC9220";
  		this->mixer_init = stac9220_mixer_init;
 +		this->set_port = stac9220_set_port;
 +		this->unsol_event = stac9220_unsol_event;
 +		extra_size = 1;
  		break;
  	}
  	if (extra_size > 0) {
 @@ -2606,6 +2612,7 @@
  stac9220_mixer_init(codec_t *this)
  {
  	mixer_ctrl_t mc;
 +	uint32_t value;
 
  	this->nmixers = sizeof(stac9220_mixer_items) / sizeof(mixer_item_t);
  	this->mixers = malloc(sizeof(mixer_item_t) * this->nmixers,
 @@ -2633,7 +2640,104 @@
  	mc.un.value.level[1] = mc.un.value.level[0];
  	generic_mixer_set(this, 0x0c, MI_TARGET_OUTAMP, &mc);
 
 +#define STAC9220_XXX_ID		0x01cd1028
 +#define STAC9220_EVENT_HP	0
 +#define STAC9220_EXTRA_MASTER	0
 +#define STAC9220_NID_MASTER	0x0b
 +#define STAC9220_NID_HP		0x0d
 +	if (this->subid == STAC9220_XXX_ID) {
 +		/* setup a unsolicited event for the headphones */
 +		this->comresp(this, STAC9220_NID_HP, CORB_SET_UNSOLICITED_RESPONSE,
 +		    CORB_UNSOL_ENABLE | STAC9220_EVENT_HP, NULL);
 +		this->extra[STAC9220_EXTRA_MASTER] = 0; /* unmute */
 +		/* If the headphone presents, mute the internal speaker */
 +		this->comresp(this, STAC9220_NID_HP, CORB_GET_PIN_SENSE, 0, &value);
 +		mc.un.ord = value & CORB_PS_PRESENSE ? 1 : 0;
 +		generic_mixer_set(this, STAC9220_NID_MASTER, MI_TARGET_OUTAMP, &mc);
 +		this->get_port = stac9220_get_port;
 +	}
 +	return 0;
 +}
 +
 +static int
 +stac9220_set_port(codec_t *this, mixer_ctrl_t *mc)
 +{
 +	const mixer_item_t *m;
 +	uint32_t value;
 +	int err;
 +
 +	if (mc->dev >= this->nmixers)
 +		return ENXIO;
 +	m = &this->mixers[mc->dev];
 +	if (mc->type != m->devinfo.type)
 +		return EINVAL;
 +	if (mc->type == AUDIO_MIXER_CLASS)
 +		return 0;
 +	if (this->subid == STAC9220_XXX_ID && m->nid == STAC9220_NID_MASTER &&
 +		   m->target == MI_TARGET_OUTAMP && mc->type == AUDIO_MIXER_ENUM) {
 +		if (mc->un.ord != 0 && mc->un.ord != 1)
 +			return EINVAL;
 +		this->extra[STAC9220_EXTRA_MASTER] = mc->un.ord;
 +		err = this->comresp(this, STAC9220_NID_HP,
 +		    CORB_GET_PIN_SENSE, 0, &value);
 +		if (err)
 +			return err;
 +		if (!(value & CORB_PS_PRESENSE)) {
 +			return generic_mixer_set(this, m->nid, m->target, mc);
 +		}
 +		return 0;
 +	}
 +	return generic_mixer_set(this, m->nid, m->target, mc);
 +}
 +
 +static int
 +stac9220_get_port(codec_t *this, mixer_ctrl_t *mc)
 +{
 +	const mixer_item_t *m;
 +
 +	if (mc->dev >= this->nmixers)
 +		return ENXIO;
 +	m = &this->mixers[mc->dev];
 +	mc->type = m->devinfo.type;
 +	if (mc->type == AUDIO_MIXER_CLASS)
 +		return 0;
 +	if (this->subid == STAC9220_XXX_ID && m->nid == STAC9220_NID_MASTER &&
 +	    m->target == MI_TARGET_OUTAMP && mc->type == AUDIO_MIXER_ENUM) {
 +		mc->un.ord = this->extra[STAC9220_EXTRA_MASTER];
 +		return 0;
 +	}
 +	return generic_mixer_get(this, m->nid, m->target, mc);
 +}
 +
 +static int
 +stac9220_unsol_event(codec_t *this, int tag)
 +{
 +	int err;
 +	uint32_t value;
 +	mixer_ctrl_t mc;
 +
 +	switch (tag) {
 +	case STAC9220_EVENT_HP:
 +		err = this->comresp(this, STAC9220_NID_HP,
 +		    CORB_GET_PIN_SENSE, 0, &value);
 +		if (err)
 +			break;
 +		mc.dev = -1;
 +		mc.type = AUDIO_MIXER_ENUM;
 +		if (value & CORB_PS_PRESENSE) {
 +			DPRINTF(("%s: headphone has been inserted.\n", __func__));
 +			mc.un.ord = 1; /* mute */
 +			generic_mixer_set(this, STAC9220_NID_MASTER,
 +			    MI_TARGET_OUTAMP, &mc);
 +		} else {
 +			DPRINTF(("%s: headphone has been pulled out.\n", __func__));
 +			mc.un.ord = this->extra[ALC260_EXTRA_MASTER];
 +			generic_mixer_set(this, STAC9220_NID_MASTER,
 +			    MI_TARGET_OUTAMP, &mc);
 +		}
 +		break;
 +	default:
 +		printf("%s: unknown tag: %d\n", __func__, tag);
 +	}
  	return 0;
  }
 ----------------------------------------------------------------
 -- 
 TAMURA Kent <kent_2007 at hauN.org> <kent at NetBSD.org>