diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 4250fb091..37560fd46 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -154,6 +154,7 @@ int register_device(struct device_d *new_device) INIT_LIST_HEAD(&new_device->cdevs); INIT_LIST_HEAD(&new_device->parameters); INIT_LIST_HEAD(&new_device->active); + INIT_LIST_HEAD(&new_device->bus_list); if (new_device->bus) { if (!new_device->parent) @@ -181,6 +182,8 @@ int unregister_device(struct device_d *old_dev) dev_dbg(old_dev, "unregister\n"); + dev_remove_parameters(old_dev); + if (old_dev->driver) old_dev->bus->remove(old_dev); diff --git a/drivers/mtd/core.c b/drivers/mtd/core.c index 3439a389a..36a363fa3 100644 --- a/drivers/mtd/core.c +++ b/drivers/mtd/core.c @@ -146,6 +146,7 @@ static int mtd_op_erase(struct cdev *cdev, size_t count, loff_t offset) { struct mtd_info *mtd = cdev->priv; struct erase_info erase; + uint32_t addr; int ret; ret = mtd_erase_align(mtd, &count, &offset); @@ -154,9 +155,10 @@ static int mtd_op_erase(struct cdev *cdev, size_t count, loff_t offset) memset(&erase, 0, sizeof(erase)); erase.mtd = mtd; - erase.addr = offset; + addr = offset; if (!mtd->block_isbad) { + erase.addr = addr; erase.len = count; return mtd_erase(mtd, &erase); } @@ -164,22 +166,24 @@ static int mtd_op_erase(struct cdev *cdev, size_t count, loff_t offset) erase.len = mtd->erasesize; while (count > 0) { - dev_dbg(cdev->dev, "erase %d %d\n", erase.addr, erase.len); + dev_dbg(cdev->dev, "erase %d %d\n", addr, erase.len); if (!mtd->allow_erasebad) - ret = mtd_block_isbad(mtd, erase.addr); + ret = mtd_block_isbad(mtd, addr); else ret = 0; + erase.addr = addr; + if (ret > 0) { - printf("Skipping bad block at 0x%08x\n", erase.addr); + printf("Skipping bad block at 0x%08x\n", addr); } else { ret = mtd_erase(mtd, &erase); if (ret) return ret; } - erase.addr += mtd->erasesize; + addr += mtd->erasesize; count -= count > mtd->erasesize ? mtd->erasesize : count; } @@ -404,7 +408,8 @@ int add_mtd_device(struct mtd_info *mtd, char *devname, int device_id) } devfs_create(&mtd->cdev); - if (mtd->parent) + + if (mtd->parent && !mtd->master) of_parse_partitions(&mtd->cdev, mtd->parent->device_node); list_for_each_entry(hook, &mtd_register_hooks, hook) diff --git a/drivers/mtd/mtdoob.c b/drivers/mtd/mtdoob.c index 1e88b534f..b9cac2ae6 100644 --- a/drivers/mtd/mtdoob.c +++ b/drivers/mtd/mtdoob.c @@ -73,7 +73,7 @@ static int add_mtdoob_device(struct mtd_info *mtd, char *devname, void **priv) { struct mtdoob *mtdoob; - if (mtd->oobsize == 0) + if (mtd->master || mtd->oobsize == 0) return 0; mtdoob = xzalloc(sizeof(*mtdoob)); @@ -93,6 +93,9 @@ static int del_mtdoob_device(struct mtd_info *mtd, void **priv) { struct mtdoob *mtdoob; + if (mtd->master || mtd->oobsize == 0) + return 0; + mtdoob = *priv; devfs_remove(&mtdoob->cdev); free(mtdoob); diff --git a/drivers/mtd/mtdraw.c b/drivers/mtd/mtdraw.c index be347233b..006b28f9b 100644 --- a/drivers/mtd/mtdraw.c +++ b/drivers/mtd/mtdraw.c @@ -285,6 +285,9 @@ static int add_mtdraw_device(struct mtd_info *mtd, char *devname, void **priv) { struct mtdraw *mtdraw; + if (mtd->master || mtd->oobsize == 0) + return 0; + mtdraw = xzalloc(sizeof(*mtdraw)); mtdraw->writebuf = xmalloc(RAW_WRITEBUF_SIZE); mtdraw->mtd = mtd; @@ -306,6 +309,9 @@ static int del_mtdraw_device(struct mtd_info *mtd, void **priv) { struct mtdraw *mtdraw; + if (mtd->master || mtd->oobsize == 0) + return 0; + mtdraw = *priv; devfs_remove(&mtdraw->cdev); free(mtdraw); diff --git a/drivers/mtd/partition.c b/drivers/mtd/partition.c index 85f486d0e..351c5831b 100644 --- a/drivers/mtd/partition.c +++ b/drivers/mtd/partition.c @@ -4,29 +4,19 @@ #include #include -struct mtd_part { - struct mtd_info mtd; - struct mtd_info *master; - uint64_t offset; - struct list_head list; -}; - -#define PART(x) ((struct mtd_part *)(x)) - static int mtd_part_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { - struct mtd_part *part = PART(mtd); struct mtd_ecc_stats stats; int res; - stats = part->master->ecc_stats; + stats = mtd->master->ecc_stats; if (from >= mtd->size) len = 0; else if (from + len > mtd->size) len = mtd->size - from; - res = part->master->read(part->master, from + part->offset, + res = mtd->master->read(mtd->master, from + mtd->master_offset, len, retlen, buf); return res; } @@ -34,57 +24,52 @@ static int mtd_part_read(struct mtd_info *mtd, loff_t from, size_t len, static int mtd_part_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { - struct mtd_part *part = PART(mtd); - if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; if (to >= mtd->size) len = 0; else if (to + len > mtd->size) len = mtd->size - to; - return part->master->write(part->master, to + part->offset, + return mtd->master->write(mtd->master, to + mtd->master_offset, len, retlen, buf); } static int mtd_part_erase(struct mtd_info *mtd, struct erase_info *instr) { - struct mtd_part *part = PART(mtd); int ret; if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; if (instr->addr >= mtd->size) return -EINVAL; - instr->addr += part->offset; - ret = part->master->erase(part->master, instr); + instr->addr += mtd->master_offset; + ret = mtd->master->erase(mtd->master, instr); if (ret) { if (instr->fail_addr != 0xffffffff) - instr->fail_addr -= part->offset; - instr->addr -= part->offset; + instr->fail_addr -= mtd->master_offset; + instr->addr -= mtd->master_offset; } return ret; } static int mtd_part_block_isbad(struct mtd_info *mtd, loff_t ofs) { - struct mtd_part *part = PART(mtd); if (ofs >= mtd->size) return -EINVAL; - ofs += part->offset; - return mtd_block_isbad(part->master, ofs); + ofs += mtd->master_offset; + return mtd_block_isbad(mtd->master, ofs); } static int mtd_part_block_markbad(struct mtd_info *mtd, loff_t ofs) { - struct mtd_part *part = PART(mtd); int res; if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; if (ofs >= mtd->size) return -EINVAL; - ofs += part->offset; - res = part->master->block_markbad(part->master, ofs); + ofs += mtd->master_offset; + res = mtd->master->block_markbad(mtd->master, ofs); if (!res) mtd->ecc_stats.badblocks++; return res; @@ -93,14 +78,23 @@ static int mtd_part_block_markbad(struct mtd_info *mtd, loff_t ofs) struct mtd_info *mtd_add_partition(struct mtd_info *mtd, off_t offset, size_t size, unsigned long flags, const char *name) { - struct mtd_part *slave; - struct mtd_info *slave_mtd; + struct mtd_info *part; int start = 0, end = 0, i; - slave = xzalloc(sizeof(*slave)); - slave_mtd = &slave->mtd; + part = xzalloc(sizeof(*part)); - memcpy(slave_mtd, mtd, sizeof(*slave)); + part->type = mtd->type; + part->flags = mtd->flags; + part->parent = &mtd->class_dev; + part->erasesize = mtd->erasesize; + part->writesize = mtd->writesize; + part->writebufsize = mtd->writebufsize; + part->oobsize = mtd->oobsize; + part->oobavail = mtd->oobavail; + part->bitflip_threshold = mtd->bitflip_threshold; + part->ecclayout = mtd->ecclayout; + part->ecc_strength = mtd->ecc_strength; + part->subpage_sft = mtd->subpage_sft; /* * find the number of eraseregions the partition includes. @@ -118,26 +112,37 @@ struct mtd_info *mtd_add_partition(struct mtd_info *mtd, off_t offset, size_t si end = i; } - slave_mtd->numeraseregions = end - start; + part->numeraseregions = end - start; - slave_mtd->read = mtd_part_read; - slave_mtd->write = mtd_part_write; - slave_mtd->erase = mtd_part_erase; - slave_mtd->block_isbad = mtd->block_isbad ? mtd_part_block_isbad : NULL; - slave_mtd->block_markbad = mtd->block_markbad ? mtd_part_block_markbad : NULL; - slave_mtd->size = size; - slave_mtd->name = strdup(name); + part->read = mtd_part_read; + part->write = mtd_part_write; + part->erase = mtd_part_erase; + part->block_isbad = mtd->block_isbad ? mtd_part_block_isbad : NULL; + part->block_markbad = mtd->block_markbad ? mtd_part_block_markbad : NULL; + part->size = size; + part->name = strdup(name); - slave->offset = offset; - slave->master = mtd; + part->master_offset = offset; + part->master = mtd; - return slave_mtd; + if (!strncmp(mtd->cdev.name, name, strlen(mtd->cdev.name))) + part->cdev.partname = xstrdup(name + strlen(mtd->cdev.name) + 1); + + add_mtd_device(part, part->name, DEVICE_ID_SINGLE); + + return part; } -void mtd_del_partition(struct mtd_info *mtd) +int mtd_del_partition(struct mtd_info *part) { - struct mtd_part *part = PART(mtd); + if (!part->master) + return -EINVAL; - free(mtd->name); + del_mtd_device(part); + + free(part->cdev.partname); + free(part->name); free(part); + + return 0; } diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 202b04602..9c75442ac 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -157,10 +157,18 @@ static int uif_init(struct ubi_device *ubi, int *ref) *ref = 0; sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num); + sprintf(ubi->dev.name, "ubi"); + ubi->dev.id = DEVICE_ID_DYNAMIC; + ubi->dev.parent = &ubi->mtd->class_dev; + + err = register_device(&ubi->dev); + if (err) + goto out_unreg; + err = ubi_cdev_add(ubi); if (err) { ubi_err("cannot add character device"); - goto out_unreg; + goto out_dev; } for (i = 0; i < ubi->vtbl_slots; i++) @@ -177,6 +185,8 @@ static int uif_init(struct ubi_device *ubi, int *ref) out_volumes: kill_volumes(ubi); devfs_remove(&ubi->cdev); +out_dev: + unregister_device(&ubi->dev); out_unreg: ubi_err("cannot initialize UBI %s, error %d", ubi->ubi_name, err); return err; @@ -193,6 +203,7 @@ out_unreg: static void uif_close(struct ubi_device *ubi) { kill_volumes(ubi); + unregister_device(&ubi->dev); ubi_cdev_remove(ubi); } diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index 129f2e2e2..e8beaa501 100644 --- a/drivers/mtd/ubi/cdev.c +++ b/drivers/mtd/ubi/cdev.c @@ -179,6 +179,7 @@ int ubi_volume_cdev_add(struct ubi_device *ubi, struct ubi_volume *vol) cdev->name = asprintf("ubi%d.%s", ubi->ubi_num, vol->name); cdev->priv = priv; cdev->size = vol->used_bytes; + cdev->dev = &vol->dev; printf("registering %s as /dev/%s\n", vol->name, cdev->name); ret = devfs_create(cdev); if (ret) { @@ -199,6 +200,7 @@ void ubi_volume_cdev_remove(struct ubi_volume *vol) list_del(&vol->list); devfs_remove(cdev); + unregister_device(&vol->dev); kfree(cdev->name); kfree(priv); } diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 65339efb9..d828b3293 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -147,6 +147,13 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) vol->last_eb_bytes = vol->usable_leb_size; } + sprintf(vol->dev.name, "%s.%s", dev_name(&ubi->dev), vol->name); + vol->dev.id = DEVICE_ID_SINGLE; + vol->dev.parent = &ubi->dev; + err = register_device(&vol->dev); + if (err) + goto out_acc; + /* Register character device for the volume */ err = ubi_volume_cdev_add(ubi, vol); if (err) { @@ -190,6 +197,7 @@ out_sysfs: out_mapping: if (do_free) kfree(vol->eba_tbl); + unregister_device(&vol->dev); out_acc: ubi->rsvd_pebs -= vol->reserved_pebs; ubi->avail_pebs += vol->reserved_pebs; @@ -245,6 +253,7 @@ int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl) goto out_err; } + unregister_device(&vol->dev); devfs_remove(&vol->cdev); ubi->rsvd_pebs -= reserved_pebs; @@ -427,6 +436,13 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol) dbg_gen("add volume"); + sprintf(vol->dev.name, "%s.%s", dev_name(&ubi->dev), vol->name); + vol->dev.id = DEVICE_ID_SINGLE; + vol->dev.parent = &ubi->dev; + err = register_device(&vol->dev); + if (err) + return err; + /* Register character device for the volume */ err = ubi_volume_cdev_add(ubi, vol); if (err) { @@ -454,6 +470,7 @@ void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol) dbg_gen("free volume %d", vol->vol_id); ubi->volumes[vol->vol_id] = NULL; + unregister_device(&vol->dev); devfs_remove(&vol->cdev); } diff --git a/fs/devfs-core.c b/fs/devfs-core.c index 44f0169e6..bd6d48286 100644 --- a/fs/devfs-core.c +++ b/fs/devfs-core.c @@ -276,6 +276,15 @@ struct cdev *devfs_add_partition(const char *devname, loff_t offset, loff_t size if (offset + size > cdev->size) return ERR_PTR(-EINVAL); + if (IS_ENABLED(CONFIG_PARTITION_NEED_MTD) && cdev->mtd) { + struct mtd_info *mtd; + + mtd = mtd_add_partition(cdev->mtd, offset, size, flags, name); + if (IS_ERR(mtd)) + return (void *)mtd; + return 0; + } + new = xzalloc(sizeof (*new)); new->name = strdup(name); if (!strncmp(devname, name, strlen(devname))) @@ -287,17 +296,6 @@ struct cdev *devfs_add_partition(const char *devname, loff_t offset, loff_t size new->dev = cdev->dev; new->flags = flags | DEVFS_IS_PARTITION; -#ifdef CONFIG_PARTITION_NEED_MTD - if (cdev->mtd) { - new->mtd = mtd_add_partition(cdev->mtd, offset, size, flags, name); - if (IS_ERR(new->mtd)) { - int ret = PTR_ERR(new->mtd); - free(new); - return ERR_PTR(ret); - } - } -#endif - devfs_create(new); return new; @@ -312,16 +310,16 @@ int devfs_del_partition(const char *name) if (!cdev) return -ENOENT; + if (IS_ENABLED(CONFIG_PARTITION_NEED_MTD) && cdev->mtd) { + ret = mtd_del_partition(cdev->mtd); + return ret; + } + if (!(cdev->flags & DEVFS_IS_PARTITION)) return -EINVAL; if (cdev->flags & DEVFS_PARTITION_FIXED) return -EPERM; -#ifdef CONFIG_PARTITION_NEED_MTD - if (cdev->mtd) - mtd_del_partition(cdev->mtd); -#endif - ret = devfs_remove(cdev); if (ret) return ret; diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 402e4978b..e02204a50 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -217,6 +217,9 @@ struct mtd_info { /* If true erasing bad blocks is allowed, this is set via a device parameter */ bool allow_erasebad; int p_allow_erasebad; + + struct mtd_info *master; + uint32_t master_offset; }; int mtd_erase(struct mtd_info *mtd, struct erase_info *instr); @@ -272,7 +275,7 @@ struct mtd_notifier { struct mtd_info *mtd_add_partition(struct mtd_info *mtd, off_t offset, size_t size, unsigned long flags, const char *name); -void mtd_del_partition(struct mtd_info *mtd); +int mtd_del_partition(struct mtd_info *mtd); extern void register_mtd_user (struct mtd_notifier *new); extern int unregister_mtd_user (struct mtd_notifier *old); diff --git a/net/eth.c b/net/eth.c index cb59e7614..524fb8978 100644 --- a/net/eth.c +++ b/net/eth.c @@ -380,8 +380,6 @@ void eth_unregister(struct eth_device *edev) if (edev == eth_current) eth_current = NULL; - dev_remove_parameters(&edev->dev); - if (IS_ENABLED(CONFIG_OFDEVICE)) free(edev->nodepath);