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 --- Corrections: sound/soc/codecs/cx20442.c line 300: -static struct tty_ldisc_ops v253_ops = { +struct tty_ldisc_ops v253_ops = { line 420: - dev_err(&codec->dev, "Failed to register codec: %d\n", ret); + dev_err(codec->dev, "Failed to register codec: %d\n", ret); line 425: - dev_err(&codec->dev, "Failed to register DAI: %d\n", ret); + dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
Corrected patch:
--- linux-2.6.31-rc3/sound/soc/codecs/cx20442.h.orig 2009-07-22 04:56:45.000000000 +0200 +++ linux-2.6.31-rc3/sound/soc/codecs/cx20442.h 2009-07-28 21:23:17.000000000 +0200 @@ -15,5 +15,6 @@
extern struct snd_soc_dai cx20442_dai; extern struct snd_soc_codec_device cx20442_codec_dev; +extern struct tty_ldisc_ops v253_ops;
#endif --- linux-2.6.31-rc3/sound/soc/codecs/cx20442.c.orig 2009-07-28 20:26:18.000000000 +0200 +++ linux-2.6.31-rc3/sound/soc/codecs/cx20442.c 2009-07-29 02:16:05.000000000 +0200 @@ -13,6 +13,8 @@ * option) any later version. */
+#include <linux/tty.h> + #include <sound/core.h> #include <sound/initval.h> #include <sound/soc-dapm.h> @@ -172,8 +174,7 @@ static int cx20442_write(struct snd_soc_ return -EINVAL;
/* hw_write and control_data pointers required for talking to the modem - * are expected to be set by the machine driver's line discipline - * initialization code */ + * are expected to be set by the line discipline initialization code */ if (!codec->hw_write || !codec->control_data) return -EIO;
@@ -208,6 +209,111 @@ static int cx20442_write(struct snd_soc_ return 0; }
+ +/* Moved up here as line discipline referres it during initialization */ +static struct snd_soc_codec *cx20442_codec; + + +/* + * Line discpline related code + * + * Any of the callback functions below can be used in two ways: + * 1) registerd by a machine driver as one of line discipline operations, + * 2) called from a machine's provided line discipline callback function + * in case when extra machine specific code must be run as well. + */ + +/* Modem init: echo off, digital speaker off, quiet off, voice mode */ +static const char *v253_init = "ate0m0q0+fclass=8\r"; + +/* Line discipline .open() */ +static int v253_open(struct tty_struct *tty) +{ + struct snd_soc_codec *codec = cx20442_codec; + int ret, len = strlen(v253_init); + + /* Doesn't make sense without write callback */ + if (!tty->ops->write) + return -EINVAL; + + /* Pass the codec structure address for use by other ldisc callbacks */ + tty->disc_data = codec; + + if (tty->ops->write(tty, v253_init, len) != len) { + ret = -EIO; + goto err; + } + /* Actual setup will be performed after the modem responds. */ + return 0; +err: + tty->disc_data = NULL; + return ret; +} + +/* Line discipline .close() */ +static void v253_close(struct tty_struct *tty) +{ + struct snd_soc_codec *codec = tty->disc_data; + + tty->disc_data = NULL; + + if (!codec) + return; + + /* Prevent the codec driver from further accessing the modem */ + codec->hw_write = NULL; + codec->control_data = NULL; + codec->pop_time = 0; +} + +/* Line discipline .hangup() */ +static int v253_hangup(struct tty_struct *tty) +{ + v253_close(tty); + return 0; +} + +/* Line discipline .receive_buf() */ +static void v253_receive(struct tty_struct *tty, + const unsigned char *cp, char *fp, int count) +{ + struct snd_soc_codec *codec = tty->disc_data; + + if (!codec) + return; + + if (!codec->control_data) { + /* First modem response, complete setup procedure */ + + /* Set up codec driver access to modem controls */ + codec->control_data = tty; + codec->hw_write = (hw_write_t)tty->ops->write; + codec->pop_time = 1; + } +} + +/* Line discipline .write_wakeup() */ +static void v253_wakeup(struct tty_struct *tty) +{ +} + +struct tty_ldisc_ops v253_ops = { + .magic = TTY_LDISC_MAGIC, + .name = "cx20442", + .owner = THIS_MODULE, + .open = v253_open, + .close = v253_close, + .hangup = v253_hangup, + .receive_buf = v253_receive, + .write_wakeup = v253_wakeup, +}; +EXPORT_SYMBOL_GPL(v253_ops); + + +/* + * Codec DAI + */ + struct snd_soc_dai cx20442_dai = { .name = "CX20442", .playback = { @@ -227,8 +333,6 @@ struct snd_soc_dai cx20442_dai = { }; EXPORT_SYMBOL_GPL(cx20442_dai);
-static struct snd_soc_codec *cx20442_codec; - static int cx20442_codec_probe(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); @@ -313,13 +417,13 @@ static int cx20442_register(struct cx204
ret = snd_soc_register_codec(codec); if (ret != 0) { - dev_err(&codec->dev, "Failed to register codec: %d\n", ret); + dev_err(codec->dev, "Failed to register codec: %d\n", ret); goto err; }
ret = snd_soc_register_dai(&cx20442_dai); if (ret != 0) { - dev_err(&codec->dev, "Failed to register DAI: %d\n", ret); + dev_err(codec->dev, "Failed to register DAI: %d\n", ret); goto err_codec; }