changeset 9842:333f65f565a1

6828784 Beep doesn't work for Opensolaris on DELL LATITUDE D630 6664842 Keyboard beep no longer working in Xorg 6821734 Toshiba M10 - random static pops when trying to play a beep
author lipeng sang - Sun Microsystems - Beijing China <Lipeng.Sang@Sun.COM>
date Thu, 11 Jun 2009 09:38:14 +0800
parents c7ecdbcb7950
children e1f475c3a5f6
files usr/src/uts/common/io/audio/drv/audiohd/audiohd.c usr/src/uts/common/io/audio/drv/audiohd/audiohd.conf usr/src/uts/common/io/audio/drv/audiohd/audiohd.h
diffstat 3 files changed, 571 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/io/audio/drv/audiohd/audiohd.c	Thu Jun 11 09:17:20 2009 +0800
+++ b/usr/src/uts/common/io/audio/drv/audiohd/audiohd.c	Thu Jun 11 09:38:14 2009 +0800
@@ -25,6 +25,7 @@
 
 #include <sys/audio/audio_driver.h>
 #include <sys/note.h>
+#include <sys/beep.h>
 #include <sys/pci.h>
 #include "audiohd.h"
 
@@ -77,6 +78,21 @@
 static void audiohd_init_path(audiohd_state_t *statep);
 static void audiohd_del_controls(audiohd_state_t *statep);
 static void audiohd_destroy(audiohd_state_t *statep);
+static void audiohd_beep_on(void *arg);
+static void audiohd_beep_off(void *arg);
+static void audiohd_beep_freq(void *arg, int freq);
+static wid_t audiohd_find_beep(hda_codec_t *codec, wid_t wid, int depth);
+static void audiohd_build_beep_path(hda_codec_t *codec);
+static void audiohd_build_beep_amp(hda_codec_t *codec);
+static void  audiohd_finish_beep_path(hda_codec_t *codec);
+static void audiohd_do_set_beep_volume(audiohd_state_t *statep,
+    audiohd_path_t *path, uint64_t val);
+static void audiohd_set_beep_volume(audiohd_state_t *statep);
+static int audiohd_set_beep(void *arg, uint64_t val);
+
+static	int	audiohd_beep;
+static	int	audiohd_beep_divider;
+static	int	audiohd_beep_vol = 1;
 
 static ddi_device_acc_attr_t hda_dev_accattr = {
 	DDI_DEVICE_ATTR_V0,
@@ -119,7 +135,8 @@
 	CTL_CD,
 	CTL_MONGAIN,
 	CTL_MONSRC,
-	CTL_RECSRC
+	CTL_RECSRC,
+	CTL_BEEP
 };
 
 static void
@@ -328,6 +345,24 @@
 	if (audio_dev_unregister(statep->adev) != DDI_SUCCESS)
 		return (DDI_FAILURE);
 
+	mutex_enter(&statep->hda_mutex);
+	audiohd_stop_dma(statep);
+	audiohd_disable_intr(statep);
+	mutex_exit(&statep->hda_mutex);
+	ddi_remove_intr(dip, 0, statep->hda_intr_cookie);
+	if (statep->hda_ksp)
+		kstat_delete(statep->hda_ksp);
+	audiohd_free_port(statep);
+	if (audiohd_beep)
+		(void) beep_fini();
+	audiohd_destroy_codec(statep);
+	audiohd_del_controls(statep);
+	audiohd_fini_controller(statep);
+	audiohd_fini_pci(statep);
+	mutex_destroy(&statep->hda_mutex);
+	if (statep->adev)
+		audio_dev_free(statep->adev);
+	kmem_free(statep, sizeof (*statep));
 	audiohd_destroy(statep);
 	return (DDI_SUCCESS);
 }
@@ -1292,6 +1327,119 @@
 }
 
 static void
+audiohd_set_beep_volume(audiohd_state_t *statep)
+{
+	int			i;
+	audiohd_path_t		*path;
+	hda_codec_t		*codec;
+	uint64_t		val;
+	uint_t			tmp;
+	audiohd_ctrl_t		*control;
+	uint32_t		vid;
+
+	control = statep->controls[CTL_BEEP];
+	if (control == NULL)
+		return;
+	val = control->val;
+	for (i = 0; i < statep->pathnum; i++) {
+		path = statep->path[i];
+		if (!path || path->path_type != BEEP)
+			continue;
+		codec = path->codec;
+		vid = codec->vid;
+		vid = vid >> 16;
+
+		switch (vid) {
+		case  AUDIOHD_VID_SIGMATEL:
+			/*
+			 * Sigmatel HD codec specific operation.
+			 * There is a workaround,
+			 * Due to Sigmatel HD codec hardware problem,
+			 * which it can't mute beep when volume is 0.
+			 * So add global value audiohd_beep_vol,
+			 * Set freq to 0 when volume is 0.
+			 */
+			tmp = val * path->gain_bits / 100;
+			if (tmp == 0) {
+				audiohd_beep_vol = 0;
+			} else {
+				audiohd_beep_vol = tmp;
+				(void) audioha_codec_verb_get(
+				    statep,
+				    codec->index,
+				    path->beep_wid,
+				    AUDIOHDC_VERB_SET_BEEP_VOL,
+				    tmp);
+			}
+			break;
+
+		default:
+			/* Common operation based on audiohd spec */
+			audiohd_do_set_beep_volume(statep, path, val);
+			break;
+		}
+	}
+}
+
+static void
+audiohd_do_set_beep_volume(audiohd_state_t *statep, audiohd_path_t *path,
+    uint64_t val)
+{
+	uint8_t		l, r;
+	uint_t		tmp;
+	int		gain;
+
+	if (val == 0) {
+		(void) audioha_codec_4bit_verb_get(
+		    statep,
+		    path->codec->index,
+		    path->mute_wid,
+		    AUDIOHDC_VERB_SET_AMP_MUTE,
+		    path->mute_dir |
+		    AUDIOHDC_AMP_SET_LNR |
+		    AUDIOHDC_AMP_SET_MUTE);
+		return;
+	}
+
+	r = (val & 0xff);
+	l = r;
+
+	tmp = l * path->gain_bits / 100;
+	(void) audioha_codec_4bit_verb_get(statep,
+	    path->codec->index,
+	    path->gain_wid,
+	    AUDIOHDC_VERB_SET_AMP_MUTE,
+	    AUDIOHDC_AMP_SET_LEFT | path->gain_dir |
+	    tmp);
+	tmp = r * path->gain_bits / 100;
+	(void) audioha_codec_4bit_verb_get(statep,
+	    path->codec->index,
+	    path->gain_wid,
+	    AUDIOHDC_VERB_SET_AMP_MUTE,
+	    AUDIOHDC_AMP_SET_RIGHT | path->gain_dir |
+	    tmp);
+	if (path->mute_wid != path->gain_wid) {
+		gain = AUDIOHDC_GAIN_MAX;
+		(void) audioha_codec_4bit_verb_get(
+		    statep,
+		    path->codec->index,
+		    path->mute_wid,
+		    AUDIOHDC_VERB_SET_AMP_MUTE,
+		    path->mute_dir |
+		    AUDIOHDC_AMP_SET_LEFT |
+		    gain);
+		(void) audioha_codec_4bit_verb_get(
+		    statep,
+		    path->codec->index,
+		    path->mute_wid,
+		    AUDIOHDC_VERB_SET_AMP_MUTE,
+		    path->mute_dir |
+		    AUDIOHDC_AMP_SET_RIGHT |
+		    gain);
+	}
+}
+
+static void
 audiohd_restore_volume(audiohd_state_t *statep)
 {
 	audiohd_set_pin_volume(statep, DTYPE_LINEOUT);
@@ -1591,6 +1739,25 @@
 	return (0);
 }
 
+static int
+audiohd_set_beep(void *arg, uint64_t val)
+{
+	audiohd_ctrl_t  *pc = arg;
+	audiohd_state_t *statep = pc->statep;
+
+	val &= 0xff;
+
+	if (val > 100)
+		return (EINVAL);
+
+	mutex_enter(&statep->hda_mutex);
+	pc->val = val;
+	audiohd_set_beep_volume(statep);
+	mutex_exit(&statep->hda_mutex);
+
+	return (0);
+}
+
 #define	PLAYCTL	(AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_PLAY)
 #define	RECCTL	(AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_REC)
 #define	MONCTL	(AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_MONITOR)
@@ -1598,6 +1765,7 @@
 #define	MONVOL	(MONCTL | AUDIO_CTRL_FLAG_MONVOL)
 #define	MAINVOL	(PLAYCTL | AUDIO_CTRL_FLAG_MAINVOL)
 #define	RECVOL	(RECCTL | AUDIO_CTRL_FLAG_RECVOL)
+#define	RWCTL	AUDIO_CTRL_FLAG_RW
 
 static audiohd_ctrl_t *
 audiohd_alloc_ctrl(audiohd_state_t *statep, uint32_t num, uint64_t val)
@@ -1732,6 +1900,15 @@
 		}
 		fn = audiohd_set_recsrc;
 		break;
+
+	case CTL_BEEP:
+		desc.acd_name = AUDIO_CTRL_ID_BEEP;
+		desc.acd_type =	AUDIO_CTRL_TYPE_MONO;
+		desc.acd_minvalue = 0;
+		desc.acd_maxvalue = 100;
+		desc.acd_flags = RWCTL;
+		fn = audiohd_set_beep;
+		break;
 	}
 
 	pc->val = val;
@@ -1811,6 +1988,15 @@
 		if (!path)
 			continue;
 		codec = path->codec;
+		if (path->path_type == BEEP) {
+			widget = codec->widget[path->beep_wid];
+			if (widget->type == WTYPE_BEEP &&
+			    path->gain_wid != 0) {
+				ADD_CTRL(CTL_BEEP, 0x4b4b);
+				break;
+			}
+		}
+
 		for (j = 0; j < path->pin_nums; j++) {
 			wid = path->pin_wid[j];
 			widget = codec->widget[wid];
@@ -1877,6 +2063,49 @@
 
 	return (DDI_SUCCESS);
 }
+
+static void
+audiohd_beep_on(void *arg)
+{
+	hda_codec_t *codec = ((audiohd_widget_t *)arg)->codec;
+	audiohd_state_t *statep = codec->soft_statep;
+	int caddr = codec->index;
+	wid_t wid = ((audiohd_widget_t *)arg)->wid_wid;
+
+	(void) audioha_codec_verb_get(statep, caddr, wid,
+	    AUDIOHDC_VERB_SET_BEEP_GEN, audiohd_beep_divider);
+}
+
+static void
+audiohd_beep_off(void *arg)
+{
+	hda_codec_t *codec = ((audiohd_widget_t *)arg)->codec;
+	audiohd_state_t *statep = codec->soft_statep;
+	int caddr = codec->index;
+	wid_t wid = ((audiohd_widget_t *)arg)->wid_wid;
+
+	(void) audioha_codec_verb_get(statep, caddr, wid,
+	    AUDIOHDC_VERB_SET_BEEP_GEN, AUDIOHDC_MUTE_BEEP_GEN);
+}
+
+static void
+audiohd_beep_freq(void *arg, int freq)
+{
+	_NOTE(ARGUNUSED(arg));
+	if (freq == 0) {
+		audiohd_beep_divider = 0;
+	} else {
+		if (freq > AUDIOHDC_MAX_BEEP_GEN)
+			freq = AUDIOHDC_MAX_BEEP_GEN;
+		else if (freq < AUDIOHDC_MIX_BEEP_GEN)
+			freq = AUDIOHDC_MIX_BEEP_GEN;
+		audiohd_beep_divider = AUDIOHDC_SAMPR48000 / freq;
+	}
+
+	if (audiohd_beep_vol == 0)
+		audiohd_beep_divider = 0;
+}
+
 /*
  * audiohd_init_state()
  *
@@ -2688,6 +2917,21 @@
 			audiohd_get_pin_config(widget);
 			break;
 		case WTYPE_BEEP:
+			/*
+			 * Get the audiohd_beep_switch value from audiohd.conf,
+			 * which is for turning on/off widget beep.
+			 */
+			audiohd_beep = ddi_prop_get_int(DDI_DEV_T_ANY,
+			    statep->hda_dip,
+			    DDI_PROP_DONTPASS, "audiohd_beep", 1);
+
+			if (audiohd_beep) {
+				(void) beep_fini();
+				(void) beep_init((void *) widget,
+				    audiohd_beep_on,
+				    audiohd_beep_off,
+				    audiohd_beep_freq);
+			}
 			break;
 		default:
 			break;
@@ -4440,6 +4684,314 @@
 	}
 }
 
+/*
+ * audiohd_find_beep()
+ * Description:
+ *      Find a beep for a beep path. Then the play data can be sent to the out
+ *      put pin through the beep path.
+ *
+ * Arguments:
+ *      hda_codec_t     *codec          where the beep widget exists
+ *      wid_t           wid             the no. of a widget
+ *      int             depth           the depth of search
+ *
+ * Return:
+ *      1) wid of Beep widget;
+ *      2) 0 if no path
+ */
+static wid_t
+audiohd_find_beep(hda_codec_t *codec, wid_t wid, int depth)
+{
+	audiohd_widget_t	*widget = codec->widget[wid];
+	wid_t   		wbeep = (uint32_t)(DDI_FAILURE);
+	wid_t   		retval;
+
+	if (depth > AUDIOHD_MAX_DEPTH)
+		return (uint32_t)(DDI_FAILURE);
+
+	if (widget == NULL)
+		return (uint32_t)(DDI_FAILURE);
+
+	switch (widget->type) {
+	case WTYPE_BEEP:
+		widget->path_flags |= AUDIOHD_PATH_BEEP;
+		wbeep = widget->wid_wid;
+		break;
+
+	case WTYPE_AUDIO_MIX:
+	case WTYPE_AUDIO_SEL:
+		for (int i = 0; i < widget->nconns; i++) {
+			retval = audiohd_find_beep(codec,
+			    widget->avail_conn[i], depth + 1);
+			if (retval != (uint32_t)DDI_FAILURE) {
+				if (widget->selconn != AUDIOHD_NULL_CONN)
+					continue;
+				widget->selconn = i;
+				wbeep = retval;
+				widget->path_flags |= AUDIOHD_PATH_BEEP;
+				return (wbeep);
+			}
+		}
+	default:
+		break;
+	}
+
+	return (wbeep);
+}       /* audiohd_find_beep() */
+
+/*
+ * audiohd_build_beep_path()
+ *
+ * Description:
+ *      Search an beep path for each pin in the codec.
+ * Arguments:
+ *      hda_codec_t     *codec          where the beep path exists
+ */
+static void
+audiohd_build_beep_path(hda_codec_t *codec)
+{
+	audiohd_pin_t		*pin;
+	audiohd_widget_t	*widget;
+	audiohd_path_t		*path;
+	wid_t			wid;
+	audiohd_state_t		*statep;
+	int			i;
+	boolean_t		beeppath = B_FALSE;
+
+	statep = codec->soft_statep;
+
+	for (pin = codec->first_pin; pin; pin = pin->next) {
+		if ((pin->cap & AUDIOHD_PIN_CAP_MASK) == 0)
+			continue;
+		if ((pin->config & AUDIOHD_PIN_CONF_MASK) ==
+		    AUDIOHD_PIN_NO_CONN)
+			continue;
+		if ((pin->device != DTYPE_LINEOUT) &&
+		    (pin->device != DTYPE_SPEAKER) &&
+		    (pin->device != DTYPE_SPDIF_OUT) &&
+		    (pin->device != DTYPE_HP_OUT))
+			continue;
+		widget = codec->widget[pin->wid];
+
+		widget->inamp_cap = 0;
+		for (i = 0; i < widget->nconns; i++) {
+			/*
+			 * If a beep found, the return value is the wid of the
+			 * widget on the path, or the return value is
+			 * DDI_FAILURE
+			 */
+			wid = audiohd_find_beep(codec,
+			    widget->avail_conn[i], 0);
+			/*
+			 * A beep was not found
+			 */
+			if (wid == (wid_t)DDI_FAILURE)
+				continue;
+			if (widget->selconn != AUDIOHD_NULL_CONN)
+				continue;
+			path = (audiohd_path_t *)
+			    kmem_zalloc(sizeof (audiohd_path_t),
+			    KM_SLEEP);
+			path->beep_wid = wid;
+			path->pin_wid[0] = widget->wid_wid;
+			path->pin_nums = 1;
+			path->path_type = BEEP;
+			beeppath = 1;
+			path->codec = codec;
+			path->statep = statep;
+			widget->path_flags |= AUDIOHD_PATH_BEEP;
+			widget->selconn = i;
+			statep->path[statep->pathnum++] = path;
+
+			break;
+		}
+	}
+
+	if (!beeppath) {
+		for (int i = 0; i < AUDIOHD_CODEC_MAX; i++) {
+			codec = statep->codec[i];
+			if (!codec)
+				continue;
+			for (wid = codec->first_wid; wid <= codec->last_wid;
+			    wid++) {
+				widget = codec->widget[wid];
+				if (widget->type == WTYPE_BEEP) {
+					path = (audiohd_path_t *)
+					    kmem_zalloc(sizeof (audiohd_path_t),
+					    KM_SLEEP);
+					path->beep_wid = wid;
+					path->pin_nums = 0;
+					path->path_type = BEEP;
+					beeppath = 1;
+					path->codec = codec;
+					path->statep = statep;
+					widget->path_flags |= AUDIOHD_PATH_BEEP;
+					statep->path[statep->pathnum++] = path;
+					break;
+				}
+			}
+		}
+	}
+}       /* audiohd_build_beep_path() */
+
+/*
+ * audiohd_build_beep_amp
+ *
+ * Description:
+ *      Find the gain control and mute control widget
+ */
+static void
+audiohd_build_beep_amp(hda_codec_t *codec)
+{
+	audiohd_path_t		*path;
+	audiohd_widget_t	*widget, *wpin, *wbeep;
+	wid_t			wid;
+	int			i, j;
+	uint32_t		gain;
+
+	for (i = 0; i < codec->soft_statep->pathnum; i++) {
+		path = codec->soft_statep->path[i];
+		if (path == NULL || path->path_type != BEEP ||
+		    path->codec != codec)
+			continue;
+		if (path->pin_nums == 0) {
+			path->mute_wid = path->beep_wid;
+			path->mute_dir = AUDIOHDC_AMP_SET_OUTPUT;
+			wbeep = codec->widget[path->beep_wid];
+			gain = (wbeep->outamp_cap &
+			    AUDIOHDC_AMP_CAP_STEP_NUMS);
+			if (gain) {
+				path->gain_dir = AUDIOHDC_AMP_SET_OUTPUT;
+				path->gain_bits = gain;
+				path->gain_wid = path->beep_wid;
+			}
+			path->gain_bits >>= AUDIOHD_GAIN_OFF;
+			break;
+		}
+		for (j = 0; j < path->pin_nums; j++) {
+			wid = path->pin_wid[j];
+			wpin = codec->widget[wid];
+			wbeep = codec->widget[path->beep_wid];
+
+			widget = wpin;
+			while (widget) {
+				if (widget->out_weight == 0 &&
+				    widget->outamp_cap &
+				    AUDIOHDC_AMP_CAP_MUTE_CAP) {
+					path->mute_wid = widget->wid_wid;
+					path->mute_dir =
+					    AUDIOHDC_AMP_SET_OUTPUT;
+					break;
+				}
+				if (widget->selconn == AUDIOHD_NULL_CONN)
+					break;
+				wid = widget->avail_conn[widget->selconn];
+				widget = codec->widget[wid];
+			}
+
+			gain = 0;
+			widget = wpin;
+			while (widget) {
+				if (widget->out_weight == 0 &&
+				    widget->outamp_cap &
+				    AUDIOHDC_AMP_CAP_STEP_NUMS) {
+					gain = (widget->outamp_cap &
+					    AUDIOHDC_AMP_CAP_STEP_NUMS);
+					if (gain && gain > path->gain_bits) {
+						path->gain_dir =
+						    AUDIOHDC_AMP_SET_OUTPUT;
+						path->gain_bits = gain;
+						path->gain_wid =
+						    widget->wid_wid;
+					}
+				}
+				if (widget->selconn == AUDIOHD_NULL_CONN)
+					break;
+				wid = widget->avail_conn[widget->selconn];
+				widget = codec->widget[wid];
+			}
+			path->gain_bits >>= AUDIOHD_GAIN_OFF;
+		}
+	}
+}       /* audiohd_build_beep_amp */
+
+/*
+ * audiohd_finish_beep_path()
+ *
+ * Description:
+ *      Enable the widgets on the beep path
+ */
+static void
+audiohd_finish_beep_path(hda_codec_t *codec)
+{
+	audiohd_state_t		*statep = codec->soft_statep;
+	audiohd_path_t		*path;
+	audiohd_widget_t	*widget;
+	uint_t			caddr = codec->index;
+	wid_t			wid;
+	int			i, j;
+
+	for (i = 0; i < codec->soft_statep->pathnum; i++) {
+		path = codec->soft_statep->path[i];
+		if (!path || path->path_type != BEEP || path->codec != codec)
+			continue;
+		for (j = 0; j < path->pin_nums; j++) {
+			wid = path->pin_wid[j];
+			widget = codec->widget[wid];
+
+			(void) audioha_codec_verb_get(statep, caddr, wid,
+			    AUDIOHDC_VERB_SET_CONN_SEL, widget->selconn);
+
+			wid = widget->avail_conn[widget->selconn];
+			widget = codec->widget[wid];
+
+			while (widget) {
+				/*
+				 * Set all amplifiers in this path to
+				 * the maximum
+				 * volume and unmute them.
+				 */
+				if (widget->out_weight != 0)
+					continue;
+				if (widget->outamp_cap) {
+					(void) audioha_codec_4bit_verb_get(
+					    statep,
+					    caddr,
+					    wid, AUDIOHDC_VERB_SET_AMP_MUTE,
+					    AUDIOHDC_AMP_SET_LR_OUTPUT |
+					    AUDIOHDC_GAIN_MAX);
+					}
+				if (widget->inamp_cap) {
+					(void) audioha_codec_4bit_verb_get(
+					    statep,
+					    caddr,
+					    wid, AUDIOHDC_VERB_SET_AMP_MUTE,
+					    AUDIOHDC_AMP_SET_LR_INPUT |
+					    AUDIOHDC_GAIN_MAX |
+					    (widget->selconn <<
+					    AUDIOHDC_AMP_SET_INDEX_OFFSET));
+				}
+
+				if (widget->selconn == AUDIOHD_NULL_CONN)
+					break;
+				/*
+				 * Accoding to HD spec, mixer doesn't support
+				 * "select connection"
+				 */
+				if ((widget->type != WTYPE_AUDIO_MIX) &&
+				    (widget->nconns > 1))
+					(void) audioha_codec_verb_get(statep,
+					    caddr,
+					    wid,
+					    AUDIOHDC_VERB_SET_CONN_SEL,
+					    widget->selconn);
+
+				wid = widget->avail_conn[widget->selconn];
+				widget = codec->widget[wid];
+			}
+		}
+	}
+}       /* audiohd_finish_beep_path */
 
 /*
  * audiohd_build_path()
@@ -4467,6 +5019,10 @@
 			audiohd_build_monitor_path(statep->codec[i]);
 			audiohd_build_monitor_amp(statep->codec[i]);
 			audiohd_finish_monitor_path(statep->codec[i]);
+
+			audiohd_build_beep_path(statep->codec[i]);
+			audiohd_build_beep_amp(statep->codec[i]);
+			audiohd_finish_beep_path(statep->codec[i]);
 		}
 	}
 }	/* audiohd_build_path */
--- a/usr/src/uts/common/io/audio/drv/audiohd/audiohd.conf	Thu Jun 11 09:17:20 2009 +0800
+++ b/usr/src/uts/common/io/audio/drv/audiohd/audiohd.conf	Thu Jun 11 09:38:14 2009 +0800
@@ -45,3 +45,4 @@
 #
 play-interrupts=175;
 record-interrupts=175;
+audiohd_beep=1;
--- a/usr/src/uts/common/io/audio/drv/audiohd/audiohd.h	Thu Jun 11 09:17:20 2009 +0800
+++ b/usr/src/uts/common/io/audio/drv/audiohd/audiohd.h	Thu Jun 11 09:38:14 2009 +0800
@@ -35,6 +35,7 @@
 #define	AUDIOHD_VID_INTEL	0x8086
 #define	AUDIOHD_VID_ATI		0x1002
 #define	AUDIOHD_VID_NVIDIA	0x10de
+#define	AUDIOHD_VID_SIGMATEL	0x8384
 
 /*
  * specific codec id used by specific vendors
@@ -321,6 +322,11 @@
 #define	AUDIOHDC_12BIT_VERB_MASK	0xfffff000
 #define	AUDIOHDC_4BIT_VERB_MASK		0xfffffff0
 
+#define	AUDIOHDC_SAMPR48000		48000
+#define	AUDIOHDC_MAX_BEEP_GEN		12000
+#define	AUDIOHDC_MIX_BEEP_GEN		47
+#define	AUDIOHDC_MUTE_BEEP_GEN		0x0
+
 /*
  * 12-bit verbs
  */
@@ -348,6 +354,7 @@
 #define	AUDIOHDC_VERB_EXEC_PIN_SENSE		0x709
 
 #define	AUDIOHDC_VERB_GET_BEEP_GEN		0xf0a
+#define	AUDIOHDC_VERB_SET_BEEP_GEN		0x70a
 
 #define	AUDIOHDC_VERB_GET_EAPD			0xf0c
 #define	AUDIOHDC_VERB_SET_EAPD			0x70c
@@ -384,6 +391,7 @@
 
 #define	AUDIOHDC_VERB_GET_AMP_MUTE		0xb
 #define	AUDIOHDC_VERB_SET_AMP_MUTE		0x3
+#define	AUDIOHDC_VERB_SET_BEEP_VOL		0x3A0
 
 /*
  * parameters of nodes
@@ -538,13 +546,14 @@
 	AUDIOHD_PIN_OTHER = 0xf,
 };
 
-#define	CTRL_NUM	15
+#define	CTRL_NUM	16
 
 /* values for audiohd_widget.path_flags */
 #define	AUDIOHD_PATH_DAC	(1 << 0)
 #define	AUDIOHD_PATH_ADC	(1 << 1)
 #define	AUDIOHD_PATH_MON	(1 << 2)
 #define	AUDIOHD_PATH_NOMON	(1 << 3)
+#define	AUDIOHD_PATH_BEEP	(1 << 4)
 
 typedef struct audiohd_path		audiohd_path_t;
 typedef struct audiohd_widget	audiohd_widget_t;
@@ -625,10 +634,12 @@
 typedef enum {
 	PLAY = 0,
 	RECORD = 1,
+	BEEP = 2,
 } path_type_t;
 
 struct audiohd_path {
 	wid_t			adda_wid;
+	wid_t			beep_wid;
 
 	wid_t			pin_wid[AUDIOHD_MAX_PINS];
 	int			sum_selconn[AUDIOHD_MAX_PINS];
@@ -713,6 +724,7 @@
 	uint32_t	assoc;
 	uint32_t	seq;
 	wid_t		adc_dac_wid; /* AD/DA wid which can route to this pin */
+	wid_t		beep_wid;
 	int		no_phys_conn;
 	enum audiohda_device_type	device;