mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-10-31 03:58:17 +00:00 
			
		
		
		
	As part of bringing the master branch back in to next, we need to allow for all of these changes to exist here. Reported-by: Jonas Karlman <jonas@kwiboo.se> Signed-off-by: Tom Rini <trini@konsulko.com>
		
			
				
	
	
		
			274 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			274 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0+
 | |
| /*
 | |
|  * Copyright (c) 2012, Google Inc.
 | |
|  */
 | |
| 
 | |
| #include <command.h>
 | |
| #include <dm.h>
 | |
| #include <fs.h>
 | |
| #include <part.h>
 | |
| #include <sandbox_host.h>
 | |
| #include <dm/device_compat.h>
 | |
| #include <dm/device-internal.h>
 | |
| #include <dm/uclass-internal.h>
 | |
| #include <linux/errno.h>
 | |
| #include <linux/log2.h>
 | |
| 
 | |
| static int do_host_load(struct cmd_tbl *cmdtp, int flag, int argc,
 | |
| 			char *const argv[])
 | |
| {
 | |
| 	return do_load(cmdtp, flag, argc, argv, FS_TYPE_SANDBOX);
 | |
| }
 | |
| 
 | |
| static int do_host_ls(struct cmd_tbl *cmdtp, int flag, int argc,
 | |
| 		      char *const argv[])
 | |
| {
 | |
| 	return do_ls(cmdtp, flag, argc, argv, FS_TYPE_SANDBOX);
 | |
| }
 | |
| 
 | |
| static int do_host_size(struct cmd_tbl *cmdtp, int flag, int argc,
 | |
| 			char *const argv[])
 | |
| {
 | |
| 	return do_size(cmdtp, flag, argc, argv, FS_TYPE_SANDBOX);
 | |
| }
 | |
| 
 | |
| static int do_host_save(struct cmd_tbl *cmdtp, int flag, int argc,
 | |
| 			char *const argv[])
 | |
| {
 | |
| 	return do_save(cmdtp, flag, argc, argv, FS_TYPE_SANDBOX);
 | |
| }
 | |
| 
 | |
| static int do_host_bind(struct cmd_tbl *cmdtp, int flag, int argc,
 | |
| 			char *const argv[])
 | |
| {
 | |
| 	bool removable = false;
 | |
| 	struct udevice *dev;
 | |
| 	const char *label;
 | |
| 	char *file;
 | |
| 	unsigned long blksz = DEFAULT_BLKSZ;
 | |
| 	int ret;
 | |
| 
 | |
| 	/* Skip 'bind' */
 | |
| 	argc--;
 | |
| 	argv++;
 | |
| 	if (argc < 2)
 | |
| 		return CMD_RET_USAGE;
 | |
| 
 | |
| 	if (!strcmp(argv[0], "-r")) {
 | |
| 		removable = true;
 | |
| 		argc--;
 | |
| 		argv++;
 | |
| 	}
 | |
| 
 | |
| 	if (argc < 2 || argc > 3)
 | |
| 		return CMD_RET_USAGE;
 | |
| 	label = argv[0];
 | |
| 	file = argv[1];
 | |
| 	if (argc > 2) {
 | |
| 		blksz = dectoul(argv[2], NULL);
 | |
| 		if (blksz < DEFAULT_BLKSZ || !is_power_of_2(blksz)) {
 | |
| 			printf("blksz must be >= 512 and power of 2\n");
 | |
| 			return CMD_RET_FAILURE;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	ret = host_create_attach_file(label, file, removable, blksz, &dev);
 | |
| 	if (ret) {
 | |
| 		printf("Cannot create device / bind file\n");
 | |
| 		return CMD_RET_FAILURE;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * parse_host_label() - Parse a device label or sequence number
 | |
|  *
 | |
|  * This shows an error if it returns NULL
 | |
|  *
 | |
|  * @label: String containing the label or sequence number
 | |
|  * Returns: Associated device, or NULL if not found
 | |
|  */
 | |
| static struct udevice *parse_host_label(const char *label)
 | |
| {
 | |
| 	struct udevice *dev;
 | |
| 
 | |
| 	dev = host_find_by_label(label);
 | |
| 	if (!dev) {
 | |
| 		int devnum;
 | |
| 		char *ep;
 | |
| 
 | |
| 		devnum = hextoul(label, &ep);
 | |
| 		if (*ep ||
 | |
| 		    uclass_find_device_by_seq(UCLASS_HOST, devnum, &dev)) {
 | |
| 			printf("No such device '%s'\n", label);
 | |
| 			return NULL;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return dev;
 | |
| }
 | |
| 
 | |
| static int do_host_unbind(struct cmd_tbl *cmdtp, int flag, int argc,
 | |
| 			  char *const argv[])
 | |
| {
 | |
| 	struct udevice *dev;
 | |
| 	const char *label;
 | |
| 	int ret;
 | |
| 
 | |
| 	if (argc < 2)
 | |
| 		return CMD_RET_USAGE;
 | |
| 
 | |
| 	label = argv[1];
 | |
| 	dev = parse_host_label(label);
 | |
| 	if (!dev)
 | |
| 		return CMD_RET_FAILURE;
 | |
| 
 | |
| 	ret = host_detach_file(dev);
 | |
| 	if (ret) {
 | |
| 		printf("Cannot detach file (err=%d)\n", ret);
 | |
| 		return CMD_RET_FAILURE;
 | |
| 	}
 | |
| 
 | |
| 	ret = device_unbind(dev);
 | |
| 	if (ret) {
 | |
| 		printf("Cannot attach file\n");
 | |
| 		ret = device_unbind(dev);
 | |
| 		if (ret)
 | |
| 			printf("Cannot unbind device '%s'\n", dev->name);
 | |
| 		return CMD_RET_FAILURE;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static void show_host_dev(struct udevice *dev)
 | |
| {
 | |
| 	struct host_sb_plat *plat = dev_get_plat(dev);
 | |
| 	struct blk_desc *desc;
 | |
| 	struct udevice *blk;
 | |
| 	int ret;
 | |
| 
 | |
| 	printf("%3d ", dev_seq(dev));
 | |
| 	if (!plat->fd) {
 | |
| 		printf("Not bound to a backing file\n");
 | |
| 		return;
 | |
| 	}
 | |
| 	ret = blk_get_from_parent(dev, &blk);
 | |
| 	if (ret)  /* cannot happen */
 | |
| 		return;
 | |
| 
 | |
| 	desc = dev_get_uclass_plat(blk);
 | |
| 	printf("%12lu %6lu %-15s %s\n", (unsigned long)desc->lba, desc->blksz,
 | |
| 	       plat->label, plat->filename);
 | |
| }
 | |
| 
 | |
| static int do_host_info(struct cmd_tbl *cmdtp, int flag, int argc,
 | |
| 			char *const argv[])
 | |
| {
 | |
| 	struct udevice *dev;
 | |
| 
 | |
| 	if (argc < 1)
 | |
| 		return CMD_RET_USAGE;
 | |
| 
 | |
| 	dev = NULL;
 | |
| 	if (argc >= 2) {
 | |
| 		dev = parse_host_label(argv[1]);
 | |
| 		if (!dev)
 | |
| 			return CMD_RET_FAILURE;
 | |
| 	}
 | |
| 
 | |
| 	printf("%3s %12s %6s %-15s %s\n",
 | |
| 	       "dev", "blocks", "blksz", "label", "path");
 | |
| 	if (dev) {
 | |
| 		show_host_dev(dev);
 | |
| 	} else {
 | |
| 		struct uclass *uc;
 | |
| 
 | |
| 		uclass_id_foreach_dev(UCLASS_HOST, dev, uc)
 | |
| 			show_host_dev(dev);
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int do_host_dev(struct cmd_tbl *cmdtp, int flag, int argc,
 | |
| 		       char *const argv[])
 | |
| {
 | |
| 	struct udevice *dev;
 | |
| 	const char *label;
 | |
| 
 | |
| 	if (argc < 1 || argc > 3)
 | |
| 		return CMD_RET_USAGE;
 | |
| 
 | |
| 	if (argc == 1) {
 | |
| 		struct host_sb_plat *plat;
 | |
| 
 | |
| 		dev = host_get_cur_dev();
 | |
| 		if (!dev) {
 | |
| 			printf("No current host device\n");
 | |
| 			return CMD_RET_FAILURE;
 | |
| 		}
 | |
| 		plat = dev_get_plat(dev);
 | |
| 		printf("Current host device: %d: %s\n", dev_seq(dev),
 | |
| 		       plat->label);
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	label = argv[1];
 | |
| 	dev = parse_host_label(argv[1]);
 | |
| 	if (!dev)
 | |
| 		return CMD_RET_FAILURE;
 | |
| 
 | |
| 	host_set_cur_dev(dev);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static struct cmd_tbl cmd_host_sub[] = {
 | |
| 	U_BOOT_CMD_MKENT(load, 7, 0, do_host_load, "", ""),
 | |
| 	U_BOOT_CMD_MKENT(ls, 3, 0, do_host_ls, "", ""),
 | |
| 	U_BOOT_CMD_MKENT(save, 6, 0, do_host_save, "", ""),
 | |
| 	U_BOOT_CMD_MKENT(size, 3, 0, do_host_size, "", ""),
 | |
| 	U_BOOT_CMD_MKENT(bind, 4, 0, do_host_bind, "", ""),
 | |
| 	U_BOOT_CMD_MKENT(unbind, 4, 0, do_host_unbind, "", ""),
 | |
| 	U_BOOT_CMD_MKENT(info, 3, 0, do_host_info, "", ""),
 | |
| 	U_BOOT_CMD_MKENT(dev, 0, 1, do_host_dev, "", ""),
 | |
| };
 | |
| 
 | |
| static int do_host(struct cmd_tbl *cmdtp, int flag, int argc,
 | |
| 		   char *const argv[])
 | |
| {
 | |
| 	struct cmd_tbl *c;
 | |
| 
 | |
| 	/* Skip past 'host' */
 | |
| 	argc--;
 | |
| 	argv++;
 | |
| 
 | |
| 	c = find_cmd_tbl(argv[0], cmd_host_sub, ARRAY_SIZE(cmd_host_sub));
 | |
| 
 | |
| 	if (c)
 | |
| 		return c->cmd(cmdtp, flag, argc, argv);
 | |
| 	else
 | |
| 		return CMD_RET_USAGE;
 | |
| }
 | |
| 
 | |
| U_BOOT_CMD(
 | |
| 	host, 8, 1, do_host,
 | |
| 	"Miscellaneous host commands",
 | |
| 	"load hostfs - <addr> <filename> [<bytes> <offset>]  - "
 | |
| 		"load a file from host\n"
 | |
| 	"host ls hostfs - <filename>                    - list files on host\n"
 | |
| 	"host save hostfs - <addr> <filename> <bytes> [<offset>] - "
 | |
| 		"save a file to host\n"
 | |
| 	"host size hostfs - <filename> - determine size of file on host\n"
 | |
| 	"host bind [-r] <label> <filename> [<blksz>] - bind \"host\" device to file,\n"
 | |
| 	"     and optionally set the device's logical block size\n"
 | |
| 	"     -r = mark as removable\n"
 | |
| 	"host unbind <label>     - unbind file from \"host\" device\n"
 | |
| 	"host info [<label>]     - show device binding & info\n"
 | |
| 	"host dev [<label>]      - set or retrieve the current host device\n"
 | |
| 	"host commands use the \"hostfs\" device. The \"host\" device is used\n"
 | |
| 	"with standard IO commands such as fatls or ext2load"
 | |
| );
 |