Changeset 2706

Show
Ignore:
Timestamp:
09/10/07 17:07:57 (1 year ago)
Author:
mickflemm
Message:
  • Add write capability to ath_info
  • Does not need driver to be loaded anymore
  • Added man page for ath_info

Thanx to Joerg Albert for his work !

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/tools/ath_info.c

    r2665 r2706  
     1/* -*- linux-c -*- */ 
    12/*- 
    23 * Copyright (c) 2007 Nick Kossifidis <mickflemm@gmail.com> 
     4 * Copyright (c) 2007 Joerg Albert    <jal2 *at* gmx.de> 
    35 *  
    46 * This program is free software you can redistribute it and/or modify 
     
    3638 * load madwifi-ng or madwifi-old if not already loaded (be sure the  
    3739 * interface is down!) 
    38  *  
     40 * 
    3941 * modprobe ath_pci 
    4042 *  
     43 * OR 
     44 * 
     45 * call: 
     46 * setpci -s 02:02.0 command=0x41f cache_line_size=0x10 
     47 * 
     48 * to enable access to the PCI device. 
     49 * 
    4150 * and we run the thing... 
    4251 *  
    4352 * ./ath_info 0xc2000000 
    4453 *  
     54 * In order to change the regdomain to 0 , call: 
     55 * 
     56 * ./ath_info -w 0xc2000000 regdomain 0 
     57 * 
     58 * to change any PCI ID value, say: 
     59 * 
     60 * ./ath_info -w 0xc2000000 <name> X 
     61 * 
     62 * with <name> ::= pci_dev_id | pci_vendor_id | pci_class |  
     63 *                 pci_subsys_dev_id | pci_subsys_vendor_id 
     64 * 
     65 * With newer chipsets (>= AR5004x, i.e. MAC >= AR5213), Atheros introduced 
     66 * write protection on the EEPROM. On a GIGABYTE GN-WI01HT you can set GPIO 4 
     67 * to low to be able to write the EEPROM. This depends highly on the PCB layout, 
     68 * so there may be different GPIO used. 
     69 * This program currently sets GPIO 4 to low for a MAC >= AR5213, but you can 
     70 * override this with the -g option: 
     71 * 
     72 * ./ath_info -g 5:0 -w 0xc2000000 regdomain X 
     73 * 
     74 * would set GPIO 5 to low (and wouldn't touch GPIO 4). -g can be given several times. 
     75 * 
     76 * The write function is currently not tested with 5210 devices. 
     77 * 
    4578 * Use at your own risk, entering a false device address will have really  
    46  * nasty results! */ 
     79 * nasty results! 
     80 * 
     81 * Writing wrong values to the PCI id fields may prevent the driver from 
     82 * detecting the card! 
     83 * 
     84 * Transmitting on illegal frequencies may violate state laws. Stick to the local 
     85 * regulations! 
     86 * 
     87 * DISCLAIMER: 
     88 * The authors are in no case responsible for damaged hardware or violation of 
     89 * local laws by operating modified hardware. 
     90 *   
     91 */ 
    4792 
    4893 
     
    55100#include <sys/mman.h> 
    56101 
     102#define dbg(fmt , __args__...) do { if (verbose) printf("#DBG %s: " fmt "\n", __FUNCTION__, ##__args__ ); } while (0) 
     103 
     104#define err(fmt , __args__...) fprintf(stderr, "#ERR %s: " fmt "\n", __FUNCTION__, ##__args__ ) 
     105 
    57106#define AR5K_PCI_MEM_SIZE 0x10000 
    58107#define AR5K_ELEMENTS(_array)   (sizeof(_array) / sizeof(_array[0])) 
     108 
     109#define AR5K_NUM_GPIO   6 
     110 
     111#define AR5K_GPIOCR             0x4014                          /*Register Address*/ 
     112#define AR5K_GPIOCR_OUT(n)      (3 << ((n) * 2))        /*Mode 3 for pin n*/ 
     113#define AR5K_GPIOCR_INT_SEL(n)  ((n) << 12)             /*Interrupt for GPIO pin n*/ 
     114 
     115/* 
     116 * "General Purpose Input/Output" (GPIO) data output register 
     117 */ 
     118#define AR5K_GPIODO     0x4018 
     119 
     120/* 
     121 * "General Purpose Input/Output" (GPIO) data input register 
     122 */ 
     123#define AR5K_GPIODI     0x401c 
    59124 
    60125/* 
     
    135200#define AR5K_PHY_SHIFT_5GHZ             0x00000007 
    136201 
     202#define AR5K_RESET_CTL          0x4000                  /* Register Address */ 
     203#define AR5K_RESET_CTL_PCU      0x00000001      /* Protocol Control Unit reset */ 
     204#define AR5K_RESET_CTL_DMA      0x00000002      /* DMA (Rx/Tx) reset -5210 only */ 
     205#define AR5K_RESET_CTL_BASEBAND 0x00000002      /* Baseband reset (5211/5212) */ 
     206#define AR5K_RESET_CTL_MAC      0x00000004      /* MAC reset (PCU+Baseband ?) -5210 only */ 
     207#define AR5K_RESET_CTL_PHY      0x00000008      /* PHY reset -5210 only */ 
     208#define AR5K_RESET_CTL_PCI      0x00000010      /* PCI Core reset (interrupts etc) */ 
     209#define AR5K_RESET_CTL_CHIP     (AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA |      \ 
     210                                AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY) 
     211 
     212/* 
     213 * Sleep control register 
     214 */ 
     215#define AR5K_SLEEP_CTL                  0x4004                  /*Register Address*/ 
     216#define AR5K_SLEEP_CTL_SLDUR            0x0000ffff      /*Sleep duration mask*/ 
     217#define AR5K_SLEEP_CTL_SLDUR_S          0 
     218#define AR5K_SLEEP_CTL_SLE              0x00030000      /*Sleep enable mask*/ 
     219#define AR5K_SLEEP_CTL_SLE_S            16 
     220#define AR5K_SLEEP_CTL_SLE_WAKE         0x00000000      /*Force chip awake*/ 
     221#define AR5K_SLEEP_CTL_SLE_SLP          0x00010000      /*Force chip sleep*/ 
     222#define AR5K_SLEEP_CTL_SLE_ALLOW        0x00020000       
     223#define AR5K_SLEEP_CTL_SLE_UNITS        0x00000008      /*non 5210*/ 
     224 
    137225#define AR5K_PCICFG                     0x4010                  /* Register Address */ 
    138226#define AR5K_PCICFG_EEAE                0x00000001      /* Eeprom access enable [5210] */ 
     
    145233#define AR5K_PCICFG_EESIZE_FAIL         3               /* Failed to get size (?) [5211+] */ 
    146234 
     235#define AR5K_PCICFG_SPWR_DN             0x00010000      /*Mask for power status (5210)*/ 
     236 
    147237#define AR5K_EEPROM_BASE        0x6000 
    148238 
     
    235325 
    236326#define AR5K_TUNE_REGISTER_TIMEOUT              20000 
     327 
     328 
     329/* names for eeprom fields */ 
     330static const struct { 
     331        const char *name; 
     332        int addr; 
     333} eeprom_addr[] = { 
     334        {"pci_dev_id", 0}, 
     335        {"pci_vendor_id", 1}, 
     336        {"pci_class", 2}, 
     337        {"pci_rev_id", 3}, 
     338        {"pci_subsys_dev_id", 7}, 
     339        {"pci_subsys_vendor_id", 8}, 
     340 
     341        {"regdomain", AR5K_EEPROM_REG_DOMAIN}, 
     342}; 
     343static const int eeprom_addr_len = sizeof(eeprom_addr)/sizeof(eeprom_addr[0]); 
     344 
     345static int force_write=0; 
     346static int verbose=0; 
     347 
     348/* forward decl. */ 
     349static void usage(const char *n); 
    237350 
    238351 
     
    300413 
    301414/* 
     415 * Write to EEPROM 
     416 */ 
     417int 
     418ath5k_hw_eeprom_write(void *mem, u_int32_t offset, u_int16_t data,  
     419                      u_int8_t mac_version) 
     420{ 
     421        u_int32_t status, timeout; 
     422 
     423        /* 
     424         * Initialize EEPROM access 
     425         */ 
     426 
     427        if (mac_version == AR5K_SREV_VER_AR5210) { 
     428 
     429                AR5K_REG_ENABLE_BITS(AR5K_PCICFG, AR5K_PCICFG_EEAE); 
     430 
     431                /* data to write */ 
     432                (void)AR5K_REG_WRITE(AR5K_EEPROM_BASE + (4 * offset), data); 
     433 
     434        } else { 
     435                /* !=  5210 */ 
     436                /* reset eeprom access */ 
     437                AR5K_REG_WRITE(AR5K_EEPROM_CMD, AR5K_EEPROM_CMD_RESET); 
     438                usleep(5); 
     439                 
     440                AR5K_REG_WRITE(AR5K_EEPROM_DATA, data); 
     441         
     442                /* set offset in EEPROM to write to */ 
     443                AR5K_REG_WRITE(AR5K_EEPROM_BASE, offset); 
     444                usleep(5); 
     445 
     446                /* issue write command */ 
     447                AR5K_REG_WRITE(AR5K_EEPROM_CMD, AR5K_EEPROM_CMD_WRITE); 
     448        } 
     449 
     450        for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) { 
     451                status = AR5K_REG_READ(AR5K_EEPROM_STATUS); 
     452                if (status & AR5K_EEPROM_STAT_WRDONE) { 
     453                        if (status & AR5K_EEPROM_STAT_WRERR) { 
     454                                err("eeprom write access to 0x%04x failed", offset); 
     455                                return 1; 
     456                        } 
     457                        return 0; 
     458                } 
     459                usleep(15); 
     460        } 
     461 
     462        return 1; 
     463} 
     464 
     465 
     466/* 
    302467 * Read from EEPROM 
    303468 */ 
     
    355520} 
    356521 
     522/* returns -1 on unknown name */ 
     523int eeprom_name2addr(const char *name) 
     524{ 
     525        int i; 
     526        if (!name || !name[0]) 
     527                return -1; 
     528        for(i=0; i < eeprom_addr_len; i++) 
     529                if (!strcmp(name, eeprom_addr[i].name)) 
     530                        return eeprom_addr[i].addr; 
     531        return -1; 
     532} /* eeprom_name2addr */ 
     533 
     534/* returns "<unknown>" on unknown address */ 
     535const char *eeprom_addr2name(int addr) 
     536{ 
     537        int i; 
     538        for(i=0; i < eeprom_addr_len; i++) 
     539                if (eeprom_addr[i].addr == addr) 
     540                        return eeprom_addr[i].name; 
     541        return "<unknown>"; 
     542} /* eeprom_addr2name */ 
     543 
     544 
     545static int  
     546do_write_pairs(int anr, int argc, char **argv, unsigned char *mem, int mac_version) 
     547{ 
     548#define MAX_NR_WRITES 16 
     549        struct { 
     550                int addr; 
     551                unsigned int val; 
     552        } wr_ops[MAX_NR_WRITES]; 
     553        int wr_ops_len = 0; 
     554        int i; 
     555        char *end; 
     556        int errors = 0; /* count errors during write/verify */ 
     557 
     558        if (anr >= argc) { 
     559                err("missing values to write."); 
     560                usage(argv[0]); 
     561                return 1; 
     562        } 
     563 
     564        if ((argc-anr) % 2) { 
     565                err("write spec. needs an even number of arguments."); 
     566                usage(argv[0]); 
     567                return 2; 
     568        } 
     569 
     570        if ((argc-anr)/2 > MAX_NR_WRITES) { 
     571                err("too many values to write (max. %d)", MAX_NR_WRITES); 
     572                return 3; 
     573        } 
     574 
     575        /* get the (addr,val) pairs we have to write */ 
     576        i=0; 
     577        while (anr < (argc-1)) { 
     578                wr_ops[i].addr = strtoul(argv[anr], &end, 0); 
     579                if (end == argv[anr]) { 
     580                        /* maybe a symbolic name for the address ? */ 
     581                        if ((wr_ops[i].addr = eeprom_name2addr(argv[anr])) == -1) { 
     582                                err("pair %d: bad address %s", i, argv[anr]); 
     583                                return 4; 
     584                        } 
     585                } 
     586 
     587                if (wr_ops[i].addr >= AR5K_EEPROM_INFO_BASE) { 
     588                        err("offset 0x%04x in CRC protected area is not supported", 
     589                            wr_ops[i].addr); 
     590                        return 5; 
     591                } 
     592 
     593                anr++; 
     594                wr_ops[i].val = strtoul(argv[anr], &end, 0); 
     595                if (end == argv[anr]) { 
     596                        err("pair %d: bad val %s", i, argv[anr]); 
     597                        return 5; 
     598                } 
     599 
     600                if (wr_ops[i].val > 0xffff) { 
     601                        err("pair %d: value %u too large", i, wr_ops[i].val); 
     602                        return 6; 
     603                } 
     604                anr++; 
     605                i++; 
     606        } /* while (anr < (argc-1)) */ 
     607 
     608        if (!(wr_ops_len=i)) { 
     609                err("no (addr,val) pairs given"); 
     610                return 7; 
     611        } 
     612 
     613        if (verbose || !force_write) { 
     614                for(i=0; i < wr_ops_len; i++) 
     615                        printf("%20s (0x%04x) := 0x%04x\n", 
     616                               eeprom_addr2name(wr_ops[i].addr), wr_ops[i].addr, wr_ops[i].val); 
     617        } 
     618 
     619        if (!force_write) { 
     620                int c; 
     621                printf( 
     622                        "WARNING: The write function may easy brick your device or\n" 
     623                        "violate state regulation on frequency usage.\n" 
     624                        "Proceed on your own risk!\n" 
     625                        "Shall I write the above value(s)? (y/n)\n"); 
     626                c=getchar(); 
     627                if (c != 'y' && c != 'Y') { 
     628                        printf("user abort\n"); 
     629                        return 0; 
     630                } 
     631        } 
     632 
     633        for(i=0; i < wr_ops_len; i++) { 
     634                u_int16_t oldval,u; 
     635 
     636                if (ath5k_hw_eeprom_read(mem, wr_ops[i].addr, &oldval, mac_version)) { 
     637                        err("failed to read old value from offset 0x%04x ", wr_ops[i].addr); 
     638                        errors++; 
     639                } 
     640 
     641                if (oldval == wr_ops[i].val) { 
     642                        dbg("pair %d: skipped, value already there", i); 
     643                        continue; 
     644                } 
     645                 
     646                dbg("writing *0x%04x := 0x%04x", wr_ops[i].addr, wr_ops[i].val);  
     647                if (ath5k_hw_eeprom_write(mem, wr_ops[i].addr, wr_ops[i].val, mac_version)) { 
     648                        err("failed to write 0x%04x to offset 0x%04x", 
     649                            wr_ops[i].val, wr_ops[i].addr); 
     650                        errors++; 
     651                } else { 
     652                        if (ath5k_hw_eeprom_read(mem, wr_ops[i].addr, &u, mac_version)) { 
     653                                err("failed to read offset 0x%04x for verification", wr_ops[i].addr); 
     654                                errors++; 
     655                        } else { 
     656                                if (u != wr_ops[i].val) { 
     657                                        err("offset 0x%04x: wrote 0x%04x but read 0x%04x",  
     658                                            wr_ops[i].addr, wr_ops[i].val, u); 
     659                                        errors++; 
     660                                } 
     661                        } 
     662                } 
     663        } 
     664 
     665        return errors ? 11 : 0; 
     666} /* do_write_pairs */ 
     667 
     668static void 
     669usage(const char *n) 
     670{ 
     671        int i; 
     672 
     673        fprintf(stderr, "%s [-w [-g N:M]] [-v] [-f] <base_address> " 
     674                "[<name1> <val1> [<name2> <val2> ...]]\n\n", n); 
     675        fprintf(stderr, 
     676                "-w      write values into EEPROM\n" 
     677                "-g N:M  set GPIO N to level M (only used with -w)\n" 
     678                "-v      verbose output\n" 
     679                "-f      force; suppress question before writing\n" 
     680                "<base_address>  device base address (see lspci output)\n\n"); 
     681 
     682        fprintf(stderr, 
     683                "- read info:\n" 
     684                "  %s <base_address>\n\n" 
     685                "- set regdomain to N:\n" 
     686                "  %s -w <base_address> regdomain N\n\n" 
     687                "- set a PCI id field to value N:\n" 
     688                "  %s -w <base_address> <field> N\n" 
     689                "  where <field> is on of:\n    ", n,n,n); 
     690        for(i=0; i < eeprom_addr_len; i++) 
     691                fprintf(stderr, " %s", eeprom_addr[i].name); 
     692        fprintf(stderr,"\n\n"); 
     693        fprintf(stderr, 
     694                "You may need to set a GPIO to a certain value in order to enable\n" 
     695                "writing to the EEPROM with newer chipsets, e.g. set GPIO 4 to low:\n" 
     696                "  %s -g 4:0 -w <base_address> regdomain N\n", n); 
     697        fprintf(stderr, 
     698                "\nDISCLAIMER: The authors are not responsible for any damages caused by\n" 
     699                "this program. Writing improper values may damage the card or cause\n" 
     700                "unlawful radio transmissions!\n\n"); 
     701} 
     702 
    357703int 
    358704main(int argc, char *argv[]) 
     
    364710        void *mem; 
    365711        int fd; 
    366  
    367         if ((argc < 2) || (argc > 2)) { 
    368                 printf("Usage: ath5k_info <phys address> \n"); 
     712        int i, anr=1; 
     713        int do_write=0; /* default: read only */ 
     714        struct { 
     715                int valid; 
     716                int value; 
     717        } gpio_set[AR5K_NUM_GPIO]; 
     718        int nr_gpio_set=0; 
     719 
     720        for(i=0; i < sizeof(gpio_set)/sizeof(gpio_set[0]); i++) 
     721                gpio_set[i].valid = 0; 
     722 
     723 
     724        if (argc < 2) { 
     725                usage(argv[0]); 
    369726                return -1; 
    370727        } 
    371728 
    372         dev_addr = strtoul(argv[1], NULL, 0); 
     729        while (anr < argc && argv[anr][0] == '-') { 
     730                switch (argv[anr][1]) { 
     731                case 'w': 
     732                        do_write=1; 
     733                        break; 
     734                case 'g': 
     735                        anr++; 
     736                        if (strlen(argv[anr]) != 3 || argv[anr][1] != ':' || 
     737                            argv[anr][0] < '0' || argv[anr][0] > '5' || 
     738                            (argv[anr][2] != '0' && argv[anr][2] != '1')) { 
     739                                err("invalid gpio spec. %s", argv[anr]); 
     740                                return 2; 
     741                        } 
     742                        gpio_set[argv[anr][0] - '0'].valid = 1; 
     743                        gpio_set[argv[anr][0] - '0'].value = argv[anr][2]-'0'; 
     744                        nr_gpio_set++; 
     745                        break; 
     746 
     747                case 'f': 
     748                        force_write=1; 
     749                        break; 
     750 
     751                case 'v': 
     752                        verbose=1; 
     753                        break; 
     754 
     755                case 'h': 
     756                        usage(argv[0]); 
     757                        return 0; 
     758                        break; 
     759 
     760                default: 
     761                        err("unknown option %s", argv[anr]); 
     762                        return 2; 
     763                } /* switch (argv[anr][1]) */ 
     764     
     765                anr++; 
     766        } /* while (anr < argc && ...) */ 
     767   
     768        if (anr >= argc) { 
     769                err("missing device address"); 
     770                usage(argv[0]); 
     771                return 3; 
     772        } 
     773 
     774        dev_addr = strtoul(argv[anr], NULL, 0); 
    373775 
    374776        fd = open("/dev/mem", O_RDWR); 
     
    386788                return -3; 
    387789        } 
     790 
     791        /* wake from power-down and remove reset (in case the driver isn't running) */ 
     792        { 
     793                unsigned long int 
     794                        sleep_ctl=AR5K_REG_READ(AR5K_SLEEP_CTL),  
     795                        reset_ctl=AR5K_REG_READ(AR5K_RESET_CTL); 
     796 
     797                dbg("sleep_ctl reg %08lx   reset_ctl reg %08lx", 
     798                    sleep_ctl, reset_ctl); 
     799                if (sleep_ctl & AR5K_SLEEP_CTL_SLE_SLP) { 
     800                        dbg("waking up the chip"); 
     801                        AR5K_REG_WRITE(AR5K_SLEEP_CTL,  
     802                                       (sleep_ctl & ~AR5K_SLEEP_CTL_SLE_SLP)); 
     803                } 
     804                 
     805                if (reset_ctl) { 
     806                        dbg("removing resets"); 
     807                        AR5K_REG_WRITE(AR5K_RESET_CTL, 0); 
     808                } 
     809        } 
     810 
     811        AR5K_REG_DISABLE_BITS(AR5K_PCICFG, AR5K_PCICFG_SPWR_DN); 
     812        usleep(500);                                                         
    388813 
    389814        srev = AR5K_REG_READ(AR5K_SREV); 
     
    550975        } 
    551976        printf(" ========================\n"); 
     977 
     978        /* print current GPIO settings */ 
     979        printf("GPIO registers: CR %08lx DO %08lx DI %08lx\n", 
     980               AR5K_REG_READ(AR5K_GPIOCR), AR5K_REG_READ(AR5K_GPIODO), 
     981               AR5K_REG_READ(AR5K_GPIODI)); 
     982 
     983        if (do_write) { 
     984                unsigned long int rcr=AR5K_REG_READ(AR5K_GPIOCR), 
     985                        rdo=AR5K_REG_READ(AR5K_GPIODO); 
     986                unsigned long int old_cr=rcr, old_do= rdo; 
     987                int rc; 
     988  
     989                if (mac_version >= AR5K_SREV_VER_AR5213 && !nr_gpio_set) { 
     990                        dbg("new MAC %x (>= AR5213) set gpio4 to low", mac_version); 
     991                        gpio_set[4].valid=1; 
     992                        gpio_set[4].value=0; 
     993                } 
     994 
     995                /* set gpios */ 
     996                dbg("old GPIO CR %08lx DO %08lx DI %08lx", 
     997                    rcr, rdo, AR5K_REG_READ(AR5K_GPIODI)); 
     998 
     999                for(i=0; i < sizeof(gpio_set)/sizeof(gpio_set[0]); i++) { 
     1000                        if (gpio_set[i].valid) { 
     1001                                rcr |= AR5K_GPIOCR_OUT(i); /* we use mode 3 */ 
     1002                                rcr &= ~AR5K_GPIOCR_INT_SEL(i); 
     1003                                rdo &= ~(1<<i); 
     1004                                rdo |= (gpio_set[i].value<<i);  
     1005                        } 
     1006                } 
     1007 
     1008                if (rcr != old_cr) { 
     1009                        dbg("GPIO CR %lx -> %lx", old_cr, rcr); 
     1010                        AR5K_REG_WRITE(AR5K_GPIOCR, rcr); 
     1011                } 
     1012                usleep(5); 
     1013 
     1014                if (rdo != old_do) { 
     1015                        dbg("GPIO CR %lx -> %lx", old_do, rdo); 
     1016                        AR5K_REG_WRITE(AR5K_GPIODO, rdo); 
     1017                } 
     1018 
     1019                /*dump current values again if we have written anything */ 
     1020                if (rcr != old_cr || rdo != old_do) 
     1021                        dbg("new GPIO CR %08lx DO %08lx DI %08lx", 
     1022                            AR5K_REG_READ(AR5K_GPIOCR),  
     1023                            AR5K_REG_READ(AR5K_GPIODO),  
     1024                            AR5K_REG_READ(AR5K_GPIODI)); 
     1025 
     1026                /* let argv[anr] be the first write parameter */ 
     1027                anr++; 
     1028 
     1029                rc=do_write_pairs(anr, argc, argv, mem, mac_version); 
     1030 
     1031                /* restore old GPIO settings */ 
     1032                if (rcr != old_cr) { 
     1033                        dbg("restoring GPIO CR %lx -> %lx", rcr, old_cr); 
     1034                        AR5K_REG_WRITE(AR5K_GPIOCR, old_cr); 
     1035                } 
     1036                usleep(5); 
     1037 
     1038                if (rdo != old_do) { 
     1039                        dbg("restoring GPIO CR %lx -> %lx", rdo, old_do); 
     1040                        AR5K_REG_WRITE(AR5K_GPIODO, old_do); 
     1041                } 
     1042 
     1043                return rc; 
     1044        } 
    5521045        return 0; 
    5531046}