From: Yousong Zhou Subject: [PATCH] ath79: 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/ethernet/eth.c | 83 ++++++++++++------ 1 files changed, 72 insertions(+), 11 deletions(-) --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -538,6 +538,63 @@ int eth_platform_get_mac_address(struct } EXPORT_SYMBOL(eth_platform_get_mac_address); +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, + }, +}; + /** * nvmem_get_mac_address - Obtain the MAC address from an nvmem cell named * 'mac-address' associated with given device. @@ -549,21 +606,28 @@ EXPORT_SYMBOL(eth_platform_get_mac_addre */ int nvmem_get_mac_address(struct device *dev, void *addrbuf) { + struct nvmem_cell_mac_address_property *property; struct nvmem_cell *cell; const void *mac; - size_t len; + int i; + + for (i = 0; i < ARRAY_SIZE(nvmem_cell_mac_address_properties); i++) { + property = &nvmem_cell_mac_address_properties[i]; + cell = nvmem_cell_get(dev, 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; + } - cell = nvmem_cell_get(dev, "mac-address"); 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; }