| 1 | --- a/ath/if_ath.c |
| 2 | +++ b/ath/if_ath.c |
| 3 | @@ -62,6 +62,7 @@ |
| 4 | #include <linux/if_arp.h> |
| 5 | #include <linux/rtnetlink.h> |
| 6 | #include <linux/time.h> |
| 7 | +#include <linux/pci.h> |
| 8 | #include <asm/uaccess.h> |
| 9 | |
| 10 | #include "if_ethersubr.h" /* for ETHER_IS_MULTICAST */ |
| 11 | @@ -401,6 +402,15 @@ static int outdoor = -1; |
| 12 | static int xchanmode = -1; |
| 13 | static int beacon_cal = 1; |
| 14 | |
| 15 | +static const struct ath_hw_detect generic_hw_info = { |
| 16 | + .vendor_name = "Unknown", |
| 17 | + .card_name = "Generic", |
| 18 | + .vendor = PCI_ANY_ID, |
| 19 | + .id = PCI_ANY_ID, |
| 20 | + .subvendor = PCI_ANY_ID, |
| 21 | + .subid = PCI_ANY_ID |
| 22 | +}; |
| 23 | + |
| 24 | static const char *hal_status_desc[] = { |
| 25 | "No error", |
| 26 | "No hardware present or device not yet supported", |
| 27 | @@ -542,6 +552,8 @@ ath_attach(u_int16_t devid, struct net_d |
| 28 | DPRINTF(sc, ATH_DEBUG_ANY, "%s: devid 0x%x\n", __func__, devid); |
| 29 | #endif |
| 30 | |
| 31 | + sc->sc_hwinfo = &generic_hw_info; |
| 32 | + |
| 33 | /* Allocate space for dynamically determined maximum VAP count */ |
| 34 | sc->sc_bslot = |
| 35 | kmalloc(ath_maxvaps * sizeof(struct ieee80211vap*), GFP_KERNEL); |
| 36 | @@ -1508,6 +1520,29 @@ ath_vap_create(struct ieee80211com *ic, |
| 37 | return vap; |
| 38 | } |
| 39 | |
| 40 | +void |
| 41 | +ath_hw_detect(struct ath_softc *sc, const struct ath_hw_detect *cards, int n_cards, u32 vendor, u32 id, u32 subvendor, u32 subid) |
| 42 | +{ |
| 43 | + int i; |
| 44 | + |
| 45 | + for (i = 0; i < n_cards; i++) { |
| 46 | + const struct ath_hw_detect *c = &cards[i]; |
| 47 | + |
| 48 | + if ((c->vendor != PCI_ANY_ID) && c->vendor != vendor) |
| 49 | + continue; |
| 50 | + if ((c->id != PCI_ANY_ID) && c->id != id) |
| 51 | + continue; |
| 52 | + if ((c->subvendor != PCI_ANY_ID) && c->subvendor != subvendor) |
| 53 | + continue; |
| 54 | + if ((c->subid != PCI_ANY_ID) && c->subid != subid) |
| 55 | + continue; |
| 56 | + |
| 57 | + sc->sc_hwinfo = c; |
| 58 | + sc->sc_poweroffset = c->poweroffset; |
| 59 | + break; |
| 60 | + } |
| 61 | +} |
| 62 | + |
| 63 | static void |
| 64 | ath_vap_delete(struct ieee80211vap *vap) |
| 65 | { |
| 66 | @@ -10225,6 +10260,7 @@ static u_int32_t |
| 67 | ath_set_clamped_maxtxpower(struct ath_softc *sc, |
| 68 | u_int32_t new_clamped_maxtxpower) |
| 69 | { |
| 70 | + new_clamped_maxtxpower -= sc->sc_poweroffset; |
| 71 | (void)ath_hal_settxpowlimit(sc->sc_ah, new_clamped_maxtxpower); |
| 72 | return ath_get_clamped_maxtxpower(sc); |
| 73 | } |
| 74 | @@ -10238,6 +10274,7 @@ ath_get_clamped_maxtxpower(struct ath_so |
| 75 | { |
| 76 | u_int32_t clamped_maxtxpower; |
| 77 | (void)ath_hal_getmaxtxpow(sc->sc_ah, &clamped_maxtxpower); |
| 78 | + clamped_maxtxpower += sc->sc_poweroffset; |
| 79 | return clamped_maxtxpower; |
| 80 | } |
| 81 | |
| 82 | @@ -10821,6 +10858,12 @@ ath_ioctl(struct net_device *dev, struct |
| 83 | * is to add module parameters. |
| 84 | */ |
| 85 | |
| 86 | +/* sysctls for hardware info */ |
| 87 | +enum { |
| 88 | + ATH_CARD_VENDOR, |
| 89 | + ATH_CARD_NAME, |
| 90 | +}; |
| 91 | + |
| 92 | /* |
| 93 | * Dynamic (i.e. per-device) sysctls. These are automatically |
| 94 | * mirrored in /proc/sys. |
| 95 | @@ -10900,6 +10943,38 @@ ath_sysctl_get_intmit(struct ath_softc * |
| 96 | } |
| 97 | |
| 98 | static int |
| 99 | +ATH_SYSCTL_DECL(ath_sysctl_hwinfo, ctl, write, filp, buffer, lenp, ppos) |
| 100 | +{ |
| 101 | + struct ath_softc *sc = ctl->extra1; |
| 102 | + struct ath_hal *ah = sc->sc_ah; |
| 103 | + int ret = 0; |
| 104 | + |
| 105 | + if (write) |
| 106 | + return -EINVAL; |
| 107 | + |
| 108 | + ATH_LOCK(sc); |
| 109 | + switch((long)ctl->extra2) { |
| 110 | + case ATH_CARD_VENDOR: |
| 111 | + ctl->data = (char *)sc->sc_hwinfo->vendor_name; |
| 112 | + break; |
| 113 | + case ATH_CARD_NAME: |
| 114 | + ctl->data = (char *)sc->sc_hwinfo->card_name; |
| 115 | + break; |
| 116 | + default: |
| 117 | + ret = -EINVAL; |
| 118 | + break; |
| 119 | + } |
| 120 | + if (ret == 0) { |
| 121 | + ctl->maxlen = strlen(ctl->data); |
| 122 | + ret = ATH_SYSCTL_PROC_DOSTRING(ctl, write, filp, |
| 123 | + buffer, lenp, ppos); |
| 124 | + } |
| 125 | + ATH_UNLOCK(sc); |
| 126 | + |
| 127 | + return ret; |
| 128 | +} |
| 129 | + |
| 130 | +static int |
| 131 | ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl, write, filp, buffer, lenp, ppos) |
| 132 | { |
| 133 | struct ath_softc *sc = ctl->extra1; |
| 134 | @@ -11179,6 +11254,24 @@ static int maxint = 0x7fffffff; /* 32-b |
| 135 | |
| 136 | static const ctl_table ath_sysctl_template[] = { |
| 137 | { .ctl_name = CTL_AUTO, |
| 138 | + .procname = "dev_vendor", |
| 139 | + .mode = 0644, |
| 140 | + .proc_handler = ath_sysctl_hwinfo, |
| 141 | + .strategy = &sysctl_string, |
| 142 | + .data = "N/A", |
| 143 | + .maxlen = 1, |
| 144 | + .extra2 = (void *)ATH_CARD_VENDOR, |
| 145 | + }, |
| 146 | + { .ctl_name = CTL_AUTO, |
| 147 | + .procname = "dev_name", |
| 148 | + .mode = 0644, |
| 149 | + .proc_handler = ath_sysctl_hwinfo, |
| 150 | + .strategy = &sysctl_string, |
| 151 | + .data = "N/A", |
| 152 | + .maxlen = 1, |
| 153 | + .extra2 = (void *)ATH_CARD_NAME, |
| 154 | + }, |
| 155 | + { .ctl_name = CTL_AUTO, |
| 156 | .procname = "slottime", |
| 157 | .mode = 0644, |
| 158 | .proc_handler = ath_sysctl_halparam, |
| 159 | --- a/ath/if_athvar.h |
| 160 | +++ b/ath/if_athvar.h |
| 161 | @@ -168,12 +168,16 @@ static inline struct net_device *_alloc_ |
| 162 | void __user *buffer, size_t *lenp) |
| 163 | #define ATH_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer, lenp, ppos) \ |
| 164 | proc_dointvec(ctl, write, filp, buffer, lenp) |
| 165 | +#define ATH_SYSCTL_PROC_DOSTRING(ctl, write, filp, buffer, lenp, ppos) \ |
| 166 | + proc_dostring(ctl, write, filp, buffer, lenp) |
| 167 | #else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8) */ |
| 168 | #define ATH_SYSCTL_DECL(f, ctl, write, filp, buffer, lenp, ppos) \ |
| 169 | f(ctl_table *ctl, int write, struct file *filp, \ |
| 170 | void __user *buffer, size_t *lenp, loff_t *ppos) |
| 171 | #define ATH_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer, lenp, ppos) \ |
| 172 | proc_dointvec(ctl, write, filp, buffer, lenp, ppos) |
| 173 | +#define ATH_SYSCTL_PROC_DOSTRING(ctl, write, filp, buffer, lenp, ppos) \ |
| 174 | + proc_dostring(ctl, write, filp, buffer, lenp, ppos) |
| 175 | #endif |
| 176 | |
| 177 | #define ATH_TIMEOUT 1000 |
| 178 | @@ -469,6 +473,7 @@ struct ath_hal; |
| 179 | struct ath_desc; |
| 180 | struct ath_ratectrl; |
| 181 | struct ath_tx99; |
| 182 | +struct ath_hw_detect; |
| 183 | struct proc_dir_entry; |
| 184 | |
| 185 | /* |
| 186 | @@ -629,6 +634,7 @@ struct ath_softc { |
| 187 | struct ath_ratectrl *sc_rc; /* tx rate control support */ |
| 188 | struct ath_tx99 *sc_tx99; /* tx99 support */ |
| 189 | void (*sc_setdefantenna)(struct ath_softc *, u_int); |
| 190 | + const struct ath_hw_detect *sc_hwinfo; |
| 191 | |
| 192 | unsigned int sc_invalid:1; /* being detached */ |
| 193 | unsigned int sc_mrretry:1; /* multi-rate retry support */ |
| 194 | @@ -683,6 +689,7 @@ struct ath_softc { |
| 195 | const HAL_RATE_TABLE *sc_quarter_rates; /* quarter rate table */ |
| 196 | HAL_OPMODE sc_opmode; /* current hal operating mode */ |
| 197 | enum ieee80211_phymode sc_curmode; /* current phy mode */ |
| 198 | + u_int sc_poweroffset; /* hardware power offset */ |
| 199 | u_int16_t sc_curtxpow; /* current tx power limit */ |
| 200 | u_int16_t sc_curaid; /* current association id */ |
| 201 | HAL_CHANNEL sc_curchan; /* current h/w channel */ |
| 202 | @@ -929,4 +936,16 @@ int ar_device(int devid); |
| 203 | |
| 204 | void ath_radar_detected(struct ath_softc *sc, const char* message); |
| 205 | |
| 206 | +struct ath_hw_detect { |
| 207 | + const char *vendor_name; |
| 208 | + const char *card_name; |
| 209 | + u32 vendor; |
| 210 | + u32 id; |
| 211 | + u32 subvendor; |
| 212 | + u32 subid; |
| 213 | + u32 poweroffset; |
| 214 | +}; |
| 215 | + |
| 216 | +extern void ath_hw_detect(struct ath_softc *sc, const struct ath_hw_detect *cards, int n_cards, u32 vendor, u32 id, u32 subvendor, u32 subid); |
| 217 | + |
| 218 | #endif /* _DEV_ATH_ATHVAR_H */ |
| 219 | --- a/ath/if_ath_ahb.c |
| 220 | +++ b/ath/if_ath_ahb.c |
| 221 | @@ -20,6 +20,7 @@ |
| 222 | #include <linux/netdevice.h> |
| 223 | #include <linux/cache.h> |
| 224 | #include <linux/platform_device.h> |
| 225 | +#include <linux/pci.h> |
| 226 | |
| 227 | #include <asm/io.h> |
| 228 | #include <asm/uaccess.h> |
| 229 | @@ -181,12 +182,32 @@ exit_ath_wmac(u_int16_t wlanNum, struct |
| 230 | return 0; |
| 231 | } |
| 232 | |
| 233 | +static const char ubnt[] = "Ubiquiti Networks"; |
| 234 | +/* { vendorname, cardname, vendorid, cardid, subsys vendorid, subsys id, poweroffset } */ |
| 235 | +static const struct ath_hw_detect cards[] = { |
| 236 | + { ubnt, "PowerStation2 (18V)", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xb102 }, |
| 237 | + { ubnt, "PowerStation2 (16D)", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xb202 }, |
| 238 | + { ubnt, "PowerStation2 (EXT)", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xb302 }, |
| 239 | + { ubnt, "PowerStation5 (22V)", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xb105 }, |
| 240 | + { ubnt, "PowerStation5 (EXT)", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xb305 }, |
| 241 | + { ubnt, "WispStation5", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xa105 }, |
| 242 | + { ubnt, "LiteStation2", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xa002 }, |
| 243 | + { ubnt, "LiteStation5", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xa005 }, |
| 244 | + { ubnt, "NanoStation2", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xc002 }, |
| 245 | + { ubnt, "NanoStation5", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xc005 }, |
| 246 | + { ubnt, "NanoStation Loco2", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xc102 }, |
| 247 | + { ubnt, "NanoStation Loco5", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xc105 }, |
| 248 | + { ubnt, "Bullet2", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xc202 }, |
| 249 | + { ubnt, "Bullet5", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xc205 }, |
| 250 | +}; |
| 251 | + |
| 252 | static int |
| 253 | init_ath_wmac(u_int16_t devid, u_int16_t wlanNum, struct ar531x_config *config) |
| 254 | { |
| 255 | const char *athname; |
| 256 | struct net_device *dev; |
| 257 | struct ath_ahb_softc *sc; |
| 258 | + u16 *radio_data; |
| 259 | |
| 260 | if (((wlanNum != 0) && (wlanNum != 1)) || |
| 261 | (sclist[wlanNum] != NULL)) |
| 262 | @@ -248,6 +269,16 @@ init_ath_wmac(u_int16_t devid, u_int16_t |
| 263 | sc->aps_sc.sc_softled = 1; /* SoftLED over GPIO */ |
| 264 | sc->aps_sc.sc_ledpin = config->board->sysLedGpio; |
| 265 | sc->aps_sc.sc_invalid = 0; |
| 266 | + radio_data = (u16 *) config->radio; |
| 267 | + if (radio_data) { |
| 268 | + u16 vendor, id, subvendor, subid; |
| 269 | + vendor = radio_data[1]; |
| 270 | + id = radio_data[0]; |
| 271 | + subvendor = radio_data[8]; |
| 272 | + subid = radio_data[7]; |
| 273 | + ath_hw_detect(&sc->aps_sc, cards, ARRAY_SIZE(cards), vendor, id, subvendor, subid); |
| 274 | + } |
| 275 | + |
| 276 | return 0; |
| 277 | |
| 278 | bad4: |
| 279 | --- a/ath/if_ath_pci.c |
| 280 | +++ b/ath/if_ath_pci.c |
| 281 | @@ -123,6 +123,33 @@ static u16 ath_devidmap[][2] = { |
| 282 | { 0xff1a, 0x001a } |
| 283 | }; |
| 284 | |
| 285 | +static const char ubnt[] = "Ubiquiti Networks"; |
| 286 | +/* { vendorname, cardname, vendorid, cardid, subsys vendorid, subsys id, poweroffset } */ |
| 287 | +static const struct ath_hw_detect cards[] = { |
| 288 | + { ubnt, "XR2", 0x168c, 0x001b, 0x0777, 0x3002, 10 }, |
| 289 | + { ubnt, "XR2", 0x168c, 0x001b, 0x7777, 0x3002, 10 }, |
| 290 | + { ubnt, "XR2.3", 0x168c, 0x001b, 0x0777, 0x3b02, 10 }, |
| 291 | + { ubnt, "XR2.6", 0x168c, 0x001b, 0x0777, 0x3c02, 10 }, |
| 292 | + { ubnt, "XR3-2.8", 0x168c, 0x001b, 0x0777, 0x3b03, 10 }, |
| 293 | + { ubnt, "XR3-3.6", 0x168c, 0x001b, 0x0777, 0x3c03, 10 }, |
| 294 | + { ubnt, "XR3", 0x168c, 0x001b, 0x0777, 0x3003, 10 }, |
| 295 | + { ubnt, "XR4", 0x168c, 0x001b, 0x0777, 0x3004, 10 }, |
| 296 | + { ubnt, "XR5", 0x168c, 0x001b, 0x0777, 0x3005, 10 }, |
| 297 | + { ubnt, "XR5", 0x168c, 0x001b, 0x7777, 0x3005, 10 }, |
| 298 | + { ubnt, "XR7", 0x168c, 0x001b, 0x0777, 0x3007, 10 }, |
| 299 | + { ubnt, "XR9", 0x168c, 0x001b, 0x0777, 0x3009, 10 }, |
| 300 | + { ubnt, "SRC", 0x168c, 0x0013, 0x168c, 0x1042, 1 }, |
| 301 | + { ubnt, "SR2", 0x168c, 0x0013, 0x0777, 0x2041, 10 }, |
| 302 | + { ubnt, "SR4", 0x168c, 0x0013, 0x0777, 0x2004, 6 }, |
| 303 | + { ubnt, "SR4", 0x168c, 0x0013, 0x7777, 0x2004, 6 }, |
| 304 | + { ubnt, "SR4C", 0x168c, 0x0013, 0x0777, 0x1004, 6 }, |
| 305 | + { ubnt, "SR4C", 0x168c, 0x0013, 0x7777, 0x1004, 6 }, |
| 306 | + { ubnt, "SR5", 0x168c, 0x0013, 0x168c, 0x2042, 7 }, |
| 307 | + { ubnt, "SR9", 0x168c, 0x0013, 0x7777, 0x2009, 12 }, |
| 308 | + { ubnt, "SR71A", 0x168c, 0x0027, 0x168c, 0x2082, 10 }, |
| 309 | + { ubnt, "SR71", 0x168c, 0x0027, 0x0777, 0x4082, 10 }, |
| 310 | +}; |
| 311 | + |
| 312 | static int |
| 313 | ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
| 314 | { |
| 315 | @@ -257,6 +284,10 @@ ath_pci_probe(struct pci_dev *pdev, cons |
| 316 | printk(KERN_INFO "%s: %s: %s: mem=0x%lx, irq=%d\n", |
| 317 | dev_info, dev->name, athname ? athname : "Atheros ???", phymem, dev->irq); |
| 318 | |
| 319 | + ath_hw_detect(&sc->aps_sc, cards, ARRAY_SIZE(cards), |
| 320 | + pdev->vendor, pdev->device, |
| 321 | + pdev->subsystem_vendor, pdev->subsystem_device); |
| 322 | + |
| 323 | /* ready to process interrupts */ |
| 324 | sc->aps_sc.sc_invalid = 0; |
| 325 | |
| 326 | |