Module Name: src
Committed By: nonaka
Date: Sat Apr 18 05:20:21 UTC 2009
Modified Files:
src/sys/arch/zaurus/dev: scoop.c scoopvar.h zaudio.c
Log Message:
zaudio(4): Support recording.
To generate a diff of this commit:
cvs rdiff -u -r1.6 -r1.7 src/sys/arch/zaurus/dev/scoop.c
cvs rdiff -u -r1.4 -r1.5 src/sys/arch/zaurus/dev/scoopvar.h
cvs rdiff -u -r1.9 -r1.10 src/sys/arch/zaurus/dev/zaudio.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/zaurus/dev/scoop.c
diff -u src/sys/arch/zaurus/dev/scoop.c:1.6 src/sys/arch/zaurus/dev/scoop.c:1.7
--- src/sys/arch/zaurus/dev/scoop.c:1.6 Thu Jan 29 12:28:15 2009
+++ src/sys/arch/zaurus/dev/scoop.c Sat Apr 18 05:20:21 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: scoop.c,v 1.6 2009/01/29 12:28:15 nonaka Exp $ */
+/* $NetBSD: scoop.c,v 1.7 2009/04/18 05:20:21 nonaka Exp $ */
/* $OpenBSD: zaurus_scoop.c,v 1.12 2005/11/17 05:26:31 uwe Exp $ */
/*
@@ -18,7 +18,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: scoop.c,v 1.6 2009/01/29 12:28:15 nonaka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: scoop.c,v 1.7 2009/04/18 05:20:21 nonaka Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -256,6 +256,19 @@
}
/*
+ * Enable or disable the mic bias
+ */
+void
+scoop_set_mic_bias(int onoff)
+{
+ struct scoop_softc *sc1;
+
+ sc1 = device_lookup_private(&scoop_cd, 1);
+ if (sc1 != NULL)
+ scoop_gpio_pin_write(sc1, SCOOP1_MIC_BIAS, onoff);
+}
+
+/*
* Turn on pullup resistor while not reading the remote control.
*/
void
Index: src/sys/arch/zaurus/dev/scoopvar.h
diff -u src/sys/arch/zaurus/dev/scoopvar.h:1.4 src/sys/arch/zaurus/dev/scoopvar.h:1.5
--- src/sys/arch/zaurus/dev/scoopvar.h:1.4 Wed Oct 17 19:58:34 2007
+++ src/sys/arch/zaurus/dev/scoopvar.h Sat Apr 18 05:20:21 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: scoopvar.h,v 1.4 2007/10/17 19:58:34 garbled Exp $ */
+/* $NetBSD: scoopvar.h,v 1.5 2009/04/18 05:20:21 nonaka Exp $ */
/* $OpenBSD: zaurus_scoopvar.h,v 1.10 2005/11/17 05:26:31 uwe Exp $ */
/*
@@ -32,6 +32,7 @@
void scoop_set_sdmmc_power(int);
void scoop_check_mcr(void);
void scoop_set_headphone(int);
+void scoop_set_mic_bias(int);
void scoop_akin_pullup(int);
void scoop_suspend(void);
void scoop_resume(void);
Index: src/sys/arch/zaurus/dev/zaudio.c
diff -u src/sys/arch/zaurus/dev/zaudio.c:1.9 src/sys/arch/zaurus/dev/zaudio.c:1.10
--- src/sys/arch/zaurus/dev/zaudio.c:1.9 Fri Mar 13 13:55:18 2009
+++ src/sys/arch/zaurus/dev/zaudio.c Sat Apr 18 05:20:21 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: zaudio.c,v 1.9 2009/03/13 13:55:18 nonaka Exp $ */
+/* $NetBSD: zaudio.c,v 1.10 2009/04/18 05:20:21 nonaka Exp $ */
/* $OpenBSD: zaurus_audio.c,v 1.8 2005/08/18 13:23:02 robert Exp $ */
/*
@@ -17,14 +17,39 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+/*-
+ * Copyright (c) 2009 NONAKA Kimihiro <[email protected]>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
/*
* TODO:
* - powerhooks (currently only works until first suspend)
- * - record support
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: zaudio.c,v 1.9 2009/03/13 13:55:18 nonaka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: zaudio.c,v 1.10 2009/04/18 05:20:21 nonaka Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -52,7 +77,6 @@
#include <zaurus/dev/scoopvar.h>
#define WM8750_ADDRESS 0x1B
-#define SPKR_VOLUME 112
#define wm8750_write(sc, reg, val) \
pxa2x0_i2c_write_2(&sc->sc_i2c, WM8750_ADDRESS, \
@@ -65,6 +89,8 @@
#define ZAUDIO_OP_SPKR 0
#define ZAUDIO_OP_HP 1
+#define ZAUDIO_OP_MIC 2
+#define ZAUDIO_OP_NUM 3
#define ZAUDIO_JACK_STATE_OUT 0
#define ZAUDIO_JACK_STATE_IN 1
@@ -90,9 +116,10 @@
struct pxa2x0_i2c_softc sc_i2c;
int sc_playing;
+ int sc_recording;
- struct zaudio_volume sc_volume[2];
- char sc_unmute[2];
+ struct zaudio_volume sc_volume[ZAUDIO_OP_NUM];
+ char sc_unmute[ZAUDIO_OP_NUM];
int sc_state;
int sc_icount;
@@ -108,25 +135,62 @@
"wm"
};
-#define ZAUDIO_NFORMATS 4
-static const struct audio_format zaudio_formats[ZAUDIO_NFORMATS] = {
- {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_LE, 16, 16,
- 2, AUFMT_STEREO, 0, {4000, 48000}},
- {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_LE, 16, 16,
- 1, AUFMT_MONAURAL, 0, {4000, 48000}},
- {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_ULINEAR_LE, 8, 8,
- 2, AUFMT_STEREO, 0, {4000, 48000}},
- {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_ULINEAR_LE, 8, 8,
- 1, AUFMT_MONAURAL, 0, {4000, 48000}},
+static const struct audio_format zaudio_formats[] = {
+ {
+ .driver_data = NULL,
+ .mode = AUMODE_PLAY | AUMODE_RECORD,
+ .encoding = AUDIO_ENCODING_SLINEAR_LE,
+ .validbits = 16,
+ .precision = 16,
+ .channels = 2,
+ .channel_mask = AUFMT_STEREO,
+ .frequency_type = 0,
+ .frequency = { 4000, 48000 }
+ },
+ {
+ .driver_data = NULL,
+ .mode = AUMODE_PLAY | AUMODE_RECORD,
+ .encoding = AUDIO_ENCODING_SLINEAR_LE,
+ .validbits = 16,
+ .precision = 16,
+ .channels = 1,
+ .channel_mask = AUFMT_MONAURAL,
+ .frequency_type = 0,
+ .frequency = { 4000, 48000 }
+ },
+ {
+ .driver_data = NULL,
+ .mode = AUMODE_PLAY | AUMODE_RECORD,
+ .encoding = AUDIO_ENCODING_ULINEAR_LE,
+ .validbits = 8,
+ .precision = 8,
+ .channels = 2,
+ .channel_mask = AUFMT_STEREO,
+ .frequency_type = 0,
+ .frequency = { 4000, 48000 }
+ },
+ {
+ .driver_data = NULL,
+ .mode = AUMODE_PLAY | AUMODE_RECORD,
+ .encoding = AUDIO_ENCODING_ULINEAR_LE,
+ .validbits = 8,
+ .precision = 8,
+ .channels = 1,
+ .channel_mask = AUFMT_MONAURAL,
+ .frequency_type = 0,
+ .frequency = { 4000, 48000 }
+ },
};
+static const int zaudio_nformats = (int)__arraycount(zaudio_formats);
-void zaudio_init(struct zaudio_softc *);
+static void zaudio_init(struct zaudio_softc *);
static int zaudio_jack_intr(void *);
-void zaudio_jack(void *);
-void zaudio_standby(struct zaudio_softc *);
-void zaudio_update_volume(struct zaudio_softc *, int);
-void zaudio_update_mutes(struct zaudio_softc *);
-void zaudio_play_setup(struct zaudio_softc *);
+static void zaudio_jack(void *);
+static void zaudio_standby(struct zaudio_softc *);
+static void zaudio_update_volume(struct zaudio_softc *, int);
+static void zaudio_update_mutes(struct zaudio_softc *, int);
+static void zaudio_play_setup(struct zaudio_softc *);
+/*static*/ void zaudio_record_setup(struct zaudio_softc *);
static int zaudio_open(void *, int);
static void zaudio_close(void *);
static int zaudio_query_encoding(void *, struct audio_encoding *);
@@ -178,7 +242,7 @@
.powerstate = NULL,
};
-static const uint16_t playback_registers[][2] = {
+static const uint16_t playback_regs[][2] = {
/* Unmute DAC */
{ ADCDACCTL_REG, 0x000 },
@@ -196,12 +260,36 @@
/* Direct DACs to output mixers */
{ LOUTMIX1_REG, LOUTMIX1_LD2LO },
+ { LOUTMIX2_REG, 0x000 },
+ { ROUTMIX1_REG, 0x000 },
{ ROUTMIX2_REG, ROUTMIX2_RD2RO },
/* End of list */
{ 0xffff, 0xffff }
};
+static const uint16_t record_regs[][2] = {
+ /* Unmute DAC */
+ { ADCDACCTL_REG, 0x000 },
+
+ /* 16 bit audio words */
+ { AUDINT_REG, AUDINT_SET_FORMAT(2) },
+
+ /* Enable thermal protection, power, left DAC for both channel */
+ { ADCTL1_REG, ADCTL1_TSDEN | ADCTL1_SET_VSEL(3)
+ | ADCTL1_SET_DATSEL(1) },
+
+ /* Diffrential input select: LINPUT1-RINPUT1, stereo */
+ { ADCINPMODE_REG, 0x000 },
+
+ /* L-R differential, micboost 20dB */
+ { ADCLSPATH_REG, ADCLSPATH_SET_LINSEL(3) | ADCLSPATH_SET_LMICBOOST(2) },
+ { ADCRSPATH_REG, ADCRSPATH_SET_RINSEL(3) | ADCRSPATH_SET_RMICBOOST(2) },
+
+ /* End of list */
+ { 0xffff, 0xffff }
+};
+
static int
zaudio_match(device_t parent, cfdata_t cf, void *aux)
{
@@ -256,13 +344,15 @@
sc->sc_volume[ZAUDIO_OP_HP].left = 180;
sc->sc_volume[ZAUDIO_OP_HP].right = 180;
sc->sc_unmute[ZAUDIO_OP_HP] = 0;
+ sc->sc_volume[ZAUDIO_OP_MIC].left = 240;
+ sc->sc_unmute[ZAUDIO_OP_MIC] = 0;
/* Configure headphone jack state change handling. */
callout_init(&sc->sc_to, 0);
callout_setfunc(&sc->sc_to, zaudio_jack, sc);
pxa2x0_gpio_set_function(GPIO_HP_IN_C3000, GPIO_IN);
- (void)pxa2x0_gpio_intr_establish(GPIO_HP_IN_C3000,
- IST_EDGE_BOTH, IPL_BIO, zaudio_jack_intr, sc);
+ (void) pxa2x0_gpio_intr_establish(GPIO_HP_IN_C3000, IST_EDGE_BOTH,
+ IPL_BIO, zaudio_jack_intr, sc);
zaudio_init(sc);
@@ -301,7 +391,7 @@
return true;
}
-void
+static void
zaudio_init(struct zaudio_softc *sc)
{
@@ -321,10 +411,12 @@
/* Initialise volume levels */
zaudio_update_volume(sc, ZAUDIO_OP_SPKR);
zaudio_update_volume(sc, ZAUDIO_OP_HP);
+ zaudio_update_volume(sc, ZAUDIO_OP_MIC);
pxa2x0_i2c_close(&sc->sc_i2c);
scoop_set_headphone(0);
+ scoop_set_mic_bias(0);
/* Assume that the jack state has changed. */
zaudio_jack(sc);
@@ -341,7 +433,7 @@
return 1;
}
-void
+static void
zaudio_jack(void *v)
{
struct zaudio_softc *sc = v;
@@ -360,6 +452,7 @@
sc->sc_state = ZAUDIO_JACK_STATE_IN;
sc->sc_unmute[ZAUDIO_OP_SPKR] = 0;
sc->sc_unmute[ZAUDIO_OP_HP] = 1;
+ sc->sc_unmute[ZAUDIO_OP_MIC] = 1;
goto update_mutes;
} else
sc->sc_state = ZAUDIO_JACK_STATE_OUT;
@@ -379,6 +472,7 @@
sc->sc_state = ZAUDIO_JACK_STATE_OUT;
sc->sc_unmute[ZAUDIO_OP_SPKR] = 1;
sc->sc_unmute[ZAUDIO_OP_HP] = 0;
+ sc->sc_unmute[ZAUDIO_OP_MIC] = 0;
goto update_mutes;
} else
sc->sc_state = ZAUDIO_JACK_STATE_IN;
@@ -393,14 +487,17 @@
update_mutes:
callout_stop(&sc->sc_to);
- if (sc->sc_playing) {
+ if (sc->sc_playing || sc->sc_recording) {
pxa2x0_i2c_open(&sc->sc_i2c);
- zaudio_update_mutes(sc);
+ if (sc->sc_playing)
+ zaudio_update_mutes(sc, 1);
+ if (sc->sc_recording)
+ zaudio_update_mutes(sc, 2);
pxa2x0_i2c_close(&sc->sc_i2c);
}
}
-void
+static void
zaudio_standby(struct zaudio_softc *sc)
{
@@ -413,64 +510,94 @@
pxa2x0_i2c_close(&sc->sc_i2c);
scoop_set_headphone(0);
+ scoop_set_mic_bias(0);
}
-void
+static void
zaudio_update_volume(struct zaudio_softc *sc, int output)
{
switch (output) {
case ZAUDIO_OP_SPKR:
wm8750_write(sc, LOUT2VOL_REG, LOUT2VOL_LO2VU | LOUT2VOL_LO2ZC |
- LOUT2VOL_SET_LOUT2VOL(sc->sc_volume[ZAUDIO_OP_SPKR
- ].left >> 1));
+ LOUT2VOL_SET_LOUT2VOL(sc->sc_volume[ZAUDIO_OP_SPKR].left >> 1));
wm8750_write(sc, ROUT2VOL_REG, ROUT2VOL_RO2VU | ROUT2VOL_RO2ZC |
- ROUT2VOL_SET_ROUT2VOL(sc->sc_volume[ZAUDIO_OP_SPKR
- ].left >> 1));
+ ROUT2VOL_SET_ROUT2VOL(sc->sc_volume[ZAUDIO_OP_SPKR].left >> 1));
break;
case ZAUDIO_OP_HP:
wm8750_write(sc, LOUT1VOL_REG, LOUT1VOL_LO1VU | LOUT1VOL_LO1ZC |
- LOUT1VOL_SET_LOUT1VOL(sc->sc_volume[ZAUDIO_OP_HP
- ].left >> 1));
+ LOUT1VOL_SET_LOUT1VOL(sc->sc_volume[ZAUDIO_OP_HP].left >> 1));
wm8750_write(sc, ROUT1VOL_REG, ROUT1VOL_RO1VU | ROUT1VOL_RO1ZC |
- ROUT1VOL_SET_ROUT1VOL(sc->sc_volume[ZAUDIO_OP_HP
- ].right >> 1));
+ ROUT1VOL_SET_ROUT1VOL(sc->sc_volume[ZAUDIO_OP_HP].right >> 1));
+ break;
+
+ case ZAUDIO_OP_MIC:
+ wm8750_write(sc, LINVOL_REG, LINVOL_LIVU |
+ LINVOL_SET_LINVOL(sc->sc_volume[ZAUDIO_OP_MIC].left >> 2));
+ wm8750_write(sc, RINVOL_REG, RINVOL_RIVU |
+ RINVOL_SET_RINVOL(sc->sc_volume[ZAUDIO_OP_MIC].left >> 2));
break;
}
}
-void
-zaudio_update_mutes(struct zaudio_softc *sc)
+static void
+zaudio_update_mutes(struct zaudio_softc *sc, int mask)
{
uint16_t val;
- val = PWRMGMT2_DACL | PWRMGMT2_DACR;
+ /* playback */
+ if (mask & 1) {
+ val = PWRMGMT2_DACL | PWRMGMT2_DACR;
+ if (sc->sc_unmute[ZAUDIO_OP_SPKR])
+ val |= PWRMGMT2_LOUT2 | PWRMGMT2_ROUT2;
+ if (sc->sc_unmute[ZAUDIO_OP_HP])
+ val |= PWRMGMT2_LOUT1 | PWRMGMT2_ROUT1;
+ wm8750_write(sc, PWRMGMT2_REG, val);
+ scoop_set_headphone(sc->sc_unmute[ZAUDIO_OP_HP]);
+ }
- if (sc->sc_unmute[ZAUDIO_OP_SPKR])
- val |= PWRMGMT2_LOUT2 | PWRMGMT2_ROUT2;
+ /* record */
+ if (mask & 2) {
+ val = PWRMGMT1_SET_VMIDSEL(1) | PWRMGMT1_VREF;
+ if (sc->sc_unmute[ZAUDIO_OP_MIC]) {
+ val |= PWRMGMT1_AINL | PWRMGMT1_AINR
+ | PWRMGMT1_ADCL | PWRMGMT1_ADCR | PWRMGMT1_MICB;
+ }
+ wm8750_write(sc, PWRMGMT1_REG, val);
+ scoop_set_mic_bias(sc->sc_unmute[ZAUDIO_OP_MIC]);
+ }
+}
+
+static void
+zaudio_play_setup(struct zaudio_softc *sc)
+{
+ int i;
- if (sc->sc_unmute[ZAUDIO_OP_HP])
- val |= PWRMGMT2_LOUT1 | PWRMGMT2_ROUT1;
+ pxa2x0_i2c_open(&sc->sc_i2c);
- wm8750_write(sc, PWRMGMT2_REG, val);
+ /* Program the codec with playback settings */
+ for (i = 0; playback_regs[i][0] != 0xffff; i++) {
+ wm8750_write(sc, playback_regs[i][0], playback_regs[i][1]);
+ }
+ zaudio_update_mutes(sc, 1);
- scoop_set_headphone(sc->sc_unmute[ZAUDIO_OP_HP]);
+ pxa2x0_i2c_close(&sc->sc_i2c);
}
-void
-zaudio_play_setup(struct zaudio_softc *sc)
+/*static*/ void
+zaudio_record_setup(struct zaudio_softc *sc)
{
int i;
pxa2x0_i2c_open(&sc->sc_i2c);
/* Program the codec with playback settings */
- for (i = 0; playback_registers[i][0] != 0xffff; i++) {
- wm8750_write(sc, playback_registers[i][0],
- playback_registers[i][1]);
+ for (i = 0; record_regs[i][0] != 0xffff; i++) {
+ wm8750_write(sc, record_regs[i][0], record_regs[i][1]);
}
- zaudio_update_mutes(sc);
+
+ zaudio_update_mutes(sc, 2);
pxa2x0_i2c_close(&sc->sc_i2c);
}
@@ -601,7 +728,7 @@
return EINVAL;
fil = (mode == AUMODE_PLAY) ? pfil : rfil;
- i = auconv_set_converter(zaudio_formats, ZAUDIO_NFORMATS,
+ i = auconv_set_converter(zaudio_formats, zaudio_nformats,
mode, p, false, fil);
if (i < 0)
return EINVAL;
@@ -631,7 +758,8 @@
int rv;
rv = pxa2x0_i2s_halt_output(&sc->sc_i2s);
- zaudio_standby(sc);
+ if (!sc->sc_recording)
+ zaudio_standby(sc);
sc->sc_playing = 0;
return rv;
@@ -644,6 +772,9 @@
int rv;
rv = pxa2x0_i2s_halt_input(&sc->sc_i2s);
+ if (!sc->sc_playing)
+ zaudio_standby(sc);
+ sc->sc_recording = 0;
return rv;
}
@@ -651,7 +782,6 @@
static int
zaudio_getdev(void *hdl, struct audio_device *ret)
{
- /* struct zaudio_softc *sc = hdl; */
*ret = wm8750_device;
return 0;
@@ -661,7 +791,12 @@
#define ZAUDIO_SPKR_MUTE 1
#define ZAUDIO_HP_LVL 2
#define ZAUDIO_HP_MUTE 3
-#define ZAUDIO_OUTPUT_CLASS 4
+#define ZAUDIO_MIC_LVL 4
+#define ZAUDIO_MIC_MUTE 5
+#define ZAUDIO_RECORD_SOURCE 6
+#define ZAUDIO_OUTPUT_CLASS 7
+#define ZAUDIO_INPUT_CLASS 8
+#define ZAUDIO_RECORD_CLASS 9
static int
zaudio_set_port(void *hdl, struct mixer_ctrl *mc)
@@ -690,7 +825,7 @@
if (mc->type != AUDIO_MIXER_ENUM)
break;
sc->sc_unmute[ZAUDIO_OP_SPKR] = mc->un.ord ? 1 : 0;
- zaudio_update_mutes(sc);
+ zaudio_update_mutes(sc, 1);
error = 0;
break;
@@ -718,7 +853,36 @@
if (mc->type != AUDIO_MIXER_ENUM)
break;
sc->sc_unmute[ZAUDIO_OP_HP] = mc->un.ord ? 1 : 0;
- zaudio_update_mutes(sc);
+ zaudio_update_mutes(sc, 1);
+ error = 0;
+ break;
+
+ case ZAUDIO_MIC_LVL:
+ if (mc->type != AUDIO_MIXER_VALUE)
+ break;
+ if (mc->un.value.num_channels == 1)
+ sc->sc_volume[ZAUDIO_OP_MIC].left =
+ mc->un.value.level[AUDIO_MIXER_LEVEL_MONO];
+ else
+ break;
+ zaudio_update_volume(sc, ZAUDIO_OP_MIC);
+ error = 0;
+ break;
+
+ case ZAUDIO_MIC_MUTE:
+ if (mc->type != AUDIO_MIXER_ENUM)
+ break;
+ sc->sc_unmute[ZAUDIO_OP_MIC] = mc->un.ord ? 1 : 0;
+ zaudio_update_mutes(sc, 2);
+ error = 0;
+ break;
+
+ case ZAUDIO_RECORD_SOURCE:
+ if (mc->type != AUDIO_MIXER_ENUM)
+ break;
+ if (mc->un.ord != 0)
+ break;
+ /* MIC only */
error = 0;
break;
}
@@ -777,15 +941,40 @@
mc->un.ord = sc->sc_unmute[ZAUDIO_OP_HP] ? 1 : 0;
error = 0;
break;
+
+ case ZAUDIO_MIC_LVL:
+ if (mc->type != AUDIO_MIXER_VALUE)
+ break;
+ if (mc->un.value.num_channels == 1)
+ mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
+ sc->sc_volume[ZAUDIO_OP_MIC].left;
+ else
+ break;
+ error = 0;
+ break;
+
+ case ZAUDIO_MIC_MUTE:
+ if (mc->type != AUDIO_MIXER_ENUM)
+ break;
+ mc->un.ord = sc->sc_unmute[ZAUDIO_OP_MIC] ? 1 : 0;
+ error = 0;
+ break;
+
+ case ZAUDIO_RECORD_SOURCE:
+ if (mc->type != AUDIO_MIXER_ENUM)
+ break;
+ mc->un.ord = 0; /* MIC only */
+ error = 0;
+ break;
}
return error;
}
+/*ARGSUSED*/
static int
zaudio_query_devinfo(void *hdl, struct mixer_devinfo *di)
{
- /* struct zaudio_softc *sc = hdl; */
switch (di->index) {
case ZAUDIO_SPKR_LVL:
@@ -793,8 +982,7 @@
di->mixer_class = ZAUDIO_OUTPUT_CLASS;
di->prev = AUDIO_MIXER_LAST;
di->next = ZAUDIO_SPKR_MUTE;
- strlcpy(di->label.name, AudioNspeaker,
- sizeof(di->label.name));
+ strlcpy(di->label.name, AudioNspeaker, sizeof(di->label.name));
strlcpy(di->un.v.units.name, AudioNvolume,
sizeof(di->un.v.units.name));
di->un.v.num_channels = 1;
@@ -835,13 +1023,59 @@
di->un.e.member[1].ord = 1;
break;
+ case ZAUDIO_MIC_LVL:
+ di->type = AUDIO_MIXER_VALUE;
+ di->mixer_class = ZAUDIO_INPUT_CLASS;
+ di->prev = AUDIO_MIXER_LAST;
+ di->next = ZAUDIO_MIC_MUTE;
+ strlcpy(di->label.name, AudioNmicrophone,
+ sizeof(di->label.name));
+ strlcpy(di->un.v.units.name, AudioNvolume,
+ sizeof(di->un.v.units.name));
+ di->un.v.num_channels = 1;
+ break;
+
+ case ZAUDIO_MIC_MUTE:
+ di->type = AUDIO_MIXER_ENUM;
+ di->mixer_class = ZAUDIO_INPUT_CLASS;
+ di->prev = ZAUDIO_MIC_LVL;
+ di->next = AUDIO_MIXER_LAST;
+ goto mute;
+
+ case ZAUDIO_RECORD_SOURCE:
+ di->type = AUDIO_MIXER_ENUM;
+ di->mixer_class = ZAUDIO_RECORD_CLASS;
+ di->prev = AUDIO_MIXER_LAST;
+ di->next = AUDIO_MIXER_LAST;
+ strlcpy(di->label.name, AudioNsource, sizeof(di->label.name));
+ di->un.e.num_mem = 1;
+ strlcpy(di->un.e.member[0].label.name, AudioNmicrophone,
+ sizeof(di->un.e.member[0].label.name));
+ di->un.e.member[0].ord = 0;
+ break;
+
case ZAUDIO_OUTPUT_CLASS:
di->type = AUDIO_MIXER_CLASS;
di->mixer_class = ZAUDIO_OUTPUT_CLASS;
di->prev = AUDIO_MIXER_LAST;
di->next = AUDIO_MIXER_LAST;
- strlcpy(di->label.name, AudioCoutputs,
- sizeof(di->label.name));
+ strlcpy(di->label.name, AudioCoutputs, sizeof(di->label.name));
+ break;
+
+ case ZAUDIO_INPUT_CLASS:
+ di->type = AUDIO_MIXER_CLASS;
+ di->mixer_class = ZAUDIO_INPUT_CLASS;
+ di->prev = AUDIO_MIXER_LAST;
+ di->next = AUDIO_MIXER_LAST;
+ strlcpy(di->label.name, AudioCinputs, sizeof(di->label.name));
+ break;
+
+ case ZAUDIO_RECORD_CLASS:
+ di->type = AUDIO_MIXER_CLASS;
+ di->mixer_class = ZAUDIO_RECORD_CLASS;
+ di->prev = AUDIO_MIXER_LAST;
+ di->next = AUDIO_MIXER_LAST;
+ strlcpy(di->label.name, AudioCinputs, sizeof(di->label.name));
break;
default:
@@ -852,8 +1086,8 @@
}
static void *
-zaudio_allocm(void *hdl, int direction, size_t size,
- struct malloc_type *type, int flags)
+zaudio_allocm(void *hdl, int direction, size_t size, struct malloc_type *type,
+ int flags)
{
struct zaudio_softc *sc = hdl;
@@ -888,7 +1122,7 @@
zaudio_get_props(void *hdl)
{
- return AUDIO_PROP_MMAP|AUDIO_PROP_INDEPENDENT|AUDIO_PROP_FULLDUPLEX;
+ return AUDIO_PROP_MMAP|AUDIO_PROP_INDEPENDENT;
}
static int
@@ -907,7 +1141,8 @@
/* Start DMA via I2S */
rv = pxa2x0_i2s_start_output(&sc->sc_i2s, block, bsize, intr, intrarg);
if (rv) {
- zaudio_standby(sc);
+ if (!sc->sc_recording)
+ zaudio_standby(sc);
sc->sc_playing = 0;
}
return rv;
@@ -917,6 +1152,21 @@
zaudio_start_input(void *hdl, void *block, int bsize, void (*intr)(void *),
void *intrarg)
{
+ struct zaudio_softc *sc = hdl;
+ int rv;
+
+ /* Power up codec if we are not already recording. */
+ if (!sc->sc_recording) {
+ sc->sc_recording = 1;
+ zaudio_record_setup(sc);
+ }
- return ENXIO;
+ /* Start DMA via I2S */
+ rv = pxa2x0_i2s_start_input(&sc->sc_i2s, block, bsize, intr, intrarg);
+ if (rv) {
+ if (!sc->sc_playing)
+ zaudio_standby(sc);
+ sc->sc_recording = 0;
+ }
+ return rv;
}