Commit 14dd1ff0 authored by David Brownell's avatar David Brownell Committed by Linus Torvalds

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: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarKevin Hilman <khilman@deeprootsystems.com>
Cc: Jean Delvare <khali@linux-fr.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 7274ec8b
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
struct at25_data { struct at25_data {
struct spi_device *spi; struct spi_device *spi;
struct memory_accessor mem;
struct mutex lock; struct mutex lock;
struct spi_eeprom chip; struct spi_eeprom chip;
struct bin_attribute bin; struct bin_attribute bin;
...@@ -75,6 +76,13 @@ at25_ee_read( ...@@ -75,6 +76,13 @@ at25_ee_read(
struct spi_transfer t[2]; struct spi_transfer t[2];
struct spi_message m; struct spi_message m;
if (unlikely(offset >= at25->bin.size))
return 0;
if ((offset + count) > at25->bin.size)
count = at25->bin.size - offset;
if (unlikely(!count))
return count;
cp = command; cp = command;
*cp++ = AT25_READ; *cp++ = AT25_READ;
...@@ -127,13 +135,6 @@ at25_bin_read(struct kobject *kobj, struct bin_attribute *bin_attr, ...@@ -127,13 +135,6 @@ at25_bin_read(struct kobject *kobj, struct bin_attribute *bin_attr,
dev = container_of(kobj, struct device, kobj); dev = container_of(kobj, struct device, kobj);
at25 = dev_get_drvdata(dev); at25 = dev_get_drvdata(dev);
if (unlikely(off >= at25->bin.size))
return 0;
if ((off + count) > at25->bin.size)
count = at25->bin.size - off;
if (unlikely(!count))
return count;
return at25_ee_read(at25, buf, off, count); return at25_ee_read(at25, buf, off, count);
} }
...@@ -146,6 +147,13 @@ at25_ee_write(struct at25_data *at25, char *buf, loff_t off, size_t count) ...@@ -146,6 +147,13 @@ at25_ee_write(struct at25_data *at25, char *buf, loff_t off, size_t count)
unsigned buf_size; unsigned buf_size;
u8 *bounce; u8 *bounce;
if (unlikely(off >= at25->bin.size))
return -EFBIG;
if ((off + count) > at25->bin.size)
count = at25->bin.size - off;
if (unlikely(!count))
return count;
/* Temp buffer starts with command and address */ /* Temp buffer starts with command and address */
buf_size = at25->chip.page_size; buf_size = at25->chip.page_size;
if (buf_size > io_limit) if (buf_size > io_limit)
...@@ -253,18 +261,31 @@ at25_bin_write(struct kobject *kobj, struct bin_attribute *bin_attr, ...@@ -253,18 +261,31 @@ at25_bin_write(struct kobject *kobj, struct bin_attribute *bin_attr,
dev = container_of(kobj, struct device, kobj); dev = container_of(kobj, struct device, kobj);
at25 = dev_get_drvdata(dev); at25 = dev_get_drvdata(dev);
if (unlikely(off >= at25->bin.size))
return -EFBIG;
if ((off + count) > at25->bin.size)
count = at25->bin.size - off;
if (unlikely(!count))
return count;
return at25_ee_write(at25, buf, off, count); return at25_ee_write(at25, buf, off, count);
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/* Let in-kernel code access the eeprom data. */
static ssize_t at25_mem_read(struct memory_accessor *mem, char *buf,
off_t offset, size_t count)
{
struct at25_data *at25 = container_of(mem, struct at25_data, mem);
return at25_ee_read(at25, buf, offset, count);
}
static ssize_t at25_mem_write(struct memory_accessor *mem, char *buf,
off_t offset, size_t count)
{
struct at25_data *at25 = container_of(mem, struct at25_data, mem);
return at25_ee_write(at25, buf, offset, count);
}
/*-------------------------------------------------------------------------*/
static int at25_probe(struct spi_device *spi) static int at25_probe(struct spi_device *spi)
{ {
struct at25_data *at25 = NULL; struct at25_data *at25 = NULL;
...@@ -317,6 +338,10 @@ static int at25_probe(struct spi_device *spi) ...@@ -317,6 +338,10 @@ static int at25_probe(struct spi_device *spi)
at25->addrlen = addrlen; at25->addrlen = addrlen;
/* Export the EEPROM bytes through sysfs, since that's convenient. /* Export the EEPROM bytes through sysfs, since that's convenient.
* And maybe to other kernel code; it might hold a board's Ethernet
* address, or board-specific calibration data generated on the
* manufacturing floor.
*
* Default to root-only access to the data; EEPROMs often hold data * Default to root-only access to the data; EEPROMs often hold data
* that's sensitive for read and/or write, like ethernet addresses, * that's sensitive for read and/or write, like ethernet addresses,
* security codes, board-specific manufacturing calibrations, etc. * security codes, board-specific manufacturing calibrations, etc.
...@@ -324,17 +349,22 @@ static int at25_probe(struct spi_device *spi) ...@@ -324,17 +349,22 @@ static int at25_probe(struct spi_device *spi)
at25->bin.attr.name = "eeprom"; at25->bin.attr.name = "eeprom";
at25->bin.attr.mode = S_IRUSR; at25->bin.attr.mode = S_IRUSR;
at25->bin.read = at25_bin_read; at25->bin.read = at25_bin_read;
at25->mem.read = at25_mem_read;
at25->bin.size = at25->chip.byte_len; at25->bin.size = at25->chip.byte_len;
if (!(chip->flags & EE_READONLY)) { if (!(chip->flags & EE_READONLY)) {
at25->bin.write = at25_bin_write; at25->bin.write = at25_bin_write;
at25->bin.attr.mode |= S_IWUSR; at25->bin.attr.mode |= S_IWUSR;
at25->mem.write = at25_mem_write;
} }
err = sysfs_create_bin_file(&spi->dev.kobj, &at25->bin); err = sysfs_create_bin_file(&spi->dev.kobj, &at25->bin);
if (err) if (err)
goto fail; goto fail;
if (chip->setup)
chip->setup(&at25->mem, chip->context);
dev_info(&spi->dev, "%Zd %s %s eeprom%s, pagesize %u\n", dev_info(&spi->dev, "%Zd %s %s eeprom%s, pagesize %u\n",
(at25->bin.size < 1024) (at25->bin.size < 1024)
? at25->bin.size ? at25->bin.size
......
#ifndef __LINUX_SPI_EEPROM_H #ifndef __LINUX_SPI_EEPROM_H
#define __LINUX_SPI_EEPROM_H #define __LINUX_SPI_EEPROM_H
#include <linux/memory.h>
/* /*
* Put one of these structures in platform_data for SPI EEPROMS handled * Put one of these structures in platform_data for SPI EEPROMS handled
* by the "at25" driver. On SPI, most EEPROMS understand the same core * by the "at25" driver. On SPI, most EEPROMS understand the same core
...@@ -17,6 +19,10 @@ struct spi_eeprom { ...@@ -17,6 +19,10 @@ struct spi_eeprom {
#define EE_ADDR2 0x0002 /* 16 bit addrs */ #define EE_ADDR2 0x0002 /* 16 bit addrs */
#define EE_ADDR3 0x0004 /* 24 bit addrs */ #define EE_ADDR3 0x0004 /* 24 bit addrs */
#define EE_READONLY 0x0008 /* disallow writes */ #define EE_READONLY 0x0008 /* disallow writes */
/* for exporting this chip's data to other kernel code */
void (*setup)(struct memory_accessor *mem, void *context);
void *context;
}; };
#endif /* __LINUX_SPI_EEPROM_H */ #endif /* __LINUX_SPI_EEPROM_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment