summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWaldemar Brodkorb <wbrodkorb@conet.de>2014-12-07 05:00:48 +0100
committerWaldemar Brodkorb <wbrodkorb@conet.de>2014-12-07 05:00:48 +0100
commit444d0ea061cabd9851ba0e144a94a10271ca6c79 (patch)
tree515486402bd57f764af8fc97a86b59e94634bb2d
parent36d63c60dbe2d074dff81a6af7dd77b62b5f23dc (diff)
parent4c9ab0d218fbf8f29ce4250f2b9941e6feae0651 (diff)
Merge branch 'master' of git+ssh://openadk.org/git/openadk
-rw-r--r--mk/kernel-ver.mk6
-rw-r--r--mk/vars.mk3
-rw-r--r--package/curl/Makefile4
-rw-r--r--package/ffmpeg/Makefile4
-rw-r--r--package/gnutls/Makefile4
-rw-r--r--package/kmod/Makefile4
-rw-r--r--package/kodi/Makefile14
-rw-r--r--package/kodi/patches/patch-tools_Linux_xbmc_sh_in59
-rw-r--r--package/kodi/patches/patch-xbmc_Application_cpp41
-rw-r--r--package/libcec/Makefile12
-rw-r--r--package/libcec/patches/imx6.patch3051
-rw-r--r--package/libcec/patches/patch-src_lib_adapter_RPi_RPiCECAdapterCommunication_cpp12
-rw-r--r--package/libcec/patches/patch-src_lib_libcec_pc_in4
-rw-r--r--package/libcec/patches/patch-src_lib_platform_posix_serialport_cpp11
-rw-r--r--package/libpng/patches/libpng-1.6.14-apng.patch1701
-rw-r--r--package/mesalib/Makefile4
-rw-r--r--package/nginx/Makefile4
-rw-r--r--package/pciutils/Makefile4
-rw-r--r--package/php/Makefile4
-rw-r--r--package/stunnel/Makefile4
-rw-r--r--package/usbutils/Makefile9
-rw-r--r--target/arch.lst1
-rw-r--r--target/arm/kernel/linksys-nslu25
-rw-r--r--target/arm/raspberry-pi/patches/3.17.4/raspberry-pi.patch (renamed from target/arm/raspberry-pi/patches/3.16.6/raspberry-pi.patch)0
-rw-r--r--target/arm/solidrun-imx6/patches/3.17.4/rmk.patch (renamed from target/arm/solidrun-imx6/patches/3.16.6/rmk.patch)0
-rw-r--r--target/arm/systems/linksys-nslu211
-rw-r--r--target/c6x/Makefile9
-rw-r--r--target/c6x/systems/toolchain-c6x11
-rw-r--r--target/c6x/uclibc.config248
-rw-r--r--target/config/Config.in.cpu4
-rw-r--r--target/config/Config.in.endian.choice4
-rw-r--r--target/config/Config.in.kernel2
-rw-r--r--target/config/Config.in.kernelversion.choice8
-rw-r--r--target/config/Config.in.kernelversion.default4
-rw-r--r--target/config/Config.in.toolchain9
-rw-r--r--target/linux/patches/3.16.6/disable-netfilter.patch160
-rw-r--r--target/linux/patches/3.16.6/sparc-memset.patch50
-rw-r--r--target/linux/patches/3.17.4/bsd-compatibility.patch (renamed from target/linux/patches/3.16.6/bsd-compatibility.patch)0
-rw-r--r--target/linux/patches/3.17.4/cleankernel.patch (renamed from target/linux/patches/3.16.6/cleankernel.patch)0
-rw-r--r--target/linux/patches/3.17.4/cris-header.patch (renamed from target/linux/patches/3.16.6/cris-header.patch)0
-rw-r--r--target/linux/patches/3.17.4/defaults.patch (renamed from target/linux/patches/3.16.6/defaults.patch)0
-rw-r--r--target/linux/patches/3.17.4/export-symbol-for-exmap.patch (renamed from target/linux/patches/3.16.6/export-symbol-for-exmap.patch)0
-rw-r--r--target/linux/patches/3.17.4/gemalto.patch (renamed from target/linux/patches/3.16.6/gemalto.patch)0
-rw-r--r--target/linux/patches/3.17.4/initramfs-nosizelimit.patch (renamed from target/linux/patches/3.16.6/initramfs-nosizelimit.patch)0
-rw-r--r--target/linux/patches/3.17.4/lemote-rfkill.patch (renamed from target/linux/patches/3.16.6/lemote-rfkill.patch)0
-rw-r--r--target/linux/patches/3.17.4/microblaze-axi.patch (renamed from target/linux/patches/3.16.6/microblaze-axi.patch)0
-rw-r--r--target/linux/patches/3.17.4/microblaze-ethernet.patch (renamed from target/linux/patches/3.16.6/microblaze-ethernet.patch)0
-rw-r--r--target/linux/patches/3.17.4/mkpiggy.patch (renamed from target/linux/patches/3.16.6/mkpiggy.patch)0
-rw-r--r--target/linux/patches/3.17.4/mtd-rootfs.patch (renamed from target/linux/patches/3.16.6/mtd-rootfs.patch)0
-rw-r--r--target/linux/patches/3.17.4/nfsv3-tcp.patch (renamed from target/linux/patches/3.16.6/nfsv3-tcp.patch)0
-rw-r--r--target/linux/patches/3.17.4/non-static.patch (renamed from target/linux/patches/3.16.6/non-static.patch)0
-rw-r--r--target/linux/patches/3.17.4/patch-fblogo (renamed from target/linux/patches/3.16.6/patch-fblogo)0
-rw-r--r--target/linux/patches/3.17.4/patch-yaffs2 (renamed from target/linux/patches/3.16.6/patch-yaffs2)0
-rw-r--r--target/linux/patches/3.17.4/ppc64-missing-zlib.patch (renamed from target/linux/patches/3.16.6/ppc64-missing-zlib.patch)0
-rw-r--r--target/linux/patches/3.17.4/regmap-boolean.patch (renamed from target/linux/patches/3.16.6/regmap-boolean.patch)0
-rw-r--r--target/linux/patches/3.17.4/relocs.patch (renamed from target/linux/patches/3.16.6/relocs.patch)0
-rw-r--r--target/linux/patches/3.17.4/sgidefs.patch (renamed from target/linux/patches/3.16.6/sgidefs.patch)0
-rw-r--r--target/linux/patches/3.17.4/sortext.patch (renamed from target/linux/patches/3.16.6/sortext.patch)0
-rw-r--r--target/linux/patches/3.17.4/startup.patch (renamed from target/linux/patches/3.16.6/startup.patch)0
-rw-r--r--target/linux/patches/3.17.4/wlan-cf.patch (renamed from target/linux/patches/3.16.6/wlan-cf.patch)0
-rw-r--r--target/linux/patches/3.17.4/xargs.patch (renamed from target/linux/patches/3.16.6/xargs.patch)0
-rw-r--r--target/m68k/qemu-m68k/patches/3.16.6/m68k-coldfire-fec.patch145
-rw-r--r--target/m68k/qemu-m68k/patches/3.17.4/qemu-coldfire.patch (renamed from target/m68k/qemu-m68k/patches/3.16.6/qemu-coldfire.patch)0
-rw-r--r--target/mips/dragino-ms14s/patches/3.14.17/0001-mtd-add-rb4xx-nand-driver.patch351
-rw-r--r--target/mips/dragino-ms14s/patches/3.14.17/0002-phy-add-ethtool-ioctl-support-used-by-ag71xx-driver.patch80
-rw-r--r--target/mips/dragino-ms14s/patches/3.14.17/0003-net-add-ag71xx-mac-driver.patch4245
-rw-r--r--target/mips/dragino-ms14s/patches/3.14.17/0004-drivers-link-SPI-drivers-before-MTD-drivers.patch27
-rw-r--r--target/mips/dragino-ms14s/patches/3.14.17/0005-spi-add-various-flags-to-spi_transfer-and-spi_messag.patch34
-rw-r--r--target/mips/dragino-ms14s/patches/3.14.17/0006-spi-add-rb4xx-SPI-driver.patch557
-rw-r--r--target/mips/dragino-ms14s/patches/3.14.17/0007-spi-add-rb4xx-cpld-driver.patch548
-rw-r--r--target/mips/dragino-ms14s/patches/3.14.17/0008-gpio-add-GPIO-latch-driver.patch290
-rw-r--r--target/mips/dragino-ms14s/patches/3.14.17/0009-spi-export-spi_bitbang_bufs-function.patch45
-rw-r--r--target/mips/dragino-ms14s/patches/3.14.17/0010-spi-add-type-field-to-spi_transfer-struct.patch37
-rw-r--r--target/mips/dragino-ms14s/patches/3.14.17/0011-mtd-m25p80-set-SPI-transfer-type.patch29
-rw-r--r--target/mips/dragino-ms14s/patches/3.14.17/0012-mips-ath79-swizzle-PCI-address-for-ar71xx.patch130
-rw-r--r--target/mips/dragino-ms14s/patches/3.14.17/0013-net-add-swconfig-support.patch1859
-rw-r--r--target/mips/dragino-ms14s/patches/3.14.17/0014-phy-add-detach-callback-to-struct-phy_driver.patch46
-rw-r--r--target/mips/dragino-ms14s/patches/3.14.17/0015-phy-add-ar8216-PHY-support.patch3671
-rw-r--r--target/mips/dragino-ms14s/patches/3.14.17/0016-phy-mdio-bitbang-ignore-TA-value.patch44
-rw-r--r--target/mips/dragino-ms14s/patches/3.14.17/0017-MIPS-ath79-fix-maximum-timeout.patch37
-rw-r--r--target/mips/dragino-ms14s/patches/3.14.17/0018-net-allow-PHY-drivers-to-insert-packet-mangle-hooks.patch211
-rw-r--r--target/mips/dragino-ms14s/patches/3.14.17/0019-MIPS-ath79-process-board-cmdline-option.patch26
-rw-r--r--target/mips/dragino-ms14s/patches/3.14.17/0020-spi-ath79-add-fast-flash-read-support.patch202
-rw-r--r--target/mips/dragino-ms14s/patches/3.14.17/0021-phy-add-mdio-boardinfo.patch227
-rw-r--r--target/mips/dragino-ms14s/patches/3.14.17/0022-mips-ath79-add-ath79-ethernet-driver.patch1429
-rw-r--r--target/mips/dragino-ms14s/patches/3.14.17/0023-MIPS-ath79-add-Mikrotik-rb4xx-device-support.patch536
-rw-r--r--target/mips/dragino-ms14s/patches/3.14.17/0024-various-fixups-for-Werror.patch105
-rw-r--r--target/mips/dragino-ms14s/patches/3.14.17/0025-rb4xx_nand-add-partition-for-cfgfs.patch28
-rw-r--r--target/mips/dragino-ms14s/patches/3.14.17/0026-various-fixups-for-ath5k-fixing-system-freezes.patch108
-rw-r--r--target/mips/kernel/dragino-ms14s12
-rw-r--r--target/mips/systems/dragino-ms14s11
-rw-r--r--target/mips64/lemote-yeelong/patches/3.17.4/sm7xx-fb.patch (renamed from target/mips64/lemote-yeelong/patches/3.16.6/sm7xx-fb.patch)0
-rw-r--r--toolchain/gcc/Makefile.inc6
-rw-r--r--toolchain/gcc/patches/4.9.2/cflags.patch (renamed from toolchain/gcc/patches/4.9.1/cflags.patch)0
94 files changed, 16976 insertions, 3585 deletions
diff --git a/mk/kernel-ver.mk b/mk/kernel-ver.mk
index 12d008cf6..8b66ee033 100644
--- a/mk/kernel-ver.mk
+++ b/mk/kernel-ver.mk
@@ -1,8 +1,8 @@
-ifeq ($(ADK_KERNEL_VERSION_3_16_6),y)
-KERNEL_VERSION:= 3.16.6
+ifeq ($(ADK_KERNEL_VERSION_3_17_4),y)
+KERNEL_VERSION:= 3.17.4
KERNEL_MOD_VERSION:= $(KERNEL_VERSION)
KERNEL_RELEASE:= 1
-KERNEL_MD5SUM:= 2edc96a1272b04d58245707eb12b4902
+KERNEL_MD5SUM:= ce49828adecf8908eb3a9ffc5b860d44
endif
ifeq ($(ADK_KERNEL_VERSION_3_14_22),y)
KERNEL_VERSION:= 3.14.22
diff --git a/mk/vars.mk b/mk/vars.mk
index 18a0d6199..e57c4f93e 100644
--- a/mk/vars.mk
+++ b/mk/vars.mk
@@ -64,6 +64,9 @@ ADK_TARGET_LINUXTYPE:= linux
endif
GNU_TARGET_NAME:= $(ADK_TARGET_CPU_ARCH)-$(ADK_VENDOR)-$(ADK_TARGET_LINUXTYPE)-$(ADK_TARGET_SUFFIX)
+ifeq ($(ADK_LINUX_C6X),y)
+GNU_TARGET_NAME:= $(ADK_TARGET_CPU_ARCH)-$(ADK_TARGET_LINUXTYPE)
+endif
TARGET_CROSS:= $(TOOLCHAIN_DIR)/usr/bin/$(GNU_TARGET_NAME)-
TARGET_COMPILER_PREFIX?=${TARGET_CROSS}
CONFIGURE_TRIPLE:= --build=${GNU_HOST_NAME} \
diff --git a/package/curl/Makefile b/package/curl/Makefile
index 53d32c6a1..c30302cee 100644
--- a/package/curl/Makefile
+++ b/package/curl/Makefile
@@ -4,9 +4,9 @@
include ${ADK_TOPDIR}/rules.mk
PKG_NAME:= curl
-PKG_VERSION:= 7.38.0
+PKG_VERSION:= 7.39.0
PKG_RELEASE:= 1
-PKG_MD5SUM:= b6e3ea55bb718f2270489581efa50a8a
+PKG_MD5SUM:= 88c5650122873712296d4b1db3f12e6c
PKG_DESCR:= client-side url transfer tool
PKG_SECTION:= net/http
PKG_DEPENDS:= libcurl
diff --git a/package/ffmpeg/Makefile b/package/ffmpeg/Makefile
index c766fca11..2a372a564 100644
--- a/package/ffmpeg/Makefile
+++ b/package/ffmpeg/Makefile
@@ -4,9 +4,9 @@
include ${ADK_TOPDIR}/rules.mk
PKG_NAME:= ffmpeg
-PKG_VERSION:= 2.4.1
+PKG_VERSION:= 2.4.3
PKG_RELEASE:= 1
-PKG_MD5SUM:= c36caa8d29b3677dcb7bd8c546890c9d
+PKG_MD5SUM:= 8da635baff57d7ab704b1daca5a99b47
PKG_DESCR:= record, convert and stream audio & video
PKG_SECTION:= libs/video
PKG_FDEPENDS:= libpthread
diff --git a/package/gnutls/Makefile b/package/gnutls/Makefile
index 72a4a943d..d517cd66c 100644
--- a/package/gnutls/Makefile
+++ b/package/gnutls/Makefile
@@ -4,9 +4,9 @@
include ${ADK_TOPDIR}/rules.mk
PKG_NAME:= gnutls
-PKG_VERSION:= 3.3.4
+PKG_VERSION:= 3.3.10
PKG_RELEASE:= 1
-PKG_MD5SUM:= 908dc1e98e28cb1c2c255a71785a4af2
+PKG_MD5SUM:= c0a72b2c0553fe1c4992e30835808012
PKG_DESCR:= transport layer security library
PKG_SECTION:= libs/crypto
PKG_DEPENDS:= libgcrypt libtasn1 zlib libnettle libgmp
diff --git a/package/kmod/Makefile b/package/kmod/Makefile
index 57e1c10c2..814ea5ac0 100644
--- a/package/kmod/Makefile
+++ b/package/kmod/Makefile
@@ -4,9 +4,9 @@
include $(ADK_TOPDIR)/rules.mk
PKG_NAME:= kmod
-PKG_VERSION:= 18
+PKG_VERSION:= 19
PKG_RELEASE:= 1
-PKG_MD5SUM:= 82835c7f01983634e06ca72b4ee30cc6
+PKG_MD5SUM:= a08643f814aa4efc12211c6e5909f4d9
PKG_DESCR:= kernel module utils
PKG_SECTION:= sys/utils
PKG_DEPENDS:= libkmod
diff --git a/package/kodi/Makefile b/package/kodi/Makefile
index 74a240bd2..08b230cc9 100644
--- a/package/kodi/Makefile
+++ b/package/kodi/Makefile
@@ -4,13 +4,13 @@
include $(ADK_TOPDIR)/rules.mk
PKG_NAME:= kodi
-PKG_VERSION:= 14.0alpha4
-PKG_RELEASE:= 5
-PKG_MD5SUM:= 88a68db6e653b2029efddbfa0a855e1c
+PKG_VERSION:= 14.0rc2
+PKG_RELEASE:= 1
+PKG_MD5SUM:= f56aeb81db6878fcac6631f6a3e2c702
PKG_DESCR:= software media player
PKG_SECTION:= mm/video
PKG_DEPENDS:= boost python2 libstdcxx glibc-gconv
-PKG_DEPENDS+= libglew mesalib libass libmpeg2 libmad libdbus
+PKG_DEPENDS+= libass libmpeg2 libmad libdbus
PKG_DEPENDS+= libjpeg-turbo libogg libvorbis libmodplug libcurl
PKG_DEPENDS+= libflac libopenssl libbz2 libtiff liblzo
PKG_DEPENDS+= yajl tinyxml libsqlite libpcrecpp libpng libncurses
@@ -18,7 +18,7 @@ PKG_DEPENDS+= libpcre libcdio libfreetype libsamplerate
PKG_DEPENDS+= taglib libjasper libmp3lame libmicrohttpd
PKG_DEPENDS+= libgpg-error libudev python2-mod-sqlite libffmpeg
PKG_DEPENDS+= libxslt libvorbisenc alsa-lib glib libglu librt
-PKG_BUILDDEP:= boost python2 mesalib libglew libass ffmpeg
+PKG_BUILDDEP:= boost python2 libass ffmpeg
PKG_BUILDDEP+= libmpeg2 libmad libjpeg-turbo libogg libvorbis
PKG_BUILDDEP+= curl flac openssl bzip2 libtiff liblzo yajl
PKG_BUILDDEP+= tinyxml sqlite pcre libpng libcdio freetype
@@ -61,8 +61,8 @@ PKGFD_WITH_WEBSERVER:= enable internal webserver support
PKG_LIBC_DEPENDS:= glibc
-PKG_DEPENDS_RASPBERRY_PI:= bcm2835-vc
-PKG_BUILDDEP_RASPBERRY_PI:= bcm2835-vc
+PKG_DEPENDS_RASPBERRY_PI:= bcm2835-vc libglew mesalib
+PKG_BUILDDEP_RASPBERRY_PI:= bcm2835-vc libglew mesalib
PKG_DEPENDS_SOLIDRUN_IMX6:= libfslvpuwrap gpu-viv-bin-mx6q
PKG_BUILDDEP_SOLIDRUN_IMX6:= libfslvpuwrap gpu-viv-bin-mx6q
PKG_SYSTEM_DEPENDS:= raspberry-pi solidrun-imx6
diff --git a/package/kodi/patches/patch-tools_Linux_xbmc_sh_in b/package/kodi/patches/patch-tools_Linux_xbmc_sh_in
deleted file mode 100644
index 30804493f..000000000
--- a/package/kodi/patches/patch-tools_Linux_xbmc_sh_in
+++ /dev/null
@@ -1,59 +0,0 @@
---- kodi-14.0alpha4.orig/tools/Linux/xbmc.sh.in 2014-09-05 14:09:59.000000000 +0200
-+++ kodi-14.0alpha4/tools/Linux/xbmc.sh.in 2014-09-08 13:26:02.745294460 +0200
-@@ -58,7 +58,7 @@ single_stacktrace()
-
- print_crash_report()
- {
-- FILE="$CRASHLOG_DIR/xbmc_crashlog-`date +%Y%m%d_%H%M%S`.log"
-+ FILE="/tmp/xbmc_crashlog-`date +%Y%m%d_%H%M%S`.log"
- echo "############## XBMC CRASH LOG ###############" >> $FILE
- echo >> $FILE
- echo "################ SYSTEM INFO ################" >> $FILE
-@@ -70,15 +70,6 @@ print_crash_report()
- echo -n " Kernel: " >> $FILE
- uname -rvs >> $FILE
- echo -n " Release: " >> $FILE
-- if [ -f /etc/os-release ]; then
-- . /etc/os-release
-- echo $NAME $VERSION >> $FILE
-- elif command_exists lsb_release; then
-- echo >> $FILE
-- lsb_release -a 2> /dev/null | sed -e 's/^/ /' >> $FILE
-- else
-- echo "lsb_release not available" >> $FILE
-- fi
- echo "############## END SYSTEM INFO ##############" >> $FILE
- echo >> $FILE
- echo "############### STACK TRACE #################" >> $FILE
-@@ -100,31 +91,8 @@ print_crash_report()
- echo "gdb not installed, can't get stack trace." >> $FILE
- fi
- echo "############# END STACK TRACE ###############" >> $FILE
-- echo >> $FILE
-- echo "################# LOG FILE ##################" >> $FILE
-- echo >> $FILE
-- if [ -f ~/.xbmc/temp/xbmc.log ]
-- then
-- cat ~/.xbmc/temp/xbmc.log >> $FILE
-- echo >> $FILE
-- else
-- echo "Logfile not found in the usual place." >> $FILE
-- echo "Please attach it seperately." >> $FILE
-- echo "Use pastebin.com or similar for forums or IRC." >> $FILE
-- fi
-- echo >> $FILE
-- echo "############### END LOG FILE ################" >> $FILE
-- echo >> $FILE
-- echo "############ END XBMC CRASH LOG #############" >> $FILE
-- echo "Crash report available at $FILE"
- }
-
--python @datadir@/xbmc/FEH.py $SAVED_ARGS
--RET=$?
--if [ $RET -ne 0 ]; then
-- exit $RET
--fi
--
- if command_exists gdb; then
- # Output warning in case ulimit is unsupported by shell
- eval ulimit -c unlimited
diff --git a/package/kodi/patches/patch-xbmc_Application_cpp b/package/kodi/patches/patch-xbmc_Application_cpp
deleted file mode 100644
index a90c36f89..000000000
--- a/package/kodi/patches/patch-xbmc_Application_cpp
+++ /dev/null
@@ -1,41 +0,0 @@
---- kodi-14.0alpha4.orig/xbmc/Application.cpp 2014-10-06 11:34:37.000000000 -0500
-+++ kodi-14.0alpha4/xbmc/Application.cpp 2014-10-08 01:25:47.880436000 -0500
-@@ -642,7 +642,7 @@ bool CApplication::Create()
-
- if (!CLog::Init(CSpecialProtocol::TranslatePath(g_advancedSettings.m_logFolder).c_str()))
- {
-- fprintf(stderr,"Could not init logging classes. Permission errors on ~/.xbmc (%s)\n",
-+ fprintf(stderr,"Could not init logging classes. Permission errors on %s\n",
- CSpecialProtocol::TranslatePath(g_advancedSettings.m_logFolder).c_str());
- return false;
- }
-@@ -1064,10 +1064,13 @@ bool CApplication::InitDirectoriesLinux(
- userName = "root";
-
- CStdString userHome;
-+ userHome = "/data/xbmc";
-+/*
- if (getenv("HOME"))
- userHome = getenv("HOME");
- else
- userHome = "/root";
-+*/
-
- CStdString xbmcBinPath, xbmcPath;
- CUtil::GetHomePath(xbmcBinPath, "XBMC_BIN_HOME");
-@@ -1099,11 +1102,11 @@ bool CApplication::InitDirectoriesLinux(
- // map our special drives
- CSpecialProtocol::SetXBMCBinPath(xbmcBinPath);
- CSpecialProtocol::SetXBMCPath(xbmcPath);
-- CSpecialProtocol::SetHomePath(userHome + "/.xbmc");
-- CSpecialProtocol::SetMasterProfilePath(userHome + "/.xbmc/userdata");
-+ CSpecialProtocol::SetHomePath(userHome);
-+ CSpecialProtocol::SetMasterProfilePath(userHome + "/userdata");
-
-- CStdString strTempPath = userHome;
-- strTempPath = URIUtils::AddFileToFolder(strTempPath, ".xbmc/temp");
-+ CStdString strTempPath = "/tmp";
-+ strTempPath = URIUtils::AddFileToFolder(strTempPath, "/xbmc");
- if (getenv("XBMC_TEMP"))
- strTempPath = getenv("XBMC_TEMP");
- CSpecialProtocol::SetTempPath(strTempPath);
diff --git a/package/libcec/Makefile b/package/libcec/Makefile
index d48adda31..0d7502bc5 100644
--- a/package/libcec/Makefile
+++ b/package/libcec/Makefile
@@ -4,22 +4,20 @@
include $(ADK_TOPDIR)/rules.mk
PKG_NAME:= libcec
-PKG_VERSION:= 2.1.4
-PKG_RELEASE:= 6
-PKG_MD5SUM:= faa58944f87e9beda165f615d4b46766
+PKG_VERSION:= 2.2.0
+PKG_RELEASE:= 1
+PKG_MD5SUM:= 17d6ec05d2ac9e6779eb8d2986a62688
PKG_DESCR:= control your device with your tv remote control
PKG_SECTION:= libs/video
PKG_DEPENDS:= libudev
PKG_BUILDDEP:= eudev
PKG_URL:= http://libcec.pulse-eight.com/
-PKG_SITES:= http://packages.pulse-eight.net/pulse/sources/libcec/
+PKG_SITES:= http://openadk.org/distfiles/
PKG_OPTS:= dev
-DISTFILES:= ${PKG_NAME}-${PKG_VERSION}.tar.gz
-
PKG_DEPENDS_RASPBERRY_PI:= bcm2835-vc
PKG_BUILDDEP_RASPBERRY_PI:= bcm2835-vc
-PKG_SYSTEM_DEPENDS:= raspberry-pi ibm-x40 solidrun-imx6
+PKG_SYSTEM_DEPENDS:= raspberry-pi solidrun-imx6
include $(ADK_TOPDIR)/mk/package.mk
diff --git a/package/libcec/patches/imx6.patch b/package/libcec/patches/imx6.patch
deleted file mode 100644
index aadb217e8..000000000
--- a/package/libcec/patches/imx6.patch
+++ /dev/null
@@ -1,3051 +0,0 @@
-diff -Nur libcec-2.1.4/ChangeLog libcec-imx6/ChangeLog
---- libcec-2.1.4/ChangeLog 2013-12-16 10:32:51.000000000 +0100
-+++ libcec-imx6/ChangeLog 2014-09-01 13:48:53.610430917 +0200
-@@ -1,3 +1,10 @@
-+libcec (2.1.4-2) unstable; urgency=low
-+
-+ * fixed:
-+ * OS X build
-+
-+ -- Pulse-Eight Packaging <packaging@pulse-eight.com> Wed, 18 Dec 2013 02:14:00 +0100
-+
- libcec (2.1.4-1) unstable; urgency=low
-
- * changed / added:
-diff -Nur libcec-2.1.4/configure.ac libcec-imx6/configure.ac
---- libcec-2.1.4/configure.ac 2013-12-16 10:32:51.000000000 +0100
-+++ libcec-imx6/configure.ac 2014-09-01 13:48:53.610430917 +0200
-@@ -93,6 +93,14 @@
- esac
- fi
-
-+## i.MX6 support
-+AC_ARG_ENABLE([imx6],
-+ [AS_HELP_STRING([--enable-imx6],
-+ [enable support for freescale i.MX6 (default is no)])],
-+ [use_imx6=$enableval],
-+ [use_imx6=no])
-+
-+
- ## add the top dir and include to the include path, so we can include config.h and cec.h
- CPPFLAGS="$CPPFLAGS -I\$(abs_top_srcdir)/src -I\$(abs_top_srcdir)/include"
-
-@@ -130,6 +138,7 @@
- use_udev="no"
- use_adapter_detection="yes"
- use_lockdev="no"
-+SUPPRESS_MANGLING_WARNINGS=" -Wno-psabi"
- case "${host}" in
- *-*-linux*)
- ## search for udev if pkg-config was found
-@@ -210,6 +219,7 @@
- AC_CHECK_HEADER(mach/mach_time.h,,AC_MSG_ERROR($msg_required_header_missing))
- AC_CHECK_HEADER(CoreVideo/CVHostTime.h,,AC_MSG_ERROR($msg_required_header_missing))
- AC_DEFINE([TARGET_DARWIN], [1], [Darwin target])
-+ SUPPRESS_MANGLING_WARNINGS=""
- ;;
- esac
-
-@@ -268,6 +278,17 @@
- features="$features\n TDA995x support :\t\t\tno"
- fi
-
-+## mark i.MX6 support as available
-+if test "x$use_imx6" != "xno"; then
-+ AC_DEFINE([HAVE_IMX_API],[1],[Define to 1 to include i.MX6 support])
-+ AM_CONDITIONAL(USE_IMX_API, true)
-+ features="$features\n i.MX6 support :\t\t\tyes"
-+ LIB_INFO="$LIB_INFO 'i.MX6'"
-+else
-+ AM_CONDITIONAL(USE_IMX_API, false)
-+ features="$features\n i.MX6 support :\t\t\tno"
-+fi
-+
- ## check if our build system is complete
- AC_CHECK_HEADER(algorithm,,AC_MSG_ERROR($msg_required_header_missing))
- AC_CHECK_HEADER(ctype.h,,AC_MSG_ERROR($msg_required_header_missing))
-@@ -342,7 +363,7 @@
- LIBS_LIBCEC="$LIBS"
- LIBS="$libs_client"
-
--CXXFLAGS="$CXXFLAGS -fPIC -Wall -Wextra -Wno-missing-field-initializers -Wno-psabi"
-+CXXFLAGS="$CXXFLAGS -fPIC -Wall -Wextra -Wno-missing-field-initializers $SUPPRESS_MANGLING_WARNINGS"
-
- if test "x$use_debug" = "xyes"; then
- CXXFLAGS="$CXXFLAGS -g"
-diff -Nur libcec-2.1.4/debian/changelog libcec-imx6/debian/changelog
---- libcec-2.1.4/debian/changelog 2013-12-16 10:32:51.000000000 +0100
-+++ libcec-imx6/debian/changelog 2014-09-01 13:48:53.698431426 +0200
-@@ -1,3 +1,10 @@
-+libcec (2.1.4-2) unstable; urgency=low
-+
-+ * fixed:
-+ * OS X build
-+
-+ -- Pulse-Eight Packaging <packaging@pulse-eight.com> Wed, 18 Dec 2013 02:14:00 +0100
-+
- libcec (2.1.4-1) unstable; urgency=low
-
- * changed / added:
-diff -Nur libcec-2.1.4/driver/p8usb-cec.inf libcec-imx6/driver/p8usb-cec.inf
---- libcec-2.1.4/driver/p8usb-cec.inf 1970-01-01 01:00:00.000000000 +0100
-+++ libcec-imx6/driver/p8usb-cec.inf 2014-09-01 13:48:53.702431449 +0200
-@@ -0,0 +1,89 @@
-+; Copyright (c) 2012 Pulse-Eight Limited
-+
-+[Version]
-+Signature="$Windows NT$"
-+Class=Ports
-+ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}
-+Provider=%MFGNAME%
-+LayoutFile=layout.inf
-+CatalogFile=%MFGFILENAME%.cat
-+DriverVer=08/29/2012,1.1.0.0
-+
-+[Manufacturer]
-+%MFGNAME%=DeviceList, NTamd64
-+
-+[DestinationDirs]
-+FakeModemCopyFileSection=12
-+DefaultDestDir=12
-+
-+
-+;------------------------------------------------------------------------------
-+; Windows 2000/XP/Vista-32bit Sections
-+;------------------------------------------------------------------------------
-+
-+[DriverInstall.nt]
-+include = mdmcpq.inf
-+CopyFiles = FakeModemCopyFileSection
-+AddReg = DriverInstall.nt.AddReg
-+
-+[DriverInstall.nt.AddReg]
-+HKR,,DevLoader,,*ntkern
-+HKR,,NTMPDriver,,%DRIVERFILENAME%.sys
-+HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
-+HKR,,PortSubClass,1,01
-+
-+[DriverInstall.nt.Services]
-+AddService = usbser, 0x00000002, DriverService.nt
-+
-+[DriverService.nt]
-+DisplayName = %SERVICE%
-+ServiceType = 1 ; SERVICE_KERNEL_DRIVER
-+StartType = 3 ; SERVICE_DEMAND_START
-+ErrorControl = 1 ; SERVICE_ERROR_NORMAL
-+ServiceBinary = %12%\%DRIVERFILENAME%.sys
-+LoadOrderGroup = Base
-+
-+;------------------------------------------------------------------------------
-+; Vista-64bit Sections
-+;------------------------------------------------------------------------------
-+
-+[DriverInstall.NTamd64]
-+include = mdmcpq.inf
-+CopyFiles = FakeModemCopyFileSection
-+AddReg = DriverInstall.NTamd64.AddReg
-+
-+[DriverInstall.NTamd64.AddReg]
-+HKR,,DevLoader,,*ntkern
-+HKR,,NTMPDriver,,%DRIVERFILENAME%.sys
-+HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
-+HKR,,PortSubClass,1,01
-+
-+[DriverInstall.NTamd64.Services]
-+AddService = usbser, 0x00000002, DriverService.NTamd64
-+
-+[DriverService.NTamd64]
-+DisplayName = %SERVICE%
-+ServiceType = 1 ; SERVICE_KERNEL_DRIVER
-+StartType = 3 ; SERVICE_DEMAND_START
-+ErrorControl = 1 ; SERVICE_ERROR_NORMAL
-+ServiceBinary = %12%\%DRIVERFILENAME%.sys
-+LoadOrderGroup = Base
-+
-+[SourceDisksFiles]
-+[SourceDisksNames]
-+[DeviceList]
-+%DESCRIPTION2% = DriverInstall, USB\VID_2548&PID_1002&MI_00
-+%DESCRIPTION% = DriverInstall, USB\VID_2548&PID_1001
-+
-+[DeviceList.NTamd64]
-+%DESCRIPTION2% = DriverInstall, USB\VID_2548&PID_1002&MI_00
-+%DESCRIPTION% = DriverInstall, USB\VID_2548&PID_1001
-+
-+[Strings]
-+MFGFILENAME = "p8usb-cec"
-+DRIVERFILENAME = "usbser"
-+MFGNAME = "Pulse-Eight Limited"
-+INSTDISK = "Pulse-Eight USB-CEC Installation Disc"
-+DESCRIPTION = "Pulse-Eight USB to HDMI CEC Adapter"
-+DESCRIPTION2 = "Pulse-Eight USB to HDMI CEC Adapter (rev.2)"
-+SERVICE = "USB to HDMI-CEC"
-diff -Nur libcec-2.1.4/.gitignore libcec-imx6/.gitignore
---- libcec-2.1.4/.gitignore 1970-01-01 01:00:00.000000000 +0100
-+++ libcec-imx6/.gitignore 2014-09-01 13:48:53.610430917 +0200
-@@ -0,0 +1,117 @@
-+/build
-+/.cproject
-+/.project
-+/.settings
-+*.dll
-+*.exe
-+*.exp
-+*.ilk
-+*.lib
-+*.manifest
-+*.metagen
-+*.ncb
-+*.opensdf
-+*.pdb
-+*.suo
-+*.user
-+*.aps
-+
-+*~
-+
-+/support/private
-+
-+/driver/p8usb-cec.cat
-+/bootloader-driver/p8_usb_dfu.cat
-+
-+aclocal.m4
-+autom4te.cache
-+config.guess
-+config.log
-+config.status
-+config.sub
-+depcomp
-+configure
-+install-sh
-+INSTALL
-+libtool
-+ltmain.sh
-+Makefile
-+Makefile.in
-+missing
-+config.h
-+config.h.in
-+config.h.in~
-+stamp-h1
-+
-+/debian/*.log
-+/debian/*.substvars
-+/debian/*.debhelper
-+/debian/files
-+/debian/cec-utils
-+/debian/libcec-dev
-+/debian/libcec
-+/debian/libcec2
-+/debian/tmp
-+
-+include/boost
-+
-+project/bin
-+project/Debug/
-+project/*.exe
-+project/Release/
-+project/ipch/
-+project/libcec.sdf
-+project/obj
-+project/Properties
-+project/_*
-+project/x64
-+project/LibCecSharp/x64
-+project/LibCecSharp/Debug
-+project/LibCecSharp/Release
-+project/libcec/x64
-+project/libcec/Debug
-+project/libcec/Release
-+project/testclient/x64
-+project/testclient/Debug
-+project/testclient/Release
-+
-+project/RPi/toolchain
-+project/RPi/firmware
-+project/RPi/deps
-+
-+src/lib/.deps
-+src/lib/.libs
-+src/lib/*.a
-+src/lib/*.la
-+src/lib/*.lo
-+src/lib/*.o
-+src/lib/*.P
-+src/lib/libcec.pc
-+src/lib/Makefile
-+src/lib/Makefile.in
-+
-+src/lib/util/*.d
-+src/lib/util/*.o
-+src/lib/util/*.a
-+src/lib/util/*.P
-+
-+src/testclient/.deps
-+src/testclient/.libs
-+src/testclient/cec-client
-+src/testclient/*.o
-+
-+src/CecSharpTester/bin
-+src/CecSharpTester/obj
-+
-+src/cec-config-gui/obj
-+src/cec-config/cec-config
-+src/cec-config/*.o
-+src/cec-config/.deps
-+
-+src/libcec-wmc/bin
-+src/libcec-wmc/obj
-+
-+/dpinst-x86.exe
-+/dpinst-amd64.exe
-+
-+/documentation
-diff -Nur libcec-2.1.4/include/cectypes.h libcec-imx6/include/cectypes.h
---- libcec-2.1.4/include/cectypes.h 2013-12-16 10:32:51.000000000 +0100
-+++ libcec-imx6/include/cectypes.h 2014-09-01 13:48:53.702431449 +0200
-@@ -295,6 +295,17 @@
- #define CEC_TDA995x_VIRTUAL_COM "CuBox"
-
- /*!
-+ * the path to use for the i.MX CEC wire
-+ */
-+#define CEC_IMX_PATH "/dev/mxc_hdmi_cec"
-+
-+/*!
-+ * the name of the virtual COM port to use for the i.MX CEC wire
-+ */
-+#define CEC_IMX_VIRTUAL_COM "i.MX"
-+
-+
-+/*!
- * Mimimum client version
- */
- #define CEC_MIN_LIB_VERSION 2
-@@ -858,7 +869,8 @@
- ADAPTERTYPE_P8_EXTERNAL = 0x1,
- ADAPTERTYPE_P8_DAUGHTERBOARD = 0x2,
- ADAPTERTYPE_RPI = 0x100,
-- ADAPTERTYPE_TDA995x = 0x200
-+ ADAPTERTYPE_TDA995x = 0x200,
-+ ADAPTERTYPE_IMX = 0x300,
- } cec_adapter_type;
-
- typedef struct cec_menu_language
-Binärdateien libcec-2.1.4/project/favicon.ico und libcec-imx6/project/favicon.ico sind verschieden.
-Binärdateien libcec-2.1.4/project/libcec/libcec.rc und libcec-imx6/project/libcec/libcec.rc sind verschieden.
-diff -Nur libcec-2.1.4/project/libcec/libcec.vcxproj libcec-imx6/project/libcec/libcec.vcxproj
---- libcec-2.1.4/project/libcec/libcec.vcxproj 1970-01-01 01:00:00.000000000 +0100
-+++ libcec-imx6/project/libcec/libcec.vcxproj 2014-09-01 13:48:53.702431449 +0200
-@@ -0,0 +1,281 @@
-+<?xml version="1.0" encoding="utf-8"?>
-+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-+ <ItemGroup Label="ProjectConfigurations">
-+ <ProjectConfiguration Include="Debug|Win32">
-+ <Configuration>Debug</Configuration>
-+ <Platform>Win32</Platform>
-+ </ProjectConfiguration>
-+ <ProjectConfiguration Include="Debug|x64">
-+ <Configuration>Debug</Configuration>
-+ <Platform>x64</Platform>
-+ </ProjectConfiguration>
-+ <ProjectConfiguration Include="Release|Win32">
-+ <Configuration>Release</Configuration>
-+ <Platform>Win32</Platform>
-+ </ProjectConfiguration>
-+ <ProjectConfiguration Include="Release|x64">
-+ <Configuration>Release</Configuration>
-+ <Platform>x64</Platform>
-+ </ProjectConfiguration>
-+ </ItemGroup>
-+ <ItemGroup>
-+ <ClInclude Include="..\..\include\cec.h" />
-+ <ClInclude Include="..\..\include\cecc.h" />
-+ <ClInclude Include="..\..\include\cecloader.h" />
-+ <ClInclude Include="..\..\include\cectypes.h" />
-+ <ClInclude Include="..\..\src\lib\adapter\AdapterCommunication.h" />
-+ <ClInclude Include="..\..\src\lib\adapter\AdapterFactory.h" />
-+ <ClInclude Include="..\..\src\lib\adapter\Pulse-Eight\USBCECAdapterCommands.h" />
-+ <ClInclude Include="..\..\src\lib\adapter\Pulse-Eight\USBCECAdapterCommunication.h" />
-+ <ClInclude Include="..\..\src\lib\adapter\Pulse-Eight\USBCECAdapterDetection.h" />
-+ <ClInclude Include="..\..\src\lib\adapter\Pulse-Eight\USBCECAdapterMessage.h" />
-+ <ClInclude Include="..\..\src\lib\adapter\Pulse-Eight\USBCECAdapterMessageQueue.h" />
-+ <ClInclude Include="..\..\src\lib\CECClient.h" />
-+ <ClInclude Include="..\..\src\lib\CECInputBuffer.h" />
-+ <ClInclude Include="..\..\src\lib\CECProcessor.h" />
-+ <ClInclude Include="..\..\src\lib\CECTypeUtils.h" />
-+ <ClInclude Include="..\..\src\lib\devices\CECAudioSystem.h" />
-+ <ClInclude Include="..\..\src\lib\devices\CECBusDevice.h" />
-+ <ClInclude Include="..\..\src\lib\devices\CECDeviceMap.h" />
-+ <ClInclude Include="..\..\src\lib\devices\CECPlaybackDevice.h" />
-+ <ClInclude Include="..\..\src\lib\devices\CECRecordingDevice.h" />
-+ <ClInclude Include="..\..\src\lib\devices\CECTuner.h" />
-+ <ClInclude Include="..\..\src\lib\devices\CECTV.h" />
-+ <ClInclude Include="..\..\src\lib\implementations\ANCommandHandler.h" />
-+ <ClInclude Include="..\..\src\lib\implementations\CECCommandHandler.h" />
-+ <ClInclude Include="..\..\src\lib\implementations\PHCommandHandler.h" />
-+ <ClInclude Include="..\..\src\lib\implementations\RLCommandHandler.h" />
-+ <ClInclude Include="..\..\src\lib\implementations\SLCommandHandler.h" />
-+ <ClInclude Include="..\..\src\lib\implementations\VLCommandHandler.h" />
-+ <ClInclude Include="..\..\src\lib\implementations\RHCommandHandler.h" />
-+ <ClInclude Include="..\..\src\lib\implementations\AQCommandHandler.h" />
-+ <ClInclude Include="..\..\src\lib\LibCEC.h" />
-+ <ClInclude Include="..\..\src\lib\platform\adl\adl-edid.h" />
-+ <ClInclude Include="..\..\src\lib\platform\adl\adl_defines.h" />
-+ <ClInclude Include="..\..\src\lib\platform\adl\adl_sdk.h" />
-+ <ClInclude Include="..\..\src\lib\platform\adl\adl_structures.h" />
-+ <ClInclude Include="..\..\src\lib\platform\nvidia\nv-edid.h" />
-+ <ClInclude Include="..\..\src\lib\platform\os.h" />
-+ <ClInclude Include="..\..\src\lib\platform\sockets\serialport.h" />
-+ <ClInclude Include="..\..\src\lib\platform\sockets\socket.h" />
-+ <ClInclude Include="..\..\src\lib\platform\sockets\tcp.h" />
-+ <ClInclude Include="..\..\src\lib\platform\threads\mutex.h" />
-+ <ClInclude Include="..\..\src\lib\platform\threads\threads.h" />
-+ <ClInclude Include="..\..\src\lib\platform\util\baudrate.h" />
-+ <ClInclude Include="..\..\src\lib\platform\util\buffer.h" />
-+ <ClInclude Include="..\..\src\lib\platform\util\edid.h" />
-+ <ClInclude Include="..\..\src\lib\platform\util\StdString.h" />
-+ <ClInclude Include="..\..\src\lib\platform\util\timeutils.h" />
-+ <ClInclude Include="..\..\src\lib\platform\windows\dlfcn-win32.h" />
-+ <ClInclude Include="..\..\src\lib\platform\windows\os-socket.h" />
-+ <ClInclude Include="..\..\src\lib\platform\windows\os-threads.h" />
-+ <ClInclude Include="..\..\src\lib\platform\windows\os-types.h" />
-+ <ClInclude Include="..\..\src\lib\platform\windows\stdint.h" />
-+ <ClInclude Include="resource.h" />
-+ </ItemGroup>
-+ <ItemGroup>
-+ <ClCompile Include="..\..\src\lib\adapter\AdapterFactory.cpp" />
-+ <ClCompile Include="..\..\src\lib\adapter\Pulse-Eight\USBCECAdapterCommands.cpp" />
-+ <ClCompile Include="..\..\src\lib\adapter\Pulse-Eight\USBCECAdapterCommunication.cpp" />
-+ <ClCompile Include="..\..\src\lib\adapter\Pulse-Eight\USBCECAdapterDetection.cpp" />
-+ <ClCompile Include="..\..\src\lib\adapter\Pulse-Eight\USBCECAdapterMessage.cpp" />
-+ <ClCompile Include="..\..\src\lib\adapter\Pulse-Eight\USBCECAdapterMessageQueue.cpp" />
-+ <ClCompile Include="..\..\src\lib\CECClient.cpp" />
-+ <ClCompile Include="..\..\src\lib\CECProcessor.cpp" />
-+ <ClCompile Include="..\..\src\lib\devices\CECAudioSystem.cpp" />
-+ <ClCompile Include="..\..\src\lib\devices\CECBusDevice.cpp" />
-+ <ClCompile Include="..\..\src\lib\devices\CECDeviceMap.cpp" />
-+ <ClCompile Include="..\..\src\lib\devices\CECPlaybackDevice.cpp" />
-+ <ClCompile Include="..\..\src\lib\devices\CECRecordingDevice.cpp" />
-+ <ClCompile Include="..\..\src\lib\devices\CECTuner.cpp" />
-+ <ClCompile Include="..\..\src\lib\devices\CECTV.cpp" />
-+ <ClCompile Include="..\..\src\lib\implementations\ANCommandHandler.cpp" />
-+ <ClCompile Include="..\..\src\lib\implementations\CECCommandHandler.cpp" />
-+ <ClCompile Include="..\..\src\lib\implementations\PHCommandHandler.cpp" />
-+ <ClCompile Include="..\..\src\lib\implementations\RLCommandHandler.cpp" />
-+ <ClCompile Include="..\..\src\lib\implementations\SLCommandHandler.cpp" />
-+ <ClCompile Include="..\..\src\lib\implementations\VLCommandHandler.cpp" />
-+ <ClCompile Include="..\..\src\lib\implementations\RHCommandHandler.cpp" />
-+ <ClCompile Include="..\..\src\lib\implementations\AQCommandHandler.cpp" />
-+ <ClCompile Include="..\..\src\lib\LibCEC.cpp" />
-+ <ClCompile Include="..\..\src\lib\LibCECC.cpp" />
-+ <ClCompile Include="..\..\src\lib\LibCECDll.cpp" />
-+ <ClCompile Include="..\..\src\lib\platform\adl\adl-edid.cpp" />
-+ <ClCompile Include="..\..\src\lib\platform\nvidia\nv-edid.cpp" />
-+ <ClCompile Include="..\..\src\lib\platform\windows\dlfcn-win32.cpp" />
-+ <ClCompile Include="..\..\src\lib\platform\windows\os-edid.cpp" />
-+ <ClCompile Include="..\..\src\lib\platform\windows\os-threads.cpp" />
-+ <ClCompile Include="..\..\src\lib\platform\windows\serialport.cpp" />
-+ </ItemGroup>
-+ <ItemGroup>
-+ <ResourceCompile Include="libcec.rc" />
-+ </ItemGroup>
-+ <PropertyGroup Label="Globals">
-+ <ProjectGuid>{C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}</ProjectGuid>
-+ <RootNamespace>libcec</RootNamespace>
-+ <ProjectName>libcec</ProjectName>
-+ </PropertyGroup>
-+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
-+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
-+ <ConfigurationType>DynamicLibrary</ConfigurationType>
-+ <UseDebugLibraries>true</UseDebugLibraries>
-+ <CharacterSet>MultiByte</CharacterSet>
-+ <PlatformToolset>v100</PlatformToolset>
-+ </PropertyGroup>
-+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
-+ <ConfigurationType>DynamicLibrary</ConfigurationType>
-+ <UseDebugLibraries>true</UseDebugLibraries>
-+ <CharacterSet>MultiByte</CharacterSet>
-+ <PlatformToolset>v100</PlatformToolset>
-+ </PropertyGroup>
-+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
-+ <ConfigurationType>DynamicLibrary</ConfigurationType>
-+ <UseDebugLibraries>false</UseDebugLibraries>
-+ <CharacterSet>MultiByte</CharacterSet>
-+ <PlatformToolset>v100</PlatformToolset>
-+ </PropertyGroup>
-+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
-+ <ConfigurationType>DynamicLibrary</ConfigurationType>
-+ <UseDebugLibraries>false</UseDebugLibraries>
-+ <CharacterSet>MultiByte</CharacterSet>
-+ <PlatformToolset>v100</PlatformToolset>
-+ </PropertyGroup>
-+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
-+ <ImportGroup Label="ExtensionSettings">
-+ </ImportGroup>
-+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-+ </ImportGroup>
-+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
-+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-+ </ImportGroup>
-+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-+ </ImportGroup>
-+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
-+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-+ </ImportGroup>
-+ <PropertyGroup Label="UserMacros" />
-+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-+ <OutDir>$(SolutionDir)..\build\</OutDir>
-+ </PropertyGroup>
-+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-+ <OutDir>$(SolutionDir)..\build\x64\</OutDir>
-+ </PropertyGroup>
-+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-+ <TargetName>libcec</TargetName>
-+ </PropertyGroup>
-+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-+ <TargetName>$(ProjectName)</TargetName>
-+ </PropertyGroup>
-+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-+ <IncludePath>$(SolutionDir)..\include;$(IncludePath)</IncludePath>
-+ <LibraryPath>C:\WinDDK\7600.16385.1\lib\win7\i386;$(LibraryPath)</LibraryPath>
-+ </PropertyGroup>
-+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-+ <IncludePath>$(SolutionDir)..\include;$(IncludePath)</IncludePath>
-+ <LibraryPath>C:\WinDDK\7600.16385.1\lib\win7\amd64;$(LibraryPath)</LibraryPath>
-+ </PropertyGroup>
-+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-+ <OutDir>$(SolutionDir)..\build\</OutDir>
-+ <TargetName>libcec</TargetName>
-+ <IncludePath>$(SolutionDir)..\include;$(IncludePath)</IncludePath>
-+ <LibraryPath>C:\WinDDK\7600.16385.1\lib\win7\i386;$(LibraryPath)</LibraryPath>
-+ </PropertyGroup>
-+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-+ <OutDir>$(SolutionDir)..\build\x64\</OutDir>
-+ <TargetName>$(ProjectName)</TargetName>
-+ <IncludePath>$(SolutionDir)..\include;$(IncludePath)</IncludePath>
-+ <LibraryPath>C:\WinDDK\7600.16385.1\lib\win7\amd64;$(LibraryPath)</LibraryPath>
-+ </PropertyGroup>
-+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-+ <ClCompile>
-+ <WarningLevel>Level4</WarningLevel>
-+ <Optimization>Disabled</Optimization>
-+ <PreprocessorDefinitions>CEC_DEBUGGING;HAVE_P8_USB;_USE_32BIT_TIME_T;_DEBUG;_CRT_SECURE_NO_WARNINGS;_WINSOCKAPI_;__STDC_CONSTANT_MACROS;DLL_EXPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-+ <AdditionalIncludeDirectories>$(SolutionDir)..\include;$(SolutionDir)..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-+ <DisableSpecificWarnings>
-+ </DisableSpecificWarnings>
-+ <TreatWarningAsError>true</TreatWarningAsError>
-+ </ClCompile>
-+ <Link>
-+ <GenerateDebugInformation>true</GenerateDebugInformation>
-+ <Version>
-+ </Version>
-+ </Link>
-+ </ItemDefinitionGroup>
-+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-+ <ClCompile>
-+ <WarningLevel>Level4</WarningLevel>
-+ <Optimization>Disabled</Optimization>
-+ <PreprocessorDefinitions>CEC_DEBUGGING;HAVE_P8_USB;_WIN64;_DEBUG;_CRT_SECURE_NO_WARNINGS;_WINSOCKAPI_;__STDC_CONSTANT_MACROS;DLL_EXPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-+ <AdditionalIncludeDirectories>$(SolutionDir)..\include;$(SolutionDir)..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-+ <DisableSpecificWarnings>
-+ </DisableSpecificWarnings>
-+ <TreatWarningAsError>true</TreatWarningAsError>
-+ </ClCompile>
-+ <Link>
-+ <AdditionalDependencies>
-+ </AdditionalDependencies>
-+ <IgnoreSpecificDefaultLibraries>
-+ </IgnoreSpecificDefaultLibraries>
-+ <Version>
-+ </Version>
-+ <GenerateDebugInformation>true</GenerateDebugInformation>
-+ </Link>
-+ </ItemDefinitionGroup>
-+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-+ <ClCompile>
-+ <WarningLevel>Level4</WarningLevel>
-+ <Optimization>Full</Optimization>
-+ <FunctionLevelLinking>true</FunctionLevelLinking>
-+ <IntrinsicFunctions>true</IntrinsicFunctions>
-+ <AdditionalIncludeDirectories>$(SolutionDir)..\include;$(SolutionDir)..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-+ <PreprocessorDefinitions>HAVE_P8_USB;_USE_32BIT_TIME_T;_CRT_SECURE_NO_WARNINGS;_WINSOCKAPI_;__STDC_CONSTANT_MACROS;DLL_EXPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-+ <DisableSpecificWarnings>
-+ </DisableSpecificWarnings>
-+ <TreatWarningAsError>true</TreatWarningAsError>
-+ <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
-+ </ClCompile>
-+ <Link>
-+ <GenerateDebugInformation>false</GenerateDebugInformation>
-+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
-+ <OptimizeReferences>true</OptimizeReferences>
-+ <Version>
-+ </Version>
-+ </Link>
-+ </ItemDefinitionGroup>
-+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-+ <ClCompile>
-+ <WarningLevel>Level4</WarningLevel>
-+ <Optimization>Full</Optimization>
-+ <IntrinsicFunctions>true</IntrinsicFunctions>
-+ <AdditionalIncludeDirectories>$(SolutionDir)..\include;$(SolutionDir)..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-+ <PreprocessorDefinitions>HAVE_P8_USB;_WIN64;_CRT_SECURE_NO_WARNINGS;_WINSOCKAPI_;__STDC_CONSTANT_MACROS;DLL_EXPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-+ <DisableSpecificWarnings>
-+ </DisableSpecificWarnings>
-+ <TreatWarningAsError>true</TreatWarningAsError>
-+ <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
-+ </ClCompile>
-+ <Link>
-+ <GenerateDebugInformation>false</GenerateDebugInformation>
-+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
-+ <OptimizeReferences>true</OptimizeReferences>
-+ <AdditionalDependencies>
-+ </AdditionalDependencies>
-+ <IgnoreSpecificDefaultLibraries>
-+ </IgnoreSpecificDefaultLibraries>
-+ <Version>
-+ </Version>
-+ </Link>
-+ <ProjectReference />
-+ <Lib>
-+ <TargetMachine>MachineX64</TargetMachine>
-+ <TreatLibWarningAsErrors>true</TreatLibWarningAsErrors>
-+ <SubSystem>Windows</SubSystem>
-+ </Lib>
-+ </ItemDefinitionGroup>
-+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
-+ <ImportGroup Label="ExtensionTargets">
-+ </ImportGroup>
-+</Project>
-\ Kein Zeilenumbruch am Dateiende.
-diff -Nur libcec-2.1.4/project/libcec/libcec.vcxproj.filters libcec-imx6/project/libcec/libcec.vcxproj.filters
---- libcec-2.1.4/project/libcec/libcec.vcxproj.filters 1970-01-01 01:00:00.000000000 +0100
-+++ libcec-imx6/project/libcec/libcec.vcxproj.filters 2014-09-01 13:48:53.702431449 +0200
-@@ -0,0 +1,281 @@
-+<?xml version="1.0" encoding="utf-8"?>
-+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-+ <ItemGroup>
-+ <Filter Include="exports">
-+ <UniqueIdentifier>{01b9c84a-dcfe-4bdc-b983-69e3e3929b0f}</UniqueIdentifier>
-+ </Filter>
-+ <Filter Include="implementations">
-+ <UniqueIdentifier>{03bd59df-ccac-4664-b61b-3151bb219efa}</UniqueIdentifier>
-+ </Filter>
-+ <Filter Include="devices">
-+ <UniqueIdentifier>{bfc43a58-636d-4c1a-b191-486cb8509c7c}</UniqueIdentifier>
-+ </Filter>
-+ <Filter Include="adapter">
-+ <UniqueIdentifier>{51614b77-8a0e-47a8-8500-5beb0fd12d49}</UniqueIdentifier>
-+ </Filter>
-+ <Filter Include="platform">
-+ <UniqueIdentifier>{7d05b1b5-e728-4f9e-b78f-d63cac4ded8e}</UniqueIdentifier>
-+ </Filter>
-+ <Filter Include="platform\sockets">
-+ <UniqueIdentifier>{6cfe4bad-ed3a-4a16-8c59-4489089f5fe5}</UniqueIdentifier>
-+ </Filter>
-+ <Filter Include="platform\util">
-+ <UniqueIdentifier>{39a56ebf-ba93-4e7b-bf72-2f57b99a1ee1}</UniqueIdentifier>
-+ </Filter>
-+ <Filter Include="platform\threads">
-+ <UniqueIdentifier>{be183456-d61e-4283-b642-fe25ed71e9c5}</UniqueIdentifier>
-+ </Filter>
-+ <Filter Include="platform\windows">
-+ <UniqueIdentifier>{65c4a590-4577-40e4-91ad-339e20b99ebe}</UniqueIdentifier>
-+ </Filter>
-+ <Filter Include="platform\adl">
-+ <UniqueIdentifier>{4fbd02e2-5671-4132-9b37-964c17fb3b0d}</UniqueIdentifier>
-+ </Filter>
-+ <Filter Include="platform\nvidia">
-+ <UniqueIdentifier>{685e2589-204d-4f9a-a637-a7ba1b61c669}</UniqueIdentifier>
-+ </Filter>
-+ <Filter Include="adapter\Pulse-Eight">
-+ <UniqueIdentifier>{a5e91a49-0595-49bd-9bdb-d729d63f024e}</UniqueIdentifier>
-+ </Filter>
-+ </ItemGroup>
-+ <ItemGroup>
-+ <ClInclude Include="..\..\src\lib\CECProcessor.h" />
-+ <ClInclude Include="..\..\src\lib\LibCEC.h" />
-+ <ClInclude Include="..\..\include\cec.h">
-+ <Filter>exports</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\include\cecc.h">
-+ <Filter>exports</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\include\cecloader.h">
-+ <Filter>exports</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\include\cectypes.h">
-+ <Filter>exports</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\implementations\ANCommandHandler.h">
-+ <Filter>implementations</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\implementations\CECCommandHandler.h">
-+ <Filter>implementations</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\implementations\SLCommandHandler.h">
-+ <Filter>implementations</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\devices\CECBusDevice.h">
-+ <Filter>devices</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\implementations\VLCommandHandler.h">
-+ <Filter>implementations</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\implementations\RHCommandHandler.h">
-+ <Filter>implementations</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\implementations\ANCommandHandler.h">
-+ <Filter>implementations</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\devices\CECAudioSystem.h">
-+ <Filter>devices</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\devices\CECPlaybackDevice.h">
-+ <Filter>devices</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\devices\CECRecordingDevice.h">
-+ <Filter>devices</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\devices\CECTuner.h">
-+ <Filter>devices</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\devices\CECTV.h">
-+ <Filter>devices</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\platform\os.h">
-+ <Filter>platform</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\platform\sockets\serialport.h">
-+ <Filter>platform\sockets</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\platform\sockets\socket.h">
-+ <Filter>platform\sockets</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\platform\sockets\tcp.h">
-+ <Filter>platform\sockets</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\platform\util\baudrate.h">
-+ <Filter>platform\util</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\platform\util\buffer.h">
-+ <Filter>platform\util</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\platform\util\StdString.h">
-+ <Filter>platform\util</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\platform\util\timeutils.h">
-+ <Filter>platform\util</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\platform\threads\mutex.h">
-+ <Filter>platform\threads</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\platform\threads\threads.h">
-+ <Filter>platform\threads</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\platform\windows\os-socket.h">
-+ <Filter>platform\windows</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\platform\windows\os-threads.h">
-+ <Filter>platform\windows</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\platform\windows\os-types.h">
-+ <Filter>platform\windows</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\platform\windows\stdint.h">
-+ <Filter>platform\windows</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\implementations\RLCommandHandler.h">
-+ <Filter>implementations</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\implementations\PHCommandHandler.h">
-+ <Filter>implementations</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\CECClient.h" />
-+ <ClInclude Include="..\..\src\lib\CECInputBuffer.h" />
-+ <ClInclude Include="..\..\src\lib\devices\CECDeviceMap.h">
-+ <Filter>devices</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\CECTypeUtils.h" />
-+ <ClInclude Include="..\..\src\lib\platform\util\edid.h">
-+ <Filter>platform\util</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\platform\adl\adl_defines.h">
-+ <Filter>platform\adl</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\platform\adl\adl_sdk.h">
-+ <Filter>platform\adl</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\platform\adl\adl_structures.h">
-+ <Filter>platform\adl</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\platform\adl\adl-edid.h">
-+ <Filter>platform\adl</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\platform\windows\dlfcn-win32.h">
-+ <Filter>platform\windows</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\platform\nvidia\nv-edid.h">
-+ <Filter>platform\nvidia</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\adapter\AdapterCommunication.h">
-+ <Filter>adapter</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\adapter\Pulse-Eight\USBCECAdapterCommands.h">
-+ <Filter>adapter\Pulse-Eight</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\adapter\Pulse-Eight\USBCECAdapterCommunication.h">
-+ <Filter>adapter\Pulse-Eight</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\adapter\Pulse-Eight\USBCECAdapterDetection.h">
-+ <Filter>adapter\Pulse-Eight</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\adapter\Pulse-Eight\USBCECAdapterMessage.h">
-+ <Filter>adapter\Pulse-Eight</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\adapter\Pulse-Eight\USBCECAdapterMessageQueue.h">
-+ <Filter>adapter\Pulse-Eight</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\adapter\AdapterFactory.h">
-+ <Filter>adapter</Filter>
-+ </ClInclude>
-+ <ClInclude Include="resource.h" />
-+ </ItemGroup>
-+ <ItemGroup>
-+ <ClCompile Include="..\..\src\lib\CECProcessor.cpp" />
-+ <ClCompile Include="..\..\src\lib\LibCEC.cpp" />
-+ <ClCompile Include="..\..\src\lib\LibCECC.cpp" />
-+ <ClCompile Include="..\..\src\lib\LibCECDll.cpp" />
-+ <ClCompile Include="..\..\src\lib\implementations\ANCommandHandler.cpp">
-+ <Filter>implementations</Filter>
-+ </ClCompile>
-+ <ClCompile Include="..\..\src\lib\implementations\CECCommandHandler.cpp">
-+ <Filter>implementations</Filter>
-+ </ClCompile>
-+ <ClCompile Include="..\..\src\lib\implementations\SLCommandHandler.cpp">
-+ <Filter>implementations</Filter>
-+ </ClCompile>
-+ <ClCompile Include="..\..\src\lib\devices\CECBusDevice.cpp">
-+ <Filter>devices</Filter>
-+ </ClCompile>
-+ <ClCompile Include="..\..\src\lib\implementations\VLCommandHandler.cpp">
-+ <Filter>implementations</Filter>
-+ </ClCompile>
-+ <ClCompile Include="..\..\src\lib\implementations\RHCommandHandler.cpp">
-+ <Filter>implementations</Filter>
-+ </ClCompile>
-+ <ClCompile Include="..\..\src\lib\implementations\AQCommandHandler.cpp">
-+ <Filter>implementations</Filter>
-+ </ClCompile>
-+ <ClCompile Include="..\..\src\lib\devices\CECAudioSystem.cpp">
-+ <Filter>devices</Filter>
-+ </ClCompile>
-+ <ClCompile Include="..\..\src\lib\devices\CECPlaybackDevice.cpp">
-+ <Filter>devices</Filter>
-+ </ClCompile>
-+ <ClCompile Include="..\..\src\lib\devices\CECRecordingDevice.cpp">
-+ <Filter>devices</Filter>
-+ </ClCompile>
-+ <ClCompile Include="..\..\src\lib\devices\CECTuner.cpp">
-+ <Filter>devices</Filter>
-+ </ClCompile>
-+ <ClCompile Include="..\..\src\lib\devices\CECTV.cpp">
-+ <Filter>devices</Filter>
-+ </ClCompile>
-+ <ClCompile Include="..\..\src\lib\platform\windows\os-threads.cpp">
-+ <Filter>platform\windows</Filter>
-+ </ClCompile>
-+ <ClCompile Include="..\..\src\lib\platform\windows\serialport.cpp">
-+ <Filter>platform\windows</Filter>
-+ </ClCompile>
-+ <ClCompile Include="..\..\src\lib\implementations\RLCommandHandler.cpp">
-+ <Filter>implementations</Filter>
-+ </ClCompile>
-+ <ClCompile Include="..\..\src\lib\implementations\PHCommandHandler.cpp">
-+ <Filter>implementations</Filter>
-+ </ClCompile>
-+ <ClCompile Include="..\..\src\lib\CECClient.cpp" />
-+ <ClCompile Include="..\..\src\lib\devices\CECDeviceMap.cpp">
-+ <Filter>devices</Filter>
-+ </ClCompile>
-+ <ClCompile Include="..\..\src\lib\platform\windows\os-edid.cpp">
-+ <Filter>platform\windows</Filter>
-+ </ClCompile>
-+ <ClCompile Include="..\..\src\lib\platform\adl\adl-edid.cpp">
-+ <Filter>platform\adl</Filter>
-+ </ClCompile>
-+ <ClCompile Include="..\..\src\lib\platform\windows\dlfcn-win32.cpp">
-+ <Filter>platform\windows</Filter>
-+ </ClCompile>
-+ <ClCompile Include="..\..\src\lib\platform\nvidia\nv-edid.cpp">
-+ <Filter>platform\nvidia</Filter>
-+ </ClCompile>
-+ <ClCompile Include="..\..\src\lib\adapter\Pulse-Eight\USBCECAdapterCommands.cpp">
-+ <Filter>adapter\Pulse-Eight</Filter>
-+ </ClCompile>
-+ <ClCompile Include="..\..\src\lib\adapter\Pulse-Eight\USBCECAdapterCommunication.cpp">
-+ <Filter>adapter\Pulse-Eight</Filter>
-+ </ClCompile>
-+ <ClCompile Include="..\..\src\lib\adapter\Pulse-Eight\USBCECAdapterDetection.cpp">
-+ <Filter>adapter\Pulse-Eight</Filter>
-+ </ClCompile>
-+ <ClCompile Include="..\..\src\lib\adapter\Pulse-Eight\USBCECAdapterMessage.cpp">
-+ <Filter>adapter\Pulse-Eight</Filter>
-+ </ClCompile>
-+ <ClCompile Include="..\..\src\lib\adapter\Pulse-Eight\USBCECAdapterMessageQueue.cpp">
-+ <Filter>adapter\Pulse-Eight</Filter>
-+ </ClCompile>
-+ <ClCompile Include="..\..\src\lib\adapter\AdapterFactory.cpp">
-+ <Filter>adapter</Filter>
-+ </ClCompile>
-+ </ItemGroup>
-+ <ItemGroup>
-+ <ResourceCompile Include="libcec.rc" />
-+ </ItemGroup>
-+</Project>
-\ Kein Zeilenumbruch am Dateiende.
-Binärdateien libcec-2.1.4/project/libcec/resource.h und libcec-imx6/project/libcec/resource.h sind verschieden.
-diff -Nur libcec-2.1.4/project/libCEC.nsi libcec-imx6/project/libCEC.nsi
---- libcec-2.1.4/project/libCEC.nsi 1970-01-01 01:00:00.000000000 +0100
-+++ libcec-imx6/project/libCEC.nsi 2014-09-01 13:48:53.702431449 +0200
-@@ -0,0 +1,342 @@
-+;libCEC installer
-+;Copyright (C) 2011-2013 Pulse-Eight Ltd.
-+;http://www.pulse-eight.com/
-+
-+!include "MUI2.nsh"
-+!include "nsDialogs.nsh"
-+!include "LogicLib.nsh"
-+!include "x64.nsh"
-+
-+Name "Pulse-Eight libCEC"
-+OutFile "..\build\libCEC-installer.exe"
-+
-+XPStyle on
-+InstallDir "$PROGRAMFILES\Pulse-Eight\USB-CEC Adapter"
-+InstallDirRegKey HKLM "Software\Pulse-Eight\USB-CEC Adapter software" ""
-+RequestExecutionLevel admin
-+Var StartMenuFolder
-+Var VSRedistSetupError
-+Var VSRedistInstalled
-+
-+!define MUI_FINISHPAGE_LINK "Visit http://libcec.pulse-eight.com/ for more information."
-+!define MUI_FINISHPAGE_LINK_LOCATION "http://libcec.pulse-eight.com/"
-+!define MUI_ABORTWARNING
-+
-+!insertmacro MUI_PAGE_WELCOME
-+!insertmacro MUI_PAGE_LICENSE "..\COPYING"
-+!insertmacro MUI_PAGE_COMPONENTS
-+!insertmacro MUI_PAGE_DIRECTORY
-+
-+!define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKLM"
-+!define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\Pulse-Eight\USB-CEC Adapter sofware"
-+!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
-+!insertmacro MUI_PAGE_STARTMENU Application $StartMenuFolder
-+
-+!insertmacro MUI_PAGE_INSTFILES
-+!insertmacro MUI_PAGE_FINISH
-+
-+!insertmacro MUI_UNPAGE_WELCOME
-+!insertmacro MUI_UNPAGE_CONFIRM
-+!insertmacro MUI_UNPAGE_INSTFILES
-+!insertmacro MUI_UNPAGE_FINISH
-+
-+!insertmacro MUI_LANGUAGE "English"
-+
-+InstType "USB-CEC Driver & libCEC"
-+InstType "USB-CEC Driver Only"
-+InstType "Full installation"
-+
-+Section "USB-CEC Driver" SecDriver
-+ SetShellVarContext current
-+ SectionIn RO
-+ SectionIn 1 2 3
-+
-+ ; Uninstall the old unsigned software if it's found
-+ ReadRegStr $1 HKCU "Software\libCEC" ""
-+ ${If} $1 != ""
-+ MessageBox MB_OK \
-+ "A previous libCEC and USB-CEC Driver was found. This update requires the old version to be uninstalled. Press OK to uninstall the old version."
-+ ExecWait '"$1\Uninstall.exe" /S _?=$1'
-+ Delete "$1\Uninstall.exe"
-+ RMDir "$1"
-+ ${EndIf}
-+
-+ ; Delete libcec.dll and libcec.x64.dll from the system directory
-+ ; Let a seperate installer do this, when we need it
-+ Delete "$SYSDIR\libcec.dll"
-+ ${If} ${RunningX64}
-+ Delete "$SYSDIR\libcec.x64.dll"
-+ ${EndIf}
-+
-+ ; Copy to the installation directory
-+ SetOutPath "$INSTDIR"
-+ File "..\AUTHORS"
-+ File "..\COPYING"
-+
-+ ; Copy the driver installer
-+ SetOutPath "$INSTDIR\driver"
-+ File "..\build\p8-usbcec-driver-installer.exe"
-+
-+ ;Store installation folder
-+ WriteRegStr HKLM "Software\Pulse-Eight\USB-CEC Adapter software" "" $INSTDIR
-+
-+ ;Create uninstaller
-+ WriteUninstaller "$INSTDIR\Uninstall.exe"
-+
-+ !insertmacro MUI_STARTMENU_WRITE_BEGIN Application
-+ SetOutPath "$INSTDIR"
-+
-+ CreateDirectory "$SMPROGRAMS\$StartMenuFolder"
-+ CreateShortCut "$SMPROGRAMS\$StartMenuFolder\Uninstall Pulse-Eight USB-CEC Adapter software.lnk" "$INSTDIR\Uninstall.exe" \
-+ "" "$INSTDIR\Uninstall.exe" 0 SW_SHOWNORMAL \
-+ "" "Uninstall Pulse-Eight USB-CEC Adapter software."
-+
-+ WriteINIStr "$SMPROGRAMS\$StartMenuFolder\Visit Pulse-Eight.url" "InternetShortcut" "URL" "http://www.pulse-eight.com/"
-+ !insertmacro MUI_STARTMENU_WRITE_END
-+
-+ ;add entry to add/remove programs
-+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter sofware" \
-+ "DisplayName" "Pulse-Eight USB-CEC Adapter software"
-+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter sofware" \
-+ "UninstallString" "$INSTDIR\uninstall.exe"
-+ WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter sofware" \
-+ "NoModify" 1
-+ WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter sofware" \
-+ "NoRepair" 1
-+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter sofware" \
-+ "InstallLocation" "$INSTDIR"
-+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter sofware" \
-+ "DisplayIcon" "$INSTDIR\cec-client.exe,0"
-+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter sofware" \
-+ "Publisher" "Pulse-Eight Limited"
-+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter sofware" \
-+ "HelpLink" "http://www.pulse-eight.com/"
-+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter sofware" \
-+ "URLInfoAbout" "http://www.pulse-eight.com"
-+
-+ ;install driver
-+ ExecWait '"$INSTDIR\driver\p8-usbcec-driver-installer.exe" /S'
-+ Delete "$INSTDIR\driver\p8-usbcec-driver-installer.exe"
-+SectionEnd
-+
-+Section "libCEC" SecLibCec
-+ SetShellVarContext current
-+ SectionIn 1 3
-+
-+ ; Copy to the installation directory
-+ SetOutPath "$INSTDIR"
-+ File "..\ChangeLog"
-+ File "..\README"
-+ File "..\build\*.dll"
-+ File "..\build\*.xml"
-+ SetOutPath "$INSTDIR\x64"
-+ File /nonfatal "..\build\x64\*.dll"
-+ File /nonfatal "..\build\x64\*.xml"
-+
-+ ; Copy to XBMC\system
-+ ReadRegStr $1 HKCU "Software\XBMC" ""
-+ ${If} $1 != ""
-+ SetOutPath "$1\system"
-+ File "..\build\libcec.dll"
-+ ${EndIf}
-+
-+ ; Copy the headers
-+ SetOutPath "$INSTDIR\include"
-+ File /r /x *.so "..\include\cec*.*"
-+SectionEnd
-+
-+Section "CEC Debug Client" SecCecClient
-+ SetShellVarContext current
-+ SectionIn 3
-+
-+ ; Copy to the installation directory
-+ SetOutPath "$INSTDIR"
-+ File /x p8-usbcec-driver-installer.exe /x cec-tray.exe "..\build\*.exe"
-+ SetOutPath "$INSTDIR\x64"
-+ File /nonfatal "..\build\x64\*.exe"
-+
-+ !insertmacro MUI_STARTMENU_WRITE_BEGIN Application
-+ SetOutPath "$INSTDIR"
-+
-+ CreateDirectory "$SMPROGRAMS\$StartMenuFolder"
-+ ${If} ${RunningX64}
-+ CreateShortCut "$SMPROGRAMS\$StartMenuFolder\CEC Test client (x64).lnk" "$INSTDIR\x64\cec-client.exe" \
-+ "" "$INSTDIR\x64\cec-client.exe" 0 SW_SHOWNORMAL \
-+ "" "Start the CEC Test client (x64)."
-+ ${Else}
-+ CreateShortCut "$SMPROGRAMS\$StartMenuFolder\CEC Test client.lnk" "$INSTDIR\cec-client.exe" \
-+ "" "$INSTDIR\cec-client.exe" 0 SW_SHOWNORMAL \
-+ "" "Start the CEC Test client."
-+ ${EndIf}
-+ !insertmacro MUI_STARTMENU_WRITE_END
-+
-+SectionEnd
-+
-+Section "libCEC Tray Application" SecCecTray
-+ SetShellVarContext current
-+ SectionIn 1 3
-+
-+ ; Uninstall previous beta builds of the tray application
-+ ReadRegStr $1 HKLM "Software\Pulse-Eight\libCECTray" ""
-+ ${If} $1 != ""
-+ MessageBox MB_OK \
-+ "A previous beta build of the libCEC Tray Application was found. Press OK to uninstall the old version. Do not uninstall the driver when asked to. Thank you for participating in the beta test."
-+ ExecWait '"$1\Uninstall.exe" /S _?=$1'
-+ Delete "$1\Uninstall.exe"
-+ ${EndIf}
-+
-+ ; Replace cec-config-gui.exe
-+ Delete "$INSTDIR\cec-config-gui.exe"
-+ ${If} ${RunningX64}
-+ Delete "$INSTDIR\x64\cec-config-gui.exe"
-+ ${EndIf}
-+ Delete "$SMPROGRAMS\$StartMenuFolder\CEC Adapter Configuration.lnk"
-+ ${If} ${RunningX64}
-+ Delete "$SMPROGRAMS\$StartMenuFolder\CEC Adapter Configuration (x64).lnk"
-+ ${EndIf}
-+
-+ ; Copy to the installation directory
-+ SetOutPath "$INSTDIR"
-+ File "..\build\cec-tray.exe"
-+ SetOutPath "$INSTDIR\x64"
-+ File /nonfatal "..\build\x64\cec-tray.exe"
-+
-+ !insertmacro MUI_STARTMENU_WRITE_BEGIN Application
-+ SetOutPath "$INSTDIR"
-+
-+ CreateDirectory "$SMPROGRAMS\$StartMenuFolder"
-+ ${If} ${RunningX64}
-+ CreateShortCut "$SMPROGRAMS\$StartMenuFolder\libCEC Tray (x64).lnk" "$INSTDIR\x64\cec-tray.exe" \
-+ "" "$INSTDIR\x64\cec-tray.exe" 0 SW_SHOWNORMAL \
-+ "" "Start the libCEC Tray (x64)."
-+ ${Else}
-+ CreateShortCut "$SMPROGRAMS\$StartMenuFolder\libCEC Tray.lnk" "$INSTDIR\cec-tray.exe" \
-+ "" "$INSTDIR\cec-tray.exe" 0 SW_SHOWNORMAL \
-+ "" "Start the libCEC Tray."
-+ ${EndIf}
-+ !insertmacro MUI_STARTMENU_WRITE_END
-+
-+SectionEnd
-+
-+!define REDISTRIBUTABLE_SECTIONNAME "Microsoft Visual C++ 2010 Redistributable Package"
-+Section "" SecVCRedist
-+ SetShellVarContext current
-+ SectionIn 1 3
-+
-+
-+ ${If} $VSRedistInstalled != "Yes"
-+ ; Download redistributable
-+ SetOutPath "$TEMP\vc20XX"
-+ ${If} ${RunningX64}
-+ NSISdl::download http://packages.pulse-eight.net/windows/vcredist_x64.exe vcredist_x64.exe
-+ ExecWait '"$TEMP\vc20XX\vcredist_x64.exe" /q' $VSRedistSetupError
-+ ${Else}
-+ NSISdl::download http://packages.pulse-eight.net/windows/vcredist_x86.exe vcredist_x86.exe
-+ ExecWait '"$TEMP\vc20XX\vcredist_x86.exe" /q' $VSRedistSetupError
-+ ${Endif}
-+ RMDIR /r "$TEMP\vc20XX"
-+ ${Endif}
-+
-+SectionEnd
-+
-+Function .onInit
-+
-+ ; SP0 x86
-+ ReadRegDword $1 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{196BB40D-1578-3D01-B289-BEFC77A11A1E}" "Version"
-+ ${If} $1 != ""
-+ StrCpy $VSRedistInstalled "Yes"
-+ ${Endif}
-+
-+ ; SP0 x64
-+ ReadRegDword $1 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{DA5E371C-6333-3D8A-93A4-6FD5B20BCC6E}" "Version"
-+ ${If} $1 != ""
-+ StrCpy $VSRedistInstalled "Yes"
-+ ${Endif}
-+
-+ ; SP0 ia64
-+ ReadRegDword $1 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{C1A35166-4301-38E9-BA67-02823AD72A1B}" "Version"
-+ ${If} $1 != ""
-+ StrCpy $VSRedistInstalled "Yes"
-+ ${Endif}
-+
-+ ; SP1 x86
-+ ReadRegDword $1 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{F0C3E5D1-1ADE-321E-8167-68EF0DE699A5}" "Version"
-+ ${If} $1 != ""
-+ StrCpy $VSRedistInstalled "Yes"
-+ ${Endif}
-+
-+ ; SP1 x64
-+ ReadRegDword $1 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{1D8E6291-B0D5-35EC-8441-6616F567A0F7}" "Version"
-+ ${If} $1 != ""
-+ StrCpy $VSRedistInstalled "Yes"
-+ ${Endif}
-+
-+ ; SP1 ia64
-+ ReadRegDword $1 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{88C73C1C-2DE5-3B01-AFB8-B46EF4AB41CD}" "Version"
-+ ${If} $1 != ""
-+ StrCpy $VSRedistInstalled "Yes"
-+ ${Endif}
-+
-+ ${If} $VSRedistInstalled == "Yes"
-+ !insertMacro UnSelectSection ${SecVCRedist}
-+ SectionSetText ${SecVCRedist} ""
-+ ${Else}
-+ !insertMacro SelectSection ${SecVCRedist}
-+ SectionSetText ${SecVCRedist} "${REDISTRIBUTABLE_SECTIONNAME}"
-+ ${Endif}
-+
-+FunctionEnd
-+
-+;--------------------------------
-+;Uninstaller Section
-+
-+Section "Uninstall"
-+
-+ SetShellVarContext current
-+
-+ Delete "$INSTDIR\AUTHORS"
-+ Delete "$INSTDIR\*.exe"
-+ Delete "$INSTDIR\ChangeLog"
-+ Delete "$INSTDIR\COPYING"
-+ Delete "$INSTDIR\*.dll"
-+ Delete "$INSTDIR\*.lib"
-+ Delete "$INSTDIR\*.xml"
-+ Delete "$INSTDIR\x64\*.dll"
-+ Delete "$INSTDIR\x64\*.lib"
-+ Delete "$INSTDIR\x64\*.exe"
-+ Delete "$INSTDIR\x64\*.xml"
-+ Delete "$INSTDIR\README"
-+ Delete "$SYSDIR\libcec.dll"
-+ ${If} ${RunningX64}
-+ Delete "$SYSDIR\libcec.x64.dll"
-+ ${EndIf}
-+
-+ ; Uninstall the driver
-+ ReadRegStr $1 HKLM "Software\Pulse-Eight\USB-CEC Adapter driver" ""
-+ ${If} $1 != ""
-+ ExecWait '"$1\Uninstall.exe" /S _?=$1'
-+ ${EndIf}
-+
-+ RMDir /r "$INSTDIR\include"
-+ Delete "$INSTDIR\Uninstall.exe"
-+ RMDir /r "$INSTDIR"
-+ RMDir "$PROGRAMFILES\Pulse-Eight"
-+
-+ !insertmacro MUI_STARTMENU_GETFOLDER Application $StartMenuFolder
-+ Delete "$SMPROGRAMS\$StartMenuFolder\libCEC Tray.lnk"
-+ ${If} ${RunningX64}
-+ Delete "$SMPROGRAMS\$StartMenuFolder\libCEC Tray (x64).lnk"
-+ ${EndIf}
-+ Delete "$SMPROGRAMS\$StartMenuFolder\CEC Test client.lnk"
-+ ${If} ${RunningX64}
-+ Delete "$SMPROGRAMS\$StartMenuFolder\CEC Test client (x64).lnk"
-+ ${EndIf}
-+ Delete "$SMPROGRAMS\$StartMenuFolder\Uninstall Pulse-Eight USB-CEC Adapter software.lnk"
-+ Delete "$SMPROGRAMS\$StartMenuFolder\Visit Pulse-Eight.url"
-+ RMDir "$SMPROGRAMS\$StartMenuFolder"
-+
-+ DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter software"
-+ DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter driver"
-+ DeleteRegKey /ifempty HKLM "Software\Pulse-Eight\USB-CEC Adapter software"
-+ DeleteRegKey /ifempty HKLM "Software\Pulse-Eight"
-+SectionEnd
-Binärdateien libcec-2.1.4/project/LibCecSharp/LibCecSharp.rc und libcec-imx6/project/LibCecSharp/LibCecSharp.rc sind verschieden.
-diff -Nur libcec-2.1.4/project/LibCecSharp/LibCecSharp.vcxproj libcec-imx6/project/LibCecSharp/LibCecSharp.vcxproj
---- libcec-2.1.4/project/LibCecSharp/LibCecSharp.vcxproj 1970-01-01 01:00:00.000000000 +0100
-+++ libcec-imx6/project/LibCecSharp/LibCecSharp.vcxproj 2014-09-01 13:48:53.702431449 +0200
-@@ -0,0 +1,208 @@
-+<?xml version="1.0" encoding="utf-8"?>
-+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-+ <ItemGroup Label="ProjectConfigurations">
-+ <ProjectConfiguration Include="Debug|Win32">
-+ <Configuration>Debug</Configuration>
-+ <Platform>Win32</Platform>
-+ </ProjectConfiguration>
-+ <ProjectConfiguration Include="Debug|x64">
-+ <Configuration>Debug</Configuration>
-+ <Platform>x64</Platform>
-+ </ProjectConfiguration>
-+ <ProjectConfiguration Include="Release|Win32">
-+ <Configuration>Release</Configuration>
-+ <Platform>Win32</Platform>
-+ </ProjectConfiguration>
-+ <ProjectConfiguration Include="Release|x64">
-+ <Configuration>Release</Configuration>
-+ <Platform>x64</Platform>
-+ </ProjectConfiguration>
-+ </ItemGroup>
-+ <PropertyGroup Label="Globals">
-+ <ProjectGuid>{E54D4581-CD59-4687-BB10-694B8192EABA}</ProjectGuid>
-+ <RootNamespace>LibCecSharp</RootNamespace>
-+ <Keyword>ManagedCProj</Keyword>
-+ <TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
-+ </PropertyGroup>
-+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
-+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
-+ <ConfigurationType>DynamicLibrary</ConfigurationType>
-+ <PlatformToolset>v90</PlatformToolset>
-+ <CharacterSet>Unicode</CharacterSet>
-+ <CLRSupport>true</CLRSupport>
-+ <WholeProgramOptimization>true</WholeProgramOptimization>
-+ </PropertyGroup>
-+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
-+ <ConfigurationType>DynamicLibrary</ConfigurationType>
-+ <PlatformToolset>v90</PlatformToolset>
-+ <CharacterSet>Unicode</CharacterSet>
-+ <CLRSupport>true</CLRSupport>
-+ </PropertyGroup>
-+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
-+ <ConfigurationType>DynamicLibrary</ConfigurationType>
-+ <PlatformToolset>v90</PlatformToolset>
-+ <CharacterSet>Unicode</CharacterSet>
-+ <CLRSupport>true</CLRSupport>
-+ <WholeProgramOptimization>true</WholeProgramOptimization>
-+ </PropertyGroup>
-+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
-+ <ConfigurationType>DynamicLibrary</ConfigurationType>
-+ <PlatformToolset>v90</PlatformToolset>
-+ <CharacterSet>Unicode</CharacterSet>
-+ <CLRSupport>true</CLRSupport>
-+ </PropertyGroup>
-+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
-+ <ImportGroup Label="ExtensionSettings">
-+ </ImportGroup>
-+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
-+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-+ </ImportGroup>
-+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
-+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-+ </ImportGroup>
-+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
-+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-+ </ImportGroup>
-+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
-+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-+ </ImportGroup>
-+ <PropertyGroup Label="UserMacros" />
-+ <PropertyGroup>
-+ <_ProjectFileVersion>11.0.50727.1</_ProjectFileVersion>
-+ </PropertyGroup>
-+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-+ <ReferencePath>$(SolutionDir)..;$(ReferencePath)</ReferencePath>
-+ <OutDir>$(SolutionDir)..\build\</OutDir>
-+ <IntDir>$(Configuration)\</IntDir>
-+ </PropertyGroup>
-+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-+ <ReferencePath>$(SolutionDir)..;$(ReferencePath)</ReferencePath>
-+ <OutDir>$(SolutionDir)..\build\x64\</OutDir>
-+ <IntDir>$(Platform)\$(Configuration)\</IntDir>
-+ <LinkIncremental>true</LinkIncremental>
-+ </PropertyGroup>
-+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-+ <ReferencePath>$(SolutionDir)..;$(ReferencePath)</ReferencePath>
-+ <OutDir>$(SolutionDir)..\build\</OutDir>
-+ <IntDir>$(Configuration)\</IntDir>
-+ <LinkIncremental>false</LinkIncremental>
-+ </PropertyGroup>
-+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-+ <ReferencePath>$(SolutionDir)..;$(ReferencePath)</ReferencePath>
-+ <OutDir>$(SolutionDir)..\build\x64\</OutDir>
-+ <IntDir>$(Platform)\$(Configuration)\</IntDir>
-+ </PropertyGroup>
-+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-+ <Midl>
-+ <TargetEnvironment>X64</TargetEnvironment>
-+ </Midl>
-+ <ClCompile>
-+ <Optimization>Disabled</Optimization>
-+ <AdditionalIncludeDirectories>$(SolutionDir)..\include;$(SolutionDir)..\src;$(SolutionDir)..\src\lib\platform\windows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-+ <PreprocessorDefinitions>_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
-+ <PrecompiledHeader />
-+ <GenerateXMLDocumentationFiles>true</GenerateXMLDocumentationFiles>
-+ <WarningLevel>Level3</WarningLevel>
-+ <TreatWarningAsError>true</TreatWarningAsError>
-+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
-+ </ClCompile>
-+ <Link>
-+ <AdditionalDependencies>$(OutDir)libcec.lib;%(AdditionalDependencies)</AdditionalDependencies>
-+ <GenerateDebugInformation>true</GenerateDebugInformation>
-+ <AssemblyDebug>true</AssemblyDebug>
-+ <TargetMachine>MachineX86</TargetMachine>
-+ </Link>
-+ </ItemDefinitionGroup>
-+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-+ <Midl>
-+ <TargetEnvironment>X64</TargetEnvironment>
-+ </Midl>
-+ <ClCompile>
-+ <Optimization>Disabled</Optimization>
-+ <AdditionalIncludeDirectories>$(SolutionDir)..\include;$(SolutionDir)..\src;$(SolutionDir)..\src\lib\platform\windows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-+ <PreprocessorDefinitions>_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
-+ <PrecompiledHeader />
-+ <GenerateXMLDocumentationFiles>true</GenerateXMLDocumentationFiles>
-+ <WarningLevel>Level3</WarningLevel>
-+ <TreatWarningAsError>true</TreatWarningAsError>
-+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
-+ </ClCompile>
-+ <Link>
-+ <AdditionalDependencies>$(OutDir)libcec.lib;%(AdditionalDependencies)</AdditionalDependencies>
-+ <GenerateDebugInformation>true</GenerateDebugInformation>
-+ <AssemblyDebug>true</AssemblyDebug>
-+ <TargetMachine>MachineX64</TargetMachine>
-+ </Link>
-+ </ItemDefinitionGroup>
-+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-+ <Midl>
-+ <TargetEnvironment>X64</TargetEnvironment>
-+ </Midl>
-+ <ClCompile>
-+ <AdditionalIncludeDirectories>$(SolutionDir)..\include;$(SolutionDir)..\src;$(SolutionDir)..\src\lib\platform\windows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-+ <PreprocessorDefinitions>NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
-+ <PrecompiledHeader />
-+ <GenerateXMLDocumentationFiles>true</GenerateXMLDocumentationFiles>
-+ <WarningLevel>Level3</WarningLevel>
-+ <TreatWarningAsError>true</TreatWarningAsError>
-+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
-+ </ClCompile>
-+ <Link>
-+ <AdditionalDependencies>$(OutDir)libcec.lib;%(AdditionalDependencies)</AdditionalDependencies>
-+ <GenerateDebugInformation>true</GenerateDebugInformation>
-+ <TargetMachine>MachineX86</TargetMachine>
-+ </Link>
-+ </ItemDefinitionGroup>
-+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-+ <Midl>
-+ <TargetEnvironment>X64</TargetEnvironment>
-+ </Midl>
-+ <ClCompile>
-+ <AdditionalIncludeDirectories>$(SolutionDir)..\include;$(SolutionDir)..\src;$(SolutionDir)..\src\lib\platform\windows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-+ <PreprocessorDefinitions>NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
-+ <PrecompiledHeader />
-+ <GenerateXMLDocumentationFiles>true</GenerateXMLDocumentationFiles>
-+ <WarningLevel>Level3</WarningLevel>
-+ <TreatWarningAsError>true</TreatWarningAsError>
-+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
-+ </ClCompile>
-+ <Link>
-+ <AdditionalDependencies>$(OutDir)libcec.lib;%(AdditionalDependencies)</AdditionalDependencies>
-+ </Link>
-+ </ItemDefinitionGroup>
-+ <ItemGroup>
-+ <Reference Include="System">
-+ <CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
-+ <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
-+ </Reference>
-+ <Reference Include="System.Data">
-+ <CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
-+ <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
-+ </Reference>
-+ <Reference Include="System.Xml">
-+ <CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
-+ <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
-+ </Reference>
-+ </ItemGroup>
-+ <ItemGroup>
-+ <ClCompile Include="..\..\src\LibCecSharp\AssemblyInfo.cpp" />
-+ <ClCompile Include="..\..\src\LibCecSharp\LibCecSharp.cpp" />
-+ </ItemGroup>
-+ <ItemGroup>
-+ <ClInclude Include="..\..\include\cec.h" />
-+ <ClInclude Include="..\..\src\LibCecSharp\CecSharpTypes.h" />
-+ <ClInclude Include="..\..\include\cectypes.h" />
-+ <ClInclude Include="..\..\src\lib\platform\windows\stdint.h" />
-+ <ClInclude Include="resource.h" />
-+ </ItemGroup>
-+ <ItemGroup>
-+ <ResourceCompile Include="LibCecSharp.rc" />
-+ </ItemGroup>
-+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
-+ <ImportGroup Label="ExtensionTargets">
-+ </ImportGroup>
-+</Project>
-\ Kein Zeilenumbruch am Dateiende.
-diff -Nur libcec-2.1.4/project/LibCecSharp/LibCecSharp.vcxproj.filters libcec-imx6/project/LibCecSharp/LibCecSharp.vcxproj.filters
---- libcec-2.1.4/project/LibCecSharp/LibCecSharp.vcxproj.filters 1970-01-01 01:00:00.000000000 +0100
-+++ libcec-imx6/project/LibCecSharp/LibCecSharp.vcxproj.filters 2014-09-01 13:48:53.702431449 +0200
-@@ -0,0 +1,41 @@
-+<?xml version="1.0" encoding="utf-8"?>
-+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-+ <ItemGroup>
-+ <Filter Include="Source Files">
-+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
-+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
-+ </Filter>
-+ <Filter Include="Header Files">
-+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
-+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
-+ </Filter>
-+ </ItemGroup>
-+ <ItemGroup>
-+ <ClCompile Include="..\..\src\LibCecSharp\AssemblyInfo.cpp">
-+ <Filter>Source Files</Filter>
-+ </ClCompile>
-+ <ClCompile Include="..\..\src\LibCecSharp\LibCecSharp.cpp">
-+ <Filter>Source Files</Filter>
-+ </ClCompile>
-+ </ItemGroup>
-+ <ItemGroup>
-+ <ClInclude Include="..\..\include\cec.h">
-+ <Filter>Header Files</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\LibCecSharp\CecSharpTypes.h">
-+ <Filter>Header Files</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\include\cectypes.h">
-+ <Filter>Header Files</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\src\lib\platform\windows\stdint.h">
-+ <Filter>Header Files</Filter>
-+ </ClInclude>
-+ <ClInclude Include="resource.h">
-+ <Filter>Header Files</Filter>
-+ </ClInclude>
-+ </ItemGroup>
-+ <ItemGroup>
-+ <ResourceCompile Include="LibCecSharp.rc" />
-+ </ItemGroup>
-+</Project>
-\ Kein Zeilenumbruch am Dateiende.
-Binärdateien libcec-2.1.4/project/LibCecSharp/resource.h und libcec-imx6/project/LibCecSharp/resource.h sind verschieden.
-diff -Nur libcec-2.1.4/project/libcec.sln libcec-imx6/project/libcec.sln
---- libcec-2.1.4/project/libcec.sln 1970-01-01 01:00:00.000000000 +0100
-+++ libcec-imx6/project/libcec.sln 2014-09-01 13:48:53.702431449 +0200
-@@ -0,0 +1,74 @@
-+
-+Microsoft Visual Studio Solution File, Format Version 12.00
-+# Visual Studio 2012
-+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcec", "libcec\libcec.vcxproj", "{C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}"
-+EndProject
-+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testclient", "testclient\testclient.vcxproj", "{F01222BF-6B3D-43BD-B254-434031CB9887}"
-+ ProjectSection(ProjectDependencies) = postProject
-+ {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0} = {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}
-+ EndProjectSection
-+EndProject
-+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LibCecSharp", "LibCecSharp\LibCecSharp.vcxproj", "{E54D4581-CD59-4687-BB10-694B8192EABA}"
-+ ProjectSection(ProjectDependencies) = postProject
-+ {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0} = {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}
-+ EndProjectSection
-+EndProject
-+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B119505D-5CD1-48E4-BED1-9C2BF26153D5}"
-+EndProject
-+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CecSharpTester", "..\src\CecSharpTester\CecSharpTester.csproj", "{B6A7F3A9-F47C-41E5-9754-0BFF233B1172}"
-+EndProject
-+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibCECTray", "..\src\LibCecTray\LibCECTray.csproj", "{58C106FE-C159-46D3-97E1-73AB83232670}"
-+EndProject
-+Global
-+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
-+ Debug|x64 = Debug|x64
-+ Debug|x86 = Debug|x86
-+ Release|x64 = Release|x64
-+ Release|x86 = Release|x86
-+ EndGlobalSection
-+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
-+ {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Debug|x64.ActiveCfg = Debug|x64
-+ {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Debug|x64.Build.0 = Debug|x64
-+ {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Debug|x86.ActiveCfg = Debug|Win32
-+ {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Debug|x86.Build.0 = Debug|Win32
-+ {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Release|x64.ActiveCfg = Release|x64
-+ {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Release|x64.Build.0 = Release|x64
-+ {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Release|x86.ActiveCfg = Release|Win32
-+ {C04B0FB1-667D-4F1C-BDAE-A07CDFFAAAA0}.Release|x86.Build.0 = Release|Win32
-+ {F01222BF-6B3D-43BD-B254-434031CB9887}.Debug|x64.ActiveCfg = Debug|x64
-+ {F01222BF-6B3D-43BD-B254-434031CB9887}.Debug|x64.Build.0 = Debug|x64
-+ {F01222BF-6B3D-43BD-B254-434031CB9887}.Debug|x86.ActiveCfg = Debug|Win32
-+ {F01222BF-6B3D-43BD-B254-434031CB9887}.Debug|x86.Build.0 = Debug|Win32
-+ {F01222BF-6B3D-43BD-B254-434031CB9887}.Release|x64.ActiveCfg = Release|x64
-+ {F01222BF-6B3D-43BD-B254-434031CB9887}.Release|x64.Build.0 = Release|x64
-+ {F01222BF-6B3D-43BD-B254-434031CB9887}.Release|x86.ActiveCfg = Release|Win32
-+ {F01222BF-6B3D-43BD-B254-434031CB9887}.Release|x86.Build.0 = Release|Win32
-+ {E54D4581-CD59-4687-BB10-694B8192EABA}.Debug|x64.ActiveCfg = Debug|x64
-+ {E54D4581-CD59-4687-BB10-694B8192EABA}.Debug|x64.Build.0 = Debug|x64
-+ {E54D4581-CD59-4687-BB10-694B8192EABA}.Debug|x86.ActiveCfg = Debug|Win32
-+ {E54D4581-CD59-4687-BB10-694B8192EABA}.Debug|x86.Build.0 = Debug|Win32
-+ {E54D4581-CD59-4687-BB10-694B8192EABA}.Release|x64.ActiveCfg = Release|x64
-+ {E54D4581-CD59-4687-BB10-694B8192EABA}.Release|x64.Build.0 = Release|x64
-+ {E54D4581-CD59-4687-BB10-694B8192EABA}.Release|x86.ActiveCfg = Release|Win32
-+ {E54D4581-CD59-4687-BB10-694B8192EABA}.Release|x86.Build.0 = Release|Win32
-+ {B6A7F3A9-F47C-41E5-9754-0BFF233B1172}.Debug|x64.ActiveCfg = Debug|x64
-+ {B6A7F3A9-F47C-41E5-9754-0BFF233B1172}.Debug|x64.Build.0 = Debug|x64
-+ {B6A7F3A9-F47C-41E5-9754-0BFF233B1172}.Debug|x86.ActiveCfg = Debug|x86
-+ {B6A7F3A9-F47C-41E5-9754-0BFF233B1172}.Debug|x86.Build.0 = Debug|x86
-+ {B6A7F3A9-F47C-41E5-9754-0BFF233B1172}.Release|x64.ActiveCfg = Release|x64
-+ {B6A7F3A9-F47C-41E5-9754-0BFF233B1172}.Release|x64.Build.0 = Release|x64
-+ {B6A7F3A9-F47C-41E5-9754-0BFF233B1172}.Release|x86.ActiveCfg = Release|x86
-+ {B6A7F3A9-F47C-41E5-9754-0BFF233B1172}.Release|x86.Build.0 = Release|x86
-+ {58C106FE-C159-46D3-97E1-73AB83232670}.Debug|x64.ActiveCfg = Debug|x64
-+ {58C106FE-C159-46D3-97E1-73AB83232670}.Debug|x64.Build.0 = Debug|x64
-+ {58C106FE-C159-46D3-97E1-73AB83232670}.Debug|x86.ActiveCfg = Debug|x86
-+ {58C106FE-C159-46D3-97E1-73AB83232670}.Debug|x86.Build.0 = Debug|x86
-+ {58C106FE-C159-46D3-97E1-73AB83232670}.Release|x64.ActiveCfg = Release|x64
-+ {58C106FE-C159-46D3-97E1-73AB83232670}.Release|x64.Build.0 = Release|x64
-+ {58C106FE-C159-46D3-97E1-73AB83232670}.Release|x86.ActiveCfg = Release|x86
-+ {58C106FE-C159-46D3-97E1-73AB83232670}.Release|x86.Build.0 = Release|x86
-+ EndGlobalSection
-+ GlobalSection(SolutionProperties) = preSolution
-+ HideSolutionNode = FALSE
-+ EndGlobalSection
-+EndGlobal
-diff -Nur libcec-2.1.4/project/p8-usbcec-driver.nsi libcec-imx6/project/p8-usbcec-driver.nsi
---- libcec-2.1.4/project/p8-usbcec-driver.nsi 1970-01-01 01:00:00.000000000 +0100
-+++ libcec-imx6/project/p8-usbcec-driver.nsi 2014-09-01 13:48:53.702431449 +0200
-@@ -0,0 +1,118 @@
-+;p8-usbcec-driver installer
-+;Copyright (C) 2011-2013 Pulse-Eight Ltd.
-+;http://www.pulse-eight.com/
-+
-+!include "MUI2.nsh"
-+!include "nsDialogs.nsh"
-+!include "LogicLib.nsh"
-+!include "x64.nsh"
-+
-+Name "Pulse-Eight USB-CEC Adapter"
-+OutFile "..\build\p8-usbcec-driver-installer.exe"
-+
-+XPStyle on
-+InstallDir "$PROGRAMFILES\Pulse-Eight\USB-CEC Adapter\driver"
-+InstallDirRegKey HKLM "Software\Pulse-Eight\USB-CEC Adapter driver" ""
-+RequestExecutionLevel admin
-+
-+!define MUI_FINISHPAGE_LINK "Visit http://www.pulse-eight.com/ for more information."
-+!define MUI_FINISHPAGE_LINK_LOCATION "http://www.pulse-eight.com/"
-+!define MUI_ABORTWARNING
-+
-+!insertmacro MUI_PAGE_WELCOME
-+!insertmacro MUI_PAGE_LICENSE "..\COPYING"
-+!insertmacro MUI_PAGE_DIRECTORY
-+
-+!define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKLM"
-+!define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\Pulse-Eight\USB-CEC Adapter driver"
-+
-+!insertmacro MUI_PAGE_INSTFILES
-+!insertmacro MUI_PAGE_FINISH
-+
-+!insertmacro MUI_UNPAGE_WELCOME
-+!insertmacro MUI_UNPAGE_CONFIRM
-+!insertmacro MUI_UNPAGE_INSTFILES
-+!insertmacro MUI_UNPAGE_FINISH
-+
-+!insertmacro MUI_LANGUAGE "English"
-+
-+InstType "USB-CEC driver only"
-+
-+Section "USB-CEC driver" SecDriver
-+ SetShellVarContext current
-+ SectionIn RO
-+ SectionIn 1
-+
-+ ; Copy to the installation directory
-+ SetOutPath "$INSTDIR"
-+ File "..\AUTHORS"
-+ File "..\COPYING"
-+
-+ ; Copy the driver installer and .inf file
-+ File "..\build\dpinst-amd64.exe"
-+ File "..\build\dpinst-x86.exe"
-+ File "..\driver\p8usb-cec.inf"
-+ File "..\driver\p8usb-cec.cat"
-+
-+ ;Store installation folder
-+ WriteRegStr HKLM "Software\Pulse-Eight\USB-CEC Adapter driver" "" $INSTDIR
-+
-+ ;Create uninstaller
-+ WriteUninstaller "$INSTDIR\Uninstall.exe"
-+
-+ ;add entry to add/remove programs
-+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter driver" \
-+ "DisplayName" "Pulse-Eight USB-CEC Adapter driver"
-+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter driver" \
-+ "UninstallString" "$INSTDIR\uninstall.exe"
-+ WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter driver" \
-+ "NoModify" 1
-+ WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter driver" \
-+ "NoRepair" 1
-+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter driver" \
-+ "InstallLocation" "$INSTDIR"
-+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter driver" \
-+ "Publisher" "Pulse-Eight Limited"
-+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter driver" \
-+ "HelpLink" "http://www.pulse-eight.com/"
-+ WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter driver" \
-+ "URLInfoAbout" "http://www.pulse-eight.com"
-+
-+ ;install driver
-+ ${If} ${RunningX64}
-+ ExecWait '"$INSTDIR\dpinst-amd64.exe" /lm /sa /sw /PATH "$INSTDIR"'
-+ ${Else}
-+ ExecWait '"$INSTDIR\dpinst-x86.exe" /lm /sa /sw /PATH "$INSTDIR"'
-+ ${EndIf}
-+SectionEnd
-+
-+;--------------------------------
-+;Uninstaller Section
-+
-+Section "Uninstall"
-+
-+ SetShellVarContext current
-+
-+ ${If} ${RunningX64}
-+ ExecWait '"$INSTDIR\dpinst-amd64.exe" /u "$INSTDIR\p8usb-cec.inf"'
-+ ${Else}
-+ ExecWait '"$INSTDIR\dpinst-x64.exe" /u "$INSTDIR\p8usb-cec.inf"'
-+ ${EndIf}
-+ Delete "$INSTDIR\AUTHORS"
-+ Delete "$INSTDIR\COPYING"
-+ Delete "$INSTDIR\p8usb-cec.inf"
-+ Delete "$INSTDIR\p8usb-cec.cat"
-+ Delete "$INSTDIR\dpinst-amd64.exe"
-+ Delete "$INSTDIR\dpinst-x86.exe"
-+
-+ RMDir /r "$INSTDIR\include"
-+ Delete "$INSTDIR\Uninstall.exe"
-+ RMDir /r "$INSTDIR"
-+ RMDir "$PROGRAMFILES\Pulse-Eight\USB-CEC Adapter"
-+ RMDir "$PROGRAMFILES\Pulse-Eight"
-+
-+ DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter driver"
-+ DeleteRegKey /ifempty HKLM "Software\Pulse-Eight\USB-CEC Adapter driver"
-+ DeleteRegKey /ifempty HKLM "Software\Pulse-Eight"
-+
-+SectionEnd
-diff -Nur libcec-2.1.4/project/RPi/bootstrap.sh libcec-imx6/project/RPi/bootstrap.sh
---- libcec-2.1.4/project/RPi/bootstrap.sh 1970-01-01 01:00:00.000000000 +0100
-+++ libcec-imx6/project/RPi/bootstrap.sh 2014-09-01 13:48:53.702431449 +0200
-@@ -0,0 +1,32 @@
-+#!/bin/bash
-+
-+_usage()
-+{
-+ echo "Usage: $0 /path/to/toolchain /source/path"
-+ exit 1
-+}
-+
-+if [[ -z "$2" || ! -d "$1" || ! -d "$2" ]]; then
-+ echo "1 = '$1'"
-+ echo "2 = '$2'"
-+ _usage
-+fi
-+
-+SCRIPT_PATH=`dirname $0`
-+cd $SCRIPT_PATH
-+SCRIPT_PATH=`pwd`
-+cd -
-+
-+source $SCRIPT_PATH/config
-+mkdir -p $SCRIPT_PATH/deps
-+
-+cd "$2"
-+
-+if [ -f "configure.ac" ]; then
-+ _set_toolchain_path "$1"
-+ autoreconf -vif
-+ exit $?
-+fi
-+
-+exit 0
-+
-diff -Nur libcec-2.1.4/project/RPi/build-deps.sh libcec-imx6/project/RPi/build-deps.sh
---- libcec-2.1.4/project/RPi/build-deps.sh 1970-01-01 01:00:00.000000000 +0100
-+++ libcec-imx6/project/RPi/build-deps.sh 2014-09-01 13:48:53.702431449 +0200
-@@ -0,0 +1,36 @@
-+#!/bin/bash
-+
-+SCRIPT_PATH=`dirname $0`
-+cd $SCRIPT_PATH
-+SCRIPT_PATH=`pwd`
-+cd -
-+
-+source $SCRIPT_PATH/config
-+
-+mkdir -p $SCRIPT_PATH/deps/build
-+cd $SCRIPT_PATH/deps/build
-+
-+if [ ! -d lockdev ]; then
-+ wget ${TARBALL_LOCATION}${LOCKDEV_TARBALL}
-+ tar -Jxf $LOCKDEV_TARBALL
-+
-+ mv `echo $LOCKDEV_TARBALL | sed 's/.tar.xz//'` lockdev
-+ rm $LOCKDEV_TARBALL
-+
-+ cd $SCRIPT_PATH/deps/build/lockdev && \
-+ $SCRIPT_PATH/bootstrap.sh $SCRIPT_PATH/toolchain .
-+
-+ if [ $? -eq 0 ]; then
-+ _set_toolchain_path "$SCRIPT_PATH/toolchain"
-+ ./configure --host=$TARGET_HOST --build=`cc -dumpmachine` --prefix=$SCRIPT_PATH/deps && \
-+ make && \
-+ make install
-+
-+ exit $?
-+ else
-+ exit 1
-+ fi
-+fi
-+
-+exit 0
-+
-diff -Nur libcec-2.1.4/project/RPi/build.sh libcec-imx6/project/RPi/build.sh
---- libcec-2.1.4/project/RPi/build.sh 1970-01-01 01:00:00.000000000 +0100
-+++ libcec-imx6/project/RPi/build.sh 2014-09-01 13:48:53.702431449 +0200
-@@ -0,0 +1,37 @@
-+#!/bin/bash
-+
-+SCRIPT_PATH=`dirname $0`
-+cd $SCRIPT_PATH
-+SCRIPT_PATH=`pwd`
-+cd -
-+
-+if [ -z "$1" ]; then
-+ DEST_DIR="/opt/libcec-rpi"
-+else
-+ DEST_DIR="$1"
-+fi
-+
-+source $SCRIPT_PATH/config
-+
-+$SCRIPT_PATH/get-toolchain.sh && \
-+$SCRIPT_PATH/build-deps.sh && \
-+$SCRIPT_PATH/bootstrap.sh $SCRIPT_PATH/toolchain .
-+
-+if [ $? -eq 0 ]; then
-+ _set_toolchain_path "$SCRIPT_PATH/toolchain"
-+ # configure with --enable-rpi-cec-api so we bug out if we can't find Pi support or can't build it
-+ ./configure --host=$TARGET_HOST \
-+ --build=`cc -dumpmachine` \
-+ --prefix=$DEST_DIR \
-+ --enable-debug \
-+ --enable-rpi \
-+ --with-rpi-include-path="${SCRIPT_PATH}/firmware/hardfp/opt/vc/include" \
-+ --with-rpi-lib-path="${SCRIPT_PATH}/firmware/hardfp/opt/vc/lib" && \
-+ make clean && \
-+ make V=0
-+
-+ exit $?
-+else
-+ exit 1
-+fi
-+
-diff -Nur libcec-2.1.4/project/RPi/config libcec-imx6/project/RPi/config
---- libcec-2.1.4/project/RPi/config 1970-01-01 01:00:00.000000000 +0100
-+++ libcec-imx6/project/RPi/config 2014-09-01 13:48:53.702431449 +0200
-@@ -0,0 +1,37 @@
-+TOOLCHAIN_GIT="git://github.com/raspberrypi/tools.git"
-+FIRMWARE_GIT="git://github.com/raspberrypi/firmware.git"
-+TARBALL_LOCATION="http://sources.openelec.tv/devel/"
-+LOCKDEV_TARBALL="lockdev-16b8996.tar.xz"
-+
-+_set_toolchain_path()
-+{
-+ echo "Setting toolchain path to: '$1'"
-+
-+ export TARGET_TOOLCHAIN_PATH="$1/arm-bcm2708/arm-bcm2708hardfp-linux-gnueabi/bin"
-+ export TARGET_TOOLCHAIN_LIB_PATH="$1/arm-bcm2708/arm-bcm2708hardfp-linux-gnueabi/lib"
-+ export TARGET_HOST="arm-bcm2708hardfp-linux-gnueabi"
-+
-+ export CC=${TARGET_TOOLCHAIN_PATH}/${TARGET_HOST}-gcc
-+ export CXX=${TARGET_TOOLCHAIN_PATH}/${TARGET_HOST}-g++
-+ export LD=${TARGET_TOOLCHAIN_PATH}/${TARGET_HOST}-ld
-+ export AS=${TARGET_TOOLCHAIN_PATH}/${TARGET_HOST}-as
-+ export AR=${TARGET_TOOLCHAIN_PATH}/${TARGET_HOST}-ar
-+ export NM=${TARGET_TOOLCHAIN_PATH}/${TARGET_HOST}-nm
-+ export RANLIB=${TARGET_TOOLCHAIN_PATH}/${TARGET_HOST}-ranlib
-+ export OBJCOPY=${TARGET_TOOLCHAIN_PATH}/${TARGET_HOST}-objcopy
-+ export OBJDUMP=${TARGET_TOOLCHAIN_PATH}/${TARGET_HOST}-objdump
-+ export STRIP=${TARGET_TOOLCHAIN_PATH}/${TARGET_HOST}-strip
-+
-+ export CPPFLAGS="-I${SCRIPT_PATH}/deps/include"
-+ export CFLAGS="-march=armv6 -mfpu=vfp -mfloat-abi=hard -Wno-psabi -Wa,-mno-warn-deprecated -O3 -fexcess-precision=fast -ffast-math -I${SCRIPT_PATH}/deps/include"
-+ export CXXFLAGS="$CFLAGS"
-+ export LDFLAGS="-march=armv6 -mtune=arm1176jzf-s -L${SCRIPT_PATH}/deps/lib"
-+
-+ #export PKG_CONFIG_PATH="$TARGET_PKG_CONFIG_PATH"
-+ export PKG_CONFIG_LIBDIR="${SCRIPT_PATH}/deps/lib/pkgconfig:${SCRIPT_PATH}/deps/lib/share/pkgconfig"
-+ export PKG_CONFIG_SYSROOT_DIR="${SCRIPT_PATH}/deps"
-+
-+ export PATH="$TARGET_TOOLCHAIN_PATH:$PATH"
-+ export LD_LIBRARY_PATH="$TARGET_TOOLCHAIN_LIB_PATH:$LD_LIBRARY_PATH"
-+}
-+
-diff -Nur libcec-2.1.4/project/RPi/get-toolchain.sh libcec-imx6/project/RPi/get-toolchain.sh
---- libcec-2.1.4/project/RPi/get-toolchain.sh 1970-01-01 01:00:00.000000000 +0100
-+++ libcec-imx6/project/RPi/get-toolchain.sh 2014-09-01 13:48:53.702431449 +0200
-@@ -0,0 +1,29 @@
-+#!/bin/bash
-+
-+SCRIPT_PATH=`dirname $0`
-+cd $SCRIPT_PATH
-+SCRIPT_PATH=`pwd`
-+cd -
-+
-+source $SCRIPT_PATH/config
-+
-+if [ ! -d $SCRIPT_PATH/toolchain ]; then
-+ git clone $TOOLCHAIN_GIT $SCRIPT_PATH/toolchain
-+else
-+ cd $SCRIPT_PATH/toolchain
-+# git pull
-+fi
-+
-+if [ ! -d $SCRIPT_PATH/firmware ]; then
-+ git clone $FIRMWARE_GIT $SCRIPT_PATH/firmware
-+else
-+ cd $SCRIPT_PATH/firmware
-+# git pull
-+fi
-+
-+if [[ -d $SCRIPT_PATH/toolchain && -d $SCRIPT_PATH/firmware ]]; then
-+ exit 0
-+else
-+ exit 1
-+fi
-+
-Binärdateien libcec-2.1.4/project/testclient/resource.h und libcec-imx6/project/testclient/resource.h sind verschieden.
-Binärdateien libcec-2.1.4/project/testclient/testclient.rc und libcec-imx6/project/testclient/testclient.rc sind verschieden.
-diff -Nur libcec-2.1.4/project/testclient/testclient.vcxproj libcec-imx6/project/testclient/testclient.vcxproj
---- libcec-2.1.4/project/testclient/testclient.vcxproj 1970-01-01 01:00:00.000000000 +0100
-+++ libcec-imx6/project/testclient/testclient.vcxproj 2014-09-01 13:48:53.702431449 +0200
-@@ -0,0 +1,187 @@
-+<?xml version="1.0" encoding="utf-8"?>
-+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-+ <ItemGroup Label="ProjectConfigurations">
-+ <ProjectConfiguration Include="Debug|Win32">
-+ <Configuration>Debug</Configuration>
-+ <Platform>Win32</Platform>
-+ </ProjectConfiguration>
-+ <ProjectConfiguration Include="Debug|x64">
-+ <Configuration>Debug</Configuration>
-+ <Platform>x64</Platform>
-+ </ProjectConfiguration>
-+ <ProjectConfiguration Include="Release|Win32">
-+ <Configuration>Release</Configuration>
-+ <Platform>Win32</Platform>
-+ </ProjectConfiguration>
-+ <ProjectConfiguration Include="Release|x64">
-+ <Configuration>Release</Configuration>
-+ <Platform>x64</Platform>
-+ </ProjectConfiguration>
-+ </ItemGroup>
-+ <PropertyGroup Label="Globals">
-+ <ProjectGuid>{F01222BF-6B3D-43BD-B254-434031CB9887}</ProjectGuid>
-+ <Keyword>Win32Proj</Keyword>
-+ <RootNamespace>testclient</RootNamespace>
-+ </PropertyGroup>
-+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
-+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
-+ <ConfigurationType>Application</ConfigurationType>
-+ <UseDebugLibraries>true</UseDebugLibraries>
-+ <CharacterSet>MultiByte</CharacterSet>
-+ <PlatformToolset>v100</PlatformToolset>
-+ </PropertyGroup>
-+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
-+ <ConfigurationType>Application</ConfigurationType>
-+ <UseDebugLibraries>true</UseDebugLibraries>
-+ <CharacterSet>MultiByte</CharacterSet>
-+ <PlatformToolset>v100</PlatformToolset>
-+ </PropertyGroup>
-+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
-+ <ConfigurationType>Application</ConfigurationType>
-+ <UseDebugLibraries>false</UseDebugLibraries>
-+ <CharacterSet>MultiByte</CharacterSet>
-+ <PlatformToolset>v100</PlatformToolset>
-+ </PropertyGroup>
-+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
-+ <ConfigurationType>Application</ConfigurationType>
-+ <UseDebugLibraries>false</UseDebugLibraries>
-+ <CharacterSet>MultiByte</CharacterSet>
-+ <PlatformToolset>v100</PlatformToolset>
-+ </PropertyGroup>
-+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
-+ <ImportGroup Label="ExtensionSettings">
-+ </ImportGroup>
-+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-+ </ImportGroup>
-+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
-+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-+ </ImportGroup>
-+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-+ </ImportGroup>
-+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
-+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
-+ </ImportGroup>
-+ <PropertyGroup Label="UserMacros" />
-+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-+ <OutDir>$(SolutionDir)..\build\</OutDir>
-+ <TargetName>cec-client</TargetName>
-+ </PropertyGroup>
-+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-+ <OutDir>$(SolutionDir)..\build\x64\</OutDir>
-+ <TargetName>cec-client</TargetName>
-+ </PropertyGroup>
-+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-+ <OutDir>$(SolutionDir)..\build\</OutDir>
-+ <TargetName>cec-client</TargetName>
-+ </PropertyGroup>
-+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-+ <OutDir>$(SolutionDir)..\build\x64\</OutDir>
-+ <TargetName>cec-client</TargetName>
-+ </PropertyGroup>
-+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
-+ <ClCompile>
-+ <PrecompiledHeader>
-+ </PrecompiledHeader>
-+ <WarningLevel>Level4</WarningLevel>
-+ <Optimization>Disabled</Optimization>
-+ <PreprocessorDefinitions>_USE_32BIT_TIME_T;_DEBUG;_CRT_SECURE_NO_WARNINGS;_WINSOCKAPI_;__STDC_CONSTANT_MACROS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-+ <TreatWarningAsError>true</TreatWarningAsError>
-+ <DisableSpecificWarnings>
-+ </DisableSpecificWarnings>
-+ <AdditionalIncludeDirectories>$(SolutiontDir)..\..\include;$(SolutionDir)..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-+ </ClCompile>
-+ <Link>
-+ <SubSystem>Console</SubSystem>
-+ <GenerateDebugInformation>true</GenerateDebugInformation>
-+ <Version>
-+ </Version>
-+ </Link>
-+ </ItemDefinitionGroup>
-+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-+ <ClCompile>
-+ <PrecompiledHeader>
-+ </PrecompiledHeader>
-+ <WarningLevel>Level4</WarningLevel>
-+ <Optimization>Disabled</Optimization>
-+ <PreprocessorDefinitions>_WIN64;_DEBUG;_CRT_SECURE_NO_WARNINGS;_WINSOCKAPI_;__STDC_CONSTANT_MACROS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-+ <TreatWarningAsError>true</TreatWarningAsError>
-+ <DisableSpecificWarnings>
-+ </DisableSpecificWarnings>
-+ <AdditionalIncludeDirectories>$(SolutiontDir)..\..\include;$(SolutionDir)..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-+ </ClCompile>
-+ <Link>
-+ <SubSystem>Console</SubSystem>
-+ <GenerateDebugInformation>true</GenerateDebugInformation>
-+ <AdditionalDependencies>
-+ </AdditionalDependencies>
-+ <Version>
-+ </Version>
-+ </Link>
-+ </ItemDefinitionGroup>
-+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
-+ <ClCompile>
-+ <WarningLevel>Level4</WarningLevel>
-+ <PrecompiledHeader>
-+ </PrecompiledHeader>
-+ <Optimization>Full</Optimization>
-+ <FunctionLevelLinking>false</FunctionLevelLinking>
-+ <IntrinsicFunctions>true</IntrinsicFunctions>
-+ <PreprocessorDefinitions>_USE_32BIT_TIME_T;_CRT_SECURE_NO_WARNINGS;_WINSOCKAPI_;__STDC_CONSTANT_MACROS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-+ <TreatWarningAsError>true</TreatWarningAsError>
-+ <DisableSpecificWarnings>
-+ </DisableSpecificWarnings>
-+ <AdditionalIncludeDirectories>$(SolutionDir)..\include;$(SolutionDir)..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-+ <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
-+ </ClCompile>
-+ <Link>
-+ <SubSystem>Console</SubSystem>
-+ <GenerateDebugInformation>false</GenerateDebugInformation>
-+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
-+ <OptimizeReferences>true</OptimizeReferences>
-+ <Version>
-+ </Version>
-+ </Link>
-+ </ItemDefinitionGroup>
-+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
-+ <ClCompile>
-+ <WarningLevel>Level4</WarningLevel>
-+ <PrecompiledHeader>
-+ </PrecompiledHeader>
-+ <Optimization>Full</Optimization>
-+ <IntrinsicFunctions>true</IntrinsicFunctions>
-+ <PreprocessorDefinitions>_WIN64;_CRT_SECURE_NO_WARNINGS;_WINSOCKAPI_;__STDC_CONSTANT_MACROS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
-+ <TreatWarningAsError>true</TreatWarningAsError>
-+ <DisableSpecificWarnings>
-+ </DisableSpecificWarnings>
-+ <AdditionalIncludeDirectories>$(SolutionDir)..\include;$(SolutionDir)..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-+ <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
-+ </ClCompile>
-+ <Link>
-+ <SubSystem>Console</SubSystem>
-+ <GenerateDebugInformation>false</GenerateDebugInformation>
-+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
-+ <OptimizeReferences>true</OptimizeReferences>
-+ <AdditionalDependencies>
-+ </AdditionalDependencies>
-+ <Version>
-+ </Version>
-+ </Link>
-+ </ItemDefinitionGroup>
-+ <ItemGroup>
-+ <ClInclude Include="..\..\include\cec.h" />
-+ <ClInclude Include="..\..\include\cecloader.h" />
-+ <ClInclude Include="resource.h" />
-+ </ItemGroup>
-+ <ItemGroup>
-+ <ClCompile Include="..\..\src\lib\platform\windows\os-threads.cpp" />
-+ <ClCompile Include="..\..\src\testclient\main.cpp" />
-+ </ItemGroup>
-+ <ItemGroup>
-+ <ResourceCompile Include="testclient.rc" />
-+ </ItemGroup>
-+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
-+ <ImportGroup Label="ExtensionTargets">
-+ </ImportGroup>
-+</Project>
-\ Kein Zeilenumbruch am Dateiende.
-diff -Nur libcec-2.1.4/project/testclient/testclient.vcxproj.filters libcec-imx6/project/testclient/testclient.vcxproj.filters
---- libcec-2.1.4/project/testclient/testclient.vcxproj.filters 1970-01-01 01:00:00.000000000 +0100
-+++ libcec-imx6/project/testclient/testclient.vcxproj.filters 2014-09-01 13:48:53.702431449 +0200
-@@ -0,0 +1,29 @@
-+<?xml version="1.0" encoding="utf-8"?>
-+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-+ <ItemGroup>
-+ <Filter Include="exports">
-+ <UniqueIdentifier>{cc0a01c1-e1e7-4af8-9656-fa9463140613}</UniqueIdentifier>
-+ </Filter>
-+ <Filter Include="platform">
-+ <UniqueIdentifier>{f08c0a80-22d9-4bdd-90de-b9cf5fa88f99}</UniqueIdentifier>
-+ </Filter>
-+ </ItemGroup>
-+ <ItemGroup>
-+ <ClInclude Include="..\..\include\cec.h">
-+ <Filter>exports</Filter>
-+ </ClInclude>
-+ <ClInclude Include="..\..\include\cecloader.h">
-+ <Filter>exports</Filter>
-+ </ClInclude>
-+ <ClInclude Include="resource.h" />
-+ </ItemGroup>
-+ <ItemGroup>
-+ <ClCompile Include="..\..\src\testclient\main.cpp" />
-+ <ClCompile Include="..\..\src\lib\platform\windows\os-threads.cpp">
-+ <Filter>platform</Filter>
-+ </ClCompile>
-+ </ItemGroup>
-+ <ItemGroup>
-+ <ResourceCompile Include="testclient.rc" />
-+ </ItemGroup>
-+</Project>
-\ Kein Zeilenumbruch am Dateiende.
-diff -Nur libcec-2.1.4/src/lib/adapter/AdapterFactory.cpp libcec-imx6/src/lib/adapter/AdapterFactory.cpp
---- libcec-2.1.4/src/lib/adapter/AdapterFactory.cpp 2013-12-16 10:32:51.000000000 +0100
-+++ libcec-imx6/src/lib/adapter/AdapterFactory.cpp 2014-09-01 13:48:54.718437326 +0200
-@@ -52,6 +52,11 @@
- #include "TDA995x/TDA995xCECAdapterCommunication.h"
- #endif
-
-+#if defined(HAVE_IMX_API)
-+#include "IMX/IMXCECAdapterDetection.h"
-+#include "IMX/IMXCECAdapterCommunication.h"
-+#endif
-+
- using namespace std;
- using namespace CEC;
-
-@@ -109,7 +114,22 @@
- }
- #endif
-
--#if !defined(HAVE_RPI_API) && !defined(HAVE_P8_USB) && !defined(HAVE_TDA995X_API)
-+
-+#if defined(HAVE_IMX_API)
-+ if (iAdaptersFound < iBufSize && CIMXCECAdapterDetection::FindAdapter() &&
-+ (!strDevicePath || !strcmp(strDevicePath, CEC_IMX_VIRTUAL_COM)))
-+ {
-+ snprintf(deviceList[iAdaptersFound].strComPath, sizeof(deviceList[iAdaptersFound].strComPath), CEC_IMX_PATH);
-+ snprintf(deviceList[iAdaptersFound].strComName, sizeof(deviceList[iAdaptersFound].strComName), CEC_IMX_VIRTUAL_COM);
-+ deviceList[iAdaptersFound].iVendorId = IMX_ADAPTER_VID;
-+ deviceList[iAdaptersFound].iProductId = IMX_ADAPTER_PID;
-+ deviceList[iAdaptersFound].adapterType = ADAPTERTYPE_IMX;
-+ iAdaptersFound++;
-+ }
-+#endif
-+
-+
-+#if !defined(HAVE_RPI_API) && !defined(HAVE_P8_USB) && !defined(HAVE_TDA995X_API) && !defined(HAVE_IMX_API)
- #error "libCEC doesn't have support for any type of adapter. please check your build system or configuration"
- #endif
-
-@@ -128,11 +148,16 @@
- return new CRPiCECAdapterCommunication(m_lib->m_cec);
- #endif
-
-+#if defined(HAVE_IMX_API)
-+ if (!strcmp(strPort, CEC_IMX_VIRTUAL_COM))
-+ return new CIMXCECAdapterCommunication(m_lib->m_cec);
-+#endif
-+
- #if defined(HAVE_P8_USB)
- return new CUSBCECAdapterCommunication(m_lib->m_cec, strPort, iBaudRate);
- #endif
-
--#if !defined(HAVE_RPI_API) && !defined(HAVE_P8_USB) && !defined(HAVE_TDA995X_API)
-+#if !defined(HAVE_RPI_API) && !defined(HAVE_P8_USB) && !defined(HAVE_TDA995X_API) && !defined(HAVE_IMX_API)
- return NULL;
- #endif
- }
-diff -Nur libcec-2.1.4/src/lib/adapter/IMX/AdapterMessageQueue.h libcec-imx6/src/lib/adapter/IMX/AdapterMessageQueue.h
---- libcec-2.1.4/src/lib/adapter/IMX/AdapterMessageQueue.h 1970-01-01 01:00:00.000000000 +0100
-+++ libcec-imx6/src/lib/adapter/IMX/AdapterMessageQueue.h 2014-09-01 13:48:54.718437326 +0200
-@@ -0,0 +1,134 @@
-+#pragma once
-+/*
-+ * This file is part of the libCEC(R) library.
-+ *
-+ * libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited. All rights reserved.
-+ * libCEC(R) is an original work, containing original code.
-+ *
-+ * libCEC(R) is a trademark of Pulse-Eight Limited.
-+ *
-+ * This program is dual-licensed; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ *
-+ *
-+ * Alternatively, you can license this library under a commercial license,
-+ * please contact Pulse-Eight Licensing for more information.
-+ *
-+ * For more information contact:
-+ * Pulse-Eight Licensing <license@pulse-eight.com>
-+ * http://www.pulse-eight.com/
-+ * http://www.pulse-eight.net/
-+ */
-+
-+#include "lib/platform/threads/mutex.h"
-+
-+namespace CEC
-+{
-+ using namespace PLATFORM;
-+
-+ class CAdapterMessageQueueEntry
-+ {
-+ public:
-+ CAdapterMessageQueueEntry(const cec_command &command)
-+ : m_bWaiting(true), m_retval((uint32_t)-1), m_bSucceeded(false)
-+ {
-+ m_hash = hashValue(
-+ uint32_t(command.opcode_set ? command.opcode : CEC_OPCODE_NONE),
-+ command.initiator, command.destination);
-+ }
-+
-+ virtual ~CAdapterMessageQueueEntry(void) {}
-+
-+ /*!
-+ * @brief Query result from worker thread
-+ */
-+ uint32_t Result() const
-+ {
-+ return m_retval;
-+ }
-+
-+ /*!
-+ * @brief Signal waiting threads
-+ */
-+ void Broadcast(void)
-+ {
-+ CLockObject lock(m_mutex);
-+ m_condition.Broadcast();
-+ }
-+
-+ /*!
-+ * @brief Signal waiting thread(s) when message matches this entry
-+ */
-+ bool CheckMatch(uint32_t opcode, cec_logical_address initiator,
-+ cec_logical_address destination, uint32_t response)
-+ {
-+ uint32_t hash = hashValue(opcode, initiator, destination);
-+
-+ if (hash == m_hash)
-+ {
-+ CLockObject lock(m_mutex);
-+
-+ m_retval = response;
-+ m_bSucceeded = true;
-+ m_condition.Signal();
-+ return true;
-+ }
-+
-+ return false;
-+ }
-+
-+ /*!
-+ * @brief Wait for a response to this command.
-+ * @param iTimeout The timeout to use while waiting.
-+ * @return True when a response was received before the timeout passed, false otherwise.
-+ */
-+ bool Wait(uint32_t iTimeout)
-+ {
-+ CLockObject lock(m_mutex);
-+
-+ bool bReturn = m_bSucceeded ? true : m_condition.Wait(m_mutex, m_bSucceeded, iTimeout);
-+ m_bWaiting = false;
-+ return bReturn;
-+ }
-+
-+ /*!
-+ * @return True while a thread is waiting for a signal or isn't waiting yet, false otherwise.
-+ */
-+ bool IsWaiting(void)
-+ {
-+ CLockObject lock(m_mutex);
-+ return m_bWaiting;
-+ }
-+
-+ /*!
-+ * @return Hash value for given cec_command
-+ */
-+ static uint32_t hashValue(uint32_t opcode,
-+ cec_logical_address initiator,
-+ cec_logical_address destination)
-+ {
-+ return 1 | ((uint32_t)initiator << 8) |
-+ ((uint32_t)destination << 16) | ((uint32_t)opcode << 16);
-+ }
-+
-+ private:
-+ bool m_bWaiting; /**< true while a thread is waiting or when it hasn't started waiting yet */
-+ PLATFORM::CCondition<bool> m_condition; /**< the condition to wait on */
-+ PLATFORM::CMutex m_mutex; /**< mutex for changes to this class */
-+ uint32_t m_hash;
-+ uint32_t m_retval;
-+ bool m_bSucceeded;
-+ };
-+
-+};
-diff -Nur libcec-2.1.4/src/lib/adapter/IMX/IMXCECAdapterCommunication.cpp libcec-imx6/src/lib/adapter/IMX/IMXCECAdapterCommunication.cpp
---- libcec-2.1.4/src/lib/adapter/IMX/IMXCECAdapterCommunication.cpp 1970-01-01 01:00:00.000000000 +0100
-+++ libcec-imx6/src/lib/adapter/IMX/IMXCECAdapterCommunication.cpp 2014-09-01 13:48:54.718437326 +0200
-@@ -0,0 +1,279 @@
-+/*
-+ * This file is part of the libCEC(R) library.
-+ *
-+ * libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited. All rights reserved.
-+ * libCEC(R) is an original work, containing original code.
-+ *
-+ * libCEC(R) is a trademark of Pulse-Eight Limited.
-+ *
-+ * IMX adpater port is Copyright (C) 2013 by Stephan Rafin
-+ *
-+ * You can redistribute this file and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ *
-+ *
-+ */
-+
-+#include "env.h"
-+
-+#if defined(HAVE_IMX_API)
-+#include "IMXCECAdapterCommunication.h"
-+
-+#include "lib/CECTypeUtils.h"
-+#include "lib/LibCEC.h"
-+#include "lib/platform/sockets/cdevsocket.h"
-+#include "lib/platform/util/StdString.h"
-+#include "lib/platform/util/buffer.h"
-+
-+/*
-+ * Ioctl definitions from kernel header
-+ */
-+#define HDMICEC_IOC_MAGIC 'H'
-+#define HDMICEC_IOC_SETLOGICALADDRESS _IOW(HDMICEC_IOC_MAGIC, 1, unsigned char)
-+#define HDMICEC_IOC_STARTDEVICE _IO(HDMICEC_IOC_MAGIC, 2)
-+#define HDMICEC_IOC_STOPDEVICE _IO(HDMICEC_IOC_MAGIC, 3)
-+#define HDMICEC_IOC_GETPHYADDRESS _IOR(HDMICEC_IOC_MAGIC, 4, unsigned char[4])
-+
-+#define MAX_CEC_MESSAGE_LEN 17
-+
-+#define MESSAGE_TYPE_RECEIVE_SUCCESS 1
-+#define MESSAGE_TYPE_NOACK 2
-+#define MESSAGE_TYPE_DISCONNECTED 3
-+#define MESSAGE_TYPE_CONNECTED 4
-+#define MESSAGE_TYPE_SEND_SUCCESS 5
-+
-+typedef struct hdmi_cec_event{
-+ int event_type;
-+ int msg_len;
-+ unsigned char msg[MAX_CEC_MESSAGE_LEN];
-+}hdmi_cec_event;
-+
-+
-+using namespace std;
-+using namespace CEC;
-+using namespace PLATFORM;
-+
-+#include "AdapterMessageQueue.h"
-+
-+#define LIB_CEC m_callback->GetLib()
-+
-+// these are defined in nxp private header file
-+#define CEC_MSG_SUCCESS 0x00 /*Message transmisson Succeed*/
-+#define CEC_CSP_OFF_STATE 0x80 /*CSP in Off State*/
-+#define CEC_BAD_REQ_SERVICE 0x81 /*Bad .req service*/
-+#define CEC_MSG_FAIL_UNABLE_TO_ACCESS 0x82 /*Message transmisson failed: Unable to access CEC line*/
-+#define CEC_MSG_FAIL_ARBITRATION_ERROR 0x83 /*Message transmisson failed: Arbitration error*/
-+#define CEC_MSG_FAIL_BIT_TIMMING_ERROR 0x84 /*Message transmisson failed: Bit timming error*/
-+#define CEC_MSG_FAIL_DEST_NOT_ACK 0x85 /*Message transmisson failed: Destination Address not aknowledged*/
-+#define CEC_MSG_FAIL_DATA_NOT_ACK 0x86 /*Message transmisson failed: Databyte not acknowledged*/
-+
-+
-+CIMXCECAdapterCommunication::CIMXCECAdapterCommunication(IAdapterCommunicationCallback *callback) :
-+ IAdapterCommunication(callback)/*,
-+ m_bLogicalAddressChanged(false)*/
-+{
-+ CLockObject lock(m_mutex);
-+
-+ m_iNextMessage = 0;
-+ //m_logicalAddresses.Clear();
-+ m_logicalAddress = CECDEVICE_UNKNOWN;
-+ m_dev = new CCDevSocket(CEC_IMX_PATH);
-+}
-+
-+CIMXCECAdapterCommunication::~CIMXCECAdapterCommunication(void)
-+{
-+ Close();
-+
-+ CLockObject lock(m_mutex);
-+ delete m_dev;
-+ m_dev = 0;
-+}
-+
-+bool CIMXCECAdapterCommunication::IsOpen(void)
-+{
-+ return IsInitialised() && m_dev->IsOpen();
-+}
-+
-+bool CIMXCECAdapterCommunication::Open(uint32_t iTimeoutMs, bool UNUSED(bSkipChecks), bool bStartListening)
-+{
-+ if (m_dev->Open(iTimeoutMs))
-+ {
-+ if (!bStartListening || CreateThread()) {
-+ if (m_dev->Ioctl(HDMICEC_IOC_STARTDEVICE, NULL) != 0) {
-+ LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: Unable to start device\n", __func__);
-+ }
-+ return true;
-+ }
-+ m_dev->Close();
-+ }
-+
-+ return false;
-+}
-+
-+
-+void CIMXCECAdapterCommunication::Close(void)
-+{
-+ StopThread(0);
-+ if (m_dev->Ioctl(HDMICEC_IOC_STOPDEVICE, NULL) != 0) {
-+ LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: Unable to stop device\n", __func__);
-+ }
-+ m_dev->Close();
-+}
-+
-+
-+std::string CIMXCECAdapterCommunication::GetError(void) const
-+{
-+ std::string strError(m_strError);
-+ return strError;
-+}
-+
-+
-+cec_adapter_message_state CIMXCECAdapterCommunication::Write(
-+ const cec_command &data, bool &UNUSED(bRetry), uint8_t UNUSED(iLineTimeout), bool UNUSED(bIsReply))
-+{
-+ //cec_frame frame;
-+ unsigned char message[MAX_CEC_MESSAGE_LEN];
-+ int msg_len = 1;
-+ cec_adapter_message_state rc = ADAPTER_MESSAGE_STATE_ERROR;
-+
-+ if ((size_t)data.parameters.size + data.opcode_set + 1 > sizeof(message))
-+ {
-+ LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: data size too large !", __func__);
-+ return ADAPTER_MESSAGE_STATE_ERROR;
-+ }
-+
-+ message[0] = (data.initiator << 4) | (data.destination & 0x0f);
-+ if (data.opcode_set)
-+ {
-+ message[1] = data.opcode;
-+ msg_len++;
-+ memcpy(&message[2], data.parameters.data, data.parameters.size);
-+ msg_len+=data.parameters.size;
-+ }
-+
-+ if (m_dev->Write(message, msg_len) == msg_len)
-+ {
-+ rc = ADAPTER_MESSAGE_STATE_SENT_ACKED;
-+ }
-+ else
-+ LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: sent command error !", __func__);
-+
-+ return rc;
-+}
-+
-+
-+uint16_t CIMXCECAdapterCommunication::GetFirmwareVersion(void)
-+{
-+ /* FIXME add ioctl ? */
-+ return 0;
-+}
-+
-+
-+cec_vendor_id CIMXCECAdapterCommunication::GetVendorId(void)
-+{
-+ return CEC_VENDOR_UNKNOWN;
-+}
-+
-+
-+uint16_t CIMXCECAdapterCommunication::GetPhysicalAddress(void)
-+{
-+ uint32_t info;
-+
-+ if (m_dev->Ioctl(HDMICEC_IOC_GETPHYADDRESS, &info) != 0)
-+ {
-+ LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: HDMICEC_IOC_GETPHYADDRESS failed !", __func__);
-+ return CEC_INVALID_PHYSICAL_ADDRESS;
-+ }
-+
-+ return info;
-+}
-+
-+
-+cec_logical_addresses CIMXCECAdapterCommunication::GetLogicalAddresses(void)
-+{
-+ cec_logical_addresses addresses;
-+ addresses.Clear();
-+
-+ CLockObject lock(m_mutex);
-+ if ( m_logicalAddress != CECDEVICE_UNKNOWN)
-+ addresses.Set(m_logicalAddress);
-+
-+ return addresses;
-+}
-+
-+
-+bool CIMXCECAdapterCommunication::SetLogicalAddresses(const cec_logical_addresses &addresses)
-+{
-+ int log_addr = addresses.primary;
-+
-+ CLockObject lock(m_mutex);
-+ if (m_logicalAddress == log_addr)
-+ return true;
-+
-+ if (m_dev->Ioctl(HDMICEC_IOC_SETLOGICALADDRESS, (void *)log_addr) != 0)
-+ {
-+ LIB_CEC->AddLog(CEC_LOG_ERROR, "%s: HDMICEC_IOC_SETLOGICALADDRESS failed !", __func__);
-+ return false;
-+ }
-+
-+ m_logicalAddress = (cec_logical_address)log_addr;
-+ return true;
-+}
-+
-+
-+void *CIMXCECAdapterCommunication::Process(void)
-+{
-+ bool bHandled;
-+ hdmi_cec_event event;
-+ int ret;
-+
-+ uint32_t opcode, status;
-+ cec_logical_address initiator, destination;
-+
-+ while (!IsStopped())
-+ {
-+ ret = m_dev->Read((char *)&event, sizeof(event), 5000);
-+ if (ret > 0)
-+ {
-+
-+ initiator = cec_logical_address(event.msg[0] >> 4);
-+ destination = cec_logical_address(event.msg[0] & 0x0f);
-+
-+ //LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s: Read data : type : %d initiator %d dest %d", __func__, event.event_type, initiator, destination);
-+ if (event.event_type == MESSAGE_TYPE_RECEIVE_SUCCESS)
-+ /* Message received */
-+ {
-+ cec_command cmd;
-+
-+ cec_command::Format(
-+ cmd, initiator, destination,
-+ ( event.msg_len > 1 ) ? cec_opcode(event.msg[1]) : CEC_OPCODE_NONE);
-+
-+ for( uint8_t i = 2; i < event.msg_len; i++ )
-+ cmd.parameters.PushBack(event.msg[i]);
-+
-+ if (!IsStopped())
-+ m_callback->OnCommandReceived(cmd);
-+ }
-+ /* We are not interested in other events */
-+ } /*else {
-+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s: Read returned %d", __func__, ret);
-+ }*/
-+
-+ }
-+
-+ return 0;
-+}
-+
-+#endif // HAVE_IMX_API
-diff -Nur libcec-2.1.4/src/lib/adapter/IMX/IMXCECAdapterCommunication.h libcec-imx6/src/lib/adapter/IMX/IMXCECAdapterCommunication.h
---- libcec-2.1.4/src/lib/adapter/IMX/IMXCECAdapterCommunication.h 1970-01-01 01:00:00.000000000 +0100
-+++ libcec-imx6/src/lib/adapter/IMX/IMXCECAdapterCommunication.h 2014-09-01 13:48:54.722437350 +0200
-@@ -0,0 +1,114 @@
-+#pragma once
-+/*
-+ * This file is part of the libCEC(R) library.
-+ *
-+ * libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited. All rights reserved.
-+ * libCEC(R) is an original work, containing original code.
-+ *
-+ * libCEC(R) is a trademark of Pulse-Eight Limited.
-+ *
-+ * IMX adpater port is Copyright (C) 2013 by Stephan Rafin
-+ *
-+ * You can redistribute this file and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ *
-+ *
-+ */
-+
-+#if defined(HAVE_IMX_API)
-+
-+#include "lib/platform/threads/mutex.h"
-+#include "lib/platform/threads/threads.h"
-+#include "lib/platform/sockets/socket.h"
-+#include "lib/adapter/AdapterCommunication.h"
-+#include <map>
-+
-+#define IMX_ADAPTER_VID 0x0471 /*FIXME TBD*/
-+#define IMX_ADAPTER_PID 0x1001
-+
-+
-+
-+namespace PLATFORM
-+{
-+ class CCDevSocket;
-+};
-+
-+
-+namespace CEC
-+{
-+ class CAdapterMessageQueueEntry;
-+
-+ class CIMXCECAdapterCommunication : public IAdapterCommunication, public PLATFORM::CThread
-+ {
-+ public:
-+ /*!
-+ * @brief Create a new USB-CEC communication handler.
-+ * @param callback The callback to use for incoming CEC commands.
-+ */
-+ CIMXCECAdapterCommunication(IAdapterCommunicationCallback *callback);
-+ virtual ~CIMXCECAdapterCommunication(void);
-+
-+ /** @name IAdapterCommunication implementation */
-+ ///{
-+ bool Open(uint32_t iTimeoutMs = CEC_DEFAULT_CONNECT_TIMEOUT, bool bSkipChecks = false, bool bStartListening = true);
-+ void Close(void);
-+ bool IsOpen(void);
-+ std::string GetError(void) const;
-+ cec_adapter_message_state Write(const cec_command &data, bool &bRetry, uint8_t iLineTimeout, bool bIsReply);
-+
-+ bool SetLineTimeout(uint8_t UNUSED(iTimeout)) { return true; }
-+ bool StartBootloader(void) { return false; }
-+ bool SetLogicalAddresses(const cec_logical_addresses &addresses);
-+ cec_logical_addresses GetLogicalAddresses(void);
-+ bool PingAdapter(void) { return IsInitialised(); }
-+ uint16_t GetFirmwareVersion(void);
-+ uint32_t GetFirmwareBuildDate(void) { return 0; }
-+ bool IsRunningLatestFirmware(void) { return true; }
-+ bool PersistConfiguration(const libcec_configuration & UNUSED(configuration)) { return false; }
-+ bool GetConfiguration(libcec_configuration & UNUSED(configuration)) { return false; }
-+ std::string GetPortName(void) { return std::string("IMX"); }
-+ uint16_t GetPhysicalAddress(void);
-+ bool SetControlledMode(bool UNUSED(controlled)) { return true; }
-+ cec_vendor_id GetVendorId(void);
-+ bool SupportsSourceLogicalAddress(const cec_logical_address address) { return address > CECDEVICE_TV && address <= CECDEVICE_BROADCAST; }
-+ cec_adapter_type GetAdapterType(void) { return ADAPTERTYPE_IMX; }
-+ uint16_t GetAdapterVendorId(void) const { return IMX_ADAPTER_VID; }
-+ uint16_t GetAdapterProductId(void) const { return IMX_ADAPTER_PID; }
-+ void SetActiveSource(bool UNUSED(bSetTo), bool UNUSED(bClientUnregistered)) {}
-+ ///}
-+
-+ /** @name PLATFORM::CThread implementation */
-+ ///{
-+ void *Process(void);
-+ ///}
-+
-+ private:
-+ bool IsInitialised(void) const { return m_dev != 0; };
-+
-+ std::string m_strError; /**< current error message */
-+
-+ //cec_logical_addresses m_logicalAddresses;
-+ cec_logical_address m_logicalAddress;
-+
-+ PLATFORM::CMutex m_mutex;
-+ PLATFORM::CCDevSocket *m_dev; /**< the device connection */
-+
-+ PLATFORM::CMutex m_messageMutex;
-+ uint32_t m_iNextMessage;
-+ std::map<uint32_t, CAdapterMessageQueueEntry *> m_messages;
-+ };
-+
-+};
-+
-+#endif
-diff -Nur libcec-2.1.4/src/lib/adapter/IMX/IMXCECAdapterDetection.cpp libcec-imx6/src/lib/adapter/IMX/IMXCECAdapterDetection.cpp
---- libcec-2.1.4/src/lib/adapter/IMX/IMXCECAdapterDetection.cpp 1970-01-01 01:00:00.000000000 +0100
-+++ libcec-imx6/src/lib/adapter/IMX/IMXCECAdapterDetection.cpp 2014-09-01 13:48:54.722437350 +0200
-@@ -0,0 +1,42 @@
-+/*
-+ * This file is part of the libCEC(R) library.
-+ *
-+ * libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited. All rights reserved.
-+ * libCEC(R) is an original work, containing original code.
-+ *
-+ * libCEC(R) is a trademark of Pulse-Eight Limited.
-+ *
-+ * IMX adpater port is Copyright (C) 2013 by Stephan Rafin
-+ *
-+ * You can redistribute this file and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ *
-+ *
-+ */
-+
-+#include "env.h"
-+#include <stdio.h>
-+
-+#if defined(HAVE_IMX_API)
-+#include "IMXCECAdapterDetection.h"
-+
-+
-+using namespace CEC;
-+
-+bool CIMXCECAdapterDetection::FindAdapter(void)
-+{
-+ return access(CEC_IMX_PATH, 0) == 0;
-+}
-+
-+#endif
-diff -Nur libcec-2.1.4/src/lib/adapter/IMX/IMXCECAdapterDetection.h libcec-imx6/src/lib/adapter/IMX/IMXCECAdapterDetection.h
---- libcec-2.1.4/src/lib/adapter/IMX/IMXCECAdapterDetection.h 1970-01-01 01:00:00.000000000 +0100
-+++ libcec-imx6/src/lib/adapter/IMX/IMXCECAdapterDetection.h 2014-09-01 13:48:54.722437350 +0200
-@@ -0,0 +1,36 @@
-+#pragma once
-+/*
-+ * This file is part of the libCEC(R) library.
-+ *
-+ * libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited. All rights reserved.
-+ * libCEC(R) is an original work, containing original code.
-+ *
-+ * libCEC(R) is a trademark of Pulse-Eight Limited.
-+ *
-+ * IMX adpater port is Copyright (C) 2013 by Stephan Rafin
-+ *
-+ * You can redistribute this file and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+ *
-+ *
-+ */
-+
-+namespace CEC
-+{
-+ class CIMXCECAdapterDetection
-+ {
-+ public:
-+ static bool FindAdapter(void);
-+ };
-+}
-diff -Nur libcec-2.1.4/src/lib/CECTypeUtils.h libcec-imx6/src/lib/CECTypeUtils.h
---- libcec-2.1.4/src/lib/CECTypeUtils.h 2013-12-16 10:32:51.000000000 +0100
-+++ libcec-imx6/src/lib/CECTypeUtils.h 2014-09-01 13:48:54.698437211 +0200
-@@ -858,6 +858,8 @@
- return "Raspberry Pi";
- case ADAPTERTYPE_TDA995x:
- return "TDA995x";
-+ case ADAPTERTYPE_IMX:
-+ return "i.MX";
- default:
- return "unknown";
- }
-diff -Nur libcec-2.1.4/src/lib/Makefile.am libcec-imx6/src/lib/Makefile.am
---- libcec-2.1.4/src/lib/Makefile.am 2013-12-16 10:32:51.000000000 +0100
-+++ libcec-imx6/src/lib/Makefile.am 2014-09-01 13:48:54.718437326 +0200
-@@ -59,5 +59,10 @@
- adapter/TDA995x/TDA995xCECAdapterCommunication.cpp
- endif
-
-+## i.MX6 support
-+if USE_IMX_API
-+libcec_la_SOURCES += adapter/IMX/IMXCECAdapterDetection.cpp \
-+ adapter/IMX/IMXCECAdapterCommunication.cpp
-+endif
-
- libcec_la_LDFLAGS = @LIBS_LIBCEC@ -version-info @VERSION@
-diff -Nur libcec-2.1.4/support/create-driver-installer.cmd libcec-imx6/support/create-driver-installer.cmd
---- libcec-2.1.4/support/create-driver-installer.cmd 1970-01-01 01:00:00.000000000 +0100
-+++ libcec-imx6/support/create-driver-installer.cmd 2014-09-01 13:48:54.758437558 +0200
-@@ -0,0 +1,58 @@
-+@echo off
-+
-+rem Check for NSIS
-+IF EXIST "%ProgramFiles%\NSIS\makensis.exe" (
-+ set NSIS="%ProgramFiles%\NSIS\makensis.exe"
-+) ELSE IF EXIST "%ProgramFiles(x86)%\NSIS\makensis.exe" (
-+ set NSIS="%ProgramFiles(x86)%\NSIS\makensis.exe"
-+) ELSE GOTO NONSIS
-+
-+rem Check for the Windows DDK
-+IF NOT EXIST "C:\WinDDK\7600.16385.1" GOTO NODDK
-+set DDK="C:\WinDDK\7600.16385.1"
-+
-+mkdir ..\build
-+
-+echo. Copying driver installer
-+copy "%DDK%\redist\DIFx\dpinst\MultiLin\amd64\dpinst.exe" ..\build\dpinst-amd64.exe
-+copy "%DDK%\redist\DIFx\dpinst\MultiLin\x86\dpinst.exe" ..\build\dpinst-x86.exe
-+
-+:CREATECAT
-+cd ..\driver
-+IF EXIST "..\support\private\create-cat.cmd" (
-+ echo. Updating the catalogue
-+ CALL ..\support\private\create-cat.cmd p8usb-cec.cat
-+)
-+
-+:CREATEINSTALLER
-+echo. Creating the installer
-+cd ..\project
-+%NSIS% /V1 /X"SetCompressor /FINAL lzma" "p8-usbcec-driver.nsi"
-+
-+IF NOT EXIST "..\build\p8-usbcec-driver-installer.exe" GOTO :ERRORCREATINGINSTALLER
-+
-+rem Sign the installer if sign-binary.cmd exists
-+IF EXIST "..\support\private\sign-binary.cmd" (
-+ echo. Signing the installer binaries
-+ CALL ..\support\private\sign-binary.cmd ..\build\p8-usbcec-driver-installer.exe
-+)
-+
-+echo. The installer can be found here: ..\build\p8-usbcec-driver-installer.exe
-+
-+GOTO EXIT
-+
-+:NOSIS
-+echo. NSIS could not be found on your system.
-+GOTO EXIT
-+
-+:NODDK
-+echo. Windows DDK could not be found on your system
-+GOTO EXIT
-+
-+:ERRORCREATINGINSTALLER
-+echo. The installer could not be created.
-+
-+:EXIT
-+del /q /f ..\build\dpinst-amd64.exe
-+del /q /f ..\build\dpinst-x86.exe
-+cd ..\support
-\ Kein Zeilenumbruch am Dateiende.
-diff -Nur libcec-2.1.4/support/create-installer.bat libcec-imx6/support/create-installer.bat
---- libcec-2.1.4/support/create-installer.bat 1970-01-01 01:00:00.000000000 +0100
-+++ libcec-imx6/support/create-installer.bat 2014-09-01 13:48:54.758437558 +0200
-@@ -0,0 +1,140 @@
-+@echo off
-+
-+set EXITCODE=1
-+
-+rem Check for NSIS
-+IF EXIST "%ProgramFiles%\NSIS\makensis.exe" (
-+ set NSIS="%ProgramFiles%\NSIS\makensis.exe"
-+) ELSE IF EXIST "%ProgramFiles(x86)%\NSIS\makensis.exe" (
-+ set NSIS="%ProgramFiles(x86)%\NSIS\makensis.exe"
-+) ELSE GOTO NONSIS
-+
-+rem Check for VC11
-+IF "%VS110COMNTOOLS%"=="" (
-+ set COMPILER11="%ProgramFiles%\Microsoft Visual Studio 11.0\Common7\IDE\VCExpress.exe"
-+) ELSE IF EXIST "%VS110COMNTOOLS%\..\IDE\VCExpress.exe" (
-+ set COMPILER11="%VS110COMNTOOLS%\..\IDE\VCExpress.exe"
-+) ELSE IF EXIST "%VS110COMNTOOLS%\..\IDE\devenv.exe" (
-+ set COMPILER11="%VS110COMNTOOLS%\..\IDE\devenv.exe"
-+) ELSE GOTO NOSDK11
-+
-+del /s /f /q ..\build
-+mkdir ..\build
-+
-+IF EXIST "..\support\p8-usbcec-driver-installer.exe" (
-+ copy "..\support\p8-usbcec-driver-installer.exe" "..\build\."
-+) ELSE (
-+ rem Check for the Windows DDK
-+ IF NOT EXIST "C:\WinDDK\7600.16385.1" GOTO NODDK
-+ set DDK="C:\WinDDK\7600.16385.1"
-+
-+ call create-driver-installer.cmd
-+)
-+
-+mkdir ..\build\x64
-+
-+cd ..\project
-+
-+rem Skip to libCEC/x86 when we're running on win32
-+if "%PROCESSOR_ARCHITECTURE%"=="x86" if "%PROCESSOR_ARCHITEW6432%"=="" goto libcecx86
-+
-+rem Compile libCEC and cec-client x64
-+echo. Cleaning libCEC (x64)
-+%COMPILER11% libcec.sln /clean "Release|x64"
-+echo. Compiling libCEC (x64)
-+%COMPILER11% libcec.sln /build "Release|x64"
-+
-+:libcecx86
-+rem Compile libCEC and cec-client Win32
-+echo. Cleaning libCEC (x86)
-+%COMPILER11% libcec.sln /clean "Release|x86"
-+echo. Compiling libCEC (x86)
-+%COMPILER11% libcec.sln /build "Release|x86"
-+
-+rem Clean things up before creating the installer
-+del /q /f ..\build\LibCecSharp.pdb
-+del /q /f ..\build\CecSharpTester.pdb
-+del /q /f ..\build\cec-tray.pdb
-+del /q /f ..\build\cec-tray.vshost.exe.manifest
-+del /q /f ..\build\cec-.vshost.exe
-+del /q /f ..\build\x64\LibCecSharp.pdb
-+del /q /f ..\build\x64\CecSharpTester.pdb
-+del /q /f ..\build\x64\cec-tray.pdb
-+del /q /f ..\build\x64\cec-tray.vshost.exe.manifest
-+del /q /f ..\build\x64\cec-.vshost.exe
-+
-+rem Check for sign-binary.cmd, only present on the Pulse-Eight production build system
-+rem Calls signtool.exe and signs the DLLs with Pulse-Eight's code signing key
-+IF NOT EXIST "..\support\private\sign-binary.cmd" GOTO CREATEINSTALLER
-+echo. Signing all binaries
-+CALL ..\support\private\sign-binary.cmd ..\build\cec-client.exe
-+CALL ..\support\private\sign-binary.cmd ..\build\CecSharpTester.exe
-+CALL ..\support\private\sign-binary.cmd ..\build\libcec.dll
-+CALL ..\support\private\sign-binary.cmd ..\build\LibCecSharp.dll
-+CALL ..\support\private\sign-binary.cmd ..\build\cec-tray.exe
-+CALL ..\support\private\sign-binary.cmd ..\build\x64\cec-client.exe
-+CALL ..\support\private\sign-binary.cmd ..\build\x64\CecSharpTester.exe
-+CALL ..\support\private\sign-binary.cmd ..\build\x64\libcec.dll
-+CALL ..\support\private\sign-binary.cmd ..\build\x64\LibCecSharp.dll
-+CALL ..\support\private\sign-binary.cmd ..\build\x64\cec-tray.exe
-+
-+:CREATEINSTALLER
-+echo. Creating the installer
-+cd ..\build\x64
-+copy libcec.dll libcec.x64.dll
-+copy cec-client.exe cec-client.x64.exe
-+cd ..\..\project
-+%NSIS% /V1 /X"SetCompressor /FINAL lzma" "libCEC.nsi"
-+
-+IF NOT EXIST "..\build\libCEC-installer.exe" GOTO :ERRORCREATINGINSTALLER
-+
-+rem Sign the installer if sign-binary.cmd exists
-+IF EXIST "..\support\private\sign-binary.cmd" (
-+ echo. Signing the installer binaries
-+ CALL ..\support\private\sign-binary.cmd ..\build\libCEC-installer.exe
-+)
-+
-+IF "%1%"=="" (
-+ echo. The installer can be found here: ..\build\libCEC-installer.exe
-+) ELSE (
-+ move ..\build\libCEC-installer.exe ..\build\libCEC-%1%-installer.exe
-+ echo. The installer can be found here: ..\build\libCEC-%1%-installer.exe
-+)
-+
-+set EXITCODE=0
-+GOTO EXIT
-+
-+:NOSDK11
-+echo. Visual Studio 2012 was not found on your system.
-+GOTO EXIT
-+
-+:NOSIS
-+echo. NSIS could not be found on your system.
-+GOTO EXIT
-+
-+:NODDK
-+echo. Windows DDK could not be found on your system
-+GOTO EXIT
-+
-+:ERRORCREATINGINSTALLER
-+echo. The installer could not be created. The most likely cause is that something went wrong while compiling.
-+
-+:EXIT
-+del /q /f ..\build\cec-client.exe
-+del /q /f ..\build\CecSharpTester.exe
-+del /q /f ..\build\cec-tray.exe
-+del /q /f ..\build\*.dll
-+del /q /f ..\build\*.lib
-+del /q /f ..\build\*.exp
-+del /q /f ..\build\*.xml
-+del /q /f ..\build\*.metagen
-+del /s /f /q ..\build\x64
-+rmdir ..\build\x64
-+cd ..\support
-+
-+IF "%1%"=="" (
-+ echo. exitcode = %EXITCODE%
-+) ELSE (
-+ exit %EXITCODE%
-+)
-+
-Binärdateien libcec-2.1.4/support/p8-usbcec-driver-installer.exe und libcec-imx6/support/p8-usbcec-driver-installer.exe sind verschieden.
diff --git a/package/libcec/patches/patch-src_lib_adapter_RPi_RPiCECAdapterCommunication_cpp b/package/libcec/patches/patch-src_lib_adapter_RPi_RPiCECAdapterCommunication_cpp
deleted file mode 100644
index f027f0f3a..000000000
--- a/package/libcec/patches/patch-src_lib_adapter_RPi_RPiCECAdapterCommunication_cpp
+++ /dev/null
@@ -1,12 +0,0 @@
---- libcec-2.1.4.orig/src/lib/adapter/RPi/RPiCECAdapterCommunication.cpp 2013-12-16 10:32:51.000000000 +0100
-+++ libcec-2.1.4/src/lib/adapter/RPi/RPiCECAdapterCommunication.cpp 2014-05-28 18:25:18.809692104 +0200
-@@ -353,7 +353,8 @@ void CRPiCECAdapterCommunication::Close(
- else
- return;
- }
-- vc_tv_unregister_callback(rpi_tv_callback);
-+ if (m_bInitialised)
-+ vc_tv_unregister_callback(rpi_tv_callback);
-
- UnregisterLogicalAddress();
-
diff --git a/package/libcec/patches/patch-src_lib_libcec_pc_in b/package/libcec/patches/patch-src_lib_libcec_pc_in
index edacd9650..5b71c1d66 100644
--- a/package/libcec/patches/patch-src_lib_libcec_pc_in
+++ b/package/libcec/patches/patch-src_lib_libcec_pc_in
@@ -1,5 +1,5 @@
---- libcec-2.1.4.orig/src/lib/libcec.pc.in 2013-12-16 10:32:51.000000000 +0100
-+++ libcec-2.1.4/src/lib/libcec.pc.in 2014-06-17 10:28:45.246000623 +0200
+--- libcec-2.2.0.orig/src/lib/libcec.pc.in 2014-11-11 13:49:38.000000000 -0600
++++ libcec-2.2.0/src/lib/libcec.pc.in 2014-11-12 13:51:02.466501999 -0600
@@ -7,6 +7,5 @@ Name: libcec
Description: Pulse-Eight CEC adapter library
URL: http://www.pulse-eight.com/
diff --git a/package/libcec/patches/patch-src_lib_platform_posix_serialport_cpp b/package/libcec/patches/patch-src_lib_platform_posix_serialport_cpp
deleted file mode 100644
index e677a0d22..000000000
--- a/package/libcec/patches/patch-src_lib_platform_posix_serialport_cpp
+++ /dev/null
@@ -1,11 +0,0 @@
---- libcec-2.1.4.orig/src/lib/platform/posix/serialport.cpp 2013-12-15 12:48:14.000000000 +0100
-+++ libcec-2.1.4/src/lib/platform/posix/serialport.cpp 2014-01-12 22:04:41.000000000 +0100
-@@ -37,7 +37,7 @@
- #include "lib/platform/util/baudrate.h"
- #include "lib/platform/posix/os-socket.h"
-
--#if defined(__APPLE__) || defined(__FreeBSD__)
-+#if defined(__APPLE__) || defined(__FreeBSD__) || !defined(__GLIBC__)
- #ifndef XCASE
- #define XCASE 0
- #endif
diff --git a/package/libpng/patches/libpng-1.6.14-apng.patch b/package/libpng/patches/libpng-1.6.14-apng.patch
new file mode 100644
index 000000000..c168b02cc
--- /dev/null
+++ b/package/libpng/patches/libpng-1.6.14-apng.patch
@@ -0,0 +1,1701 @@
+diff -Naru libpng-1.6.14.org/png.h libpng-1.6.14/png.h
+--- libpng-1.6.14.org/png.h 2014-10-23 23:57:22.656674917 +0900
++++ libpng-1.6.14/png.h 2014-10-23 23:57:22.729677456 +0900
+@@ -470,6 +470,10 @@
+ # include "pnglibconf.h"
+ #endif
+
++#define PNG_APNG_SUPPORTED
++#define PNG_READ_APNG_SUPPORTED
++#define PNG_WRITE_APNG_SUPPORTED
++
+ #ifndef PNG_VERSION_INFO_ONLY
+ /* Machine specific configuration. */
+ # include "pngconf.h"
+@@ -560,6 +564,17 @@
+ * See pngconf.h for base types that vary by machine/system
+ */
+
++#ifdef PNG_APNG_SUPPORTED
++/* dispose_op flags from inside fcTL */
++#define PNG_DISPOSE_OP_NONE 0x00
++#define PNG_DISPOSE_OP_BACKGROUND 0x01
++#define PNG_DISPOSE_OP_PREVIOUS 0x02
++
++/* blend_op flags from inside fcTL */
++#define PNG_BLEND_OP_SOURCE 0x00
++#define PNG_BLEND_OP_OVER 0x01
++#endif /* PNG_APNG_SUPPORTED */
++
+ /* This triggers a compiler error in png.c, if png.c and png.h
+ * do not agree upon the version number.
+ */
+@@ -880,6 +895,10 @@
+ #define PNG_INFO_sPLT 0x2000 /* ESR, 1.0.6 */
+ #define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */
+ #define PNG_INFO_IDAT 0x8000 /* ESR, 1.0.6 */
++#ifdef PNG_APNG_SUPPORTED
++#define PNG_INFO_acTL 0x10000
++#define PNG_INFO_fcTL 0x20000
++#endif
+
+ /* This is used for the transformation routines, as some of them
+ * change these values for the row. It also should enable using
+@@ -917,6 +936,10 @@
+ #ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+ typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop));
+ typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop));
++#ifdef PNG_APNG_SUPPORTED
++typedef PNG_CALLBACK(void, *png_progressive_frame_ptr, (png_structp,
++ png_uint_32));
++#endif
+
+ /* The following callback receives png_uint_32 row_number, int pass for the
+ * png_bytep data of the row. When transforming an interlaced image the
+@@ -3255,6 +3278,74 @@
+ /*******************************************************************************
+ * END OF HARDWARE AND SOFTWARE OPTIONS
+ ******************************************************************************/
++#ifdef PNG_APNG_SUPPORTED
++PNG_EXPORT(245, png_uint_32, png_get_acTL, (png_structp png_ptr,
++ png_infop info_ptr, png_uint_32 *num_frames, png_uint_32 *num_plays));
++
++PNG_EXPORT(246, png_uint_32, png_set_acTL, (png_structp png_ptr,
++ png_infop info_ptr, png_uint_32 num_frames, png_uint_32 num_plays));
++
++PNG_EXPORT(247, png_uint_32, png_get_num_frames, (png_structp png_ptr,
++ png_infop info_ptr));
++
++PNG_EXPORT(248, png_uint_32, png_get_num_plays, (png_structp png_ptr,
++ png_infop info_ptr));
++
++PNG_EXPORT(249, png_uint_32, png_get_next_frame_fcTL,
++ (png_structp png_ptr, png_infop info_ptr, png_uint_32 *width,
++ png_uint_32 *height, png_uint_32 *x_offset, png_uint_32 *y_offset,
++ png_uint_16 *delay_num, png_uint_16 *delay_den, png_byte *dispose_op,
++ png_byte *blend_op));
++
++PNG_EXPORT(250, png_uint_32, png_set_next_frame_fcTL,
++ (png_structp png_ptr, png_infop info_ptr, png_uint_32 width,
++ png_uint_32 height, png_uint_32 x_offset, png_uint_32 y_offset,
++ png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
++ png_byte blend_op));
++
++PNG_EXPORT(251, png_uint_32, png_get_next_frame_width,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(252, png_uint_32, png_get_next_frame_height,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(253, png_uint_32, png_get_next_frame_x_offset,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(254, png_uint_32, png_get_next_frame_y_offset,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(255, png_uint_16, png_get_next_frame_delay_num,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(256, png_uint_16, png_get_next_frame_delay_den,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(257, png_byte, png_get_next_frame_dispose_op,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(258, png_byte, png_get_next_frame_blend_op,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(259, png_byte, png_get_first_frame_is_hidden,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(260, png_uint_32, png_set_first_frame_is_hidden,
++ (png_structp png_ptr, png_infop info_ptr, png_byte is_hidden));
++
++#ifdef PNG_READ_APNG_SUPPORTED
++PNG_EXPORT(261, void, png_read_frame_head, (png_structp png_ptr,
++ png_infop info_ptr));
++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
++PNG_EXPORT(262, void, png_set_progressive_frame_fn, (png_structp png_ptr,
++ png_progressive_frame_ptr frame_info_fn,
++ png_progressive_frame_ptr frame_end_fn));
++#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
++#endif /* PNG_READ_APNG_SUPPORTED */
++
++#ifdef PNG_WRITE_APNG_SUPPORTED
++PNG_EXPORT(263, void, png_write_frame_head, (png_structp png_ptr,
++ png_infop info_ptr, png_bytepp row_pointers,
++ png_uint_32 width, png_uint_32 height,
++ png_uint_32 x_offset, png_uint_32 y_offset,
++ png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
++ png_byte blend_op));
++
++PNG_EXPORT(264, void, png_write_frame_tail, (png_structp png_ptr,
++ png_infop info_ptr));
++#endif /* PNG_WRITE_APNG_SUPPORTED */
++#endif /* PNG_APNG_SUPPORTED */
+
+ /* Maintainer: Put new public prototypes here ^, in libpng.3, in project
+ * defs, and in scripts/symbols.def.
+@@ -3264,7 +3355,11 @@
+ * one to use is one more than this.)
+ */
+ #ifdef PNG_EXPORT_LAST_ORDINAL
++#ifdef PNG_APNG_SUPPORTED
++ PNG_EXPORT_LAST_ORDINAL(264);
++#else
+ PNG_EXPORT_LAST_ORDINAL(244);
++#endif /* PNG_APNG_SUPPORTED */
+ #endif
+
+ #ifdef __cplusplus
+diff -Naru libpng-1.6.14.org/pngget.c libpng-1.6.14/pngget.c
+--- libpng-1.6.14.org/pngget.c 2014-10-23 23:57:22.657674952 +0900
++++ libpng-1.6.14/pngget.c 2014-10-23 23:57:22.730677491 +0900
+@@ -1195,4 +1195,166 @@
+ # endif
+ #endif
+
++#ifdef PNG_APNG_SUPPORTED
++png_uint_32 PNGAPI
++png_get_acTL(png_structp png_ptr, png_infop info_ptr,
++ png_uint_32 *num_frames, png_uint_32 *num_plays)
++{
++ png_debug1(1, "in %s retrieval function", "acTL");
++
++ if (png_ptr != NULL && info_ptr != NULL &&
++ (info_ptr->valid & PNG_INFO_acTL) &&
++ num_frames != NULL && num_plays != NULL)
++ {
++ *num_frames = info_ptr->num_frames;
++ *num_plays = info_ptr->num_plays;
++ return (1);
++ }
++
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_num_frames(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_num_frames()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->num_frames);
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_num_plays(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_num_plays()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->num_plays);
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr,
++ png_uint_32 *width, png_uint_32 *height,
++ png_uint_32 *x_offset, png_uint_32 *y_offset,
++ png_uint_16 *delay_num, png_uint_16 *delay_den,
++ png_byte *dispose_op, png_byte *blend_op)
++{
++ png_debug1(1, "in %s retrieval function", "fcTL");
++
++ if (png_ptr != NULL && info_ptr != NULL &&
++ (info_ptr->valid & PNG_INFO_fcTL) &&
++ width != NULL && height != NULL &&
++ x_offset != NULL && y_offset != NULL &&
++ delay_num != NULL && delay_den != NULL &&
++ dispose_op != NULL && blend_op != NULL)
++ {
++ *width = info_ptr->next_frame_width;
++ *height = info_ptr->next_frame_height;
++ *x_offset = info_ptr->next_frame_x_offset;
++ *y_offset = info_ptr->next_frame_y_offset;
++ *delay_num = info_ptr->next_frame_delay_num;
++ *delay_den = info_ptr->next_frame_delay_den;
++ *dispose_op = info_ptr->next_frame_dispose_op;
++ *blend_op = info_ptr->next_frame_blend_op;
++ return (1);
++ }
++
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_width(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_width()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_width);
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_height(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_height()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_height);
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_x_offset(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_x_offset()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_x_offset);
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_y_offset(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_y_offset()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_y_offset);
++ return (0);
++}
++
++png_uint_16 PNGAPI
++png_get_next_frame_delay_num(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_delay_num()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_delay_num);
++ return (0);
++}
++
++png_uint_16 PNGAPI
++png_get_next_frame_delay_den(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_delay_den()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_delay_den);
++ return (0);
++}
++
++png_byte PNGAPI
++png_get_next_frame_dispose_op(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_dispose_op()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_dispose_op);
++ return (0);
++}
++
++png_byte PNGAPI
++png_get_next_frame_blend_op(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_blend_op()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_blend_op);
++ return (0);
++}
++
++png_byte PNGAPI
++png_get_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_first_frame_is_hidden()");
++
++ if (png_ptr != NULL)
++ return (png_byte)(png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN);
++
++ PNG_UNUSED(info_ptr)
++
++ return 0;
++}
++#endif /* PNG_APNG_SUPPORTED */
+ #endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */
+diff -Naru libpng-1.6.14.org/pnginfo.h libpng-1.6.14/pnginfo.h
+--- libpng-1.6.14.org/pnginfo.h 2014-10-23 23:57:22.657674952 +0900
++++ libpng-1.6.14/pnginfo.h 2014-10-23 23:57:22.730677491 +0900
+@@ -256,5 +256,18 @@
+ png_bytepp row_pointers; /* the image bits */
+ #endif
+
++#ifdef PNG_APNG_SUPPORTED
++ png_uint_32 num_frames; /* including default image */
++ png_uint_32 num_plays;
++ png_uint_32 next_frame_width;
++ png_uint_32 next_frame_height;
++ png_uint_32 next_frame_x_offset;
++ png_uint_32 next_frame_y_offset;
++ png_uint_16 next_frame_delay_num;
++ png_uint_16 next_frame_delay_den;
++ png_byte next_frame_dispose_op;
++ png_byte next_frame_blend_op;
++#endif
++
+ };
+ #endif /* PNGINFO_H */
+diff -Naru libpng-1.6.14.org/pngpread.c libpng-1.6.14/pngpread.c
+--- libpng-1.6.14.org/pngpread.c 2014-10-23 23:57:22.657674952 +0900
++++ libpng-1.6.14/pngpread.c 2014-10-23 23:57:22.730677491 +0900
+@@ -219,6 +219,109 @@
+
+ chunk_name = png_ptr->chunk_name;
+
++#ifdef PNG_READ_APNG_SUPPORTED
++ if (png_ptr->num_frames_read > 0 &&
++ png_ptr->num_frames_read < info_ptr->num_frames)
++ {
++ if (chunk_name == png_IDAT)
++ {
++ /* Discard trailing IDATs for the first frame */
++ if (png_ptr->mode & PNG_HAVE_fcTL || png_ptr->num_frames_read > 1)
++ png_error(png_ptr, "out of place IDAT");
++
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_push_crc_skip(png_ptr, png_ptr->push_length);
++ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++ return;
++ }
++ else if (chunk_name == png_fdAT)
++ {
++ if (png_ptr->buffer_size < 4)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_ensure_sequence_number(png_ptr, 4);
++
++ if (!(png_ptr->mode & PNG_HAVE_fcTL))
++ {
++ /* Discard trailing fdATs for frames other than the first */
++ if (png_ptr->num_frames_read < 2)
++ png_error(png_ptr, "out of place fdAT");
++
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_push_crc_skip(png_ptr, png_ptr->push_length);
++ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++ return;
++ }
++
++ else
++ {
++ /* frame data follows */
++ png_ptr->idat_size = png_ptr->push_length - 4;
++ png_ptr->mode |= PNG_HAVE_IDAT;
++ png_ptr->process_mode = PNG_READ_IDAT_MODE;
++
++ return;
++ }
++ }
++
++ else if (chunk_name == png_fcTL)
++ {
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_read_reset(png_ptr);
++ png_ptr->mode &= ~PNG_HAVE_fcTL;
++
++ png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length);
++
++ if (!(png_ptr->mode & PNG_HAVE_fcTL))
++ png_error(png_ptr, "missing required fcTL chunk");
++
++ png_read_reinit(png_ptr, info_ptr);
++ png_progressive_read_reset(png_ptr);
++
++ if (png_ptr->frame_info_fn != NULL)
++ (*(png_ptr->frame_info_fn))(png_ptr, png_ptr->num_frames_read);
++
++ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++
++ return;
++ }
++
++ else
++ {
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++ png_warning(png_ptr, "Skipped (ignored) a chunk "
++ "between APNG chunks");
++ png_push_crc_skip(png_ptr, png_ptr->push_length);
++ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++ return;
++ }
++
++ return;
++ }
++#endif /* PNG_READ_APNG_SUPPORTED */
++
+ if (chunk_name == png_IDAT)
+ {
+ if (png_ptr->mode & PNG_AFTER_IDAT)
+@@ -283,6 +386,9 @@
+
+ else if (chunk_name == png_IDAT)
+ {
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_have_info(png_ptr, info_ptr);
++#endif
+ png_ptr->idat_size = png_ptr->push_length;
+ png_ptr->process_mode = PNG_READ_IDAT_MODE;
+ png_push_have_info(png_ptr, info_ptr);
+@@ -428,6 +534,30 @@
+ png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length);
+ }
+ #endif
++#ifdef PNG_READ_APNG_SUPPORTED
++ else if (chunk_name == png_acTL)
++ {
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_handle_acTL(png_ptr, info_ptr, png_ptr->push_length);
++ }
++
++ else if (chunk_name == png_fcTL)
++ {
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length);
++ }
++
++#endif /* PNG_READ_APNG_SUPPORTED */
+
+ else
+ {
+@@ -621,7 +751,11 @@
+ png_byte chunk_tag[4];
+
+ /* TODO: this code can be commoned up with the same code in push_read */
++#ifdef PNG_READ_APNG_SUPPORTED
++ PNG_PUSH_SAVE_BUFFER_IF_LT(12)
++#else
+ PNG_PUSH_SAVE_BUFFER_IF_LT(8)
++#endif
+ png_push_fill_buffer(png_ptr, chunk_length, 4);
+ png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length);
+ png_reset_crc(png_ptr);
+@@ -629,17 +763,64 @@
+ png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag);
+ png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
+
++#ifdef PNG_READ_APNG_SUPPORTED
++ if (png_ptr->chunk_name != png_fdAT && png_ptr->num_frames_read > 0)
++ {
++ if (png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)
++ {
++ png_ptr->process_mode = PNG_READ_CHUNK_MODE;
++ if (png_ptr->frame_end_fn != NULL)
++ (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
++ png_ptr->num_frames_read++;
++ return;
++ }
++ else
++ {
++ if (png_ptr->chunk_name == png_IEND)
++ png_error(png_ptr, "Not enough image data");
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++ png_warning(png_ptr, "Skipping (ignoring) a chunk between "
++ "APNG chunks");
++ png_crc_finish(png_ptr, png_ptr->push_length);
++ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++ return;
++ }
++ }
++ else
++#endif
++#ifdef PNG_READ_APNG_SUPPORTED
++ if (png_ptr->chunk_name != png_IDAT && png_ptr->num_frames_read == 0)
++#else
+ if (png_ptr->chunk_name != png_IDAT)
++#endif
+ {
+ png_ptr->process_mode = PNG_READ_CHUNK_MODE;
+
+ if (!(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED))
+ png_error(png_ptr, "Not enough compressed data");
+
++#ifdef PNG_READ_APNG_SUPPORTED
++ if (png_ptr->frame_end_fn != NULL)
++ (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
++ png_ptr->num_frames_read++;
++#endif
++
+ return;
+ }
+
+ png_ptr->idat_size = png_ptr->push_length;
++
++#ifdef PNG_READ_APNG_SUPPORTED
++ if (png_ptr->num_frames_read > 0)
++ {
++ png_ensure_sequence_number(png_ptr, 4);
++ png_ptr->idat_size -= 4;
++ }
++#endif
+ }
+
+ if (png_ptr->idat_size && png_ptr->save_buffer_size)
+@@ -712,6 +893,15 @@
+ if (!(buffer_length > 0) || buffer == NULL)
+ png_error(png_ptr, "No IDAT data (internal error)");
+
++#ifdef PNG_READ_APNG_SUPPORTED
++ /* If the app is not APNG-aware, decode only the first frame */
++ if (!(png_ptr->apng_flags & PNG_APNG_APP) && png_ptr->num_frames_read > 0)
++ {
++ png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
++ return;
++ }
++#endif
++
+ /* This routine must process all the data it has been given
+ * before returning, calling the row callback as required to
+ * handle the uncompressed results.
+@@ -1154,6 +1344,18 @@
+ png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer);
+ }
+
++#ifdef PNG_READ_APNG_SUPPORTED
++void PNGAPI
++png_set_progressive_frame_fn(png_structp png_ptr,
++ png_progressive_frame_ptr frame_info_fn,
++ png_progressive_frame_ptr frame_end_fn)
++{
++ png_ptr->frame_info_fn = frame_info_fn;
++ png_ptr->frame_end_fn = frame_end_fn;
++ png_ptr->apng_flags |= PNG_APNG_APP;
++}
++#endif
++
+ png_voidp PNGAPI
+ png_get_progressive_ptr(png_const_structrp png_ptr)
+ {
+diff -Naru libpng-1.6.14.org/pngpriv.h libpng-1.6.14/pngpriv.h
+--- libpng-1.6.14.org/pngpriv.h 2014-10-23 23:57:22.658674987 +0900
++++ libpng-1.6.14/pngpriv.h 2014-10-23 23:57:22.731677525 +0900
+@@ -555,6 +555,10 @@
+ #define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */
+ /* 0x4000 (unused) */
+ #define PNG_IS_READ_STRUCT 0x8000 /* Else is a write struct */
++#ifdef PNG_APNG_SUPPORTED
++#define PNG_HAVE_acTL 0x10000
++#define PNG_HAVE_fcTL 0x20000
++#endif
+
+ /* Flags for the transformations the PNG library does on the image data */
+ #define PNG_BGR 0x0001
+@@ -776,6 +780,16 @@
+ #define png_tRNS PNG_U32(116, 82, 78, 83)
+ #define png_zTXt PNG_U32(122, 84, 88, 116)
+
++#ifdef PNG_APNG_SUPPORTED
++#define png_acTL PNG_U32( 97, 99, 84, 76)
++#define png_fcTL PNG_U32(102, 99, 84, 76)
++#define png_fdAT PNG_U32(102, 100, 65, 84)
++
++/* For png_struct.apng_flags: */
++#define PNG_FIRST_FRAME_HIDDEN 0x0001
++#define PNG_APNG_APP 0x0002
++#endif
++
+ /* The following will work on (signed char*) strings, whereas the get_uint_32
+ * macro will fail on top-bit-set values because of the sign extension.
+ */
+@@ -1476,6 +1490,47 @@
+ */
+ #endif
+
++#ifdef PNG_APNG_SUPPORTED
++PNG_INTERNAL_FUNCTION(void,png_ensure_fcTL_is_valid,(png_structp png_ptr,
++ png_uint_32 width, png_uint_32 height,
++ png_uint_32 x_offset, png_uint_32 y_offset,
++ png_uint_16 delay_num, png_uint_16 delay_den,
++ png_byte dispose_op, png_byte blend_op), PNG_EMPTY);
++
++#ifdef PNG_READ_APNG_SUPPORTED
++PNG_INTERNAL_FUNCTION(void,png_handle_acTL,(png_structp png_ptr, png_infop info_ptr,
++ png_uint_32 length),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_handle_fcTL,(png_structp png_ptr, png_infop info_ptr,
++ png_uint_32 length),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_handle_fdAT,(png_structp png_ptr, png_infop info_ptr,
++ png_uint_32 length),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_have_info,(png_structp png_ptr, png_infop info_ptr),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_ensure_sequence_number,(png_structp png_ptr,
++ png_uint_32 length),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_read_reset,(png_structp png_ptr),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_read_reinit,(png_structp png_ptr,
++ png_infop info_ptr),PNG_EMPTY);
++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
++PNG_INTERNAL_FUNCTION(void,png_progressive_read_reset,(png_structp png_ptr),PNG_EMPTY);
++#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
++#endif /* PNG_READ_APNG_SUPPORTED */
++
++#ifdef PNG_WRITE_APNG_SUPPORTED
++PNG_INTERNAL_FUNCTION(void,png_write_acTL,(png_structp png_ptr,
++ png_uint_32 num_frames, png_uint_32 num_plays),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_write_fcTL,(png_structp png_ptr,
++ png_uint_32 width, png_uint_32 height,
++ png_uint_32 x_offset, png_uint_32 y_offset,
++ png_uint_16 delay_num, png_uint_16 delay_den,
++ png_byte dispose_op, png_byte blend_op),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_write_fdAT,(png_structp png_ptr,
++ png_const_bytep data, png_size_t length),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_write_reset,(png_structp png_ptr),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_write_reinit,(png_structp png_ptr,
++ png_infop info_ptr, png_uint_32 width, png_uint_32 height),PNG_EMPTY);
++#endif /* PNG_WRITE_APNG_SUPPORTED */
++#endif /* PNG_APNG_SUPPORTED */
++
+ /* Added at libpng version 1.4.0 */
+ #ifdef PNG_COLORSPACE_SUPPORTED
+ /* These internal functions are for maintaining the colorspace structure within
+diff -Naru libpng-1.6.14.org/pngread.c libpng-1.6.14/pngread.c
+--- libpng-1.6.14.org/pngread.c 2014-10-23 23:57:22.659675022 +0900
++++ libpng-1.6.14/pngread.c 2014-10-23 23:57:22.732677560 +0900
+@@ -158,6 +158,9 @@
+
+ else if (chunk_name == png_IDAT)
+ {
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_have_info(png_ptr, info_ptr);
++#endif
+ png_ptr->idat_size = length;
+ break;
+ }
+@@ -247,6 +250,17 @@
+ png_handle_iTXt(png_ptr, info_ptr, length);
+ #endif
+
++#ifdef PNG_READ_APNG_SUPPORTED
++ else if (chunk_name == png_acTL)
++ png_handle_acTL(png_ptr, info_ptr, length);
++
++ else if (chunk_name == png_fcTL)
++ png_handle_fcTL(png_ptr, info_ptr, length);
++
++ else if (chunk_name == png_fdAT)
++ png_handle_fdAT(png_ptr, info_ptr, length);
++#endif
++
+ else
+ png_handle_unknown(png_ptr, info_ptr, length,
+ PNG_HANDLE_CHUNK_AS_DEFAULT);
+@@ -254,6 +268,72 @@
+ }
+ #endif /* PNG_SEQUENTIAL_READ_SUPPORTED */
+
++#ifdef PNG_READ_APNG_SUPPORTED
++void PNGAPI
++png_read_frame_head(png_structp png_ptr, png_infop info_ptr)
++{
++ png_byte have_chunk_after_DAT; /* after IDAT or after fdAT */
++
++ png_debug(0, "Reading frame head");
++
++ if (!(png_ptr->mode & PNG_HAVE_acTL))
++ png_error(png_ptr, "attempt to png_read_frame_head() but "
++ "no acTL present");
++
++ /* do nothing for the main IDAT */
++ if (png_ptr->num_frames_read == 0)
++ return;
++
++ png_read_reset(png_ptr);
++ png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
++ png_ptr->mode &= ~PNG_HAVE_fcTL;
++
++ have_chunk_after_DAT = 0;
++ for (;;)
++ {
++ png_uint_32 length = png_read_chunk_header(png_ptr);
++
++ if (png_ptr->chunk_name == png_IDAT)
++ {
++ /* discard trailing IDATs for the first frame */
++ if (have_chunk_after_DAT || png_ptr->num_frames_read > 1)
++ png_error(png_ptr, "png_read_frame_head(): out of place IDAT");
++ png_crc_finish(png_ptr, length);
++ }
++
++ else if (png_ptr->chunk_name == png_fcTL)
++ {
++ png_handle_fcTL(png_ptr, info_ptr, length);
++ have_chunk_after_DAT = 1;
++ }
++
++ else if (png_ptr->chunk_name == png_fdAT)
++ {
++ png_ensure_sequence_number(png_ptr, length);
++
++ /* discard trailing fdATs for frames other than the first */
++ if (!have_chunk_after_DAT && png_ptr->num_frames_read > 1)
++ png_crc_finish(png_ptr, length - 4);
++ else if(png_ptr->mode & PNG_HAVE_fcTL)
++ {
++ png_ptr->idat_size = length - 4;
++ png_ptr->mode |= PNG_HAVE_IDAT;
++
++ break;
++ }
++ else
++ png_error(png_ptr, "png_read_frame_head(): out of place fdAT");
++ }
++ else
++ {
++ png_warning(png_ptr, "Skipped (ignored) a chunk "
++ "between APNG chunks");
++ png_crc_finish(png_ptr, length);
++ }
++ }
++}
++#endif /* PNG_READ_APNG_SUPPORTED */
++
+ /* Optional call to update the users info_ptr structure */
+ void PNGAPI
+ png_read_update_info(png_structrp png_ptr, png_inforp info_ptr)
+diff -Naru libpng-1.6.14.org/pngrutil.c libpng-1.6.14/pngrutil.c
+--- libpng-1.6.14.org/pngrutil.c 2014-10-23 23:57:22.660675057 +0900
++++ libpng-1.6.14/pngrutil.c 2014-10-23 23:57:22.735677664 +0900
+@@ -817,6 +817,11 @@
+ filter_type = buf[11];
+ interlace_type = buf[12];
+
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_ptr->first_frame_width = width;
++ png_ptr->first_frame_height = height;
++#endif
++
+ /* Set internal variables */
+ png_ptr->width = width;
+ png_ptr->height = height;
+@@ -2697,6 +2702,179 @@
+ }
+ #endif
+
++#ifdef PNG_READ_APNG_SUPPORTED
++void /* PRIVATE */
++png_handle_acTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
++{
++ png_byte data[8];
++ png_uint_32 num_frames;
++ png_uint_32 num_plays;
++ png_uint_32 didSet;
++
++ png_debug(1, "in png_handle_acTL");
++
++ if (!(png_ptr->mode & PNG_HAVE_IHDR))
++ {
++ png_error(png_ptr, "Missing IHDR before acTL");
++ }
++ else if (png_ptr->mode & PNG_HAVE_IDAT)
++ {
++ png_warning(png_ptr, "Invalid acTL after IDAT skipped");
++ png_crc_finish(png_ptr, length);
++ return;
++ }
++ else if (png_ptr->mode & PNG_HAVE_acTL)
++ {
++ png_warning(png_ptr, "Duplicate acTL skipped");
++ png_crc_finish(png_ptr, length);
++ return;
++ }
++ else if (length != 8)
++ {
++ png_warning(png_ptr, "acTL with invalid length skipped");
++ png_crc_finish(png_ptr, length);
++ return;
++ }
++
++ png_crc_read(png_ptr, data, 8);
++ png_crc_finish(png_ptr, 0);
++
++ num_frames = png_get_uint_31(png_ptr, data);
++ num_plays = png_get_uint_31(png_ptr, data + 4);
++
++ /* the set function will do error checking on num_frames */
++ didSet = png_set_acTL(png_ptr, info_ptr, num_frames, num_plays);
++ if(didSet)
++ png_ptr->mode |= PNG_HAVE_acTL;
++}
++
++void /* PRIVATE */
++png_handle_fcTL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
++{
++ png_byte data[22];
++ png_uint_32 width;
++ png_uint_32 height;
++ png_uint_32 x_offset;
++ png_uint_32 y_offset;
++ png_uint_16 delay_num;
++ png_uint_16 delay_den;
++ png_byte dispose_op;
++ png_byte blend_op;
++
++ png_debug(1, "in png_handle_fcTL");
++
++ png_ensure_sequence_number(png_ptr, length);
++
++ if (!(png_ptr->mode & PNG_HAVE_IHDR))
++ {
++ png_error(png_ptr, "Missing IHDR before fcTL");
++ }
++ else if (png_ptr->mode & PNG_HAVE_IDAT)
++ {
++ /* for any frames other then the first this message may be misleading,
++ * but correct. PNG_HAVE_IDAT is unset before the frame head is read
++ * i can't think of a better message */
++ png_warning(png_ptr, "Invalid fcTL after IDAT skipped");
++ png_crc_finish(png_ptr, length-4);
++ return;
++ }
++ else if (png_ptr->mode & PNG_HAVE_fcTL)
++ {
++ png_warning(png_ptr, "Duplicate fcTL within one frame skipped");
++ png_crc_finish(png_ptr, length-4);
++ return;
++ }
++ else if (length != 26)
++ {
++ png_warning(png_ptr, "fcTL with invalid length skipped");
++ png_crc_finish(png_ptr, length-4);
++ return;
++ }
++
++ png_crc_read(png_ptr, data, 22);
++ png_crc_finish(png_ptr, 0);
++
++ width = png_get_uint_31(png_ptr, data);
++ height = png_get_uint_31(png_ptr, data + 4);
++ x_offset = png_get_uint_31(png_ptr, data + 8);
++ y_offset = png_get_uint_31(png_ptr, data + 12);
++ delay_num = png_get_uint_16(data + 16);
++ delay_den = png_get_uint_16(data + 18);
++ dispose_op = data[20];
++ blend_op = data[21];
++
++ if (png_ptr->num_frames_read == 0 && (x_offset != 0 || y_offset != 0))
++ {
++ png_warning(png_ptr, "fcTL for the first frame must have zero offset");
++ return;
++ }
++
++ if (info_ptr != NULL)
++ {
++ if (png_ptr->num_frames_read == 0 &&
++ (width != info_ptr->width || height != info_ptr->height))
++ {
++ png_warning(png_ptr, "size in first frame's fcTL must match "
++ "the size in IHDR");
++ return;
++ }
++
++ /* The set function will do more error checking */
++ png_set_next_frame_fcTL(png_ptr, info_ptr, width, height,
++ x_offset, y_offset, delay_num, delay_den,
++ dispose_op, blend_op);
++
++ png_read_reinit(png_ptr, info_ptr);
++
++ png_ptr->mode |= PNG_HAVE_fcTL;
++ }
++}
++
++void /* PRIVATE */
++png_have_info(png_structp png_ptr, png_infop info_ptr)
++{
++ if((info_ptr->valid & PNG_INFO_acTL) && !(info_ptr->valid & PNG_INFO_fcTL))
++ {
++ png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
++ info_ptr->num_frames++;
++ }
++}
++
++void /* PRIVATE */
++png_handle_fdAT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
++{
++ png_ensure_sequence_number(png_ptr, length);
++
++ /* This function is only called from png_read_end(), png_read_info(),
++ * and png_push_read_chunk() which means that:
++ * - the user doesn't want to read this frame
++ * - or this is an out-of-place fdAT
++ * in either case it is safe to ignore the chunk with a warning */
++ png_warning(png_ptr, "ignoring fdAT chunk");
++ png_crc_finish(png_ptr, length - 4);
++ PNG_UNUSED(info_ptr)
++}
++
++void /* PRIVATE */
++png_ensure_sequence_number(png_structp png_ptr, png_uint_32 length)
++{
++ png_byte data[4];
++ png_uint_32 sequence_number;
++
++ if (length < 4)
++ png_error(png_ptr, "invalid fcTL or fdAT chunk found");
++
++ png_crc_read(png_ptr, data, 4);
++ sequence_number = png_get_uint_31(png_ptr, data);
++
++ if (sequence_number != png_ptr->next_seq_num)
++ png_error(png_ptr, "fcTL or fdAT chunk with out-of-order sequence "
++ "number found");
++
++ png_ptr->next_seq_num++;
++}
++#endif /* PNG_READ_APNG_SUPPORTED */
++
+ #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
+ /* Utility function for png_handle_unknown; set up png_ptr::unknown_chunk */
+ static int
+@@ -3953,7 +4131,38 @@
+ {
+ uInt avail_in;
+ png_bytep buffer;
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_uint_32 bytes_to_skip = 0;
++
++ while (png_ptr->idat_size == 0 || bytes_to_skip != 0)
++ {
++ png_crc_finish(png_ptr, bytes_to_skip);
++ bytes_to_skip = 0;
+
++ png_ptr->idat_size = png_read_chunk_header(png_ptr);
++ if (png_ptr->num_frames_read == 0)
++ {
++ if (png_ptr->chunk_name != png_IDAT)
++ png_error(png_ptr, "Not enough image data");
++ }
++ else
++ {
++ if (png_ptr->chunk_name == png_IEND)
++ png_error(png_ptr, "Not enough image data");
++ if (png_ptr->chunk_name != png_fdAT)
++ {
++ png_warning(png_ptr, "Skipped (ignored) a chunk "
++ "between APNG chunks");
++ bytes_to_skip = png_ptr->idat_size;
++ continue;
++ }
++
++ png_ensure_sequence_number(png_ptr, png_ptr->idat_size);
++
++ png_ptr->idat_size -= 4;
++ }
++ }
++#else
+ while (png_ptr->idat_size == 0)
+ {
+ png_crc_finish(png_ptr, 0);
+@@ -3965,7 +4174,7 @@
+ if (png_ptr->chunk_name != png_IDAT)
+ png_error(png_ptr, "Not enough image data");
+ }
+-
++#endif /* PNG_READ_APNG_SUPPORTED */
+ avail_in = png_ptr->IDAT_read_size;
+
+ if (avail_in > png_ptr->idat_size)
+@@ -4028,6 +4237,9 @@
+
+ png_ptr->mode |= PNG_AFTER_IDAT;
+ png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_ptr->num_frames_read++;
++#endif
+
+ if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0)
+ png_chunk_benign_error(png_ptr, "Extra compressed data");
+@@ -4465,4 +4677,80 @@
+
+ png_ptr->flags |= PNG_FLAG_ROW_INIT;
+ }
++
++#ifdef PNG_READ_APNG_SUPPORTED
++/* This function is to be called after the main IDAT set has been read and
++ * before a new IDAT is read. It resets some parts of png_ptr
++ * to make them usable by the read functions again */
++void /* PRIVATE */
++png_read_reset(png_structp png_ptr)
++{
++ png_ptr->mode &= ~PNG_HAVE_IDAT;
++ png_ptr->mode &= ~PNG_AFTER_IDAT;
++ png_ptr->row_number = 0;
++ png_ptr->pass = 0;
++}
++
++void /* PRIVATE */
++png_read_reinit(png_structp png_ptr, png_infop info_ptr)
++{
++ png_ptr->width = info_ptr->next_frame_width;
++ png_ptr->height = info_ptr->next_frame_height;
++ png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->width);
++ png_ptr->info_rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth,
++ png_ptr->width);
++ if (png_ptr->prev_row)
++ memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
++}
++
++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
++/* same as png_read_reset() but for the progressive reader */
++void /* PRIVATE */
++png_progressive_read_reset(png_structp png_ptr)
++{
++#ifdef PNG_READ_INTERLACING_SUPPORTED
++ /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
++
++ /* Start of interlace block */
++ const int png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
++
++ /* Offset to next interlace block */
++ const int png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
++
++ /* Start of interlace block in the y direction */
++ const int png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};
++
++ /* Offset to next interlace block in the y direction */
++ const int png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};
++
++ if (png_ptr->interlaced)
++ {
++ if (!(png_ptr->transformations & PNG_INTERLACE))
++ png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
++ png_pass_ystart[0]) / png_pass_yinc[0];
++ else
++ png_ptr->num_rows = png_ptr->height;
++
++ png_ptr->iwidth = (png_ptr->width +
++ png_pass_inc[png_ptr->pass] - 1 -
++ png_pass_start[png_ptr->pass]) /
++ png_pass_inc[png_ptr->pass];
++ }
++ else
++#endif /* PNG_READ_INTERLACING_SUPPORTED */
++ {
++ png_ptr->num_rows = png_ptr->height;
++ png_ptr->iwidth = png_ptr->width;
++ }
++ png_ptr->flags &= ~PNG_FLAG_ZSTREAM_ENDED;
++ if (inflateReset(&(png_ptr->zstream)) != Z_OK)
++ png_error(png_ptr, "inflateReset failed");
++ png_ptr->zstream.avail_in = 0;
++ png_ptr->zstream.next_in = 0;
++ png_ptr->zstream.next_out = png_ptr->row_buf;
++ png_ptr->zstream.avail_out = (uInt)PNG_ROWBYTES(png_ptr->pixel_depth,
++ png_ptr->iwidth) + 1;
++}
++#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
++#endif /* PNG_READ_APNG_SUPPORTED */
+ #endif /* PNG_READ_SUPPORTED */
+diff -Naru libpng-1.6.14.org/pngset.c libpng-1.6.14/pngset.c
+--- libpng-1.6.14.org/pngset.c 2014-10-23 23:57:22.661675091 +0900
++++ libpng-1.6.14/pngset.c 2014-10-23 23:57:22.735677664 +0900
+@@ -239,6 +239,11 @@
+ info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
+
+ info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);
++
++#ifdef PNG_APNG_SUPPORTED
++ /* for non-animated png. this may be overwritten from an acTL chunk later */
++ info_ptr->num_frames = 1;
++#endif
+ }
+
+ #ifdef PNG_oFFs_SUPPORTED
+@@ -1065,6 +1070,147 @@
+ }
+ #endif /* PNG_sPLT_SUPPORTED */
+
++#ifdef PNG_APNG_SUPPORTED
++png_uint_32 PNGAPI
++png_set_acTL(png_structp png_ptr, png_infop info_ptr,
++ png_uint_32 num_frames, png_uint_32 num_plays)
++{
++ png_debug1(1, "in %s storage function", "acTL");
++
++ if (png_ptr == NULL || info_ptr == NULL)
++ {
++ png_warning(png_ptr,
++ "Call to png_set_acTL() with NULL png_ptr "
++ "or info_ptr ignored");
++ return (0);
++ }
++ if (num_frames == 0)
++ {
++ png_warning(png_ptr,
++ "Ignoring attempt to set acTL with num_frames zero");
++ return (0);
++ }
++ if (num_frames > PNG_UINT_31_MAX)
++ {
++ png_warning(png_ptr,
++ "Ignoring attempt to set acTL with num_frames > 2^31-1");
++ return (0);
++ }
++ if (num_plays > PNG_UINT_31_MAX)
++ {
++ png_warning(png_ptr,
++ "Ignoring attempt to set acTL with num_plays "
++ "> 2^31-1");
++ return (0);
++ }
++
++ info_ptr->num_frames = num_frames;
++ info_ptr->num_plays = num_plays;
++
++ info_ptr->valid |= PNG_INFO_acTL;
++
++ return (1);
++}
++
++/* delay_num and delay_den can hold any 16-bit values including zero */
++png_uint_32 PNGAPI
++png_set_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr,
++ png_uint_32 width, png_uint_32 height,
++ png_uint_32 x_offset, png_uint_32 y_offset,
++ png_uint_16 delay_num, png_uint_16 delay_den,
++ png_byte dispose_op, png_byte blend_op)
++{
++ png_debug1(1, "in %s storage function", "fcTL");
++
++ if (png_ptr == NULL || info_ptr == NULL)
++ {
++ png_warning(png_ptr,
++ "Call to png_set_fcTL() with NULL png_ptr or info_ptr "
++ "ignored");
++ return (0);
++ }
++
++ png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
++ delay_num, delay_den, dispose_op, blend_op);
++
++ if (blend_op == PNG_BLEND_OP_OVER)
++ {
++ if (!(png_ptr->color_type & PNG_COLOR_MASK_ALPHA) &&
++ !(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
++ {
++ png_warning(png_ptr, "PNG_BLEND_OP_OVER is meaningless "
++ "and wasteful for opaque images, ignored");
++ blend_op = PNG_BLEND_OP_SOURCE;
++ }
++ }
++
++ info_ptr->next_frame_width = width;
++ info_ptr->next_frame_height = height;
++ info_ptr->next_frame_x_offset = x_offset;
++ info_ptr->next_frame_y_offset = y_offset;
++ info_ptr->next_frame_delay_num = delay_num;
++ info_ptr->next_frame_delay_den = delay_den;
++ info_ptr->next_frame_dispose_op = dispose_op;
++ info_ptr->next_frame_blend_op = blend_op;
++
++ info_ptr->valid |= PNG_INFO_fcTL;
++
++ return (1);
++}
++
++void /* PRIVATE */
++png_ensure_fcTL_is_valid(png_structp png_ptr,
++ png_uint_32 width, png_uint_32 height,
++ png_uint_32 x_offset, png_uint_32 y_offset,
++ png_uint_16 delay_num, png_uint_16 delay_den,
++ png_byte dispose_op, png_byte blend_op)
++{
++ if (width > PNG_UINT_31_MAX)
++ png_error(png_ptr, "invalid width in fcTL (> 2^31-1)");
++ if (height > PNG_UINT_31_MAX)
++ png_error(png_ptr, "invalid height in fcTL (> 2^31-1)");
++ if (x_offset > PNG_UINT_31_MAX)
++ png_error(png_ptr, "invalid x_offset in fcTL (> 2^31-1)");
++ if (y_offset > PNG_UINT_31_MAX)
++ png_error(png_ptr, "invalid y_offset in fcTL (> 2^31-1)");
++ if (width + x_offset > png_ptr->first_frame_width ||
++ height + y_offset > png_ptr->first_frame_height)
++ png_error(png_ptr, "dimensions of a frame are greater than"
++ "the ones in IHDR");
++
++ if (dispose_op != PNG_DISPOSE_OP_NONE &&
++ dispose_op != PNG_DISPOSE_OP_BACKGROUND &&
++ dispose_op != PNG_DISPOSE_OP_PREVIOUS)
++ png_error(png_ptr, "invalid dispose_op in fcTL");
++
++ if (blend_op != PNG_BLEND_OP_SOURCE &&
++ blend_op != PNG_BLEND_OP_OVER)
++ png_error(png_ptr, "invalid blend_op in fcTL");
++
++ PNG_UNUSED(delay_num)
++ PNG_UNUSED(delay_den)
++}
++
++png_uint_32 PNGAPI
++png_set_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr,
++ png_byte is_hidden)
++{
++ png_debug(1, "in png_first_frame_is_hidden()");
++
++ if (png_ptr == NULL)
++ return 0;
++
++ if (is_hidden)
++ png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
++ else
++ png_ptr->apng_flags &= ~PNG_FIRST_FRAME_HIDDEN;
++
++ PNG_UNUSED(info_ptr)
++
++ return 1;
++}
++#endif /* PNG_APNG_SUPPORTED */
++
+ #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
+ static png_byte
+ check_location(png_const_structrp png_ptr, int location)
+diff -Naru libpng-1.6.14.org/pngstruct.h libpng-1.6.14/pngstruct.h
+--- libpng-1.6.14.org/pngstruct.h 2014-10-23 23:57:22.661675091 +0900
++++ libpng-1.6.14/pngstruct.h 2014-10-23 23:57:22.735677664 +0900
+@@ -409,6 +409,27 @@
+ png_byte filter_type;
+ #endif
+
++#ifdef PNG_APNG_SUPPORTED
++ png_uint_32 apng_flags;
++ png_uint_32 next_seq_num; /* next fcTL/fdAT chunk sequence number */
++ png_uint_32 first_frame_width;
++ png_uint_32 first_frame_height;
++
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_uint_32 num_frames_read; /* incremented after all image data of */
++ /* a frame is read */
++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
++ png_progressive_frame_ptr frame_info_fn; /* frame info read callback */
++ png_progressive_frame_ptr frame_end_fn; /* frame data read callback */
++#endif
++#endif
++
++#ifdef PNG_WRITE_APNG_SUPPORTED
++ png_uint_32 num_frames_to_write;
++ png_uint_32 num_frames_written;
++#endif
++#endif /* PNG_APNG_SUPPORTED */
++
+ /* New members added in libpng-1.2.0 */
+
+ /* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */
+diff -Naru libpng-1.6.14.org/pngtest.c libpng-1.6.14/pngtest.c
+--- libpng-1.6.14.org/pngtest.c 2014-10-23 23:57:22.661675091 +0900
++++ libpng-1.6.14/pngtest.c 2014-10-23 23:57:22.736677699 +0900
+@@ -848,6 +848,10 @@
+ png_uint_32 width, height;
+ int num_pass = 1, pass;
+ int bit_depth, color_type;
++#ifdef PNG_APNG_SUPPORTED
++ png_uint_32 num_frames;
++ png_uint_32 num_plays;
++#endif
+
+ row_buf = NULL;
+ error_parameters.file_name = inname;
+@@ -1314,6 +1318,20 @@
+ }
+ }
+ #endif
++#ifdef PNG_APNG_SUPPORTED
++ if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_acTL))
++ {
++ if (png_get_acTL(read_ptr, read_info_ptr, &num_frames, &num_plays))
++ {
++ png_byte is_hidden;
++ pngtest_debug2("Handling acTL chunks (frames %ld, plays %ld)",
++ num_frames, num_plays);
++ png_set_acTL(write_ptr, write_info_ptr, num_frames, num_plays);
++ is_hidden = png_get_first_frame_is_hidden(read_ptr, read_info_ptr);
++ png_set_first_frame_is_hidden(write_ptr, write_info_ptr, is_hidden);
++ }
++ }
++#endif
+ #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
+ {
+ png_unknown_chunkp unknowns;
+@@ -1375,6 +1393,89 @@
+ t_misc += (t_stop - t_start);
+ t_start = t_stop;
+ #endif
++#ifdef PNG_APNG_SUPPORTED
++ if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_acTL))
++ {
++ png_uint_32 frame;
++ for (frame = 0; frame < num_frames; frame++)
++ {
++ png_uint_32 frame_width;
++ png_uint_32 frame_height;
++ png_uint_32 x_offset;
++ png_uint_32 y_offset;
++ png_uint_16 delay_num;
++ png_uint_16 delay_den;
++ png_byte dispose_op;
++ png_byte blend_op;
++ png_read_frame_head(read_ptr, read_info_ptr);
++ if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_fcTL))
++ {
++ png_get_next_frame_fcTL(read_ptr, read_info_ptr,
++ &frame_width, &frame_height,
++ &x_offset, &y_offset,
++ &delay_num, &delay_den,
++ &dispose_op, &blend_op);
++ }
++ else
++ {
++ frame_width = width;
++ frame_height = height;
++ x_offset = 0;
++ y_offset = 0;
++ delay_num = 1;
++ delay_den = 1;
++ dispose_op = PNG_DISPOSE_OP_NONE;
++ blend_op = PNG_BLEND_OP_SOURCE;
++ }
++#ifdef PNG_WRITE_APNG_SUPPORTED
++ png_write_frame_head(write_ptr, write_info_ptr, (png_bytepp)&row_buf,
++ frame_width, frame_height,
++ x_offset, y_offset,
++ delay_num, delay_den,
++ dispose_op, blend_op);
++#endif
++ for (pass = 0; pass < num_pass; pass++)
++ {
++ pngtest_debug1("Writing row data for pass %d", pass);
++ for (y = 0; y < frame_height; y++)
++ {
++#ifndef SINGLE_ROWBUF_ALLOC
++ pngtest_debug2("Allocating row buffer (pass %d, y = %ld)...", pass, y);
++ row_buf = (png_bytep)png_malloc(read_ptr,
++ png_get_rowbytes(read_ptr, read_info_ptr));
++ pngtest_debug2("0x%08lx (%ld bytes)", (unsigned long)row_buf,
++ png_get_rowbytes(read_ptr, read_info_ptr));
++#endif /* !SINGLE_ROWBUF_ALLOC */
++ png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
++
++#ifdef PNG_WRITE_SUPPORTED
++#ifdef PNGTEST_TIMING
++ t_stop = (float)clock();
++ t_decode += (t_stop - t_start);
++ t_start = t_stop;
++#endif
++ png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
++#ifdef PNGTEST_TIMING
++ t_stop = (float)clock();
++ t_encode += (t_stop - t_start);
++ t_start = t_stop;
++#endif
++#endif /* PNG_WRITE_SUPPORTED */
++
++#ifndef SINGLE_ROWBUF_ALLOC
++ pngtest_debug2("Freeing row buffer (pass %d, y = %ld)", pass, y);
++ png_free(read_ptr, row_buf);
++ row_buf = NULL;
++#endif /* !SINGLE_ROWBUF_ALLOC */
++ }
++ }
++#ifdef PNG_WRITE_APNG_SUPPORTED
++ png_write_frame_tail(write_ptr, write_info_ptr);
++#endif
++ }
++ }
++ else
++#endif
+ for (pass = 0; pass < num_pass; pass++)
+ {
+ pngtest_debug1("Writing row data for pass %d", pass);
+diff -Naru libpng-1.6.14.org/pngwrite.c libpng-1.6.14/pngwrite.c
+--- libpng-1.6.14.org/pngwrite.c 2014-10-23 23:57:22.662675126 +0900
++++ libpng-1.6.14/pngwrite.c 2014-10-23 23:57:22.737677734 +0900
+@@ -127,6 +127,10 @@
+ * application continues writing the PNG. So check the 'invalid' flag here
+ * too.
+ */
++#ifdef PNG_WRITE_APNG_SUPPORTED
++ if (info_ptr->valid & PNG_INFO_acTL)
++ png_write_acTL(png_ptr, info_ptr->num_frames, info_ptr->num_plays);
++#endif
+ #ifdef PNG_GAMMA_SUPPORTED
+ # ifdef PNG_WRITE_gAMA_SUPPORTED
+ if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) &&
+@@ -359,6 +363,11 @@
+ png_benign_error(png_ptr, "Wrote palette index exceeding num_palette");
+ #endif
+
++#ifdef PNG_WRITE_APNG_SUPPORTED
++ if (png_ptr->num_frames_written != png_ptr->num_frames_to_write)
++ png_error(png_ptr, "Not enough frames written");
++#endif
++
+ /* See if user wants us to write information chunks */
+ if (info_ptr != NULL)
+ {
+@@ -1665,6 +1674,43 @@
+ }
+ #endif
+
++#ifdef PNG_WRITE_APNG_SUPPORTED
++void PNGAPI
++png_write_frame_head(png_structp png_ptr, png_infop info_ptr,
++ png_bytepp row_pointers, png_uint_32 width, png_uint_32 height,
++ png_uint_32 x_offset, png_uint_32 y_offset,
++ png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
++ png_byte blend_op)
++{
++ png_debug(1, "in png_write_frame_head");
++
++ /* there is a chance this has been set after png_write_info was called,
++ * so it would be set but not written. is there a way to be sure? */
++ if (!(info_ptr->valid & PNG_INFO_acTL))
++ png_error(png_ptr, "png_write_frame_head(): acTL not set");
++
++ png_write_reset(png_ptr);
++
++ png_write_reinit(png_ptr, info_ptr, width, height);
++
++ if ( !(png_ptr->num_frames_written == 0 &&
++ (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN) ) )
++ png_write_fcTL(png_ptr, width, height, x_offset, y_offset,
++ delay_num, delay_den, dispose_op, blend_op);
++
++ PNG_UNUSED(row_pointers)
++}
++
++void PNGAPI
++png_write_frame_tail(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_write_frame_tail");
++
++ png_ptr->num_frames_written++;
++
++ PNG_UNUSED(info_ptr)
++}
++#endif /* PNG_WRITE_APNG_SUPPORTED */
+
+ #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED
+ #ifdef PNG_STDIO_SUPPORTED /* currently required for png_image_write_* */
+diff -Naru libpng-1.6.14.org/pngwutil.c libpng-1.6.14/pngwutil.c
+--- libpng-1.6.14.org/pngwutil.c 2014-10-23 23:57:22.663675161 +0900
++++ libpng-1.6.14/pngwutil.c 2014-10-23 23:57:22.738677769 +0900
+@@ -902,6 +902,11 @@
+ /* Write the chunk */
+ png_write_complete_chunk(png_ptr, png_IHDR, buf, (png_size_t)13);
+
++#ifdef PNG_WRITE_APNG_SUPPORTED
++ png_ptr->first_frame_width = width;
++ png_ptr->first_frame_height = height;
++#endif
++
+ if ((png_ptr->do_filter) == PNG_NO_FILTERS)
+ {
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
+@@ -1080,7 +1085,14 @@
+ optimize_cmf(data, png_image_size(png_ptr));
+ # endif
+
++# ifdef PNG_WRITE_APNG_SUPPORTED
++ if (png_ptr->num_frames_written == 0)
++# endif
+ png_write_complete_chunk(png_ptr, png_IDAT, data, size);
++# ifdef PNG_WRITE_APNG_SUPPORTED
++ else
++ png_write_fdAT(png_ptr, data, size);
++# endif /* PNG_WRITE_APNG_SUPPORTED */
+ png_ptr->mode |= PNG_HAVE_IDAT;
+
+ png_ptr->zstream.next_out = data;
+@@ -1126,7 +1138,15 @@
+ optimize_cmf(data, png_image_size(png_ptr));
+ # endif
+
++# ifdef PNG_WRITE_APNG_SUPPORTED
++ if (png_ptr->num_frames_written == 0)
++# endif
+ png_write_complete_chunk(png_ptr, png_IDAT, data, size);
++# ifdef PNG_WRITE_APNG_SUPPORTED
++ else
++ png_write_fdAT(png_ptr, data, size);
++# endif /* PNG_WRITE_APNG_SUPPORTED */
++
+ png_ptr->zstream.avail_out = 0;
+ png_ptr->zstream.next_out = NULL;
+ png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT;
+@@ -1939,6 +1959,82 @@
+ }
+ #endif
+
++#ifdef PNG_WRITE_APNG_SUPPORTED
++void /* PRIVATE */
++png_write_acTL(png_structp png_ptr,
++ png_uint_32 num_frames, png_uint_32 num_plays)
++{
++ png_byte buf[8];
++
++ png_debug(1, "in png_write_acTL");
++
++ png_ptr->num_frames_to_write = num_frames;
++
++ if (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN)
++ num_frames--;
++
++ png_save_uint_32(buf, num_frames);
++ png_save_uint_32(buf + 4, num_plays);
++
++ png_write_complete_chunk(png_ptr, png_acTL, buf, (png_size_t)8);
++}
++
++void /* PRIVATE */
++png_write_fcTL(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
++ png_uint_32 x_offset, png_uint_32 y_offset,
++ png_uint_16 delay_num, png_uint_16 delay_den, png_byte dispose_op,
++ png_byte blend_op)
++{
++ png_byte buf[26];
++
++ png_debug(1, "in png_write_fcTL");
++
++ if (png_ptr->num_frames_written == 0 && (x_offset != 0 || y_offset != 0))
++ png_error(png_ptr, "x and/or y offset for the first frame aren't 0");
++ if (png_ptr->num_frames_written == 0 &&
++ (width != png_ptr->first_frame_width ||
++ height != png_ptr->first_frame_height))
++ png_error(png_ptr, "width and/or height in the first frame's fcTL "
++ "don't match the ones in IHDR");
++
++ /* more error checking */
++ png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
++ delay_num, delay_den, dispose_op, blend_op);
++
++ png_save_uint_32(buf, png_ptr->next_seq_num);
++ png_save_uint_32(buf + 4, width);
++ png_save_uint_32(buf + 8, height);
++ png_save_uint_32(buf + 12, x_offset);
++ png_save_uint_32(buf + 16, y_offset);
++ png_save_uint_16(buf + 20, delay_num);
++ png_save_uint_16(buf + 22, delay_den);
++ buf[24] = dispose_op;
++ buf[25] = blend_op;
++
++ png_write_complete_chunk(png_ptr, png_fcTL, buf, (png_size_t)26);
++
++ png_ptr->next_seq_num++;
++}
++
++void /* PRIVATE */
++png_write_fdAT(png_structp png_ptr,
++ png_const_bytep data, png_size_t length)
++{
++ png_byte buf[4];
++
++ png_write_chunk_header(png_ptr, png_fdAT, (png_uint_32)(4 + length));
++
++ png_save_uint_32(buf, png_ptr->next_seq_num);
++ png_write_chunk_data(png_ptr, buf, 4);
++
++ png_write_chunk_data(png_ptr, data, length);
++
++ png_write_chunk_end(png_ptr);
++
++ png_ptr->next_seq_num++;
++}
++#endif /* PNG_WRITE_APNG_SUPPORTED */
++
+ /* Initializes the row writing capability of libpng */
+ void /* PRIVATE */
+ png_write_start_row(png_structrp png_ptr)
+@@ -3026,4 +3122,39 @@
+ }
+ #endif
+ }
++
++#ifdef PNG_WRITE_APNG_SUPPORTED
++void /* PRIVATE */
++png_write_reset(png_structp png_ptr)
++{
++ png_ptr->row_number = 0;
++ png_ptr->pass = 0;
++ png_ptr->mode &= ~PNG_HAVE_IDAT;
++}
++
++void /* PRIVATE */
++png_write_reinit(png_structp png_ptr, png_infop info_ptr,
++ png_uint_32 width, png_uint_32 height)
++{
++ if (png_ptr->num_frames_written == 0 &&
++ (width != png_ptr->first_frame_width ||
++ height != png_ptr->first_frame_height))
++ png_error(png_ptr, "width and/or height in the first frame's fcTL "
++ "don't match the ones in IHDR");
++ if (width > png_ptr->first_frame_width ||
++ height > png_ptr->first_frame_height)
++ png_error(png_ptr, "width and/or height for a frame greater than"
++ "the ones in IHDR");
++
++ png_set_IHDR(png_ptr, info_ptr, width, height,
++ info_ptr->bit_depth, info_ptr->color_type,
++ info_ptr->interlace_type, info_ptr->compression_type,
++ info_ptr->filter_type);
++
++ png_ptr->width = width;
++ png_ptr->height = height;
++ png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
++ png_ptr->usr_width = png_ptr->width;
++}
++#endif /* PNG_WRITE_APNG_SUPPORTED */
+ #endif /* PNG_WRITE_SUPPORTED */
+diff -Naru libpng-1.6.14.org/scripts/symbols.def libpng-1.6.14/scripts/symbols.def
+--- libpng-1.6.14.org/scripts/symbols.def 2014-10-23 23:57:22.670675404 +0900
++++ libpng-1.6.14/scripts/symbols.def 2014-10-23 23:57:22.746678047 +0900
+@@ -249,3 +249,23 @@
+ png_set_check_for_invalid_index @242
+ png_get_palette_max @243
+ png_set_option @244
++ png_get_acTL @245
++ png_set_acTL @246
++ png_get_num_frames @247
++ png_get_num_plays @248
++ png_get_next_frame_fcTL @249
++ png_set_next_frame_fcTL @250
++ png_get_next_frame_width @251
++ png_get_next_frame_height @252
++ png_get_next_frame_x_offset @253
++ png_get_next_frame_y_offset @254
++ png_get_next_frame_delay_num @255
++ png_get_next_frame_delay_den @256
++ png_get_next_frame_dispose_op @257
++ png_get_next_frame_blend_op @258
++ png_get_first_frame_is_hidden @259
++ png_set_first_frame_is_hidden @260
++ png_read_frame_head @261
++ png_set_progressive_frame_fn @262
++ png_write_frame_head @263
++ png_write_frame_tail @264
diff --git a/package/mesalib/Makefile b/package/mesalib/Makefile
index f41d3805c..ef9eb2164 100644
--- a/package/mesalib/Makefile
+++ b/package/mesalib/Makefile
@@ -4,9 +4,9 @@
include $(ADK_TOPDIR)/rules.mk
PKG_NAME:= mesalib
-PKG_VERSION:= 10.2.7
+PKG_VERSION:= 10.3.3
PKG_RELEASE:= 1
-PKG_MD5SUM:= 6927e1ae64818e6b692edaf06c644388
+PKG_MD5SUM:= e02efdfe0466bc75769e462841ab83f2
PKG_DESCR:= 3d graphics library
PKG_SECTION:= libs/video
PKG_DEPENDS:= libxdamage libxfixes libdrm libxxf86vm libexpat
diff --git a/package/nginx/Makefile b/package/nginx/Makefile
index 735c61985..804b6309f 100644
--- a/package/nginx/Makefile
+++ b/package/nginx/Makefile
@@ -4,9 +4,9 @@
include $(ADK_TOPDIR)/rules.mk
PKG_NAME:= nginx
-PKG_VERSION:= 1.7.1
+PKG_VERSION:= 1.7.8
PKG_RELEASE:= 1
-PKG_MD5SUM:= 9659cbb26f226f6390b18ef991a79233
+PKG_MD5SUM:= fd5ab813fc1853cd8efe580ead577c3e
PKG_DESCR:= powerful http reverse proxy and webserver
PKG_SECTION:= net/http
PKG_BUILDDEP:= openssl pcre zlib
diff --git a/package/pciutils/Makefile b/package/pciutils/Makefile
index 09d03cfca..06912c2c5 100644
--- a/package/pciutils/Makefile
+++ b/package/pciutils/Makefile
@@ -4,9 +4,9 @@
include ${ADK_TOPDIR}/rules.mk
PKG_NAME:= pciutils
-PKG_VERSION:= 3.1.10
+PKG_VERSION:= 3.3.0
PKG_RELEASE:= 1
-PKG_MD5SUM:= 72ebc3624ccb43ae2ddf872b5dfdb3c9
+PKG_MD5SUM:= 3c19adf32a8457983b71ff376ef7dafe
PKG_DESCR:= pci utilities (lspci/setpci)
PKG_SECTION:= sys/hw
PKG_DEPENDS:= zlib
diff --git a/package/php/Makefile b/package/php/Makefile
index 4d41781b2..fe1236a50 100644
--- a/package/php/Makefile
+++ b/package/php/Makefile
@@ -4,9 +4,9 @@
include $(ADK_TOPDIR)/rules.mk
PKG_NAME:= php
-PKG_VERSION:= 5.5.17
+PKG_VERSION:= 5.5.19
PKG_RELEASE:= 1
-PKG_MD5SUM:= e5f25dae73004658533ee7701a527bd0
+PKG_MD5SUM:= c63dcfd8b318d12127ba6d39ecc8a444
PKG_DESCR:= php language interpreter
PKG_SECTION:= dev/lang
PKG_DEPENDS:= libpthread librt
diff --git a/package/stunnel/Makefile b/package/stunnel/Makefile
index 9591c0f9f..940d99e7e 100644
--- a/package/stunnel/Makefile
+++ b/package/stunnel/Makefile
@@ -4,9 +4,9 @@
include $(ADK_TOPDIR)/rules.mk
PKG_NAME:= stunnel
-PKG_VERSION:= 5.02
+PKG_VERSION:= 5.07
PKG_RELEASE:= 1
-PKG_MD5SUM:= bb48b1c18cfc0a42708ef996b1a26926
+PKG_MD5SUM:= c10edd84ecbc676a5a48c7e34ab3d1c5
PKG_DESCR:= encryption wrapper
PKG_SECTION:= net/security
PKG_DEPENDS:= libopenssl
diff --git a/package/usbutils/Makefile b/package/usbutils/Makefile
index 2c5e63ad1..e61898872 100644
--- a/package/usbutils/Makefile
+++ b/package/usbutils/Makefile
@@ -4,13 +4,13 @@
include ${ADK_TOPDIR}/rules.mk
PKG_NAME:= usbutils
-PKG_VERSION:= 007
+PKG_VERSION:= 008
PKG_RELEASE:= 1
-PKG_MD5SUM:= c9df5107ae9d26b10a1736a261250139
+PKG_MD5SUM:= 2780b6ae21264c888f8f30fb2aab1259
PKG_DESCR:= program to list usb devices
PKG_SECTION:= sys/hw
PKG_DEPENDS:= libusb libusb-compat libpthread zlib librt
-PKG_BUILDDEP:= libusb libusb-compat zlib
+PKG_BUILDDEP:= libusb libusb-compat zlib eudev
PKG_SITES:= http://www.kernel.org/pub/linux/utils/usb/usbutils/
PKG_BB:= 1
@@ -21,9 +21,6 @@ include ${ADK_TOPDIR}/mk/package.mk
$(eval $(call PKG_template,LSUSB,lsusb,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
lsusb-install:
- ${INSTALL_DIR} ${IDIR_LSUSB}/usr/share
- ${INSTALL_DATA} ${WRKINST}/usr/share/usb.ids.gz \
- ${IDIR_LSUSB}/usr/share/
${INSTALL_DIR} ${IDIR_LSUSB}/usr/bin
${INSTALL_BIN} ${WRKINST}/usr/bin/lsusb ${IDIR_LSUSB}/usr/bin
diff --git a/target/arch.lst b/target/arch.lst
index fd5c9f80c..eb4a4a77e 100644
--- a/target/arch.lst
+++ b/target/arch.lst
@@ -4,6 +4,7 @@ arc
arm
avr32
bfin
+c6x
cris
m68k
microblaze
diff --git a/target/arm/kernel/linksys-nslu2 b/target/arm/kernel/linksys-nslu2
new file mode 100644
index 000000000..19cffbe68
--- /dev/null
+++ b/target/arm/kernel/linksys-nslu2
@@ -0,0 +1,5 @@
+CONFIG_ARM=y
+CONFIG_ARM_PATCH_PHYS_VIRT=y
+CONFIG_CPU_XSCALE=y
+CONFIG_ATAGS=y
+CONFIG_ATAGS_PROC=y
diff --git a/target/arm/raspberry-pi/patches/3.16.6/raspberry-pi.patch b/target/arm/raspberry-pi/patches/3.17.4/raspberry-pi.patch
index 6acfbb637..6acfbb637 100644
--- a/target/arm/raspberry-pi/patches/3.16.6/raspberry-pi.patch
+++ b/target/arm/raspberry-pi/patches/3.17.4/raspberry-pi.patch
diff --git a/target/arm/solidrun-imx6/patches/3.16.6/rmk.patch b/target/arm/solidrun-imx6/patches/3.17.4/rmk.patch
index a0e0e7495..a0e0e7495 100644
--- a/target/arm/solidrun-imx6/patches/3.16.6/rmk.patch
+++ b/target/arm/solidrun-imx6/patches/3.17.4/rmk.patch
diff --git a/target/arm/systems/linksys-nslu2 b/target/arm/systems/linksys-nslu2
new file mode 100644
index 000000000..dd72c5cae
--- /dev/null
+++ b/target/arm/systems/linksys-nslu2
@@ -0,0 +1,11 @@
+config ADK_TARGET_SYSTEM_LINKSYS_NSLU2
+ bool "Linksys NSLU2"
+ select ADK_arm
+ select ADK_big
+ select ADK_eabihf
+ select ADK_linksys_nslu2
+ select ADK_TARGET_WITH_USB
+ select ADK_TARGET_KERNEL_ZIMAGE
+ help
+ Linksys NSLU2
+
diff --git a/target/c6x/Makefile b/target/c6x/Makefile
new file mode 100644
index 000000000..ebc17340e
--- /dev/null
+++ b/target/c6x/Makefile
@@ -0,0 +1,9 @@
+# This file is part of the OpenADK project. OpenADK is copyrighted
+# material, please see the LICENCE file in the top-level directory.
+
+include $(ADK_TOPDIR)/rules.mk
+include $(ADK_TOPDIR)/mk/kernel.mk
+include $(ADK_TOPDIR)/mk/modules.mk
+include $(ADK_TOPDIR)/mk/kernel-build.mk
+include $(ADK_TOPDIR)/mk/image.mk
+
diff --git a/target/c6x/systems/toolchain-c6x b/target/c6x/systems/toolchain-c6x
new file mode 100644
index 000000000..f2a352446
--- /dev/null
+++ b/target/c6x/systems/toolchain-c6x
@@ -0,0 +1,11 @@
+config ADK_TARGET_SYSTEM_TOOLCHAIN_C6X
+ bool "Toolchain only"
+ select ADK_c6x
+ select ADK_toolchain_c6x
+ select ADK_CPU_C6X
+ select ADK_TARGET_TOOLCHAIN
+ select ADK_TARGET_PACKAGE_TXZ
+ select ADK_TARGET_UCLINUX
+ help
+ C6X toolchain.
+
diff --git a/target/c6x/uclibc.config b/target/c6x/uclibc.config
new file mode 100644
index 000000000..9915cd324
--- /dev/null
+++ b/target/c6x/uclibc.config
@@ -0,0 +1,248 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# uClibc 1.0.0-git C Library Configuration
+#
+# TARGET_alpha is not set
+# TARGET_arc is not set
+# TARGET_arm is not set
+# TARGET_avr32 is not set
+# TARGET_bfin is not set
+TARGET_c6x=y
+# TARGET_cris is not set
+# TARGET_hppa is not set
+# TARGET_i386 is not set
+# TARGET_ia64 is not set
+# TARGET_m68k is not set
+# TARGET_metag is not set
+# TARGET_microblaze is not set
+# TARGET_mips is not set
+# TARGET_nios2 is not set
+# TARGET_powerpc is not set
+# TARGET_sh is not set
+# TARGET_sh64 is not set
+# TARGET_sparc is not set
+# TARGET_vax is not set
+# TARGET_x86_64 is not set
+# TARGET_xtensa is not set
+
+#
+# Target Architecture Features and Options
+#
+TARGET_ARCH="c6x"
+FORCE_OPTIONS_FOR_ARCH=y
+# CONFIG_CRIS is not set
+# CONFIG_CRISV32 is not set
+CONFIG_GENERIC_C6X=y
+# CONFIG_TMS320C64X is not set
+# CONFIG_TMS320C64XPLUS is not set
+TARGET_SUBARCH=""
+UCLIBC_FORMAT_DSBT_ELF=y
+# UCLIBC_FORMAT_FLAT is not set
+# UCLIBC_FORMAT_FLAT_SEP_DATA is not set
+# UCLIBC_FORMAT_SHARED_FLAT is not set
+ARCH_ANY_ENDIAN=y
+ARCH_LITTLE_ENDIAN=y
+# ARCH_WANTS_BIG_ENDIAN is not set
+ARCH_WANTS_LITTLE_ENDIAN=y
+ARCH_HAS_NO_MMU=y
+
+#
+# Target CPU lacks a memory management unit (MMU)
+#
+UCLIBC_HAS_FLOATS=y
+UCLIBC_HAS_FPU=y
+DO_C99_MATH=y
+# DO_XSI_MATH is not set
+UCLIBC_HAS_FENV=y
+KERNEL_HEADERS=""
+UCLIBC_UCLINUX_BROKEN_MUNMAP=y
+HAVE_DOT_CONFIG=y
+
+#
+# General Library Settings
+#
+DOPIC=y
+HAVE_SHARED=y
+FORCE_SHAREABLE_TEXT_SEGMENTS=y
+LDSO_LDD_SUPPORT=y
+LDSO_CACHE_SUPPORT=y
+# LDSO_PRELOAD_ENV_SUPPORT is not set
+# LDSO_PRELOAD_FILE_SUPPORT is not set
+LDSO_BASE_FILENAME="ld.so"
+# LDSO_STANDALONE_SUPPORT is not set
+# LDSO_PRELINK_SUPPORT is not set
+# UCLIBC_STATIC_LDCONFIG is not set
+LDSO_RUNPATH=y
+LDSO_SAFE_RUNPATH=y
+LDSO_SEARCH_INTERP_PATH=y
+LDSO_LD_LIBRARY_PATH=y
+# LDSO_NO_CLEANUP is not set
+UCLIBC_CTOR_DTOR=y
+# LDSO_GNU_HASH_SUPPORT is not set
+# HAS_NO_THREADS is not set
+# LINUXTHREADS_OLD is not set
+# LINUXTHREADS_NEW is not set
+UCLIBC_HAS_THREADS_NATIVE=y
+UCLIBC_HAS_THREADS=y
+PTHREADS_DEBUG_SUPPORT=y
+UCLIBC_HAS_SYSLOG=y
+UCLIBC_HAS_LFS=y
+MALLOC=y
+# MALLOC_SIMPLE is not set
+# MALLOC_STANDARD is not set
+MALLOC_GLIBC_COMPAT=y
+UCLIBC_HAS_OBSTACK=y
+UCLIBC_DYNAMIC_ATEXIT=y
+COMPAT_ATEXIT=y
+UCLIBC_SUSV2_LEGACY=y
+UCLIBC_SUSV3_LEGACY=y
+# UCLIBC_SUSV3_LEGACY_MACROS is not set
+UCLIBC_SUSV4_LEGACY=y
+# UCLIBC_STRICT_HEADERS is not set
+# UCLIBC_HAS_STUBS is not set
+UCLIBC_HAS_SHADOW=y
+UCLIBC_HAS_PROGRAM_INVOCATION_NAME=y
+UCLIBC_HAS___PROGNAME=y
+UCLIBC_HAS_PTY=y
+ASSUME_DEVPTS=y
+UNIX98PTY_ONLY=y
+UCLIBC_HAS_GETPT=y
+UCLIBC_HAS_LIBUTIL=y
+UCLIBC_HAS_TM_EXTENSIONS=y
+UCLIBC_HAS_TZ_CACHING=y
+UCLIBC_HAS_TZ_FILE=y
+UCLIBC_HAS_TZ_FILE_READ_MANY=y
+UCLIBC_TZ_FILE_PATH="/etc/TZ"
+UCLIBC_FALLBACK_TO_ETC_LOCALTIME=y
+
+#
+# Advanced Library Settings
+#
+UCLIBC_PWD_BUFFER_SIZE=256
+UCLIBC_GRP_BUFFER_SIZE=256
+
+#
+# Support various families of functions
+#
+UCLIBC_LINUX_MODULE_26=y
+UCLIBC_LINUX_SPECIFIC=y
+UCLIBC_HAS_GNU_ERROR=y
+UCLIBC_BSD_SPECIFIC=y
+UCLIBC_HAS_BSD_ERR=y
+UCLIBC_HAS_OBSOLETE_BSD_SIGNAL=y
+# UCLIBC_HAS_OBSOLETE_SYSV_SIGNAL is not set
+# UCLIBC_NTP_LEGACY is not set
+UCLIBC_SV4_DEPRECATED=y
+UCLIBC_HAS_REALTIME=y
+UCLIBC_HAS_ADVANCED_REALTIME=y
+UCLIBC_HAS_EPOLL=y
+UCLIBC_HAS_XATTR=y
+# UCLIBC_HAS_PROFILING is not set
+UCLIBC_HAS_CRYPT_IMPL=y
+# UCLIBC_HAS_SHA256_CRYPT_IMPL is not set
+# UCLIBC_HAS_SHA512_CRYPT_IMPL is not set
+UCLIBC_HAS_CRYPT=y
+UCLIBC_HAS_NETWORK_SUPPORT=y
+UCLIBC_HAS_SOCKET=y
+UCLIBC_HAS_IPV4=y
+UCLIBC_HAS_IPV6=y
+# UCLIBC_HAS_RPC is not set
+UCLIBC_USE_NETLINK=y
+UCLIBC_SUPPORT_AI_ADDRCONFIG=y
+UCLIBC_HAS_BSD_RES_CLOSE=y
+UCLIBC_HAS_COMPAT_RES_STATE=y
+# UCLIBC_HAS_EXTRA_COMPAT_RES_STATE is not set
+UCLIBC_HAS_RESOLVER_SUPPORT=y
+UCLIBC_HAS_LIBRESOLV_STUB=y
+UCLIBC_HAS_LIBNSL_STUB=y
+
+#
+# String and Stdio Support
+#
+UCLIBC_HAS_STRING_GENERIC_OPT=y
+UCLIBC_HAS_STRING_ARCH_OPT=y
+UCLIBC_HAS_CTYPE_TABLES=y
+UCLIBC_HAS_CTYPE_SIGNED=y
+# UCLIBC_HAS_CTYPE_UNSAFE is not set
+UCLIBC_HAS_CTYPE_CHECKED=y
+# UCLIBC_HAS_CTYPE_ENFORCED is not set
+UCLIBC_HAS_WCHAR=y
+# UCLIBC_HAS_LOCALE is not set
+UCLIBC_HAS_HEXADECIMAL_FLOATS=y
+UCLIBC_HAS_GLIBC_CUSTOM_PRINTF=y
+UCLIBC_PRINTF_SCANF_POSITIONAL_ARGS=9
+# UCLIBC_HAS_STDIO_BUFSIZ_256 is not set
+# UCLIBC_HAS_STDIO_BUFSIZ_512 is not set
+# UCLIBC_HAS_STDIO_BUFSIZ_1024 is not set
+# UCLIBC_HAS_STDIO_BUFSIZ_2048 is not set
+UCLIBC_HAS_STDIO_BUFSIZ_4096=y
+# UCLIBC_HAS_STDIO_BUFSIZ_8192 is not set
+UCLIBC_HAS_STDIO_BUILTIN_BUFFER_NONE=y
+# UCLIBC_HAS_STDIO_BUILTIN_BUFFER_4 is not set
+# UCLIBC_HAS_STDIO_BUILTIN_BUFFER_8 is not set
+# UCLIBC_HAS_STDIO_SHUTDOWN_ON_ABORT is not set
+UCLIBC_HAS_STDIO_GETC_MACRO=y
+UCLIBC_HAS_STDIO_PUTC_MACRO=y
+UCLIBC_HAS_STDIO_AUTO_RW_TRANSITION=y
+# UCLIBC_HAS_FOPEN_LARGEFILE_MODE is not set
+UCLIBC_HAS_FOPEN_EXCLUSIVE_MODE=y
+# UCLIBC_HAS_FOPEN_CLOSEEXEC_MODE is not set
+UCLIBC_HAS_GLIBC_CUSTOM_STREAMS=y
+UCLIBC_HAS_PRINTF_M_SPEC=y
+UCLIBC_HAS_ERRNO_MESSAGES=y
+# UCLIBC_HAS_SYS_ERRLIST is not set
+UCLIBC_HAS_SIGNUM_MESSAGES=y
+# UCLIBC_HAS_SYS_SIGLIST is not set
+UCLIBC_HAS_GNU_GETOPT=y
+UCLIBC_HAS_GNU_GETSUBOPT=y
+
+#
+# Big and Tall
+#
+UCLIBC_HAS_REGEX=y
+# UCLIBC_HAS_REGEX_OLD is not set
+UCLIBC_HAS_FNMATCH=y
+# UCLIBC_HAS_FNMATCH_OLD is not set
+UCLIBC_HAS_WORDEXP=y
+UCLIBC_HAS_NFTW=y
+UCLIBC_HAS_FTW=y
+UCLIBC_HAS_FTS=y
+UCLIBC_HAS_GLOB=y
+UCLIBC_HAS_GNU_GLOB=y
+UCLIBC_HAS_UTMPX=y
+
+#
+# Library Installation Options
+#
+RUNTIME_PREFIX="/"
+DEVEL_PREFIX="/usr/"
+MULTILIB_DIR="lib"
+HARDWIRED_ABSPATH=y
+
+#
+# Security options
+#
+UCLIBC_HAS_ARC4RANDOM=y
+# ARC4RANDOM_USES_NODEV is not set
+# UCLIBC_HAS_SSP is not set
+UCLIBC_BUILD_RELRO=y
+UCLIBC_BUILD_NOW=y
+UCLIBC_BUILD_NOEXECSTACK=y
+
+#
+# Development/debugging options
+#
+CROSS_COMPILER_PREFIX=""
+UCLIBC_EXTRA_CFLAGS=""
+# DODEBUG is not set
+# DODEBUG_PT is not set
+# DOSTRIP is not set
+# DOASSERTS is not set
+# SUPPORT_LD_DEBUG is not set
+# SUPPORT_LD_DEBUG_EARLY is not set
+# UCLIBC_MALLOC_DEBUGGING is not set
+# UCLIBC_HAS_BACKTRACE is not set
+WARNINGS="-Wall"
+# EXTRA_WARNINGS is not set
+# DOMULTI is not set
+# UCLIBC_MJN3_ONLY is not set
diff --git a/target/config/Config.in.cpu b/target/config/Config.in.cpu
index afb99ebc9..4e77bcf63 100644
--- a/target/config/Config.in.cpu
+++ b/target/config/Config.in.cpu
@@ -49,6 +49,9 @@ config ADK_CPU_ARC
config ADK_CPU_TILE
boolean
+config ADK_CPU_C6X
+ boolean
+
config ADK_CPU_CRIS_V10
boolean
@@ -144,6 +147,7 @@ config ADK_TARGET_CPU_ARCH
default "arceb" if ADK_CPU_ARC && ADK_big
default "avr32" if ADK_CPU_AVR32
default "bfin" if ADK_CPU_BFIN
+ default "c6x" if ADK_CPU_C6X
default "cris" if ADK_CPU_CRIS_V10
default "crisv32" if ADK_CPU_CRIS_V32
default "i486" if ADK_CPU_I486
diff --git a/target/config/Config.in.endian.choice b/target/config/Config.in.endian.choice
index 4e866b6c5..d89184ab0 100644
--- a/target/config/Config.in.endian.choice
+++ b/target/config/Config.in.endian.choice
@@ -5,12 +5,14 @@ choice ADK_TARGET_ENDIAN_MODE
prompt "Target Endianess"
depends on !ADK_CHOOSE_TARGET_ARCH && !ADK_CHOOSE_TARGET_SYSTEM
depends on ADK_LINUX_SH || ADK_LINUX_MIPS || ADK_LINUX_MICROBLAZE \
- || ADK_LINUX_MIPS64 || ADK_LINUX_ARC || ADK_LINUX_ARM
+ || ADK_LINUX_MIPS64 || ADK_LINUX_ARC || ADK_LINUX_ARM || ADK_LINUX_C6X
depends on !ADK_TARGET_SYSTEM_MIKROTIK_RB532
+depends on !ADK_TARGET_SYSTEM_DRAGINO_MS14S
depends on !ADK_TARGET_SYSTEM_LEMOTE_YEELONG
depends on !ADK_TARGET_SYSTEM_RASPBERRY_PI
depends on !ADK_TARGET_SYSTEM_SOLIDRUN_IMX6
depends on !ADK_TARGET_SYSTEM_QEMU_ARM
+depends on !ADK_TARGET_SYSTEM_LINKSYS_NSLU2
config ADK_TARGET_LITTLE_ENDIAN
boolean "Little endian"
diff --git a/target/config/Config.in.kernel b/target/config/Config.in.kernel
index add212587..02b99a5c2 100644
--- a/target/config/Config.in.kernel
+++ b/target/config/Config.in.kernel
@@ -59,9 +59,11 @@ config ADK_TARGET_KERNEL_MINICONFIG
default "solidrun-imx6" if ADK_TARGET_SYSTEM_SOLIDRUN_IMX6
default "raspberry-pi" if ADK_TARGET_SYSTEM_RASPBERRY_PI
default "sharp-zaurus" if ADK_TARGET_SYSTEM_SHARP_ZAURUS
+ default "linksys-nslu2" if ADK_TARGET_SYSTEM_LINKSYS_NSLU2
default "lemote-yeelong" if ADK_TARGET_SYSTEM_LEMOTE_YEELONG
default "mikrotik-rb4xx" if ADK_TARGET_SYSTEM_MIKROTIK_RB4XX
default "mikrotik-rb532" if ADK_TARGET_SYSTEM_MIKROTIK_RB532
+ default "dragino-ms14s" if ADK_TARGET_SYSTEM_DRAGINO_MS14S
default "generic-pc" if ADK_TARGET_SYSTEM_GENERIC_PC
default "pcengines-apu" if ADK_TARGET_SYSTEM_PCENGINES_APU
diff --git a/target/config/Config.in.kernelversion.choice b/target/config/Config.in.kernelversion.choice
index 4ea43d591..9d1af6b8c 100644
--- a/target/config/Config.in.kernelversion.choice
+++ b/target/config/Config.in.kernelversion.choice
@@ -5,13 +5,13 @@ choice
prompt "Kernel Version"
depends on !ADK_CHOOSE_TARGET_ARCH && !ADK_CHOOSE_TARGET_SYSTEM && ADK_TARGET_KERNEL_CUSTOMISING
default ADK_KERNEL_VERSION_3_14_22 if ADK_TARGET_SYSTEM_SOLIDRUN_IMX6
-default ADK_KERNEL_VERSION_3_16_6
+default ADK_KERNEL_VERSION_3_17.4
-config ADK_KERNEL_VERSION_3_16_6
- prompt "3.16.6"
+config ADK_KERNEL_VERSION_3_17_4
+ prompt "3.17.4"
depends on !ADK_TARGET_SYSTEM_MIKROTIK_RB4XX
boolean
- select ADK_KERNEL_VERSION_3_16
+ select ADK_KERNEL_VERSION_3_17
config ADK_KERNEL_VERSION_3_14_22
prompt "3.14.22"
diff --git a/target/config/Config.in.kernelversion.default b/target/config/Config.in.kernelversion.default
index d02b41730..9209c4527 100644
--- a/target/config/Config.in.kernelversion.default
+++ b/target/config/Config.in.kernelversion.default
@@ -1,7 +1,7 @@
# This file is part of the OpenADK project. OpenADK is copyrighted
# material, please see the LICENCE file in the top-level directory.
-config ADK_KERNEL_VERSION_3_16
+config ADK_KERNEL_VERSION_3_17
boolean
config ADK_KERNEL_VERSION_3_14
@@ -18,7 +18,7 @@ config ADK_KERNEL_VERSION_3_4
config ADK_KERNEL_VERSION
string
- default "3.16.6" if ADK_KERNEL_VERSION_3_16_6
+ default "3.17.4" if ADK_KERNEL_VERSION_3_17_4
default "3.14.22" if ADK_KERNEL_VERSION_3_14_22
default "3.12.33" if ADK_KERNEL_VERSION_3_12_33
default "3.10.53" if ADK_KERNEL_VERSION_3_10_53
diff --git a/target/config/Config.in.toolchain b/target/config/Config.in.toolchain
index a5c91f0f7..7d4dbad74 100644
--- a/target/config/Config.in.toolchain
+++ b/target/config/Config.in.toolchain
@@ -26,7 +26,7 @@ config ADK_TOOLCHAIN_GCC_4_5_4
config ADK_TOOLCHAIN_GCC_4_7_4
prompt "4.7.4"
boolean
- depends on ADK_LINUX_CRIS
+ depends on ADK_LINUX_CRIS || ADK_LINUX_C6X
config ADK_TOOLCHAIN_GCC_4_8_0_ARC
prompt "4.8.0-arc"
@@ -42,14 +42,16 @@ config ADK_TOOLCHAIN_GCC_4_8_3
depends on !ADK_LINUX_AVR32
depends on !ADK_LINUX_CRIS
depends on !ADK_LINUX_TILE
+ depends on !ADK_LINUX_C6X
-config ADK_TOOLCHAIN_GCC_4_9_1
- prompt "4.9.1"
+config ADK_TOOLCHAIN_GCC_4_9_2
+ prompt "4.9.2"
boolean
depends on !ADK_LINUX_BFIN
depends on !ADK_LINUX_ARC
depends on !ADK_LINUX_AVR32
depends on !ADK_LINUX_CRIS
+ depends on !ADK_LINUX_C6X
config ADK_TOOLCHAIN_GCC_GIT
prompt "git"
@@ -134,6 +136,7 @@ config ADK_LINUX_ARM_WITH_THUMB
boolean
select ADK_KERNEL_THUMB2_KERNEL
default n
+ depends on ADK_LINUX_ARM
help
Experimental option. Use with care.
diff --git a/target/linux/patches/3.16.6/disable-netfilter.patch b/target/linux/patches/3.16.6/disable-netfilter.patch
deleted file mode 100644
index 7b1ca013a..000000000
--- a/target/linux/patches/3.16.6/disable-netfilter.patch
+++ /dev/null
@@ -1,160 +0,0 @@
-diff -Nur linux-3.7.3.orig/net/Kconfig linux-3.7.3/net/Kconfig
---- linux-3.7.3.orig/net/Kconfig 2013-01-17 17:47:40.000000000 +0100
-+++ linux-3.7.3/net/Kconfig 2013-01-19 18:19:55.000000000 +0100
-@@ -163,7 +163,7 @@
- config NETFILTER_ADVANCED
- bool "Advanced netfilter configuration"
- depends on NETFILTER
-- default y
-+ default n
- help
- If you say Y here you can select between all the netfilter modules.
- If you say N the more unusual ones will not be shown and the
-@@ -175,7 +175,7 @@
- bool "Bridged IP/ARP packets filtering"
- depends on BRIDGE && NETFILTER && INET
- depends on NETFILTER_ADVANCED
-- default y
-+ default n
- ---help---
- Enabling this option will let arptables resp. iptables see bridged
- ARP resp. IP traffic. If you want a bridging firewall, you probably
-diff -Nur linux-3.7.3.orig/net/netfilter/Kconfig linux-3.7.3/net/netfilter/Kconfig
---- linux-3.7.3.orig/net/netfilter/Kconfig 2013-01-17 17:47:40.000000000 +0100
-+++ linux-3.7.3/net/netfilter/Kconfig 2013-01-19 18:21:41.000000000 +0100
-@@ -22,7 +22,6 @@
-
- config NETFILTER_NETLINK_LOG
- tristate "Netfilter LOG over NFNETLINK interface"
-- default m if NETFILTER_ADVANCED=n
- select NETFILTER_NETLINK
- help
- If this option is enabled, the kernel will include support
-@@ -34,7 +33,6 @@
-
- config NF_CONNTRACK
- tristate "Netfilter connection tracking support"
-- default m if NETFILTER_ADVANCED=n
- help
- Connection tracking keeps a record of what packets have passed
- through your machine, in order to figure out how they are related
-@@ -60,7 +58,6 @@
- config NF_CONNTRACK_SECMARK
- bool 'Connection tracking security mark support'
- depends on NETWORK_SECMARK
-- default m if NETFILTER_ADVANCED=n
- help
- This option enables security markings to be applied to
- connections. Typically they are copied to connections from
-@@ -177,7 +174,6 @@
-
- config NF_CONNTRACK_FTP
- tristate "FTP protocol support"
-- default m if NETFILTER_ADVANCED=n
- help
- Tracking FTP connections is problematic: special helpers are
- required for tracking them, and doing masquerading and other forms
-@@ -211,7 +207,6 @@
-
- config NF_CONNTRACK_IRC
- tristate "IRC protocol support"
-- default m if NETFILTER_ADVANCED=n
- help
- There is a commonly-used extension to IRC called
- Direct Client-to-Client Protocol (DCC). This enables users to send
-@@ -296,7 +291,6 @@
-
- config NF_CONNTRACK_SIP
- tristate "SIP protocol support"
-- default m if NETFILTER_ADVANCED=n
- help
- SIP is an application-layer control protocol that can establish,
- modify, and terminate multimedia sessions (conferences) such as
-@@ -320,7 +314,6 @@
- config NF_CT_NETLINK
- tristate 'Connection tracking netlink interface'
- select NETFILTER_NETLINK
-- default m if NETFILTER_ADVANCED=n
- help
- This option enables support for a netlink-based userspace interface
-
-@@ -424,7 +417,6 @@
-
- config NETFILTER_XTABLES
- tristate "Netfilter Xtables support (required for ip_tables)"
-- default m if NETFILTER_ADVANCED=n
- help
- This is required if you intend to use any of ip_tables,
- ip6_tables or arp_tables.
-@@ -435,7 +427,6 @@
-
- config NETFILTER_XT_MARK
- tristate 'nfmark target and match support'
-- default m if NETFILTER_ADVANCED=n
- ---help---
- This option adds the "MARK" target and "mark" match.
-
-@@ -527,7 +518,6 @@
- config NETFILTER_XT_TARGET_CONNSECMARK
- tristate '"CONNSECMARK" target support'
- depends on NF_CONNTRACK && NF_CONNTRACK_SECMARK
-- default m if NETFILTER_ADVANCED=n
- help
- The CONNSECMARK target copies security markings from packets
- to connections, and restores security markings from connections
-@@ -632,7 +622,6 @@
-
- config NETFILTER_XT_TARGET_LOG
- tristate "LOG target support"
-- default m if NETFILTER_ADVANCED=n
- help
- This option adds a `LOG' target, which allows you to create rules in
- any iptables table which records the packet header to the syslog.
-@@ -660,7 +649,6 @@
-
- config NETFILTER_XT_TARGET_NFLOG
- tristate '"NFLOG" target support'
-- default m if NETFILTER_ADVANCED=n
- select NETFILTER_NETLINK_LOG
- help
- This option enables the NFLOG target, which allows to LOG
-@@ -741,7 +729,6 @@
- config NETFILTER_XT_TARGET_SECMARK
- tristate '"SECMARK" target support'
- depends on NETWORK_SECMARK
-- default m if NETFILTER_ADVANCED=n
- help
- The SECMARK target allows security marking of network
- packets, for use with security subsystems.
-@@ -751,7 +738,6 @@
- config NETFILTER_XT_TARGET_TCPMSS
- tristate '"TCPMSS" target support'
- depends on (IPV6 || IPV6=n)
-- default m if NETFILTER_ADVANCED=n
- ---help---
- This option adds a `TCPMSS' target, which allows you to alter the
- MSS value of TCP SYN packets, to control the maximum size for that
-@@ -856,7 +842,6 @@
- config NETFILTER_XT_MATCH_CONNTRACK
- tristate '"conntrack" connection tracking match support'
- depends on NF_CONNTRACK
-- default m if NETFILTER_ADVANCED=n
- help
- This is a general conntrack match module, a superset of the state match.
-
-@@ -1063,7 +1048,6 @@
- config NETFILTER_XT_MATCH_POLICY
- tristate 'IPsec "policy" match support'
- depends on XFRM
-- default m if NETFILTER_ADVANCED=n
- help
- Policy matching allows you to match packets based on the
- IPsec policy that was used during decapsulation/will
-@@ -1170,7 +1154,6 @@
- config NETFILTER_XT_MATCH_STATE
- tristate '"state" match support'
- depends on NF_CONNTRACK
-- default m if NETFILTER_ADVANCED=n
- help
- Connection state matching allows you to match packets based on their
- relationship to a tracked connection (ie. previous packets). This
diff --git a/target/linux/patches/3.16.6/sparc-memset.patch b/target/linux/patches/3.16.6/sparc-memset.patch
deleted file mode 100644
index 022c87b3a..000000000
--- a/target/linux/patches/3.16.6/sparc-memset.patch
+++ /dev/null
@@ -1,50 +0,0 @@
-This makes memset follow the standard (instead of returning 0 on success). This
-is needed when certain versions of gcc optimizes around memset calls and assume
-that the address argument is preserved in %o0.
-
-Signed-off-by: Andreas Larsson <andreas@gaisler.com>
-
-diff -Nur linux-3.16.2.orig/arch/sparc/lib/memset.S linux-3.16.2/arch/sparc/lib/memset.S
---- linux-3.16.2.orig/arch/sparc/lib/memset.S 2014-09-06 01:37:11.000000000 +0200
-+++ linux-3.16.2/arch/sparc/lib/memset.S 2014-09-18 09:53:49.563047773 +0200
-@@ -65,6 +65,8 @@
- .globl __memset_start, __memset_end
- __memset_start:
- memset:
-+ mov %o0, %g1
-+ mov 1, %g4
- and %o1, 0xff, %g3
- sll %g3, 8, %g2
- or %g3, %g2, %g3
-@@ -89,6 +91,7 @@
- sub %o0, %o2, %o0
-
- __bzero:
-+ clr %g4
- mov %g0, %g3
- 1:
- cmp %o1, 7
-@@ -151,8 +154,8 @@
- bne,a 8f
- EX(stb %g3, [%o0], and %o1, 1)
- 8:
-- retl
-- clr %o0
-+ b 0f
-+ nop
- 7:
- be 13b
- orcc %o1, 0, %g0
-@@ -164,6 +167,12 @@
- bne 8b
- EX(stb %g3, [%o0 - 1], add %o1, 1)
- 0:
-+ andcc %g4, 1, %g0
-+ be 5f
-+ nop
-+ retl
-+ mov %g1, %o0
-+5:
- retl
- clr %o0
- __memset_end:
diff --git a/target/linux/patches/3.16.6/bsd-compatibility.patch b/target/linux/patches/3.17.4/bsd-compatibility.patch
index b954b658f..b954b658f 100644
--- a/target/linux/patches/3.16.6/bsd-compatibility.patch
+++ b/target/linux/patches/3.17.4/bsd-compatibility.patch
diff --git a/target/linux/patches/3.16.6/cleankernel.patch b/target/linux/patches/3.17.4/cleankernel.patch
index d8c055dc3..d8c055dc3 100644
--- a/target/linux/patches/3.16.6/cleankernel.patch
+++ b/target/linux/patches/3.17.4/cleankernel.patch
diff --git a/target/linux/patches/3.16.6/cris-header.patch b/target/linux/patches/3.17.4/cris-header.patch
index 3db07e530..3db07e530 100644
--- a/target/linux/patches/3.16.6/cris-header.patch
+++ b/target/linux/patches/3.17.4/cris-header.patch
diff --git a/target/linux/patches/3.16.6/defaults.patch b/target/linux/patches/3.17.4/defaults.patch
index 6cdca084e..6cdca084e 100644
--- a/target/linux/patches/3.16.6/defaults.patch
+++ b/target/linux/patches/3.17.4/defaults.patch
diff --git a/target/linux/patches/3.16.6/export-symbol-for-exmap.patch b/target/linux/patches/3.17.4/export-symbol-for-exmap.patch
index 4f0fc8449..4f0fc8449 100644
--- a/target/linux/patches/3.16.6/export-symbol-for-exmap.patch
+++ b/target/linux/patches/3.17.4/export-symbol-for-exmap.patch
diff --git a/target/linux/patches/3.16.6/gemalto.patch b/target/linux/patches/3.17.4/gemalto.patch
index 65f7af1d7..65f7af1d7 100644
--- a/target/linux/patches/3.16.6/gemalto.patch
+++ b/target/linux/patches/3.17.4/gemalto.patch
diff --git a/target/linux/patches/3.16.6/initramfs-nosizelimit.patch b/target/linux/patches/3.17.4/initramfs-nosizelimit.patch
index 40d2f6bd8..40d2f6bd8 100644
--- a/target/linux/patches/3.16.6/initramfs-nosizelimit.patch
+++ b/target/linux/patches/3.17.4/initramfs-nosizelimit.patch
diff --git a/target/linux/patches/3.16.6/lemote-rfkill.patch b/target/linux/patches/3.17.4/lemote-rfkill.patch
index a61488434..a61488434 100644
--- a/target/linux/patches/3.16.6/lemote-rfkill.patch
+++ b/target/linux/patches/3.17.4/lemote-rfkill.patch
diff --git a/target/linux/patches/3.16.6/microblaze-axi.patch b/target/linux/patches/3.17.4/microblaze-axi.patch
index 1a4b17d8c..1a4b17d8c 100644
--- a/target/linux/patches/3.16.6/microblaze-axi.patch
+++ b/target/linux/patches/3.17.4/microblaze-axi.patch
diff --git a/target/linux/patches/3.16.6/microblaze-ethernet.patch b/target/linux/patches/3.17.4/microblaze-ethernet.patch
index 742ab477e..742ab477e 100644
--- a/target/linux/patches/3.16.6/microblaze-ethernet.patch
+++ b/target/linux/patches/3.17.4/microblaze-ethernet.patch
diff --git a/target/linux/patches/3.16.6/mkpiggy.patch b/target/linux/patches/3.17.4/mkpiggy.patch
index 751678b74..751678b74 100644
--- a/target/linux/patches/3.16.6/mkpiggy.patch
+++ b/target/linux/patches/3.17.4/mkpiggy.patch
diff --git a/target/linux/patches/3.16.6/mtd-rootfs.patch b/target/linux/patches/3.17.4/mtd-rootfs.patch
index 775d5fc80..775d5fc80 100644
--- a/target/linux/patches/3.16.6/mtd-rootfs.patch
+++ b/target/linux/patches/3.17.4/mtd-rootfs.patch
diff --git a/target/linux/patches/3.16.6/nfsv3-tcp.patch b/target/linux/patches/3.17.4/nfsv3-tcp.patch
index d5e07e1c2..d5e07e1c2 100644
--- a/target/linux/patches/3.16.6/nfsv3-tcp.patch
+++ b/target/linux/patches/3.17.4/nfsv3-tcp.patch
diff --git a/target/linux/patches/3.16.6/non-static.patch b/target/linux/patches/3.17.4/non-static.patch
index a967703d0..a967703d0 100644
--- a/target/linux/patches/3.16.6/non-static.patch
+++ b/target/linux/patches/3.17.4/non-static.patch
diff --git a/target/linux/patches/3.16.6/patch-fblogo b/target/linux/patches/3.17.4/patch-fblogo
index f1fad64c1..f1fad64c1 100644
--- a/target/linux/patches/3.16.6/patch-fblogo
+++ b/target/linux/patches/3.17.4/patch-fblogo
diff --git a/target/linux/patches/3.16.6/patch-yaffs2 b/target/linux/patches/3.17.4/patch-yaffs2
index bb244c7ca..bb244c7ca 100644
--- a/target/linux/patches/3.16.6/patch-yaffs2
+++ b/target/linux/patches/3.17.4/patch-yaffs2
diff --git a/target/linux/patches/3.16.6/ppc64-missing-zlib.patch b/target/linux/patches/3.17.4/ppc64-missing-zlib.patch
index c6e0616be..c6e0616be 100644
--- a/target/linux/patches/3.16.6/ppc64-missing-zlib.patch
+++ b/target/linux/patches/3.17.4/ppc64-missing-zlib.patch
diff --git a/target/linux/patches/3.16.6/regmap-boolean.patch b/target/linux/patches/3.17.4/regmap-boolean.patch
index b61c4792a..b61c4792a 100644
--- a/target/linux/patches/3.16.6/regmap-boolean.patch
+++ b/target/linux/patches/3.17.4/regmap-boolean.patch
diff --git a/target/linux/patches/3.16.6/relocs.patch b/target/linux/patches/3.17.4/relocs.patch
index 69a7c88a9..69a7c88a9 100644
--- a/target/linux/patches/3.16.6/relocs.patch
+++ b/target/linux/patches/3.17.4/relocs.patch
diff --git a/target/linux/patches/3.16.6/sgidefs.patch b/target/linux/patches/3.17.4/sgidefs.patch
index f00a284d9..f00a284d9 100644
--- a/target/linux/patches/3.16.6/sgidefs.patch
+++ b/target/linux/patches/3.17.4/sgidefs.patch
diff --git a/target/linux/patches/3.16.6/sortext.patch b/target/linux/patches/3.17.4/sortext.patch
index 8fd4e1d6b..8fd4e1d6b 100644
--- a/target/linux/patches/3.16.6/sortext.patch
+++ b/target/linux/patches/3.17.4/sortext.patch
diff --git a/target/linux/patches/3.16.6/startup.patch b/target/linux/patches/3.17.4/startup.patch
index d396b75e4..d396b75e4 100644
--- a/target/linux/patches/3.16.6/startup.patch
+++ b/target/linux/patches/3.17.4/startup.patch
diff --git a/target/linux/patches/3.16.6/wlan-cf.patch b/target/linux/patches/3.17.4/wlan-cf.patch
index fc20759e2..fc20759e2 100644
--- a/target/linux/patches/3.16.6/wlan-cf.patch
+++ b/target/linux/patches/3.17.4/wlan-cf.patch
diff --git a/target/linux/patches/3.16.6/xargs.patch b/target/linux/patches/3.17.4/xargs.patch
index 2c7b3df59..2c7b3df59 100644
--- a/target/linux/patches/3.16.6/xargs.patch
+++ b/target/linux/patches/3.17.4/xargs.patch
diff --git a/target/m68k/qemu-m68k/patches/3.16.6/m68k-coldfire-fec.patch b/target/m68k/qemu-m68k/patches/3.16.6/m68k-coldfire-fec.patch
deleted file mode 100644
index 60dfadb6d..000000000
--- a/target/m68k/qemu-m68k/patches/3.16.6/m68k-coldfire-fec.patch
+++ /dev/null
@@ -1,145 +0,0 @@
-diff -Nur linux-3.16.1.orig/drivers/net/ethernet/freescale/fec_main.c linux-3.16.1/drivers/net/ethernet/freescale/fec_main.c
---- linux-3.16.1.orig/drivers/net/ethernet/freescale/fec_main.c 2014-08-14 04:36:35.000000000 +0200
-+++ linux-3.16.1/drivers/net/ethernet/freescale/fec_main.c 2014-08-28 14:14:15.573666435 +0200
-@@ -154,7 +154,7 @@
- module_param_array(macaddr, byte, NULL, 0);
- MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
-
--#if defined(CONFIG_M5272)
-+#if defined(CONFIG_COLDFIRE)
- /*
- * Some hardware gets it MAC address out of local flash memory.
- * if this is non-zero then assume it is the address to get MAC from.
-@@ -165,14 +165,14 @@
- #define FEC_FLASHMAC 0xf0006000
- #elif defined(CONFIG_CANCam)
- #define FEC_FLASHMAC 0xf0020000
--#elif defined (CONFIG_M5272C3)
-+#elif defined (CONFIG_COLDFIREC3)
- #define FEC_FLASHMAC (0xffe04000 + 4)
- #elif defined(CONFIG_MOD5272)
- #define FEC_FLASHMAC 0xffc0406b
- #else
- #define FEC_FLASHMAC 0
- #endif
--#endif /* CONFIG_M5272 */
-+#endif /* CONFIG_COLDFIRE */
-
- /* Interrupt events/masks. */
- #define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */
-@@ -826,7 +826,9 @@
- const struct platform_device_id *id_entry =
- platform_get_device_id(fep->pdev);
- int i;
-+#if !defined(CONFIG_COLDFIRE)
- u32 val;
-+#endif
- u32 temp_mac[2];
- u32 rcntl = OPT_FRAME_SIZE | 0x04;
- u32 ecntl = 0x2; /* ETHEREN */
-@@ -892,7 +894,7 @@
- /* Set MII speed */
- writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
-
--#if !defined(CONFIG_M5272)
-+#if !defined(CONFIG_COLDFIRE)
- /* set RX checksum */
- val = readl(fep->hwp + FEC_RACC);
- if (fep->csum_flags & FLAG_RX_CSUM_ENABLED)
-@@ -953,7 +955,7 @@
- #endif
- }
-
--#if !defined(CONFIG_M5272)
-+#if !defined(CONFIG_COLDFIRE)
- /* enable pause frame*/
- if ((fep->pause_flag & FEC_PAUSE_FLAG_ENABLE) ||
- ((fep->pause_flag & FEC_PAUSE_FLAG_AUTONEG) &&
-@@ -971,13 +973,13 @@
- } else {
- rcntl &= ~FEC_ENET_FCE;
- }
--#endif /* !defined(CONFIG_M5272) */
-+#endif /* !defined(CONFIG_COLDFIRE) */
-
- writel(rcntl, fep->hwp + FEC_R_CNTRL);
-
- /* Setup multicast filter. */
- set_multicast_list(ndev);
--#ifndef CONFIG_M5272
-+#ifndef CONFIG_COLDFIRE
- writel(0, fep->hwp + FEC_HASH_TABLE_HIGH);
- writel(0, fep->hwp + FEC_HASH_TABLE_LOW);
- #endif
-@@ -992,7 +994,7 @@
- if (fep->bufdesc_ex)
- ecntl |= (1 << 4);
-
--#ifndef CONFIG_M5272
-+#ifndef CONFIG_COLDFIRE
- /* Enable the MIB statistic event counters */
- writel(0 << 31, fep->hwp + FEC_MIB_CTRLSTAT);
- #endif
-@@ -1442,7 +1444,7 @@
- * 3) from flash or fuse (via platform data)
- */
- if (!is_valid_ether_addr(iap)) {
--#ifdef CONFIG_M5272
-+#ifdef CONFIG_COLDFIRE
- if (FEC_FLASHMAC)
- iap = (unsigned char *)FEC_FLASHMAC;
- #else
-@@ -1667,7 +1669,7 @@
- /* mask with MAC supported features */
- if (id_entry->driver_data & FEC_QUIRK_HAS_GBIT) {
- phy_dev->supported &= PHY_GBIT_FEATURES;
--#if !defined(CONFIG_M5272)
-+#if !defined(CONFIG_COLDFIRE)
- phy_dev->supported |= SUPPORTED_Pause;
- #endif
- }
-@@ -1853,7 +1855,7 @@
- }
- }
-
--#if !defined(CONFIG_M5272)
-+#if !defined(CONFIG_COLDFIRE)
-
- static void fec_enet_get_pauseparam(struct net_device *ndev,
- struct ethtool_pauseparam *pause)
-@@ -1999,7 +2001,7 @@
- return -EOPNOTSUPP;
- }
- }
--#endif /* !defined(CONFIG_M5272) */
-+#endif /* !defined(CONFIG_COLDFIRE) */
-
- static int fec_enet_nway_reset(struct net_device *dev)
- {
-@@ -2013,7 +2015,7 @@
- }
-
- static const struct ethtool_ops fec_enet_ethtool_ops = {
--#if !defined(CONFIG_M5272)
-+#if !defined(CONFIG_COLDFIRE)
- .get_pauseparam = fec_enet_get_pauseparam,
- .set_pauseparam = fec_enet_set_pauseparam,
- #endif
-@@ -2023,7 +2025,7 @@
- .get_link = ethtool_op_get_link,
- .get_ts_info = fec_enet_get_ts_info,
- .nway_reset = fec_enet_nway_reset,
--#ifndef CONFIG_M5272
-+#ifndef CONFIG_COLDFIRE
- .get_ethtool_stats = fec_enet_get_ethtool_stats,
- .get_strings = fec_enet_get_strings,
- .get_sset_count = fec_enet_get_sset_count,
-@@ -2500,7 +2502,7 @@
- /* setup board info structure */
- fep = netdev_priv(ndev);
-
--#if !defined(CONFIG_M5272)
-+#if !defined(CONFIG_COLDFIRE)
- /* default enable pause frame auto negotiation */
- if (pdev->id_entry &&
- (pdev->id_entry->driver_data & FEC_QUIRK_HAS_GBIT))
diff --git a/target/m68k/qemu-m68k/patches/3.16.6/qemu-coldfire.patch b/target/m68k/qemu-m68k/patches/3.17.4/qemu-coldfire.patch
index 503fe8ef3..503fe8ef3 100644
--- a/target/m68k/qemu-m68k/patches/3.16.6/qemu-coldfire.patch
+++ b/target/m68k/qemu-m68k/patches/3.17.4/qemu-coldfire.patch
diff --git a/target/mips/dragino-ms14s/patches/3.14.17/0001-mtd-add-rb4xx-nand-driver.patch b/target/mips/dragino-ms14s/patches/3.14.17/0001-mtd-add-rb4xx-nand-driver.patch
new file mode 100644
index 000000000..8199de991
--- /dev/null
+++ b/target/mips/dragino-ms14s/patches/3.14.17/0001-mtd-add-rb4xx-nand-driver.patch
@@ -0,0 +1,351 @@
+From 1e692cc0c53202b932eedabd0315107910c5b093 Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Tue, 13 May 2014 00:08:54 +0200
+Subject: [PATCH] mtd: add rb4xx nand driver
+
+---
+ drivers/mtd/nand/Kconfig | 4 +
+ drivers/mtd/nand/Makefile | 1 +
+ drivers/mtd/nand/rb4xx_nand.c | 305 ++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 310 insertions(+)
+ create mode 100644 drivers/mtd/nand/rb4xx_nand.c
+
+diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
+index 90ff447..bb01309 100644
+--- a/drivers/mtd/nand/Kconfig
++++ b/drivers/mtd/nand/Kconfig
+@@ -510,4 +510,8 @@ config MTD_NAND_XWAY
+ Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached
+ to the External Bus Unit (EBU).
+
++config MTD_NAND_RB4XX
++ tristate "NAND flash driver for RouterBoard 4xx series"
++ depends on MTD_NAND && ATH79_MACH_RB4XX
++
+ endif # MTD_NAND
+diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
+index 542b568..e2b5e1c 100644
+--- a/drivers/mtd/nand/Makefile
++++ b/drivers/mtd/nand/Makefile
+@@ -31,6 +31,7 @@ obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o
+ obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o
+ obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o
+ obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o
++obj-$(CONFIG_MTD_NAND_RB4XX) += rb4xx_nand.o
+ obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o
+ obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o
+ obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o
+diff --git a/drivers/mtd/nand/rb4xx_nand.c b/drivers/mtd/nand/rb4xx_nand.c
+new file mode 100644
+index 0000000..5b9841b
+--- /dev/null
++++ b/drivers/mtd/nand/rb4xx_nand.c
+@@ -0,0 +1,305 @@
++/*
++ * NAND flash driver for the MikroTik RouterBoard 4xx series
++ *
++ * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This file was based on the driver for Linux 2.6.22 published by
++ * MikroTik for their RouterBoard 4xx series devices.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++#include <linux/io.h>
++#include <linux/gpio.h>
++#include <linux/slab.h>
++
++#include <asm/mach-ath79/ath79.h>
++#include <asm/mach-ath79/rb4xx_cpld.h>
++
++#define DRV_NAME "rb4xx-nand"
++#define DRV_VERSION "0.2.0"
++#define DRV_DESC "NAND flash driver for RouterBoard 4xx series"
++
++#define RB4XX_NAND_GPIO_READY 5
++#define RB4XX_NAND_GPIO_ALE 37
++#define RB4XX_NAND_GPIO_CLE 38
++#define RB4XX_NAND_GPIO_NCE 39
++
++struct rb4xx_nand_info {
++ struct nand_chip chip;
++ struct mtd_info mtd;
++};
++
++/*
++ * We need to use the OLD Yaffs-1 OOB layout, otherwise the RB bootloader
++ * will not be able to find the kernel that we load.
++ */
++static struct nand_ecclayout rb4xx_nand_ecclayout = {
++ .eccbytes = 6,
++ .eccpos = { 8, 9, 10, 13, 14, 15 },
++ .oobavail = 9,
++ .oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
++};
++
++static struct mtd_partition rb4xx_nand_partitions[] = {
++ {
++ .name = "booter",
++ .offset = 0,
++ .size = (256 * 1024),
++ .mask_flags = MTD_WRITEABLE,
++ },
++ {
++ .name = "kernel",
++ .offset = (256 * 1024),
++ .size = (4 * 1024 * 1024) - (256 * 1024),
++ },
++ {
++ .name = "rootfs",
++ .offset = MTDPART_OFS_NXTBLK,
++ .size = MTDPART_SIZ_FULL,
++ },
++};
++
++static int rb4xx_nand_dev_ready(struct mtd_info *mtd)
++{
++ return gpio_get_value_cansleep(RB4XX_NAND_GPIO_READY);
++}
++
++static void rb4xx_nand_write_cmd(unsigned char cmd)
++{
++ unsigned char data = cmd;
++ int err;
++
++ err = rb4xx_cpld_write(&data, 1);
++ if (err)
++ pr_err("rb4xx_nand: write cmd failed, err=%d\n", err);
++}
++
++static void rb4xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
++ unsigned int ctrl)
++{
++ if (ctrl & NAND_CTRL_CHANGE) {
++ gpio_set_value_cansleep(RB4XX_NAND_GPIO_CLE,
++ (ctrl & NAND_CLE) ? 1 : 0);
++ gpio_set_value_cansleep(RB4XX_NAND_GPIO_ALE,
++ (ctrl & NAND_ALE) ? 1 : 0);
++ gpio_set_value_cansleep(RB4XX_NAND_GPIO_NCE,
++ (ctrl & NAND_NCE) ? 0 : 1);
++ }
++
++ if (cmd != NAND_CMD_NONE)
++ rb4xx_nand_write_cmd(cmd);
++}
++
++static unsigned char rb4xx_nand_read_byte(struct mtd_info *mtd)
++{
++ unsigned char data = 0;
++ int err;
++
++ err = rb4xx_cpld_read(&data, NULL, 1);
++ if (err) {
++ pr_err("rb4xx_nand: read data failed, err=%d\n", err);
++ data = 0xff;
++ }
++
++ return data;
++}
++
++static void rb4xx_nand_write_buf(struct mtd_info *mtd, const unsigned char *buf,
++ int len)
++{
++ int err;
++
++ err = rb4xx_cpld_write(buf, len);
++ if (err)
++ pr_err("rb4xx_nand: write buf failed, err=%d\n", err);
++}
++
++static void rb4xx_nand_read_buf(struct mtd_info *mtd, unsigned char *buf,
++ int len)
++{
++ int err;
++
++ err = rb4xx_cpld_read(buf, NULL, len);
++ if (err)
++ pr_err("rb4xx_nand: read buf failed, err=%d\n", err);
++}
++
++static int rb4xx_nand_probe(struct platform_device *pdev)
++{
++ struct rb4xx_nand_info *info;
++ int ret;
++
++ printk(KERN_INFO DRV_DESC " version " DRV_VERSION "\n");
++
++ ret = gpio_request(RB4XX_NAND_GPIO_READY, "NAND RDY");
++ if (ret) {
++ dev_err(&pdev->dev, "unable to request gpio %d\n",
++ RB4XX_NAND_GPIO_READY);
++ goto err;
++ }
++
++ ret = gpio_direction_input(RB4XX_NAND_GPIO_READY);
++ if (ret) {
++ dev_err(&pdev->dev, "unable to set input mode on gpio %d\n",
++ RB4XX_NAND_GPIO_READY);
++ goto err_free_gpio_ready;
++ }
++
++ ret = gpio_request(RB4XX_NAND_GPIO_ALE, "NAND ALE");
++ if (ret) {
++ dev_err(&pdev->dev, "unable to request gpio %d\n",
++ RB4XX_NAND_GPIO_ALE);
++ goto err_free_gpio_ready;
++ }
++
++ ret = gpio_direction_output(RB4XX_NAND_GPIO_ALE, 0);
++ if (ret) {
++ dev_err(&pdev->dev, "unable to set output mode on gpio %d\n",
++ RB4XX_NAND_GPIO_ALE);
++ goto err_free_gpio_ale;
++ }
++
++ ret = gpio_request(RB4XX_NAND_GPIO_CLE, "NAND CLE");
++ if (ret) {
++ dev_err(&pdev->dev, "unable to request gpio %d\n",
++ RB4XX_NAND_GPIO_CLE);
++ goto err_free_gpio_ale;
++ }
++
++ ret = gpio_direction_output(RB4XX_NAND_GPIO_CLE, 0);
++ if (ret) {
++ dev_err(&pdev->dev, "unable to set output mode on gpio %d\n",
++ RB4XX_NAND_GPIO_CLE);
++ goto err_free_gpio_cle;
++ }
++
++ ret = gpio_request(RB4XX_NAND_GPIO_NCE, "NAND NCE");
++ if (ret) {
++ dev_err(&pdev->dev, "unable to request gpio %d\n",
++ RB4XX_NAND_GPIO_NCE);
++ goto err_free_gpio_cle;
++ }
++
++ ret = gpio_direction_output(RB4XX_NAND_GPIO_NCE, 1);
++ if (ret) {
++ dev_err(&pdev->dev, "unable to set output mode on gpio %d\n",
++ RB4XX_NAND_GPIO_ALE);
++ goto err_free_gpio_nce;
++ }
++
++ info = kzalloc(sizeof(*info), GFP_KERNEL);
++ if (!info) {
++ dev_err(&pdev->dev, "rb4xx-nand: no memory for private data\n");
++ ret = -ENOMEM;
++ goto err_free_gpio_nce;
++ }
++
++ info->chip.priv = &info;
++ info->mtd.priv = &info->chip;
++ info->mtd.owner = THIS_MODULE;
++
++ info->chip.cmd_ctrl = rb4xx_nand_cmd_ctrl;
++ info->chip.dev_ready = rb4xx_nand_dev_ready;
++ info->chip.read_byte = rb4xx_nand_read_byte;
++ info->chip.write_buf = rb4xx_nand_write_buf;
++ info->chip.read_buf = rb4xx_nand_read_buf;
++
++ info->chip.chip_delay = 25;
++ info->chip.ecc.mode = NAND_ECC_SOFT;
++
++ platform_set_drvdata(pdev, info);
++
++ ret = nand_scan_ident(&info->mtd, 1, NULL);
++ if (ret) {
++ ret = -ENXIO;
++ goto err_free_info;
++ }
++
++ if (info->mtd.writesize == 512)
++ info->chip.ecc.layout = &rb4xx_nand_ecclayout;
++
++ ret = nand_scan_tail(&info->mtd);
++ if (ret) {
++ return -ENXIO;
++ goto err_set_drvdata;
++ }
++
++ mtd_device_register(&info->mtd, rb4xx_nand_partitions,
++ ARRAY_SIZE(rb4xx_nand_partitions));
++ if (ret)
++ goto err_release_nand;
++
++ return 0;
++
++err_release_nand:
++ nand_release(&info->mtd);
++err_set_drvdata:
++ platform_set_drvdata(pdev, NULL);
++err_free_info:
++ kfree(info);
++err_free_gpio_nce:
++ gpio_free(RB4XX_NAND_GPIO_NCE);
++err_free_gpio_cle:
++ gpio_free(RB4XX_NAND_GPIO_CLE);
++err_free_gpio_ale:
++ gpio_free(RB4XX_NAND_GPIO_ALE);
++err_free_gpio_ready:
++ gpio_free(RB4XX_NAND_GPIO_READY);
++err:
++ return ret;
++}
++
++static int rb4xx_nand_remove(struct platform_device *pdev)
++{
++ struct rb4xx_nand_info *info = platform_get_drvdata(pdev);
++
++ nand_release(&info->mtd);
++ platform_set_drvdata(pdev, NULL);
++ kfree(info);
++ gpio_free(RB4XX_NAND_GPIO_NCE);
++ gpio_free(RB4XX_NAND_GPIO_CLE);
++ gpio_free(RB4XX_NAND_GPIO_ALE);
++ gpio_free(RB4XX_NAND_GPIO_READY);
++
++ return 0;
++}
++
++static struct platform_driver rb4xx_nand_driver = {
++ .probe = rb4xx_nand_probe,
++ .remove = rb4xx_nand_remove,
++ .driver = {
++ .name = DRV_NAME,
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init rb4xx_nand_init(void)
++{
++ return platform_driver_register(&rb4xx_nand_driver);
++}
++
++static void __exit rb4xx_nand_exit(void)
++{
++ platform_driver_unregister(&rb4xx_nand_driver);
++}
++
++module_init(rb4xx_nand_init);
++module_exit(rb4xx_nand_exit);
++
++MODULE_DESCRIPTION(DRV_DESC);
++MODULE_VERSION(DRV_VERSION);
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_AUTHOR("Imre Kaloz <kaloz@openwrt.org>");
++MODULE_LICENSE("GPL v2");
+--
+1.8.5.3
+
diff --git a/target/mips/dragino-ms14s/patches/3.14.17/0002-phy-add-ethtool-ioctl-support-used-by-ag71xx-driver.patch b/target/mips/dragino-ms14s/patches/3.14.17/0002-phy-add-ethtool-ioctl-support-used-by-ag71xx-driver.patch
new file mode 100644
index 000000000..ba7fbfad8
--- /dev/null
+++ b/target/mips/dragino-ms14s/patches/3.14.17/0002-phy-add-ethtool-ioctl-support-used-by-ag71xx-driver.patch
@@ -0,0 +1,80 @@
+From 7b864612a6e3b139a5a607abd0048a19078fe42f Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Wed, 14 May 2014 02:55:06 +0200
+Subject: [PATCH] phy: add ethtool ioctl support, used by ag71xx driver
+
+---
+ drivers/net/phy/phy.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
+ include/linux/phy.h | 1 +
+ 2 files changed, 45 insertions(+)
+
+diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
+index 76d96b9..9439ef3 100644
+--- a/drivers/net/phy/phy.c
++++ b/drivers/net/phy/phy.c
+@@ -293,6 +293,50 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd)
+ }
+ EXPORT_SYMBOL(phy_ethtool_gset);
+
++int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr)
++{
++ u32 cmd;
++ int tmp;
++ struct ethtool_cmd ecmd = { ETHTOOL_GSET };
++ struct ethtool_value edata = { ETHTOOL_GLINK };
++
++ if (get_user(cmd, (u32 *) useraddr))
++ return -EFAULT;
++
++ switch (cmd) {
++ case ETHTOOL_GSET:
++ phy_ethtool_gset(phydev, &ecmd);
++ if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
++ return -EFAULT;
++ return 0;
++
++ case ETHTOOL_SSET:
++ if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
++ return -EFAULT;
++ return phy_ethtool_sset(phydev, &ecmd);
++
++ case ETHTOOL_NWAY_RST:
++ /* if autoneg is off, it's an error */
++ tmp = phy_read(phydev, MII_BMCR);
++ if (tmp & BMCR_ANENABLE) {
++ tmp |= (BMCR_ANRESTART);
++ phy_write(phydev, MII_BMCR, tmp);
++ return 0;
++ }
++ return -EINVAL;
++
++ case ETHTOOL_GLINK:
++ edata.data = (phy_read(phydev,
++ MII_BMSR) & BMSR_LSTATUS) ? 1 : 0;
++ if (copy_to_user(useraddr, &edata, sizeof(edata)))
++ return -EFAULT;
++ return 0;
++ }
++
++ return -EOPNOTSUPP;
++}
++EXPORT_SYMBOL(phy_ethtool_ioctl);
++
+ /**
+ * phy_mii_ioctl - generic PHY MII ioctl interface
+ * @phydev: the phy_device struct
+diff --git a/include/linux/phy.h b/include/linux/phy.h
+index 565188c..9ab0d79 100644
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -628,6 +628,7 @@ void phy_stop_machine(struct phy_device *phydev);
+ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd);
+ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd);
+ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd);
++int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr);
+ int phy_start_interrupts(struct phy_device *phydev);
+ void phy_print_status(struct phy_device *phydev);
+ void phy_device_free(struct phy_device *phydev);
+--
+1.8.5.3
+
diff --git a/target/mips/dragino-ms14s/patches/3.14.17/0003-net-add-ag71xx-mac-driver.patch b/target/mips/dragino-ms14s/patches/3.14.17/0003-net-add-ag71xx-mac-driver.patch
new file mode 100644
index 000000000..1915c184c
--- /dev/null
+++ b/target/mips/dragino-ms14s/patches/3.14.17/0003-net-add-ag71xx-mac-driver.patch
@@ -0,0 +1,4245 @@
+From c5eb03f91f9185f4813431692f36db3862716a35 Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Tue, 13 May 2014 00:12:37 +0200
+Subject: [PATCH] net: add ag71xx mac driver
+
+---
+ arch/mips/include/asm/mach-ath79/ag71xx_platform.h | 65 +
+ drivers/net/ethernet/atheros/Kconfig | 2 +
+ drivers/net/ethernet/atheros/Makefile | 1 +
+ drivers/net/ethernet/atheros/ag71xx/Kconfig | 33 +
+ drivers/net/ethernet/atheros/ag71xx/Makefile | 15 +
+ drivers/net/ethernet/atheros/ag71xx/ag71xx.h | 476 +++++++
+ .../net/ethernet/atheros/ag71xx/ag71xx_ar7240.c | 1202 ++++++++++++++++++
+ .../net/ethernet/atheros/ag71xx/ag71xx_ar8216.c | 44 +
+ .../net/ethernet/atheros/ag71xx/ag71xx_debugfs.c | 284 +++++
+ .../net/ethernet/atheros/ag71xx/ag71xx_ethtool.c | 124 ++
+ drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c | 1325 ++++++++++++++++++++
+ drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c | 318 +++++
+ drivers/net/ethernet/atheros/ag71xx/ag71xx_phy.c | 235 ++++
+ 13 files changed, 4124 insertions(+)
+ create mode 100644 arch/mips/include/asm/mach-ath79/ag71xx_platform.h
+ create mode 100644 drivers/net/ethernet/atheros/ag71xx/Kconfig
+ create mode 100644 drivers/net/ethernet/atheros/ag71xx/Makefile
+ create mode 100644 drivers/net/ethernet/atheros/ag71xx/ag71xx.h
+ create mode 100644 drivers/net/ethernet/atheros/ag71xx/ag71xx_ar7240.c
+ create mode 100644 drivers/net/ethernet/atheros/ag71xx/ag71xx_ar8216.c
+ create mode 100644 drivers/net/ethernet/atheros/ag71xx/ag71xx_debugfs.c
+ create mode 100644 drivers/net/ethernet/atheros/ag71xx/ag71xx_ethtool.c
+ create mode 100644 drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c
+ create mode 100644 drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c
+ create mode 100644 drivers/net/ethernet/atheros/ag71xx/ag71xx_phy.c
+
+diff --git a/arch/mips/include/asm/mach-ath79/ag71xx_platform.h b/arch/mips/include/asm/mach-ath79/ag71xx_platform.h
+new file mode 100644
+index 0000000..d46dc4e
+--- /dev/null
++++ b/arch/mips/include/asm/mach-ath79/ag71xx_platform.h
+@@ -0,0 +1,65 @@
++/*
++ * Atheros AR71xx SoC specific platform data definitions
++ *
++ * Copyright (C) 2008-2012 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#ifndef __ASM_MACH_ATH79_PLATFORM_H
++#define __ASM_MACH_ATH79_PLATFORM_H
++
++#include <linux/if_ether.h>
++#include <linux/skbuff.h>
++#include <linux/phy.h>
++#include <linux/spi/spi.h>
++
++struct ag71xx_switch_platform_data {
++ u8 phy4_mii_en:1;
++ u8 phy_poll_mask;
++};
++
++struct ag71xx_platform_data {
++ phy_interface_t phy_if_mode;
++ u32 phy_mask;
++ int speed;
++ int duplex;
++ u32 reset_bit;
++ u8 mac_addr[ETH_ALEN];
++ struct device *mii_bus_dev;
++
++ u8 has_gbit:1;
++ u8 is_ar91xx:1;
++ u8 is_ar7240:1;
++ u8 is_ar724x:1;
++ u8 has_ar8216:1;
++
++ struct ag71xx_switch_platform_data *switch_data;
++
++ void (*ddr_flush)(void);
++ void (*set_speed)(int speed);
++
++ u32 fifo_cfg1;
++ u32 fifo_cfg2;
++ u32 fifo_cfg3;
++
++ unsigned int max_frame_len;
++ unsigned int desc_pktlen_mask;
++};
++
++struct ag71xx_mdio_platform_data {
++ u32 phy_mask;
++ u8 builtin_switch:1;
++ u8 is_ar7240:1;
++ u8 is_ar9330:1;
++ u8 is_ar934x:1;
++ unsigned long mdio_clock;
++ unsigned long ref_clock;
++
++ void (*reset)(struct mii_bus *bus);
++};
++
++#endif /* __ASM_MACH_ATH79_PLATFORM_H */
+diff --git a/drivers/net/ethernet/atheros/Kconfig b/drivers/net/ethernet/atheros/Kconfig
+index 58ad37c..1fae572 100644
+--- a/drivers/net/ethernet/atheros/Kconfig
++++ b/drivers/net/ethernet/atheros/Kconfig
+@@ -80,4 +80,6 @@ config ALX
+ To compile this driver as a module, choose M here. The module
+ will be called alx.
+
++source drivers/net/ethernet/atheros/ag71xx/Kconfig
++
+ endif # NET_VENDOR_ATHEROS
+diff --git a/drivers/net/ethernet/atheros/Makefile b/drivers/net/ethernet/atheros/Makefile
+index 5cf1c65..d1c5a49 100644
+--- a/drivers/net/ethernet/atheros/Makefile
++++ b/drivers/net/ethernet/atheros/Makefile
+@@ -2,6 +2,7 @@
+ # Makefile for the Atheros network device drivers.
+ #
+
++obj-$(CONFIG_AG71XX) += ag71xx/
+ obj-$(CONFIG_ATL1) += atlx/
+ obj-$(CONFIG_ATL2) += atlx/
+ obj-$(CONFIG_ATL1E) += atl1e/
+diff --git a/drivers/net/ethernet/atheros/ag71xx/Kconfig b/drivers/net/ethernet/atheros/ag71xx/Kconfig
+new file mode 100644
+index 0000000..42d544f
+--- /dev/null
++++ b/drivers/net/ethernet/atheros/ag71xx/Kconfig
+@@ -0,0 +1,33 @@
++config AG71XX
++ tristate "Atheros AR7XXX/AR9XXX built-in ethernet mac support"
++ depends on ATH79
++ select PHYLIB
++ help
++ If you wish to compile a kernel for AR7XXX/91XXX and enable
++ ethernet support, then you should always answer Y to this.
++
++if AG71XX
++
++config AG71XX_DEBUG
++ bool "Atheros AR71xx built-in ethernet driver debugging"
++ default n
++ help
++ Atheros AR71xx built-in ethernet driver debugging messages.
++
++config AG71XX_DEBUG_FS
++ bool "Atheros AR71xx built-in ethernet driver debugfs support"
++ depends on DEBUG_FS
++ default n
++ help
++ Say Y, if you need access to various statistics provided by
++ the ag71xx driver.
++
++config AG71XX_AR8216_SUPPORT
++ bool "special support for the Atheros AR8216 switch"
++ default n
++ default y if ATH79_MACH_WNR2000 || ATH79_MACH_MZK_W04NU
++ help
++ Say 'y' here if you want to enable special support for the
++ Atheros AR8216 switch found on some boards.
++
++endif
+diff --git a/drivers/net/ethernet/atheros/ag71xx/Makefile b/drivers/net/ethernet/atheros/ag71xx/Makefile
+new file mode 100644
+index 0000000..b3ec408
+--- /dev/null
++++ b/drivers/net/ethernet/atheros/ag71xx/Makefile
+@@ -0,0 +1,15 @@
++#
++# Makefile for the Atheros AR71xx built-in ethernet macs
++#
++
++ag71xx-y += ag71xx_main.o
++ag71xx-y += ag71xx_ethtool.o
++ag71xx-y += ag71xx_phy.o
++ag71xx-y += ag71xx_mdio.o
++ag71xx-y += ag71xx_ar7240.o
++
++ag71xx-$(CONFIG_AG71XX_DEBUG_FS) += ag71xx_debugfs.o
++ag71xx-$(CONFIG_AG71XX_AR8216_SUPPORT) += ag71xx_ar8216.o
++
++obj-$(CONFIG_AG71XX) += ag71xx.o
++
+diff --git a/drivers/net/ethernet/atheros/ag71xx/ag71xx.h b/drivers/net/ethernet/atheros/ag71xx/ag71xx.h
+new file mode 100644
+index 0000000..f6d85b9
+--- /dev/null
++++ b/drivers/net/ethernet/atheros/ag71xx/ag71xx.h
+@@ -0,0 +1,476 @@
++/*
++ * Atheros AR71xx built-in ethernet mac driver
++ *
++ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Based on Atheros' AG7100 driver
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#ifndef __AG71XX_H
++#define __AG71XX_H
++
++#include <linux/kernel.h>
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/random.h>
++#include <linux/spinlock.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++#include <linux/ethtool.h>
++#include <linux/etherdevice.h>
++#include <linux/if_vlan.h>
++#include <linux/phy.h>
++#include <linux/skbuff.h>
++#include <linux/dma-mapping.h>
++#include <linux/workqueue.h>
++
++#include <linux/bitops.h>
++
++#include <asm/mach-ath79/ar71xx_regs.h>
++#include <asm/mach-ath79/ath79.h>
++#include <asm/mach-ath79/ag71xx_platform.h>
++
++#define AG71XX_DRV_NAME "ag71xx"
++#define AG71XX_DRV_VERSION "0.5.35"
++
++#define AG71XX_NAPI_WEIGHT 64
++#define AG71XX_OOM_REFILL (1 + HZ/10)
++
++#define AG71XX_INT_ERR (AG71XX_INT_RX_BE | AG71XX_INT_TX_BE)
++#define AG71XX_INT_TX (AG71XX_INT_TX_PS)
++#define AG71XX_INT_RX (AG71XX_INT_RX_PR | AG71XX_INT_RX_OF)
++
++#define AG71XX_INT_POLL (AG71XX_INT_RX | AG71XX_INT_TX)
++#define AG71XX_INT_INIT (AG71XX_INT_ERR | AG71XX_INT_POLL)
++
++#define AG71XX_TX_MTU_LEN 1540
++
++#define AG71XX_TX_RING_SIZE_DEFAULT 32
++#define AG71XX_RX_RING_SIZE_DEFAULT 128
++
++#define AG71XX_TX_RING_SIZE_MAX 32
++#define AG71XX_RX_RING_SIZE_MAX 128
++
++#ifdef CONFIG_AG71XX_DEBUG
++#define DBG(fmt, args...) pr_debug(fmt, ## args)
++#else
++#define DBG(fmt, args...) do {} while (0)
++#endif
++
++#define ag71xx_assert(_cond) \
++do { \
++ if (_cond) \
++ break; \
++ printk("%s,%d: assertion failed\n", __FILE__, __LINE__); \
++ BUG(); \
++} while (0)
++
++struct ag71xx_desc {
++ u32 data;
++ u32 ctrl;
++#define DESC_EMPTY BIT(31)
++#define DESC_MORE BIT(24)
++#define DESC_PKTLEN_M 0xfff
++ u32 next;
++ u32 pad;
++} __attribute__((aligned(4)));
++
++struct ag71xx_buf {
++ union {
++ struct sk_buff *skb;
++ void *rx_buf;
++ };
++ struct ag71xx_desc *desc;
++ union {
++ dma_addr_t dma_addr;
++ unsigned long timestamp;
++ };
++ unsigned int len;
++};
++
++struct ag71xx_ring {
++ struct ag71xx_buf *buf;
++ u8 *descs_cpu;
++ dma_addr_t descs_dma;
++ unsigned int desc_size;
++ unsigned int curr;
++ unsigned int dirty;
++ unsigned int size;
++};
++
++struct ag71xx_mdio {
++ struct mii_bus *mii_bus;
++ int mii_irq[PHY_MAX_ADDR];
++ void __iomem *mdio_base;
++ struct ag71xx_mdio_platform_data *pdata;
++};
++
++struct ag71xx_int_stats {
++ unsigned long rx_pr;
++ unsigned long rx_be;
++ unsigned long rx_of;
++ unsigned long tx_ps;
++ unsigned long tx_be;
++ unsigned long tx_ur;
++ unsigned long total;
++};
++
++struct ag71xx_napi_stats {
++ unsigned long napi_calls;
++ unsigned long rx_count;
++ unsigned long rx_packets;
++ unsigned long rx_packets_max;
++ unsigned long tx_count;
++ unsigned long tx_packets;
++ unsigned long tx_packets_max;
++
++ unsigned long rx[AG71XX_NAPI_WEIGHT + 1];
++ unsigned long tx[AG71XX_NAPI_WEIGHT + 1];
++};
++
++struct ag71xx_debug {
++ struct dentry *debugfs_dir;
++
++ struct ag71xx_int_stats int_stats;
++ struct ag71xx_napi_stats napi_stats;
++};
++
++struct ag71xx {
++ void __iomem *mac_base;
++
++ spinlock_t lock;
++ struct platform_device *pdev;
++ struct net_device *dev;
++ struct napi_struct napi;
++ u32 msg_enable;
++
++ struct ag71xx_desc *stop_desc;
++ dma_addr_t stop_desc_dma;
++
++ struct ag71xx_ring rx_ring;
++ struct ag71xx_ring tx_ring;
++
++ struct mii_bus *mii_bus;
++ struct phy_device *phy_dev;
++ void *phy_priv;
++
++ unsigned int link;
++ unsigned int speed;
++ int duplex;
++
++ unsigned int max_frame_len;
++ unsigned int desc_pktlen_mask;
++ unsigned int rx_buf_size;
++
++ struct work_struct restart_work;
++ struct delayed_work link_work;
++ struct timer_list oom_timer;
++
++#ifdef CONFIG_AG71XX_DEBUG_FS
++ struct ag71xx_debug debug;
++#endif
++};
++
++extern struct ethtool_ops ag71xx_ethtool_ops;
++void ag71xx_link_adjust(struct ag71xx *ag);
++
++int ag71xx_mdio_driver_init(void) __init;
++void ag71xx_mdio_driver_exit(void);
++
++int ag71xx_phy_connect(struct ag71xx *ag);
++void ag71xx_phy_disconnect(struct ag71xx *ag);
++void ag71xx_phy_start(struct ag71xx *ag);
++void ag71xx_phy_stop(struct ag71xx *ag);
++
++static inline struct ag71xx_platform_data *ag71xx_get_pdata(struct ag71xx *ag)
++{
++ return ag->pdev->dev.platform_data;
++}
++
++static inline int ag71xx_desc_empty(struct ag71xx_desc *desc)
++{
++ return (desc->ctrl & DESC_EMPTY) != 0;
++}
++
++/* Register offsets */
++#define AG71XX_REG_MAC_CFG1 0x0000
++#define AG71XX_REG_MAC_CFG2 0x0004
++#define AG71XX_REG_MAC_IPG 0x0008
++#define AG71XX_REG_MAC_HDX 0x000c
++#define AG71XX_REG_MAC_MFL 0x0010
++#define AG71XX_REG_MII_CFG 0x0020
++#define AG71XX_REG_MII_CMD 0x0024
++#define AG71XX_REG_MII_ADDR 0x0028
++#define AG71XX_REG_MII_CTRL 0x002c
++#define AG71XX_REG_MII_STATUS 0x0030
++#define AG71XX_REG_MII_IND 0x0034
++#define AG71XX_REG_MAC_IFCTL 0x0038
++#define AG71XX_REG_MAC_ADDR1 0x0040
++#define AG71XX_REG_MAC_ADDR2 0x0044
++#define AG71XX_REG_FIFO_CFG0 0x0048
++#define AG71XX_REG_FIFO_CFG1 0x004c
++#define AG71XX_REG_FIFO_CFG2 0x0050
++#define AG71XX_REG_FIFO_CFG3 0x0054
++#define AG71XX_REG_FIFO_CFG4 0x0058
++#define AG71XX_REG_FIFO_CFG5 0x005c
++#define AG71XX_REG_FIFO_RAM0 0x0060
++#define AG71XX_REG_FIFO_RAM1 0x0064
++#define AG71XX_REG_FIFO_RAM2 0x0068
++#define AG71XX_REG_FIFO_RAM3 0x006c
++#define AG71XX_REG_FIFO_RAM4 0x0070
++#define AG71XX_REG_FIFO_RAM5 0x0074
++#define AG71XX_REG_FIFO_RAM6 0x0078
++#define AG71XX_REG_FIFO_RAM7 0x007c
++
++#define AG71XX_REG_TX_CTRL 0x0180
++#define AG71XX_REG_TX_DESC 0x0184
++#define AG71XX_REG_TX_STATUS 0x0188
++#define AG71XX_REG_RX_CTRL 0x018c
++#define AG71XX_REG_RX_DESC 0x0190
++#define AG71XX_REG_RX_STATUS 0x0194
++#define AG71XX_REG_INT_ENABLE 0x0198
++#define AG71XX_REG_INT_STATUS 0x019c
++
++#define AG71XX_REG_FIFO_DEPTH 0x01a8
++#define AG71XX_REG_RX_SM 0x01b0
++#define AG71XX_REG_TX_SM 0x01b4
++
++#define MAC_CFG1_TXE BIT(0) /* Tx Enable */
++#define MAC_CFG1_STX BIT(1) /* Synchronize Tx Enable */
++#define MAC_CFG1_RXE BIT(2) /* Rx Enable */
++#define MAC_CFG1_SRX BIT(3) /* Synchronize Rx Enable */
++#define MAC_CFG1_TFC BIT(4) /* Tx Flow Control Enable */
++#define MAC_CFG1_RFC BIT(5) /* Rx Flow Control Enable */
++#define MAC_CFG1_LB BIT(8) /* Loopback mode */
++#define MAC_CFG1_SR BIT(31) /* Soft Reset */
++
++#define MAC_CFG2_FDX BIT(0)
++#define MAC_CFG2_CRC_EN BIT(1)
++#define MAC_CFG2_PAD_CRC_EN BIT(2)
++#define MAC_CFG2_LEN_CHECK BIT(4)
++#define MAC_CFG2_HUGE_FRAME_EN BIT(5)
++#define MAC_CFG2_IF_1000 BIT(9)
++#define MAC_CFG2_IF_10_100 BIT(8)
++
++#define FIFO_CFG0_WTM BIT(0) /* Watermark Module */
++#define FIFO_CFG0_RXS BIT(1) /* Rx System Module */
++#define FIFO_CFG0_RXF BIT(2) /* Rx Fabric Module */
++#define FIFO_CFG0_TXS BIT(3) /* Tx System Module */
++#define FIFO_CFG0_TXF BIT(4) /* Tx Fabric Module */
++#define FIFO_CFG0_ALL (FIFO_CFG0_WTM | FIFO_CFG0_RXS | FIFO_CFG0_RXF \
++ | FIFO_CFG0_TXS | FIFO_CFG0_TXF)
++
++#define FIFO_CFG0_ENABLE_SHIFT 8
++
++#define FIFO_CFG4_DE BIT(0) /* Drop Event */
++#define FIFO_CFG4_DV BIT(1) /* RX_DV Event */
++#define FIFO_CFG4_FC BIT(2) /* False Carrier */
++#define FIFO_CFG4_CE BIT(3) /* Code Error */
++#define FIFO_CFG4_CR BIT(4) /* CRC error */
++#define FIFO_CFG4_LM BIT(5) /* Length Mismatch */
++#define FIFO_CFG4_LO BIT(6) /* Length out of range */
++#define FIFO_CFG4_OK BIT(7) /* Packet is OK */
++#define FIFO_CFG4_MC BIT(8) /* Multicast Packet */
++#define FIFO_CFG4_BC BIT(9) /* Broadcast Packet */
++#define FIFO_CFG4_DR BIT(10) /* Dribble */
++#define FIFO_CFG4_LE BIT(11) /* Long Event */
++#define FIFO_CFG4_CF BIT(12) /* Control Frame */
++#define FIFO_CFG4_PF BIT(13) /* Pause Frame */
++#define FIFO_CFG4_UO BIT(14) /* Unsupported Opcode */
++#define FIFO_CFG4_VT BIT(15) /* VLAN tag detected */
++#define FIFO_CFG4_FT BIT(16) /* Frame Truncated */
++#define FIFO_CFG4_UC BIT(17) /* Unicast Packet */
++
++#define FIFO_CFG5_DE BIT(0) /* Drop Event */
++#define FIFO_CFG5_DV BIT(1) /* RX_DV Event */
++#define FIFO_CFG5_FC BIT(2) /* False Carrier */
++#define FIFO_CFG5_CE BIT(3) /* Code Error */
++#define FIFO_CFG5_LM BIT(4) /* Length Mismatch */
++#define FIFO_CFG5_LO BIT(5) /* Length Out of Range */
++#define FIFO_CFG5_OK BIT(6) /* Packet is OK */
++#define FIFO_CFG5_MC BIT(7) /* Multicast Packet */
++#define FIFO_CFG5_BC BIT(8) /* Broadcast Packet */
++#define FIFO_CFG5_DR BIT(9) /* Dribble */
++#define FIFO_CFG5_CF BIT(10) /* Control Frame */
++#define FIFO_CFG5_PF BIT(11) /* Pause Frame */
++#define FIFO_CFG5_UO BIT(12) /* Unsupported Opcode */
++#define FIFO_CFG5_VT BIT(13) /* VLAN tag detected */
++#define FIFO_CFG5_LE BIT(14) /* Long Event */
++#define FIFO_CFG5_FT BIT(15) /* Frame Truncated */
++#define FIFO_CFG5_16 BIT(16) /* unknown */
++#define FIFO_CFG5_17 BIT(17) /* unknown */
++#define FIFO_CFG5_SF BIT(18) /* Short Frame */
++#define FIFO_CFG5_BM BIT(19) /* Byte Mode */
++
++#define AG71XX_INT_TX_PS BIT(0)
++#define AG71XX_INT_TX_UR BIT(1)
++#define AG71XX_INT_TX_BE BIT(3)
++#define AG71XX_INT_RX_PR BIT(4)
++#define AG71XX_INT_RX_OF BIT(6)
++#define AG71XX_INT_RX_BE BIT(7)
++
++#define MAC_IFCTL_SPEED BIT(16)
++
++#define MII_CFG_CLK_DIV_4 0
++#define MII_CFG_CLK_DIV_6 2
++#define MII_CFG_CLK_DIV_8 3
++#define MII_CFG_CLK_DIV_10 4
++#define MII_CFG_CLK_DIV_14 5
++#define MII_CFG_CLK_DIV_20 6
++#define MII_CFG_CLK_DIV_28 7
++#define MII_CFG_CLK_DIV_34 8
++#define MII_CFG_CLK_DIV_42 9
++#define MII_CFG_CLK_DIV_50 10
++#define MII_CFG_CLK_DIV_58 11
++#define MII_CFG_CLK_DIV_66 12
++#define MII_CFG_CLK_DIV_74 13
++#define MII_CFG_CLK_DIV_82 14
++#define MII_CFG_CLK_DIV_98 15
++#define MII_CFG_RESET BIT(31)
++
++#define MII_CMD_WRITE 0x0
++#define MII_CMD_READ 0x1
++#define MII_ADDR_SHIFT 8
++#define MII_IND_BUSY BIT(0)
++#define MII_IND_INVALID BIT(2)
++
++#define TX_CTRL_TXE BIT(0) /* Tx Enable */
++
++#define TX_STATUS_PS BIT(0) /* Packet Sent */
++#define TX_STATUS_UR BIT(1) /* Tx Underrun */
++#define TX_STATUS_BE BIT(3) /* Bus Error */
++
++#define RX_CTRL_RXE BIT(0) /* Rx Enable */
++
++#define RX_STATUS_PR BIT(0) /* Packet Received */
++#define RX_STATUS_OF BIT(2) /* Rx Overflow */
++#define RX_STATUS_BE BIT(3) /* Bus Error */
++
++static inline void ag71xx_check_reg_offset(struct ag71xx *ag, unsigned reg)
++{
++ switch (reg) {
++ case AG71XX_REG_MAC_CFG1 ... AG71XX_REG_MAC_MFL:
++ case AG71XX_REG_MAC_IFCTL ... AG71XX_REG_TX_SM:
++ case AG71XX_REG_MII_CFG:
++ break;
++
++ default:
++ BUG();
++ }
++}
++
++static inline void ag71xx_wr(struct ag71xx *ag, unsigned reg, u32 value)
++{
++ ag71xx_check_reg_offset(ag, reg);
++
++ __raw_writel(value, ag->mac_base + reg);
++ /* flush write */
++ (void) __raw_readl(ag->mac_base + reg);
++}
++
++static inline u32 ag71xx_rr(struct ag71xx *ag, unsigned reg)
++{
++ ag71xx_check_reg_offset(ag, reg);
++
++ return __raw_readl(ag->mac_base + reg);
++}
++
++static inline void ag71xx_sb(struct ag71xx *ag, unsigned reg, u32 mask)
++{
++ void __iomem *r;
++
++ ag71xx_check_reg_offset(ag, reg);
++
++ r = ag->mac_base + reg;
++ __raw_writel(__raw_readl(r) | mask, r);
++ /* flush write */
++ (void)__raw_readl(r);
++}
++
++static inline void ag71xx_cb(struct ag71xx *ag, unsigned reg, u32 mask)
++{
++ void __iomem *r;
++
++ ag71xx_check_reg_offset(ag, reg);
++
++ r = ag->mac_base + reg;
++ __raw_writel(__raw_readl(r) & ~mask, r);
++ /* flush write */
++ (void) __raw_readl(r);
++}
++
++static inline void ag71xx_int_enable(struct ag71xx *ag, u32 ints)
++{
++ ag71xx_sb(ag, AG71XX_REG_INT_ENABLE, ints);
++}
++
++static inline void ag71xx_int_disable(struct ag71xx *ag, u32 ints)
++{
++ ag71xx_cb(ag, AG71XX_REG_INT_ENABLE, ints);
++}
++
++#ifdef CONFIG_AG71XX_AR8216_SUPPORT
++void ag71xx_add_ar8216_header(struct ag71xx *ag, struct sk_buff *skb);
++int ag71xx_remove_ar8216_header(struct ag71xx *ag, struct sk_buff *skb,
++ int pktlen);
++static inline int ag71xx_has_ar8216(struct ag71xx *ag)
++{
++ return ag71xx_get_pdata(ag)->has_ar8216;
++}
++#else
++static inline void ag71xx_add_ar8216_header(struct ag71xx *ag,
++ struct sk_buff *skb)
++{
++}
++
++static inline int ag71xx_remove_ar8216_header(struct ag71xx *ag,
++ struct sk_buff *skb,
++ int pktlen)
++{
++ return 0;
++}
++static inline int ag71xx_has_ar8216(struct ag71xx *ag)
++{
++ return 0;
++}
++#endif
++
++#ifdef CONFIG_AG71XX_DEBUG_FS
++int ag71xx_debugfs_root_init(void);
++void ag71xx_debugfs_root_exit(void);
++int ag71xx_debugfs_init(struct ag71xx *ag);
++void ag71xx_debugfs_exit(struct ag71xx *ag);
++void ag71xx_debugfs_update_int_stats(struct ag71xx *ag, u32 status);
++void ag71xx_debugfs_update_napi_stats(struct ag71xx *ag, int rx, int tx);
++#else
++static inline int ag71xx_debugfs_root_init(void) { return 0; }
++static inline void ag71xx_debugfs_root_exit(void) {}
++static inline int ag71xx_debugfs_init(struct ag71xx *ag) { return 0; }
++static inline void ag71xx_debugfs_exit(struct ag71xx *ag) {}
++static inline void ag71xx_debugfs_update_int_stats(struct ag71xx *ag,
++ u32 status) {}
++static inline void ag71xx_debugfs_update_napi_stats(struct ag71xx *ag,
++ int rx, int tx) {}
++#endif /* CONFIG_AG71XX_DEBUG_FS */
++
++void ag71xx_ar7240_start(struct ag71xx *ag);
++void ag71xx_ar7240_stop(struct ag71xx *ag);
++int ag71xx_ar7240_init(struct ag71xx *ag);
++void ag71xx_ar7240_cleanup(struct ag71xx *ag);
++
++int ag71xx_mdio_mii_read(struct ag71xx_mdio *am, int addr, int reg);
++void ag71xx_mdio_mii_write(struct ag71xx_mdio *am, int addr, int reg, u16 val);
++
++u16 ar7240sw_phy_read(struct mii_bus *mii, unsigned phy_addr,
++ unsigned reg_addr);
++int ar7240sw_phy_write(struct mii_bus *mii, unsigned phy_addr,
++ unsigned reg_addr, u16 reg_val);
++
++#endif /* _AG71XX_H */
+diff --git a/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar7240.c b/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar7240.c
+new file mode 100644
+index 0000000..d4ccc02
+--- /dev/null
++++ b/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar7240.c
+@@ -0,0 +1,1202 @@
++/*
++ * Driver for the built-in ethernet switch of the Atheros AR7240 SoC
++ * Copyright (c) 2010 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (c) 2010 Felix Fietkau <nbd@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ *
++ */
++
++#include <linux/etherdevice.h>
++#include <linux/list.h>
++#include <linux/netdevice.h>
++#include <linux/phy.h>
++#include <linux/mii.h>
++#include <linux/bitops.h>
++#include <linux/switch.h>
++#include "ag71xx.h"
++
++#define BITM(_count) (BIT(_count) - 1)
++#define BITS(_shift, _count) (BITM(_count) << _shift)
++
++#define AR7240_REG_MASK_CTRL 0x00
++#define AR7240_MASK_CTRL_REVISION_M BITM(8)
++#define AR7240_MASK_CTRL_VERSION_M BITM(8)
++#define AR7240_MASK_CTRL_VERSION_S 8
++#define AR7240_MASK_CTRL_VERSION_AR7240 0x01
++#define AR7240_MASK_CTRL_VERSION_AR934X 0x02
++#define AR7240_MASK_CTRL_SOFT_RESET BIT(31)
++
++#define AR7240_REG_MAC_ADDR0 0x20
++#define AR7240_REG_MAC_ADDR1 0x24
++
++#define AR7240_REG_FLOOD_MASK 0x2c
++#define AR7240_FLOOD_MASK_BROAD_TO_CPU BIT(26)
++
++#define AR7240_REG_GLOBAL_CTRL 0x30
++#define AR7240_GLOBAL_CTRL_MTU_M BITM(11)
++#define AR9340_GLOBAL_CTRL_MTU_M BITM(14)
++
++#define AR7240_REG_VTU 0x0040
++#define AR7240_VTU_OP BITM(3)
++#define AR7240_VTU_OP_NOOP 0x0
++#define AR7240_VTU_OP_FLUSH 0x1
++#define AR7240_VTU_OP_LOAD 0x2
++#define AR7240_VTU_OP_PURGE 0x3
++#define AR7240_VTU_OP_REMOVE_PORT 0x4
++#define AR7240_VTU_ACTIVE BIT(3)
++#define AR7240_VTU_FULL BIT(4)
++#define AR7240_VTU_PORT BITS(8, 4)
++#define AR7240_VTU_PORT_S 8
++#define AR7240_VTU_VID BITS(16, 12)
++#define AR7240_VTU_VID_S 16
++#define AR7240_VTU_PRIO BITS(28, 3)
++#define AR7240_VTU_PRIO_S 28
++#define AR7240_VTU_PRIO_EN BIT(31)
++
++#define AR7240_REG_VTU_DATA 0x0044
++#define AR7240_VTUDATA_MEMBER BITS(0, 10)
++#define AR7240_VTUDATA_VALID BIT(11)
++
++#define AR7240_REG_ATU 0x50
++#define AR7240_ATU_FLUSH_ALL 0x1
++
++#define AR7240_REG_AT_CTRL 0x5c
++#define AR7240_AT_CTRL_AGE_TIME BITS(0, 15)
++#define AR7240_AT_CTRL_AGE_EN BIT(17)
++#define AR7240_AT_CTRL_LEARN_CHANGE BIT(18)
++#define AR7240_AT_CTRL_RESERVED BIT(19)
++#define AR7240_AT_CTRL_ARP_EN BIT(20)
++
++#define AR7240_REG_TAG_PRIORITY 0x70
++
++#define AR7240_REG_SERVICE_TAG 0x74
++#define AR7240_SERVICE_TAG_M BITM(16)
++
++#define AR7240_REG_CPU_PORT 0x78
++#define AR7240_MIRROR_PORT_S 4
++#define AR7240_CPU_PORT_EN BIT(8)
++
++#define AR7240_REG_MIB_FUNCTION0 0x80
++#define AR7240_MIB_TIMER_M BITM(16)
++#define AR7240_MIB_AT_HALF_EN BIT(16)
++#define AR7240_MIB_BUSY BIT(17)
++#define AR7240_MIB_FUNC_S 24
++#define AR7240_MIB_FUNC_M BITM(3)
++#define AR7240_MIB_FUNC_NO_OP 0x0
++#define AR7240_MIB_FUNC_FLUSH 0x1
++#define AR7240_MIB_FUNC_CAPTURE 0x3
++
++#define AR7240_REG_MDIO_CTRL 0x98
++#define AR7240_MDIO_CTRL_DATA_M BITM(16)
++#define AR7240_MDIO_CTRL_REG_ADDR_S 16
++#define AR7240_MDIO_CTRL_PHY_ADDR_S 21
++#define AR7240_MDIO_CTRL_CMD_WRITE 0
++#define AR7240_MDIO_CTRL_CMD_READ BIT(27)
++#define AR7240_MDIO_CTRL_MASTER_EN BIT(30)
++#define AR7240_MDIO_CTRL_BUSY BIT(31)
++
++#define AR7240_REG_PORT_BASE(_port) (0x100 + (_port) * 0x100)
++
++#define AR7240_REG_PORT_STATUS(_port) (AR7240_REG_PORT_BASE((_port)) + 0x00)
++#define AR7240_PORT_STATUS_SPEED_S 0
++#define AR7240_PORT_STATUS_SPEED_M BITM(2)
++#define AR7240_PORT_STATUS_SPEED_10 0
++#define AR7240_PORT_STATUS_SPEED_100 1
++#define AR7240_PORT_STATUS_SPEED_1000 2
++#define AR7240_PORT_STATUS_TXMAC BIT(2)
++#define AR7240_PORT_STATUS_RXMAC BIT(3)
++#define AR7240_PORT_STATUS_TXFLOW BIT(4)
++#define AR7240_PORT_STATUS_RXFLOW BIT(5)
++#define AR7240_PORT_STATUS_DUPLEX BIT(6)
++#define AR7240_PORT_STATUS_LINK_UP BIT(8)
++#define AR7240_PORT_STATUS_LINK_AUTO BIT(9)
++#define AR7240_PORT_STATUS_LINK_PAUSE BIT(10)
++
++#define AR7240_REG_PORT_CTRL(_port) (AR7240_REG_PORT_BASE((_port)) + 0x04)
++#define AR7240_PORT_CTRL_STATE_M BITM(3)
++#define AR7240_PORT_CTRL_STATE_DISABLED 0
++#define AR7240_PORT_CTRL_STATE_BLOCK 1
++#define AR7240_PORT_CTRL_STATE_LISTEN 2
++#define AR7240_PORT_CTRL_STATE_LEARN 3
++#define AR7240_PORT_CTRL_STATE_FORWARD 4
++#define AR7240_PORT_CTRL_LEARN_LOCK BIT(7)
++#define AR7240_PORT_CTRL_VLAN_MODE_S 8
++#define AR7240_PORT_CTRL_VLAN_MODE_KEEP 0
++#define AR7240_PORT_CTRL_VLAN_MODE_STRIP 1
++#define AR7240_PORT_CTRL_VLAN_MODE_ADD 2
++#define AR7240_PORT_CTRL_VLAN_MODE_DOUBLE_TAG 3
++#define AR7240_PORT_CTRL_IGMP_SNOOP BIT(10)
++#define AR7240_PORT_CTRL_HEADER BIT(11)
++#define AR7240_PORT_CTRL_MAC_LOOP BIT(12)
++#define AR7240_PORT_CTRL_SINGLE_VLAN BIT(13)
++#define AR7240_PORT_CTRL_LEARN BIT(14)
++#define AR7240_PORT_CTRL_DOUBLE_TAG BIT(15)
++#define AR7240_PORT_CTRL_MIRROR_TX BIT(16)
++#define AR7240_PORT_CTRL_MIRROR_RX BIT(17)
++
++#define AR7240_REG_PORT_VLAN(_port) (AR7240_REG_PORT_BASE((_port)) + 0x08)
++
++#define AR7240_PORT_VLAN_DEFAULT_ID_S 0
++#define AR7240_PORT_VLAN_DEST_PORTS_S 16
++#define AR7240_PORT_VLAN_MODE_S 30
++#define AR7240_PORT_VLAN_MODE_PORT_ONLY 0
++#define AR7240_PORT_VLAN_MODE_PORT_FALLBACK 1
++#define AR7240_PORT_VLAN_MODE_VLAN_ONLY 2
++#define AR7240_PORT_VLAN_MODE_SECURE 3
++
++
++#define AR7240_REG_STATS_BASE(_port) (0x20000 + (_port) * 0x100)
++
++#define AR7240_STATS_RXBROAD 0x00
++#define AR7240_STATS_RXPAUSE 0x04
++#define AR7240_STATS_RXMULTI 0x08
++#define AR7240_STATS_RXFCSERR 0x0c
++#define AR7240_STATS_RXALIGNERR 0x10
++#define AR7240_STATS_RXRUNT 0x14
++#define AR7240_STATS_RXFRAGMENT 0x18
++#define AR7240_STATS_RX64BYTE 0x1c
++#define AR7240_STATS_RX128BYTE 0x20
++#define AR7240_STATS_RX256BYTE 0x24
++#define AR7240_STATS_RX512BYTE 0x28
++#define AR7240_STATS_RX1024BYTE 0x2c
++#define AR7240_STATS_RX1518BYTE 0x30
++#define AR7240_STATS_RXMAXBYTE 0x34
++#define AR7240_STATS_RXTOOLONG 0x38
++#define AR7240_STATS_RXGOODBYTE 0x3c
++#define AR7240_STATS_RXBADBYTE 0x44
++#define AR7240_STATS_RXOVERFLOW 0x4c
++#define AR7240_STATS_FILTERED 0x50
++#define AR7240_STATS_TXBROAD 0x54
++#define AR7240_STATS_TXPAUSE 0x58
++#define AR7240_STATS_TXMULTI 0x5c
++#define AR7240_STATS_TXUNDERRUN 0x60
++#define AR7240_STATS_TX64BYTE 0x64
++#define AR7240_STATS_TX128BYTE 0x68
++#define AR7240_STATS_TX256BYTE 0x6c
++#define AR7240_STATS_TX512BYTE 0x70
++#define AR7240_STATS_TX1024BYTE 0x74
++#define AR7240_STATS_TX1518BYTE 0x78
++#define AR7240_STATS_TXMAXBYTE 0x7c
++#define AR7240_STATS_TXOVERSIZE 0x80
++#define AR7240_STATS_TXBYTE 0x84
++#define AR7240_STATS_TXCOLLISION 0x8c
++#define AR7240_STATS_TXABORTCOL 0x90
++#define AR7240_STATS_TXMULTICOL 0x94
++#define AR7240_STATS_TXSINGLECOL 0x98
++#define AR7240_STATS_TXEXCDEFER 0x9c
++#define AR7240_STATS_TXDEFER 0xa0
++#define AR7240_STATS_TXLATECOL 0xa4
++
++#define AR7240_PORT_CPU 0
++#define AR7240_NUM_PORTS 6
++#define AR7240_NUM_PHYS 5
++
++#define AR7240_PHY_ID1 0x004d
++#define AR7240_PHY_ID2 0xd041
++
++#define AR934X_PHY_ID1 0x004d
++#define AR934X_PHY_ID2 0xd042
++
++#define AR7240_MAX_VLANS 16
++
++#define AR934X_REG_OPER_MODE0 0x04
++#define AR934X_OPER_MODE0_MAC_GMII_EN BIT(6)
++#define AR934X_OPER_MODE0_PHY_MII_EN BIT(10)
++
++#define AR934X_REG_OPER_MODE1 0x08
++#define AR934X_REG_OPER_MODE1_PHY4_MII_EN BIT(28)
++
++#define AR934X_REG_FLOOD_MASK 0x2c
++#define AR934X_FLOOD_MASK_MC_DP(_p) BIT(16 + (_p))
++#define AR934X_FLOOD_MASK_BC_DP(_p) BIT(25 + (_p))
++
++#define AR934X_REG_QM_CTRL 0x3c
++#define AR934X_QM_CTRL_ARP_EN BIT(15)
++
++#define AR934X_REG_AT_CTRL 0x5c
++#define AR934X_AT_CTRL_AGE_TIME BITS(0, 15)
++#define AR934X_AT_CTRL_AGE_EN BIT(17)
++#define AR934X_AT_CTRL_LEARN_CHANGE BIT(18)
++
++#define AR934X_MIB_ENABLE BIT(30)
++
++#define AR934X_REG_PORT_BASE(_port) (0x100 + (_port) * 0x100)
++
++#define AR934X_REG_PORT_VLAN1(_port) (AR934X_REG_PORT_BASE((_port)) + 0x08)
++#define AR934X_PORT_VLAN1_DEFAULT_SVID_S 0
++#define AR934X_PORT_VLAN1_FORCE_DEFAULT_VID_EN BIT(12)
++#define AR934X_PORT_VLAN1_PORT_TLS_MODE BIT(13)
++#define AR934X_PORT_VLAN1_PORT_VLAN_PROP_EN BIT(14)
++#define AR934X_PORT_VLAN1_PORT_CLONE_EN BIT(15)
++#define AR934X_PORT_VLAN1_DEFAULT_CVID_S 16
++#define AR934X_PORT_VLAN1_FORCE_PORT_VLAN_EN BIT(28)
++#define AR934X_PORT_VLAN1_ING_PORT_PRI_S 29
++
++#define AR934X_REG_PORT_VLAN2(_port) (AR934X_REG_PORT_BASE((_port)) + 0x0c)
++#define AR934X_PORT_VLAN2_PORT_VID_MEM_S 16
++#define AR934X_PORT_VLAN2_8021Q_MODE_S 30
++#define AR934X_PORT_VLAN2_8021Q_MODE_PORT_ONLY 0
++#define AR934X_PORT_VLAN2_8021Q_MODE_PORT_FALLBACK 1
++#define AR934X_PORT_VLAN2_8021Q_MODE_VLAN_ONLY 2
++#define AR934X_PORT_VLAN2_8021Q_MODE_SECURE 3
++
++#define sw_to_ar7240(_dev) container_of(_dev, struct ar7240sw, swdev)
++
++struct ar7240sw_port_stat {
++ unsigned long rx_broadcast;
++ unsigned long rx_pause;
++ unsigned long rx_multicast;
++ unsigned long rx_fcs_error;
++ unsigned long rx_align_error;
++ unsigned long rx_runt;
++ unsigned long rx_fragments;
++ unsigned long rx_64byte;
++ unsigned long rx_128byte;
++ unsigned long rx_256byte;
++ unsigned long rx_512byte;
++ unsigned long rx_1024byte;
++ unsigned long rx_1518byte;
++ unsigned long rx_maxbyte;
++ unsigned long rx_toolong;
++ unsigned long rx_good_byte;
++ unsigned long rx_bad_byte;
++ unsigned long rx_overflow;
++ unsigned long filtered;
++
++ unsigned long tx_broadcast;
++ unsigned long tx_pause;
++ unsigned long tx_multicast;
++ unsigned long tx_underrun;
++ unsigned long tx_64byte;
++ unsigned long tx_128byte;
++ unsigned long tx_256byte;
++ unsigned long tx_512byte;
++ unsigned long tx_1024byte;
++ unsigned long tx_1518byte;
++ unsigned long tx_maxbyte;
++ unsigned long tx_oversize;
++ unsigned long tx_byte;
++ unsigned long tx_collision;
++ unsigned long tx_abortcol;
++ unsigned long tx_multicol;
++ unsigned long tx_singlecol;
++ unsigned long tx_excdefer;
++ unsigned long tx_defer;
++ unsigned long tx_xlatecol;
++};
++
++struct ar7240sw {
++ struct mii_bus *mii_bus;
++ struct ag71xx_switch_platform_data *swdata;
++ struct switch_dev swdev;
++ int num_ports;
++ u8 ver;
++ bool vlan;
++ u16 vlan_id[AR7240_MAX_VLANS];
++ u8 vlan_table[AR7240_MAX_VLANS];
++ u8 vlan_tagged;
++ u16 pvid[AR7240_NUM_PORTS];
++ char buf[80];
++
++ rwlock_t stats_lock;
++ struct ar7240sw_port_stat port_stats[AR7240_NUM_PORTS];
++};
++
++struct ar7240sw_hw_stat {
++ char string[ETH_GSTRING_LEN];
++ int sizeof_stat;
++ int reg;
++};
++
++static DEFINE_MUTEX(reg_mutex);
++
++static inline int sw_is_ar7240(struct ar7240sw *as)
++{
++ return as->ver == AR7240_MASK_CTRL_VERSION_AR7240;
++}
++
++static inline int sw_is_ar934x(struct ar7240sw *as)
++{
++ return as->ver == AR7240_MASK_CTRL_VERSION_AR934X;
++}
++
++static inline u32 ar7240sw_port_mask(struct ar7240sw *as, int port)
++{
++ return BIT(port);
++}
++
++static inline u32 ar7240sw_port_mask_all(struct ar7240sw *as)
++{
++ return BIT(as->swdev.ports) - 1;
++}
++
++static inline u32 ar7240sw_port_mask_but(struct ar7240sw *as, int port)
++{
++ return ar7240sw_port_mask_all(as) & ~BIT(port);
++}
++
++static inline u16 mk_phy_addr(u32 reg)
++{
++ return 0x17 & ((reg >> 4) | 0x10);
++}
++
++static inline u16 mk_phy_reg(u32 reg)
++{
++ return (reg << 1) & 0x1e;
++}
++
++static inline u16 mk_high_addr(u32 reg)
++{
++ return (reg >> 7) & 0x1ff;
++}
++
++static u32 __ar7240sw_reg_read(struct mii_bus *mii, u32 reg)
++{
++ unsigned long flags;
++ u16 phy_addr;
++ u16 phy_reg;
++ u32 hi, lo;
++
++ reg = (reg & 0xfffffffc) >> 2;
++ phy_addr = mk_phy_addr(reg);
++ phy_reg = mk_phy_reg(reg);
++
++ local_irq_save(flags);
++ ag71xx_mdio_mii_write(mii->priv, 0x1f, 0x10, mk_high_addr(reg));
++ lo = (u32) ag71xx_mdio_mii_read(mii->priv, phy_addr, phy_reg);
++ hi = (u32) ag71xx_mdio_mii_read(mii->priv, phy_addr, phy_reg + 1);
++ local_irq_restore(flags);
++
++ return (hi << 16) | lo;
++}
++
++static void __ar7240sw_reg_write(struct mii_bus *mii, u32 reg, u32 val)
++{
++ unsigned long flags;
++ u16 phy_addr;
++ u16 phy_reg;
++
++ reg = (reg & 0xfffffffc) >> 2;
++ phy_addr = mk_phy_addr(reg);
++ phy_reg = mk_phy_reg(reg);
++
++ local_irq_save(flags);
++ ag71xx_mdio_mii_write(mii->priv, 0x1f, 0x10, mk_high_addr(reg));
++ ag71xx_mdio_mii_write(mii->priv, phy_addr, phy_reg + 1, (val >> 16));
++ ag71xx_mdio_mii_write(mii->priv, phy_addr, phy_reg, (val & 0xffff));
++ local_irq_restore(flags);
++}
++
++static u32 ar7240sw_reg_read(struct mii_bus *mii, u32 reg_addr)
++{
++ u32 ret;
++
++ mutex_lock(&reg_mutex);
++ ret = __ar7240sw_reg_read(mii, reg_addr);
++ mutex_unlock(&reg_mutex);
++
++ return ret;
++}
++
++static void ar7240sw_reg_write(struct mii_bus *mii, u32 reg_addr, u32 reg_val)
++{
++ mutex_lock(&reg_mutex);
++ __ar7240sw_reg_write(mii, reg_addr, reg_val);
++ mutex_unlock(&reg_mutex);
++}
++
++static u32 ar7240sw_reg_rmw(struct mii_bus *mii, u32 reg, u32 mask, u32 val)
++{
++ u32 t;
++
++ mutex_lock(&reg_mutex);
++ t = __ar7240sw_reg_read(mii, reg);
++ t &= ~mask;
++ t |= val;
++ __ar7240sw_reg_write(mii, reg, t);
++ mutex_unlock(&reg_mutex);
++
++ return t;
++}
++
++static void ar7240sw_reg_set(struct mii_bus *mii, u32 reg, u32 val)
++{
++ u32 t;
++
++ mutex_lock(&reg_mutex);
++ t = __ar7240sw_reg_read(mii, reg);
++ t |= val;
++ __ar7240sw_reg_write(mii, reg, t);
++ mutex_unlock(&reg_mutex);
++}
++
++static int __ar7240sw_reg_wait(struct mii_bus *mii, u32 reg, u32 mask, u32 val,
++ unsigned timeout)
++{
++ int i;
++
++ for (i = 0; i < timeout; i++) {
++ u32 t;
++
++ t = __ar7240sw_reg_read(mii, reg);
++ if ((t & mask) == val)
++ return 0;
++
++ msleep(1);
++ }
++
++ return -ETIMEDOUT;
++}
++
++static int ar7240sw_reg_wait(struct mii_bus *mii, u32 reg, u32 mask, u32 val,
++ unsigned timeout)
++{
++ int ret;
++
++ mutex_lock(&reg_mutex);
++ ret = __ar7240sw_reg_wait(mii, reg, mask, val, timeout);
++ mutex_unlock(&reg_mutex);
++ return ret;
++}
++
++u16 ar7240sw_phy_read(struct mii_bus *mii, unsigned phy_addr,
++ unsigned reg_addr)
++{
++ u32 t, val = 0xffff;
++ int err;
++
++ if (phy_addr >= AR7240_NUM_PHYS)
++ return 0xffff;
++
++ mutex_lock(&reg_mutex);
++ t = (reg_addr << AR7240_MDIO_CTRL_REG_ADDR_S) |
++ (phy_addr << AR7240_MDIO_CTRL_PHY_ADDR_S) |
++ AR7240_MDIO_CTRL_MASTER_EN |
++ AR7240_MDIO_CTRL_BUSY |
++ AR7240_MDIO_CTRL_CMD_READ;
++
++ __ar7240sw_reg_write(mii, AR7240_REG_MDIO_CTRL, t);
++ err = __ar7240sw_reg_wait(mii, AR7240_REG_MDIO_CTRL,
++ AR7240_MDIO_CTRL_BUSY, 0, 5);
++ if (!err)
++ val = __ar7240sw_reg_read(mii, AR7240_REG_MDIO_CTRL);
++ mutex_unlock(&reg_mutex);
++
++ return val & AR7240_MDIO_CTRL_DATA_M;
++}
++
++int ar7240sw_phy_write(struct mii_bus *mii, unsigned phy_addr,
++ unsigned reg_addr, u16 reg_val)
++{
++ u32 t;
++ int ret;
++
++ if (phy_addr >= AR7240_NUM_PHYS)
++ return -EINVAL;
++
++ mutex_lock(&reg_mutex);
++ t = (phy_addr << AR7240_MDIO_CTRL_PHY_ADDR_S) |
++ (reg_addr << AR7240_MDIO_CTRL_REG_ADDR_S) |
++ AR7240_MDIO_CTRL_MASTER_EN |
++ AR7240_MDIO_CTRL_BUSY |
++ AR7240_MDIO_CTRL_CMD_WRITE |
++ reg_val;
++
++ __ar7240sw_reg_write(mii, AR7240_REG_MDIO_CTRL, t);
++ ret = __ar7240sw_reg_wait(mii, AR7240_REG_MDIO_CTRL,
++ AR7240_MDIO_CTRL_BUSY, 0, 5);
++ mutex_unlock(&reg_mutex);
++
++ return ret;
++}
++
++static int ar7240sw_capture_stats(struct ar7240sw *as)
++{
++ struct mii_bus *mii = as->mii_bus;
++ int port;
++ int ret;
++
++ write_lock(&as->stats_lock);
++
++ /* Capture the hardware statistics for all ports */
++ ar7240sw_reg_rmw(mii, AR7240_REG_MIB_FUNCTION0,
++ (AR7240_MIB_FUNC_M << AR7240_MIB_FUNC_S),
++ (AR7240_MIB_FUNC_CAPTURE << AR7240_MIB_FUNC_S));
++
++ /* Wait for the capturing to complete. */
++ ret = ar7240sw_reg_wait(mii, AR7240_REG_MIB_FUNCTION0,
++ AR7240_MIB_BUSY, 0, 10);
++
++ if (ret)
++ goto unlock;
++
++ for (port = 0; port < AR7240_NUM_PORTS; port++) {
++ unsigned int base;
++ struct ar7240sw_port_stat *stats;
++
++ base = AR7240_REG_STATS_BASE(port);
++ stats = &as->port_stats[port];
++
++#define READ_STAT(_r) ar7240sw_reg_read(mii, base + AR7240_STATS_ ## _r)
++
++ stats->rx_good_byte += READ_STAT(RXGOODBYTE);
++ stats->tx_byte += READ_STAT(TXBYTE);
++
++#undef READ_STAT
++ }
++
++ ret = 0;
++
++unlock:
++ write_unlock(&as->stats_lock);
++ return ret;
++}
++
++static void ar7240sw_disable_port(struct ar7240sw *as, unsigned port)
++{
++ ar7240sw_reg_write(as->mii_bus, AR7240_REG_PORT_CTRL(port),
++ AR7240_PORT_CTRL_STATE_DISABLED);
++}
++
++static void ar7240sw_setup(struct ar7240sw *as)
++{
++ struct mii_bus *mii = as->mii_bus;
++
++ /* Enable CPU port, and disable mirror port */
++ ar7240sw_reg_write(mii, AR7240_REG_CPU_PORT,
++ AR7240_CPU_PORT_EN |
++ (15 << AR7240_MIRROR_PORT_S));
++
++ /* Setup TAG priority mapping */
++ ar7240sw_reg_write(mii, AR7240_REG_TAG_PRIORITY, 0xfa50);
++
++ if (sw_is_ar934x(as)) {
++ /* Enable aging, MAC replacing */
++ ar7240sw_reg_write(mii, AR934X_REG_AT_CTRL,
++ 0x2b /* 5 min age time */ |
++ AR934X_AT_CTRL_AGE_EN |
++ AR934X_AT_CTRL_LEARN_CHANGE);
++ /* Enable ARP frame acknowledge */
++ ar7240sw_reg_set(mii, AR934X_REG_QM_CTRL,
++ AR934X_QM_CTRL_ARP_EN);
++ /* Enable Broadcast/Multicast frames transmitted to the CPU */
++ ar7240sw_reg_set(mii, AR934X_REG_FLOOD_MASK,
++ AR934X_FLOOD_MASK_BC_DP(0) |
++ AR934X_FLOOD_MASK_MC_DP(0));
++
++ /* setup MTU */
++ ar7240sw_reg_rmw(mii, AR7240_REG_GLOBAL_CTRL,
++ AR9340_GLOBAL_CTRL_MTU_M,
++ AR9340_GLOBAL_CTRL_MTU_M);
++
++ /* Enable MIB counters */
++ ar7240sw_reg_set(mii, AR7240_REG_MIB_FUNCTION0,
++ AR934X_MIB_ENABLE);
++
++ } else {
++ /* Enable ARP frame acknowledge, aging, MAC replacing */
++ ar7240sw_reg_write(mii, AR7240_REG_AT_CTRL,
++ AR7240_AT_CTRL_RESERVED |
++ 0x2b /* 5 min age time */ |
++ AR7240_AT_CTRL_AGE_EN |
++ AR7240_AT_CTRL_ARP_EN |
++ AR7240_AT_CTRL_LEARN_CHANGE);
++ /* Enable Broadcast frames transmitted to the CPU */
++ ar7240sw_reg_set(mii, AR7240_REG_FLOOD_MASK,
++ AR7240_FLOOD_MASK_BROAD_TO_CPU);
++
++ /* setup MTU */
++ ar7240sw_reg_rmw(mii, AR7240_REG_GLOBAL_CTRL,
++ AR7240_GLOBAL_CTRL_MTU_M,
++ AR7240_GLOBAL_CTRL_MTU_M);
++ }
++
++ /* setup Service TAG */
++ ar7240sw_reg_rmw(mii, AR7240_REG_SERVICE_TAG, AR7240_SERVICE_TAG_M, 0);
++}
++
++static int ar7240sw_reset(struct ar7240sw *as)
++{
++ struct mii_bus *mii = as->mii_bus;
++ int ret;
++ int i;
++
++ /* Set all ports to disabled state. */
++ for (i = 0; i < AR7240_NUM_PORTS; i++)
++ ar7240sw_disable_port(as, i);
++
++ /* Wait for transmit queues to drain. */
++ msleep(2);
++
++ /* Reset the switch. */
++ ar7240sw_reg_write(mii, AR7240_REG_MASK_CTRL,
++ AR7240_MASK_CTRL_SOFT_RESET);
++
++ ret = ar7240sw_reg_wait(mii, AR7240_REG_MASK_CTRL,
++ AR7240_MASK_CTRL_SOFT_RESET, 0, 1000);
++
++ /* setup PHYs */
++ for (i = 0; i < AR7240_NUM_PHYS; i++) {
++ ar7240sw_phy_write(mii, i, MII_ADVERTISE,
++ ADVERTISE_ALL | ADVERTISE_PAUSE_CAP |
++ ADVERTISE_PAUSE_ASYM);
++ ar7240sw_phy_write(mii, i, MII_BMCR,
++ BMCR_RESET | BMCR_ANENABLE);
++ }
++ msleep(1000);
++
++ ar7240sw_setup(as);
++ return ret;
++}
++
++static void ar7240sw_setup_port(struct ar7240sw *as, unsigned port, u8 portmask)
++{
++ struct mii_bus *mii = as->mii_bus;
++ u32 ctrl;
++ u32 vid, mode;
++
++ ctrl = AR7240_PORT_CTRL_STATE_FORWARD | AR7240_PORT_CTRL_LEARN |
++ AR7240_PORT_CTRL_SINGLE_VLAN;
++
++ if (port == AR7240_PORT_CPU) {
++ ar7240sw_reg_write(mii, AR7240_REG_PORT_STATUS(port),
++ AR7240_PORT_STATUS_SPEED_1000 |
++ AR7240_PORT_STATUS_TXFLOW |
++ AR7240_PORT_STATUS_RXFLOW |
++ AR7240_PORT_STATUS_TXMAC |
++ AR7240_PORT_STATUS_RXMAC |
++ AR7240_PORT_STATUS_DUPLEX);
++ } else {
++ ar7240sw_reg_write(mii, AR7240_REG_PORT_STATUS(port),
++ AR7240_PORT_STATUS_LINK_AUTO);
++ }
++
++ /* Set the default VID for this port */
++ if (as->vlan) {
++ vid = as->vlan_id[as->pvid[port]];
++ mode = AR7240_PORT_VLAN_MODE_SECURE;
++ } else {
++ vid = port;
++ mode = AR7240_PORT_VLAN_MODE_PORT_ONLY;
++ }
++
++ if (as->vlan) {
++ if (as->vlan_tagged & BIT(port))
++ ctrl |= AR7240_PORT_CTRL_VLAN_MODE_ADD <<
++ AR7240_PORT_CTRL_VLAN_MODE_S;
++ else
++ ctrl |= AR7240_PORT_CTRL_VLAN_MODE_STRIP <<
++ AR7240_PORT_CTRL_VLAN_MODE_S;
++ } else {
++ ctrl |= AR7240_PORT_CTRL_VLAN_MODE_KEEP <<
++ AR7240_PORT_CTRL_VLAN_MODE_S;
++ }
++
++ if (!portmask) {
++ if (port == AR7240_PORT_CPU)
++ portmask = ar7240sw_port_mask_but(as, AR7240_PORT_CPU);
++ else
++ portmask = ar7240sw_port_mask(as, AR7240_PORT_CPU);
++ }
++
++ /* allow the port to talk to all other ports, but exclude its
++ * own ID to prevent frames from being reflected back to the
++ * port that they came from */
++ portmask &= ar7240sw_port_mask_but(as, port);
++
++ ar7240sw_reg_write(mii, AR7240_REG_PORT_CTRL(port), ctrl);
++ if (sw_is_ar934x(as)) {
++ u32 vlan1, vlan2;
++
++ vlan1 = (vid << AR934X_PORT_VLAN1_DEFAULT_CVID_S);
++ vlan2 = (portmask << AR934X_PORT_VLAN2_PORT_VID_MEM_S) |
++ (mode << AR934X_PORT_VLAN2_8021Q_MODE_S);
++ ar7240sw_reg_write(mii, AR934X_REG_PORT_VLAN1(port), vlan1);
++ ar7240sw_reg_write(mii, AR934X_REG_PORT_VLAN2(port), vlan2);
++ } else {
++ u32 vlan;
++
++ vlan = vid | (mode << AR7240_PORT_VLAN_MODE_S) |
++ (portmask << AR7240_PORT_VLAN_DEST_PORTS_S);
++
++ ar7240sw_reg_write(mii, AR7240_REG_PORT_VLAN(port), vlan);
++ }
++}
++
++static int ar7240_set_addr(struct ar7240sw *as, u8 *addr)
++{
++ struct mii_bus *mii = as->mii_bus;
++ u32 t;
++
++ t = (addr[4] << 8) | addr[5];
++ ar7240sw_reg_write(mii, AR7240_REG_MAC_ADDR0, t);
++
++ t = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3];
++ ar7240sw_reg_write(mii, AR7240_REG_MAC_ADDR1, t);
++
++ return 0;
++}
++
++static int
++ar7240_set_vid(struct switch_dev *dev, const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ struct ar7240sw *as = sw_to_ar7240(dev);
++ as->vlan_id[val->port_vlan] = val->value.i;
++ return 0;
++}
++
++static int
++ar7240_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ struct ar7240sw *as = sw_to_ar7240(dev);
++ val->value.i = as->vlan_id[val->port_vlan];
++ return 0;
++}
++
++static int
++ar7240_set_pvid(struct switch_dev *dev, int port, int vlan)
++{
++ struct ar7240sw *as = sw_to_ar7240(dev);
++
++ /* make sure no invalid PVIDs get set */
++
++ if (vlan >= dev->vlans)
++ return -EINVAL;
++
++ as->pvid[port] = vlan;
++ return 0;
++}
++
++static int
++ar7240_get_pvid(struct switch_dev *dev, int port, int *vlan)
++{
++ struct ar7240sw *as = sw_to_ar7240(dev);
++ *vlan = as->pvid[port];
++ return 0;
++}
++
++static int
++ar7240_get_ports(struct switch_dev *dev, struct switch_val *val)
++{
++ struct ar7240sw *as = sw_to_ar7240(dev);
++ u8 ports = as->vlan_table[val->port_vlan];
++ int i;
++
++ val->len = 0;
++ for (i = 0; i < as->swdev.ports; i++) {
++ struct switch_port *p;
++
++ if (!(ports & (1 << i)))
++ continue;
++
++ p = &val->value.ports[val->len++];
++ p->id = i;
++ if (as->vlan_tagged & (1 << i))
++ p->flags = (1 << SWITCH_PORT_FLAG_TAGGED);
++ else
++ p->flags = 0;
++ }
++ return 0;
++}
++
++static int
++ar7240_set_ports(struct switch_dev *dev, struct switch_val *val)
++{
++ struct ar7240sw *as = sw_to_ar7240(dev);
++ u8 *vt = &as->vlan_table[val->port_vlan];
++ int i, j;
++
++ *vt = 0;
++ for (i = 0; i < val->len; i++) {
++ struct switch_port *p = &val->value.ports[i];
++
++ if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED))
++ as->vlan_tagged |= (1 << p->id);
++ else {
++ as->vlan_tagged &= ~(1 << p->id);
++ as->pvid[p->id] = val->port_vlan;
++
++ /* make sure that an untagged port does not
++ * appear in other vlans */
++ for (j = 0; j < AR7240_MAX_VLANS; j++) {
++ if (j == val->port_vlan)
++ continue;
++ as->vlan_table[j] &= ~(1 << p->id);
++ }
++ }
++
++ *vt |= 1 << p->id;
++ }
++ return 0;
++}
++
++static int
++ar7240_set_vlan(struct switch_dev *dev, const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ struct ar7240sw *as = sw_to_ar7240(dev);
++ as->vlan = !!val->value.i;
++ return 0;
++}
++
++static int
++ar7240_get_vlan(struct switch_dev *dev, const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ struct ar7240sw *as = sw_to_ar7240(dev);
++ val->value.i = as->vlan;
++ return 0;
++}
++
++static void
++ar7240_vtu_op(struct ar7240sw *as, u32 op, u32 val)
++{
++ struct mii_bus *mii = as->mii_bus;
++
++ if (ar7240sw_reg_wait(mii, AR7240_REG_VTU, AR7240_VTU_ACTIVE, 0, 5))
++ return;
++
++ if ((op & AR7240_VTU_OP) == AR7240_VTU_OP_LOAD) {
++ val &= AR7240_VTUDATA_MEMBER;
++ val |= AR7240_VTUDATA_VALID;
++ ar7240sw_reg_write(mii, AR7240_REG_VTU_DATA, val);
++ }
++ op |= AR7240_VTU_ACTIVE;
++ ar7240sw_reg_write(mii, AR7240_REG_VTU, op);
++}
++
++static int
++ar7240_hw_apply(struct switch_dev *dev)
++{
++ struct ar7240sw *as = sw_to_ar7240(dev);
++ u8 portmask[AR7240_NUM_PORTS];
++ int i, j;
++
++ /* flush all vlan translation unit entries */
++ ar7240_vtu_op(as, AR7240_VTU_OP_FLUSH, 0);
++
++ memset(portmask, 0, sizeof(portmask));
++ if (as->vlan) {
++ /* calculate the port destination masks and load vlans
++ * into the vlan translation unit */
++ for (j = 0; j < AR7240_MAX_VLANS; j++) {
++ u8 vp = as->vlan_table[j];
++
++ if (!vp)
++ continue;
++
++ for (i = 0; i < as->swdev.ports; i++) {
++ u8 mask = (1 << i);
++ if (vp & mask)
++ portmask[i] |= vp & ~mask;
++ }
++
++ ar7240_vtu_op(as,
++ AR7240_VTU_OP_LOAD |
++ (as->vlan_id[j] << AR7240_VTU_VID_S),
++ as->vlan_table[j]);
++ }
++ } else {
++ /* vlan disabled:
++ * isolate all ports, but connect them to the cpu port */
++ for (i = 0; i < as->swdev.ports; i++) {
++ if (i == AR7240_PORT_CPU)
++ continue;
++
++ portmask[i] = 1 << AR7240_PORT_CPU;
++ portmask[AR7240_PORT_CPU] |= (1 << i);
++ }
++ }
++
++ /* update the port destination mask registers and tag settings */
++ for (i = 0; i < as->swdev.ports; i++)
++ ar7240sw_setup_port(as, i, portmask[i]);
++
++ return 0;
++}
++
++static int
++ar7240_reset_switch(struct switch_dev *dev)
++{
++ struct ar7240sw *as = sw_to_ar7240(dev);
++ ar7240sw_reset(as);
++ return 0;
++}
++
++static int
++ar7240_get_port_link(struct switch_dev *dev, int port,
++ struct switch_port_link *link)
++{
++ struct ar7240sw *as = sw_to_ar7240(dev);
++ struct mii_bus *mii = as->mii_bus;
++ u32 status;
++
++ if (port > AR7240_NUM_PORTS)
++ return -EINVAL;
++
++ status = ar7240sw_reg_read(mii, AR7240_REG_PORT_STATUS(port));
++ link->aneg = !!(status & AR7240_PORT_STATUS_LINK_AUTO);
++ if (link->aneg) {
++ link->link = !!(status & AR7240_PORT_STATUS_LINK_UP);
++ if (!link->link)
++ return 0;
++ } else {
++ link->link = true;
++ }
++
++ link->duplex = !!(status & AR7240_PORT_STATUS_DUPLEX);
++ link->tx_flow = !!(status & AR7240_PORT_STATUS_TXFLOW);
++ link->rx_flow = !!(status & AR7240_PORT_STATUS_RXFLOW);
++ switch (status & AR7240_PORT_STATUS_SPEED_M) {
++ case AR7240_PORT_STATUS_SPEED_10:
++ link->speed = SWITCH_PORT_SPEED_10;
++ break;
++ case AR7240_PORT_STATUS_SPEED_100:
++ link->speed = SWITCH_PORT_SPEED_100;
++ break;
++ case AR7240_PORT_STATUS_SPEED_1000:
++ link->speed = SWITCH_PORT_SPEED_1000;
++ break;
++ }
++
++ return 0;
++}
++
++static int
++ar7240_get_port_stats(struct switch_dev *dev, int port,
++ struct switch_port_stats *stats)
++{
++ struct ar7240sw *as = sw_to_ar7240(dev);
++
++ if (port > AR7240_NUM_PORTS)
++ return -EINVAL;
++
++ ar7240sw_capture_stats(as);
++
++ read_lock(&as->stats_lock);
++ stats->rx_bytes = as->port_stats[port].rx_good_byte;
++ stats->tx_bytes = as->port_stats[port].tx_byte;
++ read_unlock(&as->stats_lock);
++
++ return 0;
++}
++
++static struct switch_attr ar7240_globals[] = {
++ {
++ .type = SWITCH_TYPE_INT,
++ .name = "enable_vlan",
++ .description = "Enable VLAN mode",
++ .set = ar7240_set_vlan,
++ .get = ar7240_get_vlan,
++ .max = 1
++ },
++};
++
++static struct switch_attr ar7240_port[] = {
++};
++
++static struct switch_attr ar7240_vlan[] = {
++ {
++ .type = SWITCH_TYPE_INT,
++ .name = "vid",
++ .description = "VLAN ID",
++ .set = ar7240_set_vid,
++ .get = ar7240_get_vid,
++ .max = 4094,
++ },
++};
++
++static const struct switch_dev_ops ar7240_ops = {
++ .attr_global = {
++ .attr = ar7240_globals,
++ .n_attr = ARRAY_SIZE(ar7240_globals),
++ },
++ .attr_port = {
++ .attr = ar7240_port,
++ .n_attr = ARRAY_SIZE(ar7240_port),
++ },
++ .attr_vlan = {
++ .attr = ar7240_vlan,
++ .n_attr = ARRAY_SIZE(ar7240_vlan),
++ },
++ .get_port_pvid = ar7240_get_pvid,
++ .set_port_pvid = ar7240_set_pvid,
++ .get_vlan_ports = ar7240_get_ports,
++ .set_vlan_ports = ar7240_set_ports,
++ .apply_config = ar7240_hw_apply,
++ .reset_switch = ar7240_reset_switch,
++ .get_port_link = ar7240_get_port_link,
++ .get_port_stats = ar7240_get_port_stats,
++};
++
++static struct ar7240sw *ar7240_probe(struct ag71xx *ag)
++{
++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++ struct mii_bus *mii = ag->mii_bus;
++ struct ar7240sw *as;
++ struct switch_dev *swdev;
++ u32 ctrl;
++ u16 phy_id1;
++ u16 phy_id2;
++ int i;
++
++ phy_id1 = ar7240sw_phy_read(mii, 0, MII_PHYSID1);
++ phy_id2 = ar7240sw_phy_read(mii, 0, MII_PHYSID2);
++ if ((phy_id1 != AR7240_PHY_ID1 || phy_id2 != AR7240_PHY_ID2) &&
++ (phy_id1 != AR934X_PHY_ID1 || phy_id2 != AR934X_PHY_ID2)) {
++ pr_err("%s: unknown phy id '%04x:%04x'\n",
++ dev_name(&mii->dev), phy_id1, phy_id2);
++ return NULL;
++ }
++
++ as = kzalloc(sizeof(*as), GFP_KERNEL);
++ if (!as)
++ return NULL;
++
++ as->mii_bus = mii;
++ as->swdata = pdata->switch_data;
++
++ swdev = &as->swdev;
++
++ ctrl = ar7240sw_reg_read(mii, AR7240_REG_MASK_CTRL);
++ as->ver = (ctrl >> AR7240_MASK_CTRL_VERSION_S) &
++ AR7240_MASK_CTRL_VERSION_M;
++
++ if (sw_is_ar7240(as)) {
++ swdev->name = "AR7240/AR9330 built-in switch";
++ swdev->ports = AR7240_NUM_PORTS - 1;
++ } else if (sw_is_ar934x(as)) {
++ swdev->name = "AR934X built-in switch";
++
++ if (pdata->phy_if_mode == PHY_INTERFACE_MODE_GMII) {
++ ar7240sw_reg_set(mii, AR934X_REG_OPER_MODE0,
++ AR934X_OPER_MODE0_MAC_GMII_EN);
++ } else if (pdata->phy_if_mode == PHY_INTERFACE_MODE_MII) {
++ ar7240sw_reg_set(mii, AR934X_REG_OPER_MODE0,
++ AR934X_OPER_MODE0_PHY_MII_EN);
++ } else {
++ pr_err("%s: invalid PHY interface mode\n",
++ dev_name(&mii->dev));
++ goto err_free;
++ }
++
++ if (as->swdata->phy4_mii_en) {
++ ar7240sw_reg_set(mii, AR934X_REG_OPER_MODE1,
++ AR934X_REG_OPER_MODE1_PHY4_MII_EN);
++ swdev->ports = AR7240_NUM_PORTS - 1;
++ } else {
++ swdev->ports = AR7240_NUM_PORTS;
++ }
++ } else {
++ pr_err("%s: unsupported chip, ctrl=%08x\n",
++ dev_name(&mii->dev), ctrl);
++ goto err_free;
++ }
++
++ swdev->cpu_port = AR7240_PORT_CPU;
++ swdev->vlans = AR7240_MAX_VLANS;
++ swdev->ops = &ar7240_ops;
++
++ if (register_switch(&as->swdev, ag->dev) < 0)
++ goto err_free;
++
++ pr_info("%s: Found an %s\n", dev_name(&mii->dev), swdev->name);
++
++ /* initialize defaults */
++ for (i = 0; i < AR7240_MAX_VLANS; i++)
++ as->vlan_id[i] = i;
++
++ as->vlan_table[0] = ar7240sw_port_mask_all(as);
++
++ return as;
++
++err_free:
++ kfree(as);
++ return NULL;
++}
++
++static void link_function(struct work_struct *work) {
++ struct ag71xx *ag = container_of(work, struct ag71xx, link_work.work);
++ struct ar7240sw *as = ag->phy_priv;
++ unsigned long flags;
++ u8 mask;
++ int i;
++ int status = 0;
++
++ mask = ~as->swdata->phy_poll_mask;
++ for (i = 0; i < AR7240_NUM_PHYS; i++) {
++ int link;
++
++ if (!(mask & BIT(i)))
++ continue;
++
++ link = ar7240sw_phy_read(ag->mii_bus, i, MII_BMSR);
++ if (link & BMSR_LSTATUS) {
++ status = 1;
++ break;
++ }
++ }
++
++ spin_lock_irqsave(&ag->lock, flags);
++ if (status != ag->link) {
++ ag->link = status;
++ ag71xx_link_adjust(ag);
++ }
++ spin_unlock_irqrestore(&ag->lock, flags);
++
++ schedule_delayed_work(&ag->link_work, HZ / 2);
++}
++
++void ag71xx_ar7240_start(struct ag71xx *ag)
++{
++ struct ar7240sw *as = ag->phy_priv;
++
++ ar7240sw_reset(as);
++
++ ag->speed = SPEED_1000;
++ ag->duplex = 1;
++
++ ar7240_set_addr(as, ag->dev->dev_addr);
++ ar7240_hw_apply(&as->swdev);
++
++ schedule_delayed_work(&ag->link_work, HZ / 10);
++}
++
++void ag71xx_ar7240_stop(struct ag71xx *ag)
++{
++ cancel_delayed_work_sync(&ag->link_work);
++}
++
++int ag71xx_ar7240_init(struct ag71xx *ag)
++{
++ struct ar7240sw *as;
++
++ as = ar7240_probe(ag);
++ if (!as)
++ return -ENODEV;
++
++ ag->phy_priv = as;
++ ar7240sw_reset(as);
++
++ rwlock_init(&as->stats_lock);
++ INIT_DELAYED_WORK(&ag->link_work, link_function);
++
++ return 0;
++}
++
++void ag71xx_ar7240_cleanup(struct ag71xx *ag)
++{
++ struct ar7240sw *as = ag->phy_priv;
++
++ if (!as)
++ return;
++
++ unregister_switch(&as->swdev);
++ kfree(as);
++ ag->phy_priv = NULL;
++}
+diff --git a/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar8216.c b/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar8216.c
+new file mode 100644
+index 0000000..7ec43b7
+--- /dev/null
++++ b/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar8216.c
+@@ -0,0 +1,44 @@
++/*
++ * Atheros AR71xx built-in ethernet mac driver
++ * Special support for the Atheros ar8216 switch chip
++ *
++ * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * Based on Atheros' AG7100 driver
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include "ag71xx.h"
++
++#define AR8216_PACKET_TYPE_MASK 0xf
++#define AR8216_PACKET_TYPE_NORMAL 0
++
++#define AR8216_HEADER_LEN 2
++
++void ag71xx_add_ar8216_header(struct ag71xx *ag, struct sk_buff *skb)
++{
++ skb_push(skb, AR8216_HEADER_LEN);
++ skb->data[0] = 0x10;
++ skb->data[1] = 0x80;
++}
++
++int ag71xx_remove_ar8216_header(struct ag71xx *ag, struct sk_buff *skb,
++ int pktlen)
++{
++ u8 type;
++
++ type = skb->data[1] & AR8216_PACKET_TYPE_MASK;
++ switch (type) {
++ case AR8216_PACKET_TYPE_NORMAL:
++ break;
++
++ default:
++ return -EINVAL;
++ }
++
++ skb_pull(skb, AR8216_HEADER_LEN);
++ return 0;
++}
+diff --git a/drivers/net/ethernet/atheros/ag71xx/ag71xx_debugfs.c b/drivers/net/ethernet/atheros/ag71xx/ag71xx_debugfs.c
+new file mode 100644
+index 0000000..757a572
+--- /dev/null
++++ b/drivers/net/ethernet/atheros/ag71xx/ag71xx_debugfs.c
+@@ -0,0 +1,284 @@
++/*
++ * Atheros AR71xx built-in ethernet mac driver
++ *
++ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Based on Atheros' AG7100 driver
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/debugfs.h>
++
++#include "ag71xx.h"
++
++static struct dentry *ag71xx_debugfs_root;
++
++static int ag71xx_debugfs_generic_open(struct inode *inode, struct file *file)
++{
++ file->private_data = inode->i_private;
++ return 0;
++}
++
++void ag71xx_debugfs_update_int_stats(struct ag71xx *ag, u32 status)
++{
++ if (status)
++ ag->debug.int_stats.total++;
++ if (status & AG71XX_INT_TX_PS)
++ ag->debug.int_stats.tx_ps++;
++ if (status & AG71XX_INT_TX_UR)
++ ag->debug.int_stats.tx_ur++;
++ if (status & AG71XX_INT_TX_BE)
++ ag->debug.int_stats.tx_be++;
++ if (status & AG71XX_INT_RX_PR)
++ ag->debug.int_stats.rx_pr++;
++ if (status & AG71XX_INT_RX_OF)
++ ag->debug.int_stats.rx_of++;
++ if (status & AG71XX_INT_RX_BE)
++ ag->debug.int_stats.rx_be++;
++}
++
++static ssize_t read_file_int_stats(struct file *file, char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++#define PR_INT_STAT(_label, _field) \
++ len += snprintf(buf + len, sizeof(buf) - len, \
++ "%20s: %10lu\n", _label, ag->debug.int_stats._field);
++
++ struct ag71xx *ag = file->private_data;
++ char buf[256];
++ unsigned int len = 0;
++
++ PR_INT_STAT("TX Packet Sent", tx_ps);
++ PR_INT_STAT("TX Underrun", tx_ur);
++ PR_INT_STAT("TX Bus Error", tx_be);
++ PR_INT_STAT("RX Packet Received", rx_pr);
++ PR_INT_STAT("RX Overflow", rx_of);
++ PR_INT_STAT("RX Bus Error", rx_be);
++ len += snprintf(buf + len, sizeof(buf) - len, "\n");
++ PR_INT_STAT("Total", total);
++
++ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
++#undef PR_INT_STAT
++}
++
++static const struct file_operations ag71xx_fops_int_stats = {
++ .open = ag71xx_debugfs_generic_open,
++ .read = read_file_int_stats,
++ .owner = THIS_MODULE
++};
++
++void ag71xx_debugfs_update_napi_stats(struct ag71xx *ag, int rx, int tx)
++{
++ struct ag71xx_napi_stats *stats = &ag->debug.napi_stats;
++
++ if (rx) {
++ stats->rx_count++;
++ stats->rx_packets += rx;
++ if (rx <= AG71XX_NAPI_WEIGHT)
++ stats->rx[rx]++;
++ if (rx > stats->rx_packets_max)
++ stats->rx_packets_max = rx;
++ }
++
++ if (tx) {
++ stats->tx_count++;
++ stats->tx_packets += tx;
++ if (tx <= AG71XX_NAPI_WEIGHT)
++ stats->tx[tx]++;
++ if (tx > stats->tx_packets_max)
++ stats->tx_packets_max = tx;
++ }
++}
++
++static ssize_t read_file_napi_stats(struct file *file, char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct ag71xx *ag = file->private_data;
++ struct ag71xx_napi_stats *stats = &ag->debug.napi_stats;
++ char *buf;
++ unsigned int buflen;
++ unsigned int len = 0;
++ unsigned long rx_avg = 0;
++ unsigned long tx_avg = 0;
++ int ret;
++ int i;
++
++ buflen = 2048;
++ buf = kmalloc(buflen, GFP_KERNEL);
++ if (!buf)
++ return -ENOMEM;
++
++ if (stats->rx_count)
++ rx_avg = stats->rx_packets / stats->rx_count;
++
++ if (stats->tx_count)
++ tx_avg = stats->tx_packets / stats->tx_count;
++
++ len += snprintf(buf + len, buflen - len, "%3s %10s %10s\n",
++ "len", "rx", "tx");
++
++ for (i = 1; i <= AG71XX_NAPI_WEIGHT; i++)
++ len += snprintf(buf + len, buflen - len,
++ "%3d: %10lu %10lu\n",
++ i, stats->rx[i], stats->tx[i]);
++
++ len += snprintf(buf + len, buflen - len, "\n");
++
++ len += snprintf(buf + len, buflen - len, "%3s: %10lu %10lu\n",
++ "sum", stats->rx_count, stats->tx_count);
++ len += snprintf(buf + len, buflen - len, "%3s: %10lu %10lu\n",
++ "avg", rx_avg, tx_avg);
++ len += snprintf(buf + len, buflen - len, "%3s: %10lu %10lu\n",
++ "max", stats->rx_packets_max, stats->tx_packets_max);
++ len += snprintf(buf + len, buflen - len, "%3s: %10lu %10lu\n",
++ "pkt", stats->rx_packets, stats->tx_packets);
++
++ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
++ kfree(buf);
++
++ return ret;
++}
++
++static const struct file_operations ag71xx_fops_napi_stats = {
++ .open = ag71xx_debugfs_generic_open,
++ .read = read_file_napi_stats,
++ .owner = THIS_MODULE
++};
++
++#define DESC_PRINT_LEN 64
++
++static ssize_t read_file_ring(struct file *file, char __user *user_buf,
++ size_t count, loff_t *ppos,
++ struct ag71xx *ag,
++ struct ag71xx_ring *ring,
++ unsigned desc_reg)
++{
++ char *buf;
++ unsigned int buflen;
++ unsigned int len = 0;
++ unsigned long flags;
++ ssize_t ret;
++ int curr;
++ int dirty;
++ u32 desc_hw;
++ int i;
++
++ buflen = (ring->size * DESC_PRINT_LEN);
++ buf = kmalloc(buflen, GFP_KERNEL);
++ if (!buf)
++ return -ENOMEM;
++
++ len += snprintf(buf + len, buflen - len,
++ "Idx ... %-8s %-8s %-8s %-8s . %-10s\n",
++ "desc", "next", "data", "ctrl", "timestamp");
++
++ spin_lock_irqsave(&ag->lock, flags);
++
++ curr = (ring->curr % ring->size);
++ dirty = (ring->dirty % ring->size);
++ desc_hw = ag71xx_rr(ag, desc_reg);
++ for (i = 0; i < ring->size; i++) {
++ struct ag71xx_buf *ab = &ring->buf[i];
++ u32 desc_dma = ((u32) ring->descs_dma) + i * ring->desc_size;
++
++ len += snprintf(buf + len, buflen - len,
++ "%3d %c%c%c %08x %08x %08x %08x %c %10lu\n",
++ i,
++ (i == curr) ? 'C' : ' ',
++ (i == dirty) ? 'D' : ' ',
++ (desc_hw == desc_dma) ? 'H' : ' ',
++ desc_dma,
++ ab->desc->next,
++ ab->desc->data,
++ ab->desc->ctrl,
++ (ab->desc->ctrl & DESC_EMPTY) ? 'E' : '*',
++ ab->timestamp);
++ }
++
++ spin_unlock_irqrestore(&ag->lock, flags);
++
++ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
++ kfree(buf);
++
++ return ret;
++}
++
++static ssize_t read_file_tx_ring(struct file *file, char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct ag71xx *ag = file->private_data;
++
++ return read_file_ring(file, user_buf, count, ppos, ag, &ag->tx_ring,
++ AG71XX_REG_TX_DESC);
++}
++
++static const struct file_operations ag71xx_fops_tx_ring = {
++ .open = ag71xx_debugfs_generic_open,
++ .read = read_file_tx_ring,
++ .owner = THIS_MODULE
++};
++
++static ssize_t read_file_rx_ring(struct file *file, char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct ag71xx *ag = file->private_data;
++
++ return read_file_ring(file, user_buf, count, ppos, ag, &ag->rx_ring,
++ AG71XX_REG_RX_DESC);
++}
++
++static const struct file_operations ag71xx_fops_rx_ring = {
++ .open = ag71xx_debugfs_generic_open,
++ .read = read_file_rx_ring,
++ .owner = THIS_MODULE
++};
++
++void ag71xx_debugfs_exit(struct ag71xx *ag)
++{
++ debugfs_remove_recursive(ag->debug.debugfs_dir);
++}
++
++int ag71xx_debugfs_init(struct ag71xx *ag)
++{
++ struct device *dev = &ag->pdev->dev;
++
++ ag->debug.debugfs_dir = debugfs_create_dir(dev_name(dev),
++ ag71xx_debugfs_root);
++ if (!ag->debug.debugfs_dir) {
++ dev_err(dev, "unable to create debugfs directory\n");
++ return -ENOENT;
++ }
++
++ debugfs_create_file("int_stats", S_IRUGO, ag->debug.debugfs_dir,
++ ag, &ag71xx_fops_int_stats);
++ debugfs_create_file("napi_stats", S_IRUGO, ag->debug.debugfs_dir,
++ ag, &ag71xx_fops_napi_stats);
++ debugfs_create_file("tx_ring", S_IRUGO, ag->debug.debugfs_dir,
++ ag, &ag71xx_fops_tx_ring);
++ debugfs_create_file("rx_ring", S_IRUGO, ag->debug.debugfs_dir,
++ ag, &ag71xx_fops_rx_ring);
++
++ return 0;
++}
++
++int ag71xx_debugfs_root_init(void)
++{
++ if (ag71xx_debugfs_root)
++ return -EBUSY;
++
++ ag71xx_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
++ if (!ag71xx_debugfs_root)
++ return -ENOENT;
++
++ return 0;
++}
++
++void ag71xx_debugfs_root_exit(void)
++{
++ debugfs_remove(ag71xx_debugfs_root);
++ ag71xx_debugfs_root = NULL;
++}
+diff --git a/drivers/net/ethernet/atheros/ag71xx/ag71xx_ethtool.c b/drivers/net/ethernet/atheros/ag71xx/ag71xx_ethtool.c
+new file mode 100644
+index 0000000..498fbed
+--- /dev/null
++++ b/drivers/net/ethernet/atheros/ag71xx/ag71xx_ethtool.c
+@@ -0,0 +1,124 @@
++/*
++ * Atheros AR71xx built-in ethernet mac driver
++ *
++ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Based on Atheros' AG7100 driver
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include "ag71xx.h"
++
++static int ag71xx_ethtool_get_settings(struct net_device *dev,
++ struct ethtool_cmd *cmd)
++{
++ struct ag71xx *ag = netdev_priv(dev);
++ struct phy_device *phydev = ag->phy_dev;
++
++ if (!phydev)
++ return -ENODEV;
++
++ return phy_ethtool_gset(phydev, cmd);
++}
++
++static int ag71xx_ethtool_set_settings(struct net_device *dev,
++ struct ethtool_cmd *cmd)
++{
++ struct ag71xx *ag = netdev_priv(dev);
++ struct phy_device *phydev = ag->phy_dev;
++
++ if (!phydev)
++ return -ENODEV;
++
++ return phy_ethtool_sset(phydev, cmd);
++}
++
++static void ag71xx_ethtool_get_drvinfo(struct net_device *dev,
++ struct ethtool_drvinfo *info)
++{
++ struct ag71xx *ag = netdev_priv(dev);
++
++ strcpy(info->driver, ag->pdev->dev.driver->name);
++ strcpy(info->version, AG71XX_DRV_VERSION);
++ strcpy(info->bus_info, dev_name(&ag->pdev->dev));
++}
++
++static u32 ag71xx_ethtool_get_msglevel(struct net_device *dev)
++{
++ struct ag71xx *ag = netdev_priv(dev);
++
++ return ag->msg_enable;
++}
++
++static void ag71xx_ethtool_set_msglevel(struct net_device *dev, u32 msg_level)
++{
++ struct ag71xx *ag = netdev_priv(dev);
++
++ ag->msg_enable = msg_level;
++}
++
++static void ag71xx_ethtool_get_ringparam(struct net_device *dev,
++ struct ethtool_ringparam *er)
++{
++ struct ag71xx *ag = netdev_priv(dev);
++
++ er->tx_max_pending = AG71XX_TX_RING_SIZE_MAX;
++ er->rx_max_pending = AG71XX_RX_RING_SIZE_MAX;
++ er->rx_mini_max_pending = 0;
++ er->rx_jumbo_max_pending = 0;
++
++ er->tx_pending = ag->tx_ring.size;
++ er->rx_pending = ag->rx_ring.size;
++ er->rx_mini_pending = 0;
++ er->rx_jumbo_pending = 0;
++}
++
++static int ag71xx_ethtool_set_ringparam(struct net_device *dev,
++ struct ethtool_ringparam *er)
++{
++ struct ag71xx *ag = netdev_priv(dev);
++ unsigned tx_size;
++ unsigned rx_size;
++ int err;
++
++ if (er->rx_mini_pending != 0||
++ er->rx_jumbo_pending != 0 ||
++ er->rx_pending == 0 ||
++ er->tx_pending == 0)
++ return -EINVAL;
++
++ tx_size = er->tx_pending < AG71XX_TX_RING_SIZE_MAX ?
++ er->tx_pending : AG71XX_TX_RING_SIZE_MAX;
++
++ rx_size = er->rx_pending < AG71XX_RX_RING_SIZE_MAX ?
++ er->rx_pending : AG71XX_RX_RING_SIZE_MAX;
++
++ if (netif_running(dev)) {
++ err = dev->netdev_ops->ndo_stop(dev);
++ if (err)
++ return err;
++ }
++
++ ag->tx_ring.size = tx_size;
++ ag->rx_ring.size = rx_size;
++
++ if (netif_running(dev))
++ err = dev->netdev_ops->ndo_open(dev);
++
++ return err;
++}
++
++struct ethtool_ops ag71xx_ethtool_ops = {
++ .set_settings = ag71xx_ethtool_set_settings,
++ .get_settings = ag71xx_ethtool_get_settings,
++ .get_drvinfo = ag71xx_ethtool_get_drvinfo,
++ .get_msglevel = ag71xx_ethtool_get_msglevel,
++ .set_msglevel = ag71xx_ethtool_set_msglevel,
++ .get_ringparam = ag71xx_ethtool_get_ringparam,
++ .set_ringparam = ag71xx_ethtool_set_ringparam,
++ .get_link = ethtool_op_get_link,
++};
+diff --git a/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c b/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c
+new file mode 100644
+index 0000000..d010373
+--- /dev/null
++++ b/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c
+@@ -0,0 +1,1325 @@
++/*
++ * Atheros AR71xx built-in ethernet mac driver
++ *
++ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Based on Atheros' AG7100 driver
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include "ag71xx.h"
++
++#define AG71XX_DEFAULT_MSG_ENABLE \
++ (NETIF_MSG_DRV \
++ | NETIF_MSG_PROBE \
++ | NETIF_MSG_LINK \
++ | NETIF_MSG_TIMER \
++ | NETIF_MSG_IFDOWN \
++ | NETIF_MSG_IFUP \
++ | NETIF_MSG_RX_ERR \
++ | NETIF_MSG_TX_ERR)
++
++static int ag71xx_msg_level = -1;
++
++module_param_named(msg_level, ag71xx_msg_level, int, 0);
++MODULE_PARM_DESC(msg_level, "Message level (-1=defaults,0=none,...,16=all)");
++
++#define ETH_SWITCH_HEADER_LEN 2
++
++static inline unsigned int ag71xx_max_frame_len(unsigned int mtu)
++{
++ return ETH_SWITCH_HEADER_LEN + ETH_HLEN + VLAN_HLEN + mtu + ETH_FCS_LEN;
++}
++
++static void ag71xx_dump_dma_regs(struct ag71xx *ag)
++{
++ DBG("%s: dma_tx_ctrl=%08x, dma_tx_desc=%08x, dma_tx_status=%08x\n",
++ ag->dev->name,
++ ag71xx_rr(ag, AG71XX_REG_TX_CTRL),
++ ag71xx_rr(ag, AG71XX_REG_TX_DESC),
++ ag71xx_rr(ag, AG71XX_REG_TX_STATUS));
++
++ DBG("%s: dma_rx_ctrl=%08x, dma_rx_desc=%08x, dma_rx_status=%08x\n",
++ ag->dev->name,
++ ag71xx_rr(ag, AG71XX_REG_RX_CTRL),
++ ag71xx_rr(ag, AG71XX_REG_RX_DESC),
++ ag71xx_rr(ag, AG71XX_REG_RX_STATUS));
++}
++
++static void ag71xx_dump_regs(struct ag71xx *ag)
++{
++ DBG("%s: mac_cfg1=%08x, mac_cfg2=%08x, ipg=%08x, hdx=%08x, mfl=%08x\n",
++ ag->dev->name,
++ ag71xx_rr(ag, AG71XX_REG_MAC_CFG1),
++ ag71xx_rr(ag, AG71XX_REG_MAC_CFG2),
++ ag71xx_rr(ag, AG71XX_REG_MAC_IPG),
++ ag71xx_rr(ag, AG71XX_REG_MAC_HDX),
++ ag71xx_rr(ag, AG71XX_REG_MAC_MFL));
++ DBG("%s: mac_ifctl=%08x, mac_addr1=%08x, mac_addr2=%08x\n",
++ ag->dev->name,
++ ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL),
++ ag71xx_rr(ag, AG71XX_REG_MAC_ADDR1),
++ ag71xx_rr(ag, AG71XX_REG_MAC_ADDR2));
++ DBG("%s: fifo_cfg0=%08x, fifo_cfg1=%08x, fifo_cfg2=%08x\n",
++ ag->dev->name,
++ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG0),
++ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG1),
++ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG2));
++ DBG("%s: fifo_cfg3=%08x, fifo_cfg4=%08x, fifo_cfg5=%08x\n",
++ ag->dev->name,
++ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG3),
++ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG4),
++ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5));
++}
++
++static inline void ag71xx_dump_intr(struct ag71xx *ag, char *label, u32 intr)
++{
++ DBG("%s: %s intr=%08x %s%s%s%s%s%s\n",
++ ag->dev->name, label, intr,
++ (intr & AG71XX_INT_TX_PS) ? "TXPS " : "",
++ (intr & AG71XX_INT_TX_UR) ? "TXUR " : "",
++ (intr & AG71XX_INT_TX_BE) ? "TXBE " : "",
++ (intr & AG71XX_INT_RX_PR) ? "RXPR " : "",
++ (intr & AG71XX_INT_RX_OF) ? "RXOF " : "",
++ (intr & AG71XX_INT_RX_BE) ? "RXBE " : "");
++}
++
++static void ag71xx_ring_free(struct ag71xx_ring *ring)
++{
++ kfree(ring->buf);
++
++ if (ring->descs_cpu)
++ dma_free_coherent(NULL, ring->size * ring->desc_size,
++ ring->descs_cpu, ring->descs_dma);
++}
++
++static int ag71xx_ring_alloc(struct ag71xx_ring *ring)
++{
++ int err;
++ int i;
++
++ ring->desc_size = sizeof(struct ag71xx_desc);
++ if (ring->desc_size % cache_line_size()) {
++ DBG("ag71xx: ring %p, desc size %u rounded to %u\n",
++ ring, ring->desc_size,
++ roundup(ring->desc_size, cache_line_size()));
++ ring->desc_size = roundup(ring->desc_size, cache_line_size());
++ }
++
++ ring->descs_cpu = dma_alloc_coherent(NULL, ring->size * ring->desc_size,
++ &ring->descs_dma, GFP_ATOMIC);
++ if (!ring->descs_cpu) {
++ err = -ENOMEM;
++ goto err;
++ }
++
++
++ ring->buf = kzalloc(ring->size * sizeof(*ring->buf), GFP_KERNEL);
++ if (!ring->buf) {
++ err = -ENOMEM;
++ goto err;
++ }
++
++ for (i = 0; i < ring->size; i++) {
++ int idx = i * ring->desc_size;
++ ring->buf[i].desc = (struct ag71xx_desc *)&ring->descs_cpu[idx];
++ DBG("ag71xx: ring %p, desc %d at %p\n",
++ ring, i, ring->buf[i].desc);
++ }
++
++ return 0;
++
++err:
++ return err;
++}
++
++static void ag71xx_ring_tx_clean(struct ag71xx *ag)
++{
++ struct ag71xx_ring *ring = &ag->tx_ring;
++ struct net_device *dev = ag->dev;
++ u32 bytes_compl = 0, pkts_compl = 0;
++
++ while (ring->curr != ring->dirty) {
++ u32 i = ring->dirty % ring->size;
++
++ if (!ag71xx_desc_empty(ring->buf[i].desc)) {
++ ring->buf[i].desc->ctrl = 0;
++ dev->stats.tx_errors++;
++ }
++
++ if (ring->buf[i].skb) {
++ bytes_compl += ring->buf[i].len;
++ pkts_compl++;
++ dev_kfree_skb_any(ring->buf[i].skb);
++ }
++ ring->buf[i].skb = NULL;
++ ring->dirty++;
++ }
++
++ /* flush descriptors */
++ wmb();
++
++ netdev_completed_queue(dev, pkts_compl, bytes_compl);
++}
++
++static void ag71xx_ring_tx_init(struct ag71xx *ag)
++{
++ struct ag71xx_ring *ring = &ag->tx_ring;
++ int i;
++
++ for (i = 0; i < ring->size; i++) {
++ ring->buf[i].desc->next = (u32) (ring->descs_dma +
++ ring->desc_size * ((i + 1) % ring->size));
++
++ ring->buf[i].desc->ctrl = DESC_EMPTY;
++ ring->buf[i].skb = NULL;
++ }
++
++ /* flush descriptors */
++ wmb();
++
++ ring->curr = 0;
++ ring->dirty = 0;
++ netdev_reset_queue(ag->dev);
++}
++
++static void ag71xx_ring_rx_clean(struct ag71xx *ag)
++{
++ struct ag71xx_ring *ring = &ag->rx_ring;
++ int i;
++
++ if (!ring->buf)
++ return;
++
++ for (i = 0; i < ring->size; i++)
++ if (ring->buf[i].rx_buf) {
++ dma_unmap_single(&ag->dev->dev, ring->buf[i].dma_addr,
++ ag->rx_buf_size, DMA_FROM_DEVICE);
++ kfree(ring->buf[i].rx_buf);
++ }
++}
++
++static int ag71xx_buffer_offset(struct ag71xx *ag)
++{
++ int offset = NET_SKB_PAD;
++
++ /*
++ * On AR71xx/AR91xx packets must be 4-byte aligned.
++ *
++ * When using builtin AR8216 support, hardware adds a 2-byte header,
++ * so we don't need any extra alignment in that case.
++ */
++ if (!ag71xx_get_pdata(ag)->is_ar724x || ag71xx_has_ar8216(ag))
++ return offset;
++
++ return offset + NET_IP_ALIGN;
++}
++
++static bool ag71xx_fill_rx_buf(struct ag71xx *ag, struct ag71xx_buf *buf,
++ int offset)
++{
++ void *data;
++
++ data = kmalloc(ag->rx_buf_size +
++ SKB_DATA_ALIGN(sizeof(struct skb_shared_info)),
++ GFP_ATOMIC);
++ if (!data)
++ return false;
++
++ buf->rx_buf = data;
++ buf->dma_addr = dma_map_single(&ag->dev->dev, data, ag->rx_buf_size,
++ DMA_FROM_DEVICE);
++ buf->desc->data = (u32) buf->dma_addr + offset;
++ return true;
++}
++
++static int ag71xx_ring_rx_init(struct ag71xx *ag)
++{
++ struct ag71xx_ring *ring = &ag->rx_ring;
++ unsigned int i;
++ int ret;
++ int offset = ag71xx_buffer_offset(ag);
++
++ ret = 0;
++ for (i = 0; i < ring->size; i++) {
++ ring->buf[i].desc->next = (u32) (ring->descs_dma +
++ ring->desc_size * ((i + 1) % ring->size));
++
++ DBG("ag71xx: RX desc at %p, next is %08x\n",
++ ring->buf[i].desc,
++ ring->buf[i].desc->next);
++ }
++
++ for (i = 0; i < ring->size; i++) {
++ if (!ag71xx_fill_rx_buf(ag, &ring->buf[i], offset)) {
++ ret = -ENOMEM;
++ break;
++ }
++
++ ring->buf[i].desc->ctrl = DESC_EMPTY;
++ }
++
++ /* flush descriptors */
++ wmb();
++
++ ring->curr = 0;
++ ring->dirty = 0;
++
++ return ret;
++}
++
++static int ag71xx_ring_rx_refill(struct ag71xx *ag)
++{
++ struct ag71xx_ring *ring = &ag->rx_ring;
++ unsigned int count;
++ int offset = ag71xx_buffer_offset(ag);
++
++ count = 0;
++ for (; ring->curr - ring->dirty > 0; ring->dirty++) {
++ unsigned int i;
++
++ i = ring->dirty % ring->size;
++
++ if (!ring->buf[i].rx_buf &&
++ !ag71xx_fill_rx_buf(ag, &ring->buf[i], offset))
++ break;
++
++ ring->buf[i].desc->ctrl = DESC_EMPTY;
++ count++;
++ }
++
++ /* flush descriptors */
++ wmb();
++
++ DBG("%s: %u rx descriptors refilled\n", ag->dev->name, count);
++
++ return count;
++}
++
++static int ag71xx_rings_init(struct ag71xx *ag)
++{
++ int ret;
++
++ ret = ag71xx_ring_alloc(&ag->tx_ring);
++ if (ret)
++ return ret;
++
++ ag71xx_ring_tx_init(ag);
++
++ ret = ag71xx_ring_alloc(&ag->rx_ring);
++ if (ret)
++ return ret;
++
++ ret = ag71xx_ring_rx_init(ag);
++ return ret;
++}
++
++static void ag71xx_rings_cleanup(struct ag71xx *ag)
++{
++ ag71xx_ring_rx_clean(ag);
++ ag71xx_ring_free(&ag->rx_ring);
++
++ ag71xx_ring_tx_clean(ag);
++ netdev_reset_queue(ag->dev);
++ ag71xx_ring_free(&ag->tx_ring);
++}
++
++static unsigned char *ag71xx_speed_str(struct ag71xx *ag)
++{
++ switch (ag->speed) {
++ case SPEED_1000:
++ return "1000";
++ case SPEED_100:
++ return "100";
++ case SPEED_10:
++ return "10";
++ }
++
++ return "?";
++}
++
++static void ag71xx_hw_set_macaddr(struct ag71xx *ag, unsigned char *mac)
++{
++ u32 t;
++
++ t = (((u32) mac[5]) << 24) | (((u32) mac[4]) << 16)
++ | (((u32) mac[3]) << 8) | ((u32) mac[2]);
++
++ ag71xx_wr(ag, AG71XX_REG_MAC_ADDR1, t);
++
++ t = (((u32) mac[1]) << 24) | (((u32) mac[0]) << 16);
++ ag71xx_wr(ag, AG71XX_REG_MAC_ADDR2, t);
++}
++
++static void ag71xx_dma_reset(struct ag71xx *ag)
++{
++ u32 val;
++ int i;
++
++ ag71xx_dump_dma_regs(ag);
++
++ /* stop RX and TX */
++ ag71xx_wr(ag, AG71XX_REG_RX_CTRL, 0);
++ ag71xx_wr(ag, AG71XX_REG_TX_CTRL, 0);
++
++ /*
++ * give the hardware some time to really stop all rx/tx activity
++ * clearing the descriptors too early causes random memory corruption
++ */
++ mdelay(1);
++
++ /* clear descriptor addresses */
++ ag71xx_wr(ag, AG71XX_REG_TX_DESC, ag->stop_desc_dma);
++ ag71xx_wr(ag, AG71XX_REG_RX_DESC, ag->stop_desc_dma);
++
++ /* clear pending RX/TX interrupts */
++ for (i = 0; i < 256; i++) {
++ ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_PR);
++ ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_PS);
++ }
++
++ /* clear pending errors */
++ ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_BE | RX_STATUS_OF);
++ ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_BE | TX_STATUS_UR);
++
++ val = ag71xx_rr(ag, AG71XX_REG_RX_STATUS);
++ if (val)
++ pr_alert("%s: unable to clear DMA Rx status: %08x\n",
++ ag->dev->name, val);
++
++ val = ag71xx_rr(ag, AG71XX_REG_TX_STATUS);
++
++ /* mask out reserved bits */
++ val &= ~0xff000000;
++
++ if (val)
++ pr_alert("%s: unable to clear DMA Tx status: %08x\n",
++ ag->dev->name, val);
++
++ ag71xx_dump_dma_regs(ag);
++}
++
++#define MAC_CFG1_INIT (MAC_CFG1_RXE | MAC_CFG1_TXE | \
++ MAC_CFG1_SRX | MAC_CFG1_STX)
++
++#define FIFO_CFG0_INIT (FIFO_CFG0_ALL << FIFO_CFG0_ENABLE_SHIFT)
++
++#define FIFO_CFG4_INIT (FIFO_CFG4_DE | FIFO_CFG4_DV | FIFO_CFG4_FC | \
++ FIFO_CFG4_CE | FIFO_CFG4_CR | FIFO_CFG4_LM | \
++ FIFO_CFG4_LO | FIFO_CFG4_OK | FIFO_CFG4_MC | \
++ FIFO_CFG4_BC | FIFO_CFG4_DR | FIFO_CFG4_LE | \
++ FIFO_CFG4_CF | FIFO_CFG4_PF | FIFO_CFG4_UO | \
++ FIFO_CFG4_VT)
++
++#define FIFO_CFG5_INIT (FIFO_CFG5_DE | FIFO_CFG5_DV | FIFO_CFG5_FC | \
++ FIFO_CFG5_CE | FIFO_CFG5_LO | FIFO_CFG5_OK | \
++ FIFO_CFG5_MC | FIFO_CFG5_BC | FIFO_CFG5_DR | \
++ FIFO_CFG5_CF | FIFO_CFG5_PF | FIFO_CFG5_VT | \
++ FIFO_CFG5_LE | FIFO_CFG5_FT | FIFO_CFG5_16 | \
++ FIFO_CFG5_17 | FIFO_CFG5_SF)
++
++static void ag71xx_hw_stop(struct ag71xx *ag)
++{
++ /* disable all interrupts and stop the rx/tx engine */
++ ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, 0);
++ ag71xx_wr(ag, AG71XX_REG_RX_CTRL, 0);
++ ag71xx_wr(ag, AG71XX_REG_TX_CTRL, 0);
++}
++
++static void ag71xx_hw_setup(struct ag71xx *ag)
++{
++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++
++ /* setup MAC configuration registers */
++ ag71xx_wr(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_INIT);
++
++ ag71xx_sb(ag, AG71XX_REG_MAC_CFG2,
++ MAC_CFG2_PAD_CRC_EN | MAC_CFG2_LEN_CHECK);
++
++ /* setup max frame length to zero */
++ ag71xx_wr(ag, AG71XX_REG_MAC_MFL, 0);
++
++ /* setup FIFO configuration registers */
++ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG0, FIFO_CFG0_INIT);
++ if (pdata->is_ar724x) {
++ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG1, pdata->fifo_cfg1);
++ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG2, pdata->fifo_cfg2);
++ } else {
++ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG1, 0x0fff0000);
++ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG2, 0x00001fff);
++ }
++ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG4, FIFO_CFG4_INIT);
++ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, FIFO_CFG5_INIT);
++}
++
++static void ag71xx_hw_init(struct ag71xx *ag)
++{
++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++ u32 reset_mask = pdata->reset_bit;
++
++ ag71xx_hw_stop(ag);
++
++ if (pdata->is_ar724x) {
++ u32 reset_phy = reset_mask;
++
++ reset_phy &= AR71XX_RESET_GE0_PHY | AR71XX_RESET_GE1_PHY;
++ reset_mask &= ~(AR71XX_RESET_GE0_PHY | AR71XX_RESET_GE1_PHY);
++
++ ath79_device_reset_set(reset_phy);
++ mdelay(50);
++ ath79_device_reset_clear(reset_phy);
++ mdelay(200);
++ }
++
++ ag71xx_sb(ag, AG71XX_REG_MAC_CFG1, MAC_CFG1_SR);
++ udelay(20);
++
++ ath79_device_reset_set(reset_mask);
++ mdelay(100);
++ ath79_device_reset_clear(reset_mask);
++ mdelay(200);
++
++ ag71xx_hw_setup(ag);
++
++ ag71xx_dma_reset(ag);
++}
++
++static void ag71xx_fast_reset(struct ag71xx *ag)
++{
++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++ struct net_device *dev = ag->dev;
++ u32 reset_mask = pdata->reset_bit;
++ u32 rx_ds, tx_ds;
++ u32 mii_reg;
++
++ reset_mask &= AR71XX_RESET_GE0_MAC | AR71XX_RESET_GE1_MAC;
++
++ mii_reg = ag71xx_rr(ag, AG71XX_REG_MII_CFG);
++ rx_ds = ag71xx_rr(ag, AG71XX_REG_RX_DESC);
++ tx_ds = ag71xx_rr(ag, AG71XX_REG_TX_DESC);
++
++ ath79_device_reset_set(reset_mask);
++ udelay(10);
++ ath79_device_reset_clear(reset_mask);
++ udelay(10);
++
++ ag71xx_dma_reset(ag);
++ ag71xx_hw_setup(ag);
++
++ /* setup max frame length */
++ ag71xx_wr(ag, AG71XX_REG_MAC_MFL,
++ ag71xx_max_frame_len(ag->dev->mtu));
++
++ ag71xx_wr(ag, AG71XX_REG_RX_DESC, rx_ds);
++ ag71xx_wr(ag, AG71XX_REG_TX_DESC, tx_ds);
++ ag71xx_wr(ag, AG71XX_REG_MII_CFG, mii_reg);
++
++ ag71xx_hw_set_macaddr(ag, dev->dev_addr);
++}
++
++static void ag71xx_hw_start(struct ag71xx *ag)
++{
++ /* start RX engine */
++ ag71xx_wr(ag, AG71XX_REG_RX_CTRL, RX_CTRL_RXE);
++
++ /* enable interrupts */
++ ag71xx_wr(ag, AG71XX_REG_INT_ENABLE, AG71XX_INT_INIT);
++}
++
++void ag71xx_link_adjust(struct ag71xx *ag)
++{
++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++ u32 cfg2;
++ u32 ifctl;
++ u32 fifo5;
++
++ if (!ag->link) {
++ ag71xx_hw_stop(ag);
++ netif_carrier_off(ag->dev);
++ if (netif_msg_link(ag))
++ pr_info("%s: link down\n", ag->dev->name);
++ return;
++ }
++
++ if (pdata->is_ar724x)
++ ag71xx_fast_reset(ag);
++
++ cfg2 = ag71xx_rr(ag, AG71XX_REG_MAC_CFG2);
++ cfg2 &= ~(MAC_CFG2_IF_1000 | MAC_CFG2_IF_10_100 | MAC_CFG2_FDX);
++ cfg2 |= (ag->duplex) ? MAC_CFG2_FDX : 0;
++
++ ifctl = ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL);
++ ifctl &= ~(MAC_IFCTL_SPEED);
++
++ fifo5 = ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5);
++ fifo5 &= ~FIFO_CFG5_BM;
++
++ switch (ag->speed) {
++ case SPEED_1000:
++ cfg2 |= MAC_CFG2_IF_1000;
++ fifo5 |= FIFO_CFG5_BM;
++ break;
++ case SPEED_100:
++ cfg2 |= MAC_CFG2_IF_10_100;
++ ifctl |= MAC_IFCTL_SPEED;
++ break;
++ case SPEED_10:
++ cfg2 |= MAC_CFG2_IF_10_100;
++ break;
++ default:
++ BUG();
++ return;
++ }
++
++ if (pdata->is_ar91xx)
++ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, 0x00780fff);
++ else if (pdata->is_ar724x)
++ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, pdata->fifo_cfg3);
++ else
++ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG3, 0x008001ff);
++
++ if (pdata->set_speed)
++ pdata->set_speed(ag->speed);
++
++ ag71xx_wr(ag, AG71XX_REG_MAC_CFG2, cfg2);
++ ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, fifo5);
++ ag71xx_wr(ag, AG71XX_REG_MAC_IFCTL, ifctl);
++ ag71xx_hw_start(ag);
++
++ netif_carrier_on(ag->dev);
++ if (netif_msg_link(ag))
++ pr_info("%s: link up (%sMbps/%s duplex)\n",
++ ag->dev->name,
++ ag71xx_speed_str(ag),
++ (DUPLEX_FULL == ag->duplex) ? "Full" : "Half");
++
++ DBG("%s: fifo_cfg0=%#x, fifo_cfg1=%#x, fifo_cfg2=%#x\n",
++ ag->dev->name,
++ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG0),
++ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG1),
++ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG2));
++
++ DBG("%s: fifo_cfg3=%#x, fifo_cfg4=%#x, fifo_cfg5=%#x\n",
++ ag->dev->name,
++ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG3),
++ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG4),
++ ag71xx_rr(ag, AG71XX_REG_FIFO_CFG5));
++
++ DBG("%s: mac_cfg2=%#x, mac_ifctl=%#x\n",
++ ag->dev->name,
++ ag71xx_rr(ag, AG71XX_REG_MAC_CFG2),
++ ag71xx_rr(ag, AG71XX_REG_MAC_IFCTL));
++}
++
++static int ag71xx_open(struct net_device *dev)
++{
++ struct ag71xx *ag = netdev_priv(dev);
++ unsigned int max_frame_len;
++ int ret;
++
++ max_frame_len = ag71xx_max_frame_len(dev->mtu);
++ ag->rx_buf_size = max_frame_len + NET_SKB_PAD + NET_IP_ALIGN;
++
++ /* setup max frame length */
++ ag71xx_wr(ag, AG71XX_REG_MAC_MFL, max_frame_len);
++
++ ret = ag71xx_rings_init(ag);
++ if (ret)
++ goto err;
++
++ napi_enable(&ag->napi);
++
++ netif_carrier_off(dev);
++ ag71xx_phy_start(ag);
++
++ ag71xx_wr(ag, AG71XX_REG_TX_DESC, ag->tx_ring.descs_dma);
++ ag71xx_wr(ag, AG71XX_REG_RX_DESC, ag->rx_ring.descs_dma);
++
++ ag71xx_hw_set_macaddr(ag, dev->dev_addr);
++
++ netif_start_queue(dev);
++
++ return 0;
++
++err:
++ ag71xx_rings_cleanup(ag);
++ return ret;
++}
++
++static int ag71xx_stop(struct net_device *dev)
++{
++ struct ag71xx *ag = netdev_priv(dev);
++ unsigned long flags;
++
++ netif_carrier_off(dev);
++ ag71xx_phy_stop(ag);
++
++ spin_lock_irqsave(&ag->lock, flags);
++
++ netif_stop_queue(dev);
++
++ ag71xx_hw_stop(ag);
++ ag71xx_dma_reset(ag);
++
++ napi_disable(&ag->napi);
++ del_timer_sync(&ag->oom_timer);
++
++ spin_unlock_irqrestore(&ag->lock, flags);
++
++ ag71xx_rings_cleanup(ag);
++
++ return 0;
++}
++
++static netdev_tx_t ag71xx_hard_start_xmit(struct sk_buff *skb,
++ struct net_device *dev)
++{
++ struct ag71xx *ag = netdev_priv(dev);
++ struct ag71xx_ring *ring = &ag->tx_ring;
++ struct ag71xx_desc *desc;
++ dma_addr_t dma_addr;
++ int i;
++
++ i = ring->curr % ring->size;
++ desc = ring->buf[i].desc;
++
++ if (!ag71xx_desc_empty(desc))
++ goto err_drop;
++
++ if (ag71xx_has_ar8216(ag))
++ ag71xx_add_ar8216_header(ag, skb);
++
++ if (skb->len <= 0) {
++ DBG("%s: packet len is too small\n", ag->dev->name);
++ goto err_drop;
++ }
++
++ dma_addr = dma_map_single(&dev->dev, skb->data, skb->len,
++ DMA_TO_DEVICE);
++
++ netdev_sent_queue(dev, skb->len);
++ ring->buf[i].len = skb->len;
++ ring->buf[i].skb = skb;
++ ring->buf[i].timestamp = jiffies;
++
++ /* setup descriptor fields */
++ desc->data = (u32) dma_addr;
++ desc->ctrl = skb->len & ag->desc_pktlen_mask;
++
++ /* flush descriptor */
++ wmb();
++
++ ring->curr++;
++ if (ring->curr == (ring->dirty + ring->size)) {
++ DBG("%s: tx queue full\n", ag->dev->name);
++ netif_stop_queue(dev);
++ }
++
++ DBG("%s: packet injected into TX queue\n", ag->dev->name);
++
++ /* enable TX engine */
++ ag71xx_wr(ag, AG71XX_REG_TX_CTRL, TX_CTRL_TXE);
++
++ return NETDEV_TX_OK;
++
++err_drop:
++ dev->stats.tx_dropped++;
++
++ dev_kfree_skb(skb);
++ return NETDEV_TX_OK;
++}
++
++static int ag71xx_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
++{
++ struct ag71xx *ag = netdev_priv(dev);
++ int ret;
++
++ switch (cmd) {
++ case SIOCETHTOOL:
++ if (ag->phy_dev == NULL)
++ break;
++
++ spin_lock_irq(&ag->lock);
++ ret = phy_ethtool_ioctl(ag->phy_dev, (void *) ifr->ifr_data);
++ spin_unlock_irq(&ag->lock);
++ return ret;
++
++ case SIOCSIFHWADDR:
++ if (copy_from_user
++ (dev->dev_addr, ifr->ifr_data, sizeof(dev->dev_addr)))
++ return -EFAULT;
++ return 0;
++
++ case SIOCGIFHWADDR:
++ if (copy_to_user
++ (ifr->ifr_data, dev->dev_addr, sizeof(dev->dev_addr)))
++ return -EFAULT;
++ return 0;
++
++ case SIOCGMIIPHY:
++ case SIOCGMIIREG:
++ case SIOCSMIIREG:
++ if (ag->phy_dev == NULL)
++ break;
++
++ return phy_mii_ioctl(ag->phy_dev, ifr, cmd);
++
++ default:
++ break;
++ }
++
++ return -EOPNOTSUPP;
++}
++
++static void ag71xx_oom_timer_handler(unsigned long data)
++{
++ struct net_device *dev = (struct net_device *) data;
++ struct ag71xx *ag = netdev_priv(dev);
++
++ napi_schedule(&ag->napi);
++}
++
++static void ag71xx_tx_timeout(struct net_device *dev)
++{
++ struct ag71xx *ag = netdev_priv(dev);
++
++ if (netif_msg_tx_err(ag))
++ pr_info("%s: tx timeout\n", ag->dev->name);
++
++ schedule_work(&ag->restart_work);
++}
++
++static void ag71xx_restart_work_func(struct work_struct *work)
++{
++ struct ag71xx *ag = container_of(work, struct ag71xx, restart_work);
++
++ if (ag71xx_get_pdata(ag)->is_ar724x) {
++ ag->link = 0;
++ ag71xx_link_adjust(ag);
++ return;
++ }
++
++ ag71xx_stop(ag->dev);
++ ag71xx_open(ag->dev);
++}
++
++static bool ag71xx_check_dma_stuck(struct ag71xx *ag, unsigned long timestamp)
++{
++ u32 rx_sm, tx_sm, rx_fd;
++
++ if (likely(time_before(jiffies, timestamp + HZ/10)))
++ return false;
++
++ if (!netif_carrier_ok(ag->dev))
++ return false;
++
++ rx_sm = ag71xx_rr(ag, AG71XX_REG_RX_SM);
++ if ((rx_sm & 0x7) == 0x3 && ((rx_sm >> 4) & 0x7) == 0x6)
++ return true;
++
++ tx_sm = ag71xx_rr(ag, AG71XX_REG_TX_SM);
++ rx_fd = ag71xx_rr(ag, AG71XX_REG_FIFO_DEPTH);
++ if (((tx_sm >> 4) & 0x7) == 0 && ((rx_sm & 0x7) == 0) &&
++ ((rx_sm >> 4) & 0x7) == 0 && rx_fd == 0)
++ return true;
++
++ return false;
++}
++
++static int ag71xx_tx_packets(struct ag71xx *ag)
++{
++ struct ag71xx_ring *ring = &ag->tx_ring;
++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++ int sent = 0;
++ int bytes_compl = 0;
++
++ DBG("%s: processing TX ring\n", ag->dev->name);
++
++ while (ring->dirty != ring->curr) {
++ unsigned int i = ring->dirty % ring->size;
++ struct ag71xx_desc *desc = ring->buf[i].desc;
++ struct sk_buff *skb = ring->buf[i].skb;
++ int len = ring->buf[i].len;
++
++ if (!ag71xx_desc_empty(desc)) {
++ if (pdata->is_ar7240 &&
++ ag71xx_check_dma_stuck(ag, ring->buf[i].timestamp))
++ schedule_work(&ag->restart_work);
++ break;
++ }
++
++ ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_PS);
++
++ bytes_compl += len;
++ ag->dev->stats.tx_bytes += len;
++ ag->dev->stats.tx_packets++;
++
++ dev_kfree_skb_any(skb);
++ ring->buf[i].skb = NULL;
++
++ ring->dirty++;
++ sent++;
++ }
++
++ DBG("%s: %d packets sent out\n", ag->dev->name, sent);
++
++ if (!sent)
++ return 0;
++
++ netdev_completed_queue(ag->dev, sent, bytes_compl);
++ if ((ring->curr - ring->dirty) < (ring->size * 3) / 4)
++ netif_wake_queue(ag->dev);
++
++ return sent;
++}
++
++static int ag71xx_rx_packets(struct ag71xx *ag, int limit)
++{
++ struct net_device *dev = ag->dev;
++ struct ag71xx_ring *ring = &ag->rx_ring;
++ int offset = ag71xx_buffer_offset(ag);
++ unsigned int pktlen_mask = ag->desc_pktlen_mask;
++ int done = 0;
++
++ DBG("%s: rx packets, limit=%d, curr=%u, dirty=%u\n",
++ dev->name, limit, ring->curr, ring->dirty);
++
++ while (done < limit) {
++ unsigned int i = ring->curr % ring->size;
++ struct ag71xx_desc *desc = ring->buf[i].desc;
++ struct sk_buff *skb;
++ int pktlen;
++ int err = 0;
++
++ if (ag71xx_desc_empty(desc))
++ break;
++
++ if ((ring->dirty + ring->size) == ring->curr) {
++ ag71xx_assert(0);
++ break;
++ }
++
++ ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_PR);
++
++ pktlen = desc->ctrl & pktlen_mask;
++ pktlen -= ETH_FCS_LEN;
++
++ dma_unmap_single(&dev->dev, ring->buf[i].dma_addr,
++ ag->rx_buf_size, DMA_FROM_DEVICE);
++
++ dev->stats.rx_packets++;
++ dev->stats.rx_bytes += pktlen;
++
++ skb = build_skb(ring->buf[i].rx_buf, 0);
++ if (!skb) {
++ kfree(ring->buf[i].rx_buf);
++ goto next;
++ }
++
++ skb_reserve(skb, offset);
++ skb_put(skb, pktlen);
++
++ if (ag71xx_has_ar8216(ag))
++ err = ag71xx_remove_ar8216_header(ag, skb, pktlen);
++
++ if (err) {
++ dev->stats.rx_dropped++;
++ kfree_skb(skb);
++ } else {
++ skb->dev = dev;
++ skb->ip_summed = CHECKSUM_NONE;
++ skb->protocol = eth_type_trans(skb, dev);
++ netif_receive_skb(skb);
++ }
++
++next:
++ ring->buf[i].rx_buf = NULL;
++ done++;
++
++ ring->curr++;
++ }
++
++ ag71xx_ring_rx_refill(ag);
++
++ DBG("%s: rx finish, curr=%u, dirty=%u, done=%d\n",
++ dev->name, ring->curr, ring->dirty, done);
++
++ return done;
++}
++
++static int ag71xx_poll(struct napi_struct *napi, int limit)
++{
++ struct ag71xx *ag = container_of(napi, struct ag71xx, napi);
++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++ struct net_device *dev = ag->dev;
++ struct ag71xx_ring *rx_ring;
++ unsigned long flags;
++ u32 status;
++ int tx_done;
++ int rx_done;
++
++ pdata->ddr_flush();
++ tx_done = ag71xx_tx_packets(ag);
++
++ DBG("%s: processing RX ring\n", dev->name);
++ rx_done = ag71xx_rx_packets(ag, limit);
++
++ ag71xx_debugfs_update_napi_stats(ag, rx_done, tx_done);
++
++ rx_ring = &ag->rx_ring;
++ if (rx_ring->buf[rx_ring->dirty % rx_ring->size].rx_buf == NULL)
++ goto oom;
++
++ status = ag71xx_rr(ag, AG71XX_REG_RX_STATUS);
++ if (unlikely(status & RX_STATUS_OF)) {
++ ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_OF);
++ dev->stats.rx_fifo_errors++;
++
++ /* restart RX */
++ ag71xx_wr(ag, AG71XX_REG_RX_CTRL, RX_CTRL_RXE);
++ }
++
++ if (rx_done < limit) {
++ if (status & RX_STATUS_PR)
++ goto more;
++
++ status = ag71xx_rr(ag, AG71XX_REG_TX_STATUS);
++ if (status & TX_STATUS_PS)
++ goto more;
++
++ DBG("%s: disable polling mode, rx=%d, tx=%d,limit=%d\n",
++ dev->name, rx_done, tx_done, limit);
++
++ napi_complete(napi);
++
++ /* enable interrupts */
++ spin_lock_irqsave(&ag->lock, flags);
++ ag71xx_int_enable(ag, AG71XX_INT_POLL);
++ spin_unlock_irqrestore(&ag->lock, flags);
++ return rx_done;
++ }
++
++more:
++ DBG("%s: stay in polling mode, rx=%d, tx=%d, limit=%d\n",
++ dev->name, rx_done, tx_done, limit);
++ return rx_done;
++
++oom:
++ if (netif_msg_rx_err(ag))
++ pr_info("%s: out of memory\n", dev->name);
++
++ mod_timer(&ag->oom_timer, jiffies + AG71XX_OOM_REFILL);
++ napi_complete(napi);
++ return 0;
++}
++
++static irqreturn_t ag71xx_interrupt(int irq, void *dev_id)
++{
++ struct net_device *dev = dev_id;
++ struct ag71xx *ag = netdev_priv(dev);
++ u32 status;
++
++ status = ag71xx_rr(ag, AG71XX_REG_INT_STATUS);
++ ag71xx_dump_intr(ag, "raw", status);
++
++ if (unlikely(!status))
++ return IRQ_NONE;
++
++ if (unlikely(status & AG71XX_INT_ERR)) {
++ if (status & AG71XX_INT_TX_BE) {
++ ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_BE);
++ dev_err(&dev->dev, "TX BUS error\n");
++ }
++ if (status & AG71XX_INT_RX_BE) {
++ ag71xx_wr(ag, AG71XX_REG_RX_STATUS, RX_STATUS_BE);
++ dev_err(&dev->dev, "RX BUS error\n");
++ }
++ }
++
++ if (likely(status & AG71XX_INT_POLL)) {
++ ag71xx_int_disable(ag, AG71XX_INT_POLL);
++ DBG("%s: enable polling mode\n", dev->name);
++ napi_schedule(&ag->napi);
++ }
++
++ ag71xx_debugfs_update_int_stats(ag, status);
++
++ return IRQ_HANDLED;
++}
++
++#ifdef CONFIG_NET_POLL_CONTROLLER
++/*
++ * Polling 'interrupt' - used by things like netconsole to send skbs
++ * without having to re-enable interrupts. It's not called while
++ * the interrupt routine is executing.
++ */
++static void ag71xx_netpoll(struct net_device *dev)
++{
++ disable_irq(dev->irq);
++ ag71xx_interrupt(dev->irq, dev);
++ enable_irq(dev->irq);
++}
++#endif
++
++static int ag71xx_change_mtu(struct net_device *dev, int new_mtu)
++{
++ struct ag71xx *ag = netdev_priv(dev);
++ unsigned int max_frame_len;
++
++ max_frame_len = ag71xx_max_frame_len(new_mtu);
++ if (new_mtu < 68 || max_frame_len > ag->max_frame_len)
++ return -EINVAL;
++
++ if (netif_running(dev))
++ return -EBUSY;
++
++ dev->mtu = new_mtu;
++ return 0;
++}
++
++static const struct net_device_ops ag71xx_netdev_ops = {
++ .ndo_open = ag71xx_open,
++ .ndo_stop = ag71xx_stop,
++ .ndo_start_xmit = ag71xx_hard_start_xmit,
++ .ndo_do_ioctl = ag71xx_do_ioctl,
++ .ndo_tx_timeout = ag71xx_tx_timeout,
++ .ndo_change_mtu = ag71xx_change_mtu,
++ .ndo_set_mac_address = eth_mac_addr,
++ .ndo_validate_addr = eth_validate_addr,
++#ifdef CONFIG_NET_POLL_CONTROLLER
++ .ndo_poll_controller = ag71xx_netpoll,
++#endif
++};
++
++static const char *ag71xx_get_phy_if_mode_name(phy_interface_t mode)
++{
++ switch (mode) {
++ case PHY_INTERFACE_MODE_MII:
++ return "MII";
++ case PHY_INTERFACE_MODE_GMII:
++ return "GMII";
++ case PHY_INTERFACE_MODE_RMII:
++ return "RMII";
++ case PHY_INTERFACE_MODE_RGMII:
++ return "RGMII";
++ case PHY_INTERFACE_MODE_SGMII:
++ return "SGMII";
++ default:
++ break;
++ }
++
++ return "unknown";
++}
++
++
++static int ag71xx_probe(struct platform_device *pdev)
++{
++ struct net_device *dev;
++ struct resource *res;
++ struct ag71xx *ag;
++ struct ag71xx_platform_data *pdata;
++ int err;
++
++ pdata = pdev->dev.platform_data;
++ if (!pdata) {
++ dev_err(&pdev->dev, "no platform data specified\n");
++ err = -ENXIO;
++ goto err_out;
++ }
++
++ if (pdata->mii_bus_dev == NULL && pdata->phy_mask) {
++ dev_err(&pdev->dev, "no MII bus device specified\n");
++ err = -EINVAL;
++ goto err_out;
++ }
++
++ dev = alloc_etherdev(sizeof(*ag));
++ if (!dev) {
++ dev_err(&pdev->dev, "alloc_etherdev failed\n");
++ err = -ENOMEM;
++ goto err_out;
++ }
++
++ if (!pdata->max_frame_len || !pdata->desc_pktlen_mask)
++ return -EINVAL;
++
++ SET_NETDEV_DEV(dev, &pdev->dev);
++
++ ag = netdev_priv(dev);
++ ag->pdev = pdev;
++ ag->dev = dev;
++ ag->msg_enable = netif_msg_init(ag71xx_msg_level,
++ AG71XX_DEFAULT_MSG_ENABLE);
++ spin_lock_init(&ag->lock);
++
++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mac_base");
++ if (!res) {
++ dev_err(&pdev->dev, "no mac_base resource found\n");
++ err = -ENXIO;
++ goto err_out;
++ }
++
++ ag->mac_base = ioremap_nocache(res->start, res->end - res->start + 1);
++ if (!ag->mac_base) {
++ dev_err(&pdev->dev, "unable to ioremap mac_base\n");
++ err = -ENOMEM;
++ goto err_free_dev;
++ }
++
++ dev->irq = platform_get_irq(pdev, 0);
++ err = request_irq(dev->irq, ag71xx_interrupt,
++ IRQF_DISABLED,
++ dev->name, dev);
++ if (err) {
++ dev_err(&pdev->dev, "unable to request IRQ %d\n", dev->irq);
++ goto err_unmap_base;
++ }
++
++ dev->base_addr = (unsigned long)ag->mac_base;
++ dev->netdev_ops = &ag71xx_netdev_ops;
++ dev->ethtool_ops = &ag71xx_ethtool_ops;
++
++ INIT_WORK(&ag->restart_work, ag71xx_restart_work_func);
++
++ init_timer(&ag->oom_timer);
++ ag->oom_timer.data = (unsigned long) dev;
++ ag->oom_timer.function = ag71xx_oom_timer_handler;
++
++ ag->tx_ring.size = AG71XX_TX_RING_SIZE_DEFAULT;
++ ag->rx_ring.size = AG71XX_RX_RING_SIZE_DEFAULT;
++
++ ag->max_frame_len = pdata->max_frame_len;
++ ag->desc_pktlen_mask = pdata->desc_pktlen_mask;
++
++ ag->stop_desc = dma_alloc_coherent(NULL,
++ sizeof(struct ag71xx_desc), &ag->stop_desc_dma, GFP_KERNEL);
++
++ if (!ag->stop_desc)
++ goto err_free_irq;
++
++ ag->stop_desc->data = 0;
++ ag->stop_desc->ctrl = 0;
++ ag->stop_desc->next = (u32) ag->stop_desc_dma;
++
++ memcpy(dev->dev_addr, pdata->mac_addr, ETH_ALEN);
++
++ netif_napi_add(dev, &ag->napi, ag71xx_poll, AG71XX_NAPI_WEIGHT);
++
++ ag71xx_dump_regs(ag);
++
++ ag71xx_hw_init(ag);
++
++ ag71xx_dump_regs(ag);
++
++ err = ag71xx_phy_connect(ag);
++ if (err)
++ goto err_free_desc;
++
++ err = ag71xx_debugfs_init(ag);
++ if (err)
++ goto err_phy_disconnect;
++
++ platform_set_drvdata(pdev, dev);
++
++ err = register_netdev(dev);
++ if (err) {
++ dev_err(&pdev->dev, "unable to register net device\n");
++ goto err_debugfs_exit;
++ }
++
++ pr_info("%s: Atheros AG71xx at 0x%08lx, irq %d, mode:%s\n",
++ dev->name, dev->base_addr, dev->irq,
++ ag71xx_get_phy_if_mode_name(pdata->phy_if_mode));
++
++ return 0;
++
++err_debugfs_exit:
++ ag71xx_debugfs_exit(ag);
++err_phy_disconnect:
++ ag71xx_phy_disconnect(ag);
++err_free_desc:
++ dma_free_coherent(NULL, sizeof(struct ag71xx_desc), ag->stop_desc,
++ ag->stop_desc_dma);
++err_free_irq:
++ free_irq(dev->irq, dev);
++err_unmap_base:
++ iounmap(ag->mac_base);
++err_free_dev:
++ kfree(dev);
++err_out:
++ platform_set_drvdata(pdev, NULL);
++ return err;
++}
++
++static int ag71xx_remove(struct platform_device *pdev)
++{
++ struct net_device *dev = platform_get_drvdata(pdev);
++
++ if (dev) {
++ struct ag71xx *ag = netdev_priv(dev);
++
++ ag71xx_debugfs_exit(ag);
++ ag71xx_phy_disconnect(ag);
++ unregister_netdev(dev);
++ free_irq(dev->irq, dev);
++ iounmap(ag->mac_base);
++ kfree(dev);
++ platform_set_drvdata(pdev, NULL);
++ }
++
++ return 0;
++}
++
++static struct platform_driver ag71xx_driver = {
++ .probe = ag71xx_probe,
++ .remove = ag71xx_remove,
++ .driver = {
++ .name = AG71XX_DRV_NAME,
++ }
++};
++
++static int __init ag71xx_module_init(void)
++{
++ int ret;
++
++ ret = ag71xx_debugfs_root_init();
++ if (ret)
++ goto err_out;
++
++ ret = ag71xx_mdio_driver_init();
++ if (ret)
++ goto err_debugfs_exit;
++
++ ret = platform_driver_register(&ag71xx_driver);
++ if (ret)
++ goto err_mdio_exit;
++
++ return 0;
++
++err_mdio_exit:
++ ag71xx_mdio_driver_exit();
++err_debugfs_exit:
++ ag71xx_debugfs_root_exit();
++err_out:
++ return ret;
++}
++
++static void __exit ag71xx_module_exit(void)
++{
++ platform_driver_unregister(&ag71xx_driver);
++ ag71xx_mdio_driver_exit();
++ ag71xx_debugfs_root_exit();
++}
++
++module_init(ag71xx_module_init);
++module_exit(ag71xx_module_exit);
++
++MODULE_VERSION(AG71XX_DRV_VERSION);
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_AUTHOR("Imre Kaloz <kaloz@openwrt.org>");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:" AG71XX_DRV_NAME);
+diff --git a/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c b/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c
+new file mode 100644
+index 0000000..71ae825
+--- /dev/null
++++ b/drivers/net/ethernet/atheros/ag71xx/ag71xx_mdio.c
+@@ -0,0 +1,318 @@
++/*
++ * Atheros AR71xx built-in ethernet mac driver
++ *
++ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Based on Atheros' AG7100 driver
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include "ag71xx.h"
++
++#define AG71XX_MDIO_RETRY 1000
++#define AG71XX_MDIO_DELAY 5
++
++static inline void ag71xx_mdio_wr(struct ag71xx_mdio *am, unsigned reg,
++ u32 value)
++{
++ void __iomem *r;
++
++ r = am->mdio_base + reg;
++ __raw_writel(value, r);
++
++ /* flush write */
++ (void) __raw_readl(r);
++}
++
++static inline u32 ag71xx_mdio_rr(struct ag71xx_mdio *am, unsigned reg)
++{
++ return __raw_readl(am->mdio_base + reg);
++}
++
++static void ag71xx_mdio_dump_regs(struct ag71xx_mdio *am)
++{
++ DBG("%s: mii_cfg=%08x, mii_cmd=%08x, mii_addr=%08x\n",
++ am->mii_bus->name,
++ ag71xx_mdio_rr(am, AG71XX_REG_MII_CFG),
++ ag71xx_mdio_rr(am, AG71XX_REG_MII_CMD),
++ ag71xx_mdio_rr(am, AG71XX_REG_MII_ADDR));
++ DBG("%s: mii_ctrl=%08x, mii_status=%08x, mii_ind=%08x\n",
++ am->mii_bus->name,
++ ag71xx_mdio_rr(am, AG71XX_REG_MII_CTRL),
++ ag71xx_mdio_rr(am, AG71XX_REG_MII_STATUS),
++ ag71xx_mdio_rr(am, AG71XX_REG_MII_IND));
++}
++
++static int ag71xx_mdio_wait_busy(struct ag71xx_mdio *am)
++{
++ int i;
++
++ for (i = 0; i < AG71XX_MDIO_RETRY; i++) {
++ u32 busy;
++
++ udelay(AG71XX_MDIO_DELAY);
++
++ busy = ag71xx_mdio_rr(am, AG71XX_REG_MII_IND);
++ if (!busy)
++ return 0;
++
++ udelay(AG71XX_MDIO_DELAY);
++ }
++
++ pr_err("%s: MDIO operation timed out\n", am->mii_bus->name);
++
++ return -ETIMEDOUT;
++}
++
++int ag71xx_mdio_mii_read(struct ag71xx_mdio *am, int addr, int reg)
++{
++ int err;
++ int ret;
++
++ err = ag71xx_mdio_wait_busy(am);
++ if (err)
++ return 0xffff;
++
++ ag71xx_mdio_wr(am, AG71XX_REG_MII_CMD, MII_CMD_WRITE);
++ ag71xx_mdio_wr(am, AG71XX_REG_MII_ADDR,
++ ((addr & 0xff) << MII_ADDR_SHIFT) | (reg & 0xff));
++ ag71xx_mdio_wr(am, AG71XX_REG_MII_CMD, MII_CMD_READ);
++
++ err = ag71xx_mdio_wait_busy(am);
++ if (err)
++ return 0xffff;
++
++ ret = ag71xx_mdio_rr(am, AG71XX_REG_MII_STATUS) & 0xffff;
++ ag71xx_mdio_wr(am, AG71XX_REG_MII_CMD, MII_CMD_WRITE);
++
++ DBG("mii_read: addr=%04x, reg=%04x, value=%04x\n", addr, reg, ret);
++
++ return ret;
++}
++
++void ag71xx_mdio_mii_write(struct ag71xx_mdio *am, int addr, int reg, u16 val)
++{
++ DBG("mii_write: addr=%04x, reg=%04x, value=%04x\n", addr, reg, val);
++
++ ag71xx_mdio_wr(am, AG71XX_REG_MII_ADDR,
++ ((addr & 0xff) << MII_ADDR_SHIFT) | (reg & 0xff));
++ ag71xx_mdio_wr(am, AG71XX_REG_MII_CTRL, val);
++
++ ag71xx_mdio_wait_busy(am);
++}
++
++static const u32 ar71xx_mdio_div_table[] = {
++ 4, 4, 6, 8, 10, 14, 20, 28,
++};
++
++static const u32 ar7240_mdio_div_table[] = {
++ 2, 2, 4, 6, 8, 12, 18, 26, 32, 40, 48, 56, 62, 70, 78, 96,
++};
++
++static const u32 ar933x_mdio_div_table[] = {
++ 4, 4, 6, 8, 10, 14, 20, 28, 34, 42, 50, 58, 66, 74, 82, 98,
++};
++
++static int ag71xx_mdio_get_divider(struct ag71xx_mdio *am, u32 *div)
++{
++ unsigned long ref_clock, mdio_clock;
++ const u32 *table;
++ int ndivs;
++ int i;
++
++ ref_clock = am->pdata->ref_clock;
++ mdio_clock = am->pdata->mdio_clock;
++
++ if (!ref_clock || !mdio_clock)
++ return -EINVAL;
++
++ if (am->pdata->is_ar9330 || am->pdata->is_ar934x) {
++ table = ar933x_mdio_div_table;
++ ndivs = ARRAY_SIZE(ar933x_mdio_div_table);
++ } else if (am->pdata->is_ar7240) {
++ table = ar7240_mdio_div_table;
++ ndivs = ARRAY_SIZE(ar7240_mdio_div_table);
++ } else {
++ table = ar71xx_mdio_div_table;
++ ndivs = ARRAY_SIZE(ar71xx_mdio_div_table);
++ }
++
++ for (i = 0; i < ndivs; i++) {
++ unsigned long t;
++
++ t = ref_clock / table[i];
++ if (t <= mdio_clock) {
++ *div = i;
++ return 0;
++ }
++ }
++
++ dev_err(&am->mii_bus->dev, "no divider found for %lu/%lu\n",
++ ref_clock, mdio_clock);
++ return -ENOENT;
++}
++
++static int ag71xx_mdio_reset(struct mii_bus *bus)
++{
++ struct ag71xx_mdio *am = bus->priv;
++ u32 t;
++ int err;
++
++ err = ag71xx_mdio_get_divider(am, &t);
++ if (err) {
++ /* fallback */
++ if (am->pdata->is_ar7240)
++ t = MII_CFG_CLK_DIV_6;
++ else if (am->pdata->builtin_switch && !am->pdata->is_ar934x)
++ t = MII_CFG_CLK_DIV_10;
++ else if (!am->pdata->builtin_switch && am->pdata->is_ar934x)
++ t = MII_CFG_CLK_DIV_58;
++ else
++ t = MII_CFG_CLK_DIV_28;
++ }
++
++ ag71xx_mdio_wr(am, AG71XX_REG_MII_CFG, t | MII_CFG_RESET);
++ udelay(100);
++
++ ag71xx_mdio_wr(am, AG71XX_REG_MII_CFG, t);
++ udelay(100);
++
++ if (am->pdata->reset)
++ am->pdata->reset(bus);
++
++ return 0;
++}
++
++static int ag71xx_mdio_read(struct mii_bus *bus, int addr, int reg)
++{
++ struct ag71xx_mdio *am = bus->priv;
++
++ if (am->pdata->builtin_switch)
++ return ar7240sw_phy_read(bus, addr, reg);
++ else
++ return ag71xx_mdio_mii_read(am, addr, reg);
++}
++
++static int ag71xx_mdio_write(struct mii_bus *bus, int addr, int reg, u16 val)
++{
++ struct ag71xx_mdio *am = bus->priv;
++
++ if (am->pdata->builtin_switch)
++ ar7240sw_phy_write(bus, addr, reg, val);
++ else
++ ag71xx_mdio_mii_write(am, addr, reg, val);
++ return 0;
++}
++
++static int ag71xx_mdio_probe(struct platform_device *pdev)
++{
++ struct ag71xx_mdio_platform_data *pdata;
++ struct ag71xx_mdio *am;
++ struct resource *res;
++ int i;
++ int err;
++
++ pdata = pdev->dev.platform_data;
++ if (!pdata) {
++ dev_err(&pdev->dev, "no platform data specified\n");
++ return -EINVAL;
++ }
++
++ am = kzalloc(sizeof(*am), GFP_KERNEL);
++ if (!am) {
++ err = -ENOMEM;
++ goto err_out;
++ }
++
++ am->pdata = pdata;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res) {
++ dev_err(&pdev->dev, "no iomem resource found\n");
++ err = -ENXIO;
++ goto err_out;
++ }
++
++ am->mdio_base = ioremap_nocache(res->start, res->end - res->start + 1);
++ if (!am->mdio_base) {
++ dev_err(&pdev->dev, "unable to ioremap registers\n");
++ err = -ENOMEM;
++ goto err_free_mdio;
++ }
++
++ am->mii_bus = mdiobus_alloc();
++ if (am->mii_bus == NULL) {
++ err = -ENOMEM;
++ goto err_iounmap;
++ }
++
++ am->mii_bus->name = "ag71xx_mdio";
++ am->mii_bus->read = ag71xx_mdio_read;
++ am->mii_bus->write = ag71xx_mdio_write;
++ am->mii_bus->reset = ag71xx_mdio_reset;
++ am->mii_bus->irq = am->mii_irq;
++ am->mii_bus->priv = am;
++ am->mii_bus->parent = &pdev->dev;
++ snprintf(am->mii_bus->id, MII_BUS_ID_SIZE, "%s", dev_name(&pdev->dev));
++ am->mii_bus->phy_mask = pdata->phy_mask;
++
++ for (i = 0; i < PHY_MAX_ADDR; i++)
++ am->mii_irq[i] = PHY_POLL;
++
++ ag71xx_mdio_wr(am, AG71XX_REG_MAC_CFG1, 0);
++
++ err = mdiobus_register(am->mii_bus);
++ if (err)
++ goto err_free_bus;
++
++ ag71xx_mdio_dump_regs(am);
++
++ platform_set_drvdata(pdev, am);
++ return 0;
++
++err_free_bus:
++ mdiobus_free(am->mii_bus);
++err_iounmap:
++ iounmap(am->mdio_base);
++err_free_mdio:
++ kfree(am);
++err_out:
++ return err;
++}
++
++static int ag71xx_mdio_remove(struct platform_device *pdev)
++{
++ struct ag71xx_mdio *am = platform_get_drvdata(pdev);
++
++ if (am) {
++ mdiobus_unregister(am->mii_bus);
++ mdiobus_free(am->mii_bus);
++ iounmap(am->mdio_base);
++ kfree(am);
++ platform_set_drvdata(pdev, NULL);
++ }
++
++ return 0;
++}
++
++static struct platform_driver ag71xx_mdio_driver = {
++ .probe = ag71xx_mdio_probe,
++ .remove = ag71xx_mdio_remove,
++ .driver = {
++ .name = "ag71xx-mdio",
++ }
++};
++
++int __init ag71xx_mdio_driver_init(void)
++{
++ return platform_driver_register(&ag71xx_mdio_driver);
++}
++
++void ag71xx_mdio_driver_exit(void)
++{
++ platform_driver_unregister(&ag71xx_mdio_driver);
++}
+diff --git a/drivers/net/ethernet/atheros/ag71xx/ag71xx_phy.c b/drivers/net/ethernet/atheros/ag71xx/ag71xx_phy.c
+new file mode 100644
+index 0000000..9de77e9
+--- /dev/null
++++ b/drivers/net/ethernet/atheros/ag71xx/ag71xx_phy.c
+@@ -0,0 +1,235 @@
++/*
++ * Atheros AR71xx built-in ethernet mac driver
++ *
++ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Based on Atheros' AG7100 driver
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include "ag71xx.h"
++
++static void ag71xx_phy_link_adjust(struct net_device *dev)
++{
++ struct ag71xx *ag = netdev_priv(dev);
++ struct phy_device *phydev = ag->phy_dev;
++ unsigned long flags;
++ int status_change = 0;
++
++ spin_lock_irqsave(&ag->lock, flags);
++
++ if (phydev->link) {
++ if (ag->duplex != phydev->duplex
++ || ag->speed != phydev->speed) {
++ status_change = 1;
++ }
++ }
++
++ if (phydev->link != ag->link)
++ status_change = 1;
++
++ ag->link = phydev->link;
++ ag->duplex = phydev->duplex;
++ ag->speed = phydev->speed;
++
++ if (status_change)
++ ag71xx_link_adjust(ag);
++
++ spin_unlock_irqrestore(&ag->lock, flags);
++}
++
++void ag71xx_phy_start(struct ag71xx *ag)
++{
++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++
++ if (ag->phy_dev) {
++ phy_start(ag->phy_dev);
++ } else if (pdata->mii_bus_dev && pdata->switch_data) {
++ ag71xx_ar7240_start(ag);
++ } else {
++ ag->link = 1;
++ ag71xx_link_adjust(ag);
++ }
++}
++
++void ag71xx_phy_stop(struct ag71xx *ag)
++{
++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++ unsigned long flags;
++
++ if (ag->phy_dev)
++ phy_stop(ag->phy_dev);
++ else if (pdata->mii_bus_dev && pdata->switch_data)
++ ag71xx_ar7240_stop(ag);
++
++ spin_lock_irqsave(&ag->lock, flags);
++ if (ag->link) {
++ ag->link = 0;
++ ag71xx_link_adjust(ag);
++ }
++ spin_unlock_irqrestore(&ag->lock, flags);
++}
++
++static int ag71xx_phy_connect_fixed(struct ag71xx *ag)
++{
++ struct device *dev = &ag->pdev->dev;
++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++ int ret = 0;
++
++ /* use fixed settings */
++ switch (pdata->speed) {
++ case SPEED_10:
++ case SPEED_100:
++ case SPEED_1000:
++ break;
++ default:
++ dev_err(dev, "invalid speed specified\n");
++ ret = -EINVAL;
++ break;
++ }
++
++ dev_dbg(dev, "using fixed link parameters\n");
++
++ ag->duplex = pdata->duplex;
++ ag->speed = pdata->speed;
++
++ return ret;
++}
++
++static int ag71xx_phy_connect_multi(struct ag71xx *ag)
++{
++ struct device *dev = &ag->pdev->dev;
++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++ struct phy_device *phydev = NULL;
++ int phy_addr;
++ int ret = 0;
++
++ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
++ if (!(pdata->phy_mask & (1 << phy_addr)))
++ continue;
++
++ if (ag->mii_bus->phy_map[phy_addr] == NULL)
++ continue;
++
++ DBG("%s: PHY found at %s, uid=%08x\n",
++ dev_name(dev),
++ dev_name(&ag->mii_bus->phy_map[phy_addr]->dev),
++ ag->mii_bus->phy_map[phy_addr]->phy_id);
++
++ if (phydev == NULL)
++ phydev = ag->mii_bus->phy_map[phy_addr];
++ }
++
++ if (!phydev) {
++ dev_err(dev, "no PHY found with phy_mask=%08x\n",
++ pdata->phy_mask);
++ return -ENODEV;
++ }
++
++ ag->phy_dev = phy_connect(ag->dev, dev_name(&phydev->dev),
++ &ag71xx_phy_link_adjust,
++ pdata->phy_if_mode);
++
++ if (IS_ERR(ag->phy_dev)) {
++ dev_err(dev, "could not connect to PHY at %s\n",
++ dev_name(&phydev->dev));
++ return PTR_ERR(ag->phy_dev);
++ }
++
++ /* mask with MAC supported features */
++ if (pdata->has_gbit)
++ phydev->supported &= PHY_GBIT_FEATURES;
++ else
++ phydev->supported &= PHY_BASIC_FEATURES;
++
++ phydev->advertising = phydev->supported;
++
++ dev_info(dev, "connected to PHY at %s [uid=%08x, driver=%s]\n",
++ dev_name(&phydev->dev), phydev->phy_id, phydev->drv->name);
++
++ ag->link = 0;
++ ag->speed = 0;
++ ag->duplex = -1;
++
++ return ret;
++}
++
++static int dev_is_class(struct device *dev, void *class)
++{
++ if (dev->class != NULL && !strcmp(dev->class->name, class))
++ return 1;
++
++ return 0;
++}
++
++static struct device *dev_find_class(struct device *parent, char *class)
++{
++ if (dev_is_class(parent, class)) {
++ get_device(parent);
++ return parent;
++ }
++
++ return device_find_child(parent, class, dev_is_class);
++}
++
++static struct mii_bus *dev_to_mii_bus(struct device *dev)
++{
++ struct device *d;
++
++ d = dev_find_class(dev, "mdio_bus");
++ if (d != NULL) {
++ struct mii_bus *bus;
++
++ bus = to_mii_bus(d);
++ put_device(d);
++
++ return bus;
++ }
++
++ return NULL;
++}
++
++int ag71xx_phy_connect(struct ag71xx *ag)
++{
++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++
++ if (pdata->mii_bus_dev == NULL ||
++ pdata->mii_bus_dev->bus == NULL )
++ return ag71xx_phy_connect_fixed(ag);
++
++ ag->mii_bus = dev_to_mii_bus(pdata->mii_bus_dev);
++ if (ag->mii_bus == NULL) {
++ dev_err(&ag->pdev->dev, "unable to find MII bus on device '%s'\n",
++ dev_name(pdata->mii_bus_dev));
++ return -ENODEV;
++ }
++
++ /* Reset the mdio bus explicitly */
++ if (ag->mii_bus->reset) {
++ mutex_lock(&ag->mii_bus->mdio_lock);
++ ag->mii_bus->reset(ag->mii_bus);
++ mutex_unlock(&ag->mii_bus->mdio_lock);
++ }
++
++ if (pdata->switch_data)
++ return ag71xx_ar7240_init(ag);
++
++ if (pdata->phy_mask)
++ return ag71xx_phy_connect_multi(ag);
++
++ return ag71xx_phy_connect_fixed(ag);
++}
++
++void ag71xx_phy_disconnect(struct ag71xx *ag)
++{
++ struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag);
++
++ if (pdata->switch_data)
++ ag71xx_ar7240_cleanup(ag);
++ else if (ag->phy_dev)
++ phy_disconnect(ag->phy_dev);
++}
+--
+1.8.5.3
+
diff --git a/target/mips/dragino-ms14s/patches/3.14.17/0004-drivers-link-SPI-drivers-before-MTD-drivers.patch b/target/mips/dragino-ms14s/patches/3.14.17/0004-drivers-link-SPI-drivers-before-MTD-drivers.patch
new file mode 100644
index 000000000..824d6ebec
--- /dev/null
+++ b/target/mips/dragino-ms14s/patches/3.14.17/0004-drivers-link-SPI-drivers-before-MTD-drivers.patch
@@ -0,0 +1,27 @@
+From 3c367cc533d07353f60110340c110f6d622094b8 Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Tue, 13 May 2014 00:14:15 +0200
+Subject: [PATCH] drivers: link SPI drivers before MTD drivers
+
+This prevents probe deferral in SPI-driven MTD drivers.
+---
+ drivers/Makefile | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/Makefile b/drivers/Makefile
+index 8e3b8b0..61bbeb2 100644
+--- a/drivers/Makefile
++++ b/drivers/Makefile
+@@ -64,8 +64,8 @@ obj-$(CONFIG_IDE) += ide/
+ obj-$(CONFIG_SCSI) += scsi/
+ obj-$(CONFIG_ATA) += ata/
+ obj-$(CONFIG_TARGET_CORE) += target/
+-obj-$(CONFIG_MTD) += mtd/
+ obj-$(CONFIG_SPI) += spi/
++obj-$(CONFIG_MTD) += mtd/
+ obj-y += hsi/
+ obj-y += net/
+ obj-$(CONFIG_ATM) += atm/
+--
+1.8.5.3
+
diff --git a/target/mips/dragino-ms14s/patches/3.14.17/0005-spi-add-various-flags-to-spi_transfer-and-spi_messag.patch b/target/mips/dragino-ms14s/patches/3.14.17/0005-spi-add-various-flags-to-spi_transfer-and-spi_messag.patch
new file mode 100644
index 000000000..505562fe0
--- /dev/null
+++ b/target/mips/dragino-ms14s/patches/3.14.17/0005-spi-add-various-flags-to-spi_transfer-and-spi_messag.patch
@@ -0,0 +1,34 @@
+From 34dcc540e28cc2253fd3bdaacdd77faf1d42d759 Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Tue, 13 May 2014 00:17:06 +0200
+Subject: [PATCH] spi: add various flags to spi_transfer and spi_message
+ structs
+
+---
+ include/linux/spi/spi.h | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
+index 4203c66..4ee1a02 100644
+--- a/include/linux/spi/spi.h
++++ b/include/linux/spi/spi.h
+@@ -581,6 +581,8 @@ struct spi_transfer {
+ dma_addr_t rx_dma;
+
+ unsigned cs_change:1;
++ unsigned verify:1;
++ unsigned fast_write:1;
+ unsigned tx_nbits:3;
+ unsigned rx_nbits:3;
+ #define SPI_NBITS_SINGLE 0x01 /* 1bit transfer */
+@@ -627,6 +629,7 @@ struct spi_message {
+ struct spi_device *spi;
+
+ unsigned is_dma_mapped:1;
++ unsigned fast_read:1;
+
+ /* REVISIT: we might want a flag affecting the behavior of the
+ * last transfer ... allowing things like "read 16 bit length L"
+--
+1.8.5.3
+
diff --git a/target/mips/dragino-ms14s/patches/3.14.17/0006-spi-add-rb4xx-SPI-driver.patch b/target/mips/dragino-ms14s/patches/3.14.17/0006-spi-add-rb4xx-SPI-driver.patch
new file mode 100644
index 000000000..757dc775b
--- /dev/null
+++ b/target/mips/dragino-ms14s/patches/3.14.17/0006-spi-add-rb4xx-SPI-driver.patch
@@ -0,0 +1,557 @@
+From 97ffc04a7528abe1d84c069d99afb19704d50224 Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Tue, 13 May 2014 00:18:58 +0200
+Subject: [PATCH] spi: add rb4xx SPI driver
+
+---
+ drivers/spi/Kconfig | 6 +
+ drivers/spi/Makefile | 1 +
+ drivers/spi/spi-rb4xx.c | 507 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 514 insertions(+)
+ create mode 100644 drivers/spi/spi-rb4xx.c
+
+diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
+index 581ee2a..721f3a7 100644
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -381,6 +381,12 @@ config SPI_RSPI
+ help
+ SPI driver for Renesas RSPI and QSPI blocks.
+
++config SPI_RB4XX
++ tristate "Mikrotik RB4XX SPI master"
++ depends on SPI_MASTER && ATH79_MACH_RB4XX
++ help
++ SPI controller driver for the Mikrotik RB4xx series boards.
++
+ config SPI_S3C24XX
+ tristate "Samsung S3C24XX series SPI"
+ depends on ARCH_S3C24XX
+diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
+index 95af48d..e738c7a 100644
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -59,6 +59,7 @@ spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_PXADMA) += spi-pxa2xx-pxadma.o
+ spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_DMA) += spi-pxa2xx-dma.o
+ obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o
+ obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o
++obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o
+ obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
+ obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o
+ spi-s3c24xx-hw-y := spi-s3c24xx.o
+diff --git a/drivers/spi/spi-rb4xx.c b/drivers/spi/spi-rb4xx.c
+new file mode 100644
+index 0000000..56260ff
+--- /dev/null
++++ b/drivers/spi/spi-rb4xx.c
+@@ -0,0 +1,507 @@
++/*
++ * SPI controller driver for the Mikrotik RB4xx boards
++ *
++ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This file was based on the patches for Linux 2.6.27.39 published by
++ * MikroTik for their RouterBoard 4xx series devices.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/spinlock.h>
++#include <linux/workqueue.h>
++#include <linux/platform_device.h>
++#include <linux/spi/spi.h>
++
++#include <asm/mach-ath79/ar71xx_regs.h>
++#include <asm/mach-ath79/ath79.h>
++
++#define DRV_NAME "rb4xx-spi"
++#define DRV_DESC "Mikrotik RB4xx SPI controller driver"
++#define DRV_VERSION "0.1.0"
++
++#define SPI_CTRL_FASTEST 0x40
++#define SPI_FLASH_HZ 33333334
++#define SPI_CPLD_HZ 33333334
++
++#define CPLD_CMD_READ_FAST 0x0b
++
++#undef RB4XX_SPI_DEBUG
++
++struct rb4xx_spi {
++ void __iomem *base;
++ struct spi_master *master;
++
++ unsigned spi_ctrl_flash;
++ unsigned spi_ctrl_fread;
++
++ struct clk *ahb_clk;
++ unsigned long ahb_freq;
++
++ spinlock_t lock;
++ struct list_head queue;
++ int busy:1;
++ int cs_wait;
++};
++
++static unsigned spi_clk_low = AR71XX_SPI_IOC_CS1;
++
++#ifdef RB4XX_SPI_DEBUG
++static inline void do_spi_delay(void)
++{
++ ndelay(20000);
++}
++#else
++static inline void do_spi_delay(void) { }
++#endif
++
++static inline void do_spi_init(struct spi_device *spi)
++{
++ unsigned cs = AR71XX_SPI_IOC_CS0 | AR71XX_SPI_IOC_CS1;
++
++ if (!(spi->mode & SPI_CS_HIGH))
++ cs ^= (spi->chip_select == 2) ? AR71XX_SPI_IOC_CS1 :
++ AR71XX_SPI_IOC_CS0;
++
++ spi_clk_low = cs;
++}
++
++static inline void do_spi_finish(void __iomem *base)
++{
++ do_spi_delay();
++ __raw_writel(AR71XX_SPI_IOC_CS0 | AR71XX_SPI_IOC_CS1,
++ base + AR71XX_SPI_REG_IOC);
++}
++
++static inline void do_spi_clk(void __iomem *base, int bit)
++{
++ unsigned bval = spi_clk_low | ((bit & 1) ? AR71XX_SPI_IOC_DO : 0);
++
++ do_spi_delay();
++ __raw_writel(bval, base + AR71XX_SPI_REG_IOC);
++ do_spi_delay();
++ __raw_writel(bval | AR71XX_SPI_IOC_CLK, base + AR71XX_SPI_REG_IOC);
++}
++
++static void do_spi_byte(void __iomem *base, unsigned char byte)
++{
++ do_spi_clk(base, byte >> 7);
++ do_spi_clk(base, byte >> 6);
++ do_spi_clk(base, byte >> 5);
++ do_spi_clk(base, byte >> 4);
++ do_spi_clk(base, byte >> 3);
++ do_spi_clk(base, byte >> 2);
++ do_spi_clk(base, byte >> 1);
++ do_spi_clk(base, byte);
++
++ pr_debug("spi_byte sent 0x%02x got 0x%02x\n",
++ (unsigned)byte,
++ (unsigned char)__raw_readl(base + AR71XX_SPI_REG_RDS));
++}
++
++static inline void do_spi_clk_fast(void __iomem *base, unsigned bit1,
++ unsigned bit2)
++{
++ unsigned bval = (spi_clk_low |
++ ((bit1 & 1) ? AR71XX_SPI_IOC_DO : 0) |
++ ((bit2 & 1) ? AR71XX_SPI_IOC_CS2 : 0));
++ do_spi_delay();
++ __raw_writel(bval, base + AR71XX_SPI_REG_IOC);
++ do_spi_delay();
++ __raw_writel(bval | AR71XX_SPI_IOC_CLK, base + AR71XX_SPI_REG_IOC);
++}
++
++static void do_spi_byte_fast(void __iomem *base, unsigned char byte)
++{
++ do_spi_clk_fast(base, byte >> 7, byte >> 6);
++ do_spi_clk_fast(base, byte >> 5, byte >> 4);
++ do_spi_clk_fast(base, byte >> 3, byte >> 2);
++ do_spi_clk_fast(base, byte >> 1, byte >> 0);
++
++ pr_debug("spi_byte_fast sent 0x%02x got 0x%02x\n",
++ (unsigned)byte,
++ (unsigned char) __raw_readl(base + AR71XX_SPI_REG_RDS));
++}
++
++static int rb4xx_spi_txrx(void __iomem *base, struct spi_transfer *t)
++{
++ const unsigned char *rxv_ptr = NULL;
++ const unsigned char *tx_ptr = t->tx_buf;
++ unsigned char *rx_ptr = t->rx_buf;
++ unsigned i;
++
++ pr_debug("spi_txrx len %u tx %u rx %u\n",
++ t->len,
++ (t->tx_buf ? 1 : 0),
++ (t->rx_buf ? 1 : 0));
++
++ if (t->verify) {
++ rxv_ptr = tx_ptr;
++ tx_ptr = NULL;
++ }
++
++ for (i = 0; i < t->len; ++i) {
++ unsigned char sdata = tx_ptr ? tx_ptr[i] : 0;
++
++ if (t->fast_write)
++ do_spi_byte_fast(base, sdata);
++ else
++ do_spi_byte(base, sdata);
++
++ if (rx_ptr) {
++ rx_ptr[i] = __raw_readl(base + AR71XX_SPI_REG_RDS) & 0xff;
++ } else if (rxv_ptr) {
++ unsigned char c = __raw_readl(base + AR71XX_SPI_REG_RDS);
++ if (rxv_ptr[i] != c)
++ return i;
++ }
++ }
++
++ return i;
++}
++
++static int rb4xx_spi_read_fast(struct rb4xx_spi *rbspi,
++ struct spi_message *m)
++{
++ struct spi_transfer *t;
++ const unsigned char *tx_ptr;
++ unsigned addr;
++ void __iomem *base = rbspi->base;
++
++ /* check for exactly two transfers */
++ if (list_empty(&m->transfers) ||
++ list_is_last(m->transfers.next, &m->transfers) ||
++ !list_is_last(m->transfers.next->next, &m->transfers)) {
++ return -1;
++ }
++
++ /* first transfer contains command and address */
++ t = list_entry(m->transfers.next,
++ struct spi_transfer, transfer_list);
++
++ if (t->len != 5 || t->tx_buf == NULL)
++ return -1;
++
++ tx_ptr = t->tx_buf;
++ if (tx_ptr[0] != CPLD_CMD_READ_FAST)
++ return -1;
++
++ addr = tx_ptr[1];
++ addr = tx_ptr[2] | (addr << 8);
++ addr = tx_ptr[3] | (addr << 8);
++ addr += (unsigned) base;
++
++ m->actual_length += t->len;
++
++ /* second transfer contains data itself */
++ t = list_entry(m->transfers.next->next,
++ struct spi_transfer, transfer_list);
++
++ if (t->tx_buf && !t->verify)
++ return -1;
++
++ __raw_writel(AR71XX_SPI_FS_GPIO, base + AR71XX_SPI_REG_FS);
++ __raw_writel(rbspi->spi_ctrl_fread, base + AR71XX_SPI_REG_CTRL);
++ __raw_writel(0, base + AR71XX_SPI_REG_FS);
++
++ if (t->rx_buf) {
++ memcpy(t->rx_buf, (const void *)addr, t->len);
++ } else if (t->tx_buf) {
++ unsigned char buf[t->len];
++ memcpy(buf, (const void *)addr, t->len);
++ if (memcmp(t->tx_buf, buf, t->len) != 0)
++ m->status = -EMSGSIZE;
++ }
++ m->actual_length += t->len;
++
++ if (rbspi->spi_ctrl_flash != rbspi->spi_ctrl_fread) {
++ __raw_writel(AR71XX_SPI_FS_GPIO, base + AR71XX_SPI_REG_FS);
++ __raw_writel(rbspi->spi_ctrl_flash, base + AR71XX_SPI_REG_CTRL);
++ __raw_writel(0, base + AR71XX_SPI_REG_FS);
++ }
++
++ return 0;
++}
++
++static int rb4xx_spi_msg(struct rb4xx_spi *rbspi, struct spi_message *m)
++{
++ struct spi_transfer *t = NULL;
++ void __iomem *base = rbspi->base;
++
++ m->status = 0;
++ if (list_empty(&m->transfers))
++ return -1;
++
++ if (m->fast_read)
++ if (rb4xx_spi_read_fast(rbspi, m) == 0)
++ return -1;
++
++ __raw_writel(AR71XX_SPI_FS_GPIO, base + AR71XX_SPI_REG_FS);
++ __raw_writel(SPI_CTRL_FASTEST, base + AR71XX_SPI_REG_CTRL);
++ do_spi_init(m->spi);
++
++ list_for_each_entry(t, &m->transfers, transfer_list) {
++ int len;
++
++ len = rb4xx_spi_txrx(base, t);
++ if (len != t->len) {
++ m->status = -EMSGSIZE;
++ break;
++ }
++ m->actual_length += len;
++
++ if (t->cs_change) {
++ if (list_is_last(&t->transfer_list, &m->transfers)) {
++ /* wait for continuation */
++ return m->spi->chip_select;
++ }
++ do_spi_finish(base);
++ ndelay(100);
++ }
++ }
++
++ do_spi_finish(base);
++ __raw_writel(rbspi->spi_ctrl_flash, base + AR71XX_SPI_REG_CTRL);
++ __raw_writel(0, base + AR71XX_SPI_REG_FS);
++ return -1;
++}
++
++static void rb4xx_spi_process_queue_locked(struct rb4xx_spi *rbspi,
++ unsigned long *flags)
++{
++ int cs = rbspi->cs_wait;
++
++ rbspi->busy = 1;
++ while (!list_empty(&rbspi->queue)) {
++ struct spi_message *m;
++
++ list_for_each_entry(m, &rbspi->queue, queue)
++ if (cs < 0 || cs == m->spi->chip_select)
++ break;
++
++ if (&m->queue == &rbspi->queue)
++ break;
++
++ list_del_init(&m->queue);
++ spin_unlock_irqrestore(&rbspi->lock, *flags);
++
++ cs = rb4xx_spi_msg(rbspi, m);
++ m->complete(m->context);
++
++ spin_lock_irqsave(&rbspi->lock, *flags);
++ }
++
++ rbspi->cs_wait = cs;
++ rbspi->busy = 0;
++
++ if (cs >= 0) {
++ /* TODO: add timer to unlock cs after 1s inactivity */
++ }
++}
++
++static int rb4xx_spi_transfer(struct spi_device *spi,
++ struct spi_message *m)
++{
++ struct rb4xx_spi *rbspi = spi_master_get_devdata(spi->master);
++ unsigned long flags;
++
++ m->actual_length = 0;
++ m->status = -EINPROGRESS;
++
++ spin_lock_irqsave(&rbspi->lock, flags);
++ list_add_tail(&m->queue, &rbspi->queue);
++ if (rbspi->busy ||
++ (rbspi->cs_wait >= 0 && rbspi->cs_wait != m->spi->chip_select)) {
++ /* job will be done later */
++ spin_unlock_irqrestore(&rbspi->lock, flags);
++ return 0;
++ }
++
++ /* process job in current context */
++ rb4xx_spi_process_queue_locked(rbspi, &flags);
++ spin_unlock_irqrestore(&rbspi->lock, flags);
++
++ return 0;
++}
++
++static int rb4xx_spi_setup(struct spi_device *spi)
++{
++ struct rb4xx_spi *rbspi = spi_master_get_devdata(spi->master);
++ unsigned long flags;
++
++ if (spi->mode & ~(SPI_CS_HIGH)) {
++ dev_err(&spi->dev, "mode %x not supported\n",
++ (unsigned) spi->mode);
++ return -EINVAL;
++ }
++
++ if (spi->bits_per_word != 8 && spi->bits_per_word != 0) {
++ dev_err(&spi->dev, "bits_per_word %u not supported\n",
++ (unsigned) spi->bits_per_word);
++ return -EINVAL;
++ }
++
++ spin_lock_irqsave(&rbspi->lock, flags);
++ if (rbspi->cs_wait == spi->chip_select && !rbspi->busy) {
++ rbspi->cs_wait = -1;
++ rb4xx_spi_process_queue_locked(rbspi, &flags);
++ }
++ spin_unlock_irqrestore(&rbspi->lock, flags);
++
++ return 0;
++}
++
++static unsigned get_spi_ctrl(struct rb4xx_spi *rbspi, unsigned hz_max,
++ const char *name)
++{
++ unsigned div;
++
++ div = (rbspi->ahb_freq - 1) / (2 * hz_max);
++
++ /*
++ * CPU has a bug at (div == 0) - first bit read is random
++ */
++ if (div == 0)
++ ++div;
++
++ if (name) {
++ unsigned ahb_khz = (rbspi->ahb_freq + 500) / 1000;
++ unsigned div_real = 2 * (div + 1);
++ pr_debug("rb4xx: %s SPI clock %u kHz (AHB %u kHz / %u)\n",
++ name,
++ ahb_khz / div_real,
++ ahb_khz, div_real);
++ }
++
++ return SPI_CTRL_FASTEST + div;
++}
++
++static int rb4xx_spi_probe(struct platform_device *pdev)
++{
++ struct spi_master *master;
++ struct rb4xx_spi *rbspi;
++ struct resource *r;
++ int err = 0;
++
++ master = spi_alloc_master(&pdev->dev, sizeof(*rbspi));
++ if (master == NULL) {
++ dev_err(&pdev->dev, "no memory for spi_master\n");
++ err = -ENOMEM;
++ goto err_out;
++ }
++
++ master->bus_num = 0;
++ master->num_chipselect = 3;
++ master->setup = rb4xx_spi_setup;
++ master->transfer = rb4xx_spi_transfer;
++
++ rbspi = spi_master_get_devdata(master);
++
++ rbspi->ahb_clk = clk_get(&pdev->dev, "ahb");
++ if (IS_ERR(rbspi->ahb_clk)) {
++ err = PTR_ERR(rbspi->ahb_clk);
++ goto err_put_master;
++ }
++
++ err = clk_enable(rbspi->ahb_clk);
++ if (err)
++ goto err_clk_put;
++
++ rbspi->ahb_freq = clk_get_rate(rbspi->ahb_clk);
++ if (!rbspi->ahb_freq) {
++ err = -EINVAL;
++ goto err_clk_disable;
++ }
++
++ platform_set_drvdata(pdev, rbspi);
++
++ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (r == NULL) {
++ err = -ENOENT;
++ goto err_clk_disable;
++ }
++
++ rbspi->base = ioremap(r->start, r->end - r->start + 1);
++ if (!rbspi->base) {
++ err = -ENXIO;
++ goto err_clk_disable;
++ }
++
++ rbspi->master = master;
++ rbspi->spi_ctrl_flash = get_spi_ctrl(rbspi, SPI_FLASH_HZ, "FLASH");
++ rbspi->spi_ctrl_fread = get_spi_ctrl(rbspi, SPI_CPLD_HZ, "CPLD");
++ rbspi->cs_wait = -1;
++
++ spin_lock_init(&rbspi->lock);
++ INIT_LIST_HEAD(&rbspi->queue);
++
++ err = spi_register_master(master);
++ if (err) {
++ dev_err(&pdev->dev, "failed to register SPI master\n");
++ goto err_iounmap;
++ }
++
++ return 0;
++
++err_iounmap:
++ iounmap(rbspi->base);
++err_clk_disable:
++ clk_disable(rbspi->ahb_clk);
++err_clk_put:
++ clk_put(rbspi->ahb_clk);
++err_put_master:
++ platform_set_drvdata(pdev, NULL);
++ spi_master_put(master);
++err_out:
++ return err;
++}
++
++static int rb4xx_spi_remove(struct platform_device *pdev)
++{
++ struct rb4xx_spi *rbspi = platform_get_drvdata(pdev);
++
++ iounmap(rbspi->base);
++ clk_disable(rbspi->ahb_clk);
++ clk_put(rbspi->ahb_clk);
++ platform_set_drvdata(pdev, NULL);
++ spi_master_put(rbspi->master);
++
++ return 0;
++}
++
++static struct platform_driver rb4xx_spi_drv = {
++ .probe = rb4xx_spi_probe,
++ .remove = rb4xx_spi_remove,
++ .driver = {
++ .name = DRV_NAME,
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init rb4xx_spi_init(void)
++{
++ return platform_driver_register(&rb4xx_spi_drv);
++}
++subsys_initcall(rb4xx_spi_init);
++
++static void __exit rb4xx_spi_exit(void)
++{
++ platform_driver_unregister(&rb4xx_spi_drv);
++}
++
++module_exit(rb4xx_spi_exit);
++
++MODULE_DESCRIPTION(DRV_DESC);
++MODULE_VERSION(DRV_VERSION);
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_LICENSE("GPL v2");
+--
+1.8.5.3
+
diff --git a/target/mips/dragino-ms14s/patches/3.14.17/0007-spi-add-rb4xx-cpld-driver.patch b/target/mips/dragino-ms14s/patches/3.14.17/0007-spi-add-rb4xx-cpld-driver.patch
new file mode 100644
index 000000000..452f2e761
--- /dev/null
+++ b/target/mips/dragino-ms14s/patches/3.14.17/0007-spi-add-rb4xx-cpld-driver.patch
@@ -0,0 +1,548 @@
+From bb8d2a4ebf63bc2f04f15a28c92652700416ff83 Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Tue, 13 May 2014 00:20:04 +0200
+Subject: [PATCH] spi: add rb4xx cpld driver
+
+---
+ arch/mips/include/asm/mach-ath79/rb4xx_cpld.h | 48 +++
+ drivers/spi/Kconfig | 7 +
+ drivers/spi/Makefile | 1 +
+ drivers/spi/spi-rb4xx-cpld.c | 441 ++++++++++++++++++++++++++
+ 4 files changed, 497 insertions(+)
+ create mode 100644 arch/mips/include/asm/mach-ath79/rb4xx_cpld.h
+ create mode 100644 drivers/spi/spi-rb4xx-cpld.c
+
+diff --git a/arch/mips/include/asm/mach-ath79/rb4xx_cpld.h b/arch/mips/include/asm/mach-ath79/rb4xx_cpld.h
+new file mode 100644
+index 0000000..5b17e94
+--- /dev/null
++++ b/arch/mips/include/asm/mach-ath79/rb4xx_cpld.h
+@@ -0,0 +1,48 @@
++/*
++ * SPI driver definitions for the CPLD chip on the Mikrotik RB4xx boards
++ *
++ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This file was based on the patches for Linux 2.6.27.39 published by
++ * MikroTik for their RouterBoard 4xx series devices.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#define CPLD_GPIO_nLED1 0
++#define CPLD_GPIO_nLED2 1
++#define CPLD_GPIO_nLED3 2
++#define CPLD_GPIO_nLED4 3
++#define CPLD_GPIO_FAN 4
++#define CPLD_GPIO_ALE 5
++#define CPLD_GPIO_CLE 6
++#define CPLD_GPIO_nCE 7
++#define CPLD_GPIO_nLED5 8
++
++#define CPLD_NUM_GPIOS 9
++
++#define CPLD_CFG_nLED1 BIT(CPLD_GPIO_nLED1)
++#define CPLD_CFG_nLED2 BIT(CPLD_GPIO_nLED2)
++#define CPLD_CFG_nLED3 BIT(CPLD_GPIO_nLED3)
++#define CPLD_CFG_nLED4 BIT(CPLD_GPIO_nLED4)
++#define CPLD_CFG_FAN BIT(CPLD_GPIO_FAN)
++#define CPLD_CFG_ALE BIT(CPLD_GPIO_ALE)
++#define CPLD_CFG_CLE BIT(CPLD_GPIO_CLE)
++#define CPLD_CFG_nCE BIT(CPLD_GPIO_nCE)
++#define CPLD_CFG_nLED5 BIT(CPLD_GPIO_nLED5)
++
++struct rb4xx_cpld_platform_data {
++ unsigned gpio_base;
++};
++
++extern int rb4xx_cpld_change_cfg(unsigned mask, unsigned value);
++extern int rb4xx_cpld_read(unsigned char *rx_buf,
++ const unsigned char *verify_buf,
++ unsigned cnt);
++extern int rb4xx_cpld_read_from(unsigned addr,
++ unsigned char *rx_buf,
++ const unsigned char *verify_buf,
++ unsigned cnt);
++extern int rb4xx_cpld_write(const unsigned char *buf, unsigned count);
+diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
+index 721f3a7..dbd7e98 100644
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -577,6 +577,13 @@ config SPI_TLE62X0
+ sysfs interface, with each line presented as a kind of GPIO
+ exposing both switch control and diagnostic feedback.
+
++config SPI_RB4XX_CPLD
++ tristate "MikroTik RB4XX CPLD driver"
++ depends on ATH79_MACH_RB4XX
++ help
++ SPI driver for the Xilinx CPLD chip present on the
++ MikroTik RB4xx boards.
++
+ #
+ # Add new SPI protocol masters in alphabetical order above this line
+ #
+diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
+index e738c7a..50913ae 100644
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -60,6 +60,7 @@ spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_DMA) += spi-pxa2xx-dma.o
+ obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o
+ obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o
+ obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o
++obj-$(CONFIG_SPI_RB4XX_CPLD) += spi-rb4xx-cpld.o
+ obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
+ obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o
+ spi-s3c24xx-hw-y := spi-s3c24xx.o
+diff --git a/drivers/spi/spi-rb4xx-cpld.c b/drivers/spi/spi-rb4xx-cpld.c
+new file mode 100644
+index 0000000..a8d5282
+--- /dev/null
++++ b/drivers/spi/spi-rb4xx-cpld.c
+@@ -0,0 +1,441 @@
++/*
++ * SPI driver for the CPLD chip on the Mikrotik RB4xx boards
++ *
++ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This file was based on the patches for Linux 2.6.27.39 published by
++ * MikroTik for their RouterBoard 4xx series devices.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/device.h>
++#include <linux/bitops.h>
++#include <linux/spi/spi.h>
++#include <linux/gpio.h>
++#include <linux/slab.h>
++
++#include <asm/mach-ath79/rb4xx_cpld.h>
++
++#define DRV_NAME "spi-rb4xx-cpld"
++#define DRV_DESC "RB4xx CPLD driver"
++#define DRV_VERSION "0.1.0"
++
++#define CPLD_CMD_WRITE_NAND 0x08 /* send cmd, n x send data, send indle */
++#define CPLD_CMD_WRITE_CFG 0x09 /* send cmd, n x send cfg */
++#define CPLD_CMD_READ_NAND 0x0a /* send cmd, send idle, n x read data */
++#define CPLD_CMD_READ_FAST 0x0b /* send cmd, 4 x idle, n x read data */
++#define CPLD_CMD_LED5_ON 0x0c /* send cmd */
++#define CPLD_CMD_LED5_OFF 0x0d /* send cmd */
++
++struct rb4xx_cpld {
++ struct spi_device *spi;
++ struct mutex lock;
++ struct gpio_chip chip;
++ unsigned int config;
++};
++
++static struct rb4xx_cpld *rb4xx_cpld;
++
++static inline struct rb4xx_cpld *gpio_to_cpld(struct gpio_chip *chip)
++{
++ return container_of(chip, struct rb4xx_cpld, chip);
++}
++
++static int rb4xx_cpld_write_cmd(struct rb4xx_cpld *cpld, unsigned char cmd)
++{
++ struct spi_transfer t[1];
++ struct spi_message m;
++ unsigned char tx_buf[1];
++ int err;
++
++ spi_message_init(&m);
++ memset(&t, 0, sizeof(t));
++
++ t[0].tx_buf = tx_buf;
++ t[0].len = sizeof(tx_buf);
++ spi_message_add_tail(&t[0], &m);
++
++ tx_buf[0] = cmd;
++
++ err = spi_sync(cpld->spi, &m);
++ return err;
++}
++
++static int rb4xx_cpld_write_cfg(struct rb4xx_cpld *cpld, unsigned char config)
++{
++ struct spi_transfer t[1];
++ struct spi_message m;
++ unsigned char cmd[2];
++ int err;
++
++ spi_message_init(&m);
++ memset(&t, 0, sizeof(t));
++
++ t[0].tx_buf = cmd;
++ t[0].len = sizeof(cmd);
++ spi_message_add_tail(&t[0], &m);
++
++ cmd[0] = CPLD_CMD_WRITE_CFG;
++ cmd[1] = config;
++
++ err = spi_sync(cpld->spi, &m);
++ return err;
++}
++
++static int __rb4xx_cpld_change_cfg(struct rb4xx_cpld *cpld, unsigned mask,
++ unsigned value)
++{
++ unsigned int config;
++ int err;
++
++ config = cpld->config & ~mask;
++ config |= value;
++
++ if ((cpld->config ^ config) & 0xff) {
++ err = rb4xx_cpld_write_cfg(cpld, config);
++ if (err)
++ return err;
++ }
++
++ if ((cpld->config ^ config) & CPLD_CFG_nLED5) {
++ err = rb4xx_cpld_write_cmd(cpld, (value) ? CPLD_CMD_LED5_ON :
++ CPLD_CMD_LED5_OFF);
++ if (err)
++ return err;
++ }
++
++ cpld->config = config;
++ return 0;
++}
++
++int rb4xx_cpld_change_cfg(unsigned mask, unsigned value)
++{
++ int ret;
++
++ if (rb4xx_cpld == NULL)
++ return -ENODEV;
++
++ mutex_lock(&rb4xx_cpld->lock);
++ ret = __rb4xx_cpld_change_cfg(rb4xx_cpld, mask, value);
++ mutex_unlock(&rb4xx_cpld->lock);
++
++ return ret;
++}
++EXPORT_SYMBOL_GPL(rb4xx_cpld_change_cfg);
++
++int rb4xx_cpld_read_from(unsigned addr, unsigned char *rx_buf,
++ const unsigned char *verify_buf, unsigned count)
++{
++ const unsigned char cmd[5] = {
++ CPLD_CMD_READ_FAST,
++ (addr >> 16) & 0xff,
++ (addr >> 8) & 0xff,
++ addr & 0xff,
++ 0
++ };
++ struct spi_transfer t[2] = {
++ {
++ .tx_buf = &cmd,
++ .len = 5,
++ },
++ {
++ .tx_buf = verify_buf,
++ .rx_buf = rx_buf,
++ .len = count,
++ .verify = (verify_buf != NULL),
++ },
++ };
++ struct spi_message m;
++
++ if (rb4xx_cpld == NULL)
++ return -ENODEV;
++
++ spi_message_init(&m);
++ m.fast_read = 1;
++ spi_message_add_tail(&t[0], &m);
++ spi_message_add_tail(&t[1], &m);
++ return spi_sync(rb4xx_cpld->spi, &m);
++}
++EXPORT_SYMBOL_GPL(rb4xx_cpld_read_from);
++
++#if 0
++int rb4xx_cpld_read(unsigned char *buf, unsigned char *verify_buf,
++ unsigned count)
++{
++ struct spi_transfer t[2];
++ struct spi_message m;
++ unsigned char cmd[2];
++
++ if (rb4xx_cpld == NULL)
++ return -ENODEV;
++
++ spi_message_init(&m);
++ memset(&t, 0, sizeof(t));
++
++ /* send command */
++ t[0].tx_buf = cmd;
++ t[0].len = sizeof(cmd);
++ spi_message_add_tail(&t[0], &m);
++
++ cmd[0] = CPLD_CMD_READ_NAND;
++ cmd[1] = 0;
++
++ /* read data */
++ t[1].rx_buf = buf;
++ t[1].len = count;
++ spi_message_add_tail(&t[1], &m);
++
++ return spi_sync(rb4xx_cpld->spi, &m);
++}
++#else
++int rb4xx_cpld_read(unsigned char *rx_buf, const unsigned char *verify_buf,
++ unsigned count)
++{
++ static const unsigned char cmd[2] = { CPLD_CMD_READ_NAND, 0 };
++ struct spi_transfer t[2] = {
++ {
++ .tx_buf = &cmd,
++ .len = 2,
++ }, {
++ .tx_buf = verify_buf,
++ .rx_buf = rx_buf,
++ .len = count,
++ .verify = (verify_buf != NULL),
++ },
++ };
++ struct spi_message m;
++
++ if (rb4xx_cpld == NULL)
++ return -ENODEV;
++
++ spi_message_init(&m);
++ spi_message_add_tail(&t[0], &m);
++ spi_message_add_tail(&t[1], &m);
++ return spi_sync(rb4xx_cpld->spi, &m);
++}
++#endif
++EXPORT_SYMBOL_GPL(rb4xx_cpld_read);
++
++int rb4xx_cpld_write(const unsigned char *buf, unsigned count)
++{
++#if 0
++ struct spi_transfer t[3];
++ struct spi_message m;
++ unsigned char cmd[1];
++
++ if (rb4xx_cpld == NULL)
++ return -ENODEV;
++
++ memset(&t, 0, sizeof(t));
++ spi_message_init(&m);
++
++ /* send command */
++ t[0].tx_buf = cmd;
++ t[0].len = sizeof(cmd);
++ spi_message_add_tail(&t[0], &m);
++
++ cmd[0] = CPLD_CMD_WRITE_NAND;
++
++ /* write data */
++ t[1].tx_buf = buf;
++ t[1].len = count;
++ spi_message_add_tail(&t[1], &m);
++
++ /* send idle */
++ t[2].len = 1;
++ spi_message_add_tail(&t[2], &m);
++
++ return spi_sync(rb4xx_cpld->spi, &m);
++#else
++ static const unsigned char cmd = CPLD_CMD_WRITE_NAND;
++ struct spi_transfer t[3] = {
++ {
++ .tx_buf = &cmd,
++ .len = 1,
++ }, {
++ .tx_buf = buf,
++ .len = count,
++ .fast_write = 1,
++ }, {
++ .len = 1,
++ .fast_write = 1,
++ },
++ };
++ struct spi_message m;
++
++ if (rb4xx_cpld == NULL)
++ return -ENODEV;
++
++ spi_message_init(&m);
++ spi_message_add_tail(&t[0], &m);
++ spi_message_add_tail(&t[1], &m);
++ spi_message_add_tail(&t[2], &m);
++ return spi_sync(rb4xx_cpld->spi, &m);
++#endif
++}
++EXPORT_SYMBOL_GPL(rb4xx_cpld_write);
++
++static int rb4xx_cpld_gpio_get(struct gpio_chip *chip, unsigned offset)
++{
++ struct rb4xx_cpld *cpld = gpio_to_cpld(chip);
++ int ret;
++
++ mutex_lock(&cpld->lock);
++ ret = (cpld->config >> offset) & 1;
++ mutex_unlock(&cpld->lock);
++
++ return ret;
++}
++
++static void rb4xx_cpld_gpio_set(struct gpio_chip *chip, unsigned offset,
++ int value)
++{
++ struct rb4xx_cpld *cpld = gpio_to_cpld(chip);
++
++ mutex_lock(&cpld->lock);
++ __rb4xx_cpld_change_cfg(cpld, (1 << offset), !!value << offset);
++ mutex_unlock(&cpld->lock);
++}
++
++static int rb4xx_cpld_gpio_direction_input(struct gpio_chip *chip,
++ unsigned offset)
++{
++ return -EOPNOTSUPP;
++}
++
++static int rb4xx_cpld_gpio_direction_output(struct gpio_chip *chip,
++ unsigned offset,
++ int value)
++{
++ struct rb4xx_cpld *cpld = gpio_to_cpld(chip);
++ int ret;
++
++ mutex_lock(&cpld->lock);
++ ret = __rb4xx_cpld_change_cfg(cpld, (1 << offset), !!value << offset);
++ mutex_unlock(&cpld->lock);
++
++ return ret;
++}
++
++static int rb4xx_cpld_gpio_init(struct rb4xx_cpld *cpld, unsigned int base)
++{
++ int err;
++
++ /* init config */
++ cpld->config = CPLD_CFG_nLED1 | CPLD_CFG_nLED2 | CPLD_CFG_nLED3 |
++ CPLD_CFG_nLED4 | CPLD_CFG_nCE;
++ rb4xx_cpld_write_cfg(cpld, cpld->config);
++
++ /* setup GPIO chip */
++ cpld->chip.label = DRV_NAME;
++
++ cpld->chip.get = rb4xx_cpld_gpio_get;
++ cpld->chip.set = rb4xx_cpld_gpio_set;
++ cpld->chip.direction_input = rb4xx_cpld_gpio_direction_input;
++ cpld->chip.direction_output = rb4xx_cpld_gpio_direction_output;
++
++ cpld->chip.base = base;
++ cpld->chip.ngpio = CPLD_NUM_GPIOS;
++ cpld->chip.can_sleep = 1;
++ cpld->chip.dev = &cpld->spi->dev;
++ cpld->chip.owner = THIS_MODULE;
++
++ err = gpiochip_add(&cpld->chip);
++ if (err)
++ dev_err(&cpld->spi->dev, "adding GPIO chip failed, err=%d\n",
++ err);
++
++ return err;
++}
++
++static int rb4xx_cpld_probe(struct spi_device *spi)
++{
++ struct rb4xx_cpld *cpld;
++ struct rb4xx_cpld_platform_data *pdata;
++ int err;
++
++ pdata = spi->dev.platform_data;
++ if (!pdata) {
++ dev_dbg(&spi->dev, "no platform data\n");
++ return -EINVAL;
++ }
++
++ cpld = kzalloc(sizeof(*cpld), GFP_KERNEL);
++ if (!cpld) {
++ dev_err(&spi->dev, "no memory for private data\n");
++ return -ENOMEM;
++ }
++
++ mutex_init(&cpld->lock);
++ cpld->spi = spi_dev_get(spi);
++ dev_set_drvdata(&spi->dev, cpld);
++
++ spi->mode = SPI_MODE_0;
++ spi->bits_per_word = 8;
++ err = spi_setup(spi);
++ if (err) {
++ dev_err(&spi->dev, "spi_setup failed, err=%d\n", err);
++ goto err_drvdata;
++ }
++
++ err = rb4xx_cpld_gpio_init(cpld, pdata->gpio_base);
++ if (err)
++ goto err_drvdata;
++
++ rb4xx_cpld = cpld;
++
++ return 0;
++
++err_drvdata:
++ dev_set_drvdata(&spi->dev, NULL);
++ kfree(cpld);
++
++ return err;
++}
++
++static int rb4xx_cpld_remove(struct spi_device *spi)
++{
++ struct rb4xx_cpld *cpld;
++
++ rb4xx_cpld = NULL;
++ cpld = dev_get_drvdata(&spi->dev);
++ dev_set_drvdata(&spi->dev, NULL);
++ kfree(cpld);
++
++ return 0;
++}
++
++static struct spi_driver rb4xx_cpld_driver = {
++ .driver = {
++ .name = DRV_NAME,
++ .bus = &spi_bus_type,
++ .owner = THIS_MODULE,
++ },
++ .probe = rb4xx_cpld_probe,
++ .remove = rb4xx_cpld_remove,
++};
++
++static int __init rb4xx_cpld_init(void)
++{
++ return spi_register_driver(&rb4xx_cpld_driver);
++}
++module_init(rb4xx_cpld_init);
++
++static void __exit rb4xx_cpld_exit(void)
++{
++ spi_unregister_driver(&rb4xx_cpld_driver);
++}
++module_exit(rb4xx_cpld_exit);
++
++MODULE_DESCRIPTION(DRV_DESC);
++MODULE_VERSION(DRV_VERSION);
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_LICENSE("GPL v2");
+--
+1.8.5.3
+
diff --git a/target/mips/dragino-ms14s/patches/3.14.17/0008-gpio-add-GPIO-latch-driver.patch b/target/mips/dragino-ms14s/patches/3.14.17/0008-gpio-add-GPIO-latch-driver.patch
new file mode 100644
index 000000000..188cec3b2
--- /dev/null
+++ b/target/mips/dragino-ms14s/patches/3.14.17/0008-gpio-add-GPIO-latch-driver.patch
@@ -0,0 +1,290 @@
+From dd93d7e5b6530f1574860776fe6f960c4fd2661d Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Tue, 13 May 2014 00:21:54 +0200
+Subject: [PATCH] gpio: add GPIO latch driver
+
+---
+ drivers/gpio/Kconfig | 7 +
+ drivers/gpio/Makefile | 1 +
+ drivers/gpio/gpio-latch.c | 219 +++++++++++++++++++++++++++++++
+ include/linux/platform_data/gpio-latch.h | 14 ++
+ 4 files changed, 241 insertions(+)
+ create mode 100644 drivers/gpio/gpio-latch.c
+ create mode 100644 include/linux/platform_data/gpio-latch.h
+
+diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
+index 903f24d..905730b 100644
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -834,4 +834,11 @@ config GPIO_VIPERBOARD
+ River Tech's viperboard.h for detailed meaning
+ of the module parameters.
+
++comment "Other GPIO expanders"
++
++config GPIO_LATCH
++ tristate "GPIO latch driver"
++ help
++ Say yes here to enable a GPIO latch driver.
++
+ endif
+diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
+index 5d50179..7d03524 100644
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -36,6 +36,7 @@ obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o
+ obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o
+ obj-$(CONFIG_GPIO_INTEL_MID) += gpio-intel-mid.o
+ obj-$(CONFIG_GPIO_LP3943) += gpio-lp3943.o
++obj-$(CONFIG_GPIO_LATCH) += gpio-latch.o
+ obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o
+ obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o
+ obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o
+diff --git a/drivers/gpio/gpio-latch.c b/drivers/gpio/gpio-latch.c
+new file mode 100644
+index 0000000..1efa1a1
+--- /dev/null
++++ b/drivers/gpio/gpio-latch.c
+@@ -0,0 +1,219 @@
++/*
++ * GPIO latch driver
++ *
++ * Copyright (C) 2014 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/gpio.h>
++#include <linux/slab.h>
++#include <linux/platform_device.h>
++
++#include <linux/platform_data/gpio-latch.h>
++
++struct gpio_latch_chip {
++ struct gpio_chip gc;
++
++ struct mutex mutex;
++ struct mutex latch_mutex;
++ bool latch_enabled;
++ int le_gpio;
++ bool le_active_low;
++ int *gpios;
++};
++
++static inline struct gpio_latch_chip *to_gpio_latch_chip(struct gpio_chip *gc)
++{
++ return container_of(gc, struct gpio_latch_chip, gc);
++}
++
++static void gpio_latch_lock(struct gpio_latch_chip *glc, bool enable)
++{
++ mutex_lock(&glc->mutex);
++
++ if (enable)
++ glc->latch_enabled = true;
++
++ if (glc->latch_enabled)
++ mutex_lock(&glc->latch_mutex);
++}
++
++static void gpio_latch_unlock(struct gpio_latch_chip *glc, bool disable)
++{
++ if (glc->latch_enabled)
++ mutex_unlock(&glc->latch_mutex);
++
++ if (disable)
++ glc->latch_enabled = true;
++
++ mutex_unlock(&glc->mutex);
++}
++
++static int
++gpio_latch_get(struct gpio_chip *gc, unsigned offset)
++{
++ struct gpio_latch_chip *glc = to_gpio_latch_chip(gc);
++ int ret;
++
++ gpio_latch_lock(glc, false);
++ ret = gpio_get_value(glc->gpios[offset]);
++ gpio_latch_unlock(glc, false);
++
++ return ret;
++}
++
++static void
++gpio_latch_set(struct gpio_chip *gc, unsigned offset, int value)
++{
++ struct gpio_latch_chip *glc = to_gpio_latch_chip(gc);
++ bool enable_latch = false;
++ bool disable_latch = false;
++ int gpio;
++
++ gpio = glc->gpios[offset];
++
++ if (gpio == glc->le_gpio) {
++ enable_latch = value ^ glc->le_active_low;
++ disable_latch = !enable_latch;
++ }
++
++ gpio_latch_lock(glc, enable_latch);
++ gpio_set_value(gpio, value);
++ gpio_latch_unlock(glc, disable_latch);
++}
++
++static int
++gpio_latch_direction_input(struct gpio_chip *gc, unsigned offset)
++{
++ struct gpio_latch_chip *glc = to_gpio_latch_chip(gc);
++ int ret;
++
++ gpio_latch_lock(glc, false);
++ ret = gpio_direction_input(glc->gpios[offset]);
++ gpio_latch_unlock(glc, false);
++
++ return ret;
++}
++
++static int
++gpio_latch_direction_output(struct gpio_chip *gc, unsigned offset, int value)
++{
++ struct gpio_latch_chip *glc = to_gpio_latch_chip(gc);
++ bool enable_latch = false;
++ bool disable_latch = false;
++ int gpio;
++ int ret;
++
++ gpio = glc->gpios[offset];
++
++ if (gpio == glc->le_gpio) {
++ enable_latch = value ^ glc->le_active_low;
++ disable_latch = !enable_latch;
++ }
++
++ gpio_latch_lock(glc, enable_latch);
++ ret = gpio_direction_output(gpio, value);
++ gpio_latch_unlock(glc, disable_latch);
++
++ return ret;
++}
++
++static int gpio_latch_probe(struct platform_device *pdev)
++{
++ struct gpio_latch_chip *glc;
++ struct gpio_latch_platform_data *pdata;
++ struct gpio_chip *gc;
++ int size;
++ int ret;
++ int i;
++
++ pdata = dev_get_platdata(&pdev->dev);
++ if (!pdata)
++ return -EINVAL;
++
++ if (pdata->le_gpio_index >= pdata->num_gpios ||
++ !pdata->num_gpios ||
++ !pdata->gpios)
++ return -EINVAL;
++
++ for (i = 0; i < pdata->num_gpios; i++) {
++ int gpio = pdata->gpios[i];
++
++ ret = devm_gpio_request(&pdev->dev, gpio,
++ GPIO_LATCH_DRIVER_NAME);
++ if (ret)
++ return ret;
++ }
++
++ glc = devm_kzalloc(&pdev->dev, sizeof(*glc), GFP_KERNEL);
++ if (!glc)
++ return -ENOMEM;
++
++ mutex_init(&glc->mutex);
++ mutex_init(&glc->latch_mutex);
++
++ size = pdata->num_gpios * sizeof(glc->gpios[0]);
++ glc->gpios = devm_kzalloc(&pdev->dev, size , GFP_KERNEL);
++ if (!glc->gpios)
++ return -ENOMEM;
++
++ memcpy(glc->gpios, pdata->gpios, size);
++
++ glc->le_gpio = glc->gpios[pdata->le_gpio_index];
++ glc->le_active_low = pdata->le_active_low;
++
++ gc = &glc->gc;
++
++ gc->label = GPIO_LATCH_DRIVER_NAME;
++ gc->base = pdata->base;
++ gc->can_sleep = true;
++ gc->ngpio = pdata->num_gpios;
++ gc->get = gpio_latch_get;
++ gc->set = gpio_latch_set;
++ gc->direction_input = gpio_latch_direction_input,
++ gc->direction_output = gpio_latch_direction_output;
++
++ platform_set_drvdata(pdev, glc);
++
++ ret = gpiochip_add(&glc->gc);
++ if (ret)
++ return ret;
++
++ return 0;
++}
++
++static int gpio_latch_remove(struct platform_device *pdev)
++{
++ struct gpio_latch_chip *glc = platform_get_drvdata(pdev);
++
++ return gpiochip_remove(&glc->gc);;
++}
++
++
++static struct platform_driver gpio_latch_driver = {
++ .probe = gpio_latch_probe,
++ .remove = gpio_latch_remove,
++ .driver = {
++ .name = GPIO_LATCH_DRIVER_NAME,
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init gpio_latch_init(void)
++{
++ return platform_driver_register(&gpio_latch_driver);
++}
++
++postcore_initcall(gpio_latch_init);
++
++MODULE_DESCRIPTION("GPIO latch driver");
++MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:" GPIO_LATCH_DRIVER_NAME);
+diff --git a/include/linux/platform_data/gpio-latch.h b/include/linux/platform_data/gpio-latch.h
+new file mode 100644
+index 0000000..0450e67
+--- /dev/null
++++ b/include/linux/platform_data/gpio-latch.h
+@@ -0,0 +1,14 @@
++#ifndef _GPIO_LATCH_H_
++#define _GPIO_LATCH_H_
++
++#define GPIO_LATCH_DRIVER_NAME "gpio-latch"
++
++struct gpio_latch_platform_data {
++ int base;
++ int num_gpios;
++ int *gpios;
++ int le_gpio_index;
++ bool le_active_low;
++};
++
++#endif /* _GPIO_LATCH_H_ */
+--
+1.8.5.3
+
diff --git a/target/mips/dragino-ms14s/patches/3.14.17/0009-spi-export-spi_bitbang_bufs-function.patch b/target/mips/dragino-ms14s/patches/3.14.17/0009-spi-export-spi_bitbang_bufs-function.patch
new file mode 100644
index 000000000..dc6af0a9d
--- /dev/null
+++ b/target/mips/dragino-ms14s/patches/3.14.17/0009-spi-export-spi_bitbang_bufs-function.patch
@@ -0,0 +1,45 @@
+From ff81dc67568d5393c30352c6075b43afc9de2329 Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Tue, 13 May 2014 00:22:55 +0200
+Subject: [PATCH] spi: export spi_bitbang_bufs function
+
+---
+ drivers/spi/spi-bitbang.c | 3 ++-
+ include/linux/spi/spi_bitbang.h | 1 +
+ 2 files changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c
+index bd222f6..2145d77 100644
+--- a/drivers/spi/spi-bitbang.c
++++ b/drivers/spi/spi-bitbang.c
+@@ -234,13 +234,14 @@ void spi_bitbang_cleanup(struct spi_device *spi)
+ }
+ EXPORT_SYMBOL_GPL(spi_bitbang_cleanup);
+
+-static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
++int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
+ {
+ struct spi_bitbang_cs *cs = spi->controller_state;
+ unsigned nsecs = cs->nsecs;
+
+ return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t);
+ }
++EXPORT_SYMBOL_GPL(spi_bitbang_bufs);
+
+ /*----------------------------------------------------------------------*/
+
+diff --git a/include/linux/spi/spi_bitbang.h b/include/linux/spi/spi_bitbang.h
+index daebaba..1631d7a 100644
+--- a/include/linux/spi/spi_bitbang.h
++++ b/include/linux/spi/spi_bitbang.h
+@@ -39,6 +39,7 @@ extern int spi_bitbang_setup(struct spi_device *spi);
+ extern void spi_bitbang_cleanup(struct spi_device *spi);
+ extern int spi_bitbang_setup_transfer(struct spi_device *spi,
+ struct spi_transfer *t);
++extern int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t);
+
+ /* start or stop queue processing */
+ extern int spi_bitbang_start(struct spi_bitbang *spi);
+--
+1.8.5.3
+
diff --git a/target/mips/dragino-ms14s/patches/3.14.17/0010-spi-add-type-field-to-spi_transfer-struct.patch b/target/mips/dragino-ms14s/patches/3.14.17/0010-spi-add-type-field-to-spi_transfer-struct.patch
new file mode 100644
index 000000000..2721d3c4e
--- /dev/null
+++ b/target/mips/dragino-ms14s/patches/3.14.17/0010-spi-add-type-field-to-spi_transfer-struct.patch
@@ -0,0 +1,37 @@
+From eaf82ac5fc9272545d4d4fb4582eab69d37e389a Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Tue, 13 May 2014 00:23:56 +0200
+Subject: [PATCH] spi: add type field to spi_transfer struct
+
+---
+ include/linux/spi/spi.h | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
+index 4ee1a02..a77d6c6 100644
+--- a/include/linux/spi/spi.h
++++ b/include/linux/spi/spi.h
+@@ -475,6 +475,12 @@ extern struct spi_master *spi_busnum_to_master(u16 busnum);
+
+ /*---------------------------------------------------------------------------*/
+
++enum spi_transfer_type {
++ SPI_TRANSFER_GENERIC = 0,
++ SPI_TRANSFER_FLASH_READ_CMD,
++ SPI_TRANSFER_FLASH_READ_DATA,
++};
++
+ /*
+ * I/O INTERFACE between SPI controller and protocol drivers
+ *
+@@ -591,6 +597,7 @@ struct spi_transfer {
+ u8 bits_per_word;
+ u16 delay_usecs;
+ u32 speed_hz;
++ enum spi_transfer_type type;
+
+ struct list_head transfer_list;
+ };
+--
+1.8.5.3
+
diff --git a/target/mips/dragino-ms14s/patches/3.14.17/0011-mtd-m25p80-set-SPI-transfer-type.patch b/target/mips/dragino-ms14s/patches/3.14.17/0011-mtd-m25p80-set-SPI-transfer-type.patch
new file mode 100644
index 000000000..e2dfad6e0
--- /dev/null
+++ b/target/mips/dragino-ms14s/patches/3.14.17/0011-mtd-m25p80-set-SPI-transfer-type.patch
@@ -0,0 +1,29 @@
+From 531989d989855f673af76ef85300769a8a167405 Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Tue, 13 May 2014 00:25:59 +0200
+Subject: [PATCH] mtd: m25p80: set SPI transfer type
+
+---
+ drivers/mtd/devices/m25p80.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
+index ad19139..cdabcc0 100644
+--- a/drivers/mtd/devices/m25p80.c
++++ b/drivers/mtd/devices/m25p80.c
+@@ -524,10 +524,12 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
+ return -EINVAL;
+ }
+
++ t[0].type = SPI_TRANSFER_FLASH_READ_CMD;
+ t[0].tx_buf = flash->command;
+ t[0].len = m25p_cmdsz(flash) + dummy;
+ spi_message_add_tail(&t[0], &m);
+
++ t[1].type = SPI_TRANSFER_FLASH_READ_DATA;
+ t[1].rx_buf = buf;
+ t[1].rx_nbits = m25p80_rx_nbits(flash);
+ t[1].len = len;
+--
+1.8.5.3
+
diff --git a/target/mips/dragino-ms14s/patches/3.14.17/0012-mips-ath79-swizzle-PCI-address-for-ar71xx.patch b/target/mips/dragino-ms14s/patches/3.14.17/0012-mips-ath79-swizzle-PCI-address-for-ar71xx.patch
new file mode 100644
index 000000000..c63489112
--- /dev/null
+++ b/target/mips/dragino-ms14s/patches/3.14.17/0012-mips-ath79-swizzle-PCI-address-for-ar71xx.patch
@@ -0,0 +1,130 @@
+From 0c139cb15774f3c41a0cf6620727e676c874834a Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Tue, 13 May 2014 00:28:24 +0200
+Subject: [PATCH] mips: ath79: swizzle PCI address for ar71xx
+
+---
+ arch/mips/ath79/pci.c | 42 ++++++++++++++++++++++++++
+ arch/mips/include/asm/mach-ath79/mangle-port.h | 37 +++++++++++++++++++++++
+ 2 files changed, 79 insertions(+)
+ create mode 100644 arch/mips/include/asm/mach-ath79/mangle-port.h
+
+diff --git a/arch/mips/ath79/pci.c b/arch/mips/ath79/pci.c
+index 730c0b0..47be58c 100644
+--- a/arch/mips/ath79/pci.c
++++ b/arch/mips/ath79/pci.c
+@@ -13,6 +13,7 @@
+ */
+
+ #include <linux/init.h>
++#include <linux/export.h>
+ #include <linux/pci.h>
+ #include <linux/resource.h>
+ #include <linux/platform_device.h>
+@@ -25,6 +26,9 @@ static int (*ath79_pci_plat_dev_init)(struct pci_dev *dev);
+ static const struct ath79_pci_irq *ath79_pci_irq_map __initdata;
+ static unsigned ath79_pci_nr_irqs __initdata;
+
++static unsigned long (*__ath79_pci_swizzle_b)(unsigned long port);
++static unsigned long (*__ath79_pci_swizzle_w)(unsigned long port);
++
+ static const struct ath79_pci_irq ar71xx_pci_irq_map[] __initconst = {
+ {
+ .slot = 17,
+@@ -212,12 +216,50 @@ ath79_register_pci_ar724x(int id,
+ return pdev;
+ }
+
++static inline bool ar71xx_is_pci_addr(unsigned long port)
++{
++ unsigned long phys = CPHYSADDR(port);
++
++ return (phys >= AR71XX_PCI_MEM_BASE &&
++ phys < AR71XX_PCI_MEM_BASE + AR71XX_PCI_MEM_SIZE);
++}
++
++static unsigned long ar71xx_pci_swizzle_b(unsigned long port)
++{
++ return ar71xx_is_pci_addr(port) ? port ^ 3 : port;
++}
++
++static unsigned long ar71xx_pci_swizzle_w(unsigned long port)
++{
++ return ar71xx_is_pci_addr(port) ? port ^ 2 : port;
++}
++
++unsigned long ath79_pci_swizzle_b(unsigned long port)
++{
++ if (__ath79_pci_swizzle_b)
++ return __ath79_pci_swizzle_b(port);
++
++ return port;
++}
++EXPORT_SYMBOL(ath79_pci_swizzle_b);
++
++unsigned long ath79_pci_swizzle_w(unsigned long port)
++{
++ if (__ath79_pci_swizzle_w)
++ return __ath79_pci_swizzle_w(port);
++
++ return port;
++}
++EXPORT_SYMBOL(ath79_pci_swizzle_w);
++
+ int __init ath79_register_pci(void)
+ {
+ struct platform_device *pdev = NULL;
+
+ if (soc_is_ar71xx()) {
+ pdev = ath79_register_pci_ar71xx();
++ __ath79_pci_swizzle_b = ar71xx_pci_swizzle_b;
++ __ath79_pci_swizzle_w = ar71xx_pci_swizzle_w;
+ } else if (soc_is_ar724x()) {
+ pdev = ath79_register_pci_ar724x(-1,
+ AR724X_PCI_CFG_BASE,
+diff --git a/arch/mips/include/asm/mach-ath79/mangle-port.h b/arch/mips/include/asm/mach-ath79/mangle-port.h
+new file mode 100644
+index 0000000..ffd4e20
+--- /dev/null
++++ b/arch/mips/include/asm/mach-ath79/mangle-port.h
+@@ -0,0 +1,37 @@
++/*
++ * Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This file was derived from: inlude/asm-mips/mach-generic/mangle-port.h
++ * Copyright (C) 2003, 2004 Ralf Baechle
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#ifndef __ASM_MACH_ATH79_MANGLE_PORT_H
++#define __ASM_MACH_ATH79_MANGLE_PORT_H
++
++#ifdef CONFIG_PCI
++extern unsigned long (ath79_pci_swizzle_b)(unsigned long port);
++extern unsigned long (ath79_pci_swizzle_w)(unsigned long port);
++#else
++#define ath79_pci_swizzle_b(port) (port)
++#define ath79_pci_swizzle_w(port) (port)
++#endif
++
++#define __swizzle_addr_b(port) ath79_pci_swizzle_b(port)
++#define __swizzle_addr_w(port) ath79_pci_swizzle_w(port)
++#define __swizzle_addr_l(port) (port)
++#define __swizzle_addr_q(port) (port)
++
++# define ioswabb(a, x) (x)
++# define __mem_ioswabb(a, x) (x)
++# define ioswabw(a, x) (x)
++# define __mem_ioswabw(a, x) cpu_to_le16(x)
++# define ioswabl(a, x) (x)
++# define __mem_ioswabl(a, x) cpu_to_le32(x)
++# define ioswabq(a, x) (x)
++# define __mem_ioswabq(a, x) cpu_to_le64(x)
++
++#endif /* __ASM_MACH_ATH79_MANGLE_PORT_H */
+--
+1.8.5.3
+
diff --git a/target/mips/dragino-ms14s/patches/3.14.17/0013-net-add-swconfig-support.patch b/target/mips/dragino-ms14s/patches/3.14.17/0013-net-add-swconfig-support.patch
new file mode 100644
index 000000000..57c112842
--- /dev/null
+++ b/target/mips/dragino-ms14s/patches/3.14.17/0013-net-add-swconfig-support.patch
@@ -0,0 +1,1859 @@
+From fe40f6aba9ba59000ffa681a23ad59e9347346af Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Tue, 13 May 2014 00:36:13 +0200
+Subject: [PATCH] net: add swconfig support
+
+---
+ drivers/net/phy/Kconfig | 10 +
+ drivers/net/phy/Makefile | 1 +
+ drivers/net/phy/swconfig.c | 1144 +++++++++++++++++++++++++++++++++++++++
+ drivers/net/phy/swconfig_leds.c | 354 ++++++++++++
+ include/linux/switch.h | 167 ++++++
+ include/uapi/linux/Kbuild | 1 +
+ include/uapi/linux/switch.h | 103 ++++
+ 7 files changed, 1780 insertions(+)
+ create mode 100644 drivers/net/phy/swconfig.c
+ create mode 100644 drivers/net/phy/swconfig_leds.c
+ create mode 100644 include/linux/switch.h
+ create mode 100644 include/uapi/linux/switch.h
+
+diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
+index 9b5d46c..36a13fc 100644
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -12,6 +12,16 @@ menuconfig PHYLIB
+
+ if PHYLIB
+
++config SWCONFIG
++ tristate "Switch configuration API"
++ ---help---
++ Switch configuration API using netlink. This allows
++ you to configure the VLAN features of certain switches.
++
++config SWCONFIG_LEDS
++ bool "Switch LED trigger support"
++ depends on (SWCONFIG && LEDS_TRIGGERS)
++
+ comment "MII PHY device drivers"
+
+ config AT803X_PHY
+diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
+index 9013dfa..b510bd6 100644
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -3,6 +3,7 @@
+ libphy-objs := phy.o phy_device.o mdio_bus.o
+
+ obj-$(CONFIG_PHYLIB) += libphy.o
++obj-$(CONFIG_SWCONFIG) += swconfig.o
+ obj-$(CONFIG_MARVELL_PHY) += marvell.o
+ obj-$(CONFIG_DAVICOM_PHY) += davicom.o
+ obj-$(CONFIG_CICADA_PHY) += cicada.o
+diff --git a/drivers/net/phy/swconfig.c b/drivers/net/phy/swconfig.c
+new file mode 100644
+index 0000000..c043ee4
+--- /dev/null
++++ b/drivers/net/phy/swconfig.c
+@@ -0,0 +1,1144 @@
++/*
++ * swconfig.c: Switch configuration API
++ *
++ * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/types.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/if.h>
++#include <linux/if_ether.h>
++#include <linux/capability.h>
++#include <linux/skbuff.h>
++#include <linux/switch.h>
++#include <linux/of.h>
++#include <linux/version.h>
++
++#define SWCONFIG_DEVNAME "switch%d"
++
++#include "swconfig_leds.c"
++
++MODULE_AUTHOR("Felix Fietkau <nbd@openwrt.org>");
++MODULE_LICENSE("GPL");
++
++static int swdev_id;
++static struct list_head swdevs;
++static DEFINE_SPINLOCK(swdevs_lock);
++struct swconfig_callback;
++
++struct swconfig_callback {
++ struct sk_buff *msg;
++ struct genlmsghdr *hdr;
++ struct genl_info *info;
++ int cmd;
++
++ /* callback for filling in the message data */
++ int (*fill)(struct swconfig_callback *cb, void *arg);
++
++ /* callback for closing the message before sending it */
++ int (*close)(struct swconfig_callback *cb, void *arg);
++
++ struct nlattr *nest[4];
++ int args[4];
++};
++
++/* defaults */
++
++static int
++swconfig_get_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ int ret;
++ if (val->port_vlan >= dev->vlans)
++ return -EINVAL;
++
++ if (!dev->ops->get_vlan_ports)
++ return -EOPNOTSUPP;
++
++ ret = dev->ops->get_vlan_ports(dev, val);
++ return ret;
++}
++
++static int
++swconfig_set_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ struct switch_port *ports = val->value.ports;
++ const struct switch_dev_ops *ops = dev->ops;
++ int i;
++
++ if (val->port_vlan >= dev->vlans)
++ return -EINVAL;
++
++ /* validate ports */
++ if (val->len > dev->ports)
++ return -EINVAL;
++
++ if (!ops->set_vlan_ports)
++ return -EOPNOTSUPP;
++
++ for (i = 0; i < val->len; i++) {
++ if (ports[i].id >= dev->ports)
++ return -EINVAL;
++
++ if (ops->set_port_pvid &&
++ !(ports[i].flags & (1 << SWITCH_PORT_FLAG_TAGGED)))
++ ops->set_port_pvid(dev, ports[i].id, val->port_vlan);
++ }
++
++ return ops->set_vlan_ports(dev, val);
++}
++
++static int
++swconfig_set_pvid(struct switch_dev *dev, const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ if (val->port_vlan >= dev->ports)
++ return -EINVAL;
++
++ if (!dev->ops->set_port_pvid)
++ return -EOPNOTSUPP;
++
++ return dev->ops->set_port_pvid(dev, val->port_vlan, val->value.i);
++}
++
++static int
++swconfig_get_pvid(struct switch_dev *dev, const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ if (val->port_vlan >= dev->ports)
++ return -EINVAL;
++
++ if (!dev->ops->get_port_pvid)
++ return -EOPNOTSUPP;
++
++ return dev->ops->get_port_pvid(dev, val->port_vlan, &val->value.i);
++}
++
++static const char *
++swconfig_speed_str(enum switch_port_speed speed)
++{
++ switch (speed) {
++ case SWITCH_PORT_SPEED_10:
++ return "10baseT";
++ case SWITCH_PORT_SPEED_100:
++ return "100baseT";
++ case SWITCH_PORT_SPEED_1000:
++ return "1000baseT";
++ default:
++ break;
++ }
++
++ return "unknown";
++}
++
++static int
++swconfig_get_link(struct switch_dev *dev, const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ struct switch_port_link link;
++ int len;
++ int ret;
++
++ if (val->port_vlan >= dev->ports)
++ return -EINVAL;
++
++ if (!dev->ops->get_port_link)
++ return -EOPNOTSUPP;
++
++ memset(&link, 0, sizeof(link));
++ ret = dev->ops->get_port_link(dev, val->port_vlan, &link);
++ if (ret)
++ return ret;
++
++ memset(dev->buf, 0, sizeof(dev->buf));
++
++ if (link.link)
++ len = snprintf(dev->buf, sizeof(dev->buf),
++ "port:%d link:up speed:%s %s-duplex %s%s%s",
++ val->port_vlan,
++ swconfig_speed_str(link.speed),
++ link.duplex ? "full" : "half",
++ link.tx_flow ? "txflow " : "",
++ link.rx_flow ? "rxflow " : "",
++ link.aneg ? "auto" : "");
++ else
++ len = snprintf(dev->buf, sizeof(dev->buf), "port:%d link:down",
++ val->port_vlan);
++
++ val->value.s = dev->buf;
++ val->len = len;
++
++ return 0;
++}
++
++static int
++swconfig_apply_config(struct switch_dev *dev, const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ /* don't complain if not supported by the switch driver */
++ if (!dev->ops->apply_config)
++ return 0;
++
++ return dev->ops->apply_config(dev);
++}
++
++static int
++swconfig_reset_switch(struct switch_dev *dev, const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ /* don't complain if not supported by the switch driver */
++ if (!dev->ops->reset_switch)
++ return 0;
++
++ return dev->ops->reset_switch(dev);
++}
++
++enum global_defaults {
++ GLOBAL_APPLY,
++ GLOBAL_RESET,
++};
++
++enum vlan_defaults {
++ VLAN_PORTS,
++};
++
++enum port_defaults {
++ PORT_PVID,
++ PORT_LINK,
++};
++
++static struct switch_attr default_global[] = {
++ [GLOBAL_APPLY] = {
++ .type = SWITCH_TYPE_NOVAL,
++ .name = "apply",
++ .description = "Activate changes in the hardware",
++ .set = swconfig_apply_config,
++ },
++ [GLOBAL_RESET] = {
++ .type = SWITCH_TYPE_NOVAL,
++ .name = "reset",
++ .description = "Reset the switch",
++ .set = swconfig_reset_switch,
++ }
++};
++
++static struct switch_attr default_port[] = {
++ [PORT_PVID] = {
++ .type = SWITCH_TYPE_INT,
++ .name = "pvid",
++ .description = "Primary VLAN ID",
++ .set = swconfig_set_pvid,
++ .get = swconfig_get_pvid,
++ },
++ [PORT_LINK] = {
++ .type = SWITCH_TYPE_STRING,
++ .name = "link",
++ .description = "Get port link information",
++ .set = NULL,
++ .get = swconfig_get_link,
++ }
++};
++
++static struct switch_attr default_vlan[] = {
++ [VLAN_PORTS] = {
++ .type = SWITCH_TYPE_PORTS,
++ .name = "ports",
++ .description = "VLAN port mapping",
++ .set = swconfig_set_vlan_ports,
++ .get = swconfig_get_vlan_ports,
++ },
++};
++
++static const struct switch_attr *
++swconfig_find_attr_by_name(const struct switch_attrlist *alist,
++ const char *name)
++{
++ int i;
++
++ for (i = 0; i < alist->n_attr; i++)
++ if (strcmp(name, alist->attr[i].name) == 0)
++ return &alist->attr[i];
++
++ return NULL;
++}
++
++static void swconfig_defaults_init(struct switch_dev *dev)
++{
++ const struct switch_dev_ops *ops = dev->ops;
++
++ dev->def_global = 0;
++ dev->def_vlan = 0;
++ dev->def_port = 0;
++
++ if (ops->get_vlan_ports || ops->set_vlan_ports)
++ set_bit(VLAN_PORTS, &dev->def_vlan);
++
++ if (ops->get_port_pvid || ops->set_port_pvid)
++ set_bit(PORT_PVID, &dev->def_port);
++
++ if (ops->get_port_link &&
++ !swconfig_find_attr_by_name(&ops->attr_port, "link"))
++ set_bit(PORT_LINK, &dev->def_port);
++
++ /* always present, can be no-op */
++ set_bit(GLOBAL_APPLY, &dev->def_global);
++ set_bit(GLOBAL_RESET, &dev->def_global);
++}
++
++
++static struct genl_family switch_fam = {
++ .id = GENL_ID_GENERATE,
++ .name = "switch",
++ .hdrsize = 0,
++ .version = 1,
++ .maxattr = SWITCH_ATTR_MAX,
++};
++
++static const struct nla_policy switch_policy[SWITCH_ATTR_MAX+1] = {
++ [SWITCH_ATTR_ID] = { .type = NLA_U32 },
++ [SWITCH_ATTR_OP_ID] = { .type = NLA_U32 },
++ [SWITCH_ATTR_OP_PORT] = { .type = NLA_U32 },
++ [SWITCH_ATTR_OP_VLAN] = { .type = NLA_U32 },
++ [SWITCH_ATTR_OP_VALUE_INT] = { .type = NLA_U32 },
++ [SWITCH_ATTR_OP_VALUE_STR] = { .type = NLA_NUL_STRING },
++ [SWITCH_ATTR_OP_VALUE_PORTS] = { .type = NLA_NESTED },
++ [SWITCH_ATTR_TYPE] = { .type = NLA_U32 },
++};
++
++static const struct nla_policy port_policy[SWITCH_PORT_ATTR_MAX+1] = {
++ [SWITCH_PORT_ID] = { .type = NLA_U32 },
++ [SWITCH_PORT_FLAG_TAGGED] = { .type = NLA_FLAG },
++};
++
++static inline void
++swconfig_lock(void)
++{
++ spin_lock(&swdevs_lock);
++}
++
++static inline void
++swconfig_unlock(void)
++{
++ spin_unlock(&swdevs_lock);
++}
++
++static struct switch_dev *
++swconfig_get_dev(struct genl_info *info)
++{
++ struct switch_dev *dev = NULL;
++ struct switch_dev *p;
++ int id;
++
++ if (!info->attrs[SWITCH_ATTR_ID])
++ goto done;
++
++ id = nla_get_u32(info->attrs[SWITCH_ATTR_ID]);
++ swconfig_lock();
++ list_for_each_entry(p, &swdevs, dev_list) {
++ if (id != p->id)
++ continue;
++
++ dev = p;
++ break;
++ }
++ if (dev)
++ mutex_lock(&dev->sw_mutex);
++ else
++ pr_debug("device %d not found\n", id);
++ swconfig_unlock();
++done:
++ return dev;
++}
++
++static inline void
++swconfig_put_dev(struct switch_dev *dev)
++{
++ mutex_unlock(&dev->sw_mutex);
++}
++
++static int
++swconfig_dump_attr(struct swconfig_callback *cb, void *arg)
++{
++ struct switch_attr *op = arg;
++ struct genl_info *info = cb->info;
++ struct sk_buff *msg = cb->msg;
++ int id = cb->args[0];
++ void *hdr;
++
++ hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &switch_fam,
++ NLM_F_MULTI, SWITCH_CMD_NEW_ATTR);
++ if (IS_ERR(hdr))
++ return -1;
++
++ if (nla_put_u32(msg, SWITCH_ATTR_OP_ID, id))
++ goto nla_put_failure;
++ if (nla_put_u32(msg, SWITCH_ATTR_OP_TYPE, op->type))
++ goto nla_put_failure;
++ if (nla_put_string(msg, SWITCH_ATTR_OP_NAME, op->name))
++ goto nla_put_failure;
++ if (op->description)
++ if (nla_put_string(msg, SWITCH_ATTR_OP_DESCRIPTION,
++ op->description))
++ goto nla_put_failure;
++
++ return genlmsg_end(msg, hdr);
++nla_put_failure:
++ genlmsg_cancel(msg, hdr);
++ return -EMSGSIZE;
++}
++
++/* spread multipart messages across multiple message buffers */
++static int
++swconfig_send_multipart(struct swconfig_callback *cb, void *arg)
++{
++ struct genl_info *info = cb->info;
++ int restart = 0;
++ int err;
++
++ do {
++ if (!cb->msg) {
++ cb->msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
++ if (cb->msg == NULL)
++ goto error;
++ }
++
++ if (!(cb->fill(cb, arg) < 0))
++ break;
++
++ /* fill failed, check if this was already the second attempt */
++ if (restart)
++ goto error;
++
++ /* try again in a new message, send the current one */
++ restart = 1;
++ if (cb->close) {
++ if (cb->close(cb, arg) < 0)
++ goto error;
++ }
++ err = genlmsg_reply(cb->msg, info);
++ cb->msg = NULL;
++ if (err < 0)
++ goto error;
++
++ } while (restart);
++
++ return 0;
++
++error:
++ if (cb->msg)
++ nlmsg_free(cb->msg);
++ return -1;
++}
++
++static int
++swconfig_list_attrs(struct sk_buff *skb, struct genl_info *info)
++{
++ struct genlmsghdr *hdr = nlmsg_data(info->nlhdr);
++ const struct switch_attrlist *alist;
++ struct switch_dev *dev;
++ struct swconfig_callback cb;
++ int err = -EINVAL;
++ int i;
++
++ /* defaults */
++ struct switch_attr *def_list;
++ unsigned long *def_active;
++ int n_def;
++
++ dev = swconfig_get_dev(info);
++ if (!dev)
++ return -EINVAL;
++
++ switch (hdr->cmd) {
++ case SWITCH_CMD_LIST_GLOBAL:
++ alist = &dev->ops->attr_global;
++ def_list = default_global;
++ def_active = &dev->def_global;
++ n_def = ARRAY_SIZE(default_global);
++ break;
++ case SWITCH_CMD_LIST_VLAN:
++ alist = &dev->ops->attr_vlan;
++ def_list = default_vlan;
++ def_active = &dev->def_vlan;
++ n_def = ARRAY_SIZE(default_vlan);
++ break;
++ case SWITCH_CMD_LIST_PORT:
++ alist = &dev->ops->attr_port;
++ def_list = default_port;
++ def_active = &dev->def_port;
++ n_def = ARRAY_SIZE(default_port);
++ break;
++ default:
++ WARN_ON(1);
++ goto out;
++ }
++
++ memset(&cb, 0, sizeof(cb));
++ cb.info = info;
++ cb.fill = swconfig_dump_attr;
++ for (i = 0; i < alist->n_attr; i++) {
++ if (alist->attr[i].disabled)
++ continue;
++ cb.args[0] = i;
++ err = swconfig_send_multipart(&cb, (void *) &alist->attr[i]);
++ if (err < 0)
++ goto error;
++ }
++
++ /* defaults */
++ for (i = 0; i < n_def; i++) {
++ if (!test_bit(i, def_active))
++ continue;
++ cb.args[0] = SWITCH_ATTR_DEFAULTS_OFFSET + i;
++ err = swconfig_send_multipart(&cb, (void *) &def_list[i]);
++ if (err < 0)
++ goto error;
++ }
++ swconfig_put_dev(dev);
++
++ if (!cb.msg)
++ return 0;
++
++ return genlmsg_reply(cb.msg, info);
++
++error:
++ if (cb.msg)
++ nlmsg_free(cb.msg);
++out:
++ swconfig_put_dev(dev);
++ return err;
++}
++
++static const struct switch_attr *
++swconfig_lookup_attr(struct switch_dev *dev, struct genl_info *info,
++ struct switch_val *val)
++{
++ struct genlmsghdr *hdr = nlmsg_data(info->nlhdr);
++ const struct switch_attrlist *alist;
++ const struct switch_attr *attr = NULL;
++ int attr_id;
++
++ /* defaults */
++ struct switch_attr *def_list;
++ unsigned long *def_active;
++ int n_def;
++
++ if (!info->attrs[SWITCH_ATTR_OP_ID])
++ goto done;
++
++ switch (hdr->cmd) {
++ case SWITCH_CMD_SET_GLOBAL:
++ case SWITCH_CMD_GET_GLOBAL:
++ alist = &dev->ops->attr_global;
++ def_list = default_global;
++ def_active = &dev->def_global;
++ n_def = ARRAY_SIZE(default_global);
++ break;
++ case SWITCH_CMD_SET_VLAN:
++ case SWITCH_CMD_GET_VLAN:
++ alist = &dev->ops->attr_vlan;
++ def_list = default_vlan;
++ def_active = &dev->def_vlan;
++ n_def = ARRAY_SIZE(default_vlan);
++ if (!info->attrs[SWITCH_ATTR_OP_VLAN])
++ goto done;
++ val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_VLAN]);
++ if (val->port_vlan >= dev->vlans)
++ goto done;
++ break;
++ case SWITCH_CMD_SET_PORT:
++ case SWITCH_CMD_GET_PORT:
++ alist = &dev->ops->attr_port;
++ def_list = default_port;
++ def_active = &dev->def_port;
++ n_def = ARRAY_SIZE(default_port);
++ if (!info->attrs[SWITCH_ATTR_OP_PORT])
++ goto done;
++ val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_PORT]);
++ if (val->port_vlan >= dev->ports)
++ goto done;
++ break;
++ default:
++ WARN_ON(1);
++ goto done;
++ }
++
++ if (!alist)
++ goto done;
++
++ attr_id = nla_get_u32(info->attrs[SWITCH_ATTR_OP_ID]);
++ if (attr_id >= SWITCH_ATTR_DEFAULTS_OFFSET) {
++ attr_id -= SWITCH_ATTR_DEFAULTS_OFFSET;
++ if (attr_id >= n_def)
++ goto done;
++ if (!test_bit(attr_id, def_active))
++ goto done;
++ attr = &def_list[attr_id];
++ } else {
++ if (attr_id >= alist->n_attr)
++ goto done;
++ attr = &alist->attr[attr_id];
++ }
++
++ if (attr->disabled)
++ attr = NULL;
++
++done:
++ if (!attr)
++ pr_debug("attribute lookup failed\n");
++ val->attr = attr;
++ return attr;
++}
++
++static int
++swconfig_parse_ports(struct sk_buff *msg, struct nlattr *head,
++ struct switch_val *val, int max)
++{
++ struct nlattr *nla;
++ int rem;
++
++ val->len = 0;
++ nla_for_each_nested(nla, head, rem) {
++ struct nlattr *tb[SWITCH_PORT_ATTR_MAX+1];
++ struct switch_port *port = &val->value.ports[val->len];
++
++ if (val->len >= max)
++ return -EINVAL;
++
++ if (nla_parse_nested(tb, SWITCH_PORT_ATTR_MAX, nla,
++ port_policy))
++ return -EINVAL;
++
++ if (!tb[SWITCH_PORT_ID])
++ return -EINVAL;
++
++ port->id = nla_get_u32(tb[SWITCH_PORT_ID]);
++ if (tb[SWITCH_PORT_FLAG_TAGGED])
++ port->flags |= (1 << SWITCH_PORT_FLAG_TAGGED);
++ val->len++;
++ }
++
++ return 0;
++}
++
++static int
++swconfig_set_attr(struct sk_buff *skb, struct genl_info *info)
++{
++ const struct switch_attr *attr;
++ struct switch_dev *dev;
++ struct switch_val val;
++ int err = -EINVAL;
++
++ dev = swconfig_get_dev(info);
++ if (!dev)
++ return -EINVAL;
++
++ memset(&val, 0, sizeof(val));
++ attr = swconfig_lookup_attr(dev, info, &val);
++ if (!attr || !attr->set)
++ goto error;
++
++ val.attr = attr;
++ switch (attr->type) {
++ case SWITCH_TYPE_NOVAL:
++ break;
++ case SWITCH_TYPE_INT:
++ if (!info->attrs[SWITCH_ATTR_OP_VALUE_INT])
++ goto error;
++ val.value.i =
++ nla_get_u32(info->attrs[SWITCH_ATTR_OP_VALUE_INT]);
++ break;
++ case SWITCH_TYPE_STRING:
++ if (!info->attrs[SWITCH_ATTR_OP_VALUE_STR])
++ goto error;
++ val.value.s =
++ nla_data(info->attrs[SWITCH_ATTR_OP_VALUE_STR]);
++ break;
++ case SWITCH_TYPE_PORTS:
++ val.value.ports = dev->portbuf;
++ memset(dev->portbuf, 0,
++ sizeof(struct switch_port) * dev->ports);
++
++ /* TODO: implement multipart? */
++ if (info->attrs[SWITCH_ATTR_OP_VALUE_PORTS]) {
++ err = swconfig_parse_ports(skb,
++ info->attrs[SWITCH_ATTR_OP_VALUE_PORTS],
++ &val, dev->ports);
++ if (err < 0)
++ goto error;
++ } else {
++ val.len = 0;
++ err = 0;
++ }
++ break;
++ default:
++ goto error;
++ }
++
++ err = attr->set(dev, attr, &val);
++error:
++ swconfig_put_dev(dev);
++ return err;
++}
++
++static int
++swconfig_close_portlist(struct swconfig_callback *cb, void *arg)
++{
++ if (cb->nest[0])
++ nla_nest_end(cb->msg, cb->nest[0]);
++ return 0;
++}
++
++static int
++swconfig_send_port(struct swconfig_callback *cb, void *arg)
++{
++ const struct switch_port *port = arg;
++ struct nlattr *p = NULL;
++
++ if (!cb->nest[0]) {
++ cb->nest[0] = nla_nest_start(cb->msg, cb->cmd);
++ if (!cb->nest[0])
++ return -1;
++ }
++
++ p = nla_nest_start(cb->msg, SWITCH_ATTR_PORT);
++ if (!p)
++ goto error;
++
++ if (nla_put_u32(cb->msg, SWITCH_PORT_ID, port->id))
++ goto nla_put_failure;
++ if (port->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) {
++ if (nla_put_flag(cb->msg, SWITCH_PORT_FLAG_TAGGED))
++ goto nla_put_failure;
++ }
++
++ nla_nest_end(cb->msg, p);
++ return 0;
++
++nla_put_failure:
++ nla_nest_cancel(cb->msg, p);
++error:
++ nla_nest_cancel(cb->msg, cb->nest[0]);
++ return -1;
++}
++
++static int
++swconfig_send_ports(struct sk_buff **msg, struct genl_info *info, int attr,
++ const struct switch_val *val)
++{
++ struct swconfig_callback cb;
++ int err = 0;
++ int i;
++
++ if (!val->value.ports)
++ return -EINVAL;
++
++ memset(&cb, 0, sizeof(cb));
++ cb.cmd = attr;
++ cb.msg = *msg;
++ cb.info = info;
++ cb.fill = swconfig_send_port;
++ cb.close = swconfig_close_portlist;
++
++ cb.nest[0] = nla_nest_start(cb.msg, cb.cmd);
++ for (i = 0; i < val->len; i++) {
++ err = swconfig_send_multipart(&cb, &val->value.ports[i]);
++ if (err)
++ goto done;
++ }
++ err = val->len;
++ swconfig_close_portlist(&cb, NULL);
++ *msg = cb.msg;
++
++done:
++ return err;
++}
++
++static int
++swconfig_get_attr(struct sk_buff *skb, struct genl_info *info)
++{
++ struct genlmsghdr *hdr = nlmsg_data(info->nlhdr);
++ const struct switch_attr *attr;
++ struct switch_dev *dev;
++ struct sk_buff *msg = NULL;
++ struct switch_val val;
++ int err = -EINVAL;
++ int cmd = hdr->cmd;
++
++ dev = swconfig_get_dev(info);
++ if (!dev)
++ return -EINVAL;
++
++ memset(&val, 0, sizeof(val));
++ attr = swconfig_lookup_attr(dev, info, &val);
++ if (!attr || !attr->get)
++ goto error;
++
++ if (attr->type == SWITCH_TYPE_PORTS) {
++ val.value.ports = dev->portbuf;
++ memset(dev->portbuf, 0,
++ sizeof(struct switch_port) * dev->ports);
++ }
++
++ err = attr->get(dev, attr, &val);
++ if (err)
++ goto error;
++
++ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
++ if (!msg)
++ goto error;
++
++ hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &switch_fam,
++ 0, cmd);
++ if (IS_ERR(hdr))
++ goto nla_put_failure;
++
++ switch (attr->type) {
++ case SWITCH_TYPE_INT:
++ if (nla_put_u32(msg, SWITCH_ATTR_OP_VALUE_INT, val.value.i))
++ goto nla_put_failure;
++ break;
++ case SWITCH_TYPE_STRING:
++ if (nla_put_string(msg, SWITCH_ATTR_OP_VALUE_STR, val.value.s))
++ goto nla_put_failure;
++ break;
++ case SWITCH_TYPE_PORTS:
++ err = swconfig_send_ports(&msg, info,
++ SWITCH_ATTR_OP_VALUE_PORTS, &val);
++ if (err < 0)
++ goto nla_put_failure;
++ break;
++ default:
++ pr_debug("invalid type in attribute\n");
++ err = -EINVAL;
++ goto error;
++ }
++ err = genlmsg_end(msg, hdr);
++ if (err < 0)
++ goto nla_put_failure;
++
++ swconfig_put_dev(dev);
++ return genlmsg_reply(msg, info);
++
++nla_put_failure:
++ if (msg)
++ nlmsg_free(msg);
++error:
++ swconfig_put_dev(dev);
++ if (!err)
++ err = -ENOMEM;
++ return err;
++}
++
++static int
++swconfig_send_switch(struct sk_buff *msg, u32 pid, u32 seq, int flags,
++ const struct switch_dev *dev)
++{
++ struct nlattr *p = NULL, *m = NULL;
++ void *hdr;
++ int i;
++
++ hdr = genlmsg_put(msg, pid, seq, &switch_fam, flags,
++ SWITCH_CMD_NEW_ATTR);
++ if (IS_ERR(hdr))
++ return -1;
++
++ if (nla_put_u32(msg, SWITCH_ATTR_ID, dev->id))
++ goto nla_put_failure;
++ if (nla_put_string(msg, SWITCH_ATTR_DEV_NAME, dev->devname))
++ goto nla_put_failure;
++ if (nla_put_string(msg, SWITCH_ATTR_ALIAS, dev->alias))
++ goto nla_put_failure;
++ if (nla_put_string(msg, SWITCH_ATTR_NAME, dev->name))
++ goto nla_put_failure;
++ if (nla_put_u32(msg, SWITCH_ATTR_VLANS, dev->vlans))
++ goto nla_put_failure;
++ if (nla_put_u32(msg, SWITCH_ATTR_PORTS, dev->ports))
++ goto nla_put_failure;
++ if (nla_put_u32(msg, SWITCH_ATTR_CPU_PORT, dev->cpu_port))
++ goto nla_put_failure;
++
++ m = nla_nest_start(msg, SWITCH_ATTR_PORTMAP);
++ if (!m)
++ goto nla_put_failure;
++ for (i = 0; i < dev->ports; i++) {
++ p = nla_nest_start(msg, SWITCH_ATTR_PORTS);
++ if (!p)
++ continue;
++ if (dev->portmap[i].s) {
++ if (nla_put_string(msg, SWITCH_PORTMAP_SEGMENT,
++ dev->portmap[i].s))
++ goto nla_put_failure;
++ if (nla_put_u32(msg, SWITCH_PORTMAP_VIRT,
++ dev->portmap[i].virt))
++ goto nla_put_failure;
++ }
++ nla_nest_end(msg, p);
++ }
++ nla_nest_end(msg, m);
++ return genlmsg_end(msg, hdr);
++nla_put_failure:
++ genlmsg_cancel(msg, hdr);
++ return -EMSGSIZE;
++}
++
++static int swconfig_dump_switches(struct sk_buff *skb,
++ struct netlink_callback *cb)
++{
++ struct switch_dev *dev;
++ int start = cb->args[0];
++ int idx = 0;
++
++ swconfig_lock();
++ list_for_each_entry(dev, &swdevs, dev_list) {
++ if (++idx <= start)
++ continue;
++ if (swconfig_send_switch(skb, NETLINK_CB(cb->skb).portid,
++ cb->nlh->nlmsg_seq, NLM_F_MULTI,
++ dev) < 0)
++ break;
++ }
++ swconfig_unlock();
++ cb->args[0] = idx;
++
++ return skb->len;
++}
++
++static int
++swconfig_done(struct netlink_callback *cb)
++{
++ return 0;
++}
++
++static struct genl_ops swconfig_ops[] = {
++ {
++ .cmd = SWITCH_CMD_LIST_GLOBAL,
++ .doit = swconfig_list_attrs,
++ .policy = switch_policy,
++ },
++ {
++ .cmd = SWITCH_CMD_LIST_VLAN,
++ .doit = swconfig_list_attrs,
++ .policy = switch_policy,
++ },
++ {
++ .cmd = SWITCH_CMD_LIST_PORT,
++ .doit = swconfig_list_attrs,
++ .policy = switch_policy,
++ },
++ {
++ .cmd = SWITCH_CMD_GET_GLOBAL,
++ .doit = swconfig_get_attr,
++ .policy = switch_policy,
++ },
++ {
++ .cmd = SWITCH_CMD_GET_VLAN,
++ .doit = swconfig_get_attr,
++ .policy = switch_policy,
++ },
++ {
++ .cmd = SWITCH_CMD_GET_PORT,
++ .doit = swconfig_get_attr,
++ .policy = switch_policy,
++ },
++ {
++ .cmd = SWITCH_CMD_SET_GLOBAL,
++ .doit = swconfig_set_attr,
++ .policy = switch_policy,
++ },
++ {
++ .cmd = SWITCH_CMD_SET_VLAN,
++ .doit = swconfig_set_attr,
++ .policy = switch_policy,
++ },
++ {
++ .cmd = SWITCH_CMD_SET_PORT,
++ .doit = swconfig_set_attr,
++ .policy = switch_policy,
++ },
++ {
++ .cmd = SWITCH_CMD_GET_SWITCH,
++ .dumpit = swconfig_dump_switches,
++ .policy = switch_policy,
++ .done = swconfig_done,
++ }
++};
++
++#ifdef CONFIG_OF
++void
++of_switch_load_portmap(struct switch_dev *dev)
++{
++ struct device_node *port;
++
++ if (!dev->of_node)
++ return;
++
++ for_each_child_of_node(dev->of_node, port) {
++ const __be32 *prop;
++ const char *segment;
++ int size, phys;
++
++ if (!of_device_is_compatible(port, "swconfig,port"))
++ continue;
++
++ if (of_property_read_string(port, "swconfig,segment", &segment))
++ continue;
++
++ prop = of_get_property(port, "swconfig,portmap", &size);
++ if (!prop)
++ continue;
++
++ if (size != (2 * sizeof(*prop))) {
++ pr_err("%s: failed to parse port mapping\n",
++ port->name);
++ continue;
++ }
++
++ phys = be32_to_cpup(prop++);
++ if ((phys < 0) | (phys >= dev->ports)) {
++ pr_err("%s: physical port index out of range\n",
++ port->name);
++ continue;
++ }
++
++ dev->portmap[phys].s = kstrdup(segment, GFP_KERNEL);
++ dev->portmap[phys].virt = be32_to_cpup(prop);
++ pr_debug("Found port: %s, physical: %d, virtual: %d\n",
++ segment, phys, dev->portmap[phys].virt);
++ }
++}
++#endif
++
++int
++register_switch(struct switch_dev *dev, struct net_device *netdev)
++{
++ struct switch_dev *sdev;
++ const int max_switches = 8 * sizeof(unsigned long);
++ unsigned long in_use = 0;
++ int err;
++ int i;
++
++ INIT_LIST_HEAD(&dev->dev_list);
++ if (netdev) {
++ dev->netdev = netdev;
++ if (!dev->alias)
++ dev->alias = netdev->name;
++ }
++ BUG_ON(!dev->alias);
++
++ if (dev->ports > 0) {
++ dev->portbuf = kzalloc(sizeof(struct switch_port) *
++ dev->ports, GFP_KERNEL);
++ if (!dev->portbuf)
++ return -ENOMEM;
++ dev->portmap = kzalloc(sizeof(struct switch_portmap) *
++ dev->ports, GFP_KERNEL);
++ if (!dev->portmap) {
++ kfree(dev->portbuf);
++ return -ENOMEM;
++ }
++ }
++ swconfig_defaults_init(dev);
++ mutex_init(&dev->sw_mutex);
++ swconfig_lock();
++ dev->id = ++swdev_id;
++
++ list_for_each_entry(sdev, &swdevs, dev_list) {
++ if (!sscanf(sdev->devname, SWCONFIG_DEVNAME, &i))
++ continue;
++ if (i < 0 || i > max_switches)
++ continue;
++
++ set_bit(i, &in_use);
++ }
++ i = find_first_zero_bit(&in_use, max_switches);
++
++ if (i == max_switches) {
++ swconfig_unlock();
++ return -ENFILE;
++ }
++
++#ifdef CONFIG_OF
++ if (dev->ports)
++ of_switch_load_portmap(dev);
++#endif
++
++ /* fill device name */
++ snprintf(dev->devname, IFNAMSIZ, SWCONFIG_DEVNAME, i);
++
++ list_add(&dev->dev_list, &swdevs);
++ swconfig_unlock();
++
++ err = swconfig_create_led_trigger(dev);
++ if (err)
++ return err;
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(register_switch);
++
++void
++unregister_switch(struct switch_dev *dev)
++{
++ swconfig_destroy_led_trigger(dev);
++ kfree(dev->portbuf);
++ mutex_lock(&dev->sw_mutex);
++ swconfig_lock();
++ list_del(&dev->dev_list);
++ swconfig_unlock();
++ mutex_unlock(&dev->sw_mutex);
++}
++EXPORT_SYMBOL_GPL(unregister_switch);
++
++
++static int __init
++swconfig_init(void)
++{
++ int i, err;
++
++ INIT_LIST_HEAD(&swdevs);
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0))
++ err = genl_register_family(&switch_fam);
++ if (err)
++ return err;
++
++ for (i = 0; i < ARRAY_SIZE(swconfig_ops); i++) {
++ err = genl_register_ops(&switch_fam, &swconfig_ops[i]);
++ if (err)
++ goto unregister;
++ }
++#else
++ err = genl_register_family_with_ops(&switch_fam, swconfig_ops);
++ if (err)
++ return err;
++#endif
++ return 0;
++
++unregister:
++ genl_unregister_family(&switch_fam);
++ return err;
++}
++
++static void __exit
++swconfig_exit(void)
++{
++ genl_unregister_family(&switch_fam);
++}
++
++module_init(swconfig_init);
++module_exit(swconfig_exit);
++
+diff --git a/drivers/net/phy/swconfig_leds.c b/drivers/net/phy/swconfig_leds.c
+new file mode 100644
+index 0000000..abd7bed
+--- /dev/null
++++ b/drivers/net/phy/swconfig_leds.c
+@@ -0,0 +1,354 @@
++/*
++ * swconfig_led.c: LED trigger support for the switch configuration API
++ *
++ * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ */
++
++#ifdef CONFIG_SWCONFIG_LEDS
++
++#include <linux/leds.h>
++#include <linux/ctype.h>
++#include <linux/device.h>
++#include <linux/workqueue.h>
++
++#define SWCONFIG_LED_TIMER_INTERVAL (HZ / 10)
++#define SWCONFIG_LED_NUM_PORTS 32
++
++struct switch_led_trigger {
++ struct led_trigger trig;
++ struct switch_dev *swdev;
++
++ struct delayed_work sw_led_work;
++ u32 port_mask;
++ u32 port_link;
++ unsigned long port_traffic[SWCONFIG_LED_NUM_PORTS];
++};
++
++struct swconfig_trig_data {
++ struct led_classdev *led_cdev;
++ struct switch_dev *swdev;
++
++ rwlock_t lock;
++ u32 port_mask;
++
++ bool prev_link;
++ unsigned long prev_traffic;
++ enum led_brightness prev_brightness;
++};
++
++static void
++swconfig_trig_set_brightness(struct swconfig_trig_data *trig_data,
++ enum led_brightness brightness)
++{
++ led_set_brightness(trig_data->led_cdev, brightness);
++ trig_data->prev_brightness = brightness;
++}
++
++static void
++swconfig_trig_update_port_mask(struct led_trigger *trigger)
++{
++ struct list_head *entry;
++ struct switch_led_trigger *sw_trig;
++ u32 port_mask;
++
++ if (!trigger)
++ return;
++
++ sw_trig = (void *) trigger;
++
++ port_mask = 0;
++ read_lock(&trigger->leddev_list_lock);
++ list_for_each(entry, &trigger->led_cdevs) {
++ struct led_classdev *led_cdev;
++ struct swconfig_trig_data *trig_data;
++
++ led_cdev = list_entry(entry, struct led_classdev, trig_list);
++ trig_data = led_cdev->trigger_data;
++ if (trig_data) {
++ read_lock(&trig_data->lock);
++ port_mask |= trig_data->port_mask;
++ read_unlock(&trig_data->lock);
++ }
++ }
++ read_unlock(&trigger->leddev_list_lock);
++
++ sw_trig->port_mask = port_mask;
++
++ if (port_mask)
++ schedule_delayed_work(&sw_trig->sw_led_work,
++ SWCONFIG_LED_TIMER_INTERVAL);
++ else
++ cancel_delayed_work_sync(&sw_trig->sw_led_work);
++}
++
++static ssize_t
++swconfig_trig_port_mask_store(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t size)
++{
++ struct led_classdev *led_cdev = dev_get_drvdata(dev);
++ struct swconfig_trig_data *trig_data = led_cdev->trigger_data;
++ unsigned long port_mask;
++ ssize_t ret = -EINVAL;
++ char *after;
++ size_t count;
++
++ port_mask = simple_strtoul(buf, &after, 16);
++ count = after - buf;
++
++ if (*after && isspace(*after))
++ count++;
++
++ if (count == size) {
++ bool changed;
++
++ write_lock(&trig_data->lock);
++
++ changed = (trig_data->port_mask != port_mask);
++ if (changed) {
++ trig_data->port_mask = port_mask;
++ if (port_mask == 0)
++ swconfig_trig_set_brightness(trig_data, LED_OFF);
++ }
++
++ write_unlock(&trig_data->lock);
++
++ if (changed)
++ swconfig_trig_update_port_mask(led_cdev->trigger);
++
++ ret = count;
++ }
++
++ return ret;
++}
++
++static ssize_t
++swconfig_trig_port_mask_show(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct led_classdev *led_cdev = dev_get_drvdata(dev);
++ struct swconfig_trig_data *trig_data = led_cdev->trigger_data;
++
++ read_lock(&trig_data->lock);
++ sprintf(buf, "%#x\n", trig_data->port_mask);
++ read_unlock(&trig_data->lock);
++
++ return strlen(buf) + 1;
++}
++
++static DEVICE_ATTR(port_mask, 0644, swconfig_trig_port_mask_show,
++ swconfig_trig_port_mask_store);
++
++static void
++swconfig_trig_activate(struct led_classdev *led_cdev)
++{
++ struct switch_led_trigger *sw_trig;
++ struct swconfig_trig_data *trig_data;
++ int err;
++
++ if (led_cdev->trigger->activate != swconfig_trig_activate)
++ return;
++
++ trig_data = kzalloc(sizeof(struct swconfig_trig_data), GFP_KERNEL);
++ if (!trig_data)
++ return;
++
++ sw_trig = (void *) led_cdev->trigger;
++
++ rwlock_init(&trig_data->lock);
++ trig_data->led_cdev = led_cdev;
++ trig_data->swdev = sw_trig->swdev;
++ led_cdev->trigger_data = trig_data;
++
++ err = device_create_file(led_cdev->dev, &dev_attr_port_mask);
++ if (err)
++ goto err_free;
++
++ return;
++
++err_free:
++ led_cdev->trigger_data = NULL;
++ kfree(trig_data);
++}
++
++static void
++swconfig_trig_deactivate(struct led_classdev *led_cdev)
++{
++ struct swconfig_trig_data *trig_data;
++
++ swconfig_trig_update_port_mask(led_cdev->trigger);
++
++ trig_data = (void *) led_cdev->trigger_data;
++ if (trig_data) {
++ device_remove_file(led_cdev->dev, &dev_attr_port_mask);
++ kfree(trig_data);
++ }
++}
++
++static void
++swconfig_trig_led_event(struct switch_led_trigger *sw_trig,
++ struct led_classdev *led_cdev)
++{
++ struct swconfig_trig_data *trig_data;
++ u32 port_mask;
++ bool link;
++
++ trig_data = led_cdev->trigger_data;
++ if (!trig_data)
++ return;
++
++ read_lock(&trig_data->lock);
++ port_mask = trig_data->port_mask;
++ read_unlock(&trig_data->lock);
++
++ link = !!(sw_trig->port_link & port_mask);
++ if (!link) {
++ if (link != trig_data->prev_link)
++ swconfig_trig_set_brightness(trig_data, LED_OFF);
++ } else {
++ unsigned long traffic;
++ int i;
++
++ traffic = 0;
++ for (i = 0; i < SWCONFIG_LED_NUM_PORTS; i++) {
++ if (port_mask & (1 << i))
++ traffic += sw_trig->port_traffic[i];
++ }
++
++ if (trig_data->prev_brightness != LED_FULL)
++ swconfig_trig_set_brightness(trig_data, LED_FULL);
++ else if (traffic != trig_data->prev_traffic)
++ swconfig_trig_set_brightness(trig_data, LED_OFF);
++
++ trig_data->prev_traffic = traffic;
++ }
++
++ trig_data->prev_link = link;
++}
++
++static void
++swconfig_trig_update_leds(struct switch_led_trigger *sw_trig)
++{
++ struct list_head *entry;
++ struct led_trigger *trigger;
++
++ trigger = &sw_trig->trig;
++ read_lock(&trigger->leddev_list_lock);
++ list_for_each(entry, &trigger->led_cdevs) {
++ struct led_classdev *led_cdev;
++
++ led_cdev = list_entry(entry, struct led_classdev, trig_list);
++ swconfig_trig_led_event(sw_trig, led_cdev);
++ }
++ read_unlock(&trigger->leddev_list_lock);
++}
++
++static void
++swconfig_led_work_func(struct work_struct *work)
++{
++ struct switch_led_trigger *sw_trig;
++ struct switch_dev *swdev;
++ u32 port_mask;
++ u32 link;
++ int i;
++
++ sw_trig = container_of(work, struct switch_led_trigger,
++ sw_led_work.work);
++
++ port_mask = sw_trig->port_mask;
++ swdev = sw_trig->swdev;
++
++ link = 0;
++ for (i = 0; i < SWCONFIG_LED_NUM_PORTS; i++) {
++ u32 port_bit;
++
++ port_bit = BIT(i);
++ if ((port_mask & port_bit) == 0)
++ continue;
++
++ if (swdev->ops->get_port_link) {
++ struct switch_port_link port_link;
++
++ memset(&port_link, '\0', sizeof(port_link));
++ swdev->ops->get_port_link(swdev, i, &port_link);
++
++ if (port_link.link)
++ link |= port_bit;
++ }
++
++ if (swdev->ops->get_port_stats) {
++ struct switch_port_stats port_stats;
++
++ memset(&port_stats, '\0', sizeof(port_stats));
++ swdev->ops->get_port_stats(swdev, i, &port_stats);
++ sw_trig->port_traffic[i] = port_stats.tx_bytes +
++ port_stats.rx_bytes;
++ }
++ }
++
++ sw_trig->port_link = link;
++
++ swconfig_trig_update_leds(sw_trig);
++
++ schedule_delayed_work(&sw_trig->sw_led_work,
++ SWCONFIG_LED_TIMER_INTERVAL);
++}
++
++static int
++swconfig_create_led_trigger(struct switch_dev *swdev)
++{
++ struct switch_led_trigger *sw_trig;
++ int err;
++
++ if (!swdev->ops->get_port_link)
++ return 0;
++
++ sw_trig = kzalloc(sizeof(struct switch_led_trigger), GFP_KERNEL);
++ if (!sw_trig)
++ return -ENOMEM;
++
++ sw_trig->swdev = swdev;
++ sw_trig->trig.name = swdev->devname;
++ sw_trig->trig.activate = swconfig_trig_activate;
++ sw_trig->trig.deactivate = swconfig_trig_deactivate;
++
++ INIT_DELAYED_WORK(&sw_trig->sw_led_work, swconfig_led_work_func);
++
++ err = led_trigger_register(&sw_trig->trig);
++ if (err)
++ goto err_free;
++
++ swdev->led_trigger = sw_trig;
++
++ return 0;
++
++err_free:
++ kfree(sw_trig);
++ return err;
++}
++
++static void
++swconfig_destroy_led_trigger(struct switch_dev *swdev)
++{
++ struct switch_led_trigger *sw_trig;
++
++ sw_trig = swdev->led_trigger;
++ if (sw_trig) {
++ cancel_delayed_work_sync(&sw_trig->sw_led_work);
++ led_trigger_unregister(&sw_trig->trig);
++ kfree(sw_trig);
++ }
++}
++
++#else /* SWCONFIG_LEDS */
++static inline int
++swconfig_create_led_trigger(struct switch_dev *swdev) { return 0; }
++
++static inline void
++swconfig_destroy_led_trigger(struct switch_dev *swdev) { }
++#endif /* CONFIG_SWCONFIG_LEDS */
+diff --git a/include/linux/switch.h b/include/linux/switch.h
+new file mode 100644
+index 0000000..b53431e
+--- /dev/null
++++ b/include/linux/switch.h
+@@ -0,0 +1,167 @@
++/*
++ * switch.h: Switch configuration API
++ *
++ * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++#ifndef _LINUX_SWITCH_H
++#define _LINUX_SWITCH_H
++
++#include <net/genetlink.h>
++#include <uapi/linux/switch.h>
++
++struct switch_dev;
++struct switch_op;
++struct switch_val;
++struct switch_attr;
++struct switch_attrlist;
++struct switch_led_trigger;
++
++int register_switch(struct switch_dev *dev, struct net_device *netdev);
++void unregister_switch(struct switch_dev *dev);
++
++/**
++ * struct switch_attrlist - attribute list
++ *
++ * @n_attr: number of attributes
++ * @attr: pointer to the attributes array
++ */
++struct switch_attrlist {
++ int n_attr;
++ const struct switch_attr *attr;
++};
++
++enum switch_port_speed {
++ SWITCH_PORT_SPEED_UNKNOWN = 0,
++ SWITCH_PORT_SPEED_10 = 10,
++ SWITCH_PORT_SPEED_100 = 100,
++ SWITCH_PORT_SPEED_1000 = 1000,
++};
++
++struct switch_port_link {
++ bool link;
++ bool duplex;
++ bool aneg;
++ bool tx_flow;
++ bool rx_flow;
++ enum switch_port_speed speed;
++};
++
++struct switch_port_stats {
++ unsigned long tx_bytes;
++ unsigned long rx_bytes;
++};
++
++/**
++ * struct switch_dev_ops - switch driver operations
++ *
++ * @attr_global: global switch attribute list
++ * @attr_port: port attribute list
++ * @attr_vlan: vlan attribute list
++ *
++ * Callbacks:
++ *
++ * @get_vlan_ports: read the port list of a VLAN
++ * @set_vlan_ports: set the port list of a VLAN
++ *
++ * @get_port_pvid: get the primary VLAN ID of a port
++ * @set_port_pvid: set the primary VLAN ID of a port
++ *
++ * @apply_config: apply all changed settings to the switch
++ * @reset_switch: resetting the switch
++ */
++struct switch_dev_ops {
++ struct switch_attrlist attr_global, attr_port, attr_vlan;
++
++ int (*get_vlan_ports)(struct switch_dev *dev, struct switch_val *val);
++ int (*set_vlan_ports)(struct switch_dev *dev, struct switch_val *val);
++
++ int (*get_port_pvid)(struct switch_dev *dev, int port, int *val);
++ int (*set_port_pvid)(struct switch_dev *dev, int port, int val);
++
++ int (*apply_config)(struct switch_dev *dev);
++ int (*reset_switch)(struct switch_dev *dev);
++
++ int (*get_port_link)(struct switch_dev *dev, int port,
++ struct switch_port_link *link);
++ int (*get_port_stats)(struct switch_dev *dev, int port,
++ struct switch_port_stats *stats);
++};
++
++struct switch_dev {
++ struct device_node *of_node;
++ const struct switch_dev_ops *ops;
++ /* will be automatically filled */
++ char devname[IFNAMSIZ];
++
++ const char *name;
++ /* NB: either alias or netdev must be set */
++ const char *alias;
++ struct net_device *netdev;
++
++ int ports;
++ int vlans;
++ int cpu_port;
++
++ /* the following fields are internal for swconfig */
++ int id;
++ struct list_head dev_list;
++ unsigned long def_global, def_port, def_vlan;
++
++ struct mutex sw_mutex;
++ struct switch_port *portbuf;
++ struct switch_portmap *portmap;
++
++ char buf[128];
++
++#ifdef CONFIG_SWCONFIG_LEDS
++ struct switch_led_trigger *led_trigger;
++#endif
++};
++
++struct switch_port {
++ u32 id;
++ u32 flags;
++};
++
++struct switch_portmap {
++ u32 virt;
++ const char *s;
++};
++
++struct switch_val {
++ const struct switch_attr *attr;
++ int port_vlan;
++ int len;
++ union {
++ const char *s;
++ u32 i;
++ struct switch_port *ports;
++ } value;
++};
++
++struct switch_attr {
++ int disabled;
++ int type;
++ const char *name;
++ const char *description;
++
++ int (*set)(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val);
++ int (*get)(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val);
++
++ /* for driver internal use */
++ int id;
++ int ofs;
++ int max;
++};
++
++#endif /* _LINUX_SWITCH_H */
+diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
+index 3ce25b5..b9565df 100644
+--- a/include/uapi/linux/Kbuild
++++ b/include/uapi/linux/Kbuild
+@@ -365,6 +365,7 @@ header-y += stddef.h
+ header-y += string.h
+ header-y += suspend_ioctls.h
+ header-y += swab.h
++header-y += switch.h
+ header-y += synclink.h
+ header-y += sysctl.h
+ header-y += sysinfo.h
+diff --git a/include/uapi/linux/switch.h b/include/uapi/linux/switch.h
+new file mode 100644
+index 0000000..a59b239
+--- /dev/null
++++ b/include/uapi/linux/switch.h
+@@ -0,0 +1,103 @@
++/*
++ * switch.h: Switch configuration API
++ *
++ * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef _UAPI_LINUX_SWITCH_H
++#define _UAPI_LINUX_SWITCH_H
++
++#include <linux/types.h>
++#include <linux/netdevice.h>
++#include <linux/netlink.h>
++#include <linux/genetlink.h>
++#ifndef __KERNEL__
++#include <netlink/netlink.h>
++#include <netlink/genl/genl.h>
++#include <netlink/genl/ctrl.h>
++#endif
++
++/* main attributes */
++enum {
++ SWITCH_ATTR_UNSPEC,
++ /* global */
++ SWITCH_ATTR_TYPE,
++ /* device */
++ SWITCH_ATTR_ID,
++ SWITCH_ATTR_DEV_NAME,
++ SWITCH_ATTR_ALIAS,
++ SWITCH_ATTR_NAME,
++ SWITCH_ATTR_VLANS,
++ SWITCH_ATTR_PORTS,
++ SWITCH_ATTR_PORTMAP,
++ SWITCH_ATTR_CPU_PORT,
++ /* attributes */
++ SWITCH_ATTR_OP_ID,
++ SWITCH_ATTR_OP_TYPE,
++ SWITCH_ATTR_OP_NAME,
++ SWITCH_ATTR_OP_PORT,
++ SWITCH_ATTR_OP_VLAN,
++ SWITCH_ATTR_OP_VALUE_INT,
++ SWITCH_ATTR_OP_VALUE_STR,
++ SWITCH_ATTR_OP_VALUE_PORTS,
++ SWITCH_ATTR_OP_DESCRIPTION,
++ /* port lists */
++ SWITCH_ATTR_PORT,
++ SWITCH_ATTR_MAX
++};
++
++enum {
++ /* port map */
++ SWITCH_PORTMAP_PORTS,
++ SWITCH_PORTMAP_SEGMENT,
++ SWITCH_PORTMAP_VIRT,
++ SWITCH_PORTMAP_MAX
++};
++
++/* commands */
++enum {
++ SWITCH_CMD_UNSPEC,
++ SWITCH_CMD_GET_SWITCH,
++ SWITCH_CMD_NEW_ATTR,
++ SWITCH_CMD_LIST_GLOBAL,
++ SWITCH_CMD_GET_GLOBAL,
++ SWITCH_CMD_SET_GLOBAL,
++ SWITCH_CMD_LIST_PORT,
++ SWITCH_CMD_GET_PORT,
++ SWITCH_CMD_SET_PORT,
++ SWITCH_CMD_LIST_VLAN,
++ SWITCH_CMD_GET_VLAN,
++ SWITCH_CMD_SET_VLAN
++};
++
++/* data types */
++enum switch_val_type {
++ SWITCH_TYPE_UNSPEC,
++ SWITCH_TYPE_INT,
++ SWITCH_TYPE_STRING,
++ SWITCH_TYPE_PORTS,
++ SWITCH_TYPE_NOVAL,
++};
++
++/* port nested attributes */
++enum {
++ SWITCH_PORT_UNSPEC,
++ SWITCH_PORT_ID,
++ SWITCH_PORT_FLAG_TAGGED,
++ SWITCH_PORT_ATTR_MAX
++};
++
++#define SWITCH_ATTR_DEFAULTS_OFFSET 0x1000
++
++
++#endif /* _UAPI_LINUX_SWITCH_H */
+--
+1.8.5.3
+
diff --git a/target/mips/dragino-ms14s/patches/3.14.17/0014-phy-add-detach-callback-to-struct-phy_driver.patch b/target/mips/dragino-ms14s/patches/3.14.17/0014-phy-add-detach-callback-to-struct-phy_driver.patch
new file mode 100644
index 000000000..43ca7ce9b
--- /dev/null
+++ b/target/mips/dragino-ms14s/patches/3.14.17/0014-phy-add-detach-callback-to-struct-phy_driver.patch
@@ -0,0 +1,46 @@
+From 76e9965a69ff97c3ca973ca54f145a96023bdeca Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Wed, 14 May 2014 03:24:00 +0200
+Subject: [PATCH] phy: add detach callback to struct phy_driver
+
+This is used by ar8216 driver.
+---
+ drivers/net/phy/phy_device.c | 4 ++++
+ include/linux/phy.h | 6 ++++++
+ 2 files changed, 10 insertions(+)
+
+diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
+index 3653754..b35ece2 100644
+--- a/drivers/net/phy/phy_device.c
++++ b/drivers/net/phy/phy_device.c
+@@ -662,6 +662,10 @@ EXPORT_SYMBOL(phy_attach);
+ void phy_detach(struct phy_device *phydev)
+ {
+ int i;
++
++ if (phydev->drv && phydev->drv->detach)
++ phydev->drv->detach(phydev);
++
+ phydev->attached_dev->phydev = NULL;
+ phydev->attached_dev = NULL;
+ phy_suspend(phydev);
+diff --git a/include/linux/phy.h b/include/linux/phy.h
+index 9ab0d79..f1441b4 100644
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -432,6 +432,12 @@ struct phy_driver {
+ */
+ int (*did_interrupt)(struct phy_device *phydev);
+
++ /*
++ * Called before an ethernet device is detached
++ * from the PHY.
++ */
++ void (*detach)(struct phy_device *phydev);
++
+ /* Clears up any memory if needed */
+ void (*remove)(struct phy_device *phydev);
+
+--
+1.8.5.3
+
diff --git a/target/mips/dragino-ms14s/patches/3.14.17/0015-phy-add-ar8216-PHY-support.patch b/target/mips/dragino-ms14s/patches/3.14.17/0015-phy-add-ar8216-PHY-support.patch
new file mode 100644
index 000000000..46b2ba467
--- /dev/null
+++ b/target/mips/dragino-ms14s/patches/3.14.17/0015-phy-add-ar8216-PHY-support.patch
@@ -0,0 +1,3671 @@
+From 6137bedf972f576765c6e5d4373a488951371609 Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Tue, 13 May 2014 00:37:30 +0200
+Subject: [PATCH] phy: add ar8216 PHY support
+
+---
+ drivers/net/phy/Kconfig | 9 +
+ drivers/net/phy/Makefile | 1 +
+ drivers/net/phy/ar8216.c | 2978 +++++++++++++++++++++++++++++++++++++++
+ drivers/net/phy/ar8216.h | 492 +++++++
+ include/linux/ar8216_platform.h | 131 ++
+ 5 files changed, 3611 insertions(+)
+ create mode 100644 drivers/net/phy/ar8216.c
+ create mode 100644 drivers/net/phy/ar8216.h
+ create mode 100644 include/linux/ar8216_platform.h
+
+diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
+index 36a13fc..0414889 100644
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -116,6 +116,15 @@ config MICREL_PHY
+ ---help---
+ Supports the KSZ9021, VSC8201, KS8001 PHYs.
+
++config AR8216_PHY
++ tristate "Driver for Atheros AR8216 switches"
++ select ETHERNET_PACKET_MANGLE
++ select SWCONFIG
++
++config AR8216_PHY_LEDS
++ bool "Atheros AR8216 switch LED support"
++ depends on (AR8216_PHY && LEDS_CLASS)
++
+ config FIXED_PHY
+ bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
+ depends on PHYLIB=y
+diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
+index b510bd6..3c76ff8 100644
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -16,6 +16,7 @@ obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o
+ obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o
+ obj-$(CONFIG_ICPLUS_PHY) += icplus.o
+ obj-$(CONFIG_REALTEK_PHY) += realtek.o
++obj-$(CONFIG_AR8216_PHY) += ar8216.o
+ obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o
+ obj-$(CONFIG_FIXED_PHY) += fixed.o
+ obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
+diff --git a/drivers/net/phy/ar8216.c b/drivers/net/phy/ar8216.c
+new file mode 100644
+index 0000000..3f60878
+--- /dev/null
++++ b/drivers/net/phy/ar8216.c
+@@ -0,0 +1,2978 @@
++/*
++ * ar8216.c: AR8216 switch driver
++ *
++ * Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
++ * Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/if.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/if_ether.h>
++#include <linux/skbuff.h>
++#include <linux/netdevice.h>
++#include <linux/netlink.h>
++#include <linux/bitops.h>
++#include <net/genetlink.h>
++#include <linux/switch.h>
++#include <linux/delay.h>
++#include <linux/phy.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/lockdep.h>
++#include <linux/ar8216_platform.h>
++#include <linux/workqueue.h>
++#include <linux/of_device.h>
++#include <linux/leds.h>
++#include <linux/gpio.h>
++
++#include "ar8216.h"
++
++/* size of the vlan table */
++#define AR8X16_MAX_VLANS 128
++#define AR8X16_PROBE_RETRIES 10
++#define AR8X16_MAX_PORTS 8
++
++#define AR8XXX_MIB_WORK_DELAY 2000 /* msecs */
++
++struct ar8xxx_priv;
++
++#define AR8XXX_CAP_GIGE BIT(0)
++#define AR8XXX_CAP_MIB_COUNTERS BIT(1)
++
++enum {
++ AR8XXX_VER_AR8216 = 0x01,
++ AR8XXX_VER_AR8236 = 0x03,
++ AR8XXX_VER_AR8316 = 0x10,
++ AR8XXX_VER_AR8327 = 0x12,
++ AR8XXX_VER_AR8337 = 0x13,
++};
++
++struct ar8xxx_mib_desc {
++ unsigned int size;
++ unsigned int offset;
++ const char *name;
++};
++
++struct ar8xxx_chip {
++ unsigned long caps;
++
++ int (*hw_init)(struct ar8xxx_priv *priv);
++ void (*cleanup)(struct ar8xxx_priv *priv);
++
++ void (*init_globals)(struct ar8xxx_priv *priv);
++ void (*init_port)(struct ar8xxx_priv *priv, int port);
++ void (*setup_port)(struct ar8xxx_priv *priv, int port, u32 egress,
++ u32 ingress, u32 members, u32 pvid);
++ u32 (*read_port_status)(struct ar8xxx_priv *priv, int port);
++ int (*atu_flush)(struct ar8xxx_priv *priv);
++ void (*vtu_flush)(struct ar8xxx_priv *priv);
++ void (*vtu_load_vlan)(struct ar8xxx_priv *priv, u32 vid, u32 port_mask);
++
++ const struct ar8xxx_mib_desc *mib_decs;
++ unsigned num_mibs;
++};
++
++enum ar8327_led_pattern {
++ AR8327_LED_PATTERN_OFF = 0,
++ AR8327_LED_PATTERN_BLINK,
++ AR8327_LED_PATTERN_ON,
++ AR8327_LED_PATTERN_RULE,
++};
++
++struct ar8327_led_entry {
++ unsigned reg;
++ unsigned shift;
++};
++
++struct ar8327_led {
++ struct led_classdev cdev;
++ struct ar8xxx_priv *sw_priv;
++
++ char *name;
++ bool active_low;
++ u8 led_num;
++ enum ar8327_led_mode mode;
++
++ struct mutex mutex;
++ spinlock_t lock;
++ struct work_struct led_work;
++ bool enable_hw_mode;
++ enum ar8327_led_pattern pattern;
++};
++
++struct ar8327_data {
++ u32 port0_status;
++ u32 port6_status;
++
++ struct ar8327_led **leds;
++ unsigned int num_leds;
++};
++
++struct ar8xxx_priv {
++ struct switch_dev dev;
++ struct mii_bus *mii_bus;
++ struct phy_device *phy;
++
++ u32 (*read)(struct ar8xxx_priv *priv, int reg);
++ void (*write)(struct ar8xxx_priv *priv, int reg, u32 val);
++ u32 (*rmw)(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val);
++
++ int (*get_port_link)(unsigned port);
++
++ const struct net_device_ops *ndo_old;
++ struct net_device_ops ndo;
++ struct mutex reg_mutex;
++ u8 chip_ver;
++ u8 chip_rev;
++ const struct ar8xxx_chip *chip;
++ union {
++ struct ar8327_data ar8327;
++ } chip_data;
++ bool initialized;
++ bool port4_phy;
++ char buf[2048];
++
++ bool init;
++ bool mii_lo_first;
++
++ struct mutex mib_lock;
++ struct delayed_work mib_work;
++ int mib_next_port;
++ u64 *mib_stats;
++
++ struct list_head list;
++ unsigned int use_count;
++
++ /* all fields below are cleared on reset */
++ bool vlan;
++ u16 vlan_id[AR8X16_MAX_VLANS];
++ u8 vlan_table[AR8X16_MAX_VLANS];
++ u8 vlan_tagged;
++ u16 pvid[AR8X16_MAX_PORTS];
++
++ /* mirroring */
++ bool mirror_rx;
++ bool mirror_tx;
++ int source_port;
++ int monitor_port;
++};
++
++#define MIB_DESC(_s , _o, _n) \
++ { \
++ .size = (_s), \
++ .offset = (_o), \
++ .name = (_n), \
++ }
++
++static const struct ar8xxx_mib_desc ar8216_mibs[] = {
++ MIB_DESC(1, AR8216_STATS_RXBROAD, "RxBroad"),
++ MIB_DESC(1, AR8216_STATS_RXPAUSE, "RxPause"),
++ MIB_DESC(1, AR8216_STATS_RXMULTI, "RxMulti"),
++ MIB_DESC(1, AR8216_STATS_RXFCSERR, "RxFcsErr"),
++ MIB_DESC(1, AR8216_STATS_RXALIGNERR, "RxAlignErr"),
++ MIB_DESC(1, AR8216_STATS_RXRUNT, "RxRunt"),
++ MIB_DESC(1, AR8216_STATS_RXFRAGMENT, "RxFragment"),
++ MIB_DESC(1, AR8216_STATS_RX64BYTE, "Rx64Byte"),
++ MIB_DESC(1, AR8216_STATS_RX128BYTE, "Rx128Byte"),
++ MIB_DESC(1, AR8216_STATS_RX256BYTE, "Rx256Byte"),
++ MIB_DESC(1, AR8216_STATS_RX512BYTE, "Rx512Byte"),
++ MIB_DESC(1, AR8216_STATS_RX1024BYTE, "Rx1024Byte"),
++ MIB_DESC(1, AR8216_STATS_RXMAXBYTE, "RxMaxByte"),
++ MIB_DESC(1, AR8216_STATS_RXTOOLONG, "RxTooLong"),
++ MIB_DESC(2, AR8216_STATS_RXGOODBYTE, "RxGoodByte"),
++ MIB_DESC(2, AR8216_STATS_RXBADBYTE, "RxBadByte"),
++ MIB_DESC(1, AR8216_STATS_RXOVERFLOW, "RxOverFlow"),
++ MIB_DESC(1, AR8216_STATS_FILTERED, "Filtered"),
++ MIB_DESC(1, AR8216_STATS_TXBROAD, "TxBroad"),
++ MIB_DESC(1, AR8216_STATS_TXPAUSE, "TxPause"),
++ MIB_DESC(1, AR8216_STATS_TXMULTI, "TxMulti"),
++ MIB_DESC(1, AR8216_STATS_TXUNDERRUN, "TxUnderRun"),
++ MIB_DESC(1, AR8216_STATS_TX64BYTE, "Tx64Byte"),
++ MIB_DESC(1, AR8216_STATS_TX128BYTE, "Tx128Byte"),
++ MIB_DESC(1, AR8216_STATS_TX256BYTE, "Tx256Byte"),
++ MIB_DESC(1, AR8216_STATS_TX512BYTE, "Tx512Byte"),
++ MIB_DESC(1, AR8216_STATS_TX1024BYTE, "Tx1024Byte"),
++ MIB_DESC(1, AR8216_STATS_TXMAXBYTE, "TxMaxByte"),
++ MIB_DESC(1, AR8216_STATS_TXOVERSIZE, "TxOverSize"),
++ MIB_DESC(2, AR8216_STATS_TXBYTE, "TxByte"),
++ MIB_DESC(1, AR8216_STATS_TXCOLLISION, "TxCollision"),
++ MIB_DESC(1, AR8216_STATS_TXABORTCOL, "TxAbortCol"),
++ MIB_DESC(1, AR8216_STATS_TXMULTICOL, "TxMultiCol"),
++ MIB_DESC(1, AR8216_STATS_TXSINGLECOL, "TxSingleCol"),
++ MIB_DESC(1, AR8216_STATS_TXEXCDEFER, "TxExcDefer"),
++ MIB_DESC(1, AR8216_STATS_TXDEFER, "TxDefer"),
++ MIB_DESC(1, AR8216_STATS_TXLATECOL, "TxLateCol"),
++};
++
++static const struct ar8xxx_mib_desc ar8236_mibs[] = {
++ MIB_DESC(1, AR8236_STATS_RXBROAD, "RxBroad"),
++ MIB_DESC(1, AR8236_STATS_RXPAUSE, "RxPause"),
++ MIB_DESC(1, AR8236_STATS_RXMULTI, "RxMulti"),
++ MIB_DESC(1, AR8236_STATS_RXFCSERR, "RxFcsErr"),
++ MIB_DESC(1, AR8236_STATS_RXALIGNERR, "RxAlignErr"),
++ MIB_DESC(1, AR8236_STATS_RXRUNT, "RxRunt"),
++ MIB_DESC(1, AR8236_STATS_RXFRAGMENT, "RxFragment"),
++ MIB_DESC(1, AR8236_STATS_RX64BYTE, "Rx64Byte"),
++ MIB_DESC(1, AR8236_STATS_RX128BYTE, "Rx128Byte"),
++ MIB_DESC(1, AR8236_STATS_RX256BYTE, "Rx256Byte"),
++ MIB_DESC(1, AR8236_STATS_RX512BYTE, "Rx512Byte"),
++ MIB_DESC(1, AR8236_STATS_RX1024BYTE, "Rx1024Byte"),
++ MIB_DESC(1, AR8236_STATS_RX1518BYTE, "Rx1518Byte"),
++ MIB_DESC(1, AR8236_STATS_RXMAXBYTE, "RxMaxByte"),
++ MIB_DESC(1, AR8236_STATS_RXTOOLONG, "RxTooLong"),
++ MIB_DESC(2, AR8236_STATS_RXGOODBYTE, "RxGoodByte"),
++ MIB_DESC(2, AR8236_STATS_RXBADBYTE, "RxBadByte"),
++ MIB_DESC(1, AR8236_STATS_RXOVERFLOW, "RxOverFlow"),
++ MIB_DESC(1, AR8236_STATS_FILTERED, "Filtered"),
++ MIB_DESC(1, AR8236_STATS_TXBROAD, "TxBroad"),
++ MIB_DESC(1, AR8236_STATS_TXPAUSE, "TxPause"),
++ MIB_DESC(1, AR8236_STATS_TXMULTI, "TxMulti"),
++ MIB_DESC(1, AR8236_STATS_TXUNDERRUN, "TxUnderRun"),
++ MIB_DESC(1, AR8236_STATS_TX64BYTE, "Tx64Byte"),
++ MIB_DESC(1, AR8236_STATS_TX128BYTE, "Tx128Byte"),
++ MIB_DESC(1, AR8236_STATS_TX256BYTE, "Tx256Byte"),
++ MIB_DESC(1, AR8236_STATS_TX512BYTE, "Tx512Byte"),
++ MIB_DESC(1, AR8236_STATS_TX1024BYTE, "Tx1024Byte"),
++ MIB_DESC(1, AR8236_STATS_TX1518BYTE, "Tx1518Byte"),
++ MIB_DESC(1, AR8236_STATS_TXMAXBYTE, "TxMaxByte"),
++ MIB_DESC(1, AR8236_STATS_TXOVERSIZE, "TxOverSize"),
++ MIB_DESC(2, AR8236_STATS_TXBYTE, "TxByte"),
++ MIB_DESC(1, AR8236_STATS_TXCOLLISION, "TxCollision"),
++ MIB_DESC(1, AR8236_STATS_TXABORTCOL, "TxAbortCol"),
++ MIB_DESC(1, AR8236_STATS_TXMULTICOL, "TxMultiCol"),
++ MIB_DESC(1, AR8236_STATS_TXSINGLECOL, "TxSingleCol"),
++ MIB_DESC(1, AR8236_STATS_TXEXCDEFER, "TxExcDefer"),
++ MIB_DESC(1, AR8236_STATS_TXDEFER, "TxDefer"),
++ MIB_DESC(1, AR8236_STATS_TXLATECOL, "TxLateCol"),
++};
++
++static DEFINE_MUTEX(ar8xxx_dev_list_lock);
++static LIST_HEAD(ar8xxx_dev_list);
++
++static inline struct ar8xxx_priv *
++swdev_to_ar8xxx(struct switch_dev *swdev)
++{
++ return container_of(swdev, struct ar8xxx_priv, dev);
++}
++
++static inline bool ar8xxx_has_gige(struct ar8xxx_priv *priv)
++{
++ return priv->chip->caps & AR8XXX_CAP_GIGE;
++}
++
++static inline bool ar8xxx_has_mib_counters(struct ar8xxx_priv *priv)
++{
++ return priv->chip->caps & AR8XXX_CAP_MIB_COUNTERS;
++}
++
++static inline bool chip_is_ar8216(struct ar8xxx_priv *priv)
++{
++ return priv->chip_ver == AR8XXX_VER_AR8216;
++}
++
++static inline bool chip_is_ar8236(struct ar8xxx_priv *priv)
++{
++ return priv->chip_ver == AR8XXX_VER_AR8236;
++}
++
++static inline bool chip_is_ar8316(struct ar8xxx_priv *priv)
++{
++ return priv->chip_ver == AR8XXX_VER_AR8316;
++}
++
++static inline bool chip_is_ar8327(struct ar8xxx_priv *priv)
++{
++ return priv->chip_ver == AR8XXX_VER_AR8327;
++}
++
++static inline bool chip_is_ar8337(struct ar8xxx_priv *priv)
++{
++ return priv->chip_ver == AR8XXX_VER_AR8337;
++}
++
++static inline void
++split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page)
++{
++ regaddr >>= 1;
++ *r1 = regaddr & 0x1e;
++
++ regaddr >>= 5;
++ *r2 = regaddr & 0x7;
++
++ regaddr >>= 3;
++ *page = regaddr & 0x1ff;
++}
++
++static u32
++ar8xxx_mii_read(struct ar8xxx_priv *priv, int reg)
++{
++ struct mii_bus *bus = priv->mii_bus;
++ u16 r1, r2, page;
++ u16 lo, hi;
++
++ split_addr((u32) reg, &r1, &r2, &page);
++
++ mutex_lock(&bus->mdio_lock);
++
++ bus->write(bus, 0x18, 0, page);
++ usleep_range(1000, 2000); /* wait for the page switch to propagate */
++ lo = bus->read(bus, 0x10 | r2, r1);
++ hi = bus->read(bus, 0x10 | r2, r1 + 1);
++
++ mutex_unlock(&bus->mdio_lock);
++
++ return (hi << 16) | lo;
++}
++
++static void
++ar8xxx_mii_write(struct ar8xxx_priv *priv, int reg, u32 val)
++{
++ struct mii_bus *bus = priv->mii_bus;
++ u16 r1, r2, r3;
++ u16 lo, hi;
++
++ split_addr((u32) reg, &r1, &r2, &r3);
++ lo = val & 0xffff;
++ hi = (u16) (val >> 16);
++
++ mutex_lock(&bus->mdio_lock);
++
++ bus->write(bus, 0x18, 0, r3);
++ usleep_range(1000, 2000); /* wait for the page switch to propagate */
++ if (priv->mii_lo_first) {
++ bus->write(bus, 0x10 | r2, r1, lo);
++ bus->write(bus, 0x10 | r2, r1 + 1, hi);
++ } else {
++ bus->write(bus, 0x10 | r2, r1 + 1, hi);
++ bus->write(bus, 0x10 | r2, r1, lo);
++ }
++
++ mutex_unlock(&bus->mdio_lock);
++}
++
++static u32
++ar8xxx_mii_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val)
++{
++ struct mii_bus *bus = priv->mii_bus;
++ u16 r1, r2, page;
++ u16 lo, hi;
++ u32 ret;
++
++ split_addr((u32) reg, &r1, &r2, &page);
++
++ mutex_lock(&bus->mdio_lock);
++
++ bus->write(bus, 0x18, 0, page);
++ usleep_range(1000, 2000); /* wait for the page switch to propagate */
++
++ lo = bus->read(bus, 0x10 | r2, r1);
++ hi = bus->read(bus, 0x10 | r2, r1 + 1);
++
++ ret = hi << 16 | lo;
++ ret &= ~mask;
++ ret |= val;
++
++ lo = ret & 0xffff;
++ hi = (u16) (ret >> 16);
++
++ if (priv->mii_lo_first) {
++ bus->write(bus, 0x10 | r2, r1, lo);
++ bus->write(bus, 0x10 | r2, r1 + 1, hi);
++ } else {
++ bus->write(bus, 0x10 | r2, r1 + 1, hi);
++ bus->write(bus, 0x10 | r2, r1, lo);
++ }
++
++ mutex_unlock(&bus->mdio_lock);
++
++ return ret;
++}
++
++
++static void
++ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr,
++ u16 dbg_addr, u16 dbg_data)
++{
++ struct mii_bus *bus = priv->mii_bus;
++
++ mutex_lock(&bus->mdio_lock);
++ bus->write(bus, phy_addr, MII_ATH_DBG_ADDR, dbg_addr);
++ bus->write(bus, phy_addr, MII_ATH_DBG_DATA, dbg_data);
++ mutex_unlock(&bus->mdio_lock);
++}
++
++static void
++ar8xxx_phy_mmd_write(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 data)
++{
++ struct mii_bus *bus = priv->mii_bus;
++
++ mutex_lock(&bus->mdio_lock);
++ bus->write(bus, phy_addr, MII_ATH_MMD_ADDR, addr);
++ bus->write(bus, phy_addr, MII_ATH_MMD_DATA, data);
++ mutex_unlock(&bus->mdio_lock);
++}
++
++static inline u32
++ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val)
++{
++ return priv->rmw(priv, reg, mask, val);
++}
++
++static inline void
++ar8xxx_reg_set(struct ar8xxx_priv *priv, int reg, u32 val)
++{
++ priv->rmw(priv, reg, 0, val);
++}
++
++static int
++ar8xxx_reg_wait(struct ar8xxx_priv *priv, u32 reg, u32 mask, u32 val,
++ unsigned timeout)
++{
++ int i;
++
++ for (i = 0; i < timeout; i++) {
++ u32 t;
++
++ t = priv->read(priv, reg);
++ if ((t & mask) == val)
++ return 0;
++
++ usleep_range(1000, 2000);
++ }
++
++ return -ETIMEDOUT;
++}
++
++static int
++ar8xxx_mib_op(struct ar8xxx_priv *priv, u32 op)
++{
++ unsigned mib_func;
++ int ret;
++
++ lockdep_assert_held(&priv->mib_lock);
++
++ if (chip_is_ar8327(priv) || chip_is_ar8337(priv))
++ mib_func = AR8327_REG_MIB_FUNC;
++ else
++ mib_func = AR8216_REG_MIB_FUNC;
++
++ /* Capture the hardware statistics for all ports */
++ ar8xxx_rmw(priv, mib_func, AR8216_MIB_FUNC, (op << AR8216_MIB_FUNC_S));
++
++ /* Wait for the capturing to complete. */
++ ret = ar8xxx_reg_wait(priv, mib_func, AR8216_MIB_BUSY, 0, 10);
++ if (ret)
++ goto out;
++
++ ret = 0;
++
++out:
++ return ret;
++}
++
++static int
++ar8xxx_mib_capture(struct ar8xxx_priv *priv)
++{
++ return ar8xxx_mib_op(priv, AR8216_MIB_FUNC_CAPTURE);
++}
++
++static int
++ar8xxx_mib_flush(struct ar8xxx_priv *priv)
++{
++ return ar8xxx_mib_op(priv, AR8216_MIB_FUNC_FLUSH);
++}
++
++static void
++ar8xxx_mib_fetch_port_stat(struct ar8xxx_priv *priv, int port, bool flush)
++{
++ unsigned int base;
++ u64 *mib_stats;
++ int i;
++
++ WARN_ON(port >= priv->dev.ports);
++
++ lockdep_assert_held(&priv->mib_lock);
++
++ if (chip_is_ar8327(priv) || chip_is_ar8337(priv))
++ base = AR8327_REG_PORT_STATS_BASE(port);
++ else if (chip_is_ar8236(priv) ||
++ chip_is_ar8316(priv))
++ base = AR8236_REG_PORT_STATS_BASE(port);
++ else
++ base = AR8216_REG_PORT_STATS_BASE(port);
++
++ mib_stats = &priv->mib_stats[port * priv->chip->num_mibs];
++ for (i = 0; i < priv->chip->num_mibs; i++) {
++ const struct ar8xxx_mib_desc *mib;
++ u64 t;
++
++ mib = &priv->chip->mib_decs[i];
++ t = priv->read(priv, base + mib->offset);
++ if (mib->size == 2) {
++ u64 hi;
++
++ hi = priv->read(priv, base + mib->offset + 4);
++ t |= hi << 32;
++ }
++
++ if (flush)
++ mib_stats[i] = 0;
++ else
++ mib_stats[i] += t;
++ }
++}
++
++static void
++ar8216_read_port_link(struct ar8xxx_priv *priv, int port,
++ struct switch_port_link *link)
++{
++ u32 status;
++ u32 speed;
++
++ memset(link, '\0', sizeof(*link));
++
++ status = priv->chip->read_port_status(priv, port);
++
++ link->aneg = !!(status & AR8216_PORT_STATUS_LINK_AUTO);
++ if (link->aneg) {
++ link->link = !!(status & AR8216_PORT_STATUS_LINK_UP);
++ } else {
++ link->link = true;
++
++ if (priv->get_port_link) {
++ int err;
++
++ err = priv->get_port_link(port);
++ if (err >= 0)
++ link->link = !!err;
++ }
++ }
++
++ if (!link->link)
++ return;
++
++ link->duplex = !!(status & AR8216_PORT_STATUS_DUPLEX);
++ link->tx_flow = !!(status & AR8216_PORT_STATUS_TXFLOW);
++ link->rx_flow = !!(status & AR8216_PORT_STATUS_RXFLOW);
++
++ speed = (status & AR8216_PORT_STATUS_SPEED) >>
++ AR8216_PORT_STATUS_SPEED_S;
++
++ switch (speed) {
++ case AR8216_PORT_SPEED_10M:
++ link->speed = SWITCH_PORT_SPEED_10;
++ break;
++ case AR8216_PORT_SPEED_100M:
++ link->speed = SWITCH_PORT_SPEED_100;
++ break;
++ case AR8216_PORT_SPEED_1000M:
++ link->speed = SWITCH_PORT_SPEED_1000;
++ break;
++ default:
++ link->speed = SWITCH_PORT_SPEED_UNKNOWN;
++ break;
++ }
++}
++
++static struct sk_buff *
++ar8216_mangle_tx(struct net_device *dev, struct sk_buff *skb)
++{
++ struct ar8xxx_priv *priv = dev->phy_ptr;
++ unsigned char *buf;
++
++ if (unlikely(!priv))
++ goto error;
++
++ if (!priv->vlan)
++ goto send;
++
++ if (unlikely(skb_headroom(skb) < 2)) {
++ if (pskb_expand_head(skb, 2, 0, GFP_ATOMIC) < 0)
++ goto error;
++ }
++
++ buf = skb_push(skb, 2);
++ buf[0] = 0x10;
++ buf[1] = 0x80;
++
++send:
++ return skb;
++
++error:
++ dev_kfree_skb_any(skb);
++ return NULL;
++}
++
++static void
++ar8216_mangle_rx(struct net_device *dev, struct sk_buff *skb)
++{
++ struct ar8xxx_priv *priv;
++ unsigned char *buf;
++ int port, vlan;
++
++ priv = dev->phy_ptr;
++ if (!priv)
++ return;
++
++ /* don't strip the header if vlan mode is disabled */
++ if (!priv->vlan)
++ return;
++
++ /* strip header, get vlan id */
++ buf = skb->data;
++ skb_pull(skb, 2);
++
++ /* check for vlan header presence */
++ if ((buf[12 + 2] != 0x81) || (buf[13 + 2] != 0x00))
++ return;
++
++ port = buf[0] & 0xf;
++
++ /* no need to fix up packets coming from a tagged source */
++ if (priv->vlan_tagged & (1 << port))
++ return;
++
++ /* lookup port vid from local table, the switch passes an invalid vlan id */
++ vlan = priv->vlan_id[priv->pvid[port]];
++
++ buf[14 + 2] &= 0xf0;
++ buf[14 + 2] |= vlan >> 8;
++ buf[15 + 2] = vlan & 0xff;
++}
++
++static int
++ar8216_wait_bit(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val)
++{
++ int timeout = 20;
++ u32 t = 0;
++
++ while (1) {
++ t = priv->read(priv, reg);
++ if ((t & mask) == val)
++ return 0;
++
++ if (timeout-- <= 0)
++ break;
++
++ udelay(10);
++ }
++
++ pr_err("ar8216: timeout on reg %08x: %08x & %08x != %08x\n",
++ (unsigned int) reg, t, mask, val);
++ return -ETIMEDOUT;
++}
++
++static void
++ar8216_vtu_op(struct ar8xxx_priv *priv, u32 op, u32 val)
++{
++ if (ar8216_wait_bit(priv, AR8216_REG_VTU, AR8216_VTU_ACTIVE, 0))
++ return;
++ if ((op & AR8216_VTU_OP) == AR8216_VTU_OP_LOAD) {
++ val &= AR8216_VTUDATA_MEMBER;
++ val |= AR8216_VTUDATA_VALID;
++ priv->write(priv, AR8216_REG_VTU_DATA, val);
++ }
++ op |= AR8216_VTU_ACTIVE;
++ priv->write(priv, AR8216_REG_VTU, op);
++}
++
++static void
++ar8216_vtu_flush(struct ar8xxx_priv *priv)
++{
++ ar8216_vtu_op(priv, AR8216_VTU_OP_FLUSH, 0);
++}
++
++static void
++ar8216_vtu_load_vlan(struct ar8xxx_priv *priv, u32 vid, u32 port_mask)
++{
++ u32 op;
++
++ op = AR8216_VTU_OP_LOAD | (vid << AR8216_VTU_VID_S);
++ ar8216_vtu_op(priv, op, port_mask);
++}
++
++static int
++ar8216_atu_flush(struct ar8xxx_priv *priv)
++{
++ int ret;
++
++ ret = ar8216_wait_bit(priv, AR8216_REG_ATU, AR8216_ATU_ACTIVE, 0);
++ if (!ret)
++ priv->write(priv, AR8216_REG_ATU, AR8216_ATU_OP_FLUSH);
++
++ return ret;
++}
++
++static u32
++ar8216_read_port_status(struct ar8xxx_priv *priv, int port)
++{
++ return priv->read(priv, AR8216_REG_PORT_STATUS(port));
++}
++
++static void
++ar8216_setup_port(struct ar8xxx_priv *priv, int port, u32 egress, u32 ingress,
++ u32 members, u32 pvid)
++{
++ u32 header;
++
++ if (chip_is_ar8216(priv) && priv->vlan && port == AR8216_PORT_CPU)
++ header = AR8216_PORT_CTRL_HEADER;
++ else
++ header = 0;
++
++ ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port),
++ AR8216_PORT_CTRL_LEARN | AR8216_PORT_CTRL_VLAN_MODE |
++ AR8216_PORT_CTRL_SINGLE_VLAN | AR8216_PORT_CTRL_STATE |
++ AR8216_PORT_CTRL_HEADER | AR8216_PORT_CTRL_LEARN_LOCK,
++ AR8216_PORT_CTRL_LEARN | header |
++ (egress << AR8216_PORT_CTRL_VLAN_MODE_S) |
++ (AR8216_PORT_STATE_FORWARD << AR8216_PORT_CTRL_STATE_S));
++
++ ar8xxx_rmw(priv, AR8216_REG_PORT_VLAN(port),
++ AR8216_PORT_VLAN_DEST_PORTS | AR8216_PORT_VLAN_MODE |
++ AR8216_PORT_VLAN_DEFAULT_ID,
++ (members << AR8216_PORT_VLAN_DEST_PORTS_S) |
++ (ingress << AR8216_PORT_VLAN_MODE_S) |
++ (pvid << AR8216_PORT_VLAN_DEFAULT_ID_S));
++}
++
++static int
++ar8216_hw_init(struct ar8xxx_priv *priv)
++{
++ return 0;
++}
++
++static void
++ar8216_init_globals(struct ar8xxx_priv *priv)
++{
++ /* standard atheros magic */
++ priv->write(priv, 0x38, 0xc000050e);
++
++ ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL,
++ AR8216_GCTRL_MTU, 1518 + 8 + 2);
++}
++
++static void
++ar8216_init_port(struct ar8xxx_priv *priv, int port)
++{
++ /* Enable port learning and tx */
++ priv->write(priv, AR8216_REG_PORT_CTRL(port),
++ AR8216_PORT_CTRL_LEARN |
++ (4 << AR8216_PORT_CTRL_STATE_S));
++
++ priv->write(priv, AR8216_REG_PORT_VLAN(port), 0);
++
++ if (port == AR8216_PORT_CPU) {
++ priv->write(priv, AR8216_REG_PORT_STATUS(port),
++ AR8216_PORT_STATUS_LINK_UP |
++ (ar8xxx_has_gige(priv) ?
++ AR8216_PORT_SPEED_1000M : AR8216_PORT_SPEED_100M) |
++ AR8216_PORT_STATUS_TXMAC |
++ AR8216_PORT_STATUS_RXMAC |
++ (chip_is_ar8316(priv) ? AR8216_PORT_STATUS_RXFLOW : 0) |
++ (chip_is_ar8316(priv) ? AR8216_PORT_STATUS_TXFLOW : 0) |
++ AR8216_PORT_STATUS_DUPLEX);
++ } else {
++ priv->write(priv, AR8216_REG_PORT_STATUS(port),
++ AR8216_PORT_STATUS_LINK_AUTO);
++ }
++}
++
++static const struct ar8xxx_chip ar8216_chip = {
++ .caps = AR8XXX_CAP_MIB_COUNTERS,
++
++ .hw_init = ar8216_hw_init,
++ .init_globals = ar8216_init_globals,
++ .init_port = ar8216_init_port,
++ .setup_port = ar8216_setup_port,
++ .read_port_status = ar8216_read_port_status,
++ .atu_flush = ar8216_atu_flush,
++ .vtu_flush = ar8216_vtu_flush,
++ .vtu_load_vlan = ar8216_vtu_load_vlan,
++
++ .num_mibs = ARRAY_SIZE(ar8216_mibs),
++ .mib_decs = ar8216_mibs,
++};
++
++static void
++ar8236_setup_port(struct ar8xxx_priv *priv, int port, u32 egress, u32 ingress,
++ u32 members, u32 pvid)
++{
++ ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port),
++ AR8216_PORT_CTRL_LEARN | AR8216_PORT_CTRL_VLAN_MODE |
++ AR8216_PORT_CTRL_SINGLE_VLAN | AR8216_PORT_CTRL_STATE |
++ AR8216_PORT_CTRL_HEADER | AR8216_PORT_CTRL_LEARN_LOCK,
++ AR8216_PORT_CTRL_LEARN |
++ (egress << AR8216_PORT_CTRL_VLAN_MODE_S) |
++ (AR8216_PORT_STATE_FORWARD << AR8216_PORT_CTRL_STATE_S));
++
++ ar8xxx_rmw(priv, AR8236_REG_PORT_VLAN(port),
++ AR8236_PORT_VLAN_DEFAULT_ID,
++ (pvid << AR8236_PORT_VLAN_DEFAULT_ID_S));
++
++ ar8xxx_rmw(priv, AR8236_REG_PORT_VLAN2(port),
++ AR8236_PORT_VLAN2_VLAN_MODE |
++ AR8236_PORT_VLAN2_MEMBER,
++ (ingress << AR8236_PORT_VLAN2_VLAN_MODE_S) |
++ (members << AR8236_PORT_VLAN2_MEMBER_S));
++}
++
++static int
++ar8236_hw_init(struct ar8xxx_priv *priv)
++{
++ int i;
++ struct mii_bus *bus;
++
++ if (priv->initialized)
++ return 0;
++
++ /* Initialize the PHYs */
++ bus = priv->mii_bus;
++ for (i = 0; i < 5; i++) {
++ mdiobus_write(bus, i, MII_ADVERTISE,
++ ADVERTISE_ALL | ADVERTISE_PAUSE_CAP |
++ ADVERTISE_PAUSE_ASYM);
++ mdiobus_write(bus, i, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
++ }
++ msleep(1000);
++
++ priv->initialized = true;
++ return 0;
++}
++
++static void
++ar8236_init_globals(struct ar8xxx_priv *priv)
++{
++ /* enable jumbo frames */
++ ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL,
++ AR8316_GCTRL_MTU, 9018 + 8 + 2);
++
++ /* Enable MIB counters */
++ ar8xxx_rmw(priv, AR8216_REG_MIB_FUNC, AR8216_MIB_FUNC | AR8236_MIB_EN,
++ (AR8216_MIB_FUNC_NO_OP << AR8216_MIB_FUNC_S) |
++ AR8236_MIB_EN);
++}
++
++static const struct ar8xxx_chip ar8236_chip = {
++ .caps = AR8XXX_CAP_MIB_COUNTERS,
++ .hw_init = ar8236_hw_init,
++ .init_globals = ar8236_init_globals,
++ .init_port = ar8216_init_port,
++ .setup_port = ar8236_setup_port,
++ .read_port_status = ar8216_read_port_status,
++ .atu_flush = ar8216_atu_flush,
++ .vtu_flush = ar8216_vtu_flush,
++ .vtu_load_vlan = ar8216_vtu_load_vlan,
++
++ .num_mibs = ARRAY_SIZE(ar8236_mibs),
++ .mib_decs = ar8236_mibs,
++};
++
++static int
++ar8316_hw_init(struct ar8xxx_priv *priv)
++{
++ int i;
++ u32 val, newval;
++ struct mii_bus *bus;
++
++ val = priv->read(priv, AR8316_REG_POSTRIP);
++
++ if (priv->phy->interface == PHY_INTERFACE_MODE_RGMII) {
++ if (priv->port4_phy) {
++ /* value taken from Ubiquiti RouterStation Pro */
++ newval = 0x81461bea;
++ pr_info("ar8316: Using port 4 as PHY\n");
++ } else {
++ newval = 0x01261be2;
++ pr_info("ar8316: Using port 4 as switch port\n");
++ }
++ } else if (priv->phy->interface == PHY_INTERFACE_MODE_GMII) {
++ /* value taken from AVM Fritz!Box 7390 sources */
++ newval = 0x010e5b71;
++ } else {
++ /* no known value for phy interface */
++ pr_err("ar8316: unsupported mii mode: %d.\n",
++ priv->phy->interface);
++ return -EINVAL;
++ }
++
++ if (val == newval)
++ goto out;
++
++ priv->write(priv, AR8316_REG_POSTRIP, newval);
++
++ if (priv->port4_phy &&
++ priv->phy->interface == PHY_INTERFACE_MODE_RGMII) {
++ /* work around for phy4 rgmii mode */
++ ar8xxx_phy_dbg_write(priv, 4, 0x12, 0x480c);
++ /* rx delay */
++ ar8xxx_phy_dbg_write(priv, 4, 0x0, 0x824e);
++ /* tx delay */
++ ar8xxx_phy_dbg_write(priv, 4, 0x5, 0x3d47);
++ msleep(1000);
++ }
++
++ /* Initialize the ports */
++ bus = priv->mii_bus;
++ for (i = 0; i < 5; i++) {
++ /* initialize the port itself */
++ mdiobus_write(bus, i, MII_ADVERTISE,
++ ADVERTISE_ALL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
++ mdiobus_write(bus, i, MII_CTRL1000, ADVERTISE_1000FULL);
++ mdiobus_write(bus, i, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
++ }
++
++ msleep(1000);
++
++out:
++ priv->initialized = true;
++ return 0;
++}
++
++static void
++ar8316_init_globals(struct ar8xxx_priv *priv)
++{
++ /* standard atheros magic */
++ priv->write(priv, 0x38, 0xc000050e);
++
++ /* enable cpu port to receive multicast and broadcast frames */
++ priv->write(priv, AR8216_REG_FLOOD_MASK, 0x003f003f);
++
++ /* enable jumbo frames */
++ ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL,
++ AR8316_GCTRL_MTU, 9018 + 8 + 2);
++
++ /* Enable MIB counters */
++ ar8xxx_rmw(priv, AR8216_REG_MIB_FUNC, AR8216_MIB_FUNC | AR8236_MIB_EN,
++ (AR8216_MIB_FUNC_NO_OP << AR8216_MIB_FUNC_S) |
++ AR8236_MIB_EN);
++}
++
++static const struct ar8xxx_chip ar8316_chip = {
++ .caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS,
++ .hw_init = ar8316_hw_init,
++ .init_globals = ar8316_init_globals,
++ .init_port = ar8216_init_port,
++ .setup_port = ar8216_setup_port,
++ .read_port_status = ar8216_read_port_status,
++ .atu_flush = ar8216_atu_flush,
++ .vtu_flush = ar8216_vtu_flush,
++ .vtu_load_vlan = ar8216_vtu_load_vlan,
++
++ .num_mibs = ARRAY_SIZE(ar8236_mibs),
++ .mib_decs = ar8236_mibs,
++};
++
++static u32
++ar8327_get_pad_cfg(struct ar8327_pad_cfg *cfg)
++{
++ u32 t;
++
++ if (!cfg)
++ return 0;
++
++ t = 0;
++ switch (cfg->mode) {
++ case AR8327_PAD_NC:
++ break;
++
++ case AR8327_PAD_MAC2MAC_MII:
++ t = AR8327_PAD_MAC_MII_EN;
++ if (cfg->rxclk_sel)
++ t |= AR8327_PAD_MAC_MII_RXCLK_SEL;
++ if (cfg->txclk_sel)
++ t |= AR8327_PAD_MAC_MII_TXCLK_SEL;
++ break;
++
++ case AR8327_PAD_MAC2MAC_GMII:
++ t = AR8327_PAD_MAC_GMII_EN;
++ if (cfg->rxclk_sel)
++ t |= AR8327_PAD_MAC_GMII_RXCLK_SEL;
++ if (cfg->txclk_sel)
++ t |= AR8327_PAD_MAC_GMII_TXCLK_SEL;
++ break;
++
++ case AR8327_PAD_MAC_SGMII:
++ t = AR8327_PAD_SGMII_EN;
++
++ /*
++ * WAR for the QUalcomm Atheros AP136 board.
++ * It seems that RGMII TX/RX delay settings needs to be
++ * applied for SGMII mode as well, The ethernet is not
++ * reliable without this.
++ */
++ t |= cfg->txclk_delay_sel << AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S;
++ t |= cfg->rxclk_delay_sel << AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S;
++ if (cfg->rxclk_delay_en)
++ t |= AR8327_PAD_RGMII_RXCLK_DELAY_EN;
++ if (cfg->txclk_delay_en)
++ t |= AR8327_PAD_RGMII_TXCLK_DELAY_EN;
++
++ if (cfg->sgmii_delay_en)
++ t |= AR8327_PAD_SGMII_DELAY_EN;
++
++ break;
++
++ case AR8327_PAD_MAC2PHY_MII:
++ t = AR8327_PAD_PHY_MII_EN;
++ if (cfg->rxclk_sel)
++ t |= AR8327_PAD_PHY_MII_RXCLK_SEL;
++ if (cfg->txclk_sel)
++ t |= AR8327_PAD_PHY_MII_TXCLK_SEL;
++ break;
++
++ case AR8327_PAD_MAC2PHY_GMII:
++ t = AR8327_PAD_PHY_GMII_EN;
++ if (cfg->pipe_rxclk_sel)
++ t |= AR8327_PAD_PHY_GMII_PIPE_RXCLK_SEL;
++ if (cfg->rxclk_sel)
++ t |= AR8327_PAD_PHY_GMII_RXCLK_SEL;
++ if (cfg->txclk_sel)
++ t |= AR8327_PAD_PHY_GMII_TXCLK_SEL;
++ break;
++
++ case AR8327_PAD_MAC_RGMII:
++ t = AR8327_PAD_RGMII_EN;
++ t |= cfg->txclk_delay_sel << AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S;
++ t |= cfg->rxclk_delay_sel << AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S;
++ if (cfg->rxclk_delay_en)
++ t |= AR8327_PAD_RGMII_RXCLK_DELAY_EN;
++ if (cfg->txclk_delay_en)
++ t |= AR8327_PAD_RGMII_TXCLK_DELAY_EN;
++ break;
++
++ case AR8327_PAD_PHY_GMII:
++ t = AR8327_PAD_PHYX_GMII_EN;
++ break;
++
++ case AR8327_PAD_PHY_RGMII:
++ t = AR8327_PAD_PHYX_RGMII_EN;
++ break;
++
++ case AR8327_PAD_PHY_MII:
++ t = AR8327_PAD_PHYX_MII_EN;
++ break;
++ }
++
++ return t;
++}
++
++static void
++ar8327_phy_fixup(struct ar8xxx_priv *priv, int phy)
++{
++ switch (priv->chip_rev) {
++ case 1:
++ /* For 100M waveform */
++ ar8xxx_phy_dbg_write(priv, phy, 0, 0x02ea);
++ /* Turn on Gigabit clock */
++ ar8xxx_phy_dbg_write(priv, phy, 0x3d, 0x68a0);
++ break;
++
++ case 2:
++ ar8xxx_phy_mmd_write(priv, phy, 0x7, 0x3c);
++ ar8xxx_phy_mmd_write(priv, phy, 0x4007, 0x0);
++ /* fallthrough */
++ case 4:
++ ar8xxx_phy_mmd_write(priv, phy, 0x3, 0x800d);
++ ar8xxx_phy_mmd_write(priv, phy, 0x4003, 0x803f);
++
++ ar8xxx_phy_dbg_write(priv, phy, 0x3d, 0x6860);
++ ar8xxx_phy_dbg_write(priv, phy, 0x5, 0x2c46);
++ ar8xxx_phy_dbg_write(priv, phy, 0x3c, 0x6000);
++ break;
++ }
++}
++
++static u32
++ar8327_get_port_init_status(struct ar8327_port_cfg *cfg)
++{
++ u32 t;
++
++ if (!cfg->force_link)
++ return AR8216_PORT_STATUS_LINK_AUTO;
++
++ t = AR8216_PORT_STATUS_TXMAC | AR8216_PORT_STATUS_RXMAC;
++ t |= cfg->duplex ? AR8216_PORT_STATUS_DUPLEX : 0;
++ t |= cfg->rxpause ? AR8216_PORT_STATUS_RXFLOW : 0;
++ t |= cfg->txpause ? AR8216_PORT_STATUS_TXFLOW : 0;
++
++ switch (cfg->speed) {
++ case AR8327_PORT_SPEED_10:
++ t |= AR8216_PORT_SPEED_10M;
++ break;
++ case AR8327_PORT_SPEED_100:
++ t |= AR8216_PORT_SPEED_100M;
++ break;
++ case AR8327_PORT_SPEED_1000:
++ t |= AR8216_PORT_SPEED_1000M;
++ break;
++ }
++
++ return t;
++}
++
++#define AR8327_LED_ENTRY(_num, _reg, _shift) \
++ [_num] = { .reg = (_reg), .shift = (_shift) }
++
++static const struct ar8327_led_entry
++ar8327_led_map[AR8327_NUM_LEDS] = {
++ AR8327_LED_ENTRY(AR8327_LED_PHY0_0, 0, 14),
++ AR8327_LED_ENTRY(AR8327_LED_PHY0_1, 1, 14),
++ AR8327_LED_ENTRY(AR8327_LED_PHY0_2, 2, 14),
++
++ AR8327_LED_ENTRY(AR8327_LED_PHY1_0, 3, 8),
++ AR8327_LED_ENTRY(AR8327_LED_PHY1_1, 3, 10),
++ AR8327_LED_ENTRY(AR8327_LED_PHY1_2, 3, 12),
++
++ AR8327_LED_ENTRY(AR8327_LED_PHY2_0, 3, 14),
++ AR8327_LED_ENTRY(AR8327_LED_PHY2_1, 3, 16),
++ AR8327_LED_ENTRY(AR8327_LED_PHY2_2, 3, 18),
++
++ AR8327_LED_ENTRY(AR8327_LED_PHY3_0, 3, 20),
++ AR8327_LED_ENTRY(AR8327_LED_PHY3_1, 3, 22),
++ AR8327_LED_ENTRY(AR8327_LED_PHY3_2, 3, 24),
++
++ AR8327_LED_ENTRY(AR8327_LED_PHY4_0, 0, 30),
++ AR8327_LED_ENTRY(AR8327_LED_PHY4_1, 1, 30),
++ AR8327_LED_ENTRY(AR8327_LED_PHY4_2, 2, 30),
++};
++
++static void
++ar8327_set_led_pattern(struct ar8xxx_priv *priv, unsigned int led_num,
++ enum ar8327_led_pattern pattern)
++{
++ const struct ar8327_led_entry *entry;
++
++ entry = &ar8327_led_map[led_num];
++ ar8xxx_rmw(priv, AR8327_REG_LED_CTRL(entry->reg),
++ (3 << entry->shift), pattern << entry->shift);
++}
++
++static void
++ar8327_led_work_func(struct work_struct *work)
++{
++ struct ar8327_led *aled;
++ u8 pattern;
++
++ aled = container_of(work, struct ar8327_led, led_work);
++
++ spin_lock(&aled->lock);
++ pattern = aled->pattern;
++ spin_unlock(&aled->lock);
++
++ ar8327_set_led_pattern(aled->sw_priv, aled->led_num,
++ pattern);
++}
++
++static void
++ar8327_led_schedule_change(struct ar8327_led *aled, u8 pattern)
++{
++ if (aled->pattern == pattern)
++ return;
++
++ aled->pattern = pattern;
++ schedule_work(&aled->led_work);
++}
++
++static inline struct ar8327_led *
++led_cdev_to_ar8327_led(struct led_classdev *led_cdev)
++{
++ return container_of(led_cdev, struct ar8327_led, cdev);
++}
++
++static int
++ar8327_led_blink_set(struct led_classdev *led_cdev,
++ unsigned long *delay_on,
++ unsigned long *delay_off)
++{
++ struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev);
++
++ if (*delay_on == 0 && *delay_off == 0) {
++ *delay_on = 125;
++ *delay_off = 125;
++ }
++
++ if (*delay_on != 125 || *delay_off != 125) {
++ /*
++ * The hardware only supports blinking at 4Hz. Fall back
++ * to software implementation in other cases.
++ */
++ return -EINVAL;
++ }
++
++ spin_lock(&aled->lock);
++
++ aled->enable_hw_mode = false;
++ ar8327_led_schedule_change(aled, AR8327_LED_PATTERN_BLINK);
++
++ spin_unlock(&aled->lock);
++
++ return 0;
++}
++
++static void
++ar8327_led_set_brightness(struct led_classdev *led_cdev,
++ enum led_brightness brightness)
++{
++ struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev);
++ u8 pattern;
++ bool active;
++
++ active = (brightness != LED_OFF);
++ active ^= aled->active_low;
++
++ pattern = (active) ? AR8327_LED_PATTERN_ON :
++ AR8327_LED_PATTERN_OFF;
++
++ spin_lock(&aled->lock);
++
++ aled->enable_hw_mode = false;
++ ar8327_led_schedule_change(aled, pattern);
++
++ spin_unlock(&aled->lock);
++}
++
++static ssize_t
++ar8327_led_enable_hw_mode_show(struct device *dev,
++ struct device_attribute *attr,
++ char *buf)
++{
++ struct led_classdev *led_cdev = dev_get_drvdata(dev);
++ struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev);
++ ssize_t ret = 0;
++
++ spin_lock(&aled->lock);
++ ret += sprintf(buf, "%d\n", aled->enable_hw_mode);
++ spin_unlock(&aled->lock);
++
++ return ret;
++}
++
++static ssize_t
++ar8327_led_enable_hw_mode_store(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf,
++ size_t size)
++{
++ struct led_classdev *led_cdev = dev_get_drvdata(dev);
++ struct ar8327_led *aled = led_cdev_to_ar8327_led(led_cdev);
++ u8 pattern;
++ u8 value;
++ int ret;
++
++ ret = kstrtou8(buf, 10, &value);
++ if (ret < 0)
++ return -EINVAL;
++
++ spin_lock(&aled->lock);
++
++ aled->enable_hw_mode = !!value;
++ if (aled->enable_hw_mode)
++ pattern = AR8327_LED_PATTERN_RULE;
++ else
++ pattern = AR8327_LED_PATTERN_OFF;
++
++ ar8327_led_schedule_change(aled, pattern);
++
++ spin_unlock(&aled->lock);
++
++ return size;
++}
++
++static DEVICE_ATTR(enable_hw_mode, S_IRUGO | S_IWUSR,
++ ar8327_led_enable_hw_mode_show,
++ ar8327_led_enable_hw_mode_store);
++
++static int
++ar8327_led_register(struct ar8xxx_priv *priv, struct ar8327_led *aled)
++{
++ int ret;
++
++ ret = led_classdev_register(NULL, &aled->cdev);
++ if (ret < 0)
++ return ret;
++
++ if (aled->mode == AR8327_LED_MODE_HW) {
++ ret = device_create_file(aled->cdev.dev,
++ &dev_attr_enable_hw_mode);
++ if (ret)
++ goto err_unregister;
++ }
++
++ return 0;
++
++err_unregister:
++ led_classdev_unregister(&aled->cdev);
++ return ret;
++}
++
++static void
++ar8327_led_unregister(struct ar8327_led *aled)
++{
++ if (aled->mode == AR8327_LED_MODE_HW)
++ device_remove_file(aled->cdev.dev, &dev_attr_enable_hw_mode);
++
++ led_classdev_unregister(&aled->cdev);
++ cancel_work_sync(&aled->led_work);
++}
++
++static int
++ar8327_led_create(struct ar8xxx_priv *priv,
++ const struct ar8327_led_info *led_info)
++{
++ struct ar8327_data *data = &priv->chip_data.ar8327;
++ struct ar8327_led *aled;
++ int ret;
++
++ if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS))
++ return 0;
++
++ if (!led_info->name)
++ return -EINVAL;
++
++ if (led_info->led_num >= AR8327_NUM_LEDS)
++ return -EINVAL;
++
++ aled = kzalloc(sizeof(*aled) + strlen(led_info->name) + 1,
++ GFP_KERNEL);
++ if (!aled)
++ return -ENOMEM;
++
++ aled->sw_priv = priv;
++ aled->led_num = led_info->led_num;
++ aled->active_low = led_info->active_low;
++ aled->mode = led_info->mode;
++
++ if (aled->mode == AR8327_LED_MODE_HW)
++ aled->enable_hw_mode = true;
++
++ aled->name = (char *)(aled + 1);
++ strcpy(aled->name, led_info->name);
++
++ aled->cdev.name = aled->name;
++ aled->cdev.brightness_set = ar8327_led_set_brightness;
++ aled->cdev.blink_set = ar8327_led_blink_set;
++ aled->cdev.default_trigger = led_info->default_trigger;
++
++ spin_lock_init(&aled->lock);
++ mutex_init(&aled->mutex);
++ INIT_WORK(&aled->led_work, ar8327_led_work_func);
++
++ ret = ar8327_led_register(priv, aled);
++ if (ret)
++ goto err_free;
++
++ data->leds[data->num_leds++] = aled;
++
++ return 0;
++
++err_free:
++ kfree(aled);
++ return ret;
++}
++
++static void
++ar8327_led_destroy(struct ar8327_led *aled)
++{
++ ar8327_led_unregister(aled);
++ kfree(aled);
++}
++
++static void
++ar8327_leds_init(struct ar8xxx_priv *priv)
++{
++ struct ar8327_data *data;
++ unsigned i;
++
++ if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS))
++ return;
++
++ data = &priv->chip_data.ar8327;
++
++ for (i = 0; i < data->num_leds; i++) {
++ struct ar8327_led *aled;
++
++ aled = data->leds[i];
++
++ if (aled->enable_hw_mode)
++ aled->pattern = AR8327_LED_PATTERN_RULE;
++ else
++ aled->pattern = AR8327_LED_PATTERN_OFF;
++
++ ar8327_set_led_pattern(priv, aled->led_num, aled->pattern);
++ }
++}
++
++static void
++ar8327_leds_cleanup(struct ar8xxx_priv *priv)
++{
++ struct ar8327_data *data = &priv->chip_data.ar8327;
++ unsigned i;
++
++ if (!IS_ENABLED(CONFIG_AR8216_PHY_LEDS))
++ return;
++
++ for (i = 0; i < data->num_leds; i++) {
++ struct ar8327_led *aled;
++
++ aled = data->leds[i];
++ ar8327_led_destroy(aled);
++ }
++
++ kfree(data->leds);
++}
++
++static int
++ar8327_hw_config_pdata(struct ar8xxx_priv *priv,
++ struct ar8327_platform_data *pdata)
++{
++ struct ar8327_led_cfg *led_cfg;
++ struct ar8327_data *data;
++ u32 pos, new_pos;
++ u32 t;
++
++ if (!pdata)
++ return -EINVAL;
++
++ priv->get_port_link = pdata->get_port_link;
++
++ data = &priv->chip_data.ar8327;
++
++ data->port0_status = ar8327_get_port_init_status(&pdata->port0_cfg);
++ data->port6_status = ar8327_get_port_init_status(&pdata->port6_cfg);
++
++ t = ar8327_get_pad_cfg(pdata->pad0_cfg);
++ if (chip_is_ar8337(priv))
++ t |= AR8337_PAD_MAC06_EXCHANGE_EN;
++
++ priv->write(priv, AR8327_REG_PAD0_MODE, t);
++ t = ar8327_get_pad_cfg(pdata->pad5_cfg);
++ priv->write(priv, AR8327_REG_PAD5_MODE, t);
++ t = ar8327_get_pad_cfg(pdata->pad6_cfg);
++ priv->write(priv, AR8327_REG_PAD6_MODE, t);
++
++ pos = priv->read(priv, AR8327_REG_POWER_ON_STRIP);
++ new_pos = pos;
++
++ led_cfg = pdata->led_cfg;
++ if (led_cfg) {
++ if (led_cfg->open_drain)
++ new_pos |= AR8327_POWER_ON_STRIP_LED_OPEN_EN;
++ else
++ new_pos &= ~AR8327_POWER_ON_STRIP_LED_OPEN_EN;
++
++ priv->write(priv, AR8327_REG_LED_CTRL0, led_cfg->led_ctrl0);
++ priv->write(priv, AR8327_REG_LED_CTRL1, led_cfg->led_ctrl1);
++ priv->write(priv, AR8327_REG_LED_CTRL2, led_cfg->led_ctrl2);
++ priv->write(priv, AR8327_REG_LED_CTRL3, led_cfg->led_ctrl3);
++
++ if (new_pos != pos)
++ new_pos |= AR8327_POWER_ON_STRIP_POWER_ON_SEL;
++ }
++
++ if (pdata->sgmii_cfg) {
++ t = pdata->sgmii_cfg->sgmii_ctrl;
++ if (priv->chip_rev == 1)
++ t |= AR8327_SGMII_CTRL_EN_PLL |
++ AR8327_SGMII_CTRL_EN_RX |
++ AR8327_SGMII_CTRL_EN_TX;
++ else
++ t &= ~(AR8327_SGMII_CTRL_EN_PLL |
++ AR8327_SGMII_CTRL_EN_RX |
++ AR8327_SGMII_CTRL_EN_TX);
++
++ priv->write(priv, AR8327_REG_SGMII_CTRL, t);
++
++ if (pdata->sgmii_cfg->serdes_aen)
++ new_pos &= ~AR8327_POWER_ON_STRIP_SERDES_AEN;
++ else
++ new_pos |= AR8327_POWER_ON_STRIP_SERDES_AEN;
++ }
++
++ priv->write(priv, AR8327_REG_POWER_ON_STRIP, new_pos);
++
++ if (pdata->leds && pdata->num_leds) {
++ int i;
++
++ data->leds = kzalloc(pdata->num_leds * sizeof(void *),
++ GFP_KERNEL);
++ if (!data->leds)
++ return -ENOMEM;
++
++ for (i = 0; i < pdata->num_leds; i++)
++ ar8327_led_create(priv, &pdata->leds[i]);
++ }
++
++ return 0;
++}
++
++#ifdef CONFIG_OF
++static int
++ar8327_hw_config_of(struct ar8xxx_priv *priv, struct device_node *np)
++{
++ const __be32 *paddr;
++ int len;
++ int i;
++
++ paddr = of_get_property(np, "qca,ar8327-initvals", &len);
++ if (!paddr || len < (2 * sizeof(*paddr)))
++ return -EINVAL;
++
++ len /= sizeof(*paddr);
++
++ for (i = 0; i < len - 1; i += 2) {
++ u32 reg;
++ u32 val;
++
++ reg = be32_to_cpup(paddr + i);
++ val = be32_to_cpup(paddr + i + 1);
++
++ switch (reg) {
++ case AR8327_REG_PORT_STATUS(0):
++ priv->chip_data.ar8327.port0_status = val;
++ break;
++ case AR8327_REG_PORT_STATUS(6):
++ priv->chip_data.ar8327.port6_status = val;
++ break;
++ default:
++ priv->write(priv, reg, val);
++ break;
++ }
++ }
++
++ return 0;
++}
++#else
++static inline int
++ar8327_hw_config_of(struct ar8xxx_priv *priv, struct device_node *np)
++{
++ return -EINVAL;
++}
++#endif
++
++static int
++ar8327_hw_init(struct ar8xxx_priv *priv)
++{
++ struct mii_bus *bus;
++ int ret;
++ int i;
++
++ if (priv->phy->dev.of_node)
++ ret = ar8327_hw_config_of(priv, priv->phy->dev.of_node);
++ else
++ ret = ar8327_hw_config_pdata(priv,
++ priv->phy->dev.platform_data);
++
++ if (ret)
++ return ret;
++
++ ar8327_leds_init(priv);
++
++ bus = priv->mii_bus;
++ for (i = 0; i < AR8327_NUM_PHYS; i++) {
++ ar8327_phy_fixup(priv, i);
++
++ /* start aneg on the PHY */
++ mdiobus_write(bus, i, MII_ADVERTISE, ADVERTISE_ALL |
++ ADVERTISE_PAUSE_CAP |
++ ADVERTISE_PAUSE_ASYM);
++ mdiobus_write(bus, i, MII_CTRL1000, ADVERTISE_1000FULL);
++ mdiobus_write(bus, i, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
++ }
++
++ msleep(1000);
++
++ return 0;
++}
++
++static void
++ar8327_cleanup(struct ar8xxx_priv *priv)
++{
++ ar8327_leds_cleanup(priv);
++}
++
++static void
++ar8327_init_globals(struct ar8xxx_priv *priv)
++{
++ u32 t;
++
++ /* enable CPU port and disable mirror port */
++ t = AR8327_FWD_CTRL0_CPU_PORT_EN |
++ AR8327_FWD_CTRL0_MIRROR_PORT;
++ priv->write(priv, AR8327_REG_FWD_CTRL0, t);
++
++ /* forward multicast and broadcast frames to CPU */
++ t = (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_UC_FLOOD_S) |
++ (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_MC_FLOOD_S) |
++ (AR8327_PORTS_ALL << AR8327_FWD_CTRL1_BC_FLOOD_S);
++ priv->write(priv, AR8327_REG_FWD_CTRL1, t);
++
++ /* enable jumbo frames */
++ ar8xxx_rmw(priv, AR8327_REG_MAX_FRAME_SIZE,
++ AR8327_MAX_FRAME_SIZE_MTU, 9018 + 8 + 2);
++
++ /* Enable MIB counters */
++ ar8xxx_reg_set(priv, AR8327_REG_MODULE_EN,
++ AR8327_MODULE_EN_MIB);
++}
++
++static void
++ar8327_init_port(struct ar8xxx_priv *priv, int port)
++{
++ u32 t;
++
++ if (port == AR8216_PORT_CPU)
++ t = priv->chip_data.ar8327.port0_status;
++ else if (port == 6)
++ t = priv->chip_data.ar8327.port6_status;
++ else
++ t = AR8216_PORT_STATUS_LINK_AUTO;
++
++ priv->write(priv, AR8327_REG_PORT_STATUS(port), t);
++ priv->write(priv, AR8327_REG_PORT_HEADER(port), 0);
++
++ t = 1 << AR8327_PORT_VLAN0_DEF_SVID_S;
++ t |= 1 << AR8327_PORT_VLAN0_DEF_CVID_S;
++ priv->write(priv, AR8327_REG_PORT_VLAN0(port), t);
++
++ t = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH << AR8327_PORT_VLAN1_OUT_MODE_S;
++ priv->write(priv, AR8327_REG_PORT_VLAN1(port), t);
++
++ t = AR8327_PORT_LOOKUP_LEARN;
++ t |= AR8216_PORT_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S;
++ priv->write(priv, AR8327_REG_PORT_LOOKUP(port), t);
++}
++
++static u32
++ar8327_read_port_status(struct ar8xxx_priv *priv, int port)
++{
++ return priv->read(priv, AR8327_REG_PORT_STATUS(port));
++}
++
++static int
++ar8327_atu_flush(struct ar8xxx_priv *priv)
++{
++ int ret;
++
++ ret = ar8216_wait_bit(priv, AR8327_REG_ATU_FUNC,
++ AR8327_ATU_FUNC_BUSY, 0);
++ if (!ret)
++ priv->write(priv, AR8327_REG_ATU_FUNC,
++ AR8327_ATU_FUNC_OP_FLUSH);
++
++ return ret;
++}
++
++static void
++ar8327_vtu_op(struct ar8xxx_priv *priv, u32 op, u32 val)
++{
++ if (ar8216_wait_bit(priv, AR8327_REG_VTU_FUNC1,
++ AR8327_VTU_FUNC1_BUSY, 0))
++ return;
++
++ if ((op & AR8327_VTU_FUNC1_OP) == AR8327_VTU_FUNC1_OP_LOAD)
++ priv->write(priv, AR8327_REG_VTU_FUNC0, val);
++
++ op |= AR8327_VTU_FUNC1_BUSY;
++ priv->write(priv, AR8327_REG_VTU_FUNC1, op);
++}
++
++static void
++ar8327_vtu_flush(struct ar8xxx_priv *priv)
++{
++ ar8327_vtu_op(priv, AR8327_VTU_FUNC1_OP_FLUSH, 0);
++}
++
++static void
++ar8327_vtu_load_vlan(struct ar8xxx_priv *priv, u32 vid, u32 port_mask)
++{
++ u32 op;
++ u32 val;
++ int i;
++
++ op = AR8327_VTU_FUNC1_OP_LOAD | (vid << AR8327_VTU_FUNC1_VID_S);
++ val = AR8327_VTU_FUNC0_VALID | AR8327_VTU_FUNC0_IVL;
++ for (i = 0; i < AR8327_NUM_PORTS; i++) {
++ u32 mode;
++
++ if ((port_mask & BIT(i)) == 0)
++ mode = AR8327_VTU_FUNC0_EG_MODE_NOT;
++ else if (priv->vlan == 0)
++ mode = AR8327_VTU_FUNC0_EG_MODE_KEEP;
++ else if (priv->vlan_tagged & BIT(i))
++ mode = AR8327_VTU_FUNC0_EG_MODE_TAG;
++ else
++ mode = AR8327_VTU_FUNC0_EG_MODE_UNTAG;
++
++ val |= mode << AR8327_VTU_FUNC0_EG_MODE_S(i);
++ }
++ ar8327_vtu_op(priv, op, val);
++}
++
++static void
++ar8327_setup_port(struct ar8xxx_priv *priv, int port, u32 egress, u32 ingress,
++ u32 members, u32 pvid)
++{
++ u32 t;
++ u32 mode;
++
++ t = pvid << AR8327_PORT_VLAN0_DEF_SVID_S;
++ t |= pvid << AR8327_PORT_VLAN0_DEF_CVID_S;
++ priv->write(priv, AR8327_REG_PORT_VLAN0(port), t);
++
++ mode = AR8327_PORT_VLAN1_OUT_MODE_UNMOD;
++ switch (egress) {
++ case AR8216_OUT_KEEP:
++ mode = AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH;
++ break;
++ case AR8216_OUT_STRIP_VLAN:
++ mode = AR8327_PORT_VLAN1_OUT_MODE_UNTAG;
++ break;
++ case AR8216_OUT_ADD_VLAN:
++ mode = AR8327_PORT_VLAN1_OUT_MODE_TAG;
++ break;
++ }
++
++ t = AR8327_PORT_VLAN1_PORT_VLAN_PROP;
++ t |= mode << AR8327_PORT_VLAN1_OUT_MODE_S;
++ priv->write(priv, AR8327_REG_PORT_VLAN1(port), t);
++
++ t = members;
++ t |= AR8327_PORT_LOOKUP_LEARN;
++ t |= ingress << AR8327_PORT_LOOKUP_IN_MODE_S;
++ t |= AR8216_PORT_STATE_FORWARD << AR8327_PORT_LOOKUP_STATE_S;
++ priv->write(priv, AR8327_REG_PORT_LOOKUP(port), t);
++}
++
++static const struct ar8xxx_chip ar8327_chip = {
++ .caps = AR8XXX_CAP_GIGE | AR8XXX_CAP_MIB_COUNTERS,
++ .hw_init = ar8327_hw_init,
++ .cleanup = ar8327_cleanup,
++ .init_globals = ar8327_init_globals,
++ .init_port = ar8327_init_port,
++ .setup_port = ar8327_setup_port,
++ .read_port_status = ar8327_read_port_status,
++ .atu_flush = ar8327_atu_flush,
++ .vtu_flush = ar8327_vtu_flush,
++ .vtu_load_vlan = ar8327_vtu_load_vlan,
++
++ .num_mibs = ARRAY_SIZE(ar8236_mibs),
++ .mib_decs = ar8236_mibs,
++};
++
++static int
++ar8xxx_sw_set_vlan(struct switch_dev *dev, const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
++ priv->vlan = !!val->value.i;
++ return 0;
++}
++
++static int
++ar8xxx_sw_get_vlan(struct switch_dev *dev, const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
++ val->value.i = priv->vlan;
++ return 0;
++}
++
++
++static int
++ar8xxx_sw_set_pvid(struct switch_dev *dev, int port, int vlan)
++{
++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
++
++ /* make sure no invalid PVIDs get set */
++
++ if (vlan >= dev->vlans)
++ return -EINVAL;
++
++ priv->pvid[port] = vlan;
++ return 0;
++}
++
++static int
++ar8xxx_sw_get_pvid(struct switch_dev *dev, int port, int *vlan)
++{
++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
++ *vlan = priv->pvid[port];
++ return 0;
++}
++
++static int
++ar8xxx_sw_set_vid(struct switch_dev *dev, const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
++ priv->vlan_id[val->port_vlan] = val->value.i;
++ return 0;
++}
++
++static int
++ar8xxx_sw_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
++ val->value.i = priv->vlan_id[val->port_vlan];
++ return 0;
++}
++
++static int
++ar8xxx_sw_get_port_link(struct switch_dev *dev, int port,
++ struct switch_port_link *link)
++{
++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
++
++ ar8216_read_port_link(priv, port, link);
++ return 0;
++}
++
++static int
++ar8xxx_sw_get_ports(struct switch_dev *dev, struct switch_val *val)
++{
++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
++ u8 ports = priv->vlan_table[val->port_vlan];
++ int i;
++
++ val->len = 0;
++ for (i = 0; i < dev->ports; i++) {
++ struct switch_port *p;
++
++ if (!(ports & (1 << i)))
++ continue;
++
++ p = &val->value.ports[val->len++];
++ p->id = i;
++ if (priv->vlan_tagged & (1 << i))
++ p->flags = (1 << SWITCH_PORT_FLAG_TAGGED);
++ else
++ p->flags = 0;
++ }
++ return 0;
++}
++
++static int
++ar8xxx_sw_set_ports(struct switch_dev *dev, struct switch_val *val)
++{
++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
++ u8 *vt = &priv->vlan_table[val->port_vlan];
++ int i, j;
++
++ *vt = 0;
++ for (i = 0; i < val->len; i++) {
++ struct switch_port *p = &val->value.ports[i];
++
++ if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) {
++ priv->vlan_tagged |= (1 << p->id);
++ } else {
++ priv->vlan_tagged &= ~(1 << p->id);
++ priv->pvid[p->id] = val->port_vlan;
++
++ /* make sure that an untagged port does not
++ * appear in other vlans */
++ for (j = 0; j < AR8X16_MAX_VLANS; j++) {
++ if (j == val->port_vlan)
++ continue;
++ priv->vlan_table[j] &= ~(1 << p->id);
++ }
++ }
++
++ *vt |= 1 << p->id;
++ }
++ return 0;
++}
++
++static void
++ar8327_set_mirror_regs(struct ar8xxx_priv *priv)
++{
++ int port;
++
++ /* reset all mirror registers */
++ ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL0,
++ AR8327_FWD_CTRL0_MIRROR_PORT,
++ (0xF << AR8327_FWD_CTRL0_MIRROR_PORT_S));
++ for (port = 0; port < AR8327_NUM_PORTS; port++) {
++ ar8xxx_rmw(priv, AR8327_REG_PORT_LOOKUP(port),
++ AR8327_PORT_LOOKUP_ING_MIRROR_EN,
++ 0);
++
++ ar8xxx_rmw(priv, AR8327_REG_PORT_HOL_CTRL1(port),
++ AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN,
++ 0);
++ }
++
++ /* now enable mirroring if necessary */
++ if (priv->source_port >= AR8327_NUM_PORTS ||
++ priv->monitor_port >= AR8327_NUM_PORTS ||
++ priv->source_port == priv->monitor_port) {
++ return;
++ }
++
++ ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL0,
++ AR8327_FWD_CTRL0_MIRROR_PORT,
++ (priv->monitor_port << AR8327_FWD_CTRL0_MIRROR_PORT_S));
++
++ if (priv->mirror_rx)
++ ar8xxx_rmw(priv, AR8327_REG_PORT_LOOKUP(priv->source_port),
++ AR8327_PORT_LOOKUP_ING_MIRROR_EN,
++ AR8327_PORT_LOOKUP_ING_MIRROR_EN);
++
++ if (priv->mirror_tx)
++ ar8xxx_rmw(priv, AR8327_REG_PORT_HOL_CTRL1(priv->source_port),
++ AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN,
++ AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN);
++}
++
++static void
++ar8216_set_mirror_regs(struct ar8xxx_priv *priv)
++{
++ int port;
++
++ /* reset all mirror registers */
++ ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CPUPORT,
++ AR8216_GLOBAL_CPUPORT_MIRROR_PORT,
++ (0xF << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S));
++ for (port = 0; port < AR8216_NUM_PORTS; port++) {
++ ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port),
++ AR8216_PORT_CTRL_MIRROR_RX,
++ 0);
++
++ ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port),
++ AR8216_PORT_CTRL_MIRROR_TX,
++ 0);
++ }
++
++ /* now enable mirroring if necessary */
++ if (priv->source_port >= AR8216_NUM_PORTS ||
++ priv->monitor_port >= AR8216_NUM_PORTS ||
++ priv->source_port == priv->monitor_port) {
++ return;
++ }
++
++ ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CPUPORT,
++ AR8216_GLOBAL_CPUPORT_MIRROR_PORT,
++ (priv->monitor_port << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S));
++
++ if (priv->mirror_rx)
++ ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(priv->source_port),
++ AR8216_PORT_CTRL_MIRROR_RX,
++ AR8216_PORT_CTRL_MIRROR_RX);
++
++ if (priv->mirror_tx)
++ ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(priv->source_port),
++ AR8216_PORT_CTRL_MIRROR_TX,
++ AR8216_PORT_CTRL_MIRROR_TX);
++}
++
++static void
++ar8xxx_set_mirror_regs(struct ar8xxx_priv *priv)
++{
++ if (chip_is_ar8327(priv) || chip_is_ar8337(priv)) {
++ ar8327_set_mirror_regs(priv);
++ } else {
++ ar8216_set_mirror_regs(priv);
++ }
++}
++
++static int
++ar8xxx_sw_hw_apply(struct switch_dev *dev)
++{
++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
++ u8 portmask[AR8X16_MAX_PORTS];
++ int i, j;
++
++ mutex_lock(&priv->reg_mutex);
++ /* flush all vlan translation unit entries */
++ priv->chip->vtu_flush(priv);
++
++ memset(portmask, 0, sizeof(portmask));
++ if (!priv->init) {
++ /* calculate the port destination masks and load vlans
++ * into the vlan translation unit */
++ for (j = 0; j < AR8X16_MAX_VLANS; j++) {
++ u8 vp = priv->vlan_table[j];
++
++ if (!vp)
++ continue;
++
++ for (i = 0; i < dev->ports; i++) {
++ u8 mask = (1 << i);
++ if (vp & mask)
++ portmask[i] |= vp & ~mask;
++ }
++
++ priv->chip->vtu_load_vlan(priv, priv->vlan_id[j],
++ priv->vlan_table[j]);
++ }
++ } else {
++ /* vlan disabled:
++ * isolate all ports, but connect them to the cpu port */
++ for (i = 0; i < dev->ports; i++) {
++ if (i == AR8216_PORT_CPU)
++ continue;
++
++ portmask[i] = 1 << AR8216_PORT_CPU;
++ portmask[AR8216_PORT_CPU] |= (1 << i);
++ }
++ }
++
++ /* update the port destination mask registers and tag settings */
++ for (i = 0; i < dev->ports; i++) {
++ int egress, ingress;
++ int pvid;
++
++ if (priv->vlan) {
++ pvid = priv->vlan_id[priv->pvid[i]];
++ if (priv->vlan_tagged & (1 << i))
++ egress = AR8216_OUT_ADD_VLAN;
++ else
++ egress = AR8216_OUT_STRIP_VLAN;
++ ingress = AR8216_IN_SECURE;
++ } else {
++ pvid = i;
++ egress = AR8216_OUT_KEEP;
++ ingress = AR8216_IN_PORT_ONLY;
++ }
++
++ priv->chip->setup_port(priv, i, egress, ingress, portmask[i],
++ pvid);
++ }
++
++ ar8xxx_set_mirror_regs(priv);
++
++ mutex_unlock(&priv->reg_mutex);
++ return 0;
++}
++
++static int
++ar8xxx_sw_reset_switch(struct switch_dev *dev)
++{
++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
++ int i;
++
++ mutex_lock(&priv->reg_mutex);
++ memset(&priv->vlan, 0, sizeof(struct ar8xxx_priv) -
++ offsetof(struct ar8xxx_priv, vlan));
++
++ for (i = 0; i < AR8X16_MAX_VLANS; i++)
++ priv->vlan_id[i] = i;
++
++ /* Configure all ports */
++ for (i = 0; i < dev->ports; i++)
++ priv->chip->init_port(priv, i);
++
++ priv->mirror_rx = false;
++ priv->mirror_tx = false;
++ priv->source_port = 0;
++ priv->monitor_port = 0;
++
++ priv->chip->init_globals(priv);
++
++ mutex_unlock(&priv->reg_mutex);
++
++ return ar8xxx_sw_hw_apply(dev);
++}
++
++static int
++ar8xxx_sw_set_reset_mibs(struct switch_dev *dev,
++ const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
++ unsigned int len;
++ int ret;
++
++ if (!ar8xxx_has_mib_counters(priv))
++ return -EOPNOTSUPP;
++
++ mutex_lock(&priv->mib_lock);
++
++ len = priv->dev.ports * priv->chip->num_mibs *
++ sizeof(*priv->mib_stats);
++ memset(priv->mib_stats, '\0', len);
++ ret = ar8xxx_mib_flush(priv);
++ if (ret)
++ goto unlock;
++
++ ret = 0;
++
++unlock:
++ mutex_unlock(&priv->mib_lock);
++ return ret;
++}
++
++static int
++ar8xxx_sw_set_mirror_rx_enable(struct switch_dev *dev,
++ const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
++
++ mutex_lock(&priv->reg_mutex);
++ priv->mirror_rx = !!val->value.i;
++ ar8xxx_set_mirror_regs(priv);
++ mutex_unlock(&priv->reg_mutex);
++
++ return 0;
++}
++
++static int
++ar8xxx_sw_get_mirror_rx_enable(struct switch_dev *dev,
++ const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
++ val->value.i = priv->mirror_rx;
++ return 0;
++}
++
++static int
++ar8xxx_sw_set_mirror_tx_enable(struct switch_dev *dev,
++ const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
++
++ mutex_lock(&priv->reg_mutex);
++ priv->mirror_tx = !!val->value.i;
++ ar8xxx_set_mirror_regs(priv);
++ mutex_unlock(&priv->reg_mutex);
++
++ return 0;
++}
++
++static int
++ar8xxx_sw_get_mirror_tx_enable(struct switch_dev *dev,
++ const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
++ val->value.i = priv->mirror_tx;
++ return 0;
++}
++
++static int
++ar8xxx_sw_set_mirror_monitor_port(struct switch_dev *dev,
++ const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
++
++ mutex_lock(&priv->reg_mutex);
++ priv->monitor_port = val->value.i;
++ ar8xxx_set_mirror_regs(priv);
++ mutex_unlock(&priv->reg_mutex);
++
++ return 0;
++}
++
++static int
++ar8xxx_sw_get_mirror_monitor_port(struct switch_dev *dev,
++ const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
++ val->value.i = priv->monitor_port;
++ return 0;
++}
++
++static int
++ar8xxx_sw_set_mirror_source_port(struct switch_dev *dev,
++ const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
++
++ mutex_lock(&priv->reg_mutex);
++ priv->source_port = val->value.i;
++ ar8xxx_set_mirror_regs(priv);
++ mutex_unlock(&priv->reg_mutex);
++
++ return 0;
++}
++
++static int
++ar8xxx_sw_get_mirror_source_port(struct switch_dev *dev,
++ const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
++ val->value.i = priv->source_port;
++ return 0;
++}
++
++static int
++ar8xxx_sw_set_port_reset_mib(struct switch_dev *dev,
++ const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
++ int port;
++ int ret;
++
++ if (!ar8xxx_has_mib_counters(priv))
++ return -EOPNOTSUPP;
++
++ port = val->port_vlan;
++ if (port >= dev->ports)
++ return -EINVAL;
++
++ mutex_lock(&priv->mib_lock);
++ ret = ar8xxx_mib_capture(priv);
++ if (ret)
++ goto unlock;
++
++ ar8xxx_mib_fetch_port_stat(priv, port, true);
++
++ ret = 0;
++
++unlock:
++ mutex_unlock(&priv->mib_lock);
++ return ret;
++}
++
++static int
++ar8xxx_sw_get_port_mib(struct switch_dev *dev,
++ const struct switch_attr *attr,
++ struct switch_val *val)
++{
++ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
++ const struct ar8xxx_chip *chip = priv->chip;
++ u64 *mib_stats;
++ int port;
++ int ret;
++ char *buf = priv->buf;
++ int i, len = 0;
++
++ if (!ar8xxx_has_mib_counters(priv))
++ return -EOPNOTSUPP;
++
++ port = val->port_vlan;
++ if (port >= dev->ports)
++ return -EINVAL;
++
++ mutex_lock(&priv->mib_lock);
++ ret = ar8xxx_mib_capture(priv);
++ if (ret)
++ goto unlock;
++
++ ar8xxx_mib_fetch_port_stat(priv, port, false);
++
++ len += snprintf(buf + len, sizeof(priv->buf) - len,
++ "Port %d MIB counters\n",
++ port);
++
++ mib_stats = &priv->mib_stats[port * chip->num_mibs];
++ for (i = 0; i < chip->num_mibs; i++)
++ len += snprintf(buf + len, sizeof(priv->buf) - len,
++ "%-12s: %llu\n",
++ chip->mib_decs[i].name,
++ mib_stats[i]);
++
++ val->value.s = buf;
++ val->len = len;
++
++ ret = 0;
++
++unlock:
++ mutex_unlock(&priv->mib_lock);
++ return ret;
++}
++
++static struct switch_attr ar8xxx_sw_attr_globals[] = {
++ {
++ .type = SWITCH_TYPE_INT,
++ .name = "enable_vlan",
++ .description = "Enable VLAN mode",
++ .set = ar8xxx_sw_set_vlan,
++ .get = ar8xxx_sw_get_vlan,
++ .max = 1
++ },
++ {
++ .type = SWITCH_TYPE_NOVAL,
++ .name = "reset_mibs",
++ .description = "Reset all MIB counters",
++ .set = ar8xxx_sw_set_reset_mibs,
++ },
++ {
++ .type = SWITCH_TYPE_INT,
++ .name = "enable_mirror_rx",
++ .description = "Enable mirroring of RX packets",
++ .set = ar8xxx_sw_set_mirror_rx_enable,
++ .get = ar8xxx_sw_get_mirror_rx_enable,
++ .max = 1
++ },
++ {
++ .type = SWITCH_TYPE_INT,
++ .name = "enable_mirror_tx",
++ .description = "Enable mirroring of TX packets",
++ .set = ar8xxx_sw_set_mirror_tx_enable,
++ .get = ar8xxx_sw_get_mirror_tx_enable,
++ .max = 1
++ },
++ {
++ .type = SWITCH_TYPE_INT,
++ .name = "mirror_monitor_port",
++ .description = "Mirror monitor port",
++ .set = ar8xxx_sw_set_mirror_monitor_port,
++ .get = ar8xxx_sw_get_mirror_monitor_port,
++ .max = AR8216_NUM_PORTS - 1
++ },
++ {
++ .type = SWITCH_TYPE_INT,
++ .name = "mirror_source_port",
++ .description = "Mirror source port",
++ .set = ar8xxx_sw_set_mirror_source_port,
++ .get = ar8xxx_sw_get_mirror_source_port,
++ .max = AR8216_NUM_PORTS - 1
++ },
++};
++
++static struct switch_attr ar8327_sw_attr_globals[] = {
++ {
++ .type = SWITCH_TYPE_INT,
++ .name = "enable_vlan",
++ .description = "Enable VLAN mode",
++ .set = ar8xxx_sw_set_vlan,
++ .get = ar8xxx_sw_get_vlan,
++ .max = 1
++ },
++ {
++ .type = SWITCH_TYPE_NOVAL,
++ .name = "reset_mibs",
++ .description = "Reset all MIB counters",
++ .set = ar8xxx_sw_set_reset_mibs,
++ },
++ {
++ .type = SWITCH_TYPE_INT,
++ .name = "enable_mirror_rx",
++ .description = "Enable mirroring of RX packets",
++ .set = ar8xxx_sw_set_mirror_rx_enable,
++ .get = ar8xxx_sw_get_mirror_rx_enable,
++ .max = 1
++ },
++ {
++ .type = SWITCH_TYPE_INT,
++ .name = "enable_mirror_tx",
++ .description = "Enable mirroring of TX packets",
++ .set = ar8xxx_sw_set_mirror_tx_enable,
++ .get = ar8xxx_sw_get_mirror_tx_enable,
++ .max = 1
++ },
++ {
++ .type = SWITCH_TYPE_INT,
++ .name = "mirror_monitor_port",
++ .description = "Mirror monitor port",
++ .set = ar8xxx_sw_set_mirror_monitor_port,
++ .get = ar8xxx_sw_get_mirror_monitor_port,
++ .max = AR8327_NUM_PORTS - 1
++ },
++ {
++ .type = SWITCH_TYPE_INT,
++ .name = "mirror_source_port",
++ .description = "Mirror source port",
++ .set = ar8xxx_sw_set_mirror_source_port,
++ .get = ar8xxx_sw_get_mirror_source_port,
++ .max = AR8327_NUM_PORTS - 1
++ },
++};
++
++static struct switch_attr ar8xxx_sw_attr_port[] = {
++ {
++ .type = SWITCH_TYPE_NOVAL,
++ .name = "reset_mib",
++ .description = "Reset single port MIB counters",
++ .set = ar8xxx_sw_set_port_reset_mib,
++ },
++ {
++ .type = SWITCH_TYPE_STRING,
++ .name = "mib",
++ .description = "Get port's MIB counters",
++ .set = NULL,
++ .get = ar8xxx_sw_get_port_mib,
++ },
++};
++
++static struct switch_attr ar8xxx_sw_attr_vlan[] = {
++ {
++ .type = SWITCH_TYPE_INT,
++ .name = "vid",
++ .description = "VLAN ID (0-4094)",
++ .set = ar8xxx_sw_set_vid,
++ .get = ar8xxx_sw_get_vid,
++ .max = 4094,
++ },
++};
++
++static const struct switch_dev_ops ar8xxx_sw_ops = {
++ .attr_global = {
++ .attr = ar8xxx_sw_attr_globals,
++ .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_globals),
++ },
++ .attr_port = {
++ .attr = ar8xxx_sw_attr_port,
++ .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_port),
++ },
++ .attr_vlan = {
++ .attr = ar8xxx_sw_attr_vlan,
++ .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_vlan),
++ },
++ .get_port_pvid = ar8xxx_sw_get_pvid,
++ .set_port_pvid = ar8xxx_sw_set_pvid,
++ .get_vlan_ports = ar8xxx_sw_get_ports,
++ .set_vlan_ports = ar8xxx_sw_set_ports,
++ .apply_config = ar8xxx_sw_hw_apply,
++ .reset_switch = ar8xxx_sw_reset_switch,
++ .get_port_link = ar8xxx_sw_get_port_link,
++};
++
++static const struct switch_dev_ops ar8327_sw_ops = {
++ .attr_global = {
++ .attr = ar8327_sw_attr_globals,
++ .n_attr = ARRAY_SIZE(ar8327_sw_attr_globals),
++ },
++ .attr_port = {
++ .attr = ar8xxx_sw_attr_port,
++ .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_port),
++ },
++ .attr_vlan = {
++ .attr = ar8xxx_sw_attr_vlan,
++ .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_vlan),
++ },
++ .get_port_pvid = ar8xxx_sw_get_pvid,
++ .set_port_pvid = ar8xxx_sw_set_pvid,
++ .get_vlan_ports = ar8xxx_sw_get_ports,
++ .set_vlan_ports = ar8xxx_sw_set_ports,
++ .apply_config = ar8xxx_sw_hw_apply,
++ .reset_switch = ar8xxx_sw_reset_switch,
++ .get_port_link = ar8xxx_sw_get_port_link,
++};
++
++static int
++ar8xxx_id_chip(struct ar8xxx_priv *priv)
++{
++ u32 val;
++ u16 id;
++ int i;
++
++ val = priv->read(priv, AR8216_REG_CTRL);
++ if (val == ~0)
++ return -ENODEV;
++
++ id = val & (AR8216_CTRL_REVISION | AR8216_CTRL_VERSION);
++ for (i = 0; i < AR8X16_PROBE_RETRIES; i++) {
++ u16 t;
++
++ val = priv->read(priv, AR8216_REG_CTRL);
++ if (val == ~0)
++ return -ENODEV;
++
++ t = val & (AR8216_CTRL_REVISION | AR8216_CTRL_VERSION);
++ if (t != id)
++ return -ENODEV;
++ }
++
++ priv->chip_ver = (id & AR8216_CTRL_VERSION) >> AR8216_CTRL_VERSION_S;
++ priv->chip_rev = (id & AR8216_CTRL_REVISION);
++
++ switch (priv->chip_ver) {
++ case AR8XXX_VER_AR8216:
++ priv->chip = &ar8216_chip;
++ break;
++ case AR8XXX_VER_AR8236:
++ priv->chip = &ar8236_chip;
++ break;
++ case AR8XXX_VER_AR8316:
++ priv->chip = &ar8316_chip;
++ break;
++ case AR8XXX_VER_AR8327:
++ priv->mii_lo_first = true;
++ priv->chip = &ar8327_chip;
++ break;
++ case AR8XXX_VER_AR8337:
++ priv->mii_lo_first = true;
++ priv->chip = &ar8327_chip;
++ break;
++ default:
++ pr_err("ar8216: Unknown Atheros device [ver=%d, rev=%d]\n",
++ priv->chip_ver, priv->chip_rev);
++
++ return -ENODEV;
++ }
++
++ return 0;
++}
++
++static void
++ar8xxx_mib_work_func(struct work_struct *work)
++{
++ struct ar8xxx_priv *priv;
++ int err;
++
++ priv = container_of(work, struct ar8xxx_priv, mib_work.work);
++
++ mutex_lock(&priv->mib_lock);
++
++ err = ar8xxx_mib_capture(priv);
++ if (err)
++ goto next_port;
++
++ ar8xxx_mib_fetch_port_stat(priv, priv->mib_next_port, false);
++
++next_port:
++ priv->mib_next_port++;
++ if (priv->mib_next_port >= priv->dev.ports)
++ priv->mib_next_port = 0;
++
++ mutex_unlock(&priv->mib_lock);
++ schedule_delayed_work(&priv->mib_work,
++ msecs_to_jiffies(AR8XXX_MIB_WORK_DELAY));
++}
++
++static int
++ar8xxx_mib_init(struct ar8xxx_priv *priv)
++{
++ unsigned int len;
++
++ if (!ar8xxx_has_mib_counters(priv))
++ return 0;
++
++ BUG_ON(!priv->chip->mib_decs || !priv->chip->num_mibs);
++
++ len = priv->dev.ports * priv->chip->num_mibs *
++ sizeof(*priv->mib_stats);
++ priv->mib_stats = kzalloc(len, GFP_KERNEL);
++
++ if (!priv->mib_stats)
++ return -ENOMEM;
++
++ return 0;
++}
++
++static void
++ar8xxx_mib_start(struct ar8xxx_priv *priv)
++{
++ if (!ar8xxx_has_mib_counters(priv))
++ return;
++
++ schedule_delayed_work(&priv->mib_work,
++ msecs_to_jiffies(AR8XXX_MIB_WORK_DELAY));
++}
++
++static void
++ar8xxx_mib_stop(struct ar8xxx_priv *priv)
++{
++ if (!ar8xxx_has_mib_counters(priv))
++ return;
++
++ cancel_delayed_work(&priv->mib_work);
++}
++
++static struct ar8xxx_priv *
++ar8xxx_create(void)
++{
++ struct ar8xxx_priv *priv;
++
++ priv = kzalloc(sizeof(struct ar8xxx_priv), GFP_KERNEL);
++ if (priv == NULL)
++ return NULL;
++
++ mutex_init(&priv->reg_mutex);
++ mutex_init(&priv->mib_lock);
++ INIT_DELAYED_WORK(&priv->mib_work, ar8xxx_mib_work_func);
++
++ return priv;
++}
++
++static void
++ar8xxx_free(struct ar8xxx_priv *priv)
++{
++ if (priv->chip && priv->chip->cleanup)
++ priv->chip->cleanup(priv);
++
++ kfree(priv->mib_stats);
++ kfree(priv);
++}
++
++static struct ar8xxx_priv *
++ar8xxx_create_mii(struct mii_bus *bus)
++{
++ struct ar8xxx_priv *priv;
++
++ priv = ar8xxx_create();
++ if (priv) {
++ priv->mii_bus = bus;
++ priv->read = ar8xxx_mii_read;
++ priv->write = ar8xxx_mii_write;
++ priv->rmw = ar8xxx_mii_rmw;
++ }
++
++ return priv;
++}
++
++static int
++ar8xxx_probe_switch(struct ar8xxx_priv *priv)
++{
++ struct switch_dev *swdev;
++ int ret;
++
++ ret = ar8xxx_id_chip(priv);
++ if (ret)
++ return ret;
++
++ swdev = &priv->dev;
++ swdev->cpu_port = AR8216_PORT_CPU;
++ swdev->ops = &ar8xxx_sw_ops;
++
++ if (chip_is_ar8316(priv)) {
++ swdev->name = "Atheros AR8316";
++ swdev->vlans = AR8X16_MAX_VLANS;
++ swdev->ports = AR8216_NUM_PORTS;
++ } else if (chip_is_ar8236(priv)) {
++ swdev->name = "Atheros AR8236";
++ swdev->vlans = AR8216_NUM_VLANS;
++ swdev->ports = AR8216_NUM_PORTS;
++ } else if (chip_is_ar8327(priv)) {
++ swdev->name = "Atheros AR8327";
++ swdev->vlans = AR8X16_MAX_VLANS;
++ swdev->ports = AR8327_NUM_PORTS;
++ swdev->ops = &ar8327_sw_ops;
++ } else if (chip_is_ar8337(priv)) {
++ swdev->name = "Atheros AR8337";
++ swdev->vlans = AR8X16_MAX_VLANS;
++ swdev->ports = AR8327_NUM_PORTS;
++ swdev->ops = &ar8327_sw_ops;
++ } else {
++ swdev->name = "Atheros AR8216";
++ swdev->vlans = AR8216_NUM_VLANS;
++ swdev->ports = AR8216_NUM_PORTS;
++ }
++
++ ret = ar8xxx_mib_init(priv);
++ if (ret)
++ return ret;
++
++ return 0;
++}
++
++static int
++ar8xxx_start(struct ar8xxx_priv *priv)
++{
++ int ret;
++
++ priv->init = true;
++
++ ret = priv->chip->hw_init(priv);
++ if (ret)
++ return ret;
++
++ ret = ar8xxx_sw_reset_switch(&priv->dev);
++ if (ret)
++ return ret;
++
++ priv->init = false;
++
++ ar8xxx_mib_start(priv);
++
++ return 0;
++}
++
++static int
++ar8xxx_phy_config_init(struct phy_device *phydev)
++{
++ struct ar8xxx_priv *priv = phydev->priv;
++ struct net_device *dev = phydev->attached_dev;
++ int ret;
++
++ if (WARN_ON(!priv))
++ return -ENODEV;
++
++ if (chip_is_ar8327(priv) || chip_is_ar8337(priv))
++ return 0;
++
++ priv->phy = phydev;
++
++ if (phydev->addr != 0) {
++ if (chip_is_ar8316(priv)) {
++ /* switch device has been initialized, reinit */
++ priv->dev.ports = (AR8216_NUM_PORTS - 1);
++ priv->initialized = false;
++ priv->port4_phy = true;
++ ar8316_hw_init(priv);
++ return 0;
++ }
++
++ return 0;
++ }
++
++ ret = ar8xxx_start(priv);
++ if (ret)
++ return ret;
++
++ /* VID fixup only needed on ar8216 */
++ if (chip_is_ar8216(priv)) {
++ dev->phy_ptr = priv;
++ dev->priv_flags |= IFF_NO_IP_ALIGN;
++ dev->eth_mangle_rx = ar8216_mangle_rx;
++ dev->eth_mangle_tx = ar8216_mangle_tx;
++ }
++
++ return 0;
++}
++
++static int
++ar8xxx_phy_read_status(struct phy_device *phydev)
++{
++ struct ar8xxx_priv *priv = phydev->priv;
++ struct switch_port_link link;
++ int ret;
++
++ if (phydev->addr != 0)
++ return genphy_read_status(phydev);
++
++ ar8216_read_port_link(priv, phydev->addr, &link);
++ phydev->link = !!link.link;
++ if (!phydev->link)
++ return 0;
++
++ switch (link.speed) {
++ case SWITCH_PORT_SPEED_10:
++ phydev->speed = SPEED_10;
++ break;
++ case SWITCH_PORT_SPEED_100:
++ phydev->speed = SPEED_100;
++ break;
++ case SWITCH_PORT_SPEED_1000:
++ phydev->speed = SPEED_1000;
++ break;
++ default:
++ phydev->speed = 0;
++ }
++ phydev->duplex = link.duplex ? DUPLEX_FULL : DUPLEX_HALF;
++
++ /* flush the address translation unit */
++ mutex_lock(&priv->reg_mutex);
++ ret = priv->chip->atu_flush(priv);
++ mutex_unlock(&priv->reg_mutex);
++
++ phydev->state = PHY_RUNNING;
++ netif_carrier_on(phydev->attached_dev);
++ phydev->adjust_link(phydev->attached_dev);
++
++ return ret;
++}
++
++static int
++ar8xxx_phy_config_aneg(struct phy_device *phydev)
++{
++ if (phydev->addr == 0)
++ return 0;
++
++ return genphy_config_aneg(phydev);
++}
++
++static const u32 ar8xxx_phy_ids[] = {
++ 0x004dd033,
++ 0x004dd034, /* AR8327 */
++ 0x004dd036, /* AR8337 */
++ 0x004dd041,
++ 0x004dd042,
++};
++
++static bool
++ar8xxx_phy_match(u32 phy_id)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(ar8xxx_phy_ids); i++)
++ if (phy_id == ar8xxx_phy_ids[i])
++ return true;
++
++ return false;
++}
++
++static bool
++ar8xxx_is_possible(struct mii_bus *bus)
++{
++ unsigned i;
++
++ for (i = 0; i < 4; i++) {
++ u32 phy_id;
++
++ phy_id = mdiobus_read(bus, i, MII_PHYSID1) << 16;
++ phy_id |= mdiobus_read(bus, i, MII_PHYSID2);
++ if (!ar8xxx_phy_match(phy_id)) {
++ pr_debug("ar8xxx: unknown PHY at %s:%02x id:%08x\n",
++ dev_name(&bus->dev), i, phy_id);
++ return false;
++ }
++ }
++
++ return true;
++}
++
++static int
++ar8xxx_phy_probe(struct phy_device *phydev)
++{
++ struct ar8xxx_priv *priv;
++ struct switch_dev *swdev;
++ int ret;
++
++ /* skip PHYs at unused adresses */
++ if (phydev->addr != 0 && phydev->addr != 4)
++ return -ENODEV;
++
++ if (!ar8xxx_is_possible(phydev->bus))
++ return -ENODEV;
++
++ mutex_lock(&ar8xxx_dev_list_lock);
++ list_for_each_entry(priv, &ar8xxx_dev_list, list)
++ if (priv->mii_bus == phydev->bus)
++ goto found;
++
++ priv = ar8xxx_create_mii(phydev->bus);
++ if (priv == NULL) {
++ ret = -ENOMEM;
++ goto unlock;
++ }
++
++ ret = ar8xxx_probe_switch(priv);
++ if (ret)
++ goto free_priv;
++
++ swdev = &priv->dev;
++ swdev->alias = dev_name(&priv->mii_bus->dev);
++ ret = register_switch(swdev, NULL);
++ if (ret)
++ goto free_priv;
++
++ pr_info("%s: %s rev. %u switch registered on %s\n",
++ swdev->devname, swdev->name, priv->chip_rev,
++ dev_name(&priv->mii_bus->dev));
++
++found:
++ priv->use_count++;
++
++ if (phydev->addr == 0) {
++ if (ar8xxx_has_gige(priv)) {
++ phydev->supported = SUPPORTED_1000baseT_Full;
++ phydev->advertising = ADVERTISED_1000baseT_Full;
++ } else {
++ phydev->supported = SUPPORTED_100baseT_Full;
++ phydev->advertising = ADVERTISED_100baseT_Full;
++ }
++
++ if (chip_is_ar8327(priv) || chip_is_ar8337(priv)) {
++ priv->phy = phydev;
++
++ ret = ar8xxx_start(priv);
++ if (ret)
++ goto err_unregister_switch;
++ }
++ } else {
++ if (ar8xxx_has_gige(priv)) {
++ phydev->supported |= SUPPORTED_1000baseT_Full;
++ phydev->advertising |= ADVERTISED_1000baseT_Full;
++ }
++ }
++
++ phydev->priv = priv;
++
++ list_add(&priv->list, &ar8xxx_dev_list);
++
++ mutex_unlock(&ar8xxx_dev_list_lock);
++
++ return 0;
++
++err_unregister_switch:
++ if (--priv->use_count)
++ goto unlock;
++
++ unregister_switch(&priv->dev);
++
++free_priv:
++ ar8xxx_free(priv);
++unlock:
++ mutex_unlock(&ar8xxx_dev_list_lock);
++ return ret;
++}
++
++static void
++ar8xxx_phy_detach(struct phy_device *phydev)
++{
++ struct net_device *dev = phydev->attached_dev;
++
++ if (!dev)
++ return;
++
++ dev->phy_ptr = NULL;
++ dev->priv_flags &= ~IFF_NO_IP_ALIGN;
++ dev->eth_mangle_rx = NULL;
++ dev->eth_mangle_tx = NULL;
++}
++
++static void
++ar8xxx_phy_remove(struct phy_device *phydev)
++{
++ struct ar8xxx_priv *priv = phydev->priv;
++
++ if (WARN_ON(!priv))
++ return;
++
++ phydev->priv = NULL;
++ if (--priv->use_count > 0)
++ return;
++
++ mutex_lock(&ar8xxx_dev_list_lock);
++ list_del(&priv->list);
++ mutex_unlock(&ar8xxx_dev_list_lock);
++
++ unregister_switch(&priv->dev);
++ ar8xxx_mib_stop(priv);
++ ar8xxx_free(priv);
++}
++
++static struct phy_driver ar8xxx_phy_driver = {
++ .phy_id = 0x004d0000,
++ .name = "Atheros AR8216/AR8236/AR8316",
++ .phy_id_mask = 0xffff0000,
++ .features = PHY_BASIC_FEATURES,
++ .probe = ar8xxx_phy_probe,
++ .remove = ar8xxx_phy_remove,
++ .detach = ar8xxx_phy_detach,
++ .config_init = ar8xxx_phy_config_init,
++ .config_aneg = ar8xxx_phy_config_aneg,
++ .read_status = ar8xxx_phy_read_status,
++ .driver = { .owner = THIS_MODULE },
++};
++
++int __init
++ar8xxx_init(void)
++{
++ return phy_driver_register(&ar8xxx_phy_driver);
++}
++
++void __exit
++ar8xxx_exit(void)
++{
++ phy_driver_unregister(&ar8xxx_phy_driver);
++}
++
++module_init(ar8xxx_init);
++module_exit(ar8xxx_exit);
++MODULE_LICENSE("GPL");
++
+diff --git a/drivers/net/phy/ar8216.h b/drivers/net/phy/ar8216.h
+new file mode 100644
+index 0000000..00d6d7f
+--- /dev/null
++++ b/drivers/net/phy/ar8216.h
+@@ -0,0 +1,492 @@
++/*
++ * ar8216.h: AR8216 switch driver
++ *
++ * Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef __AR8216_H
++#define __AR8216_H
++
++#define BITS(_s, _n) (((1UL << (_n)) - 1) << _s)
++
++#define AR8216_PORT_CPU 0
++#define AR8216_NUM_PORTS 6
++#define AR8216_NUM_VLANS 16
++#define AR8316_NUM_VLANS 4096
++
++/* Atheros specific MII registers */
++#define MII_ATH_MMD_ADDR 0x0d
++#define MII_ATH_MMD_DATA 0x0e
++#define MII_ATH_DBG_ADDR 0x1d
++#define MII_ATH_DBG_DATA 0x1e
++
++#define AR8216_REG_CTRL 0x0000
++#define AR8216_CTRL_REVISION BITS(0, 8)
++#define AR8216_CTRL_REVISION_S 0
++#define AR8216_CTRL_VERSION BITS(8, 8)
++#define AR8216_CTRL_VERSION_S 8
++#define AR8216_CTRL_RESET BIT(31)
++
++#define AR8216_REG_FLOOD_MASK 0x002C
++#define AR8216_FM_UNI_DEST_PORTS BITS(0, 6)
++#define AR8216_FM_MULTI_DEST_PORTS BITS(16, 6)
++
++#define AR8216_REG_GLOBAL_CTRL 0x0030
++#define AR8216_GCTRL_MTU BITS(0, 11)
++#define AR8236_GCTRL_MTU BITS(0, 14)
++#define AR8316_GCTRL_MTU BITS(0, 14)
++
++#define AR8216_REG_VTU 0x0040
++#define AR8216_VTU_OP BITS(0, 3)
++#define AR8216_VTU_OP_NOOP 0x0
++#define AR8216_VTU_OP_FLUSH 0x1
++#define AR8216_VTU_OP_LOAD 0x2
++#define AR8216_VTU_OP_PURGE 0x3
++#define AR8216_VTU_OP_REMOVE_PORT 0x4
++#define AR8216_VTU_ACTIVE BIT(3)
++#define AR8216_VTU_FULL BIT(4)
++#define AR8216_VTU_PORT BITS(8, 4)
++#define AR8216_VTU_PORT_S 8
++#define AR8216_VTU_VID BITS(16, 12)
++#define AR8216_VTU_VID_S 16
++#define AR8216_VTU_PRIO BITS(28, 3)
++#define AR8216_VTU_PRIO_S 28
++#define AR8216_VTU_PRIO_EN BIT(31)
++
++#define AR8216_REG_VTU_DATA 0x0044
++#define AR8216_VTUDATA_MEMBER BITS(0, 10)
++#define AR8236_VTUDATA_MEMBER BITS(0, 7)
++#define AR8216_VTUDATA_VALID BIT(11)
++
++#define AR8216_REG_ATU 0x0050
++#define AR8216_ATU_OP BITS(0, 3)
++#define AR8216_ATU_OP_NOOP 0x0
++#define AR8216_ATU_OP_FLUSH 0x1
++#define AR8216_ATU_OP_LOAD 0x2
++#define AR8216_ATU_OP_PURGE 0x3
++#define AR8216_ATU_OP_FLUSH_LOCKED 0x4
++#define AR8216_ATU_OP_FLUSH_UNICAST 0x5
++#define AR8216_ATU_OP_GET_NEXT 0x6
++#define AR8216_ATU_ACTIVE BIT(3)
++#define AR8216_ATU_PORT_NUM BITS(8, 4)
++#define AR8216_ATU_FULL_VIO BIT(12)
++#define AR8216_ATU_ADDR4 BITS(16, 8)
++#define AR8216_ATU_ADDR5 BITS(24, 8)
++
++#define AR8216_REG_ATU_DATA 0x0054
++#define AR8216_ATU_ADDR3 BITS(0, 8)
++#define AR8216_ATU_ADDR2 BITS(8, 8)
++#define AR8216_ATU_ADDR1 BITS(16, 8)
++#define AR8216_ATU_ADDR0 BITS(24, 8)
++
++#define AR8216_REG_ATU_CTRL 0x005C
++#define AR8216_ATU_CTRL_AGE_EN BIT(17)
++#define AR8216_ATU_CTRL_AGE_TIME BITS(0, 16)
++#define AR8216_ATU_CTRL_AGE_TIME_S 0
++
++#define AR8216_REG_MIB_FUNC 0x0080
++#define AR8216_MIB_TIMER BITS(0, 16)
++#define AR8216_MIB_AT_HALF_EN BIT(16)
++#define AR8216_MIB_BUSY BIT(17)
++#define AR8216_MIB_FUNC BITS(24, 3)
++#define AR8216_MIB_FUNC_S 24
++#define AR8216_MIB_FUNC_NO_OP 0x0
++#define AR8216_MIB_FUNC_FLUSH 0x1
++#define AR8216_MIB_FUNC_CAPTURE 0x3
++#define AR8236_MIB_EN BIT(30)
++
++#define AR8216_REG_GLOBAL_CPUPORT 0x0078
++#define AR8216_GLOBAL_CPUPORT_MIRROR_PORT BITS(4, 4)
++#define AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S 4
++
++#define AR8216_PORT_OFFSET(_i) (0x0100 * (_i + 1))
++#define AR8216_REG_PORT_STATUS(_i) (AR8216_PORT_OFFSET(_i) + 0x0000)
++#define AR8216_PORT_STATUS_SPEED BITS(0,2)
++#define AR8216_PORT_STATUS_SPEED_S 0
++#define AR8216_PORT_STATUS_TXMAC BIT(2)
++#define AR8216_PORT_STATUS_RXMAC BIT(3)
++#define AR8216_PORT_STATUS_TXFLOW BIT(4)
++#define AR8216_PORT_STATUS_RXFLOW BIT(5)
++#define AR8216_PORT_STATUS_DUPLEX BIT(6)
++#define AR8216_PORT_STATUS_LINK_UP BIT(8)
++#define AR8216_PORT_STATUS_LINK_AUTO BIT(9)
++#define AR8216_PORT_STATUS_LINK_PAUSE BIT(10)
++
++#define AR8216_REG_PORT_CTRL(_i) (AR8216_PORT_OFFSET(_i) + 0x0004)
++
++/* port forwarding state */
++#define AR8216_PORT_CTRL_STATE BITS(0, 3)
++#define AR8216_PORT_CTRL_STATE_S 0
++
++#define AR8216_PORT_CTRL_LEARN_LOCK BIT(7)
++
++/* egress 802.1q mode */
++#define AR8216_PORT_CTRL_VLAN_MODE BITS(8, 2)
++#define AR8216_PORT_CTRL_VLAN_MODE_S 8
++
++#define AR8216_PORT_CTRL_IGMP_SNOOP BIT(10)
++#define AR8216_PORT_CTRL_HEADER BIT(11)
++#define AR8216_PORT_CTRL_MAC_LOOP BIT(12)
++#define AR8216_PORT_CTRL_SINGLE_VLAN BIT(13)
++#define AR8216_PORT_CTRL_LEARN BIT(14)
++#define AR8216_PORT_CTRL_MIRROR_TX BIT(16)
++#define AR8216_PORT_CTRL_MIRROR_RX BIT(17)
++
++#define AR8216_REG_PORT_VLAN(_i) (AR8216_PORT_OFFSET(_i) + 0x0008)
++
++#define AR8216_PORT_VLAN_DEFAULT_ID BITS(0, 12)
++#define AR8216_PORT_VLAN_DEFAULT_ID_S 0
++
++#define AR8216_PORT_VLAN_DEST_PORTS BITS(16, 9)
++#define AR8216_PORT_VLAN_DEST_PORTS_S 16
++
++/* bit0 added to the priority field of egress frames */
++#define AR8216_PORT_VLAN_TX_PRIO BIT(27)
++
++/* port default priority */
++#define AR8216_PORT_VLAN_PRIORITY BITS(28, 2)
++#define AR8216_PORT_VLAN_PRIORITY_S 28
++
++/* ingress 802.1q mode */
++#define AR8216_PORT_VLAN_MODE BITS(30, 2)
++#define AR8216_PORT_VLAN_MODE_S 30
++
++#define AR8216_REG_PORT_RATE(_i) (AR8216_PORT_OFFSET(_i) + 0x000c)
++#define AR8216_REG_PORT_PRIO(_i) (AR8216_PORT_OFFSET(_i) + 0x0010)
++
++#define AR8216_REG_PORT_STATS_BASE(_i) (0x19000 + (_i) * 0xa0)
++
++#define AR8216_STATS_RXBROAD 0x00
++#define AR8216_STATS_RXPAUSE 0x04
++#define AR8216_STATS_RXMULTI 0x08
++#define AR8216_STATS_RXFCSERR 0x0c
++#define AR8216_STATS_RXALIGNERR 0x10
++#define AR8216_STATS_RXRUNT 0x14
++#define AR8216_STATS_RXFRAGMENT 0x18
++#define AR8216_STATS_RX64BYTE 0x1c
++#define AR8216_STATS_RX128BYTE 0x20
++#define AR8216_STATS_RX256BYTE 0x24
++#define AR8216_STATS_RX512BYTE 0x28
++#define AR8216_STATS_RX1024BYTE 0x2c
++#define AR8216_STATS_RXMAXBYTE 0x30
++#define AR8216_STATS_RXTOOLONG 0x34
++#define AR8216_STATS_RXGOODBYTE 0x38
++#define AR8216_STATS_RXBADBYTE 0x40
++#define AR8216_STATS_RXOVERFLOW 0x48
++#define AR8216_STATS_FILTERED 0x4c
++#define AR8216_STATS_TXBROAD 0x50
++#define AR8216_STATS_TXPAUSE 0x54
++#define AR8216_STATS_TXMULTI 0x58
++#define AR8216_STATS_TXUNDERRUN 0x5c
++#define AR8216_STATS_TX64BYTE 0x60
++#define AR8216_STATS_TX128BYTE 0x64
++#define AR8216_STATS_TX256BYTE 0x68
++#define AR8216_STATS_TX512BYTE 0x6c
++#define AR8216_STATS_TX1024BYTE 0x70
++#define AR8216_STATS_TXMAXBYTE 0x74
++#define AR8216_STATS_TXOVERSIZE 0x78
++#define AR8216_STATS_TXBYTE 0x7c
++#define AR8216_STATS_TXCOLLISION 0x84
++#define AR8216_STATS_TXABORTCOL 0x88
++#define AR8216_STATS_TXMULTICOL 0x8c
++#define AR8216_STATS_TXSINGLECOL 0x90
++#define AR8216_STATS_TXEXCDEFER 0x94
++#define AR8216_STATS_TXDEFER 0x98
++#define AR8216_STATS_TXLATECOL 0x9c
++
++#define AR8236_REG_PORT_VLAN(_i) (AR8216_PORT_OFFSET((_i)) + 0x0008)
++#define AR8236_PORT_VLAN_DEFAULT_ID BITS(16, 12)
++#define AR8236_PORT_VLAN_DEFAULT_ID_S 16
++#define AR8236_PORT_VLAN_PRIORITY BITS(29, 3)
++#define AR8236_PORT_VLAN_PRIORITY_S 28
++
++#define AR8236_REG_PORT_VLAN2(_i) (AR8216_PORT_OFFSET((_i)) + 0x000c)
++#define AR8236_PORT_VLAN2_MEMBER BITS(16, 7)
++#define AR8236_PORT_VLAN2_MEMBER_S 16
++#define AR8236_PORT_VLAN2_TX_PRIO BIT(23)
++#define AR8236_PORT_VLAN2_VLAN_MODE BITS(30, 2)
++#define AR8236_PORT_VLAN2_VLAN_MODE_S 30
++
++#define AR8236_REG_PORT_STATS_BASE(_i) (0x20000 + (_i) * 0x100)
++
++#define AR8236_STATS_RXBROAD 0x00
++#define AR8236_STATS_RXPAUSE 0x04
++#define AR8236_STATS_RXMULTI 0x08
++#define AR8236_STATS_RXFCSERR 0x0c
++#define AR8236_STATS_RXALIGNERR 0x10
++#define AR8236_STATS_RXRUNT 0x14
++#define AR8236_STATS_RXFRAGMENT 0x18
++#define AR8236_STATS_RX64BYTE 0x1c
++#define AR8236_STATS_RX128BYTE 0x20
++#define AR8236_STATS_RX256BYTE 0x24
++#define AR8236_STATS_RX512BYTE 0x28
++#define AR8236_STATS_RX1024BYTE 0x2c
++#define AR8236_STATS_RX1518BYTE 0x30
++#define AR8236_STATS_RXMAXBYTE 0x34
++#define AR8236_STATS_RXTOOLONG 0x38
++#define AR8236_STATS_RXGOODBYTE 0x3c
++#define AR8236_STATS_RXBADBYTE 0x44
++#define AR8236_STATS_RXOVERFLOW 0x4c
++#define AR8236_STATS_FILTERED 0x50
++#define AR8236_STATS_TXBROAD 0x54
++#define AR8236_STATS_TXPAUSE 0x58
++#define AR8236_STATS_TXMULTI 0x5c
++#define AR8236_STATS_TXUNDERRUN 0x60
++#define AR8236_STATS_TX64BYTE 0x64
++#define AR8236_STATS_TX128BYTE 0x68
++#define AR8236_STATS_TX256BYTE 0x6c
++#define AR8236_STATS_TX512BYTE 0x70
++#define AR8236_STATS_TX1024BYTE 0x74
++#define AR8236_STATS_TX1518BYTE 0x78
++#define AR8236_STATS_TXMAXBYTE 0x7c
++#define AR8236_STATS_TXOVERSIZE 0x80
++#define AR8236_STATS_TXBYTE 0x84
++#define AR8236_STATS_TXCOLLISION 0x8c
++#define AR8236_STATS_TXABORTCOL 0x90
++#define AR8236_STATS_TXMULTICOL 0x94
++#define AR8236_STATS_TXSINGLECOL 0x98
++#define AR8236_STATS_TXEXCDEFER 0x9c
++#define AR8236_STATS_TXDEFER 0xa0
++#define AR8236_STATS_TXLATECOL 0xa4
++
++#define AR8316_REG_POSTRIP 0x0008
++#define AR8316_POSTRIP_MAC0_GMII_EN BIT(0)
++#define AR8316_POSTRIP_MAC0_RGMII_EN BIT(1)
++#define AR8316_POSTRIP_PHY4_GMII_EN BIT(2)
++#define AR8316_POSTRIP_PHY4_RGMII_EN BIT(3)
++#define AR8316_POSTRIP_MAC0_MAC_MODE BIT(4)
++#define AR8316_POSTRIP_RTL_MODE BIT(5)
++#define AR8316_POSTRIP_RGMII_RXCLK_DELAY_EN BIT(6)
++#define AR8316_POSTRIP_RGMII_TXCLK_DELAY_EN BIT(7)
++#define AR8316_POSTRIP_SERDES_EN BIT(8)
++#define AR8316_POSTRIP_SEL_ANA_RST BIT(9)
++#define AR8316_POSTRIP_GATE_25M_EN BIT(10)
++#define AR8316_POSTRIP_SEL_CLK25M BIT(11)
++#define AR8316_POSTRIP_HIB_PULSE_HW BIT(12)
++#define AR8316_POSTRIP_DBG_MODE_I BIT(13)
++#define AR8316_POSTRIP_MAC5_MAC_MODE BIT(14)
++#define AR8316_POSTRIP_MAC5_PHY_MODE BIT(15)
++#define AR8316_POSTRIP_POWER_DOWN_HW BIT(16)
++#define AR8316_POSTRIP_LPW_STATE_EN BIT(17)
++#define AR8316_POSTRIP_MAN_EN BIT(18)
++#define AR8316_POSTRIP_PHY_PLL_ON BIT(19)
++#define AR8316_POSTRIP_LPW_EXIT BIT(20)
++#define AR8316_POSTRIP_TXDELAY_S0 BIT(21)
++#define AR8316_POSTRIP_TXDELAY_S1 BIT(22)
++#define AR8316_POSTRIP_RXDELAY_S0 BIT(23)
++#define AR8316_POSTRIP_LED_OPEN_EN BIT(24)
++#define AR8316_POSTRIP_SPI_EN BIT(25)
++#define AR8316_POSTRIP_RXDELAY_S1 BIT(26)
++#define AR8316_POSTRIP_POWER_ON_SEL BIT(31)
++
++#define AR8327_NUM_PORTS 7
++#define AR8327_NUM_LEDS 15
++#define AR8327_NUM_PHYS 5
++#define AR8327_PORTS_ALL 0x7f
++#define AR8327_NUM_LED_CTRL_REGS 4
++
++#define AR8327_REG_MASK 0x000
++
++#define AR8327_REG_PAD0_MODE 0x004
++#define AR8327_REG_PAD5_MODE 0x008
++#define AR8327_REG_PAD6_MODE 0x00c
++#define AR8327_PAD_MAC_MII_RXCLK_SEL BIT(0)
++#define AR8327_PAD_MAC_MII_TXCLK_SEL BIT(1)
++#define AR8327_PAD_MAC_MII_EN BIT(2)
++#define AR8327_PAD_MAC_GMII_RXCLK_SEL BIT(4)
++#define AR8327_PAD_MAC_GMII_TXCLK_SEL BIT(5)
++#define AR8327_PAD_MAC_GMII_EN BIT(6)
++#define AR8327_PAD_SGMII_EN BIT(7)
++#define AR8327_PAD_PHY_MII_RXCLK_SEL BIT(8)
++#define AR8327_PAD_PHY_MII_TXCLK_SEL BIT(9)
++#define AR8327_PAD_PHY_MII_EN BIT(10)
++#define AR8327_PAD_PHY_GMII_PIPE_RXCLK_SEL BIT(11)
++#define AR8327_PAD_PHY_GMII_RXCLK_SEL BIT(12)
++#define AR8327_PAD_PHY_GMII_TXCLK_SEL BIT(13)
++#define AR8327_PAD_PHY_GMII_EN BIT(14)
++#define AR8327_PAD_PHYX_GMII_EN BIT(16)
++#define AR8327_PAD_PHYX_RGMII_EN BIT(17)
++#define AR8327_PAD_PHYX_MII_EN BIT(18)
++#define AR8327_PAD_SGMII_DELAY_EN BIT(19)
++#define AR8327_PAD_RGMII_RXCLK_DELAY_SEL BITS(20, 2)
++#define AR8327_PAD_RGMII_RXCLK_DELAY_SEL_S 20
++#define AR8327_PAD_RGMII_TXCLK_DELAY_SEL BITS(22, 2)
++#define AR8327_PAD_RGMII_TXCLK_DELAY_SEL_S 22
++#define AR8327_PAD_RGMII_RXCLK_DELAY_EN BIT(24)
++#define AR8327_PAD_RGMII_TXCLK_DELAY_EN BIT(25)
++#define AR8327_PAD_RGMII_EN BIT(26)
++
++#define AR8327_REG_POWER_ON_STRIP 0x010
++#define AR8327_POWER_ON_STRIP_POWER_ON_SEL BIT(31)
++#define AR8327_POWER_ON_STRIP_LED_OPEN_EN BIT(24)
++#define AR8327_POWER_ON_STRIP_SERDES_AEN BIT(7)
++
++#define AR8327_REG_INT_STATUS0 0x020
++#define AR8327_INT0_VT_DONE BIT(20)
++
++#define AR8327_REG_INT_STATUS1 0x024
++#define AR8327_REG_INT_MASK0 0x028
++#define AR8327_REG_INT_MASK1 0x02c
++
++#define AR8327_REG_MODULE_EN 0x030
++#define AR8327_MODULE_EN_MIB BIT(0)
++
++#define AR8327_REG_MIB_FUNC 0x034
++#define AR8327_MIB_CPU_KEEP BIT(20)
++
++#define AR8327_REG_SERVICE_TAG 0x048
++#define AR8327_REG_LED_CTRL(_i) (0x050 + (_i) * 4)
++#define AR8327_REG_LED_CTRL0 0x050
++#define AR8327_REG_LED_CTRL1 0x054
++#define AR8327_REG_LED_CTRL2 0x058
++#define AR8327_REG_LED_CTRL3 0x05c
++#define AR8327_REG_MAC_ADDR0 0x060
++#define AR8327_REG_MAC_ADDR1 0x064
++
++#define AR8327_REG_MAX_FRAME_SIZE 0x078
++#define AR8327_MAX_FRAME_SIZE_MTU BITS(0, 14)
++
++#define AR8327_REG_PORT_STATUS(_i) (0x07c + (_i) * 4)
++
++#define AR8327_REG_HEADER_CTRL 0x098
++#define AR8327_REG_PORT_HEADER(_i) (0x09c + (_i) * 4)
++
++#define AR8327_REG_SGMII_CTRL 0x0e0
++#define AR8327_SGMII_CTRL_EN_PLL BIT(1)
++#define AR8327_SGMII_CTRL_EN_RX BIT(2)
++#define AR8327_SGMII_CTRL_EN_TX BIT(3)
++
++#define AR8327_REG_PORT_VLAN0(_i) (0x420 + (_i) * 0x8)
++#define AR8327_PORT_VLAN0_DEF_SVID BITS(0, 12)
++#define AR8327_PORT_VLAN0_DEF_SVID_S 0
++#define AR8327_PORT_VLAN0_DEF_CVID BITS(16, 12)
++#define AR8327_PORT_VLAN0_DEF_CVID_S 16
++
++#define AR8327_REG_PORT_VLAN1(_i) (0x424 + (_i) * 0x8)
++#define AR8327_PORT_VLAN1_PORT_VLAN_PROP BIT(6)
++#define AR8327_PORT_VLAN1_OUT_MODE BITS(12, 2)
++#define AR8327_PORT_VLAN1_OUT_MODE_S 12
++#define AR8327_PORT_VLAN1_OUT_MODE_UNMOD 0
++#define AR8327_PORT_VLAN1_OUT_MODE_UNTAG 1
++#define AR8327_PORT_VLAN1_OUT_MODE_TAG 2
++#define AR8327_PORT_VLAN1_OUT_MODE_UNTOUCH 3
++
++#define AR8327_REG_ATU_DATA0 0x600
++#define AR8327_REG_ATU_DATA1 0x604
++#define AR8327_REG_ATU_DATA2 0x608
++
++#define AR8327_REG_ATU_FUNC 0x60c
++#define AR8327_ATU_FUNC_OP BITS(0, 4)
++#define AR8327_ATU_FUNC_OP_NOOP 0x0
++#define AR8327_ATU_FUNC_OP_FLUSH 0x1
++#define AR8327_ATU_FUNC_OP_LOAD 0x2
++#define AR8327_ATU_FUNC_OP_PURGE 0x3
++#define AR8327_ATU_FUNC_OP_FLUSH_LOCKED 0x4
++#define AR8327_ATU_FUNC_OP_FLUSH_UNICAST 0x5
++#define AR8327_ATU_FUNC_OP_GET_NEXT 0x6
++#define AR8327_ATU_FUNC_OP_SEARCH_MAC 0x7
++#define AR8327_ATU_FUNC_OP_CHANGE_TRUNK 0x8
++#define AR8327_ATU_FUNC_BUSY BIT(31)
++
++#define AR8327_REG_VTU_FUNC0 0x0610
++#define AR8327_VTU_FUNC0_EG_MODE BITS(4, 14)
++#define AR8327_VTU_FUNC0_EG_MODE_S(_i) (4 + (_i) * 2)
++#define AR8327_VTU_FUNC0_EG_MODE_KEEP 0
++#define AR8327_VTU_FUNC0_EG_MODE_UNTAG 1
++#define AR8327_VTU_FUNC0_EG_MODE_TAG 2
++#define AR8327_VTU_FUNC0_EG_MODE_NOT 3
++#define AR8327_VTU_FUNC0_IVL BIT(19)
++#define AR8327_VTU_FUNC0_VALID BIT(20)
++
++#define AR8327_REG_VTU_FUNC1 0x0614
++#define AR8327_VTU_FUNC1_OP BITS(0, 3)
++#define AR8327_VTU_FUNC1_OP_NOOP 0
++#define AR8327_VTU_FUNC1_OP_FLUSH 1
++#define AR8327_VTU_FUNC1_OP_LOAD 2
++#define AR8327_VTU_FUNC1_OP_PURGE 3
++#define AR8327_VTU_FUNC1_OP_REMOVE_PORT 4
++#define AR8327_VTU_FUNC1_OP_GET_NEXT 5
++#define AR8327_VTU_FUNC1_OP_GET_ONE 6
++#define AR8327_VTU_FUNC1_FULL BIT(4)
++#define AR8327_VTU_FUNC1_PORT BIT(8, 4)
++#define AR8327_VTU_FUNC1_PORT_S 8
++#define AR8327_VTU_FUNC1_VID BIT(16, 12)
++#define AR8327_VTU_FUNC1_VID_S 16
++#define AR8327_VTU_FUNC1_BUSY BIT(31)
++
++#define AR8327_REG_FWD_CTRL0 0x620
++#define AR8327_FWD_CTRL0_CPU_PORT_EN BIT(10)
++#define AR8327_FWD_CTRL0_MIRROR_PORT BITS(4, 4)
++#define AR8327_FWD_CTRL0_MIRROR_PORT_S 4
++
++#define AR8327_REG_FWD_CTRL1 0x624
++#define AR8327_FWD_CTRL1_UC_FLOOD BITS(0, 7)
++#define AR8327_FWD_CTRL1_UC_FLOOD_S 0
++#define AR8327_FWD_CTRL1_MC_FLOOD BITS(8, 7)
++#define AR8327_FWD_CTRL1_MC_FLOOD_S 8
++#define AR8327_FWD_CTRL1_BC_FLOOD BITS(16, 7)
++#define AR8327_FWD_CTRL1_BC_FLOOD_S 16
++#define AR8327_FWD_CTRL1_IGMP BITS(24, 7)
++#define AR8327_FWD_CTRL1_IGMP_S 24
++
++#define AR8327_REG_PORT_LOOKUP(_i) (0x660 + (_i) * 0xc)
++#define AR8327_PORT_LOOKUP_MEMBER BITS(0, 7)
++#define AR8327_PORT_LOOKUP_IN_MODE BITS(8, 2)
++#define AR8327_PORT_LOOKUP_IN_MODE_S 8
++#define AR8327_PORT_LOOKUP_STATE BITS(16, 3)
++#define AR8327_PORT_LOOKUP_STATE_S 16
++#define AR8327_PORT_LOOKUP_LEARN BIT(20)
++#define AR8327_PORT_LOOKUP_ING_MIRROR_EN BIT(25)
++
++#define AR8327_REG_PORT_PRIO(_i) (0x664 + (_i) * 0xc)
++
++#define AR8327_REG_PORT_HOL_CTRL1(_i) (0x974 + (_i) * 0x8)
++#define AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN BIT(16)
++
++#define AR8327_REG_PORT_STATS_BASE(_i) (0x1000 + (_i) * 0x100)
++
++#define AR8337_PAD_MAC06_EXCHANGE_EN BIT(31)
++
++/* port speed */
++enum {
++ AR8216_PORT_SPEED_10M = 0,
++ AR8216_PORT_SPEED_100M = 1,
++ AR8216_PORT_SPEED_1000M = 2,
++ AR8216_PORT_SPEED_ERR = 3,
++};
++
++/* ingress 802.1q mode */
++enum {
++ AR8216_IN_PORT_ONLY = 0,
++ AR8216_IN_PORT_FALLBACK = 1,
++ AR8216_IN_VLAN_ONLY = 2,
++ AR8216_IN_SECURE = 3
++};
++
++/* egress 802.1q mode */
++enum {
++ AR8216_OUT_KEEP = 0,
++ AR8216_OUT_STRIP_VLAN = 1,
++ AR8216_OUT_ADD_VLAN = 2
++};
++
++/* port forwarding state */
++enum {
++ AR8216_PORT_STATE_DISABLED = 0,
++ AR8216_PORT_STATE_BLOCK = 1,
++ AR8216_PORT_STATE_LISTEN = 2,
++ AR8216_PORT_STATE_LEARN = 3,
++ AR8216_PORT_STATE_FORWARD = 4
++};
++
++#endif
+diff --git a/include/linux/ar8216_platform.h b/include/linux/ar8216_platform.h
+new file mode 100644
+index 0000000..4935ad3
+--- /dev/null
++++ b/include/linux/ar8216_platform.h
+@@ -0,0 +1,131 @@
++/*
++ * AR8216 switch driver platform data
++ *
++ * Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef AR8216_PLATFORM_H
++#define AR8216_PLATFORM_H
++
++enum ar8327_pad_mode {
++ AR8327_PAD_NC = 0,
++ AR8327_PAD_MAC2MAC_MII,
++ AR8327_PAD_MAC2MAC_GMII,
++ AR8327_PAD_MAC_SGMII,
++ AR8327_PAD_MAC2PHY_MII,
++ AR8327_PAD_MAC2PHY_GMII,
++ AR8327_PAD_MAC_RGMII,
++ AR8327_PAD_PHY_GMII,
++ AR8327_PAD_PHY_RGMII,
++ AR8327_PAD_PHY_MII,
++};
++
++enum ar8327_clk_delay_sel {
++ AR8327_CLK_DELAY_SEL0 = 0,
++ AR8327_CLK_DELAY_SEL1,
++ AR8327_CLK_DELAY_SEL2,
++ AR8327_CLK_DELAY_SEL3,
++};
++
++struct ar8327_pad_cfg {
++ enum ar8327_pad_mode mode;
++ bool rxclk_sel;
++ bool txclk_sel;
++ bool pipe_rxclk_sel;
++ bool txclk_delay_en;
++ bool rxclk_delay_en;
++ bool sgmii_delay_en;
++ enum ar8327_clk_delay_sel txclk_delay_sel;
++ enum ar8327_clk_delay_sel rxclk_delay_sel;
++};
++
++enum ar8327_port_speed {
++ AR8327_PORT_SPEED_10 = 0,
++ AR8327_PORT_SPEED_100,
++ AR8327_PORT_SPEED_1000,
++};
++
++struct ar8327_port_cfg {
++ int force_link:1;
++ enum ar8327_port_speed speed;
++ int txpause:1;
++ int rxpause:1;
++ int duplex:1;
++};
++
++struct ar8327_sgmii_cfg {
++ u32 sgmii_ctrl;
++ bool serdes_aen;
++};
++
++struct ar8327_led_cfg {
++ u32 led_ctrl0;
++ u32 led_ctrl1;
++ u32 led_ctrl2;
++ u32 led_ctrl3;
++ bool open_drain;
++};
++
++enum ar8327_led_num {
++ AR8327_LED_PHY0_0 = 0,
++ AR8327_LED_PHY0_1,
++ AR8327_LED_PHY0_2,
++ AR8327_LED_PHY1_0,
++ AR8327_LED_PHY1_1,
++ AR8327_LED_PHY1_2,
++ AR8327_LED_PHY2_0,
++ AR8327_LED_PHY2_1,
++ AR8327_LED_PHY2_2,
++ AR8327_LED_PHY3_0,
++ AR8327_LED_PHY3_1,
++ AR8327_LED_PHY3_2,
++ AR8327_LED_PHY4_0,
++ AR8327_LED_PHY4_1,
++ AR8327_LED_PHY4_2,
++};
++
++enum ar8327_led_mode {
++ AR8327_LED_MODE_HW = 0,
++ AR8327_LED_MODE_SW,
++};
++
++struct ar8327_led_info {
++ const char *name;
++ const char *default_trigger;
++ bool active_low;
++ enum ar8327_led_num led_num;
++ enum ar8327_led_mode mode;
++};
++
++#define AR8327_LED_INFO(_led, _mode, _name) { \
++ .name = (_name), \
++ .led_num = AR8327_LED_ ## _led, \
++ .mode = AR8327_LED_MODE_ ## _mode \
++}
++
++struct ar8327_platform_data {
++ struct ar8327_pad_cfg *pad0_cfg;
++ struct ar8327_pad_cfg *pad5_cfg;
++ struct ar8327_pad_cfg *pad6_cfg;
++ struct ar8327_sgmii_cfg *sgmii_cfg;
++ struct ar8327_port_cfg port0_cfg;
++ struct ar8327_port_cfg port6_cfg;
++ struct ar8327_led_cfg *led_cfg;
++
++ int (*get_port_link)(unsigned port);
++
++ unsigned num_leds;
++ const struct ar8327_led_info *leds;
++};
++
++#endif /* AR8216_PLATFORM_H */
+\ No newline at end of file
+--
+1.8.5.3
+
diff --git a/target/mips/dragino-ms14s/patches/3.14.17/0016-phy-mdio-bitbang-ignore-TA-value.patch b/target/mips/dragino-ms14s/patches/3.14.17/0016-phy-mdio-bitbang-ignore-TA-value.patch
new file mode 100644
index 000000000..fe23f4912
--- /dev/null
+++ b/target/mips/dragino-ms14s/patches/3.14.17/0016-phy-mdio-bitbang-ignore-TA-value.patch
@@ -0,0 +1,44 @@
+From e73f7d9a658c7fc693a9b9c45a1f65c014dd6e40 Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Tue, 13 May 2014 01:17:38 +0200
+Subject: [PATCH] phy: mdio-bitbang: ignore TA value
+
+This is necessary on rb493g to make the kernel detect the second switch.
+---
+ drivers/net/phy/mdio-bitbang.c | 13 ++-----------
+ 1 file changed, 2 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c
+index daec9b0..4fa2be0 100644
+--- a/drivers/net/phy/mdio-bitbang.c
++++ b/drivers/net/phy/mdio-bitbang.c
+@@ -155,7 +155,7 @@ static int mdiobb_cmd_addr(struct mdiobb_ctrl *ctrl, int phy, u32 addr)
+ static int mdiobb_read(struct mii_bus *bus, int phy, int reg)
+ {
+ struct mdiobb_ctrl *ctrl = bus->priv;
+- int ret, i;
++ int ret;
+
+ if (reg & MII_ADDR_C45) {
+ reg = mdiobb_cmd_addr(ctrl, phy, reg);
+@@ -165,16 +165,7 @@ static int mdiobb_read(struct mii_bus *bus, int phy, int reg)
+
+ ctrl->ops->set_mdio_dir(ctrl, 0);
+
+- /* check the turnaround bit: the PHY should be driving it to zero */
+- if (mdiobb_get_bit(ctrl) != 0) {
+- /* PHY didn't drive TA low -- flush any bits it
+- * may be trying to send.
+- */
+- for (i = 0; i < 32; i++)
+- mdiobb_get_bit(ctrl);
+-
+- return 0xffff;
+- }
++ mdiobb_get_bit(ctrl);
+
+ ret = mdiobb_get_num(ctrl, 16);
+ mdiobb_get_bit(ctrl);
+--
+1.8.5.3
+
diff --git a/target/mips/dragino-ms14s/patches/3.14.17/0017-MIPS-ath79-fix-maximum-timeout.patch b/target/mips/dragino-ms14s/patches/3.14.17/0017-MIPS-ath79-fix-maximum-timeout.patch
new file mode 100644
index 000000000..3ca02783d
--- /dev/null
+++ b/target/mips/dragino-ms14s/patches/3.14.17/0017-MIPS-ath79-fix-maximum-timeout.patch
@@ -0,0 +1,37 @@
+From 54d01581baa903adb8515625d98652ed43efba36 Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Tue, 13 May 2014 01:21:59 +0200
+Subject: [PATCH] MIPS: ath79: fix maximum timeout
+
+If the userland tries to set a timeout higher than the max_timeout, then
+we should fallback to max_timeout.
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/watchdog/ath79_wdt.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/watchdog/ath79_wdt.c b/drivers/watchdog/ath79_wdt.c
+index 9fa1f69..bf26baf 100644
+--- a/drivers/watchdog/ath79_wdt.c
++++ b/drivers/watchdog/ath79_wdt.c
+@@ -105,10 +105,14 @@ static inline void ath79_wdt_disable(void)
+
+ static int ath79_wdt_set_timeout(int val)
+ {
+- if (val < 1 || val > max_timeout)
++ if (val < 1)
+ return -EINVAL;
+
+- timeout = val;
++ if (val > max_timeout)
++ timeout = max_timeout;
++ else
++ timeout = val;
++
+ ath79_wdt_keepalive();
+
+ return 0;
+--
+1.8.5.3
+
diff --git a/target/mips/dragino-ms14s/patches/3.14.17/0018-net-allow-PHY-drivers-to-insert-packet-mangle-hooks.patch b/target/mips/dragino-ms14s/patches/3.14.17/0018-net-allow-PHY-drivers-to-insert-packet-mangle-hooks.patch
new file mode 100644
index 000000000..6a372c8f1
--- /dev/null
+++ b/target/mips/dragino-ms14s/patches/3.14.17/0018-net-allow-PHY-drivers-to-insert-packet-mangle-hooks.patch
@@ -0,0 +1,211 @@
+From ebca842041d737b7441748a17ffd535aab851fce Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Tue, 13 May 2014 01:32:11 +0200
+Subject: [PATCH] net: allow PHY drivers to insert packet mangle hooks
+
+---
+ include/linux/netdevice.h | 8 ++++++++
+ include/linux/skbuff.h | 14 ++++----------
+ include/uapi/linux/if.h | 1 +
+ net/Kconfig | 6 ++++++
+ net/core/dev.c | 36 ++++++++++++++++++++++++++++--------
+ net/core/skbuff.c | 17 +++++++++++++++++
+ net/ethernet/eth.c | 6 ++++++
+ 7 files changed, 70 insertions(+), 18 deletions(-)
+
+diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
+index 911718f..8e8dd46 100644
+--- a/include/linux/netdevice.h
++++ b/include/linux/netdevice.h
+@@ -1245,6 +1245,11 @@ struct net_device {
+ const struct ethtool_ops *ethtool_ops;
+ const struct forwarding_accel_ops *fwd_ops;
+
++#ifdef CONFIG_ETHERNET_PACKET_MANGLE
++ void (*eth_mangle_rx)(struct net_device *dev, struct sk_buff *skb);
++ struct sk_buff *(*eth_mangle_tx)(struct net_device *dev, struct sk_buff *skb);
++#endif
++
+ /* Hardware header description */
+ const struct header_ops *header_ops;
+
+@@ -1313,6 +1318,9 @@ struct net_device {
+ void *ax25_ptr; /* AX.25 specific data */
+ struct wireless_dev *ieee80211_ptr; /* IEEE 802.11 specific data,
+ assign before registering */
++#ifdef CONFIG_ETHERNET_PACKET_MANGLE
++ void *phy_ptr; /* PHY device specific data */
++#endif
+
+ /*
+ * Cache lines mostly used on receive path (including eth_type_trans())
+diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
+index 15ede6a..5530766 100644
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -1858,6 +1858,10 @@ static inline int pskb_trim(struct sk_buff *skb, unsigned int len)
+ return (len < skb->len) ? __pskb_trim(skb, len) : 0;
+ }
+
++extern struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
++ unsigned int length, gfp_t gfp);
++
++
+ /**
+ * pskb_trim_unique - remove end from a paged unique (not cloned) buffer
+ * @skb: buffer to alter
+@@ -1966,16 +1970,6 @@ static inline struct sk_buff *dev_alloc_skb(unsigned int length)
+ }
+
+
+-static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
+- unsigned int length, gfp_t gfp)
+-{
+- struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp);
+-
+- if (NET_IP_ALIGN && skb)
+- skb_reserve(skb, NET_IP_ALIGN);
+- return skb;
+-}
+-
+ static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev,
+ unsigned int length)
+ {
+diff --git a/include/uapi/linux/if.h b/include/uapi/linux/if.h
+index d758163..7ffa548 100644
+--- a/include/uapi/linux/if.h
++++ b/include/uapi/linux/if.h
+@@ -84,6 +84,7 @@
+ #define IFF_LIVE_ADDR_CHANGE 0x100000 /* device supports hardware address
+ * change when it's running */
+ #define IFF_MACVLAN 0x200000 /* Macvlan device */
++#define IFF_NO_IP_ALIGN 0x400000 /* do not ip-align allocated rx pkts */
+
+
+ #define IF_GET_IFACE 0x0001 /* for querying only */
+diff --git a/net/Kconfig b/net/Kconfig
+index e411046..970c52a 100644
+--- a/net/Kconfig
++++ b/net/Kconfig
+@@ -24,6 +24,12 @@ menuconfig NET
+
+ if NET
+
++config ETHERNET_PACKET_MANGLE
++ bool
++ help
++ This option can be selected by phy drivers that need to mangle
++ packets going in or out of an ethernet device.
++
+ config WANT_COMPAT_NETLINK_MESSAGES
+ bool
+ help
+diff --git a/net/core/dev.c b/net/core/dev.c
+index fccc195..2e0ba23 100644
+--- a/net/core/dev.c
++++ b/net/core/dev.c
+@@ -2607,10 +2607,20 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
+ if (!list_empty(&ptype_all))
+ dev_queue_xmit_nit(skb, dev);
+
+- skb_len = skb->len;
+- trace_net_dev_start_xmit(skb, dev);
+- rc = ops->ndo_start_xmit(skb, dev);
+- trace_net_dev_xmit(skb, rc, dev, skb_len);
++#ifdef CONFIG_ETHERNET_PACKET_MANGLE
++ if (!dev->eth_mangle_tx ||
++ (skb = dev->eth_mangle_tx(dev, skb)) != NULL)
++#else
++ if (1)
++#endif
++ {
++ skb_len = skb->len;
++ trace_net_dev_start_xmit(skb, dev);
++ rc = ops->ndo_start_xmit(skb, dev);
++ trace_net_dev_xmit(skb, rc, dev, skb_len);
++ } else {
++ rc = NETDEV_TX_OK;
++ }
+ if (rc == NETDEV_TX_OK)
+ txq_trans_update(txq);
+ return rc;
+@@ -2626,10 +2636,20 @@ gso:
+ if (!list_empty(&ptype_all))
+ dev_queue_xmit_nit(nskb, dev);
+
+- skb_len = nskb->len;
+- trace_net_dev_start_xmit(nskb, dev);
+- rc = ops->ndo_start_xmit(nskb, dev);
+- trace_net_dev_xmit(nskb, rc, dev, skb_len);
++#ifdef CONFIG_ETHERNET_PACKET_MANGLE
++ if (!dev->eth_mangle_tx ||
++ (nskb = dev->eth_mangle_tx(dev, nskb)) != NULL)
++#else
++ if (1)
++#endif
++ {
++ skb_len = nskb->len;
++ trace_net_dev_start_xmit(nskb, dev);
++ rc = ops->ndo_start_xmit(nskb, dev);
++ trace_net_dev_xmit(nskb, rc, dev, skb_len);
++ } else {
++ rc = NETDEV_TX_OK;
++ }
+ if (unlikely(rc != NETDEV_TX_OK)) {
+ if (rc & ~NETDEV_TX_MASK)
+ goto out_kfree_gso_skb;
+diff --git a/net/core/skbuff.c b/net/core/skbuff.c
+index e5ae776e..400ff2a 100644
+--- a/net/core/skbuff.c
++++ b/net/core/skbuff.c
+@@ -62,6 +62,7 @@
+ #include <linux/scatterlist.h>
+ #include <linux/errqueue.h>
+ #include <linux/prefetch.h>
++#include <uapi/linux/if.h>
+
+ #include <net/protocol.h>
+ #include <net/dst.h>
+@@ -439,6 +440,22 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev,
+ }
+ EXPORT_SYMBOL(__netdev_alloc_skb);
+
++struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
++ unsigned int length, gfp_t gfp)
++{
++ struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp);
++
++#ifdef CONFIG_ETHERNET_PACKET_MANGLE
++ if (dev && (dev->priv_flags & IFF_NO_IP_ALIGN))
++ return skb;
++#endif
++
++ if (NET_IP_ALIGN && skb)
++ skb_reserve(skb, NET_IP_ALIGN);
++ return skb;
++}
++EXPORT_SYMBOL(__netdev_alloc_skb_ip_align);
++
+ void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off,
+ int size, unsigned int truesize)
+ {
+diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
+index 5dc638c..f4fd124 100644
+--- a/net/ethernet/eth.c
++++ b/net/ethernet/eth.c
+@@ -161,6 +161,12 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
+ const struct ethhdr *eth;
+
+ skb->dev = dev;
++
++#ifdef CONFIG_ETHERNET_PACKET_MANGLE
++ if (dev->eth_mangle_rx)
++ dev->eth_mangle_rx(dev, skb);
++#endif
++
+ skb_reset_mac_header(skb);
+ skb_pull_inline(skb, ETH_HLEN);
+ eth = eth_hdr(skb);
+--
+1.8.5.3
+
diff --git a/target/mips/dragino-ms14s/patches/3.14.17/0019-MIPS-ath79-process-board-cmdline-option.patch b/target/mips/dragino-ms14s/patches/3.14.17/0019-MIPS-ath79-process-board-cmdline-option.patch
new file mode 100644
index 000000000..13eae3b8c
--- /dev/null
+++ b/target/mips/dragino-ms14s/patches/3.14.17/0019-MIPS-ath79-process-board-cmdline-option.patch
@@ -0,0 +1,26 @@
+From 4c84b317734842765cb1c52624fc569efd9222dc Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Tue, 13 May 2014 02:11:59 +0200
+Subject: [PATCH] MIPS: ath79: process board cmdline option
+
+This is necessary to correctly identify the running machine.
+---
+ arch/mips/ath79/setup.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/arch/mips/ath79/setup.c b/arch/mips/ath79/setup.c
+index 64807a4..0c95758 100644
+--- a/arch/mips/ath79/setup.c
++++ b/arch/mips/ath79/setup.c
+@@ -229,6 +229,8 @@ void __init plat_time_init(void)
+ mips_hpt_frequency = cpu_clk_rate / 2;
+ }
+
++__setup("board=", mips_machtype_setup);
++
+ static int __init ath79_setup(void)
+ {
+ ath79_gpio_init();
+--
+1.8.5.3
+
diff --git a/target/mips/dragino-ms14s/patches/3.14.17/0020-spi-ath79-add-fast-flash-read-support.patch b/target/mips/dragino-ms14s/patches/3.14.17/0020-spi-ath79-add-fast-flash-read-support.patch
new file mode 100644
index 000000000..8fd174448
--- /dev/null
+++ b/target/mips/dragino-ms14s/patches/3.14.17/0020-spi-ath79-add-fast-flash-read-support.patch
@@ -0,0 +1,202 @@
+From c4388a57860440e23c9654f4de2f515433e685a1 Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Tue, 13 May 2014 04:12:35 +0200
+Subject: [PATCH] spi-ath79: add fast flash read support
+
+---
+ .../include/asm/mach-ath79/ath79_spi_platform.h | 1 +
+ drivers/spi/spi-ath79.c | 124 ++++++++++++++++++++-
+ 2 files changed, 120 insertions(+), 5 deletions(-)
+
+diff --git a/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h b/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
+index aa2283e..65369fe 100644
+--- a/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
++++ b/arch/mips/include/asm/mach-ath79/ath79_spi_platform.h
+@@ -18,6 +18,7 @@ struct ath79_spi_platform_data {
+
+ struct ath79_spi_controller_data {
+ unsigned gpio;
++ bool is_flash;
+ };
+
+ #endif /* _ATH79_SPI_PLATFORM_H */
+diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c
+index c3b2fb9..a26a6a4 100644
+--- a/drivers/spi/spi-ath79.c
++++ b/drivers/spi/spi-ath79.c
+@@ -35,6 +35,11 @@
+ #define ATH79_SPI_RRW_DELAY_FACTOR 12000
+ #define MHZ (1000 * 1000)
+
++enum ath79_spi_state {
++ ATH79_SPI_STATE_WAIT_CMD = 0,
++ ATH79_SPI_STATE_WAIT_READ,
++};
++
+ struct ath79_spi {
+ struct spi_bitbang bitbang;
+ u32 ioc_base;
+@@ -42,6 +47,11 @@ struct ath79_spi {
+ void __iomem *base;
+ struct clk *clk;
+ unsigned rrw_delay;
++
++ enum ath79_spi_state state;
++ u32 clk_div;
++ unsigned long read_addr;
++ unsigned long ahb_rate;
+ };
+
+ static inline u32 ath79_spi_rr(struct ath79_spi *sp, unsigned reg)
+@@ -104,9 +114,6 @@ static void ath79_spi_enable(struct ath79_spi *sp)
+ /* save CTRL register */
+ sp->reg_ctrl = ath79_spi_rr(sp, AR71XX_SPI_REG_CTRL);
+ sp->ioc_base = ath79_spi_rr(sp, AR71XX_SPI_REG_IOC);
+-
+- /* TODO: setup speed? */
+- ath79_spi_wr(sp, AR71XX_SPI_REG_CTRL, 0x43);
+ }
+
+ static void ath79_spi_disable(struct ath79_spi *sp)
+@@ -203,6 +210,110 @@ static u32 ath79_spi_txrx_mode0(struct spi_device *spi, unsigned nsecs,
+ return ath79_spi_rr(sp, AR71XX_SPI_REG_RDS);
+ }
+
++static int ath79_spi_do_read_flash_data(struct spi_device *spi,
++ struct spi_transfer *t)
++{
++ struct ath79_spi *sp = ath79_spidev_to_sp(spi);
++
++ /* disable GPIO mode */
++ ath79_spi_wr(sp, AR71XX_SPI_REG_FS, 0);
++
++ memcpy_fromio(t->rx_buf, sp->base + sp->read_addr, t->len);
++
++ /* enable GPIO mode */
++ ath79_spi_wr(sp, AR71XX_SPI_REG_FS, AR71XX_SPI_FS_GPIO);
++
++ /* restore IOC register */
++ ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base);
++
++ return t->len;
++}
++
++static int ath79_spi_do_read_flash_cmd(struct spi_device *spi,
++ struct spi_transfer *t)
++{
++ struct ath79_spi *sp = ath79_spidev_to_sp(spi);
++ int len;
++ const u8 *p;
++
++ sp->read_addr = 0;
++
++ len = t->len - 1;
++ p = t->tx_buf;
++
++ while (len--) {
++ p++;
++ sp->read_addr <<= 8;
++ sp->read_addr |= *p;
++ }
++
++ return t->len;
++}
++
++static bool ath79_spi_is_read_cmd(struct spi_device *spi,
++ struct spi_transfer *t)
++{
++ return t->type == SPI_TRANSFER_FLASH_READ_CMD;
++}
++
++static bool ath79_spi_is_data_read(struct spi_device *spi,
++ struct spi_transfer *t)
++{
++ return t->type == SPI_TRANSFER_FLASH_READ_DATA;
++}
++
++static int ath79_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
++{
++ struct ath79_spi *sp = ath79_spidev_to_sp(spi);
++ int ret;
++
++ switch (sp->state) {
++ case ATH79_SPI_STATE_WAIT_CMD:
++ if (ath79_spi_is_read_cmd(spi, t)) {
++ ret = ath79_spi_do_read_flash_cmd(spi, t);
++ sp->state = ATH79_SPI_STATE_WAIT_READ;
++ } else {
++ ret = spi_bitbang_bufs(spi, t);
++ }
++ break;
++
++ case ATH79_SPI_STATE_WAIT_READ:
++ if (ath79_spi_is_data_read(spi, t)) {
++ ret = ath79_spi_do_read_flash_data(spi, t);
++ } else {
++ dev_warn(&spi->dev, "flash data read expected\n");
++ ret = -EIO;
++ }
++ sp->state = ATH79_SPI_STATE_WAIT_CMD;
++ break;
++
++ default:
++ BUG();
++ }
++
++ return ret;
++}
++
++static int ath79_spi_setup_transfer(struct spi_device *spi,
++ struct spi_transfer *t)
++{
++ struct ath79_spi *sp = ath79_spidev_to_sp(spi);
++ struct ath79_spi_controller_data *cdata;
++ int ret;
++
++ ret = spi_bitbang_setup_transfer(spi, t);
++ if (ret)
++ return ret;
++
++ cdata = spi->controller_data;
++ if (cdata->is_flash)
++ sp->bitbang.txrx_bufs = ath79_spi_txrx_bufs;
++ else
++ sp->bitbang.txrx_bufs = spi_bitbang_bufs;
++
++ return ret;
++}
++
+ static int ath79_spi_probe(struct platform_device *pdev)
+ {
+ struct spi_master *master;
+@@ -223,6 +334,8 @@ static int ath79_spi_probe(struct platform_device *pdev)
+
+ pdata = dev_get_platdata(&pdev->dev);
+
++ sp->state = ATH79_SPI_STATE_WAIT_CMD;
++
+ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
+ master->setup = ath79_spi_setup;
+ master->cleanup = ath79_spi_cleanup;
+@@ -234,7 +347,7 @@ static int ath79_spi_probe(struct platform_device *pdev)
+ sp->bitbang.master = master;
+ sp->bitbang.chipselect = ath79_spi_chipselect;
+ sp->bitbang.txrx_word[SPI_MODE_0] = ath79_spi_txrx_mode0;
+- sp->bitbang.setup_transfer = spi_bitbang_setup_transfer;
++ sp->bitbang.setup_transfer = ath79_spi_setup_transfer;
+ sp->bitbang.flags = SPI_CS_HIGH;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+@@ -259,7 +372,8 @@ static int ath79_spi_probe(struct platform_device *pdev)
+ if (ret)
+ goto err_put_master;
+
+- rate = DIV_ROUND_UP(clk_get_rate(sp->clk), MHZ);
++ sp->ahb_rate = clk_get_rate(sp->clk);
++ rate = DIV_ROUND_UP(sp->ahb_rate, MHZ);
+ if (!rate) {
+ ret = -EINVAL;
+ goto err_clk_disable;
+--
+1.8.5.3
+
diff --git a/target/mips/dragino-ms14s/patches/3.14.17/0021-phy-add-mdio-boardinfo.patch b/target/mips/dragino-ms14s/patches/3.14.17/0021-phy-add-mdio-boardinfo.patch
new file mode 100644
index 000000000..3ec15e171
--- /dev/null
+++ b/target/mips/dragino-ms14s/patches/3.14.17/0021-phy-add-mdio-boardinfo.patch
@@ -0,0 +1,227 @@
+From b8d5957374dc0e6ec8687c6e1b154ea066d27a5b Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Wed, 14 May 2014 02:44:43 +0200
+Subject: [PATCH] phy: add mdio boardinfo
+
+---
+ drivers/net/Makefile | 2 +-
+ drivers/net/phy/Kconfig | 4 +++
+ drivers/net/phy/Makefile | 2 ++
+ drivers/net/phy/mdio-boardinfo.c | 58 ++++++++++++++++++++++++++++++++++++++++
+ drivers/net/phy/mdio-boardinfo.h | 22 +++++++++++++++
+ drivers/net/phy/mdio_bus.c | 20 ++++++++++++++
+ include/linux/phy.h | 18 +++++++++++++
+ 7 files changed, 125 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/net/phy/mdio-boardinfo.c
+ create mode 100644 drivers/net/phy/mdio-boardinfo.h
+
+diff --git a/drivers/net/Makefile b/drivers/net/Makefile
+index 3fef8a8..70b736b 100644
+--- a/drivers/net/Makefile
++++ b/drivers/net/Makefile
+@@ -15,7 +15,7 @@ obj-$(CONFIG_MII) += mii.o
+ obj-$(CONFIG_MDIO) += mdio.o
+ obj-$(CONFIG_NET) += Space.o loopback.o
+ obj-$(CONFIG_NETCONSOLE) += netconsole.o
+-obj-$(CONFIG_PHYLIB) += phy/
++obj-y += phy/
+ obj-$(CONFIG_RIONET) += rionet.o
+ obj-$(CONFIG_NET_TEAM) += team/
+ obj-$(CONFIG_TUN) += tun.o
+diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
+index 0414889..97ca8ec 100644
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -12,6 +12,10 @@ menuconfig PHYLIB
+
+ if PHYLIB
+
++config MDIO_BOARDINFO
++ bool
++ default y
++
+ config SWCONFIG
+ tristate "Switch configuration API"
+ ---help---
+diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
+index 3c76ff8..0c990a4 100644
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -2,6 +2,8 @@
+
+ libphy-objs := phy.o phy_device.o mdio_bus.o
+
++obj-$(CONFIG_MDIO_BOARDINFO) += mdio-boardinfo.o
++
+ obj-$(CONFIG_PHYLIB) += libphy.o
+ obj-$(CONFIG_SWCONFIG) += swconfig.o
+ obj-$(CONFIG_MARVELL_PHY) += marvell.o
+diff --git a/drivers/net/phy/mdio-boardinfo.c b/drivers/net/phy/mdio-boardinfo.c
+new file mode 100644
+index 0000000..9b8aaed
+--- /dev/null
++++ b/drivers/net/phy/mdio-boardinfo.c
+@@ -0,0 +1,58 @@
++/*
++ * mdio-boardinfo.c - collect pre-declarations of PHY devices
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/phy.h>
++#include <linux/slab.h>
++#include <linux/export.h>
++#include <linux/mutex.h>
++#include <linux/phy.h>
++
++#include "mdio-boardinfo.h"
++
++/*
++ * These symbols are exported ONLY FOR the mdio_bus component.
++ * No other users will be supported.
++ */
++
++LIST_HEAD(__mdio_board_list);
++EXPORT_SYMBOL_GPL(__mdio_board_list);
++
++DEFINE_MUTEX(__mdio_board_lock);
++EXPORT_SYMBOL_GPL(__mdio_board_lock);
++
++/**
++ * mdio_register_board_info - register PHY devices for a given board
++ * @info: array of chip descriptors
++ * @n: how many descriptors are provided
++ * Context: can sleep
++ *
++ * The board info passed can safely be __initdata ... but be careful of
++ * any embedded pointers (platform_data, etc), they're copied as-is.
++ */
++int __init
++mdiobus_register_board_info(struct mdio_board_info const *info, unsigned n)
++{
++ struct mdio_board_entry *be;
++ int i;
++
++ be = kzalloc(n * sizeof(*be), GFP_KERNEL);
++ if (!be)
++ return -ENOMEM;
++
++ for (i = 0; i < n; i++, be++, info++) {
++ memcpy(&be->board_info, info, sizeof(*info));
++ mutex_lock(&__mdio_board_lock);
++ list_add_tail(&be->list, &__mdio_board_list);
++ mutex_unlock(&__mdio_board_lock);
++ }
++
++ return 0;
++}
+diff --git a/drivers/net/phy/mdio-boardinfo.h b/drivers/net/phy/mdio-boardinfo.h
+new file mode 100644
+index 0000000..28fbc0d
+--- /dev/null
++++ b/drivers/net/phy/mdio-boardinfo.h
+@@ -0,0 +1,22 @@
++/*
++ * mdio-boardinfo.h - boardinfo interface internal to the mdio_bus component
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ */
++
++#include <linux/mutex.h>
++
++struct mdio_board_entry {
++ struct list_head list;
++ struct mdio_board_info board_info;
++};
++
++/* __mdio_board_lock protects __mdio_board_list
++ * only mdio_bus components are allowed to use these symbols.
++ */
++extern struct mutex __mdio_board_lock;
++extern struct list_head __mdio_board_list;
+diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
+index 71e4900..50fbe35 100644
+--- a/drivers/net/phy/mdio_bus.c
++++ b/drivers/net/phy/mdio_bus.c
+@@ -38,6 +38,8 @@
+
+ #include <asm/irq.h>
+
++#include "mdio-boardinfo.h"
++
+ /**
+ * mdiobus_alloc_size - allocate a mii_bus structure
+ * @size: extra amount of memory to allocate for private storage.
+@@ -224,15 +226,33 @@ void mdiobus_free(struct mii_bus *bus)
+ }
+ EXPORT_SYMBOL(mdiobus_free);
+
++static void mdiobus_setup_phydev_from_boardinfo(struct mii_bus *bus,
++ struct phy_device *phydev,
++ struct mdio_board_info *bi)
++{
++ if (strcmp(bus->id, bi->bus_id) ||
++ bi->phy_addr != phydev->addr)
++ return;
++
++ phydev->dev.platform_data = (void *) bi->platform_data;
++}
++
+ struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)
+ {
+ struct phy_device *phydev;
++ struct mdio_board_entry *be;
+ int err;
+
+ phydev = get_phy_device(bus, addr, false);
+ if (IS_ERR(phydev) || phydev == NULL)
+ return phydev;
+
++ mutex_lock(&__mdio_board_lock);
++ list_for_each_entry(be, &__mdio_board_list, list)
++ mdiobus_setup_phydev_from_boardinfo(bus, phydev,
++ &be->board_info);
++ mutex_unlock(&__mdio_board_lock);
++
+ err = phy_device_register(phydev);
+ if (err) {
+ phy_device_free(phydev);
+diff --git a/include/linux/phy.h b/include/linux/phy.h
+index f1441b4..9dca415 100644
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -658,4 +658,22 @@ int __init mdio_bus_init(void);
+ void mdio_bus_exit(void);
+
+ extern struct bus_type mdio_bus_type;
++
++struct mdio_board_info {
++ const char *bus_id;
++ int phy_addr;
++
++ const void *platform_data;
++};
++
++#ifdef CONFIG_MDIO_BOARDINFO
++int mdiobus_register_board_info(const struct mdio_board_info *info, unsigned n);
++#else
++static inline int
++mdiobus_register_board_info(const struct mdio_board_info *info, unsigned n)
++{
++ return 0;
++}
++#endif
++
+ #endif /* __PHY_H */
+--
+1.8.5.3
+
diff --git a/target/mips/dragino-ms14s/patches/3.14.17/0022-mips-ath79-add-ath79-ethernet-driver.patch b/target/mips/dragino-ms14s/patches/3.14.17/0022-mips-ath79-add-ath79-ethernet-driver.patch
new file mode 100644
index 000000000..a7eff47b1
--- /dev/null
+++ b/target/mips/dragino-ms14s/patches/3.14.17/0022-mips-ath79-add-ath79-ethernet-driver.patch
@@ -0,0 +1,1429 @@
+From 0c6bdad5f210f5f2fe28dc197ab77a36402bb36e Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Wed, 14 May 2014 03:08:37 +0200
+Subject: [PATCH] mips: ath79: add ath79 ethernet driver
+
+---
+ arch/mips/ath79/Kconfig | 3 +
+ arch/mips/ath79/Makefile | 1 +
+ arch/mips/ath79/dev-eth.c | 1151 ++++++++++++++++++++++++
+ arch/mips/ath79/dev-eth.h | 51 ++
+ arch/mips/include/asm/mach-ath79/ar71xx_regs.h | 81 ++
+ 5 files changed, 1287 insertions(+)
+ create mode 100644 arch/mips/ath79/dev-eth.c
+ create mode 100644 arch/mips/ath79/dev-eth.h
+
+diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig
+index 3995e31..52cefd7 100644
+--- a/arch/mips/ath79/Kconfig
++++ b/arch/mips/ath79/Kconfig
+@@ -109,6 +109,9 @@ config SOC_QCA955X
+ config PCI_AR724X
+ def_bool n
+
++config ATH79_DEV_ETH
++ def_bool n
++
+ config ATH79_DEV_GPIO_BUTTONS
+ def_bool n
+
+diff --git a/arch/mips/ath79/Makefile b/arch/mips/ath79/Makefile
+index 5c9ff69..05485da 100644
+--- a/arch/mips/ath79/Makefile
++++ b/arch/mips/ath79/Makefile
+@@ -17,6 +17,7 @@ obj-$(CONFIG_PCI) += pci.o
+ # Devices
+ #
+ obj-y += dev-common.o
++obj-$(CONFIG_ATH79_DEV_ETH) += dev-eth.o
+ obj-$(CONFIG_ATH79_DEV_GPIO_BUTTONS) += dev-gpio-buttons.o
+ obj-$(CONFIG_ATH79_DEV_LEDS_GPIO) += dev-leds-gpio.o
+ obj-$(CONFIG_ATH79_DEV_SPI) += dev-spi.o
+diff --git a/arch/mips/ath79/dev-eth.c b/arch/mips/ath79/dev-eth.c
+new file mode 100644
+index 0000000..21feeb9
+--- /dev/null
++++ b/arch/mips/ath79/dev-eth.c
+@@ -0,0 +1,1151 @@
++/*
++ * Atheros AR71xx SoC platform devices
++ *
++ * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
++ * Copyright (C) 2008-2012 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Parts of this file are based on Atheros 2.6.15 BSP
++ * Parts of this file are based on Atheros 2.6.31 BSP
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/etherdevice.h>
++#include <linux/platform_device.h>
++#include <linux/serial_8250.h>
++#include <linux/clk.h>
++#include <linux/sizes.h>
++
++#include <asm/mach-ath79/ath79.h>
++#include <asm/mach-ath79/ar71xx_regs.h>
++#include <asm/mach-ath79/irq.h>
++
++#include "common.h"
++#include "dev-eth.h"
++
++unsigned char ath79_mac_base[ETH_ALEN] __initdata;
++
++static struct resource ath79_mdio0_resources[] = {
++ {
++ .name = "mdio_base",
++ .flags = IORESOURCE_MEM,
++ .start = AR71XX_GE0_BASE,
++ .end = AR71XX_GE0_BASE + 0x200 - 1,
++ }
++};
++
++struct ag71xx_mdio_platform_data ath79_mdio0_data;
++
++struct platform_device ath79_mdio0_device = {
++ .name = "ag71xx-mdio",
++ .id = 0,
++ .resource = ath79_mdio0_resources,
++ .num_resources = ARRAY_SIZE(ath79_mdio0_resources),
++ .dev = {
++ .platform_data = &ath79_mdio0_data,
++ },
++};
++
++static struct resource ath79_mdio1_resources[] = {
++ {
++ .name = "mdio_base",
++ .flags = IORESOURCE_MEM,
++ .start = AR71XX_GE1_BASE,
++ .end = AR71XX_GE1_BASE + 0x200 - 1,
++ }
++};
++
++struct ag71xx_mdio_platform_data ath79_mdio1_data;
++
++struct platform_device ath79_mdio1_device = {
++ .name = "ag71xx-mdio",
++ .id = 1,
++ .resource = ath79_mdio1_resources,
++ .num_resources = ARRAY_SIZE(ath79_mdio1_resources),
++ .dev = {
++ .platform_data = &ath79_mdio1_data,
++ },
++};
++
++static void ath79_set_pll(u32 cfg_reg, u32 pll_reg, u32 pll_val, u32 shift)
++{
++ void __iomem *base;
++ u32 t;
++
++ base = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
++
++ t = __raw_readl(base + cfg_reg);
++ t &= ~(3 << shift);
++ t |= (2 << shift);
++ __raw_writel(t, base + cfg_reg);
++ udelay(100);
++
++ __raw_writel(pll_val, base + pll_reg);
++
++ t |= (3 << shift);
++ __raw_writel(t, base + cfg_reg);
++ udelay(100);
++
++ t &= ~(3 << shift);
++ __raw_writel(t, base + cfg_reg);
++ udelay(100);
++
++ printk(KERN_DEBUG "ar71xx: pll_reg %#x: %#x\n",
++ (unsigned int)(base + pll_reg), __raw_readl(base + pll_reg));
++
++ iounmap(base);
++}
++
++static void __init ath79_mii_ctrl_set_if(unsigned int reg,
++ unsigned int mii_if)
++{
++ void __iomem *base;
++ u32 t;
++
++ base = ioremap(AR71XX_MII_BASE, AR71XX_MII_SIZE);
++
++ t = __raw_readl(base + reg);
++ t &= ~(AR71XX_MII_CTRL_IF_MASK);
++ t |= (mii_if & AR71XX_MII_CTRL_IF_MASK);
++ __raw_writel(t, base + reg);
++
++ iounmap(base);
++}
++
++static void ath79_mii_ctrl_set_speed(unsigned int reg, unsigned int speed)
++{
++ void __iomem *base;
++ unsigned int mii_speed;
++ u32 t;
++
++ switch (speed) {
++ case SPEED_10:
++ mii_speed = AR71XX_MII_CTRL_SPEED_10;
++ break;
++ case SPEED_100:
++ mii_speed = AR71XX_MII_CTRL_SPEED_100;
++ break;
++ case SPEED_1000:
++ mii_speed = AR71XX_MII_CTRL_SPEED_1000;
++ break;
++ default:
++ BUG();
++ }
++
++ base = ioremap(AR71XX_MII_BASE, AR71XX_MII_SIZE);
++
++ t = __raw_readl(base + reg);
++ t &= ~(AR71XX_MII_CTRL_SPEED_MASK << AR71XX_MII_CTRL_SPEED_SHIFT);
++ t |= mii_speed << AR71XX_MII_CTRL_SPEED_SHIFT;
++ __raw_writel(t, base + reg);
++
++ iounmap(base);
++}
++
++static unsigned long ar934x_get_mdio_ref_clock(void)
++{
++ void __iomem *base;
++ unsigned long ret;
++ u32 t;
++
++ base = ioremap(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
++
++ ret = 0;
++ t = __raw_readl(base + AR934X_PLL_SWITCH_CLOCK_CONTROL_REG);
++ if (t & AR934X_PLL_SWITCH_CLOCK_CONTROL_MDIO_CLK_SEL) {
++ ret = 100 * 1000 * 1000;
++ } else {
++ struct clk *clk;
++
++ clk = clk_get(NULL, "ref");
++ if (!IS_ERR(clk))
++ ret = clk_get_rate(clk);
++ }
++
++ iounmap(base);
++
++ return ret;
++}
++
++void __init ath79_register_mdio(unsigned int id, u32 phy_mask)
++{
++ struct platform_device *mdio_dev;
++ struct ag71xx_mdio_platform_data *mdio_data;
++ unsigned int max_id;
++
++ if (ath79_soc == ATH79_SOC_AR9341 ||
++ ath79_soc == ATH79_SOC_AR9342 ||
++ ath79_soc == ATH79_SOC_AR9344 ||
++ ath79_soc == ATH79_SOC_QCA9556 ||
++ ath79_soc == ATH79_SOC_QCA9558)
++ max_id = 1;
++ else
++ max_id = 0;
++
++ if (id > max_id) {
++ printk(KERN_ERR "ar71xx: invalid MDIO id %u\n", id);
++ return;
++ }
++
++ switch (ath79_soc) {
++ case ATH79_SOC_AR7241:
++ case ATH79_SOC_AR9330:
++ case ATH79_SOC_AR9331:
++ mdio_dev = &ath79_mdio1_device;
++ mdio_data = &ath79_mdio1_data;
++ break;
++
++ case ATH79_SOC_AR9341:
++ case ATH79_SOC_AR9342:
++ case ATH79_SOC_AR9344:
++ case ATH79_SOC_QCA9556:
++ case ATH79_SOC_QCA9558:
++ if (id == 0) {
++ mdio_dev = &ath79_mdio0_device;
++ mdio_data = &ath79_mdio0_data;
++ } else {
++ mdio_dev = &ath79_mdio1_device;
++ mdio_data = &ath79_mdio1_data;
++ }
++ break;
++
++ case ATH79_SOC_AR7242:
++ ath79_set_pll(AR71XX_PLL_REG_SEC_CONFIG,
++ AR7242_PLL_REG_ETH0_INT_CLOCK, 0x62000000,
++ AR71XX_ETH0_PLL_SHIFT);
++ /* fall through */
++ default:
++ mdio_dev = &ath79_mdio0_device;
++ mdio_data = &ath79_mdio0_data;
++ break;
++ }
++
++ mdio_data->phy_mask = phy_mask;
++
++ switch (ath79_soc) {
++ case ATH79_SOC_AR7240:
++ mdio_data->is_ar7240 = 1;
++ /* fall through */
++ case ATH79_SOC_AR7241:
++ mdio_data->builtin_switch = 1;
++ break;
++
++ case ATH79_SOC_AR9330:
++ mdio_data->is_ar9330 = 1;
++ /* fall through */
++ case ATH79_SOC_AR9331:
++ mdio_data->builtin_switch = 1;
++ break;
++
++ case ATH79_SOC_AR9341:
++ case ATH79_SOC_AR9342:
++ case ATH79_SOC_AR9344:
++ if (id == 1) {
++ mdio_data->builtin_switch = 1;
++ mdio_data->ref_clock = ar934x_get_mdio_ref_clock();
++ mdio_data->mdio_clock = 6250000;
++ }
++ mdio_data->is_ar934x = 1;
++ break;
++
++ case ATH79_SOC_QCA9556:
++ case ATH79_SOC_QCA9558:
++ mdio_data->is_ar934x = 1;
++ break;
++
++ default:
++ break;
++ }
++
++ platform_device_register(mdio_dev);
++}
++
++struct ath79_eth_pll_data ath79_eth0_pll_data;
++struct ath79_eth_pll_data ath79_eth1_pll_data;
++
++static u32 ath79_get_eth_pll(unsigned int mac, int speed)
++{
++ struct ath79_eth_pll_data *pll_data;
++ u32 pll_val;
++
++ switch (mac) {
++ case 0:
++ pll_data = &ath79_eth0_pll_data;
++ break;
++ case 1:
++ pll_data = &ath79_eth1_pll_data;
++ break;
++ default:
++ BUG();
++ }
++
++ switch (speed) {
++ case SPEED_10:
++ pll_val = pll_data->pll_10;
++ break;
++ case SPEED_100:
++ pll_val = pll_data->pll_100;
++ break;
++ case SPEED_1000:
++ pll_val = pll_data->pll_1000;
++ break;
++ default:
++ BUG();
++ }
++
++ return pll_val;
++}
++
++static void ath79_set_speed_ge0(int speed)
++{
++ u32 val = ath79_get_eth_pll(0, speed);
++
++ ath79_set_pll(AR71XX_PLL_REG_SEC_CONFIG, AR71XX_PLL_REG_ETH0_INT_CLOCK,
++ val, AR71XX_ETH0_PLL_SHIFT);
++ ath79_mii_ctrl_set_speed(AR71XX_MII_REG_MII0_CTRL, speed);
++}
++
++static void ath79_set_speed_ge1(int speed)
++{
++ u32 val = ath79_get_eth_pll(1, speed);
++
++ ath79_set_pll(AR71XX_PLL_REG_SEC_CONFIG, AR71XX_PLL_REG_ETH1_INT_CLOCK,
++ val, AR71XX_ETH1_PLL_SHIFT);
++ ath79_mii_ctrl_set_speed(AR71XX_MII_REG_MII1_CTRL, speed);
++}
++
++static void ar7242_set_speed_ge0(int speed)
++{
++ u32 val = ath79_get_eth_pll(0, speed);
++ void __iomem *base;
++
++ base = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
++ __raw_writel(val, base + AR7242_PLL_REG_ETH0_INT_CLOCK);
++ iounmap(base);
++}
++
++static void ar91xx_set_speed_ge0(int speed)
++{
++ u32 val = ath79_get_eth_pll(0, speed);
++
++ ath79_set_pll(AR913X_PLL_REG_ETH_CONFIG, AR913X_PLL_REG_ETH0_INT_CLOCK,
++ val, AR913X_ETH0_PLL_SHIFT);
++ ath79_mii_ctrl_set_speed(AR71XX_MII_REG_MII0_CTRL, speed);
++}
++
++static void ar91xx_set_speed_ge1(int speed)
++{
++ u32 val = ath79_get_eth_pll(1, speed);
++
++ ath79_set_pll(AR913X_PLL_REG_ETH_CONFIG, AR913X_PLL_REG_ETH1_INT_CLOCK,
++ val, AR913X_ETH1_PLL_SHIFT);
++ ath79_mii_ctrl_set_speed(AR71XX_MII_REG_MII1_CTRL, speed);
++}
++
++static void ar934x_set_speed_ge0(int speed)
++{
++ void __iomem *base;
++ u32 val = ath79_get_eth_pll(0, speed);
++
++ base = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
++ __raw_writel(val, base + AR934X_PLL_ETH_XMII_CONTROL_REG);
++ iounmap(base);
++}
++
++static void qca955x_set_speed_xmii(int speed)
++{
++ void __iomem *base;
++ u32 val = ath79_get_eth_pll(0, speed);
++
++ base = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
++ __raw_writel(val, base + QCA955X_PLL_ETH_XMII_CONTROL_REG);
++ iounmap(base);
++}
++
++static void qca955x_set_speed_sgmii(int speed)
++{
++ void __iomem *base;
++ u32 val = ath79_get_eth_pll(1, speed);
++
++ base = ioremap_nocache(AR71XX_PLL_BASE, AR71XX_PLL_SIZE);
++ __raw_writel(val, base + QCA955X_PLL_ETH_SGMII_CONTROL_REG);
++ iounmap(base);
++}
++
++static void ath79_set_speed_dummy(int speed)
++{
++}
++
++static void ath79_ddr_no_flush(void)
++{
++}
++
++static void ath79_ddr_flush_ge0(void)
++{
++ ath79_ddr_wb_flush(AR71XX_DDR_REG_FLUSH_GE0);
++}
++
++static void ath79_ddr_flush_ge1(void)
++{
++ ath79_ddr_wb_flush(AR71XX_DDR_REG_FLUSH_GE1);
++}
++
++static void ar724x_ddr_flush_ge0(void)
++{
++ ath79_ddr_wb_flush(AR724X_DDR_REG_FLUSH_GE0);
++}
++
++static void ar724x_ddr_flush_ge1(void)
++{
++ ath79_ddr_wb_flush(AR724X_DDR_REG_FLUSH_GE1);
++}
++
++static void ar91xx_ddr_flush_ge0(void)
++{
++ ath79_ddr_wb_flush(AR913X_DDR_REG_FLUSH_GE0);
++}
++
++static void ar91xx_ddr_flush_ge1(void)
++{
++ ath79_ddr_wb_flush(AR913X_DDR_REG_FLUSH_GE1);
++}
++
++static void ar933x_ddr_flush_ge0(void)
++{
++ ath79_ddr_wb_flush(AR933X_DDR_REG_FLUSH_GE0);
++}
++
++static void ar933x_ddr_flush_ge1(void)
++{
++ ath79_ddr_wb_flush(AR933X_DDR_REG_FLUSH_GE1);
++}
++
++static struct resource ath79_eth0_resources[] = {
++ {
++ .name = "mac_base",
++ .flags = IORESOURCE_MEM,
++ .start = AR71XX_GE0_BASE,
++ .end = AR71XX_GE0_BASE + 0x200 - 1,
++ }, {
++ .name = "mac_irq",
++ .flags = IORESOURCE_IRQ,
++ .start = ATH79_CPU_IRQ(4),
++ .end = ATH79_CPU_IRQ(4),
++ },
++};
++
++struct ag71xx_platform_data ath79_eth0_data = {
++ .reset_bit = AR71XX_RESET_GE0_MAC,
++};
++
++struct platform_device ath79_eth0_device = {
++ .name = "ag71xx",
++ .id = 0,
++ .resource = ath79_eth0_resources,
++ .num_resources = ARRAY_SIZE(ath79_eth0_resources),
++ .dev = {
++ .platform_data = &ath79_eth0_data,
++ },
++};
++
++static struct resource ath79_eth1_resources[] = {
++ {
++ .name = "mac_base",
++ .flags = IORESOURCE_MEM,
++ .start = AR71XX_GE1_BASE,
++ .end = AR71XX_GE1_BASE + 0x200 - 1,
++ }, {
++ .name = "mac_irq",
++ .flags = IORESOURCE_IRQ,
++ .start = ATH79_CPU_IRQ(5),
++ .end = ATH79_CPU_IRQ(5),
++ },
++};
++
++struct ag71xx_platform_data ath79_eth1_data = {
++ .reset_bit = AR71XX_RESET_GE1_MAC,
++};
++
++struct platform_device ath79_eth1_device = {
++ .name = "ag71xx",
++ .id = 1,
++ .resource = ath79_eth1_resources,
++ .num_resources = ARRAY_SIZE(ath79_eth1_resources),
++ .dev = {
++ .platform_data = &ath79_eth1_data,
++ },
++};
++
++struct ag71xx_switch_platform_data ath79_switch_data;
++
++#define AR71XX_PLL_VAL_1000 0x00110000
++#define AR71XX_PLL_VAL_100 0x00001099
++#define AR71XX_PLL_VAL_10 0x00991099
++
++#define AR724X_PLL_VAL_1000 0x00110000
++#define AR724X_PLL_VAL_100 0x00001099
++#define AR724X_PLL_VAL_10 0x00991099
++
++#define AR7242_PLL_VAL_1000 0x16000000
++#define AR7242_PLL_VAL_100 0x00000101
++#define AR7242_PLL_VAL_10 0x00001616
++
++#define AR913X_PLL_VAL_1000 0x1a000000
++#define AR913X_PLL_VAL_100 0x13000a44
++#define AR913X_PLL_VAL_10 0x00441099
++
++#define AR933X_PLL_VAL_1000 0x00110000
++#define AR933X_PLL_VAL_100 0x00001099
++#define AR933X_PLL_VAL_10 0x00991099
++
++#define AR934X_PLL_VAL_1000 0x16000000
++#define AR934X_PLL_VAL_100 0x00000101
++#define AR934X_PLL_VAL_10 0x00001616
++
++static void __init ath79_init_eth_pll_data(unsigned int id)
++{
++ struct ath79_eth_pll_data *pll_data;
++ u32 pll_10, pll_100, pll_1000;
++
++ switch (id) {
++ case 0:
++ pll_data = &ath79_eth0_pll_data;
++ break;
++ case 1:
++ pll_data = &ath79_eth1_pll_data;
++ break;
++ default:
++ BUG();
++ }
++
++ switch (ath79_soc) {
++ case ATH79_SOC_AR7130:
++ case ATH79_SOC_AR7141:
++ case ATH79_SOC_AR7161:
++ pll_10 = AR71XX_PLL_VAL_10;
++ pll_100 = AR71XX_PLL_VAL_100;
++ pll_1000 = AR71XX_PLL_VAL_1000;
++ break;
++
++ case ATH79_SOC_AR7240:
++ case ATH79_SOC_AR7241:
++ pll_10 = AR724X_PLL_VAL_10;
++ pll_100 = AR724X_PLL_VAL_100;
++ pll_1000 = AR724X_PLL_VAL_1000;
++ break;
++
++ case ATH79_SOC_AR7242:
++ pll_10 = AR7242_PLL_VAL_10;
++ pll_100 = AR7242_PLL_VAL_100;
++ pll_1000 = AR7242_PLL_VAL_1000;
++ break;
++
++ case ATH79_SOC_AR9130:
++ case ATH79_SOC_AR9132:
++ pll_10 = AR913X_PLL_VAL_10;
++ pll_100 = AR913X_PLL_VAL_100;
++ pll_1000 = AR913X_PLL_VAL_1000;
++ break;
++
++ case ATH79_SOC_AR9330:
++ case ATH79_SOC_AR9331:
++ pll_10 = AR933X_PLL_VAL_10;
++ pll_100 = AR933X_PLL_VAL_100;
++ pll_1000 = AR933X_PLL_VAL_1000;
++ break;
++
++ case ATH79_SOC_AR9341:
++ case ATH79_SOC_AR9342:
++ case ATH79_SOC_AR9344:
++ case ATH79_SOC_QCA9556:
++ case ATH79_SOC_QCA9558:
++ pll_10 = AR934X_PLL_VAL_10;
++ pll_100 = AR934X_PLL_VAL_100;
++ pll_1000 = AR934X_PLL_VAL_1000;
++ break;
++
++ default:
++ BUG();
++ }
++
++ if (!pll_data->pll_10)
++ pll_data->pll_10 = pll_10;
++
++ if (!pll_data->pll_100)
++ pll_data->pll_100 = pll_100;
++
++ if (!pll_data->pll_1000)
++ pll_data->pll_1000 = pll_1000;
++}
++
++static int __init ath79_setup_phy_if_mode(unsigned int id,
++ struct ag71xx_platform_data *pdata)
++{
++ unsigned int mii_if;
++
++ switch (id) {
++ case 0:
++ switch (ath79_soc) {
++ case ATH79_SOC_AR7130:
++ case ATH79_SOC_AR7141:
++ case ATH79_SOC_AR7161:
++ case ATH79_SOC_AR9130:
++ case ATH79_SOC_AR9132:
++ switch (pdata->phy_if_mode) {
++ case PHY_INTERFACE_MODE_MII:
++ mii_if = AR71XX_MII0_CTRL_IF_MII;
++ break;
++ case PHY_INTERFACE_MODE_GMII:
++ mii_if = AR71XX_MII0_CTRL_IF_GMII;
++ break;
++ case PHY_INTERFACE_MODE_RGMII:
++ mii_if = AR71XX_MII0_CTRL_IF_RGMII;
++ break;
++ case PHY_INTERFACE_MODE_RMII:
++ mii_if = AR71XX_MII0_CTRL_IF_RMII;
++ break;
++ default:
++ return -EINVAL;
++ }
++ ath79_mii_ctrl_set_if(AR71XX_MII_REG_MII0_CTRL, mii_if);
++ break;
++
++ case ATH79_SOC_AR7240:
++ case ATH79_SOC_AR7241:
++ case ATH79_SOC_AR9330:
++ case ATH79_SOC_AR9331:
++ pdata->phy_if_mode = PHY_INTERFACE_MODE_MII;
++ break;
++
++ case ATH79_SOC_AR7242:
++ /* FIXME */
++
++ case ATH79_SOC_AR9341:
++ case ATH79_SOC_AR9342:
++ case ATH79_SOC_AR9344:
++ switch (pdata->phy_if_mode) {
++ case PHY_INTERFACE_MODE_MII:
++ case PHY_INTERFACE_MODE_GMII:
++ case PHY_INTERFACE_MODE_RGMII:
++ case PHY_INTERFACE_MODE_RMII:
++ break;
++ default:
++ return -EINVAL;
++ }
++ break;
++
++ case ATH79_SOC_QCA9556:
++ case ATH79_SOC_QCA9558:
++ switch (pdata->phy_if_mode) {
++ case PHY_INTERFACE_MODE_MII:
++ case PHY_INTERFACE_MODE_RGMII:
++ case PHY_INTERFACE_MODE_SGMII:
++ break;
++ default:
++ return -EINVAL;
++ }
++ break;
++
++ default:
++ BUG();
++ }
++ break;
++ case 1:
++ switch (ath79_soc) {
++ case ATH79_SOC_AR7130:
++ case ATH79_SOC_AR7141:
++ case ATH79_SOC_AR7161:
++ case ATH79_SOC_AR9130:
++ case ATH79_SOC_AR9132:
++ switch (pdata->phy_if_mode) {
++ case PHY_INTERFACE_MODE_RMII:
++ mii_if = AR71XX_MII1_CTRL_IF_RMII;
++ break;
++ case PHY_INTERFACE_MODE_RGMII:
++ mii_if = AR71XX_MII1_CTRL_IF_RGMII;
++ break;
++ default:
++ return -EINVAL;
++ }
++ ath79_mii_ctrl_set_if(AR71XX_MII_REG_MII1_CTRL, mii_if);
++ break;
++
++ case ATH79_SOC_AR7240:
++ case ATH79_SOC_AR7241:
++ case ATH79_SOC_AR9330:
++ case ATH79_SOC_AR9331:
++ pdata->phy_if_mode = PHY_INTERFACE_MODE_GMII;
++ break;
++
++ case ATH79_SOC_AR7242:
++ /* FIXME */
++
++ case ATH79_SOC_AR9341:
++ case ATH79_SOC_AR9342:
++ case ATH79_SOC_AR9344:
++ switch (pdata->phy_if_mode) {
++ case PHY_INTERFACE_MODE_MII:
++ case PHY_INTERFACE_MODE_GMII:
++ break;
++ default:
++ return -EINVAL;
++ }
++ break;
++
++ case ATH79_SOC_QCA9556:
++ case ATH79_SOC_QCA9558:
++ switch (pdata->phy_if_mode) {
++ case PHY_INTERFACE_MODE_MII:
++ case PHY_INTERFACE_MODE_RGMII:
++ case PHY_INTERFACE_MODE_SGMII:
++ break;
++ default:
++ return -EINVAL;
++ }
++ break;
++
++ default:
++ BUG();
++ }
++ break;
++ }
++
++ return 0;
++}
++
++void __init ath79_setup_ar933x_phy4_switch(bool mac, bool mdio)
++{
++ void __iomem *base;
++ u32 t;
++
++ base = ioremap(AR933X_GMAC_BASE, AR933X_GMAC_SIZE);
++
++ t = __raw_readl(base + AR933X_GMAC_REG_ETH_CFG);
++ t &= ~(AR933X_ETH_CFG_SW_PHY_SWAP | AR933X_ETH_CFG_SW_PHY_ADDR_SWAP);
++ if (mac)
++ t |= AR933X_ETH_CFG_SW_PHY_SWAP;
++ if (mdio)
++ t |= AR933X_ETH_CFG_SW_PHY_ADDR_SWAP;
++ __raw_writel(t, base + AR933X_GMAC_REG_ETH_CFG);
++
++ iounmap(base);
++}
++
++void __init ath79_setup_ar934x_eth_cfg(u32 mask)
++{
++ void __iomem *base;
++ u32 t;
++
++ base = ioremap(AR934X_GMAC_BASE, AR934X_GMAC_SIZE);
++
++ t = __raw_readl(base + AR934X_GMAC_REG_ETH_CFG);
++
++ t &= ~(AR934X_ETH_CFG_RGMII_GMAC0 |
++ AR934X_ETH_CFG_MII_GMAC0 |
++ AR934X_ETH_CFG_GMII_GMAC0 |
++ AR934X_ETH_CFG_SW_ONLY_MODE |
++ AR934X_ETH_CFG_SW_PHY_SWAP);
++
++ t |= mask;
++
++ __raw_writel(t, base + AR934X_GMAC_REG_ETH_CFG);
++ /* flush write */
++ __raw_readl(base + AR934X_GMAC_REG_ETH_CFG);
++
++ iounmap(base);
++}
++
++static int ath79_eth_instance __initdata;
++void __init ath79_register_eth(unsigned int id)
++{
++ struct platform_device *pdev;
++ struct ag71xx_platform_data *pdata;
++ int err;
++
++ if (id > 1) {
++ printk(KERN_ERR "ar71xx: invalid ethernet id %d\n", id);
++ return;
++ }
++
++ ath79_init_eth_pll_data(id);
++
++ if (id == 0)
++ pdev = &ath79_eth0_device;
++ else
++ pdev = &ath79_eth1_device;
++
++ pdata = pdev->dev.platform_data;
++
++ pdata->max_frame_len = 1540;
++ pdata->desc_pktlen_mask = 0xfff;
++
++ err = ath79_setup_phy_if_mode(id, pdata);
++ if (err) {
++ printk(KERN_ERR
++ "ar71xx: invalid PHY interface mode for GE%u\n", id);
++ return;
++ }
++
++ switch (ath79_soc) {
++ case ATH79_SOC_AR7130:
++ if (id == 0) {
++ pdata->ddr_flush = ath79_ddr_flush_ge0;
++ pdata->set_speed = ath79_set_speed_ge0;
++ } else {
++ pdata->ddr_flush = ath79_ddr_flush_ge1;
++ pdata->set_speed = ath79_set_speed_ge1;
++ }
++ break;
++
++ case ATH79_SOC_AR7141:
++ case ATH79_SOC_AR7161:
++ if (id == 0) {
++ pdata->ddr_flush = ath79_ddr_flush_ge0;
++ pdata->set_speed = ath79_set_speed_ge0;
++ } else {
++ pdata->ddr_flush = ath79_ddr_flush_ge1;
++ pdata->set_speed = ath79_set_speed_ge1;
++ }
++ pdata->has_gbit = 1;
++ break;
++
++ case ATH79_SOC_AR7242:
++ if (id == 0) {
++ pdata->reset_bit |= AR724X_RESET_GE0_MDIO |
++ AR71XX_RESET_GE0_PHY;
++ pdata->ddr_flush = ar724x_ddr_flush_ge0;
++ pdata->set_speed = ar7242_set_speed_ge0;
++ } else {
++ pdata->reset_bit |= AR724X_RESET_GE1_MDIO |
++ AR71XX_RESET_GE1_PHY;
++ pdata->ddr_flush = ar724x_ddr_flush_ge1;
++ pdata->set_speed = ath79_set_speed_dummy;
++ }
++ pdata->has_gbit = 1;
++ pdata->is_ar724x = 1;
++
++ if (!pdata->fifo_cfg1)
++ pdata->fifo_cfg1 = 0x0010ffff;
++ if (!pdata->fifo_cfg2)
++ pdata->fifo_cfg2 = 0x015500aa;
++ if (!pdata->fifo_cfg3)
++ pdata->fifo_cfg3 = 0x01f00140;
++ break;
++
++ case ATH79_SOC_AR7241:
++ if (id == 0)
++ pdata->reset_bit |= AR724X_RESET_GE0_MDIO;
++ else
++ pdata->reset_bit |= AR724X_RESET_GE1_MDIO;
++ /* fall through */
++ case ATH79_SOC_AR7240:
++ if (id == 0) {
++ pdata->reset_bit |= AR71XX_RESET_GE0_PHY;
++ pdata->ddr_flush = ar724x_ddr_flush_ge0;
++ pdata->set_speed = ath79_set_speed_dummy;
++
++ pdata->phy_mask = BIT(4);
++ } else {
++ pdata->reset_bit |= AR71XX_RESET_GE1_PHY;
++ pdata->ddr_flush = ar724x_ddr_flush_ge1;
++ pdata->set_speed = ath79_set_speed_dummy;
++
++ pdata->speed = SPEED_1000;
++ pdata->duplex = DUPLEX_FULL;
++ pdata->switch_data = &ath79_switch_data;
++
++ ath79_switch_data.phy_poll_mask |= BIT(4);
++ }
++ pdata->has_gbit = 1;
++ pdata->is_ar724x = 1;
++ if (ath79_soc == ATH79_SOC_AR7240)
++ pdata->is_ar7240 = 1;
++
++ if (!pdata->fifo_cfg1)
++ pdata->fifo_cfg1 = 0x0010ffff;
++ if (!pdata->fifo_cfg2)
++ pdata->fifo_cfg2 = 0x015500aa;
++ if (!pdata->fifo_cfg3)
++ pdata->fifo_cfg3 = 0x01f00140;
++ break;
++
++ case ATH79_SOC_AR9130:
++ if (id == 0) {
++ pdata->ddr_flush = ar91xx_ddr_flush_ge0;
++ pdata->set_speed = ar91xx_set_speed_ge0;
++ } else {
++ pdata->ddr_flush = ar91xx_ddr_flush_ge1;
++ pdata->set_speed = ar91xx_set_speed_ge1;
++ }
++ pdata->is_ar91xx = 1;
++ break;
++
++ case ATH79_SOC_AR9132:
++ if (id == 0) {
++ pdata->ddr_flush = ar91xx_ddr_flush_ge0;
++ pdata->set_speed = ar91xx_set_speed_ge0;
++ } else {
++ pdata->ddr_flush = ar91xx_ddr_flush_ge1;
++ pdata->set_speed = ar91xx_set_speed_ge1;
++ }
++ pdata->is_ar91xx = 1;
++ pdata->has_gbit = 1;
++ break;
++
++ case ATH79_SOC_AR9330:
++ case ATH79_SOC_AR9331:
++ if (id == 0) {
++ pdata->reset_bit = AR933X_RESET_GE0_MAC |
++ AR933X_RESET_GE0_MDIO;
++ pdata->ddr_flush = ar933x_ddr_flush_ge0;
++ pdata->set_speed = ath79_set_speed_dummy;
++
++ pdata->phy_mask = BIT(4);
++ } else {
++ pdata->reset_bit = AR933X_RESET_GE1_MAC |
++ AR933X_RESET_GE1_MDIO;
++ pdata->ddr_flush = ar933x_ddr_flush_ge1;
++ pdata->set_speed = ath79_set_speed_dummy;
++
++ pdata->speed = SPEED_1000;
++ pdata->duplex = DUPLEX_FULL;
++ pdata->switch_data = &ath79_switch_data;
++
++ ath79_switch_data.phy_poll_mask |= BIT(4);
++ }
++
++ pdata->has_gbit = 1;
++ pdata->is_ar724x = 1;
++
++ if (!pdata->fifo_cfg1)
++ pdata->fifo_cfg1 = 0x0010ffff;
++ if (!pdata->fifo_cfg2)
++ pdata->fifo_cfg2 = 0x015500aa;
++ if (!pdata->fifo_cfg3)
++ pdata->fifo_cfg3 = 0x01f00140;
++ break;
++
++ case ATH79_SOC_AR9341:
++ case ATH79_SOC_AR9342:
++ case ATH79_SOC_AR9344:
++ if (id == 0) {
++ pdata->reset_bit = AR934X_RESET_GE0_MAC |
++ AR934X_RESET_GE0_MDIO;
++ pdata->set_speed = ar934x_set_speed_ge0;
++ } else {
++ pdata->reset_bit = AR934X_RESET_GE1_MAC |
++ AR934X_RESET_GE1_MDIO;
++ pdata->set_speed = ath79_set_speed_dummy;
++
++ pdata->switch_data = &ath79_switch_data;
++
++ /* reset the built-in switch */
++ ath79_device_reset_set(AR934X_RESET_ETH_SWITCH);
++ ath79_device_reset_clear(AR934X_RESET_ETH_SWITCH);
++ }
++
++ pdata->ddr_flush = ath79_ddr_no_flush;
++ pdata->has_gbit = 1;
++ pdata->is_ar724x = 1;
++
++ pdata->max_frame_len = SZ_16K - 1;
++ pdata->desc_pktlen_mask = SZ_16K - 1;
++
++ if (!pdata->fifo_cfg1)
++ pdata->fifo_cfg1 = 0x0010ffff;
++ if (!pdata->fifo_cfg2)
++ pdata->fifo_cfg2 = 0x015500aa;
++ if (!pdata->fifo_cfg3)
++ pdata->fifo_cfg3 = 0x01f00140;
++ break;
++
++ case ATH79_SOC_QCA9556:
++ case ATH79_SOC_QCA9558:
++ if (id == 0) {
++ pdata->reset_bit = QCA955X_RESET_GE0_MAC |
++ QCA955X_RESET_GE0_MDIO;
++ pdata->set_speed = qca955x_set_speed_xmii;
++ } else {
++ pdata->reset_bit = QCA955X_RESET_GE1_MAC |
++ QCA955X_RESET_GE1_MDIO;
++ pdata->set_speed = qca955x_set_speed_sgmii;
++ }
++
++ pdata->ddr_flush = ath79_ddr_no_flush;
++ pdata->has_gbit = 1;
++ pdata->is_ar724x = 1;
++
++ /*
++ * Limit the maximum frame length to 4095 bytes.
++ * Although the documentation says that the hardware
++ * limit is 16383 bytes but that does not work in
++ * practice. It seems that the hardware only updates
++ * the lowest 12 bits of the packet length field
++ * in the RX descriptor.
++ */
++ pdata->max_frame_len = SZ_4K - 1;
++ pdata->desc_pktlen_mask = SZ_16K - 1;
++
++ if (!pdata->fifo_cfg1)
++ pdata->fifo_cfg1 = 0x0010ffff;
++ if (!pdata->fifo_cfg2)
++ pdata->fifo_cfg2 = 0x015500aa;
++ if (!pdata->fifo_cfg3)
++ pdata->fifo_cfg3 = 0x01f00140;
++ break;
++
++ default:
++ BUG();
++ }
++
++ switch (pdata->phy_if_mode) {
++ case PHY_INTERFACE_MODE_GMII:
++ case PHY_INTERFACE_MODE_RGMII:
++ case PHY_INTERFACE_MODE_SGMII:
++ if (!pdata->has_gbit) {
++ printk(KERN_ERR "ar71xx: no gbit available on eth%d\n",
++ id);
++ return;
++ }
++ /* fallthrough */
++ default:
++ break;
++ }
++
++ if (!is_valid_ether_addr(pdata->mac_addr)) {
++ random_ether_addr(pdata->mac_addr);
++ printk(KERN_DEBUG
++ "ar71xx: using random MAC address for eth%d\n",
++ ath79_eth_instance);
++ }
++
++ if (pdata->mii_bus_dev == NULL) {
++ switch (ath79_soc) {
++ case ATH79_SOC_AR9341:
++ case ATH79_SOC_AR9342:
++ case ATH79_SOC_AR9344:
++ if (id == 0)
++ pdata->mii_bus_dev = &ath79_mdio0_device.dev;
++ else
++ pdata->mii_bus_dev = &ath79_mdio1_device.dev;
++ break;
++
++ case ATH79_SOC_AR7241:
++ case ATH79_SOC_AR9330:
++ case ATH79_SOC_AR9331:
++ pdata->mii_bus_dev = &ath79_mdio1_device.dev;
++ break;
++
++ case ATH79_SOC_QCA9556:
++ case ATH79_SOC_QCA9558:
++ /* don't assign any MDIO device by default */
++ break;
++
++ default:
++ pdata->mii_bus_dev = &ath79_mdio0_device.dev;
++ break;
++ }
++ }
++
++ /* Reset the device */
++ ath79_device_reset_set(pdata->reset_bit);
++ mdelay(100);
++
++ ath79_device_reset_clear(pdata->reset_bit);
++ mdelay(100);
++
++ platform_device_register(pdev);
++ ath79_eth_instance++;
++}
++
++void __init ath79_set_mac_base(unsigned char *mac)
++{
++ memcpy(ath79_mac_base, mac, ETH_ALEN);
++}
++
++void __init ath79_parse_ascii_mac(char *mac_str, u8 *mac)
++{
++ int t;
++
++ t = sscanf(mac_str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
++ &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
++
++ if (t != ETH_ALEN)
++ t = sscanf(mac_str, "%02hhx.%02hhx.%02hhx.%02hhx.%02hhx.%02hhx",
++ &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
++
++ if (t != ETH_ALEN || !is_valid_ether_addr(mac)) {
++ memset(mac, 0, ETH_ALEN);
++ printk(KERN_DEBUG "ar71xx: invalid mac address \"%s\"\n",
++ mac_str);
++ }
++}
++
++static void __init ath79_set_mac_base_ascii(char *str)
++{
++ u8 mac[ETH_ALEN];
++
++ ath79_parse_ascii_mac(str, mac);
++ ath79_set_mac_base(mac);
++}
++
++static int __init ath79_ethaddr_setup(char *str)
++{
++ ath79_set_mac_base_ascii(str);
++ return 1;
++}
++__setup("ethaddr=", ath79_ethaddr_setup);
++
++static int __init ath79_kmac_setup(char *str)
++{
++ ath79_set_mac_base_ascii(str);
++ return 1;
++}
++__setup("kmac=", ath79_kmac_setup);
++
++void __init ath79_init_mac(unsigned char *dst, const unsigned char *src,
++ int offset)
++{
++ int t;
++
++ if (!dst)
++ return;
++
++ if (!src || !is_valid_ether_addr(src)) {
++ memset(dst, '\0', ETH_ALEN);
++ return;
++ }
++
++ t = (((u32) src[3]) << 16) + (((u32) src[4]) << 8) + ((u32) src[5]);
++ t += offset;
++
++ dst[0] = src[0];
++ dst[1] = src[1];
++ dst[2] = src[2];
++ dst[3] = (t >> 16) & 0xff;
++ dst[4] = (t >> 8) & 0xff;
++ dst[5] = t & 0xff;
++}
++
++void __init ath79_init_local_mac(unsigned char *dst, const unsigned char *src)
++{
++ int i;
++
++ if (!dst)
++ return;
++
++ if (!src || !is_valid_ether_addr(src)) {
++ memset(dst, '\0', ETH_ALEN);
++ return;
++ }
++
++ for (i = 0; i < ETH_ALEN; i++)
++ dst[i] = src[i];
++ dst[0] |= 0x02;
++}
+diff --git a/arch/mips/ath79/dev-eth.h b/arch/mips/ath79/dev-eth.h
+new file mode 100644
+index 0000000..ff26ec4
+--- /dev/null
++++ b/arch/mips/ath79/dev-eth.h
+@@ -0,0 +1,51 @@
++/*
++ * Atheros AR71xx SoC device definitions
++ *
++ * Copyright (C) 2008-2012 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#ifndef _ATH79_DEV_ETH_H
++#define _ATH79_DEV_ETH_H
++
++#include <asm/mach-ath79/ag71xx_platform.h>
++
++struct platform_device;
++
++extern unsigned char ath79_mac_base[] __initdata;
++void ath79_parse_ascii_mac(char *mac_str, u8 *mac);
++void ath79_init_mac(unsigned char *dst, const unsigned char *src,
++ int offset);
++void ath79_init_local_mac(unsigned char *dst, const unsigned char *src);
++
++struct ath79_eth_pll_data {
++ u32 pll_10;
++ u32 pll_100;
++ u32 pll_1000;
++};
++
++extern struct ath79_eth_pll_data ath79_eth0_pll_data;
++extern struct ath79_eth_pll_data ath79_eth1_pll_data;
++
++extern struct ag71xx_platform_data ath79_eth0_data;
++extern struct ag71xx_platform_data ath79_eth1_data;
++extern struct platform_device ath79_eth0_device;
++extern struct platform_device ath79_eth1_device;
++void ath79_register_eth(unsigned int id);
++
++extern struct ag71xx_switch_platform_data ath79_switch_data;
++
++extern struct ag71xx_mdio_platform_data ath79_mdio0_data;
++extern struct ag71xx_mdio_platform_data ath79_mdio1_data;
++extern struct platform_device ath79_mdio0_device;
++extern struct platform_device ath79_mdio1_device;
++void ath79_register_mdio(unsigned int id, u32 phy_mask);
++
++void ath79_setup_ar933x_phy4_switch(bool mac, bool mdio);
++void ath79_setup_ar934x_eth_cfg(u32 mask);
++
++#endif /* _ATH79_DEV_ETH_H */
+diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
+index cd41e93..3e6b2ed 100644
+--- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
++++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
+@@ -20,6 +20,10 @@
+ #include <linux/bitops.h>
+
+ #define AR71XX_APB_BASE 0x18000000
++#define AR71XX_GE0_BASE 0x19000000
++#define AR71XX_GE0_SIZE 0x10000
++#define AR71XX_GE1_BASE 0x1a000000
++#define AR71XX_GE1_SIZE 0x10000
+ #define AR71XX_EHCI_BASE 0x1b000000
+ #define AR71XX_EHCI_SIZE 0x1000
+ #define AR71XX_OHCI_BASE 0x1c000000
+@@ -39,6 +43,8 @@
+ #define AR71XX_PLL_SIZE 0x100
+ #define AR71XX_RESET_BASE (AR71XX_APB_BASE + 0x00060000)
+ #define AR71XX_RESET_SIZE 0x100
++#define AR71XX_MII_BASE (AR71XX_APB_BASE + 0x00070000)
++#define AR71XX_MII_SIZE 0x100
+
+ #define AR71XX_PCI_MEM_BASE 0x10000000
+ #define AR71XX_PCI_MEM_SIZE 0x07000000
+@@ -81,11 +87,15 @@
+
+ #define AR933X_UART_BASE (AR71XX_APB_BASE + 0x00020000)
+ #define AR933X_UART_SIZE 0x14
++#define AR933X_GMAC_BASE (AR71XX_APB_BASE + 0x00070000)
++#define AR933X_GMAC_SIZE 0x04
+ #define AR933X_WMAC_BASE (AR71XX_APB_BASE + 0x00100000)
+ #define AR933X_WMAC_SIZE 0x20000
+ #define AR933X_EHCI_BASE 0x1b000000
+ #define AR933X_EHCI_SIZE 0x1000
+
++#define AR934X_GMAC_BASE (AR71XX_APB_BASE + 0x00070000)
++#define AR934X_GMAC_SIZE 0x14
+ #define AR934X_WMAC_BASE (AR71XX_APB_BASE + 0x00100000)
+ #define AR934X_WMAC_SIZE 0x20000
+ #define AR934X_EHCI_BASE 0x1b000000
+@@ -166,6 +176,9 @@
+ #define AR71XX_AHB_DIV_SHIFT 20
+ #define AR71XX_AHB_DIV_MASK 0x7
+
++#define AR71XX_ETH0_PLL_SHIFT 17
++#define AR71XX_ETH1_PLL_SHIFT 19
++
+ #define AR724X_PLL_REG_CPU_CONFIG 0x00
+ #define AR724X_PLL_REG_PCIE_CONFIG 0x18
+
+@@ -178,6 +191,8 @@
+ #define AR724X_DDR_DIV_SHIFT 22
+ #define AR724X_DDR_DIV_MASK 0x3
+
++#define AR7242_PLL_REG_ETH0_INT_CLOCK 0x2c
++
+ #define AR913X_PLL_REG_CPU_CONFIG 0x00
+ #define AR913X_PLL_REG_ETH_CONFIG 0x04
+ #define AR913X_PLL_REG_ETH0_INT_CLOCK 0x14
+@@ -190,6 +205,9 @@
+ #define AR913X_AHB_DIV_SHIFT 19
+ #define AR913X_AHB_DIV_MASK 0x1
+
++#define AR913X_ETH0_PLL_SHIFT 20
++#define AR913X_ETH1_PLL_SHIFT 22
++
+ #define AR933X_PLL_CPU_CONFIG_REG 0x00
+ #define AR933X_PLL_CLOCK_CTRL_REG 0x08
+
+@@ -211,6 +229,8 @@
+ #define AR934X_PLL_CPU_CONFIG_REG 0x00
+ #define AR934X_PLL_DDR_CONFIG_REG 0x04
+ #define AR934X_PLL_CPU_DDR_CLK_CTRL_REG 0x08
++#define AR934X_PLL_SWITCH_CLOCK_CONTROL_REG 0x24
++#define AR934X_PLL_ETH_XMII_CONTROL_REG 0x2c
+
+ #define AR934X_PLL_CPU_CONFIG_NFRAC_SHIFT 0
+ #define AR934X_PLL_CPU_CONFIG_NFRAC_MASK 0x3f
+@@ -243,9 +263,13 @@
+ #define AR934X_PLL_CPU_DDR_CLK_CTRL_DDRCLK_FROM_DDRPLL BIT(21)
+ #define AR934X_PLL_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL BIT(24)
+
++#define AR934X_PLL_SWITCH_CLOCK_CONTROL_MDIO_CLK_SEL BIT(6)
++
+ #define QCA955X_PLL_CPU_CONFIG_REG 0x00
+ #define QCA955X_PLL_DDR_CONFIG_REG 0x04
+ #define QCA955X_PLL_CLK_CTRL_REG 0x08
++#define QCA955X_PLL_ETH_XMII_CONTROL_REG 0x28
++#define QCA955X_PLL_ETH_SGMII_CONTROL_REG 0x48
+
+ #define QCA955X_PLL_CPU_CONFIG_NFRAC_SHIFT 0
+ #define QCA955X_PLL_CPU_CONFIG_NFRAC_MASK 0x3f
+@@ -370,16 +394,30 @@
+ #define AR913X_RESET_USB_HOST BIT(5)
+ #define AR913X_RESET_USB_PHY BIT(4)
+
++#define AR933X_RESET_GE1_MDIO BIT(23)
++#define AR933X_RESET_GE0_MDIO BIT(22)
++#define AR933X_RESET_GE1_MAC BIT(13)
+ #define AR933X_RESET_WMAC BIT(11)
++#define AR933X_RESET_GE0_MAC BIT(9)
+ #define AR933X_RESET_USB_HOST BIT(5)
+ #define AR933X_RESET_USB_PHY BIT(4)
+ #define AR933X_RESET_USBSUS_OVERRIDE BIT(3)
+
++#define AR934X_RESET_GE1_MDIO BIT(23)
++#define AR934X_RESET_GE0_MDIO BIT(22)
++#define AR934X_RESET_GE1_MAC BIT(13)
+ #define AR934X_RESET_USB_PHY_ANALOG BIT(11)
++#define AR934X_RESET_GE0_MAC BIT(9)
++#define AR934X_RESET_ETH_SWITCH BIT(8)
+ #define AR934X_RESET_USB_HOST BIT(5)
+ #define AR934X_RESET_USB_PHY BIT(4)
+ #define AR934X_RESET_USBSUS_OVERRIDE BIT(3)
+
++#define QCA955X_RESET_GE1_MDIO BIT(23)
++#define QCA955X_RESET_GE0_MDIO BIT(22)
++#define QCA955X_RESET_GE1_MAC BIT(13)
++#define QCA955X_RESET_GE0_MAC BIT(9)
++
+ #define AR933X_BOOTSTRAP_REF_CLK_40 BIT(0)
+
+ #define AR934X_BOOTSTRAP_SW_OPTION8 BIT(23)
+@@ -552,4 +590,47 @@
+ #define AR934X_SRIF_DPLL2_OUTDIV_SHIFT 13
+ #define AR934X_SRIF_DPLL2_OUTDIV_MASK 0x7
+
++#define AR71XX_GPIO_FUNC_SPI_CS2_EN BIT(13)
++#define AR71XX_GPIO_FUNC_SPI_CS1_EN BIT(12)
++
++/*
++ * MII_CTRL block
++ */
++#define AR71XX_MII_REG_MII0_CTRL 0x00
++#define AR71XX_MII_REG_MII1_CTRL 0x04
++
++#define AR71XX_MII_CTRL_IF_MASK 3
++#define AR71XX_MII_CTRL_SPEED_SHIFT 4
++#define AR71XX_MII_CTRL_SPEED_MASK 3
++#define AR71XX_MII_CTRL_SPEED_10 0
++#define AR71XX_MII_CTRL_SPEED_100 1
++#define AR71XX_MII_CTRL_SPEED_1000 2
++
++#define AR71XX_MII0_CTRL_IF_GMII 0
++#define AR71XX_MII0_CTRL_IF_MII 1
++#define AR71XX_MII0_CTRL_IF_RGMII 2
++#define AR71XX_MII0_CTRL_IF_RMII 3
++
++#define AR71XX_MII1_CTRL_IF_RGMII 0
++#define AR71XX_MII1_CTRL_IF_RMII 1
++
++/*
++ * AR933X GMAC interface
++ */
++#define AR933X_GMAC_REG_ETH_CFG 0x00
++
++#define AR933X_ETH_CFG_SW_PHY_SWAP BIT(7)
++#define AR933X_ETH_CFG_SW_PHY_ADDR_SWAP BIT(8)
++
++/*
++ * AR934X GMAC Interface
++ */
++#define AR934X_GMAC_REG_ETH_CFG 0x00
++
++#define AR934X_ETH_CFG_RGMII_GMAC0 BIT(0)
++#define AR934X_ETH_CFG_MII_GMAC0 BIT(1)
++#define AR934X_ETH_CFG_GMII_GMAC0 BIT(2)
++#define AR934X_ETH_CFG_SW_ONLY_MODE BIT(6)
++#define AR934X_ETH_CFG_SW_PHY_SWAP BIT(7)
++
+ #endif /* __ASM_MACH_AR71XX_REGS_H */
+--
+1.8.5.3
+
diff --git a/target/mips/dragino-ms14s/patches/3.14.17/0023-MIPS-ath79-add-Mikrotik-rb4xx-device-support.patch b/target/mips/dragino-ms14s/patches/3.14.17/0023-MIPS-ath79-add-Mikrotik-rb4xx-device-support.patch
new file mode 100644
index 000000000..67d390432
--- /dev/null
+++ b/target/mips/dragino-ms14s/patches/3.14.17/0023-MIPS-ath79-add-Mikrotik-rb4xx-device-support.patch
@@ -0,0 +1,536 @@
+From 7f5193750c4fb525ab7bd0610d05631b1dfbd8bb Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Wed, 14 May 2014 03:10:28 +0200
+Subject: [PATCH] MIPS: ath79: add Mikrotik rb4xx device support
+
+---
+ arch/mips/ath79/Kconfig | 8 +
+ arch/mips/ath79/Makefile | 1 +
+ arch/mips/ath79/mach-rb4xx.c | 465 +++++++++++++++++++++++++++++++++++++++++++
+ arch/mips/ath79/machtypes.h | 9 +
+ 4 files changed, 483 insertions(+)
+ create mode 100644 arch/mips/ath79/mach-rb4xx.c
+
+diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig
+index 52cefd7..7863079 100644
+--- a/arch/mips/ath79/Kconfig
++++ b/arch/mips/ath79/Kconfig
+@@ -61,6 +61,14 @@ config ATH79_MACH_PB44
+ Say 'Y' here if you want your kernel to support the
+ Atheros PB44 reference board.
+
++config ATH79_MACH_RB4XX
++ bool "MikroTik RouterBOARD 4xx series support"
++ select SOC_AR71XX
++ select ATH79_DEV_ETH
++ select ATH79_DEV_GPIO_BUTTONS
++ select ATH79_DEV_LEDS_GPIO
++ select ATH79_DEV_USB
++
+ config ATH79_MACH_UBNT_XM
+ bool "Ubiquiti Networks XM (rev 1.0) board"
+ select SOC_AR724X
+diff --git a/arch/mips/ath79/Makefile b/arch/mips/ath79/Makefile
+index 05485da..2b0e01b 100644
+--- a/arch/mips/ath79/Makefile
++++ b/arch/mips/ath79/Makefile
+@@ -32,4 +32,5 @@ obj-$(CONFIG_ATH79_MACH_AP136) += mach-ap136.o
+ obj-$(CONFIG_ATH79_MACH_AP81) += mach-ap81.o
+ obj-$(CONFIG_ATH79_MACH_DB120) += mach-db120.o
+ obj-$(CONFIG_ATH79_MACH_PB44) += mach-pb44.o
++obj-$(CONFIG_ATH79_MACH_RB4XX) += mach-rb4xx.o
+ obj-$(CONFIG_ATH79_MACH_UBNT_XM) += mach-ubnt-xm.o
+diff --git a/arch/mips/ath79/mach-rb4xx.c b/arch/mips/ath79/mach-rb4xx.c
+new file mode 100644
+index 0000000..1a61b45
+--- /dev/null
++++ b/arch/mips/ath79/mach-rb4xx.c
+@@ -0,0 +1,465 @@
++/*
++ * MikroTik RouterBOARD 4xx series support
++ *
++ * Copyright (C) 2008-2012 Gabor Juhos <juhosg@openwrt.org>
++ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation.
++ */
++
++#include <linux/platform_device.h>
++#include <linux/irq.h>
++#include <linux/mdio-gpio.h>
++#include <linux/mmc/host.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/flash.h>
++#include <linux/spi/mmc_spi.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/mach-ath79/ar71xx_regs.h>
++#include <asm/mach-ath79/ath79.h>
++#include <asm/mach-ath79/rb4xx_cpld.h>
++
++#include "common.h"
++#include "dev-eth.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "dev-usb.h"
++#include "machtypes.h"
++#include "pci.h"
++
++#define RB4XX_GPIO_USER_LED 4
++#define RB4XX_GPIO_RESET_SWITCH 7
++
++#define RB4XX_GPIO_CPLD_BASE 32
++#define RB4XX_GPIO_CPLD_LED1 (RB4XX_GPIO_CPLD_BASE + CPLD_GPIO_nLED1)
++#define RB4XX_GPIO_CPLD_LED2 (RB4XX_GPIO_CPLD_BASE + CPLD_GPIO_nLED2)
++#define RB4XX_GPIO_CPLD_LED3 (RB4XX_GPIO_CPLD_BASE + CPLD_GPIO_nLED3)
++#define RB4XX_GPIO_CPLD_LED4 (RB4XX_GPIO_CPLD_BASE + CPLD_GPIO_nLED4)
++#define RB4XX_GPIO_CPLD_LED5 (RB4XX_GPIO_CPLD_BASE + CPLD_GPIO_nLED5)
++
++#define RB4XX_KEYS_POLL_INTERVAL 20 /* msecs */
++#define RB4XX_KEYS_DEBOUNCE_INTERVAL (3 * RB4XX_KEYS_POLL_INTERVAL)
++
++static struct gpio_led rb4xx_leds_gpio[] __initdata = {
++ {
++ .name = "rb4xx:yellow:user",
++ .gpio = RB4XX_GPIO_USER_LED,
++ .active_low = 0,
++ }, {
++ .name = "rb4xx:green:led1",
++ .gpio = RB4XX_GPIO_CPLD_LED1,
++ .active_low = 1,
++ }, {
++ .name = "rb4xx:green:led2",
++ .gpio = RB4XX_GPIO_CPLD_LED2,
++ .active_low = 1,
++ }, {
++ .name = "rb4xx:green:led3",
++ .gpio = RB4XX_GPIO_CPLD_LED3,
++ .active_low = 1,
++ }, {
++ .name = "rb4xx:green:led4",
++ .gpio = RB4XX_GPIO_CPLD_LED4,
++ .active_low = 1,
++ }, {
++ .name = "rb4xx:green:led5",
++ .gpio = RB4XX_GPIO_CPLD_LED5,
++ .active_low = 0,
++ },
++};
++
++static struct gpio_keys_button rb4xx_gpio_keys[] __initdata = {
++ {
++ .desc = "reset_switch",
++ .type = EV_KEY,
++ .code = KEY_RESTART,
++ .debounce_interval = RB4XX_KEYS_DEBOUNCE_INTERVAL,
++ .gpio = RB4XX_GPIO_RESET_SWITCH,
++ .active_low = 1,
++ }
++};
++
++static struct platform_device rb4xx_nand_device = {
++ .name = "rb4xx-nand",
++ .id = -1,
++};
++
++static struct ath79_pci_irq rb4xx_pci_irqs[] __initdata = {
++ {
++ .slot = 17,
++ .pin = 1,
++ .irq = ATH79_PCI_IRQ(2),
++ }, {
++ .slot = 18,
++ .pin = 1,
++ .irq = ATH79_PCI_IRQ(0),
++ }, {
++ .slot = 18,
++ .pin = 2,
++ .irq = ATH79_PCI_IRQ(1),
++ }, {
++ .slot = 19,
++ .pin = 1,
++ .irq = ATH79_PCI_IRQ(1),
++ }, {
++ .slot = 19,
++ .pin = 2,
++ .irq = ATH79_PCI_IRQ(2),
++ }, {
++ .slot = 20,
++ .pin = 1,
++ .irq = ATH79_PCI_IRQ(2),
++ }, {
++ .slot = 20,
++ .pin = 2,
++ .irq = ATH79_PCI_IRQ(0),
++ }, {
++ .slot = 21,
++ .pin = 1,
++ .irq = ATH79_PCI_IRQ(0),
++ }, {
++ .slot = 22,
++ .pin = 1,
++ .irq = ATH79_PCI_IRQ(1),
++ }, {
++ .slot = 22,
++ .pin = 2,
++ .irq = ATH79_PCI_IRQ(2),
++ }, {
++ .slot = 23,
++ .pin = 1,
++ .irq = ATH79_PCI_IRQ(2),
++ }, {
++ .slot = 23,
++ .pin = 2,
++ .irq = ATH79_PCI_IRQ(0),
++ }
++};
++
++static struct mtd_partition rb4xx_partitions[] = {
++ {
++ .name = "routerboot",
++ .offset = 0,
++ .size = 0x0b000,
++ .mask_flags = MTD_WRITEABLE,
++ }, {
++ .name = "hard_config",
++ .offset = 0x0b000,
++ .size = 0x01000,
++ .mask_flags = MTD_WRITEABLE,
++ }, {
++ .name = "bios",
++ .offset = 0x0d000,
++ .size = 0x02000,
++ .mask_flags = MTD_WRITEABLE,
++ }, {
++ .name = "soft_config",
++ .offset = 0x0f000,
++ .size = 0x01000,
++ }
++};
++
++static struct flash_platform_data rb4xx_flash_data = {
++ .type = "pm25lv512",
++ .parts = rb4xx_partitions,
++ .nr_parts = ARRAY_SIZE(rb4xx_partitions),
++};
++
++static struct rb4xx_cpld_platform_data rb4xx_cpld_data = {
++ .gpio_base = RB4XX_GPIO_CPLD_BASE,
++};
++
++static struct mmc_spi_platform_data rb4xx_mmc_data = {
++ .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
++};
++
++static struct spi_board_info rb4xx_spi_info[] = {
++ {
++ .bus_num = 0,
++ .chip_select = 0,
++ .max_speed_hz = 25000000,
++ .modalias = "m25p80",
++ .platform_data = &rb4xx_flash_data,
++ }, {
++ .bus_num = 0,
++ .chip_select = 1,
++ .max_speed_hz = 25000000,
++ .modalias = "spi-rb4xx-cpld",
++ .platform_data = &rb4xx_cpld_data,
++ }
++};
++
++static struct spi_board_info rb4xx_microsd_info[] = {
++ {
++ .bus_num = 0,
++ .chip_select = 2,
++ .max_speed_hz = 25000000,
++ .modalias = "mmc_spi",
++ .platform_data = &rb4xx_mmc_data,
++ }
++};
++
++
++static struct resource rb4xx_spi_resources[] = {
++ {
++ .start = AR71XX_SPI_BASE,
++ .end = AR71XX_SPI_BASE + AR71XX_SPI_SIZE - 1,
++ .flags = IORESOURCE_MEM,
++ },
++};
++
++static struct platform_device rb4xx_spi_device = {
++ .name = "rb4xx-spi",
++ .id = -1,
++ .resource = rb4xx_spi_resources,
++ .num_resources = ARRAY_SIZE(rb4xx_spi_resources),
++};
++
++static void __init rb4xx_generic_setup(void)
++{
++ ath79_gpio_function_enable(AR71XX_GPIO_FUNC_SPI_CS1_EN |
++ AR71XX_GPIO_FUNC_SPI_CS2_EN);
++
++ ath79_register_leds_gpio(-1, ARRAY_SIZE(rb4xx_leds_gpio),
++ rb4xx_leds_gpio);
++
++ ath79_register_gpio_keys_polled(-1, RB4XX_KEYS_POLL_INTERVAL,
++ ARRAY_SIZE(rb4xx_gpio_keys),
++ rb4xx_gpio_keys);
++
++ spi_register_board_info(rb4xx_spi_info, ARRAY_SIZE(rb4xx_spi_info));
++ platform_device_register(&rb4xx_spi_device);
++ platform_device_register(&rb4xx_nand_device);
++}
++
++static void __init rb411_setup(void)
++{
++ rb4xx_generic_setup();
++ spi_register_board_info(rb4xx_microsd_info,
++ ARRAY_SIZE(rb4xx_microsd_info));
++
++ ath79_register_mdio(0, 0xfffffffc);
++
++ ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 0);
++ ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
++ ath79_eth0_data.phy_mask = 0x00000003;
++
++ ath79_register_eth(0);
++
++ ath79_pci_set_irq_map(ARRAY_SIZE(rb4xx_pci_irqs), rb4xx_pci_irqs);
++ ath79_register_pci();
++}
++
++MIPS_MACHINE(ATH79_MACH_RB_411, "411", "MikroTik RouterBOARD 411/A/AH",
++ rb411_setup);
++
++static void __init rb411u_setup(void)
++{
++ rb411_setup();
++ ath79_register_usb();
++}
++
++MIPS_MACHINE(ATH79_MACH_RB_411U, "411U", "MikroTik RouterBOARD 411U",
++ rb411u_setup);
++
++#define RB433_LAN_PHYMASK BIT(0)
++#define RB433_WAN_PHYMASK BIT(4)
++#define RB433_MDIO_PHYMASK (RB433_LAN_PHYMASK | RB433_WAN_PHYMASK)
++
++static void __init rb433_setup(void)
++{
++ rb4xx_generic_setup();
++ spi_register_board_info(rb4xx_microsd_info,
++ ARRAY_SIZE(rb4xx_microsd_info));
++
++ ath79_register_mdio(0, ~RB433_MDIO_PHYMASK);
++
++ ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 1);
++ ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
++ ath79_eth0_data.phy_mask = RB433_LAN_PHYMASK;
++
++ ath79_init_mac(ath79_eth1_data.mac_addr, ath79_mac_base, 0);
++ ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ath79_eth1_data.phy_mask = RB433_WAN_PHYMASK;
++
++ ath79_register_eth(1);
++ ath79_register_eth(0);
++
++ ath79_pci_set_irq_map(ARRAY_SIZE(rb4xx_pci_irqs), rb4xx_pci_irqs);
++ ath79_register_pci();
++}
++
++MIPS_MACHINE(ATH79_MACH_RB_433, "433", "MikroTik RouterBOARD 433/AH",
++ rb433_setup);
++
++static void __init rb433u_setup(void)
++{
++ rb433_setup();
++ ath79_register_usb();
++}
++
++MIPS_MACHINE(ATH79_MACH_RB_433U, "433U", "MikroTik RouterBOARD 433UAH",
++ rb433u_setup);
++
++static void __init rb435g_setup(void)
++{
++ rb4xx_generic_setup();
++
++ spi_register_board_info(rb4xx_microsd_info,
++ ARRAY_SIZE(rb4xx_microsd_info));
++
++ ath79_register_mdio(0, ~RB433_MDIO_PHYMASK);
++
++ ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 1);
++ ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++ ath79_eth0_data.phy_mask = RB433_LAN_PHYMASK;
++
++ ath79_init_mac(ath79_eth1_data.mac_addr, ath79_mac_base, 0);
++ ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++ ath79_eth1_data.phy_mask = RB433_WAN_PHYMASK;
++
++ ath79_register_eth(1);
++ ath79_register_eth(0);
++
++ ath79_pci_set_irq_map(ARRAY_SIZE(rb4xx_pci_irqs), rb4xx_pci_irqs);
++ ath79_register_pci();
++
++ ath79_register_usb();
++}
++
++MIPS_MACHINE(ATH79_MACH_RB_435G, "435G", "MikroTik RouterBOARD 435G",
++ rb435g_setup);
++
++#define RB450_LAN_PHYMASK BIT(0)
++#define RB450_WAN_PHYMASK BIT(4)
++#define RB450_MDIO_PHYMASK (RB450_LAN_PHYMASK | RB450_WAN_PHYMASK)
++
++static void __init rb450_generic_setup(int gige)
++{
++ rb4xx_generic_setup();
++ ath79_register_mdio(0, ~RB450_MDIO_PHYMASK);
++
++ ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 1);
++ ath79_eth0_data.phy_if_mode = (gige) ?
++ PHY_INTERFACE_MODE_RGMII : PHY_INTERFACE_MODE_MII;
++ ath79_eth0_data.phy_mask = RB450_LAN_PHYMASK;
++
++ ath79_init_mac(ath79_eth1_data.mac_addr, ath79_mac_base, 0);
++ ath79_eth1_data.phy_if_mode = (gige) ?
++ PHY_INTERFACE_MODE_RGMII : PHY_INTERFACE_MODE_RMII;
++ ath79_eth1_data.phy_mask = RB450_WAN_PHYMASK;
++
++ ath79_register_eth(1);
++ ath79_register_eth(0);
++}
++
++static void __init rb450_setup(void)
++{
++ rb450_generic_setup(0);
++}
++
++MIPS_MACHINE(ATH79_MACH_RB_450, "450", "MikroTik RouterBOARD 450",
++ rb450_setup);
++
++static void __init rb450g_setup(void)
++{
++ rb450_generic_setup(1);
++ spi_register_board_info(rb4xx_microsd_info,
++ ARRAY_SIZE(rb4xx_microsd_info));
++}
++
++MIPS_MACHINE(ATH79_MACH_RB_450G, "450G", "MikroTik RouterBOARD 450G",
++ rb450g_setup);
++
++static void __init rb493_setup(void)
++{
++ rb4xx_generic_setup();
++
++ ath79_register_mdio(0, 0x3fffff00);
++
++ ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 0);
++ ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
++ ath79_eth0_data.speed = SPEED_100;
++ ath79_eth0_data.duplex = DUPLEX_FULL;
++
++ ath79_init_mac(ath79_eth1_data.mac_addr, ath79_mac_base, 1);
++ ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RMII;
++ ath79_eth1_data.phy_mask = 0x00000001;
++
++ ath79_register_eth(0);
++ ath79_register_eth(1);
++
++ ath79_pci_set_irq_map(ARRAY_SIZE(rb4xx_pci_irqs), rb4xx_pci_irqs);
++ ath79_register_pci();
++}
++
++MIPS_MACHINE(ATH79_MACH_RB_493, "493", "MikroTik RouterBOARD 493/AH",
++ rb493_setup);
++
++#define RB493G_GPIO_MDIO_MDC 7
++#define RB493G_GPIO_MDIO_DATA 8
++
++#define RB493G_MDIO_PHYMASK BIT(0)
++
++static struct mdio_gpio_platform_data rb493g_mdio_data = {
++ .mdc = RB493G_GPIO_MDIO_MDC,
++ .mdio = RB493G_GPIO_MDIO_DATA,
++
++ .phy_mask = ~RB493G_MDIO_PHYMASK,
++};
++
++static struct platform_device rb493g_mdio_device = {
++ .name = "mdio-gpio",
++ .id = -1,
++ .dev = {
++ .platform_data = &rb493g_mdio_data,
++ },
++};
++
++static void __init rb493g_setup(void)
++{
++ ath79_gpio_function_enable(AR71XX_GPIO_FUNC_SPI_CS1_EN |
++ AR71XX_GPIO_FUNC_SPI_CS2_EN);
++
++ ath79_register_leds_gpio(-1, ARRAY_SIZE(rb4xx_leds_gpio),
++ rb4xx_leds_gpio);
++
++ spi_register_board_info(rb4xx_spi_info, ARRAY_SIZE(rb4xx_spi_info));
++ spi_register_board_info(rb4xx_microsd_info,
++ ARRAY_SIZE(rb4xx_microsd_info));
++
++ platform_device_register(&rb4xx_spi_device);
++ platform_device_register(&rb4xx_nand_device);
++
++ ath79_register_mdio(0, ~RB493G_MDIO_PHYMASK);
++
++ ath79_init_mac(ath79_eth0_data.mac_addr, ath79_mac_base, 0);
++ ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++ ath79_eth0_data.phy_mask = RB493G_MDIO_PHYMASK;
++ ath79_eth0_data.speed = SPEED_1000;
++ ath79_eth0_data.duplex = DUPLEX_FULL;
++
++ ath79_init_mac(ath79_eth1_data.mac_addr, ath79_mac_base, 1);
++ ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_RGMII;
++ ath79_eth1_data.mii_bus_dev = &rb493g_mdio_device.dev;
++ ath79_eth1_data.phy_mask = RB493G_MDIO_PHYMASK;
++ ath79_eth1_data.speed = SPEED_1000;
++ ath79_eth1_data.duplex = DUPLEX_FULL;
++
++ platform_device_register(&rb493g_mdio_device);
++
++ ath79_register_eth(1);
++ ath79_register_eth(0);
++
++ ath79_register_usb();
++
++ ath79_pci_set_irq_map(ARRAY_SIZE(rb4xx_pci_irqs), rb4xx_pci_irqs);
++ ath79_register_pci();
++}
++
++MIPS_MACHINE(ATH79_MACH_RB_493G, "493G", "MikroTik RouterBOARD 493G",
++ rb493g_setup);
+diff --git a/arch/mips/ath79/machtypes.h b/arch/mips/ath79/machtypes.h
+index 2625405..7630954 100644
+--- a/arch/mips/ath79/machtypes.h
++++ b/arch/mips/ath79/machtypes.h
+@@ -21,6 +21,15 @@ enum ath79_mach_type {
+ ATH79_MACH_AP81, /* Atheros AP81 reference board */
+ ATH79_MACH_DB120, /* Atheros DB120 reference board */
+ ATH79_MACH_PB44, /* Atheros PB44 reference board */
++ ATH79_MACH_RB_411, /* MikroTik RouterBOARD 411/411A/411AH */
++ ATH79_MACH_RB_411U, /* MikroTik RouterBOARD 411U */
++ ATH79_MACH_RB_433, /* MikroTik RouterBOARD 433/433AH */
++ ATH79_MACH_RB_433U, /* MikroTik RouterBOARD 433UAH */
++ ATH79_MACH_RB_435G, /* MikroTik RouterBOARD 435G */
++ ATH79_MACH_RB_450G, /* MikroTik RouterBOARD 450G */
++ ATH79_MACH_RB_450, /* MikroTik RouterBOARD 450 */
++ ATH79_MACH_RB_493, /* Mikrotik RouterBOARD 493/493AH */
++ ATH79_MACH_RB_493G, /* Mikrotik RouterBOARD 493G */
+ ATH79_MACH_UBNT_XM, /* Ubiquiti Networks XM board rev 1.0 */
+ };
+
+--
+1.8.5.3
+
diff --git a/target/mips/dragino-ms14s/patches/3.14.17/0024-various-fixups-for-Werror.patch b/target/mips/dragino-ms14s/patches/3.14.17/0024-various-fixups-for-Werror.patch
new file mode 100644
index 000000000..77883846d
--- /dev/null
+++ b/target/mips/dragino-ms14s/patches/3.14.17/0024-various-fixups-for-Werror.patch
@@ -0,0 +1,105 @@
+From 45bdbeaf12f96a95bda6016a2aa943ae2dfceb96 Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Fri, 16 May 2014 04:37:17 +0200
+Subject: [PATCH] various fixups for -Werror
+
+---
+ arch/mips/ath79/common.c | 4 ++--
+ arch/mips/ath79/dev-eth.c | 8 ++++----
+ drivers/net/phy/swconfig.c | 18 +-----------------
+ 3 files changed, 7 insertions(+), 23 deletions(-)
+
+diff --git a/arch/mips/ath79/common.c b/arch/mips/ath79/common.c
+index eb3966c..def54c2 100644
+--- a/arch/mips/ath79/common.c
++++ b/arch/mips/ath79/common.c
+@@ -59,7 +59,7 @@ EXPORT_SYMBOL_GPL(ath79_ddr_wb_flush);
+ void ath79_device_reset_set(u32 mask)
+ {
+ unsigned long flags;
+- u32 reg;
++ u32 reg = 0;
+ u32 t;
+
+ if (soc_is_ar71xx())
+@@ -87,7 +87,7 @@ EXPORT_SYMBOL_GPL(ath79_device_reset_set);
+ void ath79_device_reset_clear(u32 mask)
+ {
+ unsigned long flags;
+- u32 reg;
++ u32 reg = 0;
+ u32 t;
+
+ if (soc_is_ar71xx())
+diff --git a/arch/mips/ath79/dev-eth.c b/arch/mips/ath79/dev-eth.c
+index 21feeb9..879f1cd 100644
+--- a/arch/mips/ath79/dev-eth.c
++++ b/arch/mips/ath79/dev-eth.c
+@@ -121,7 +121,7 @@ static void __init ath79_mii_ctrl_set_if(unsigned int reg,
+ static void ath79_mii_ctrl_set_speed(unsigned int reg, unsigned int speed)
+ {
+ void __iomem *base;
+- unsigned int mii_speed;
++ unsigned int mii_speed = 0;
+ u32 t;
+
+ switch (speed) {
+@@ -271,8 +271,8 @@ struct ath79_eth_pll_data ath79_eth1_pll_data;
+
+ static u32 ath79_get_eth_pll(unsigned int mac, int speed)
+ {
+- struct ath79_eth_pll_data *pll_data;
+- u32 pll_val;
++ struct ath79_eth_pll_data *pll_data = NULL;
++ u32 pll_val = 0;
+
+ switch (mac) {
+ case 0:
+@@ -511,7 +511,7 @@ struct ag71xx_switch_platform_data ath79_switch_data;
+ static void __init ath79_init_eth_pll_data(unsigned int id)
+ {
+ struct ath79_eth_pll_data *pll_data;
+- u32 pll_10, pll_100, pll_1000;
++ u32 pll_10 = 0, pll_100 = 0, pll_1000 = 0;
+
+ switch (id) {
+ case 0:
+diff --git a/drivers/net/phy/swconfig.c b/drivers/net/phy/swconfig.c
+index c043ee4..c4d7689 100644
+--- a/drivers/net/phy/swconfig.c
++++ b/drivers/net/phy/swconfig.c
+@@ -1107,30 +1107,14 @@ EXPORT_SYMBOL_GPL(unregister_switch);
+ static int __init
+ swconfig_init(void)
+ {
+- int i, err;
++ int err;
+
+ INIT_LIST_HEAD(&swdevs);
+-
+-#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0))
+- err = genl_register_family(&switch_fam);
+- if (err)
+- return err;
+
+- for (i = 0; i < ARRAY_SIZE(swconfig_ops); i++) {
+- err = genl_register_ops(&switch_fam, &swconfig_ops[i]);
+- if (err)
+- goto unregister;
+- }
+-#else
+ err = genl_register_family_with_ops(&switch_fam, swconfig_ops);
+ if (err)
+ return err;
+-#endif
+ return 0;
+-
+-unregister:
+- genl_unregister_family(&switch_fam);
+- return err;
+ }
+
+ static void __exit
+--
+1.8.5.3
+
diff --git a/target/mips/dragino-ms14s/patches/3.14.17/0025-rb4xx_nand-add-partition-for-cfgfs.patch b/target/mips/dragino-ms14s/patches/3.14.17/0025-rb4xx_nand-add-partition-for-cfgfs.patch
new file mode 100644
index 000000000..7d9d85f62
--- /dev/null
+++ b/target/mips/dragino-ms14s/patches/3.14.17/0025-rb4xx_nand-add-partition-for-cfgfs.patch
@@ -0,0 +1,28 @@
+From 8cbc2ee92ec6dbed4a806cedffc6919b6b90275b Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Tue, 3 Jun 2014 00:32:22 +0200
+Subject: [PATCH] rb4xx_nand: add partition for cfgfs
+
+---
+ drivers/mtd/nand/rb4xx_nand.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/drivers/mtd/nand/rb4xx_nand.c b/drivers/mtd/nand/rb4xx_nand.c
+index 5b9841b..603d001 100644
+--- a/drivers/mtd/nand/rb4xx_nand.c
++++ b/drivers/mtd/nand/rb4xx_nand.c
+@@ -65,6 +65,11 @@ static struct mtd_partition rb4xx_nand_partitions[] = {
+ .size = (4 * 1024 * 1024) - (256 * 1024),
+ },
+ {
++ .name = "cfgfs",
++ .offset = MTDPART_OFS_NXTBLK,
++ .size = 0x400000,
++ },
++ {
+ .name = "rootfs",
+ .offset = MTDPART_OFS_NXTBLK,
+ .size = MTDPART_SIZ_FULL,
+--
+1.8.5.3
+
diff --git a/target/mips/dragino-ms14s/patches/3.14.17/0026-various-fixups-for-ath5k-fixing-system-freezes.patch b/target/mips/dragino-ms14s/patches/3.14.17/0026-various-fixups-for-ath5k-fixing-system-freezes.patch
new file mode 100644
index 000000000..4b17700d8
--- /dev/null
+++ b/target/mips/dragino-ms14s/patches/3.14.17/0026-various-fixups-for-ath5k-fixing-system-freezes.patch
@@ -0,0 +1,108 @@
+From 95945fe79069ee6b7ccce2b14fb9f8b93db33918 Mon Sep 17 00:00:00 2001
+From: Phil Sutter <phil@nwl.cc>
+Date: Sun, 15 Jun 2014 18:29:27 +0200
+Subject: [PATCH] various fixups for ath5k, fixing system freezes
+
+---
+ drivers/net/wireless/ath/ath5k/base.c | 3 +++
+ drivers/net/wireless/ath/ath5k/dma.c | 9 +++++++++
+ drivers/net/wireless/ath/ath5k/initvals.c | 6 ++++++
+ drivers/net/wireless/ath/ath5k/phy.c | 4 ++--
+ drivers/net/wireless/ath/ath5k/reset.c | 2 ++
+ 5 files changed, 22 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
+index ef35da8..4b18434 100644
+--- a/drivers/net/wireless/ath/ath5k/base.c
++++ b/drivers/net/wireless/ath/ath5k/base.c
+@@ -751,6 +751,9 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf,
+ bf->skbaddr = dma_map_single(ah->dev, skb->data, skb->len,
+ DMA_TO_DEVICE);
+
++ if (dma_mapping_error(ah->dev, bf->skbaddr))
++ return -ENOSPC;
++
+ ieee80211_get_tx_rates(info->control.vif, (control) ? control->sta : NULL, skb, bf->rates,
+ ARRAY_SIZE(bf->rates));
+
+diff --git a/drivers/net/wireless/ath/ath5k/dma.c b/drivers/net/wireless/ath/ath5k/dma.c
+index e6c52f7..72bf600 100644
+--- a/drivers/net/wireless/ath/ath5k/dma.c
++++ b/drivers/net/wireless/ath/ath5k/dma.c
+@@ -869,10 +869,19 @@ ath5k_hw_dma_init(struct ath5k_hw *ah)
+ * guess we can tweak it and see how it goes ;-)
+ */
+ if (ah->ah_version != AR5K_AR5210) {
++#if !defined(CONFIG_ATHEROS_AR71XX) && !defined(CONFIG_ATH79)
+ AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
+ AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B);
+ AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG,
+ AR5K_RXCFG_SDMAMW, AR5K_DMASIZE_128B);
++#else
++ /* WAR for AR71xx PCI bug */
++ AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
++ AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B);
++ AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG,
++ AR5K_RXCFG_SDMAMW, AR5K_DMASIZE_4B);
++#endif
++
+ }
+
+ /* Pre-enable interrupts on 5211/5212*/
+diff --git a/drivers/net/wireless/ath/ath5k/initvals.c b/drivers/net/wireless/ath/ath5k/initvals.c
+index ee1c2fa..ba84ab5 100644
+--- a/drivers/net/wireless/ath/ath5k/initvals.c
++++ b/drivers/net/wireless/ath/ath5k/initvals.c
+@@ -62,8 +62,14 @@ static const struct ath5k_ini ar5210_ini[] = {
+ { AR5K_IMR, 0 },
+ { AR5K_IER, AR5K_IER_DISABLE },
+ { AR5K_BSR, 0, AR5K_INI_READ },
++#if !defined(CONFIG_ATHEROS_AR71XX) && !defined(CONFIG_ATH79)
+ { AR5K_TXCFG, AR5K_DMASIZE_128B },
+ { AR5K_RXCFG, AR5K_DMASIZE_128B },
++#else
++ /* WAR for AR71xx PCI bug */
++ { AR5K_TXCFG, AR5K_DMASIZE_128B },
++ { AR5K_RXCFG, AR5K_DMASIZE_4B },
++#endif
+ { AR5K_CFG, AR5K_INIT_CFG },
+ { AR5K_TOPS, 8 },
+ { AR5K_RXNOFRM, 8 },
+diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
+index 1a2973b..0fce1c7 100644
+--- a/drivers/net/wireless/ath/ath5k/phy.c
++++ b/drivers/net/wireless/ath/ath5k/phy.c
+@@ -3709,8 +3709,8 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
+ AR5K_REG_MS(AR5K_TUNE_MAX_TXPOWER, AR5K_TPC_CHIRP),
+ AR5K_TPC);
+ } else {
+- ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX |
+- AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX);
++ ath5k_hw_reg_write(ah, AR5K_TUNE_MAX_TXPOWER,
++ AR5K_PHY_TXPOWER_RATE_MAX);
+ }
+
+ return 0;
+diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
+index a3399c4..66d0ecc 100644
+--- a/drivers/net/wireless/ath/ath5k/reset.c
++++ b/drivers/net/wireless/ath/ath5k/reset.c
+@@ -1154,6 +1154,7 @@ ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
+ tsf_lo = 0;
+ mode = 0;
+
++#if 0
+ /*
+ * Sanity check for fast flag
+ * Fast channel change only available
+@@ -1161,6 +1162,7 @@ ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
+ */
+ if (fast && (ah->ah_radio != AR5K_RF2413) &&
+ (ah->ah_radio != AR5K_RF5413))
++#endif
+ fast = false;
+
+ /* Disable sleep clock operation
+--
+1.8.5.3
+
diff --git a/target/mips/kernel/dragino-ms14s b/target/mips/kernel/dragino-ms14s
new file mode 100644
index 000000000..cce44918e
--- /dev/null
+++ b/target/mips/kernel/dragino-ms14s
@@ -0,0 +1,12 @@
+CONFIG_MIPS=y
+CONFIG_ATH79=y
+CONFIG_ATH79_MACH_Linino=y
+CONFIG_NET_VENDOR_ATHEROS=y
+CONFIG_AG71XX=y
+CONFIG_AG71XX_AR8216_SUPPORT=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=1
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
diff --git a/target/mips/systems/dragino-ms14s b/target/mips/systems/dragino-ms14s
new file mode 100644
index 000000000..6b1dd0368
--- /dev/null
+++ b/target/mips/systems/dragino-ms14s
@@ -0,0 +1,11 @@
+config ADK_TARGET_SYSTEM_DRAGINO_MS14S
+ bool "Dragino2 ms14-s"
+ select ADK_mips
+ select ADK_big
+ select ADK_dragino_ms14s
+ select ADK_CPU_MIPS32
+ select ADK_TARGET_WITH_WATCHDOG
+ select ADK_TARGET_WITH_NAND
+ help
+ Support for Dragino2 ms14-s.
+
diff --git a/target/mips64/lemote-yeelong/patches/3.16.6/sm7xx-fb.patch b/target/mips64/lemote-yeelong/patches/3.17.4/sm7xx-fb.patch
index 413840abd..413840abd 100644
--- a/target/mips64/lemote-yeelong/patches/3.16.6/sm7xx-fb.patch
+++ b/target/mips64/lemote-yeelong/patches/3.17.4/sm7xx-fb.patch
diff --git a/toolchain/gcc/Makefile.inc b/toolchain/gcc/Makefile.inc
index 2a616adbd..e522805f2 100644
--- a/toolchain/gcc/Makefile.inc
+++ b/toolchain/gcc/Makefile.inc
@@ -2,9 +2,9 @@
# material, please see the LICENCE file in the top-level directory.
PKG_NAME:= gcc
-ifeq ($(ADK_TOOLCHAIN_GCC_4_9_1),y)
-PKG_VERSION:= 4.9.1
-PKG_MD5SUM:= b188a3c9be25ddbf36b4fa6f04aaafaa
+ifeq ($(ADK_TOOLCHAIN_GCC_4_9_2),y)
+PKG_VERSION:= 4.9.2
+PKG_MD5SUM:= 76f464e0511c26c93425a9dcdc9134cf
PKG_SITES:= ${MASTER_SITE_GNU:=gcc/gcc-${PKG_VERSION}/}
PKG_RELEASE:= 1
DISTFILES:= ${PKG_NAME}-${PKG_VERSION}.tar.gz
diff --git a/toolchain/gcc/patches/4.9.1/cflags.patch b/toolchain/gcc/patches/4.9.2/cflags.patch
index d4119cd39..d4119cd39 100644
--- a/toolchain/gcc/patches/4.9.1/cflags.patch
+++ b/toolchain/gcc/patches/4.9.2/cflags.patch