mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-30 21:44:27 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			326 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			326 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| --- a/ath/if_ath.c
 | |
| +++ b/ath/if_ath.c
 | |
| @@ -62,6 +62,7 @@
 | |
|  #include <linux/if_arp.h>
 | |
|  #include <linux/rtnetlink.h>
 | |
|  #include <linux/time.h>
 | |
| +#include <linux/pci.h>
 | |
|  #include <asm/uaccess.h>
 | |
|  
 | |
|  #include "if_ethersubr.h"		/* for ETHER_IS_MULTICAST */
 | |
| @@ -401,6 +402,15 @@ static int outdoor = -1;
 | |
|  static int xchanmode = -1;
 | |
|  static int beacon_cal = 1;
 | |
|  
 | |
| +static const struct ath_hw_detect generic_hw_info = {
 | |
| +	.vendor_name = "Unknown",
 | |
| +	.card_name = "Generic",
 | |
| +	.vendor = PCI_ANY_ID,
 | |
| +	.id = PCI_ANY_ID,
 | |
| +	.subvendor = PCI_ANY_ID,
 | |
| +	.subid = PCI_ANY_ID
 | |
| +};
 | |
| +
 | |
|  static const char *hal_status_desc[] = {
 | |
|  	"No error",
 | |
|  	"No hardware present or device not yet supported",
 | |
| @@ -542,6 +552,8 @@ ath_attach(u_int16_t devid, struct net_d
 | |
|  	DPRINTF(sc, ATH_DEBUG_ANY, "%s: devid 0x%x\n", __func__, devid);
 | |
|  #endif
 | |
|  
 | |
| +	sc->sc_hwinfo = &generic_hw_info;
 | |
| +
 | |
|  	/* Allocate space for dynamically determined maximum VAP count */
 | |
|  	sc->sc_bslot = 
 | |
|  		kmalloc(ath_maxvaps * sizeof(struct ieee80211vap*), GFP_KERNEL);
 | |
| @@ -1508,6 +1520,29 @@ ath_vap_create(struct ieee80211com *ic, 
 | |
|  	return vap;
 | |
|  }
 | |
|  
 | |
| +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)
 | |
| +{
 | |
| +	int i;
 | |
| +
 | |
| +	for (i = 0; i < n_cards; i++) {
 | |
| +		const struct ath_hw_detect *c = &cards[i];
 | |
| +
 | |
| +		if ((c->vendor != PCI_ANY_ID) && c->vendor != vendor)
 | |
| +			continue;
 | |
| +		if ((c->id != PCI_ANY_ID) && c->id != id)
 | |
| +			continue;
 | |
| +		if ((c->subvendor != PCI_ANY_ID) && c->subvendor != subvendor)
 | |
| +			continue;
 | |
| +		if ((c->subid != PCI_ANY_ID) && c->subid != subid)
 | |
| +			continue;
 | |
| +
 | |
| +		sc->sc_hwinfo = c;
 | |
| +		sc->sc_poweroffset = c->poweroffset;
 | |
| +		break;
 | |
| +	}
 | |
| +}
 | |
| +
 | |
|  static void
 | |
|  ath_vap_delete(struct ieee80211vap *vap)
 | |
|  {
 | |
| @@ -10225,6 +10260,7 @@ static u_int32_t
 | |
|  ath_set_clamped_maxtxpower(struct ath_softc *sc, 
 | |
|  		u_int32_t new_clamped_maxtxpower)
 | |
|  {
 | |
| +	new_clamped_maxtxpower -= sc->sc_poweroffset;
 | |
|  	(void)ath_hal_settxpowlimit(sc->sc_ah, new_clamped_maxtxpower);
 | |
|  	return ath_get_clamped_maxtxpower(sc);
 | |
|  }
 | |
| @@ -10238,6 +10274,7 @@ ath_get_clamped_maxtxpower(struct ath_so
 | |
|  {
 | |
|  	u_int32_t clamped_maxtxpower;
 | |
|  	(void)ath_hal_getmaxtxpow(sc->sc_ah, &clamped_maxtxpower);
 | |
| +	clamped_maxtxpower += sc->sc_poweroffset;
 | |
|  	return clamped_maxtxpower;
 | |
|  }
 | |
|  
 | |
| @@ -10821,6 +10858,12 @@ ath_ioctl(struct net_device *dev, struct
 | |
|   * is to add module parameters.
 | |
|   */
 | |
|  
 | |
| +/* sysctls for hardware info */
 | |
| +enum {
 | |
| +	ATH_CARD_VENDOR,
 | |
| +	ATH_CARD_NAME,
 | |
| +};
 | |
| +
 | |
|  /*
 | |
|   * Dynamic (i.e. per-device) sysctls.  These are automatically
 | |
|   * mirrored in /proc/sys.
 | |
| @@ -10900,6 +10943,38 @@ ath_sysctl_get_intmit(struct ath_softc *
 | |
|  }
 | |
|  
 | |
|  static int
 | |
| +ATH_SYSCTL_DECL(ath_sysctl_hwinfo, ctl, write, filp, buffer, lenp, ppos)
 | |
| +{
 | |
| +	struct ath_softc *sc = ctl->extra1;
 | |
| +	struct ath_hal *ah = sc->sc_ah;
 | |
| +	int ret = 0;
 | |
| +
 | |
| +	if (write)
 | |
| +		return -EINVAL;
 | |
| +
 | |
| +	ATH_LOCK(sc);
 | |
| +	switch((long)ctl->extra2) {
 | |
| +	case ATH_CARD_VENDOR:
 | |
| +		ctl->data = (char *)sc->sc_hwinfo->vendor_name;
 | |
| +		break;
 | |
| +	case ATH_CARD_NAME:
 | |
| +		ctl->data = (char *)sc->sc_hwinfo->card_name;
 | |
| +		break;
 | |
| +	default:
 | |
| +		ret = -EINVAL;
 | |
| +		break;
 | |
| +	}
 | |
| +	if (ret == 0) {
 | |
| +		ctl->maxlen = strlen(ctl->data);
 | |
| +		ret = ATH_SYSCTL_PROC_DOSTRING(ctl, write, filp,
 | |
| +				buffer, lenp, ppos);
 | |
| +	}
 | |
| +	ATH_UNLOCK(sc);
 | |
| +
 | |
| +	return ret;
 | |
| +}
 | |
| +
 | |
| +static int
 | |
|  ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl, write, filp, buffer, lenp, ppos)
 | |
|  {
 | |
|  	struct ath_softc *sc = ctl->extra1;
 | |
| @@ -11179,6 +11254,24 @@ static int maxint = 0x7fffffff;		/* 32-b
 | |
|  
 | |
|  static const ctl_table ath_sysctl_template[] = {
 | |
|  	{ .ctl_name	= CTL_AUTO,
 | |
| +	  .procname	= "dev_vendor",
 | |
| +	  .mode		= 0644,
 | |
| +	  .proc_handler	= ath_sysctl_hwinfo,
 | |
| +	  .strategy   = &sysctl_string,
 | |
| +	  .data		= "N/A",
 | |
| +	  .maxlen   = 1,
 | |
| +	  .extra2	= (void *)ATH_CARD_VENDOR,
 | |
| +	},
 | |
| +	{ .ctl_name	= CTL_AUTO,
 | |
| +	  .procname	= "dev_name",
 | |
| +	  .mode		= 0644,
 | |
| +	  .proc_handler	= ath_sysctl_hwinfo,
 | |
| +	  .strategy   = &sysctl_string,
 | |
| +	  .data		= "N/A",
 | |
| +	  .maxlen   = 1,
 | |
| +	  .extra2	= (void *)ATH_CARD_NAME,
 | |
| +	},
 | |
| +	{ .ctl_name	= CTL_AUTO,
 | |
|  	  .procname	= "slottime",
 | |
|  	  .mode		= 0644,
 | |
|  	  .proc_handler	= ath_sysctl_halparam,
 | |
| --- a/ath/if_athvar.h
 | |
| +++ b/ath/if_athvar.h
 | |
| @@ -168,12 +168,16 @@ static inline struct net_device *_alloc_
 | |
|  	  void __user *buffer, size_t *lenp)
 | |
|  #define	ATH_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer, lenp, ppos) \
 | |
|  	proc_dointvec(ctl, write, filp, buffer, lenp)
 | |
| +#define	ATH_SYSCTL_PROC_DOSTRING(ctl, write, filp, buffer, lenp, ppos) \
 | |
| +	proc_dostring(ctl, write, filp, buffer, lenp)
 | |
|  #else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8) */
 | |
|  #define	ATH_SYSCTL_DECL(f, ctl, write, filp, buffer, lenp, ppos) \
 | |
|  	f(ctl_table *ctl, int write, struct file *filp, \
 | |
|  	  void __user *buffer, size_t *lenp, loff_t *ppos)
 | |
|  #define	ATH_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer, lenp, ppos) \
 | |
|  	proc_dointvec(ctl, write, filp, buffer, lenp, ppos)
 | |
| +#define	ATH_SYSCTL_PROC_DOSTRING(ctl, write, filp, buffer, lenp, ppos) \
 | |
| +	proc_dostring(ctl, write, filp, buffer, lenp, ppos)
 | |
|  #endif
 | |
|  
 | |
|  #define	ATH_TIMEOUT	1000
 | |
| @@ -469,6 +473,7 @@ struct ath_hal;
 | |
|  struct ath_desc;
 | |
|  struct ath_ratectrl;
 | |
|  struct ath_tx99;
 | |
| +struct ath_hw_detect;
 | |
|  struct proc_dir_entry;
 | |
|  
 | |
|  /*
 | |
| @@ -629,6 +634,7 @@ struct ath_softc {
 | |
|  	struct ath_ratectrl *sc_rc;		/* tx rate control support */
 | |
|  	struct ath_tx99 *sc_tx99; 		/* tx99 support */
 | |
|  	void (*sc_setdefantenna)(struct ath_softc *, u_int);
 | |
| +	const struct ath_hw_detect *sc_hwinfo;
 | |
|  
 | |
|  	unsigned int 	sc_invalid:1;		/* being detached */
 | |
|  	unsigned int	sc_mrretry:1;		/* multi-rate retry support */
 | |
| @@ -683,6 +689,7 @@ struct ath_softc {
 | |
|  	const HAL_RATE_TABLE *sc_quarter_rates;	/* quarter rate table */
 | |
|  	HAL_OPMODE sc_opmode;			/* current hal operating mode */
 | |
|  	enum ieee80211_phymode sc_curmode;	/* current phy mode */
 | |
| +	u_int sc_poweroffset;			/* hardware power offset */
 | |
|  	u_int16_t sc_curtxpow;			/* current tx power limit */
 | |
|  	u_int16_t sc_curaid;			/* current association id */
 | |
|  	HAL_CHANNEL sc_curchan;			/* current h/w channel */
 | |
| @@ -929,4 +936,16 @@ int ar_device(int devid);
 | |
|  
 | |
|  void ath_radar_detected(struct ath_softc *sc, const char* message);
 | |
|  
 | |
| +struct ath_hw_detect {
 | |
| +	const char *vendor_name;
 | |
| +	const char *card_name;
 | |
| +	u32 vendor;
 | |
| +	u32 id;
 | |
| +	u32 subvendor;
 | |
| +	u32 subid;
 | |
| +	u32 poweroffset;
 | |
| +};
 | |
| +
 | |
| +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);
 | |
| +
 | |
|  #endif /* _DEV_ATH_ATHVAR_H */
 | |
| --- a/ath/if_ath_ahb.c
 | |
| +++ b/ath/if_ath_ahb.c
 | |
| @@ -20,6 +20,7 @@
 | |
|  #include <linux/netdevice.h>
 | |
|  #include <linux/cache.h>
 | |
|  #include <linux/platform_device.h>
 | |
| +#include <linux/pci.h>
 | |
|  
 | |
|  #include <asm/io.h>
 | |
|  #include <asm/uaccess.h>
 | |
| @@ -181,12 +182,32 @@ exit_ath_wmac(u_int16_t wlanNum, struct 
 | |
|  	return 0;
 | |
|  }
 | |
|  
 | |
| +static const char ubnt[] = "Ubiquiti Networks";
 | |
| +/* { vendorname, cardname, vendorid, cardid, subsys vendorid, subsys id, poweroffset } */
 | |
| +static const struct ath_hw_detect cards[] = {
 | |
| +	{ ubnt, "PowerStation2 (18V)", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xb102 },
 | |
| +	{ ubnt, "PowerStation2 (16D)", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xb202 },
 | |
| +	{ ubnt, "PowerStation2 (EXT)", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xb302 },
 | |
| +	{ ubnt, "PowerStation5 (22V)", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xb105 },
 | |
| +	{ ubnt, "PowerStation5 (EXT)", PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xb305 },
 | |
| +	{ ubnt, "WispStation5",        PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xa105 },
 | |
| +	{ ubnt, "LiteStation2",        PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xa002 },
 | |
| +	{ ubnt, "LiteStation5",        PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xa005 },
 | |
| +	{ ubnt, "NanoStation2",        PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xc002 },
 | |
| +	{ ubnt, "NanoStation5",        PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xc005 },
 | |
| +	{ ubnt, "NanoStation Loco2",   PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xc102 },
 | |
| +	{ ubnt, "NanoStation Loco5",   PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xc105 },
 | |
| +	{ ubnt, "Bullet2",             PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xc202 },
 | |
| +	{ ubnt, "Bullet5",             PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0xc205 },
 | |
| +};
 | |
| +
 | |
|  static int
 | |
|  init_ath_wmac(u_int16_t devid, u_int16_t wlanNum, struct ar531x_config *config)
 | |
|  {
 | |
|  	const char *athname;
 | |
|  	struct net_device *dev;
 | |
|  	struct ath_ahb_softc *sc;
 | |
| +	u16 *radio_data;
 | |
|  
 | |
|  	if (((wlanNum != 0) && (wlanNum != 1)) ||
 | |
|  		(sclist[wlanNum] != NULL))
 | |
| @@ -248,6 +269,16 @@ init_ath_wmac(u_int16_t devid, u_int16_t
 | |
|  	sc->aps_sc.sc_softled = 1; /* SoftLED over GPIO */
 | |
|  	sc->aps_sc.sc_ledpin = config->board->sysLedGpio;
 | |
|  	sc->aps_sc.sc_invalid = 0;
 | |
| +	radio_data = (u16 *) config->radio;
 | |
| +	if (radio_data) {
 | |
| +		u16 vendor, id, subvendor, subid;
 | |
| +		vendor = radio_data[1];
 | |
| +		id = radio_data[0];
 | |
| +		subvendor = radio_data[8];
 | |
| +		subid = radio_data[7];
 | |
| +		ath_hw_detect(&sc->aps_sc, cards, ARRAY_SIZE(cards), vendor, id, subvendor, subid);
 | |
| +	}
 | |
| +
 | |
|  	return 0;
 | |
|  
 | |
|   bad4:
 | |
| --- a/ath/if_ath_pci.c
 | |
| +++ b/ath/if_ath_pci.c
 | |
| @@ -123,6 +123,33 @@ static u16 ath_devidmap[][2] = {
 | |
|  	{ 0xff1a, 0x001a }
 | |
|  };
 | |
|  
 | |
| +static const char ubnt[] = "Ubiquiti Networks";
 | |
| +/* { vendorname, cardname, vendorid, cardid, subsys vendorid, subsys id, poweroffset } */
 | |
| +static const struct ath_hw_detect cards[] = {
 | |
| +	{ ubnt, "XR2",     0x168c, 0x001b, 0x0777, 0x3002, 10 },
 | |
| +	{ ubnt, "XR2",     0x168c, 0x001b, 0x7777, 0x3002, 10 },
 | |
| +	{ ubnt, "XR2.3",   0x168c, 0x001b, 0x0777, 0x3b02, 10 },
 | |
| +	{ ubnt, "XR2.6",   0x168c, 0x001b, 0x0777, 0x3c02, 10 },
 | |
| +	{ ubnt, "XR3-2.8", 0x168c, 0x001b, 0x0777, 0x3b03, 10 },
 | |
| +	{ ubnt, "XR3-3.6", 0x168c, 0x001b, 0x0777, 0x3c03, 10 },
 | |
| +	{ ubnt, "XR3",     0x168c, 0x001b, 0x0777, 0x3003, 10 },
 | |
| +	{ ubnt, "XR4",     0x168c, 0x001b, 0x0777, 0x3004, 10 },
 | |
| +	{ ubnt, "XR5",     0x168c, 0x001b, 0x0777, 0x3005, 10 },
 | |
| +	{ ubnt, "XR5",     0x168c, 0x001b, 0x7777, 0x3005, 10 },
 | |
| +	{ ubnt, "XR7",     0x168c, 0x001b, 0x0777, 0x3007, 10 },
 | |
| +	{ ubnt, "XR9",     0x168c, 0x001b, 0x0777, 0x3009, 10 },
 | |
| +	{ ubnt, "SRC",     0x168c, 0x0013, 0x168c, 0x1042, 1 },
 | |
| +	{ ubnt, "SR2",     0x168c, 0x0013, 0x0777, 0x2041, 10 },
 | |
| +	{ ubnt, "SR4",     0x168c, 0x0013, 0x0777, 0x2004, 6 },
 | |
| +	{ ubnt, "SR4",     0x168c, 0x0013, 0x7777, 0x2004, 6 },
 | |
| +	{ ubnt, "SR4C",    0x168c, 0x0013, 0x0777, 0x1004, 6 },
 | |
| +	{ ubnt, "SR4C",    0x168c, 0x0013, 0x7777, 0x1004, 6 },
 | |
| +	{ ubnt, "SR5",     0x168c, 0x0013, 0x168c, 0x2042, 7 },
 | |
| +	{ ubnt, "SR9",     0x168c, 0x0013, 0x7777, 0x2009, 12 },
 | |
| +	{ ubnt, "SR71A",   0x168c, 0x0027, 0x168c, 0x2082, 10 },
 | |
| +	{ ubnt, "SR71",    0x168c, 0x0027, 0x0777, 0x4082, 10 },
 | |
| +};
 | |
| +
 | |
|  static int
 | |
|  ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 | |
|  {
 | |
| @@ -257,6 +284,10 @@ ath_pci_probe(struct pci_dev *pdev, cons
 | |
|  	printk(KERN_INFO "%s: %s: %s: mem=0x%lx, irq=%d\n",
 | |
|  		dev_info, dev->name, athname ? athname : "Atheros ???", phymem, dev->irq);
 | |
|  
 | |
| +	ath_hw_detect(&sc->aps_sc, cards, ARRAY_SIZE(cards),
 | |
| +		pdev->vendor, pdev->device,
 | |
| +		pdev->subsystem_vendor, pdev->subsystem_device);
 | |
| +
 | |
|  	/* ready to process interrupts */
 | |
|  	sc->aps_sc.sc_invalid = 0;
 | |
|  
 |