1 /*- 2 * Copyright (c) 2009 Sam Leffler, Errno Consulting 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer, 10 * without modification. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13 * redistribution must be conditioned upon including a substantially 14 * similar Disclaimer requirement for further binary redistribution. 15 * 16 * NO WARRANTY 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 * THE POSSIBILITY OF SUCH DAMAGES. 28 * 29 * $FreeBSD: src/tools/tools/ath/athpoke/athpoke.c,v 1.3 2009/08/27 17:32:58 sam Exp $ 30 */ 31 #include "diag.h" 32 33 #include "ah.h" 34 #include "ah_internal.h" 35 36 #include "dumpregs.h" 37 38 #include <getopt.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <ctype.h> 42 #include <err.h> 43 #include <errno.h> 44 45 typedef struct { 46 HAL_REVS revs; 47 #define MAXREGS 5*1024 48 struct dumpreg *regs[MAXREGS]; 49 u_int nregs; 50 } dumpregs_t; 51 static dumpregs_t state; 52 53 static uint32_t regread(int s, struct ath_diag *atd, uint32_t r); 54 static void regwrite(int s, struct ath_diag *atd, uint32_t r, uint32_t v); 55 static const struct dumpreg *reglookup(const char *v); 56 57 static void 58 usage(void) 59 { 60 fprintf(stderr, "usage: athpoke [-i interface] [reg[=value]] ...\n"); 61 exit(-1); 62 } 63 64 int 65 main(int argc, char *argv[]) 66 { 67 struct ath_diag atd; 68 const char *ifname; 69 char *eptr; 70 int c, s; 71 72 s = socket(AF_INET, SOCK_DGRAM, 0); 73 if (s < 0) 74 err(1, "socket"); 75 ifname = getenv("ATH"); 76 if (!ifname) 77 ifname = ATH_DEFAULT; 78 79 while ((c = getopt(argc, argv, "i:")) != -1) 80 switch (c) { 81 case 'i': 82 ifname = optarg; 83 break; 84 default: 85 usage(); 86 /*NOTREACHED*/ 87 } 88 strncpy(atd.ad_name, ifname, sizeof (atd.ad_name)); 89 90 atd.ad_id = HAL_DIAG_REVS; 91 atd.ad_out_data = (caddr_t) &state.revs; 92 atd.ad_out_size = sizeof(state.revs); 93 if (ioctl(s, SIOCGATHDIAG, &atd) < 0) 94 err(1, atd.ad_name); 95 96 argc -= optind; 97 argv += optind; 98 99 for (; argc > 0; argc--, argv++) { 100 char *cp; 101 const struct dumpreg *dr; 102 uint32_t reg; 103 104 cp = strchr(argv[0], '='); 105 if (cp != NULL) 106 *cp++ = '\0'; 107 dr = reglookup(argv[0]); 108 if (dr == NULL) { 109 errno = 0; 110 reg = (uint32_t) strtoul(argv[0], &eptr, 0); 111 if (argv[0] == eptr || eptr[0] != '\0') 112 errx(1, "invalid register \"%s\"", argv[0]); 113 } else 114 reg = dr->addr; 115 if (cp != NULL) 116 regwrite(s, &atd, reg, (uint32_t) strtoul(cp, NULL, 0)); 117 printf("%s = %08x\n", argv[0], regread(s, &atd, reg)); 118 } 119 return 0; 120 } 121 122 static uint32_t 123 regread(int s, struct ath_diag *atd, uint32_t r) 124 { 125 HAL_REGRANGE ra; 126 uint32_t v[2]; 127 128 ra.start = r; 129 ra.end = 0; 130 131 atd->ad_in_data = (caddr_t) &ra; 132 atd->ad_in_size = sizeof(ra); 133 atd->ad_out_data = (caddr_t) v; 134 atd->ad_out_size = sizeof(v); 135 atd->ad_id = HAL_DIAG_REGS | ATH_DIAG_IN | ATH_DIAG_DYN; 136 if (ioctl(s, SIOCGATHDIAG, atd) < 0) 137 err(1, atd->ad_name); 138 return v[1]; 139 } 140 141 static void 142 regwrite(int s, struct ath_diag *atd, uint32_t r, uint32_t v) 143 { 144 HAL_REGWRITE rw; 145 146 rw.addr = r; 147 rw.value = v; 148 atd->ad_in_data = (caddr_t) &rw; 149 atd->ad_in_size = sizeof(rw); 150 atd->ad_id = HAL_DIAG_SETREGS | ATH_DIAG_IN; 151 if (ioctl(s, SIOCGATHDIAG, atd) < 0) 152 err(1, atd->ad_name); 153 } 154 155 static int 156 regcompar(const void *a, const void *b) 157 { 158 const struct dumpreg *ra = *(const struct dumpreg **)a; 159 const struct dumpreg *rb = *(const struct dumpreg **)b; 160 return ra->addr - rb->addr; 161 } 162 163 void 164 register_regs(struct dumpreg *chipregs, u_int nchipregs, 165 int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max) 166 { 167 const int existing_regs = state.nregs; 168 int i, j; 169 170 for (i = 0; i < nchipregs; i++) { 171 struct dumpreg *nr = &chipregs[i]; 172 if (nr->srevMin == 0) 173 nr->srevMin = def_srev_min; 174 if (nr->srevMax == 0) 175 nr->srevMax = def_srev_max; 176 if (nr->phyMin == 0) 177 nr->phyMin = def_phy_min; 178 if (nr->phyMax == 0) 179 nr->phyMax = def_phy_max; 180 for (j = 0; j < existing_regs; j++) { 181 struct dumpreg *r = state.regs[j]; 182 /* 183 * Check if we can just expand the mac+phy 184 * coverage for the existing entry. 185 */ 186 if (nr->addr == r->addr && 187 (nr->name == r->name || 188 nr->name != NULL && r->name != NULL && 189 strcmp(nr->name, r->name) == 0)) { 190 if (nr->srevMin < r->srevMin && 191 (r->srevMin <= nr->srevMax && 192 nr->srevMax+1 <= r->srevMax)) { 193 r->srevMin = nr->srevMin; 194 goto skip; 195 } 196 if (nr->srevMax > r->srevMax && 197 (r->srevMin <= nr->srevMin && 198 nr->srevMin <= r->srevMax)) { 199 r->srevMax = nr->srevMax; 200 goto skip; 201 } 202 } 203 if (r->addr > nr->addr) 204 break; 205 } 206 /* 207 * New item, add to the end, it'll be sorted below. 208 */ 209 if (state.nregs == MAXREGS) 210 errx(-1, "too many registers; bump MAXREGS"); 211 state.regs[state.nregs++] = nr; 212 skip: 213 ; 214 } 215 qsort(state.regs, state.nregs, sizeof(struct dumpreg *), regcompar); 216 } 217 218 void 219 register_keycache(u_int nslots, 220 int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max) 221 { 222 /* discard, no use */ 223 } 224 225 void 226 register_range(u_int brange, u_int erange, int type, 227 int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max) 228 { 229 /* discard, no use */ 230 } 231 232 static const struct dumpreg * 233 reglookup(const char *v) 234 { 235 const HAL_REVS *revs = &state.revs; 236 int i; 237 238 if (strncasecmp(v, "AR_", 3) == 0) 239 v += 3; 240 for (i = 0; i < state.nregs; i++) { 241 const struct dumpreg *dr = state.regs[i]; 242 if (MAC_MATCH(dr, revs->ah_macVersion, revs->ah_macRev) && 243 strcasecmp(v, dr->name) == 0) 244 return dr; 245 } 246 return NULL; 247 } 248