From: Yousong Zhou Subject: [PATCH] of: net: add nvmem cell mac-address-ascii support This is needed for devices with mac address stored in ascii format, e.g. HiWiFi HC6361 to be ported in the following patch. Submitted-by: Yousong Zhou --- net/core/of_net.c | 83 ++++++++++++------ 1 files changed, 72 insertions(+), 11 deletions(-) --- a/net/core/of_net.c +++ b/net/core/of_net.c @@ -57,13 +57,70 @@ static int of_get_mac_addr(struct device return -ENODEV; } +static void *nvmem_cell_get_mac_address(struct nvmem_cell *cell) +{ + size_t len; + void *mac; + + mac = nvmem_cell_read(cell, &len); + if (IS_ERR(mac)) + return mac; + if (len != ETH_ALEN) { + kfree(mac); + return ERR_PTR(-EINVAL); + } + return mac; +} + +static void *nvmem_cell_get_mac_address_ascii(struct nvmem_cell *cell) +{ + size_t len; + int ret; + void *mac_ascii; + u8 *mac; + + mac_ascii = nvmem_cell_read(cell, &len); + if (IS_ERR(mac_ascii)) + return mac_ascii; + if (len != ETH_ALEN*2+5) { + kfree(mac_ascii); + return ERR_PTR(-EINVAL); + } + mac = kmalloc(ETH_ALEN, GFP_KERNEL); + if (!mac) { + kfree(mac_ascii); + return ERR_PTR(-ENOMEM); + } + ret = sscanf(mac_ascii, "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx", + &mac[0], &mac[1], &mac[2], + &mac[3], &mac[4], &mac[5]); + kfree(mac_ascii); + if (ret == ETH_ALEN) + return mac; + kfree(mac); + return ERR_PTR(-EINVAL); +} + +static struct nvmem_cell_mac_address_property { + char *name; + void *(*read)(struct nvmem_cell *); +} nvmem_cell_mac_address_properties[] = { + { + .name = "mac-address", + .read = nvmem_cell_get_mac_address, + }, { + .name = "mac-address-ascii", + .read = nvmem_cell_get_mac_address_ascii, + }, +}; + static int of_get_mac_addr_nvmem(struct device_node *np, u8 *addr) { struct platform_device *pdev = of_find_device_by_node(np); + struct nvmem_cell_mac_address_property *property; struct nvmem_cell *cell; const void *mac; - size_t len; - int ret; + int ret, i; /* Try lookup by device first, there might be a nvmem_cell_lookup * associated with a given device. @@ -74,17 +131,26 @@ static int of_get_mac_addr_nvmem(struct return ret; } - cell = of_nvmem_cell_get(np, "mac-address"); + for (i = 0; i < ARRAY_SIZE(nvmem_cell_mac_address_properties); i++) { + property = &nvmem_cell_mac_address_properties[i]; + cell = of_nvmem_cell_get(np, property->name); + /* For -EPROBE_DEFER don't try other properties. + * We'll get back to this one. + */ + if (!IS_ERR(cell) || PTR_ERR(cell) == -EPROBE_DEFER) + break; + } + if (IS_ERR(cell)) return PTR_ERR(cell); - mac = nvmem_cell_read(cell, &len); + mac = property->read(cell); nvmem_cell_put(cell); if (IS_ERR(mac)) return PTR_ERR(mac); - if (len != ETH_ALEN || !is_valid_ether_addr(mac)) { + if (!is_valid_ether_addr(mac)) { kfree(mac); return -EINVAL; }