aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorDimitris Papastamos <dp@opensource.wolfsonmicro.com>2011-02-02 08:58:58 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2011-02-02 15:48:15 -0500
commit13fd179f14712cc89b5b3812673891b96e0ab3a2 (patch)
tree95a39581df65cfc413c33ce8f77e43857fb2b886 /sound
parenta591e969fae8b79484cb94a12aceb9799e06ac22 (diff)
ASoC: soc-core: Support debugfs entries larger than PAGE_SIZE bytes
For some codecs with large register maps, it was not possible to dump all registers via the codec_reg file but only up to PAGE_SIZE bytes. This patch fixes this problem. Signed-off-by: Dimitris Papastamos <dp@opensource.wolfsonmicro.com> Acked-by: Liam Girdwood <lrg@slimlogic.co.uk> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/soc-core.c110
1 files changed, 73 insertions, 37 deletions
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 10bc3c23b525..0c789f9150c3 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -87,15 +87,56 @@ static int min_bytes_needed(unsigned long val)
87 return c; 87 return c;
88} 88}
89 89
90/* fill buf which is 'len' bytes with a formatted
91 * string of the form 'reg: value\n' */
92static int format_register_str(struct snd_soc_codec *codec,
93 unsigned int reg, char *buf, size_t len)
94{
95 int wordsize = codec->driver->reg_word_size * 2;
96 int regsize = min_bytes_needed(codec->driver->reg_cache_size) * 2;
97 int ret;
98 char tmpbuf[len + 1];
99 char regbuf[regsize + 1];
100
101 /* since tmpbuf is allocated on the stack, warn the callers if they
102 * try to abuse this function */
103 WARN_ON(len > 63);
104
105 /* +2 for ': ' and + 1 for '\n' */
106 if (wordsize + regsize + 2 + 1 != len)
107 return -EINVAL;
108
109 ret = snd_soc_read(codec , reg);
110 if (ret < 0) {
111 memset(regbuf, 'X', regsize);
112 regbuf[regsize] = '\0';
113 } else {
114 snprintf(regbuf, regsize + 1, "%.*x", regsize, ret);
115 }
116
117 /* prepare the buffer */
118 snprintf(tmpbuf, len + 1, "%.*x: %s\n", wordsize, reg, regbuf);
119 /* copy it back to the caller without the '\0' */
120 memcpy(buf, tmpbuf, len);
121
122 return 0;
123}
124
90/* codec register dump */ 125/* codec register dump */
91static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf) 126static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf,
127 size_t count, loff_t pos)
92{ 128{
93 int ret, i, step = 1, count = 0; 129 int i, step = 1;
94 int wordsize, regsize; 130 int wordsize, regsize;
131 int len;
132 size_t total = 0;
133 loff_t p = 0;
95 134
96 wordsize = codec->driver->reg_word_size * 2; 135 wordsize = codec->driver->reg_word_size * 2;
97 regsize = min_bytes_needed(codec->driver->reg_cache_size) * 2; 136 regsize = min_bytes_needed(codec->driver->reg_cache_size) * 2;
98 137
138 len = wordsize + regsize + 2 + 1;
139
99 if (!codec->driver->reg_cache_size) 140 if (!codec->driver->reg_cache_size)
100 return 0; 141 return 0;
101 142
@@ -105,51 +146,34 @@ static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf)
105 for (i = 0; i < codec->driver->reg_cache_size; i += step) { 146 for (i = 0; i < codec->driver->reg_cache_size; i += step) {
106 if (codec->readable_register && !codec->readable_register(codec, i)) 147 if (codec->readable_register && !codec->readable_register(codec, i))
107 continue; 148 continue;
108
109 count += sprintf(buf + count, "%.*x: ", regsize, i);
110 if (count >= PAGE_SIZE - 1)
111 break;
112
113 if (codec->driver->display_register) { 149 if (codec->driver->display_register) {
114 count += codec->driver->display_register(codec, buf + count, 150 count += codec->driver->display_register(codec, buf + count,
115 PAGE_SIZE - count, i); 151 PAGE_SIZE - count, i);
116 } else { 152 } else {
117 /* If the read fails it's almost certainly due to 153 /* only support larger than PAGE_SIZE bytes debugfs
118 * the register being volatile and the device being 154 * entries for the default case */
119 * powered off. 155 if (p >= pos) {
120 */ 156 if (total + len >= count - 1)
121 ret = snd_soc_read(codec, i); 157 break;
122 if (ret >= 0) 158 format_register_str(codec, i, buf + total, len);
123 count += snprintf(buf + count, 159 total += len;
124 PAGE_SIZE - count, 160 }
125 "%.*x", wordsize, ret); 161 p += len;
126 else
127 count += snprintf(buf + count,
128 PAGE_SIZE - count,
129 "<no data: %d>", ret);
130 } 162 }
131
132 if (count >= PAGE_SIZE - 1)
133 break;
134
135 count += snprintf(buf + count, PAGE_SIZE - count, "\n");
136 if (count >= PAGE_SIZE - 1)
137 break;
138 } 163 }
139 164
140 /* Truncate count; min() would cause a warning */ 165 total = min(total, count - 1);
141 if (count >= PAGE_SIZE)
142 count = PAGE_SIZE - 1;
143 166
144 return count; 167 return total;
145} 168}
169
146static ssize_t codec_reg_show(struct device *dev, 170static ssize_t codec_reg_show(struct device *dev,
147 struct device_attribute *attr, char *buf) 171 struct device_attribute *attr, char *buf)
148{ 172{
149 struct snd_soc_pcm_runtime *rtd = 173 struct snd_soc_pcm_runtime *rtd =
150 container_of(dev, struct snd_soc_pcm_runtime, dev); 174 container_of(dev, struct snd_soc_pcm_runtime, dev);
151 175
152 return soc_codec_reg_show(rtd->codec, buf); 176 return soc_codec_reg_show(rtd->codec, buf, PAGE_SIZE, 0);
153} 177}
154 178
155static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL); 179static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL);
@@ -188,16 +212,28 @@ static int codec_reg_open_file(struct inode *inode, struct file *file)
188} 212}
189 213
190static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf, 214static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf,
191 size_t count, loff_t *ppos) 215 size_t count, loff_t *ppos)
192{ 216{
193 ssize_t ret; 217 ssize_t ret;
194 struct snd_soc_codec *codec = file->private_data; 218 struct snd_soc_codec *codec = file->private_data;
195 char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); 219 char *buf;
220
221 if (*ppos < 0 || !count)
222 return -EINVAL;
223
224 buf = kmalloc(count, GFP_KERNEL);
196 if (!buf) 225 if (!buf)
197 return -ENOMEM; 226 return -ENOMEM;
198 ret = soc_codec_reg_show(codec, buf); 227
199 if (ret >= 0) 228 ret = soc_codec_reg_show(codec, buf, count, *ppos);
200 ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); 229 if (ret >= 0) {
230 if (copy_to_user(user_buf, buf, ret)) {
231 kfree(buf);
232 return -EFAULT;
233 }
234 *ppos += ret;
235 }
236
201 kfree(buf); 237 kfree(buf);
202 return ret; 238 return ret;
203} 239}