[OpenWrt-Devel] [PATCH RFC] Add support for Ubiquiti Unifi Outdoor Plus

Kirill Berezin kyb22 at rol.ru
Mon Jun 8 03:42:53 EDT 2015


Hi Stefan,

I have a couple of suggestions.

First of all I think it will be better to initialize static variables in 
hsr_tune with zeroes :

 > ++static void hsr_tune(struct ath_hw* ah, int bw, int fq) {
 > ++	static int initialized = 0;
 > ++	static int last_bw = 0, last_fq = 0;

And I have an updated versions of write functions. I added to 
hsr_write_byte debug messages that can be activated by atheros CONFIG 
flag (of course atheros debugging must be compiled in). Also I 
simplified loops in hsr_write_a_chain because it seems that they are 
needed to get data from a some sort of output buffer which includes less 
than 6 bytes.

static u32 hsr_write_byte(struct ath_hw* ah, int delay, u32 value){
  	int i;
  	u32 rval = 0;
  	struct ath_common *common = ath9k_hw_common(ah);

  	udelay(delay);

  	ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0);
  	udelay(HSR_DELAY_HALF_TICK);

  	ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 0);
  	udelay(HSR_DELAY_HALF_TICK);

  	for( i = 0; i < 8; ++i) {
  		rval = rval << 1;

  		// pattern is left to right, that is 7-th bit runs first
  		ath9k_hw_set_gpio(ah, HSR_GPIO_DOUT, (value >> (7 - i)) & 0x1);
  		udelay(HSR_DELAY_HALF_TICK);

  		ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 1);
  		udelay(HSR_DELAY_HALF_TICK);

  		rval |= ath9k_hw_gpio_get(ah, HSR_GPIO_DIN);

  		ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0);
  		udelay(HSR_DELAY_HALF_TICK);
  	}

  	ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 1);
  	udelay(HSR_DELAY_HALF_TICK);

  	ath_dbg(common, CONFIG, "hsr_write_byte: write byte %d return value 
is %d %c \n", value, rval, rval > 32 ? rval : '-');

  	return rval & 0xff;
  }


static int hsr_write_a_chain(struct ath_hw* ah, char* chain, int items) {
  	int i = 0;
  	int status = 0;
  	
  	hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);

  	status = hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);
  	// clear HSR's reply buffer
  	if ( status) {
      int loop = 0;
      for ( loop = 0; (loop < 42) && status; ++loop) {
    		status = hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);
      }
      if ( loop >= 42) {
       printk(KERN_WARNING "hsr_write_a_chain: can't clear an output 
buffer after a 42 cycles.\n");
       return 0;
      }
     }
    // data
    for ( i =0; (i < items) && ( 0 != chain[i]); ++i) {
  		hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, (u32)chain[i]);
    }
  	
  	hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);
  	udelay(HSR_DELAY_FINAL);

  	// reply
  	memset(chain, 0, items);

  	hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);
  	udelay(HSR_DELAY_TRAILING);

  	for ( i = 0; i < (items - 1); ++i) {
  		u32 ret;
  		if ( 0 != (ret = hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0))) {
  			chain[i] = (char)ret;
  		} else {
  			break;
  		}
  		udelay(HSR_DELAY_TRAILING);
  	}

  	return (1 < i) ? simple_strtol(chain + 1, NULL, 10) : 0;
}

 > I also tried to change target/linux/ar71xx/generic/profiles/ubnt.mk and
 > target/linux/ar71xx/image/Makefile to include this module into the
 > UBNTUNIFIOUTDOORPLUS image, but this fails. Any idea why?

May be this happens when building a bunch of different profiles at once?


Kirill.

On 06/06/2015 04:28 PM, Stefan Rompf wrote:
> Hi,
>
> please review my patch to add support for the Ubiquiti Unifi Outdoor Plus
> access point based on the work of Kirill Berezin and me.
>
> The access point has a configurable RF filter in the receive path that must be
> tuned according to the selected Wifi channel.
>
> A patch to compat_wireless adds support to register a callback to the ath9k
> driver that is called whenever the channel changes. It also adds hsr.c, the
> channel change helper that tunes the filter connected to the AR9287 GPIO pins.
> I'm running this part successfully on top of the Chaos Calmer RC1 image.
>
> A new configuration option to create the kmod-ath-hsr. It contains the driver
> .ko and must be installed on the access point. This is compile tested on
> trunk.
>
> I also tried to change target/linux/ar71xx/generic/profiles/ubnt.mk and
> target/linux/ar71xx/image/Makefile to include this module into the
> UBNTUNIFIOUTDOORPLUS image, but this fails. Any idea why?
>
> Comments?
>
> Stefan
>
> Index: package/kernel/mac80211/Makefile
> ===================================================================
> --- package/kernel/mac80211/Makefile	(Revision 45907)
> +++ package/kernel/mac80211/Makefile	(Arbeitskopie)
> @@ -27,7 +27,7 @@
>   	rt2x00-lib rt2x00-pci rt2x00-usb rt2800-lib rt2400-pci rt2500-pci \
>   	rt2500-usb rt61-pci rt73-usb rt2800-mmio rt2800-pci rt2800-usb rt2800-soc \
>   	rtl8180 rtl8187 zd1211rw mac80211-hwsim carl9170 b43 b43legacy \
> -	ath9k-common ath9k ath9k-htc ath10k ath net-libipw net-ipw2100 net-ipw2200 \
> +	ath9k-common ath9k ath9k-htc ath9k-hsr ath10k ath net-libipw net-ipw2100 net-ipw2200 \
>   	mwl8k mwifiex-pcie net-hermes net-hermes-pci net-hermes-plx net-hermes-pcmcia \
>   	iwl-legacy iwl3945 iwl4965 iwlagn wlcore wl12xx wl18xx lib80211 \
>   	rtlwifi rtlwifi-pci rtlwifi-usb rtl8192c-common rtl8192ce rtl8192se \
> @@ -589,6 +589,22 @@
>   	
>   endef
>
> +define KernelPackage/ath9k-hsr
> +  $(call KernelPackage/mac80211/Default)
> +  TITLE:=Driver for the Ubiquiti UniFi Outdoor Plus HSR filter
> +  URL:=http://wiki.openwrt.org/toh/ubiquiti/unifi_outdoorplus
> +  DEPENDS+= @PCI_SUPPORT||TARGET_ar71xx +kmod-ath9k
> +  FILES:= \
> +	$(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath9k/ath9k_hsr.ko
> +  AUTOLOAD:=$(call AutoProbe,ath9k_hsr)
> +endef
> +
> +define KernelPackage/ath9k-hsr/description
> +This modules adds support for the 'High-Selectivity Receiver'
> +RF filter in the receive path of the access point. It is
> +required for this and only for this access point.
> +endef
> +
>   define KernelPackage/ath9k-htc
>     $(call KernelPackage/mac80211/Default)
>     TITLE:=Atheros 802.11n USB device support
> @@ -1559,6 +1575,8 @@
>   config-$(CONFIG_ATH_USER_REGD) += ATH_USER_REGD
>   config-$(CONFIG_ATH9K_SUPPORT_PCOEM) += ATH9K_PCOEM
>
> +config-$(call config_package,ath9k-hsr) += ATH9K_HSR
> +
>   config-$(call config_package,ath9k-htc) += ATH9K_HTC
>   config-$(call config_package,ath10k) += ATH10K ATH10K_PCI
>
> @@ -2055,6 +2073,7 @@
>   $(eval $(call KernelPackage,mac80211-hwsim))
>   $(eval $(call KernelPackage,ath9k-common))
>   $(eval $(call KernelPackage,ath9k))
> +$(eval $(call KernelPackage,ath9k-hsr))
>   $(eval $(call KernelPackage,ath9k-htc))
>   $(eval $(call KernelPackage,ath10k))
>   $(eval $(call KernelPackage,ath))
> Index: package/kernel/mac80211/patches/930-ubnt-uap-plus-hsr.patch
> ===================================================================
> --- package/kernel/mac80211/patches/930-ubnt-uap-plus-hsr.patch	(Revision 0)
> +++ package/kernel/mac80211/patches/930-ubnt-uap-plus-hsr.patch	(Arbeitskopie)
> @@ -0,0 +1,346 @@
> +diff -X diffign -Npur kernel/drivers/net/wireless/ath/ath9k.orig/ath9k.h kernel/drivers/net/wireless/ath/ath9k/ath9k.h
> +--- kernel/drivers/net/wireless/ath/ath9k.orig/ath9k.h	2015-06-04 21:19:11.000000000 +0200
> ++++ kernel/drivers/net/wireless/ath/ath9k/ath9k.h	2015-06-06 10:23:05.000000000 +0200
> +@@ -1110,4 +1110,10 @@ static inline int ath_ahb_init(void) { r
> + static inline void ath_ahb_exit(void) {};
> + #endif
> +
> ++/*
> ++ * OpenWrt UBNT HSR filter support
> ++ */
> ++typedef void (set_channel_helper_fn)(struct ath_hw* ah, int bw, int fq);
> ++void ath9k_register_set_channel_helper(set_channel_helper_fn *);
> ++
> + #endif /* ATH9K_H */
> +diff -X diffign -Npur kernel/drivers/net/wireless/ath/ath9k.orig/channel.c kernel/drivers/net/wireless/ath/ath9k/channel.c
> +--- kernel/drivers/net/wireless/ath/ath9k.orig/channel.c	2015-03-10 04:37:15.000000000 +0100
> ++++ kernel/drivers/net/wireless/ath/ath9k/channel.c	2015-06-06 10:23:05.000000000 +0200
> +@@ -16,6 +16,18 @@
> +
> + #include "ath9k.h"
> +
> ++/*
> ++ * OpenWrt UBNT HSR filter support
> ++ */
> ++static set_channel_helper_fn *ath9k_set_channel_helper;
> ++
> ++void ath9k_register_set_channel_helper(set_channel_helper_fn *chanfn)
> ++{
> ++	ath9k_set_channel_helper = chanfn;
> ++}
> ++EXPORT_SYMBOL(ath9k_register_set_channel_helper);
> ++
> ++
> + /* Set/change channels.  If the channel is really being changed, it's done
> +  * by reseting the chip.  To accomplish this we must first cleanup any pending
> +  * DMA, then restart stuff.
> +@@ -41,6 +53,9 @@ static int ath_set_channel(struct ath_so
> + 	ath_dbg(common, CONFIG, "Set channel: %d MHz width: %d\n",
> + 		chan->center_freq, chandef->width);
> +
> ++	if (ath9k_set_channel_helper)
> ++		ath9k_set_channel_helper(ah, chandef->width, chan->center_freq);
> ++
> + 	/* update survey stats for the old channel before switching */
> + 	spin_lock_bh(&common->cc_lock);
> + 	ath_update_survey_stats(sc);
> +diff -X diffign -Npur kernel/drivers/net/wireless/ath/ath9k.orig/hsr.c kernel/drivers/net/wireless/ath/ath9k/hsr.c
> +--- kernel/drivers/net/wireless/ath/ath9k.orig/hsr.c	1970-01-01 01:00:00.000000000 +0100
> ++++ kernel/drivers/net/wireless/ath/ath9k/hsr.c	2015-06-06 10:48:46.000000000 +0200
> +@@ -0,0 +1,282 @@
> ++/*
> ++ *
> ++ * The MIT License (MIT)
> ++ *
> ++ * Copyright (c) 2015 Kirill Berezin
> ++ *
> ++ * Permission is hereby granted, free of charge, to any person obtaining a copy
> ++ * of this software and associated documentation files (the "Software"), to deal
> ++ * in the Software without restriction, including without limitation the rights
> ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> ++ * copies of the Software, and to permit persons to whom the Software is
> ++ * furnished to do so, subject to the following conditions:
> ++ *
> ++ * The above copyright notice and this permission notice shall be included in all
> ++ * copies or substantial portions of the Software.
> ++ *
> ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> ++ * SOFTWARE.
> ++ *
> ++ */
> ++
> ++#include <linux/io.h>
> ++#include <linux/slab.h>
> ++#include <linux/module.h>
> ++#include <linux/time.h>
> ++#include <linux/bitops.h>
> ++#include <linux/etherdevice.h>
> ++#include <linux/rtnetlink.h>
> ++#include <asm/unaligned.h>
> ++
> ++#include "hw.h"
> ++#include "hw-ops.h"
> ++#include "ar9003_mac.h"
> ++#include "ar9003_mci.h"
> ++#include "ar9003_phy.h"
> ++#include "ath9k.h"
> ++
> ++#define HSR_GPIO_CSN 8
> ++#define HSR_GPIO_CLK 6
> ++#define HSR_GPIO_DOUT 7
> ++#define HSR_GPIO_DIN 5
> ++
> ++/* delays are in useconds */
> ++#define HSR_DELAY_HALF_TICK 100
> ++#define HSR_DELAY_PRE_WRITE 75
> ++#define HSR_DELAY_FINAL 20000
> ++#define HSR_DELAY_TRAILING 200
> ++
> ++static void hsr_init(struct ath_hw* ah);
> ++static int hsr_disable(struct ath_hw* ah);
> ++static int hsr_enable(struct ath_hw* ah, int bw, int fq);
> ++static int hsr_status(struct ath_hw* ah);
> ++
> ++static void hsr_init(struct ath_hw* ah) {
> ++	ath9k_hw_cfg_gpio_input(ah, HSR_GPIO_DIN);
> ++	ath9k_hw_cfg_output(ah, HSR_GPIO_CSN, AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
> ++	ath9k_hw_cfg_output(ah, HSR_GPIO_CLK, AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
> ++	ath9k_hw_cfg_output(ah, HSR_GPIO_DOUT, AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
> ++
> ++	ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 1);
> ++	ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0);
> ++	ath9k_hw_set_gpio(ah, HSR_GPIO_DOUT, 0);
> ++
> ++	udelay(HSR_DELAY_TRAILING);
> ++
> ++	printk(KERN_NOTICE "hsr_init: done");
> ++}
> ++
> ++static u32 hsr_write_byte(struct ath_hw* ah, int delay, u32 value){
> ++	int i;
> ++	u32 rval = 0;
> ++
> ++	udelay(delay);
> ++
> ++	ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0);
> ++	udelay(HSR_DELAY_HALF_TICK);
> ++
> ++	ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 0);
> ++	udelay(HSR_DELAY_HALF_TICK);
> ++
> ++	for( i = 0; i < 8; ++i) {
> ++		rval = rval << 1;
> ++
> ++		// pattern is left to right, that is 7-th bit runs first
> ++		ath9k_hw_set_gpio(ah, HSR_GPIO_DOUT, (value >> (7 - i)) & 0x1);
> ++		udelay(HSR_DELAY_HALF_TICK);
> ++
> ++		ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 1);
> ++		udelay(HSR_DELAY_HALF_TICK);
> ++
> ++		rval |= ath9k_hw_gpio_get(ah, HSR_GPIO_DIN);
> ++
> ++		ath9k_hw_set_gpio(ah, HSR_GPIO_CLK, 0);
> ++		udelay(HSR_DELAY_HALF_TICK);
> ++	}
> ++
> ++	ath9k_hw_set_gpio(ah, HSR_GPIO_CSN, 1);
> ++	udelay(HSR_DELAY_HALF_TICK);
> ++
> ++	/* printk(KERN_NOTICE "hsr_write_byte: write byte %d return value is %x %d %c \n", value, rval, rval, rval > 32 ? rval : '-'); */
> ++
> ++	return rval & 0xff;
> ++}
> ++
> ++static int hsr_write_a_chain(struct ath_hw* ah, char* chain, int items) {
> ++	int i = 0, j;
> ++	int status = 0;
> ++
> ++	// a preamble
> ++	hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);
> ++	status = hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);
> ++
> ++	// Continue preamble if hsr returns non zero (perhaps a stray command result)
> ++	if (status) {
> ++		int loop = 2;
> ++		do {
> ++			++loop;
> ++			if (loop > 42) {
> ++				printk(KERN_NOTICE "hsr_write_a_chain: too many loops in preamble. giving up.\n");
> ++				return -1;
> ++			}
> ++			status = hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);
> ++		} while(status);
> ++	}
> ++
> ++        for ( i =0; (i < items) && ( 0 != chain[i]); ++i) {
> ++		hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, (u32)chain[i]);
> ++	}
> ++	hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0);
> ++	mdelay(HSR_DELAY_FINAL / 1000);
> ++
> ++	memset(chain, 0, items);
> ++
> ++	for ( j = 0, i = 0; (i < 7) && (j < (items - 1)) ; ++i) {
> ++		u32 ret;
> ++		if ( 31 < (ret = hsr_write_byte(ah, HSR_DELAY_PRE_WRITE, 0))) {
> ++			chain[j] = (char)ret;
> ++			++ j;
> ++		}
> ++		udelay(HSR_DELAY_TRAILING);
> ++	}
> ++	/* printk(KERN_NOTICE "hsr_write_a_chain: j %d \n", j); */
> ++	return j > 1 ? simple_strtol(chain + 1, NULL, 10) : 0;
> ++}
> ++
> ++static int hsr_disable(struct ath_hw* ah) {
> ++	char cmd[10] = {'b', '4', '0', 0, 0, 0, 0, 0, 0, 0};
> ++	int  ret;
> ++
> ++	ret = hsr_write_a_chain(ah, cmd, sizeof(cmd));
> ++	/* printk(KERN_NOTICE "hsr_disable: return %d \n", ret); */
> ++	if ( (ret > 0) && (*cmd == 'B')) {
> ++		printk(KERN_NOTICE "hsr_disable: bandwidth set %d \n", ret);
> ++		return 0;
> ++	}
> ++
> ++	return -1;
> ++}
> ++
> ++static int hsr_enable(struct ath_hw* ah, int bw, int fq) {
> ++	char cmd[10];
> ++	int ret;
> ++
> ++	memset(cmd, 0, sizeof(cmd));
> ++	*cmd = 'b'; // 98
> ++	snprintf(cmd + 1, 3, "%02d", bw);
> ++
> ++	ret = hsr_write_a_chain(ah, cmd, sizeof(cmd));
> ++	if ( (*cmd != 'B') || (ret != bw)) {
> ++		printk(KERN_NOTICE "hsr_enable: failed changing bandwidth -> set (%d,%d) reply (%d, %d) \n", 'b', bw, *cmd, ret);
> ++		return -1;
> ++	}
> ++
> ++	memset(cmd, 0, sizeof(cmd));
> ++	*cmd = 'x'; // 120
> ++	ret = hsr_write_a_chain(ah, cmd, sizeof(cmd));
> ++	if ( *cmd != 'X') {
> ++		printk(KERN_NOTICE "hsr_enable: failed 'x' command -> reply (%d, %d) \n", *cmd, ret);
> ++		return -1;
> ++	}
> ++
> ++	memset(cmd, 0, sizeof(cmd));
> ++	*cmd = 'm'; // 109
> ++	ret = hsr_write_a_chain(ah, cmd, sizeof(cmd));
> ++	if ( *cmd != 'M') {
> ++		printk(KERN_NOTICE "hsr_enable: failed 'm' command -> reply (%d, %d) \n", *cmd, ret);
> ++		return  -1;
> ++	}
> ++
> ++	memset(cmd, 0, sizeof(cmd));
> ++	*cmd = 'f'; // 102
> ++	snprintf(cmd + 1, 6, "%05d", fq);
> ++	ret = hsr_write_a_chain(ah, cmd, sizeof(cmd));
> ++	if ( (*cmd != 'F') && (ret != fq)) {
> ++		printk(KERN_NOTICE "hsr_enable: failed set frequency -> reply (%d, %d) \n", *cmd, ret);
> ++		return -1;
> ++	}
> ++
> ++	printk(KERN_NOTICE "hsr_enable: center frequency %dMHz bandwidth %dMHz \n", fq, bw);
> ++
> ++	return 0;
> ++}
> ++
> ++static int hsr_status(struct ath_hw* ah) {
> ++	char cmd[10] = {'s', 0, 0, 0, 0, 0, 0, 0, 0, 0}; // 115
> ++	int ret;
> ++
> ++	ret = hsr_write_a_chain(ah, cmd, sizeof(cmd));
> ++	if ( (*cmd != 'S')) {
> ++		printk(KERN_NOTICE "hsr_status: returned %d,%d \n", *cmd, ret);
> ++		return -1;
> ++	}
> ++
> ++	printk(KERN_NOTICE "hsr_status: current status is %d \n", ret);
> ++
> ++	return 0;
> ++}
> ++
> ++static void hsr_tune(struct ath_hw* ah, int bw, int fq) {
> ++	static int initialized;
> ++	static int last_bw, last_fq;
> ++
> ++	if (NULL == ah) {
> ++		return;
> ++	}
> ++
> ++	/* Bandwidth argument is 0 sometimes. Assume default 802.11bgn
> ++	   20MHz on invalid values */
> ++	if ( (bw != 5) && (bw != 10) && (bw != 20) && (bw != 40)) {
> ++		bw = 20;
> ++	}
> ++
> ++	if (bw == last_bw && fq == last_fq) {
> ++		/* Avoid tuning if nothing changes */
> ++		printk(KERN_NOTICE "hsr_tune: already tuned to center frequency %dMHz bandwidth %dMHz\n", fq, bw);
> ++		return;
> ++	}
> ++
> ++	if (!initialized) {
> ++		initialized = 1;
> ++		hsr_init(ah);
> ++	}
> ++
> ++	if (!hsr_enable(ah, bw, fq)) {
> ++		hsr_status(ah);
> ++		last_bw = bw;
> ++		last_fq = fq;
> ++	} else {
> ++		/* Tuning failed - make sure that we try again */
> ++		last_bw = -1;
> ++	}
> ++}
> ++
> ++
> ++static int __init hsr_mod_init(void)
> ++{
> ++	rtnl_lock(); /* Should lock against nl80211_set_channel() */
> ++	ath9k_register_set_channel_helper(hsr_tune);
> ++	rtnl_unlock();
> ++	return 0;
> ++}
> ++
> ++static void __exit hsr_mod_exit(void)
> ++{
> ++	rtnl_lock();
> ++	ath9k_register_set_channel_helper(NULL);
> ++	rtnl_unlock();
> ++}
> ++
> ++module_init(hsr_mod_init);
> ++module_exit(hsr_mod_exit);
> ++
> ++MODULE_AUTHOR("Kirill Berezin, Stefan Rompf");
> ++MODULE_DESCRIPTION("Support for Ubiquiti Outdoor Plus HSR filter.");
> ++MODULE_SUPPORTED_DEVICE("Ubiquiti Outdoor Plus");
> ++MODULE_LICENSE("Dual MIT/GPL");
> ++
> +diff -X diffign -Npur kernel/drivers/net/wireless/ath/ath9k.orig/Makefile kernel/drivers/net/wireless/ath/ath9k/Makefile
> +--- kernel/drivers/net/wireless/ath/ath9k.orig/Makefile	2015-03-10 04:37:16.000000000 +0100
> ++++ kernel/drivers/net/wireless/ath/ath9k/Makefile	2015-06-06 10:23:05.000000000 +0200
> +@@ -22,6 +22,10 @@ ath9k-$(CPTCFG_ATH9K_STATION_STATISTICS)
> +
> + obj-$(CPTCFG_ATH9K) += ath9k.o
> +
> ++ath9k_hsr-y :=	hsr.o
> ++
> ++obj-$(CPTCFG_ATH9K) += ath9k_hsr.o
> ++
> + ath9k_hw-y:=	\
> + 		ar9002_hw.o \
> + 		ar9003_hw.o \
> Index: target/linux/ar71xx/generic/profiles/ubnt.mk
> ===================================================================
> --- target/linux/ar71xx/generic/profiles/ubnt.mk	(Revision 45907)
> +++ target/linux/ar71xx/generic/profiles/ubnt.mk	(Arbeitskopie)
> @@ -49,6 +49,17 @@
>
>   $(eval $(call Profile,UBNTUNIFIOUTDOOR))
>
> +define Profile/UBNTUNIFIOUTDOORPLUS
> +	NAME:=Ubiquiti UniFiAP Outdoor Plus
> +	PACKAGES:=kmod-ath9k-hsr
> +endef
> +
> +define Profile/UBNTUNIFIOUTDOORPLUS/Description
> +	Package set optimized for the Ubiquiti UniFiAP Outdoor Plus.
> +endef
> +
> +$(eval $(call Profile,UBNTUNIFIOUTDOORPLUS))
> +
>   define Profile/UAPPRO
>   	NAME:=Ubiquiti UniFi AP Pro
>   	PACKAGES:=
> Index: target/linux/ar71xx/image/Makefile
> ===================================================================
> --- target/linux/ar71xx/image/Makefile	(Revision 45907)
> +++ target/linux/ar71xx/image/Makefile	(Arbeitskopie)
> @@ -1975,7 +1975,7 @@
>   $(eval $(call MultiProfile,TLWR1043,TLWR1043V1 TLWR1043V2))
>   $(eval $(call MultiProfile,TLWDR4300,TLWDR3500V1 TLWDR3600V1 TLWDR4300V1 TLWDR4300V1IL TLWDR4310V1 MW4530RV1))
>   $(eval $(call MultiProfile,TUBE2H,TUBE2H8M TUBE2H16M))
> -$(eval $(call MultiProfile,UBNT,UBNTAIRROUTER UBNTRS UBNTRSPRO UBNTLSSR71 UBNTBULLETM UBNTROCKETM UBNTROCKETMXW UBNTNANOM UBNTNANOMXW UBNTLOCOXW UBNTUNIFI
> UBNTUNIFIOUTDOOR UBNTUNIFIOUTDOORPLUS UAPPRO UBNTAIRGW))
> +$(eval $(call MultiProfile,UBNT,UBNTAIRROUTER UBNTRS UBNTRSPRO UBNTLSSR71 UBNTBULLETM UBNTROCKETM UBNTROCKETMXW UBNTNANOM UBNTNANOMXW UBNTLOCOXW UBNTUNIFI
> UBNTUNIFIOUTDOOR UAPPRO UBNTAIRGW))
>   $(eval $(call MultiProfile,WNR612V2,REALWNR612V2 N150R))
>   $(eval $(call MultiProfile,WNR1000V2,REALWNR1000V2 WNR1000V2_VC))
>   $(eval $(call MultiProfile,WP543,WP543_2M WP543_4M WP543_8M WP543_16M))
>
_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel



More information about the openwrt-devel mailing list