summaryrefslogtreecommitdiff
path: root/drivers/base
diff options
context:
space:
mode:
authorStephen Warren <swarren@nvidia.com>2013-03-20 17:02:02 -0600
committerMark Brown <broonie@opensource.wolfsonmicro.com>2013-03-21 20:08:15 +0100
commitbc8ce4afd7ee7e1421c935d24b1f879f82afdd4e (patch)
treef98e73fc8ad947730682efccf198e1269f2253bf /drivers/base
parent8abac3ba51b5525354e9b2ec0eed1c9e95c905d9 (diff)
downloadlinux-3.10-bc8ce4afd7ee7e1421c935d24b1f879f82afdd4e.tar.gz
linux-3.10-bc8ce4afd7ee7e1421c935d24b1f879f82afdd4e.tar.bz2
linux-3.10-bc8ce4afd7ee7e1421c935d24b1f879f82afdd4e.zip
regmap: don't corrupt work buffer in _regmap_raw_write()
_regmap_raw_write() contains code to call regcache_write() to write values to the cache. That code calls memcpy() to copy the value data to the start of the work_buf. However, at least when _regmap_raw_write() is called from _regmap_bus_raw_write(), the value data is in the work_buf, and this memcpy() operation may over-write part of that value data, depending on the value of reg_bytes + pad_bytes. At least when using reg_bytes==1 and pad_bytes==0, corruption of the value data does occur. To solve this, remove the memcpy() operation, and modify the subsequent .parse_val() call to parse the original value buffer directly. At least in the case of 8-bit register address and 16-bit values, and writes of single registers at a time, this memcpy-then-parse combination used to cancel each-other out; for a work-buffer containing xx 89 03, the memcpy changed it to 89 03 03, and the parse_val changed it back to 89 89 03, thus leaving the value uncorrupted. This appears completely accidental though. Since commit 8a819ff "regmap: core: Split out in place value parsing", .parse_val only returns the parsed value, and does not modify the buffer, and hence does not (accidentally) undo the corruption caused by memcpy(). This caused bogus values to get written to HW, thus preventing e.g. audio playback on systems with a WM8903 CODEC. This patch fixes that. Signed-off-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/regmap/regmap.c3
1 files changed, 1 insertions, 2 deletions
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 3d2367501fd..89a920510e1 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -943,8 +943,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
unsigned int ival;
int val_bytes = map->format.val_bytes;
for (i = 0; i < val_len / val_bytes; i++) {
- memcpy(map->work_buf, val + (i * val_bytes), val_bytes);
- ival = map->format.parse_val(map->work_buf);
+ ival = map->format.parse_val(val + (i * val_bytes));
ret = regcache_write(map, reg + (i * map->reg_stride),
ival);
if (ret) {