diff options
author | David Brownell <dbrownell@users.sourceforge.net> | 2009-04-02 19:56:58 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-04-02 22:04:50 -0400 |
commit | 14dd1ff0f9e75dd4ae2f1ff8e48becb76d14f4ab (patch) | |
tree | a9e208f0c35c8e24ed0edb8a1bc5ca9a4dc9b585 /drivers/misc/eeprom | |
parent | 7274ec8bd71e99018642f474528ea7de4bb3ae25 (diff) |
memory_accessor: implement the new memory_accessor interfaces for SPI EEPROMs
- Define new setup() hook to export the accessor
- Implement accessor methods
Moves some error checking out of the sysfs interface code into the layer
below it, which is now shared by both sysfs and memory access code.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
Cc: Jean Delvare <khali@linux-fr.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/misc/eeprom')
-rw-r--r-- | drivers/misc/eeprom/at25.c | 58 |
1 files changed, 44 insertions, 14 deletions
diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c index 290dbe99647a..6bc0dac5c1e8 100644 --- a/drivers/misc/eeprom/at25.c +++ b/drivers/misc/eeprom/at25.c | |||
@@ -30,6 +30,7 @@ | |||
30 | 30 | ||
31 | struct at25_data { | 31 | struct at25_data { |
32 | struct spi_device *spi; | 32 | struct spi_device *spi; |
33 | struct memory_accessor mem; | ||
33 | struct mutex lock; | 34 | struct mutex lock; |
34 | struct spi_eeprom chip; | 35 | struct spi_eeprom chip; |
35 | struct bin_attribute bin; | 36 | struct bin_attribute bin; |
@@ -75,6 +76,13 @@ at25_ee_read( | |||
75 | struct spi_transfer t[2]; | 76 | struct spi_transfer t[2]; |
76 | struct spi_message m; | 77 | struct spi_message m; |
77 | 78 | ||
79 | if (unlikely(offset >= at25->bin.size)) | ||
80 | return 0; | ||
81 | if ((offset + count) > at25->bin.size) | ||
82 | count = at25->bin.size - offset; | ||
83 | if (unlikely(!count)) | ||
84 | return count; | ||
85 | |||
78 | cp = command; | 86 | cp = command; |
79 | *cp++ = AT25_READ; | 87 | *cp++ = AT25_READ; |
80 | 88 | ||
@@ -127,13 +135,6 @@ at25_bin_read(struct kobject *kobj, struct bin_attribute *bin_attr, | |||
127 | dev = container_of(kobj, struct device, kobj); | 135 | dev = container_of(kobj, struct device, kobj); |
128 | at25 = dev_get_drvdata(dev); | 136 | at25 = dev_get_drvdata(dev); |
129 | 137 | ||
130 | if (unlikely(off >= at25->bin.size)) | ||
131 | return 0; | ||
132 | if ((off + count) > at25->bin.size) | ||
133 | count = at25->bin.size - off; | ||
134 | if (unlikely(!count)) | ||
135 | return count; | ||
136 | |||
137 | return at25_ee_read(at25, buf, off, count); | 138 | return at25_ee_read(at25, buf, off, count); |
138 | } | 139 | } |
139 | 140 | ||
@@ -146,6 +147,13 @@ at25_ee_write(struct at25_data *at25, char *buf, loff_t off, size_t count) | |||
146 | unsigned buf_size; | 147 | unsigned buf_size; |
147 | u8 *bounce; | 148 | u8 *bounce; |
148 | 149 | ||
150 | if (unlikely(off >= at25->bin.size)) | ||
151 | return -EFBIG; | ||
152 | if ((off + count) > at25->bin.size) | ||
153 | count = at25->bin.size - off; | ||
154 | if (unlikely(!count)) | ||
155 | return count; | ||
156 | |||
149 | /* Temp buffer starts with command and address */ | 157 | /* Temp buffer starts with command and address */ |
150 | buf_size = at25->chip.page_size; | 158 | buf_size = at25->chip.page_size; |
151 | if (buf_size > io_limit) | 159 | if (buf_size > io_limit) |
@@ -253,18 +261,31 @@ at25_bin_write(struct kobject *kobj, struct bin_attribute *bin_attr, | |||
253 | dev = container_of(kobj, struct device, kobj); | 261 | dev = container_of(kobj, struct device, kobj); |
254 | at25 = dev_get_drvdata(dev); | 262 | at25 = dev_get_drvdata(dev); |
255 | 263 | ||
256 | if (unlikely(off >= at25->bin.size)) | ||
257 | return -EFBIG; | ||
258 | if ((off + count) > at25->bin.size) | ||
259 | count = at25->bin.size - off; | ||
260 | if (unlikely(!count)) | ||
261 | return count; | ||
262 | |||
263 | return at25_ee_write(at25, buf, off, count); | 264 | return at25_ee_write(at25, buf, off, count); |
264 | } | 265 | } |
265 | 266 | ||
266 | /*-------------------------------------------------------------------------*/ | 267 | /*-------------------------------------------------------------------------*/ |
267 | 268 | ||
269 | /* Let in-kernel code access the eeprom data. */ | ||
270 | |||
271 | static ssize_t at25_mem_read(struct memory_accessor *mem, char *buf, | ||
272 | off_t offset, size_t count) | ||
273 | { | ||
274 | struct at25_data *at25 = container_of(mem, struct at25_data, mem); | ||
275 | |||
276 | return at25_ee_read(at25, buf, offset, count); | ||
277 | } | ||
278 | |||
279 | static ssize_t at25_mem_write(struct memory_accessor *mem, char *buf, | ||
280 | off_t offset, size_t count) | ||
281 | { | ||
282 | struct at25_data *at25 = container_of(mem, struct at25_data, mem); | ||
283 | |||
284 | return at25_ee_write(at25, buf, offset, count); | ||
285 | } | ||
286 | |||
287 | /*-------------------------------------------------------------------------*/ | ||
288 | |||
268 | static int at25_probe(struct spi_device *spi) | 289 | static int at25_probe(struct spi_device *spi) |
269 | { | 290 | { |
270 | struct at25_data *at25 = NULL; | 291 | struct at25_data *at25 = NULL; |
@@ -317,6 +338,10 @@ static int at25_probe(struct spi_device *spi) | |||
317 | at25->addrlen = addrlen; | 338 | at25->addrlen = addrlen; |
318 | 339 | ||
319 | /* Export the EEPROM bytes through sysfs, since that's convenient. | 340 | /* Export the EEPROM bytes through sysfs, since that's convenient. |
341 | * And maybe to other kernel code; it might hold a board's Ethernet | ||
342 | * address, or board-specific calibration data generated on the | ||
343 | * manufacturing floor. | ||
344 | * | ||
320 | * Default to root-only access to the data; EEPROMs often hold data | 345 | * Default to root-only access to the data; EEPROMs often hold data |
321 | * that's sensitive for read and/or write, like ethernet addresses, | 346 | * that's sensitive for read and/or write, like ethernet addresses, |
322 | * security codes, board-specific manufacturing calibrations, etc. | 347 | * security codes, board-specific manufacturing calibrations, etc. |
@@ -324,17 +349,22 @@ static int at25_probe(struct spi_device *spi) | |||
324 | at25->bin.attr.name = "eeprom"; | 349 | at25->bin.attr.name = "eeprom"; |
325 | at25->bin.attr.mode = S_IRUSR; | 350 | at25->bin.attr.mode = S_IRUSR; |
326 | at25->bin.read = at25_bin_read; | 351 | at25->bin.read = at25_bin_read; |
352 | at25->mem.read = at25_mem_read; | ||
327 | 353 | ||
328 | at25->bin.size = at25->chip.byte_len; | 354 | at25->bin.size = at25->chip.byte_len; |
329 | if (!(chip->flags & EE_READONLY)) { | 355 | if (!(chip->flags & EE_READONLY)) { |
330 | at25->bin.write = at25_bin_write; | 356 | at25->bin.write = at25_bin_write; |
331 | at25->bin.attr.mode |= S_IWUSR; | 357 | at25->bin.attr.mode |= S_IWUSR; |
358 | at25->mem.write = at25_mem_write; | ||
332 | } | 359 | } |
333 | 360 | ||
334 | err = sysfs_create_bin_file(&spi->dev.kobj, &at25->bin); | 361 | err = sysfs_create_bin_file(&spi->dev.kobj, &at25->bin); |
335 | if (err) | 362 | if (err) |
336 | goto fail; | 363 | goto fail; |
337 | 364 | ||
365 | if (chip->setup) | ||
366 | chip->setup(&at25->mem, chip->context); | ||
367 | |||
338 | dev_info(&spi->dev, "%Zd %s %s eeprom%s, pagesize %u\n", | 368 | dev_info(&spi->dev, "%Zd %s %s eeprom%s, pagesize %u\n", |
339 | (at25->bin.size < 1024) | 369 | (at25->bin.size < 1024) |
340 | ? at25->bin.size | 370 | ? at25->bin.size |