diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/usb/asix.c | 72 |
1 files changed, 71 insertions, 1 deletions
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index e317a1e53bb2..9600516bb97c 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -49,6 +49,9 @@ KERN_INFO "ASIX USB Ethernet Adapter:v" DRV_VERSION " " __TIME__ " " __DATE__ "\n" " http://www.asix.com.tw\n"; +static char g_mac_addr[ETH_ALEN]; +static int g_usr_mac = 0; + /* configuration of maximum bulk in size */ static int bsize = AX88772B_MAX_BULKIN_16K; module_param(bsize, int, 0); @@ -69,6 +72,39 @@ static void ax8817x_mdio_write_le(struct net_device *netdev, int phy_id, static int ax8817x_mdio_read_le(struct net_device *netdev, int phy_id, int loc); static int ax88772b_set_csums(struct usbnet *dev); +/* Retrieve user set MAC address */ +static int __init setup_asix_mac(char *macstr) +{ + int i, j; + unsigned char result, value; + + for (i = 0; i < ETH_ALEN; i++) { + result = 0; + + if (i != 5 && *(macstr + 2) != ':') + return -1; + + for (j = 0; j < 2; j++) { + if (isxdigit(*macstr) + && (value = + isdigit(*macstr) ? *macstr - + '0' : toupper(*macstr) - 'A' + 10) < 16) { + result = result * 16 + value; + macstr++; + } else + return -1; + } + + macstr++; + g_mac_addr[i] = result; + } + + g_usr_mac = 1; + + return 0; +} +__setup("asix_mac=", setup_asix_mac); + /* ASIX AX8817X based USB 2.0 Ethernet Devices */ static int ax8817x_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, @@ -1171,12 +1207,32 @@ static int ax8817x_check_ether_addr(struct usbnet *dev) static int ax8817x_get_mac(struct usbnet *dev, u8* buf) { int ret, i; - + u8 default_asix_mac[ETH_ALEN] = { 0x00, 0x0e, 0xc6, 0x87, 0x72, 0x01 }; ret = access_eeprom_mac(dev, buf, 0x04, 0); if (ret < 0) goto out; + /* + * Check for default ASIX MAC (e.g. 00:0e:c6:87:72:01) in case of no + * EEPROM being present + */ + if (!memcmp(dev->net->dev_addr, default_asix_mac, ETH_ALEN)) { + if (g_usr_mac && (g_usr_mac < 3)) { + /* Get user set MAC address */ + if (g_usr_mac == 2) { + /* 0x100000 offset for 2nd Ethernet MAC */ + g_mac_addr[3] += 0x10; + if (g_mac_addr[3] < 0x10) + devwarn(dev, "MAC address byte 3 " + "(0x%02x) wrap around", + g_mac_addr[3]); + } + memcpy(dev->net->dev_addr, g_mac_addr, ETH_ALEN); + g_usr_mac++; + } else devwarn(dev, "using default ASIX MAC"); + } + if (ax8817x_check_ether_addr(dev)) { ret = access_eeprom_mac(dev, dev->net->dev_addr, 0x04, 1); if (ret < 0) { @@ -2255,6 +2311,20 @@ static void ax88772b_unbind(struct usbnet *dev, struct usb_interface *intf) struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; if (ax772b_data) { + /* Check for user set MAC address */ + if (!memcmp(dev->net->dev_addr, g_mac_addr, ETH_ALEN)) { + /* Release user set MAC address */ + g_usr_mac--; + + if (g_usr_mac == 2) { + /* 0x100000 offset for 2nd Ethernet MAC */ + g_mac_addr[3] -= 0x10; + if (g_mac_addr[3] > 0xf0) + devwarn(dev, "MAC address byte 3 " + "(0x%02x) wrap around", + g_mac_addr[3]); + } + } flush_workqueue(ax772b_data->ax_work); destroy_workqueue(ax772b_data->ax_work); |