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>
This commit is contained in:
parent
7274ec8bd7
commit
14dd1ff0f9
|
@ -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(
|
||||||
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,
|
||||||
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)
|
||||||
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,
|
||||||
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)
|
||||||
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)
|
||||||
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
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#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 {
|
||||||
#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 */
|
||||||
|
|
Reference in New Issue