diff options
Diffstat (limited to 'drivers/ssb/pcmcia.c')
| -rw-r--r-- | drivers/ssb/pcmcia.c | 232 |
1 files changed, 118 insertions, 114 deletions
diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c index 100e7a5c5ea1..e72f4046a5e0 100644 --- a/drivers/ssb/pcmcia.c +++ b/drivers/ssb/pcmcia.c | |||
| @@ -617,136 +617,140 @@ static int ssb_pcmcia_sprom_check_crc(const u16 *sprom, size_t size) | |||
| 617 | } \ | 617 | } \ |
| 618 | } while (0) | 618 | } while (0) |
| 619 | 619 | ||
| 620 | int ssb_pcmcia_get_invariants(struct ssb_bus *bus, | 620 | static int ssb_pcmcia_get_mac(struct pcmcia_device *p_dev, |
| 621 | struct ssb_init_invariants *iv) | 621 | tuple_t *tuple, |
| 622 | void *priv) | ||
| 622 | { | 623 | { |
| 623 | tuple_t tuple; | 624 | struct ssb_sprom *sprom = priv; |
| 624 | int res; | 625 | |
| 625 | unsigned char buf[32]; | 626 | if (tuple->TupleData[0] != CISTPL_FUNCE_LAN_NODE_ID) |
| 627 | return -EINVAL; | ||
| 628 | if (tuple->TupleDataLen != ETH_ALEN + 2) | ||
| 629 | return -EINVAL; | ||
| 630 | if (tuple->TupleData[1] != ETH_ALEN) | ||
| 631 | return -EINVAL; | ||
| 632 | memcpy(sprom->il0mac, &tuple->TupleData[2], ETH_ALEN); | ||
| 633 | return 0; | ||
| 634 | }; | ||
| 635 | |||
| 636 | static int ssb_pcmcia_do_get_invariants(struct pcmcia_device *p_dev, | ||
| 637 | tuple_t *tuple, | ||
| 638 | void *priv) | ||
| 639 | { | ||
| 640 | struct ssb_init_invariants *iv = priv; | ||
| 626 | struct ssb_sprom *sprom = &iv->sprom; | 641 | struct ssb_sprom *sprom = &iv->sprom; |
| 627 | struct ssb_boardinfo *bi = &iv->boardinfo; | 642 | struct ssb_boardinfo *bi = &iv->boardinfo; |
| 628 | const char *error_description; | 643 | const char *error_description; |
| 629 | 644 | ||
| 645 | GOTO_ERROR_ON(tuple->TupleDataLen < 1, "VEN tpl < 1"); | ||
| 646 | switch (tuple->TupleData[0]) { | ||
| 647 | case SSB_PCMCIA_CIS_ID: | ||
| 648 | GOTO_ERROR_ON((tuple->TupleDataLen != 5) && | ||
| 649 | (tuple->TupleDataLen != 7), | ||
| 650 | "id tpl size"); | ||
| 651 | bi->vendor = tuple->TupleData[1] | | ||
| 652 | ((u16)tuple->TupleData[2] << 8); | ||
| 653 | break; | ||
| 654 | case SSB_PCMCIA_CIS_BOARDREV: | ||
| 655 | GOTO_ERROR_ON(tuple->TupleDataLen != 2, | ||
| 656 | "boardrev tpl size"); | ||
| 657 | sprom->board_rev = tuple->TupleData[1]; | ||
| 658 | break; | ||
| 659 | case SSB_PCMCIA_CIS_PA: | ||
| 660 | GOTO_ERROR_ON((tuple->TupleDataLen != 9) && | ||
| 661 | (tuple->TupleDataLen != 10), | ||
| 662 | "pa tpl size"); | ||
| 663 | sprom->pa0b0 = tuple->TupleData[1] | | ||
| 664 | ((u16)tuple->TupleData[2] << 8); | ||
| 665 | sprom->pa0b1 = tuple->TupleData[3] | | ||
| 666 | ((u16)tuple->TupleData[4] << 8); | ||
| 667 | sprom->pa0b2 = tuple->TupleData[5] | | ||
| 668 | ((u16)tuple->TupleData[6] << 8); | ||
| 669 | sprom->itssi_a = tuple->TupleData[7]; | ||
| 670 | sprom->itssi_bg = tuple->TupleData[7]; | ||
| 671 | sprom->maxpwr_a = tuple->TupleData[8]; | ||
| 672 | sprom->maxpwr_bg = tuple->TupleData[8]; | ||
| 673 | break; | ||
| 674 | case SSB_PCMCIA_CIS_OEMNAME: | ||
| 675 | /* We ignore this. */ | ||
| 676 | break; | ||
| 677 | case SSB_PCMCIA_CIS_CCODE: | ||
| 678 | GOTO_ERROR_ON(tuple->TupleDataLen != 2, | ||
| 679 | "ccode tpl size"); | ||
| 680 | sprom->country_code = tuple->TupleData[1]; | ||
| 681 | break; | ||
| 682 | case SSB_PCMCIA_CIS_ANTENNA: | ||
| 683 | GOTO_ERROR_ON(tuple->TupleDataLen != 2, | ||
| 684 | "ant tpl size"); | ||
| 685 | sprom->ant_available_a = tuple->TupleData[1]; | ||
| 686 | sprom->ant_available_bg = tuple->TupleData[1]; | ||
| 687 | break; | ||
| 688 | case SSB_PCMCIA_CIS_ANTGAIN: | ||
| 689 | GOTO_ERROR_ON(tuple->TupleDataLen != 2, | ||
| 690 | "antg tpl size"); | ||
| 691 | sprom->antenna_gain.ghz24.a0 = tuple->TupleData[1]; | ||
| 692 | sprom->antenna_gain.ghz24.a1 = tuple->TupleData[1]; | ||
| 693 | sprom->antenna_gain.ghz24.a2 = tuple->TupleData[1]; | ||
| 694 | sprom->antenna_gain.ghz24.a3 = tuple->TupleData[1]; | ||
| 695 | sprom->antenna_gain.ghz5.a0 = tuple->TupleData[1]; | ||
| 696 | sprom->antenna_gain.ghz5.a1 = tuple->TupleData[1]; | ||
| 697 | sprom->antenna_gain.ghz5.a2 = tuple->TupleData[1]; | ||
| 698 | sprom->antenna_gain.ghz5.a3 = tuple->TupleData[1]; | ||
| 699 | break; | ||
| 700 | case SSB_PCMCIA_CIS_BFLAGS: | ||
| 701 | GOTO_ERROR_ON((tuple->TupleDataLen != 3) && | ||
| 702 | (tuple->TupleDataLen != 5), | ||
| 703 | "bfl tpl size"); | ||
| 704 | sprom->boardflags_lo = tuple->TupleData[1] | | ||
| 705 | ((u16)tuple->TupleData[2] << 8); | ||
| 706 | break; | ||
| 707 | case SSB_PCMCIA_CIS_LEDS: | ||
| 708 | GOTO_ERROR_ON(tuple->TupleDataLen != 5, | ||
| 709 | "leds tpl size"); | ||
| 710 | sprom->gpio0 = tuple->TupleData[1]; | ||
| 711 | sprom->gpio1 = tuple->TupleData[2]; | ||
| 712 | sprom->gpio2 = tuple->TupleData[3]; | ||
| 713 | sprom->gpio3 = tuple->TupleData[4]; | ||
| 714 | break; | ||
| 715 | } | ||
| 716 | return -ENOSPC; /* continue with next entry */ | ||
| 717 | |||
| 718 | error: | ||
| 719 | ssb_printk(KERN_ERR PFX | ||
| 720 | "PCMCIA: Failed to fetch device invariants: %s\n", | ||
| 721 | error_description); | ||
| 722 | return -ENODEV; | ||
| 723 | } | ||
| 724 | |||
| 725 | |||
| 726 | int ssb_pcmcia_get_invariants(struct ssb_bus *bus, | ||
| 727 | struct ssb_init_invariants *iv) | ||
| 728 | { | ||
| 729 | struct ssb_sprom *sprom = &iv->sprom; | ||
| 730 | int res; | ||
| 731 | |||
| 630 | memset(sprom, 0xFF, sizeof(*sprom)); | 732 | memset(sprom, 0xFF, sizeof(*sprom)); |
| 631 | sprom->revision = 1; | 733 | sprom->revision = 1; |
| 632 | sprom->boardflags_lo = 0; | 734 | sprom->boardflags_lo = 0; |
| 633 | sprom->boardflags_hi = 0; | 735 | sprom->boardflags_hi = 0; |
| 634 | 736 | ||
| 635 | /* First fetch the MAC address. */ | 737 | /* First fetch the MAC address. */ |
| 636 | memset(&tuple, 0, sizeof(tuple)); | 738 | res = pcmcia_loop_tuple(bus->host_pcmcia, CISTPL_FUNCE, |
| 637 | tuple.DesiredTuple = CISTPL_FUNCE; | 739 | ssb_pcmcia_get_mac, sprom); |
| 638 | tuple.TupleData = buf; | 740 | if (res != 0) { |
| 639 | tuple.TupleDataMax = sizeof(buf); | 741 | ssb_printk(KERN_ERR PFX |
| 640 | res = pcmcia_get_first_tuple(bus->host_pcmcia, &tuple); | 742 | "PCMCIA: Failed to fetch MAC address\n"); |
| 641 | GOTO_ERROR_ON(res != 0, "MAC first tpl"); | 743 | return -ENODEV; |
| 642 | res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple); | ||
| 643 | GOTO_ERROR_ON(res != 0, "MAC first tpl data"); | ||
| 644 | while (1) { | ||
| 645 | GOTO_ERROR_ON(tuple.TupleDataLen < 1, "MAC tpl < 1"); | ||
| 646 | if (tuple.TupleData[0] == CISTPL_FUNCE_LAN_NODE_ID) | ||
| 647 | break; | ||
| 648 | res = pcmcia_get_next_tuple(bus->host_pcmcia, &tuple); | ||
| 649 | GOTO_ERROR_ON(res != 0, "MAC next tpl"); | ||
| 650 | res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple); | ||
| 651 | GOTO_ERROR_ON(res != 0, "MAC next tpl data"); | ||
| 652 | } | 744 | } |
| 653 | GOTO_ERROR_ON(tuple.TupleDataLen != ETH_ALEN + 2, "MAC tpl size"); | ||
| 654 | memcpy(sprom->il0mac, &tuple.TupleData[2], ETH_ALEN); | ||
| 655 | 745 | ||
| 656 | /* Fetch the vendor specific tuples. */ | 746 | /* Fetch the vendor specific tuples. */ |
| 657 | memset(&tuple, 0, sizeof(tuple)); | 747 | res = pcmcia_loop_tuple(bus->host_pcmcia, SSB_PCMCIA_CIS, |
| 658 | tuple.DesiredTuple = SSB_PCMCIA_CIS; | 748 | ssb_pcmcia_do_get_invariants, sprom); |
| 659 | tuple.TupleData = buf; | 749 | if ((res == 0) || (res == -ENOSPC)) |
| 660 | tuple.TupleDataMax = sizeof(buf); | 750 | return 0; |
| 661 | res = pcmcia_get_first_tuple(bus->host_pcmcia, &tuple); | ||
| 662 | GOTO_ERROR_ON(res != 0, "VEN first tpl"); | ||
| 663 | res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple); | ||
| 664 | GOTO_ERROR_ON(res != 0, "VEN first tpl data"); | ||
| 665 | while (1) { | ||
| 666 | GOTO_ERROR_ON(tuple.TupleDataLen < 1, "VEN tpl < 1"); | ||
| 667 | switch (tuple.TupleData[0]) { | ||
| 668 | case SSB_PCMCIA_CIS_ID: | ||
| 669 | GOTO_ERROR_ON((tuple.TupleDataLen != 5) && | ||
| 670 | (tuple.TupleDataLen != 7), | ||
| 671 | "id tpl size"); | ||
| 672 | bi->vendor = tuple.TupleData[1] | | ||
| 673 | ((u16)tuple.TupleData[2] << 8); | ||
| 674 | break; | ||
| 675 | case SSB_PCMCIA_CIS_BOARDREV: | ||
| 676 | GOTO_ERROR_ON(tuple.TupleDataLen != 2, | ||
| 677 | "boardrev tpl size"); | ||
| 678 | sprom->board_rev = tuple.TupleData[1]; | ||
| 679 | break; | ||
| 680 | case SSB_PCMCIA_CIS_PA: | ||
| 681 | GOTO_ERROR_ON((tuple.TupleDataLen != 9) && | ||
| 682 | (tuple.TupleDataLen != 10), | ||
| 683 | "pa tpl size"); | ||
| 684 | sprom->pa0b0 = tuple.TupleData[1] | | ||
| 685 | ((u16)tuple.TupleData[2] << 8); | ||
| 686 | sprom->pa0b1 = tuple.TupleData[3] | | ||
| 687 | ((u16)tuple.TupleData[4] << 8); | ||
| 688 | sprom->pa0b2 = tuple.TupleData[5] | | ||
| 689 | ((u16)tuple.TupleData[6] << 8); | ||
| 690 | sprom->itssi_a = tuple.TupleData[7]; | ||
| 691 | sprom->itssi_bg = tuple.TupleData[7]; | ||
| 692 | sprom->maxpwr_a = tuple.TupleData[8]; | ||
| 693 | sprom->maxpwr_bg = tuple.TupleData[8]; | ||
| 694 | break; | ||
| 695 | case SSB_PCMCIA_CIS_OEMNAME: | ||
| 696 | /* We ignore this. */ | ||
| 697 | break; | ||
| 698 | case SSB_PCMCIA_CIS_CCODE: | ||
| 699 | GOTO_ERROR_ON(tuple.TupleDataLen != 2, | ||
| 700 | "ccode tpl size"); | ||
| 701 | sprom->country_code = tuple.TupleData[1]; | ||
| 702 | break; | ||
| 703 | case SSB_PCMCIA_CIS_ANTENNA: | ||
| 704 | GOTO_ERROR_ON(tuple.TupleDataLen != 2, | ||
| 705 | "ant tpl size"); | ||
| 706 | sprom->ant_available_a = tuple.TupleData[1]; | ||
| 707 | sprom->ant_available_bg = tuple.TupleData[1]; | ||
| 708 | break; | ||
| 709 | case SSB_PCMCIA_CIS_ANTGAIN: | ||
| 710 | GOTO_ERROR_ON(tuple.TupleDataLen != 2, | ||
| 711 | "antg tpl size"); | ||
| 712 | sprom->antenna_gain.ghz24.a0 = tuple.TupleData[1]; | ||
| 713 | sprom->antenna_gain.ghz24.a1 = tuple.TupleData[1]; | ||
| 714 | sprom->antenna_gain.ghz24.a2 = tuple.TupleData[1]; | ||
| 715 | sprom->antenna_gain.ghz24.a3 = tuple.TupleData[1]; | ||
| 716 | sprom->antenna_gain.ghz5.a0 = tuple.TupleData[1]; | ||
| 717 | sprom->antenna_gain.ghz5.a1 = tuple.TupleData[1]; | ||
| 718 | sprom->antenna_gain.ghz5.a2 = tuple.TupleData[1]; | ||
| 719 | sprom->antenna_gain.ghz5.a3 = tuple.TupleData[1]; | ||
| 720 | break; | ||
| 721 | case SSB_PCMCIA_CIS_BFLAGS: | ||
| 722 | GOTO_ERROR_ON((tuple.TupleDataLen != 3) && | ||
| 723 | (tuple.TupleDataLen != 5), | ||
| 724 | "bfl tpl size"); | ||
| 725 | sprom->boardflags_lo = tuple.TupleData[1] | | ||
| 726 | ((u16)tuple.TupleData[2] << 8); | ||
| 727 | break; | ||
| 728 | case SSB_PCMCIA_CIS_LEDS: | ||
| 729 | GOTO_ERROR_ON(tuple.TupleDataLen != 5, | ||
| 730 | "leds tpl size"); | ||
| 731 | sprom->gpio0 = tuple.TupleData[1]; | ||
| 732 | sprom->gpio1 = tuple.TupleData[2]; | ||
| 733 | sprom->gpio2 = tuple.TupleData[3]; | ||
| 734 | sprom->gpio3 = tuple.TupleData[4]; | ||
| 735 | break; | ||
| 736 | } | ||
| 737 | res = pcmcia_get_next_tuple(bus->host_pcmcia, &tuple); | ||
| 738 | if (res == -ENOSPC) | ||
| 739 | break; | ||
| 740 | GOTO_ERROR_ON(res != 0, "VEN next tpl"); | ||
| 741 | res = pcmcia_get_tuple_data(bus->host_pcmcia, &tuple); | ||
| 742 | GOTO_ERROR_ON(res != 0, "VEN next tpl data"); | ||
| 743 | } | ||
| 744 | 751 | ||
| 745 | return 0; | ||
| 746 | error: | ||
| 747 | ssb_printk(KERN_ERR PFX | 752 | ssb_printk(KERN_ERR PFX |
| 748 | "PCMCIA: Failed to fetch device invariants: %s\n", | 753 | "PCMCIA: Failed to fetch device invariants\n"); |
| 749 | error_description); | ||
| 750 | return -ENODEV; | 754 | return -ENODEV; |
| 751 | } | 755 | } |
| 752 | 756 | ||
