diff --git a/commands/mem.c b/commands/mem.c index be71ee4ce..f7b9e4bb6 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 4942ffdf5..4721bc1c1 100644 --- a/common/partition.c +++ b/common/partition.c @@ -32,6 +32,9 @@ #include #include #include +#include +#include +#include /** * 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 a859741c8..4bdd2f656 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 9c08ad5a2..62f15d627 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 10c2dfeab..12abc1829 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 2d90df3f5..3f0f1345f 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 38ef035d5..beee6b925 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 cade9fdfb..4000ba689 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 31243f399..2500f14c5 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 f3129c401..45417c28a 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)