summaryrefslogtreecommitdiff
path: root/drivers/net/ieee802154/atusb.c
diff options
context:
space:
mode:
authorStefan Schmidt <stefan@osg.samsung.com>2016-12-05 16:47:19 +0300
committerMarcel Holtmann <marcel@holtmann.org>2016-12-08 09:43:29 +0300
commit6cc33eba232cebc9918c558b21b1e3b5fcab27b7 (patch)
tree07edd180bbbad7716ca1dbdc9d30aa06f15ed899 /drivers/net/ieee802154/atusb.c
parent46551564a28e07325140057876f92881d58a219a (diff)
downloadlinux-6cc33eba232cebc9918c558b21b1e3b5fcab27b7.tar.xz
ieee802154: atusb: try to read permanent extended address from device
With version 0.3 the atusb firmware offers an interface to read a permanent EUI64 address from the devices EEPROM. This patch checks if the firmware is new enough and tries to read out and use the address. If this does not work we fall back to the original randomly generated address. Signed-off-by: Stefan Schmidt <stefan@osg.samsung.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'drivers/net/ieee802154/atusb.c')
-rw-r--r--drivers/net/ieee802154/atusb.c40
1 files changed, 39 insertions, 1 deletions
diff --git a/drivers/net/ieee802154/atusb.c b/drivers/net/ieee802154/atusb.c
index 9fdea642ffad..3ed34cc8a2f8 100644
--- a/drivers/net/ieee802154/atusb.c
+++ b/drivers/net/ieee802154/atusb.c
@@ -679,6 +679,43 @@ fail:
return -ENODEV;
}
+static int atusb_set_extended_addr(struct atusb *atusb)
+{
+ struct usb_device *usb_dev = atusb->usb_dev;
+ unsigned char buffer[IEEE802154_EXTENDED_ADDR_LEN];
+ __le64 extended_addr;
+ u64 addr;
+ int ret;
+
+ /* Firmware versions before 0.3 do not support the EUI64_READ command.
+ * Just use a random address and be done */
+ if (atusb->fw_ver_maj == 0 && atusb->fw_ver_min < 3) {
+ ieee802154_random_extended_addr(&atusb->hw->phy->perm_extended_addr);
+ return 0;
+ }
+
+ /* Firmware is new enough so we fetch the address from EEPROM */
+ ret = atusb_control_msg(atusb, usb_rcvctrlpipe(usb_dev, 0),
+ ATUSB_EUI64_READ, ATUSB_REQ_FROM_DEV, 0, 0,
+ buffer, IEEE802154_EXTENDED_ADDR_LEN, 1000);
+ if (ret < 0)
+ dev_err(&usb_dev->dev, "failed to fetch extended address\n");
+
+ memcpy(&extended_addr, buffer, IEEE802154_EXTENDED_ADDR_LEN);
+ /* Check if read address is not empty and the unicast bit is set correctly */
+ if (!ieee802154_is_valid_extended_unicast_addr(extended_addr)) {
+ dev_info(&usb_dev->dev, "no permanent extended address found, random address set\n");
+ ieee802154_random_extended_addr(&atusb->hw->phy->perm_extended_addr);
+ } else {
+ atusb->hw->phy->perm_extended_addr = extended_addr;
+ addr = swab64((__force u64)atusb->hw->phy->perm_extended_addr);
+ dev_info(&usb_dev->dev, "Read permanent extended address %8phC from device\n",
+ &addr);
+ }
+
+ return ret;
+}
+
/* ----- Setup ------------------------------------------------------------- */
static int atusb_probe(struct usb_interface *interface,
@@ -738,13 +775,14 @@ static int atusb_probe(struct usb_interface *interface,
hw->phy->supported.tx_powers = atusb_powers;
hw->phy->supported.tx_powers_size = ARRAY_SIZE(atusb_powers);
hw->phy->transmit_power = hw->phy->supported.tx_powers[0];
- ieee802154_random_extended_addr(&hw->phy->perm_extended_addr);
hw->phy->cca_ed_level = hw->phy->supported.cca_ed_levels[7];
atusb_command(atusb, ATUSB_RF_RESET, 0);
atusb_get_and_show_chip(atusb);
atusb_get_and_show_revision(atusb);
atusb_get_and_show_build(atusb);
+ atusb_set_extended_addr(atusb);
+
ret = atusb_get_and_clear_error(atusb);
if (ret) {
dev_err(&atusb->usb_dev->dev,