diff options
author | Janusz Krzysztofik <jkrzyszt@tis.icnet.pl> | 2009-07-29 06:24:46 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-07-31 17:38:44 -0400 |
commit | ad120dae127f5cb14b4c4ed0b98313fb13b9c846 (patch) | |
tree | b48926e3052008eddf60ff68ccaf0d5f24345031 /sound/soc/codecs/cx20442.c | |
parent | 78ed73e84d132e2d556eda90e5b76620f4390ff2 (diff) |
ASoC: CX20442: push down machine independent line discipline bits
This corrected patch adds machine independent line discipline code, prevoiusly
exsiting inside my Amstrad Delta ASoC machine dirver, to the Conexant CX20442
codec driver. The code can be used as a standalone line discipline, or as a
set of codec specific functions called from machine's line discipline
callbacks. Anyway, the line discipline itself must be registered by a machine
driver.
Applies on top of the followup to my initial driver version:
http://mailman.alsa-project.org/pipermail/alsa-devel/2009-July/019757.html
Suggested by ASoC manintainer Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs/cx20442.c')
-rw-r--r-- | sound/soc/codecs/cx20442.c | 116 |
1 files changed, 110 insertions, 6 deletions
diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c index 7bbb77baa231..f33245510c3b 100644 --- a/sound/soc/codecs/cx20442.c +++ b/sound/soc/codecs/cx20442.c | |||
@@ -13,6 +13,8 @@ | |||
13 | * option) any later version. | 13 | * option) any later version. |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/tty.h> | ||
17 | |||
16 | #include <sound/core.h> | 18 | #include <sound/core.h> |
17 | #include <sound/initval.h> | 19 | #include <sound/initval.h> |
18 | #include <sound/soc-dapm.h> | 20 | #include <sound/soc-dapm.h> |
@@ -172,8 +174,7 @@ static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg, | |||
172 | return -EINVAL; | 174 | return -EINVAL; |
173 | 175 | ||
174 | /* hw_write and control_data pointers required for talking to the modem | 176 | /* hw_write and control_data pointers required for talking to the modem |
175 | * are expected to be set by the machine driver's line discipline | 177 | * are expected to be set by the line discipline initialization code */ |
176 | * initialization code */ | ||
177 | if (!codec->hw_write || !codec->control_data) | 178 | if (!codec->hw_write || !codec->control_data) |
178 | return -EIO; | 179 | return -EIO; |
179 | 180 | ||
@@ -208,6 +209,111 @@ static int cx20442_write(struct snd_soc_codec *codec, unsigned int reg, | |||
208 | return 0; | 209 | return 0; |
209 | } | 210 | } |
210 | 211 | ||
212 | |||
213 | /* Moved up here as line discipline referres it during initialization */ | ||
214 | static struct snd_soc_codec *cx20442_codec; | ||
215 | |||
216 | |||
217 | /* | ||
218 | * Line discpline related code | ||
219 | * | ||
220 | * Any of the callback functions below can be used in two ways: | ||
221 | * 1) registerd by a machine driver as one of line discipline operations, | ||
222 | * 2) called from a machine's provided line discipline callback function | ||
223 | * in case when extra machine specific code must be run as well. | ||
224 | */ | ||
225 | |||
226 | /* Modem init: echo off, digital speaker off, quiet off, voice mode */ | ||
227 | static const char *v253_init = "ate0m0q0+fclass=8\r"; | ||
228 | |||
229 | /* Line discipline .open() */ | ||
230 | static int v253_open(struct tty_struct *tty) | ||
231 | { | ||
232 | struct snd_soc_codec *codec = cx20442_codec; | ||
233 | int ret, len = strlen(v253_init); | ||
234 | |||
235 | /* Doesn't make sense without write callback */ | ||
236 | if (!tty->ops->write) | ||
237 | return -EINVAL; | ||
238 | |||
239 | /* Pass the codec structure address for use by other ldisc callbacks */ | ||
240 | tty->disc_data = codec; | ||
241 | |||
242 | if (tty->ops->write(tty, v253_init, len) != len) { | ||
243 | ret = -EIO; | ||
244 | goto err; | ||
245 | } | ||
246 | /* Actual setup will be performed after the modem responds. */ | ||
247 | return 0; | ||
248 | err: | ||
249 | tty->disc_data = NULL; | ||
250 | return ret; | ||
251 | } | ||
252 | |||
253 | /* Line discipline .close() */ | ||
254 | static void v253_close(struct tty_struct *tty) | ||
255 | { | ||
256 | struct snd_soc_codec *codec = tty->disc_data; | ||
257 | |||
258 | tty->disc_data = NULL; | ||
259 | |||
260 | if (!codec) | ||
261 | return; | ||
262 | |||
263 | /* Prevent the codec driver from further accessing the modem */ | ||
264 | codec->hw_write = NULL; | ||
265 | codec->control_data = NULL; | ||
266 | codec->pop_time = 0; | ||
267 | } | ||
268 | |||
269 | /* Line discipline .hangup() */ | ||
270 | static int v253_hangup(struct tty_struct *tty) | ||
271 | { | ||
272 | v253_close(tty); | ||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | /* Line discipline .receive_buf() */ | ||
277 | static void v253_receive(struct tty_struct *tty, | ||
278 | const unsigned char *cp, char *fp, int count) | ||
279 | { | ||
280 | struct snd_soc_codec *codec = tty->disc_data; | ||
281 | |||
282 | if (!codec) | ||
283 | return; | ||
284 | |||
285 | if (!codec->control_data) { | ||
286 | /* First modem response, complete setup procedure */ | ||
287 | |||
288 | /* Set up codec driver access to modem controls */ | ||
289 | codec->control_data = tty; | ||
290 | codec->hw_write = (hw_write_t)tty->ops->write; | ||
291 | codec->pop_time = 1; | ||
292 | } | ||
293 | } | ||
294 | |||
295 | /* Line discipline .write_wakeup() */ | ||
296 | static void v253_wakeup(struct tty_struct *tty) | ||
297 | { | ||
298 | } | ||
299 | |||
300 | struct tty_ldisc_ops v253_ops = { | ||
301 | .magic = TTY_LDISC_MAGIC, | ||
302 | .name = "cx20442", | ||
303 | .owner = THIS_MODULE, | ||
304 | .open = v253_open, | ||
305 | .close = v253_close, | ||
306 | .hangup = v253_hangup, | ||
307 | .receive_buf = v253_receive, | ||
308 | .write_wakeup = v253_wakeup, | ||
309 | }; | ||
310 | EXPORT_SYMBOL_GPL(v253_ops); | ||
311 | |||
312 | |||
313 | /* | ||
314 | * Codec DAI | ||
315 | */ | ||
316 | |||
211 | struct snd_soc_dai cx20442_dai = { | 317 | struct snd_soc_dai cx20442_dai = { |
212 | .name = "CX20442", | 318 | .name = "CX20442", |
213 | .playback = { | 319 | .playback = { |
@@ -227,8 +333,6 @@ struct snd_soc_dai cx20442_dai = { | |||
227 | }; | 333 | }; |
228 | EXPORT_SYMBOL_GPL(cx20442_dai); | 334 | EXPORT_SYMBOL_GPL(cx20442_dai); |
229 | 335 | ||
230 | static struct snd_soc_codec *cx20442_codec; | ||
231 | |||
232 | static int cx20442_codec_probe(struct platform_device *pdev) | 336 | static int cx20442_codec_probe(struct platform_device *pdev) |
233 | { | 337 | { |
234 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 338 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
@@ -313,13 +417,13 @@ static int cx20442_register(struct cx20442_priv *cx20442) | |||
313 | 417 | ||
314 | ret = snd_soc_register_codec(codec); | 418 | ret = snd_soc_register_codec(codec); |
315 | if (ret != 0) { | 419 | if (ret != 0) { |
316 | dev_err(&codec->dev, "Failed to register codec: %d\n", ret); | 420 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); |
317 | goto err; | 421 | goto err; |
318 | } | 422 | } |
319 | 423 | ||
320 | ret = snd_soc_register_dai(&cx20442_dai); | 424 | ret = snd_soc_register_dai(&cx20442_dai); |
321 | if (ret != 0) { | 425 | if (ret != 0) { |
322 | dev_err(&codec->dev, "Failed to register DAI: %d\n", ret); | 426 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); |
323 | goto err_codec; | 427 | goto err_codec; |
324 | } | 428 | } |
325 | 429 | ||