diff --git a/Documentation/devicetree/bindings/barebox/barebox,environment.rst b/Documentation/devicetree/bindings/barebox/barebox,environment.rst index d5e52ea..12b103b 100644 --- a/Documentation/devicetree/bindings/barebox/barebox,environment.rst +++ b/Documentation/devicetree/bindings/barebox/barebox,environment.rst @@ -6,7 +6,10 @@ Required properties: * ``compatible``: should be ``barebox,environment`` -* ``device-path``: path to the environment +* ``device-path``: path to the device environment is on + +Optional properties: +* ``file-path``: path to a file in the device named by device-path The device-path is a multistring property. The first string should contain a nodepath to the node containing the physical device of the environment or @@ -19,9 +22,19 @@ be the label for MTD partitions, the number for DOS partitions (beginning with 0) or the name for GPT partitions. +The file-path is the name of a file located in a FAT filesystem on the +device named in device-path. This filesystem will be mounted and the +environment loaded from the file's location in the directory tree. + Example:: environment@0 { compatible = "barebox,environment"; device-path = &flash, "partname:barebox-environment"; }; + + environment@1 { + compatible = "barebox,environment"; + device-path = &mmc, "partname:1"; + file-path = "barebox.env"; + }; diff --git a/Documentation/devicetree/bindings/barebox/barebox,state.rst b/Documentation/devicetree/bindings/barebox/barebox,state.rst index ef66029..d1b0627 100644 --- a/Documentation/devicetree/bindings/barebox/barebox,state.rst +++ b/Documentation/devicetree/bindings/barebox/barebox,state.rst @@ -55,8 +55,8 @@ ``#size-cells = <1>``. Defines the ``offset`` and ``size`` of the variable in the ``raw`` backend. ``size`` must fit the node ``type``. Variables are not allowed to overlap. -* ``type``: Should be ``uint8``, ``uint32``, ``enum32``, ``mac`` or - ``string`` for the type of the variable +* ``type``: Should be ``uint8``, ``uint32``, ``int32``. ``enum32``, ``mac`` + or ``string`` for the type of the variable * ``names``: For ``enum32`` values only, this specifies the values possible for ``enum32``. @@ -93,6 +93,7 @@ * ``uint8``: * ``uint32``: +* ``int32``: * ``enum32``: The ``default`` value is an integer representing an offset into the names array. * ``mac``: diff --git a/arch/arm/boards/at91sam9x5ek/hw_version.c b/arch/arm/boards/at91sam9x5ek/hw_version.c index 37eb1f8..2f84d82 100644 --- a/arch/arm/boards/at91sam9x5ek/hw_version.c +++ b/arch/arm/boards/at91sam9x5ek/hw_version.c @@ -235,7 +235,7 @@ int ret; struct device_node *node; - for_each_compatible_node(node, NULL, "atmel,hsmci") { + for_each_compatible_node_from(node, root, NULL, "atmel,hsmci") { struct device_node *slotnode = of_get_child_by_name(node, "slot"); if (!slotnode) diff --git a/arch/arm/boards/highbank/init.c b/arch/arm/boards/highbank/init.c index a0d4b30..1cb02e6 100644 --- a/arch/arm/boards/highbank/init.c +++ b/arch/arm/boards/highbank/init.c @@ -35,13 +35,13 @@ __be32 latency; if (!(reg & HB_PWRDOM_STAT_SATA)) { - for_each_compatible_node(node, NULL, "calxeda,hb-ahci") + for_each_compatible_node_from(node, root, NULL, "calxeda,hb-ahci") of_set_property(node, "status", "disabled", sizeof("disabled"), 1); } if (!(reg & HB_PWRDOM_STAT_EMMC)) { - for_each_compatible_node(node, NULL, "calxeda,hb-sdhci") + for_each_compatible_node_from(node, root, NULL, "calxeda,hb-sdhci") of_set_property(node, "status", "disabled", sizeof("disabled"), 1); } diff --git a/arch/arm/configs/socfpga_defconfig b/arch/arm/configs/socfpga_defconfig index 0a31de5..7fbe045 100644 --- a/arch/arm/configs/socfpga_defconfig +++ b/arch/arm/configs/socfpga_defconfig @@ -67,6 +67,7 @@ CONFIG_NET_NETCONSOLE=y CONFIG_NET_RESOLV=y CONFIG_OF_BAREBOX_DRIVERS=y +CONFIG_OF_BAREBOX_ENV_IN_FS=y CONFIG_DRIVER_SERIAL_NS16550=y CONFIG_DRIVER_NET_DESIGNWARE=y CONFIG_MCI=y diff --git a/arch/arm/dts/socfpga.dtsi b/arch/arm/dts/socfpga.dtsi index d4d498b..d16758f 100644 --- a/arch/arm/dts/socfpga.dtsi +++ b/arch/arm/dts/socfpga.dtsi @@ -1,4 +1,12 @@ / { + chosen { + environment@0 { + compatible = "barebox,environment"; + device-path = &mmc, "partname:1"; + file-path = "barebox.env"; + }; + }; + aliases { mmc0 = &mmc; }; diff --git a/arch/arm/mach-imx/ocotp.c b/arch/arm/mach-imx/ocotp.c index 6ff5ee4..c99a003 100644 --- a/arch/arm/mach-imx/ocotp.c +++ b/arch/arm/mach-imx/ocotp.c @@ -426,7 +426,6 @@ cdev->priv = priv; cdev->size = 192; cdev->name = "imx-ocotp"; - cdev->device_node = dev->device_node; ret = devfs_create(cdev); diff --git a/arch/arm/mach-socfpga/generic.c b/arch/arm/mach-socfpga/generic.c index 2d4afd0..906bc63 100644 --- a/arch/arm/mach-socfpga/generic.c +++ b/arch/arm/mach-socfpga/generic.c @@ -103,41 +103,3 @@ return 0; } core_initcall(socfpga_init); - -#if defined(CONFIG_ENV_HANDLING) -#define ENV_PATH "/boot/barebox.env" -static int socfpga_env_init(void) -{ - struct stat s; - char *diskdev, *partname; - int ret; - - diskdev = "mmc0"; - - device_detect_by_name(diskdev); - - partname = asprintf("/dev/%s.1", diskdev); - - ret = stat(partname, &s); - - if (ret) { - pr_err("Failed to load environment: no device '%s'\n", diskdev); - goto out_free; - } - - mkdir("/boot", 0666); - ret = mount(partname, "fat", "/boot", NULL); - if (ret) { - pr_err("Failed to load environment: mount %s failed (%d)\n", partname, ret); - goto out_free; - } - - pr_debug("Loading default env from %s on device %s\n", ENV_PATH, diskdev); - default_environment_path_set(ENV_PATH); - -out_free: - free(partname); - return 0; -} -late_initcall(socfpga_env_init); -#endif diff --git a/commands/devinfo.c b/commands/devinfo.c index 3c9d6a6..c78efcb 100644 --- a/commands/devinfo.c +++ b/commands/devinfo.c @@ -21,7 +21,7 @@ static int do_devinfo_subtree(struct device_d *dev, int depth) { struct device_d *child; - struct cdev *cdev; + struct cdev *cdev, *cdevl; int i; for (i = 0; i < depth; i++) @@ -33,11 +33,14 @@ list_for_each_entry(cdev, &dev->cdevs, devices_list) { for (i = 0; i < depth + 1; i++) printf(" "); - printf("`-- 0x%08llx-0x%08llx (%10s): /dev/%s\n", + printf("`-- 0x%08llx-0x%08llx (%10s): /dev/%s", cdev->offset, cdev->offset + cdev->size - 1, size_human_readable(cdev->size), cdev->name); + list_for_each_entry(cdevl, &cdev->links, link_entry) + printf(", %s", cdevl->name); + printf("\n"); } } else { printf("\n"); diff --git a/common/partitions.c b/common/partitions.c index 4f50bfe..82ec508 100644 --- a/common/partitions.c +++ b/common/partitions.c @@ -71,20 +71,14 @@ if (!part->name[0]) return 0; - partition_name = asprintf("%s.%s", blk->cdev.name, part->name); - if (!partition_name) - return -ENOMEM; + partition_name = xasprintf("%s.%s", blk->cdev.name, part->name); + ret = devfs_create_link(cdev, partition_name); + if (ret) + dev_warn(blk->dev, "Failed to create link from %s to %s\n", + partition_name, blk->cdev.name); + free(partition_name); - dev_dbg(blk->dev, "Registering partition %s on drive %s\n", - partition_name, blk->cdev.name); - cdev = devfs_add_partition(blk->cdev.name, - start, size, 0, partition_name); - - if (IS_ERR(cdev)) - dev_warn(blk->dev, "Registering partition %s on drive %s failed\n", - partition_name, blk->cdev.name); - - ret = 0; + return 0; out: free(partition_name); return ret; diff --git a/common/partitions/Kconfig b/common/partitions/Kconfig index 90238ad..be9405a 100644 --- a/common/partitions/Kconfig +++ b/common/partitions/Kconfig @@ -16,6 +16,7 @@ config PARTITION_DISK_EFI depends on PARTITION_DISK select CRC32 + select PRINTF_UUID bool "EFI: GPT partition support" help Add support to handle partitions in GUID Partition Table style. diff --git a/common/partitions/efi.c b/common/partitions/efi.c index 61abf00..a9945dd 100644 --- a/common/partitions/efi.c +++ b/common/partitions/efi.c @@ -457,6 +457,7 @@ pentry->size = le64_to_cpu(ptes[i].ending_lba) - pentry->first_sec; pentry->size++; part_set_efi_name(&ptes[i], pentry->name); + snprintf(pentry->partuuid, sizeof(pentry->partuuid), "%pUl", &ptes[i].unique_partition_guid); pd->used_entries++; } diff --git a/common/state.c b/common/state.c index ec72dbd..d1fa47f 100644 --- a/common/state.c +++ b/common/state.c @@ -66,6 +66,7 @@ STATE_TYPE_ENUM, STATE_TYPE_U8, STATE_TYPE_U32, + STATE_TYPE_S32, STATE_TYPE_MAC, STATE_TYPE_STRING, }; @@ -209,8 +210,8 @@ return &su32->var; } -static struct state_variable *state_uint32_create(struct state *state, - const char *name, struct device_node *node) +static struct state_variable *state_int32_create(struct state *state, + const char *name, struct device_node *node, const char *format) { struct state_uint32 *su32; struct param_d *param; @@ -218,7 +219,7 @@ su32 = xzalloc(sizeof(*su32)); param = dev_add_param_int(&state->dev, name, state_set_dirty, - NULL, &su32->value, "%u", state); + NULL, &su32->value, format, state); if (IS_ERR(param)) { free(su32); return ERR_CAST(param); @@ -231,6 +232,18 @@ return &su32->var; } +static struct state_variable *state_uint32_create(struct state *state, + const char *name, struct device_node *node) +{ + return state_int32_create(state, name, node, "%u"); +} + +static struct state_variable *state_sint32_create(struct state *state, + const char *name, struct device_node *node) +{ + return state_int32_create(state, name, node, "%d"); +} + /* * enum32 */ @@ -605,6 +618,12 @@ .export = state_string_export, .import = state_string_import, .create = state_string_create, + }, { + .type = STATE_TYPE_S32, + .type_name = "int32", + .export = state_uint32_export, + .import = state_uint32_import, + .create = state_sint32_create, }, }; diff --git a/drivers/input/gpio_keys.c b/drivers/input/gpio_keys.c index d017594..5b03fd7 100644 --- a/drivers/input/gpio_keys.c +++ b/drivers/input/gpio_keys.c @@ -21,6 +21,9 @@ int active_low; int previous_state; + + int debounce_interval; + u64 debounce_start; }; struct gpio_keys { @@ -60,11 +63,17 @@ gb = &gk->buttons[i]; val = gpio_get_value(gb->gpio); - if (val != gb->previous_state && val != gb->active_low) { - kfifo_put(gk->recv_fifo, (u_char*)&gb->code, sizeof(int)); - debug("pressed gpio(%d) as %d\n", gb->gpio, gb->code); + if (!is_timeout(gb->debounce_start, gb->debounce_interval * MSECOND)) + continue; + + if (val != gb->previous_state) { + gb->debounce_start = get_time_ns(); + if (val != gb->active_low) { + kfifo_put(gk->recv_fifo, (u_char*)&gb->code, sizeof(int)); + debug("pressed gpio(%d) as %d\n", gb->gpio, gb->code); + } + gb->previous_state = val; } - gb->previous_state = val; } } @@ -111,6 +120,7 @@ gk->buttons[i].gpio = pdata->buttons[i].gpio; gk->buttons[i].code = pdata->buttons[i].code; gk->buttons[i].active_low = pdata->buttons[i].active_low; + gk->buttons[i].debounce_interval = 20; } return 0; @@ -142,6 +152,11 @@ if (ret) return ret; + gk->buttons[i].debounce_interval = 20; + + of_property_read_u32(npkey, "debounce-interval", + &gk->buttons[i].debounce_interval); + gk->buttons[i].code = keycode; i++; diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 90475cf..d0a62bd 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -43,3 +43,10 @@ support for this feature. This currently allows to configure the environment path from devicetree and to partition devices. See Documentation/devicetree/bindings/barebox/ for more information. + +config OF_BAREBOX_ENV_IN_FS + depends on OF_BAREBOX_DRIVERS + bool "Allow environment to come from file" + help + Allow the devie tree configuration of the barebox environment path + to specify a file in filesystem, which will be mounted. diff --git a/drivers/of/barebox.c b/drivers/of/barebox.c index 1b3078e..125feef 100644 --- a/drivers/of/barebox.c +++ b/drivers/of/barebox.c @@ -24,7 +24,46 @@ #include #include #include -#include +#include + +#define ENV_MNT_DIR "/boot" /* If env on filesystem, where to mount */ + +/* If dev describes a file on a fs, mount the fs and change devpath to + * point to the file's path. Otherwise leave devpath alone. Does + * nothing in env in a file support isn't enabled. */ +static int environment_check_mount(struct device_d *dev, char **devpath) +{ + const char *filepath; + int ret; + + if (!IS_ENABLED(CONFIG_OF_BAREBOX_ENV_IN_FS)) + return 0; + + ret = of_property_read_string(dev->device_node, "file-path", &filepath); + if (ret == -EINVAL) { + /* No file-path so just use device-path */ + return 0; + } else if (ret) { + /* file-path property exists, but has error */ + dev_err(dev, "Problem with file-path property\n"); + return ret; + } + + /* Get device env is on and mount it */ + mkdir(ENV_MNT_DIR, 0777); + ret = mount(*devpath, "fat", ENV_MNT_DIR, NULL); + if (ret) { + dev_err(dev, "Failed to load environment: mount %s failed (%d)\n", + *devpath, ret); + return ret; + } + + /* Set env to be in a file on the now mounted device */ + dev_dbg(dev, "Loading default env from %s on device %s\n", + filepath, *devpath); + *devpath = asprintf("%s/%s", ENV_MNT_DIR, filepath); + return 0; +} static int environment_probe(struct device_d *dev) { @@ -35,8 +74,12 @@ if (ret) return ret; - dev_info(dev, "setting default environment path to %s\n", path); + /* Do we need to mount a fs and find env there? */ + ret = environment_check_mount(dev, &path); + if (ret) + return ret; + dev_dbg(dev, "Setting default environment path to %s\n", path); default_environment_path_set(path); return 0; diff --git a/drivers/of/of_path.c b/drivers/of/of_path.c index 9016147..ed620f1 100644 --- a/drivers/of/of_path.c +++ b/drivers/of/of_path.c @@ -23,16 +23,6 @@ #include -struct of_path { - struct cdev *cdev; - struct device_d *dev; -}; - -struct of_path_type { - const char *name; - int (*parse)(struct of_path *op, const char *str); -}; - struct device_d *of_find_device_by_node_path(const char *path) { struct device_d *dev; @@ -48,65 +38,6 @@ } /** - * of_path_type_partname - find a partition based on physical device and - * partition name - * @op: of_path context - * @name: the partition name to find - */ -static int of_path_type_partname(struct of_path *op, const char *name) -{ - if (!op->dev) - return -EINVAL; - - op->cdev = device_find_partition(op->dev, name); - if (op->cdev) { - pr_debug("%s: found part '%s'\n", __func__, name); - return 0; - } else { - pr_debug("%s: cannot find part '%s'\n", __func__, name); - return -ENODEV; - } -} - -static struct of_path_type of_path_types[] = { - { - .name = "partname", - .parse = of_path_type_partname, - }, -}; - -static int of_path_parse_one(struct of_path *op, const char *str) -{ - int i, ret; - char *name, *desc; - - pr_debug("parsing: %s\n", str); - - name = xstrdup(str); - desc = strchr(name, ':'); - if (!desc) { - free(name); - return -EINVAL; - } - - *desc = 0; - desc++; - - for (i = 0; i < ARRAY_SIZE(of_path_types); i++) { - if (!strcmp(of_path_types[i].name, name)) { - ret = of_path_types[i].parse(op, desc); - goto out; - } - } - - ret = -EINVAL; -out: - free(name); - - return ret; -} - -/** * __of_find_path * * @node: The node to find the cdev for, can be the device or a @@ -119,36 +50,32 @@ */ static int __of_find_path(struct device_node *node, const char *part, char **outpath, unsigned flags) { - struct of_path op; + struct device_d *dev; + struct cdev *cdev; bool add_bb = false; - int ret; - op.dev = of_find_device_by_node_path(node->full_name); - if (!op.dev) { - op.dev = of_find_device_by_node_path(node->parent->full_name); - if (!op.dev) + dev = of_find_device_by_node_path(node->full_name); + if (!dev) { + dev = of_find_device_by_node_path(node->parent->full_name); + if (!dev) return -ENODEV; } - device_detect(op.dev); + device_detect(dev); - if (part) { - /* Find a partition inside op.dev */ - ret = of_path_parse_one(&op, part); - if (ret) - return ret; - } else { - /* node points directly to device */ - op.cdev = cdev_by_device_node(node); - if (!op.cdev) - return -ENOENT; - } + if (part) + cdev = device_find_partition(dev, part); + else + cdev = cdev_by_device_node(node); - if ((flags & OF_FIND_PATH_FLAGS_BB) && op.cdev->mtd && - mtd_can_have_bb(op.cdev->mtd)) + if (!cdev) + return -ENOENT; + + if ((flags & OF_FIND_PATH_FLAGS_BB) && cdev->mtd && + mtd_can_have_bb(cdev->mtd)) add_bb = true; - *outpath = asprintf("/dev/%s%s", op.cdev->name, add_bb ? ".bb" : ""); + *outpath = asprintf("/dev/%s%s", cdev->name, add_bb ? ".bb" : ""); return 0; } @@ -198,8 +125,8 @@ { struct device_node *rnode; const char *path; - const char *part; - int ret; + const char *part = NULL; + const char partnamestr[] = "partname:"; path = of_get_property(node, propname, NULL); if (!path) @@ -209,9 +136,15 @@ if (!rnode) return -ENODEV; - ret = of_property_read_string_index(node, propname, 1, &part); - if (ret) - part = NULL; + of_property_read_string_index(node, propname, 1, &part); + if (part) { + if (!strncmp(part, partnamestr, sizeof(partnamestr) - 1)) { + part += sizeof(partnamestr) - 1; + } else { + pr_err("Invalid device-path: %s\n", part); + return -EINVAL; + } + } return __of_find_path(rnode, part, outpath, flags); } diff --git a/drivers/pci/pci-imx6.c b/drivers/pci/pci-imx6.c index eaa5f0e..d32bd2b 100644 --- a/drivers/pci/pci-imx6.c +++ b/drivers/pci/pci-imx6.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -51,6 +52,8 @@ #define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2 0x2 #define PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK 0xf +#define PCIE_RC_LCSR 0x80 + /* PCIe Port Logic registers (memory-mapped) */ #define PL_OFFSET 0x700 #define PCIE_PL_PFLR (PL_OFFSET + 0x08) @@ -235,7 +238,10 @@ val = readl(pp->dbi_base + PCIE_PL_PFLR); val &= ~PCIE_PL_PFLR_LINK_STATE_MASK; val |= PCIE_PL_PFLR_FORCE_LINK; + + data_abort_mask(); writel(val, pp->dbi_base + PCIE_PL_PFLR); + data_abort_unmask(); gpr12 &= ~IMX6Q_GPR12_PCIE_CTL_2; writel(gpr12, imx6_pcie->iomuxc_gpr + IOMUXC_GPR12); @@ -360,13 +366,29 @@ } } +static int imx6_pcie_wait_for_speed_change(struct pcie_port *pp) +{ + uint32_t tmp; + uint64_t start = get_time_ns(); + + while (!is_timeout(start, SECOND)) { + tmp = readl(pp->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); + /* Test if the speed change finished. */ + if (!(tmp & PORT_LOGIC_SPEED_CHANGE)) + return 0; + } + + dev_err(pp->dev, "Speed change timeout\n"); + return -EINVAL; +} + + static int imx6_pcie_start_link(struct pcie_port *pp) { struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp); uint32_t tmp; int ret; u32 gpr12; - u64 start; /* * Force Gen1 operation when starting the link. In case the link is @@ -401,28 +423,22 @@ tmp |= PORT_LOGIC_SPEED_CHANGE; writel(tmp, pp->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); - start = get_time_ns(); - while (!is_timeout(start, SECOND)) { - tmp = readl(pp->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL); - /* Test if the speed change finished. */ - if (!(tmp & PORT_LOGIC_SPEED_CHANGE)) - break; + ret = imx6_pcie_wait_for_speed_change(pp); + if (ret) { + dev_err(pp->dev, "Failed to bring link up!\n"); + return ret; } /* Make sure link training is finished as well! */ - if (tmp & PORT_LOGIC_SPEED_CHANGE) - ret = -EINVAL; - else - ret = imx6_pcie_wait_for_link(pp); - + ret = imx6_pcie_wait_for_link(pp); if (ret) { dev_err(pp->dev, "Failed to bring link up!\n"); - } else { - tmp = readl(pp->dbi_base + 0x80); - dev_dbg(pp->dev, "Link up, Gen=%i\n", (tmp >> 16) & 0xf); + return ret; } - return ret; + tmp = readl(pp->dbi_base + PCIE_RC_LCSR); + dev_dbg(pp->dev, "Link up, Gen=%i\n", (tmp >> 16) & 0xf); + return 0; } static void imx6_pcie_host_init(struct pcie_port *pp) @@ -592,9 +608,35 @@ if (ret < 0) return ret; + dev->priv = imx6_pcie; + return 0; } +static void imx6_pcie_remove(struct device_d *dev) +{ + struct imx6_pcie *imx6_pcie = dev->priv; + u32 val; + + val = readl(imx6_pcie->pp.dbi_base + PCIE_PL_PFLR); + val &= ~PCIE_PL_PFLR_LINK_STATE_MASK; + val |= PCIE_PL_PFLR_FORCE_LINK; + data_abort_mask(); + writel(val, imx6_pcie->pp.dbi_base + PCIE_PL_PFLR); + data_abort_unmask(); + + val = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR12); + val &= ~IMX6Q_GPR12_PCIE_CTL_2; + writel(val, imx6_pcie->iomuxc_gpr + IOMUXC_GPR12); + + val = readl(imx6_pcie->iomuxc_gpr + IOMUXC_GPR1); + val |= IMX6Q_GPR1_PCIE_TEST_PD; + writel(val, imx6_pcie->iomuxc_gpr + IOMUXC_GPR1); + + val &= ~IMX6Q_GPR1_PCIE_REF_CLK_EN; + writel(val, imx6_pcie->iomuxc_gpr + IOMUXC_GPR1); +} + static struct of_device_id imx6_pcie_of_match[] = { { .compatible = "fsl,imx6q-pcie", }, {}, @@ -604,6 +646,7 @@ .name = "imx6-pcie", .of_compatible = DRV_OF_COMPAT(imx6_pcie_of_match), .probe = imx6_pcie_probe, + .remove = imx6_pcie_remove, }; device_platform_driver(imx6_pcie_driver); diff --git a/drivers/usb/imx/chipidea-imx.c b/drivers/usb/imx/chipidea-imx.c index ae30718..a1c36cf 100644 --- a/drivers/usb/imx/chipidea-imx.c +++ b/drivers/usb/imx/chipidea-imx.c @@ -242,7 +242,8 @@ ci->vbus = regulator_get(dev, "vbus"); - regulator_enable(ci->vbus); + if (!IS_ERR(ci->vbus)) + regulator_enable(ci->vbus); base = dev_request_mem_region(dev, 0); if (IS_ERR(base)) diff --git a/fs/devfs-core.c b/fs/devfs-core.c index 2541ea3..88a7e3a 100644 --- a/fs/devfs-core.c +++ b/fs/devfs-core.c @@ -46,7 +46,18 @@ } #endif -struct cdev *cdev_by_name(const char *filename) +struct cdev *cdev_readlink(struct cdev *cdev) +{ + if (cdev->link) + cdev = cdev->link; + + /* links to links are not allowed */ + BUG_ON(cdev->link); + + return cdev; +} + +struct cdev *lcdev_by_name(const char *filename) { struct cdev *cdev; @@ -57,6 +68,17 @@ return NULL; } +struct cdev *cdev_by_name(const char *filename) +{ + struct cdev *cdev; + + cdev = lcdev_by_name(filename); + if (!cdev) + return NULL; + + return cdev_readlink(cdev); +} + struct cdev *cdev_by_device_node(struct device_node *node) { struct cdev *cdev; @@ -65,7 +87,7 @@ if (!cdev->device_node) continue; if (cdev->device_node == node) - return cdev; + return cdev_readlink(cdev); } return NULL; } @@ -111,14 +133,6 @@ return -EBUSY; /* all indexes are used */ } -int cdev_do_open(struct cdev *cdev, unsigned long flags) -{ - if (cdev->ops->open) - return cdev->ops->open(cdev, flags); - - return 0; -} - struct cdev *cdev_open(const char *name, unsigned long flags) { struct cdev *cdev; @@ -131,9 +145,11 @@ if (!cdev) return NULL; - ret = cdev_do_open(cdev, flags); - if (ret) - return NULL; + if (cdev->ops->open) { + ret = cdev->ops->open(cdev, flags); + if (ret) + return NULL; + } return cdev; } @@ -259,22 +275,59 @@ if (cdev) return -EEXIST; + INIT_LIST_HEAD(&new->links); + list_add_tail(&new->list, &cdev_list); - if (new->dev) + if (new->dev) { list_add_tail(&new->devices_list, &new->dev->cdevs); + if (!new->device_node) + new->device_node = new->dev->device_node; + } + + return 0; +} + +int devfs_create_link(struct cdev *cdev, const char *name) +{ + struct cdev *new; + + if (cdev_by_name(name)) + return -EEXIST; + + /* + * Create a link to the real cdev instead of creating + * a link to a link. + */ + cdev = cdev_readlink(cdev); + + new = xzalloc(sizeof(*new)); + new->name = xstrdup(name); + new->link = cdev; + INIT_LIST_HEAD(&new->links); + list_add_tail(&new->list, &cdev_list); + list_add_tail(&new->link_entry, &cdev->links); return 0; } int devfs_remove(struct cdev *cdev) { + struct cdev *c, *tmp; + if (cdev->open) return -EBUSY; list_del(&cdev->list); + if (cdev->dev) list_del(&cdev->devices_list); + list_for_each_entry_safe(c, tmp, &cdev->links, link_entry) + devfs_remove(c); + + if (cdev->link) + free(cdev); + return 0; } diff --git a/fs/devfs.c b/fs/devfs.c index 5c96682..0b8d4fd 100644 --- a/fs/devfs.c +++ b/fs/devfs.c @@ -212,12 +212,18 @@ { struct cdev *cdev; - cdev = cdev_by_name(filename + 1); + cdev = lcdev_by_name(filename + 1); if (!cdev) return -ENOENT; s->st_mode = S_IFCHR; s->st_size = cdev->size; + + if (cdev->link) + s->st_mode |= S_IFLNK; + + cdev = cdev_readlink(cdev); + if (cdev->ops->write) s->st_mode |= S_IWUSR; if (cdev->ops->read) @@ -242,6 +248,24 @@ { } +static int devfs_readlink(struct device_d *dev, const char *pathname, + char *buf, size_t bufsz) +{ + struct cdev *cdev; + + cdev = cdev_by_name(pathname + 1); + if (!cdev) + return -ENOENT; + + while (cdev->link) + cdev = cdev->link; + + bufsz = min(bufsz, strlen(cdev->name)); + memcpy(buf, cdev->name, bufsz); + + return 0; +} + static struct fs_driver_d devfs_driver = { .read = devfs_read, .write = devfs_write, @@ -258,6 +282,7 @@ .erase = devfs_erase, .protect = devfs_protect, .memmap = devfs_memmap, + .readlink = devfs_readlink, .flags = FS_DRIVER_NO_DEV, .drv = { .probe = devfs_probe, diff --git a/fs/fs.c b/fs/fs.c index 4983fc7..ace72f7 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -346,6 +346,9 @@ in_automount++; + if (fs_dev_root != get_fsdevice_by_path(path)) + goto out; + list_for_each_entry(am, &automount_list, list) { int len_path = strlen(path); int len_am_path = strlen(am->path); @@ -377,12 +380,10 @@ if (ret) printf("running automount command '%s' failed\n", am->cmd); - else - automount_remove(am->path); break; } - +out: in_automount--; } diff --git a/include/bootstrap.h b/include/bootstrap.h index 9863ff4..d3ee6be 100644 --- a/include/bootstrap.h +++ b/include/bootstrap.h @@ -15,10 +15,10 @@ void bootstrap_boot(kernel_entry_func func, bool barebox); #ifdef CONFIG_BOOTSTRAP_DEVFS -void* bootstrap_read_devfs(char *devname, bool use_bb, int offset, +void* bootstrap_read_devfs(const char *devname, bool use_bb, int offset, int default_size, int max_size); #else -static inline void* bootstrap_read_devfs(char *devname, bool use_bb, int offset, +static inline void* bootstrap_read_devfs(const char *devname, bool use_bb, int offset, int default_size, int max_size) { return NULL; @@ -26,9 +26,9 @@ #endif #ifdef CONFIG_BOOTSTRAP_DISK -void* bootstrap_read_disk(char *devname, char *fstype); +void* bootstrap_read_disk(const char *devname, const char *fstype); #else -static inline void* bootstrap_read_disk(char *devname, char *fstype) +static inline void* bootstrap_read_disk(const char *devname, const char *fstype) { return NULL; } diff --git a/include/driver.h b/include/driver.h index 046dd90..31c6734 100644 --- a/include/driver.h +++ b/include/driver.h @@ -450,13 +450,18 @@ int open; struct mtd_info *mtd; u8 dos_partition_type; + struct cdev *link; + struct list_head link_entry, links; }; int devfs_create(struct cdev *); +int devfs_create_link(struct cdev *, const char *name); int devfs_remove(struct cdev *); int cdev_find_free_index(const char *); struct cdev *device_find_partition(struct device_d *dev, const char *name); struct cdev *cdev_by_name(const char *filename); +struct cdev *lcdev_by_name(const char *filename); +struct cdev *cdev_readlink(struct cdev *cdev); struct cdev *cdev_by_device_node(struct device_node *node); struct cdev *cdev_open(const char *name, unsigned long flags); int cdev_do_open(struct cdev *, unsigned long flags); diff --git a/include/of.h b/include/of.h index e60fe89..75cc3c1 100644 --- a/include/of.h +++ b/include/of.h @@ -641,9 +641,13 @@ #define for_each_node_by_name_from(dn, root, name) \ for (dn = of_find_node_by_name(root, name); dn; \ dn = of_find_node_by_name(dn, name)) -#define for_each_compatible_node(dn, type, compatible) \ - for (dn = of_find_compatible_node(NULL, type, compatible); dn; \ +/* Iterate over compatible nodes starting from given root */ +#define for_each_compatible_node_from(dn, root, type, compatible) \ + for (dn = of_find_compatible_node(root, type, compatible); dn; \ dn = of_find_compatible_node(dn, type, compatible)) +/* Iterate over compatible nodes in default device tree */ +#define for_each_compatible_node(dn, type, compatible) \ + for_each_compatible_node_from(dn, NULL, type, compatible) static inline struct device_node *of_find_matching_node( struct device_node *from, const struct of_device_id *matches) @@ -732,6 +736,17 @@ s; \ s = of_prop_next_string(prop, s)) +/* + * struct device_node *n; + * + * of_property_for_each_phandle(np, root, "propname", n) + * printk("phandle points to: %s\n", n->full_name); + */ +#define of_property_for_each_phandle(np, root, propname, n) \ + for (int _i = 0; \ + (n = of_parse_phandle_from(np, root, propname, _i));\ + _i++) + static inline int of_property_write_u8(struct device_node *np, const char *propname, u8 value) { diff --git a/lib/bootstrap/devfs.c b/lib/bootstrap/devfs.c index 5a64477..6a3dd76 100644 --- a/lib/bootstrap/devfs.c +++ b/lib/bootstrap/devfs.c @@ -80,7 +80,7 @@ } #endif -void* bootstrap_read_devfs(char *devname, bool use_bb, int offset, +void* bootstrap_read_devfs(const char *devname, bool use_bb, int offset, int default_size, int max_size) { int ret; diff --git a/lib/bootstrap/disk.c b/lib/bootstrap/disk.c index ebf9ee5..a55d5d7 100644 --- a/lib/bootstrap/disk.c +++ b/lib/bootstrap/disk.c @@ -14,12 +14,12 @@ #include #include -void* bootstrap_read_disk(char *dev, char *fstype) +void* bootstrap_read_disk(const char *dev, const char *fstype) { int ret; void *buf; int len; - char *path = "/"; + const char *path = "/"; ret = mount(dev, fstype, path, NULL); if (ret) { diff --git a/lib/readline.c b/lib/readline.c index c007e10..cac9670 100644 --- a/lib/readline.c +++ b/lib/readline.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -150,7 +151,7 @@ /* room ??? */ if (insert || *num == *eol_num) { - if (*eol_num > len - 1) { + if (*eol_num > len - 2) { getcmd_cbeep(); return; } @@ -321,7 +322,7 @@ ERASE_TO_EOL(); /* copy new line into place and display */ - strcpy(buf, hline); + safe_strncpy(buf, hline, len); eol_num = strlen(buf); REFRESH_TO_EOL(); continue;