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/usb/asix_common.c | |
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/usb/asix_common.c')
-rw-r--r-- | drivers/net/usb/asix_common.c | 81 |
1 files changed, 81 insertions, 0 deletions
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 */ |