diff options
author | Chris Zankel <chris@zankel.net> | 2009-04-03 05:29:05 -0400 |
---|---|---|
committer | Chris Zankel <chris@zankel.net> | 2009-04-03 05:29:05 -0400 |
commit | 65127d28e312bb6b38ce84a7bb71d762ef63ad4c (patch) | |
tree | d5fdf52a2d0731f7fab0ce0ed394faac50b04fbc /drivers/misc/eeprom | |
parent | b8bb76713ec50df2f11efee386e16f93d51e1076 (diff) | |
parent | 8fe74cf053de7ad2124a894996f84fa890a81093 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6 into merge
Diffstat (limited to 'drivers/misc/eeprom')
-rw-r--r-- | drivers/misc/eeprom/at24.c | 67 | ||||
-rw-r--r-- | drivers/misc/eeprom/at25.c | 58 |
2 files changed, 98 insertions, 27 deletions
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index d4775528abc6..d184dfab9631 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c | |||
@@ -53,6 +53,7 @@ | |||
53 | 53 | ||
54 | struct at24_data { | 54 | struct at24_data { |
55 | struct at24_platform_data chip; | 55 | struct at24_platform_data chip; |
56 | struct memory_accessor macc; | ||
56 | bool use_smbus; | 57 | bool use_smbus; |
57 | 58 | ||
58 | /* | 59 | /* |
@@ -225,14 +226,11 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf, | |||
225 | return status; | 226 | return status; |
226 | } | 227 | } |
227 | 228 | ||
228 | static ssize_t at24_bin_read(struct kobject *kobj, struct bin_attribute *attr, | 229 | static ssize_t at24_read(struct at24_data *at24, |
229 | char *buf, loff_t off, size_t count) | 230 | char *buf, loff_t off, size_t count) |
230 | { | 231 | { |
231 | struct at24_data *at24; | ||
232 | ssize_t retval = 0; | 232 | ssize_t retval = 0; |
233 | 233 | ||
234 | at24 = dev_get_drvdata(container_of(kobj, struct device, kobj)); | ||
235 | |||
236 | if (unlikely(!count)) | 234 | if (unlikely(!count)) |
237 | return count; | 235 | return count; |
238 | 236 | ||
@@ -262,12 +260,14 @@ static ssize_t at24_bin_read(struct kobject *kobj, struct bin_attribute *attr, | |||
262 | return retval; | 260 | return retval; |
263 | } | 261 | } |
264 | 262 | ||
263 | static ssize_t at24_bin_read(struct kobject *kobj, struct bin_attribute *attr, | ||
264 | char *buf, loff_t off, size_t count) | ||
265 | { | ||
266 | struct at24_data *at24; | ||
265 | 267 | ||
266 | /* | 268 | at24 = dev_get_drvdata(container_of(kobj, struct device, kobj)); |
267 | * REVISIT: export at24_bin{read,write}() to let other kernel code use | 269 | return at24_read(at24, buf, off, count); |
268 | * eeprom data. For example, it might hold a board's Ethernet address, or | 270 | } |
269 | * board-specific calibration data generated on the manufacturing floor. | ||
270 | */ | ||
271 | 271 | ||
272 | 272 | ||
273 | /* | 273 | /* |
@@ -347,14 +347,11 @@ static ssize_t at24_eeprom_write(struct at24_data *at24, char *buf, | |||
347 | return -ETIMEDOUT; | 347 | return -ETIMEDOUT; |
348 | } | 348 | } |
349 | 349 | ||
350 | static ssize_t at24_bin_write(struct kobject *kobj, struct bin_attribute *attr, | 350 | static ssize_t at24_write(struct at24_data *at24, |
351 | char *buf, loff_t off, size_t count) | 351 | char *buf, loff_t off, size_t count) |
352 | { | 352 | { |
353 | struct at24_data *at24; | ||
354 | ssize_t retval = 0; | 353 | ssize_t retval = 0; |
355 | 354 | ||
356 | at24 = dev_get_drvdata(container_of(kobj, struct device, kobj)); | ||
357 | |||
358 | if (unlikely(!count)) | 355 | if (unlikely(!count)) |
359 | return count; | 356 | return count; |
360 | 357 | ||
@@ -384,6 +381,39 @@ static ssize_t at24_bin_write(struct kobject *kobj, struct bin_attribute *attr, | |||
384 | return retval; | 381 | return retval; |
385 | } | 382 | } |
386 | 383 | ||
384 | static ssize_t at24_bin_write(struct kobject *kobj, struct bin_attribute *attr, | ||
385 | char *buf, loff_t off, size_t count) | ||
386 | { | ||
387 | struct at24_data *at24; | ||
388 | |||
389 | at24 = dev_get_drvdata(container_of(kobj, struct device, kobj)); | ||
390 | return at24_write(at24, buf, off, count); | ||
391 | } | ||
392 | |||
393 | /*-------------------------------------------------------------------------*/ | ||
394 | |||
395 | /* | ||
396 | * This lets other kernel code access the eeprom data. For example, it | ||
397 | * might hold a board's Ethernet address, or board-specific calibration | ||
398 | * data generated on the manufacturing floor. | ||
399 | */ | ||
400 | |||
401 | static ssize_t at24_macc_read(struct memory_accessor *macc, char *buf, | ||
402 | off_t offset, size_t count) | ||
403 | { | ||
404 | struct at24_data *at24 = container_of(macc, struct at24_data, macc); | ||
405 | |||
406 | return at24_read(at24, buf, offset, count); | ||
407 | } | ||
408 | |||
409 | static ssize_t at24_macc_write(struct memory_accessor *macc, char *buf, | ||
410 | off_t offset, size_t count) | ||
411 | { | ||
412 | struct at24_data *at24 = container_of(macc, struct at24_data, macc); | ||
413 | |||
414 | return at24_write(at24, buf, offset, count); | ||
415 | } | ||
416 | |||
387 | /*-------------------------------------------------------------------------*/ | 417 | /*-------------------------------------------------------------------------*/ |
388 | 418 | ||
389 | static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) | 419 | static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) |
@@ -413,6 +443,9 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
413 | * is recommended anyhow. | 443 | * is recommended anyhow. |
414 | */ | 444 | */ |
415 | chip.page_size = 1; | 445 | chip.page_size = 1; |
446 | |||
447 | chip.setup = NULL; | ||
448 | chip.context = NULL; | ||
416 | } | 449 | } |
417 | 450 | ||
418 | if (!is_power_of_2(chip.byte_len)) | 451 | if (!is_power_of_2(chip.byte_len)) |
@@ -463,6 +496,8 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
463 | at24->bin.read = at24_bin_read; | 496 | at24->bin.read = at24_bin_read; |
464 | at24->bin.size = chip.byte_len; | 497 | at24->bin.size = chip.byte_len; |
465 | 498 | ||
499 | at24->macc.read = at24_macc_read; | ||
500 | |||
466 | writable = !(chip.flags & AT24_FLAG_READONLY); | 501 | writable = !(chip.flags & AT24_FLAG_READONLY); |
467 | if (writable) { | 502 | if (writable) { |
468 | if (!use_smbus || i2c_check_functionality(client->adapter, | 503 | if (!use_smbus || i2c_check_functionality(client->adapter, |
@@ -470,6 +505,8 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
470 | 505 | ||
471 | unsigned write_max = chip.page_size; | 506 | unsigned write_max = chip.page_size; |
472 | 507 | ||
508 | at24->macc.write = at24_macc_write; | ||
509 | |||
473 | at24->bin.write = at24_bin_write; | 510 | at24->bin.write = at24_bin_write; |
474 | at24->bin.attr.mode |= S_IWUSR; | 511 | at24->bin.attr.mode |= S_IWUSR; |
475 | 512 | ||
@@ -520,6 +557,10 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
520 | at24->write_max, | 557 | at24->write_max, |
521 | use_smbus ? ", use_smbus" : ""); | 558 | use_smbus ? ", use_smbus" : ""); |
522 | 559 | ||
560 | /* export data to kernel code */ | ||
561 | if (chip.setup) | ||
562 | chip.setup(&at24->macc, chip.context); | ||
563 | |||
523 | return 0; | 564 | return 0; |
524 | 565 | ||
525 | err_clients: | 566 | err_clients: |
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 |