summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--commands/mem.c12
-rw-r--r--common/partition.c44
-rw-r--r--drivers/cfi_flash.c3
-rw-r--r--fs/cramfs/cramfs.c7
-rw-r--r--fs/devfs.c36
-rw-r--r--fs/fs.c34
-rw-r--r--fs/ramfs.c7
-rw-r--r--include/driver.h26
-rw-r--r--include/fs.h3
-rw-r--r--lib/driver.c32
10 files changed, 194 insertions, 10 deletions
diff --git a/commands/mem.c b/commands/mem.c
index be71ee4cec..f7b9e4bb60 100644
--- a/commands/mem.c
+++ b/commands/mem.c
@@ -120,6 +120,9 @@ int open_and_lseek(const char *filename, int mode, ulong pos)
return fd;
}
+ if (!pos)
+ return fd;
+
ret = lseek(fd, pos, SEEK_SET);
if (ret < 0) {
perror("lseek");
@@ -525,22 +528,31 @@ static struct device_d mem_dev = {
static struct driver_d mem_drv = {
.name = "mem",
.probe = dummy_probe,
+ .open = dev_open_default,
+ .close = dev_close_default,
.read = mem_read,
.write = mem_write,
+ .lseek = dev_lseek_default,
};
static struct driver_d ram_drv = {
.name = "ram",
.probe = dummy_probe,
+ .open = dev_open_default,
+ .close = dev_close_default,
.read = mem_read,
.write = mem_write,
+ .lseek = dev_lseek_default,
.type = DEVICE_TYPE_DRAM,
};
static struct driver_d rom_drv = {
.name = "rom",
.probe = dummy_probe,
+ .open = dev_open_default,
+ .close = dev_close_default,
.read = mem_read,
+ .lseek = dev_lseek_default,
};
static int mem_init(void)
diff --git a/common/partition.c b/common/partition.c
index 4942ffdf55..4721bc1c13 100644
--- a/common/partition.c
+++ b/common/partition.c
@@ -32,6 +32,9 @@
#include <errno.h>
#include <partition.h>
#include <xfuncs.h>
+#include <ioctl.h>
+#include <nand.h>
+#include <linux/mtd/mtd-abi.h>
/**
* Add one partition on top of a device, as a device.
@@ -168,6 +171,43 @@ static ssize_t part_write(struct device_d *dev, const void *buf, size_t count,
return dev_write(part->physdev, buf, count, offset + part->offset, flags);
}
+static off_t part_lseek(struct device_d *dev, off_t ofs)
+{
+ struct partition *part = dev->type_data;
+
+ return dev_lseek(part->physdev, ofs);
+}
+
+static int part_open(struct device_d *dev, struct filep *f)
+{
+ struct partition *part = dev->type_data;
+
+ return dev_open(part->physdev, f);
+}
+
+static int part_close(struct device_d *dev, struct filep *f)
+{
+ struct partition *part = dev->type_data;
+
+ return dev_close(part->physdev, f);
+}
+
+static int part_ioctl(struct device_d *dev, int request,
+ void *buf)
+{
+ struct partition *part = dev->type_data;
+ off_t offset;
+
+ switch (request) {
+ case MEMGETBADBLOCK:
+ offset = (off_t)buf;
+ offset += part->offset;
+ return dev_ioctl(part->physdev, request, (void *)offset);
+ }
+
+ return -ENOSYS;
+}
+
/**
* FIXME.
* @param[in] dev The partition info as a device
@@ -201,8 +241,12 @@ struct driver_d part_driver = {
.name = "partition",
.probe = part_probe,
.remove = part_remove,
+ .open = part_open,
+ .close = part_close,
+ .ioctl = part_ioctl,
.read = part_read,
.write = part_write,
+ .lseek = part_lseek,
.erase = part_erase,
.protect= part_protect,
.memmap = part_memmap,
diff --git a/drivers/cfi_flash.c b/drivers/cfi_flash.c
index a859741c84..4bdd2f656f 100644
--- a/drivers/cfi_flash.c
+++ b/drivers/cfi_flash.c
@@ -524,6 +524,9 @@ static struct driver_d cfi_driver = {
.probe = cfi_probe,
.read = mem_read,
.write = cfi_write,
+ .lseek = dev_lseek_default,
+ .open = dev_open_default,
+ .close = dev_close_default,
.erase = cfi_erase,
.protect= cfi_protect,
.memmap = generic_memmap_ro,
diff --git a/fs/cramfs/cramfs.c b/fs/cramfs/cramfs.c
index 9c08ad5a29..62f15d6271 100644
--- a/fs/cramfs/cramfs.c
+++ b/fs/cramfs/cramfs.c
@@ -352,6 +352,12 @@ static int cramfs_read(struct device_d *_dev, FILE *f, void *buf, size_t size)
return outsize;
}
+static off_t cramfs_lseek(struct device_d *dev, FILE *f, off_t pos)
+{
+ f->pos = pos;
+ return f->pos;
+}
+
static int cramfs_stat(struct device_d *_dev, const char *filename, struct stat *stat)
{
struct cramfs_priv *priv = _dev->priv;
@@ -443,6 +449,7 @@ static struct fs_driver_d cramfs_driver = {
.open = cramfs_open,
.close = cramfs_close,
.read = cramfs_read,
+ .lseek = cramfs_lseek,
.opendir = cramfs_opendir,
.readdir = cramfs_readdir,
.closedir = cramfs_closedir,
diff --git a/fs/devfs.c b/fs/devfs.c
index 10c2dfeab6..12abc1829d 100644
--- a/fs/devfs.c
+++ b/fs/devfs.c
@@ -44,6 +44,19 @@ static int devfs_write(struct device_d *_dev, FILE *f, const void *buf, size_t s
return dev_write(dev, buf, size, f->pos, f->flags);
}
+static off_t devfs_lseek(struct device_d *_dev, FILE *f, off_t pos)
+{
+ struct device_d *dev = f->inode;
+ int ret;
+
+ ret = dev_lseek(dev, pos);
+
+ if (ret >= 0)
+ f->pos = pos;
+
+ return ret;
+}
+
static int devfs_erase(struct device_d *_dev, FILE *f, size_t count, unsigned long offset)
{
struct device_d *dev = f->inode;
@@ -65,21 +78,30 @@ static int devfs_memmap(struct device_d *_dev, FILE *f, void **map, int flags)
return dev_memmap(dev, map, flags);
}
-static int devfs_open(struct device_d *_dev, FILE *file, const char *filename)
+static int devfs_open(struct device_d *_dev, FILE *f, const char *filename)
{
struct device_d *dev = get_device_by_id(filename + 1);
if (!dev)
return -ENOENT;
- file->size = dev->size;
- file->inode = dev;
- return 0;
+ f->size = dev->size;
+ f->inode = dev;
+ return dev_open(dev, f);
}
-static int devfs_close(struct device_d *dev, FILE *f)
+static int devfs_close(struct device_d *_dev, FILE *f)
{
- return 0;
+ struct device_d *dev = f->inode;
+
+ return dev_close(dev, f);
+}
+
+static int devfs_ioctl(struct device_d *_dev, FILE *f, int request, void *buf)
+{
+ struct device_d *dev = f->inode;
+
+ return dev_ioctl(dev, request, buf);
}
static int devfs_truncate(struct device_d *dev, FILE *f, ulong size)
@@ -156,8 +178,10 @@ static struct fs_driver_d devfs_driver = {
.type = FS_TYPE_DEVFS,
.read = devfs_read,
.write = devfs_write,
+ .lseek = devfs_lseek,
.open = devfs_open,
.close = devfs_close,
+ .ioctl = devfs_ioctl,
.opendir = devfs_opendir,
.readdir = devfs_readdir,
.truncate = devfs_truncate,
diff --git a/fs/fs.c b/fs/fs.c
index 2d90df3f5f..3f0f1345fb 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -451,6 +451,22 @@ int creat(const char *pathname, mode_t mode)
}
EXPORT_SYMBOL(creat);
+int ioctl(int fd, int request, void *buf)
+{
+ struct device_d *dev;
+ struct fs_driver_d *fsdrv;
+ FILE *f = &files[fd];
+
+ dev = f->dev;
+
+ fsdrv = (struct fs_driver_d *)dev->driver->type_data;
+
+ if (fsdrv->ioctl)
+ return fsdrv->ioctl(dev, f, request, buf);
+
+ return -ENOSYS;
+}
+
int read(int fd, void *buf, size_t count)
{
struct device_d *dev;
@@ -496,30 +512,40 @@ EXPORT_SYMBOL(write);
off_t lseek(int fildes, off_t offset, int whence)
{
+ struct device_d *dev;
+ struct fs_driver_d *fsdrv;
FILE *f = &files[fildes];
+ ulong pos;
+
errno = 0;
+ dev = f->dev;
+ fsdrv = (struct fs_driver_d *)dev->driver->type_data;
+ if (!fsdrv->lseek)
+ return -ENOSYS;
+
switch(whence) {
case SEEK_SET:
if (offset > f->size)
goto out;
- f->pos = offset;
+ pos = offset;
break;
case SEEK_CUR:
if (offset + f->pos > f->size)
goto out;
- f->pos += offset;
+ pos = f->pos + offset;
break;
case SEEK_END:
if (offset)
goto out;
- f->pos = f->size;
+ pos = f->size;
break;
default:
goto out;
}
- return 0;
+ return fsdrv->lseek(dev, f, pos);
+
out:
errno = -EINVAL;
return errno;
diff --git a/fs/ramfs.c b/fs/ramfs.c
index 38ef035d53..beee6b9256 100644
--- a/fs/ramfs.c
+++ b/fs/ramfs.c
@@ -403,6 +403,12 @@ static int ramfs_write(struct device_d *_dev, FILE *f, const void *buf, size_t i
return insize;
}
+static off_t ramfs_lseek(struct device_d *dev, FILE *f, off_t pos)
+{
+ f->pos = pos;
+ return f->pos;
+}
+
static int ramfs_truncate(struct device_d *dev, FILE *f, ulong size)
{
struct ramfs_inode *node = (struct ramfs_inode *)f->inode;
@@ -540,6 +546,7 @@ static struct fs_driver_d ramfs_driver = {
.truncate = ramfs_truncate,
.read = ramfs_read,
.write = ramfs_write,
+ .lseek = ramfs_lseek,
.mkdir = ramfs_mkdir,
.rmdir = ramfs_rmdir,
.opendir = ramfs_opendir,
diff --git a/include/driver.h b/include/driver.h
index cade9fdfb6..4000ba689e 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -64,6 +64,8 @@
/*@{*/ /* do not delete, doxygen relevant */
+struct filep;
+
/** @brief Describes a particular device present in the system */
struct device_d {
/*! This member (and 'type' described below) is used to match with a
@@ -131,6 +133,11 @@ struct driver_d {
/*! Called in response of write to this device. Required */
ssize_t (*write) (struct device_d*, const void* buf, size_t count, ulong offset, ulong flags);
+ int (*ioctl) (struct device_d*, int, void *);
+
+ off_t (*lseek) (struct device_d*, off_t);
+ int (*open) (struct device_d*, struct filep*);
+ int (*close) (struct device_d*, struct filep*);
int (*erase) (struct device_d*, size_t count, unsigned long offset);
int (*protect)(struct device_d*, size_t count, unsigned long offset, int prot);
@@ -219,6 +226,10 @@ struct driver_d *get_driver_by_name(const char *name);
ssize_t dev_read(struct device_d *dev, void *buf, size_t count, ulong offset, ulong flags);
ssize_t dev_write(struct device_d *dev, const void *buf, size_t count, ulong offset, ulong flags);
+int dev_open(struct device_d *dev, struct filep *);
+int dev_close(struct device_d *dev, struct filep *);
+int dev_ioctl(struct device_d *dev, int, void *);
+off_t dev_lseek(struct device_d *dev, off_t offset);
int dev_erase(struct device_d *dev, size_t count, unsigned long offset);
int dev_protect(struct device_d *dev, size_t count, unsigned long offset, int prot);
int dev_memmap(struct device_d *dev, void **map, int flags);
@@ -233,5 +244,20 @@ int dummy_probe(struct device_d *);
int generic_memmap_ro(struct device_d *dev, void **map, int flags);
int generic_memmap_rw(struct device_d *dev, void **map, int flags);
+static inline off_t dev_lseek_default(struct device_d *dev, off_t ofs)
+{
+ return ofs;
+}
+
+static inline int dev_open_default(struct device_d *dev, struct filep *f)
+{
+ return 0;
+}
+
+static inline int dev_close_default(struct device_d *dev, struct filep *f)
+{
+ return 0;
+}
+
#endif /* DRIVER_H */
diff --git a/include/fs.h b/include/fs.h
index 31243f399f..2500f14c54 100644
--- a/include/fs.h
+++ b/include/fs.h
@@ -58,12 +58,14 @@ struct fs_driver_d {
int (*close)(struct device_d *dev, FILE *f);
int (*read)(struct device_d *dev, FILE *f, void *buf, size_t size);
int (*write)(struct device_d *dev, FILE *f, const void *buf, size_t size);
+ off_t (*lseek)(struct device_d *dev, FILE *f, off_t pos);
struct dir* (*opendir)(struct device_d *dev, const char *pathname);
struct dirent* (*readdir)(struct device_d *dev, struct dir *dir);
int (*closedir)(struct device_d *dev, DIR *dir);
int (*stat)(struct device_d *dev, const char *file, struct stat *stat);
+ int (*ioctl)(struct device_d *dev, FILE *f, int request, void *buf);
int (*erase)(struct device_d *dev, FILE *f, size_t count,
unsigned long offset);
int (*protect)(struct device_d *dev, FILE *f, size_t count,
@@ -101,6 +103,7 @@ int unlink(const char *pathname);
int close(int fd);
int stat(const char *filename, struct stat *s);
int read(int fd, void *buf, size_t count);
+int ioctl(int fd, int request, void *buf);
ssize_t write(int fd, const void *buf, size_t count);
#define SEEK_SET 1
diff --git a/lib/driver.c b/lib/driver.c
index f3129c4015..45417c28a9 100644
--- a/lib/driver.c
+++ b/lib/driver.c
@@ -212,6 +212,38 @@ ssize_t dev_write(struct device_d *dev, const void *buf, size_t count, unsigned
return -ENOSYS;
}
+off_t dev_lseek(struct device_d *dev, off_t offset)
+{
+ if (dev->driver->lseek)
+ return dev->driver->lseek(dev, offset);
+ errno = -ENOSYS;
+ return -ENOSYS;
+}
+
+int dev_open(struct device_d *dev, struct filep *f)
+{
+ if (dev->driver->open)
+ return dev->driver->open(dev, f);
+ errno = -ENOSYS;
+ return -ENOSYS;
+}
+
+int dev_close(struct device_d *dev, struct filep *f)
+{
+ if (dev->driver->close)
+ return dev->driver->close(dev, f);
+ errno = -ENOSYS;
+ return -ENOSYS;
+}
+
+int dev_ioctl(struct device_d *dev, int request, void *buf)
+{
+ if (dev->driver->ioctl)
+ return dev->driver->ioctl(dev, request, buf);
+ errno = -ENOSYS;
+ return -ENOSYS;
+}
+
int dev_erase(struct device_d *dev, size_t count, unsigned long offset)
{
if (dev->driver->erase)