diff options
author | Christian Riesch <christian.riesch@omicron.at> | 2012-07-18 20:23:07 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-07-19 13:48:07 -0400 |
commit | cb7b24cdc63a5489798589dca7bfcae0cff46332 (patch) | |
tree | a0161265f2ed7ea329ad02c156cf06830da37678 /drivers/net | |
parent | ceb02c91dd76012e902799e0132ad3ad3e659394 (diff) |
asix: Add support for programming the EEPROM
This patch adds the asix_set_eeprom() function to provide support for
programming the configuration EEPROM via ethtool.
Signed-off-by: Christian Riesch <christian.riesch@omicron.at>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/usb/asix.h | 2 | ||||
-rw-r--r-- | drivers/net/usb/asix_common.c | 81 | ||||
-rw-r--r-- | drivers/net/usb/asix_devices.c | 3 | ||||
-rw-r--r-- | drivers/net/usb/ax88172a.c | 1 |
4 files changed, 87 insertions, 0 deletions
diff --git a/drivers/net/usb/asix.h b/drivers/net/usb/asix.h index fbff17748a1d..e889631161b8 100644 --- a/drivers/net/usb/asix.h +++ b/drivers/net/usb/asix.h | |||
@@ -208,6 +208,8 @@ int asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo); | |||
208 | int asix_get_eeprom_len(struct net_device *net); | 208 | int asix_get_eeprom_len(struct net_device *net); |
209 | int asix_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, | 209 | int asix_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, |
210 | u8 *data); | 210 | u8 *data); |
211 | int asix_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, | ||
212 | u8 *data); | ||
211 | 213 | ||
212 | void asix_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info); | 214 | void asix_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info); |
213 | 215 | ||
diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c index 0b5b2d328a56..774d9ce2dafc 100644 --- a/drivers/net/usb/asix_common.c +++ b/drivers/net/usb/asix_common.c | |||
@@ -516,6 +516,87 @@ int asix_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, | |||
516 | return 0; | 516 | return 0; |
517 | } | 517 | } |
518 | 518 | ||
519 | int asix_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, | ||
520 | u8 *data) | ||
521 | { | ||
522 | struct usbnet *dev = netdev_priv(net); | ||
523 | u16 *eeprom_buff; | ||
524 | int first_word, last_word; | ||
525 | int i; | ||
526 | int ret; | ||
527 | |||
528 | netdev_dbg(net, "write EEPROM len %d, offset %d, magic 0x%x\n", | ||
529 | eeprom->len, eeprom->offset, eeprom->magic); | ||
530 | |||
531 | if (eeprom->len == 0) | ||
532 | return -EINVAL; | ||
533 | |||
534 | if (eeprom->magic != AX_EEPROM_MAGIC) | ||
535 | return -EINVAL; | ||
536 | |||
537 | first_word = eeprom->offset >> 1; | ||
538 | last_word = (eeprom->offset + eeprom->len - 1) >> 1; | ||
539 | |||
540 | eeprom_buff = kmalloc(sizeof(u16) * (last_word - first_word + 1), | ||
541 | GFP_KERNEL); | ||
542 | if (!eeprom_buff) | ||
543 | return -ENOMEM; | ||
544 | |||
545 | /* align data to 16 bit boundaries, read the missing data from | ||
546 | the EEPROM */ | ||
547 | if (eeprom->offset & 1) { | ||
548 | ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, first_word, 0, 2, | ||
549 | &(eeprom_buff[0])); | ||
550 | if (ret < 0) { | ||
551 | netdev_err(net, "Failed to read EEPROM at offset 0x%02x.\n", first_word); | ||
552 | goto free; | ||
553 | } | ||
554 | } | ||
555 | |||
556 | if ((eeprom->offset + eeprom->len) & 1) { | ||
557 | ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, last_word, 0, 2, | ||
558 | &(eeprom_buff[last_word - first_word])); | ||
559 | if (ret < 0) { | ||
560 | netdev_err(net, "Failed to read EEPROM at offset 0x%02x.\n", last_word); | ||
561 | goto free; | ||
562 | } | ||
563 | } | ||
564 | |||
565 | memcpy((u8 *)eeprom_buff + (eeprom->offset & 1), data, eeprom->len); | ||
566 | |||
567 | /* write data to EEPROM */ | ||
568 | ret = asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0x0000, 0, 0, NULL); | ||
569 | if (ret < 0) { | ||
570 | netdev_err(net, "Failed to enable EEPROM write\n"); | ||
571 | goto free; | ||
572 | } | ||
573 | msleep(20); | ||
574 | |||
575 | for (i = first_word; i <= last_word; i++) { | ||
576 | netdev_dbg(net, "write to EEPROM at offset 0x%02x, data 0x%04x\n", | ||
577 | i, eeprom_buff[i - first_word]); | ||
578 | ret = asix_write_cmd(dev, AX_CMD_WRITE_EEPROM, i, | ||
579 | eeprom_buff[i - first_word], 0, NULL); | ||
580 | if (ret < 0) { | ||
581 | netdev_err(net, "Failed to write EEPROM at offset 0x%02x.\n", | ||
582 | i); | ||
583 | goto free; | ||
584 | } | ||
585 | msleep(20); | ||
586 | } | ||
587 | |||
588 | ret = asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0x0000, 0, 0, NULL); | ||
589 | if (ret < 0) { | ||
590 | netdev_err(net, "Failed to disable EEPROM write\n"); | ||
591 | goto free; | ||
592 | } | ||
593 | |||
594 | ret = 0; | ||
595 | free: | ||
596 | kfree(eeprom_buff); | ||
597 | return ret; | ||
598 | } | ||
599 | |||
519 | void asix_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) | 600 | void asix_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) |
520 | { | 601 | { |
521 | /* Inherit standard device info */ | 602 | /* Inherit standard device info */ |
diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c index 658c08fe2c03..4fd48df6b989 100644 --- a/drivers/net/usb/asix_devices.c +++ b/drivers/net/usb/asix_devices.c | |||
@@ -119,6 +119,7 @@ static const struct ethtool_ops ax88172_ethtool_ops = { | |||
119 | .set_wol = asix_set_wol, | 119 | .set_wol = asix_set_wol, |
120 | .get_eeprom_len = asix_get_eeprom_len, | 120 | .get_eeprom_len = asix_get_eeprom_len, |
121 | .get_eeprom = asix_get_eeprom, | 121 | .get_eeprom = asix_get_eeprom, |
122 | .set_eeprom = asix_set_eeprom, | ||
122 | .get_settings = usbnet_get_settings, | 123 | .get_settings = usbnet_get_settings, |
123 | .set_settings = usbnet_set_settings, | 124 | .set_settings = usbnet_set_settings, |
124 | .nway_reset = usbnet_nway_reset, | 125 | .nway_reset = usbnet_nway_reset, |
@@ -258,6 +259,7 @@ static const struct ethtool_ops ax88772_ethtool_ops = { | |||
258 | .set_wol = asix_set_wol, | 259 | .set_wol = asix_set_wol, |
259 | .get_eeprom_len = asix_get_eeprom_len, | 260 | .get_eeprom_len = asix_get_eeprom_len, |
260 | .get_eeprom = asix_get_eeprom, | 261 | .get_eeprom = asix_get_eeprom, |
262 | .set_eeprom = asix_set_eeprom, | ||
261 | .get_settings = usbnet_get_settings, | 263 | .get_settings = usbnet_get_settings, |
262 | .set_settings = usbnet_set_settings, | 264 | .set_settings = usbnet_set_settings, |
263 | .nway_reset = usbnet_nway_reset, | 265 | .nway_reset = usbnet_nway_reset, |
@@ -478,6 +480,7 @@ static const struct ethtool_ops ax88178_ethtool_ops = { | |||
478 | .set_wol = asix_set_wol, | 480 | .set_wol = asix_set_wol, |
479 | .get_eeprom_len = asix_get_eeprom_len, | 481 | .get_eeprom_len = asix_get_eeprom_len, |
480 | .get_eeprom = asix_get_eeprom, | 482 | .get_eeprom = asix_get_eeprom, |
483 | .set_eeprom = asix_set_eeprom, | ||
481 | .get_settings = usbnet_get_settings, | 484 | .get_settings = usbnet_get_settings, |
482 | .set_settings = usbnet_set_settings, | 485 | .set_settings = usbnet_set_settings, |
483 | .nway_reset = usbnet_nway_reset, | 486 | .nway_reset = usbnet_nway_reset, |
diff --git a/drivers/net/usb/ax88172a.c b/drivers/net/usb/ax88172a.c index 97dce0f567d2..c8e0aa85fb8e 100644 --- a/drivers/net/usb/ax88172a.c +++ b/drivers/net/usb/ax88172a.c | |||
@@ -194,6 +194,7 @@ static const struct ethtool_ops ax88172a_ethtool_ops = { | |||
194 | .set_wol = asix_set_wol, | 194 | .set_wol = asix_set_wol, |
195 | .get_eeprom_len = asix_get_eeprom_len, | 195 | .get_eeprom_len = asix_get_eeprom_len, |
196 | .get_eeprom = asix_get_eeprom, | 196 | .get_eeprom = asix_get_eeprom, |
197 | .set_eeprom = asix_set_eeprom, | ||
197 | .get_settings = ax88172a_get_settings, | 198 | .get_settings = ax88172a_get_settings, |
198 | .set_settings = ax88172a_set_settings, | 199 | .set_settings = ax88172a_set_settings, |
199 | .nway_reset = ax88172a_nway_reset, | 200 | .nway_reset = ax88172a_nway_reset, |