9
0
Fork 0

introduce cdev

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
Sascha Hauer 2009-04-22 23:39:27 +02:00
parent 6411c3b2be
commit a2b7cd183b
24 changed files with 596 additions and 937 deletions

View File

@ -43,7 +43,6 @@
*/
static struct device_d cfi_dev = {
.name = "cfi_flash",
.id = "nor0",
.map_base = IMX_CS0_BASE,
.size = 32 * 1024 * 1024, /* area size */
};
@ -245,10 +244,9 @@ static int imx31_devices_init(void)
* Create partitions that should be
* not touched by any regular user
*/
#ifdef CONFIG_PARTITION
dev_add_partition(&cfi_dev, 0x00000, 0x40000, PARTITION_FIXED, "self"); /* ourself */
dev_add_partition(&cfi_dev, 0x40000, 0x20000, PARTITION_FIXED, "env"); /* environment */
#endif
devfs_add_partition("nor0", 0x00000, 0x40000, PARTITION_FIXED, "self0"); /* ourself */
devfs_add_partition("nor0", 0x40000, 0x20000, PARTITION_FIXED, "env0"); /* environment */
dev_protect(&cfi_dev, 0x20000, 0, 1);
register_device(&sram_dev);

View File

@ -111,9 +111,9 @@ static struct device_d nand_dev = {
static int pcm038_devices_init(void)
{
struct device_d *nand, *dev;
char *envdev = "no";
int i;
struct device_d *nand;
char *envdev = "no";
unsigned int mode[] = {
PD0_AIN_FEC_TXD0,
@ -192,20 +192,16 @@ static int pcm038_devices_init(void)
nand = get_device_by_path("/dev/nand0");
if (!nand)
break;
dev = dev_add_partition(nand, 0x00000, 0x40000, PARTITION_FIXED, "self_raw");
if (!dev)
break;
dev_add_bb_dev(dev, "self0");
devfs_add_partition("nand0", 0x00000, 0x40000, PARTITION_FIXED, "self_raw");
dev_add_bb_dev("self_raw", "self0");
dev = dev_add_partition(nand, 0x40000, 0x20000, PARTITION_FIXED, "env_raw");
if (!dev)
break;
dev_add_bb_dev(dev, "env0");
devfs_add_partition("nand0", 0x40000, 0x20000, PARTITION_FIXED, "env_raw");
dev_add_bb_dev("env_raw", "env0");
envdev = "NAND";
break;
default:
dev_add_partition(&cfi_dev, 0x00000, 0x40000, PARTITION_FIXED, "self");
dev_add_partition(&cfi_dev, 0x40000, 0x20000, PARTITION_FIXED, "env");
devfs_add_partition("nor0", 0x00000, 0x40000, PARTITION_FIXED, "self0");
devfs_add_partition("nor0", 0x40000, 0x20000, PARTITION_FIXED, "env0");
dev_protect(&cfi_dev, 0x40000, 0, 1);
envdev = "NOR";
}

View File

@ -35,20 +35,24 @@
static struct device_d cfi_dev = {
.name = "cfi_flash",
.id = "nor0",
.map_base = 0x10000000,
.size = 16 * 1024 * 1024,
};
static struct memory_platform_data sdram_pdata = {
.name = "ram0",
.flags = DEVFS_RDWR,
};
static struct device_d sdram_dev = {
.name = "ram",
.id = "ram0",
.name = "mem",
.map_base = 0x08000000,
.size = 16 * 1024 * 1024,
.type = DEVICE_TYPE_DRAM,
.platform_data = &sdram_pdata,
};
static struct dm9000_platform_data dm9000_data = {
@ -93,8 +97,8 @@ static int scb9328_devices_init(void) {
register_device(&sdram_dev);
register_device(&dm9000_dev);
dev_add_partition(&cfi_dev, 0x00000, 0x20000, PARTITION_FIXED, "self");
dev_add_partition(&cfi_dev, 0x40000, 0x20000, PARTITION_FIXED, "env");
devfs_add_partition("nor0", 0x00000, 0x20000, PARTITION_FIXED, "self0");
devfs_add_partition("nor0", 0x40000, 0x20000, PARTITION_FIXED, "env0");
dev_protect(&cfi_dev, 0x20000, 0, 1);
armlinux_set_bootparams((void *)0x08000100);

View File

@ -518,44 +518,46 @@ U_BOOT_CMD_START(memcpy)
U_BOOT_CMD_HELP(cmd_memcpy_help)
U_BOOT_CMD_END
static struct device_d mem_dev = {
.name = "mem",
.id = "mem",
.map_base = 0,
.size = ~0, /* FIXME: should be 0x100000000, ahem... */
static struct file_operations memops = {
.read = mem_read,
.write = mem_write,
.memmap = generic_memmap_rw,
.lseek = dev_lseek_default,
};
static int mem_probe(struct device_d *dev)
{
struct memory_platform_data *pdata = dev->platform_data;
struct cdev *cdev;
cdev = xzalloc(sizeof (*cdev));
dev->priv = cdev;
cdev->name = pdata->name;
cdev->size = dev->size;
cdev->ops = &memops;
cdev->dev = dev;
devfs_create(cdev);
return 0;
}
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,
.memmap = mem_memmap,
.lseek = dev_lseek_default,
.probe = mem_probe,
};
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,
.memmap = mem_memmap,
.type = DEVICE_TYPE_DRAM,
static struct memory_platform_data mem_dev_pdata = {
.name = "mem",
.flags = DEVFS_RDWR,
};
static struct driver_d rom_drv = {
.name = "rom",
.probe = dummy_probe,
.open = dev_open_default,
.close = dev_close_default,
.read = mem_read,
.memmap = mem_memmap,
.lseek = dev_lseek_default,
static struct device_d mem_dev = {
.name = "mem",
.map_base = 0,
.size = ~0, /* FIXME: should be 0x100000000, ahem... */
.platform_data = &mem_dev_pdata,
};
static int mem_init(void)
@ -566,10 +568,9 @@ static int mem_init(void)
return -1;
}
register_device(&mem_dev);
register_driver(&mem_drv);
register_driver(&ram_drv);
register_driver(&rom_drv);
register_device(&mem_dev);
return 0;
}

View File

@ -17,7 +17,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <common.h>
#include <command.h>
#include <fs.h>
@ -31,40 +30,45 @@
#include <nand.h>
#include <linux/mtd/mtd-abi.h>
#include <fcntl.h>
#include <libgen.h>
struct nand_bb {
struct device_d device;
struct device_d *physdev;
char *devname;
char *name;
int open;
struct mtd_info_user info;
size_t raw_size;
size_t size;
int fd;
off_t offset;
struct cdev cdev;
};
static ssize_t nand_bb_read(struct device_d *dev, void *buf, size_t count,
static ssize_t nand_bb_read(struct cdev *cdev, void *buf, size_t count,
unsigned long offset, ulong flags)
{
struct nand_bb *bb = dev->priv;
struct nand_bb *bb = cdev->priv;
int ret, bytes = 0, now;
debug("%s %d %d\n", __func__, offset, count);
while(count) {
ret = dev_ioctl(bb->physdev, MEMGETBADBLOCK, (void *)bb->offset);
ret = ioctl(bb->fd, MEMGETBADBLOCK, (void *)bb->offset);
if (ret < 0)
return ret;
if (ret) {
debug("skipping bad block at 0x%08x\n", bb->offset);
printf("skipping bad block at 0x%08x\n", bb->offset);
bb->offset += bb->info.erasesize;
}
now = min(count, (size_t)(bb->info.erasesize -
(bb->offset % bb->info.erasesize)));
ret = dev_read(bb->physdev, buf, now, bb->offset, flags);
lseek(bb->fd, bb->offset, SEEK_SET);
ret = read(bb->fd, buf, now);
if (ret < 0)
return ret;
buf += now;
@ -76,16 +80,16 @@ static ssize_t nand_bb_read(struct device_d *dev, void *buf, size_t count,
return bytes;
}
static ssize_t nand_bb_write(struct device_d *dev, const void *buf, size_t count,
static ssize_t nand_bb_write(struct cdev *cdev, const void *buf, size_t count,
unsigned long offset, ulong flags)
{
struct nand_bb *bb = dev->priv;
struct nand_bb *bb = cdev->priv;
int ret, bytes = 0, now;
debug("%s %d %d\n", __func__, offset, count);
debug("%s offset: 0x%08x count: 0x%08x\n", __func__, offset, count);
while(count) {
ret = dev_ioctl(bb->physdev, MEMGETBADBLOCK, (void *)bb->offset);
ret = ioctl(bb->fd, MEMGETBADBLOCK, (void *)bb->offset);
if (ret < 0)
return ret;
@ -96,7 +100,8 @@ static ssize_t nand_bb_write(struct device_d *dev, const void *buf, size_t count
now = min(count, (size_t)(bb->info.erasesize -
(bb->offset % bb->info.erasesize)));
ret = dev_write(bb->physdev, buf, now, bb->offset, flags);
lseek(bb->fd, offset, SEEK_SET);
ret = write(bb->fd, buf, now);
if (ret < 0)
return ret;
buf += now;
@ -108,21 +113,21 @@ static ssize_t nand_bb_write(struct device_d *dev, const void *buf, size_t count
return bytes;
}
static int nand_bb_erase(struct device_d *dev, size_t count, unsigned long offset)
static int nand_bb_erase(struct cdev *cdev, size_t count, unsigned long offset)
{
struct nand_bb *bb = dev->priv;
struct nand_bb *bb = cdev->priv;
if (offset != 0 || count != dev->size) {
if (offset != 0 || count != bb->raw_size) {
printf("can only erase whole device\n");
return -EINVAL;
}
return dev_erase(bb->physdev, dev->size, 0);
return erase(bb->fd, bb->raw_size, 0);
}
static int nand_bb_open(struct device_d *dev, struct filep *f)
static int nand_bb_open(struct cdev *cdev, struct filep *f)
{
struct nand_bb *bb = dev->priv;
struct nand_bb *bb = cdev->priv;
if (bb->open)
return -EBUSY;
@ -133,9 +138,9 @@ static int nand_bb_open(struct device_d *dev, struct filep *f)
return 0;
}
static int nand_bb_close(struct device_d *dev, struct filep *f)
static int nand_bb_close(struct cdev *cdev, struct filep *f)
{
struct nand_bb *bb = dev->priv;
struct nand_bb *bb = cdev->priv;
bb->open = 0;
@ -147,12 +152,12 @@ static int nand_bb_calc_size(struct nand_bb *bb)
ulong pos = 0;
int ret;
while (pos < bb->physdev->size) {
ret = dev_ioctl(bb->physdev, MEMGETBADBLOCK, (void *)pos);
while (pos < bb->raw_size) {
ret = ioctl(bb->fd, MEMGETBADBLOCK, (void *)pos);
if (ret < 0)
return ret;
if (!ret)
bb->device.size += bb->info.erasesize;
bb->cdev.size += bb->info.erasesize;
pos += bb->info.erasesize;
}
@ -160,79 +165,67 @@ static int nand_bb_calc_size(struct nand_bb *bb)
return 0;
}
static int nand_bb_probe(struct device_d *dev)
{
struct nand_bb *bb = dev->priv;
int ret;
ret = dev_ioctl(bb->physdev, MEMGETINFO, &bb->info);
if (ret)
return ret;
return nand_bb_calc_size(bb);
}
static void nand_bb_remove(struct device_d *dev)
{
}
struct driver_d nand_bb_driver = {
.name = "nand_bb",
.probe = nand_bb_probe,
.remove = nand_bb_remove,
static struct file_operations nand_bb_ops = {
.open = nand_bb_open,
.close = nand_bb_close,
.read = nand_bb_read,
.write = nand_bb_write,
.erase = nand_bb_erase,
.type = DEVICE_TYPE_NAND_BB,
};
static int nand_bb_init(void)
{
return register_driver(&nand_bb_driver);
}
device_initcall(nand_bb_init);
/**
* Add a bad block aware device ontop of another (NAND) device
* @param[in] dev The device to add a partition on
* @param[in] name Partition name (can be obtained with devinfo command)
* @return The device representing the new partition.
*/
struct device_d *dev_add_bb_dev(struct device_d *dev, const char *name)
int dev_add_bb_dev(char *path, const char *name)
{
struct nand_bb *bb;
int ret;
struct stat s;
bb = xzalloc(sizeof(*bb));
bb->devname = asprintf("/dev/%s", basename(path));
if (name)
strcpy(bb->device.id, name);
bb->cdev.name = strdup(name);
else
sprintf(bb->device.id, "%s.bb", dev->id);
strcpy(bb->device.name, "nand_bb");
bb->device.priv = bb;
bb->device.size = 0;
bb->device.type = DEVICE_TYPE_NAND_BB;
bb->physdev = dev;
bb->cdev.name = asprintf("%s.bb", basename(path));
if (register_device(&bb->device))
ret = stat(bb->devname, &s);
if (ret)
goto free_out;
dev_add_child(dev, &bb->device);
bb->raw_size = s.st_size;
return &bb->device;
bb->fd = open(bb->devname, O_RDWR);
if (bb->fd < 0) {
ret = -ENODEV;
goto free_out;
}
ret = ioctl(bb->fd, MEMGETINFO, &bb->info);
if (ret)
goto free_out;
nand_bb_calc_size(bb);
bb->cdev.ops = &nand_bb_ops;
bb->cdev.priv = bb;
devfs_create(&bb->cdev);
return 0;
free_out:
free(bb);
return 0;
return ret;
}
#define NAND_ADD (1 << 0)
#define NAND_DEL (1 << 1)
#define NAND_MARKBAD (1 << 2)
static int do_nand (cmd_tbl_t *cmdtp, int argc, char *argv[])
static int do_nand(cmd_tbl_t *cmdtp, int argc, char *argv[])
{
int opt;
struct device_d *dev;
@ -262,13 +255,7 @@ static int do_nand (cmd_tbl_t *cmdtp, int argc, char *argv[])
if (command & NAND_ADD) {
while (optind < argc) {
dev = get_device_by_path(argv[optind]);
if (!dev) {
printf("no such device: %s\n", argv[optind]);
return 1;
}
if (!dev_add_bb_dev(dev, NULL))
if (dev_add_bb_dev(argv[optind], NULL))
return 1;
optind++;
@ -277,17 +264,20 @@ static int do_nand (cmd_tbl_t *cmdtp, int argc, char *argv[])
if (command & NAND_DEL) {
while (optind < argc) {
dev = get_device_by_path(argv[optind]);
if (!dev) {
struct cdev *cdev;
cdev = cdev_by_name(basename(argv[optind]));
if (!cdev) {
printf("no such device: %s\n", argv[optind]);
return 1;
}
dev = cdev->dev;
if (dev->type != DEVICE_TYPE_NAND_BB) {
printf("not a nand bb device: %s\n", dev);
return 1;
}
bb = dev->priv;
close(bb->fd);
unregister_device(dev);
free(bb);
optind++;

View File

@ -37,99 +37,29 @@
#include <partition.h>
#include <errno.h>
#include <xfuncs.h>
#include <fs.h>
#include <linux/stat.h>
#include <libgen.h>
static int dev_del_partitions(struct device_d *physdev)
{
struct device_d *child, *tmp;
struct partition *part;
int ret;
device_for_each_child_safe(physdev, tmp, child) {
if (child->type != DEVICE_TYPE_PARTITION) {
printf("not a partition: %s\n", child->id);
continue;
}
part = child->type_data;
if (part->flags & PARTITION_FIXED) {
debug("Skip fixed partition: %s\n", child->id);
continue;
}
ret = unregister_device(child);
if (ret) {
printf("delete partition `%s' failed: %s\n", child->id, errno_str());
return errno;
}
debug("deleted partition: %s\n", child->id);
free(part);
}
return 0;
}
static int dev_check_fixed(struct device_d *physdev, struct partition *new_part)
{
struct device_d *child;
device_for_each_child(physdev, child) {
struct partition *part = child->type_data;
debug("check aginst partition: %s -", child->id);
if (!(part->flags & PARTITION_FIXED)) {
debug(" not fixed, ok\n");
continue;
}
if (new_part->offset == part->offset && /* new_part is exactly part */
((new_part->device.size==0) || (new_part->device.size == part->device.size)) ) {
debug(" fixed, but same size, ok\n");
continue;
}
if ((new_part->offset >= part->offset &&
new_part->offset < part->offset + part->device.size) ||
(new_part->offset + new_part->device.size > part->offset &&
new_part->offset + new_part->device.size <= part->offset + part->device.size)) {
printf(
" failed\n"
" partition spec %s \n"
" violates fixed partition %s\n", new_part->name, child->id);
errno = -EINVAL;
return errno;
}
else
debug(" fixed and within limit?, ok\n");
}
return 0;
}
static int mtd_part_do_parse_one(struct partition *part, const char *partstr,
char **endp)
static int mtd_part_do_parse_one(char *devname, const char *partstr,
char **endp, unsigned long offset,
off_t devsize, size_t *retsize)
{
ulong size;
char *end;
char buf[MAX_DRIVER_NAME];
char buf[PATH_MAX];
unsigned long flags = 0;
int ret;
memset(buf, 0, MAX_DRIVER_NAME);
memset(buf, 0, PATH_MAX);
if (*partstr == '-') {
size = part->physdev->size - part->offset;
size = devsize - offset;
end = (char *)partstr + 1;
} else {
size = strtoul_suffix(partstr, &end, 0);
}
if (size + part->offset > part->physdev->size) {
printf("partition %s end is beyond device\n", part->name);
return -EINVAL;
}
partstr = end;
if (*partstr == '(') {
@ -139,98 +69,78 @@ static int mtd_part_do_parse_one(struct partition *part, const char *partstr,
printf("could not find matching ')'\n");
return -EINVAL;
}
if (end - partstr >= MAX_DRIVER_NAME) {
printf("device name too long\n");
return -EINVAL;
}
memcpy(part->name, partstr, end - partstr);
sprintf(buf, "%s.", devname);
memcpy(buf + strlen(buf), partstr, end - partstr);
end++;
}
if (size + offset > devsize) {
printf("%s: partition end is beyond device\n", buf);
return -EINVAL;
}
partstr = end;
if (*partstr == 'r' && *(partstr + 1) == 'o') {
part->flags |= PARTITION_READONLY;
flags |= PARTITION_READONLY;
end = (char *)(partstr + 2);
}
if (endp)
*endp = end;
strcpy(part->device.name, "partition");
part->device.size = size;
*retsize = size;
return 0;
ret = devfs_add_partition(devname, offset, size, flags, buf);
if (ret)
printf("cannot create %s: %s\n", buf, strerror(-ret));
return ret;
}
static int do_addpart(cmd_tbl_t * cmdtp, int argc, char *argv[])
{
struct partition *part;
struct device_d *dev;
char *devname;
char *endp;
int num = 0;
unsigned long offset;
unsigned long offset = 0;
off_t devsize;
struct stat s;
if (argc != 3) {
printf("Usage:\n %s\n", cmdtp->usage);
return 1;
}
dev = get_device_by_path(argv[1]);
if (!dev) {
printf("no such device: %s\n", argv[1]);
if (stat(argv[1], &s)) {
perror("addpart");
return 1;
}
devsize = s.st_size;
dev_del_partitions(dev);
offset = 0;
devname = basename(argv[1]);
endp = argv[2];
while (1) {
part = xzalloc(sizeof(struct partition));
size_t size = 0;
part->offset = offset;
part->physdev = dev;
part->num = num;
part->device.map_base = dev->map_base + offset;
part->device.type_data = part;
part->device.type = DEVICE_TYPE_PARTITION;
if (mtd_part_do_parse_one(devname, endp, &endp, offset, devsize, &size))
return 1;
if (mtd_part_do_parse_one(part, endp, &endp))
goto free_out;
if (dev_check_fixed(dev, part))
goto free_out;
sprintf(part->device.id, "%s.%s", dev->id, part->name);
if (register_device(&part->device))
goto free_out;
dev_add_child(dev, &part->device);
offset += part->device.size;
num++;
offset += size;
if (!*endp)
break;
if (*endp != ',') {
printf("parse error\n");
goto err_out;
return 1;
}
endp++;
}
return 0;
free_out:
free(part);
err_out:
dev_del_partitions(dev);
return 1;
}
static const __maybe_unused char cmd_addpart_help[] =
@ -275,38 +185,33 @@ U_BOOT_CMD_END
static int do_delpart(cmd_tbl_t * cmdtp, int argc, char *argv[])
{
struct device_d *dev;
int i, err;
if (argc != 2) {
printf("Usage:\n%s\n", cmdtp->usage);
return 1;
for (i = 1; i < argc; i++) {
err = devfs_del_partition(basename(argv[i]));
if (err) {
printf("cannot delete %s: %s\n", argv[i], strerror(-err));
break;
}
}
dev = get_device_by_path(argv[1]);
if (!dev) {
printf("no such device: %s\n", argv[1]);
return 1;
}
dev_del_partitions(dev);
return 0;
return 1;
}
static const __maybe_unused char cmd_delpart_help[] =
"Usage: delpart <device>\n"
"Usage: delpart FILE...\n"
"Delete partitions previously added to a device with addpart.\n";
U_BOOT_CMD_START(delpart)
.maxargs = 2,
.maxargs = CONFIG_MAXARGS,
.cmd = do_delpart,
.usage = "delete a partition table from a device",
.usage = "delete partition(s)",
U_BOOT_CMD_HELP(cmd_delpart_help)
U_BOOT_CMD_END
/** @page delpart_command delpart Delete a partition
*
* Usage is: delpart \<device>
* Usage is: delpart \<partions>
*
* Delete a partition previously added to a device with addpart.
*/

View File

@ -12,7 +12,6 @@ obj-y += clock.o
obj-y += command.o
obj-$(CONFIG_CONSOLE_FULL) += console.o
obj-$(CONFIG_CONSOLE_SIMPLE) += console_simple.o
obj-$(CONFIG_PARTITION) += partition.o
obj-y += env.o
obj-y += startup.o
obj-y += misc.o

View File

@ -1,358 +0,0 @@
/*
* (C) 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
/**
* @file
* @brief Partition handling on top of devices
*/
#include <common.h>
#include <init.h>
#include <driver.h>
#include <malloc.h>
#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.
* @param[in] dev The device to add a partition on
* @param[in] offset Start offset of the partition inside the whole device
* @param[in] size Size of the new partition
* @param[in] flags FIXME
* @param[in] name Partition name (can be obtained with devinfo command)
* @return The device representing the new partition.
*/
struct device_d *dev_add_partition(struct device_d *dev, unsigned long offset,
size_t size, int flags, const char *name)
{
struct partition *part;
if (offset + size > dev->size)
return NULL;
part = xzalloc(sizeof(struct partition));
strcpy(part->device.name, "partition");
part->device.map_base = dev->map_base + offset;
part->device.size = size;
part->device.type_data = part;
part->device.type = DEVICE_TYPE_PARTITION;
get_free_deviceid(part->device.id, name);
part->offset = offset;
part->physdev = dev;
part->flags = flags;
register_device(&part->device);
dev_add_child(dev, &part->device);
if (part->device.driver)
return &part->device;
unregister_device(&part->device);
free(part);
return 0;
}
/**
* Erase partition content.
* @param[in] dev The partition info as a device
* @param[in] count Length in bytes to erase
* @param[in] offset Start offset within the partition
* @return -1 if no erase feature for this device is available, anything else
* the erase function returns.
*/
static int part_erase(struct device_d *dev, size_t count, unsigned long offset)
{
struct partition *part = dev->type_data;
if (part->flags & PARTITION_READONLY)
return -EROFS;
return dev_erase(part->physdev, count, offset + part->offset);
}
/**
* Protecting a partition.
* @param[in] dev The partition info as a device
* @param[in] count Length in bytes to protect
* @param[in] offset Start offset within the partition
* @param[in] prot FIXME
* @return -1 if FIXME.
*/
static int part_protect(struct device_d *dev, size_t count, unsigned long offset, int prot)
{
struct partition *part = dev->type_data;
return dev_protect(part->physdev, count, offset + part->offset, prot);
}
/**
* FIXME.
* @param[in] dev The partition info as a device
* @param[in] map FXIME
* @param[in] flags FIXME
* @return -1 if FIXME.
*/
static int part_memmap(struct device_d *dev, void **map, int flags)
{
struct partition *part = dev->type_data;
int ret;
if (part->physdev->driver->memmap) {
ret = part->physdev->driver->memmap(part->physdev, map, flags);
if (ret)
return ret;
*map = (void *)((unsigned long)*map + part->offset);
return 0;
}
return -ENOSYS;
}
/**
* FIXME.
* @param[in] dev The partition info as a device
* @param[in] buf FXIME
* @param[in] count FXIME
* @param[in] offset FXIME
* @param[in] flags FIXME
* @return FIXME.
*/
static ssize_t part_read(struct device_d *dev, void *buf, size_t count,
unsigned long offset, ulong flags)
{
struct partition *part = dev->type_data;
return dev_read(part->physdev, buf, count, offset + part->offset, flags);
}
/**
* FIXME.
* @param[in] dev The partition info as a device
* @param[in] buf FXIME
* @param[in] count FXIME
* @param[in] offset FXIME
* @param[in] flags FIXME
* @return FIXME.
*/
static ssize_t part_write(struct device_d *dev, const void *buf, size_t count,
unsigned long offset, ulong flags)
{
struct partition *part = dev->type_data;
if (part->flags & PARTITION_READONLY)
return -EROFS;
else
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 MEMSETBADBLOCK:
case MEMGETBADBLOCK:
offset = (off_t)buf;
offset += part->offset;
return dev_ioctl(part->physdev, request, (void *)offset);
case MEMGETINFO:
return dev_ioctl(part->physdev, request, buf);
}
return -ENOSYS;
}
/**
* FIXME.
* @param[in] dev The partition info as a device
* @return FIXME.
*/
static int part_probe(struct device_d *dev)
{
#ifdef DEBUG
struct partition *part = dev->type_data;
#endif
debug("registering partition %s on device %s (size=0x%08x, name=%s)\n",
dev->id, part->physdev->id, dev->size, part->name);
return 0;
}
/**
* FIXME.
* @param[in] dev The partition info as a device
*/
static void part_remove(struct device_d *dev)
{
}
/**
* Partition driver description
*/
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,
.type = DEVICE_TYPE_PARTITION,
};
static int partition_init(void)
{
return register_driver(&part_driver);
}
device_initcall(partition_init);
/**
@page partitions Partition Handling
Partitions are runtime informartion only, not permanent. So they must be set
everytime the system starts. The required command can be embedded into the
default environment.
@note Partitions defined in this way are intended to be used with the kernel
command line partition parsing feature. In Uboot2 these types of partitions are
handled in the same way as every other device.
@par The addpart command
What we want:
@verbatim
device nor0
|--- partition 0
|--- partition 1
|--- partition 2
|--- partition 3
`--- partition 4
@endverbatim
How to get:
@verbatim
$ addpart /dev/nor0 256k(uboot),128k(env),256k(bla),1024k(blubb),2048k(friesel)
$ devinfo
|---nor0.uboot
|---nor0.env
|---nor0.bla
|---nor0.blubb
|---nor0.friesel
@endverbatim
@par Partitions with sub partitions:
Partitions are based on devices. And partitions will result into devices. So
there is a way to create sub partitions on partitions.
What we want:
@verbatim
device nor0
|--- partition 0
|--- partition 1
|--- partition 2
|--- partition 3
`--- partition 4
|--- partition 0
`--- partition 1
@endverbatim
How to get:
@verbatim
$ addpart /dev/nor0 256k(uboot),128k(env),256k(bla),1M(blubb),2048k(friesel)
$ devinfo
|---nor0.uboot
|---nor0.env
|---nor0.bla
|---nor0.blubb
|---nor0.friesel
$ addpart /dev/nor0.friesel 1024(fussel),1024k(boerks)
$ devinfo
|---nor0.uboot
|---nor0.env
|---nor0.bla
|---nor0.blubb
|---nor0.friesel
|---nor0.friesel.fussel
`---nor0.friesel.boerks
@endverbatim
@par Forwarding partitions to the kernel:
@verbatim
$ device="nor0"
$ partitions="256k(uboot),128k(env),256k(bla),1024k(blubb),2048k(friesel)"
$ addpart /dev/$device:$partitions
@endverbatim
@par Removing partitions:
As partitions are a logically information only, they can be removed from a
device at runtime. You can't remove a single partition within others on the
same device. Only all partitions on the given device can be removed with this
command.
As sub partitions occure as devices you also can remove sub partitions from
their parent in this way. Partitions cannot be removed as long as they are
mounted or have subpartitions.
*/

View File

@ -77,9 +77,13 @@ void early_init (void)
#ifdef CONFIG_DEFAULT_ENVIRONMENT
#include <uboot_default_env.h>
static struct memory_platform_data default_env_platform_data = {
.name = "defaultenv",
};
static struct device_d default_env_dev = {
.name = "rom",
.id = "defaultenv",
.name = "mem",
.platform_data = &default_env_platform_data,
};
static void register_default_env(void)

View File

@ -20,7 +20,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/mtd.h>
@ -31,9 +30,9 @@
#include <ioctl.h>
#include <nand.h>
static ssize_t nand_read(struct device_d *dev, void* buf, size_t count, ulong offset, ulong flags)
static ssize_t nand_read(struct cdev *cdev, void* buf, size_t count, ulong offset, ulong flags)
{
struct mtd_info *info = dev->priv;
struct mtd_info *info = cdev->priv;
size_t retlen;
int ret;
@ -41,16 +40,18 @@ static ssize_t nand_read(struct device_d *dev, void* buf, size_t count, ulong o
ret = info->read(info, offset, count, &retlen, buf);
if(ret)
if(ret) {
printf("err %d\n", ret);
return ret;
}
return retlen;
}
#define NOTALIGNED(x) (x & (info->writesize - 1)) != 0
static ssize_t nand_write(struct device_d* dev, const void* buf, size_t _count, ulong offset, ulong flags)
static ssize_t nand_write(struct cdev* cdev, const void *buf, size_t _count, ulong offset, ulong flags)
{
struct mtd_info *info = dev->priv;
struct mtd_info *info = cdev->priv;
size_t retlen, now;
int ret;
void *wrbuf = NULL;
@ -86,9 +87,9 @@ out:
return ret ? ret : _count;
}
static int nand_ioctl(struct device_d *dev, int request, void *buf)
static int nand_ioctl(struct cdev *cdev, int request, void *buf)
{
struct mtd_info *info = dev->priv;
struct mtd_info *info = cdev->priv;
struct mtd_info_user *user = buf;
switch (request) {
@ -113,9 +114,9 @@ static int nand_ioctl(struct device_d *dev, int request, void *buf)
return 0;
}
static ssize_t nand_erase(struct device_d *dev, size_t count, unsigned long offset)
static ssize_t nand_erase(struct cdev *cdev, size_t count, unsigned long offset)
{
struct mtd_info *info = dev->priv;
struct mtd_info *info = cdev->priv;
struct erase_info erase;
int ret;
@ -143,6 +144,14 @@ static ssize_t nand_erase(struct device_d *dev, size_t count, unsigned long offs
return 0;
}
static struct file_operations nand_ops = {
.read = nand_read,
.write = nand_write,
.ioctl = nand_ioctl,
.lseek = dev_lseek_default,
.erase = nand_erase,
};
static int nand_device_probe(struct device_d *dev)
{
return 0;
@ -151,13 +160,6 @@ static int nand_device_probe(struct device_d *dev)
static struct driver_d nand_device_driver = {
.name = "nand_device",
.probe = nand_device_probe,
.read = nand_read,
.write = nand_write,
.ioctl = nand_ioctl,
.open = dev_open_default,
.close = dev_close_default,
.lseek = dev_lseek_default,
.erase = nand_erase,
.type = DEVICE_TYPE_NAND,
};
@ -170,36 +172,27 @@ static int nand_init(void)
device_initcall(nand_init);
int add_mtd_device(struct mtd_info *mtd) {
struct device_d *dev;
int ret;
int add_mtd_device(struct mtd_info *mtd)
{
struct device_d *dev = &mtd->class_dev;
char name[MAX_DRIVER_NAME];
dev = xzalloc(sizeof(*dev));
get_free_deviceid(name, "nand");
strcpy(dev->name, "nand_device");
get_free_deviceid(dev->id, "nand");
mtd->cdev.ops = &nand_ops;
mtd->cdev.size = mtd->size;
mtd->cdev.name = strdup(name);
mtd->cdev.dev = dev;
mtd->cdev.priv = mtd;
dev->size = mtd->size;
dev->type = DEVICE_TYPE_NAND;
dev->priv = mtd;
mtd->dev = dev;
ret = register_device(dev);
if (ret)
goto out;
devfs_create(&mtd->cdev);
return 0;
out:
free(dev);
return ret;
}
int del_mtd_device (struct mtd_info *mtd)
{
unregister_device(mtd->dev);
free(mtd->dev);
unregister_device(&mtd->class_dev);
return 0;
}

View File

@ -25,6 +25,7 @@
#include <init.h>
#include <miiphy.h>
#include <clock.h>
#include <net.h>
int miiphy_restart_aneg(struct miiphy_device *mdev)
{
@ -84,12 +85,12 @@ int miiphy_wait_aneg(struct miiphy_device *mdev)
start = get_time_ns();
do {
if (is_timeout(start, 5 * SECOND)) {
printf("%s: Autonegotiation timeout\n", mdev->dev.id);
printf("%s: Autonegotiation timeout\n", mdev->cdev.name);
return -1;
}
if (mdev->read(mdev, mdev->address, MII_BMSR, &status)) {
printf("%s: Autonegotiation failed. status: 0x%04x\n", mdev->dev.id, status);
printf("%s: Autonegotiation failed. status: 0x%04x\n", mdev->cdev.name, status);
return -1;
}
} while (!(status & BMSR_LSTATUS));
@ -115,7 +116,7 @@ int miiphy_print_status(struct miiphy_device *mdev)
if (mdev->read(mdev, mdev->address, MII_LPA, &lpa) != 0)
goto err_out;
printf("%s: Link is %s", mdev->dev.id,
printf("%s: Link is %s", mdev->cdev.name,
bmsr & BMSR_LSTATUS ? "up" : "down");
if (bmcr & BMCR_ANENABLE) {
@ -130,15 +131,15 @@ int miiphy_print_status(struct miiphy_device *mdev)
return 0;
err_out:
printf("%s: failed to read\n", mdev->dev.id);
printf("%s: failed to read\n", mdev->cdev.name);
return -1;
}
static ssize_t miiphy_read(struct device_d *dev, void *_buf, size_t count, ulong offset, ulong flags)
static ssize_t miiphy_read(struct cdev *cdev, void *_buf, size_t count, ulong offset, ulong flags)
{
int i = count;
uint16_t *buf = _buf;
struct miiphy_device *mdev = dev->priv;
struct miiphy_device *mdev = cdev->priv;
while (i > 1) {
mdev->read(mdev, mdev->address, offset, buf);
@ -150,11 +151,11 @@ static ssize_t miiphy_read(struct device_d *dev, void *_buf, size_t count, ulong
return count;
}
static ssize_t miiphy_write(struct device_d *dev, const void *_buf, size_t count, ulong offset, ulong flags)
static ssize_t miiphy_write(struct cdev *cdev, const void *_buf, size_t count, ulong offset, ulong flags)
{
int i = count;
const uint16_t *buf = _buf;
struct miiphy_device *mdev = dev->priv;
struct miiphy_device *mdev = cdev->priv;
while (i > 1) {
mdev->write(mdev, mdev->address, offset, *buf);
@ -166,41 +167,36 @@ static ssize_t miiphy_write(struct device_d *dev, const void *_buf, size_t count
return count;
}
static struct file_operations miiphy_ops = {
.read = miiphy_read,
.write = miiphy_write,
};
static int miiphy_probe(struct device_d *dev)
{
return 0;
}
struct miiphy_device *mdev = dev->priv;
char name[MAX_DRIVER_NAME];
static void miiphy_remove(struct device_d *dev)
{
get_free_deviceid(name, "phy");
mdev->cdev.name = strdup(name);
mdev->cdev.size = 32;
mdev->cdev.ops = &miiphy_ops;
mdev->cdev.priv = mdev;
devfs_create(&mdev->cdev);
return 0;
}
int miiphy_register(struct miiphy_device *mdev)
{
strcpy(mdev->dev.name, "miiphy");
get_free_deviceid(mdev->dev.id, "phy");
mdev->dev.type = DEVICE_TYPE_MIIPHY;
mdev->dev.priv = mdev;
mdev->dev.size = 32;
strcpy(mdev->dev.name, "miiphy");
return register_device(&mdev->dev);
}
void miiphy_unregister(struct miiphy_device *mdev)
{
unregister_device(&mdev->dev);
}
static struct driver_d miiphy_drv = {
.name = "miiphy",
.probe = miiphy_probe,
.remove = miiphy_remove,
.open = dev_open_default,
.close = dev_close_default,
.read = miiphy_read,
.write = miiphy_write,
.lseek = dev_lseek_default,
.type = DEVICE_TYPE_MIIPHY,
};
static int miiphy_init(void)

View File

@ -42,6 +42,7 @@
#include <init.h>
#include <malloc.h>
#include <cfi_flash.h>
#include <errno.h>
#define FLASH_CMD_CFI 0x98
#define FLASH_CMD_READ_ID 0x90
@ -352,16 +353,16 @@ static int flash_erase_one (flash_info_t * info, long sect)
return rcode;
}
static int cfi_erase(struct device_d *dev, size_t count, unsigned long offset)
static int cfi_erase(struct cdev *cdev, size_t count, unsigned long offset)
{
flash_info_t *finfo = (flash_info_t *)dev->priv;
flash_info_t *finfo = (flash_info_t *)cdev->priv;
unsigned long start, end;
int i, ret = 0;
debug("%s: erase 0x%08x (size %d)\n", __FUNCTION__, offset, count);
start = flash_find_sector(finfo, dev->map_base + offset);
end = flash_find_sector(finfo, dev->map_base + offset + count - 1);
start = flash_find_sector(finfo, cdev->dev->map_base + offset);
end = flash_find_sector(finfo, cdev->dev->map_base + offset + count - 1);
for (i = start; i <= end; i++) {
ret = flash_erase_one (finfo, i);
@ -373,16 +374,16 @@ out:
return ret;
}
static int cfi_protect(struct device_d *dev, size_t count, unsigned long offset, int prot)
static int cfi_protect(struct cdev *cdev, size_t count, unsigned long offset, int prot)
{
flash_info_t *finfo = (flash_info_t *)dev->priv;
flash_info_t *finfo = (flash_info_t *)cdev->priv;
unsigned long start, end;
int i, ret = 0;
debug("%s: protect 0x%08x (size %d)\n", __FUNCTION__, offset, count);
start = flash_find_sector(finfo, dev->map_base + offset);
end = flash_find_sector(finfo, dev->map_base + offset + count - 1);
start = flash_find_sector(finfo, cdev->dev->map_base + offset);
end = flash_find_sector(finfo, cdev->dev->map_base + offset + count - 1);
for (i = start; i <= end; i++) {
ret = flash_real_protect (finfo, i, prot);
@ -394,14 +395,14 @@ out:
return ret;
}
static ssize_t cfi_write(struct device_d* dev, const void* buf, size_t count, unsigned long offset, ulong flags)
static ssize_t cfi_write(struct cdev *cdev, const void* buf, size_t count, unsigned long offset, ulong flags)
{
flash_info_t *finfo = (flash_info_t *)dev->priv;
flash_info_t *finfo = (flash_info_t *)cdev->priv;
int ret;
debug("cfi_write: buf=0x%08x addr=0x%08x count=0x%08x\n",buf, dev->map_base + offset, count);
debug("cfi_write: buf=0x%08x addr=0x%08x count=0x%08x\n",buf, cdev->dev->map_base + offset, count);
ret = write_buff (finfo, buf, dev->map_base + offset, count);
ret = write_buff (finfo, buf, cdev->dev->map_base + offset, count);
return ret == 0 ? count : -1;
}
@ -1437,43 +1438,48 @@ static int flash_write_cfibuffer (flash_info_t * info, ulong dest, const uchar *
}
#endif /* CONFIG_CFI_BUFFER_WRITE */
struct file_operations cfi_ops = {
.read = mem_read,
.write = cfi_write,
.lseek = dev_lseek_default,
.erase = cfi_erase,
.protect = cfi_protect,
.memmap = generic_memmap_ro,
};
static int cfi_probe (struct device_d *dev)
{
unsigned long size = 0;
flash_info_t *info = malloc(sizeof(flash_info_t));
flash_info_t *info = xzalloc(sizeof(flash_info_t));
char name[MAX_DRIVER_NAME];
dev->priv = (void *)info;
debug ("cfi_probe: %s base: 0x%08x size: 0x%08x\n", dev->name, dev->map_base, dev->size);
printf("cfi_probe: %s base: 0x%08x size: 0x%08x\n", dev->name, dev->map_base, dev->size);
/* Init: no FLASHes known */
info->flash_id = FLASH_UNKNOWN;
size += info->size = flash_get_size(info, dev->map_base);
if (dev->size > size) {
dev_dbg(dev, "limiting size from 0x%08x to 0x%08x\n", dev->size, size);
dev->size = size;
}
if (info->flash_id == FLASH_UNKNOWN) {
debug ("## Unknown FLASH on Bank at 0x%08x - Size = 0x%08lx = %ld MB\n",
printf ("## Unknown FLASH on Bank at 0x%08x - Size = 0x%08lx = %ld MB\n",
dev->map_base, info->size, info->size << 20);
return -ENODEV;
}
get_free_deviceid(name, "nor");
info->cdev.name = strdup(name);
info->cdev.size = info->size;
info->cdev.dev = dev;
info->cdev.ops = &cfi_ops;
info->cdev.priv = info;
devfs_create(&info->cdev);
return 0;
}
static struct driver_d cfi_driver = {
.name = "cfi_flash",
.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,
.info = cfi_info,
};

View File

@ -42,6 +42,7 @@
#include <malloc.h>
#include <cfi_flash_new.h>
#include <asm/io.h>
#include <errno.h>
/*
* This file implements a Common Flash Interface (CFI) driver for U-Boot.
@ -348,8 +349,8 @@ static ulong flash_get_size (flash_info_t *info, ulong base)
break;
#endif
default:
printf("unsopported vendor\n");
break;
printf("unsupported vendor\n");
return 0;
}
info->cfi_cmd_set->flash_read_jedec_ids (info);
flash_write_cmd (info, 0, info->cfi_offset, FLASH_CMD_CFI);
@ -505,16 +506,16 @@ flash_sect_t find_sector (flash_info_t * info, ulong addr)
return sector;
}
static int cfi_erase(struct device_d *dev, size_t count, unsigned long offset)
static int cfi_erase(struct cdev *cdev, size_t count, unsigned long offset)
{
flash_info_t *finfo = (flash_info_t *)dev->priv;
flash_info_t *finfo = (flash_info_t *)cdev->priv;
unsigned long start, end;
int i, ret = 0;
printf("%s: erase 0x%08x (size %d)\n", __FUNCTION__, offset, count);
start = find_sector(finfo, dev->map_base + offset);
end = find_sector(finfo, dev->map_base + offset + count - 1);
start = find_sector(finfo, cdev->dev->map_base + offset);
end = find_sector(finfo, cdev->dev->map_base + offset + count - 1);
for (i = start; i <= end; i++) {
ret = finfo->cfi_cmd_set->flash_erase_one(finfo, i);
@ -658,16 +659,16 @@ static int flash_real_protect (flash_info_t * info, long sector, int prot)
return retcode;
}
static int cfi_protect(struct device_d *dev, size_t count, unsigned long offset, int prot)
static int cfi_protect(struct cdev *cdev, size_t count, unsigned long offset, int prot)
{
flash_info_t *finfo = (flash_info_t *)dev->priv;
flash_info_t *finfo = (flash_info_t *)cdev->priv;
unsigned long start, end;
int i, ret = 0;
debug("%s: protect 0x%08x (size %d)\n", __FUNCTION__, offset, count);
printf("%s: protect 0x%08x (size %d)\n", __FUNCTION__, cdev->dev->map_base + offset, count);
start = find_sector(finfo, dev->map_base + offset);
end = find_sector(finfo, dev->map_base + offset + count - 1);
start = find_sector(finfo, cdev->dev->map_base + offset);
end = find_sector(finfo, cdev->dev->map_base + offset + count - 1);
for (i = start; i <= end; i++) {
ret = flash_real_protect (finfo, i, prot);
@ -679,14 +680,14 @@ out:
return ret;
}
static ssize_t cfi_write(struct device_d* dev, const void* buf, size_t count, unsigned long offset, ulong flags)
static ssize_t cfi_write(struct cdev *cdev, const void *buf, size_t count, unsigned long offset, ulong flags)
{
flash_info_t *finfo = (flash_info_t *)dev->priv;
flash_info_t *finfo = (flash_info_t *)cdev->priv;
int ret;
debug("cfi_write: buf=0x%08x addr=0x%08x count=0x%08x\n",buf, dev->map_base + offset, count);
debug("cfi_write: buf=0x%08x addr=0x%08x count=0x%08x\n",buf, cdev->dev->map_base + offset, count);
ret = write_buff (finfo, buf, dev->map_base + offset, count);
ret = write_buff (finfo, buf, cdev->dev->map_base + offset, count);
return ret == 0 ? count : -1;
}
@ -934,10 +935,20 @@ int flash_isset (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd)
return retval;
}
struct file_operations cfi_ops = {
.read = mem_read,
.write = cfi_write,
.lseek = dev_lseek_default,
.erase = cfi_erase,
.protect = cfi_protect,
.memmap = generic_memmap_ro,
};
static int cfi_probe (struct device_d *dev)
{
unsigned long size = 0;
flash_info_t *info = malloc(sizeof(flash_info_t));
flash_info_t *info = xzalloc(sizeof(flash_info_t));
char name[MAX_DRIVER_NAME];
dev->priv = (void *)info;
@ -953,27 +964,26 @@ static int cfi_probe (struct device_d *dev)
}
if (info->flash_id == FLASH_UNKNOWN) {
#ifndef CFG_FLASH_QUIET_TEST
printf ("## Unknown FLASH on Bank at 0x%08x - Size = 0x%08lx = %ld MB\n",
dev->map_base, info->size, info->size << 20);
#endif /* CFG_FLASH_QUIET_TEST */
return -ENODEV;
}
get_free_deviceid(name, "nor");
info->cdev.name = strdup(name);
info->cdev.size = info->size;
info->cdev.dev = dev;
info->cdev.ops = &cfi_ops;
info->cdev.priv = info;
devfs_create(&info->cdev);
return 0;
}
static struct driver_d cfi_driver = {
.name = "cfi_flash",
.probe = cfi_probe,
.read = mem_read,
.write = cfi_write,
.lseek = dev_lseek_default,
.open = dev_open_default,
.close = dev_close_default,
.erase = cfi_erase,
.info = cfi_info,
.protect = cfi_protect,
.memmap = generic_memmap_ro,
};
static int cfi_init(void)

View File

@ -206,14 +206,17 @@ static int pmic_probe(struct device_d *dev)
return 0;
}
static struct file_operations pmic_fops = {
.open = dev_open_default,
.lseek = dev_lseek_default,
.close = dev_close_default,
.read = pmic_read,
.write = pmic_write,
};
static struct driver_d pmic_driver = {
.name = "mc13783",
.probe = pmic_probe,
.open = dev_open_default,
.lseek = dev_lseek_default,
.close = dev_close_default,
.read = pmic_read,
.write = pmic_write,
};
static int pmic_init(void)

View File

@ -29,27 +29,53 @@
#include <errno.h>
#include <xfuncs.h>
#include <linux/stat.h>
#include <ioctl.h>
#include <nand.h>
#include <linux/mtd/mtd-abi.h>
#include <partition.h>
static int devfs_read(struct device_d *_dev, FILE *f, void *buf, size_t size)
static LIST_HEAD(cdev_list);
struct cdev *cdev_by_name(const char *filename)
{
struct device_d *dev = f->inode;
struct cdev *cdev;
return dev_read(dev, buf, size, f->pos, f->flags);
list_for_each_entry(cdev, &cdev_list, list) {
if (!strcmp(cdev->name, filename))
return cdev;
}
return NULL;
}
static int devfs_write(struct device_d *_dev, FILE *f, const void *buf, size_t size)
int devfs_read(struct device_d *_dev, FILE *f, void *buf, size_t size)
{
struct device_d *dev = f->inode;
struct cdev *cdev = f->inode;
return dev_write(dev, buf, size, f->pos, f->flags);
if (!cdev->ops->read)
return -ENOSYS;
return cdev->ops->read(cdev, buf, size,
f->pos + cdev->offset, f->flags);
}
static off_t devfs_lseek(struct device_d *_dev, FILE *f, off_t pos)
int devfs_write(struct device_d *_dev, FILE *f, const void *buf, size_t size)
{
struct device_d *dev = f->inode;
off_t ret;
struct cdev *cdev = f->inode;
ret = dev_lseek(dev, pos);
if (!cdev->ops->write)
return -ENOSYS;
return cdev->ops->write(cdev, buf, size,
f->pos + cdev->offset, f->flags);
}
off_t devfs_lseek(struct device_d *_dev, FILE *f, off_t pos)
{
struct cdev *cdev = f->inode;
off_t ret = -1;
if (cdev->ops->lseek)
ret = cdev->ops->lseek(cdev, pos + cdev->offset);
if (ret != -1)
f->pos = pos;
@ -57,51 +83,100 @@ static off_t devfs_lseek(struct device_d *_dev, FILE *f, off_t pos)
return ret;
}
static int devfs_erase(struct device_d *_dev, FILE *f, size_t count, unsigned long offset)
int devfs_erase(struct device_d *_dev, FILE *f, size_t count, unsigned long offset)
{
struct device_d *dev = f->inode;
struct cdev *cdev = f->inode;
return dev_erase(dev, count, offset);
if (!cdev->ops->erase)
return -ENOSYS;
return cdev->ops->erase(cdev, count, offset + cdev->offset);
}
static int devfs_protect(struct device_d *_dev, FILE *f, size_t count, unsigned long offset, int prot)
int devfs_protect(struct device_d *_dev, FILE *f, size_t count, unsigned long offset, int prot)
{
struct device_d *dev = f->inode;
struct cdev *cdev = f->inode;
return dev_protect(dev, count, offset, prot);
if (!cdev->ops->protect)
return -ENOSYS;
return cdev->ops->protect(cdev, count, offset + cdev->offset, prot);
}
static int devfs_memmap(struct device_d *_dev, FILE *f, void **map, int flags)
{
struct device_d *dev = f->inode;
struct cdev *cdev = f->inode;
int ret = -ENOSYS;
return dev_memmap(dev, map, flags);
if (!cdev->ops->memmap)
return -EINVAL;
ret = cdev->ops->memmap(cdev, map, flags);
if (!ret)
*map = (void *)((unsigned long)*map + cdev->offset);
return ret;
}
static int devfs_open(struct device_d *_dev, FILE *f, const char *filename)
{
struct device_d *dev = get_device_by_id(filename + 1);
struct cdev *cdev;
if (!dev)
cdev = cdev_by_name(filename + 1);
if (!cdev)
return -ENOENT;
f->size = dev->size;
f->inode = dev;
return dev_open(dev, f);
f->size = cdev->size;
f->inode = cdev;
if (cdev->ops->open)
return cdev->ops->open(cdev, f);
return 0;
}
static int devfs_close(struct device_d *_dev, FILE *f)
{
struct device_d *dev = f->inode;
struct cdev *cdev = f->inode;
return dev_close(dev, f);
if (cdev->ops->close)
return cdev->ops->close(cdev, f);
return 0;
}
static int partition_ioctl(struct cdev *cdev, int request, void *buf)
{
size_t offset;
switch (request) {
case MEMSETBADBLOCK:
case MEMGETBADBLOCK:
offset = (off_t)buf;
offset += cdev->offset;
return cdev->ops->ioctl(cdev, request, (void *)offset);
case MEMGETINFO:
return cdev->ops->ioctl(cdev, request, buf);
default:
return -EINVAL;
}
}
static int devfs_ioctl(struct device_d *_dev, FILE *f, int request, void *buf)
{
struct device_d *dev = f->inode;
struct cdev *cdev = f->inode;
int ret = -EINVAL;
return dev_ioctl(dev, request, buf);
if (!cdev->ops->ioctl)
goto out;
if (cdev->flags & DEVFS_IS_PARTITION)
ret = partition_ioctl(cdev, request, buf);
else
ret = cdev->ops->ioctl(cdev, request, buf);
out:
return ret;
}
static int devfs_truncate(struct device_d *dev, FILE *f, ulong size)
@ -117,26 +192,22 @@ static DIR* devfs_opendir(struct device_d *dev, const char *pathname)
dir = xzalloc(sizeof(DIR));
if (!list_empty(&device_list))
dir->priv = list_first_entry(&device_list, struct device_d, list);
if (!list_empty(&cdev_list))
dir->priv = list_first_entry(&cdev_list, struct cdev, list);
return dir;
}
static struct dirent* devfs_readdir(struct device_d *_dev, DIR *dir)
{
struct device_d *dev = dir->priv;
struct cdev *cdev = dir->priv;
if (!dev)
if (!cdev)
return NULL;
list_for_each_entry_from(dev, &device_list, list) {
if (!*dev->id)
continue;
if (!dev->driver)
continue;
strcpy(dir->d.d_name, dev->id);
dir->priv = list_entry(dev->list.next, struct device_d, list);
list_for_each_entry_from(cdev, &cdev_list, list) {
strcpy(dir->d.d_name, cdev->name);
dir->priv = list_entry(cdev->list.next, struct cdev, list);
return &dir->d;
}
return NULL;
@ -150,20 +221,17 @@ static int devfs_closedir(struct device_d *dev, DIR *dir)
static int devfs_stat(struct device_d *_dev, const char *filename, struct stat *s)
{
struct device_d *dev;
struct cdev *cdev;
dev = get_device_by_id(filename + 1);
if (!dev)
cdev = cdev_by_name(filename + 1);
if (!cdev)
return -ENOENT;
if (!dev->driver)
return -ENXIO;
s->st_mode = S_IFCHR;
s->st_size = dev->size;
if (dev->driver->write)
s->st_size = cdev->size;
if (cdev->ops->write)
s->st_mode |= S_IWUSR;
if (dev->driver->read)
if (cdev->ops->read)
s->st_mode |= S_IRUSR;
return 0;
@ -206,3 +274,71 @@ static int devfs_init(void)
device_initcall(devfs_init);
int devfs_create(struct cdev *new)
{
struct cdev *cdev;
cdev = cdev_by_name(new->name);
if (cdev)
return -EEXIST;
list_add_tail(&new->list, &cdev_list);
return 0;
}
void devfs_remove(struct cdev *cdev)
{
list_del(&cdev->list);
}
int devfs_add_partition(const char *devname, unsigned long offset, size_t size,
int flags, const char *name)
{
struct cdev *cdev, *new;
cdev = cdev_by_name(name);
if (cdev)
return -EEXIST;
cdev = cdev_by_name(devname);
if (!cdev)
return -ENOENT;
if (offset + size > cdev->size)
return -EINVAL;
new = xzalloc(sizeof (*new));
new->name = strdup(name);
new->ops = cdev->ops;
new->priv = cdev->priv;
new->size = size;
new->offset = offset + cdev->offset;
new->dev = cdev->dev;
new->flags = flags | DEVFS_IS_PARTITION;
list_add_tail(&new->list, &cdev_list);
return 0;
}
int devfs_del_partition(const char *name)
{
struct cdev *cdev;
cdev = cdev_by_name(name);
if (!cdev)
return -ENOENT;
if (!(cdev->flags & DEVFS_IS_PARTITION))
return -EINVAL;
if (cdev->flags & DEVFS_PARTITION_FIXED)
return -EPERM;
devfs_remove(cdev);
free(cdev->name);
free(cdev);
return 0;
}

27
fs/fs.c
View File

@ -943,29 +943,34 @@ static void memcpy_sz(void *_dst, const void *_src, ulong count, ulong rwsize)
}
}
ssize_t mem_read(struct device_d *dev, void *buf, size_t count, ulong offset, ulong flags)
ssize_t mem_read(struct cdev *cdev, void *buf, size_t count, ulong offset, ulong flags)
{
ulong size;
size = min(count, dev->size - offset);
struct device_d *dev;
if (!cdev->dev)
return -1;
dev = cdev->dev;
size = min((ulong)count, dev->size - offset);
debug("mem_read: dev->map_base: %p size: %d offset: %d\n",dev->map_base, size, offset);
memcpy_sz(buf, (void *)(dev->map_base + offset), size, flags & O_RWSIZE_MASK);
return size;
}
EXPORT_SYMBOL(mem_read);
ssize_t mem_write(struct device_d *dev, const void *buf, size_t count, ulong offset, ulong flags)
ssize_t mem_write(struct cdev *cdev, const void *buf, size_t count, ulong offset, ulong flags)
{
ulong size;
size = min(count, dev->size - offset);
struct device_d *dev;
if (!cdev->dev)
return -1;
dev = cdev->dev;
size = min((ulong)count, dev->size - offset);
memcpy_sz((void *)(dev->map_base + offset), buf, size, flags & O_RWSIZE_MASK);
return size;
}
EXPORT_SYMBOL(mem_write);
int mem_memmap(struct device_d *dev, void **map, int flags)
{
*map = (void *)dev->map_base;
return 0;
}
EXPORT_SYMBOL(mem_memmap);

View File

@ -32,6 +32,7 @@
typedef struct {
struct driver_d driver;
struct cdev cdev;
ulong size; /* total bank size in bytes */
ushort sector_count; /* number of erase units */
ulong flash_id; /* combined device & manufacturer code */

View File

@ -59,6 +59,7 @@ typedef struct {
ushort cfi_version; /* cfi version */
ushort cfi_offset; /* offset for cfi query */
struct cfi_cmd_set *cfi_cmd_set;
struct cdev cdev;
} flash_info_t;
struct cfi_cmd_set {

View File

@ -98,7 +98,6 @@ struct device_d {
void *type_data; /*! In case this device is a specific device, this pointer
* points to the type specific device, i.e. eth_device
*/
struct driver_d *driver; /*! The driver for this device */
struct list_head list; /* The list of all devices */
@ -133,22 +132,6 @@ struct driver_d {
/*! Called if an instance of a device is gone. */
void (*remove)(struct device_d *);
/*! Called in response of reading from this device. Required */
ssize_t (*read) (struct device_d*, void* buf, size_t count, ulong offset, ulong flags);
/*! 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);
int (*memmap)(struct device_d*, void **map, int flags);
void (*info) (struct device_d *);
void (*shortinfo) (struct device_d *);
@ -231,20 +214,14 @@ extern struct list_head driver_list;
*/
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);
struct cdev;
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);
/* These are used by drivers which work with direct memory accesses */
ssize_t mem_read(struct device_d *dev, void *buf, size_t count, ulong offset, ulong flags);
ssize_t mem_write(struct device_d *dev, const void *buf, size_t count, ulong offset, ulong flags);
int mem_memmap(struct device_d *dev, void **map, int flags);
ssize_t mem_read(struct cdev *cdev, void *buf, size_t count, ulong offset, ulong flags);
ssize_t mem_write(struct cdev *cdev, const void *buf, size_t count, ulong offset, ulong flags);
int mem_memmap(struct cdev *cdev, void **map, int flags);
/* Use this if you have nothing to do in your drivers probe function */
int dummy_probe(struct device_d *);
@ -254,10 +231,10 @@ int dummy_probe(struct device_d *);
*/
void devices_shutdown(void);
int generic_memmap_ro(struct device_d *dev, void **map, int flags);
int generic_memmap_rw(struct device_d *dev, void **map, int flags);
int generic_memmap_ro(struct cdev *dev, void **map, int flags);
int generic_memmap_rw(struct cdev *dev, void **map, int flags);
static inline off_t dev_lseek_default(struct device_d *dev, off_t ofs)
static inline off_t dev_lseek_default(struct cdev *cdev, off_t ofs)
{
return ofs;
}
@ -312,5 +289,51 @@ struct bus_type {
};
extern struct bus_type platform_bus;
struct file_operations {
/*! Called in response of reading from this device. Required */
ssize_t (*read)(struct cdev*, void* buf, size_t count, ulong offset, ulong flags);
/*! Called in response of write to this device. Required */
ssize_t (*write)(struct cdev*, const void* buf, size_t count, ulong offset, ulong flags);
int (*ioctl)(struct cdev*, int, void *);
off_t (*lseek)(struct cdev*, off_t);
int (*open)(struct cdev*, struct filep*);
int (*close)(struct cdev*, struct filep*);
int (*erase)(struct cdev*, size_t count, unsigned long offset);
int (*protect)(struct cdev*, size_t count, unsigned long offset, int prot);
int (*memmap)(struct cdev*, void **map, int flags);
};
struct cdev {
struct file_operations *ops;
void *priv;
struct device_d *dev;
struct list_head list;
char *name;
unsigned long offset;
size_t size;
unsigned int flags;
};
int devfs_create(struct cdev *);
void devfs_remove(struct cdev *);
struct cdev *cdev_by_name(const char *filename);
#define DEVFS_PARTITION_FIXED (1 << 0)
#define DEVFS_PARTITION_READONLY (1 << 1)
#define DEVFS_IS_PARTITION (1 << 2)
#define DEVFS_RDWR (1 << 3)
int devfs_add_partition(const char *devname, unsigned long offset, size_t size,
int flags, const char *name);
int devfs_del_partition(const char *name);
struct memory_platform_data {
char *name;
unsigned int flags;
};
#endif /* DRIVER_H */

View File

@ -9,6 +9,7 @@
#ifndef __MTD_MTD_H__
#define __MTD_MTD_H__
#include <driver.h>
#include <linux/types.h>
#include <list.h>
#include <linux/mtd/mtd-abi.h>
@ -199,7 +200,9 @@ struct mtd_info {
int (*get_device) (struct mtd_info *mtd);
void (*put_device) (struct mtd_info *mtd);
struct device_d class_dev;
struct device_d *dev;
struct cdev cdev;
};

View File

@ -146,6 +146,7 @@ struct miiphy_device {
int flags;
struct eth_device *edev;
struct cdev cdev;
};
int miiphy_register(struct miiphy_device *mdev);

View File

@ -2,7 +2,9 @@
#ifndef __NAND_H__
#define __NAND_H__
struct device_d *dev_add_bb_dev(struct device_d *dev, const char *name);
struct nand_bb;
int dev_add_bb_dev(char *filename, const char *name);
#endif /* __NAND_H__ */

View File

@ -17,20 +17,8 @@ struct partition {
struct device_d device;
char name[16];
struct cdev cdev;
};
#ifdef CONFIG_PARTITION
struct device_d *dev_add_partition(struct device_d *dev, unsigned long offset,
size_t size, int flags, const char *name);
#else
static inline struct device_d *dev_add_partition(struct device_d *dev,
unsigned long offset, size_t size, int flags,
const char *name)
{
return 0;
}
#endif
/* FIXME: counterpart missing */
#endif /* __PARTITION_H */

View File

@ -42,6 +42,18 @@ EXPORT_SYMBOL(driver_list);
static LIST_HEAD(active);
struct device_d *device_by_name(const char *name)
{
struct device_d *dev;
for_each_device(dev) {
if(!strcmp(name, dev->name))
return dev;
}
return NULL;
}
struct device_d *get_device_by_id(const char *id)
{
struct device_d *dev;
@ -217,89 +229,29 @@ struct device_d *get_device_by_path(const char *path)
}
EXPORT_SYMBOL(get_device_by_path);
ssize_t dev_read(struct device_d *dev, void *buf, size_t count, unsigned long offset, ulong flags)
{
if (dev->driver->read)
return dev->driver->read(dev, buf, count, offset, flags);
errno = -ENOSYS;
return -ENOSYS;
}
ssize_t dev_write(struct device_d *dev, const void *buf, size_t count, unsigned long offset, ulong flags)
{
if (dev->driver->write)
return dev->driver->write(dev, buf, count, offset, flags);
errno = -ENOSYS;
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 -1;
}
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)
return dev->driver->erase(dev, count, offset);
errno = -ENOSYS;
return -ENOSYS;
}
int dev_protect(struct device_d *dev, size_t count, unsigned long offset, int prot)
{
if (dev->driver->protect)
return dev->driver->protect(dev, count, offset, prot);
errno = -ENOSYS;
return -ENOSYS;
printf("%s: currently broken\n", __func__);
return -EINVAL;
}
int dev_memmap(struct device_d *dev, void **map, int flags)
int generic_memmap_ro(struct cdev *cdev, void **map, int flags)
{
if (dev->driver->memmap)
return dev->driver->memmap(dev, map, flags);
errno = -ENOSYS;
return -ENOSYS;
}
if (!cdev->dev)
return -EINVAL;
int generic_memmap_ro(struct device_d *dev, void **map, int flags)
{
if (flags & PROT_WRITE)
return -EACCES;
*map = (void *)dev->map_base;
*map = (void *)cdev->dev->map_base;
return 0;
}
int generic_memmap_rw(struct device_d *dev, void **map, int flags)
int generic_memmap_rw(struct cdev *cdev, void **map, int flags)
{
*map = (void *)dev->map_base;
if (!cdev->dev)
return -EINVAL;
*map = (void *)cdev->dev->map_base;
return 0;
}