introduce cdev
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
parent
6411c3b2be
commit
a2b7cd183b
|
@ -43,7 +43,6 @@
|
||||||
*/
|
*/
|
||||||
static struct device_d cfi_dev = {
|
static struct device_d cfi_dev = {
|
||||||
.name = "cfi_flash",
|
.name = "cfi_flash",
|
||||||
.id = "nor0",
|
|
||||||
.map_base = IMX_CS0_BASE,
|
.map_base = IMX_CS0_BASE,
|
||||||
.size = 32 * 1024 * 1024, /* area size */
|
.size = 32 * 1024 * 1024, /* area size */
|
||||||
};
|
};
|
||||||
|
@ -245,10 +244,9 @@ static int imx31_devices_init(void)
|
||||||
* Create partitions that should be
|
* Create partitions that should be
|
||||||
* not touched by any regular user
|
* not touched by any regular user
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_PARTITION
|
devfs_add_partition("nor0", 0x00000, 0x40000, PARTITION_FIXED, "self0"); /* ourself */
|
||||||
dev_add_partition(&cfi_dev, 0x00000, 0x40000, PARTITION_FIXED, "self"); /* ourself */
|
devfs_add_partition("nor0", 0x40000, 0x20000, PARTITION_FIXED, "env0"); /* environment */
|
||||||
dev_add_partition(&cfi_dev, 0x40000, 0x20000, PARTITION_FIXED, "env"); /* environment */
|
|
||||||
#endif
|
|
||||||
dev_protect(&cfi_dev, 0x20000, 0, 1);
|
dev_protect(&cfi_dev, 0x20000, 0, 1);
|
||||||
|
|
||||||
register_device(&sram_dev);
|
register_device(&sram_dev);
|
||||||
|
|
|
@ -111,9 +111,9 @@ static struct device_d nand_dev = {
|
||||||
|
|
||||||
static int pcm038_devices_init(void)
|
static int pcm038_devices_init(void)
|
||||||
{
|
{
|
||||||
struct device_d *nand, *dev;
|
|
||||||
char *envdev = "no";
|
|
||||||
int i;
|
int i;
|
||||||
|
struct device_d *nand;
|
||||||
|
char *envdev = "no";
|
||||||
|
|
||||||
unsigned int mode[] = {
|
unsigned int mode[] = {
|
||||||
PD0_AIN_FEC_TXD0,
|
PD0_AIN_FEC_TXD0,
|
||||||
|
@ -192,20 +192,16 @@ static int pcm038_devices_init(void)
|
||||||
nand = get_device_by_path("/dev/nand0");
|
nand = get_device_by_path("/dev/nand0");
|
||||||
if (!nand)
|
if (!nand)
|
||||||
break;
|
break;
|
||||||
dev = dev_add_partition(nand, 0x00000, 0x40000, PARTITION_FIXED, "self_raw");
|
devfs_add_partition("nand0", 0x00000, 0x40000, PARTITION_FIXED, "self_raw");
|
||||||
if (!dev)
|
dev_add_bb_dev("self_raw", "self0");
|
||||||
break;
|
|
||||||
dev_add_bb_dev(dev, "self0");
|
|
||||||
|
|
||||||
dev = dev_add_partition(nand, 0x40000, 0x20000, PARTITION_FIXED, "env_raw");
|
devfs_add_partition("nand0", 0x40000, 0x20000, PARTITION_FIXED, "env_raw");
|
||||||
if (!dev)
|
dev_add_bb_dev("env_raw", "env0");
|
||||||
break;
|
|
||||||
dev_add_bb_dev(dev, "env0");
|
|
||||||
envdev = "NAND";
|
envdev = "NAND";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dev_add_partition(&cfi_dev, 0x00000, 0x40000, PARTITION_FIXED, "self");
|
devfs_add_partition("nor0", 0x00000, 0x40000, PARTITION_FIXED, "self0");
|
||||||
dev_add_partition(&cfi_dev, 0x40000, 0x20000, PARTITION_FIXED, "env");
|
devfs_add_partition("nor0", 0x40000, 0x20000, PARTITION_FIXED, "env0");
|
||||||
dev_protect(&cfi_dev, 0x40000, 0, 1);
|
dev_protect(&cfi_dev, 0x40000, 0, 1);
|
||||||
envdev = "NOR";
|
envdev = "NOR";
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,20 +35,24 @@
|
||||||
|
|
||||||
static struct device_d cfi_dev = {
|
static struct device_d cfi_dev = {
|
||||||
.name = "cfi_flash",
|
.name = "cfi_flash",
|
||||||
.id = "nor0",
|
|
||||||
|
|
||||||
.map_base = 0x10000000,
|
.map_base = 0x10000000,
|
||||||
.size = 16 * 1024 * 1024,
|
.size = 16 * 1024 * 1024,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct memory_platform_data sdram_pdata = {
|
||||||
|
.name = "ram0",
|
||||||
|
.flags = DEVFS_RDWR,
|
||||||
|
};
|
||||||
|
|
||||||
static struct device_d sdram_dev = {
|
static struct device_d sdram_dev = {
|
||||||
.name = "ram",
|
.name = "mem",
|
||||||
.id = "ram0",
|
|
||||||
|
|
||||||
.map_base = 0x08000000,
|
.map_base = 0x08000000,
|
||||||
.size = 16 * 1024 * 1024,
|
.size = 16 * 1024 * 1024,
|
||||||
|
|
||||||
.type = DEVICE_TYPE_DRAM,
|
.type = DEVICE_TYPE_DRAM,
|
||||||
|
.platform_data = &sdram_pdata,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct dm9000_platform_data dm9000_data = {
|
static struct dm9000_platform_data dm9000_data = {
|
||||||
|
@ -93,8 +97,8 @@ static int scb9328_devices_init(void) {
|
||||||
register_device(&sdram_dev);
|
register_device(&sdram_dev);
|
||||||
register_device(&dm9000_dev);
|
register_device(&dm9000_dev);
|
||||||
|
|
||||||
dev_add_partition(&cfi_dev, 0x00000, 0x20000, PARTITION_FIXED, "self");
|
devfs_add_partition("nor0", 0x00000, 0x20000, PARTITION_FIXED, "self0");
|
||||||
dev_add_partition(&cfi_dev, 0x40000, 0x20000, PARTITION_FIXED, "env");
|
devfs_add_partition("nor0", 0x40000, 0x20000, PARTITION_FIXED, "env0");
|
||||||
dev_protect(&cfi_dev, 0x20000, 0, 1);
|
dev_protect(&cfi_dev, 0x20000, 0, 1);
|
||||||
|
|
||||||
armlinux_set_bootparams((void *)0x08000100);
|
armlinux_set_bootparams((void *)0x08000100);
|
||||||
|
|
|
@ -518,44 +518,46 @@ U_BOOT_CMD_START(memcpy)
|
||||||
U_BOOT_CMD_HELP(cmd_memcpy_help)
|
U_BOOT_CMD_HELP(cmd_memcpy_help)
|
||||||
U_BOOT_CMD_END
|
U_BOOT_CMD_END
|
||||||
|
|
||||||
static struct device_d mem_dev = {
|
static struct file_operations memops = {
|
||||||
.name = "mem",
|
.read = mem_read,
|
||||||
.id = "mem",
|
.write = mem_write,
|
||||||
.map_base = 0,
|
.memmap = generic_memmap_rw,
|
||||||
.size = ~0, /* FIXME: should be 0x100000000, ahem... */
|
.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 = {
|
static struct driver_d mem_drv = {
|
||||||
.name = "mem",
|
.name = "mem",
|
||||||
.probe = dummy_probe,
|
.probe = mem_probe,
|
||||||
.open = dev_open_default,
|
|
||||||
.close = dev_close_default,
|
|
||||||
.read = mem_read,
|
|
||||||
.write = mem_write,
|
|
||||||
.memmap = mem_memmap,
|
|
||||||
.lseek = dev_lseek_default,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct driver_d ram_drv = {
|
static struct memory_platform_data mem_dev_pdata = {
|
||||||
.name = "ram",
|
.name = "mem",
|
||||||
.probe = dummy_probe,
|
.flags = DEVFS_RDWR,
|
||||||
.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 driver_d rom_drv = {
|
static struct device_d mem_dev = {
|
||||||
.name = "rom",
|
.name = "mem",
|
||||||
.probe = dummy_probe,
|
.map_base = 0,
|
||||||
.open = dev_open_default,
|
.size = ~0, /* FIXME: should be 0x100000000, ahem... */
|
||||||
.close = dev_close_default,
|
.platform_data = &mem_dev_pdata,
|
||||||
.read = mem_read,
|
|
||||||
.memmap = mem_memmap,
|
|
||||||
.lseek = dev_lseek_default,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int mem_init(void)
|
static int mem_init(void)
|
||||||
|
@ -566,10 +568,9 @@ static int mem_init(void)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
register_device(&mem_dev);
|
|
||||||
register_driver(&mem_drv);
|
register_driver(&mem_drv);
|
||||||
register_driver(&ram_drv);
|
register_device(&mem_dev);
|
||||||
register_driver(&rom_drv);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
142
commands/nand.c
142
commands/nand.c
|
@ -17,7 +17,6 @@
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
#include <command.h>
|
#include <command.h>
|
||||||
#include <fs.h>
|
#include <fs.h>
|
||||||
|
@ -31,40 +30,45 @@
|
||||||
#include <nand.h>
|
#include <nand.h>
|
||||||
#include <linux/mtd/mtd-abi.h>
|
#include <linux/mtd/mtd-abi.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
|
||||||
struct nand_bb {
|
struct nand_bb {
|
||||||
struct device_d device;
|
char *devname;
|
||||||
|
char *name;
|
||||||
struct device_d *physdev;
|
|
||||||
|
|
||||||
int open;
|
int open;
|
||||||
|
|
||||||
struct mtd_info_user info;
|
struct mtd_info_user info;
|
||||||
|
|
||||||
|
size_t raw_size;
|
||||||
|
size_t size;
|
||||||
|
int fd;
|
||||||
off_t offset;
|
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)
|
unsigned long offset, ulong flags)
|
||||||
{
|
{
|
||||||
struct nand_bb *bb = dev->priv;
|
struct nand_bb *bb = cdev->priv;
|
||||||
int ret, bytes = 0, now;
|
int ret, bytes = 0, now;
|
||||||
|
|
||||||
debug("%s %d %d\n", __func__, offset, count);
|
debug("%s %d %d\n", __func__, offset, count);
|
||||||
|
|
||||||
while(count) {
|
while(count) {
|
||||||
ret = dev_ioctl(bb->physdev, MEMGETBADBLOCK, (void *)bb->offset);
|
ret = ioctl(bb->fd, MEMGETBADBLOCK, (void *)bb->offset);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (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;
|
bb->offset += bb->info.erasesize;
|
||||||
}
|
}
|
||||||
|
|
||||||
now = min(count, (size_t)(bb->info.erasesize -
|
now = min(count, (size_t)(bb->info.erasesize -
|
||||||
(bb->offset % 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)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
buf += now;
|
buf += now;
|
||||||
|
@ -76,16 +80,16 @@ static ssize_t nand_bb_read(struct device_d *dev, void *buf, size_t count,
|
||||||
return bytes;
|
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)
|
unsigned long offset, ulong flags)
|
||||||
{
|
{
|
||||||
struct nand_bb *bb = dev->priv;
|
struct nand_bb *bb = cdev->priv;
|
||||||
int ret, bytes = 0, now;
|
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) {
|
while(count) {
|
||||||
ret = dev_ioctl(bb->physdev, MEMGETBADBLOCK, (void *)bb->offset);
|
ret = ioctl(bb->fd, MEMGETBADBLOCK, (void *)bb->offset);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
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 -
|
now = min(count, (size_t)(bb->info.erasesize -
|
||||||
(bb->offset % 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)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
buf += now;
|
buf += now;
|
||||||
|
@ -108,21 +113,21 @@ static ssize_t nand_bb_write(struct device_d *dev, const void *buf, size_t count
|
||||||
return bytes;
|
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");
|
printf("can only erase whole device\n");
|
||||||
return -EINVAL;
|
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)
|
if (bb->open)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
@ -133,9 +138,9 @@ static int nand_bb_open(struct device_d *dev, struct filep *f)
|
||||||
return 0;
|
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;
|
bb->open = 0;
|
||||||
|
|
||||||
|
@ -147,12 +152,12 @@ static int nand_bb_calc_size(struct nand_bb *bb)
|
||||||
ulong pos = 0;
|
ulong pos = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
while (pos < bb->physdev->size) {
|
while (pos < bb->raw_size) {
|
||||||
ret = dev_ioctl(bb->physdev, MEMGETBADBLOCK, (void *)pos);
|
ret = ioctl(bb->fd, MEMGETBADBLOCK, (void *)pos);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
if (!ret)
|
if (!ret)
|
||||||
bb->device.size += bb->info.erasesize;
|
bb->cdev.size += bb->info.erasesize;
|
||||||
|
|
||||||
pos += bb->info.erasesize;
|
pos += bb->info.erasesize;
|
||||||
}
|
}
|
||||||
|
@ -160,79 +165,67 @@ static int nand_bb_calc_size(struct nand_bb *bb)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nand_bb_probe(struct device_d *dev)
|
static struct file_operations nand_bb_ops = {
|
||||||
{
|
|
||||||
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,
|
|
||||||
.open = nand_bb_open,
|
.open = nand_bb_open,
|
||||||
.close = nand_bb_close,
|
.close = nand_bb_close,
|
||||||
.read = nand_bb_read,
|
.read = nand_bb_read,
|
||||||
.write = nand_bb_write,
|
.write = nand_bb_write,
|
||||||
.erase = nand_bb_erase,
|
.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
|
* Add a bad block aware device ontop of another (NAND) device
|
||||||
* @param[in] dev The device to add a partition on
|
* @param[in] dev The device to add a partition on
|
||||||
* @param[in] name Partition name (can be obtained with devinfo command)
|
* @param[in] name Partition name (can be obtained with devinfo command)
|
||||||
* @return The device representing the new partition.
|
* @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;
|
struct nand_bb *bb;
|
||||||
|
int ret;
|
||||||
|
struct stat s;
|
||||||
|
|
||||||
bb = xzalloc(sizeof(*bb));
|
bb = xzalloc(sizeof(*bb));
|
||||||
|
bb->devname = asprintf("/dev/%s", basename(path));
|
||||||
if (name)
|
if (name)
|
||||||
strcpy(bb->device.id, name);
|
bb->cdev.name = strdup(name);
|
||||||
else
|
else
|
||||||
sprintf(bb->device.id, "%s.bb", dev->id);
|
bb->cdev.name = asprintf("%s.bb", basename(path));
|
||||||
strcpy(bb->device.name, "nand_bb");
|
|
||||||
bb->device.priv = bb;
|
|
||||||
bb->device.size = 0;
|
|
||||||
bb->device.type = DEVICE_TYPE_NAND_BB;
|
|
||||||
bb->physdev = dev;
|
|
||||||
|
|
||||||
if (register_device(&bb->device))
|
ret = stat(bb->devname, &s);
|
||||||
|
if (ret)
|
||||||
goto free_out;
|
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_out:
|
||||||
free(bb);
|
free(bb);
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define NAND_ADD (1 << 0)
|
#define NAND_ADD (1 << 0)
|
||||||
#define NAND_DEL (1 << 1)
|
#define NAND_DEL (1 << 1)
|
||||||
#define NAND_MARKBAD (1 << 2)
|
#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;
|
int opt;
|
||||||
struct device_d *dev;
|
struct device_d *dev;
|
||||||
|
@ -262,13 +255,7 @@ static int do_nand (cmd_tbl_t *cmdtp, int argc, char *argv[])
|
||||||
|
|
||||||
if (command & NAND_ADD) {
|
if (command & NAND_ADD) {
|
||||||
while (optind < argc) {
|
while (optind < argc) {
|
||||||
dev = get_device_by_path(argv[optind]);
|
if (dev_add_bb_dev(argv[optind], NULL))
|
||||||
if (!dev) {
|
|
||||||
printf("no such device: %s\n", argv[optind]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dev_add_bb_dev(dev, NULL))
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
optind++;
|
optind++;
|
||||||
|
@ -277,17 +264,20 @@ static int do_nand (cmd_tbl_t *cmdtp, int argc, char *argv[])
|
||||||
|
|
||||||
if (command & NAND_DEL) {
|
if (command & NAND_DEL) {
|
||||||
while (optind < argc) {
|
while (optind < argc) {
|
||||||
dev = get_device_by_path(argv[optind]);
|
struct cdev *cdev;
|
||||||
if (!dev) {
|
cdev = cdev_by_name(basename(argv[optind]));
|
||||||
|
if (!cdev) {
|
||||||
printf("no such device: %s\n", argv[optind]);
|
printf("no such device: %s\n", argv[optind]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
dev = cdev->dev;
|
||||||
|
|
||||||
if (dev->type != DEVICE_TYPE_NAND_BB) {
|
if (dev->type != DEVICE_TYPE_NAND_BB) {
|
||||||
printf("not a nand bb device: %s\n", dev);
|
printf("not a nand bb device: %s\n", dev);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
bb = dev->priv;
|
bb = dev->priv;
|
||||||
|
close(bb->fd);
|
||||||
unregister_device(dev);
|
unregister_device(dev);
|
||||||
free(bb);
|
free(bb);
|
||||||
optind++;
|
optind++;
|
||||||
|
|
|
@ -37,99 +37,29 @@
|
||||||
#include <partition.h>
|
#include <partition.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <xfuncs.h>
|
#include <xfuncs.h>
|
||||||
|
#include <fs.h>
|
||||||
|
#include <linux/stat.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
|
||||||
static int dev_del_partitions(struct device_d *physdev)
|
static int mtd_part_do_parse_one(char *devname, const char *partstr,
|
||||||
{
|
char **endp, unsigned long offset,
|
||||||
struct device_d *child, *tmp;
|
off_t devsize, size_t *retsize)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
ulong size;
|
ulong size;
|
||||||
char *end;
|
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 == '-') {
|
if (*partstr == '-') {
|
||||||
size = part->physdev->size - part->offset;
|
size = devsize - offset;
|
||||||
end = (char *)partstr + 1;
|
end = (char *)partstr + 1;
|
||||||
} else {
|
} else {
|
||||||
size = strtoul_suffix(partstr, &end, 0);
|
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;
|
partstr = end;
|
||||||
|
|
||||||
if (*partstr == '(') {
|
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");
|
printf("could not find matching ')'\n");
|
||||||
return -EINVAL;
|
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++;
|
end++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (size + offset > devsize) {
|
||||||
|
printf("%s: partition end is beyond device\n", buf);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
partstr = end;
|
partstr = end;
|
||||||
|
|
||||||
if (*partstr == 'r' && *(partstr + 1) == 'o') {
|
if (*partstr == 'r' && *(partstr + 1) == 'o') {
|
||||||
part->flags |= PARTITION_READONLY;
|
flags |= PARTITION_READONLY;
|
||||||
end = (char *)(partstr + 2);
|
end = (char *)(partstr + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (endp)
|
if (endp)
|
||||||
*endp = end;
|
*endp = end;
|
||||||
|
|
||||||
strcpy(part->device.name, "partition");
|
*retsize = size;
|
||||||
part->device.size = 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[])
|
static int do_addpart(cmd_tbl_t * cmdtp, int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct partition *part;
|
char *devname;
|
||||||
struct device_d *dev;
|
|
||||||
char *endp;
|
char *endp;
|
||||||
int num = 0;
|
unsigned long offset = 0;
|
||||||
unsigned long offset;
|
off_t devsize;
|
||||||
|
struct stat s;
|
||||||
|
|
||||||
if (argc != 3) {
|
if (argc != 3) {
|
||||||
printf("Usage:\n %s\n", cmdtp->usage);
|
printf("Usage:\n %s\n", cmdtp->usage);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev = get_device_by_path(argv[1]);
|
if (stat(argv[1], &s)) {
|
||||||
if (!dev) {
|
perror("addpart");
|
||||||
printf("no such device: %s\n", argv[1]);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
devsize = s.st_size;
|
||||||
|
|
||||||
dev_del_partitions(dev);
|
devname = basename(argv[1]);
|
||||||
|
|
||||||
offset = 0;
|
|
||||||
|
|
||||||
endp = argv[2];
|
endp = argv[2];
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
part = xzalloc(sizeof(struct partition));
|
size_t size = 0;
|
||||||
|
|
||||||
part->offset = offset;
|
if (mtd_part_do_parse_one(devname, endp, &endp, offset, devsize, &size))
|
||||||
part->physdev = dev;
|
return 1;
|
||||||
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(part, endp, &endp))
|
offset += size;
|
||||||
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++;
|
|
||||||
|
|
||||||
if (!*endp)
|
if (!*endp)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (*endp != ',') {
|
if (*endp != ',') {
|
||||||
printf("parse error\n");
|
printf("parse error\n");
|
||||||
goto err_out;
|
return 1;
|
||||||
}
|
}
|
||||||
endp++;
|
endp++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
free_out:
|
|
||||||
free(part);
|
|
||||||
err_out:
|
|
||||||
dev_del_partitions(dev);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const __maybe_unused char cmd_addpart_help[] =
|
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[])
|
static int do_delpart(cmd_tbl_t * cmdtp, int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct device_d *dev;
|
int i, err;
|
||||||
|
|
||||||
if (argc != 2) {
|
for (i = 1; i < argc; i++) {
|
||||||
printf("Usage:\n%s\n", cmdtp->usage);
|
err = devfs_del_partition(basename(argv[i]));
|
||||||
return 1;
|
if (err) {
|
||||||
|
printf("cannot delete %s: %s\n", argv[i], strerror(-err));
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dev = get_device_by_path(argv[1]);
|
return 1;
|
||||||
if (!dev) {
|
|
||||||
printf("no such device: %s\n", argv[1]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev_del_partitions(dev);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const __maybe_unused char cmd_delpart_help[] =
|
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";
|
"Delete partitions previously added to a device with addpart.\n";
|
||||||
|
|
||||||
U_BOOT_CMD_START(delpart)
|
U_BOOT_CMD_START(delpart)
|
||||||
.maxargs = 2,
|
.maxargs = CONFIG_MAXARGS,
|
||||||
.cmd = do_delpart,
|
.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_HELP(cmd_delpart_help)
|
||||||
U_BOOT_CMD_END
|
U_BOOT_CMD_END
|
||||||
|
|
||||||
/** @page delpart_command delpart Delete a partition
|
/** @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.
|
* Delete a partition previously added to a device with addpart.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -12,7 +12,6 @@ obj-y += clock.o
|
||||||
obj-y += command.o
|
obj-y += command.o
|
||||||
obj-$(CONFIG_CONSOLE_FULL) += console.o
|
obj-$(CONFIG_CONSOLE_FULL) += console.o
|
||||||
obj-$(CONFIG_CONSOLE_SIMPLE) += console_simple.o
|
obj-$(CONFIG_CONSOLE_SIMPLE) += console_simple.o
|
||||||
obj-$(CONFIG_PARTITION) += partition.o
|
|
||||||
obj-y += env.o
|
obj-y += env.o
|
||||||
obj-y += startup.o
|
obj-y += startup.o
|
||||||
obj-y += misc.o
|
obj-y += misc.o
|
||||||
|
|
|
@ -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.
|
|
||||||
|
|
||||||
*/
|
|
|
@ -77,9 +77,13 @@ void early_init (void)
|
||||||
#ifdef CONFIG_DEFAULT_ENVIRONMENT
|
#ifdef CONFIG_DEFAULT_ENVIRONMENT
|
||||||
#include <uboot_default_env.h>
|
#include <uboot_default_env.h>
|
||||||
|
|
||||||
|
static struct memory_platform_data default_env_platform_data = {
|
||||||
|
.name = "defaultenv",
|
||||||
|
};
|
||||||
|
|
||||||
static struct device_d default_env_dev = {
|
static struct device_d default_env_dev = {
|
||||||
.name = "rom",
|
.name = "mem",
|
||||||
.id = "defaultenv",
|
.platform_data = &default_env_platform_data,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void register_default_env(void)
|
static void register_default_env(void)
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||||
* MA 02111-1307 USA
|
* MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
#include <linux/mtd/nand.h>
|
#include <linux/mtd/nand.h>
|
||||||
#include <linux/mtd/mtd.h>
|
#include <linux/mtd/mtd.h>
|
||||||
|
@ -31,9 +30,9 @@
|
||||||
#include <ioctl.h>
|
#include <ioctl.h>
|
||||||
#include <nand.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;
|
size_t retlen;
|
||||||
int ret;
|
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);
|
ret = info->read(info, offset, count, &retlen, buf);
|
||||||
|
|
||||||
if(ret)
|
if(ret) {
|
||||||
|
printf("err %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
return retlen;
|
return retlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define NOTALIGNED(x) (x & (info->writesize - 1)) != 0
|
#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;
|
size_t retlen, now;
|
||||||
int ret;
|
int ret;
|
||||||
void *wrbuf = NULL;
|
void *wrbuf = NULL;
|
||||||
|
@ -86,9 +87,9 @@ out:
|
||||||
return ret ? ret : _count;
|
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;
|
struct mtd_info_user *user = buf;
|
||||||
|
|
||||||
switch (request) {
|
switch (request) {
|
||||||
|
@ -113,9 +114,9 @@ static int nand_ioctl(struct device_d *dev, int request, void *buf)
|
||||||
return 0;
|
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;
|
struct erase_info erase;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -143,6 +144,14 @@ static ssize_t nand_erase(struct device_d *dev, size_t count, unsigned long offs
|
||||||
return 0;
|
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)
|
static int nand_device_probe(struct device_d *dev)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -151,13 +160,6 @@ static int nand_device_probe(struct device_d *dev)
|
||||||
static struct driver_d nand_device_driver = {
|
static struct driver_d nand_device_driver = {
|
||||||
.name = "nand_device",
|
.name = "nand_device",
|
||||||
.probe = nand_device_probe,
|
.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,
|
.type = DEVICE_TYPE_NAND,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -170,36 +172,27 @@ static int nand_init(void)
|
||||||
|
|
||||||
device_initcall(nand_init);
|
device_initcall(nand_init);
|
||||||
|
|
||||||
int add_mtd_device(struct mtd_info *mtd) {
|
int add_mtd_device(struct mtd_info *mtd)
|
||||||
struct device_d *dev;
|
{
|
||||||
int ret;
|
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");
|
mtd->cdev.ops = &nand_ops;
|
||||||
get_free_deviceid(dev->id, "nand");
|
mtd->cdev.size = mtd->size;
|
||||||
|
mtd->cdev.name = strdup(name);
|
||||||
|
mtd->cdev.dev = dev;
|
||||||
|
mtd->cdev.priv = mtd;
|
||||||
|
|
||||||
dev->size = mtd->size;
|
devfs_create(&mtd->cdev);
|
||||||
dev->type = DEVICE_TYPE_NAND;
|
|
||||||
dev->priv = mtd;
|
|
||||||
mtd->dev = dev;
|
|
||||||
|
|
||||||
ret = register_device(dev);
|
|
||||||
if (ret)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out:
|
|
||||||
free(dev);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int del_mtd_device (struct mtd_info *mtd)
|
int del_mtd_device (struct mtd_info *mtd)
|
||||||
{
|
{
|
||||||
unregister_device(mtd->dev);
|
unregister_device(&mtd->class_dev);
|
||||||
free(mtd->dev);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <init.h>
|
#include <init.h>
|
||||||
#include <miiphy.h>
|
#include <miiphy.h>
|
||||||
#include <clock.h>
|
#include <clock.h>
|
||||||
|
#include <net.h>
|
||||||
|
|
||||||
int miiphy_restart_aneg(struct miiphy_device *mdev)
|
int miiphy_restart_aneg(struct miiphy_device *mdev)
|
||||||
{
|
{
|
||||||
|
@ -84,12 +85,12 @@ int miiphy_wait_aneg(struct miiphy_device *mdev)
|
||||||
start = get_time_ns();
|
start = get_time_ns();
|
||||||
do {
|
do {
|
||||||
if (is_timeout(start, 5 * SECOND)) {
|
if (is_timeout(start, 5 * SECOND)) {
|
||||||
printf("%s: Autonegotiation timeout\n", mdev->dev.id);
|
printf("%s: Autonegotiation timeout\n", mdev->cdev.name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mdev->read(mdev, mdev->address, MII_BMSR, &status)) {
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
} while (!(status & BMSR_LSTATUS));
|
} 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)
|
if (mdev->read(mdev, mdev->address, MII_LPA, &lpa) != 0)
|
||||||
goto err_out;
|
goto err_out;
|
||||||
|
|
||||||
printf("%s: Link is %s", mdev->dev.id,
|
printf("%s: Link is %s", mdev->cdev.name,
|
||||||
bmsr & BMSR_LSTATUS ? "up" : "down");
|
bmsr & BMSR_LSTATUS ? "up" : "down");
|
||||||
|
|
||||||
if (bmcr & BMCR_ANENABLE) {
|
if (bmcr & BMCR_ANENABLE) {
|
||||||
|
@ -130,15 +131,15 @@ int miiphy_print_status(struct miiphy_device *mdev)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
err_out:
|
err_out:
|
||||||
printf("%s: failed to read\n", mdev->dev.id);
|
printf("%s: failed to read\n", mdev->cdev.name);
|
||||||
return -1;
|
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;
|
int i = count;
|
||||||
uint16_t *buf = _buf;
|
uint16_t *buf = _buf;
|
||||||
struct miiphy_device *mdev = dev->priv;
|
struct miiphy_device *mdev = cdev->priv;
|
||||||
|
|
||||||
while (i > 1) {
|
while (i > 1) {
|
||||||
mdev->read(mdev, mdev->address, offset, buf);
|
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;
|
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;
|
int i = count;
|
||||||
const uint16_t *buf = _buf;
|
const uint16_t *buf = _buf;
|
||||||
struct miiphy_device *mdev = dev->priv;
|
struct miiphy_device *mdev = cdev->priv;
|
||||||
|
|
||||||
while (i > 1) {
|
while (i > 1) {
|
||||||
mdev->write(mdev, mdev->address, offset, *buf);
|
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;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct file_operations miiphy_ops = {
|
||||||
|
.read = miiphy_read,
|
||||||
|
.write = miiphy_write,
|
||||||
|
};
|
||||||
|
|
||||||
static int miiphy_probe(struct device_d *dev)
|
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)
|
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.priv = mdev;
|
||||||
mdev->dev.size = 32;
|
strcpy(mdev->dev.name, "miiphy");
|
||||||
|
|
||||||
return register_device(&mdev->dev);
|
return register_device(&mdev->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void miiphy_unregister(struct miiphy_device *mdev)
|
|
||||||
{
|
|
||||||
unregister_device(&mdev->dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct driver_d miiphy_drv = {
|
static struct driver_d miiphy_drv = {
|
||||||
.name = "miiphy",
|
.name = "miiphy",
|
||||||
.probe = miiphy_probe,
|
.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)
|
static int miiphy_init(void)
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#include <init.h>
|
#include <init.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <cfi_flash.h>
|
#include <cfi_flash.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#define FLASH_CMD_CFI 0x98
|
#define FLASH_CMD_CFI 0x98
|
||||||
#define FLASH_CMD_READ_ID 0x90
|
#define FLASH_CMD_READ_ID 0x90
|
||||||
|
@ -352,16 +353,16 @@ static int flash_erase_one (flash_info_t * info, long sect)
|
||||||
return rcode;
|
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;
|
unsigned long start, end;
|
||||||
int i, ret = 0;
|
int i, ret = 0;
|
||||||
|
|
||||||
debug("%s: erase 0x%08x (size %d)\n", __FUNCTION__, offset, count);
|
debug("%s: erase 0x%08x (size %d)\n", __FUNCTION__, offset, count);
|
||||||
|
|
||||||
start = flash_find_sector(finfo, dev->map_base + offset);
|
start = flash_find_sector(finfo, cdev->dev->map_base + offset);
|
||||||
end = flash_find_sector(finfo, dev->map_base + offset + count - 1);
|
end = flash_find_sector(finfo, cdev->dev->map_base + offset + count - 1);
|
||||||
|
|
||||||
for (i = start; i <= end; i++) {
|
for (i = start; i <= end; i++) {
|
||||||
ret = flash_erase_one (finfo, i);
|
ret = flash_erase_one (finfo, i);
|
||||||
|
@ -373,16 +374,16 @@ out:
|
||||||
return ret;
|
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;
|
unsigned long start, end;
|
||||||
int i, ret = 0;
|
int i, ret = 0;
|
||||||
|
|
||||||
debug("%s: protect 0x%08x (size %d)\n", __FUNCTION__, offset, count);
|
debug("%s: protect 0x%08x (size %d)\n", __FUNCTION__, offset, count);
|
||||||
|
|
||||||
start = flash_find_sector(finfo, dev->map_base + offset);
|
start = flash_find_sector(finfo, cdev->dev->map_base + offset);
|
||||||
end = flash_find_sector(finfo, dev->map_base + offset + count - 1);
|
end = flash_find_sector(finfo, cdev->dev->map_base + offset + count - 1);
|
||||||
|
|
||||||
for (i = start; i <= end; i++) {
|
for (i = start; i <= end; i++) {
|
||||||
ret = flash_real_protect (finfo, i, prot);
|
ret = flash_real_protect (finfo, i, prot);
|
||||||
|
@ -394,14 +395,14 @@ out:
|
||||||
return ret;
|
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;
|
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;
|
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 */
|
#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)
|
static int cfi_probe (struct device_d *dev)
|
||||||
{
|
{
|
||||||
unsigned long size = 0;
|
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;
|
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 */
|
/* Init: no FLASHes known */
|
||||||
info->flash_id = FLASH_UNKNOWN;
|
info->flash_id = FLASH_UNKNOWN;
|
||||||
size += info->size = flash_get_size(info, dev->map_base);
|
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) {
|
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);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct driver_d cfi_driver = {
|
static struct driver_d cfi_driver = {
|
||||||
.name = "cfi_flash",
|
.name = "cfi_flash",
|
||||||
.probe = cfi_probe,
|
.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,
|
.info = cfi_info,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <cfi_flash_new.h>
|
#include <cfi_flash_new.h>
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file implements a Common Flash Interface (CFI) driver for U-Boot.
|
* 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;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
printf("unsopported vendor\n");
|
printf("unsupported vendor\n");
|
||||||
break;
|
return 0;
|
||||||
}
|
}
|
||||||
info->cfi_cmd_set->flash_read_jedec_ids (info);
|
info->cfi_cmd_set->flash_read_jedec_ids (info);
|
||||||
flash_write_cmd (info, 0, info->cfi_offset, FLASH_CMD_CFI);
|
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;
|
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;
|
unsigned long start, end;
|
||||||
int i, ret = 0;
|
int i, ret = 0;
|
||||||
|
|
||||||
printf("%s: erase 0x%08x (size %d)\n", __FUNCTION__, offset, count);
|
printf("%s: erase 0x%08x (size %d)\n", __FUNCTION__, offset, count);
|
||||||
|
|
||||||
start = find_sector(finfo, dev->map_base + offset);
|
start = find_sector(finfo, cdev->dev->map_base + offset);
|
||||||
end = find_sector(finfo, dev->map_base + offset + count - 1);
|
end = find_sector(finfo, cdev->dev->map_base + offset + count - 1);
|
||||||
|
|
||||||
for (i = start; i <= end; i++) {
|
for (i = start; i <= end; i++) {
|
||||||
ret = finfo->cfi_cmd_set->flash_erase_one(finfo, 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;
|
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;
|
unsigned long start, end;
|
||||||
int i, ret = 0;
|
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);
|
start = find_sector(finfo, cdev->dev->map_base + offset);
|
||||||
end = find_sector(finfo, dev->map_base + offset + count - 1);
|
end = find_sector(finfo, cdev->dev->map_base + offset + count - 1);
|
||||||
|
|
||||||
for (i = start; i <= end; i++) {
|
for (i = start; i <= end; i++) {
|
||||||
ret = flash_real_protect (finfo, i, prot);
|
ret = flash_real_protect (finfo, i, prot);
|
||||||
|
@ -679,14 +680,14 @@ out:
|
||||||
return ret;
|
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;
|
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;
|
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;
|
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)
|
static int cfi_probe (struct device_d *dev)
|
||||||
{
|
{
|
||||||
unsigned long size = 0;
|
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;
|
dev->priv = (void *)info;
|
||||||
|
|
||||||
|
@ -953,27 +964,26 @@ static int cfi_probe (struct device_d *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info->flash_id == FLASH_UNKNOWN) {
|
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",
|
printf ("## Unknown FLASH on Bank at 0x%08x - Size = 0x%08lx = %ld MB\n",
|
||||||
dev->map_base, info->size, info->size << 20);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct driver_d cfi_driver = {
|
static struct driver_d cfi_driver = {
|
||||||
.name = "cfi_flash",
|
.name = "cfi_flash",
|
||||||
.probe = cfi_probe,
|
.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,
|
.info = cfi_info,
|
||||||
.protect = cfi_protect,
|
|
||||||
.memmap = generic_memmap_ro,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int cfi_init(void)
|
static int cfi_init(void)
|
||||||
|
|
|
@ -206,14 +206,17 @@ static int pmic_probe(struct device_d *dev)
|
||||||
return 0;
|
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 = {
|
static struct driver_d pmic_driver = {
|
||||||
.name = "mc13783",
|
.name = "mc13783",
|
||||||
.probe = pmic_probe,
|
.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)
|
static int pmic_init(void)
|
||||||
|
|
230
fs/devfs.c
230
fs/devfs.c
|
@ -29,27 +29,53 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <xfuncs.h>
|
#include <xfuncs.h>
|
||||||
#include <linux/stat.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;
|
struct cdev *cdev = f->inode;
|
||||||
off_t ret;
|
|
||||||
|
|
||||||
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)
|
if (ret != -1)
|
||||||
f->pos = pos;
|
f->pos = pos;
|
||||||
|
@ -57,51 +83,100 @@ static off_t devfs_lseek(struct device_d *_dev, FILE *f, off_t pos)
|
||||||
return ret;
|
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)
|
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)
|
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;
|
return -ENOENT;
|
||||||
|
|
||||||
f->size = dev->size;
|
f->size = cdev->size;
|
||||||
f->inode = dev;
|
f->inode = cdev;
|
||||||
return dev_open(dev, f);
|
|
||||||
|
if (cdev->ops->open)
|
||||||
|
return cdev->ops->open(cdev, f);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int devfs_close(struct device_d *_dev, FILE *f)
|
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)
|
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)
|
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));
|
dir = xzalloc(sizeof(DIR));
|
||||||
|
|
||||||
if (!list_empty(&device_list))
|
if (!list_empty(&cdev_list))
|
||||||
dir->priv = list_first_entry(&device_list, struct device_d, list);
|
dir->priv = list_first_entry(&cdev_list, struct cdev, list);
|
||||||
|
|
||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct dirent* devfs_readdir(struct device_d *_dev, DIR *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;
|
return NULL;
|
||||||
|
|
||||||
list_for_each_entry_from(dev, &device_list, list) {
|
list_for_each_entry_from(cdev, &cdev_list, list) {
|
||||||
if (!*dev->id)
|
strcpy(dir->d.d_name, cdev->name);
|
||||||
continue;
|
dir->priv = list_entry(cdev->list.next, struct cdev, list);
|
||||||
if (!dev->driver)
|
|
||||||
continue;
|
|
||||||
strcpy(dir->d.d_name, dev->id);
|
|
||||||
dir->priv = list_entry(dev->list.next, struct device_d, list);
|
|
||||||
return &dir->d;
|
return &dir->d;
|
||||||
}
|
}
|
||||||
return NULL;
|
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)
|
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);
|
cdev = cdev_by_name(filename + 1);
|
||||||
if (!dev)
|
if (!cdev)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
if (!dev->driver)
|
|
||||||
return -ENXIO;
|
|
||||||
|
|
||||||
s->st_mode = S_IFCHR;
|
s->st_mode = S_IFCHR;
|
||||||
s->st_size = dev->size;
|
s->st_size = cdev->size;
|
||||||
if (dev->driver->write)
|
if (cdev->ops->write)
|
||||||
s->st_mode |= S_IWUSR;
|
s->st_mode |= S_IWUSR;
|
||||||
if (dev->driver->read)
|
if (cdev->ops->read)
|
||||||
s->st_mode |= S_IRUSR;
|
s->st_mode |= S_IRUSR;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -206,3 +274,71 @@ static int devfs_init(void)
|
||||||
|
|
||||||
device_initcall(devfs_init);
|
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
27
fs/fs.c
|
@ -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;
|
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);
|
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);
|
memcpy_sz(buf, (void *)(dev->map_base + offset), size, flags & O_RWSIZE_MASK);
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(mem_read);
|
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;
|
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);
|
memcpy_sz((void *)(dev->map_base + offset), buf, size, flags & O_RWSIZE_MASK);
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(mem_write);
|
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);
|
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
struct driver_d driver;
|
struct driver_d driver;
|
||||||
|
struct cdev cdev;
|
||||||
ulong size; /* total bank size in bytes */
|
ulong size; /* total bank size in bytes */
|
||||||
ushort sector_count; /* number of erase units */
|
ushort sector_count; /* number of erase units */
|
||||||
ulong flash_id; /* combined device & manufacturer code */
|
ulong flash_id; /* combined device & manufacturer code */
|
||||||
|
|
|
@ -59,6 +59,7 @@ typedef struct {
|
||||||
ushort cfi_version; /* cfi version */
|
ushort cfi_version; /* cfi version */
|
||||||
ushort cfi_offset; /* offset for cfi query */
|
ushort cfi_offset; /* offset for cfi query */
|
||||||
struct cfi_cmd_set *cfi_cmd_set;
|
struct cfi_cmd_set *cfi_cmd_set;
|
||||||
|
struct cdev cdev;
|
||||||
} flash_info_t;
|
} flash_info_t;
|
||||||
|
|
||||||
struct cfi_cmd_set {
|
struct cfi_cmd_set {
|
||||||
|
|
|
@ -98,7 +98,6 @@ struct device_d {
|
||||||
void *type_data; /*! In case this device is a specific device, this pointer
|
void *type_data; /*! In case this device is a specific device, this pointer
|
||||||
* points to the type specific device, i.e. eth_device
|
* points to the type specific device, i.e. eth_device
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct driver_d *driver; /*! The driver for this device */
|
struct driver_d *driver; /*! The driver for this device */
|
||||||
|
|
||||||
struct list_head list; /* The list of all devices */
|
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. */
|
/*! Called if an instance of a device is gone. */
|
||||||
void (*remove)(struct device_d *);
|
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 (*info) (struct device_d *);
|
||||||
void (*shortinfo) (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);
|
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);
|
struct cdev;
|
||||||
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_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 */
|
/* 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_read(struct cdev *cdev, 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);
|
ssize_t mem_write(struct cdev *cdev, const void *buf, size_t count, ulong offset, ulong flags);
|
||||||
int mem_memmap(struct device_d *dev, void **map, int flags);
|
int mem_memmap(struct cdev *cdev, void **map, int flags);
|
||||||
|
|
||||||
/* Use this if you have nothing to do in your drivers probe function */
|
/* Use this if you have nothing to do in your drivers probe function */
|
||||||
int dummy_probe(struct device_d *);
|
int dummy_probe(struct device_d *);
|
||||||
|
@ -254,10 +231,10 @@ int dummy_probe(struct device_d *);
|
||||||
*/
|
*/
|
||||||
void devices_shutdown(void);
|
void devices_shutdown(void);
|
||||||
|
|
||||||
int generic_memmap_ro(struct device_d *dev, void **map, int flags);
|
int generic_memmap_ro(struct cdev *dev, void **map, int flags);
|
||||||
int generic_memmap_rw(struct device_d *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;
|
return ofs;
|
||||||
}
|
}
|
||||||
|
@ -312,5 +289,51 @@ struct bus_type {
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct bus_type platform_bus;
|
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 */
|
#endif /* DRIVER_H */
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#ifndef __MTD_MTD_H__
|
#ifndef __MTD_MTD_H__
|
||||||
#define __MTD_MTD_H__
|
#define __MTD_MTD_H__
|
||||||
|
|
||||||
|
#include <driver.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <list.h>
|
#include <list.h>
|
||||||
#include <linux/mtd/mtd-abi.h>
|
#include <linux/mtd/mtd-abi.h>
|
||||||
|
@ -199,7 +200,9 @@ struct mtd_info {
|
||||||
int (*get_device) (struct mtd_info *mtd);
|
int (*get_device) (struct mtd_info *mtd);
|
||||||
void (*put_device) (struct mtd_info *mtd);
|
void (*put_device) (struct mtd_info *mtd);
|
||||||
|
|
||||||
|
struct device_d class_dev;
|
||||||
struct device_d *dev;
|
struct device_d *dev;
|
||||||
|
struct cdev cdev;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -146,6 +146,7 @@ struct miiphy_device {
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
struct eth_device *edev;
|
struct eth_device *edev;
|
||||||
|
struct cdev cdev;
|
||||||
};
|
};
|
||||||
|
|
||||||
int miiphy_register(struct miiphy_device *mdev);
|
int miiphy_register(struct miiphy_device *mdev);
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
#ifndef __NAND_H__
|
#ifndef __NAND_H__
|
||||||
#define __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__ */
|
#endif /* __NAND_H__ */
|
||||||
|
|
||||||
|
|
|
@ -17,20 +17,8 @@ struct partition {
|
||||||
struct device_d device;
|
struct device_d device;
|
||||||
|
|
||||||
char name[16];
|
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 */
|
#endif /* __PARTITION_H */
|
||||||
|
|
||||||
|
|
94
lib/driver.c
94
lib/driver.c
|
@ -42,6 +42,18 @@ EXPORT_SYMBOL(driver_list);
|
||||||
|
|
||||||
static LIST_HEAD(active);
|
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 *get_device_by_id(const char *id)
|
||||||
{
|
{
|
||||||
struct device_d *dev;
|
struct device_d *dev;
|
||||||
|
@ -217,89 +229,29 @@ struct device_d *get_device_by_path(const char *path)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(get_device_by_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)
|
int dev_protect(struct device_d *dev, size_t count, unsigned long offset, int prot)
|
||||||
{
|
{
|
||||||
if (dev->driver->protect)
|
printf("%s: currently broken\n", __func__);
|
||||||
return dev->driver->protect(dev, count, offset, prot);
|
return -EINVAL;
|
||||||
errno = -ENOSYS;
|
|
||||||
return -ENOSYS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
if (!cdev->dev)
|
||||||
return dev->driver->memmap(dev, map, flags);
|
return -EINVAL;
|
||||||
errno = -ENOSYS;
|
|
||||||
return -ENOSYS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int generic_memmap_ro(struct device_d *dev, void **map, int flags)
|
|
||||||
{
|
|
||||||
if (flags & PROT_WRITE)
|
if (flags & PROT_WRITE)
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
*map = (void *)dev->map_base;
|
*map = (void *)cdev->dev->map_base;
|
||||||
return 0;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue