disk: support devices with HW partitions

Some device types (e.g. eMMC) have hardware-level partitions (for eMMC,
separate boot and user data partitions). This change allows the user to
specify the HW partition they wish to access when passing a device ID to
U-Boot Commands such as part, ls, load, ums, etc.

The syntax allows an optional ".$hwpartid" to be appended to the device
name string for those commands.

Existing syntax, for MMC device 0, default HW partition ID, SW partition
ID 1:

ls mmc 0:1 /

New syntax, for MMC device 0, HW partition ID 1 (boot0), SW partition
ID 2:

ls mmc 0.1:2 /

For my purposes, this is most useful for the ums (USB mass storage
gadget) command, but there's no reason not to allow the new syntax
globally.

This patch adds the core support infra-structure. The next patch will
provide the implementation for MMC.

Acked-by: Pantelis Antoniou <panto@antoniou-consulting.com>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
master
Stephen Warren 10 years ago committed by Pantelis Antoniou
parent 8210a343cd
commit 336b6f9048
  1. 74
      disk/part.c

@ -22,6 +22,7 @@
struct block_drvr {
char *name;
block_dev_desc_t* (*get_dev)(int dev);
int (*select_hwpart)(int dev_num, int hwpart);
};
static const struct block_drvr block_drvr[] = {
@ -52,11 +53,13 @@ static const struct block_drvr block_drvr[] = {
DECLARE_GLOBAL_DATA_PTR;
#ifdef HAVE_BLOCK_DEVICE
block_dev_desc_t *get_dev(const char *ifname, int dev)
block_dev_desc_t *get_dev_hwpart(const char *ifname, int dev, int hwpart)
{
const struct block_drvr *drvr = block_drvr;
block_dev_desc_t* (*reloc_get_dev)(int dev);
int (*select_hwpart)(int dev_num, int hwpart);
char *name;
int ret;
if (!ifname)
return NULL;
@ -68,17 +71,41 @@ block_dev_desc_t *get_dev(const char *ifname, int dev)
while (drvr->name) {
name = drvr->name;
reloc_get_dev = drvr->get_dev;
select_hwpart = drvr->select_hwpart;
#ifdef CONFIG_NEEDS_MANUAL_RELOC
name += gd->reloc_off;
reloc_get_dev += gd->reloc_off;
#endif
if (strncmp(ifname, name, strlen(name)) == 0)
return reloc_get_dev(dev);
if (select_hwpart)
select_hwpart += gd->reloc_off;
#endif
if (strncmp(ifname, name, strlen(name)) == 0) {
block_dev_desc_t *dev_desc = reloc_get_dev(dev);
if (!dev_desc)
return NULL;
if (hwpart == -1)
return dev_desc;
if (!select_hwpart)
return NULL;
ret = select_hwpart(dev_desc->dev, hwpart);
if (ret < 0)
return NULL;
return dev_desc;
}
drvr++;
}
return NULL;
}
block_dev_desc_t *get_dev(const char *ifname, int dev)
{
return get_dev_hwpart(ifname, dev, -1);
}
#else
block_dev_desc_t *get_dev_hwpart(const char *ifname, int dev, int hwpart)
{
return NULL;
}
block_dev_desc_t *get_dev(const char *ifname, int dev)
{
return NULL;
@ -413,25 +440,52 @@ int get_partition_info(block_dev_desc_t *dev_desc, int part
return -1;
}
int get_device(const char *ifname, const char *dev_str,
int get_device(const char *ifname, const char *dev_hwpart_str,
block_dev_desc_t **dev_desc)
{
char *ep;
int dev;
char *dup_str = NULL;
const char *dev_str, *hwpart_str;
int dev, hwpart;
hwpart_str = strchr(dev_hwpart_str, '.');
if (hwpart_str) {
dup_str = strdup(dev_hwpart_str);
dup_str[hwpart_str - dev_hwpart_str] = 0;
dev_str = dup_str;
hwpart_str++;
} else {
dev_str = dev_hwpart_str;
hwpart = -1;
}
dev = simple_strtoul(dev_str, &ep, 16);
if (*ep) {
printf("** Bad device specification %s %s **\n",
ifname, dev_str);
return -1;
dev = -1;
goto cleanup;
}
if (hwpart_str) {
hwpart = simple_strtoul(hwpart_str, &ep, 16);
if (*ep) {
printf("** Bad HW partition specification %s %s **\n",
ifname, hwpart_str);
dev = -1;
goto cleanup;
}
}
*dev_desc = get_dev(ifname, dev);
*dev_desc = get_dev_hwpart(ifname, dev, hwpart);
if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) {
printf("** Bad device %s %s **\n", ifname, dev_str);
return -1;
printf("** Bad device %s %s **\n", ifname, dev_hwpart_str);
dev = -1;
goto cleanup;
}
cleanup:
free(dup_str);
return dev;
}

Loading…
Cancel
Save