aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx18/cx18-alsa-mixer.c
diff options
context:
space:
mode:
authorAndy Walls <awalls@radix.net>2009-05-25 20:40:25 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-02-26 13:10:42 -0500
commit9722c8f95a5bd51a3d392cb2f125c8240b745c48 (patch)
treeb7346813bbfccb672be30a6025d558318c6fd472 /drivers/media/video/cx18/cx18-alsa-mixer.c
parent5eb3291fe84b30a8e2fda31fd5fa44c40575f283 (diff)
V4L/DVB: cx18-alsa: Initial non-working cx18-alsa files
Initial cx18-alsa module files check-in to avoid losing work. Signed-off-by: Andy Walls <awalls@radix.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/cx18/cx18-alsa-mixer.c')
-rw-r--r--drivers/media/video/cx18/cx18-alsa-mixer.c191
1 files changed, 191 insertions, 0 deletions
diff --git a/drivers/media/video/cx18/cx18-alsa-mixer.c b/drivers/media/video/cx18/cx18-alsa-mixer.c
new file mode 100644
index 000000000000..b80391a8a9fc
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-alsa-mixer.c
@@ -0,0 +1,191 @@
1/*
2 * ALSA mixer controls for the
3 * ALSA interface to cx18 PCM capture streams
4 *
5 * Copyright (C) 2009 Andy Walls <awalls@radix.net>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 * 02111-1307 USA
21 */
22
23#include <linux/init.h>
24#include <linux/kernel.h>
25#include <linux/device.h>
26#include <linux/spinlock.h>
27#include <linux/videodev2.h>
28
29#include <media/v4l2-device.h>
30
31#include <sound/core.h>
32#include <sound/control.h>
33#include <sound/tlv.h>
34
35#include "cx18-alsa.h"
36#include "cx18-driver.h"
37
38/*
39 * Mixer manipulations are like v4l2 ioctl() calls to manipulate controls,
40 * just use the same lock we use for ioctl()s for now
41 */
42static inline void snd_cx18_mixer_lock(struct snd_cx18_card *cxsc)
43{
44 struct cx18 *cx = to_cx18(cxsc->v4l2_dev);
45 mutex_lock(&cx->serialize_lock);
46}
47
48static inline void snd_cx18_mixer_unlock(struct snd_cx18_card *cxsc)
49{
50 struct cx18 *cx = to_cx18(cxsc->v4l2_dev);
51 mutex_unlock(&cx->serialize_lock);
52}
53
54/*
55 * Note the cx18-av-core volume scale is funny, due to the alignment of the
56 * scale with another chip's range:
57 *
58 * v4l2_control value /512 indicated dB actual dB reg 0x8d4
59 * 0x0000 - 0x01ff 0 -119 -96 228
60 * 0x0200 - 0x02ff 1 -118 -96 228
61 * ...
62 * 0x2c00 - 0x2dff 22 -97 -96 228
63 * 0x2e00 - 0x2fff 23 -96 -96 228
64 * 0x3000 - 0x31ff 24 -95 -95 226
65 * ...
66 * 0xee00 - 0xefff 119 0 0 36
67 * ...
68 * 0xfe00 - 0xffff 127 +8 +8 20
69 */
70static inline int dB_to_cx18_av_vol(int dB)
71{
72 if (dB < -96)
73 dB = -96;
74 else if (dB > 8)
75 dB = 8;
76 return (dB + 119) << 9;
77}
78
79static inline int cx18_av_vol_to_dB(int v)
80{
81 if (v < (23 << 9))
82 v = (23 << 9);
83 else if (v > (127 << 9))
84 v = (127 << 9);
85 return (v >> 9) - 119;
86}
87
88static int snd_cx18_mixer_tv_vol_info(struct snd_kcontrol *kcontrol,
89 struct snd_ctl_elem_info *uinfo)
90{
91 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
92 uinfo->count = 1;
93 /* We're already translating values, just keep this control in dB */
94 uinfo->value.integer.min = -96;
95 uinfo->value.integer.max = +8;
96 uinfo->value.integer.step = 1;
97 return 0;
98}
99
100static int snd_cx18_mixer_tv_vol_get(struct snd_kcontrol *kctl,
101 struct snd_ctl_elem_value *uctl)
102{
103 struct snd_cx18_card *cxsc = snd_kcontrol_chip(kctl);
104 struct cx18 *cx = to_cx18(cxsc->v4l2_dev);
105 struct v4l2_control vctrl;
106 int ret;
107
108 vctrl.id = V4L2_CID_AUDIO_VOLUME;
109 vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]);
110
111 snd_cx18_mixer_lock(cxsc);
112 ret = v4l2_subdev_call(cx->sd_av, core, g_ctrl, &vctrl);
113 snd_cx18_mixer_unlock(cxsc);
114
115 if (!ret)
116 uctl->value.integer.value[0] = cx18_av_vol_to_dB(vctrl.value);
117 return ret;
118}
119
120static int snd_cx18_mixer_tv_vol_put(struct snd_kcontrol *kctl,
121 struct snd_ctl_elem_value *uctl)
122{
123 struct snd_cx18_card *cxsc = snd_kcontrol_chip(kctl);
124 struct cx18 *cx = to_cx18(cxsc->v4l2_dev);
125 struct v4l2_control vctrl;
126 int ret;
127
128 vctrl.id = V4L2_CID_AUDIO_VOLUME;
129 vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]);
130
131 snd_cx18_mixer_lock(cxsc);
132
133 /* Fetch current state */
134 ret = v4l2_subdev_call(cx->sd_av, core, g_ctrl, &vctrl);
135
136 if (ret ||
137 (cx18_av_vol_to_dB(vctrl.value) != uctl->value.integer.value[0])) {
138
139 /* Set, if needed */
140 vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]);
141 ret = v4l2_subdev_call(cx->sd_av, core, s_ctrl, &vctrl);
142 if (!ret)
143 ret = 1; /* Indicate control was changed w/o error */
144 }
145 snd_cx18_mixer_unlock(cxsc);
146
147 return ret;
148}
149
150
151/* This is a bit of overkill, the slider is already in dB internally */
152static DECLARE_TLV_DB_SCALE(snd_cx18_mixer_tv_vol_db_scale, -9600, 100, 0);
153
154static struct snd_kcontrol_new snd_cx18_mixer_tv_vol __initdata = {
155 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
156 .name = "Analog TV Capture Volume",
157 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
158 SNDRV_CTL_ELEM_ACCESS_TLV_READ,
159 .info = snd_cx18_mixer_tv_volume_info,
160 .get = snd_cx18_mixer_tv_volume_get,
161 .put = snd_cx18_mixer_tv_volume_put,
162 .tlv.p = snd_cx18_mixer_tv_vol_db_scale
163};
164
165/* FIXME - add mute switch and balance, bass, treble sliders:
166 V4L2_CID_AUDIO_MUTE
167
168 V4L2_CID_AUDIO_BALANCE
169
170 V4L2_CID_AUDIO_BASS
171 V4L2_CID_AUDIO_TREBLE
172*/
173
174/* FIXME - add stereo, lang1, lang2, mono menu */
175/* FIXME - add CS5345 I2S volume for HVR-1600 */
176
177int __init snd_cx18_mixer_create(struct snd_cx18_card *cxsc)
178{
179 struct v4l2_device *v4l2_dev = cxsc->v4l2_dev;
180 struct snd_card *sc = cxsc->sc;
181 int ret;
182
183 strlcpy(sc->mixername, "CX23418 Mixer", sizeof(sc->mixername));
184
185 ret = snd_ctl_add(sc, snd_ctl_new1(snd_cx18_mixer_tv_vol, cxsc));
186 if (ret) {
187 CX18_ALSA_WARN("%s: failed to add %s control, err %d\n",
188 __func__, snd_cx18_mixer_tv_vol.name, ret);
189 }
190 return ret;
191}