memory_accessor: implement the new memory_accessor interfaces for SPI EEPROMs
authorDavid Brownell <dbrownell@users.sourceforge.net>
Thu, 2 Apr 2009 23:56:58 +0000 (16:56 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 3 Apr 2009 02:04:50 +0000 (19:04 -0700)
- 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>
drivers/misc/eeprom/at25.c
include/linux/spi/eeprom.h

index 290dbe9..6bc0dac 100644 (file)
@@ -30,6 +30,7 @@
 
 struct at25_data {
        struct spi_device       *spi;
+       struct memory_accessor  mem;
        struct mutex            lock;
        struct spi_eeprom       chip;
        struct bin_attribute    bin;
@@ -75,6 +76,13 @@ at25_ee_read(
        struct spi_transfer     t[2];
        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++ = AT25_READ;
 
@@ -127,13 +135,6 @@ at25_bin_read(struct kobject *kobj, struct bin_attribute *bin_attr,
        dev = container_of(kobj, struct device, kobj);
        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);
 }
 
@@ -146,6 +147,13 @@ at25_ee_write(struct at25_data *at25, char *buf, loff_t off, size_t count)
        unsigned                buf_size;
        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 */
        buf_size = at25->chip.page_size;
        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);
        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);
 }
 
 /*-------------------------------------------------------------------------*/
 
+/* 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)
 {
        struct at25_data        *at25 = NULL;
@@ -317,6 +338,10 @@ static int at25_probe(struct spi_device *spi)
        at25->addrlen = addrlen;
 
        /* 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
         * that's sensitive for read and/or write, like ethernet addresses,
         * 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.mode = S_IRUSR;
        at25->bin.read = at25_bin_read;
+       at25->mem.read = at25_mem_read;
 
        at25->bin.size = at25->chip.byte_len;
        if (!(chip->flags & EE_READONLY)) {
                at25->bin.write = at25_bin_write;
                at25->bin.attr.mode |= S_IWUSR;
+               at25->mem.write = at25_mem_write;
        }
 
        err = sysfs_create_bin_file(&spi->dev.kobj, &at25->bin);
        if (err)
                goto fail;
 
+       if (chip->setup)
+               chip->setup(&at25->mem, chip->context);
+
        dev_info(&spi->dev, "%Zd %s %s eeprom%s, pagesize %u\n",
                (at25->bin.size < 1024)
                        ? at25->bin.size
index 1085212..306e7b1 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __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
  * 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_ADDR3        0x0004                  /* 24 bit addrs */
 #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 */