diff --git a/kernel/drivers/module-bbswitch/pspec.xml b/kernel/drivers/module-bbswitch/pspec.xml index 922cfc8d..d6bf5948 100644 --- a/kernel/drivers/module-bbswitch/pspec.xml +++ b/kernel/drivers/module-bbswitch/pspec.xml @@ -11,7 +11,7 @@ Kernel module allowing to switch dedicated graphics card on Optimus laptops kernel module allowing to switch dedicated graphics card on Optimus laptops - kernel-module-headers + kernel-module-headers https://github.com/Bumblebee-Project/bbswitch/archive/v0.8.tar.gz @@ -20,7 +20,7 @@ module-bbswitch - kernel + kernel /lib/modules @@ -34,6 +34,13 @@ + + 2015-09-23 + 0.8 + Rebuild for kernel-4.1.8. + Ertuğrul Erata + ertugrulerata@gmail.com + 2015-09-18 0.8 diff --git a/kernel/drivers/module-broadcom-wl/pspec.xml b/kernel/drivers/module-broadcom-wl/pspec.xml index 06dc2432..85888a5a 100644 --- a/kernel/drivers/module-broadcom-wl/pspec.xml +++ b/kernel/drivers/module-broadcom-wl/pspec.xml @@ -15,7 +15,7 @@ http://www.broadcom.com/docs/linux_sta/hybrid-v35-nodebug-pcoem-6_30_223_248.tar.gz http://www.broadcom.com/docs/linux_sta/hybrid-v35_64-nodebug-pcoem-6_30_223_248.tar.gz - kernel-module-headers + kernel-module-headers patch/linux-40.patch @@ -30,7 +30,7 @@ module-broadcom-wl - kernel + kernel module-broadcom-wl-userspace @@ -62,6 +62,13 @@ + + 2015-09-23 + 6.30.223.248 + Rebuild for kernel 4.1.8. + Ertuğrul Erata + ertugrulerata@gmail.com + 2015-09-18 6.30.223.248 diff --git a/kernel/drivers/module-virtualbox-guest/pspec.xml b/kernel/drivers/module-virtualbox-guest/pspec.xml index 734a0576..21fb6d31 100644 --- a/kernel/drivers/module-virtualbox-guest/pspec.xml +++ b/kernel/drivers/module-virtualbox-guest/pspec.xml @@ -14,14 +14,14 @@ This package provides the kernel modules needed for mouse integration and shared folder support between VirtualBox host and guest systems. http://source.pisilinux.org/1.0/module-virtualbox-guest-4.3.28.tar.xz - kernel-module-headers + kernel-module-headers module-virtualbox-guest - kernel + kernel baselayout module-virtualbox-guest-userspace @@ -52,7 +52,14 @@ - + + 2015-08-23 + 4.3.28 + Rebuild for kernel-4.1.8. + Ertuğrul Erata + ertugrulerata@gmail.com + + 2015-08-18 4.3.28 Rebuild for kernel-4.1.7. diff --git a/kernel/drivers/module-virtualbox/pspec.xml b/kernel/drivers/module-virtualbox/pspec.xml index 5b0de905..bf9bdafe 100644 --- a/kernel/drivers/module-virtualbox/pspec.xml +++ b/kernel/drivers/module-virtualbox/pspec.xml @@ -14,14 +14,14 @@ This package provides the kernel support for VirtualBox. http://source.pisilinux.org/1.0/module-virtualbox-4.3.28.tar.xz - kernel-module-headers + kernel-module-headers module-virtualbox - kernel + kernel module-virtualbox-userspace @@ -47,6 +47,13 @@ + + 2015-09-23 + 4.3.28 + Rebuild for kernel-4.1.8. + Ertuğrul Erata + ertugrulerata@gmail.com + 2015-09-18 4.3.28 diff --git a/kernel/drivers/ndiswrapper/pspec.xml b/kernel/drivers/ndiswrapper/pspec.xml index 52c2a0ee..ce9dd73c 100644 --- a/kernel/drivers/ndiswrapper/pspec.xml +++ b/kernel/drivers/ndiswrapper/pspec.xml @@ -15,7 +15,7 @@ module-ndiswrapper allows you to use Windows XP drivers for WLAN cards without proper Linux drivers. http://download.sourceforge.net/ndiswrapper/ndiswrapper-1.59.tar.gz - kernel-module-headers + kernel-module-headers support_kernel-4.0.patch @@ -28,7 +28,7 @@ ndiswrapper - kernel + kernel /lib/modules @@ -44,7 +44,14 @@ - + + 2014-09-23 + 1.59 + Rebuild for kernel-4.1.8. + PisiLinux Community + admins@pisilinux.org + + 2014-08-18 1.59 Rebuild for kernel-4.1.6. diff --git a/kernel/kernel/files/configs/kernel-x86_64-config b/kernel/kernel/files/configs/kernel-x86_64-config index 39d4fc93..e5d999ba 100644 --- a/kernel/kernel/files/configs/kernel-x86_64-config +++ b/kernel/kernel/files/configs/kernel-x86_64-config @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/x86_64 4.1.7 Kernel Configuration +# Linux/x86_64 4.1.8 Kernel Configuration # CONFIG_64BIT=y CONFIG_X86_64=y diff --git a/kernel/kernel/files/patches/linux/patch-4.1.8.xz b/kernel/kernel/files/patches/linux/patch-4.1.8.xz new file mode 100644 index 00000000..c2d46113 Binary files /dev/null and b/kernel/kernel/files/patches/linux/patch-4.1.8.xz differ diff --git a/kernel/kernel/files/patches/mageia.old/3rd-3rdparty-1.0-tree.patch b/kernel/kernel/files/patches/mageia.old/3rd-3rdparty-1.0-tree.patch new file mode 100644 index 00000000..233389b4 --- /dev/null +++ b/kernel/kernel/files/patches/mageia.old/3rd-3rdparty-1.0-tree.patch @@ -0,0 +1,181 @@ + + 3rdparty/mkbuild.pl | 92 +++++++++++++++++++++++++++++++++++++++++++++ + Documentation/3rdparty.txt | 76 +++++++++++++++++++++++++++++++++++++ + 2 files changed, 168 insertions(+) + +diff -Nurp linux-2.6.37/3rdparty/mkbuild.pl linux-2.6.37.3rdparty/3rdparty/mkbuild.pl +--- linux-2.6.37/3rdparty/mkbuild.pl 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/mkbuild.pl 2004-04-23 14:59:03.000000000 +0300 +@@ -0,0 +1,92 @@ ++#!/usr/bin/perl -w ++# ++# Version 1.0 ++# ++# Copyright 2001 Jeff Garzik ++# Copyright 2002 Juan Quintela ++# Copyright 2003 Nicolas Planel ++# ++# This software may be used and distributed according to the terms ++# of the GNU General Public License, incorporated herein by reference. ++# ++# ++# Run "mkbuild.pl" ++# ++# This program generates the following files ++# Makefile ++# Makefile.drivers ++# Config.in ++# using the information in the subdirs of this directory. ++# ++# subdirs need to have: ++# a Config.in file ++# a Makefile with a O_TARGET/L_TARGET targets ++# The config.in should set a CONFIG_ to m/y. ++ ++use strict; ++ ++opendir(THISDIR, "."); ++# get dirs without . and .. garbage ++my (@modules) = grep(!/\.\.?$/,grep(-d, readdir(THISDIR))); ++closedir(THISDIR); ++ ++generate_kconfig(@modules); ++generate_makefile(@modules); ++exit(0); ++ ++########################################################################## ++ ++sub generate_makefile { ++ my (@modules) = @_; ++ ++ local *F; ++ open F, "> Makefile" or die "Cannot create new Makefile: $!\n"; ++ print F <<'EOM'; ++# ++# THIS IS AN AUTOMATICALLY GENERATED FILE. DO NOT EDIT. ++# ++ ++EOM ++ printf F "obj- := 3rdparty.o # Dummy rule to force built-in.o to be made\n"; ++ printf F "obj-\$(%s) += %s\n", to_CONFIG($_), $_ . '/' foreach @modules; ++} ++ ++sub generate_kconfig { ++ my (@modules) = @_; ++ ++ local *F; ++ open F, "> Kconfig" or die "Cannot create Kconfig: $!\n"; ++ print F <<"EOM"; ++# ++# THIS IS AN AUTOMATICALLY GENERATED FILE. DO NOT EDIT. ++# ++ ++menu "Unofficial 3rd party kernel additions" ++ ++EOM ++ ++ foreach (@modules) { ++ die "No Kconfig in $_.\n" if ! -r "$_/Kconfig"; ++ print F "source 3rdparty/$_/Kconfig\n"; ++ } ++ print F "\n\nendmenu\n"; ++} ++ ++sub to_CONFIG { ++ local $_ = $_[0]; ++ tr/a-z/A-Z/; ++ s/[\-\. ]/_/g; ++ "CONFIG_$_"; ++} ++ ++sub find_target { ++ my ($module_dir) = @_; ++ ++ local *F; ++ open(F, "$module_dir/Makefile") or die "$module_dir/Makefile: $!\n"; ++ while () { ++ chomp; ++ return $1 if (/[LO]_TARGET.*:=\s+(\S+)/); ++ } ++} ++ +diff -Nurp linux-2.6.37/Documentation/3rdparty.txt linux-2.6.37.3rdparty/Documentation/3rdparty.txt +--- linux-2.6.37/Documentation/3rdparty.txt 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/Documentation/3rdparty.txt 2003-11-22 01:07:26.000000000 +0200 +@@ -0,0 +1,76 @@ ++ ++Third-Party Kernel Source Module Support, or ++an easy way to add modules to your kernel build. ++ ++ ++ ++Vendors quite often add additional drivers and features to the kernel ++which require nothing more than modifying Kconfig, Makefile, and ++adding one or more files to a sub-directory. As a single discrete task, ++this is not a problem. However, using patches to add modules to the ++kernel very often results in patch conflicts, resulting in needless time ++wastage as developers regenerate an otherwise working kernel patch. ++ ++This is designed as a solution to these problems. It is NOT designed as ++a replacement for the kernel build system, but merely as a tool for ++vendors and system administrators to ease the pain of patch management. ++ ++The key feature of this system is the distinct lack of patches. Drivers ++are installed via unpacking a tarball. ++ ++ ++ ++Adding a directory to the build (usually from a tarball) ++-------------------------------------------------------- ++If a directory exists inside the 3rdparty sub-directory that contains a ++proper Makefile, it can be added to the build. It also needs a ++Kconfig file. ++ ++ cd /usr/src/linux-2.4.3/3rdparty ++ bzcat /tmp/my-driver2.tar.bz2 | tar xf - # creates "my2" dir ++ ++ ++Limitations ++----------- ++There are some limitations to this system. This system is only ++designed to support a very common case. If you find yourself running ++into limitations (kernel build experts can spot them right off), ++then you should probably be patching the kernel instead of using ++mkbuild.pl for that particular module. ++ ++FIXME: actually list the limitations ++ ++ ++ ++Other notes ++----------- ++Link order is controlled by the order of mkbuild.pl executions. ++ ++"make mrproper" will erase Makefile.meta, and empty Kconfig, Makefile, ++and Makefile.drivers. ++ ++IMPORTANT NOTE: Because this feature modifies the kernel's makefiles and ++configuration system, you MUST complete all mkbuild.pl runs before ++running any "make" command. ++ ++Building in the 3rdparty dir ++---------------------------- ++ ++If you use modules that: ++ - are contained in one subdir with the name of the module ++ - has a Makefile ++ - has a Kconfig file ++ ++The system calls the ./mkbuild.pl script. It will search for ++subdirectories, and will try to build each of them as a module. ++Things to note: ++ ++ The dependencies will be done in a module called: ++ ++ 3rdparty// ++ ++depending of CONFIG_. ++ ++ is the value of O_TARGET/L_TARGET. ++ ++ diff --git a/kernel/kernel/files/patches/mageia.old/3rd-3rdparty-merge.patch b/kernel/kernel/files/patches/mageia.old/3rd-3rdparty-merge.patch new file mode 100644 index 00000000..8c1f8421 --- /dev/null +++ b/kernel/kernel/files/patches/mageia.old/3rd-3rdparty-merge.patch @@ -0,0 +1,181 @@ + +Include 3rdparty directory into the main build-system. + +Original author is unknown. +(Was either Juan Quintela or Jeff Garzik) + +Signed-off-by: Luiz Fernando N. Capitulino +Signed-off-by: Herton Ronaldo Krzesinski +Signed-off-by: Thomas Backlund + + Makefile | 2 +- + arch/alpha/Kconfig | 1 + + arch/ia64/Kconfig | 2 ++ + arch/mips/Kconfig | 2 ++ + arch/powerpc/Kconfig | 2 ++ + arch/sparc/Kconfig | 2 ++ + arch/x86/Kconfig | 2 ++ + scripts/kconfig/Makefile | 31 +++++++++++++++++-------------- + 8 files changed, 29 insertions(+), 15 deletions(-) + +diff -Nurp linux-4.1/arch/alpha/Kconfig linux-4.1-3rd/arch/alpha/Kconfig +--- linux-4.1/arch/alpha/Kconfig 2015-06-22 07:05:43.000000000 +0200 ++++ linux-4.1-3rd/arch/alpha/Kconfig 2015-06-25 20:44:03.221647317 +0200 +@@ -750,3 +750,4 @@ source "crypto/Kconfig" + + source "lib/Kconfig" + ++source "3rdparty/Kconfig" +diff -Nurp linux-4.1/arch/ia64/Kconfig linux-4.1-3rd/arch/ia64/Kconfig +--- linux-4.1/arch/ia64/Kconfig 2015-06-22 07:05:43.000000000 +0200 ++++ linux-4.1-3rd/arch/ia64/Kconfig 2015-06-25 20:44:03.231647227 +0200 +@@ -636,3 +636,5 @@ source "lib/Kconfig" + + config IOMMU_HELPER + def_bool (IA64_HP_ZX1 || IA64_HP_ZX1_SWIOTLB || IA64_GENERIC || SWIOTLB) ++ ++source "3rdparty/Kconfig" +diff -Nurp linux-4.1/arch/mips/Kconfig linux-4.1-3rd/arch/mips/Kconfig +--- linux-4.1/arch/mips/Kconfig 2015-06-22 07:05:43.000000000 +0200 ++++ linux-4.1-3rd/arch/mips/Kconfig 2015-06-25 20:44:03.231647227 +0200 +@@ -2893,3 +2893,5 @@ source "crypto/Kconfig" + source "lib/Kconfig" + + source "arch/mips/kvm/Kconfig" ++ ++source "3rdparty/Kconfig" +diff -Nurp linux-4.1/arch/powerpc/Kconfig linux-4.1-3rd/arch/powerpc/Kconfig +--- linux-4.1/arch/powerpc/Kconfig 2015-06-22 07:05:43.000000000 +0200 ++++ linux-4.1-3rd/arch/powerpc/Kconfig 2015-06-25 20:44:03.231647227 +0200 +@@ -1090,3 +1090,5 @@ config PPC_LIB_RHEAP + bool + + source "arch/powerpc/kvm/Kconfig" ++ ++source "3rdparty/Kconfig" +diff -Nurp linux-4.1/arch/sparc/Kconfig linux-4.1-3rd/arch/sparc/Kconfig +--- linux-4.1/arch/sparc/Kconfig 2015-06-22 07:05:43.000000000 +0200 ++++ linux-4.1-3rd/arch/sparc/Kconfig 2015-06-25 20:44:03.231647227 +0200 +@@ -569,3 +569,5 @@ source "security/Kconfig" + source "crypto/Kconfig" + + source "lib/Kconfig" ++ ++source "3rdparty/Kconfig" +diff -Nurp linux-4.1/arch/x86/Kconfig linux-4.1-3rd/arch/x86/Kconfig +--- linux-4.1/arch/x86/Kconfig 2015-06-22 07:05:43.000000000 +0200 ++++ linux-4.1-3rd/arch/x86/Kconfig 2015-06-25 20:44:03.231647227 +0200 +@@ -2594,3 +2594,5 @@ source "crypto/Kconfig" + source "arch/x86/kvm/Kconfig" + + source "lib/Kconfig" ++ ++source "3rdparty/Kconfig" +diff -Nurp linux-4.1/Makefile linux-4.1-3rd/Makefile +--- linux-4.1/Makefile 2015-06-22 07:05:43.000000000 +0200 ++++ linux-4.1-3rd/Makefile 2015-06-25 20:44:03.231647227 +0200 +@@ -556,7 +556,7 @@ scripts: scripts_basic include/config/au + + # Objects we will link into vmlinux / subdirs we need to visit + init-y := init/ +-drivers-y := drivers/ sound/ firmware/ ++drivers-y := drivers/ sound/ firmware/ 3rdparty/ + net-y := net/ + libs-y := lib/ + core-y := usr/ +diff -Nurp linux-4.1/scripts/kconfig/Makefile linux-4.1-3rd/scripts/kconfig/Makefile +--- linux-4.1/scripts/kconfig/Makefile 2015-06-22 07:05:43.000000000 +0200 ++++ linux-4.1-3rd/scripts/kconfig/Makefile 2015-06-25 20:47:50.109596717 +0200 +@@ -18,26 +18,26 @@ endif + # We need this, in case the user has it in its environment + unexport CONFIG_ + +-xconfig: $(obj)/qconf ++xconfig: $(obj)/qconf 3rdparty/Makefile + $< $(silent) $(Kconfig) + +-gconfig: $(obj)/gconf ++gconfig: $(obj)/gconf 3rdparty/Makefile + $< $(silent) $(Kconfig) + +-menuconfig: $(obj)/mconf ++menuconfig: $(obj)/mconf 3rdparty/Makefile + $< $(silent) $(Kconfig) + +-config: $(obj)/conf ++config: $(obj)/conf 3rdparty/Makefile + $< $(silent) --oldaskconfig $(Kconfig) + +-nconfig: $(obj)/nconf ++nconfig: $(obj)/nconf 3rdparty/Makefile + $< $(silent) $(Kconfig) + +-silentoldconfig: $(obj)/conf ++silentoldconfig: $(obj)/conf 3rdparty/Makefile + $(Q)mkdir -p include/config include/generated + $< $(silent) --$@ $(Kconfig) + +-localyesconfig localmodconfig: $(obj)/streamline_config.pl $(obj)/conf ++localyesconfig localmodconfig: $(obj)/streamline_config.pl $(obj)/conf 3rdparty/Makefile + $(Q)mkdir -p include/config include/generated + $(Q)perl $< --$@ $(srctree) $(Kconfig) > .tmp.config + $(Q)if [ -f .config ]; then \ +@@ -80,7 +80,7 @@ simple-targets := oldconfig allnoconfig + alldefconfig randconfig listnewconfig olddefconfig + PHONY += $(simple-targets) + +-$(simple-targets): $(obj)/conf ++$(simple-targets): $(obj)/conf 3rdparty/Makefile + $< $(silent) --$@ $(Kconfig) + + PHONY += oldnoconfig savedefconfig defconfig +@@ -88,12 +88,12 @@ PHONY += oldnoconfig savedefconfig defco + # oldnoconfig is an alias of olddefconfig, because people already are dependent + # on its behavior(sets new symbols to their default value but not 'n') with the + # counter-intuitive name. +-oldnoconfig: olddefconfig ++oldnoconfig: olddefconfig 3rdparty/Makefile + +-savedefconfig: $(obj)/conf ++savedefconfig: $(obj)/conf 3rdparty/Makefile + $< $(silent) --$@=defconfig $(Kconfig) + +-defconfig: $(obj)/conf ++defconfig: $(obj)/conf 3rdparty/Makefile + ifeq ($(KBUILD_DEFCONFIG),) + $< $(silent) --defconfig $(Kconfig) + else +@@ -101,7 +101,7 @@ else + $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG) $(Kconfig) + endif + +-%_defconfig: $(obj)/conf ++%_defconfig: $(obj)/conf 3rdparty/Makefile + $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig) + + configfiles=$(wildcard $(srctree)/kernel/configs/$@ $(srctree)/arch/$(SRCARCH)/configs/$@) +@@ -112,12 +112,12 @@ configfiles=$(wildcard $(srctree)/kernel + +$(Q)yes "" | $(MAKE) -f $(srctree)/Makefile oldconfig + + PHONY += kvmconfig +-kvmconfig: kvm_guest.config ++kvmconfig: kvm_guest.config 3rdparty/Makefile + @: + + PHONY += tinyconfig + tinyconfig: +- $(Q)$(MAKE) -f $(srctree)/Makefile allnoconfig tiny.config ++ $(Q)$(MAKE) -f $(srctree)/Makefile allnoconfig tiny.config 3rdparty/Makefile + + # Help text used by make help + help: +@@ -176,6 +176,9 @@ gconf-objs := gconf.o zconf.tab.o + + hostprogs-y := conf nconf mconf kxgettext qconf gconf + ++3rdparty/Makefile: ++ pushd $(srctree)/3rdparty ; $(PERL) ./mkbuild.pl ; popd ++ + clean-files := qconf.moc .tmp_qtcheck .tmp_gtkcheck + clean-files += zconf.tab.c zconf.lex.c zconf.hash.c gconf.glade.h + clean-files += config.pot linux.pot diff --git a/kernel/kernel/files/patches/mageia.old/3rd-acerhk-0.5.35.patch b/kernel/kernel/files/patches/mageia.old/3rd-acerhk-0.5.35.patch new file mode 100644 index 00000000..5d61570f --- /dev/null +++ b/kernel/kernel/files/patches/mageia.old/3rd-acerhk-0.5.35.patch @@ -0,0 +1,4212 @@ + 3rdparty/acerhk/AUTHORS | 1 + 3rdparty/acerhk/COPYING | 340 ++++ + 3rdparty/acerhk/INSTALL | 109 + + 3rdparty/acerhk/Makefile | 65 + 3rdparty/acerhk/NEWS | 16 + 3rdparty/acerhk/README | 215 ++ + 3rdparty/acerhk/acerhk.c | 2999 ++++++++++++++++++++++++++++++++++++++++ + 3rdparty/acerhk/acerhk.h | 91 + + 3rdparty/acerhk/doc/FAQ | 150 ++ + 3rdparty/acerhk/doc/IOCTL | 61 + 3rdparty/acerhk/doc/acertm.def | 56 + 3rdparty/acerhk/doc/keycodes | 26 + 3rdparty/acerhk/doc/md95400.def | 14 + 13 files changed, 4143 insertions(+) +diff -Nurp linux-2.6.37/3rdparty/acerhk/acerhk.c linux-2.6.37.3rdparty/3rdparty/acerhk/acerhk.c +--- linux-2.6.37/3rdparty/acerhk/acerhk.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/acerhk/acerhk.c 2007-02-10 17:46:23.000000000 +0200 +@@ -0,0 +1,2999 @@ ++/********************************************************************* ++ * Filename: acerhk.c ++ * Version: 0.5 ++ * ++ * Copyright (C) 2002-2006, Olaf Tauber (olaf-tauber@versanet.de) ++ * ++ * Description: kernel driver for Acer Travelmate and similar ++ * laptops special keys ++ * Author: Olaf Tauber ++ * Created at: Mon Apr 29 22:16:42 2002 ++ * Modified at: Mon Oct 16 21:36:44 2006 ++ * Modified by: Olaf Tauber ++ * Modified at: Thu Nov 24 13:03:01 2005 ++ * Modified by: Antonio Cuni ++ * Modified at: Wed Oct 27 19:47:11 CEST 2004 ++ * Modified by: Joachim Fenkes ++ * ++ * 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. ++ * ++ * 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 ++ * ++ * ++ */ ++ ++#ifndef AUTOCONF_INCLUDED ++#include ++#endif ++ ++/* This driver is heavily dependent on the architecture, don't let ++ * anyone without an X86 machine use it. On laptops with AMD64 ++ * architecture this driver is only useable in 32 bit mode. ++ */ ++#ifdef CONFIG_X86 ++ ++#include ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) ++#define KERNEL26 ++#include ++#else ++#include ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) ++#define STATIC_INPUT_DEV ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "acerhk.h" ++ ++/* #define ACERDEBUG */ ++/* #define DUMMYHW */ ++ ++#define ACERHK_VERSION "0.5.35" ++#define MODULE_NAME "acerhk" ++ ++/* maximum number of polling loops, adjust it if needed to values between ++ * 1 and 32 ++ */ ++#define MAX_POLLING_LOOPS 16U ++ ++/* maximum length for model string */ ++#define ACERHK_MODEL_STRLEN 16 ++/* size of mapped areas */ ++#define AREA_SIZE 0xffff ++/* needed for colussi algorithm */ ++#define XSIZE 20 ++ ++/* Module parameters */ ++static int poll=1; ++static int autowlan; ++static int usedritek=1; ++static int wlan_state=-1; ++static int bluetooth_state=-1; ++static int verbose; ++static unsigned int force_series; ++#ifdef KERNEL26 ++module_param(poll, int, 0444); ++module_param(autowlan, int, 0444); ++module_param(usedritek, int, 0444); ++module_param(verbose, int, 0444); ++module_param(wlan_state, int, 0444); ++module_param(bluetooth_state, int, 0444); ++module_param(force_series, uint, 0444); ++#else ++MODULE_PARM(poll, "i"); ++MODULE_PARM(autowlan, "i"); ++MODULE_PARM(wlan_state, "i"); ++MODULE_PARM(bluetooth_state, "i"); ++MODULE_PARM(usedritek, "i"); ++MODULE_PARM(verbose, "i"); ++MODULE_PARM(force_series, "i"); ++#endif ++MODULE_PARM_DESC(poll, "start polling timer"); ++MODULE_PARM_DESC(autowlan, "automatic switching of wlan hardware"); ++MODULE_PARM_DESC(wlan_state, "(assumed) initial state of WLAN LED/hardware"); ++MODULE_PARM_DESC(bluetooth_state, "(assumed) initial state of Bluetooth LED/hardware"); ++MODULE_PARM_DESC(usedritek, "enable dritek keyboard extension"); ++MODULE_PARM_DESC(verbose, "output additional information"); ++MODULE_PARM_DESC(force_series, "force laptop series, skip autodetection"); ++ ++/* input device */ ++static struct input_dev *acerhk_input_dev_ptr; ++#ifdef STATIC_INPUT_DEV ++static struct input_dev acerhk_input_dev; ++#endif ++ ++/* mapped IO area from 0xf0000 */ ++static void *reg1; ++/* mapped IO area from 0xe0000 */ ++static void *reg2; ++/* Pointer to mapped area at 0x400 on 520 series */ ++static void *preg400; ++/* location of IO routine in mapped area */ ++static unsigned int bios_routine; ++/* index of CMOS port to get key event */ ++static unsigned int cmos_index; ++/* function for bios call */ ++static bios_call call_bios; ++/* address of model string */ ++static char *acerhk_model_addr; ++/* copied string, maximum length 16 ('TravelMate xxx') */ ++static char acerhk_model_string[ACERHK_MODEL_STRLEN]; ++/* type of hardware access */ ++static t_acer_type acerhk_type; ++/* travelmate series */ ++static unsigned int acerhk_series; ++/* supported features for this model */ ++static unsigned int acerhk_model_features; ++/* map of acer key codes to acer key names */ ++static unsigned char acerhk_key2name[0xff]; ++/* map of acer key names to key events */ ++static t_map_name2event acerhk_name2event; ++/* timer for polling key presses */ ++static struct timer_list acerhk_timer_poll; ++/* polling active */ ++static int acerhk_polling_state; ++/* polling delay */ ++static unsigned acerhk_polling_delay = HZ/5; ++/* wlan hardware toggle */ ++static int acerhk_wlan_state; ++/* bluetooth hardware toggle */ ++static int acerhk_bluetooth_state; ++ ++/* bluetooth blinking state; added by Antonio Cuni ++ possible values: ++ -1: blinking disabled (default) ++ 0: blinking enabled, led currently off ++ 1: blinking enabled, led currently on ++*/ ++static int acerhk_blueled_blinking = -1; ++/* delay between two changes of state, in jiffies */ ++static unsigned acerhk_blueled_blinking_delay; ++/* timer for blinking */ ++static struct timer_list acerhk_timer_blinking; ++ ++/* function prototypes */ ++static void start_polling(void); ++static void stop_polling(void); ++ ++/* Added by Antonio Cuni */ ++static void start_blinking(void); ++static void stop_blinking(void); ++ ++/* {{{ Experimental use of dritek keyboard extension */ ++ ++#define EC_STATUS_REG 0x66 /* Status register of EC (R) */ ++#define EC_CNTL_REG 0x66 /* Controller command register of EC (W) */ ++#define EC_DATA_REG 0x62 /* EC data register (R/W) */ ++ ++#ifdef KERNEL26 ++ ++#include ++ ++#define KBD_STATUS_REG 0x64 /* Status register (R) */ ++#define KBD_CNTL_REG 0x64 /* Controller command register (W) */ ++#define KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */ ++ ++#else ++ ++#ifndef KEY_MEDIA ++#define KEY_MEDIA 226 ++#endif ++ ++#define preempt_disable() do { } while (0) ++#define preempt_enable_no_resched() do { } while (0) ++#define preempt_enable() do { } while (0) ++#define preempt_check_resched() do { } while (0) ++#include ++ ++#endif ++ ++static inline int my_i8042_read_status(void) ++{ ++ return inb(KBD_STATUS_REG); ++} ++static int my_i8042_wait_write(void) ++{ ++ int i = 0; ++ while ((my_i8042_read_status() & 0x02) && (i < 10000)) { ++ udelay(50); ++ i++; ++ } ++ return -(i == 10000); ++} ++static void send_kbd_cmd(unsigned char cmd, unsigned char val) ++{ ++ if (usedritek) { ++ preempt_disable(); ++ if (!my_i8042_wait_write()) ++ outb(cmd, KBD_CNTL_REG); ++ if (!my_i8042_wait_write()) ++ outb(val, KBD_DATA_REG); ++ preempt_enable_no_resched(); ++ } else { ++ printk(KERN_INFO"acerhk: request for accessing EC ignored\n" ++ KERN_INFO"acerhk: Use of dritek keyboard extension not enabled, use module\n" ++ KERN_INFO"acerhk: parameter usedritek=1 to do that (possibly dangerous)\n"); ++ } ++} ++#ifdef ACERDEBUG ++static inline int my_i8042_read_ecstatus(void) ++{ ++ return inb(EC_STATUS_REG); ++} ++static int my_i8042_wait_ecwrite(void) ++{ ++ int i = 0; ++ while ((my_i8042_read_ecstatus() & 0x02) && (i < 10000)) { ++ udelay(50); ++ i++; ++ } ++ return -(i == 10000); ++} ++static void send_ec_cmd(unsigned char cmd, unsigned char val) ++{ ++ if (usedritek) { ++ preempt_disable(); ++ if (!my_i8042_wait_ecwrite()) ++ outb(cmd, EC_CNTL_REG); ++ if (!my_i8042_wait_ecwrite()) ++ outb(val, EC_DATA_REG); ++ preempt_enable_no_resched(); ++ } else { ++ printk(KERN_INFO"acerhk: request for accessing EC ignored\n" ++ KERN_INFO"acerhk: Use of dritek keyboard extension not enabled, use module\n" ++ KERN_INFO"acerhk: parameter usedritek=1 to do that (possibly dangerous)\n"); ++ } ++} ++#endif ++#ifdef ACERDEBUG ++static void enable_mute_led_ec(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: enabling mute led via EC\n"); ++ send_kbd_cmd(0x59, 0x94); ++} ++static void disable_mute_led_ec(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: disabling mute led via EC\n"); ++ send_kbd_cmd(0x59, 0x95); ++} ++static void enable_dmm_function(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: enabling WLAN via EC variant 2\n"); ++ send_kbd_cmd(0x45, 0xd3); ++} ++#endif ++static void enable_wlan_ec_1(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: enabling WLAN via EC variant 1\n"); ++ send_kbd_cmd(0xe7, 0x01); ++ acerhk_wlan_state = 1; ++} ++static void disable_wlan_ec_1(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: disabling WLAN via EC variant 1\n"); ++ send_kbd_cmd(0xe7, 0x00); ++ acerhk_wlan_state = 0; ++} ++static void enable_bluetooth_ec_1(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: enabling Bluetooth via EC variant 1\n"); ++ send_kbd_cmd(0xe7, 0x03); ++ acerhk_bluetooth_state = 1; ++} ++static void disable_bluetooth_ec_1(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: disabling Bluetooth via EC variant 1\n"); ++ send_kbd_cmd(0xe7, 0x02); ++ acerhk_bluetooth_state = 0; ++} ++static void enable_wlan_ec_2(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: enabling WLAN via EC variant 2\n"); ++ send_kbd_cmd(0x45, acerhk_bluetooth_state ? 0xa2 : 0xa0); ++ acerhk_wlan_state = 1; ++} ++static void disable_wlan_ec_2(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: disabling WLAN via EC variant 2\n"); ++ send_kbd_cmd(0x45, acerhk_bluetooth_state ? 0xa1 : 0xa3); ++ acerhk_wlan_state = 0; ++} ++static void enable_bluetooth_ec_2(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: enabling Bluetooth via EC variant 2\n"); ++ send_kbd_cmd(0x45, acerhk_wlan_state ? 0xa2 : 0xa1); ++ acerhk_bluetooth_state = 1; ++} ++static void disable_bluetooth_ec_2(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: disabling Bluetooth via EC variant 2\n"); ++ send_kbd_cmd(0x45, acerhk_wlan_state ? 0xa0 : 0xa3); ++ acerhk_bluetooth_state = 0; ++} ++#ifdef ACERDEBUG ++static void enable_wireless_ec(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: enabling wireless hardware\n"); ++ if (usedritek) { ++ preempt_disable(); ++ if (!my_i8042_wait_ecwrite()) ++ outb(0x4d, EC_CNTL_REG); ++ if (!my_i8042_wait_ecwrite()) ++ outb(0xd2, EC_DATA_REG); ++ if (!my_i8042_wait_ecwrite()) ++ outb(0x01, EC_DATA_REG); ++ preempt_enable_no_resched(); ++ } ++ acerhk_wlan_state = 1; ++} ++static void disable_wireless_ec(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: disabling wireless hardware\n"); ++ if (usedritek) { ++ preempt_disable(); ++ if (!my_i8042_wait_ecwrite()) ++ outb(0x4d, EC_CNTL_REG); ++ if (!my_i8042_wait_ecwrite()) ++ outb(0xd2, EC_DATA_REG); ++ if (!my_i8042_wait_ecwrite()) ++ outb(0x00, EC_DATA_REG); ++ preempt_enable_no_resched(); ++ } ++ acerhk_wlan_state = 0; ++} ++#endif ++static void enable_dritek_keyboard(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: enabling dritek keyboard extension\n"); ++ send_kbd_cmd(0x59, 0x90); ++} ++static void disable_dritek_keyboard(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: disabling dritek keyboard extension\n"); ++ send_kbd_cmd(0x59, 0x91); ++} ++static void enable_mail_led_ec_1(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: enabling mail led via EC variant 1\n"); ++ send_kbd_cmd(0xe8, 0x01); ++} ++static void disable_mail_led_ec_1(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: disabling mail led via EC variant 1\n"); ++ send_kbd_cmd(0xe8, 0x00); ++} ++ ++static void enable_mail_led_ec_2(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: enabling mail led via EC variant 2\n"); ++ send_kbd_cmd(0x59, 0x92); ++} ++static void disable_mail_led_ec_2(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: disabling mail led via EC variant 2\n"); ++ send_kbd_cmd(0x59, 0x93); ++} ++static void enable_mail_led_ec_3(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: enabling mail led via EC variant 3\n"); ++ if (usedritek) { ++ preempt_disable(); ++ if (!my_i8042_wait_write()) ++ outl(0x80008894, 0xCF8); ++ if (!my_i8042_wait_write()) ++ outw(0xC061, 0xCFC); ++ preempt_enable_no_resched(); ++ } ++} ++static void disable_mail_led_ec_3(void) ++{ ++ if (verbose) ++ printk(KERN_INFO "acerhk: disabling mail led via EC variant 3\n"); ++ if (usedritek) { ++ preempt_disable(); ++ if (!my_i8042_wait_write()) ++ outl(0x80008894, 0xCF8); ++ if (!my_i8042_wait_write()) ++ outw(0xC060, 0xCFC); ++ preempt_enable_no_resched(); ++ } ++} ++ ++/* }}} */ ++ ++/* {{{ string search functions */ ++ ++/* This is the Colussi algorithm, the code is taken from ++ http://www-igm.univ-mlv.fr/~lecroq/string ++*/ ++int preColussi(char *x, int m, int *h, int *next, int *shift) ++{ ++ int i, k, nd, q, r, s; ++ int hmax[XSIZE], kmin[XSIZE], nhd0[XSIZE], rmin[XSIZE]; ++ /* Computation of hmax */ ++ i = k = 1; ++ do { ++ while (x[i] == x[i - k]) ++ i++; ++ hmax[k] = i; ++ q = k + 1; ++ while (hmax[q - k] + k < i) { ++ hmax[q] = hmax[q - k] + k; ++ q++; ++ } ++ k = q; ++ if (k == i + 1) ++ i = k; ++ } while (k <= m); /* Computation of kmin */ ++ memset(kmin, 0, m*sizeof(int)); ++ r = 0; ++ for (i = m; i >= 1; --i) ++ if (hmax[i] < m) ++ kmin[hmax[i]] = i; /* Computation of rmin */ ++ for (i = m - 1; i >= 0; --i) { ++ if (hmax[i + 1] == m) ++ r = i + 1; ++ if (kmin[i] == 0) ++ rmin[i] = r; ++ else ++ rmin[i] = 0; ++ } /* Computation of h */ ++ s = -1; ++ r = m; ++ for (i = 0; i < m; ++i) ++ if (kmin[i] == 0) ++ h[--r] = i; ++ else ++ h[++s] = i; ++ nd = s; /* Computation of shift */ ++ for (i = 0; i <= nd; ++i) ++ shift[i] = kmin[h[i]]; ++ for (i = nd + 1; i < m; ++i) ++ shift[i] = rmin[h[i]]; ++ shift[m] = rmin[0]; /* Computation of nhd0 */ ++ s = 0; ++ for (i = 0; i < m; ++i) { ++ nhd0[i] = s; ++ if (kmin[i] > 0) ++ ++s; ++ } /* Computation of next */ ++ for (i = 0; i <= nd; ++i) ++ next[i] = nhd0[h[i] - kmin[h[i]]]; ++ for (i = nd + 1; i < m; ++i) ++ next[i] = nhd0[m - rmin[h[i]]]; ++ next[m] = nhd0[m - rmin[h[m - 1]]]; return(nd); ++} ++ ++int COLUSSI(char *x, int m, char *y, int n) { ++ int i, j, last, nd, ++ h[XSIZE], next[XSIZE], shift[XSIZE]; /* Processing */ ++ int match_pos; /* position of first match */ ++ nd = preColussi(x, m, h, next, shift); /* Searching */ ++ i = j = 0; ++ last = -1; ++ match_pos = -1; ++ while ( (match_pos == -1) ++ && (j <= n - m) ) { ++ while (i < m && last < j + h[i] && ++ x[h[i]] == y[j + h[i]]) ++ i++; ++ if (i >= m || last >= j + h[i]) { ++ /* Match found, bail out */ ++ match_pos = j; ++ i = m; ++ } ++ if (i > nd) ++ last = j + m - 1; ++ j += shift[i]; ++ i = next[i]; ++ } ++ return match_pos; ++} ++ ++/* }}} */ ++ ++/* {{{ hardware access functions */ ++ ++/* call_bios_ ++ * ++ * call request handler in mapped system rom ++ * ++ * the request is handed over via all 6 general purpose registers, results are ++ * taken from them and copied back to buf ++ */ ++static asmlinkage void call_bios_6xx(struct register_buffer *buf) ++{ ++ if (bios_routine) { ++ local_irq_disable(); ++ __asm__ __volatile__( ++ "movl %1,%%edx\n\t" ++ "pusha\n\t" ++ "movl %%edx,%%ebp\n\t" ++ "movl (%%ebp),%%eax\n\t" ++ "movl 4(%%ebp),%%ebx\n\t" ++ "movl 8(%%ebp),%%ecx\n\t" ++ "movl 12(%%ebp),%%edx\n\t" ++ "movl 16(%%ebp),%%edi\n\t" ++ "movl 20(%%ebp),%%esi\n\t" ++ "pushl %%ebp\n\t" ++ "call *%0\n\t" ++ "popl %%ebp\n\t" ++ "movl %%eax, (%%ebp)\n\t" ++ "movl %%ebx, 4(%%ebp)\n\t" ++ "movl %%ecx, 8(%%ebp)\n\t" ++ "movl %%edx, 12(%%ebp)\n\t" ++ "movl %%edi, 16(%%ebp)\n\t" ++ "movl %%esi, 20(%%ebp)\n\t" ++ "popa\n\t" ++ : ++ :"m" (bios_routine), "m" (buf) ++ :"%eax", "%ebx", "%ecx", "%edx", "%edi", "%esi", "%ebp" ++ ); ++ local_irq_enable(); ++ } ++} ++ ++static asmlinkage void call_bios_52x(struct register_buffer *buf) ++{ ++ if (bios_routine) { ++ local_irq_disable(); ++ __asm__ __volatile__( ++ "movl %2,%%edx\n\t" ++ "pusha\n\t" ++ "movl %%edx,%%ebp\n\t" ++ "movl (%%ebp),%%eax\n\t" ++ "movl 4(%%ebp),%%ebx\n\t" ++ "movl 8(%%ebp),%%ecx\n\t" ++ "movl 12(%%ebp),%%edx\n\t" ++ "movl 16(%%ebp),%%edi\n\t" ++ "movl 20(%%ebp),%%esi\n\t" ++ "pushl %%ebp\n\t" ++ "movl %1, %%ebp\n\t" ++ "call *%0\n\t" ++ "popl %%ebp\n\t" ++ "movl %%eax, (%%ebp)\n\t" ++ "movl %%ebx, 4(%%ebp)\n\t" ++ "movl %%ecx, 8(%%ebp)\n\t" ++ "movl %%edx, 12(%%ebp)\n\t" ++ "movl %%edi, 16(%%ebp)\n\t" ++ "movl %%esi, 20(%%ebp)\n\t" ++ "popa\n\t" ++ : ++ :"m" (bios_routine), "m" (preg400), "m" (buf) ++ :"%eax", "%ebx", "%ecx", "%edx", "%edi", "%esi", "%ebp" ++ ); ++ local_irq_enable(); ++ } ++} ++ ++#define PRINT_BUFFER(x) \ ++ printk(KERN_INFO"acerhk: eax=0x%x ebx=0x%x ecx=0x%x edx=0x%x\n" \ ++ "acerhk: edi=0x%x esi=0x%x ebp=0x%x\n", \ ++ x.eax, x.ebx, x.ecx, x.edx, x.edi, x.esi, x.ebp); ++ ++/* get_fnkey_event ++ * ++ * gets the first (oldest) key id from the queue of events ++ * ++ * return value: id of key ++ */ ++static int get_fnkey_event(void) ++{ ++ struct register_buffer regs; ++ regs.eax = 0x9610; ++ regs.ebx = 0x61C; ++ /* clear other registers, some models need this */ ++ regs.ecx = 0; ++ regs.edx = 0; ++ preempt_disable(); ++ call_bios(®s); ++ preempt_enable_no_resched(); ++ return regs.eax & 0xffff; ++} ++ ++/* get_thermal_event ++ * ++ * does what? ++ * ++ * return value: event ? ++ */ ++static int get_thermal_event(void) ++{ ++ struct register_buffer regs; ++ if (acerhk_model_features & TM_F_THERMAL) { ++ regs.eax = 0x9612; ++ regs.ebx = 0x12e; ++ preempt_disable(); ++ call_bios(®s); ++ preempt_enable_no_resched(); ++ if (verbose > 3) ++ printk(KERN_INFO"acerhk: thermal event = 0x%x\n", regs.eax); ++ } else { ++ regs.eax = 0x00; ++ if (verbose > 3) ++ printk(KERN_INFO"acerhk: thermal event not supported\n"); ++ } ++ return regs.eax & 0xffff; ++} ++ ++#ifdef ACERDEBUG ++/* pbutton_fct ++ * ++ * does what? ++ * ++ * return value: ? ++ */ ++static int pbutton_fct(void) ++{ ++ struct register_buffer regs; ++ if (acerhk_model_features & TM_F_PBUTTON) { ++ regs.eax = 0x9612; ++ regs.ebx = 0x10b; ++ regs.ecx = 0x2; ++ preempt_disable(); ++ call_bios(®s); ++ preempt_enable_no_resched(); ++ if (verbose > 3) ++ printk(KERN_INFO"acerhk: pbutton = 0x%x\n", regs.eax); ++ } else { ++ if (verbose > 3) ++ printk(KERN_INFO"acerhk: pbutton function not supported\n"); ++ regs.eax = 0x00; ++ } ++ return regs.eax & 0xffff; ++} ++#endif ++ ++/* wbutton_fct_1 ++ * ++ * turn on installed Bluetooth hardware together with the corresponding LED ++ * ++ * val: 0 turns off the LED ++ * 1 turns the LED to green/blue ++ * ++ * return value: ? ++ */ ++static int wbutton_fct_1(int val) ++{ ++ struct register_buffer regs; ++ if (acerhk_model_features & TM_F_WBUTTON) { ++ acerhk_bluetooth_state = val; ++ regs.eax = 0x9610; ++ regs.ebx = ((val & 0xff) << 8) | 0x34; ++ preempt_disable(); ++ call_bios(®s); ++ preempt_enable_no_resched(); ++ if (verbose > 3) ++ printk(KERN_INFO"acerhk: wbutton1 = 0x%x\n", regs.eax); ++ } else { ++ if (verbose > 3) ++ printk(KERN_INFO"acerhk: wbutton function 1 not supported\n"); ++ regs.eax = 0x00; ++ } ++ return regs.eax & 0xffff; ++} ++ ++/* wbutton_fct_2 ++ * ++ * turn on installed WLAN hardware together with the corresponding LED ++ * ++ * val: 0 turns off the LED ++ * 1 turns the LED to orange ++ * ++ * return value: ? ++ */ ++static int wbutton_fct_2(int val) ++{ ++ struct register_buffer regs; ++ if (acerhk_model_features & TM_F_WBUTTON) { ++ acerhk_wlan_state = val; ++ regs.eax = 0x9610; ++ regs.ebx = ((val & 0xff) << 8) | 0x35; ++ preempt_disable(); ++ call_bios(®s); ++ preempt_enable_no_resched(); ++ if (verbose > 3) ++ printk(KERN_INFO"acerhk: wbutton2 = 0x%x\n", regs.eax); ++ } else { ++ if (verbose > 3) ++ printk(KERN_INFO"acerhk: wbutton function 2 not supported\n"); ++ regs.eax = 0x00; ++ } ++ return regs.eax & 0xffff; ++} ++ ++/* get_cmos_index ++ * ++ * gets index of CMOS port from ROM. The number of events is monitored ++ * in this port. ++ * ++ * return value: index of CMOS port ++ */ ++static int get_cmos_index(void) ++{ ++ struct register_buffer regs; ++ regs.eax = 0x9610; ++ regs.ebx = 0x51C; ++ preempt_disable(); ++ call_bios(®s); ++ preempt_enable_no_resched(); ++ cmos_index = regs.ecx & 0xff; ++ if (verbose) ++ printk(KERN_INFO"acerhk: cmos index set to 0x%x\n", cmos_index); ++ return cmos_index; ++} ++ ++/* get_nr_events ++ * ++ * gets the number of cached events (keys pressed) in queue. Up to 31 events ++ * are cached. ++ * ++ * return value: number of events in queue ++ */ ++static int get_nr_events(void) ++{ ++ unsigned long flags; ++ unsigned char c = 0; ++ ++ spin_lock_irqsave (&rtc_lock, flags); ++#ifndef DUMMYHW ++ if (cmos_index) ++ c = CMOS_READ(cmos_index); ++ else if (verbose > 3) ++ printk(KERN_INFO"acerhk: get_nr_events - no valid cmos index set\n"); ++#endif ++ spin_unlock_irqrestore (&rtc_lock, flags); ++ return c; ++} ++ ++/* set_mail_led ++ * ++ * change state of mail led ++ * ++ * val: 0 - switch led off ++ * 1 - switch led on (blinking) ++ * ++ * return value: 1 - action succesfull (val valid) ++ * 0 - no action taken (val invalid) ++ */ ++static int set_mail_led(int val) ++{ ++ struct register_buffer regs; ++ if (acerhk_model_features & TM_F_MAIL_LED) { ++ regs.eax = 0x9610; ++ regs.ebx = ((val & 0xff) << 8) | 0x31; ++ preempt_disable(); ++ call_bios(®s); ++ preempt_enable_no_resched(); ++ if (verbose > 3) ++ printk(KERN_INFO"acerhk: mail led set to = 0x%x\n", val); ++ } else if (acerhk_model_features & TM_F_MAIL_LED_EC) { ++ if (val == 1) ++ enable_mail_led_ec_1(); ++ else if (val == 0) ++ disable_mail_led_ec_1(); ++ } else if (acerhk_model_features & TM_F_MAIL_LED_EC2) { ++ if (val == 1) ++ enable_mail_led_ec_2(); ++ else if (val == 0) ++ disable_mail_led_ec_2(); ++ } else if (acerhk_model_features & TM_F_MAIL_LED_EC3) { ++ if (val == 1) ++ enable_mail_led_ec_3(); ++ else if (val == 0) ++ disable_mail_led_ec_3(); ++ } else { ++ if (verbose > 3) ++ printk(KERN_INFO"acerhk: mail led not supported\n"); ++ regs.eax = 0x00; ++ } ++ return regs.eax & 0xffff; ++} ++ ++/* launch_connect ++ * ++ * does what? ++ * val: 1 - only known value from windows driver ++ */ ++static int launch_connect(int val) ++{ ++ struct register_buffer regs; ++ if (acerhk_model_features & TM_F_CONNECT) { ++ regs.eax = 0x9610; ++ regs.ebx = ((val & 0xff) << 8) | 0x2e; ++ preempt_disable(); ++ call_bios(®s); ++ preempt_enable_no_resched(); ++ if (verbose > 3) ++ printk(KERN_INFO"acerhk: connect(%d) = 0x%x\n", val, regs.eax); ++ } else { ++ if (verbose > 3) ++ printk(KERN_INFO"acerhk: connect not supported\n"); ++ regs.eax = 0x00; ++ } ++ return regs.eax & 0xffff; ++} ++ ++/* }}} */ ++ ++/* {{{ hardware probing */ ++ ++static struct proc_dir_entry *proc_acer_dir; ++ ++static unsigned int __init find_hk_area(void) ++{ ++ int offset, sig; ++ unsigned int fkt; ++ fkt = 0; ++ sig = -1; /* offset to signature in io area */ ++ /* Look for signature, start at 0xf0000, search until 0xffff0 */ ++ for (offset = 0;offset < 0xfffd; offset += 16) { ++ if (readl(reg1 + offset) == 0x30552142) { ++ sig = offset; ++ offset = 0xffff; ++ } ++ } ++ if (sig < 0) ++ printk(KERN_WARNING"acerhk: could not find request handler, possibly not all functions available\n"); ++ else { ++ /* compute location of bios routine */ ++ fkt = readl(reg1 + sig + 5); ++ /* adjust fkt to address of mapped IO area */ ++ if (fkt >= 0xf0000) ++ fkt = (unsigned int)reg1 + fkt - 0xf0000; ++ else if (fkt >= 0xe0000) ++ fkt = (unsigned int)reg1 + fkt - 0xe0000; ++ else ++ fkt = 0; ++ } ++ return fkt; ++} ++ ++static void print_features(void) ++{ ++ int i; ++ printk(KERN_INFO"acerhk: supported keys:"); ++ for (i = 0; i < 255; i++) { ++ switch (acerhk_key2name[i]) { ++ case k_help: printk(" help"); break; ++ case k_setup: printk(" setup"); break; ++ case k_p1: printk(" p1"); break; ++ case k_p2: printk(" p2"); break; ++ case k_p3: printk(" p3"); break; ++ case k_www: printk(" www"); break; ++ case k_mail: printk(" mail"); break; ++ case k_wireless: printk(" wireless"); break; ++ case k_power: printk(" power"); break; ++ case k_mute: printk(" mute"); break; ++ case k_volup: printk(" volup"); break; ++ case k_voldn: printk(" voldn"); break; ++ case k_res: printk(" res"); break; ++ case k_close: printk(" close"); break; ++ case k_open: printk(" open"); break; ++ case k_wireless2: printk(" wireless2"); break; ++ case k_play: printk(" play"); break; ++ case k_stop: printk(" stop"); break; ++ case k_prev: printk(" prev"); break; ++ case k_next: printk(" next"); break; ++ case k_display: printk(" display"); break; ++ default: break; ++ } ++ } ++ printk("\n"); ++ if (acerhk_model_features & TM_F_MUTE_LED_EC) ++ printk(KERN_INFO"acerhk: mute led is supported\n"); ++ if (acerhk_model_features & TM_F_MAIL_LED) ++ printk(KERN_INFO"acerhk: mail led is supported\n"); ++ else if (acerhk_model_features & TM_F_MAIL_LED_EC) ++ printk(KERN_INFO"acerhk: mail led (EC) is supported\n"); ++ else if (acerhk_model_features & TM_F_MAIL_LED_EC2) ++ printk(KERN_INFO"acerhk: mail led (EC2) is supported\n"); ++ else if (acerhk_model_features & TM_F_MAIL_LED_EC3) ++ printk(KERN_INFO"acerhk: mail led (EC3) is supported\n"); ++ if (acerhk_model_features & TM_F_WLAN_EC1) ++ printk(KERN_INFO"acerhk: wlan control (EC1) is supported\n"); ++ else if (acerhk_model_features & TM_F_WLAN_EC2) ++ printk(KERN_INFO"acerhk: wlan control (EC2) is supported\n"); ++ if (acerhk_model_features & TM_F_BLUE_EC1) ++ printk(KERN_INFO"acerhk: bluetooth control (EC1) is supported\n"); ++ else if (acerhk_model_features & TM_F_BLUE_EC2) ++ printk(KERN_INFO"acerhk: bluetooth control (EC2) is supported\n"); ++ printk(KERN_INFO"acerhk: supported functions:"); ++ if (acerhk_model_features & TM_F_CONNECT) ++ printk(" connect"); ++ if (acerhk_model_features & TM_F_THERMAL) ++ printk(" thermal"); ++ if (acerhk_model_features & TM_F_PBUTTON) ++ printk(" pbutton"); ++ if (acerhk_model_features & TM_F_WBUTTON) ++ printk(" wbutton"); ++ printk("\n"); ++} ++ ++static void __init setup_keymap_model(unsigned int series) ++{ ++ /* clear mapping keycode -> keyname, */ ++ memset(&acerhk_key2name[0], k_none, sizeof(acerhk_key2name)); ++ /* first set the common keys, namely FnF1 and FnF2, */ ++ acerhk_key2name[1] = k_help; ++ acerhk_key2name[2] = k_setup; ++ /* then set known keycodes according to model */ ++ switch (series) { ++ case 110: ++ acerhk_key2name[48] = k_wireless; ++ acerhk_key2name[17] = k_p1; ++ acerhk_key2name[18] = k_p2; ++ acerhk_key2name[54] = k_www; ++ acerhk_key2name[49] = k_mail; ++ acerhk_key2name[3] = k_power; ++ acerhk_key2name[8] = k_mute; ++ acerhk_key2name[32] = k_volup; ++ acerhk_key2name[33] = k_voldn; ++ /* C110 generates 2 extra codes when opening/closing the lid */ ++ acerhk_key2name[74] = k_close; ++ acerhk_key2name[75] = k_open; ++ break; ++ case 300: /* treat C300 like C100 with Bluetooth button */ ++ acerhk_key2name[68] = k_wireless2; ++ case 100: ++ acerhk_key2name[48] = k_wireless; ++ acerhk_key2name[17] = k_p1; ++ acerhk_key2name[18] = k_p2; ++ acerhk_key2name[49] = k_www; ++ acerhk_key2name[54] = k_mail; ++ acerhk_key2name[3] = k_power; ++ acerhk_key2name[8] = k_mute; ++ acerhk_key2name[32] = k_volup; ++ acerhk_key2name[33] = k_voldn; ++ break; ++ default: ++ /* only the two common keys are supported */ ++ break; ++ case 210: ++ acerhk_key2name[19] = k_p1; ++ acerhk_key2name[20] = k_p2; ++ acerhk_key2name[17] = k_www; ++ acerhk_key2name[18] = k_mail; ++ break; ++ case 220: ++ case 260: /* 260 with same keys? */ ++ acerhk_key2name[49] = k_p1; ++ acerhk_key2name[19] = k_p2; ++ acerhk_key2name[18] = k_www; ++ acerhk_key2name[17] = k_mail; ++ break; ++ case 230: ++ case 280: /* 280 with same keys? */ ++ acerhk_key2name[17] = k_p1; ++ acerhk_key2name[18] = k_p2; ++ acerhk_key2name[49] = k_mail; ++ acerhk_key2name[54] = k_www; ++ break; ++ case 1500: ++ acerhk_key2name[0x49] = k_setup; ++ acerhk_key2name[0x36] = k_www; ++ acerhk_key2name[0x31] = k_mail; ++ acerhk_key2name[0x11] = k_p1; ++ acerhk_key2name[0x12] = k_p2; ++ acerhk_key2name[0x30] = k_wireless; ++ acerhk_key2name[0x44] = k_wireless2; ++ acerhk_key2name[0x03] = k_power; ++ break; ++ case 240: ++ acerhk_key2name[0x31] = k_www; ++ acerhk_key2name[0x36] = k_mail; ++ acerhk_key2name[0x11] = k_p1; ++ acerhk_key2name[0x12] = k_p2; ++ acerhk_key2name[0x44] = k_wireless; ++ acerhk_key2name[0x30] = k_wireless2; ++ acerhk_key2name[0x03] = k_power; ++ acerhk_key2name[0x08] = k_mute; ++ // acerhk_key2name[] = k_volup; ++ // acerhk_key2name[] = k_voldn; ++ break; ++ case 2900: ++ acerhk_key2name[0x31] = k_mail; /* with led */ ++ acerhk_key2name[0x36] = k_www; ++ acerhk_key2name[0x11] = k_p1; ++ acerhk_key2name[0x12] = k_p2; ++ acerhk_key2name[0x30] = k_wireless; /* wireless, with led, related with autowlan=1 */ ++ break; ++ case 250: /* enriqueg@altern.org */ ++ /* TravelMate 254LMi_DT manual common for 240/250 series, but key order ++ differ from 240 already present on acerhk driver */ ++ /* TravelMate 254LMi_DT: 6 buttons: left to right: mail, www, p1, p2, bluetooth, wireless */ ++ acerhk_key2name[0x31] = k_mail; /* with led */ ++ acerhk_key2name[0x36] = k_www; ++ acerhk_key2name[0x11] = k_p1; ++ acerhk_key2name[0x12] = k_p2; ++ acerhk_key2name[0x44] = k_wireless2; /* bluetooth, hw optional */ ++ acerhk_key2name[0x30] = k_wireless; /* wireless, with led, related with autowlan=1 */ ++ acerhk_key2name[0x03] = k_power; /* Fn+F3 */ ++ acerhk_key2name[0x08] = k_mute; /* Fn+F8 */ ++ break; ++ case 380: ++ /* TM 380 has same codes as TM 370, with an additional one */ ++ acerhk_key2name[0x03] = k_power; ++ case 370: ++ acerhk_key2name[0x30] = k_wireless; ++ acerhk_key2name[0x11] = k_p1; ++ acerhk_key2name[0x12] = k_p2; ++ acerhk_key2name[0x13] = k_p3; ++ acerhk_key2name[0x36] = k_www; ++ acerhk_key2name[0x31] = k_mail; ++ break; ++ case 360: ++ /* 360 series has the same layout as 350, with an ++ additional wireless key */ ++ acerhk_key2name[64] = k_wireless; ++ case 350: ++ acerhk_key2name[17] = k_p1; ++ acerhk_key2name[18] = k_p2; ++ acerhk_key2name[20] = k_p3; ++ acerhk_key2name[21] = k_www; ++ acerhk_key2name[19] = k_mail; ++ break; ++ case 520: ++ acerhk_key2name[19] = k_p1; ++ acerhk_key2name[20] = k_p2; ++ acerhk_key2name[17] = k_www; ++ acerhk_key2name[18] = k_mail; ++ break; ++ case 610: ++ acerhk_key2name[17] = k_p1; ++ acerhk_key2name[18] = k_p2; ++ acerhk_key2name[19] = k_p3; ++ acerhk_key2name[21] = k_www; ++ acerhk_key2name[20] = k_mail; ++ acerhk_key2name[64] = k_wireless; ++ break; ++ case 630: ++ /* 630 has all keys of 620 plus one */ ++ acerhk_key2name[8] = k_mute; ++ case 620: ++ acerhk_key2name[17] = k_p1; ++ acerhk_key2name[18] = k_p2; ++ acerhk_key2name[19] = k_p3; ++ acerhk_key2name[54] = k_www; ++ acerhk_key2name[49] = k_mail; ++ acerhk_key2name[48] = k_wireless; ++ acerhk_key2name[3] = k_power; ++ acerhk_key2name[32] = k_volup; ++ acerhk_key2name[33] = k_voldn; ++ break; ++ case 290: ++ case 420: ++ case 430: ++ case 530: ++ case 540: ++ case 650: ++ case 660: ++ case 800: ++ case 1450: ++ case 2300: ++ case 2350: ++ case 4000: ++ case 4050: ++ case 6000: ++ case 8000: ++ case 4100: ++ case 4150: ++ case 4500: ++ case 4600: ++ case 4650: ++ case 1680: ++ case 1690: ++ /* keys are handled by dritek EC */ ++ acerhk_key2name[1] = k_none; ++ acerhk_key2name[2] = k_none; ++ break; ++ case 1300: ++ case 1310: ++ case 1350: ++ case 1360: ++ case 1400: ++ case 1700: ++ case 1800: ++ case 2000: ++ case 2010: ++ case 2020: ++ /* Aspire 13xx series laptops use dritek hardware, no ++ acerhk-mapping needed ++ VolUp and VolDown are managed as normal keys ++ 1300/1310 series should have P1, P2, Mail, WWW, Mute buttons ++ 1353 has bluetooth, wifi, p1, p2, www, mail, help, setup, power ++ and mute ++ Aspire 1400/1450/Ferrari use dritek EC, too ++ 1450 should have bluetooth, wifi, p1, p2, www, mail, help, ++ setup, power and mute ++ Aspire 1700 uses dritek EC, too ++ 1700 should have bluetooth, wifi, p1, p2, www, mail, help, ++ setup, power and mute ++ need the MM-buttons Activation? (forward, shuffle, ...) ++ 2000 hast lots of MM buttons ++ 2010 should have bluetooth, wifi, p1, p2, www, mail, help, ++ setup, power and mute ++ */ ++ acerhk_key2name[1] = k_none; ++ acerhk_key2name[2] = k_none; ++ break; ++ case 1600: ++ /* Aspire 1600 has acer keycode 0x49 for FnF2 */ ++ acerhk_key2name[73] = k_setup; ++ acerhk_key2name[48] = k_wireless; ++ acerhk_key2name[49] = k_mail; ++ acerhk_key2name[54] = k_www; ++ acerhk_key2name[17] = k_p1; ++ acerhk_key2name[18] = k_p2; ++ acerhk_key2name[19] = k_p3; ++ acerhk_key2name[3] = k_power; ++ acerhk_key2name[8] = k_mute; ++ /* VolUp and VolDown keys doesn't seem to be managed as special keys ++ but as normal keys ! */ ++ break; ++ case 5020: /* Aspire 5020 has 0x6a for Fn+F2 */ ++ acerhk_key2name[2] = k_none; ++ acerhk_key2name[106] = k_setup; ++ acerhk_key2name[3] = k_power; ++ acerhk_key2name[5] = k_display; ++ acerhk_key2name[49] = k_mail; ++ acerhk_key2name[54] = k_www; ++ acerhk_key2name[17] = k_p1; ++ acerhk_key2name[18] = k_p2; ++ acerhk_key2name[48] = k_wireless; ++ acerhk_key2name[68] = k_wireless2; ++ break; ++ case 2410: /* TM 2410 is very similar to Aspire 5020, but has 0x6s for Fn-F3 */ ++ acerhk_key2name[2] = k_none; ++ acerhk_key2name[106] = k_setup; ++ acerhk_key2name[109] = k_power; ++ acerhk_key2name[49] = k_mail; ++ acerhk_key2name[54] = k_www; ++ acerhk_key2name[17] = k_p1; ++ acerhk_key2name[18] = k_p2; ++ acerhk_key2name[48] = k_wireless; ++ acerhk_key2name[68] = k_wireless2; ++ break; ++ case 40100: ++ /* Medion MD40100, 4 keys */ ++ acerhk_key2name[54] = k_www; ++ acerhk_key2name[49] = k_mail; ++ acerhk_key2name[48] = k_wireless; ++ acerhk_key2name[55] = k_res; ++ break; ++ case 96500: ++ case 95400: ++ /* Medion MD95400, many keys */ ++ acerhk_key2name[49] = k_mail; /* 1 */ ++ acerhk_key2name[54] = k_www; /* 2 */ ++ acerhk_key2name[48] = k_wireless; /* 3 */ ++ acerhk_key2name[68] = k_wireless2; /* 4 (Bluetooth) */ ++ ++ acerhk_key2name[17] = k_p1; /* 5 */ ++ acerhk_key2name[18] = k_p2; /* 6 */ ++ acerhk_key2name[36] = k_play; /* 7 */ ++ acerhk_key2name[37] = k_stop; /* 8 */ ++ acerhk_key2name[34] = k_prev; /* 9 */ ++ acerhk_key2name[35] = k_next; /* 10 */ ++ acerhk_key2name[33] = k_voldn; /* 11 */ ++ acerhk_key2name[32] = k_volup; /* 12 */ ++ acerhk_key2name[38] = k_p3; /* 13 */ ++ acerhk_key2name[8] = k_mute; /* 14 */ ++ ++ acerhk_key2name[1] = k_help; /* FN+F1 (Help) */ ++ acerhk_key2name[5] = k_display; /* FN+F3 (Display switch) */ ++ acerhk_key2name[6] = k_res; /* FN+F4 (Display ein/ausschalten) */ ++ break; ++ case 42200: ++ /* Medion MD42200, 7 keys, no setup */ ++ acerhk_key2name[2] = k_none; ++ acerhk_key2name[5] = k_display; ++ acerhk_key2name[54] = k_www; ++ acerhk_key2name[48] = k_wireless; ++ acerhk_key2name[49] = k_mail; ++ acerhk_key2name[17] = k_p1; ++ acerhk_key2name[18] = k_p2; ++ break; ++ case 9783: ++ /* Medion MD9783, 6 keys + info, no setup */ ++ acerhk_key2name[2] = k_none; ++ acerhk_key2name[54] = k_www; ++ acerhk_key2name[49] = k_mail; ++ acerhk_key2name[17] = k_p1; ++ acerhk_key2name[18] = k_p2; ++ acerhk_key2name[19] = k_p3; ++ acerhk_key2name[8] = k_mute; ++ break; ++ case 7400: ++ /* Amilo Pro V2000 does not have Help and Setup key (?) ++ Amilo M 7400 has Help key, disabling only setup ++ */ ++ acerhk_key2name[2] = k_none; ++ acerhk_key2name[48] = k_wireless; ++ acerhk_key2name[49] = k_mail; ++ acerhk_key2name[54] = k_www; ++ acerhk_key2name[17] = k_p1; ++ acerhk_key2name[18] = k_p2; ++ break; ++ case 1559: ++ acerhk_key2name[6] = k_display; /* FN+F4 (Display ein/ausschalten) */ ++ case 1555: ++ /* AOpen (Ahtec Signal 1555M) is similar to FS Amilo M */ ++ acerhk_key2name[2] = k_none; ++ acerhk_key2name[48] = k_wireless; ++ acerhk_key2name[49] = k_mail; ++ acerhk_key2name[54] = k_www; ++ acerhk_key2name[17] = k_p1; ++ acerhk_key2name[18] = k_p2; ++ acerhk_key2name[34] = k_prev; ++ acerhk_key2name[35] = k_next; ++ acerhk_key2name[36] = k_play; ++ acerhk_key2name[37] = k_stop; ++ break; ++ case 6800: ++ case 7820: ++ /* Amilo D does not have Setup key */ ++ acerhk_key2name[2] = k_none; ++ acerhk_key2name[49] = k_mail; ++ acerhk_key2name[54] = k_www; ++ acerhk_key2name[17] = k_p1; ++ acerhk_key2name[18] = k_p2; ++ acerhk_key2name[19] = k_p3; ++ acerhk_key2name[8] = k_mute; ++ break; ++ } ++} ++ ++static void __init setup_model_features(unsigned int series) ++{ ++ switch (series) { ++ case 200: ++ case 210: ++ case 520: ++ /* nothing special */ ++ acerhk_model_features = 0; ++ acerhk_type = TM_old; ++ break; ++ case 220: ++ case 230: ++ case 260: ++ case 280: ++ case 360: ++ case 40100: /* Medion MD40100 */ ++ case 95400: /* Medion MD95400 */ ++ case 96500: /* Medion MD96500 */ ++ /* all special functions, no mail led */ ++ acerhk_model_features = 0x00f00000; ++ acerhk_type = TM_new; ++ break; ++ case 42200: /* Medion MD42200 */ ++ /* has WLAN button, should call connect() */ ++ acerhk_model_features = TM_F_WBUTTON | TM_F_CONNECT; ++ acerhk_type = TM_old; ++ break; ++ case 9783: /* Medion MD9783 */ ++ /* only email led */ ++ acerhk_model_features = TM_F_MAIL_LED; ++ acerhk_type = TM_new; ++ break; ++ case 1600: ++ acerhk_type = TM_new; ++ /* Do Aspire 1600 series have special functions or not ? I enable ++ them, perhaps it helps with problems Francois Valenduc has */ ++ acerhk_model_features = 0x00f00000; ++ break; ++ case 300: ++ case 100: ++ case 110: ++ case 240: ++ case 350: ++ case 610: ++ case 620: ++ case 630: ++ /* all special functions, mail led */ ++ acerhk_model_features = TM_F_MAIL_LED | 0x00f00000; ++ acerhk_type = TM_new; ++ break; ++ case 370: ++ case 380: ++ case 2410: ++ case 2900: /* Medion MD2900 */ ++ case 2100: /* TM 2100 uses same driver as 5020 */ ++ case 5020: /* Aspire 5020 is still old hardware */ ++ acerhk_model_features = TM_F_MAIL_LED | TM_F_CONNECT| TM_F_WBUTTON; ++ acerhk_type = TM_new; ++ break; ++ case 7400: ++ case 1555: ++ case 1559: ++ /* all special functions for Fujitsu-Siemens Amilo M7400, Pro V2000; AOpen */ ++ acerhk_model_features = 0x00f00000; ++ acerhk_type = TM_new; ++ break; ++ case 6800: ++ case 7820: ++ /* mail led and all special functions for FS Amilo D */ ++ acerhk_model_features = TM_F_MAIL_LED | 0x00f00000; ++ acerhk_type = TM_new; ++ break; ++ case 2350: ++ case 4050: ++ acerhk_wlan_state = 1; // Default state is on ++ case 290: ++ /* no special functions, wireless hardware controlled by EC */ ++ acerhk_model_features = TM_F_WLAN_EC2 | TM_F_BLUE_EC2; ++ acerhk_type = TM_dritek; ++ break; ++ case 650: ++ case 1300: ++ case 1310: ++ case 1400: ++ case 1700: ++ /* all special functions, wireless hardware can be controlled */ ++ acerhk_model_features = 0x00f00000; ++ acerhk_type = TM_dritek; ++ break; ++ case 4100: ++ case 4600: ++ case 1680: ++ case 1690: /* Aspire 1680/1690 should be similar to TM 4100/4600 */ ++ /* mail led, wireless and bluetooth controlled the old way, but keys are ++ controlled by normal keyboard controller, so mark as dritek and ++ deactivate dritek use */ ++ acerhk_model_features = TM_F_MAIL_LED | TM_F_WBUTTON; ++ acerhk_type = TM_dritek; ++ usedritek=0; ++ break; ++ case 660: ++ case 800: ++ /* all special functions, mail led */ ++ acerhk_model_features = TM_F_MAIL_LED | 0x00f00000; ++ acerhk_type = TM_dritek; ++ break; ++ case 1350: ++ case 1360: ++ /* mail led, handled by EC, wireless HW is not (yet) controllable ? */ ++ acerhk_model_features = TM_F_MAIL_LED_EC|TM_F_WLAN_EC1; ++ acerhk_type = TM_dritek; ++ break; ++ case 1450: ++ /* Bluetooth/Wlan led, Mail led handled by EC (variant 3) */ ++ acerhk_model_features = TM_F_MAIL_LED_EC3|TM_F_WBUTTON; ++ acerhk_type = TM_dritek; ++ break; ++ case 1500: ++ /* Bluetooth/Wlan led */ ++ acerhk_model_features = TM_F_WBUTTON; ++ acerhk_type = TM_new; ++ break; ++ case 420: ++ case 430: ++ /* all functions and dritek EC, mail LED is handled by EC, second ++ variant. An additional led is available, mute. (really?) ++ */ ++ acerhk_type = TM_dritek; ++ acerhk_model_features = TM_F_MUTE_LED_EC|TM_F_MAIL_LED_EC2; ++ break; ++ case 2300: ++ case 4000: ++ case 4500: ++ /* wireless hardware, hopefully under control of my driver */ ++ acerhk_type = TM_dritek; ++ acerhk_model_features = TM_F_BLUE_EC1|TM_F_WLAN_EC1; ++ break; ++ case 3200: ++ /* test, if this model uses old style wlan control */ ++ acerhk_model_features = TM_F_WBUTTON; ++ acerhk_type = TM_dritek; ++ break; ++ case 6000: ++ case 8000: ++ /* 6000 and 8000 have wireless hardware, but I don't know how to handle, ++ so I choose no features */ ++ acerhk_type = TM_dritek; ++ break; ++ case 530: ++ case 540: ++ case 2000: ++ /* No features (?) dritek EC, mail LED is handled by EC but ++ different from other Aspire series */ ++ acerhk_type = TM_dritek; ++ acerhk_model_features = TM_F_MAIL_LED_EC2; ++ break; ++ case 4150: ++ case 4650: ++ /* Dritek EC, bluetooth, wifi, mail */ ++ /* According to Andreas Stumpfl his TM 4652LMi does also work as series ++ 3200, which might mean that the BIOS function accesses the EC */ ++ acerhk_type = TM_dritek; ++ acerhk_model_features = TM_F_MAIL_LED_EC2 | TM_F_WLAN_EC2 | TM_F_BLUE_EC2; ++ break; ++ case 1800: ++ case 2010: ++ case 2020: ++ /* Dritek EC, bluetooth, wifi, mail */ ++ acerhk_type = TM_dritek; ++ acerhk_model_features = TM_F_MAIL_LED_EC2 | TM_F_WLAN_EC2 | TM_F_BLUE_EC2; ++ acerhk_wlan_state = 1; // Default state is on ++ break; ++ case 250: /* enriqueg@altern.org */ ++ /* TravelMate254LMi_DT : mail led, bluetooth (button present, hw optional), wifi (with led) */ ++ acerhk_model_features = TM_F_MAIL_LED| ++ TM_F_WBUTTON ; ++ acerhk_type = TM_new; ++ acerhk_wlan_state = 0; //Initial state is off on 254LMi_DT ++ break; ++ default: ++ /* nothing special */ ++ acerhk_model_features = 0; ++ acerhk_type = TM_unknown; ++ break; ++ } ++ /* set the correct bios call function according to type */ ++ if ((acerhk_type == TM_new) || (acerhk_type == TM_dritek)) { ++ call_bios = call_bios_6xx; ++ if (verbose > 2) ++ printk(KERN_INFO"acerhk: using call_bios_6xx mode\n"); ++ } else { ++ call_bios = call_bios_52x; ++ if (verbose > 2) ++ printk(KERN_INFO"acerhk: using call_bios_52x mode\n"); ++ } ++ /* remove key file on dritek hardware */ ++ if (acerhk_type == TM_dritek) { ++ remove_proc_entry("key", proc_acer_dir); ++ } ++ /* setup available keys */ ++ setup_keymap_model(acerhk_series); ++ if (verbose > 1) ++ print_features(); ++} ++ ++static unsigned int __init determine_laptop_series(char * str) ++{ ++ /* 0 means unknown series, handled like TM 200 */ ++ unsigned int series = 0; ++ if (strncmp(str, "TravelMate ", 11) == 0) { ++ switch (str[11]) { ++ case 'C': ++ if (str[12] == '1') { ++ if (str[13] == '0') { ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates TM C100 series\n"); ++ series = 100; ++ } else if (str[13] == '1') { ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates TM C110 series\n"); ++ series = 110; ++ } ++ } else if (str[12] == '3') { ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates TM C300 series\n"); ++ series = 300; ++ } ++ break; ++ case 'F': ++ if (str[12] == '4') { ++ series = 230; ++ } ++ break; ++ case '2': ++ if (str[14] == '0') { ++ /* newer Travelmate 2xxx series */ ++ switch (str[12]) { ++ case '0': ++ case '5': ++ series = 2000; // 2000 and 2500 are the same ++ break; ++ case '1': ++ if (str[13] == '0') ++ series = 2100; ++ break; ++ case '2': ++ case '7': ++ series = 2200; // 2200 and 2700 are the same ++ break; ++ case '3': ++ if (str[13] == '0') ++ series = 4000; // 2300 is the same as 4000 ++ else if (str[13] == '5') ++ series = 4050; // 2350 is the same as 4050 ++ break; ++ case '4': ++ if (str[13] == '1') ++ series = 2410; ++ break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown TM 2xxx series\n"); ++ break; ++ } ++ } else { ++ /* older Travelmate 2xx series */ ++ switch (str[12]) { ++ case '0': series = 200; break; ++ case '1': series = 210; break; ++ case '2': series = 220; break; ++ case '4': series = 240; break; ++ case '5': series = 250; break; /* enriqueg@altern.org */ ++ case '6': series = 260; break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown TM 2xx series\n"); ++ break; ++ } ++ } ++ break; ++ case '3': ++ switch (str[12]) { ++ case '0': series = 3200; break; /* TM 3000 works like TM 3200 */ ++ /* Travelmate 3xx series */ ++ case '5': series = 350; break; ++ case '6': series = 360; break; ++ case '7': series = 370; break; ++ case '8': series = 380; break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown TM 3xx series\n"); ++ break; ++ } ++ break; ++ case '4': ++ if ( (strnlen(str, ACERHK_MODEL_STRLEN-1) == 15) && ++ (str[14] == '0') ) { /* Travelmate 4xxx series */ ++ switch (str[12]) { ++ case '0': /* 4000 and 4500 are the same */ ++ case '5': ++ series = 4000; ++ break; ++ case '1': ++ case '6': /* 4100 and 4600 are the same */ ++ series = 4100; ++ break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown TM 4xxx series\n"); ++ break; ++ } ++ } else { /* Travelmate 4xx series */ ++ switch (str[12]) { ++ case '2': series = 420; break; ++ case '3': series = 430; break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown TM 4xx series\n"); ++ break; ++ } ++ } ++ break; ++ case '5': /* Travelmate 5xx series */ ++ if (str[12] == '2') ++ series = 520; ++ else if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown TM 5xx series\n"); ++ break; ++ case '6': /* older Travelmate 6xx series */ ++ switch (str[12]) { ++ case '1': series = 610; break; ++ case '2': series = 620; break; ++ case '3': series = 630; break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown TM 6xx series\n"); ++ break; ++ } ++ break; ++ default: ++ printk(KERN_INFO"acerhk: model string indicates unknown TM xxx series\n"); ++ break; ++ } ++ if (series && verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates TM %d series\n", series); ++ } ++ /* newer Travelmate series do not have a space after 'TravelMate' */ ++ else if (strncmp(str, "TravelMate", 10) == 0) { ++ switch (str[10]) { ++ case '2': ++ if (str[11] == '9') { ++ series = 290; ++ } else { ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown TM2xx series\n"); ++ } ++ break; ++ case '3': ++ if (str[11] == '2' && str[14] == '3') { ++ // TM 3200 uses "TravelMate32003" ++ series = 3200; ++ } else { ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown TM3xxx series\n"); ++ } ++ break; ++ case '4': ++ switch (str[11]) { ++ case '3': series = 430; break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown TM4xx series\n"); ++ break; ++ } ++ break; ++ case '5': ++ switch (str[11]) { ++ case '3': series = 530; break; ++ case '4': series = 540; break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown TM5xx series\n"); ++ break; ++ } ++ break; ++ case '6': ++ switch (str[11]) { ++ case '5': series = 650; break; ++ case '6': series = 660; break; ++ case '0': ++ if (strncmp(str, "TravelMate60003", 15) == 0) { ++ series = 6000; break; ++ } ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown TM6xx series\n"); ++ break; ++ } ++ break; ++ case '8': ++ if (strncmp(str, "TravelMate80003", 15) == 0) { ++ series = 8000; ++ } else if (str[11] == '0') { ++ series = 800; ++ } else { ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown TM8xx series\n"); ++ } ++ break; ++ default: ++ printk(KERN_INFO"acerhk: model string indicates unknown TMxxx series\n"); ++ break; ++ } ++ if (series && verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates TM%d series\n", series); ++ } ++ else if (strncmp(str, "Aspire ", 7) == 0) { ++ switch(str[7]) { ++ case '1': /* Aspire 1xxx series */ ++ switch(str[8]) { ++ case '3': /* Aspire 13xx series */ ++ switch (str[9]) { ++ case '0': series = 1300; break; ++ case '1': series = 1310; break; ++ case '5': series = 1350; break; ++ case '6': series = 1360; break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown Aspire 13xx series\n"); ++ break; ++ } ++ break; ++ case '4': /* Aspire 14xx series */ ++ switch (str[9]) { ++ case '0': series = 1400; break; ++ case '5': series = 1450; break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown Aspire 14xx series\n"); ++ break; ++ } ++ break; ++ case '5': series = 1500; break; ++ case '6': /* Aspire 14xx series */ ++ switch (str[9]) { ++ case '0': series = 1600; break; ++ case '8': ++ case '9': series = 1680; break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown Aspire 16xx series\n"); ++ break; ++ } ++ break; ++ case '7': series = 1700; break; ++ case '8': series = 1800; break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown Aspire 1xxx series\n"); ++ break; ++ } ++ break; ++ case '2': /* Aspire 2xxx series */ ++ if (str[8] == '0') { ++ switch (str[9]) { ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown Aspire 20xx series\n"); ++ break; ++ case '0': series = 2000; break; ++ case '1': series = 2010; break; ++ case '2': series = 2020; break; ++ } ++ } else { ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown Aspire 2xxx series\n"); ++ } ++ break; ++ case '3': /* Aspire 3xxx series */ ++ if (str[8] == '0') { ++ switch (str[9]) { ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown Aspire 30xx series\n"); ++ break; ++ case '2': series = 5020; break; /* Aspire 3020/5020 are identical */ ++ } ++ } else { ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown Aspire 3xxx series\n"); ++ } ++ break; ++ case '5': /* Aspire 5xxx series */ ++ if (str[8] == '0') { ++ switch (str[9]) { ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown Aspire 50xx series\n"); ++ break; ++ case '2': series = 5020; break; ++ } ++ } else { ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown Aspire 5xxx series\n"); ++ } ++ break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown Aspire series\n"); ++ break; ++ } ++ if (series && verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates Aspire %d series\n", series); ++ } ++ else if (strncmp(str, "Extensa ", 8) == 0) { ++ /* Extensa series */ ++ switch (str[8]) { ++ case '3': ++ switch (str[9]) { ++ case '0': ++ series = 3000; break; ++ default: break; ++ } ++ break; ++ default: break; ++ } ++ if (series && verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates Extensa %d series\n", series); ++ else if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown Extensa series\n"); ++ } ++ else if (strncmp(str, "Amilo ", 6) == 0) { ++ switch (str[6]) { ++ case 'D': /* complete string is "Amilo D-Series", there seems to be no model number */ ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates FS Amilo D series\n"); ++ /* this is the model number of my Amilo */ ++ series = 7820; ++ break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown FS Amilo XX series\n"); ++ series = 7820; ++ } ++ } ++ else if (strncmp(str, "AMILO ", 6) == 0) { ++ switch (str[6]) { ++ case 'D': /* AMILO D 6800 P4-2000 */ ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates FS AMILO D series\n"); ++ series = 6800; ++ break; ++ case 'M': ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates FS AMILO M(7400) series\n"); ++ series = 7400; ++ break; ++ case 'P': ++ /* it is assumed, that 'AMILO P' appears only on Amilo Pro Series */ ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates FS AMILO Pro (V2000) series\n"); ++ series = 7400; ++ break; ++ default: ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates unknown FS AMILO XX series\n"); ++ series = 6800; ++ } ++ } ++ else if (strncmp(str, "MEDIONPC", 8) == 0) { ++ uint medionmodel; ++ if ((medionmodel = COLUSSI("WIM 2040", 4, reg1, AREA_SIZE)) >= 0) { ++ printk(KERN_INFO"acerhk: found Medion model string:'%s'\n", (char*)reg1+medionmodel); ++ series = 96500; ++ } else { ++ if ((medionmodel = COLUSSI("MD 9", 4, reg1, AREA_SIZE)) >= 0) { ++ printk(KERN_INFO"acerhk: found Medion model string:'%s'\n", (char*)reg1+medionmodel); ++ } ++ series = 95400; ++ } ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates a medion MD %d\n", series); ++ } ++ else if (strncmp(str, "MEDIONNB", 8) == 0) { ++ /* Search for the Product string of the MD9783. */ ++ if (COLUSSI("MD 42200", 8, reg1, AREA_SIZE) >= 0) { ++ if (verbose>1) ++ printk(KERN_INFO"acerhk: model string indicates a Medion MD 42200\n"); ++ series = 42200; ++ } else if (COLUSSI("MD 9783", 7, reg1, AREA_SIZE) >= 0){ ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates a medion MD 9783\n"); ++ series = 9783; ++ } else if (COLUSSI("WIM 2000", 7, reg1, AREA_SIZE) >= 0){ ++ if (verbose>1) ++ printk(KERN_INFO"acerhk: model string indicates a Medion MD 2900\n"); ++ series = 2900; ++ } else { ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates a medion MD40100\n"); ++ series = 40100; ++ } ++ } else if (strncmp(str, "AOpen", 5) == 0) { ++ if (strncmp(str, "AOpen*EzRestore", 15) == 0) { ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates a AOpen 1559\n"); ++ series = 1559; ++ } else { ++ /* Unless I know of other models no further differentiation, ++ although there is a second part of the model string */ ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates a AOpen\n"); ++ series = 1555; ++ } ++ } else if (strncmp(str, "CL56", 4) == 0) { ++ /* Unless I know of other models no further differentiation, ++ although there are strings with more numbers ("CL561" on a Compal ++ CL56/Zepto 4200, reported by Stian B. Barmen) ++ It has the same functions as Acer Aspire 2010 ++ */ ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates a Compal CL56 (or similar)\n"); ++ series = 2010; ++ } else if (strncmp(str, "Geneva2", 7) == 0) { ++ /* This might be an Aspire 9110 which is very similar to 4650 */ ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates an Aspire 9110\n"); ++ series = 4650; ++ } else { ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: model string indicates no supported hardware\n"); ++ } ++ return (series); ++} ++ ++static void __init probe_model(void) { ++ int offset; /* offset from beginning of reg1 to Model string */ ++ if (verbose) ++ printk(KERN_INFO"acerhk: start search for model string at %p\n", reg1); ++ /* first we look for Travelmate, if it isn't one we try to identify other ++ laptops, such as Medion or Aspire */ ++ offset = COLUSSI("Travel", 6, reg1, AREA_SIZE); ++ /* Try to detect Aspire laptops */ ++ if (offset < 0) ++ offset = COLUSSI("Aspire", 6, reg1, AREA_SIZE); ++ /* Try to detect Extensa laptops */ ++ if (offset < 0) ++ offset = COLUSSI("Extensa", 7, reg1, AREA_SIZE); ++ /* Try to detect Medion laptops */ ++ if (offset < 0) ++ offset = COLUSSI("MEDION", 6, reg1, AREA_SIZE); ++ /* Try to detect AOpen laptops */ ++ if (offset < 0) ++ offset = COLUSSI("AOpen", 5, reg1, AREA_SIZE); ++ /* Try to detect Fujitsu Siemens Amilo laptops */ ++ if (offset < 0) ++ offset = COLUSSI("Amilo", 5, reg1, AREA_SIZE); ++ if (offset < 0) ++ offset = COLUSSI("AMILO", 5, reg1, AREA_SIZE); ++ /* Try to detect Compal */ ++ if (offset < 0) ++ offset = COLUSSI("CL56", 4, reg1, AREA_SIZE); ++ /* That might be an Aspire 9110 */ ++ if (offset < 0) ++ offset = COLUSSI("Geneva2", 7, reg1, AREA_SIZE); ++ if (offset >= 0) { ++ acerhk_model_addr = reg1 + offset; ++ /* copy the string, but not more than 15 characters */ ++ strncpy(acerhk_model_string, acerhk_model_addr, ACERHK_MODEL_STRLEN-1); ++ if (verbose) ++ printk(KERN_INFO"acerhk: found model string '%s' at %p\n", ++ acerhk_model_string, acerhk_model_addr); ++ if (bios_routine && verbose > 2) ++ printk(KERN_INFO"acerhk: offset from model string to function address: 0x%lx\n", ++ bios_routine - (unsigned long)acerhk_model_addr); ++ acerhk_series = determine_laptop_series(acerhk_model_string); ++ } else { ++ printk(KERN_WARNING"acerhk: Could not find model string, will assume type 200 series\n"); ++ acerhk_series = 200; ++ } ++} ++ ++/* }}} */ ++ ++/* {{{ key polling and translation */ ++ ++static void print_mapping(void) ++{ ++ printk(KERN_INFO"acerhk: key mapping:\n"); ++ printk("acerhk: help 0x%x\n", acerhk_name2event[k_help]); ++ printk("acerhk: setup 0x%x\n", acerhk_name2event[k_setup]); ++ printk("acerhk: p1 0x%x\n", acerhk_name2event[k_p1]); ++ printk("acerhk: p2 0x%x\n", acerhk_name2event[k_p2]); ++ printk("acerhk: p3 0x%x\n", acerhk_name2event[k_p3]); ++ printk("acerhk: www 0x%x\n", acerhk_name2event[k_www]); ++ printk("acerhk: mail 0x%x\n", acerhk_name2event[k_mail]); ++ printk("acerhk: wireless 0x%x\n", acerhk_name2event[k_wireless]); ++ printk("acerhk: power 0x%x\n", acerhk_name2event[k_power]); ++ printk("acerhk: mute 0x%x\n", acerhk_name2event[k_mute]); ++ printk("acerhk: volup 0x%x\n", acerhk_name2event[k_volup]); ++ printk("acerhk: voldn 0x%x\n", acerhk_name2event[k_voldn]); ++ printk("acerhk: res 0x%x\n", acerhk_name2event[k_res]); ++ printk("acerhk: close 0x%x\n", acerhk_name2event[k_close]); ++ printk("acerhk: open 0x%x\n", acerhk_name2event[k_open]); ++ printk("acerhk: wireless2 0x%x\n", acerhk_name2event[k_wireless2]); ++ printk("acerhk: play 0x%x\n", acerhk_name2event[k_play]); ++ printk("acerhk: stop 0x%x\n", acerhk_name2event[k_stop]); ++ printk("acerhk: prev 0x%x\n", acerhk_name2event[k_prev]); ++ printk("acerhk: next 0x%x\n", acerhk_name2event[k_next]); ++ printk("acerhk: display 0x%x\n", acerhk_name2event[k_display]); ++} ++ ++static void set_keymap_name(t_key_names name, unsigned int key) ++{ ++ acerhk_name2event[name] = key; ++} ++ ++static void init_keymap_input(void) ++{ ++ /* these values for input keys are chosen to match the key names on the ++ actual Acer laptop */ ++ set_keymap_name(k_none, KEY_RESERVED); ++ set_keymap_name(k_help, KEY_HELP); ++ set_keymap_name(k_setup, KEY_CONFIG); ++ set_keymap_name(k_p1, KEY_PROG1); ++ set_keymap_name(k_p2, KEY_PROG2); ++ set_keymap_name(k_p3, KEY_PROG3); ++ set_keymap_name(k_www, KEY_WWW); ++ set_keymap_name(k_mail, KEY_MAIL); ++ set_keymap_name(k_wireless, KEY_XFER); ++ set_keymap_name(k_power, KEY_POWER); ++ set_keymap_name(k_mute, KEY_MUTE); ++ set_keymap_name(k_volup, KEY_VOLUMEUP); ++ set_keymap_name(k_voldn, KEY_VOLUMEDOWN); ++ set_keymap_name(k_res, KEY_CONFIG); ++ set_keymap_name(k_close, KEY_CLOSE); ++ set_keymap_name(k_open, KEY_OPEN); ++ /* I am not really happy with the selections for wireless and wireless2, ++ but coffee looks good. Michal Veselenyi proposed this value */ ++ set_keymap_name(k_wireless2, KEY_COFFEE); ++ set_keymap_name(k_play, KEY_PLAYPAUSE); ++ set_keymap_name(k_stop, KEY_STOPCD); ++ set_keymap_name(k_prev, KEY_PREVIOUSSONG); ++ set_keymap_name(k_next, KEY_NEXTSONG); ++ set_keymap_name(k_display, KEY_MEDIA); /* also not happy with this */ ++ if (verbose > 1) ++ print_mapping(); ++} ++ ++static int filter_idle_value(int keycode) ++{ ++ int validkey = 0; ++ if (keycode != 0x0 && ++ keycode != 0x9610 && ++ keycode != 0xc100 && /* Francois Valenduc, Aspire 1601 LC */ ++ keycode != 0x8610 && ++ keycode != 0x861 && ++ keycode != 0x8650 && ++ keycode != 0x865) ++ validkey = keycode; ++ if (verbose > 4 && !validkey) ++ printk(KERN_INFO"acerhk: throw away idle value 0x%x\n", keycode); ++ return validkey; ++} ++ ++static void send_key_event(t_key_names key) ++{ ++ unsigned int input_key; ++ if (key != k_none) { ++ /* convert key name to kernel keycode */ ++ input_key = acerhk_name2event[key]; ++ if (verbose > 2) ++ printk(KERN_INFO"acerhk: translated acer key name 0x%x to input key 0x%x\n", ++ key, input_key); ++ /* send press and release together, as there is no such event from acer as 'release' */ ++ input_report_key(acerhk_input_dev_ptr, input_key, 1); ++ input_report_key(acerhk_input_dev_ptr, input_key, 0); ++ } ++} ++ ++static t_key_names transl8_key_code(int keycode) ++{ ++ t_key_names keyname = k_none; ++ /* first filter out idle values */ ++ if ( (keycode = filter_idle_value(keycode)) ) { ++ if (verbose > 3) ++ printk(KERN_INFO"acerhk: received key code 0x%x\n", keycode); ++ /* translate keycode to key name */ ++ if (keycode >= 0 && keycode <= 255) ++ keyname = acerhk_key2name[keycode]; ++ else { ++ if (verbose > 3) ++ printk(KERN_INFO"acerhk: keycode 0x%x too big, will use only 8 bits\n", keycode); ++ /* use only lower 8 bits of value to distinguish keys */ ++ keyname = acerhk_key2name[keycode&0xff]; ++ } ++ /* produce some log information for higher verbosity levels */ ++ if (keyname != k_none && verbose > 2) ++ printk(KERN_INFO"acerhk: translated acer key code 0x%x to key name 0x%x\n", ++ keycode, keyname); ++ else if (keyname == k_none && verbose > 3) ++ printk(KERN_INFO"acerhk: translated acer key code 0x%x to no key\n", ++ keycode); ++ if (autowlan) { ++ /* if automatic switching of wlan hardware is enabled, do it here ++ on wireless key press */ ++ if (keyname == k_wireless2) { ++ if (acerhk_bluetooth_state) ++ wbutton_fct_1(0); ++ else ++ wbutton_fct_1(1); ++ } ++ if (keyname == k_wireless) { ++ if (acerhk_wlan_state) ++ wbutton_fct_2(0); ++ else ++ wbutton_fct_2(1); ++ } ++ } ++ } ++ return keyname; ++} ++ ++/* polling timer handler */ ++static void acerhk_poll_event(unsigned long save_size) ++{ ++#ifndef DUMMYHW ++ unsigned int max = MAX_POLLING_LOOPS; ++ /* make sure not to loop more then 32 times */ ++ if (!max || max > 32) ++ max = 32; ++ if (acerhk_type != TM_dritek) { ++ while (get_nr_events() && max--) { ++ send_key_event(transl8_key_code(get_fnkey_event())); ++ } ++ } else { ++ send_key_event(transl8_key_code(get_fnkey_event())); ++ } ++#endif ++ acerhk_timer_poll.expires = jiffies + acerhk_polling_delay; ++ add_timer(&acerhk_timer_poll); ++} ++ ++/* blinking timer handler; added by Antonio Cuni */ ++static void acerhk_blink_event(unsigned long not_used) ++{ ++ if (acerhk_blueled_blinking != -1) { ++ acerhk_blueled_blinking = !acerhk_blueled_blinking; ++#ifndef DUMMYHW ++ wbutton_fct_1(acerhk_blueled_blinking); ++#endif ++ acerhk_timer_blinking.expires = jiffies + acerhk_blueled_blinking_delay; ++ add_timer(&acerhk_timer_blinking); ++ } ++ else ++ printk(KERN_WARNING "acerhk: blinking event called, but blinking not active\n"); ++} ++ ++static void init_input(void) ++{ ++ int i; ++ ++#ifndef KERNEL26 ++ /* request keyboard input module */ ++ request_module("keybdev"); ++ if (verbose > 3) ++ printk(KERN_INFO"requested keyboard input driver\n"); ++#endif ++ ++#ifndef STATIC_INPUT_DEV ++ /* allocate acerhk input device */ ++ acerhk_input_dev_ptr=input_allocate_device(); ++ /* enter some name */ ++ acerhk_input_dev_ptr->name = "Acer hotkey driver"; ++#else ++ acerhk_input_dev_ptr=&acerhk_input_dev; ++#endif ++ ++ /* some laptops have a mail led, should I announce it here? */ ++ acerhk_input_dev_ptr->evbit[0] = BIT(EV_KEY); ++ /* announce keys to input system ++ * the generated keys can be changed on runtime, ++ * but to publish those changes the device needs to ++ * get reconnected (I dont't know any other way) ++ * Therefore I enable all possible keys */ ++ for (i = KEY_RESERVED; i < BTN_MISC; i++) ++ set_bit(i, acerhk_input_dev_ptr->keybit); ++ /* set mapping keyname -> input event */ ++ init_keymap_input(); ++ if (verbose) ++ printk(KERN_INFO"acerhk: registered input device\n"); ++ input_register_device(acerhk_input_dev_ptr); ++ init_timer(&acerhk_timer_poll); ++ acerhk_polling_state = 0; ++} ++ ++static void stop_polling(void) ++{ ++ if (acerhk_polling_state == 1) { ++ del_timer(&acerhk_timer_poll); ++ if (verbose) ++ printk(KERN_INFO"acerhk: key polling stopped\n"); ++ acerhk_polling_state = 0; ++ } else ++ if (verbose) ++ printk(KERN_INFO"acerhk: key polling not active\n"); ++} ++ ++static void start_polling(void) ++{ ++ if (acerhk_polling_state != 1) { ++ acerhk_timer_poll.function = acerhk_poll_event; ++ acerhk_timer_poll.expires = jiffies + acerhk_polling_delay; ++ acerhk_timer_poll.data = get_nr_events(); ++ add_timer(&acerhk_timer_poll); ++ acerhk_polling_state = 1; ++ if (acerhk_type == TM_dritek) { ++ printk(KERN_INFO"acerhk: Your hardware does not need polling enabled for hotkeys to work, " ++ "you can safely disable polling by using the module parameter poll=0 (unless you " ++ "want to play around with the driver and see if there are buttons which need polling).\n"); ++ } ++ if (verbose) ++ printk(KERN_INFO"acerhk: starting key polling, every %d ms\n", acerhk_polling_delay); ++ } else ++ if (verbose) ++ printk(KERN_INFO"acerhk: key polling already active\n"); ++} ++ ++/* addedd by Antonio Cuni */ ++static void start_blinking(void) ++{ ++ if (acerhk_blueled_blinking == -1) { ++ // blinking was disabled... enable it! ++ acerhk_timer_blinking.function = acerhk_blink_event; ++ acerhk_timer_blinking.expires = jiffies + acerhk_blueled_blinking_delay; ++ acerhk_timer_blinking.data = 0; // not used ++ add_timer(&acerhk_timer_blinking); ++ acerhk_blueled_blinking = 0; ++ if (verbose) ++ printk(KERN_INFO "acerhk: starting blueled blinking\n"); ++ } else ++ if (verbose) ++ printk(KERN_INFO "acerhk: blueled already blinking\n"); ++} ++ ++/* Added by Antonio Cuni */ ++static void stop_blinking(void) ++{ ++ if (acerhk_blueled_blinking != -1) { ++ del_timer(&acerhk_timer_blinking); ++ if (verbose) ++ printk(KERN_INFO "acerhk: blueled blinking stopped\n"); ++ acerhk_blueled_blinking = -1; ++ } ++} ++ ++static void release_input(void) ++{ ++ stop_polling(); ++ input_unregister_device(acerhk_input_dev_ptr); ++} ++ ++/* }}} */ ++ ++/* {{{ procfs functions */ ++ ++#ifndef CONFIG_PROC_FS ++ ++static int acerhk_proc_init(void) ++{ ++ return 1; ++} ++#else ++ ++/* This macro frees the machine specific function from bounds checking and ++ * things like that... */ ++#define PRINT_PROC(fmt,args...) \ ++ do { \ ++ *len += sprintf( buffer+*len, fmt, ##args ); \ ++ if (*begin + *len > offset + size) \ ++ return( 0 ); \ ++ if (*begin + *len < offset) { \ ++ *begin += *len; \ ++ *len = 0; \ ++ } \ ++ } while(0) ++ ++static int pc_proc_infos( char *buffer, int *len, ++ off_t *begin, off_t offset, int size ) ++{ ++ PRINT_PROC( "Acer hotkeys version %s\n", ACERHK_VERSION); ++ PRINT_PROC( "Model(Type)\t: %s(", acerhk_model_string); ++ switch(acerhk_type) { ++ default: ++ PRINT_PROC( "unknown)\n"); ++ break; ++ case TM_old: ++ PRINT_PROC( "old)\n"); ++ break; ++ case TM_new: ++ PRINT_PROC( "new)\n"); ++ break; ++ case TM_dritek: ++ PRINT_PROC( "Dritek)\n"); ++ break; ++ } ++ if (bios_routine != 0) { ++ PRINT_PROC( "request handler\t: 0x%x\n", bios_routine); ++ if (cmos_index) { ++ PRINT_PROC( "CMOS index\t: 0x%x\n", cmos_index); ++ PRINT_PROC( "events pending\t: %u\n", get_nr_events()); ++ } else { ++ PRINT_PROC( "CMOS index\t: not available\n"); ++ } ++ if (acerhk_polling_state == 1) ++ PRINT_PROC( "kernel polling\t: active\n"); ++ else ++ PRINT_PROC( "kernel polling\t: inactive\n"); ++ PRINT_PROC( "autoswitch wlan\t: "); ++ if (autowlan == 1) ++ PRINT_PROC( "enabled\n"); ++ else ++ PRINT_PROC( "disabled\n"); ++ } else { ++ PRINT_PROC( "request handler\t: not found\n"); ++ PRINT_PROC( "kernel polling\t: not possible\n"); ++ } ++ /* model specific infos */ ++ if (acerhk_type == TM_dritek) { ++ PRINT_PROC( "use of Dritek EC: "); ++ if (usedritek) ++ PRINT_PROC( "enabled\n"); ++ else ++ PRINT_PROC( "disabled\n"); ++ } ++ if (acerhk_type == TM_old) ++ PRINT_PROC( "preg400\t\t: 0x%p\n", preg400); ++ return (1); ++} ++ ++static int acerhk_proc_info( char *buffer, char **start, off_t offset, ++ int size, int *eof, void *data ) ++{ ++ int len = 0; ++ off_t begin = 0; ++ ++ *eof = pc_proc_infos( buffer, &len, &begin, offset, size ); ++ ++ if (offset >= begin + len) ++ return( 0 ); ++ *start = buffer + (offset - begin); ++ return( size < begin + len - offset ? size : begin + len - offset ); ++ ++} ++ ++static int acerhk_proc_key( char *buffer, char **start, off_t offset, ++ int size, int *eof, void *data ) ++{ ++ if (size >= 5 && offset == 0) { ++ if (acerhk_type == TM_dritek || acerhk_polling_state == 1) { ++ snprintf(buffer+offset, size, "n/a\n"); ++ } else { ++ snprintf(buffer+offset, size, "0x%02x\n", filter_idle_value(get_fnkey_event())); ++ } ++ *eof = 1; ++ return 5; ++ } ++ *eof = 1; ++ return 0; ++} ++ ++static int acerhk_proc_led(struct file* file, const char* buffer, ++ unsigned long count, void* data) ++{ ++ char str[4]; ++ int len; ++ if (count > 4) ++ len = 4; ++ else ++ len = count; ++ if (copy_from_user(str, buffer, len)) ++ return -EFAULT; ++ str[3] = '\0'; ++ if ( ( (len >= 2) && (!strncmp(str, "on", 2) || !strncmp(str, "an", 2)) ) ++ || str[0] == '1') ++ set_mail_led(1); ++ else ++ set_mail_led(0); ++ return len; ++} ++ ++static int acerhk_proc_wirelessled(struct file* file, const char* buffer, ++ unsigned long count, void* data) ++{ ++ char str[4]; ++ int len; ++ if (count > 4) ++ len = 4; ++ else ++ len = count; ++ if (copy_from_user(str, buffer, len)) ++ return -EFAULT; ++ str[3] = '\0'; ++ if ( ( (len >= 2) && (!strncmp(str, "on", 2) || !strncmp(str, "an", 2)) ) ++ || str[0] == '1') { ++ if (acerhk_model_features & TM_F_WLAN_EC1) ++ enable_wlan_ec_1(); ++ else if (acerhk_model_features & TM_F_WLAN_EC2) ++ enable_wlan_ec_2(); ++ else ++ wbutton_fct_2(1); ++ } ++ else { ++ if (acerhk_model_features & TM_F_WLAN_EC1) ++ disable_wlan_ec_1(); ++ else if (acerhk_model_features & TM_F_WLAN_EC2) ++ disable_wlan_ec_2(); ++ else ++ wbutton_fct_2(0); ++ } ++ return len; ++} ++ ++ ++/* Modified by Antonio Cuni: added support for blinking ++ possible values: ++ - off, 0: led always off ++ - on, an, 1: led alway on ++ - n (a number): led blinking; n is the delay between ++ two changes of state, in jiffies; n must ++ be > 50, to prevent the user from overloading ++ the kernel. ++ ++ */ ++static int acerhk_proc_blueled(struct file* file, const char* buffer, ++ unsigned long count, void* data) ++{ ++ const int MAXLEN=11; ++ char str[MAXLEN]; ++ int len; ++ int isNumber; ++ ++ if (count > MAXLEN) ++ len = MAXLEN; ++ else ++ len = count; ++ if (copy_from_user(str, buffer, len)) ++ return -EFAULT; ++ str[MAXLEN - 1] = '\0'; ++ ++ /* try to parse a number */ ++ isNumber = sscanf(str, "%u", &acerhk_blueled_blinking_delay); ++ /* if the delay is 0, turn off the led */ ++ if (isNumber && acerhk_blueled_blinking_delay != 0 && acerhk_blueled_blinking_delay != 1) { ++ if (acerhk_blueled_blinking_delay < 50) ++ printk(KERN_INFO"acerhk: blinking request rejected. The delay must be > 50.\n"); ++ else { ++ if (verbose) ++ printk(KERN_INFO"acerhk: blinking delay set to %u.\n", acerhk_blueled_blinking_delay); ++ start_blinking(); ++ } ++ } else if (acerhk_blueled_blinking_delay == 1 || !strncmp(str, "on", 2) || !strncmp(str, "an", 2)) { ++ stop_blinking(); ++ if (acerhk_model_features & TM_F_BLUE_EC1) ++ enable_bluetooth_ec_1(); ++ else if (acerhk_model_features & TM_F_BLUE_EC2) ++ enable_bluetooth_ec_2(); ++ else ++ wbutton_fct_1(1); ++ } else { ++ /* it's 0 or everything else */ ++ stop_blinking(); ++ if (acerhk_model_features & TM_F_BLUE_EC1) ++ disable_bluetooth_ec_1(); ++ else if (acerhk_model_features & TM_F_BLUE_EC2) ++ disable_bluetooth_ec_2(); ++ else ++ wbutton_fct_1(0); ++ } ++ return len; ++} ++ ++#ifdef ACERDEBUG ++static void do_debug(const char* buffer, unsigned long len) ++{ ++ unsigned int h, i; ++ switch (buffer[0]) { ++ case 'b': ++ /* test WLAN on TM 4001 */ ++ switch (buffer[1]) { ++ case '0': ++ disable_wlan_ec_1(); ++ break; ++ case '1': ++ default: ++ enable_wlan_ec_1(); ++ } ++ break; ++ case 'B': ++ /* test BLUETOOTH on TM 4001 */ ++ switch (buffer[1]) { ++ case '0': ++ disable_bluetooth_ec_1(); ++ break; ++ case '1': ++ default: ++ enable_bluetooth_ec_1(); ++ } ++ break; ++ case 'D': ++ /* test "DMM Function Enabled" entry of TM 4150/4650 */ ++ enable_dmm_function(); ++ break; ++ case 'i': ++ case '1': ++#ifndef KERNEL26 ++ MOD_INC_USE_COUNT; ++#endif ++ break; ++ case 'e': ++ switch (buffer[1]) { ++ case '1': ++ start_polling(); ++ break; ++ default: ++ stop_polling(); ++ } ++ break; ++ case 'k': ++ for (i = 0; i <= 255;i++) { ++ input_report_key(acerhk_input_dev_ptr, i, 1); ++ input_report_key(acerhk_input_dev_ptr, i, 0); ++ } ++ break; ++ case 'm': ++ /* set mapping key names -> input events */ ++ sscanf(&buffer[2],"%x", &i); ++ h = buffer[1] - '0' + 1; ++ printk("acerhk: key name %x maps to %x\n", h, i); ++ acerhk_name2event[h] = i; ++ break; ++ case 'M': ++ /* test mute LED on dritek hardware */ ++ switch (buffer[1]) { ++ case '0': ++ disable_mute_led_ec(); ++ break; ++ case '1': ++ default: ++ enable_mute_led_ec(); ++ } ++ break; ++ case 'p': ++ printk("acerhk: pbutton = 0x%x\n", pbutton_fct()); ++ break; ++ case 's': ++ /* send key event to test the key translation in input system */ ++ sscanf(&buffer[1],"%x", &h); ++ printk("acerhk: sending key event 0x%x\n", h); ++ input_report_key(acerhk_input_dev_ptr, h, 1); ++ input_report_key(acerhk_input_dev_ptr, h, 0); ++ break; ++ case 'S': ++ /* simulate key codes to test the key translation in acerhk */ ++ sscanf(&buffer[1],"%x", &h); ++ send_key_event(transl8_key_code(h)); ++ break; ++ case 't': ++ printk("acerhk: thermal event = 0x%x\n", get_thermal_event()); ++ break; ++ case 'w': ++ /* test the wbutton functions, someone really needs to have another look ++ at the windows driver */ ++ switch (buffer[1]) { ++ case '2': ++ printk("acerhk: wbutton_2(%d) = 0x%x\n", buffer[2]-'0', wbutton_fct_2(buffer[2]-'0')); ++ break; ++ case '1': ++ default: ++ printk("acerhk: wbutton_1(%d) = 0x%x\n", buffer[2]-'0', wbutton_fct_1(buffer[2]-'0')); ++ } ++ break; ++ case 'W': ++ /* test wireless HW/LED on some models using dritek hardware */ ++ switch (buffer[1]) { ++ case '0': ++ disable_wireless_ec(); ++ break; ++ case '1': ++ default: ++ enable_wireless_ec(); ++ } ++ break; ++ case 'v': ++ verbose = buffer[1]-'0'; ++ printk("acerhk: verbosity level changed to %d\n", verbose); ++ break; ++ case 'd': ++ case '0': ++ default: ++#ifndef KERNEL26 ++ MOD_DEC_USE_COUNT; ++#endif ++ break; ++ } ++} ++ ++static int acerhk_proc_debug(struct file* file, const char* buffer, ++ unsigned long count, void* data) ++{ ++ char str[5]; ++ int len; ++ if (count > 5) ++ len = 5; ++ else ++ len = count; ++ if (copy_from_user(str, buffer, len)) ++ return -EFAULT; ++ str[4] = '\0'; ++ do_debug(str, len); ++ return len; ++} ++#endif ++ ++static int acerhk_proc_init(void) ++{ ++ int retval; ++ struct proc_dir_entry *entry; ++ /* create own directory */ ++ proc_acer_dir = proc_mkdir("driver/acerhk", NULL); ++ if (proc_acer_dir == NULL) { ++ retval = 0; ++ printk(KERN_INFO"acerhk: could not create /proc/driver/acerhk\n"); ++ } ++ else { ++ proc_acer_dir->owner = THIS_MODULE; ++ /* now create several files, first general info ... */ ++ entry = create_proc_read_entry("info", ++ 0444, proc_acer_dir, acerhk_proc_info, NULL); ++ if (entry == NULL) { ++ printk(KERN_INFO"acerhk: cannot create info file\n"); ++ remove_proc_entry("driver/acerhk", NULL); ++ retval = 0; ++ } else { ++ entry->owner = THIS_MODULE; ++ /* ... last pressed key ... */ ++ entry = create_proc_read_entry("key", ++ 0444, proc_acer_dir, acerhk_proc_key, NULL); ++ if (entry == NULL) { ++ printk(KERN_INFO"acerhk: cannot create key file\n"); ++ remove_proc_entry("info", proc_acer_dir); ++ remove_proc_entry("driver/acerhk", NULL); ++ retval = 0; ++ } else { ++ entry->owner = THIS_MODULE; ++ /* ... and led control file */ ++ entry = create_proc_entry("led", 0222, proc_acer_dir); ++ if (entry == NULL) { ++ printk(KERN_INFO"acerhk: cannot create LED file\n"); ++ remove_proc_entry("info", proc_acer_dir); ++ remove_proc_entry("key", proc_acer_dir); ++ remove_proc_entry("driver/acerhk", NULL); ++ retval = 0; ++ } ++ else { ++ entry->write_proc = acerhk_proc_led; ++ entry->owner = THIS_MODULE; ++ /* ... and wireless led controll file */ ++ entry = create_proc_entry("wirelessled", 0222, proc_acer_dir); ++ if (entry == NULL) { ++ printk(KERN_INFO"acerhk: cannot create wirelessled file\n"); ++ remove_proc_entry("info", proc_acer_dir); ++ remove_proc_entry("key", proc_acer_dir); ++ remove_proc_entry("led", proc_acer_dir); ++ remove_proc_entry("driver/acerhk", NULL); ++ retval = 0; ++ } ++ else { ++ entry->write_proc = acerhk_proc_wirelessled; ++ entry->owner = THIS_MODULE; ++ /* ... and bluetooth led controll file */ ++ entry = create_proc_entry("blueled", 0222, proc_acer_dir); ++ if (entry == NULL) { ++ printk(KERN_INFO"acerhk: cannot create blueled file\n"); ++ remove_proc_entry("info", proc_acer_dir); ++ remove_proc_entry("key", proc_acer_dir); ++ remove_proc_entry("led", proc_acer_dir); ++ remove_proc_entry("wirelessled", proc_acer_dir); ++ remove_proc_entry("driver/acerhk", NULL); ++ retval = 0; ++ } else { ++ entry->write_proc = acerhk_proc_blueled; ++ entry->owner = THIS_MODULE; ++ retval = 1; ++#ifdef ACERDEBUG ++ /* add extra file for debugging purposes */ ++ entry = create_proc_entry("debug", 0222, proc_acer_dir); ++ if (entry == NULL) { ++ printk(KERN_INFO"acerhk: cannot create debug file\n"); ++ remove_proc_entry("info", proc_acer_dir); ++ remove_proc_entry("key", proc_acer_dir); ++ remove_proc_entry("led", proc_acer_dir); ++ remove_proc_entry("wirelessled", proc_acer_dir); ++ remove_proc_entry("blueled", proc_acer_dir); ++ remove_proc_entry("driver/acerhk", NULL); ++ retval = 0; ++ } ++ else { ++ entry->write_proc = acerhk_proc_debug; ++ entry->owner = THIS_MODULE; ++ retval = 1; ++ } ++#endif ++ } ++ } ++ } ++ } ++ } ++ } ++ return retval; ++} ++ ++static void acerhk_proc_cleanup(void) ++{ ++ if (proc_acer_dir) { ++ remove_proc_entry("info", proc_acer_dir); ++ /* On dritek type hardware key file is already removed */ ++ if (acerhk_type != TM_dritek) ++ remove_proc_entry("key", proc_acer_dir); ++ remove_proc_entry("led", proc_acer_dir); ++ remove_proc_entry("wirelessled", proc_acer_dir); ++ remove_proc_entry("blueled", proc_acer_dir); ++#ifdef ACERDEBUG ++ remove_proc_entry("debug", proc_acer_dir); ++#endif ++ remove_proc_entry("driver/acerhk", NULL); ++ proc_acer_dir = NULL; ++ } ++} ++ ++#endif /* CONFIG_PROC_FS */ ++ ++/* }}} */ ++ ++/* {{{ file operations */ ++ ++static int acerhk_ioctl( struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg ) ++{ ++ int retval; ++ switch( cmd ) { ++ case ACERHK_GET_KEYCOUNT: ++ { ++ char nr; ++ nr = get_nr_events(); ++ put_user(nr, (char*)arg); ++ retval = 0; ++ break; ++ } ++ case ACERHK_GET_KEYID: ++ { ++ char id; ++ id = get_fnkey_event(); ++ put_user(id, (char*)arg); ++ retval = 0; ++ break; ++ } ++ case ACERHK_CONNECT: ++ launch_connect(1); ++ retval = 0; ++ break; ++ case ACERHK_START_POLLING: ++ start_polling(); ++ retval = 0; ++ break; ++ case ACERHK_STOP_POLLING: ++ stop_polling(); ++ retval = 0; ++ break; ++ case ACERHK_DISCONNECT: ++ launch_connect(0); ++ retval = 0; ++ break; ++ case ACERHK_GET_THERMAL_EVENT: ++ { ++ short event; ++ event = get_thermal_event(); ++ put_user(event, (short*)arg); ++ retval = 0; ++ break; ++ } ++ case ACERHK_MAIL_LED_OFF: ++ set_mail_led(0); ++ retval = 0; ++ break; ++ case ACERHK_MAIL_LED_ON: ++ set_mail_led(1); ++ retval = 0; ++ break; ++ case ACERHK_GET_KEY_MAP: ++ if (copy_to_user((t_map_name2event*)arg, &acerhk_name2event, sizeof(acerhk_name2event))) ++ retval = -EFAULT; ++ else ++ retval = 0; ++ break; ++ case ACERHK_SET_KEY_MAP: ++ if (copy_from_user(&acerhk_name2event, (t_map_name2event*)arg, sizeof(acerhk_name2event))) ++ retval = -EFAULT; ++ else { ++ if (verbose) { ++ printk(KERN_INFO"acerhk: changed key mapping\n"); ++ print_mapping(); ++ } ++ retval = 0; ++ } ++ break; ++ default: ++ retval = -EINVAL; ++ } ++ return retval; ++} ++ ++#ifdef ACERDEBUG ++static ssize_t acerhk_write (struct file* file, const char* buffer, size_t length, loff_t* offset) ++{ ++ if (length) ++ do_debug(buffer, length); ++ return length; ++} ++#endif ++ ++static int acerhk_open( struct inode *inode, struct file *file ) ++{ ++ return 0; ++} ++ ++static int acerhk_release( struct inode *inode, struct file *file ) ++{ ++ return 0; ++} ++ ++static struct file_operations acerhk_fops = { ++ owner: THIS_MODULE, ++ ioctl: acerhk_ioctl, ++ open: acerhk_open, ++#ifdef ACERDEBUG ++ write: acerhk_write, ++#endif ++ release: acerhk_release, ++}; ++ ++static struct miscdevice acerhk_dev = { ++ MISC_DYNAMIC_MINOR, ++ "acerhk", ++ &acerhk_fops ++}; ++ ++/* }}} */ ++ ++static void __init model_init(void) ++{ ++ /* set callroutine, features and keymap for model */ ++ setup_model_features(acerhk_series); ++ /* override initial state of wireless hardware if specified by module options */ ++ if (wlan_state >= 0) acerhk_wlan_state = wlan_state; ++ if (bluetooth_state >= 0) acerhk_bluetooth_state = bluetooth_state; ++ /* Launch connect only if available */ ++ if (acerhk_model_features & TM_F_CONNECT) { ++ if (verbose) ++ printk(KERN_INFO"acerhk: Model type %d, calling launch_connect(1)\n", ++ acerhk_type); ++ launch_connect(1); ++ } ++ if ( acerhk_type != TM_dritek ) { ++ get_cmos_index(); ++ } ++ if ( acerhk_type == TM_dritek ) { ++ enable_dritek_keyboard(); ++ } ++ /* added by Antonio Cuni */ ++ init_timer(&acerhk_timer_blinking); ++} ++ ++ ++static void __exit acerhk_cleanup_module (void); ++static int __init acerhk_init(void) ++{ ++ int ret; ++ ++ ret = misc_register( &acerhk_dev ); ++ if (ret) { ++ printk(KERN_ERR "acerhk: can't misc_register on minor=%d\n", ACERHK_MINOR); ++ ret = -EAGAIN; ++ } ++ else if (!acerhk_proc_init()) { ++ printk(KERN_ERR "acerhk: can't create procfs entries\n"); ++ ret = -ENOMEM; ++ misc_deregister( &acerhk_dev ); ++ } ++ else { ++ reg1 = ioremap(0xf0000, 0xffff); ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: area from 0xf000 to 0xffff mapped to %p\n", reg1); ++ reg2 = ioremap(0xe0000, 0xffff); ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: area from 0xe000 to 0xffff mapped to %p\n", reg2); ++ /* the area 0x400 is used as data area by earlier (520) series */ ++ preg400 = ioremap(0x400, 0xfff); ++ if (verbose > 1) ++ printk(KERN_INFO"acerhk: area from 0x400 to 0x13ff mapped to %p\n", preg400); ++ /* attach to input system */ ++ init_input(); ++ memset(acerhk_model_string, 0x00, ACERHK_MODEL_STRLEN); ++#ifdef DUMMYHW ++ acerhk_model_addr = (void*)0x12345678; ++ /* copy the string, but not more than 15 characters */ ++ strncpy(acerhk_model_string, "TravelmateDummy", ACERHK_MODEL_STRLEN-1); ++ /* set callroutine for model */ ++ if (force_series) ++ acerhk_series = force_series; ++ else ++ acerhk_series = 2000; ++ setup_model_features(acerhk_series); ++ printk(KERN_INFO "Acer Travelmate hotkey driver v" ACERHK_VERSION " dummy\n"); ++ if ( acerhk_type == TM_dritek ) ++ enable_dritek_keyboard(); ++ if (poll) ++ start_polling(); ++ init_timer(&acerhk_timer_blinking); ++#else ++ bios_routine = find_hk_area(); ++ if (!force_series) ++ probe_model(); ++ else { ++ if (verbose) ++ printk(KERN_INFO"acerhk: forced laptop series to %d\n", force_series); ++ acerhk_series = force_series; ++ } ++ /* do model specific initialization */ ++ model_init(); ++ /* Without a bios routine we cannot do anything except on dritek ++ type HW, unload on other types */ ++ if (bios_routine || (acerhk_type == TM_dritek)) { ++ ret = 0; ++ if (verbose && bios_routine) ++ printk(KERN_INFO"acerhk: bios routine found at 0x%x\n", bios_routine); ++ printk(KERN_INFO "Acer Travelmate hotkey driver v" ACERHK_VERSION "\n"); ++ /* If automatic switching of wlan is wanted but polling is disabled, ++ automatically enable it */ ++ if (!poll && autowlan) { ++ printk(KERN_INFO "Automatic switching of wireless hardware needs polling, enabling it\n"); ++ poll = 1; ++ } ++ /* start automatic polling of key presses if wanted and bios routine found */ ++ if (poll && bios_routine) ++ start_polling(); ++ } else { ++ printk(KERN_ERR "acerhk: can't find bios routine, cannot do anything for you, sorry!\n"); ++ ret = -ENOMEM; ++ acerhk_cleanup_module(); ++ } ++#endif ++ } ++ return ret; ++} ++ ++static void __exit acerhk_cleanup_module (void) ++{ ++ acerhk_proc_cleanup(); ++ stop_blinking(); ++ if (reg1) ++ iounmap(reg1); ++ if (reg2) ++ iounmap(reg2); ++ if (preg400) ++ iounmap(preg400); ++ release_input(); ++ misc_deregister( &acerhk_dev ); ++ if ( acerhk_type == TM_dritek ) { ++ disable_dritek_keyboard(); ++ } ++ if (verbose > 2) ++ printk(KERN_INFO "acerhk: unloaded\n"); ++} ++ ++module_init(acerhk_init); ++module_exit(acerhk_cleanup_module); ++ ++MODULE_AUTHOR("Olaf Tauber"); ++MODULE_DESCRIPTION("AcerHotkeys extra buttons keyboard driver"); ++MODULE_LICENSE("GPL"); ++ ++#ifndef KERNEL26 ++EXPORT_NO_SYMBOLS; ++#endif ++ ++#else ++#error This driver is only available for X86 architecture ++#endif ++/* ++ * Local variables: ++ * c-indent-level: 4 ++ * tab-width: 4 ++ * End: ++ */ ++ +diff -Nurp linux-2.6.37/3rdparty/acerhk/acerhk.h linux-2.6.37.3rdparty/3rdparty/acerhk/acerhk.h +--- linux-2.6.37/3rdparty/acerhk/acerhk.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/acerhk/acerhk.h 2005-06-17 00:10:12.000000000 +0300 +@@ -0,0 +1,91 @@ ++#ifndef __ACERHK_H__ ++#define __ACERHK_H__ ++ ++#include ++ ++#define ACERHK_MINOR MISC_DYNAMIC_MINOR ++ ++#define ACERHK_GET_KEYCOUNT _IOR('p', 0x01, char) /* Get number of cached key presses */ ++#define ACERHK_GET_KEYID _IOR('p', 0x02, char) /* Get first key in queue */ ++#define ACERHK_CONNECT _IO('p', 0x03) /* ? */ ++#define ACERHK_DISCONNECT _IO('p', 0x04) /* ? */ ++#define ACERHK_GET_THERMAL_EVENT _IOR('p', 0x05, short) /* ? */ ++#define ACERHK_MAIL_LED_OFF _IO('p', 0x10) /* switch mail LED off */ ++#define ACERHK_MAIL_LED_ON _IO('p', 0x11) /* switch mail LED on (blinking) */ ++#define ACERHK_START_POLLING _IO('p', 0x12) /* poll keys in kernel, send real key events */ ++#define ACERHK_STOP_POLLING _IO('p', 0x13) /* stop key polling in kernel */ ++#define ACERHK_GET_KEY_MAP _IOR('p', 0x20, int) /* Get mapping of key names to key events, */ ++#define ACERHK_SET_KEY_MAP _IOW('p', 0x21, int) /* Set mapping of key names to key events */ ++ ++/* all possible keys (known to me) */ ++typedef enum e_key_names { ++ k_none = 0, ++ k_help = 1, /* Fn+F1 */ ++ k_setup = 2, /* Fn+F2 */ ++ k_p1 = 3, ++ k_p2 = 4, ++ k_p3 = 5, ++ k_www = 6, ++ k_mail = 7, ++ k_wireless = 8, ++ k_power = 9, /* Fn+F3 */ ++ k_mute = 10, /* Fn+F8 */ ++ k_volup = 11, /* Fn+Up */ ++ k_voldn = 12, /* Fn+Down */ ++ k_res = 13, /* resolution change on Medion MD 40100 */ ++ k_close = 14, /* if lid is closed in tablet mode */ ++ k_open = 15, /* if lid is opend in tablet mode */ ++ k_wireless2 = 16, /* second wireless button on TM 243LC */ ++ k_play = 17, /* Play/Pause found on AOpen */ ++ k_stop = 18, /* Stop/Eject found on AOpen */ ++ k_prev = 19, /* Prev found on AOpen */ ++ k_next = 20, /* Next found on AOpen */ ++ k_display = 21 /* Change internal/external display on MD 42200 */ ++} t_key_names; ++#define NR_KEY_NAMES 22 ++typedef unsigned int t_map_name2event[NR_KEY_NAMES]; ++ ++#ifdef __KERNEL__ ++ ++/* available features */ ++#define TM_F_WLAN_EC1 0x00000010 ++#define TM_F_BLUE_EC1 0x00000020 ++#define TM_F_WLAN_EC2 0x00000040 ++#define TM_F_BLUE_EC2 0x00000080 ++#define TM_F_MUTE_LED_EC 0x00001000 ++#define TM_F_MAIL_LED 0x00010000 ++#define TM_F_MAIL_LED_EC 0x00020000 ++#define TM_F_MAIL_LED_EC2 0x00040000 ++#define TM_F_MAIL_LED_EC3 0x00080000 ++ ++#define TM_F_CONNECT 0x00100000 ++#define TM_F_THERMAL 0x00200000 ++#define TM_F_PBUTTON 0x00400000 ++#define TM_F_WBUTTON 0x00800000 ++ ++typedef enum acer_type { ++ TM_unknown, ++ /* 200, 210, 520, 600 and 730 series, Medion MD42200 */ ++ TM_old, ++ /* C100, C110, 220, 230, 240, 260, 350, 360, 610, 620, 630, 740 series ++ Medion MD40100, Aspire 1600, FS Amilo */ ++ TM_new, ++ /* Aspire 13xx, 14xx, 1700, TM 290, 650, 660, 800 */ ++ TM_dritek ++} t_acer_type; ++ ++struct register_buffer { ++ unsigned int eax; ++ unsigned int ebx; ++ unsigned int ecx; ++ unsigned int edx; ++ unsigned int edi; ++ unsigned int esi; ++ unsigned int ebp; ++}; ++ ++typedef asmlinkage void (*bios_call) (struct register_buffer *); ++ ++#endif ++ ++#endif +diff -Nurp linux-2.6.37/3rdparty/acerhk/AUTHORS linux-2.6.37.3rdparty/3rdparty/acerhk/AUTHORS +--- linux-2.6.37/3rdparty/acerhk/AUTHORS 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/acerhk/AUTHORS 2006-11-10 00:02:55.000000000 +0200 +@@ -0,0 +1 @@ ++Olaf Tauber +\ Ingen nyrad vid filslut +diff -Nurp linux-2.6.37/3rdparty/acerhk/COPYING linux-2.6.37.3rdparty/3rdparty/acerhk/COPYING +--- linux-2.6.37/3rdparty/acerhk/COPYING 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/acerhk/COPYING 2002-05-08 22:01:52.000000000 +0300 +@@ -0,0 +1,340 @@ ++ GNU GENERAL PUBLIC LICENSE ++ Version 2, June 1991 ++ ++ Copyright (C) 1989, 1991 Free Software Foundation, Inc. ++ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ Everyone is permitted to copy and distribute verbatim copies ++ of this license document, but changing it is not allowed. ++ ++ Preamble ++ ++ The licenses for most software are designed to take away your ++freedom to share and change it. By contrast, the GNU General Public ++License is intended to guarantee your freedom to share and change free ++software--to make sure the software is free for all its users. This ++General Public License applies to most of the Free Software ++Foundation's software and to any other program whose authors commit to ++using it. (Some other Free Software Foundation software is covered by ++the GNU Library General Public License instead.) You can apply it to ++your programs, too. ++ ++ When we speak of free software, we are referring to freedom, not ++price. Our General Public Licenses are designed to make sure that you ++have the freedom to distribute copies of free software (and charge for ++this service if you wish), that you receive source code or can get it ++if you want it, that you can change the software or use pieces of it ++in new free programs; and that you know you can do these things. ++ ++ To protect your rights, we need to make restrictions that forbid ++anyone to deny you these rights or to ask you to surrender the rights. ++These restrictions translate to certain responsibilities for you if you ++distribute copies of the software, or if you modify it. ++ ++ For example, if you distribute copies of such a program, whether ++gratis or for a fee, you must give the recipients all the rights that ++you have. You must make sure that they, too, receive or can get the ++source code. And you must show them these terms so they know their ++rights. ++ ++ We protect your rights with two steps: (1) copyright the software, and ++(2) offer you this license which gives you legal permission to copy, ++distribute and/or modify the software. ++ ++ Also, for each author's protection and ours, we want to make certain ++that everyone understands that there is no warranty for this free ++software. If the software is modified by someone else and passed on, we ++want its recipients to know that what they have is not the original, so ++that any problems introduced by others will not reflect on the original ++authors' reputations. ++ ++ Finally, any free program is threatened constantly by software ++patents. We wish to avoid the danger that redistributors of a free ++program will individually obtain patent licenses, in effect making the ++program proprietary. To prevent this, we have made it clear that any ++patent must be licensed for everyone's free use or not licensed at all. ++ ++ The precise terms and conditions for copying, distribution and ++modification follow. ++ ++ GNU GENERAL PUBLIC LICENSE ++ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION ++ ++ 0. This License applies to any program or other work which contains ++a notice placed by the copyright holder saying it may be distributed ++under the terms of this General Public License. The "Program", below, ++refers to any such program or work, and a "work based on the Program" ++means either the Program or any derivative work under copyright law: ++that is to say, a work containing the Program or a portion of it, ++either verbatim or with modifications and/or translated into another ++language. (Hereinafter, translation is included without limitation in ++the term "modification".) Each licensee is addressed as "you". ++ ++Activities other than copying, distribution and modification are not ++covered by this License; they are outside its scope. The act of ++running the Program is not restricted, and the output from the Program ++is covered only if its contents constitute a work based on the ++Program (independent of having been made by running the Program). ++Whether that is true depends on what the Program does. ++ ++ 1. You may copy and distribute verbatim copies of the Program's ++source code as you receive it, in any medium, provided that you ++conspicuously and appropriately publish on each copy an appropriate ++copyright notice and disclaimer of warranty; keep intact all the ++notices that refer to this License and to the absence of any warranty; ++and give any other recipients of the Program a copy of this License ++along with the Program. ++ ++You may charge a fee for the physical act of transferring a copy, and ++you may at your option offer warranty protection in exchange for a fee. ++ ++ 2. You may modify your copy or copies of the Program or any portion ++of it, thus forming a work based on the Program, and copy and ++distribute such modifications or work under the terms of Section 1 ++above, provided that you also meet all of these conditions: ++ ++ a) You must cause the modified files to carry prominent notices ++ stating that you changed the files and the date of any change. ++ ++ b) You must cause any work that you distribute or publish, that in ++ whole or in part contains or is derived from the Program or any ++ part thereof, to be licensed as a whole at no charge to all third ++ parties under the terms of this License. ++ ++ c) If the modified program normally reads commands interactively ++ when run, you must cause it, when started running for such ++ interactive use in the most ordinary way, to print or display an ++ announcement including an appropriate copyright notice and a ++ notice that there is no warranty (or else, saying that you provide ++ a warranty) and that users may redistribute the program under ++ these conditions, and telling the user how to view a copy of this ++ License. (Exception: if the Program itself is interactive but ++ does not normally print such an announcement, your work based on ++ the Program is not required to print an announcement.) ++ ++These requirements apply to the modified work as a whole. If ++identifiable sections of that work are not derived from the Program, ++and can be reasonably considered independent and separate works in ++themselves, then this License, and its terms, do not apply to those ++sections when you distribute them as separate works. But when you ++distribute the same sections as part of a whole which is a work based ++on the Program, the distribution of the whole must be on the terms of ++this License, whose permissions for other licensees extend to the ++entire whole, and thus to each and every part regardless of who wrote it. ++ ++Thus, it is not the intent of this section to claim rights or contest ++your rights to work written entirely by you; rather, the intent is to ++exercise the right to control the distribution of derivative or ++collective works based on the Program. ++ ++In addition, mere aggregation of another work not based on the Program ++with the Program (or with a work based on the Program) on a volume of ++a storage or distribution medium does not bring the other work under ++the scope of this License. ++ ++ 3. You may copy and distribute the Program (or a work based on it, ++under Section 2) in object code or executable form under the terms of ++Sections 1 and 2 above provided that you also do one of the following: ++ ++ a) Accompany it with the complete corresponding machine-readable ++ source code, which must be distributed under the terms of Sections ++ 1 and 2 above on a medium customarily used for software interchange; or, ++ ++ b) Accompany it with a written offer, valid for at least three ++ years, to give any third party, for a charge no more than your ++ cost of physically performing source distribution, a complete ++ machine-readable copy of the corresponding source code, to be ++ distributed under the terms of Sections 1 and 2 above on a medium ++ customarily used for software interchange; or, ++ ++ c) Accompany it with the information you received as to the offer ++ to distribute corresponding source code. (This alternative is ++ allowed only for noncommercial distribution and only if you ++ received the program in object code or executable form with such ++ an offer, in accord with Subsection b above.) ++ ++The source code for a work means the preferred form of the work for ++making modifications to it. For an executable work, complete source ++code means all the source code for all modules it contains, plus any ++associated interface definition files, plus the scripts used to ++control compilation and installation of the executable. However, as a ++special exception, the source code distributed need not include ++anything that is normally distributed (in either source or binary ++form) with the major components (compiler, kernel, and so on) of the ++operating system on which the executable runs, unless that component ++itself accompanies the executable. ++ ++If distribution of executable or object code is made by offering ++access to copy from a designated place, then offering equivalent ++access to copy the source code from the same place counts as ++distribution of the source code, even though third parties are not ++compelled to copy the source along with the object code. ++ ++ 4. You may not copy, modify, sublicense, or distribute the Program ++except as expressly provided under this License. Any attempt ++otherwise to copy, modify, sublicense or distribute the Program is ++void, and will automatically terminate your rights under this License. ++However, parties who have received copies, or rights, from you under ++this License will not have their licenses terminated so long as such ++parties remain in full compliance. ++ ++ 5. You are not required to accept this License, since you have not ++signed it. However, nothing else grants you permission to modify or ++distribute the Program or its derivative works. These actions are ++prohibited by law if you do not accept this License. Therefore, by ++modifying or distributing the Program (or any work based on the ++Program), you indicate your acceptance of this License to do so, and ++all its terms and conditions for copying, distributing or modifying ++the Program or works based on it. ++ ++ 6. Each time you redistribute the Program (or any work based on the ++Program), the recipient automatically receives a license from the ++original licensor to copy, distribute or modify the Program subject to ++these terms and conditions. You may not impose any further ++restrictions on the recipients' exercise of the rights granted herein. ++You are not responsible for enforcing compliance by third parties to ++this License. ++ ++ 7. If, as a consequence of a court judgment or allegation of patent ++infringement or for any other reason (not limited to patent issues), ++conditions are imposed on you (whether by court order, agreement or ++otherwise) that contradict the conditions of this License, they do not ++excuse you from the conditions of this License. If you cannot ++distribute so as to satisfy simultaneously your obligations under this ++License and any other pertinent obligations, then as a consequence you ++may not distribute the Program at all. For example, if a patent ++license would not permit royalty-free redistribution of the Program by ++all those who receive copies directly or indirectly through you, then ++the only way you could satisfy both it and this License would be to ++refrain entirely from distribution of the Program. ++ ++If any portion of this section is held invalid or unenforceable under ++any particular circumstance, the balance of the section is intended to ++apply and the section as a whole is intended to apply in other ++circumstances. ++ ++It is not the purpose of this section to induce you to infringe any ++patents or other property right claims or to contest validity of any ++such claims; this section has the sole purpose of protecting the ++integrity of the free software distribution system, which is ++implemented by public license practices. Many people have made ++generous contributions to the wide range of software distributed ++through that system in reliance on consistent application of that ++system; it is up to the author/donor to decide if he or she is willing ++to distribute software through any other system and a licensee cannot ++impose that choice. ++ ++This section is intended to make thoroughly clear what is believed to ++be a consequence of the rest of this License. ++ ++ 8. If the distribution and/or use of the Program is restricted in ++certain countries either by patents or by copyrighted interfaces, the ++original copyright holder who places the Program under this License ++may add an explicit geographical distribution limitation excluding ++those countries, so that distribution is permitted only in or among ++countries not thus excluded. In such case, this License incorporates ++the limitation as if written in the body of this License. ++ ++ 9. The Free Software Foundation may publish revised and/or new versions ++of the General Public License from time to time. Such new versions will ++be similar in spirit to the present version, but may differ in detail to ++address new problems or concerns. ++ ++Each version is given a distinguishing version number. If the Program ++specifies a version number of this License which applies to it and "any ++later version", you have the option of following the terms and conditions ++either of that version or of any later version published by the Free ++Software Foundation. If the Program does not specify a version number of ++this License, you may choose any version ever published by the Free Software ++Foundation. ++ ++ 10. If you wish to incorporate parts of the Program into other free ++programs whose distribution conditions are different, write to the author ++to ask for permission. For software which is copyrighted by the Free ++Software Foundation, write to the Free Software Foundation; we sometimes ++make exceptions for this. Our decision will be guided by the two goals ++of preserving the free status of all derivatives of our free software and ++of promoting the sharing and reuse of software generally. ++ ++ NO WARRANTY ++ ++ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY ++FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN ++OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES ++PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED ++OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS ++TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE ++PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, ++REPAIR OR CORRECTION. ++ ++ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING ++WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR ++REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, ++INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING ++OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED ++TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY ++YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER ++PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE ++POSSIBILITY OF SUCH DAMAGES. ++ ++ END OF TERMS AND CONDITIONS ++ ++ How to Apply These Terms to Your New Programs ++ ++ If you develop a new program, and you want it to be of the greatest ++possible use to the public, the best way to achieve this is to make it ++free software which everyone can redistribute and change under these terms. ++ ++ To do so, attach the following notices to the program. It is safest ++to attach them to the start of each source file to most effectively ++convey the exclusion of warranty; and each file should have at least ++the "copyright" line and a pointer to where the full notice is found. ++ ++ ++ Copyright (C) 19yy ++ ++ 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. ++ ++ 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 ++ ++ ++Also add information on how to contact you by electronic and paper mail. ++ ++If the program is interactive, make it output a short notice like this ++when it starts in an interactive mode: ++ ++ Gnomovision version 69, Copyright (C) 19yy name of author ++ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. ++ This is free software, and you are welcome to redistribute it ++ under certain conditions; type `show c' for details. ++ ++The hypothetical commands `show w' and `show c' should show the appropriate ++parts of the General Public License. Of course, the commands you use may ++be called something other than `show w' and `show c'; they could even be ++mouse-clicks or menu items--whatever suits your program. ++ ++You should also get your employer (if you work as a programmer) or your ++school, if any, to sign a "copyright disclaimer" for the program, if ++necessary. Here is a sample; alter the names: ++ ++ Yoyodyne, Inc., hereby disclaims all copyright interest in the program ++ `Gnomovision' (which makes passes at compilers) written by James Hacker. ++ ++ , 1 April 1989 ++ Ty Coon, President of Vice ++ ++This General Public License does not permit incorporating your program into ++proprietary programs. If your program is a subroutine library, you may ++consider it more useful to permit linking proprietary applications with the ++library. If this is what you want to do, use the GNU Library General ++Public License instead of this License. +diff -Nurp linux-2.6.37/3rdparty/acerhk/doc/acertm.def linux-2.6.37.3rdparty/3rdparty/acerhk/doc/acertm.def +--- linux-2.6.37/3rdparty/acerhk/doc/acertm.def 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/acerhk/doc/acertm.def 2003-08-24 19:46:37.000000000 +0300 +@@ -0,0 +1,56 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ Konfiguration ++ ++ Mute/Unmute ++ Lauter ++ Leiser ++ ++ Terminal ++ XEmacs ++ Play/Pause ++ Play/Pause ++ ++ ++ ++ +diff -Nurp linux-2.6.37/3rdparty/acerhk/doc/FAQ linux-2.6.37.3rdparty/3rdparty/acerhk/doc/FAQ +--- linux-2.6.37/3rdparty/acerhk/doc/FAQ 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/acerhk/doc/FAQ 2005-11-10 19:45:33.000000000 +0200 +@@ -0,0 +1,150 @@ ++****************************************************************************** ++ ++Q: I have a (non Acer) notebook which is not recognized by your driver but I ++think it should. What information do you need? ++ ++A: If it is a non-Acer laptop I would like to know, what makes you think that ++your laptop would work with my driver. A windows driver/utility package of the ++name "LaunchManager" or "EasyButton" is a good hint. If it is clear that your ++hardware is okay, I need the string with your model name from BIOS. Please ++don't ask me how to do it. To find out which functions of your laptop the ++driver will support, it is best, if you can tell me where to get this ++"LaunchManager" or "EasyButton" package. ++If it is a model from 2003 or newer then chances are good that it's a dritek ++type one. In this case try the option "force_series=6000" to at least enable ++the keys. ++ ++****************************************************************************** ++ ++Q: Why can't I activate my wireless hardware on Acer TM 420/430/6000/8000 ...? ++ ++A: On many newer laptops (Dritek type) I do not now how to do this, ++sorry. Someone would need to find out how windows does it. Volunteers? ++ ++****************************************************************************** ++ ++Q: I know that wireless hardware is supported on my Aspire 1690/TravelMate4600, ++but I cannot get it to work, why? ++ ++A: On these model (and similar) the wireless hardware is controlled on two ++different levels. One is controlled by acerhk's xxxled file, the other level ++is controlled by the key itself. To actually activate the hardware you need to ++write '1' to the xxled file and you need to press the corresponding button. ++Example: ++echo 1 > /proc/driver/acerhk/wirelessled ++ ++ ++****************************************************************************** ++ ++Q: Why do I always get 0x00 from /proc/driver/acerhk/key? ++ ++A1: Check the type of your laptop if /proc/driver/acerhk/info. If it is ++"Dritek", you cannot read the keys from the driver. Starting from version ++0.5.17 you get "n/a" out of the key file in this case. ++A2: If you have polling enabled (default) you will almost always read 0x00 ++from this file. This is because in every polling cycle it is checked for key ++events and if there is one, it is instantly translated and sent to the kernel ++input system. Starting with version 0.5.20 you get "n/a" out of the key file ++in this case. ++ ++****************************************************************************** ++ ++Q: When I press a key, nothing happens. Why are they not working? ++ ++A: Most keys won't do anything by themself. If nothing happens, that is ++because no programm knows what to do with the new keys. You need to assign ++actions to them, use the hotkey manager of your desktop to do that. If ++using Gnome, you find it under desktop settings - keyboard shortcuts. ++ ++****************************************************************************** ++ ++Q: The driver works for my laptop, but not all of the keys are working. What ++can I do? ++ ++A: There are some keys/key combinations which generate an ACPI event, ++e.g. Fn+F4 on some models or the lid button. ++If you have a different laptop than the one which got detected (or you used ++"force_series=xxx" anyway), then it is possible that the mapping acerhk uses ++to translate the codes from the buttons to key events is wrong. ++In this case, load the driver with "verbose=4" and press the buttons which do ++not work. Then look for messages from acerhk of the form "translated acer key ++code xxx to no key". Note these codes together with the button they belong to ++and send me this list along with the model name of your laptop. ++If you do not see a usable name in /proc/driver/acerhk/info please try the ++tools dmidecode/biosdecode/vpddecode to find this name. ++ ++****************************************************************************** ++Q: I press the wireless key but the hardware doesn't get activated, what's wrong? ++ ++A: The driver is only on older models (non-Dritek type) able to read ++keypresses by itself and toggle the hardware/LED automatically (with option ++autowlan=1). On Dritek type models this must be done by writing the desired ++value to one of the wireless files in the proc filesystem. In most ++cases this would be /proc/drivers/acerhk/wirelessled to control wlan ++hardware (blueled for Bluetooth hardware): ++ ++echo 1 > /proc/driver/acerhk/wirelessled ++ ++But you could use a hotkey manager to do that automatically when you press the ++button. In this case be aware that on some models the button generates ++different key events according to the actual state of the wireless hardware. ++ ++****************************************************************************** ++ ++Q: My keys do not work, I only get kernel messages of the form: ++atkbd.c: Unknown key pressed (translated set 2, code 0xf4 on isa0060/serio0). ++atkbd.c: Use 'setkeycodes e074 ' to make it known. ++ ++A: Press each of the buttons and note the mentioned ++code for it (e074 in this example). You should get a list like this: ++P1 e074 ++P2 e075 ++... ++If you are finished with it, look into /usr/include/linux/input.h, using ++your favourite text viewer/editor. Search for "KEY_STOP". You should see ++the following line in the file: ++ ++#define KEY_STOP 128 ++ ++After it many more lines with equal #defines should be visible. Look for ++key names which best match the names of your buttons, e.g. KEY_PROG1, ++KEY_WWW and so on. Note the numbers assigned to the names, for KEY_STOP ++this would be 128, for KEY_PROG1 148. ++Now you have a list with three items per entry, your button, a code ++from the kernel messages and a corresponding number from the file ++linux.h: ++P1 e074 148 ++P2 e075 149 ++... ++For each line in this list, issue the setkeycodes command as mentioned ++in the kernel message: ++setkeycodes e074 148 ++setkeycodes e075 149 ++... ++After doing that, the keys should be available for your hotkey manager. ++ ++****************************************************************************** ++ ++Q: My WLAN hardware gets activated through /proc/driver/acerhk/wirelessled, ++but the LED is not working. Why not? ++ ++A: Try if adding the option "led=1" to your wireless module helps. For the ++ipw2200 driver it works, as Didier CLERC found out: ++ ++ I have to load the module "ipw2200" with the option "led=1", then ++ the wifi button blinks until a network is detected. ++ ++****************************************************************************** ++ ++Q: I have an unsupported laptop, but the driver works when I force the series ++to a type like 610 or 2100. Only my buttons doesn't get recognized, why? ++ ++A: On models of the type TM_new (like TravelMate 600, 2100 and many other, see ++acerhk.c, function setup_model_features for details) the buttons use different ++codes on different models. Therefore the driver needs to know these codes. You ++can get them if you load the driver with verbose=4, press the buttons and key ++combinations (Fn+xx) you are interested in and look for kernel messages of the ++form "acerhk: translated acer key code 0xnn to ...". Write down the key code ++for each button/key combination and send them to me so I can patch the ++driver. I also need your model string to make autodetection work, so include ++/proc/driver/acerk/info. +\ Ingen nyrad vid filslut +diff -Nurp linux-2.6.37/3rdparty/acerhk/doc/IOCTL linux-2.6.37.3rdparty/3rdparty/acerhk/doc/IOCTL +--- linux-2.6.37/3rdparty/acerhk/doc/IOCTL 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/acerhk/doc/IOCTL 2004-01-31 22:38:17.000000000 +0200 +@@ -0,0 +1,61 @@ ++Documentation of possible IOCTLs used by acerhk +++++++++++++++++++++++++++++++++++++++++++++++++ ++ ++ACERHK_GET_KEYCOUNT ++ Read the number of unread key presses in queue ++ Parameter: pointer to char ++ ++ACERHK_GET_KEYID ++ Read the code of the first key press (oldest) in queue ++ Parameter: pointer to char ++ ++ACERHK_CONNECT ++ Don't know what it does, used in windows driver ++ ++ACERHK_DISCONNECT ++ Don't know what it does, used in windows driver ++ ++ACERHK_GET_THERMAL_EVENT ++ Don't know what it does, used in windows driver ++ Parameter: pointer to short ++ ++ACERHK_MAIL_LED_OFF ++ Switch off the LED of the mail button(if available) ++ ++ACERHK_MAIL_LED_ON ++ Switch on the LED of the mail button (if available) ++ ++ACERHK_START_POLLING ++ Start polling (and translation to key events) in kernel ++ ++ACERHK_STOP_POLLING ++ Stop polling in kernel ++ ++ACERHK_GET_KEY_MAP ++ Get mapping of key names to key events ++ Parameter: pointer to t_map_name2event ++ ++ACERHK_SET_KEY_MAP ++ Set mapping of key names to key events ++ Parameter: pointer to t_map_name2event ++ ++IOCTLs used by windows driver +++++++++++++++++++++++++++++++ ++device name: ++\DosDevices\HOTKEY ++\Device\HOTKEY ++ ++ ++630 series: ++0x222404 ++ Get CMOS index ++0x222408 ++ ACERHK_GET_KEYCOUNT ++0x22240C ++ ACERHK_GET_KEYID ++0x222410 ++ ACERHK_MAIL_LED_OFF/ACERHK_MAIL_LED_ON ++0x222414 ++ ACERHK_CONNECT/ACERHK_DISCONNECT ++0x222418 ++ ACERHK_GET_THERMAL_EVENT +diff -Nurp linux-2.6.37/3rdparty/acerhk/doc/keycodes linux-2.6.37.3rdparty/3rdparty/acerhk/doc/keycodes +--- linux-2.6.37/3rdparty/acerhk/doc/keycodes 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/acerhk/doc/keycodes 2004-04-18 20:42:59.000000000 +0300 +@@ -0,0 +1,26 @@ ++standard X keycodes with older (acerhk controlled) hardware from Acer ++********************************************************************* ++help (Fn+F1) 226 ++setup (Fn+F2) 129 ++p1 153 ++p2 144 ++p3 171 ++www 178 ++mail 236 ++wireless 147 ++power (Fn+F3) 222 ++mute (Fn+F8) 166 ++volup (Fn+Up) 158 ++voldn (Fn+Down) 165 ++ ++standard X keycodes with newer (acerhk activated) hardware from Dritek ++********************************************************************** ++help (Fn+F1) 226 ++setup (Fn+F2) 129 ++p1 153 ++p2 144 ++www 178 ++mail 236 ++volup (Fn+Up) 176 ++voldn (Fn+Down) 174 ++mute (Fn+F8) 160 +diff -Nurp linux-2.6.37/3rdparty/acerhk/doc/md95400.def linux-2.6.37.3rdparty/3rdparty/acerhk/doc/md95400.def +--- linux-2.6.37/3rdparty/acerhk/doc/md95400.def 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/acerhk/doc/md95400.def 2005-03-01 22:46:53.000000000 +0200 +@@ -0,0 +1,14 @@ ++ ++ ++ ++Mail ++Web ++Play/Pause ++Stop ++Previous ++Next ++Leiser ++Lauter ++ ++ ++ +diff -Nurp linux-2.6.37/3rdparty/acerhk/INSTALL linux-2.6.37.3rdparty/3rdparty/acerhk/INSTALL +--- linux-2.6.37/3rdparty/acerhk/INSTALL 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/acerhk/INSTALL 2005-12-07 14:27:16.000000000 +0200 +@@ -0,0 +1,109 @@ ++Installation ++************ ++ ++1. You need the kernel sources (or kernel headers for your kernel) ++installed to compile the driver. ++ ++2. Your kernel needs loadable module support with version information for ++modules enabled. Usage of procfs is highly recommended. ++If you want the driver to generate regular keyboard events using ++kernel version 2.4 you need the input system of the kernel enabled ++(Input core support AND keyboard support). In kernel version 2.6 all ++needed functionality should be available by default. ++ ++In most cases you can skip the next step, the Makefile tries do determine ++the correct directory on its own. Change KERNELSRC only if the autodetection ++does not work for you. Otherwise proceed directly with step 4. ++ ++3. Before you compile the driver, change KERNELSRC in the makefile to your ++path to the kernel build environment. If you are using a self compiled kernel, ++point it to the root of your sources. If you are using a packaged kernel of ++your distribution, install the package with kernel headers ++(Debian:kernel-headers) and point KERNELSRC to where the headers and config ++files are located. If you are using Debian, this ++would be "/lib/modules//build". ++ ++4. Do: ++ make ++to compile the driver. If you run into problems because of the makefile not ++recognizing your kernel version correctly, try this: ++ make acerhk.o - kernel version 2.4 ++ make acerhk.ko - kernel version 2.6 ++ ++5. Do: ++ make install ++to automatically copy the driver into the kernel module library. If you've ++done so, proceed directly with step 8. If you want to install the module ++binary yourself (because you want a different location), use steps 6 and 7 ++instead. ++ ++6. Copy the created file "acerhk.o" ("acerhk.ko" with version 2.6) to your ++kernel modules path. In Debian this could be ++"/lib/modules//kernel/drivers/extra/". ++ ++7. Update module dependencies: depmod -a ++ ++8. Try loading the module with: ++ insmod/modprobe acerhk ++If it succeeds - congratulations! If you have procfs enabled, you can try the ++following to test the driver: ++ ++Non-Dritek models: ++Press one of the special keys and after that: ++ cat /proc/driver/acerhk/key ++to read the (hexadezimal) code of the key pressed. It should ++be different from 0x00. ++(Note: You mustn't have the polling feature enabled for this to work, so load ++ the module with poll=0) ++ ++Dritek-models: ++Press one of the special keys and look for the generated key with "xev". If ++there is none, then you should see at least kernel messages about using ++setkeycodes. ++ ++If your notebook has a mail led you can try this: ++ echo on > /proc/driver/acerhk/led ++This should sete the mail led to blinking mode. ++ echo off > /proc/driver/acerhk/led ++turns it off again. ++See README for further usage information. ++ ++If the module didn't load look into your kernel messages what went wrong. If ++you see something like the following lines: ++ acerhk: could not find request handler ++ acerhk: can't find ROM area ++ acerhk: unloaded ++then your hardware is not recognized. See README for supported models. If it ++won't work on your notebook, please contact me and I will see if I can fix ++that. ++ ++Integrating the driver into kernel tree version 2.6 ++*************************************************** ++ ++If you want the driver to fully integrate into the kernel tree of version 2.6 ++proceed as follows: ++1. Copy the acerhk directory into the source tree, for instance ++ /usr/src/linux/drivers/misc/acerhk ++2. Include the driver directory in the config files. Add to the Kconfig ++file of the parent directory(/usr/src/linux/drivers/misc/Kconfig): ++ ++config ACERHK ++ tristate "Acerhk driver" ++ depends on EXPERIMENTAL ++ ---help--- ++ This is an experimental acer keyboard driver for ++ acer laptops ++ ++3. Include the acer directory in it's parents ++Makefile(/usr/src/linux/drivers/misc/Makefile): ++ ++obj-$(CONFIG_ACERHK) += acerhk/ ++ ++4. In this case you also need to activate the misc drivers first ++(/usr/src/linux/drivers/Kconfig): ++ ++source "drivers/misc/Kconfig" ++ ++If that's done, you should be able to select the driver from the configuration ++programm and build the module. ++ +diff -Nurp linux-2.6.37/3rdparty/acerhk/Makefile linux-2.6.37.3rdparty/3rdparty/acerhk/Makefile +--- linux-2.6.37/3rdparty/acerhk/Makefile 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/acerhk/Makefile 2006-08-16 19:11:08.000000000 +0300 +@@ -0,0 +1,65 @@ ++# change KERNELSRC to the location of your kernel build tree only if ++# autodetection does not work ++#KERNELSRC=/usr/src/linux ++KERNELSRC?=/lib/modules/`uname -r`/build ++# Starting with 2.6.18, the kernel version is in utsrelease.h instead of version.h, accomodate both cases ++KERNELVERSION=$(shell awk -F\" '/REL/ {print $$2}' $(shell grep -s -l REL $(KERNELSRC)/include/linux/version.h $(KERNELSRC)/include/linux/utsrelease.h)) ++KERNELMAJOR=$(shell echo $(KERNELVERSION)|head -c3) ++ ++# next line is for kernel 2.6, if you integrate the driver in the kernel tree ++# /usr/src/linux/drivers/acerhk - or something similar ++# don't forget to add the following line to the parent dir's Makefile: ++# (/usr/src/linux/drivers/Makefile) ++# obj-m += acerhk/ ++CONFIG_ACERHK?=m ++obj-$(CONFIG_ACERHK) += acerhk.o ++ ++CFLAGS+=-c -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fomit-frame-pointer -fno-strict-aliasing -fno-common -pipe ++INCLUDE=-I$(KERNELSRC)/include ++ ++ifeq ($(KERNELMAJOR), 2.6) ++TARGET := acerhk.ko ++else ++TARGET := acerhk.o ++endif ++ ++SOURCE := acerhk.c ++ ++all: $(TARGET) ++ ++help: ++ @echo Possible targets: ++ @echo -e all\\t- default target, builds kernel module ++ @echo -e install\\t- copies module binary to /lib/modules/$(KERNELVERSION)/extra/ ++ @echo -e clean\\t- removes all binaries and temporary files ++ ++# this target is only for me, don't use it yourself (Olaf) ++export: ++ sh export.sh ++ ++acerhk.ko: $(SOURCE) acerhk.h ++ $(MAKE) -C $(KERNELSRC) SUBDIRS=$(PWD) modules ++ ++acerhk.o: $(SOURCE) acerhk.h ++ $(CC) $(INCLUDE) $(CFLAGS) -DMODVERSIONS -DMODULE -D__KERNEL__ -o $(TARGET) $(SOURCE) ++ ++asm: $(SOURCE) ++ifeq ($(KERNELMAJOR), 2.6) ++ $(CC) $(INCLUDE) $(INCLUDE)/asm-i386/mach-default $(CFLAGS) -fverbose-asm -S -DMODVERSIONS -DMODULE -D__KERNEL__ $(SOURCE) ++else ++ $(CC) $(INCLUDE) $(CFLAGS) -fverbose-asm -S -DMODVERSIONS -DMODULE -D__KERNEL__ $(SOURCE) ++endif ++ ++clean: ++ rm -f *~ *.o *.s *.ko .acerhk* *.mod.c ++ ++load: $(TARGET) ++ insmod $(TARGET) ++ ++unload: ++ rmmod acerhk ++ ++install: $(TARGET) ++ mkdir -p /lib/modules/$(KERNELVERSION)/extra ++ cp -v $(TARGET) /lib/modules/$(KERNELVERSION)/extra/ ++ depmod -a +diff -Nurp linux-2.6.37/3rdparty/acerhk/NEWS linux-2.6.37.3rdparty/3rdparty/acerhk/NEWS +--- linux-2.6.37/3rdparty/acerhk/NEWS 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/acerhk/NEWS 2003-02-28 02:47:18.000000000 +0200 +@@ -0,0 +1,16 @@ ++2003-02-28 Version 0.5.0 ++ completely changed key polling/translation ++ support for more series ++2002-07-06 Version 0.4.2 ++ added debug functionality ++ bugfix with 520/210 ++2002-06-24 Version 0.4.1 ++ added support for TM 210 series ++ removed nvram dependency ++2002-06-15 Version 0.4 ++ added model recognition ++ added kernel polling an key event generation ++ added support for 520 series ++ ++2002-04-29 Version 0.3 ++ Initial release +\ Ingen nyrad vid filslut +diff -Nurp linux-2.6.37/3rdparty/acerhk/README linux-2.6.37.3rdparty/3rdparty/acerhk/README +--- linux-2.6.37/3rdparty/acerhk/README 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/acerhk/README 2006-11-10 00:01:46.000000000 +0200 +@@ -0,0 +1,215 @@ ++ ++What is this driver good for? ++***************************** ++ ++This driver will give access to the special keys on notebooks of the ++Acer Travelmate series, which are not handled by the keyboard ++driver. ++It also works on notebooks from other manufacturers (some Medion, ++Fujitsu-Siemens, ...). ++ ++It also has some other related functionality (depending on the model): ++- controlling LEDs (Mail, Wireless) ++- enable/disable wireless hardware ++ ++Usage ++***** ++ ++The driver provides a device /dev/misc/acerhk where you can access all ++functions through IOCTL's, look into acerhk.h for their definitions. ++I use devfs and don't care about the minor number. You may want to change ++ACERHK_MINOR in acerhk.h. ++If you don't use devfs you need to create the device node. The device uses ++major 10 (misc character devices), the minor is chosen by the kernel (if ++ACERHK_MINOR equals MISC_DYNAMIC_MINOR) or by yourself (any other value). ++Use something like ++ mknod /dev/acerhk c 10 123 ++to create the device node. ++You can also use most functions through procfs. You will find some files in ++/proc/driver/acerhk: ++ led - write "on" or "off" to set the mail led state ++ key - read it to get a key press, only useful on non-dritek models ++ and only if polling is disabled ++ This file exists only on non-dritek models ++ info - some information about the driver, including the number of ++ pending keys ++ wirelessled - write "on" or "off" to set the led state and enable ++ wlan hardware ++ On some laptops you need to load the ipw2200 (others ++ too?) with option "led=1" to make the led work. ++ blueled - write "on" or "off" to set the led state and enable ++ bluetooth hardware ++ write a value n >= 50 to let the led blink every n jiffies ++ Do not use blinking mode where not only the led but also the ++ bluetooth hardware is controlled! ++ ++Probably the best way to use the driver is to let it poll for the keys itself ++and generate real key events. this is the normal case when loading the module ++without an additional parameter : ++ ++ modprobe acerhk ++ ++or you can use the ioctl as specified in acerhk.h to control the polling. If ++your kernel has keyboard input support you will get real key events when ++pressing the special keys. ++You can then use whatever software you like to make use of those keys, ++i.e. 'hotkeys' or Linux Easy Access Keyboard 'lineakd'. I prefer hotkeys, just ++in case anyone is interested, you can find a sample configuration for this ++programm in doc/acertm.def. ++Gnome >= 2.4 has built in support for multimedia keys (acme), that's ++what I use now. ++ ++Have a look at ++ http://mmkc.sourceforge.net/ ++ ++Note: If you have one of the newer models using dritek hardware you don't need ++polling (nor the file /proc/driver/acerhk/key) to use your buttons. On this ++hardware the driver only needs to send a special command to the keyboard ++controller to make them work. The actual key presses are then handled by the ++normal keyboard driver of the kernel. You can switch of polling by ++loading the module with poll=0. It saves you precious cpu time. ++ ++ ++Module parameters ++***************** ++name values meaning ++autowlan 0,1 disable(default)/enable automatic switching of wlan hardware ++ on wireless keypress, only useful for older (no ++ dritek-hardware) models, works only will poll=1 ++poll 0,1 disable/enable(default) kernel polling of key events ++verbose 0-4 verbosity level, see below ++usedritek 0,1 disable/enable(default) use of dritek hardware on newer ++ series, needed to activate the keys on such models ++force_series set this to the laptop series number you want the driver to ++ assume, skip autodetection (look at function ++ setup_model_features() for possible values) ++ ++Debugging ++********* ++ ++You can make the the driver be more verbose. To do this, add the following ++parameter when loading the module: ++ ++ verbose= ++ ++n is an integer, 0 (default) means no additional information while increasing ++values provide an increasing amount of information. Currently 3 is maximum, ++bigger values will have the same effect as 3. The existing verbosity levels ++will generate information about: ++ Level Information ++ 1 state changes and variable initialization ++ 2 model probing ++ 3 key translation, only known keys ++ 4 key translation, also unknown keys ++ 5 misc. information (idle values) ++ ++If you have rather serious problems you can activate debugging functionality ++in the driver. To do this, uncomment the '#define ACERDEBUG' in acerhk.c. You ++will find a new file in /proc/driver/acerhk, named 'debug'. You cannot read ++from this file, but you can write commands consisting of up to 4 digits. The ++first one specifies the action, while the latter can give additional ++parameters. Implemented are: ++ 'd' decrement module usage counter ++ 'i' increment module usage counter ++ ++ 'p' call function pbutton_fct() ++ 't' call function get_thermal_event() ++ 'w1x' call function wbutton_fct_1() with parameter x (0-9) ++ 'w2x' call function wbutton_fct_2() with parameter x (0-9) ++ ++ 'vx' change verbosity level to x (0-9) ++ ++ 'mxyy' set mapping of key name x to key event yy (hex) ++ 'sxx' send key event xx (hex) to input system ++ 'Sxx' simulate acer key press with code xx (hex) ++ ++ 'e0' stop kernel polling ++ 'e1' start kernel polling ++ ++Example: ++ ++1) echo d > /proc/driver/acerhk/debug ++ ++will decrement the usage counter, very useful if a program using the driver ++segfaulted. This way you can still unload the driver. ++ ++2) echo v4 > /proc/driver/acerhk/debug ++ ++will set the verbosity level to maximum. ++ ++Keycodes ++******** ++ ++see doc/keycodes ++Also see http://bernd-wurst.de/linux/tm800.php#mmkeys (only in german) ++ ++If you have one of the newer models with the dritek hardware, use kernel 2.6 ++and get (after enabling it) kernel messages of the form: ++ ++ atkbd.c: Unknown key pressed (translated set 2, code 0xf4 on ++ isa0060/serio0). ++ atkbd.c: Use 'setkeycodes e074 ' to make it known. ++ ++then you should do exactly what your told. In this case you could do ++ ++ setkeycodes e074 158 ++ ++to map the button with scancode e074 (hex) to keycode 158 (decimal). To find ++out the scancodes of the buttons either look into the kernel log or into the ++file MMKEYBD.CFG of the windows launch manager package. There you should find ++lines like this: ++ ++Key 1 = 1,E0,74,E0,F4,F500,P1 ++ ** ** ** ++ ++The important information is marked in the example above. The numbers give the ++scancode produced by the button which's name is given last. ++The keycode you give as parameter to setkeycodes is one out of the header file ++linux/input.h, in the example above the one for KEY_BACK. ++Important note: I received mails from a number of people where setkeycodes ++rejected keycodes above a certain value. This is caused by an outdated version ++of setkeycodes, use a more recent one. ++To ease the setup of keymappings for the newer series I will try to include ++setup scripts for the different notebook series. If I have enough time to ++spare I will perhaps expand the driver itself do to that. ++ ++How does it work? ++***************** ++ ++The driver is based on the windows Me for series 610 driver and ++resembles its structure and functionality. ++Key presses are events, which are stored in a FIFO queue with 31 ++entries. You can access the event count via CMOS nvram, but the access to ++the actual queue (and other functionality like switching the mail led) is ++done through calling a system ROM function. ++Upon loading the driver looks for this function, if it cannot find it, ++loading aborts. ++Newer Dritek Hardware: ++Button handling is done entirely by the EC (embbedded/environment ++controller) which behaves like an extended keyboard controller. My ++driver only enables/disables this extension. ++ ++ ++Credits ++******* ++ ++Leif Jensen, whose driver inspired me to do the probing stuff ++http://www.math.columbia.edu/~jensen/linux/acertm/ ++ ++Thanks to all who contributed patches to this driver or who just tried it out ++on their laptops, without them it wouldn't support anything else but my ++TM 613. ++ ++Contact ++******* ++ ++If you have problems with the driver, please include the following information: ++1. name of your laptop (e.g. Acer TM 4001) ++2. content of /proc/driver/acerhk/info, if available ++3. kernel output after loading the module with verbose=2 ++ ++Email: Olaf Tauber ++ ++The latest version can be found here: ++ ++http://www.informatik.hu-berlin.de/~tauber/acerhk diff --git a/kernel/kernel/files/patches/mageia.old/3rd-acerhk-2.6.36-buildfix.patch b/kernel/kernel/files/patches/mageia.old/3rd-acerhk-2.6.36-buildfix.patch new file mode 100644 index 00000000..47a71053 --- /dev/null +++ b/kernel/kernel/files/patches/mageia.old/3rd-acerhk-2.6.36-buildfix.patch @@ -0,0 +1,20 @@ +--- linux-2.6.35/3rdparty/acerhk/acerhk.c.orig 2010-10-03 12:50:33.000000000 +0000 ++++ linux-2.6.35/3rdparty/acerhk/acerhk.c 2010-10-03 13:13:22.093868410 +0000 +@@ -2730,7 +2730,7 @@ static void acerhk_proc_cleanup(void) + + /* {{{ file operations */ + +-static int acerhk_ioctl( struct inode *inode, struct file *file, ++static long acerhk_ioctl( struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg ) + { + int retval; +@@ -2827,7 +2827,7 @@ static int acerhk_release( struct inode + + static struct file_operations acerhk_fops = { + owner: THIS_MODULE, +- ioctl: acerhk_ioctl, ++ unlocked_ioctl: acerhk_ioctl, + open: acerhk_open, + #ifdef ACERDEBUG + write: acerhk_write, diff --git a/kernel/kernel/files/patches/mageia.old/3rd-acerhk-extra-cflags.patch b/kernel/kernel/files/patches/mageia.old/3rd-acerhk-extra-cflags.patch new file mode 100644 index 00000000..7971c699 --- /dev/null +++ b/kernel/kernel/files/patches/mageia.old/3rd-acerhk-extra-cflags.patch @@ -0,0 +1,33 @@ +CFLAGS use isn't allowed anymore with 2.6.24, we must use EXTRA_CFLAGS +in its place + +Signed-off-by: Herton Ronaldo Krzesinski + +--- linux-2.6.23/3rdparty/acerhk/Makefile.orig 2007-11-08 21:32:43.000000000 -0200 ++++ linux-2.6.23/3rdparty/acerhk/Makefile 2007-11-08 21:33:28.000000000 -0200 +@@ -14,7 +14,7 @@ + CONFIG_ACERHK?=m + obj-$(CONFIG_ACERHK) += acerhk.o + +-CFLAGS+=-c -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fomit-frame-pointer -fno-strict-aliasing -fno-common -pipe ++EXTRA_CFLAGS+=-c -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fomit-frame-pointer -fno-strict-aliasing -fno-common -pipe + INCLUDE=-I$(KERNELSRC)/include + + ifeq ($(KERNELMAJOR), 2.6) +@@ -41,13 +41,13 @@ acerhk.ko: $(SOURCE) acerhk.h + $(MAKE) -C $(KERNELSRC) SUBDIRS=$(PWD) modules + + acerhk.o: $(SOURCE) acerhk.h +- $(CC) $(INCLUDE) $(CFLAGS) -DMODVERSIONS -DMODULE -D__KERNEL__ -o $(TARGET) $(SOURCE) ++ $(CC) $(INCLUDE) $(EXTRA_CFLAGS) -DMODVERSIONS -DMODULE -D__KERNEL__ -o $(TARGET) $(SOURCE) + + asm: $(SOURCE) + ifeq ($(KERNELMAJOR), 2.6) +- $(CC) $(INCLUDE) $(INCLUDE)/asm-i386/mach-default $(CFLAGS) -fverbose-asm -S -DMODVERSIONS -DMODULE -D__KERNEL__ $(SOURCE) ++ $(CC) $(INCLUDE) $(INCLUDE)/asm-i386/mach-default $(EXTRA_CFLAGS) -fverbose-asm -S -DMODVERSIONS -DMODULE -D__KERNEL__ $(SOURCE) + else +- $(CC) $(INCLUDE) $(CFLAGS) -fverbose-asm -S -DMODVERSIONS -DMODULE -D__KERNEL__ $(SOURCE) ++ $(CC) $(INCLUDE) $(EXTRA_CFLAGS) -fverbose-asm -S -DMODVERSIONS -DMODULE -D__KERNEL__ $(SOURCE) + endif + + clean: diff --git a/kernel/kernel/files/patches/mageia.old/3rd-acerhk-fix-build-with-function-tracer.patch b/kernel/kernel/files/patches/mageia.old/3rd-acerhk-fix-build-with-function-tracer.patch new file mode 100644 index 00000000..c8d000b5 --- /dev/null +++ b/kernel/kernel/files/patches/mageia.old/3rd-acerhk-fix-build-with-function-tracer.patch @@ -0,0 +1,22 @@ +Fix acerhk build with FUNCTION_TRACER enabled. + +Signed-off-by: Herton Ronaldo Krzesinski +--- + 3rdparty/acerhk/Makefile | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff -p -up linux-2.6.31/3rdparty/acerhk/Makefile.orig linux-2.6.31/3rdparty/acerhk/Makefile +--- linux-2.6.31/3rdparty/acerhk/Makefile.orig 2009-10-02 16:39:06.000000000 -0300 ++++ linux-2.6.31/3rdparty/acerhk/Makefile 2009-10-02 16:45:13.000000000 -0300 +@@ -14,7 +14,10 @@ + CONFIG_ACERHK?=m + obj-$(CONFIG_ACERHK) += acerhk.o + +-EXTRA_CFLAGS+=-c -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fomit-frame-pointer -fno-strict-aliasing -fno-common -pipe ++CFLAGS_acerhk.o += -c -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fomit-frame-pointer -fno-strict-aliasing -fno-common -pipe ++ifdef CONFIG_FUNCTION_TRACER ++CFLAGS_REMOVE_acerhk.o = -pg ++endif + INCLUDE=-I$(KERNELSRC)/include + + ifeq ($(KERNELMAJOR), 2.6) diff --git a/kernel/kernel/files/patches/mageia.old/3rd-acerhk-fix-include.patch b/kernel/kernel/files/patches/mageia.old/3rd-acerhk-fix-include.patch new file mode 100644 index 00000000..cba26984 --- /dev/null +++ b/kernel/kernel/files/patches/mageia.old/3rd-acerhk-fix-include.patch @@ -0,0 +1,23 @@ + +AUTOCONF_INCLUDED is not defined anymore in 2.6.38, so old include got exposed. + +Fix by removing the offending bits. + +Signed-off-by: Thomas Backlund + + 3rdparty/acerhk/acerhk.c | 4 ---- + 1 file changed, 4 deletions(-) + +--- linux-2.6.38/3rdparty/acerhk/acerhk.c.orig 2011-03-20 13:57:32.000000000 +0200 ++++ linux-2.6.38/3rdparty/acerhk/acerhk.c 2011-03-20 15:00:45.768659568 +0200 +@@ -35,10 +35,6 @@ + * + */ + +-#ifndef AUTOCONF_INCLUDED +-#include +-#endif +- + /* This driver is heavily dependent on the architecture, don't let + * anyone without an X86 machine use it. On laptops with AMD64 + * architecture this driver is only useable in 32 bit mode. diff --git a/kernel/kernel/files/patches/mageia.old/3rd-acerhk-kbuild.patch b/kernel/kernel/files/patches/mageia.old/3rd-acerhk-kbuild.patch new file mode 100644 index 00000000..f0c419ad --- /dev/null +++ b/kernel/kernel/files/patches/mageia.old/3rd-acerhk-kbuild.patch @@ -0,0 +1,37 @@ +Fix Makefile and add Kconfig for the acerhk driver +--- + 3rdparty/acerhk/Kconfig | 8 8 + 0 - 0 ! + 3rdparty/acerhk/Makefile | 6 3 + 3 - 0 ! + 2 files changed, 11 insertions(+), 3 deletions(-) + +Index: linux-2.6.21/3rdparty/acerhk/Makefile +=================================================================== +--- linux-2.6.21.orig/3rdparty/acerhk/Makefile 2007-05-15 15:34:48.000000000 +0200 ++++ linux-2.6.21/3rdparty/acerhk/Makefile 2007-05-15 15:37:17.000000000 +0200 +@@ -1,10 +1,10 @@ + # change KERNELSRC to the location of your kernel build tree only if + # autodetection does not work + #KERNELSRC=/usr/src/linux +-KERNELSRC?=/lib/modules/`uname -r`/build ++#KERNELSRC?=/lib/modules/`uname -r`/build + # Starting with 2.6.18, the kernel version is in utsrelease.h instead of version.h, accomodate both cases +-KERNELVERSION=$(shell awk -F\" '/REL/ {print $$2}' $(shell grep -s -l REL $(KERNELSRC)/include/linux/version.h $(KERNELSRC)/include/linux/utsrelease.h)) +-KERNELMAJOR=$(shell echo $(KERNELVERSION)|head -c3) ++#KERNELVERSION=$(shell awk -F\" '/REL/ {print $$2}' $(shell grep -s -l REL $(KERNELSRC)/include/linux/version.h $(KERNELSRC)/include/linux/utsrelease.h)) ++#KERNELMAJOR=$(shell echo $(KERNELVERSION)|head -c3) + + # next line is for kernel 2.6, if you integrate the driver in the kernel tree + # /usr/src/linux/drivers/acerhk - or something similar +Index: linux-2.6.21/3rdparty/acerhk/Kconfig +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.21/3rdparty/acerhk/Kconfig 2007-05-15 15:39:30.000000000 +0200 +@@ -0,0 +1,8 @@ ++config ACERHK ++ tristate "Acerhk driver" ++ depends on EXPERIMENTAL && X86 ++ ---help--- ++ This is an experimental acer keyboard driver for ++ acer laptops. If you have a notebook with a ipw2X00 ++ wireless card, it allows you to turn off the rf_kill ++ diff --git a/kernel/kernel/files/patches/mageia.old/3rd-acerhk-proc_dir_entry-owner.patch b/kernel/kernel/files/patches/mageia.old/3rd-acerhk-proc_dir_entry-owner.patch new file mode 100644 index 00000000..e5821d46 --- /dev/null +++ b/kernel/kernel/files/patches/mageia.old/3rd-acerhk-proc_dir_entry-owner.patch @@ -0,0 +1,67 @@ +Updated for owner removal from struct proc_dir_entry (2.6.30) + +Signed-off-by: Herton Ronaldo Krzesinski + +--- + 3rdparty/acerhk/acerhk.c | 7 ------- + 1 file changed, 7 deletions(-) + +diff -p -up linux-2.6.29/3rdparty/acerhk/acerhk.c.orig linux-2.6.29/3rdparty/acerhk/acerhk.c +--- linux-2.6.29/3rdparty/acerhk/acerhk.c.orig 2009-05-22 02:42:44.000000000 -0300 ++++ linux-2.6.29/3rdparty/acerhk/acerhk.c 2009-05-22 02:43:45.000000000 -0300 +@@ -2626,7 +2626,6 @@ static int acerhk_proc_init(void) + printk(KERN_INFO"acerhk: could not create /proc/driver/acerhk\n"); + } + else { +- proc_acer_dir->owner = THIS_MODULE; + /* now create several files, first general info ... */ + entry = create_proc_read_entry("info", + 0444, proc_acer_dir, acerhk_proc_info, NULL); +@@ -2635,7 +2634,6 @@ static int acerhk_proc_init(void) + remove_proc_entry("driver/acerhk", NULL); + retval = 0; + } else { +- entry->owner = THIS_MODULE; + /* ... last pressed key ... */ + entry = create_proc_read_entry("key", + 0444, proc_acer_dir, acerhk_proc_key, NULL); +@@ -2645,7 +2643,6 @@ static int acerhk_proc_init(void) + remove_proc_entry("driver/acerhk", NULL); + retval = 0; + } else { +- entry->owner = THIS_MODULE; + /* ... and led control file */ + entry = create_proc_entry("led", 0222, proc_acer_dir); + if (entry == NULL) { +@@ -2657,7 +2654,6 @@ static int acerhk_proc_init(void) + } + else { + entry->write_proc = acerhk_proc_led; +- entry->owner = THIS_MODULE; + /* ... and wireless led controll file */ + entry = create_proc_entry("wirelessled", 0222, proc_acer_dir); + if (entry == NULL) { +@@ -2670,7 +2666,6 @@ static int acerhk_proc_init(void) + } + else { + entry->write_proc = acerhk_proc_wirelessled; +- entry->owner = THIS_MODULE; + /* ... and bluetooth led controll file */ + entry = create_proc_entry("blueled", 0222, proc_acer_dir); + if (entry == NULL) { +@@ -2683,7 +2678,6 @@ static int acerhk_proc_init(void) + retval = 0; + } else { + entry->write_proc = acerhk_proc_blueled; +- entry->owner = THIS_MODULE; + retval = 1; + #ifdef ACERDEBUG + /* add extra file for debugging purposes */ +@@ -2700,7 +2694,6 @@ static int acerhk_proc_init(void) + } + else { + entry->write_proc = acerhk_proc_debug; +- entry->owner = THIS_MODULE; + retval = 1; + } + #endif diff --git a/kernel/kernel/files/patches/mageia.old/3rd-aes2501-kbuild.patch b/kernel/kernel/files/patches/mageia.old/3rd-aes2501-kbuild.patch new file mode 100644 index 00000000..1dcf8fa0 --- /dev/null +++ b/kernel/kernel/files/patches/mageia.old/3rd-aes2501-kbuild.patch @@ -0,0 +1,47 @@ +Fix Makefile and add Kconfig for the aes2501 driver. + +Signed-off-by: Herton Ronaldo Krzesinski + +--- + linux-2.6.23/3rdparty/aes2501/Kconfig | 10 ++++++++++ + linux-2.6.23/3rdparty/aes2501/Makefile | 19 +------------------ + 2 files changed, 11 insertions(+), 18 deletions(-) + +diff -p -up linux-2.6.23/3rdparty/aes2501/Kconfig.orig linux-2.6.23/3rdparty/aes2501/Kconfig +--- linux-2.6.23/3rdparty/aes2501/Kconfig.orig 2008-01-13 23:14:47.000000000 -0200 ++++ linux-2.6.23/3rdparty/aes2501/Kconfig 2008-01-13 23:35:21.000000000 -0200 +@@ -0,0 +1,10 @@ ++config AES2501 ++ tristate "AuthenTec AES2501 Fingerprint Sensor Driver" ++ depends on USB ++ default m ++ ---help--- ++ Say Y here if you have a AuthenTec AES2501 Fingerprint ++ Sensor device. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called aes2501. +diff -p -up linux-2.6.23/3rdparty/aes2501/Makefile.orig linux-2.6.23/3rdparty/aes2501/Makefile +--- linux-2.6.23/3rdparty/aes2501/Makefile.orig 2008-01-13 23:14:36.000000000 -0200 ++++ linux-2.6.23/3rdparty/aes2501/Makefile 2008-01-13 23:21:33.000000000 -0200 +@@ -1,19 +1,2 @@ +- +-obj-m := aes2501.o +- +-KERNELDIR ?= /lib/modules/$(shell uname -r)/build +- +-PWD := $(shell pwd) +- +-all: usertest +- $(MAKE) -C $(KERNELDIR) M=$(PWD) +- +-usertest: +- gcc -I. -o usertest usertest.c +- +-clean: +- rm -f *.o *~ aes2501.ko aes2501.mod.c Module.symvers usertest +- rm -rf .tmp_versions +- rm -f .*.cmd +- ++obj-$(CONFIG_AES2501) := aes2501.o + diff --git a/kernel/kernel/files/patches/mageia.old/3rd-aes2501-r19.patch b/kernel/kernel/files/patches/mageia.old/3rd-aes2501-r19.patch new file mode 100644 index 00000000..a5f95e79 --- /dev/null +++ b/kernel/kernel/files/patches/mageia.old/3rd-aes2501-r19.patch @@ -0,0 +1,2356 @@ + 3rdparty/aes2501/ChangeLog | 95 ++ + 3rdparty/aes2501/Makefile | 19 + 3rdparty/aes2501/aes2501.c | 1629 ++++++++++++++++++++++++++++++++++++++++ + 3rdparty/aes2501/aes2501.h | 40 + 3rdparty/aes2501/aes2501_regs.h | 464 +++++++++++ + 3rdparty/aes2501/usertest.c | 78 + + 6 files changed, 2325 insertions(+) +diff -Nurp linux-2.6.37/3rdparty/aes2501/aes2501.c linux-2.6.37.3rdparty/3rdparty/aes2501/aes2501.c +--- linux-2.6.37/3rdparty/aes2501/aes2501.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/aes2501/aes2501.c 2008-01-14 03:07:30.000000000 +0200 +@@ -0,0 +1,1629 @@ ++ ++/* ++ * aes2501.c -- AuthenTec AES2501 Fingerprint Sensor Driver for Linux ++ * ++ * Maintainer: Cyrille Bagard ++ * ++ * Copyright (C) 2007 Cyrille Bagard ++ * ++ * This file is part of the AES2501 driver. ++ * ++ * the AES2501 driver 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. ++ * ++ * the AES2501 driver 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 the AES2501 driver; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#include "aes2501.h" ++#include "aes2501_regs.h" ++ ++ ++static int major = 0; ++ ++module_param(major, int, 0); ++MODULE_PARM_DESC(major, "major number"); ++ ++ ++//#define DEBUG ++ ++ ++#define PRINTK_INFO(fmt, arg...) printk(KERN_INFO "aes2501: " fmt, ## arg) ++ ++#define PRINTK_CRIT(fmt, arg...) printk(KERN_CRIT "aes2501: " fmt, ## arg) ++ ++#define PRINTK_DBG(fmt, arg...) printk(KERN_DEBUG "aes2501: " fmt, ## arg) ++ ++ ++static struct workqueue_struct *comm_queue; ++ ++ ++static char *finger_print = NULL; ++static size_t finger_print_len; ++ ++ ++ ++static DECLARE_WAIT_QUEUE_HEAD(wq); ++static int flag = 0; ++ ++ ++ ++struct usb_aes2501 *_dev; ++ ++ ++ ++ ++ ++ ++struct aes2501 { ++ ++ struct usb_device *udev; ++ ++ int temp; ++ ++ unsigned char *int_in_buffer; ++ struct urb *int_in_urb; ++ ++}; ++ ++ ++/* ++#define VENDOR_ID 0x08f7 ++#define PRODUCT_ID 0x0002 ++*/ ++ ++#define VENDOR_ID 0x08ff ++#define PRODUCT_ID 0x2580 ++ ++ ++/* Table of devices that work with this driver */ ++ ++static struct usb_device_id id_table [] = { ++ { USB_DEVICE(VENDOR_ID, PRODUCT_ID) }, ++ { } ++}; ++ ++MODULE_DEVICE_TABLE(usb, id_table); ++ ++ ++/* Get a minor range for your devices from the usb maintainer */ ++#define USB_AES2501_MINOR_BASE 192 ++ ++ ++ ++#define WRITES_IN_FLIGHT 8 /* ??? */ ++ ++ ++ ++enum AES2501_Status { ++ ++ AESS_INIT_DONE, ++ AESS_IS_SCANNING, ++ ++ AESS_COUNT ++ ++}; ++ ++ ++#define BULK_OUT_BUFFER_SIZE 32 ++ ++ ++/* Read a register value from a dump sent by the device. */ ++static int read_register_value(const uint8_t *, Aes2501Registers); ++ ++/* Tells if a finger motion is still detected. */ ++static int sum_histogram_values(const uint8_t *, uint8_t); ++ ++ ++/* Structure to hold all device specific stuff */ ++struct usb_aes2501 { ++ ++ struct usb_device *udev; /* the usb device for this device */ ++ struct usb_interface *interface; /* the interface for this device */ ++ struct semaphore limit_sem; /* limiting the number of writes in progress */ ++ unsigned char *bulk_in_buffer; /* the buffer to receive data */ ++ size_t bulk_in_size; /* the size of the receive buffer */ ++ __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ ++ uint8_t bulk_out_buffer[BULK_OUT_BUFFER_SIZE]; /* the buffer to send data (32 / 8 = 4) */ ++ size_t bulk_out_buffer_used; /* the quantity of buffered data to send */ ++ __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ ++ struct kref kref; ++ struct mutex io_mutex; /* synchronize I/O with disconnect */ ++ ++ DECLARE_BITMAP(status, AESS_COUNT); /* Information about what has been set / is running */ ++ ++ struct work_struct scan_work; ++ uint8_t stop_scan; /* Flag to stop finger detecting during module removal */ ++}; ++ ++ ++#define to_aes2501_dev(r) container_of(r, struct usb_aes2501, kref) ++ ++static struct usb_driver aes2501_driver; ++ ++static void aes2501_delete(struct kref *kref) ++{ ++ struct usb_aes2501 *dev; ++ ++ dev = to_aes2501_dev(kref); ++ ++ usb_put_dev(dev->udev); ++ kfree(dev->bulk_in_buffer); ++ kfree(dev); ++ ++} ++ ++ ++static int aes2501_open(struct inode *inode, struct file *file); ++/* ++struct usb_aes2501 *_dev; ++static int aes2501_open(struct inode *inode, struct file *file) ++{ ++ printk(KERN_INFO "Plop !\n"); ++ ++ ++ ++ return 0; ++} ++*/ ++ ++static ssize_t aes2501_read(struct file *file, char *buffer, size_t count, loff_t *ppos) ++{ ++ int read_len; ++ ++ //printk(KERN_INFO "aes2501_read ! got %d -> need (%d ; %d)\n", finger_print_len, *ppos, count); ++ ++ if (flag == 0) ++ printk(KERN_INFO "Process %i (%s) is going to sleep\n", current->pid, current->comm); ++ ++ wait_event_interruptible(wq, flag == 1); ++ ++ if (signal_pending(current)) ++ return -ERESTARTSYS; ++ ++ if (finger_print_len == 0) ++ return -ENODATA; ++ ++ if (unlikely((*ppos < 0) || (loff_t)(*ppos + count) < 0)) ++ return -EINVAL; ++ ++ if (*ppos + count > finger_print_len) ++ read_len = finger_print_len - *ppos; ++ else read_len = count; ++ ++ if (read_len > 0) ++ { ++ if (!access_ok(VERIFY_WRITE, buffer, read_len)) ++ return -EFAULT; ++ ++ read_len -= copy_to_user(buffer, finger_print + *ppos, read_len); ++ *ppos += read_len; ++ ++ } ++ ++ /* !!!! */ ++ else flag = 0; ++ ++ return read_len; ++ ++} ++ ++ ++ ++static int detect_finger_on_aes2501(struct usb_aes2501 *dev); ++ ++static void do_scanning(struct work_struct *work); ++ ++ ++// ioctl - I/O control ++static int aes2501_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ struct usb_aes2501 *dev; ++ int retval; ++ ++ dev = _dev; ++ ++ ++ printk(KERN_INFO "Get IOCtl :: cmd = %d vs %d\n", cmd, (AES2501_IOC_TEST)); ++ ++ switch (cmd) { ++ ++ case AES2501_IOC_TEST: ++ ++#if defined(_arch_um__) || !(LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)) ++ INIT_WORK(&dev->scan_work, do_scanning); ++#else ++ INIT_WORK(&dev->scan_work, do_scanning, NULL); ++#endif ++ ++ retval = queue_work(comm_queue, &dev->scan_work); ++ ++ ++ } ++ ++ ++ ++ return 0; ++ ++ ++#if 0 ++ int retval = 0; ++ switch ( cmd ) { ++ case CASE1:/* for writing data to arg */ ++ if (copy_from_user(&data, (int *)arg, sizeof(int))) ++ return -EFAULT; ++ break; ++ case CASE2:/* for reading data from arg */ ++ if (copy_to_user((int *)arg, &data, sizeof(int))) ++ return -EFAULT; ++ break; ++ default: ++ retval = -EINVAL; ++ } ++ return retval; ++#endif ++} ++ ++ ++ ++static const struct file_operations aes2501_fops = { ++ .owner = THIS_MODULE, ++ .read = aes2501_read,/* ++ .write = aes2501_write,*/ ++ .open = aes2501_open,/* ++ .release = skel_release,*/ ++ .ioctl = aes2501_ioctl ++}; ++ ++ ++ ++/* ++static int send_data_to_aes2501(struct usb_aes2501 *dev, unsigned char *buffer, int len) ++{ ++#ifdef DEBUG ++ int i; ++#endif ++ int bytes_written; ++ int ret; ++ ++#ifdef DEBUG ++ printk(KERN_INFO "\n:: OUT :: len=%d\n", len); ++ ++ for (i = 0; i < len; i++) ++ { ++ if (i > 0 && i % 16 == 0) ++ printk("\n"); ++ if (i % 16 == 0) ++ printk(KERN_INFO " %05x: ", i); ++ ++ if (i % 8 == 0) ++ printk(" "); ++ ++ printk("%02x ", buffer[i]); ++ ++ } ++ ++ printk("\n"); ++#endif ++ ++ ret = usb_bulk_msg(dev->udev, ++ usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), ++ buffer, ++ len, ++ &bytes_written, 4000); ++ ++ if (ret < 0) ++ PRINTK_CRIT("error while sending data: %d\n", ret); ++ ++ if (bytes_written != len) ++ printk(KERN_INFO "did not write all ! %d vs %d\n", bytes_written, len); ++ ++ return ret; ++ ++} ++*/ ++ ++static int flush_aes2501_bulk_out(struct usb_aes2501 *dev) ++{ ++ int ret; ++ int bytes_written; ++ ++ ret = 0; ++ ++ if (dev->bulk_out_buffer_used > 0) { ++ ++ ret = usb_bulk_msg(dev->udev, ++ usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), ++ dev->bulk_out_buffer, ++ dev->bulk_out_buffer_used, ++ &bytes_written, 4000); ++ ++ if (ret < 0) ++ PRINTK_CRIT("error while sending data: %d\n", ret); ++ ++ else if (bytes_written != dev->bulk_out_buffer_used) ++ { ++ printk(KERN_INFO "did not write all ! %d vs %d\n", bytes_written, dev->bulk_out_buffer_used); ++ /*ret = ... */ ++ } ++ ++ dev->bulk_out_buffer_used = 0; ++ ++ } ++ ++ return ret; ++ ++} ++ ++ ++static int write_aes2501_register(struct usb_aes2501 *dev, uint8_t reg, uint8_t data) ++{ ++ int ret; ++ ++ if (dev->bulk_out_buffer_used == BULK_OUT_BUFFER_SIZE) ++ ret = flush_aes2501_bulk_out(dev); ++ else ++ ret = 0; ++ ++ dev->bulk_out_buffer[dev->bulk_out_buffer_used++] = reg; ++ dev->bulk_out_buffer[dev->bulk_out_buffer_used++] = data; ++ ++ return ret; ++ ++} ++ ++ ++static int recv_data_to_aes2501(struct usb_aes2501 *dev, unsigned char *buffer, int len) ++{ ++ int bytes_read; ++ int ret; ++#ifdef DEBUG ++ int i; ++#endif ++ ++ ret = usb_bulk_msg(dev->udev, ++ usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr), ++ buffer, ++ len, ++ &bytes_read, 4000); ++ ++ if (ret < 0) ++ PRINTK_CRIT("error while sending data: %d\n", ret); ++ ++ if (bytes_read != len) ++ printk(KERN_INFO "did not read all ! %d vs %d\n", bytes_read, len); ++ ++#ifdef DEBUG ++ if (ret == 0) ++ { ++ printk(KERN_INFO "\n:: IN :: len=%d\n", len); ++ ++ for (i = 0; i < len; i++) ++ { ++ if (i > 0 && i % 16 == 0) ++ printk("\n"); ++ if (i % 16 == 0) ++ printk(KERN_INFO " %05x: ", i); ++ ++ if (i % 8 == 0) ++ printk(" "); ++ ++ printk("%02x ", buffer[i]); ++ ++ } ++ ++ printk("\n"); ++ ++ } ++#endif ++ ++ return ret; ++ ++} ++ ++ ++ ++static int standby_aes2501(struct usb_aes2501 *dev) ++{ ++ ++ //unsigned char cmd[] = "\xac\x01\xad\x1a\x81\x02"; ++ ++ ++ unsigned char buffer[4]; ++ ++ ++ ++ ++ printk(KERN_INFO ">> Standby aes2501 !\n"); ++ ++ ++ //msleep(800); ++ ++ write_aes2501_register(dev, AES2501_REG_TREGC, AES2501_TREGC_ENABLE); ++ write_aes2501_register(dev, AES2501_REG_TREGD, 0x1a); ++ ++ flush_aes2501_bulk_out(dev); ++ ++ /** ++ * TODO: ++ * - lire ici les deux octets. ++ * - voir pour inverser les commandes. ++ */ ++ ++ write_aes2501_register(dev, AES2501_REG_CTRL2, 0x02/* AES2501_CTRL2_READ_REGS ??? */); ++ flush_aes2501_bulk_out(dev); ++ ++ //send_data_to_aes2501(dev, cmd, 6); ++ recv_data_to_aes2501(dev, buffer, 2); ++ ++ ++ ++ printk(KERN_INFO " %02x %02x\n", buffer[0], buffer[1]); ++ ++ ++ if ((buffer[1] & AES2501_STAT_SCAN) == buffer[1]) ++ { ++ PRINTK_DBG("scan state: "); ++ ++ switch (buffer[1]) ++ { ++ case STATE_WAITING_FOR_FINGER: ++ printk("'Waiting for finger'\n"); ++ break; ++ case STATE_FINGER_SETTLING_DELAY: ++ printk("'In Finger settling delay'\n"); ++ break; ++ case STATE_POWER_UP_DELAY: ++ printk("'In power up delay'\n"); ++ break; ++ case STATE_WAITING_TO_START_SCAN: ++ printk("'Waiting to start image scan'\n"); ++ break; ++ case STATE_PRELOADING_SUBARRAY_0: ++ printk("'Pre-loading subarray 0'\n"); ++ break; ++ case STATE_SETUP_FOR_ROW_ADVANCE: ++ printk("'Setup for row advance'\n"); ++ break; ++ case STATE_WAITING_FOR_ROW_ADVANCE: ++ printk("'Waiting for row advance'\n"); ++ break; ++ case STATE_PRELOADING_COL_0: ++ printk("'Pre-loading column 0'\n"); ++ break; ++ case STATE_SETUP_FOR_COL_ADVANCE: ++ printk("'Setup for column advance'\n"); ++ break; ++ case STATE_WAITING_FOR_COL_ADVANCE: ++ printk("'Waiting for column advance'\n"); ++ break; ++ case STATE_WAITING_FOR_SCAN_START: ++ printk("'Waiting for scan start'\n"); ++ break; ++ case STATE_WAITING_FOR_SCAN_END: ++ printk("'Waiting for scan end'\n"); ++ break; ++ case STATE_WAITING_FOR_ROW_SETUP: ++ printk("'Waiting for row setup'\n"); ++ break; ++ case STATE_WAITING_FOR_COL_TIME: ++ printk("'Waiting for one column time (depends on scan rate)'\n"); ++ break; ++ case STATE_WAITING_FOR_QUEUED_DATA: ++ printk("'Waiting for queued data transmission to be completed'\n"); ++ break; ++ case STATE_WAIT_FOR_128_US: ++ printk("'Wait for 128 us'\n"); ++ break; ++ default: ++ printk("none (?!)\n"); ++ break; ++ ++ } ++ ++ } ++ ++ if (buffer[1] & AES2501_STAT_ERROR) ++ PRINTK_DBG("got serial interface framing error\n"); ++ ++ if (buffer[1] & AES2501_STAT_PAUSED) ++ PRINTK_DBG("scan was paused due to input buffer full\n"); ++ ++ if (buffer[1] & AES2501_STAT_RESET) ++ PRINTK_DBG("master reset input has been asserted\n"); ++ ++ ++ ++ ++ return 0; ++ ++ ++} ++ ++ ++ ++ ++static int setup_aes2501(struct usb_aes2501 *dev) ++{ ++ //unsigned char patch_msg[] = "\x80\x01"; ++ ++ ++ //unsigned char cmd[] = "\x80\x01\x81\x02"; ++ ++ //unsigned char cmd_00[] = "\xb0\x27"; ++ //unsigned char cmd_01[] = "\x80\x01\x82\x40"; ++ //unsigned char cmd_02[] = "\xff\x00"; ++ //unsigned char cmd_03[] = "\x80\x01\x82\x40\x83\x00\x88\x02\x89\x10\x8a\x05\x8c\x00\x8e\x13\x91\x44\x92\x34\x95\x16\x96\x16\x97\x18\xa1\x70\xa2\x02\xa7\x00\xac\x01\xad\x1a\x80\x04\x81\x04\xb4\x00";/*42*/ ++ //unsigned char cmd_04[] = "\x80\x01\x82\x40"; ++ ++ //unsigned char cmd2[] = "\x80\x01\xa8\x41\x82\x42\x83\x53\x80\x04\x81\x02";/*12*/ ++ ++ //unsigned char cmd3_00[] = "\xff\x00"; ++ //unsigned char cmd3_01[] = "\x80\x01\xa8\x41\x82\x42\x83\x53\x80\x04\x81\x02";/*12*/ ++ ++ //unsigned char cmd4[] = "\x80\x01\x82\x40\xb0\x27\x94\x0a\x80\x04\x83\x45\xa8\x41";/*14*/ ++ ++ //unsigned char cmd5_00[] = "\xb0\x27"; ++ //unsigned char cmd5_01[] = "\x80\x01\x82\x40"; ++ //unsigned char cmd5_02[] = "\xff\x00"; ++ //unsigned char cmd5_03[] = "\x80\x02"; ++ //unsigned char cmd5_04[] = "\x81\x02"; ++ ++ ++ int i; ++ ++ unsigned char buffer[128]; ++ ++ ++ /* To be sure the device will respond */ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ //send_data_to_aes2501(dev, patch_msg, 2); ++ flush_aes2501_bulk_out(dev);/* ... */ ++ ++ printk(KERN_INFO ">> Setting up aes2501 !\n"); ++ ++ /* Part 1 */ ++ ++ printk(KERN_INFO " -- part 1 --\n"); ++ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_CTRL2, AES2501_CTRL2_READ_REGS); ++ flush_aes2501_bulk_out(dev); ++ ++ //send_data_to_aes2501(dev, cmd, 4); ++ recv_data_to_aes2501(dev, buffer, 126); ++ ++ ++ ++ //send_data_to_aes2501(dev, cmd_00, 2); ++ ++ write_aes2501_register(dev, 0xb0, 0x27);/* Reserved */ ++ ++ ++ ++ //send_data_to_aes2501(dev, cmd_01, 4); ++ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */ ++ ++ for (i = 0; i <= 10; i++) ++ { ++ //msleep(200); ++ //send_data_to_aes2501(dev, cmd_02, 2); ++ write_aes2501_register(dev, 0xff, 0x00);/* Reserved */ ++ } ++ ++ //msleep(100); ++ ++ ++ //send_data_to_aes2501(dev, cmd_03, 42); ++ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */ ++ write_aes2501_register(dev, AES2501_REG_DETCTRL, AES2501_DETCTRL_DRATE_CONTINUOUS | AES2501_DETCTRL_SDELAY_31_MS); ++ write_aes2501_register(dev, AES2501_REG_COLSCAN, AES2501_COLSCAN_SRATE_128_US); ++ write_aes2501_register(dev, AES2501_REG_MEASDRV, AES2501_MEASDRV_MDRIVE_0_325 | AES2501_MEASDRV_MEASURE_SQUARE); ++ write_aes2501_register(dev, AES2501_REG_MEASFREQ, AES2501_MEASFREQ_2M); ++ write_aes2501_register(dev, AES2501_REG_DEMODPHASE1, DEMODPHASE_NONE);/* Default */ ++ write_aes2501_register(dev, AES2501_REG_DEMODPHASE2, DEMODPHASE_NONE); ++ write_aes2501_register(dev, AES2501_REG_CHANGAIN, AES2501_CHANGAIN_STAGE2_4X | AES2501_CHANGAIN_STAGE1_16X); ++ write_aes2501_register(dev, AES2501_REG_ADREFHI, 0x44); ++ write_aes2501_register(dev, AES2501_REG_ADREFLO, 0x34); ++ write_aes2501_register(dev, AES2501_REG_STRTCOL, 0x16); ++ write_aes2501_register(dev, AES2501_REG_ENDCOL, 0x16); ++ write_aes2501_register(dev, AES2501_REG_DATFMT, AES2501_DATFMT_BIN_IMG | 0x08);/* ??? */ ++ write_aes2501_register(dev, AES2501_REG_TREG1, 0x70);/* Reserved + 0xXX */ ++ write_aes2501_register(dev, 0xa2, 0x02);/* Reserved */ ++ write_aes2501_register(dev, 0xa7, 0x00);/* Reserved */ ++ write_aes2501_register(dev, AES2501_REG_TREGC, AES2501_TREGC_ENABLE); ++ write_aes2501_register(dev, AES2501_REG_TREGD, 0x1a); ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE); ++ write_aes2501_register(dev, AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT); ++ write_aes2501_register(dev, AES2501_REG_LPONT, AES2501_LPONT_MIN_VALUE); ++ ++ ++ flush_aes2501_bulk_out(dev); ++ ++ recv_data_to_aes2501(dev, buffer, 20); ++ ++ ++ ++ //send_data_to_aes2501(dev, cmd_04, 4); ++ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */ ++ ++ /* Part 2 */ ++ ++ printk(KERN_INFO " -- part 2 --\n"); ++ ++ //msleep(100); ++ ++ //send_data_to_aes2501(dev, cmd2, 12); ++ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_AUTOCALOFFSET, 0x41); ++ write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x42);/* ??? */ ++ write_aes2501_register(dev, AES2501_REG_DETCTRL, 0x53);/* Cumul ??? */ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE); ++ write_aes2501_register(dev, AES2501_REG_CTRL2, AES2501_CTRL2_READ_REGS); ++ ++ ++ ++ ++ flush_aes2501_bulk_out(dev); ++ ++ ++ recv_data_to_aes2501(dev, buffer, 126); ++ ++ /* Part 3 */ ++ ++ printk(KERN_INFO " -- part 3 --\n"); ++ ++ i = 0; ++ ++ printk(KERN_INFO " reg 0xaf = 0x%x\n", buffer[0x5f]); ++ while (buffer[0x5f] == 0x6b) ++ { ++ //msleep(200); ++ ++ ++ //send_data_to_aes2501(dev, cmd3_00, 2); ++ write_aes2501_register(dev, 0xff, 0x00);/* Reserved */ ++ ++ //msleep(80); ++ ++ //send_data_to_aes2501(dev, cmd3_01, 12); ++ ++ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_AUTOCALOFFSET, 0x41); ++ write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x42);/* ??? */ ++ write_aes2501_register(dev, AES2501_REG_DETCTRL, 0x53);/* Cumul ??? */ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE); ++ write_aes2501_register(dev, AES2501_REG_CTRL2, AES2501_CTRL2_READ_REGS); ++ ++ flush_aes2501_bulk_out(dev); ++ ++ ++ ++ ++ recv_data_to_aes2501(dev, buffer, 126); ++ ++ printk(KERN_INFO " +reg 0xaf = 0x%x\n", buffer[0x5f]); ++ ++ if (++i == 13) break; ++ ++ } ++ ++ ++ ++ ++ ++ /* Part 4 */ ++ ++ printk(KERN_INFO " -- part 4 --\n"); ++ ++ //send_data_to_aes2501(dev, cmd4, 14); ++ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */ ++ write_aes2501_register(dev, 0xb0, 0x27);/* Reserved */ ++ write_aes2501_register(dev, AES2501_REG_ENDROW, 0x0a); ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE); ++ write_aes2501_register(dev, AES2501_REG_DETCTRL, 0x45);/* ???? */ ++ write_aes2501_register(dev, AES2501_REG_AUTOCALOFFSET, 0x41); ++ ++ ++ ++ ++ ++ ++ /* ... */ ++ ++ ++/* ++ for (i = 0; i < 126; i += 10) ++ { ++ printk(KERN_INFO " %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", ++ buffer[i + 0], buffer[i + 1], buffer[i + 2], buffer[i + 3], buffer[i + 4], ++ buffer[i + 5], buffer[i + 6], buffer[i + 7], buffer[i + 8], buffer[i + 9]); ++ ++ if (i % 20 == 0) ++ printk(KERN_INFO "\n "); ++ ++ } ++ ++ printk(KERN_INFO "\n"); ++*/ ++ ++ ++ ++ /* Part 5 */ ++ ++ printk(KERN_INFO " -- part 5 --\n"); ++ ++ //send_data_to_aes2501(dev, cmd5_00, 2); ++ ++ write_aes2501_register(dev, 0xb0, 0x27);/* Reserved */ ++ ++ //send_data_to_aes2501(dev, cmd5_01, 4); ++ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */ ++ ++ //msleep(200); ++ ++ ++ //send_data_to_aes2501(dev, cmd5_02, 2); ++ //send_data_to_aes2501(dev, cmd5_01, 4); ++ //send_data_to_aes2501(dev, cmd5_01, 4); ++ ++ write_aes2501_register(dev, 0xff, 0x00);/* Reserved */ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */ ++ ++ ++ ++ //msleep(50); ++ ++ //send_data_to_aes2501(dev, cmd5_01, 4); ++ //send_data_to_aes2501(dev, cmd5_01, 4); ++ //send_data_to_aes2501(dev, cmd5_01, 4); ++ //send_data_to_aes2501(dev, cmd5_03, 2); ++ //send_data_to_aes2501(dev, cmd5_03, 2); ++ //send_data_to_aes2501(dev, cmd5_04, 2); ++ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_SCAN_RESET); ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_SCAN_RESET); ++ write_aes2501_register(dev, AES2501_REG_CTRL2, AES2501_CTRL2_READ_REGS); ++ flush_aes2501_bulk_out(dev); ++ ++ ++ recv_data_to_aes2501(dev, buffer, 126); ++ ++ ++ ++ ++ ++ return 0; ++ ++} ++ ++static int detect_finger_on_aes2501(struct usb_aes2501 *dev) ++{ ++ //uint8_t cmd1[] = "\x80\x01\x82\x40"; ++ //uint8_t cmd2[] = "\x80\x01\x82\x40\x83\x00\x88\x02\x89\x10\x8a\x05\x8c\x00\x8e\x13\x91\x44\x92\x34\x95\x16\x96\x16\x97\x18\xa1\x70\xa2\x02\xa7\x00\xac\x01\xad\x1a\x80\x04\x81\x04\xb4\x00";/*42*/ ++ ++ ++ unsigned char buffer[22]; ++ unsigned i, sum; ++ ++ //send_data_to_aes2501(dev, cmd1, 4); ++ ++ //msleep(30); ++ ++ ++ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* Reserved */ ++ write_aes2501_register(dev, AES2501_REG_DETCTRL, AES2501_DETCTRL_DRATE_CONTINUOUS | AES2501_DETCTRL_SDELAY_31_MS); ++ write_aes2501_register(dev, AES2501_REG_COLSCAN, AES2501_COLSCAN_SRATE_128_US);/* not the faster ??? */ ++ write_aes2501_register(dev, AES2501_REG_MEASDRV, AES2501_MEASDRV_MDRIVE_0_325 | AES2501_MEASDRV_MEASURE_SQUARE); ++ write_aes2501_register(dev, AES2501_REG_MEASFREQ, AES2501_MEASFREQ_2M); ++ write_aes2501_register(dev, AES2501_REG_DEMODPHASE1, DEMODPHASE_NONE);/* Default */ ++ write_aes2501_register(dev, AES2501_REG_DEMODPHASE2, DEMODPHASE_NONE); ++ write_aes2501_register(dev, AES2501_REG_CHANGAIN, AES2501_CHANGAIN_STAGE2_4X | AES2501_CHANGAIN_STAGE1_16X); ++ write_aes2501_register(dev, AES2501_REG_ADREFHI, 0x44); ++ write_aes2501_register(dev, AES2501_REG_ADREFLO, 0x34); ++ write_aes2501_register(dev, AES2501_REG_STRTCOL, 0x16); ++ write_aes2501_register(dev, AES2501_REG_ENDCOL, 0x16); ++ write_aes2501_register(dev, AES2501_REG_DATFMT, AES2501_DATFMT_BIN_IMG | 0x08); ++ write_aes2501_register(dev, AES2501_REG_TREG1, 0x70);/* Reserved + 0xXX */ ++ write_aes2501_register(dev, 0xa2, 0x02);/* Reserved */ ++ write_aes2501_register(dev, 0xa7, 0x00);/* Reserved */ ++ write_aes2501_register(dev, AES2501_REG_TREGC, AES2501_TREGC_ENABLE); ++ write_aes2501_register(dev, AES2501_REG_TREGD, 0x1a); ++ ++ flush_aes2501_bulk_out(dev); ++ ++ /** ++ * TODO: ++ * - lire ici les deux octets. ++ * - voir pour inverser les commandes. ++ */ ++ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE); ++ write_aes2501_register(dev, AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT); ++ write_aes2501_register(dev, AES2501_REG_LPONT, AES2501_LPONT_MIN_VALUE); ++ ++ flush_aes2501_bulk_out(dev); ++ ++ ++ //send_data_to_aes2501(dev, cmd2, 42); ++ ++ recv_data_to_aes2501(dev, buffer, 20); ++ ++ ++ /* One column is returned here but I don't know which one. ++ Maybe an average over the whole sensor area. */ ++ sum = 0; ++ for (i = 1; i != 9; i++) { ++ sum += (buffer[i] & 0xf) + (buffer[i] >> 4); ++ } ++ ++ ++ //printk(KERN_INFO "===finger=== sum = %d vs %d\n", sum, 20); ++ ++ ++ /* ++ return (sum > aes->fingerTh1); ++ */ ++ ++ return sum > 20; ++ ++} ++ ++ ++static unsigned read_fingerprint_on_aes2501(struct usb_aes2501 *dev, void *raw_, unsigned maxstrip) ++{ ++ //unsigned char patch_msg[] = "\x80\x01"; ++ ++ /* 8e xx = set gain */ ++ //uint8_t cmd1_00[] = "0x80\x01\x82\x40"; ++ //uint8_t cmd1_01[] = "0x80\x01\x82\x40\x83\x00\x88\x02\x8c\x7c\x89\x10\x8d\x24\x9b\x00\x9c\x6c\x9d\x09\x9e\x54\x9f\x78\xa2\x02\xa7\x00\xb6\x26\xb7\x1a\x80\x04\x98\x23\x95\x10\x96\x1f\x8e\x00\x91\x70\x92\x20\x81\x04\xb4\x00";/*50*/ ++ ++ //uint8_t cmd2[] = "\x98\x23\x95\x10\x96\x1f\x8e\x03\x91\x70\x92\x20\x81\x04";/*14*/ ++ ++ //uint8_t cmd3[] = "\x98\x22\x95\x00\x96\x2f\x8e\x03\x91\x5b\x92\x20\x81\x04";/*14*/ ++ ++ uint8_t buf[1705]; ++ uint8_t *raw = (uint8_t *) raw_; ++ unsigned nstrips; ++ ++ int threshold; ++ int sum; ++ ++ ++ //send_data_to_aes2501(dev, patch_msg, 2); ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ flush_aes2501_bulk_out(dev); ++ ++ ++ ++ //send_data_to_aes2501(dev, cmd1_00, 4); ++ ++ ++ //send_data_to_aes2501(dev, cmd1_01, 50); ++ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET); ++ write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* Reserved */ ++ write_aes2501_register(dev, AES2501_REG_DETCTRL, AES2501_DETCTRL_SDELAY_31_MS | AES2501_DETCTRL_DRATE_CONTINUOUS); ++ write_aes2501_register(dev, AES2501_REG_COLSCAN, AES2501_COLSCAN_SRATE_128_US); ++ write_aes2501_register(dev, AES2501_REG_DEMODPHASE2, 0x7c);/* ... */ ++ write_aes2501_register(dev, AES2501_REG_MEASDRV, AES2501_MEASDRV_MEASURE_SQUARE | AES2501_MEASDRV_MDRIVE_0_325); ++ write_aes2501_register(dev, AES2501_REG_DEMODPHASE1, 0x24);/* ... */ ++ write_aes2501_register(dev, AES2501_REG_CHWORD1, 0x00);/* Challenge Word */ ++ write_aes2501_register(dev, AES2501_REG_CHWORD2, 0x6c);/* Challenge Word */ ++ write_aes2501_register(dev, AES2501_REG_CHWORD3, 0x09);/* Challenge Word */ ++ write_aes2501_register(dev, AES2501_REG_CHWORD4, 0x54);/* Challenge Word */ ++ write_aes2501_register(dev, AES2501_REG_CHWORD5, 0x78);/* Challenge Word */ ++ write_aes2501_register(dev, 0xa2, 0x02);/* Reserved */ ++ write_aes2501_register(dev, 0xa7, 0x00);/* Reserved */ ++ write_aes2501_register(dev, 0xb6, 0x26);/* Reserved */ ++ write_aes2501_register(dev, 0xb7, 0x1a);/* Reserved */ ++ write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE); ++ write_aes2501_register(dev, AES2501_REG_IMAGCTRL, AES2501_IMAGCTRL_TST_REG_ENABLE | AES2501_IMAGCTRL_HISTO_DATA_ENABLE | AES2501_IMAGCTRL_IMG_DATA_DISABLE); ++ write_aes2501_register(dev, AES2501_REG_STRTCOL, 0x10); ++ write_aes2501_register(dev, AES2501_REG_ENDCOL, 0x1f); ++ write_aes2501_register(dev, AES2501_REG_CHANGAIN, AES2501_CHANGAIN_STAGE1_2X | AES2501_CHANGAIN_STAGE2_2X); ++ write_aes2501_register(dev, AES2501_REG_ADREFHI, 0x70); ++ write_aes2501_register(dev, AES2501_REG_ADREFLO, 0x20); ++ write_aes2501_register(dev, AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT); ++ write_aes2501_register(dev, AES2501_REG_LPONT, AES2501_LPONT_MIN_VALUE); ++ ++ ///////recv_data_to_aes2501(dev, buf, 159); ++ /* TODO: calibration e.g setting gain (0x8e xx) */ ++ ++ ++ ++ ++ //send_data_to_aes2501(dev, cmd2, 14); ++ ++ ++ ++ write_aes2501_register(dev, AES2501_REG_IMAGCTRL, AES2501_IMAGCTRL_TST_REG_ENABLE | AES2501_IMAGCTRL_HISTO_DATA_ENABLE | AES2501_IMAGCTRL_IMG_DATA_DISABLE); ++ write_aes2501_register(dev, AES2501_REG_STRTCOL, 0x10); ++ write_aes2501_register(dev, AES2501_REG_ENDCOL, 0x1f); ++ write_aes2501_register(dev, AES2501_REG_CHANGAIN, AES2501_CHANGAIN_STAGE1_16X); ++ write_aes2501_register(dev, AES2501_REG_ADREFHI, 0x70); ++ write_aes2501_register(dev, AES2501_REG_ADREFLO, 0x20); ++ write_aes2501_register(dev, AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT); ++ ++ flush_aes2501_bulk_out(dev); ++ ++ ++ recv_data_to_aes2501(dev, buf, 159); ++ ++ nstrips = 0; ++ do { ++ printk(KERN_INFO "-start-\n"); ++ /* Timing in this loop is critical. It decides how fast you can move your finger. ++ If one loop takes tl second, the maximum speed is: ++ (16/500 * 25.4) / tl [mm per sec] ++ */ ++ //send_data_to_aes2501(dev, cmd3, 14); ++ ++ write_aes2501_register(dev, AES2501_REG_IMAGCTRL, AES2501_IMAGCTRL_TST_REG_ENABLE | AES2501_IMAGCTRL_HISTO_DATA_ENABLE); ++ write_aes2501_register(dev, AES2501_REG_STRTCOL, 0x00); ++ write_aes2501_register(dev, AES2501_REG_ENDCOL, 0x2f); ++ write_aes2501_register(dev, AES2501_REG_CHANGAIN, AES2501_CHANGAIN_STAGE1_16X); ++ write_aes2501_register(dev, AES2501_REG_ADREFHI, 0x5b); ++ write_aes2501_register(dev, AES2501_REG_ADREFLO, 0x20); ++ write_aes2501_register(dev, AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT); ++ ++ flush_aes2501_bulk_out(dev); ++ ++ ++ ++ recv_data_to_aes2501(dev, buf, 1705); ++ memcpy(raw, buf+1, 192*8); ++ raw += 192*8; ++ ++ printk(KERN_INFO "-end of copy-\n"); ++ ++ ++ threshold = read_register_value((buf + 1 + 192*8 + 1 + 16*2 + 1 + 8), _AES2501_REG_DATFMT); ++ /*if (threshold < 0) ++ return threshold;*/ ++ ++ threshold &= 0x0f; ++ ++ sum = sum_histogram_values((buf + 1 + 192*8), threshold); ++ /*if (threshold < 0) ++ return threshold;*/ ++ ++ nstrips++; ++ printk(KERN_INFO "-end- %d vs %d\n", nstrips, maxstrip); ++ } while (sum > 0 && nstrips < maxstrip); ++ printk(KERN_INFO "nstrips = %u\n", nstrips); ++ if (nstrips == maxstrip) ++ printk(KERN_INFO "nstrips == %u, swiping the finger too slowly?\n", maxstrip); ++ return nstrips; ++} ++ ++ ++ ++/** ++ * Read a register value from a dump sent by the device. ++ * @data: list of couples . ++ * @target: index of the register to process. ++ * @return: -EILSEQ,-EINVAL if error, value > 0 if a finger is here. ++ */ ++int read_register_value(const uint8_t *data, Aes2501Registers target) ++{ ++ int result; ++ uint8_t offset; ++ ++ if (*data == FIRST_AES2501_REG) ++ { ++ offset = target; ++ ++ if (!(FIRST_AES2501_REG <= offset && offset <= LAST_AES2501_REG)) ++ result = -EINVAL; ++ ++ else ++ { ++ offset -= FIRST_AES2501_REG; ++ offset *= 2; ++ ++ result = data[++offset]; ++ ++ } ++ ++ } ++ else result = -EILSEQ; ++ ++ return result; ++ ++} ++ ++ ++/** ++ * Tells if a finger motion is still detected. ++ * @data: start point of data to handle, preceded by 0xde. ++ * @threshold: index of values set to 1 by the device. ++ * @return: -EILSEQ,-EINVAL if error, value > 0 if a finger is here. ++ * ++ * Histograms always are a 16-uint16_t long message, where ++ * histogram[i] = number of pixels of value i. ++ */ ++int sum_histogram_values(const uint8_t *data, uint8_t threshold) ++{ ++ int result; ++ uint16_t *histogram; ++ uint8_t i; ++ ++ if (*data == 0xde) ++ { ++ if (threshold > 0x0f) ++ result = -EINVAL; ++ ++ else ++ { ++ result = 0; ++ histogram = (uint16_t *)(data + 1); ++ ++ for (i = threshold; i < 16; i++) ++ result += histogram[i]; ++ ++ } ++ ++ } ++ else result = -EILSEQ; ++ ++ return result; ++ ++} ++ ++ ++ ++/********************************************************** ++ ** Image processing ++ **********************************************************/ ++ ++/* This function finds overlapping parts of two frames ++ * Based on calculating normalized hamming distance ++ * between two frames ++ */ ++ ++static unsigned find_overlap(const uint8_t *first_frame, ++ const uint8_t *second_frame, ++ uint32_t frame_height, ++ uint32_t frame_width, ++ uint32_t *min_error) ++{ ++ uint32_t dy, i; ++ uint32_t error, not_overlapped_height = 0; ++ *min_error = 255 * frame_height * frame_width; ++ for (dy = 0; dy < frame_height; dy++) { ++ /* Calculating difference (error) between parts of frames */ ++ error = 0; ++ for (i = 0; i < frame_width * (frame_height - dy); i++) { ++ /* Using ? operator to avoid abs function */ ++ error += first_frame[i] > second_frame[i] ? ++ (first_frame[i] - second_frame[i]) : ++ (second_frame[i] - first_frame[i]); ++ } ++ ++ /* Normalizing error */ ++ error *= 15; ++ error /= i; ++ if (error < *min_error) { ++ *min_error = error; ++ not_overlapped_height = dy; ++ } ++ first_frame += frame_width; ++ } ++ ++ return not_overlapped_height; ++} ++ ++ ++/* This function assembles frames to single image, returns image height ++ * TODO: add Doxygen comments ++ */ ++static unsigned assemble(const uint8_t *input, /* Raw data received from device */ ++ uint8_t *output, /* Output buffer */ ++ uint32_t frame_height, /* Height of each frame */ ++ uint32_t frame_width, /* Width of each frame */ ++ uint32_t frames_count, /* Frames count */ ++ /*int overlap, */ ++ uint8_t reversed, ++ uint32_t *errors_sum ++ ) ++{ ++ uint8_t *assembled = output; ++ uint32_t frame, column, row, image_height = frame_height; ++ uint32_t error, not_overlapped; ++ ++ *errors_sum = 0; ++ ++ if (frames_count < 1) return 0; ++ ++ /* Rotating given data by 90 degrees ++ * Taken from document describing aes2501 image format ++ * TODO: move reversing detection here */ ++ if (reversed) { ++ output += (frames_count - 1) * frame_width * frame_height; ++ } ++ ++ for (frame = 0; frame < frames_count; frame++) { ++ for (column = 0; column < frame_width; column++) { ++ for (row = 0; row < (frame_height / 2); row++) { ++ output[frame_width * ( 2 * row) + column] = *input & 0x0F; ++ output[frame_width * ( 2 * row + 1) + column] = *input >> 4; ++ input++; ++ } ++ } ++ ++ if (reversed) { ++ output -= frame_width * frame_height; ++ } ++ else { ++ output += frame_width * frame_height; ++ } ++ } ++ ++ /* Detecting where frames overlaped */ ++ output = assembled; ++ for (frame = 1; frame < frames_count; frame++) ++ { ++ output += frame_width * frame_height; ++ not_overlapped = find_overlap(assembled, output, frame_height, frame_width, &error); ++ *errors_sum += error; ++ image_height += not_overlapped; ++ assembled += frame_width * not_overlapped; ++ memcpy(assembled, output, frame_width * frame_height); ++ } ++ ++ return image_height; ++} ++ ++ ++ ++static void store_new_aes2501_pnm(const uint8_t *data, unsigned int width, unsigned int height) ++{ ++ char header[20]; ++ __kernel_size_t header_len; ++ int i; ++ char *iter; ++ ++ sprintf(header, "P5\n%u %u\n255\n", width, height); ++ header_len = strlen(header); ++ ++ finger_print_len = header_len + width * height; ++ finger_print = kzalloc(finger_print_len, GFP_KERNEL); ++ ++ memcpy(finger_print, header, header_len); ++ ++ for (i = 0, iter = &finger_print[header_len]; i < width * height; i++, iter++) ++ *iter = (data[i] << 4) + 0x0f; ++ ++} ++ ++ ++ ++static void do_scanning(struct work_struct *work) ++{ ++ struct usb_aes2501 *dev; ++ ++ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ ++ ++ uint8_t *raw, *cooked; ++ unsigned swidth = 192; ++ unsigned sheight = 16; ++ unsigned maxstrip = 150; ++ unsigned nstrips, height, mindiff_sum, mindiff_sum_r; ++ ++ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ ++ ++ dev = container_of(work, struct usb_aes2501, scan_work); ++ ++ ++ ++ ++ ++ ++ setup_aes2501(dev); ++ ++ while (!detect_finger_on_aes2501(dev)) ++ { ++ if (dev->stop_scan) ++ { ++ PRINTK_INFO("aborting scan due to module removal\n"); ++ return; ++ } ++ }; ++ ++ /* We don't need physical continuity of allocated memory */ ++ raw = (uint8_t *)vmalloc((3 * maxstrip * sheight * swidth) / 2); ++ if (raw == NULL) ++ { ++ PRINTK_CRIT("failed to allocate memory\n"); ++ return; ++ } ++ ++ cooked = raw + (maxstrip * sheight * swidth)/2; ++ ++ ++ ++ printk(KERN_INFO "Raw is 0x%p\n", raw); ++ ++ ++ printk(KERN_INFO "Scanning...\n"); ++ nstrips = read_fingerprint_on_aes2501(dev, raw, maxstrip); ++ ++ printk(KERN_INFO "Assembling...\n"); ++ ++ ++ height = assemble(raw, cooked, 16, 192, nstrips, 0, &mindiff_sum); ++ height = assemble(raw, cooked, 16, 192, nstrips, 1, &mindiff_sum_r); ++ ++ ++ printk(KERN_INFO "Mindiff normal: %d, mindiff reversed: %d\n", mindiff_sum, mindiff_sum_r); ++ ++ if (mindiff_sum_r < mindiff_sum) ++ { ++ PRINTK_INFO("reversed image detected\n"); ++ } ++ else ++ { ++ height = assemble(raw, cooked, 16, 192, nstrips, 0, &mindiff_sum); ++ } ++ ++ printk(KERN_INFO "First height :: %d\n", height); ++ ++#if 0 ++ if (height < 100) { ++ /* It was a "touch", not a finger scan. */ ++ printk(KERN_INFO "Was only a 'touch' ;( [%d]\n", height); ++ /*break;*/ ++ } ++ else ++ ++ { ++ //store_new_aes2501_pnm(cooked, swidth, height); ++ height = assemble(raw, cooked, nstrips, 1, sensor_reversed); ++ printk(KERN_INFO "Second height :: %d\n", height); ++ store_new_aes2501_pnm(cooked, swidth, height); ++ } ++#endif ++ store_new_aes2501_pnm(cooked, swidth, height); ++ standby_aes2501(dev); ++ ++ vfree(raw); ++ ++ flag = 1; ++ wake_up_interruptible(&wq); ++ ++ ++} ++ ++ ++static int aes2501_open(struct inode *inode, struct file *file) ++{ ++ struct usb_aes2501 *dev; ++ ++ //return 0; ++ ++ ++ dev = _dev; ++ ++ printk(KERN_INFO "Plop !\n"); ++ ++ ++ return 0; ++} ++ ++ ++ ++ ++ ++ ++/* ++ * usb class driver info in order to get a minor number from the usb core, ++ * and to have the device registered with the driver core ++ */ ++static struct usb_class_driver aes2501_class = { ++ .name = "aes2501%d", ++ .fops = &aes2501_fops, ++ .minor_base = USB_AES2501_MINOR_BASE, ++}; ++ ++static int aes2501_probe(struct usb_interface *interface, const struct usb_device_id *id) ++{ ++ int retval; ++ struct usb_aes2501 *dev; ++ struct usb_host_interface *iface_desc; ++ __u8 i; ++ struct usb_endpoint_descriptor *endpoint; ++ __u16 buffer_size; ++ ++ ++ ++#if 0 ++ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ ++ ++ uint8_t *raw, *cooked; ++ unsigned swidth = 192; ++ unsigned sheight = 16; ++ unsigned maxstrip = 150; ++ unsigned nstrips, height; ++ ++ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ ++ ++ ++ raw = (uint8_t *)__get_free_page(GFP_KERNEL);//kmalloc((3 * maxstrip * sheight * swidth) / 2, GFP_KERNEL); ++ cooked = raw + (maxstrip * sheight * swidth)/2; ++#endif ++ ++ printk(KERN_INFO "aes2501 probe !\n"); ++ ++ ++ retval = -ENOMEM; ++ ++ /* Allocate memory for our device state and initialize it */ ++ ++ dev = kzalloc(sizeof(*dev), GFP_KERNEL); ++ if (dev == NULL) ++ { ++ PRINTK_CRIT("out of memory\n"); ++ goto error; ++ } ++ ++ _dev = dev; ++ ++ dev->stop_scan = 0; ++ ++ kref_init(&dev->kref); ++ sema_init(&dev->limit_sem, WRITES_IN_FLIGHT); ++ mutex_init(&dev->io_mutex); ++ ++ dev->udev = usb_get_dev(interface_to_usbdev(interface)); ++ dev->interface = interface; ++ ++ printk(KERN_INFO "num_altsetting == %d\n", interface->num_altsetting); ++ ++ /** ++ * Set up the endpoint information. ++ * Use only the first bulk-in and bulk-out endpoints. ++ */ ++ ++ iface_desc = interface->cur_altsetting; ++ ++ printk(KERN_INFO "BULK COUNT %d\n", iface_desc->desc.bNumEndpoints); ++ ++ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) ++ { ++ endpoint = &iface_desc->endpoint[i].desc; ++ ++ if (!dev->bulk_in_endpointAddr && /*usb_endpoint_is_bulk_in(endpoint))*/ ++ ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ++ == USB_DIR_IN) && ++ ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ++ == USB_ENDPOINT_XFER_BULK)) ++ { ++ /* We found a bulk in endpoint */ ++ buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); ++ dev->bulk_in_size = buffer_size; ++ dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; ++ dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); ++ ++ printk(KERN_INFO "BULK IN %d ; size = %d\n", i, buffer_size); ++ ++ if (dev->bulk_in_buffer == NULL) ++ { ++ PRINTK_CRIT("could not allocate bulk_in_buffer\n"); ++ goto error; ++ } ++ ++ } ++ ++ if (!dev->bulk_out_endpointAddr && /*usb_endpoint_is_bulk_out(endpoint))*/ ++ ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ++ == USB_DIR_OUT) && ++ ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ++ == USB_ENDPOINT_XFER_BULK)) ++ { ++ printk(KERN_INFO "BULK OUT %d\n", i); ++ ++ /* We found a bulk out endpoint */ ++ dev->bulk_out_endpointAddr = endpoint->bEndpointAddress; ++ } ++ ++ } ++ ++ if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) ++ { ++ PRINTK_CRIT("could not find both bulk-in and bulk-out endpoints\n"); ++ goto error; ++ } ++ ++/* ++ dev->once_tasklet = kzalloc(sizeof(*dev->once_tasklet), GFP_KERNEL); ++ if (dev->once_tasklet == NULL) ++ { ++ PRINTK_CRIT("out of memory\n"); ++ goto error; ++ } ++*/ ++ /* Save our data pointer in this interface device */ ++ usb_set_intfdata(interface, dev); ++ ++ /* We can register the device now, as it is ready */ ++ retval = usb_register_dev(interface, &aes2501_class); ++ if (retval) { ++ /* something prevented us from registering this driver */ ++ PRINTK_CRIT("not able to get a minor for this device\n"); ++ usb_set_intfdata(interface, NULL); ++ goto error; ++ } ++ ++ /* Let the user know what node this device is now attached to */ ++ PRINTK_INFO("device now attached to aes2501-%d\n", interface->minor); ++ ++#if 0 ++ setup_aes2501(dev); ++ ++ while (!detect_finger_on_aes2501(dev)); ++ ++ ++ printk(KERN_INFO "Raw is 0x%p\n", raw); ++ ++ ++ printk(KERN_INFO "Scanning...\n"); ++ nstrips = read_fingerprint_on_aes2501(dev, raw, maxstrip); ++ ++ printk(KERN_INFO "Assembling...\n"); ++ ++ height = assemble(raw, cooked, nstrips, 1); ++ if (height < 100) { ++ /* It was a "touch", not a finger scan. */ ++ printk(KERN_INFO "Was only a 'touch' ;(\n"); ++ /*break;*/ ++ } ++ else ++ { ++ store_new_aes2501_pnm(cooked, swidth, height); ++ height = assemble(raw, cooked, nstrips, 0); ++ store_new_aes2501_pnm(cooked, swidth, height); ++ } ++ ++ standby_aes2501(dev); ++#endif ++ ++ return 0; ++ ++error: ++ if (dev != NULL) ++ kref_put(&dev->kref, aes2501_delete); ++ ++ return retval; ++ ++} ++ ++ ++static void aes2501_disconnect(struct usb_interface *interface) ++{ ++ int minor; ++ struct usb_aes2501 *dev; ++ ++ minor = interface->minor; ++ ++ /* Prevent aes2501_open() from racing aes2501_disconnect() */ ++ lock_kernel(); ++ ++ dev = usb_get_intfdata(interface); ++ usb_set_intfdata(interface, NULL); ++ ++ /* Give back our minor */ ++ usb_deregister_dev(interface, &aes2501_class); ++ ++ /* Prevent more I/O from starting */ ++ mutex_lock(&dev->io_mutex); ++ dev->interface = NULL; ++ mutex_unlock(&dev->io_mutex); ++ ++ unlock_kernel(); ++ ++ /* Decrement our usage count */ ++ kref_put(&dev->kref, aes2501_delete); ++ ++ PRINTK_INFO("aes2501 device #%d now disconnected\n", minor); ++ ++ ++ ++ ++ printk(KERN_INFO "aes2501 disconnect !\n"); ++ ++ ++} ++ ++ ++static struct usb_driver aes2501_driver = { ++ .name = "aes2501", ++ .probe = aes2501_probe, ++ .disconnect = aes2501_disconnect, ++ .id_table = id_table, ++}; ++ ++ ++static int __init aes2501_init(void) ++{ ++ int retval; ++ ++ comm_queue = create_singlethread_workqueue("aes2501"); ++ if (comm_queue == NULL) { ++ PRINTK_CRIT("could not create work queue\n"); ++ return -ENOMEM; ++ } ++ ++ retval = usb_register(&aes2501_driver); ++ if (retval == -EINVAL) ++ { ++ printk(KERN_ERR "usb_register failed. Error number %d\n", retval); ++ destroy_workqueue(comm_queue); ++ return retval; ++ } ++ ++ return 0; ++ ++} ++ ++static void __exit aes2501_exit(void) ++{ ++ _dev->stop_scan = 1; ++ destroy_workqueue(comm_queue); ++ usb_deregister(&aes2501_driver); ++} ++ ++module_init(aes2501_init); ++module_exit(aes2501_exit); ++ ++MODULE_AUTHOR("Cyrille Bagard"); ++MODULE_DESCRIPTION("AES 2501 fingerprint scanner driver"); ++MODULE_LICENSE("GPL"); +diff -Nurp linux-2.6.37/3rdparty/aes2501/aes2501.h linux-2.6.37.3rdparty/3rdparty/aes2501/aes2501.h +--- linux-2.6.37/3rdparty/aes2501/aes2501.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/aes2501/aes2501.h 2008-01-14 03:07:30.000000000 +0200 +@@ -0,0 +1,40 @@ ++ ++/* ++ * aes2501.h -- AuthenTec AES2501 Fingerprint Sensor Driver for Linux ++ * ++ * Maintainer: Cyrille Bagard ++ * ++ * Copyright (C) 2007 Cyrille Bagard ++ * ++ * This file is part of the AES2501 driver. ++ * ++ * the AES2501 driver 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. ++ * ++ * the AES2501 driver 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 the AES2501 driver; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ */ ++ ++ ++#ifndef __AES2501_H ++#define __AES2501_H ++ ++ ++#define AES2501_IOC_MAGIC 'N' ++ ++ ++#define AES2501_IOC_TEST _IOW(AES2501_IOC_MAGIC, 1, int) ++ ++ ++ ++ ++#endif /* __AES2501_H */ +diff -Nurp linux-2.6.37/3rdparty/aes2501/aes2501_regs.h linux-2.6.37.3rdparty/3rdparty/aes2501/aes2501_regs.h +--- linux-2.6.37/3rdparty/aes2501/aes2501_regs.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/aes2501/aes2501_regs.h 2008-01-14 03:07:30.000000000 +0200 +@@ -0,0 +1,464 @@ ++ ++/* ++ * aes2501_regs.h -- AuthenTec AES2501 Fingerprint Sensor Driver for Linux ++ * ++ * Maintainer: Cyrille Bagard ++ * ++ * Copyright (C) 2007 Cyrille Bagard ++ * ++ * This file is part of the AES2501 driver. ++ * ++ * the AES2501 driver 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. ++ * ++ * the AES2501 driver 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 the AES2501 driver; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ * ++ */ ++ ++ ++#ifndef __AES2501_REGS_H ++#define __AES2501_REGS_H ++ ++ ++ ++/* ++ * AES2501 Control Register 1 (CTRL1) ++ */ ++ ++#define AES2501_REG_CTRL1 0x80 ++ ++#define AES2501_CTRL1_MASTER_RESET 0x01 /* Master reset, same as Power On Reset */ ++#define AES2501_CTRL1_SCAN_RESET 0x02 /* Scan reset: stop and restart the scan sequencer */ ++#define AES2501_CTRL1_REG_UPDATE 0x04 /* 1 = continuously updated, 0 = updated prior to starting a scan */ ++ ++ ++/* ++ * AES2501 Control Register 2 (CTRL2) ++ */ ++ ++#define AES2501_REG_CTRL2 0x81 ++ ++#define AES2501_CTRL2_CONTINUOUS 0x01 /* 1 = continuous scans, 0 = single scans */ ++#define AES2501_CTRL2_READ_REGS 0x02 /* Read the current state of the local registers in the Sensor IC */ ++#define AES2501_CTRL2_SET_ONE_SHOT 0x04 /* Set the one-shot flip-flop */ ++#define AES2501_CTRL2_CLR_ONE_SHOT 0x08 /* Clear the one-shot flip-flop */ ++#define AES2501_CTRL2_READ_ID 0x10 /* Read the ID register of the chip */ ++ ++ ++/* ++ * AES2501 Excitation Common Control Register (EXCITCTRL) ++ */ ++ ++#define AES2501_REG_EXCITCTRL 0x82 ++ ++#define AES2501_EXCITCTRL_LO_PWR 0x01 /* If set, enable detection in sleep/suspend mode */ ++#define AES2501_EXCITCTRL_AUTO_CAL 0x02 /* If set, perform finger detection calibration */ ++#define AES2501_EXCITCTRL_SGC_ENABLE 0x04 /* ??? */ ++#define AES2501_EXCITCTRL_SGC_RESTART 0x08 /* ??? */ ++ ++#define AES2501_EXCITCTRL_EXCIT_SQR 0x20 /* Select the (1=square | 0=sine) wave finger drive signal */ ++#define AES2501_EXCITCTRL_EXCIT_BOOST 0x10 /* TODO: understand this part */ ++ ++ ++/* ++ * AES2501 Detect Control Register (DETCTRL) ++ */ ++ ++#define AES2501_REG_DETCTRL 0x83 ++ ++enum aes2501_detection_rate { ++ ++ AES2501_DETCTRL_DRATE_CONTINUOUS = 0x00, /* Detection cycles occur continuously */ ++ AES2501_DETCTRL_DRATE_16_MS = 0x01, /* Detection cycles occur every 16.62 ms */ ++ AES2501_DETCTRL_DRATE_31_MS = 0x02, /* Detection cycles occur every 31.24 ms */ ++ AES2501_DETCTRL_DRATE_62_MS = 0x03, /* Detection cycles occur every 62.50 ms */ ++ AES2501_DETCTRL_DRATE_125_MS = 0x04, /* Detection cycles occur every 125.0 ms */ ++ AES2501_DETCTRL_DRATE_250_MS = 0x05, /* Detection cycles occur every 250.0 ms */ ++ AES2501_DETCTRL_DRATE_500_MS = 0x06, /* Detection cycles occur every 500.0 ms */ ++ AES2501_DETCTRL_DRATE_1_S = 0x07 /* Detection cycles occur every 1 s */ ++ ++}; ++ ++enum aes2501_settling_delay { ++ ++ AES2501_DETCTRL_SDELAY_31_MS = 0x00, /* 31.25 ms */ ++ AES2501_DETCTRL_SSDELAY_62_MS = 0x10, /* 62.5 ms */ ++ AES2501_DETCTRL_SSDELAY_125_MS = 0x20, /* 125 ms */ ++ AES2501_DETCTRL_SSDELAY_250_MS = 0x30 /* 250 ms */ ++ ++}; ++ ++ ++ ++ ++ ++/* ++ * AES2501 Column Scan Rate Register (COLSCAN) ++ */ ++ ++#define AES2501_REG_COLSCAN 0x88 ++ ++enum aes2501_col_scan_rate { ++ ++ AES2501_COLSCAN_SRATE_32_US = 0x00, /* 32 us */ ++ AES2501_COLSCAN_SRATE_64_US = 0x01, /* 64 us */ ++ AES2501_COLSCAN_SRATE_128_US = 0x02, /* 128 us */ ++ AES2501_COLSCAN_SRATE_256_US = 0x03, /* 256 us */ ++ AES2501_COLSCAN_SRATE_512_US = 0x04, /* 512 us */ ++ AES2501_COLSCAN_SRATE_1024_US = 0x05, /* 1024 us */ ++ AES2501_COLSCAN_SRATE_2048_US = 0x06, /* 2048 us */ ++ ++}; ++ ++ ++/* ++ * AES2501 Measure Drive Register (MEASDRV) ++ */ ++ ++#define AES2501_REG_MEASDRV 0x89 ++ ++enum aes2501_mesure_drive { ++ ++ AES2501_MEASDRV_MDRIVE_0_325 = 0x00, /* 0.325 Vpp */ ++ AES2501_MEASDRV_MDRIVE_0_65 = 0x01, /* 0.65 Vpp */ ++ AES2501_MEASDRV_MDRIVE_1_3 = 0x02, /* 1.3 Vpp */ ++ AES2501_MEASDRV_MDRIVE_2_6 = 0x03 /* 2.6 Vpp */ ++ ++}; ++ ++#define AES2501_MEASDRV_SQUARE 0x20 /* Select (1=square | 0=sine) wave drive during measure */ ++#define AES2501_MEASDRV_MEASURE_SQUARE 0x10 /* 0 = use mesure drive setting, 1 = when sine wave is selected */ ++ ++ ++/* ++ * AES2501 Measure Frequency Register (MEASFREQ) ++ */ ++ ++#define AES2501_REG_MEASFREQ 0x8a ++ ++enum aes2501_measure_freq { ++ ++ AES2501_MEASFREQ_125K = 0x01, /* 125 kHz */ ++ AES2501_MEASFREQ_250K = 0x02, /* 250 kHz */ ++ AES2501_MEASFREQ_500K = 0x03, /* 500 kHz */ ++ AES2501_MEASFREQ_1M = 0x04, /* 1 MHz */ ++ AES2501_MEASFREQ_2M = 0x05 /* 2 MHz */ ++ ++}; ++ ++ ++ ++ ++/* ++ * AES2501 Demod Phase 2 Register (DEMODPHASE2) ++ */ ++ ++#define AES2501_REG_DEMODPHASE2 0x8c ++ ++#define DEMODPHASE_NONE 0x00 ++ ++#define DEMODPHASE_180_00 0x40 /* 180 degrees */ ++#define DEMODPHASE_2_81 0x01 /* 2.8125 degrees */ ++ ++ ++/* ++ * AES2501 Demod Phase 1 Register (DEMODPHASE1) ++ */ ++ ++#define AES2501_REG_DEMODPHASE1 0x8d ++ ++#define DEMODPHASE_1_40 0x40 /* 1.40625 degrees */ ++#define DEMODPHASE_0_02 0x01 /* 0.02197256 degrees */ ++ ++ ++/* ++ * AES2501 Channel Gain Register (CHANGAIN) ++ */ ++ ++#define AES2501_REG_CHANGAIN 0x8e ++ ++enum aes2501_sensor_gain1 { ++ ++ AES2501_CHANGAIN_STAGE1_2X = 0x00, /* 2x */ ++ AES2501_CHANGAIN_STAGE1_4X = 0x01, /* 4x */ ++ AES2501_CHANGAIN_STAGE1_8X = 0x02, /* 8x */ ++ AES2501_CHANGAIN_STAGE1_16X = 0x03 /* 16x */ ++ ++}; ++ ++enum aes2501_sensor_gain2 { ++ ++ AES2501_CHANGAIN_STAGE2_2X = 0x00, /* 2x */ ++ AES2501_CHANGAIN_STAGE2_4X = 0x10, /* 4x */ ++ AES2501_CHANGAIN_STAGE2_8X = 0x20, /* 8x */ ++ AES2501_CHANGAIN_STAGE2_16X = 0x30 /* 16x */ ++ ++}; ++ ++ ++ ++/* ++ * AES2501 A/D Reference High Register (ADREFHI) ++ */ ++ ++#define AES2501_REG_ADREFHI 0x91 ++ ++ ++/* ++ * AES2501 A/D Reference Low Register (ADREFLO) ++ */ ++ ++#define AES2501_REG_ADREFLO 0x92 ++ ++ ++/* ++ * AES2501 Start Row Register (STRTROW) ++ */ ++ ++#define AES2501_REG_STRTROW 0x93 ++ ++ ++/* ++ * AES2501 End Row Register (ENDROW) ++ */ ++ ++#define AES2501_REG_ENDROW 0x94 ++ ++ ++/* ++ * AES2501 Start Column Register (STRTCOL) ++ */ ++ ++#define AES2501_REG_STRTCOL 0x95 ++ ++ ++/* ++ * AES2501 End Column Register (ENDCOL) ++ */ ++ ++#define AES2501_REG_ENDCOL 0x96 ++ ++ ++/* ++ * AES2501 Data Format Register (DATFMT) ++ */ ++ ++#define AES2501_REG_DATFMT 0x97 ++ ++#define AES2501_DATFMT_EIGHT 0x40 /* 1 = 8-bit data, 0 = 4-bit data */ ++#define AES2501_DATFMT_LOW_RES 0x20 /* TODO: understand this part */ ++#define AES2501_DATFMT_BIN_IMG 0x10 /* TODO: understand this part */ ++ ++/* TODO: Threshold */ ++ ++ ++/* ++ * AES2501 Image Data Control Register (IMAGCTRL) ++ */ ++ ++#define AES2501_REG_IMAGCTRL 0x98 ++ ++#define AES2501_IMAGCTRL_IMG_DATA_DISABLE 0x01 /* If set, image data message and authentication message are not returned when imaging */ ++#define AES2501_IMAGCTRL_HISTO_DATA_ENABLE 0x02 /* if set, send histogram message when imaging */ ++#define AES2501_IMAGCTRL_HISTO_EACH_ROW 0x04 /* A histo message is sent at the end of (1=each row | 0 = scanning) */ ++#define AES2501_IMAGCTRL_HISTO_FULL_ARRAY 0x08 /* 1 = full image array, 0 = 64x64 center */ ++#define AES2501_IMAGCTRL_REG_FIRST 0x10 /* Registers are returned (1=before | 0=after) image data */ ++#define AES2501_IMAGCTRL_TST_REG_ENABLE 0x20 /* If set, Test Registers are returned with register messages */ ++ ++ ++ ++ ++ ++ ++ ++ ++/* ++ * AES2501 Status Register (STAT) ++ */ ++ ++#define AES2501_REG_STAT 0x9a ++ ++#define AES2501_STAT_SCAN 0x0f /* Scan state */ ++#define AES2501_STAT_ERROR 0x10 /* Framing error */ ++#define AES2501_STAT_PAUSED 0x20 /* Scan paused */ ++#define AES2501_STAT_RESET 0x40 /* Reset occurred */ ++ ++enum aes2501_scan_state { ++ ++ STATE_WAITING_FOR_FINGER = 0x00, /* Waiting for finger */ ++ STATE_FINGER_SETTLING_DELAY = 0x01, /* In Finger settling delay */ ++ STATE_POWER_UP_DELAY = 0x02, /* In power up delay */ ++ STATE_WAITING_TO_START_SCAN = 0x03, /* Waiting to start image scan */ ++ STATE_PRELOADING_SUBARRAY_0 = 0x04, /* Pre-loading subarray 0 */ ++ STATE_SETUP_FOR_ROW_ADVANCE = 0x05, /* Setup for row advance */ ++ STATE_WAITING_FOR_ROW_ADVANCE = 0x06, /* Waiting for row advance */ ++ STATE_PRELOADING_COL_0 = 0x07, /* Pre-loading column 0 */ ++ STATE_SETUP_FOR_COL_ADVANCE = 0x08, /* Setup for column advance */ ++ STATE_WAITING_FOR_COL_ADVANCE = 0x09, /* Waiting for column advance */ ++ STATE_WAITING_FOR_SCAN_START = 0x0a, /* Waiting for scan start */ ++ STATE_WAITING_FOR_SCAN_END = 0x0b, /* Waiting for scan end */ ++ STATE_WAITING_FOR_ROW_SETUP = 0x0c, /* Waiting for row setup */ ++ STATE_WAITING_FOR_COL_TIME = 0x0d, /* Waiting for one column time (depends on scan rate) */ ++ STATE_WAITING_FOR_QUEUED_DATA = 0x0e, /* Waiting for queued data transmission to be completed */ ++ STATE_WAIT_FOR_128_US = 0x0f /* Wait for 128 us */ ++ ++}; ++ ++ ++/* ++ * AES2501 Challenge Word 1 Register (CHWORD1) ++ */ ++ ++#define AES2501_REG_CHWORD1 0x9b ++ ++#define AES2501_CHWORD1_IS_FINGER 0x01 /* If set, finger is present */ ++ ++ ++/* ++ * AES2501 Challenge Word 2 Register (CHWORD2) ++ */ ++ ++#define AES2501_REG_CHWORD2 0x9c ++ ++ ++/* ++ * AES2501 Challenge Word 3 Register (CHWORD3) ++ */ ++ ++#define AES2501_REG_CHWORD3 0x9d ++ ++ ++/* ++ * AES2501 Challenge Word 4 Register (CHWORD4) ++ */ ++ ++#define AES2501_REG_CHWORD4 0x9e ++ ++ ++/* ++ * AES2501 Challenge Word 5 Register (CHWORD5) ++ */ ++ ++#define AES2501_REG_CHWORD5 0x9f ++ ++ ++ ++ ++ ++/* ++ * AES2501 Test Register 1 (TREG1) ++ */ ++ ++#define AES2501_REG_TREG1 0xa1 ++ ++#define AES2501_TREG1_SBIAS_UNLCK 0x10 /* 1 = unlock the controlling of sense amp bias, 0 = sense amp bias changes */ ++ ++enum aes2501_sense_amp_bias { ++ ++ AES2501_TREG1_SAMP_BIAS_2_UA = 0x00, /* 2.5 uA */ ++ AES2501_TREG1_SAMP_BIAS_5_UA = 0x01, /* 5 uA */ ++ AES2501_TREG1_SAMP_BIAS_8_UA = 0x02, /* 8 uA */ ++ AES2501_TREG1_SAMP_BIAS_10_UA = 0x03 /* 10 uA */ ++ ++}; ++ ++ ++ ++ ++/* ++ * AES2501 Auto-Calibration Offset Register (AUTOCALOFFSET) ++ */ ++ ++#define AES2501_REG_AUTOCALOFFSET 0xa8 ++ ++ ++ ++ ++ ++/* ++ * AES2501 Test Register C (TREGC) ++ */ ++ ++#define AES2501_REG_TREGC 0xac ++ ++#define AES2501_TREGC_ENABLE 0x01 /* Enable the reading of the register in TREGD */ ++ ++ ++/* ++ * AES2501 Test Register D (TREGD) ++ */ ++ ++#define AES2501_REG_TREGD 0xad ++ ++ ++ ++ ++ ++/* ++ * AES2501 Low Power Oscillator On Time Register (LPONT) ++ */ ++ ++#define AES2501_REG_LPONT 0xb4 ++ ++/* ++ * This register sets the low power oscillator on time. ++ * Units are roughly equivalent to milliseconds. ++ */ ++ ++#define AES2501_LPONT_MIN_VALUE 0x00 /* 0 ms */ ++#define AES2501_LPONT_MAX_VALUE 0x1f /* About 16 ms */ ++ ++ ++ ++#define ENUM_REG(reg) _ ## reg = reg ++ ++typedef enum _Aes2501Registers ++{ ++ ENUM_REG(AES2501_REG_CTRL1), ++ ENUM_REG(AES2501_REG_CTRL2), ++ ENUM_REG(AES2501_REG_EXCITCTRL), ++ ENUM_REG(AES2501_REG_DETCTRL), ++ ENUM_REG(AES2501_REG_COLSCAN), ++ ENUM_REG(AES2501_REG_MEASDRV), ++ ENUM_REG(AES2501_REG_MEASFREQ), ++ ENUM_REG(AES2501_REG_DEMODPHASE2), ++ ENUM_REG(AES2501_REG_DEMODPHASE1), ++ ENUM_REG(AES2501_REG_CHANGAIN), ++ ENUM_REG(AES2501_REG_ADREFHI), ++ ENUM_REG(AES2501_REG_ADREFLO), ++ ENUM_REG(AES2501_REG_STRTROW), ++ ENUM_REG(AES2501_REG_ENDROW), ++ ENUM_REG(AES2501_REG_STRTCOL), ++ ENUM_REG(AES2501_REG_ENDCOL), ++ ENUM_REG(AES2501_REG_DATFMT), ++ ENUM_REG(AES2501_REG_IMAGCTRL), ++ ENUM_REG(AES2501_REG_STAT), ++ ENUM_REG(AES2501_REG_CHWORD1), ++ ENUM_REG(AES2501_REG_CHWORD2), ++ ENUM_REG(AES2501_REG_CHWORD3), ++ ENUM_REG(AES2501_REG_CHWORD4), ++ ENUM_REG(AES2501_REG_CHWORD5), ++ ENUM_REG(AES2501_REG_TREG1), ++ ENUM_REG(AES2501_REG_AUTOCALOFFSET), ++ ENUM_REG(AES2501_REG_TREGC), ++ ENUM_REG(AES2501_REG_TREGD), ++ ENUM_REG(AES2501_REG_LPONT) ++ ++} Aes2501Registers; ++ ++ ++#define FIRST_AES2501_REG 0x80 ++#define LAST_AES2501_REG 0x9f ++ ++ ++ ++#endif /* __AES2501_REGS_H */ +diff -Nurp linux-2.6.37/3rdparty/aes2501/ChangeLog linux-2.6.37.3rdparty/3rdparty/aes2501/ChangeLog +--- linux-2.6.37/3rdparty/aes2501/ChangeLog 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/aes2501/ChangeLog 2008-01-14 03:07:30.000000000 +0200 +@@ -0,0 +1,95 @@ ++2007-11-05 Cyrille Bagard ++ ++ * aes2501.c: ++ Apply Vasily Khoruzhick's new patch: rewrite image processing functions. ++ Thus, there should be no more significant common points with aes2501-wy. ++ ++2007-11-05 Cyrille Bagard ++ ++ * aes2501.c: ++ In order to respect the license of aes2501-wy, on which this driver is ++ based, begin to rewrite some functions. Thus, better handle histograms. ++ One more strip is often processed, but that is more logical like this. ++ ++ * aes2501_regs.h: ++ Enumerate all used registers for convenience. ++ ++2007-11-03 Cyrille Bagard ++ ++ * aes2501.c: ++ Clean the code. Take care of signals when processes are awaking. ++ Apply Vasily Khoruzhick's new patch: autodetect picture reversing needs ++ and fix kernel oops in case of module removal. ++ ++ * Makefile: ++ Remove hidden files and clean the rules. KERNELDIR has to be overrided ++ from the sheel if needed now. ++ ++2007-10-29 Cyrille Bagard ++ ++ * aes2501.c: ++ Apply Vasily Khoruzhick's patch and thus increase the resulting pictures ++ quality. Many thanks to him ! ++ ++ * Makefile: ++ Add two new rules: usertest and clean. ++ ++ * usertest.c: ++ Initial commit. ++ ++2007-08-27 Cyrille Bagard ++ ++ * aes2501.c: ++ Make INIT_WORK macro working with 2.6.20+ kernels. Many thanks to ++ Miguel Gea Milvaques for the patch ! ++ ++2007-06-13 Cyrille Bagard ++ ++ * aes2501.c: ++ * aes2501_regs.h: ++ Complete translation of all binary communications using well documented ++ registers and values (as often as possible). ++ ++2007-06-13 Cyrille Bagard ++ ++ * aes2501.c: ++ Increase communication speed by buffering bulk out. Output data ++ need to be flushed at the end now. ++ ++2007-06-13 Cyrille Bagard ++ ++ * aes2501.c: ++ * aes2501_regs.h: ++ Translate binary data used in finger detection. Some register values ++ still need to be understood. Note: some hex values are reserved bits ++ in registers. ++ ++2007-06-12 Cyrille Bagard ++ ++ * aes2501.c: ++ Begin the binary translation: the "standby" function now uses understood ++ instructions and prints debug status information if needed. CTRL2 register ++ value needs to be checked. ++ ++ * aes2501_regs.h: ++ Define the interesting hex values for the following registers: ++ CTRL2, STAT, TREGC and TREGD. ++ ++2007-06-12 Cyrille Bagard ++ ++ * aes2501.c: ++ Clean the driver a little bit by removing old piece of code to handle ++ a character device in the old way. ++ ++2007-06-12 Cyrille Bagard ++ ++ * aes2501.c: ++ Use an own work queue. Scanning now starts with the AES2501_IOC_TEST ++ ioctl command. Reading the /dev entry blocks until data is available. ++ ++2007-06-12 Cyrille Bagard ++ ++ * aes2501.c: ++ * aes2501.h: ++ * Makefile: ++ Initial [crappy] commit. +diff -Nurp linux-2.6.37/3rdparty/aes2501/Makefile linux-2.6.37.3rdparty/3rdparty/aes2501/Makefile +--- linux-2.6.37/3rdparty/aes2501/Makefile 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/aes2501/Makefile 2008-01-14 03:07:30.000000000 +0200 +@@ -0,0 +1,19 @@ ++ ++obj-m := aes2501.o ++ ++KERNELDIR ?= /lib/modules/$(shell uname -r)/build ++ ++PWD := $(shell pwd) ++ ++all: usertest ++ $(MAKE) -C $(KERNELDIR) M=$(PWD) ++ ++usertest: ++ gcc -I. -o usertest usertest.c ++ ++clean: ++ rm -f *.o *~ aes2501.ko aes2501.mod.c Module.symvers usertest ++ rm -rf .tmp_versions ++ rm -f .*.cmd ++ ++ +diff -Nurp linux-2.6.37/3rdparty/aes2501/usertest.c linux-2.6.37.3rdparty/3rdparty/aes2501/usertest.c +--- linux-2.6.37/3rdparty/aes2501/usertest.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/aes2501/usertest.c 2008-01-14 03:07:30.000000000 +0200 +@@ -0,0 +1,78 @@ ++/** ++ * AES2501 Device Driver ++ * Userspace test program ++ * ++ * Compile with: ++ * gcc -I. -o usertest usertest.c ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define BUFFER_SIZE 256 ++ ++ ++int main(int argc, char *argv[]) ++{ ++ int fd_in; ++ int fd_out; ++ char buffer[BUFFER_SIZE]; ++ size_t len; ++ ++ fd_in = -1; ++ fd_out = -1; ++ ++ ++ int data, rdata; ++ ++ ++ ++ fd_in = open("/dev/aes2501", O_RDONLY); ++ if (fd_in == -1) { ++ perror("open() -- "); ++ goto err; ++ } ++ ++ fd_out = open("/root/pic.pnm", O_CREAT | O_WRONLY); ++ if (fd_out == -1) { ++ perror("open() -- "); ++ goto err; ++ } ++ ++ ++ ++ data = 0x55555555; ++ ioctl(fd_in, AES2501_IOC_TEST, data); ++ //ioctl(fd_in, CASE2, &rdata); ++ ++ printf("IOCTL test: written: '%x' - received: '%x'\n", data, rdata); ++ ++ ++ ++ ++ /* Write the fingerprint */ ++ while ((len = read(fd_in, buffer, BUFFER_SIZE)) > 0) ++ write(fd_out, buffer, len); ++ ++ close(fd_in); ++ close(fd_out); ++ ++ return EXIT_SUCCESS; ++ ++ err: ++ ++ if (fd_in != -1) ++ close(fd_in); ++ ++ if (fd_out != -1) ++ close(fd_out); ++ ++ return EXIT_FAILURE; ++ ++} diff --git a/kernel/kernel/files/patches/mageia.old/3rd-aes2501-rmmod-oops-fix.patch b/kernel/kernel/files/patches/mageia.old/3rd-aes2501-rmmod-oops-fix.patch new file mode 100644 index 00000000..f11cc2e5 --- /dev/null +++ b/kernel/kernel/files/patches/mageia.old/3rd-aes2501-rmmod-oops-fix.patch @@ -0,0 +1,21 @@ +Prevent oops on module removal when we don't have the device available. + +Signed-off-by: Herton Ronaldo Krzesinski + +--- + linux-2.6.23/3rdparty/aes2501/aes2501.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff -p -up linux-2.6.23/3rdparty/aes2501/aes2501.c.orig linux-2.6.23/3rdparty/aes2501/aes2501.c +--- linux-2.6.23/3rdparty/aes2501/aes2501.c.orig 2008-01-13 23:37:38.000000000 -0200 ++++ linux-2.6.23/3rdparty/aes2501/aes2501.c 2008-01-13 23:38:26.000000000 -0200 +@@ -1616,7 +1616,8 @@ static int __init aes2501_init(void) + + static void __exit aes2501_exit(void) + { +- _dev->stop_scan = 1; ++ if (_dev) ++ _dev->stop_scan = 1; + destroy_workqueue(comm_queue); + usb_deregister(&aes2501_driver); + } diff --git a/kernel/kernel/files/patches/mageia.old/3rd-ndiswrapper-1.59.patch b/kernel/kernel/files/patches/mageia.old/3rd-ndiswrapper-1.59.patch new file mode 100644 index 00000000..63ccc093 --- /dev/null +++ b/kernel/kernel/files/patches/mageia.old/3rd-ndiswrapper-1.59.patch @@ -0,0 +1,26399 @@ +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/crt.c linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/crt.c +--- linux-3.12.2/3rdparty/ndiswrapper/crt.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/crt.c 2013-11-28 21:42:10.000000000 +0200 +@@ -0,0 +1,589 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * 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 "ntoskernel.h" ++#include "crt_exports.h" ++ ++#ifdef CONFIG_X86_64 ++/* Windows long is 32-bit, so strip single 'l' in integer formats */ ++static void strip_l_modifier(char *str) ++{ ++ char *ptr = str; ++ int in_format = 0; ++ char *lptr = NULL; ++ char last = 0; ++ char *end_ptr; ++ char *wptr; ++ ++ /* Replace single 'l' inside integer formats with '\0' */ ++ for (ptr = str; *ptr; ptr++) { ++ if (!in_format) { ++ if (*ptr == '%') ++ in_format = 1; ++ last = *ptr; ++ continue; ++ } ++ switch (*ptr) { ++ case 'd': ++ case 'i': ++ case 'o': ++ case 'u': ++ case 'x': ++ case 'X': ++ case 'p': ++ case 'n': ++ case 'm': ++ if (lptr) { ++ *lptr = '\0'; ++ lptr = NULL; ++ } ++ in_format = 0; ++ break; ++ case 'c': ++ case 'C': ++ case 's': ++ case 'S': ++ case 'f': ++ case 'e': ++ case 'E': ++ case 'g': ++ case 'G': ++ case 'a': ++ case 'A': ++ lptr = NULL; ++ in_format = 0; ++ break; ++ case '%': ++ lptr = NULL; ++ if (last == '%') ++ in_format = 0; ++ else ++ in_format = 1; /* ignore previous junk */ ++ break; ++ case 'l': ++ if (last == 'l') ++ lptr = NULL; ++ else ++ lptr = ptr; ++ break; ++ default: ++ break; ++ } ++ last = *ptr; ++ } ++ ++ /* Purge zeroes from the resulting string */ ++ end_ptr = ptr; ++ wptr = str; ++ for (ptr = str; ptr < end_ptr; ptr++) ++ if (*ptr != 0) ++ *(wptr++) = *ptr; ++ *wptr = 0; ++} ++ ++/* ++ * va_list on x86_64 Linux is designed to allow passing arguments in registers ++ * even to variadic functions. va_list is a structure holding pointers to the ++ * register save area, which holds the arguments passed in registers, and to ++ * the stack, which may have the arguments that did not fit the registers. ++ * va_list also holds offsets in the register save area for the next general ++ * purpose and floating point registers that the next va_arg() would fetch. ++ * ++ * Unlike Linux, the Windows va_list is just a pointer to the stack. No ++ * arguments are passed in the registers. That's why we construct the Linux ++ * va_list so that the register save area is never used. For that goal, we set ++ * the offsets to the maximal allowed values, meaning that the arguments passed ++ * in the registers have been exhausted. The values are 48 for general purpose ++ * registers (6 registers, 8 bytes each) and 304 for floating point registers ++ * (16 registers, 16 bytes each, on top of general purpose register). ++ */ ++ ++struct x86_64_va_list { ++ int gp_offset; ++ int fp_offset; ++ void *overflow_arg_area; ++ void *reg_save_area; ++}; ++ ++#define VA_LIST_DECL(_args) \ ++ va_list _args##new; \ ++ struct x86_64_va_list *_args##x; ++#define VA_LIST_PREP(_args) \ ++do { \ ++ _args##x = (struct x86_64_va_list *)&_args##new; \ ++ _args##x->gp_offset = 6 * 8; /* GP registers exhausted */ \ ++ _args##x->fp_offset = 6 * 8 + 16 * 16; /* FP registers exhausted */ \ ++ _args##x->overflow_arg_area = (void *)_args; \ ++ _args##x->reg_save_area = NULL; \ ++} while (0) ++#define VA_LIST_CONV(_args) (_args##new) ++#define VA_LIST_FREE(_args) ++#define FMT_DECL(_fmt) \ ++ char *_fmt##copy; \ ++ int _fmt##len; ++#define FMT_PREP(_fmt) \ ++do { \ ++ _fmt##len = strlen(format) + 1; \ ++ _fmt##copy = kmalloc(_fmt##len, irql_gfp()); \ ++ if (_fmt##copy) { \ ++ memcpy(_fmt##copy, format, _fmt##len); \ ++ strip_l_modifier(_fmt##copy); \ ++ } \ ++} while (0) ++#define FMT_CONV(_fmt) (_fmt##copy ? _fmt##copy : format) ++#define FMT_FREE(_fmt) kfree(_fmt##copy) ++ ++#else /* !CONFIG_X86_64 */ ++ ++#define VA_LIST_DECL(_args) ++#define VA_LIST_PREP(_args) ++#define VA_LIST_CONV(_args) (_args) ++#define VA_LIST_FREE(_args) ++#define FMT_DECL(_fmt) ++#define FMT_PREP(_fmt) ++#define FMT_CONV(_fmt) (format) ++#define FMT_FREE(_fmt) ++ ++#endif /* !CONFIG_X86_64 */ ++ ++__attribute__((format(printf, 2, 3))) ++noregparm INT WIN_FUNC(_win_sprintf,12) ++ (char *buf, const char *format, ...) ++{ ++ va_list args; ++ int res; ++ FMT_DECL(format) ++ ++ FMT_PREP(format); ++ va_start(args, format); ++ res = vsprintf(buf, FMT_CONV(format), args); ++ va_end(args); ++ FMT_FREE(format); ++ ++ TRACE2("buf: %p: %s", buf, buf); ++ return res; ++} ++ ++noregparm INT WIN_FUNC(swprintf,12) ++ (wchar_t *buf, const wchar_t *format, ...) ++{ ++ TODO(); ++ EXIT2(return 0); ++} ++ ++noregparm INT WIN_FUNC(_win_vsprintf,3) ++ (char *str, const char *format, va_list ap) ++{ ++ INT i; ++ VA_LIST_DECL(ap) ++ FMT_DECL(format) ++ ++ VA_LIST_PREP(ap); ++ FMT_PREP(format); ++ ++ i = vsprintf(str, FMT_CONV(format), VA_LIST_CONV(ap)); ++ TRACE2("str: %p: %s", str, str); ++ ++ FMT_FREE(format); ++ VA_LIST_FREE(ap); ++ EXIT2(return i); ++} ++ ++__attribute__((format(printf, 3, 4))) ++noregparm INT WIN_FUNC(_win_snprintf,12) ++ (char *buf, SIZE_T count, const char *format, ...) ++{ ++ va_list args; ++ int res; ++ FMT_DECL(format) ++ ++ FMT_PREP(format); ++ va_start(args, format); ++ res = vsnprintf(buf, count, FMT_CONV(format), args); ++ va_end(args); ++ TRACE2("buf: %p: %s", buf, buf); ++ ++ FMT_FREE(format); ++ return res; ++} ++ ++__attribute__((format(printf, 3, 4))) ++noregparm INT WIN_FUNC(_win__snprintf,12) ++ (char *buf, SIZE_T count, const char *format, ...) ++{ ++ va_list args; ++ int res; ++ FMT_DECL(format) ++ ++ FMT_PREP(format); ++ va_start(args, format); ++ res = vsnprintf(buf, count, FMT_CONV(format), args); ++ va_end(args); ++ TRACE2("buf: %p: %s", buf, buf); ++ ++ FMT_FREE(format); ++ return res; ++} ++ ++noregparm INT WIN_FUNC(_win_vsnprintf,4) ++ (char *str, SIZE_T size, const char *format, va_list ap) ++{ ++ INT i; ++ VA_LIST_DECL(ap) ++ FMT_DECL(format) ++ ++ VA_LIST_PREP(ap); ++ FMT_PREP(format); ++ ++ i = vsnprintf(str, size, FMT_CONV(format), VA_LIST_CONV(ap)); ++ TRACE2("str: %p: %s", str, str); ++ ++ FMT_FREE(format); ++ VA_LIST_FREE(ap); ++ EXIT2(return i); ++} ++ ++noregparm INT WIN_FUNC(_win__vsnprintf,4) ++ (char *str, SIZE_T size, const char *format, va_list ap) ++{ ++ INT i; ++ VA_LIST_DECL(ap) ++ FMT_DECL(format) ++ ++ VA_LIST_PREP(ap); ++ FMT_PREP(format); ++ ++ i = vsnprintf(str, size, FMT_CONV(format), VA_LIST_CONV(ap)); ++ TRACE2("str: %p: %s", str, str); ++ ++ FMT_FREE(format); ++ VA_LIST_FREE(ap); ++ EXIT2(return i); ++} ++ ++noregparm INT WIN_FUNC(_win__vsnwprintf,4) ++ (wchar_t *str, SIZE_T size, const wchar_t *format, va_list ap) ++{ ++ int ret; ++ ++ TODO(); /* format expansion not implemented */ ++ _win_wcsncpy(str, format, size); ++ ret = _win_wcslen(format); ++ if (ret >= size) ++ ret = -1; ++ return ret; ++} ++ ++noregparm char *WIN_FUNC(_win_strncpy,3) ++ (char *dst, char *src, SIZE_T n) ++{ ++ return strncpy(dst, src, n); ++} ++ ++noregparm SIZE_T WIN_FUNC(_win_strlen,1) ++ (const char *s) ++{ ++ return strlen(s); ++} ++ ++noregparm INT WIN_FUNC(_win_strncmp,3) ++ (const char *s1, const char *s2, SIZE_T n) ++{ ++ return strncmp(s1, s2, n); ++} ++ ++noregparm INT WIN_FUNC(_win_strcmp,2) ++ (const char *s1, const char *s2) ++{ ++ return strcmp(s1, s2); ++} ++ ++noregparm INT WIN_FUNC(_win_stricmp,2) ++ (const char *s1, const char *s2) ++{ ++ return stricmp(s1, s2); ++} ++ ++noregparm char *WIN_FUNC(_win_strncat,3) ++ (char *dest, const char *src, SIZE_T n) ++{ ++ return strncat(dest, src, n); ++} ++ ++noregparm INT WIN_FUNC(_win_wcscmp,2) ++ (const wchar_t *s1, const wchar_t *s2) ++{ ++ while (*s1 && *s1 == *s2) { ++ s1++; ++ s2++; ++ } ++ return *s1 - *s2; ++} ++ ++noregparm INT WIN_FUNC(_win_wcsicmp,2) ++ (const wchar_t *s1, const wchar_t *s2) ++{ ++ while (*s1 && tolower((char)*s1) == tolower((char)*s2)) { ++ s1++; ++ s2++; ++ } ++ return tolower((char)*s1) - tolower((char)*s2); ++} ++ ++noregparm SIZE_T WIN_FUNC(_win_wcslen,1) ++ (const wchar_t *s) ++{ ++ const wchar_t *t = s; ++ while (*t) ++ t++; ++ return t - s; ++} ++ ++noregparm wchar_t *WIN_FUNC(_win_wcsncpy,3) ++ (wchar_t *dest, const wchar_t *src, SIZE_T n) ++{ ++ const wchar_t *s; ++ wchar_t *d; ++ s = src + n; ++ d = dest; ++ while (src < s && (*d++ = *src++)) ++ ; ++ if (s > src) ++ memset(d, 0, (s - src) * sizeof(wchar_t)); ++ return dest; ++} ++ ++noregparm wchar_t *WIN_FUNC(_win_wcscpy,2) ++ (wchar_t *dest, const wchar_t *src) ++{ ++ wchar_t *d = dest; ++ while ((*d++ = *src++)) ++ ; ++ return dest; ++} ++ ++noregparm wchar_t *WIN_FUNC(_win_wcscat,2) ++ (wchar_t *dest, const wchar_t *src) ++{ ++ wchar_t *d; ++ d = dest; ++ while (*d) ++ d++; ++ while ((*d++ = *src++)) ++ ; ++ return dest; ++} ++ ++noregparm INT WIN_FUNC(_win_towupper,1) ++ (wchar_t c) ++{ ++ return toupper(c); ++} ++ ++noregparm INT WIN_FUNC(_win_towlower,1) ++ (wchar_t c) ++{ ++ return tolower(c); ++} ++ ++noregparm INT WIN_FUNC(_win_tolower,1) ++ (INT c) ++{ ++ return tolower(c); ++} ++ ++noregparm INT WIN_FUNC(_win_toupper,1) ++ (INT c) ++{ ++ return toupper(c); ++} ++ ++noregparm void *WIN_FUNC(_win_strcpy,2) ++ (void *to, const void *from) ++{ ++ return strcpy(to, from); ++} ++ ++noregparm char *WIN_FUNC(_win_strstr,2) ++ (const char *s1, const char *s2) ++{ ++ return strstr(s1, s2); ++} ++ ++noregparm char *WIN_FUNC(_win_strchr,2) ++ (const char *s, int c) ++{ ++ return strchr(s, c); ++} ++ ++noregparm char *WIN_FUNC(_win_strrchr,2) ++ (const char *s, int c) ++{ ++ return strrchr(s, c); ++} ++ ++noregparm void *WIN_FUNC(_win_memmove,3) ++ (void *to, void *from, SIZE_T count) ++{ ++ return memmove(to, from, count); ++} ++ ++noregparm void *WIN_FUNC(_win_memchr,3) ++ (const void *s, INT c, SIZE_T n) ++{ ++ return memchr(s, c, n); ++} ++ ++noregparm void *WIN_FUNC(_win_memcpy,3) ++ (void *to, const void *from, SIZE_T n) ++{ ++ return memcpy(to, from, n); ++} ++ ++noregparm void *WIN_FUNC(_win_memset,3) ++ (void *s, char c, SIZE_T count) ++{ ++ return memset(s, c, count); ++} ++ ++noregparm int WIN_FUNC(_win_memcmp,3) ++ (void *s1, void *s2, SIZE_T n) ++{ ++ return memcmp(s1, s2, n); ++} ++ ++noregparm void WIN_FUNC(_win_srand,1) ++ (UINT seed) ++{ ++ net_srandom(seed); ++} ++ ++noregparm int WIN_FUNC(rand,0) ++ (void) ++{ ++ char buf[6]; ++ int i, n; ++ ++ get_random_bytes(buf, sizeof(buf)); ++ for (n = i = 0; i < sizeof(buf); i++) ++ n += buf[i]; ++ return n; ++} ++ ++noregparm int WIN_FUNC(_win_atoi,1) ++ (const char *ptr) ++{ ++ int i = simple_strtol(ptr, NULL, 10); ++ return i; ++} ++ ++noregparm int WIN_FUNC(_win_isdigit,1) ++ (int c) ++{ ++ return isdigit(c); ++} ++ ++noregparm int WIN_FUNC(_win_isprint,1) ++ (int c) ++{ ++ return isprint(c); ++} ++ ++wstdcall s64 WIN_FUNC(_alldiv,2) ++ (s64 a, s64 b) ++{ ++ return a / b; ++} ++ ++wstdcall u64 WIN_FUNC(_aulldiv,2) ++ (u64 a, u64 b) ++{ ++ return a / b; ++} ++ ++wstdcall s64 WIN_FUNC(_allmul,2) ++ (s64 a, s64 b) ++{ ++ return a * b; ++} ++ ++wstdcall u64 WIN_FUNC(_aullmul,2) ++ (u64 a, u64 b) ++{ ++ return a * b; ++} ++ ++wstdcall s64 WIN_FUNC(_allrem,2) ++ (s64 a, s64 b) ++{ ++ return a % b; ++} ++ ++wstdcall u64 WIN_FUNC(_aullrem,2) ++ (u64 a, u64 b) ++{ ++ return a % b; ++} ++ ++regparm3 s64 WIN_FUNC(_allshl,2) ++ (s64 a, u8 b) ++{ ++ return a << b; ++} ++ ++regparm3 u64 WIN_FUNC(_aullshl,2) ++ (u64 a, u8 b) ++{ ++ return a << b; ++} ++ ++regparm3 s64 WIN_FUNC(_allshr,2) ++ (s64 a, u8 b) ++{ ++ return a >> b; ++} ++ ++regparm3 u64 WIN_FUNC(_aullshr,2) ++ (u64 a, u8 b) ++{ ++ return a >> b; ++} ++ ++int stricmp(const char *s1, const char *s2) ++{ ++ while (*s1 && tolower(*s1) == tolower(*s2)) { ++ s1++; ++ s2++; ++ } ++ return *s1 - *s2; ++} ++ ++void dump_bytes(const char *ctx, const u8 *from, int len) ++{ ++ int i, j; ++ u8 *buf; ++ ++ buf = kmalloc(len * 3 + 1, irql_gfp()); ++ if (!buf) { ++ ERROR("couldn't allocate memory"); ++ return; ++ } ++ for (i = j = 0; i < len; i++, j += 3) { ++ sprintf(&buf[j], "%02x ", from[i]); ++ } ++ buf[j] = 0; ++ printk(KERN_DEBUG "%s: %p: %s\n", ctx, from, buf); ++ kfree(buf); ++} +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/divdi3.c linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/divdi3.c +--- linux-3.12.2/3rdparty/ndiswrapper/divdi3.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/divdi3.c 2013-11-28 21:42:10.000000000 +0200 +@@ -0,0 +1,329 @@ ++/* 64-bit multiplication and division ++ Copyright (C) 1989, 1992-1999, 2000, 2001, 2002, 2003 ++ Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, write to the Free ++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ 02111-1307 USA. */ ++ ++#include ++#include ++ ++#if BITS_PER_LONG != 32 ++#error This is for 32-bit targets only ++#endif ++ ++typedef unsigned int UQItype __attribute__ ((mode (QI))); ++typedef int SItype __attribute__ ((mode (SI))); ++typedef unsigned int USItype __attribute__ ((mode (SI))); ++typedef int DItype __attribute__ ((mode (DI))); ++typedef unsigned int UDItype __attribute__ ((mode (DI))); ++#define Wtype SItype ++#define HWtype SItype ++#define DWtype DItype ++#define UWtype USItype ++#define UHWtype USItype ++#define UDWtype UDItype ++#define W_TYPE_SIZE 32 ++ ++#include "longlong.h" ++ ++#if defined(__BIG_ENDIAN) ++struct DWstruct { Wtype high, low;}; ++#elif defined(__LITTLE_ENDIAN) ++struct DWstruct { Wtype low, high;}; ++#else ++#error Unhandled endianity ++#endif ++typedef union { struct DWstruct s; DWtype ll; } DWunion; ++ ++/* Prototypes of exported functions. */ ++extern DWtype __divdi3 (DWtype u, DWtype v); ++extern DWtype __moddi3 (DWtype u, DWtype v); ++extern UDWtype __udivdi3 (UDWtype u, UDWtype v); ++extern UDWtype __umoddi3 (UDWtype u, UDWtype v); ++ ++static UDWtype ++__udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp) ++{ ++ DWunion ww; ++ DWunion nn, dd; ++ DWunion rr; ++ UWtype d0, d1, n0, n1, n2; ++ UWtype q0, q1; ++ UWtype b, bm; ++ ++ nn.ll = n; ++ dd.ll = d; ++ ++ d0 = dd.s.low; ++ d1 = dd.s.high; ++ n0 = nn.s.low; ++ n1 = nn.s.high; ++ ++#if !UDIV_NEEDS_NORMALIZATION ++ if (d1 == 0) ++ { ++ if (d0 > n1) ++ { ++ /* 0q = nn / 0D */ ++ ++ udiv_qrnnd (q0, n0, n1, n0, d0); ++ q1 = 0; ++ ++ /* Remainder in n0. */ ++ } ++ else ++ { ++ /* qq = NN / 0d */ ++ ++ if (d0 == 0) ++ d0 = 1 / d0; /* Divide intentionally by zero. */ ++ ++ udiv_qrnnd (q1, n1, 0, n1, d0); ++ udiv_qrnnd (q0, n0, n1, n0, d0); ++ ++ /* Remainder in n0. */ ++ } ++ ++ if (rp != NULL) ++ { ++ rr.s.low = n0; ++ rr.s.high = 0; ++ *rp = rr.ll; ++ } ++ } ++ ++#else /* UDIV_NEEDS_NORMALIZATION */ ++ ++ if (d1 == 0) ++ { ++ if (d0 > n1) ++ { ++ /* 0q = nn / 0D */ ++ ++ count_leading_zeros (bm, d0); ++ ++ if (bm != 0) ++ { ++ /* Normalize, i.e. make the most significant bit of the ++ denominator set. */ ++ ++ d0 = d0 << bm; ++ n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm)); ++ n0 = n0 << bm; ++ } ++ ++ udiv_qrnnd (q0, n0, n1, n0, d0); ++ q1 = 0; ++ ++ /* Remainder in n0 >> bm. */ ++ } ++ else ++ { ++ /* qq = NN / 0d */ ++ ++ if (d0 == 0) ++ d0 = 1 / d0; /* Divide intentionally by zero. */ ++ ++ count_leading_zeros (bm, d0); ++ ++ if (bm == 0) ++ { ++ /* From (n1 >= d0) /\ (the most significant bit of d0 is set), ++ conclude (the most significant bit of n1 is set) /\ (the ++ leading quotient digit q1 = 1). ++ ++ This special case is necessary, not an optimization. ++ (Shifts counts of W_TYPE_SIZE are undefined.) */ ++ ++ n1 -= d0; ++ q1 = 1; ++ } ++ else ++ { ++ /* Normalize. */ ++ ++ b = W_TYPE_SIZE - bm; ++ ++ d0 = d0 << bm; ++ n2 = n1 >> b; ++ n1 = (n1 << bm) | (n0 >> b); ++ n0 = n0 << bm; ++ ++ udiv_qrnnd (q1, n1, n2, n1, d0); ++ } ++ ++ /* n1 != d0... */ ++ ++ udiv_qrnnd (q0, n0, n1, n0, d0); ++ ++ /* Remainder in n0 >> bm. */ ++ } ++ ++ if (rp != NULL) ++ { ++ rr.s.low = n0 >> bm; ++ rr.s.high = 0; ++ *rp = rr.ll; ++ } ++ } ++#endif /* UDIV_NEEDS_NORMALIZATION */ ++ ++ else ++ { ++ if (d1 > n1) ++ { ++ /* 00 = nn / DD */ ++ ++ q0 = 0; ++ q1 = 0; ++ ++ /* Remainder in n1n0. */ ++ if (rp != NULL) ++ { ++ rr.s.low = n0; ++ rr.s.high = n1; ++ *rp = rr.ll; ++ } ++ } ++ else ++ { ++ /* 0q = NN / dd */ ++ ++ count_leading_zeros (bm, d1); ++ if (bm == 0) ++ { ++ /* From (n1 >= d1) /\ (the most significant bit of d1 is set), ++ conclude (the most significant bit of n1 is set) /\ (the ++ quotient digit q0 = 0 or 1). ++ ++ This special case is necessary, not an optimization. */ ++ ++ /* The condition on the next line takes advantage of that ++ n1 >= d1 (true due to program flow). */ ++ if (n1 > d1 || n0 >= d0) ++ { ++ q0 = 1; ++ sub_ddmmss (n1, n0, n1, n0, d1, d0); ++ } ++ else ++ q0 = 0; ++ ++ q1 = 0; ++ ++ if (rp != NULL) ++ { ++ rr.s.low = n0; ++ rr.s.high = n1; ++ *rp = rr.ll; ++ } ++ } ++ else ++ { ++ UWtype m1, m0; ++ /* Normalize. */ ++ ++ b = W_TYPE_SIZE - bm; ++ ++ d1 = (d1 << bm) | (d0 >> b); ++ d0 = d0 << bm; ++ n2 = n1 >> b; ++ n1 = (n1 << bm) | (n0 >> b); ++ n0 = n0 << bm; ++ ++ udiv_qrnnd (q0, n1, n2, n1, d1); ++ umul_ppmm (m1, m0, q0, d0); ++ ++ if (m1 > n1 || (m1 == n1 && m0 > n0)) ++ { ++ q0--; ++ sub_ddmmss (m1, m0, m1, m0, d1, d0); ++ } ++ ++ q1 = 0; ++ ++ /* Remainder in (n1n0 - m1m0) >> bm. */ ++ if (rp != NULL) ++ { ++ sub_ddmmss (n1, n0, n1, n0, m1, m0); ++ rr.s.low = (n1 << b) | (n0 >> bm); ++ rr.s.high = n1 >> bm; ++ *rp = rr.ll; ++ } ++ } ++ } ++ } ++ ++ ww.s.low = q0; ++ ww.s.high = q1; ++ return ww.ll; ++} ++ ++DWtype ++__divdi3 (DWtype u, DWtype v) ++{ ++ Wtype c = 0; ++ DWtype w; ++ ++ if (u < 0) ++ { ++ c = ~c; ++ u = -u; ++ } ++ if (v < 0) ++ { ++ c = ~c; ++ v = -v; ++ } ++ w = __udivmoddi4 (u, v, NULL); ++ if (c) ++ w = -w; ++ return w; ++} ++ ++DWtype ++__moddi3 (DWtype u, DWtype v) ++{ ++ Wtype c = 0; ++ DWtype w; ++ ++ if (u < 0) ++ { ++ c = ~c; ++ u = -u; ++ } ++ if (v < 0) ++ v = -v; ++ __udivmoddi4 (u, v, &w); ++ if (c) ++ w = -w; ++ return w; ++} ++ ++UDWtype ++__udivdi3 (UDWtype u, UDWtype v) ++{ ++ return __udivmoddi4 (u, v, NULL); ++} ++ ++UDWtype ++__umoddi3 (UDWtype u, UDWtype v) ++{ ++ UDWtype w; ++ ++ __udivmoddi4 (u, v, &w); ++ return w; ++} +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/hal.c linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/hal.c +--- linux-3.12.2/3rdparty/ndiswrapper/hal.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/hal.c 2013-11-28 21:42:10.000000000 +0200 +@@ -0,0 +1,157 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * 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 "ntoskernel.h" ++#include "hal_exports.h" ++ ++wstdcall void WIN_FUNC(WRITE_PORT_ULONG,2) ++ (ULONG_PTR port, ULONG value) ++{ ++ outl(value, port); ++} ++ ++wstdcall ULONG WIN_FUNC(READ_PORT_ULONG,1) ++ (ULONG_PTR port) ++{ ++ return inl(port); ++} ++ ++wstdcall void WIN_FUNC(WRITE_PORT_USHORT,2) ++ (ULONG_PTR port, USHORT value) ++{ ++ outw(value, port); ++} ++ ++wstdcall USHORT WIN_FUNC(READ_PORT_USHORT,1) ++ (ULONG_PTR port) ++{ ++ return inw(port); ++} ++ ++wstdcall void WIN_FUNC(WRITE_PORT_UCHAR,2) ++ (ULONG_PTR port, UCHAR value) ++{ ++ outb(value, port); ++} ++ ++wstdcall UCHAR WIN_FUNC(READ_PORT_UCHAR,1) ++ (ULONG_PTR port) ++{ ++ return inb(port); ++} ++ ++wstdcall void WIN_FUNC(WRITE_PORT_BUFFER_USHORT,3) ++ (ULONG_PTR port, USHORT *buf, ULONG count) ++{ ++ outsw(port, buf, count); ++} ++ ++wstdcall void WIN_FUNC(READ_PORT_BUFFER_USHORT,3) ++ (ULONG_PTR port, USHORT *buf, ULONG count) ++{ ++ insw(port, buf, count); ++} ++ ++wstdcall void WIN_FUNC(WRITE_PORT_BUFFER_ULONG,3) ++ (ULONG_PTR port, ULONG *buf, ULONG count) ++{ ++ outsl(port, buf, count); ++} ++ ++wstdcall void WIN_FUNC(READ_PORT_BUFFER_ULONG,3) ++ (ULONG_PTR port, ULONG *buf, ULONG count) ++{ ++ insl(port, buf, count); ++} ++ ++wstdcall USHORT WIN_FUNC(READ_REGISTER_USHORT,1) ++ (void __iomem *reg) ++{ ++ return readw(reg); ++} ++ ++wstdcall void WIN_FUNC(WRITE_REGISTER_ULONG,2) ++ (void __iomem *reg, UINT val) ++{ ++ writel(val, reg); ++} ++ ++wstdcall void WIN_FUNC(WRITE_REGISTER_USHORT,2) ++ (void __iomem *reg, USHORT val) ++{ ++ writew(val, reg); ++} ++ ++wstdcall void WIN_FUNC(WRITE_REGISTER_UCHAR,2) ++ (void __iomem *reg, UCHAR val) ++{ ++ writeb(val, reg); ++} ++ ++wstdcall void WIN_FUNC(KeStallExecutionProcessor,1) ++ (ULONG usecs) ++{ ++ udelay(usecs); ++} ++ ++wstdcall KIRQL WIN_FUNC(KeGetCurrentIrql,0) ++ (void) ++{ ++ return current_irql(); ++} ++ ++wfastcall KIRQL WIN_FUNC(KfRaiseIrql,1) ++ (KIRQL newirql) ++{ ++ return raise_irql(newirql); ++} ++ ++wfastcall void WIN_FUNC(KfLowerIrql,1) ++ (KIRQL oldirql) ++{ ++ lower_irql(oldirql); ++} ++ ++wfastcall KIRQL WIN_FUNC(KfAcquireSpinLock,1) ++ (NT_SPIN_LOCK *lock) ++{ ++ return nt_spin_lock_irql(lock, DISPATCH_LEVEL); ++} ++ ++wfastcall void WIN_FUNC(KfReleaseSpinLock,2) ++ (NT_SPIN_LOCK *lock, KIRQL oldirql) ++{ ++ nt_spin_unlock_irql(lock, oldirql); ++} ++ ++wfastcall void WIN_FUNC(KefAcquireSpinLockAtDpcLevel,1) ++ (NT_SPIN_LOCK *lock) ++{ ++#ifdef DEBUG_IRQL ++ if (current_irql() != DISPATCH_LEVEL) ++ ERROR("irql != DISPATCH_LEVEL"); ++#endif ++ nt_spin_lock(lock); ++} ++ ++wfastcall void WIN_FUNC(KefReleaseSpinLockFromDpcLevel,1) ++ (NT_SPIN_LOCK *lock) ++{ ++#ifdef DEBUG_IRQL ++ if (current_irql() != DISPATCH_LEVEL) ++ ERROR("irql != DISPATCH_LEVEL"); ++#endif ++ nt_spin_unlock(lock); ++} +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/iw_ndis.c linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/iw_ndis.c +--- linux-3.12.2/3rdparty/ndiswrapper/iw_ndis.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/iw_ndis.c 2013-11-28 21:42:10.000000000 +0200 +@@ -0,0 +1,2001 @@ ++ /* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "iw_ndis.h" ++#include "wrapndis.h" ++ ++#ifdef CONFIG_WIRELESS_EXT ++ ++static int freq_chan[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, ++ 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; ++ ++static const char *network_names[] = {"IEEE 802.11FH", "IEEE 802.11b", ++ "IEEE 802.11a", "IEEE 802.11g", "Auto"}; ++ ++static int set_essid(struct ndis_device *wnd, const char *ssid, int ssid_len) ++{ ++ NDIS_STATUS res; ++ struct ndis_essid req; ++ ++ if (ssid_len > NDIS_ESSID_MAX_SIZE) ++ return -EINVAL; ++ ++ memset(&req, 0, sizeof(req)); ++ req.length = ssid_len; ++ if (ssid_len) ++ memcpy(&req.essid, ssid, ssid_len); ++ ++ res = mp_set(wnd, OID_802_11_SSID, &req, sizeof(req)); ++ if (res) { ++ WARNING("setting essid failed (%08X)", res); ++ EXIT2(return -EINVAL); ++ } ++ memcpy(&wnd->essid, &req, sizeof(req)); ++ EXIT2(return 0); ++} ++ ++static int set_iw_auth_mode(struct ndis_device *wnd, int wpa_version, ++ int auth_80211_alg) ++{ ++ NDIS_STATUS res; ++ ULONG auth_mode; ++ ++ ENTER2("%d, %d", wpa_version, auth_80211_alg); ++ if (wpa_version & IW_AUTH_WPA_VERSION_WPA2) { ++ if (wnd->iw_auth_key_mgmt & IW_AUTH_KEY_MGMT_802_1X) ++ auth_mode = Ndis802_11AuthModeWPA2; ++ else ++ auth_mode = Ndis802_11AuthModeWPA2PSK; ++ } else if (wpa_version & IW_AUTH_WPA_VERSION_WPA) { ++ if (wnd->iw_auth_key_mgmt & IW_AUTH_KEY_MGMT_802_1X) ++ auth_mode = Ndis802_11AuthModeWPA; ++ else if (wnd->iw_auth_key_mgmt & IW_AUTH_KEY_MGMT_PSK) ++ auth_mode = Ndis802_11AuthModeWPAPSK; ++ else ++ auth_mode = Ndis802_11AuthModeWPANone; ++ } else if (auth_80211_alg & IW_AUTH_ALG_SHARED_KEY) { ++ if (auth_80211_alg & IW_AUTH_ALG_OPEN_SYSTEM) ++ auth_mode = Ndis802_11AuthModeAutoSwitch; ++ else ++ auth_mode = Ndis802_11AuthModeShared; ++ } else ++ auth_mode = Ndis802_11AuthModeOpen; ++ ++ res = mp_set_int(wnd, OID_802_11_AUTHENTICATION_MODE, auth_mode); ++ if (res) { ++ WARNING("setting auth mode to %u failed (%08X)", ++ auth_mode, res); ++ if (res == NDIS_STATUS_INVALID_DATA) ++ EXIT2(return -EINVAL); ++ return -EOPNOTSUPP; ++ } ++ wnd->iw_auth_wpa_version = wpa_version; ++ wnd->iw_auth_80211_alg = auth_80211_alg; ++ EXIT2(return 0); ++} ++ ++static int set_auth_mode(struct ndis_device *wnd) ++{ ++ return set_iw_auth_mode(wnd, wnd->iw_auth_wpa_version, ++ wnd->iw_auth_80211_alg); ++} ++ ++static enum ndis_priv_filter ndis_priv_mode(struct ndis_device *wnd) ++{ ++ if (wnd->iw_auth_wpa_version & IW_AUTH_WPA_VERSION_WPA2 || ++ wnd->iw_auth_wpa_version & IW_AUTH_WPA_VERSION_WPA) ++ return Ndis802_11PrivFilter8021xWEP; ++ else ++ return Ndis802_11PrivFilterAcceptAll; ++} ++ ++static int set_priv_filter(struct ndis_device *wnd) ++{ ++ NDIS_STATUS res; ++ ULONG flags; ++ ++ flags = ndis_priv_mode(wnd); ++ ENTER2("filter: %d", flags); ++ res = mp_set_int(wnd, OID_802_11_PRIVACY_FILTER, flags); ++ if (res) ++ TRACE2("setting privacy filter to %d failed (%08X)", ++ flags, res); ++ EXIT2(return 0); ++} ++ ++static int set_encr_mode(struct ndis_device *wnd) ++{ ++ return set_iw_encr_mode(wnd, wnd->iw_auth_cipher_pairwise, ++ wnd->iw_auth_cipher_group); ++} ++ ++static int set_assoc_params(struct ndis_device *wnd) ++{ ++ TRACE2("wpa_version=0x%x auth_alg=0x%x key_mgmt=0x%x " ++ "cipher_pairwise=0x%x cipher_group=0x%x", ++ wnd->iw_auth_wpa_version, wnd->iw_auth_80211_alg, ++ wnd->iw_auth_key_mgmt, wnd->iw_auth_cipher_pairwise, ++ wnd->iw_auth_cipher_group); ++ set_auth_mode(wnd); ++ set_priv_filter(wnd); ++ set_encr_mode(wnd); ++ return 0; ++} ++ ++static int iw_set_essid(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ int length; ++ ++ ENTER2(""); ++ /* there is no way to turn off essid other than to set to ++ * random bytes; instead, we use off to mean any */ ++ if (wrqu->essid.flags) { ++ length = wrqu->essid.length; ++ /* Strip '\0' appended by wireless extensions 19 and older */ ++ if (length > 0 && extra[length - 1] == '\0') ++ length--; ++ TRACE2("%d", length); ++ if (length <= 0 || length > NDIS_ESSID_MAX_SIZE) ++ EXIT2(return -EINVAL); ++ } else ++ length = 0; ++ ++ set_assoc_params(wnd); ++ ++ if (set_essid(wnd, extra, length)) ++ EXIT2(return -EINVAL); ++ ++ EXIT2(return 0); ++} ++ ++static int iw_get_essid(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ NDIS_STATUS res; ++ struct ndis_essid req; ++ ++ ENTER2(""); ++ memset(&req, 0, sizeof(req)); ++ res = mp_query(wnd, OID_802_11_SSID, &req, sizeof(req)); ++ if (res) { ++ WARNING("getting essid failed (%08X)", res); ++ EXIT2(return -EOPNOTSUPP); ++ } ++ memcpy(extra, req.essid, req.length); ++ if (req.length > 0) ++ wrqu->essid.flags = 1; ++ else ++ wrqu->essid.flags = 0; ++ wrqu->essid.length = req.length; ++ EXIT2(return 0); ++} ++ ++/* index must be 0 - N, as per NDIS */ ++static int add_wep_key(struct ndis_device *wnd, char *key, int key_len, ++ int index) ++{ ++ struct ndis_encr_key ndis_key; ++ NDIS_STATUS res; ++ ++ ENTER2("key index: %d, length: %d", index, key_len); ++ if (key_len <= 0 || key_len > NDIS_ENCODING_TOKEN_MAX) { ++ WARNING("invalid key length (%d)", key_len); ++ EXIT2(return -EINVAL); ++ } ++ if (index < 0 || index >= MAX_ENCR_KEYS) { ++ WARNING("invalid key index (%d)", index); ++ EXIT2(return -EINVAL); ++ } ++ ndis_key.struct_size = sizeof(ndis_key); ++ ndis_key.length = key_len; ++ memcpy(&ndis_key.key, key, key_len); ++ ndis_key.index = index; ++ ++ if (index == wnd->encr_info.tx_key_index) { ++ ndis_key.index |= (1 << 31); ++ res = set_iw_encr_mode(wnd, IW_AUTH_CIPHER_WEP104, ++ IW_AUTH_CIPHER_NONE); ++ if (res) ++ WARNING("encryption couldn't be enabled (%08X)", res); ++ } ++ TRACE2("key %d: " MACSTRSEP, index, MAC2STR(key)); ++ res = mp_set(wnd, OID_802_11_ADD_WEP, &ndis_key, sizeof(ndis_key)); ++ if (res) { ++ WARNING("adding encryption key %d failed (%08X)", ++ index+1, res); ++ EXIT2(return -EINVAL); ++ } ++ ++ /* Atheros driver messes up ndis_key during ADD_WEP, so ++ * don't rely on that; instead use info in key and key_len */ ++ wnd->encr_info.keys[index].length = key_len; ++ memcpy(&wnd->encr_info.keys[index].key, key, key_len); ++ ++ EXIT2(return 0); ++} ++ ++static int set_infra_mode(struct ndis_device *wnd, ++ enum ndis_infrastructure_mode mode) ++{ ++ NDIS_STATUS res; ++ unsigned int i; ++ ++ ENTER2("%d", mode); ++ res = mp_query_int(wnd, OID_802_11_INFRASTRUCTURE_MODE, ++ &wnd->infrastructure_mode); ++ if (res != NDIS_STATUS_SUCCESS) { ++ WARNING("getting operating mode failed (%08X)", res); ++ EXIT2(return -EINVAL); ++ } ++ if (wnd->infrastructure_mode == mode) ++ EXIT2(return 0); ++ res = mp_set_int(wnd, OID_802_11_INFRASTRUCTURE_MODE, mode); ++ if (res) { ++ WARNING("setting operating mode to %d failed (%08X)", ++ mode, res); ++ EXIT2(return -EINVAL); ++ } ++ /* NDIS drivers clear keys when infrastructure mode is ++ * changed. But Linux tools assume otherwise. So set the ++ * keys */ ++ if (wnd->iw_auth_key_mgmt == 0 || ++ wnd->iw_auth_key_mgmt == IW_AUTH_KEY_MGMT_802_1X) { ++ for (i = 0; i < MAX_ENCR_KEYS; i++) { ++ if (wnd->encr_info.keys[i].length > 0) ++ add_wep_key(wnd, wnd->encr_info.keys[i].key, ++ wnd->encr_info.keys[i].length, i); ++ } ++ } ++ wnd->infrastructure_mode = mode; ++ EXIT2(return 0); ++} ++ ++static int iw_set_infra_mode(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ enum ndis_infrastructure_mode ndis_mode; ++ ++ ENTER2("%d", wrqu->mode); ++ switch (wrqu->mode) { ++ case IW_MODE_ADHOC: ++ ndis_mode = Ndis802_11IBSS; ++ break; ++ case IW_MODE_INFRA: ++ ndis_mode = Ndis802_11Infrastructure; ++ break; ++ case IW_MODE_AUTO: ++ ndis_mode = Ndis802_11AutoUnknown; ++ break; ++ default: ++ EXIT2(return -EINVAL); ++ } ++ ++ if (set_infra_mode(wnd, ndis_mode)) ++ EXIT2(return -EINVAL); ++ ++ EXIT2(return 0); ++} ++ ++static int iw_get_infra_mode(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ int ndis_mode, iw_mode; ++ NDIS_STATUS res; ++ ++ ENTER2(""); ++ res = mp_query_int(wnd, OID_802_11_INFRASTRUCTURE_MODE, &ndis_mode); ++ if (res) { ++ WARNING("getting operating mode failed (%08X)", res); ++ EXIT2(return -EOPNOTSUPP); ++ } ++ ++ switch (ndis_mode) { ++ case Ndis802_11IBSS: ++ iw_mode = IW_MODE_ADHOC; ++ break; ++ case Ndis802_11Infrastructure: ++ iw_mode = IW_MODE_INFRA; ++ break; ++ case Ndis802_11AutoUnknown: ++ iw_mode = IW_MODE_AUTO; ++ break; ++ default: ++ ERROR("invalid operating mode (%u)", ndis_mode); ++ EXIT2(return -EINVAL); ++ } ++ wrqu->mode = iw_mode; ++ EXIT2(return 0); ++} ++ ++static const char *network_type_to_name(int net_type) ++{ ++ if (net_type >= 0 && net_type < ARRAY_SIZE(network_names)) ++ return network_names[net_type]; ++ else ++ return network_names[ARRAY_SIZE(network_names) - 1]; ++} ++ ++static int iw_get_network_type(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ unsigned int network_type; ++ NDIS_STATUS res; ++ ++ ENTER2(""); ++ res = mp_query_int(wnd, OID_802_11_NETWORK_TYPE_IN_USE, ++ &network_type); ++ if (res) { ++ WARNING("getting network type failed: %08X", res); ++ network_type = -1; ++ } ++ strncpy(wrqu->name, network_type_to_name(network_type), ++ sizeof(wrqu->name) - 1); ++ wrqu->name[sizeof(wrqu->name)-1] = 0; ++ return 0; ++} ++ ++static int iw_get_freq(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ NDIS_STATUS res; ++ struct ndis_configuration req; ++ ++ ENTER2(""); ++ memset(&req, 0, sizeof(req)); ++ res = mp_query(wnd, OID_802_11_CONFIGURATION, &req, sizeof(req)); ++ if (res) { ++ WARNING("getting configuration failed (%08X)", res); ++ EXIT2(return -EOPNOTSUPP); ++ } ++ ++ memset(&(wrqu->freq), 0, sizeof(struct iw_freq)); ++ ++ /* see comment in wireless.h above the "struct iw_freq" ++ definition for an explanation of this if ++ NOTE: 1000000 is due to the kHz ++ */ ++ if (req.ds_config > 1000000) { ++ wrqu->freq.m = req.ds_config / 10; ++ wrqu->freq.e = 1; ++ } ++ else ++ wrqu->freq.m = req.ds_config; ++ ++ /* convert from kHz to Hz */ ++ wrqu->freq.e += 3; ++ ++ return 0; ++} ++ ++static int iw_set_freq(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ NDIS_STATUS res; ++ struct ndis_configuration req; ++ ++ ENTER2(""); ++ /* this OID is valid only when not associated */ ++ if (netif_carrier_ok(wnd->net_dev)) ++ EXIT2(return 0); ++ memset(&req, 0, sizeof(req)); ++ res = mp_query(wnd, OID_802_11_CONFIGURATION, &req, sizeof(req)); ++ if (res) { ++ WARNING("getting configuration failed (%08X)", res); ++ EXIT2(return 0); ++ } ++ ++ if (wrqu->freq.m < 1000 && wrqu->freq.e == 0) { ++ if (wrqu->freq.m >= 1 && wrqu->freq.m <= ARRAY_SIZE(freq_chan)) ++ req.ds_config = freq_chan[wrqu->freq.m - 1] * 1000; ++ else ++ return -EINVAL; ++ } else { ++ int i; ++ req.ds_config = wrqu->freq.m; ++ for (i = wrqu->freq.e; i > 0; i--) ++ req.ds_config *= 10; ++ req.ds_config /= 1000; ++ } ++ res = mp_set(wnd, OID_802_11_CONFIGURATION, &req, sizeof(req)); ++ if (res) ++ WARNING("setting configuration failed (%08X)", res); ++ return 0; ++} ++ ++static int iw_get_tx_power(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ndis_tx_power_level ndis_power; ++ NDIS_STATUS res; ++ ++ ENTER2(""); ++ res = mp_query(wnd, OID_802_11_TX_POWER_LEVEL, ++ &ndis_power, sizeof(ndis_power)); ++ if (res) ++ return -EOPNOTSUPP; ++ wrqu->txpower.flags = IW_TXPOW_MWATT; ++ wrqu->txpower.disabled = 0; ++ wrqu->txpower.fixed = 0; ++ wrqu->txpower.value = ndis_power; ++ return 0; ++} ++ ++static int iw_set_tx_power(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ndis_tx_power_level ndis_power; ++ NDIS_STATUS res; ++ ++ ENTER2(""); ++ if (wrqu->txpower.disabled) ++ ndis_power = 0; ++ else { ++ if (wrqu->txpower.flags == IW_TXPOW_MWATT) ++ ndis_power = wrqu->txpower.value; ++ else { // wrqu->txpower.flags == IW_TXPOW_DBM ++ if (wrqu->txpower.value > 20) ++ ndis_power = 128; ++ else if (wrqu->txpower.value < -43) ++ ndis_power = 127; ++ else { ++ signed char tmp; ++ tmp = wrqu->txpower.value; ++ tmp = -12 - tmp; ++ tmp <<= 2; ++ ndis_power = (unsigned char)tmp; ++ } ++ } ++ } ++ TRACE2("%d", ndis_power); ++ res = mp_set(wnd, OID_802_11_TX_POWER_LEVEL, ++ &ndis_power, sizeof(ndis_power)); ++ if (res) ++ EXIT2(return -EOPNOTSUPP); ++ if (ndis_power == 0) ++ res = disassociate(wnd, 0); ++ EXIT2(return 0); ++} ++ ++static int iw_get_bitrate(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ULONG ndis_rate; ++ int res; ++ ++ ENTER2(""); ++ res = mp_query(wnd, OID_GEN_LINK_SPEED, &ndis_rate, sizeof(ndis_rate)); ++ if (res) { ++ WARNING("getting bitrate failed (%08X)", res); ++ ndis_rate = 0; ++ } ++ ++ wrqu->bitrate.value = ndis_rate * 100; ++ return 0; ++} ++ ++static int iw_set_bitrate(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ int i, n; ++ NDIS_STATUS res; ++ UCHAR rates[NDIS_MAX_RATES_EX]; ++ ++ ENTER2(""); ++ if (wrqu->bitrate.fixed == 0) ++ EXIT2(return 0); ++ ++ res = mp_query_info(wnd, OID_802_11_SUPPORTED_RATES, &rates, ++ sizeof(rates), &n, NULL); ++ if (res) { ++ WARNING("getting bit rate failed (%08X)", res); ++ EXIT2(return 0); ++ } ++ for (i = 0; i < n; i++) { ++ if (rates[i] & 0x80) ++ continue; ++ if ((rates[i] & 0x7f) * 500000 > wrqu->bitrate.value) { ++ TRACE2("setting rate %d to 0", ++ (rates[i] & 0x7f) * 500000); ++ rates[i] = 0; ++ } ++ } ++ ++ res = mp_set(wnd, OID_802_11_DESIRED_RATES, &rates, n); ++ if (res) { ++ WARNING("setting bit rate failed (%08X)", res); ++ EXIT2(return 0); ++ } ++ ++ return 0; ++} ++ ++static int iw_set_dummy(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ /* Do nothing. Used for ioctls that are not implemented. */ ++ return 0; ++} ++ ++static int iw_get_rts_threshold(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ndis_rts_threshold threshold; ++ NDIS_STATUS res; ++ ++ ENTER2(""); ++ res = mp_query(wnd, OID_802_11_RTS_THRESHOLD, ++ &threshold, sizeof(threshold)); ++ if (res) ++ return -EOPNOTSUPP; ++ ++ wrqu->rts.value = threshold; ++ return 0; ++} ++ ++static int iw_set_rts_threshold(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ndis_rts_threshold threshold; ++ NDIS_STATUS res; ++ ++ ENTER2(""); ++ threshold = wrqu->rts.value; ++ res = mp_set(wnd, OID_802_11_RTS_THRESHOLD, ++ &threshold, sizeof(threshold)); ++ if (res == NDIS_STATUS_INVALID_DATA) ++ return -EINVAL; ++ if (res) ++ return -EOPNOTSUPP; ++ ++ return 0; ++} ++ ++static int iw_get_frag_threshold(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ndis_fragmentation_threshold frag_threshold; ++ NDIS_STATUS res; ++ ++ ENTER2(""); ++ res = mp_query(wnd, OID_802_11_FRAGMENTATION_THRESHOLD, ++ &frag_threshold, sizeof(frag_threshold)); ++ if (res) ++ return -ENOTSUPP; ++ ++ wrqu->frag.value = frag_threshold; ++ return 0; ++} ++ ++static int iw_set_frag_threshold(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ndis_rts_threshold threshold; ++ NDIS_STATUS res; ++ ++ ENTER2(""); ++ threshold = wrqu->frag.value; ++ res = mp_set(wnd, OID_802_11_FRAGMENTATION_THRESHOLD, ++ &threshold, sizeof(threshold)); ++ if (res == NDIS_STATUS_INVALID_DATA) ++ return -EINVAL; ++ if (res) ++ return -EOPNOTSUPP; ++ return 0; ++} ++ ++int get_ap_address(struct ndis_device *wnd, mac_address ap_addr) ++{ ++ NDIS_STATUS res; ++ ++ res = mp_query(wnd, OID_802_11_BSSID, ap_addr, ETH_ALEN); ++ TRACE2(MACSTRSEP, MAC2STR(ap_addr)); ++ if (res) { ++ TRACE2("res: %08X", res); ++ memset(ap_addr, 0x0, ETH_ALEN); ++ EXIT2(return -EOPNOTSUPP); ++ } ++ EXIT2(return 0); ++} ++ ++static int iw_get_ap_address(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ mac_address ap_addr; ++ ++ ENTER2(""); ++ get_ap_address(wnd, ap_addr); ++ memcpy(wrqu->ap_addr.sa_data, ap_addr, ETH_ALEN); ++ wrqu->ap_addr.sa_family = ARPHRD_ETHER; ++ EXIT2(return 0); ++} ++ ++static int iw_set_ap_address(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ NDIS_STATUS res; ++ mac_address ap_addr; ++ ++ ENTER2(""); ++ memcpy(ap_addr, wrqu->ap_addr.sa_data, ETH_ALEN); ++ TRACE2(MACSTRSEP, MAC2STR(ap_addr)); ++ res = mp_set(wnd, OID_802_11_BSSID, ap_addr, ETH_ALEN); ++ /* user apps may set ap's mac address, which is not required; ++ * they may fail to work if this function fails, so return ++ * success */ ++ if (res) ++ WARNING("setting AP mac address failed (%08X)", res); ++ ++ EXIT2(return 0); ++} ++ ++int set_ndis_auth_mode(struct ndis_device *wnd, ULONG auth_mode) ++{ ++ NDIS_STATUS res; ++ ++ ENTER2("%d", auth_mode); ++ res = mp_set_int(wnd, OID_802_11_AUTHENTICATION_MODE, auth_mode); ++ if (res) { ++ WARNING("setting auth mode to %u failed (%08X)", ++ auth_mode, res); ++ if (res == NDIS_STATUS_INVALID_DATA) ++ EXIT2(return -EINVAL); ++ return -EOPNOTSUPP; ++ } ++ switch (auth_mode) { ++ case Ndis802_11AuthModeWPA: ++ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_WPA; ++ wnd->iw_auth_key_mgmt = IW_AUTH_KEY_MGMT_802_1X; ++ break; ++ case Ndis802_11AuthModeWPAPSK: ++ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_WPA; ++ wnd->iw_auth_key_mgmt = IW_AUTH_KEY_MGMT_PSK; ++ case Ndis802_11AuthModeWPANone: ++ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_DISABLED; ++ wnd->iw_auth_key_mgmt = IW_AUTH_KEY_MGMT_PSK; ++ break; ++ case Ndis802_11AuthModeWPA2: ++ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_WPA2; ++ wnd->iw_auth_key_mgmt = IW_AUTH_KEY_MGMT_802_1X; ++ break; ++ case Ndis802_11AuthModeWPA2PSK: ++ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_WPA2; ++ wnd->iw_auth_key_mgmt = IW_AUTH_KEY_MGMT_PSK; ++ break; ++ case Ndis802_11AuthModeOpen: ++ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_DISABLED; ++ wnd->iw_auth_80211_alg = IW_AUTH_ALG_OPEN_SYSTEM; ++ break; ++ case Ndis802_11AuthModeShared: ++ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_DISABLED; ++ wnd->iw_auth_80211_alg = IW_AUTH_ALG_SHARED_KEY; ++ break; ++ case Ndis802_11AuthModeAutoSwitch: ++ wnd->iw_auth_wpa_version = IW_AUTH_WPA_VERSION_DISABLED; ++ wnd->iw_auth_80211_alg = IW_AUTH_ALG_SHARED_KEY; ++ wnd->iw_auth_80211_alg |= IW_AUTH_ALG_OPEN_SYSTEM; ++ break; ++ default: ++ WARNING("invalid authentication algorithm: %d", auth_mode); ++ break; ++ } ++ EXIT2(return 0); ++} ++ ++int get_ndis_auth_mode(struct ndis_device *wnd) ++{ ++ ULONG mode; ++ NDIS_STATUS res; ++ ++ res = mp_query_int(wnd, OID_802_11_AUTHENTICATION_MODE, &mode); ++ if (res) { ++ WARNING("getting authentication mode failed (%08X)", res); ++ EXIT2(return -EOPNOTSUPP); ++ } ++ TRACE2("%d", mode); ++ return mode; ++} ++ ++int set_iw_encr_mode(struct ndis_device *wnd, int cipher_pairwise, ++ int cipher_groupwise) ++{ ++ NDIS_STATUS res; ++ ULONG ndis_mode; ++ ++ ENTER2("%d, %d", cipher_pairwise, cipher_groupwise); ++ if (cipher_pairwise & IW_AUTH_CIPHER_CCMP) ++ ndis_mode = Ndis802_11Encryption3Enabled; ++ else if (cipher_pairwise & IW_AUTH_CIPHER_TKIP) ++ ndis_mode = Ndis802_11Encryption2Enabled; ++ else if (cipher_pairwise & ++ (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104)) ++ ndis_mode = Ndis802_11Encryption1Enabled; ++ else if (cipher_groupwise & IW_AUTH_CIPHER_CCMP) ++ ndis_mode = Ndis802_11Encryption3Enabled; ++ else if (cipher_groupwise & IW_AUTH_CIPHER_TKIP) ++ ndis_mode = Ndis802_11Encryption2Enabled; ++ else ++ ndis_mode = Ndis802_11EncryptionDisabled; ++ ++ res = mp_set_int(wnd, OID_802_11_ENCRYPTION_STATUS, ndis_mode); ++ if (res) { ++ WARNING("setting encryption mode to %u failed (%08X)", ++ ndis_mode, res); ++ if (res == NDIS_STATUS_INVALID_DATA) ++ EXIT2(return -EINVAL); ++ return -EOPNOTSUPP; ++ } ++ wnd->iw_auth_cipher_pairwise = cipher_pairwise; ++ wnd->iw_auth_cipher_group = cipher_groupwise; ++ EXIT2(return 0); ++} ++ ++int get_ndis_encr_mode(struct ndis_device *wnd) ++{ ++ ULONG mode; ++ NDIS_STATUS res; ++ ++ ENTER2(""); ++ res = mp_query_int(wnd, OID_802_11_ENCRYPTION_STATUS, &mode); ++ if (res) { ++ WARNING("getting encryption status failed (%08X)", res); ++ EXIT2(return -EOPNOTSUPP); ++ } else ++ EXIT2(return mode); ++} ++ ++static int iw_get_encr(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ int index, mode; ++ struct encr_info *encr_info = &wnd->encr_info; ++ ++ ENTER2("wnd = %p", wnd); ++ wrqu->data.length = 0; ++ extra[0] = 0; ++ ++ index = (wrqu->encoding.flags & IW_ENCODE_INDEX); ++ TRACE2("index = %u", index); ++ if (index > 0) ++ index--; ++ else ++ index = encr_info->tx_key_index; ++ ++ if (index < 0 || index >= MAX_ENCR_KEYS) { ++ WARNING("encryption index out of range (%u)", index); ++ EXIT2(return -EINVAL); ++ } ++ ++ if (index != encr_info->tx_key_index) { ++ if (encr_info->keys[index].length > 0) { ++ wrqu->data.flags |= IW_ENCODE_ENABLED; ++ wrqu->data.length = encr_info->keys[index].length; ++ memcpy(extra, encr_info->keys[index].key, ++ encr_info->keys[index].length); ++ } ++ else ++ wrqu->data.flags |= IW_ENCODE_DISABLED; ++ ++ EXIT2(return 0); ++ } ++ ++ /* transmit key */ ++ mode = get_ndis_encr_mode(wnd); ++ if (mode < 0) ++ EXIT2(return -EOPNOTSUPP); ++ ++ if (mode == Ndis802_11EncryptionDisabled || ++ mode == Ndis802_11EncryptionNotSupported) ++ wrqu->data.flags |= IW_ENCODE_DISABLED; ++ else { ++ if (mode == Ndis802_11Encryption1KeyAbsent || ++ mode == Ndis802_11Encryption2KeyAbsent || ++ mode == Ndis802_11Encryption3KeyAbsent) ++ wrqu->data.flags |= IW_ENCODE_NOKEY; ++ else { ++ wrqu->data.flags |= IW_ENCODE_ENABLED; ++ wrqu->encoding.flags |= index+1; ++ wrqu->data.length = encr_info->keys[index].length; ++ memcpy(extra, encr_info->keys[index].key, ++ encr_info->keys[index].length); ++ } ++ } ++ mode = get_ndis_auth_mode(wnd); ++ if (mode < 0) ++ EXIT2(return -EOPNOTSUPP); ++ ++ if (mode == Ndis802_11AuthModeOpen) ++ wrqu->data.flags |= IW_ENCODE_OPEN; ++ else if (mode == Ndis802_11AuthModeAutoSwitch) ++ wrqu->data.flags |= IW_ENCODE_RESTRICTED; ++ else // Ndis802_11AuthModeAutoSwitch, Ndis802_11AuthModeWPA etc. ++ wrqu->data.flags |= IW_ENCODE_RESTRICTED; ++ ++ EXIT2(return 0); ++} ++ ++/* remove_key is for both wep and wpa */ ++static int remove_key(struct ndis_device *wnd, int index, ++ mac_address bssid) ++{ ++ NDIS_STATUS res; ++ if (wnd->encr_info.keys[index].length == 0) ++ EXIT2(return 0); ++ wnd->encr_info.keys[index].length = 0; ++ memset(&wnd->encr_info.keys[index].key, 0, ++ sizeof(wnd->encr_info.keys[index].length)); ++ if (wnd->iw_auth_cipher_pairwise == IW_AUTH_CIPHER_TKIP || ++ wnd->iw_auth_cipher_pairwise == IW_AUTH_CIPHER_CCMP || ++ wnd->iw_auth_cipher_group == IW_AUTH_CIPHER_TKIP || ++ wnd->iw_auth_cipher_group == IW_AUTH_CIPHER_CCMP) { ++ struct ndis_remove_key rmkey; ++ rmkey.struct_size = sizeof(rmkey); ++ rmkey.index = index; ++ if (bssid) { ++ /* pairwise key */ ++ if (memcmp(bssid, "\xff\xff\xff\xff\xff\xff", ++ ETH_ALEN) != 0) ++ rmkey.index |= (1 << 30); ++ memcpy(rmkey.bssid, bssid, sizeof(rmkey.bssid)); ++ } else ++ memset(rmkey.bssid, 0xff, sizeof(rmkey.bssid)); ++ if (mp_set(wnd, OID_802_11_REMOVE_KEY, &rmkey, sizeof(rmkey))) ++ EXIT2(return -EINVAL); ++ } else { ++ ndis_key_index keyindex = index; ++ res = mp_set_int(wnd, OID_802_11_REMOVE_WEP, keyindex); ++ if (res) { ++ WARNING("removing encryption key %d failed (%08X)", ++ keyindex, res); ++ EXIT2(return -EINVAL); ++ } ++ } ++ /* if it is transmit key, disable encryption */ ++ if (index == wnd->encr_info.tx_key_index) { ++ res = set_iw_encr_mode(wnd, IW_AUTH_CIPHER_NONE, ++ IW_AUTH_CIPHER_NONE); ++ if (res) ++ WARNING("changing encr status failed (%08X)", res); ++ } ++ TRACE2("key %d removed", index); ++ EXIT2(return 0); ++} ++ ++static int iw_set_wep(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ NDIS_STATUS res; ++ unsigned int index, key_len; ++ struct encr_info *encr_info = &wnd->encr_info; ++ unsigned char *key; ++ ++ ENTER2(""); ++ index = (wrqu->encoding.flags & IW_ENCODE_INDEX); ++ TRACE2("index = %u", index); ++ ++ /* iwconfig gives index as 1 - N */ ++ if (index > 0) ++ index--; ++ else ++ index = encr_info->tx_key_index; ++ ++ if (index >= MAX_ENCR_KEYS) { ++ WARNING("encryption index out of range (%u)", index); ++ EXIT2(return -EINVAL); ++ } ++ ++ /* remove key if disabled */ ++ if (wrqu->data.flags & IW_ENCODE_DISABLED) { ++ if (remove_key(wnd, index, NULL)) ++ EXIT2(return -EINVAL); ++ else ++ EXIT2(return 0); ++ } ++ ++ /* global encryption state (for all keys) */ ++ if (wrqu->data.flags & IW_ENCODE_OPEN) ++ res = set_ndis_auth_mode(wnd, Ndis802_11AuthModeOpen); ++ else // if (wrqu->data.flags & IW_ENCODE_RESTRICTED) ++ res = set_ndis_auth_mode(wnd, Ndis802_11AuthModeShared); ++ if (res) { ++ WARNING("setting authentication mode failed (%08X)", res); ++ EXIT2(return -EINVAL); ++ } ++ ++ TRACE2("key length: %d", wrqu->data.length); ++ ++ if (wrqu->data.length > 0) { ++ key_len = wrqu->data.length; ++ key = extra; ++ } else { // must be set as tx key ++ if (encr_info->keys[index].length == 0) { ++ WARNING("key %d is not set", index+1); ++ EXIT2(return -EINVAL); ++ } ++ key_len = encr_info->keys[index].length; ++ key = encr_info->keys[index].key; ++ encr_info->tx_key_index = index; ++ } ++ ++ if (add_wep_key(wnd, key, key_len, index)) ++ EXIT2(return -EINVAL); ++ ++ if (index == encr_info->tx_key_index) { ++ /* if transmit key is at index other than 0, some ++ * drivers, at least Atheros and TI, want another ++ * (global) non-transmit key to be set; don't know why */ ++ if (index != 0) { ++ int i; ++ for (i = 0; i < MAX_ENCR_KEYS; i++) ++ if (i != index && ++ encr_info->keys[i].length != 0) ++ break; ++ if (i == MAX_ENCR_KEYS) { ++ if (index == 0) ++ i = index + 1; ++ else ++ i = index - 1; ++ if (add_wep_key(wnd, key, key_len, i)) ++ WARNING("couldn't add broadcast key" ++ " at %d", i); ++ } ++ } ++ /* ndis drivers want essid to be set after setting encr */ ++ set_essid(wnd, wnd->essid.essid, wnd->essid.length); ++ } ++ EXIT2(return 0); ++} ++ ++static int iw_set_nick(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ++ if (wrqu->data.length >= sizeof(wnd->nick)) ++ return -EINVAL; ++ memcpy(wnd->nick, extra, wrqu->data.length); ++ wnd->nick[wrqu->data.length] = 0; ++ return 0; ++} ++ ++static int iw_get_nick(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ++ wrqu->data.length = strlen(wnd->nick); ++ memcpy(extra, wnd->nick, wrqu->data.length); ++ return 0; ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) && !defined(IW_REQUEST_FLAG_COMPAT) ++#define iwe_stream_add_event(a, b, c, d, e) iwe_stream_add_event(b, c, d, e) ++#define iwe_stream_add_point(a, b, c, d, e) iwe_stream_add_point(b, c, d, e) ++#define iwe_stream_add_value(a, b, c, d, e, f) \ ++ iwe_stream_add_value(b, c, d, e, f) ++#define iwe_stream_lcp_len(a) IW_EV_LCP_LEN ++#endif ++ ++static char *ndis_translate_scan(struct net_device *dev, ++ struct iw_request_info *info, char *event, ++ char *end_buf, void *item) ++{ ++ struct iw_event iwe; ++ char *current_val; ++ char *ret; ++ int i, nrates; ++ unsigned char custom_str[64]; ++ struct ndis_wlan_bssid *bssid; ++ struct ndis_wlan_bssid_ex *bssid_ex; ++ int extended; ++ ++ ENTER2("%p, %p", event, item); ++ bssid = item; ++ bssid_ex = item; ++ extended = (bssid->length > offsetof(struct ndis_wlan_bssid_ex, var)); ++ ++ /* add mac address */ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWAP; ++ iwe.u.ap_addr.sa_family = ARPHRD_ETHER; ++ iwe.len = IW_EV_ADDR_LEN; ++ memcpy(iwe.u.ap_addr.sa_data, bssid->mac, ETH_ALEN); ++ ret = iwe_stream_add_event(info, event, end_buf, &iwe, IW_EV_ADDR_LEN); ++ if (ret == event) ++ return NULL; ++ event = ret; ++ ++ /* add essid */ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWESSID; ++ iwe.u.data.length = bssid->ssid.length; ++ if (iwe.u.data.length > IW_ESSID_MAX_SIZE) ++ iwe.u.data.length = IW_ESSID_MAX_SIZE; ++ iwe.u.data.flags = 1; ++ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; ++ ret = iwe_stream_add_point(info, event, end_buf, &iwe, ++ bssid->ssid.essid); ++ if (ret == event) ++ return NULL; ++ event = ret; ++ ++ /* add protocol name */ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWNAME; ++ strncpy(iwe.u.name, network_type_to_name(bssid->net_type), IFNAMSIZ); ++ ret = iwe_stream_add_event(info, event, end_buf, &iwe, IW_EV_CHAR_LEN); ++ if (ret == event) ++ return NULL; ++ event = ret; ++ ++ /* add mode */ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWMODE; ++ if (bssid->mode == Ndis802_11IBSS) ++ iwe.u.mode = IW_MODE_ADHOC; ++ else if (bssid->mode == Ndis802_11Infrastructure) ++ iwe.u.mode = IW_MODE_MASTER; ++ else // if (bssid->mode == Ndis802_11AutoUnknown) ++ iwe.u.mode = IW_MODE_AUTO; ++ ret = iwe_stream_add_event(info, event, end_buf, &iwe, IW_EV_UINT_LEN); ++ if (ret == event) ++ return NULL; ++ event = ret; ++ ++ /* add freq */ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWFREQ; ++ iwe.u.freq.m = bssid->config.ds_config; ++ if (bssid->config.ds_config > 1000000) { ++ iwe.u.freq.m = bssid->config.ds_config / 10; ++ iwe.u.freq.e = 1; ++ } ++ else ++ iwe.u.freq.m = bssid->config.ds_config; ++ /* convert from kHz to Hz */ ++ iwe.u.freq.e += 3; ++ iwe.len = IW_EV_FREQ_LEN; ++ ret = iwe_stream_add_event(info, event, end_buf, &iwe, IW_EV_FREQ_LEN); ++ if (ret == event) ++ return NULL; ++ event = ret; ++ ++ /* add qual */ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVQUAL; ++ i = 100 * (bssid->rssi - WL_NOISE) / (WL_SIGMAX - WL_NOISE); ++ if (i < 0) ++ i = 0; ++ else if (i > 100) ++ i = 100; ++ iwe.u.qual.level = bssid->rssi; ++ iwe.u.qual.noise = WL_NOISE; ++ iwe.u.qual.qual = i; ++ iwe.len = IW_EV_QUAL_LEN; ++ ret = iwe_stream_add_event(info, event, end_buf, &iwe, IW_EV_QUAL_LEN); ++ if (ret == event) ++ return NULL; ++ event = ret; ++ ++ /* add key info */ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = SIOCGIWENCODE; ++ if (bssid->privacy == Ndis802_11PrivFilterAcceptAll) ++ iwe.u.data.flags = IW_ENCODE_DISABLED; ++ else ++ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; ++ iwe.u.data.length = 0; ++ iwe.len = IW_EV_POINT_LEN; ++ ret = iwe_stream_add_point(info, event, end_buf, &iwe, ++ bssid->ssid.essid); ++ if (ret == event) ++ return NULL; ++ event = ret; ++ ++ /* add rate */ ++ memset(&iwe, 0, sizeof(iwe)); ++ current_val = event + iwe_stream_lcp_len(info); ++ iwe.cmd = SIOCGIWRATE; ++ if (extended) ++ nrates = ARRAY_SIZE(bssid->rates); ++ else ++ nrates = ARRAY_SIZE(bssid_ex->rates_ex); ++ for (i = 0; i < nrates; i++) { ++ if (bssid_ex->rates_ex[i] & 0x7f) { ++ iwe.u.bitrate.value = ((bssid->rates[i] & 0x7f) * ++ 500000); ++ ret = iwe_stream_add_value(info, event, current_val, ++ end_buf, &iwe, ++ IW_EV_PARAM_LEN); ++ if (ret == current_val) ++ return NULL; ++ current_val = ret; ++ } ++ } ++ ++ if ((current_val - event) > iwe_stream_lcp_len(info)) ++ event = current_val; ++ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVCUSTOM; ++ sprintf(custom_str, "bcn_int=%d", bssid->config.beacon_period); ++ iwe.u.data.length = strlen(custom_str); ++ ret = iwe_stream_add_point(info, event, end_buf, &iwe, custom_str); ++ if (ret == event) ++ return NULL; ++ event = ret; ++ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVCUSTOM; ++ sprintf(custom_str, "atim=%u", bssid->config.atim_window); ++ iwe.u.data.length = strlen(custom_str); ++ ret = iwe_stream_add_point(info, event, end_buf, &iwe, custom_str); ++ if (ret == event) ++ return NULL; ++ event = ret; ++ ++ TRACE2("%d, %zu", bssid->length, sizeof(*bssid)); ++ if (extended) { ++ struct ndis_variable_ies *iep = bssid_ex->var; ++ unsigned char *end = (unsigned char *)&bssid_ex->fixed + ++ bssid_ex->ie_length; ++ ++ while (&iep->length < end && &iep->data[iep->length] <= end) { ++ unsigned char ielen = iep->length + 2; ++ ++ memset(&iwe, 0, sizeof(iwe)); ++ iwe.cmd = IWEVGENIE; ++ iwe.u.data.length = ielen; ++ ret = iwe_stream_add_point(info, event, end_buf, &iwe, ++ (char *)iep); ++ if (ret == event) ++ return NULL; ++ event = ret; ++ iep = (typeof(iep))&iep->data[iep->length]; ++ } ++ } ++ TRACE2("event = %p, current_val = %p", event, current_val); ++ EXIT2(return event); ++} ++ ++static int set_scan(struct ndis_device *wnd) ++{ ++ NDIS_STATUS res; ++ ++ ENTER2(""); ++ res = mp_set(wnd, OID_802_11_BSSID_LIST_SCAN, NULL, 0); ++ if (res) { ++ WARNING("scanning failed (%08X)", res); ++ EXIT2(return -EOPNOTSUPP); ++ } ++ wnd->scan_timestamp = jiffies; ++ EXIT2(return 0); ++} ++ ++static int iw_set_scan(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ return set_scan(wnd); ++} ++ ++static int iw_get_scan(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ unsigned int i, buf_len, needed, data_len; ++ NDIS_STATUS res; ++ struct ndis_bssid_list *bssid_list = NULL; ++ char *event = extra; ++ struct ndis_wlan_bssid *cur_item; ++ ++ ENTER2(""); ++ if (time_before(jiffies, wnd->scan_timestamp + 3 * HZ)) ++ return -EAGAIN; ++ /* try with space for a few scan items */ ++ buf_len = sizeof(ULONG) + offsetof(struct ndis_wlan_bssid_ex, var) * 8; ++ ++ /* Try many times, as the needed space may grow between queries */ ++ for (i = 0; i < 10; i++) { ++ bssid_list = kzalloc(buf_len, GFP_KERNEL); ++ if (!bssid_list) { ++ ERROR("couldn't allocate %u bytes for scan results", ++ buf_len); ++ return -ENOMEM; ++ } ++ ++ needed = 0; ++ data_len = 0; ++ res = mp_query_info(wnd, OID_802_11_BSSID_LIST, bssid_list, ++ buf_len, &data_len, &needed); ++ TRACE2("try %d: given %d bytes, needed %d, written %d", ++ i, buf_len, needed, data_len); ++ if (needed <= buf_len) ++ break; ++ kfree(bssid_list); ++ buf_len = needed; ++ } ++ if (res) { ++ WARNING("getting BSSID list failed (%08X)", res); ++ kfree(bssid_list); ++ EXIT2(return -EOPNOTSUPP); ++ } ++ ++ /* some drivers don't set bssid_list->num_items to 0 if ++ OID_802_11_BSSID_LIST returns no items (prism54 driver, e.g.,) */ ++ TRACE2("items: %d", bssid_list->num_items); ++ cur_item = &bssid_list->bssid[0]; ++ for (i = 0; i < bssid_list->num_items; i++) { ++ TRACE2("item %d: len %d, remaining data %d", ++ i, cur_item->length, data_len); ++ /* drop truncated items */ ++ if (cur_item->length > data_len) ++ break; ++ event = ndis_translate_scan(dev, info, event, ++ extra + wrqu->data.length, ++ cur_item); ++ if (!event) { ++ kfree(bssid_list); ++ return -E2BIG; ++ } ++ data_len -= cur_item->length; ++ cur_item = (struct ndis_wlan_bssid *)((char *)cur_item + ++ cur_item->length); ++ } ++ wrqu->data.length = event - extra; ++ wrqu->data.flags = 0; ++ kfree(bssid_list); ++ EXIT2(return 0); ++} ++ ++static int iw_set_power_mode(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ NDIS_STATUS res; ++ enum ndis_power power_mode; ++ ++ if (wrqu->power.disabled == 1) ++ power_mode = NDIS_POWER_OFF; ++ else if (wrqu->power.flags & IW_POWER_MIN) ++ power_mode = NDIS_POWER_MIN; ++ else // if (wrqu->power.flags & IW_POWER_MAX) ++ power_mode = NDIS_POWER_MAX; ++ ++ TRACE2("%d", power_mode); ++ res = mp_set(wnd, OID_802_11_POWER_MODE, ++ &power_mode, sizeof(power_mode)); ++ if (res) ++ WARNING("setting power mode failed (%08X)", res); ++ return 0; ++} ++ ++static int iw_get_power_mode(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ NDIS_STATUS res; ++ enum ndis_power power_mode; ++ ++ ENTER2(""); ++ res = mp_query(wnd, OID_802_11_POWER_MODE, ++ &power_mode, sizeof(power_mode)); ++ if (res) ++ return -ENOTSUPP; ++ ++ if (power_mode == NDIS_POWER_OFF) ++ wrqu->power.disabled = 1; ++ else { ++ if (wrqu->power.flags != 0) ++ return 0; ++ wrqu->power.flags |= IW_POWER_ALL_R; ++ wrqu->power.flags |= IW_POWER_TIMEOUT; ++ wrqu->power.value = 0; ++ wrqu->power.disabled = 0; ++ ++ if (power_mode == NDIS_POWER_MIN) ++ wrqu->power.flags |= IW_POWER_MIN; ++ else // if (power_mode == NDIS_POWER_MAX) ++ wrqu->power.flags |= IW_POWER_MAX; ++ } ++ return 0; ++} ++ ++static int iw_get_sensitivity(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ NDIS_STATUS res; ++ ndis_rssi rssi_trigger; ++ ++ ENTER2(""); ++ res = mp_query(wnd, OID_802_11_RSSI_TRIGGER, ++ &rssi_trigger, sizeof(rssi_trigger)); ++ if (res) ++ return -EOPNOTSUPP; ++ wrqu->param.value = rssi_trigger; ++ wrqu->param.disabled = (rssi_trigger == 0); ++ wrqu->param.fixed = 1; ++ return 0; ++} ++ ++static int iw_set_sensitivity(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ NDIS_STATUS res; ++ ndis_rssi rssi_trigger; ++ ++ ENTER2(""); ++ if (wrqu->param.disabled) ++ rssi_trigger = 0; ++ else ++ rssi_trigger = wrqu->param.value; ++ res = mp_set(wnd, OID_802_11_RSSI_TRIGGER, ++ &rssi_trigger, sizeof(rssi_trigger)); ++ if (res == NDIS_STATUS_INVALID_DATA) ++ return -EINVAL; ++ if (res) ++ return -EOPNOTSUPP; ++ return 0; ++} ++ ++static int iw_get_ndis_stats(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ struct iw_statistics *stats = &wnd->iw_stats; ++ memcpy(&wrqu->qual, &stats->qual, sizeof(stats->qual)); ++ return 0; ++} ++ ++static int iw_get_range(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct iw_range *range = (struct iw_range *)extra; ++ struct iw_point *data = &wrqu->data; ++ struct ndis_device *wnd = netdev_priv(dev); ++ unsigned int i, n; ++ NDIS_STATUS res; ++ UCHAR rates[NDIS_MAX_RATES_EX]; ++ ndis_tx_power_level tx_power; ++ ++ ENTER2(""); ++ data->length = sizeof(struct iw_range); ++ memset(range, 0, sizeof(struct iw_range)); ++ ++ range->txpower_capa = IW_TXPOW_MWATT; ++ range->num_txpower = 0; ++ ++ res = mp_query(wnd, OID_802_11_TX_POWER_LEVEL, ++ &tx_power, sizeof(tx_power)); ++ if (!res) { ++ range->num_txpower = 1; ++ range->txpower[0] = tx_power; ++ } ++ ++ range->we_version_compiled = WIRELESS_EXT; ++ range->we_version_source = 19; ++ ++ range->retry_capa = IW_RETRY_LIMIT; ++ range->retry_flags = IW_RETRY_LIMIT; ++ range->min_retry = 0; ++ range->max_retry = 255; ++ ++ range->num_channels = 1; ++ ++ range->max_qual.qual = 100; ++ range->max_qual.level = 154; ++ range->max_qual.noise = 154; ++ range->sensitivity = 3; ++ ++ range->max_encoding_tokens = 4; ++ range->num_encoding_sizes = 2; ++ range->encoding_size[0] = 5; ++ range->encoding_size[1] = 13; ++ ++ range->num_bitrates = 0; ++ memset(&rates, 0, sizeof(rates)); ++ res = mp_query_info(wnd, OID_802_11_SUPPORTED_RATES, ++ &rates, sizeof(rates), &n, NULL); ++ if (res) ++ WARNING("getting bit rates failed: %08X", res); ++ else { ++ for (i = 0; i < n && range->num_bitrates < IW_MAX_BITRATES; i++) ++ if (rates[i] & 0x80) ++ continue; ++ else if (rates[i] & 0x7f) { ++ range->bitrate[range->num_bitrates] = ++ (rates[i] & 0x7f) * 500000; ++ range->num_bitrates++; ++ } ++ } ++ ++ range->num_channels = ARRAY_SIZE(freq_chan); ++ ++ for (i = 0; i < ARRAY_SIZE(freq_chan) && i < IW_MAX_FREQUENCIES; i++) { ++ range->freq[i].i = i + 1; ++ range->freq[i].m = freq_chan[i] * 100000; ++ range->freq[i].e = 1; ++ } ++ range->num_frequency = i; ++ ++ range->min_rts = 0; ++ range->max_rts = 2347; ++ range->min_frag = 256; ++ range->max_frag = 2346; ++ ++ /* Event capability (kernel + driver) */ ++ range->event_capa[0] = (IW_EVENT_CAPA_K_0 | ++ IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) | ++ IW_EVENT_CAPA_MASK(SIOCGIWAP) | ++ IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); ++ range->event_capa[1] = IW_EVENT_CAPA_K_1; ++ range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVTXDROP) | ++ IW_EVENT_CAPA_MASK(IWEVCUSTOM) | ++ IW_EVENT_CAPA_MASK(IWEVREGISTERED) | ++ IW_EVENT_CAPA_MASK(IWEVEXPIRED)); ++ ++ range->enc_capa = 0; ++ ++ if (test_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr)) ++ range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP; ++ if (test_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr)) ++ range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP; ++ ++ if (test_bit(Ndis802_11AuthModeWPA, &wnd->capa.auth) || ++ test_bit(Ndis802_11AuthModeWPAPSK, &wnd->capa.auth)) ++ range->enc_capa |= IW_ENC_CAPA_WPA; ++ if (test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) || ++ test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth)) ++ range->enc_capa |= IW_ENC_CAPA_WPA2; ++ ++ return 0; ++} ++ ++void set_default_iw_params(struct ndis_device *wnd) ++{ ++ wnd->iw_auth_key_mgmt = 0; ++ wnd->iw_auth_wpa_version = 0; ++ set_infra_mode(wnd, Ndis802_11Infrastructure); ++ set_ndis_auth_mode(wnd, Ndis802_11AuthModeOpen); ++ set_priv_filter(wnd); ++ set_iw_encr_mode(wnd, IW_AUTH_CIPHER_NONE, IW_AUTH_CIPHER_NONE); ++} ++ ++static int deauthenticate(struct ndis_device *wnd) ++{ ++ int ret; ++ ++ ENTER2(""); ++ ret = disassociate(wnd, 1); ++ set_default_iw_params(wnd); ++ EXIT2(return ret); ++} ++ ++NDIS_STATUS disassociate(struct ndis_device *wnd, int reset_ssid) ++{ ++ NDIS_STATUS res; ++ u8 buf[NDIS_ESSID_MAX_SIZE]; ++ int i; ++ ++ TRACE2(""); ++ res = mp_set(wnd, OID_802_11_DISASSOCIATE, NULL, 0); ++ /* disassociate causes radio to be turned off; if reset_ssid ++ * is given, set ssid to random to enable radio */ ++ if (reset_ssid) { ++ get_random_bytes(buf, sizeof(buf)); ++ for (i = 0; i < sizeof(buf); i++) ++ buf[i] = 'a' + (buf[i] % 26); ++ set_essid(wnd, buf, sizeof(buf)); ++ } ++ return res; ++} ++ ++static int iw_set_mlme(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ struct iw_mlme *mlme = (struct iw_mlme *)extra; ++ ++ ENTER2(""); ++ switch (mlme->cmd) { ++ case IW_MLME_DEAUTH: ++ return deauthenticate(wnd); ++ case IW_MLME_DISASSOC: ++ TRACE2("cmd=%d reason_code=%d", mlme->cmd, mlme->reason_code); ++ return disassociate(wnd, 1); ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return 0; ++} ++ ++static int iw_set_genie(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ /* ++ * NDIS drivers do not allow IEs to be configured; this is ++ * done by the driver based on other configuration. Return 0 ++ * to avoid causing issues with user space programs that ++ * expect this function to succeed. ++ */ ++ return 0; ++} ++ ++static int iw_set_auth(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ TRACE2("index=%d value=%d", wrqu->param.flags & IW_AUTH_INDEX, ++ wrqu->param.value); ++ switch (wrqu->param.flags & IW_AUTH_INDEX) { ++ case IW_AUTH_WPA_VERSION: ++ wnd->iw_auth_wpa_version = wrqu->param.value; ++ break; ++ case IW_AUTH_CIPHER_PAIRWISE: ++ wnd->iw_auth_cipher_pairwise = wrqu->param.value; ++ break; ++ case IW_AUTH_CIPHER_GROUP: ++ wnd->iw_auth_cipher_group = wrqu->param.value; ++ break; ++ case IW_AUTH_KEY_MGMT: ++ wnd->iw_auth_key_mgmt = wrqu->param.value; ++ break; ++ case IW_AUTH_80211_AUTH_ALG: ++ wnd->iw_auth_80211_alg = wrqu->param.value; ++ break; ++ case IW_AUTH_WPA_ENABLED: ++ if (wrqu->param.value) ++ deauthenticate(wnd); ++ break; ++#ifdef IW_AUTH_MFP ++ case IW_AUTH_MFP: ++ if (wrqu->param.value == IW_AUTH_MFP_DISABLED || ++ wrqu->param.value == IW_AUTH_MFP_OPTIONAL) ++ break; ++ WARNING("MFP not implemented"); ++ return -EOPNOTSUPP; ++#endif ++ case IW_AUTH_TKIP_COUNTERMEASURES: ++ case IW_AUTH_DROP_UNENCRYPTED: ++ case IW_AUTH_RX_UNENCRYPTED_EAPOL: ++ case IW_AUTH_PRIVACY_INVOKED: ++ TRACE2("%d not implemented: %d", ++ wrqu->param.flags & IW_AUTH_INDEX, wrqu->param.value); ++ break; ++ default: ++ WARNING("invalid cmd %d", wrqu->param.flags & IW_AUTH_INDEX); ++ return -EOPNOTSUPP; ++ } ++ return 0; ++} ++ ++static int iw_get_auth(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ++ ENTER2("index=%d", wrqu->param.flags & IW_AUTH_INDEX); ++ switch (wrqu->param.flags & IW_AUTH_INDEX) { ++ case IW_AUTH_WPA_VERSION: ++ wrqu->param.value = wnd->iw_auth_wpa_version; ++ break; ++ case IW_AUTH_CIPHER_PAIRWISE: ++ wrqu->param.value = wnd->iw_auth_cipher_pairwise; ++ break; ++ case IW_AUTH_CIPHER_GROUP: ++ wrqu->param.value = wnd->iw_auth_cipher_group; ++ break; ++ case IW_AUTH_KEY_MGMT: ++ wrqu->param.value = wnd->iw_auth_key_mgmt; ++ break; ++ case IW_AUTH_80211_AUTH_ALG: ++ wrqu->param.value = wnd->iw_auth_80211_alg; ++ break; ++ default: ++ WARNING("invalid cmd %d", wrqu->param.flags & IW_AUTH_INDEX); ++ return -EOPNOTSUPP; ++ } ++ return 0; ++} ++ ++static int iw_set_encodeext(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; ++ struct ndis_device *wnd = netdev_priv(dev); ++ struct ndis_add_key ndis_key; ++ int i, keyidx; ++ NDIS_STATUS res; ++ u8 *addr; ++ ++ keyidx = wrqu->encoding.flags & IW_ENCODE_INDEX; ++ ENTER2("%d", keyidx); ++ if (keyidx) ++ keyidx--; ++ else ++ keyidx = wnd->encr_info.tx_key_index; ++ ++ if (keyidx < 0 || keyidx >= MAX_ENCR_KEYS) ++ return -EINVAL; ++ ++ if (ext->alg == WPA_ALG_WEP) { ++ if (!test_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr)) ++ EXIT2(return -1); ++ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) ++ wnd->encr_info.tx_key_index = keyidx; ++ if (add_wep_key(wnd, ext->key, ext->key_len, keyidx)) ++ EXIT2(return -1); ++ else ++ EXIT2(return 0); ++ } ++ if ((wrqu->encoding.flags & IW_ENCODE_DISABLED) || ++ ext->alg == IW_ENCODE_ALG_NONE || ext->key_len == 0) ++ EXIT2(return remove_key(wnd, keyidx, ndis_key.bssid)); ++ ++ if (ext->key_len > sizeof(ndis_key.key)) { ++ TRACE2("incorrect key length (%u)", ext->key_len); ++ EXIT2(return -1); ++ } ++ ++ memset(&ndis_key, 0, sizeof(ndis_key)); ++ ++ ndis_key.struct_size = ++ sizeof(ndis_key) - sizeof(ndis_key.key) + ext->key_len; ++ ndis_key.length = ext->key_len; ++ ndis_key.index = keyidx; ++ ++ if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { ++ for (i = 0; i < 6; i++) ++ ndis_key.rsc |= (((u64)ext->rx_seq[i]) << (i * 8)); ++ TRACE2("0x%llx", ndis_key.rsc); ++ ndis_key.index |= 1 << 29; ++ } ++ ++ addr = ext->addr.sa_data; ++ if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { ++ /* group key */ ++ if (wnd->infrastructure_mode == Ndis802_11IBSS) ++ memset(ndis_key.bssid, 0xff, ETH_ALEN); ++ else ++ get_ap_address(wnd, ndis_key.bssid); ++ } else { ++ /* pairwise key */ ++ ndis_key.index |= (1 << 30); ++ memcpy(ndis_key.bssid, addr, ETH_ALEN); ++ } ++ TRACE2(MACSTRSEP, MAC2STR(ndis_key.bssid)); ++ ++ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) ++ ndis_key.index |= (1 << 31); ++ ++ if (ext->alg == IW_ENCODE_ALG_TKIP && ext->key_len == 32) { ++ /* wpa_supplicant gives us the Michael MIC RX/TX keys in ++ * different order than NDIS spec, so swap the order here. */ ++ memcpy(ndis_key.key, ext->key, 16); ++ memcpy(ndis_key.key + 16, ext->key + 24, 8); ++ memcpy(ndis_key.key + 24, ext->key + 16, 8); ++ } else ++ memcpy(ndis_key.key, ext->key, ext->key_len); ++ ++ res = mp_set(wnd, OID_802_11_ADD_KEY, &ndis_key, ndis_key.struct_size); ++ if (res) { ++ TRACE2("adding key failed (%08X), %u", ++ res, ndis_key.struct_size); ++ EXIT2(return -1); ++ } ++ wnd->encr_info.keys[keyidx].length = ext->key_len; ++ memcpy(&wnd->encr_info.keys[keyidx].key, ndis_key.key, ext->key_len); ++ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) ++ wnd->encr_info.tx_key_index = keyidx; ++ TRACE2("key %d added", keyidx); ++ ++ EXIT2(return 0); ++} ++ ++static int iw_get_encodeext(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ /* struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; */ ++ /* TODO */ ++ ENTER2(""); ++ return 0; ++} ++ ++static int iw_set_pmksa(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct iw_pmksa *pmksa = (struct iw_pmksa *)extra; ++ struct ndis_pmkid pmkid; ++ NDIS_STATUS res; ++ struct ndis_device *wnd = netdev_priv(dev); ++ ++ /* TODO: must keep local list of PMKIDs since NDIS drivers ++ * expect that all PMKID entries are included whenever a new ++ * one is added. */ ++ ++ ENTER2("%d", pmksa->cmd); ++ if ((pmksa->cmd == IW_PMKSA_ADD || pmksa->cmd == IW_PMKSA_REMOVE) && ++ (!(wnd->iw_auth_wpa_version & IW_AUTH_WPA_VERSION_WPA2))) ++ EXIT2(return -EOPNOTSUPP); ++ ++ memset(&pmkid, 0, sizeof(pmkid)); ++ if (pmksa->cmd == IW_PMKSA_ADD) { ++ pmkid.bssid_info_count = 1; ++ memcpy(pmkid.bssid_info[0].bssid, pmksa->bssid.sa_data, ++ ETH_ALEN); ++ memcpy(pmkid.bssid_info[0].pmkid, pmksa->pmkid, IW_PMKID_LEN); ++ } ++ pmkid.length = sizeof(pmkid); ++ ++ res = mp_set(wnd, OID_802_11_PMKID, &pmkid, pmkid.length); ++ if (res == NDIS_STATUS_FAILURE) ++ EXIT2(return -EOPNOTSUPP); ++ TRACE2("OID_802_11_PMKID -> %d", res); ++ if (res) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++#define WEXT(id) [id - SIOCIWFIRST] ++ ++static const iw_handler ndis_handler[] = { ++ WEXT(SIOCGIWNAME) = iw_get_network_type, ++ WEXT(SIOCSIWESSID) = iw_set_essid, ++ WEXT(SIOCGIWESSID) = iw_get_essid, ++ WEXT(SIOCSIWMODE) = iw_set_infra_mode, ++ WEXT(SIOCGIWMODE) = iw_get_infra_mode, ++ WEXT(SIOCGIWFREQ) = iw_get_freq, ++ WEXT(SIOCSIWFREQ) = iw_set_freq, ++ WEXT(SIOCGIWTXPOW) = iw_get_tx_power, ++ WEXT(SIOCSIWTXPOW) = iw_set_tx_power, ++ WEXT(SIOCGIWRATE) = iw_get_bitrate, ++ WEXT(SIOCSIWRATE) = iw_set_bitrate, ++ WEXT(SIOCGIWRTS) = iw_get_rts_threshold, ++ WEXT(SIOCSIWRTS) = iw_set_rts_threshold, ++ WEXT(SIOCGIWFRAG) = iw_get_frag_threshold, ++ WEXT(SIOCSIWFRAG) = iw_set_frag_threshold, ++ WEXT(SIOCGIWAP) = iw_get_ap_address, ++ WEXT(SIOCSIWAP) = iw_set_ap_address, ++ WEXT(SIOCSIWENCODE) = iw_set_wep, ++ WEXT(SIOCGIWENCODE) = iw_get_encr, ++ WEXT(SIOCSIWSCAN) = iw_set_scan, ++ WEXT(SIOCGIWSCAN) = iw_get_scan, ++ WEXT(SIOCGIWPOWER) = iw_get_power_mode, ++ WEXT(SIOCSIWPOWER) = iw_set_power_mode, ++ WEXT(SIOCGIWRANGE) = iw_get_range, ++ WEXT(SIOCGIWSTATS) = iw_get_ndis_stats, ++ WEXT(SIOCGIWSENS) = iw_get_sensitivity, ++ WEXT(SIOCSIWSENS) = iw_set_sensitivity, ++ WEXT(SIOCGIWNICKN) = iw_get_nick, ++ WEXT(SIOCSIWNICKN) = iw_set_nick, ++ WEXT(SIOCSIWCOMMIT) = iw_set_dummy, ++ WEXT(SIOCSIWMLME) = iw_set_mlme, ++ WEXT(SIOCSIWGENIE) = iw_set_genie, ++ WEXT(SIOCSIWAUTH) = iw_set_auth, ++ WEXT(SIOCGIWAUTH) = iw_get_auth, ++ WEXT(SIOCSIWENCODEEXT) = iw_set_encodeext, ++ WEXT(SIOCGIWENCODEEXT) = iw_get_encodeext, ++ WEXT(SIOCSIWPMKSA) = iw_set_pmksa, ++}; ++ ++/* private ioctl's */ ++ ++static int priv_reset(struct net_device *dev, struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int res; ++ ENTER2(""); ++ res = mp_reset(netdev_priv(dev)); ++ if (res) { ++ WARNING("reset failed: %08X", res); ++ return -EOPNOTSUPP; ++ } ++ return 0; ++} ++ ++static int priv_deauthenticate(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ int res; ++ ENTER2(""); ++ res = deauthenticate(netdev_priv(dev)); ++ return res; ++} ++ ++static int priv_power_profile(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ struct miniport *mp; ++ ULONG profile_inf; ++ ++ ENTER2(""); ++ mp = &wnd->wd->driver->ndis_driver->mp; ++ if (!mp->pnp_event_notify) ++ EXIT2(return -EOPNOTSUPP); ++ ++ /* 1 for AC and 0 for Battery */ ++ if (wrqu->param.value) ++ profile_inf = NdisPowerProfileAcOnLine; ++ else ++ profile_inf = NdisPowerProfileBattery; ++ ++ LIN2WIN4(mp->pnp_event_notify, wnd->nmb->mp_ctx, ++ NdisDevicePnPEventPowerProfileChanged, ++ &profile_inf, sizeof(profile_inf)); ++ EXIT2(return 0); ++} ++ ++static int priv_network_type(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ enum network_type network_type; ++ NDIS_STATUS res; ++ char type; ++ ++ ENTER2(""); ++ type = wrqu->param.value; ++ if (type == 'f') ++ network_type = Ndis802_11FH; ++ else if (type == 'b') ++ network_type = Ndis802_11DS; ++ else if (type == 'a') ++ network_type = Ndis802_11OFDM5; ++ else if (type == 'g' || type == 'n') ++ network_type = Ndis802_11OFDM24; ++ else ++ network_type = Ndis802_11Automode; ++ ++ res = mp_set_int(wnd, OID_802_11_NETWORK_TYPE_IN_USE, network_type); ++ if (res) { ++ WARNING("setting network type to %d failed (%08X)", ++ network_type, res); ++ EXIT2(return -EINVAL); ++ } ++ ++ EXIT2(return 0); ++} ++ ++static int priv_media_stream_mode(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ NDIS_STATUS res; ++ int mode; ++ ++ ENTER2(""); ++ if (wrqu->param.value > 0) ++ mode = Ndis802_11MediaStreamOn; ++ else ++ mode = Ndis802_11MediaStreamOff; ++ res = mp_set_int(wnd, OID_802_11_MEDIA_STREAM_MODE, mode); ++ if (res) { ++ WARNING("oid failed (%08X)", res); ++ EXIT2(return -EINVAL); ++ } ++ EXIT2(return 0); ++} ++ ++static int priv_reload_defaults(struct net_device *dev, ++ struct iw_request_info *info, ++ union iwreq_data *wrqu, char *extra) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ int res; ++ ENTER2(""); ++ res = mp_set_int(wnd, OID_802_11_RELOAD_DEFAULTS, ++ Ndis802_11ReloadWEPKeys); ++ if (res) { ++ WARNING("reloading defaults failed: %08X", res); ++ return -EOPNOTSUPP; ++ } ++ return 0; ++} ++ ++static const struct iw_priv_args priv_args[] = { ++ {PRIV_RESET, 0, 0, "ndis_reset"}, ++ {PRIV_POWER_PROFILE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, ++ "power_profile"}, ++ {PRIV_DEAUTHENTICATE, 0, 0, "deauthenticate"}, ++ {PRIV_NETWORK_TYPE, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, ++ "network_type"}, ++ {PRIV_MEDIA_STREAM_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, ++ "media_stream"}, ++ ++ {PRIV_RELOAD_DEFAULTS, 0, 0, "reload_defaults"}, ++}; ++ ++#define WEPRIV(id) [id - SIOCIWFIRSTPRIV] ++ ++static const iw_handler priv_handler[] = { ++ WEPRIV(PRIV_RESET) = priv_reset, ++ WEPRIV(PRIV_POWER_PROFILE) = priv_power_profile, ++ WEPRIV(PRIV_DEAUTHENTICATE) = priv_deauthenticate, ++ WEPRIV(PRIV_NETWORK_TYPE) = priv_network_type, ++ WEPRIV(PRIV_MEDIA_STREAM_MODE) = priv_media_stream_mode, ++ WEPRIV(PRIV_RELOAD_DEFAULTS) = priv_reload_defaults, ++}; ++ ++const struct iw_handler_def ndis_handler_def = { ++ .num_standard = ARRAY_SIZE(ndis_handler), ++ .num_private = ARRAY_SIZE(priv_handler), ++ .num_private_args = ARRAY_SIZE(priv_args), ++ ++ .standard = (iw_handler *)ndis_handler, ++ .private = (iw_handler *)priv_handler, ++ .private_args = (struct iw_priv_args *)priv_args, ++ .get_wireless_stats = get_iw_stats, ++}; ++ ++#endif +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/iw_ndis.h linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/iw_ndis.h +--- linux-3.12.2/3rdparty/ndiswrapper/iw_ndis.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/iw_ndis.h 2013-11-28 21:42:10.000000000 +0200 +@@ -0,0 +1,194 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * 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 _IW_NDIS_H_ ++#define _IW_NDIS_H_ ++ ++#include "ndis.h" ++ ++#define WL_NOISE -96 /* typical noise level in dBm */ ++#define WL_SIGMAX -32 /* typical maximum signal level in dBm */ ++ ++struct ndis_encr_key { ++ ULONG struct_size; ++ ULONG index; ++ ULONG length; ++ UCHAR key[NDIS_ENCODING_TOKEN_MAX]; ++}; ++ ++struct ndis_add_key { ++ ULONG struct_size; ++ ndis_key_index index; ++ ULONG length; ++ mac_address bssid; ++ UCHAR pad[6]; ++ ndis_key_rsc rsc; ++ UCHAR key[NDIS_ENCODING_TOKEN_MAX]; ++}; ++ ++struct ndis_remove_key { ++ ULONG struct_size; ++ ndis_key_index index; ++ mac_address bssid; ++}; ++ ++struct ndis_fixed_ies { ++ UCHAR time_stamp[8]; ++ USHORT beacon_interval; ++ USHORT capa; ++}; ++ ++struct ndis_variable_ies { ++ UCHAR elem_id; ++ UCHAR length; ++ UCHAR data[]; ++}; ++ ++enum ndis_reload_defaults { Ndis802_11ReloadWEPKeys }; ++ ++struct ndis_assoc_info { ++ ULONG length; ++ USHORT req_ies; ++ struct req_ie { ++ USHORT capa; ++ USHORT listen_interval; ++ mac_address cur_ap_address; ++ } req_ie; ++ ULONG req_ie_length; ++ ULONG offset_req_ies; ++ USHORT resp_ies; ++ struct resp_ie { ++ USHORT capa; ++ USHORT status_code; ++ USHORT assoc_id; ++ } resp_ie; ++ ULONG resp_ie_length; ++ ULONG offset_resp_ies; ++}; ++ ++struct ndis_configuration_fh { ++ ULONG length; ++ ULONG hop_pattern; ++ ULONG hop_set; ++ ULONG dwell_time; ++}; ++ ++struct ndis_configuration { ++ ULONG length; ++ ULONG beacon_period; ++ ULONG atim_window; ++ ULONG ds_config; ++ struct ndis_configuration_fh fh_config; ++}; ++ ++struct ndis_wlan_bssid { ++ ULONG length; ++ mac_address mac; ++ UCHAR reserved[2]; ++ struct ndis_essid ssid; ++ ULONG privacy; ++ ndis_rssi rssi; ++ UINT net_type; ++ struct ndis_configuration config; ++ UINT mode; ++ UCHAR rates[NDIS_MAX_RATES]; ++}; ++ ++struct ndis_wlan_bssid_ex { ++ ULONG length; ++ mac_address mac; ++ UCHAR reserved[2]; ++ struct ndis_essid ssid; ++ ULONG privacy; ++ ndis_rssi rssi; ++ UINT net_type; ++ struct ndis_configuration config; ++ UINT mode; ++ UCHAR rates_ex[NDIS_MAX_RATES_EX]; ++ ULONG ie_length; ++ struct ndis_fixed_ies fixed; ++ struct ndis_variable_ies var[]; ++}; ++ ++/* we use bssid_list as bssid_list_ex also */ ++struct ndis_bssid_list { ++ ULONG num_items; ++ struct ndis_wlan_bssid bssid[1]; ++}; ++ ++enum ndis_priv_filter { ++ Ndis802_11PrivFilterAcceptAll, Ndis802_11PrivFilter8021xWEP ++}; ++ ++enum network_type { ++ Ndis802_11FH, Ndis802_11DS, Ndis802_11OFDM5, Ndis802_11OFDM24, ++ /* MSDN site uses Ndis802_11Automode, which is not mentioned ++ * in DDK, so add one and assign it to ++ * Ndis802_11NetworkTypeMax */ ++ Ndis802_11Automode, Ndis802_11NetworkTypeMax = Ndis802_11Automode ++}; ++ ++struct network_type_list { ++ ULONG num; ++ enum network_type types[1]; ++}; ++ ++enum ndis_power { ++ NDIS_POWER_OFF = 0, NDIS_POWER_MAX, NDIS_POWER_MIN, ++}; ++ ++struct ndis_auth_req { ++ ULONG length; ++ mac_address bssid; ++ ULONG flags; ++}; ++ ++struct ndis_bssid_info { ++ mac_address bssid; ++ UCHAR pmkid[IW_PMKID_LEN]; ++}; ++ ++struct ndis_pmkid { ++ ULONG length; ++ ULONG bssid_info_count; ++ struct ndis_bssid_info bssid_info[1]; ++}; ++ ++int get_ap_address(struct ndis_device *wnd, mac_address mac); ++int set_ndis_auth_mode(struct ndis_device *wnd, ULONG auth_mode); ++int get_ndis_encr_mode(struct ndis_device *wnd); ++int set_iw_encr_mode(struct ndis_device *wnd, int cipher_pairwise, ++ int cipher_groupwise); ++int get_ndis_auth_mode(struct ndis_device *wnd); ++NDIS_STATUS disassociate(struct ndis_device *wnd, int reset_ssid); ++void set_default_iw_params(struct ndis_device *wnd); ++extern const struct iw_handler_def ndis_handler_def; ++ ++#define PRIV_RESET SIOCIWFIRSTPRIV+16 ++#define PRIV_POWER_PROFILE SIOCIWFIRSTPRIV+17 ++#define PRIV_NETWORK_TYPE SIOCIWFIRSTPRIV+18 ++#define PRIV_DEAUTHENTICATE SIOCIWFIRSTPRIV+19 ++#define PRIV_MEDIA_STREAM_MODE SIOCIWFIRSTPRIV+20 ++#define PRIV_RELOAD_DEFAULTS SIOCIWFIRSTPRIV+23 ++ ++/* these have to match what is in wpa_supplicant */ ++ ++enum wpa_alg { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP }; ++enum wpa_cipher { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP, ++ CIPHER_WEP104 }; ++enum wpa_key_mgmt { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE, ++ KEY_MGMT_802_1X_NO_WPA, KEY_MGMT_WPA_NONE }; ++ ++#endif // IW_NDIS_H +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/lin2win.h linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/lin2win.h +--- linux-3.12.2/3rdparty/ndiswrapper/lin2win.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/lin2win.h 2013-11-28 21:42:10.000000000 +0200 +@@ -0,0 +1,111 @@ ++/* ++ * Copyright (C) 2006 Giridhar Pemmasani ++ * ++ * 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. ++ * ++ */ ++ ++#ifdef CONFIG_X86_64 ++ ++u64 lin2win0(void *func); ++u64 lin2win1(void *func, u64 arg1); ++u64 lin2win2(void *func, u64 arg1, u64 arg2); ++u64 lin2win3(void *func, u64 arg1, u64 arg2, u64 arg3); ++u64 lin2win4(void *func, u64 arg1, u64 arg2, u64 arg3, u64 arg4); ++u64 lin2win5(void *func, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5); ++u64 lin2win6(void *func, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, ++ u64 arg6); ++ ++#define LIN2WIN0(func) \ ++({ \ ++ if (0) \ ++ func(); \ ++ lin2win0(func); \ ++}) ++ ++#define LIN2WIN1(func, arg1) \ ++({ \ ++ if (0) \ ++ func(arg1); \ ++ lin2win1(func, (u64)arg1); \ ++}) ++ ++#define LIN2WIN2(func, arg1, arg2) \ ++({ \ ++ if (0) \ ++ func(arg1, arg2); \ ++ lin2win2(func, (u64)arg1, (u64)arg2); \ ++}) ++ ++#define LIN2WIN3(func, arg1, arg2, arg3) \ ++({ \ ++ if (0) \ ++ func(arg1, arg2, arg3); \ ++ lin2win3(func, (u64)arg1, (u64)arg2, (u64)arg3); \ ++}) ++ ++#define LIN2WIN4(func, arg1, arg2, arg3, arg4) \ ++({ \ ++ if (0) \ ++ func(arg1, arg2, arg3, arg4); \ ++ lin2win4(func, (u64)arg1, (u64)arg2, (u64)arg3, (u64)arg4); \ ++}) ++ ++#define LIN2WIN5(func, arg1, arg2, arg3, arg4, arg5) \ ++({ \ ++ if (0) \ ++ func(arg1, arg2, arg3, arg4, arg5); \ ++ lin2win5(func, (u64)arg1, (u64)arg2, (u64)arg3, (u64)arg4, \ ++ (u64)arg5); \ ++}) ++ ++#define LIN2WIN6(func, arg1, arg2, arg3, arg4, arg5, arg6) \ ++({ \ ++ if (0) \ ++ func(arg1, arg2, arg3, arg4, arg5, arg6); \ ++ lin2win6(func, (u64)arg1, (u64)arg2, (u64)arg3, (u64)arg4, \ ++ (u64)arg5, (u64)arg6); \ ++}) ++ ++#else // CONFIG_X86_64 ++ ++#define LIN2WIN1(func, arg1) \ ++({ \ ++ TRACE6("calling %p", func); \ ++ func(arg1); \ ++}) ++#define LIN2WIN2(func, arg1, arg2) \ ++({ \ ++ TRACE6("calling %p", func); \ ++ func(arg1, arg2); \ ++}) ++#define LIN2WIN3(func, arg1, arg2, arg3) \ ++({ \ ++ TRACE6("calling %p", func); \ ++ func(arg1, arg2, arg3); \ ++}) ++#define LIN2WIN4(func, arg1, arg2, arg3, arg4) \ ++({ \ ++ TRACE6("calling %p", func); \ ++ func(arg1, arg2, arg3, arg4); \ ++}) ++#define LIN2WIN5(func, arg1, arg2, arg3, arg4, arg5) \ ++({ \ ++ TRACE6("calling %p", func); \ ++ func(arg1, arg2, arg3, arg4, arg5); \ ++}) ++#define LIN2WIN6(func, arg1, arg2, arg3, arg4, arg5, arg6) \ ++({ \ ++ TRACE6("calling %p", func); \ ++ func(arg1, arg2, arg3, arg4, arg5, arg6); \ ++}) ++ ++#endif // CONFIG_X86_64 +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/lin2win.S linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/lin2win.S +--- linux-3.12.2/3rdparty/ndiswrapper/lin2win.S 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/lin2win.S 2013-11-28 21:42:10.000000000 +0200 +@@ -0,0 +1,138 @@ ++/* ++ * Copyright (C) 2011 Pavel Roskin ++ * ++ * 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 ++ ++ .text ++ ++#define WORD_BYTES 8 ++#define LINUX_REG_ARGS 6 ++#define WINDOWS_REG_ARGS 4 ++ ++/* %rbp is saved to create a stack frame, which can help with debugging */ ++#define SAVED_REGS 1 ++ ++/* ++ * When calling a Windows function, stack space is allocated for at least 4 ++ * arguments even if the number of arguments is less than 4. The value of ++ * true is -1 in assembler, so we multiply it by another true value. ++ */ ++#define stack_args(argc) \ ++ (WINDOWS_REG_ARGS + \ ++ (0 < 1) * (argc > WINDOWS_REG_ARGS) * (argc - WINDOWS_REG_ARGS)) ++ ++/* Full required change of stack pointer, in words */ ++#define stack_words_raw(argc) (stack_args(argc) + SAVED_REGS + 1) ++ ++/* Full actual change of stack pointer, in words (must be even) */ ++#define stack_words_aligned(argc) ((stack_words_raw(argc) + 1) & ~1) ++ ++/* Space allocated for Linux arguments on stack */ ++#define stack_space(argc) \ ++ ((stack_words_aligned(argc) - SAVED_REGS - 1) * WORD_BYTES) ++ ++/* ++ * lin2win_win_arg(N) gives the address of the Nth Windows argument on our ++ * stack frame. %rsp points to the first argument. The Nth argument is ++ * therefore at ((N - 1) * 8)(%rsp). ++ * ++ * Don't call with N less than 5! ++ */ ++#define lin2win_win_arg(n) ((n - 1) * WORD_BYTES)(%rsp) ++ ++/* ++ * lin2win_lin_arg(N, ARGC) gives the address of the Nth Linux argument after ++ * the stack has been prepared for a Windows function call with ARGC arguments. ++ * ++ * When called from Linux, the Nth argument is at ((N - 6) * 8)(%rsp). We add ++ * the allocated stack space and saved registers to compensate for %rsp change. ++ * ++ * Don't call with N less than 7! ++ */ ++#define lin2win_lin_arg(n, argc) \ ++ (stack_space(argc) + \ ++ (SAVED_REGS + n - LINUX_REG_ARGS) * WORD_BYTES)(%rsp) ++ ++/* ++ * lin2win(func, winarg1, winarg2, ...) ++ * Call Windows FUNC function with ARGC arguments WINARG1, WINARG2, ... ++ * We get (ARGC + 1) arguments. ++ */ ++.macro lin2win name, argc ++ .type \name, @function ++ ENTRY(\name) ++ ++ /* Create a call frame - it's optional, but good for debugging */ ++ .cfi_startproc ++ push %rbp ++ .cfi_def_cfa %rsp, 2 * WORD_BYTES ++ .cfi_offset %rbp, -2 * WORD_BYTES ++ mov %rsp, %rbp ++ .cfi_def_cfa %rbp, 2 * WORD_BYTES ++ ++ /* Allocate space for Windows arguments */ ++ sub $stack_space(\argc), %rsp ++ ++ /* arg7 to winarg6 */ ++ .if (\argc >= 6) ++ mov lin2win_lin_arg(7, \argc), %r11 ++ mov %r11, lin2win_win_arg(6) ++ .endif ++ ++ /* arg6 to winarg5 */ ++ .if (\argc >= 5) ++ mov %r9, lin2win_win_arg(5) ++ .endif ++ ++ /* arg5 to winarg4 */ ++ .if (\argc >= 4) ++ mov %r8, %r9 ++ .endif ++ ++ /* arg4 to winarg3 */ ++ .if (\argc >= 3) ++ mov %rcx, %r8 ++ .endif ++ ++ /* arg3 to winarg2 - nothing needed, both are in %rdx */ ++ ++ /* arg2 to winarg1 */ ++ .if (\argc >= 1) ++ mov %rsi, %rcx ++ .endif ++ ++ /* Call function (arg1) */ ++ call *%rdi ++ ++ /* Reclaim space for Windows arguments */ ++ add $stack_space(\argc), %rsp ++ ++ /* Return to the caller */ ++ leave ++ .cfi_def_cfa %rsp, WORD_BYTES ++ .cfi_restore %rbp ++ ret ++ .cfi_endproc ++ .size \name, (. - \name) ++.endm ++ ++/* Define lin2winN functions */ ++lin2win lin2win0, 0 ++lin2win lin2win1, 1 ++lin2win lin2win2, 2 ++lin2win lin2win3, 3 ++lin2win lin2win4, 4 ++lin2win lin2win5, 5 ++lin2win lin2win6, 6 +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/loader.c linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/loader.c +--- linux-3.12.2/3rdparty/ndiswrapper/loader.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/loader.c 2013-11-28 21:42:10.000000000 +0200 +@@ -0,0 +1,967 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * 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 "ndis.h" ++#include "loader.h" ++#include "wrapndis.h" ++#include "pnp.h" ++ ++#include ++#include ++#include ++#include ++ ++/* ++ Network adapter: ClassGuid = {4d36e972-e325-11ce-bfc1-08002be10318} ++ Network client: ClassGuid = {4d36e973-e325-11ce-bfc1-08002be10318} ++ PCMCIA adapter: ClassGuid = {4d36e977-e325-11ce-bfc1-08002be10318} ++ USB: ClassGuid = {36fc9e60-c465-11cf-8056-444553540000} ++*/ ++ ++/* the indices used here must match macros WRAP_NDIS_DEVICE etc. */ ++static struct guid class_guids[] = { ++ /* Network */ ++ { .data1 = 0x4d36e972, .data2 = 0xe325, .data3 = 0x11ce }, ++ /* USB WDM */ ++ { .data1 = 0x36fc9e60, .data2 = 0xc465, .data3 = 0x11cf }, ++ /* Bluetooth */ ++ { .data1 = 0xe0cbf06c, .data2 = 0xcd8b, .data3 = 0x4647 }, ++ /* ivtcorporation.com's bluetooth device claims this is ++ * bluetooth guid */ ++ { .data1 = 0xf12d3cf8, .data2 = 0xb11d, .data3 = 0x457e}, ++}; ++ ++struct mutex loader_mutex; ++static struct completion loader_complete; ++ ++static struct nt_list wrap_devices; ++static struct nt_list wrap_drivers; ++ ++static int wrap_device_type(int data1) ++{ ++ int i; ++ for (i = 0; i < ARRAY_SIZE(class_guids); i++) ++ if (data1 == class_guids[i].data1) ++ return i; ++ ERROR("unknown device: 0x%x\n", data1); ++ return -1; ++} ++ ++/* load driver for given device, if not already loaded */ ++struct wrap_driver *load_wrap_driver(struct wrap_device *wd) ++{ ++ int ret; ++ struct nt_list *cur; ++ struct wrap_driver *wrap_driver; ++ ++ ENTER1("device: %04X:%04X:%04X:%04X", wd->vendor, wd->device, ++ wd->subvendor, wd->subdevice); ++ mutex_lock(&loader_mutex); ++ wrap_driver = NULL; ++ nt_list_for_each(cur, &wrap_drivers) { ++ wrap_driver = container_of(cur, struct wrap_driver, list); ++ if (!stricmp(wrap_driver->name, wd->driver_name)) { ++ TRACE1("driver %s already loaded", wrap_driver->name); ++ break; ++ } else ++ wrap_driver = NULL; ++ } ++ mutex_unlock(&loader_mutex); ++ ++ if (!wrap_driver) { ++ char *argv[] = {"loadndisdriver", WRAP_CMD_LOAD_DRIVER, ++#if DEBUG >= 1 ++ "1", ++#else ++ "0", ++#endif ++ UTILS_VERSION, wd->driver_name, ++ wd->conf_file_name, NULL}; ++ char *env[] = {NULL}; ++ ++ TRACE1("loading driver %s", wd->driver_name); ++ mutex_lock(&loader_mutex); ++ reinit_completion(&loader_complete); ++ ret = call_usermodehelper("/sbin/loadndisdriver", argv, env, ++ UMH_WAIT_PROC); ++ if (ret) { ++ mutex_unlock(&loader_mutex); ++ ERROR("couldn't load driver %s; check system log " ++ "for messages from 'loadndisdriver'", ++ wd->driver_name); ++ EXIT1(return NULL); ++ } ++ wait_for_completion(&loader_complete); ++ TRACE1("%s", wd->driver_name); ++ wrap_driver = NULL; ++ nt_list_for_each(cur, &wrap_drivers) { ++ wrap_driver = container_of(cur, struct wrap_driver, ++ list); ++ if (!stricmp(wrap_driver->name, wd->driver_name)) { ++ wd->driver = wrap_driver; ++ break; ++ } else ++ wrap_driver = NULL; ++ } ++ mutex_unlock(&loader_mutex); ++ if (wrap_driver) ++ TRACE1("driver %s is loaded", wrap_driver->name); ++ else ++ ERROR("couldn't load driver '%s'", wd->driver_name); ++ } ++ EXIT1(return wrap_driver); ++} ++ ++/* load the driver files from userspace. */ ++static int load_sys_files(struct wrap_driver *driver, ++ struct load_driver *load_driver) ++{ ++ int i, err; ++ ++ TRACE1("num_pe_images = %d", load_driver->num_sys_files); ++ TRACE1("loading driver: %s", load_driver->name); ++ strncpy(driver->name, load_driver->name, sizeof(driver->name)); ++ driver->name[sizeof(driver->name)-1] = 0; ++ TRACE1("driver: %s", driver->name); ++ err = 0; ++ driver->num_pe_images = 0; ++ for (i = 0; i < load_driver->num_sys_files; i++) { ++ struct pe_image *pe_image; ++ pe_image = &driver->pe_images[driver->num_pe_images]; ++ ++ strncpy(pe_image->name, load_driver->sys_files[i].name, ++ sizeof(pe_image->name)); ++ pe_image->name[sizeof(pe_image->name)-1] = 0; ++ TRACE1("image size: %zu bytes", load_driver->sys_files[i].size); ++ ++#ifdef CONFIG_X86_64 ++#ifdef PAGE_KERNEL_EXECUTABLE ++ pe_image->image = ++ __vmalloc(load_driver->sys_files[i].size, ++ GFP_KERNEL | __GFP_HIGHMEM, ++ PAGE_KERNEL_EXECUTABLE); ++#elif defined PAGE_KERNEL_EXEC ++ pe_image->image = ++ __vmalloc(load_driver->sys_files[i].size, ++ GFP_KERNEL | __GFP_HIGHMEM, ++ PAGE_KERNEL_EXEC); ++#else ++#error x86_64 should have either PAGE_KERNEL_EXECUTABLE or PAGE_KERNEL_EXEC ++#endif ++#else ++ /* hate to play with kernel macros, but PAGE_KERNEL_EXEC is ++ * not available to modules! */ ++#ifdef cpu_has_nx ++ if (cpu_has_nx) ++ pe_image->image = ++ __vmalloc(load_driver->sys_files[i].size, ++ GFP_KERNEL | __GFP_HIGHMEM, ++ __pgprot(__PAGE_KERNEL & ~_PAGE_NX)); ++ else ++ pe_image->image = ++ vmalloc(load_driver->sys_files[i].size); ++#else ++ pe_image->image = ++ vmalloc(load_driver->sys_files[i].size); ++#endif ++#endif ++ if (!pe_image->image) { ++ ERROR("couldn't allocate memory"); ++ err = -ENOMEM; ++ break; ++ } ++ TRACE1("image is at %p", pe_image->image); ++ ++ if (copy_from_user(pe_image->image, ++ load_driver->sys_files[i].data, ++ load_driver->sys_files[i].size)) { ++ ERROR("couldn't load file %s", ++ load_driver->sys_files[i].name); ++ err = -EFAULT; ++ break; ++ } ++ pe_image->size = load_driver->sys_files[i].size; ++ driver->num_pe_images++; ++ } ++ ++ if (!err && link_pe_images(driver->pe_images, driver->num_pe_images)) { ++ ERROR("couldn't prepare driver '%s'", load_driver->name); ++ err = -EINVAL; ++ } ++ ++ if (driver->num_pe_images < load_driver->num_sys_files || err) { ++ for (i = 0; i < driver->num_pe_images; i++) ++ if (driver->pe_images[i].image) ++ vfree(driver->pe_images[i].image); ++ driver->num_pe_images = 0; ++ EXIT1(return err); ++ } else ++ EXIT1(return 0); ++} ++ ++struct wrap_bin_file *get_bin_file(char *bin_file_name) ++{ ++ int i = 0; ++ struct wrap_driver *driver, *cur; ++ ++ ENTER1("%s", bin_file_name); ++ mutex_lock(&loader_mutex); ++ driver = NULL; ++ nt_list_for_each_entry(cur, &wrap_drivers, list) { ++ for (i = 0; i < cur->num_bin_files; i++) ++ if (!stricmp(cur->bin_files[i].name, bin_file_name)) { ++ driver = cur; ++ break; ++ } ++ if (driver) ++ break; ++ } ++ mutex_unlock(&loader_mutex); ++ if (!driver) { ++ TRACE1("couldn't find bin file '%s'", bin_file_name); ++ return NULL; ++ } ++ ++ if (!driver->bin_files[i].data) { ++ char *argv[] = {"loadndisdriver", WRAP_CMD_LOAD_BIN_FILE, ++#if DEBUG >= 1 ++ "1", ++#else ++ "0", ++#endif ++ UTILS_VERSION, driver->name, ++ driver->bin_files[i].name, NULL}; ++ char *env[] = {NULL}; ++ int ret; ++ ++ TRACE1("loading bin file %s/%s", driver->name, ++ driver->bin_files[i].name); ++ mutex_lock(&loader_mutex); ++ reinit_completion(&loader_complete); ++ ret = call_usermodehelper("/sbin/loadndisdriver", argv, env, ++ UMH_WAIT_PROC); ++ if (ret) { ++ mutex_unlock(&loader_mutex); ++ ERROR("couldn't load file %s/%s; check system log " ++ "for messages from 'loadndisdriver' (%d)", ++ driver->name, driver->bin_files[i].name, ret); ++ EXIT1(return NULL); ++ } ++ wait_for_completion(&loader_complete); ++ mutex_unlock(&loader_mutex); ++ if (!driver->bin_files[i].data) { ++ WARNING("couldn't load binary file %s", ++ driver->bin_files[i].name); ++ EXIT1(return NULL); ++ } ++ } ++ EXIT2(return &(driver->bin_files[i])); ++} ++ ++/* called with loader_mutex down */ ++static int add_bin_file(struct load_driver_file *driver_file) ++{ ++ struct wrap_driver *driver, *cur; ++ struct wrap_bin_file *bin_file; ++ int i = 0; ++ ++ driver = NULL; ++ nt_list_for_each_entry(cur, &wrap_drivers, list) { ++ for (i = 0; i < cur->num_bin_files; i++) ++ if (!stricmp(cur->bin_files[i].name, ++ driver_file->name)) { ++ driver = cur; ++ break; ++ } ++ if (driver) ++ break; ++ } ++ if (!driver) { ++ ERROR("couldn't find %s", driver_file->name); ++ return -EINVAL; ++ } ++ bin_file = &driver->bin_files[i]; ++ strncpy(bin_file->name, driver_file->name, sizeof(bin_file->name)); ++ bin_file->name[sizeof(bin_file->name)-1] = 0; ++ bin_file->data = vmalloc(driver_file->size); ++ if (!bin_file->data) { ++ ERROR("couldn't allocate memory"); ++ return -ENOMEM; ++ } ++ bin_file->size = driver_file->size; ++ if (copy_from_user(bin_file->data, driver_file->data, bin_file->size)) { ++ ERROR("couldn't copy data"); ++ free_bin_file(bin_file); ++ return -EFAULT; ++ } ++ return 0; ++} ++ ++void free_bin_file(struct wrap_bin_file *bin_file) ++{ ++ TRACE2("unloading %s", bin_file->name); ++ if (bin_file->data) ++ vfree(bin_file->data); ++ bin_file->data = NULL; ++ bin_file->size = 0; ++ EXIT2(return); ++} ++ ++/* load firmware files from userspace */ ++static int load_bin_files_info(struct wrap_driver *driver, ++ struct load_driver *load_driver) ++{ ++ struct wrap_bin_file *bin_files; ++ int i; ++ ++ ENTER1("%s, %d", load_driver->name, load_driver->num_bin_files); ++ driver->num_bin_files = 0; ++ driver->bin_files = NULL; ++ if (load_driver->num_bin_files == 0) ++ EXIT1(return 0); ++ bin_files = kzalloc(load_driver->num_bin_files * sizeof(*bin_files), ++ GFP_KERNEL); ++ if (!bin_files) { ++ ERROR("couldn't allocate memory"); ++ EXIT1(return -ENOMEM); ++ } ++ ++ for (i = 0; i < load_driver->num_bin_files; i++) { ++ strncpy(bin_files[i].name, load_driver->bin_files[i].name, ++ sizeof(bin_files[i].name)); ++ bin_files[i].name[sizeof(bin_files[i].name)-1] = 0; ++ TRACE2("loaded bin file %s", bin_files[i].name); ++ } ++ driver->num_bin_files = load_driver->num_bin_files; ++ driver->bin_files = bin_files; ++ EXIT1(return 0); ++} ++ ++/* load settings for a device. called with loader_mutex down */ ++static int load_settings(struct wrap_driver *wrap_driver, ++ struct load_driver *load_driver) ++{ ++ int i, num_settings; ++ ++ ENTER1("%p, %p", wrap_driver, load_driver); ++ ++ num_settings = 0; ++ for (i = 0; i < load_driver->num_settings; i++) { ++ struct load_device_setting *load_setting = ++ &load_driver->settings[i]; ++ struct wrap_device_setting *setting; ++ ULONG data1; ++ ++ setting = kzalloc(sizeof(*setting), GFP_KERNEL); ++ if (!setting) { ++ ERROR("couldn't allocate memory"); ++ break; ++ } ++ strncpy(setting->name, load_setting->name, ++ sizeof(setting->name)); ++ setting->name[sizeof(setting->name)-1] = 0; ++ strncpy(setting->value, load_setting->value, ++ sizeof(setting->value)); ++ setting->value[sizeof(setting->value)-1] = 0; ++ TRACE2("%p: %s=%s", setting, setting->name, setting->value); ++ ++ if (strcmp(setting->name, "driver_version") == 0) { ++ strncpy(wrap_driver->version, setting->value, ++ sizeof(wrap_driver->version)); ++ wrap_driver->version[sizeof(wrap_driver->version)-1] = 0; ++ } else if (strcmp(setting->name, "class_guid") == 0 && ++ sscanf(setting->value, "%x", &data1) == 1) { ++ wrap_driver->dev_type = wrap_device_type(data1); ++ if (wrap_driver->dev_type < 0) { ++ WARNING("unknown guid: %x", data1); ++ wrap_driver->dev_type = 0; ++ } ++ } ++ InsertTailList(&wrap_driver->settings, &setting->list); ++ num_settings++; ++ } ++ /* it is not a fatal error if some settings couldn't be loaded */ ++ if (num_settings > 0) ++ EXIT1(return 0); ++ else ++ EXIT1(return -EINVAL); ++} ++ ++void unload_wrap_device(struct wrap_device *wd) ++{ ++ struct nt_list *cur; ++ ENTER1("unloading device %p (%04X:%04X:%04X:%04X), driver %s", wd, ++ wd->vendor, wd->device, wd->subvendor, wd->subdevice, ++ wd->driver_name); ++ mutex_lock(&loader_mutex); ++ while ((cur = RemoveHeadList(&wd->settings))) { ++ struct wrap_device_setting *setting; ++ setting = container_of(cur, struct wrap_device_setting, list); ++ kfree(setting); ++ } ++ RemoveEntryList(&wd->list); ++ mutex_unlock(&loader_mutex); ++ kfree(wd); ++ EXIT1(return); ++} ++ ++/* should be called with loader_mutex down */ ++void unload_wrap_driver(struct wrap_driver *driver) ++{ ++ int i; ++ struct driver_object *drv_obj; ++ struct nt_list *cur, *next; ++ ++ ENTER1("unloading driver: %s (%p)", driver->name, driver); ++ TRACE1("freeing %d images", driver->num_pe_images); ++ drv_obj = driver->drv_obj; ++ for (i = 0; i < driver->num_pe_images; i++) ++ if (driver->pe_images[i].image) { ++ TRACE1("freeing image at %p", ++ driver->pe_images[i].image); ++ vfree(driver->pe_images[i].image); ++ } ++ ++ TRACE1("freeing %d bin files", driver->num_bin_files); ++ for (i = 0; i < driver->num_bin_files; i++) { ++ TRACE1("freeing image at %p", driver->bin_files[i].data); ++ if (driver->bin_files[i].data) ++ vfree(driver->bin_files[i].data); ++ } ++ kfree(driver->bin_files); ++ RtlFreeUnicodeString(&drv_obj->name); ++ RemoveEntryList(&driver->list); ++ nt_list_for_each_safe(cur, next, &driver->settings) { ++ struct wrap_device_setting *setting; ++ struct ndis_configuration_parameter *param; ++ ++ setting = container_of(cur, struct wrap_device_setting, list); ++ TRACE2("%p", setting); ++ param = setting->encoded; ++ if (param) { ++ TRACE2("%p", param); ++ if (param->type == NdisParameterString) ++ RtlFreeUnicodeString(¶m->data.string); ++ ExFreePool(param); ++ } ++ kfree(setting); ++ } ++ /* this frees driver */ ++ free_custom_extensions(drv_obj->drv_ext); ++ kfree(drv_obj->drv_ext); ++ TRACE1("drv_obj: %p", drv_obj); ++ ++ EXIT1(return); ++} ++ ++/* call the entry point of the driver */ ++static int start_wrap_driver(struct wrap_driver *driver) ++{ ++ int i; ++ NTSTATUS ret, res; ++ struct driver_object *drv_obj; ++ typeof(driver->pe_images[0].entry) entry; ++ ++ ENTER1("%s", driver->name); ++ drv_obj = driver->drv_obj; ++ for (ret = res = 0, i = 0; i < driver->num_pe_images; i++) ++ /* dlls are already started by loader */ ++ if (driver->pe_images[i].type == IMAGE_FILE_EXECUTABLE_IMAGE) { ++ entry = driver->pe_images[i].entry; ++ drv_obj->start = driver->pe_images[i].entry; ++ drv_obj->driver_size = driver->pe_images[i].size; ++ TRACE1("entry: %p, %p, drv_obj: %p", ++ entry, *entry, drv_obj); ++ res = LIN2WIN2(entry, drv_obj, &drv_obj->name); ++ ret |= res; ++ TRACE1("entry returns %08X", res); ++ break; ++ } ++ if (ret) { ++ ERROR("driver initialization failed: %08X", ret); ++ RtlFreeUnicodeString(&drv_obj->name); ++ /* this frees ndis_driver */ ++ free_custom_extensions(drv_obj->drv_ext); ++ kfree(drv_obj->drv_ext); ++ TRACE1("drv_obj: %p", drv_obj); ++ ObDereferenceObject(drv_obj); ++ EXIT1(return -EINVAL); ++ } ++ EXIT1(return 0); ++} ++ ++/* ++ * add driver to list of loaded driver but make sure this driver is ++ * not loaded before. called with loader_mutex down ++ */ ++static int add_wrap_driver(struct wrap_driver *driver) ++{ ++ struct wrap_driver *tmp; ++ ++ ENTER1("name: %s", driver->name); ++ nt_list_for_each_entry(tmp, &wrap_drivers, list) { ++ if (stricmp(tmp->name, driver->name) == 0) { ++ ERROR("cannot add duplicate driver"); ++ EXIT1(return -EBUSY); ++ } ++ } ++ InsertHeadList(&wrap_drivers, &driver->list); ++ EXIT1(return 0); ++} ++ ++/* load a driver from userspace and initialize it. called with ++ * loader_mutex down */ ++static int load_user_space_driver(struct load_driver *load_driver) ++{ ++ struct driver_object *drv_obj; ++ struct ansi_string ansi_reg; ++ struct wrap_driver *wrap_driver = NULL; ++ ++ ENTER1("%p", load_driver); ++ drv_obj = allocate_object(sizeof(*drv_obj), OBJECT_TYPE_DRIVER, NULL); ++ if (!drv_obj) { ++ ERROR("couldn't allocate memory"); ++ EXIT1(return -ENOMEM); ++ } ++ TRACE1("drv_obj: %p", drv_obj); ++ drv_obj->drv_ext = kzalloc(sizeof(*(drv_obj->drv_ext)), GFP_KERNEL); ++ if (!drv_obj->drv_ext) { ++ ERROR("couldn't allocate memory"); ++ ObDereferenceObject(drv_obj); ++ EXIT1(return -ENOMEM); ++ } ++ InitializeListHead(&drv_obj->drv_ext->custom_ext); ++ if (IoAllocateDriverObjectExtension(drv_obj, ++ (void *)WRAP_DRIVER_CLIENT_ID, ++ sizeof(*wrap_driver), ++ (void **)&wrap_driver) != ++ STATUS_SUCCESS) ++ EXIT1(return -ENOMEM); ++ TRACE1("driver: %p", wrap_driver); ++ memset(wrap_driver, 0, sizeof(*wrap_driver)); ++ InitializeListHead(&wrap_driver->list); ++ InitializeListHead(&wrap_driver->settings); ++ wrap_driver->drv_obj = drv_obj; ++ RtlInitAnsiString(&ansi_reg, "/tmp"); ++ if (RtlAnsiStringToUnicodeString(&drv_obj->name, &ansi_reg, TRUE) != ++ STATUS_SUCCESS) { ++ ERROR("couldn't initialize registry path"); ++ free_custom_extensions(drv_obj->drv_ext); ++ kfree(drv_obj->drv_ext); ++ TRACE1("drv_obj: %p", drv_obj); ++ ObDereferenceObject(drv_obj); ++ EXIT1(return -EINVAL); ++ } ++ strncpy(wrap_driver->name, load_driver->name, sizeof(wrap_driver->name)); ++ wrap_driver->name[sizeof(wrap_driver->name)-1] = 0; ++ if (load_sys_files(wrap_driver, load_driver) || ++ load_bin_files_info(wrap_driver, load_driver) || ++ load_settings(wrap_driver, load_driver) || ++ start_wrap_driver(wrap_driver) || ++ add_wrap_driver(wrap_driver)) { ++ unload_wrap_driver(wrap_driver); ++ ObDereferenceObject(drv_obj); ++ EXIT1(return -EINVAL); ++ } else { ++ printk(KERN_INFO "%s: driver %s (%s) loaded\n", ++ DRIVER_NAME, wrap_driver->name, wrap_driver->version); ++ add_taint(TAINT_PROPRIETARY_MODULE, LOCKDEP_NOW_UNRELIABLE); ++ EXIT1(return 0); ++ } ++} ++ ++static struct pci_device_id wrap_pci_id_table[] = { ++ { ++ .vendor = PCI_ANY_ID, ++ .device = PCI_ANY_ID, ++ .subvendor = PCI_ANY_ID, ++ .subdevice = PCI_ANY_ID, ++ .class = 0, ++ .class_mask = 0, ++ .driver_data = 0 ++ } ++}; ++ ++static struct pci_driver wrap_pci_driver = { ++ .name = DRIVER_NAME, ++ .id_table = wrap_pci_id_table, ++ .probe = wrap_pnp_start_pci_device, ++ .remove = wrap_pnp_remove_pci_device, ++ .suspend = wrap_pnp_suspend_pci_device, ++ .resume = wrap_pnp_resume_pci_device, ++}; ++ ++#ifdef ENABLE_USB ++static struct usb_device_id wrap_usb_id_table[] = { ++ { ++ .driver_info = 1 ++ }, ++}; ++ ++static struct usb_driver wrap_usb_driver = { ++ .name = DRIVER_NAME, ++ .id_table = wrap_usb_id_table, ++ .probe = wrap_pnp_start_usb_device, ++ .disconnect = wrap_pnp_remove_usb_device, ++ .suspend = wrap_pnp_suspend_usb_device, ++ .resume = wrap_pnp_resume_usb_device, ++}; ++#endif ++ ++/* register drivers for pci and usb */ ++static void register_devices(void) ++{ ++ int res; ++ ++ res = pci_register_driver(&wrap_pci_driver); ++ if (res < 0) { ++ ERROR("couldn't register pci driver: %d", res); ++ wrap_pci_driver.name = NULL; ++ } ++ ++#ifdef ENABLE_USB ++ res = usb_register(&wrap_usb_driver); ++ if (res < 0) { ++ ERROR("couldn't register usb driver: %d", res); ++ wrap_usb_driver.name = NULL; ++ } ++#endif ++ EXIT1(return); ++} ++ ++static void unregister_devices(void) ++{ ++ struct nt_list *cur, *next; ++ ++ mutex_lock(&loader_mutex); ++ nt_list_for_each_safe(cur, next, &wrap_devices) { ++ struct wrap_device *wd; ++ wd = container_of(cur, struct wrap_device, list); ++ set_bit(HW_DISABLED, &wd->hw_status); ++ } ++ mutex_unlock(&loader_mutex); ++ ++ if (wrap_pci_driver.name) ++ pci_unregister_driver(&wrap_pci_driver); ++#ifdef ENABLE_USB ++ if (wrap_usb_driver.name) ++ usb_deregister(&wrap_usb_driver); ++#endif ++} ++ ++struct wrap_device *load_wrap_device(struct load_device *load_device) ++{ ++ int ret; ++ struct nt_list *cur; ++ struct wrap_device *wd = NULL; ++ char vendor[5], device[5], subvendor[5], subdevice[5], bus[5]; ++ ++ ENTER1("%04x, %04x, %04x, %04x", load_device->vendor, ++ load_device->device, load_device->subvendor, ++ load_device->subdevice); ++ if (sprintf(vendor, "%04x", load_device->vendor) == 4 && ++ sprintf(device, "%04x", load_device->device) == 4 && ++ sprintf(subvendor, "%04x", load_device->subvendor) == 4 && ++ sprintf(subdevice, "%04x", load_device->subdevice) == 4 && ++ sprintf(bus, "%04x", load_device->bus) == 4) { ++ char *argv[] = {"loadndisdriver", WRAP_CMD_LOAD_DEVICE, ++#if DEBUG >= 1 ++ "1", ++#else ++ "0", ++#endif ++ UTILS_VERSION, vendor, device, ++ subvendor, subdevice, bus, NULL}; ++ char *env[] = {NULL}; ++ TRACE2("%s, %s, %s, %s, %s", vendor, device, ++ subvendor, subdevice, bus); ++ mutex_lock(&loader_mutex); ++ reinit_completion(&loader_complete); ++ ret = call_usermodehelper("/sbin/loadndisdriver", argv, env, ++ UMH_WAIT_PROC); ++ if (ret) { ++ mutex_unlock(&loader_mutex); ++ TRACE1("couldn't load device %04x:%04x; check system " ++ "log for messages from 'loadndisdriver'", ++ load_device->vendor, load_device->device); ++ EXIT1(return NULL); ++ } ++ wait_for_completion(&loader_complete); ++ wd = NULL; ++ nt_list_for_each(cur, &wrap_devices) { ++ wd = container_of(cur, struct wrap_device, list); ++ TRACE2("%p, %04x, %04x, %04x, %04x", wd, wd->vendor, ++ wd->device, wd->subvendor, wd->subdevice); ++ if (wd->vendor == load_device->vendor && ++ wd->device == load_device->device) ++ break; ++ else ++ wd = NULL; ++ } ++ mutex_unlock(&loader_mutex); ++ } else ++ wd = NULL; ++ EXIT1(return wd); ++} ++ ++struct wrap_device *get_wrap_device(void *dev, int bus) ++{ ++ struct nt_list *cur; ++ struct wrap_device *wd; ++ ++ mutex_lock(&loader_mutex); ++ wd = NULL; ++ nt_list_for_each(cur, &wrap_devices) { ++ wd = container_of(cur, struct wrap_device, list); ++ if (bus == WRAP_PCI_BUS && ++ wrap_is_pci_bus(wd->dev_bus) && wd->pci.pdev == dev) ++ break; ++ else if (bus == WRAP_USB_BUS && ++ wrap_is_usb_bus(wd->dev_bus) && wd->usb.udev == dev) ++ break; ++ else ++ wd = NULL; ++ } ++ mutex_unlock(&loader_mutex); ++ return wd; ++} ++ ++/* called with loader_mutex is down */ ++static long wrapper_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ struct load_driver *load_driver; ++ struct load_device load_device; ++ struct load_driver_file load_bin_file; ++ int ret; ++ void __user *addr = (void __user *)arg; ++ ++ ENTER1("cmd: 0x%x", cmd); ++ ++ ret = 0; ++ switch (cmd) { ++ case WRAP_IOCTL_LOAD_DEVICE: ++ if (copy_from_user(&load_device, addr, sizeof(load_device))) { ++ ret = -EFAULT; ++ break; ++ } ++ TRACE2("%04x, %04x, %04x, %04x", load_device.vendor, ++ load_device.device, load_device.subvendor, ++ load_device.subdevice); ++ if (load_device.vendor) { ++ struct wrap_device *wd; ++ wd = kzalloc(sizeof(*wd), GFP_KERNEL); ++ if (!wd) { ++ ret = -ENOMEM; ++ break; ++ } ++ InitializeListHead(&wd->settings); ++ wd->dev_bus = WRAP_BUS(load_device.bus); ++ wd->vendor = load_device.vendor; ++ wd->device = load_device.device; ++ wd->subvendor = load_device.subvendor; ++ wd->subdevice = load_device.subdevice; ++ strncpy(wd->conf_file_name, load_device.conf_file_name, ++ sizeof(wd->conf_file_name)); ++ wd->conf_file_name[sizeof(wd->conf_file_name)-1] = 0; ++ strncpy(wd->driver_name, load_device.driver_name, ++ sizeof(wd->driver_name)); ++ wd->driver_name[sizeof(wd->driver_name)-1] = 0; ++ InsertHeadList(&wrap_devices, &wd->list); ++ ret = 0; ++ } else ++ ret = -EINVAL; ++ break; ++ case WRAP_IOCTL_LOAD_DRIVER: ++ TRACE1("loading driver at %p", addr); ++ load_driver = vmalloc(sizeof(*load_driver)); ++ if (!load_driver) { ++ ret = -ENOMEM; ++ break; ++ } ++ if (copy_from_user(load_driver, addr, sizeof(*load_driver))) ++ ret = -EFAULT; ++ else ++ ret = load_user_space_driver(load_driver); ++ vfree(load_driver); ++ break; ++ case WRAP_IOCTL_LOAD_BIN_FILE: ++ if (copy_from_user(&load_bin_file, addr, sizeof(load_bin_file))) ++ ret = -EFAULT; ++ else ++ ret = add_bin_file(&load_bin_file); ++ break; ++ default: ++ ERROR("unknown ioctl 0x%x", cmd); ++ ret = -EINVAL; ++ break; ++ } ++ complete(&loader_complete); ++ EXIT1(return ret); ++} ++ ++#ifdef CONFIG_COMPAT ++static int copy_load_driver_file32(struct load_driver_file *k, ++ struct load_driver_file32 __user *u) ++{ ++ u32 data; ++ ++ if (copy_from_user(&k->driver_name, &u->driver_name, ++ sizeof(u->driver_name) + sizeof(u->name))) ++ return -EFAULT; ++ ++ if (get_user(k->size, &u->size)) ++ return -EFAULT; ++ if (get_user(data, &u->data)) ++ return -EFAULT; ++ ++ k->data = (void __user *)(unsigned long)data; ++ return 0; ++} ++ ++static int copy_load_driver32(struct load_driver *k, ++ struct load_driver32 __user *u) ++{ ++ int i; ++ ++ if (copy_from_user(&k->name, &u->name, ++ sizeof(u->name) + sizeof(u->conf_file_name))) ++ return -EFAULT; ++ ++ if (get_user(k->num_sys_files, &u->num_sys_files)) ++ return -EFAULT; ++ ++ for (i = 0; i < k->num_sys_files; i++) ++ if (copy_load_driver_file32(&k->sys_files[i], &u->sys_files[i])) ++ return -EFAULT; ++ ++ if (get_user(k->num_settings, &u->num_settings)) ++ return -EFAULT; ++ ++ if (copy_from_user(&k->settings, &u->settings, ++ sizeof(u->settings[0]) * k->num_settings)) ++ return -EFAULT; ++ ++ if (get_user(k->num_bin_files, &u->num_bin_files)) ++ return -EFAULT; ++ ++ for (i = 0; i < k->num_bin_files; i++) ++ if (copy_load_driver_file32(&k->bin_files[i], &u->bin_files[i])) ++ return -EFAULT; ++ ++ return 0; ++} ++ ++static long wrapper_ioctl_compat(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ int ret = 0; ++ void __user *addr = (void __user *)arg; ++ struct load_driver *kdriver; ++ struct load_driver32 __user *udriver = addr; ++ struct load_driver_file kfile; ++ struct load_driver_file32 __user *ufile = addr; ++ ++ ENTER1("cmd: 0x%x", cmd); ++ ++ switch (cmd) { ++ case WRAP_IOCTL_LOAD_DEVICE32: ++ return wrapper_ioctl(file, WRAP_IOCTL_LOAD_DEVICE, arg); ++ case WRAP_IOCTL_LOAD_DRIVER32: ++ TRACE1("loading driver at %p", addr); ++ kdriver = vmalloc(sizeof(*kdriver)); ++ if (!kdriver) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ ret = copy_load_driver32(kdriver, udriver); ++ if (!ret) ++ ret = load_user_space_driver(kdriver); ++ ++ vfree(kdriver); ++ break; ++ case WRAP_IOCTL_LOAD_BIN_FILE32: ++ ret = copy_load_driver_file32(&kfile, ufile); ++ if (ret) ++ break; ++ ++ ret = add_bin_file(&kfile); ++ break; ++ default: ++ ERROR("unknown ioctl 0x%x", cmd); ++ ret = -EINVAL; ++ break; ++ } ++ complete(&loader_complete); ++ EXIT1(return ret); ++} ++#endif ++ ++static int wrapper_ioctl_release(struct inode *inode, struct file *file) ++{ ++ ENTER1(""); ++ complete(&loader_complete); ++ return 0; ++} ++ ++static struct file_operations wrapper_fops = { ++ .owner = THIS_MODULE, ++ .unlocked_ioctl = wrapper_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = wrapper_ioctl_compat, ++#endif ++ .release = wrapper_ioctl_release, ++}; ++ ++static struct miscdevice wrapper_misc = { ++ .name = DRIVER_NAME, ++ .minor = MISC_DYNAMIC_MINOR, ++ .fops = &wrapper_fops ++}; ++ ++int loader_init(void) ++{ ++ int err; ++ ++ InitializeListHead(&wrap_drivers); ++ InitializeListHead(&wrap_devices); ++ mutex_init(&loader_mutex); ++ init_completion(&loader_complete); ++ if ((err = misc_register(&wrapper_misc)) < 0) { ++ ERROR("couldn't register module (%d)", err); ++ unregister_devices(); ++ EXIT1(return err); ++ } ++ register_devices(); ++ EXIT1(return 0); ++} ++ ++void loader_exit(void) ++{ ++ struct nt_list *cur, *next; ++ ++ ENTER1(""); ++ misc_deregister(&wrapper_misc); ++ unregister_devices(); ++ mutex_lock(&loader_mutex); ++ nt_list_for_each_safe(cur, next, &wrap_drivers) { ++ struct wrap_driver *driver; ++ driver = container_of(cur, struct wrap_driver, list); ++ unload_wrap_driver(driver); ++ } ++ mutex_unlock(&loader_mutex); ++ EXIT1(return); ++} +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/loader.h linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/loader.h +--- linux-3.12.2/3rdparty/ndiswrapper/loader.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/loader.h 2013-11-28 21:42:10.000000000 +0200 +@@ -0,0 +1,108 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * 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 _LOADER_H_ ++#define _LOADER_H_ ++ ++#include "ndiswrapper.h" ++ ++#ifndef __KERNEL__ ++#define __user ++#endif ++ ++struct load_driver_file { ++ char driver_name[MAX_DRIVER_NAME_LEN]; ++ char name[MAX_DRIVER_NAME_LEN]; ++ size_t size; ++ void __user *data; ++}; ++ ++struct load_device_setting { ++ char name[MAX_SETTING_NAME_LEN]; ++ char value[MAX_SETTING_VALUE_LEN]; ++}; ++ ++struct load_device { ++ int bus; ++ int vendor; ++ int device; ++ int subvendor; ++ int subdevice; ++ char conf_file_name[MAX_DRIVER_NAME_LEN]; ++ char driver_name[MAX_DRIVER_NAME_LEN]; ++}; ++ ++struct load_driver { ++ char name[MAX_DRIVER_NAME_LEN]; ++ char conf_file_name[MAX_DRIVER_NAME_LEN]; ++ unsigned int num_sys_files; ++ struct load_driver_file sys_files[MAX_DRIVER_PE_IMAGES]; ++ unsigned int num_settings; ++ struct load_device_setting settings[MAX_DEVICE_SETTINGS]; ++ unsigned int num_bin_files; ++ struct load_driver_file bin_files[MAX_DRIVER_BIN_FILES]; ++}; ++ ++#define WRAP_IOCTL_LOAD_DEVICE _IOW(('N' + 'd' + 'i' + 'S'), 0, \ ++ struct load_device *) ++#define WRAP_IOCTL_LOAD_DRIVER _IOW(('N' + 'd' + 'i' + 'S'), 1, \ ++ struct load_driver *) ++#define WRAP_IOCTL_LOAD_BIN_FILE _IOW(('N' + 'd' + 'i' + 'S'), 2, \ ++ struct load_driver_file *) ++ ++#ifdef CONFIG_COMPAT ++struct load_driver_file32 { ++ char driver_name[MAX_DRIVER_NAME_LEN]; ++ char name[MAX_DRIVER_NAME_LEN]; ++ u32 size; ++ u32 data; ++}; ++ ++struct load_driver32 { ++ char name[MAX_DRIVER_NAME_LEN]; ++ char conf_file_name[MAX_DRIVER_NAME_LEN]; ++ u32 num_sys_files; ++ struct load_driver_file32 sys_files[MAX_DRIVER_PE_IMAGES]; ++ u32 num_settings; ++ struct load_device_setting settings[MAX_DEVICE_SETTINGS]; ++ u32 num_bin_files; ++ struct load_driver_file32 bin_files[MAX_DRIVER_BIN_FILES]; ++} __packed; ++ ++#define WRAP_IOCTL_LOAD_DEVICE32 _IOW(('N' + 'd' + 'i' + 'S'), 0, u32) ++#define WRAP_IOCTL_LOAD_DRIVER32 _IOW(('N' + 'd' + 'i' + 'S'), 1, u32) ++#define WRAP_IOCTL_LOAD_BIN_FILE32 _IOW(('N' + 'd' + 'i' + 'S'), 2, u32) ++#endif ++ ++#define WRAP_CMD_LOAD_DEVICE "load_device" ++#define WRAP_CMD_LOAD_DRIVER "load_driver" ++#define WRAP_CMD_LOAD_BIN_FILE "load_bin_file" ++ ++int loader_init(void); ++void loader_exit(void); ++ ++#ifdef __KERNEL__ ++struct wrap_device *load_wrap_device(struct load_device *load_device); ++struct wrap_driver *load_wrap_driver(struct wrap_device *device); ++struct wrap_bin_file *get_bin_file(char *bin_file_name); ++void free_bin_file(struct wrap_bin_file *bin_file); ++void unload_wrap_driver(struct wrap_driver *driver); ++void unload_wrap_device(struct wrap_device *wd); ++struct wrap_device *get_wrap_device(void *dev, int bus_type); ++ ++extern struct mutex loader_mutex; ++#endif ++ ++#endif /* LOADER_H */ +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/longlong.h linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/longlong.h +--- linux-3.12.2/3rdparty/ndiswrapper/longlong.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/longlong.h 2013-11-28 21:42:10.000000000 +0200 +@@ -0,0 +1,1333 @@ ++/* longlong.h -- definitions for mixed size 32/64 bit arithmetic. ++ Copyright (C) 1991, 1992, 1994, 1995, 1996, 1997, 1998, 1999, 2000 ++ Free Software Foundation, Inc. ++ ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, write to the Free ++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA ++ 02111-1307 USA. */ ++ ++/* You have to define the following before including this file: ++ ++ UWtype -- An unsigned type, default type for operations (typically a "word") ++ UHWtype -- An unsigned type, at least half the size of UWtype. ++ UDWtype -- An unsigned type, at least twice as large a UWtype ++ W_TYPE_SIZE -- size in bits of UWtype ++ ++ UQItype -- Unsigned 8 bit type. ++ SItype, USItype -- Signed and unsigned 32 bit types. ++ DItype, UDItype -- Signed and unsigned 64 bit types. ++ ++ On a 32 bit machine UWtype should typically be USItype; ++ on a 64 bit machine, UWtype should typically be UDItype. ++*/ ++ ++#define __BITS4 (W_TYPE_SIZE / 4) ++#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2)) ++#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1)) ++#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2)) ++ ++#ifndef W_TYPE_SIZE ++#define W_TYPE_SIZE 32 ++#define UWtype USItype ++#define UHWtype USItype ++#define UDWtype UDItype ++#endif ++ ++/* Define auxiliary asm macros. ++ ++ 1) umul_ppmm(high_prod, low_prod, multipler, multiplicand) multiplies two ++ UWtype integers MULTIPLER and MULTIPLICAND, and generates a two UWtype ++ word product in HIGH_PROD and LOW_PROD. ++ ++ 2) __umulsidi3(a,b) multiplies two UWtype integers A and B, and returns a ++ UDWtype product. This is just a variant of umul_ppmm. ++ ++ 3) udiv_qrnnd(quotient, remainder, high_numerator, low_numerator, ++ denominator) divides a UDWtype, composed by the UWtype integers ++ HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and places the quotient ++ in QUOTIENT and the remainder in REMAINDER. HIGH_NUMERATOR must be less ++ than DENOMINATOR for correct operation. If, in addition, the most ++ significant bit of DENOMINATOR must be 1, then the pre-processor symbol ++ UDIV_NEEDS_NORMALIZATION is defined to 1. ++ ++ 4) sdiv_qrnnd(quotient, remainder, high_numerator, low_numerator, ++ denominator). Like udiv_qrnnd but the numbers are signed. The quotient ++ is rounded towards 0. ++ ++ 5) count_leading_zeros(count, x) counts the number of zero-bits from the ++ msb to the first nonzero bit in the UWtype X. This is the number of ++ steps X needs to be shifted left to set the msb. Undefined for X == 0, ++ unless the symbol COUNT_LEADING_ZEROS_0 is defined to some value. ++ ++ 6) count_trailing_zeros(count, x) like count_leading_zeros, but counts ++ from the least significant end. ++ ++ 7) add_ssaaaa(high_sum, low_sum, high_addend_1, low_addend_1, ++ high_addend_2, low_addend_2) adds two UWtype integers, composed by ++ HIGH_ADDEND_1 and LOW_ADDEND_1, and HIGH_ADDEND_2 and LOW_ADDEND_2 ++ respectively. The result is placed in HIGH_SUM and LOW_SUM. Overflow ++ (i.e. carry out) is not stored anywhere, and is lost. ++ ++ 8) sub_ddmmss(high_difference, low_difference, high_minuend, low_minuend, ++ high_subtrahend, low_subtrahend) subtracts two two-word UWtype integers, ++ composed by HIGH_MINUEND_1 and LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and ++ LOW_SUBTRAHEND_2 respectively. The result is placed in HIGH_DIFFERENCE ++ and LOW_DIFFERENCE. Overflow (i.e. carry out) is not stored anywhere, ++ and is lost. ++ ++ If any of these macros are left undefined for a particular CPU, ++ C macros are used. */ ++ ++/* The CPUs come in alphabetical order below. ++ ++ Please add support for more CPUs here, or improve the current support ++ for the CPUs below! ++ (E.g. WE32100, IBM360.) */ ++ ++#if defined (__GNUC__) && !defined (NO_ASM) ++ ++/* We sometimes need to clobber "cc" with gcc2, but that would not be ++ understood by gcc1. Use cpp to avoid major code duplication. */ ++#if __GNUC__ < 2 ++#define __CLOBBER_CC ++#define __AND_CLOBBER_CC ++#else /* __GNUC__ >= 2 */ ++#define __CLOBBER_CC : "cc" ++#define __AND_CLOBBER_CC , "cc" ++#endif /* __GNUC__ < 2 */ ++ ++#if defined (__alpha) && W_TYPE_SIZE == 64 ++#define umul_ppmm(ph, pl, m0, m1) \ ++ do { \ ++ UDItype __m0 = (m0), __m1 = (m1); \ ++ __asm__ ("umulh %r1,%2,%0" \ ++ : "=r" ((UDItype) ph) \ ++ : "%rJ" (__m0), \ ++ "rI" (__m1)); \ ++ (pl) = __m0 * __m1; \ ++ } while (0) ++#define UMUL_TIME 46 ++#ifndef LONGLONG_STANDALONE ++#define udiv_qrnnd(q, r, n1, n0, d) \ ++ do { UDItype __r; \ ++ (q) = __udiv_qrnnd (&__r, (n1), (n0), (d)); \ ++ (r) = __r; \ ++ } while (0) ++extern UDItype __udiv_qrnnd (UDItype *, UDItype, UDItype, UDItype); ++#define UDIV_TIME 220 ++#endif /* LONGLONG_STANDALONE */ ++#ifdef __alpha_cix__ ++#define count_leading_zeros(COUNT,X) \ ++ __asm__("ctlz %1,%0" : "=r"(COUNT) : "r"(X)) ++#define count_trailing_zeros(COUNT,X) \ ++ __asm__("cttz %1,%0" : "=r"(COUNT) : "r"(X)) ++#define COUNT_LEADING_ZEROS_0 64 ++#else ++extern const UQItype __clz_tab[]; ++#define count_leading_zeros(COUNT,X) \ ++ do { \ ++ UDItype __xr = (X), __t, __a; \ ++ __asm__("cmpbge $31,%1,%0" : "=r"(__t) : "r"(__xr)); \ ++ __a = __clz_tab[__t ^ 0xff] - 1; \ ++ __asm__("extbl %1,%2,%0" : "=r"(__t) : "r"(__xr), "r"(__a)); \ ++ (COUNT) = 64 - (__clz_tab[__t] + __a*8); \ ++ } while (0) ++#define count_trailing_zeros(COUNT,X) \ ++ do { \ ++ UDItype __xr = (X), __t, __a; \ ++ __asm__("cmpbge $31,%1,%0" : "=r"(__t) : "r"(__xr)); \ ++ __t = ~__t & -~__t; \ ++ __a = ((__t & 0xCC) != 0) * 2; \ ++ __a += ((__t & 0xF0) != 0) * 4; \ ++ __a += ((__t & 0xAA) != 0); \ ++ __asm__("extbl %1,%2,%0" : "=r"(__t) : "r"(__xr), "r"(__a)); \ ++ __a <<= 3; \ ++ __t &= -__t; \ ++ __a += ((__t & 0xCC) != 0) * 2; \ ++ __a += ((__t & 0xF0) != 0) * 4; \ ++ __a += ((__t & 0xAA) != 0); \ ++ (COUNT) = __a; \ ++ } while (0) ++#endif /* __alpha_cix__ */ ++#endif /* __alpha */ ++ ++#if defined (__arc__) && W_TYPE_SIZE == 32 ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("add.f %1, %4, %5\n\tadc %0, %2, %3" \ ++ : "=r" ((USItype) (sh)), \ ++ "=&r" ((USItype) (sl)) \ ++ : "%r" ((USItype) (ah)), \ ++ "rIJ" ((USItype) (bh)), \ ++ "%r" ((USItype) (al)), \ ++ "rIJ" ((USItype) (bl))) ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("sub.f %1, %4, %5\n\tsbc %0, %2, %3" \ ++ : "=r" ((USItype) (sh)), \ ++ "=&r" ((USItype) (sl)) \ ++ : "r" ((USItype) (ah)), \ ++ "rIJ" ((USItype) (bh)), \ ++ "r" ((USItype) (al)), \ ++ "rIJ" ((USItype) (bl))) ++/* Call libgcc routine. */ ++#define umul_ppmm(w1, w0, u, v) \ ++do { \ ++ DWunion __w; \ ++ __w.ll = __umulsidi3 (u, v); \ ++ w1 = __w.s.high; \ ++ w0 = __w.s.low; \ ++} while (0) ++#define __umulsidi3 __umulsidi3 ++UDItype __umulsidi3 (USItype, USItype); ++#endif ++ ++#if defined (__arm__) && W_TYPE_SIZE == 32 ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("adds %1, %4, %5\n\tadc %0, %2, %3" \ ++ : "=r" ((USItype) (sh)), \ ++ "=&r" ((USItype) (sl)) \ ++ : "%r" ((USItype) (ah)), \ ++ "rI" ((USItype) (bh)), \ ++ "%r" ((USItype) (al)), \ ++ "rI" ((USItype) (bl))) ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("subs %1, %4, %5\n\tsbc %0, %2, %3" \ ++ : "=r" ((USItype) (sh)), \ ++ "=&r" ((USItype) (sl)) \ ++ : "r" ((USItype) (ah)), \ ++ "rI" ((USItype) (bh)), \ ++ "r" ((USItype) (al)), \ ++ "rI" ((USItype) (bl))) ++#define umul_ppmm(xh, xl, a, b) \ ++{register USItype __t0, __t1, __t2; \ ++ __asm__ ("%@ Inlined umul_ppmm\n" \ ++ " mov %2, %5, lsr #16\n" \ ++ " mov %0, %6, lsr #16\n" \ ++ " bic %3, %5, %2, lsl #16\n" \ ++ " bic %4, %6, %0, lsl #16\n" \ ++ " mul %1, %3, %4\n" \ ++ " mul %4, %2, %4\n" \ ++ " mul %3, %0, %3\n" \ ++ " mul %0, %2, %0\n" \ ++ " adds %3, %4, %3\n" \ ++ " addcs %0, %0, #65536\n" \ ++ " adds %1, %1, %3, lsl #16\n" \ ++ " adc %0, %0, %3, lsr #16" \ ++ : "=&r" ((USItype) (xh)), \ ++ "=r" ((USItype) (xl)), \ ++ "=&r" (__t0), "=&r" (__t1), "=r" (__t2) \ ++ : "r" ((USItype) (a)), \ ++ "r" ((USItype) (b)));} ++#define UMUL_TIME 20 ++#define UDIV_TIME 100 ++#endif /* __arm__ */ ++ ++#if defined (__hppa) && W_TYPE_SIZE == 32 ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("add %4,%5,%1\n\taddc %2,%3,%0" \ ++ : "=r" ((USItype) (sh)), \ ++ "=&r" ((USItype) (sl)) \ ++ : "%rM" ((USItype) (ah)), \ ++ "rM" ((USItype) (bh)), \ ++ "%rM" ((USItype) (al)), \ ++ "rM" ((USItype) (bl))) ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("sub %4,%5,%1\n\tsubb %2,%3,%0" \ ++ : "=r" ((USItype) (sh)), \ ++ "=&r" ((USItype) (sl)) \ ++ : "rM" ((USItype) (ah)), \ ++ "rM" ((USItype) (bh)), \ ++ "rM" ((USItype) (al)), \ ++ "rM" ((USItype) (bl))) ++#if defined (_PA_RISC1_1) ++#define umul_ppmm(w1, w0, u, v) \ ++ do { \ ++ union \ ++ { \ ++ UDItype __f; \ ++ struct {USItype __w1, __w0;} __w1w0; \ ++ } __t; \ ++ __asm__ ("xmpyu %1,%2,%0" \ ++ : "=x" (__t.__f) \ ++ : "x" ((USItype) (u)), \ ++ "x" ((USItype) (v))); \ ++ (w1) = __t.__w1w0.__w1; \ ++ (w0) = __t.__w1w0.__w0; \ ++ } while (0) ++#define UMUL_TIME 8 ++#else ++#define UMUL_TIME 30 ++#endif ++#define UDIV_TIME 40 ++#define count_leading_zeros(count, x) \ ++ do { \ ++ USItype __tmp; \ ++ __asm__ ( \ ++ "ldi 1,%0\n" \ ++" extru,= %1,15,16,%%r0 ; Bits 31..16 zero?\n" \ ++" extru,tr %1,15,16,%1 ; No. Shift down, skip add.\n"\ ++" ldo 16(%0),%0 ; Yes. Perform add.\n" \ ++" extru,= %1,23,8,%%r0 ; Bits 15..8 zero?\n" \ ++" extru,tr %1,23,8,%1 ; No. Shift down, skip add.\n"\ ++" ldo 8(%0),%0 ; Yes. Perform add.\n" \ ++" extru,= %1,27,4,%%r0 ; Bits 7..4 zero?\n" \ ++" extru,tr %1,27,4,%1 ; No. Shift down, skip add.\n"\ ++" ldo 4(%0),%0 ; Yes. Perform add.\n" \ ++" extru,= %1,29,2,%%r0 ; Bits 3..2 zero?\n" \ ++" extru,tr %1,29,2,%1 ; No. Shift down, skip add.\n"\ ++" ldo 2(%0),%0 ; Yes. Perform add.\n" \ ++" extru %1,30,1,%1 ; Extract bit 1.\n" \ ++" sub %0,%1,%0 ; Subtract it.\n" \ ++ : "=r" (count), "=r" (__tmp) : "1" (x)); \ ++ } while (0) ++#endif ++ ++#if (defined (__i370__) || defined (__mvs__)) && W_TYPE_SIZE == 32 ++#define umul_ppmm(xh, xl, m0, m1) \ ++ do { \ ++ union {UDItype __ll; \ ++ struct {USItype __h, __l;} __i; \ ++ } __xx; \ ++ USItype __m0 = (m0), __m1 = (m1); \ ++ __asm__ ("mr %0,%3" \ ++ : "=r" (__xx.__i.__h), \ ++ "=r" (__xx.__i.__l) \ ++ : "%1" (__m0), \ ++ "r" (__m1)); \ ++ (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \ ++ (xh) += ((((SItype) __m0 >> 31) & __m1) \ ++ + (((SItype) __m1 >> 31) & __m0)); \ ++ } while (0) ++#define smul_ppmm(xh, xl, m0, m1) \ ++ do { \ ++ union {DItype __ll; \ ++ struct {USItype __h, __l;} __i; \ ++ } __xx; \ ++ __asm__ ("mr %0,%3" \ ++ : "=r" (__xx.__i.__h), \ ++ "=r" (__xx.__i.__l) \ ++ : "%1" (m0), \ ++ "r" (m1)); \ ++ (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \ ++ } while (0) ++#define sdiv_qrnnd(q, r, n1, n0, d) \ ++ do { \ ++ union {DItype __ll; \ ++ struct {USItype __h, __l;} __i; \ ++ } __xx; \ ++ __xx.__i.__h = n1; __xx.__i.__l = n0; \ ++ __asm__ ("dr %0,%2" \ ++ : "=r" (__xx.__ll) \ ++ : "0" (__xx.__ll), "r" (d)); \ ++ (q) = __xx.__i.__l; (r) = __xx.__i.__h; \ ++ } while (0) ++#endif ++ ++#if (defined (__i386__) || defined (__i486__)) && W_TYPE_SIZE == 32 ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("addl %5,%1\n\tadcl %3,%0" \ ++ : "=r" (sh), \ ++ "=&r" (sl) \ ++ : "%0" ((USItype) (ah)), \ ++ "g" ((USItype) (bh)), \ ++ "%1" ((USItype) (al)), \ ++ "g" ((USItype) (bl))) ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("subl %5,%1\n\tsbbl %3,%0" \ ++ : "=r" (sh), \ ++ "=&r" (sl) \ ++ : "0" ((USItype) (ah)), \ ++ "g" ((USItype) (bh)), \ ++ "1" ((USItype) (al)), \ ++ "g" ((USItype) (bl))) ++#define umul_ppmm(w1, w0, u, v) \ ++ __asm__ ("mull %3" \ ++ : "=a" (w0), \ ++ "=d" (w1) \ ++ : "%0" ((USItype) (u)), \ ++ "rm" ((USItype) (v))) ++#define udiv_qrnnd(q, r, n1, n0, dv) \ ++ __asm__ ("divl %4" \ ++ : "=a" (q), \ ++ "=d" (r) \ ++ : "0" ((USItype) (n0)), \ ++ "1" ((USItype) (n1)), \ ++ "rm" ((USItype) (dv))) ++#define count_leading_zeros(count, x) \ ++ do { \ ++ USItype __cbtmp; \ ++ __asm__ ("bsrl %1,%0" \ ++ : "=r" (__cbtmp) : "rm" ((USItype) (x))); \ ++ (count) = __cbtmp ^ 31; \ ++ } while (0) ++#define count_trailing_zeros(count, x) \ ++ __asm__ ("bsfl %1,%0" : "=r" (count) : "rm" ((USItype)(x))) ++#define UMUL_TIME 40 ++#define UDIV_TIME 40 ++#endif /* 80x86 */ ++ ++#if defined (__i960__) && W_TYPE_SIZE == 32 ++#define umul_ppmm(w1, w0, u, v) \ ++ ({union {UDItype __ll; \ ++ struct {USItype __l, __h;} __i; \ ++ } __xx; \ ++ __asm__ ("emul %2,%1,%0" \ ++ : "=d" (__xx.__ll) \ ++ : "%dI" ((USItype) (u)), \ ++ "dI" ((USItype) (v))); \ ++ (w1) = __xx.__i.__h; (w0) = __xx.__i.__l;}) ++#define __umulsidi3(u, v) \ ++ ({UDItype __w; \ ++ __asm__ ("emul %2,%1,%0" \ ++ : "=d" (__w) \ ++ : "%dI" ((USItype) (u)), \ ++ "dI" ((USItype) (v))); \ ++ __w; }) ++#endif /* __i960__ */ ++ ++#if defined (__M32R__) && W_TYPE_SIZE == 32 ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ /* The cmp clears the condition bit. */ \ ++ __asm__ ("cmp %0,%0\n\taddx %%5,%1\n\taddx %%3,%0" \ ++ : "=r" ((USItype) (sh)), \ ++ "=&r" ((USItype) (sl)) \ ++ : "%0" ((USItype) (ah)), \ ++ "r" ((USItype) (bh)), \ ++ "%1" ((USItype) (al)), \ ++ "r" ((USItype) (bl)) \ ++ : "cbit") ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ /* The cmp clears the condition bit. */ \ ++ __asm__ ("cmp %0,%0\n\tsubx %5,%1\n\tsubx %3,%0" \ ++ : "=r" ((USItype) (sh)), \ ++ "=&r" ((USItype) (sl)) \ ++ : "0" ((USItype) (ah)), \ ++ "r" ((USItype) (bh)), \ ++ "1" ((USItype) (al)), \ ++ "r" ((USItype) (bl)) \ ++ : "cbit") ++#endif /* __M32R__ */ ++ ++#if defined (__mc68000__) && W_TYPE_SIZE == 32 ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("add%.l %5,%1\n\taddx%.l %3,%0" \ ++ : "=d" ((USItype) (sh)), \ ++ "=&d" ((USItype) (sl)) \ ++ : "%0" ((USItype) (ah)), \ ++ "d" ((USItype) (bh)), \ ++ "%1" ((USItype) (al)), \ ++ "g" ((USItype) (bl))) ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("sub%.l %5,%1\n\tsubx%.l %3,%0" \ ++ : "=d" ((USItype) (sh)), \ ++ "=&d" ((USItype) (sl)) \ ++ : "0" ((USItype) (ah)), \ ++ "d" ((USItype) (bh)), \ ++ "1" ((USItype) (al)), \ ++ "g" ((USItype) (bl))) ++ ++/* The '020, '030, '040 and CPU32 have 32x32->64 and 64/32->32q-32r. */ ++#if defined (__mc68020__) || defined(mc68020) \ ++ || defined(__mc68030__) || defined(mc68030) \ ++ || defined(__mc68040__) || defined(mc68040) \ ++ || defined(__mcpu32__) || defined(mcpu32) ++#define umul_ppmm(w1, w0, u, v) \ ++ __asm__ ("mulu%.l %3,%1:%0" \ ++ : "=d" ((USItype) (w0)), \ ++ "=d" ((USItype) (w1)) \ ++ : "%0" ((USItype) (u)), \ ++ "dmi" ((USItype) (v))) ++#define UMUL_TIME 45 ++#define udiv_qrnnd(q, r, n1, n0, d) \ ++ __asm__ ("divu%.l %4,%1:%0" \ ++ : "=d" ((USItype) (q)), \ ++ "=d" ((USItype) (r)) \ ++ : "0" ((USItype) (n0)), \ ++ "1" ((USItype) (n1)), \ ++ "dmi" ((USItype) (d))) ++#define UDIV_TIME 90 ++#define sdiv_qrnnd(q, r, n1, n0, d) \ ++ __asm__ ("divs%.l %4,%1:%0" \ ++ : "=d" ((USItype) (q)), \ ++ "=d" ((USItype) (r)) \ ++ : "0" ((USItype) (n0)), \ ++ "1" ((USItype) (n1)), \ ++ "dmi" ((USItype) (d))) ++ ++#else /* not mc68020 */ ++#if !defined(__mcf5200__) ++/* %/ inserts REGISTER_PREFIX, %# inserts IMMEDIATE_PREFIX. */ ++#define umul_ppmm(xh, xl, a, b) \ ++ __asm__ ("| Inlined umul_ppmm\n" \ ++ " move%.l %2,%/d0\n" \ ++ " move%.l %3,%/d1\n" \ ++ " move%.l %/d0,%/d2\n" \ ++ " swap %/d0\n" \ ++ " move%.l %/d1,%/d3\n" \ ++ " swap %/d1\n" \ ++ " move%.w %/d2,%/d4\n" \ ++ " mulu %/d3,%/d4\n" \ ++ " mulu %/d1,%/d2\n" \ ++ " mulu %/d0,%/d3\n" \ ++ " mulu %/d0,%/d1\n" \ ++ " move%.l %/d4,%/d0\n" \ ++ " eor%.w %/d0,%/d0\n" \ ++ " swap %/d0\n" \ ++ " add%.l %/d0,%/d2\n" \ ++ " add%.l %/d3,%/d2\n" \ ++ " jcc 1f\n" \ ++ " add%.l %#65536,%/d1\n" \ ++ "1: swap %/d2\n" \ ++ " moveq %#0,%/d0\n" \ ++ " move%.w %/d2,%/d0\n" \ ++ " move%.w %/d4,%/d2\n" \ ++ " move%.l %/d2,%1\n" \ ++ " add%.l %/d1,%/d0\n" \ ++ " move%.l %/d0,%0" \ ++ : "=g" ((USItype) (xh)), \ ++ "=g" ((USItype) (xl)) \ ++ : "g" ((USItype) (a)), \ ++ "g" ((USItype) (b)) \ ++ : "d0", "d1", "d2", "d3", "d4") ++#define UMUL_TIME 100 ++#define UDIV_TIME 400 ++#endif /* not mcf5200 */ ++#endif /* not mc68020 */ ++ ++/* The '020, '030, '040 and '060 have bitfield insns. */ ++#if defined (__mc68020__) || defined(mc68020) \ ++ || defined(__mc68030__) || defined(mc68030) \ ++ || defined(__mc68040__) || defined(mc68040) \ ++ || defined(__mc68060__) || defined(mc68060) ++#define count_leading_zeros(count, x) \ ++ __asm__ ("bfffo %1{%b2:%b2},%0" \ ++ : "=d" ((USItype) (count)) \ ++ : "od" ((USItype) (x)), "n" (0)) ++#endif ++#endif /* mc68000 */ ++ ++#if defined (__m88000__) && W_TYPE_SIZE == 32 ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("addu.co %1,%r4,%r5\n\taddu.ci %0,%r2,%r3" \ ++ : "=r" ((USItype) (sh)), \ ++ "=&r" ((USItype) (sl)) \ ++ : "%rJ" ((USItype) (ah)), \ ++ "rJ" ((USItype) (bh)), \ ++ "%rJ" ((USItype) (al)), \ ++ "rJ" ((USItype) (bl))) ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("subu.co %1,%r4,%r5\n\tsubu.ci %0,%r2,%r3" \ ++ : "=r" ((USItype) (sh)), \ ++ "=&r" ((USItype) (sl)) \ ++ : "rJ" ((USItype) (ah)), \ ++ "rJ" ((USItype) (bh)), \ ++ "rJ" ((USItype) (al)), \ ++ "rJ" ((USItype) (bl))) ++#define count_leading_zeros(count, x) \ ++ do { \ ++ USItype __cbtmp; \ ++ __asm__ ("ff1 %0,%1" \ ++ : "=r" (__cbtmp) \ ++ : "r" ((USItype) (x))); \ ++ (count) = __cbtmp ^ 31; \ ++ } while (0) ++#define COUNT_LEADING_ZEROS_0 63 /* sic */ ++#if defined (__mc88110__) ++#define umul_ppmm(wh, wl, u, v) \ ++ do { \ ++ union {UDItype __ll; \ ++ struct {USItype __h, __l;} __i; \ ++ } __xx; \ ++ __asm__ ("mulu.d %0,%1,%2" \ ++ : "=r" (__xx.__ll) \ ++ : "r" ((USItype) (u)), \ ++ "r" ((USItype) (v))); \ ++ (wh) = __xx.__i.__h; \ ++ (wl) = __xx.__i.__l; \ ++ } while (0) ++#define udiv_qrnnd(q, r, n1, n0, d) \ ++ ({union {UDItype __ll; \ ++ struct {USItype __h, __l;} __i; \ ++ } __xx; \ ++ USItype __q; \ ++ __xx.__i.__h = (n1); __xx.__i.__l = (n0); \ ++ __asm__ ("divu.d %0,%1,%2" \ ++ : "=r" (__q) \ ++ : "r" (__xx.__ll), \ ++ "r" ((USItype) (d))); \ ++ (r) = (n0) - __q * (d); (q) = __q; }) ++#define UMUL_TIME 5 ++#define UDIV_TIME 25 ++#else ++#define UMUL_TIME 17 ++#define UDIV_TIME 150 ++#endif /* __mc88110__ */ ++#endif /* __m88000__ */ ++ ++#if defined (__mips__) && W_TYPE_SIZE == 32 ++#define umul_ppmm(w1, w0, u, v) \ ++ __asm__ ("multu %2,%3" \ ++ : "=l" ((USItype) (w0)), \ ++ "=h" ((USItype) (w1)) \ ++ : "d" ((USItype) (u)), \ ++ "d" ((USItype) (v))) ++#define UMUL_TIME 10 ++#define UDIV_TIME 100 ++#endif /* __mips__ */ ++ ++#if defined (__ns32000__) && W_TYPE_SIZE == 32 ++#define umul_ppmm(w1, w0, u, v) \ ++ ({union {UDItype __ll; \ ++ struct {USItype __l, __h;} __i; \ ++ } __xx; \ ++ __asm__ ("meid %2,%0" \ ++ : "=g" (__xx.__ll) \ ++ : "%0" ((USItype) (u)), \ ++ "g" ((USItype) (v))); \ ++ (w1) = __xx.__i.__h; (w0) = __xx.__i.__l;}) ++#define __umulsidi3(u, v) \ ++ ({UDItype __w; \ ++ __asm__ ("meid %2,%0" \ ++ : "=g" (__w) \ ++ : "%0" ((USItype) (u)), \ ++ "g" ((USItype) (v))); \ ++ __w; }) ++#define udiv_qrnnd(q, r, n1, n0, d) \ ++ ({union {UDItype __ll; \ ++ struct {USItype __l, __h;} __i; \ ++ } __xx; \ ++ __xx.__i.__h = (n1); __xx.__i.__l = (n0); \ ++ __asm__ ("deid %2,%0" \ ++ : "=g" (__xx.__ll) \ ++ : "0" (__xx.__ll), \ ++ "g" ((USItype) (d))); \ ++ (r) = __xx.__i.__l; (q) = __xx.__i.__h; }) ++#define count_trailing_zeros(count,x) \ ++ do { \ ++ __asm__ ("ffsd %2,%0" \ ++ : "=r" ((USItype) (count)) \ ++ : "0" ((USItype) 0), \ ++ "r" ((USItype) (x))); \ ++ } while (0) ++#endif /* __ns32000__ */ ++ ++/* FIXME: We should test _IBMR2 here when we add assembly support for the ++ system vendor compilers. ++ FIXME: What's needed for gcc PowerPC VxWorks? __vxworks__ is not good ++ enough, since that hits ARM and m68k too. */ ++#if (defined (_ARCH_PPC) /* AIX */ \ ++ || defined (_ARCH_PWR) /* AIX */ \ ++ || defined (_ARCH_COM) /* AIX */ \ ++ || defined (__powerpc__) /* gcc */ \ ++ || defined (__POWERPC__) /* BEOS */ \ ++ || defined (__ppc__) /* Darwin */ \ ++ || defined (PPC) /* GNU/Linux, SysV */ \ ++ ) && W_TYPE_SIZE == 32 ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ do { \ ++ if (__builtin_constant_p (bh) && (bh) == 0) \ ++ __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \ ++ : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\ ++ else if (__builtin_constant_p (bh) && (bh) == ~(USItype) 0) \ ++ __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \ ++ : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\ ++ else \ ++ __asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \ ++ : "=r" (sh), "=&r" (sl) \ ++ : "%r" (ah), "r" (bh), "%r" (al), "rI" (bl)); \ ++ } while (0) ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ do { \ ++ if (__builtin_constant_p (ah) && (ah) == 0) \ ++ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \ ++ : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\ ++ else if (__builtin_constant_p (ah) && (ah) == ~(USItype) 0) \ ++ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \ ++ : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\ ++ else if (__builtin_constant_p (bh) && (bh) == 0) \ ++ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \ ++ : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\ ++ else if (__builtin_constant_p (bh) && (bh) == ~(USItype) 0) \ ++ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \ ++ : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\ ++ else \ ++ __asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \ ++ : "=r" (sh), "=&r" (sl) \ ++ : "r" (ah), "r" (bh), "rI" (al), "r" (bl)); \ ++ } while (0) ++#define count_leading_zeros(count, x) \ ++ __asm__ ("{cntlz|cntlzw} %0,%1" : "=r" (count) : "r" (x)) ++#define COUNT_LEADING_ZEROS_0 32 ++#if defined (_ARCH_PPC) || defined (__powerpc__) || defined (__POWERPC__) \ ++ || defined (__ppc__) || defined (PPC) || defined (__vxworks__) ++#define umul_ppmm(ph, pl, m0, m1) \ ++ do { \ ++ USItype __m0 = (m0), __m1 = (m1); \ ++ __asm__ ("mulhwu %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1)); \ ++ (pl) = __m0 * __m1; \ ++ } while (0) ++#define UMUL_TIME 15 ++#define smul_ppmm(ph, pl, m0, m1) \ ++ do { \ ++ SItype __m0 = (m0), __m1 = (m1); \ ++ __asm__ ("mulhw %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1)); \ ++ (pl) = __m0 * __m1; \ ++ } while (0) ++#define SMUL_TIME 14 ++#define UDIV_TIME 120 ++#elif defined (_ARCH_PWR) ++#define UMUL_TIME 8 ++#define smul_ppmm(xh, xl, m0, m1) \ ++ __asm__ ("mul %0,%2,%3" : "=r" (xh), "=q" (xl) : "r" (m0), "r" (m1)) ++#define SMUL_TIME 4 ++#define sdiv_qrnnd(q, r, nh, nl, d) \ ++ __asm__ ("div %0,%2,%4" : "=r" (q), "=q" (r) : "r" (nh), "1" (nl), "r" (d)) ++#define UDIV_TIME 100 ++#endif ++#endif /* 32-bit POWER architecture variants. */ ++ ++/* We should test _IBMR2 here when we add assembly support for the system ++ vendor compilers. */ ++#if (defined (_ARCH_PPC64) || defined (__powerpc64__)) && W_TYPE_SIZE == 64 ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ do { \ ++ if (__builtin_constant_p (bh) && (bh) == 0) \ ++ __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \ ++ : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\ ++ else if (__builtin_constant_p (bh) && (bh) == ~(UDItype) 0) \ ++ __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \ ++ : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl));\ ++ else \ ++ __asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \ ++ : "=r" (sh), "=&r" (sl) \ ++ : "%r" (ah), "r" (bh), "%r" (al), "rI" (bl)); \ ++ } while (0) ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ do { \ ++ if (__builtin_constant_p (ah) && (ah) == 0) \ ++ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \ ++ : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\ ++ else if (__builtin_constant_p (ah) && (ah) == ~(UDItype) 0) \ ++ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \ ++ : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl));\ ++ else if (__builtin_constant_p (bh) && (bh) == 0) \ ++ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \ ++ : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\ ++ else if (__builtin_constant_p (bh) && (bh) == ~(UDItype) 0) \ ++ __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \ ++ : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl));\ ++ else \ ++ __asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \ ++ : "=r" (sh), "=&r" (sl) \ ++ : "r" (ah), "r" (bh), "rI" (al), "r" (bl)); \ ++ } while (0) ++#define count_leading_zeros(count, x) \ ++ __asm__ ("cntlzd %0,%1" : "=r" (count) : "r" (x)) ++#define COUNT_LEADING_ZEROS_0 64 ++#define umul_ppmm(ph, pl, m0, m1) \ ++ do { \ ++ UDItype __m0 = (m0), __m1 = (m1); \ ++ __asm__ ("mulhdu %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1)); \ ++ (pl) = __m0 * __m1; \ ++ } while (0) ++#define UMUL_TIME 15 ++#define smul_ppmm(ph, pl, m0, m1) \ ++ do { \ ++ DItype __m0 = (m0), __m1 = (m1); \ ++ __asm__ ("mulhd %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1)); \ ++ (pl) = __m0 * __m1; \ ++ } while (0) ++#define SMUL_TIME 14 /* ??? */ ++#define UDIV_TIME 120 /* ??? */ ++#endif /* 64-bit PowerPC. */ ++ ++#if defined (__ibm032__) /* RT/ROMP */ && W_TYPE_SIZE == 32 ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("a %1,%5\n\tae %0,%3" \ ++ : "=r" ((USItype) (sh)), \ ++ "=&r" ((USItype) (sl)) \ ++ : "%0" ((USItype) (ah)), \ ++ "r" ((USItype) (bh)), \ ++ "%1" ((USItype) (al)), \ ++ "r" ((USItype) (bl))) ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("s %1,%5\n\tse %0,%3" \ ++ : "=r" ((USItype) (sh)), \ ++ "=&r" ((USItype) (sl)) \ ++ : "0" ((USItype) (ah)), \ ++ "r" ((USItype) (bh)), \ ++ "1" ((USItype) (al)), \ ++ "r" ((USItype) (bl))) ++#define umul_ppmm(ph, pl, m0, m1) \ ++ do { \ ++ USItype __m0 = (m0), __m1 = (m1); \ ++ __asm__ ( \ ++ "s r2,r2\n" \ ++" mts r10,%2\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" m r2,%3\n" \ ++" cas %0,r2,r0\n" \ ++" mfs r10,%1" \ ++ : "=r" ((USItype) (ph)), \ ++ "=r" ((USItype) (pl)) \ ++ : "%r" (__m0), \ ++ "r" (__m1) \ ++ : "r2"); \ ++ (ph) += ((((SItype) __m0 >> 31) & __m1) \ ++ + (((SItype) __m1 >> 31) & __m0)); \ ++ } while (0) ++#define UMUL_TIME 20 ++#define UDIV_TIME 200 ++#define count_leading_zeros(count, x) \ ++ do { \ ++ if ((x) >= 0x10000) \ ++ __asm__ ("clz %0,%1" \ ++ : "=r" ((USItype) (count)) \ ++ : "r" ((USItype) (x) >> 16)); \ ++ else \ ++ { \ ++ __asm__ ("clz %0,%1" \ ++ : "=r" ((USItype) (count)) \ ++ : "r" ((USItype) (x))); \ ++ (count) += 16; \ ++ } \ ++ } while (0) ++#endif ++ ++#if defined (__sh2__) && W_TYPE_SIZE == 32 ++#define umul_ppmm(w1, w0, u, v) \ ++ __asm__ ( \ ++ "dmulu.l %2,%3\n\tsts macl,%1\n\tsts mach,%0" \ ++ : "=r" ((USItype)(w1)), \ ++ "=r" ((USItype)(w0)) \ ++ : "r" ((USItype)(u)), \ ++ "r" ((USItype)(v)) \ ++ : "macl", "mach") ++#define UMUL_TIME 5 ++#endif ++ ++#if defined (__SH5__) && __SHMEDIA__ && W_TYPE_SIZE == 32 ++#define __umulsidi3(u,v) ((UDItype)(USItype)u*(USItype)v) ++#define count_leading_zeros(count, x) \ ++ do \ ++ { \ ++ UDItype x_ = (USItype)(x); \ ++ SItype c_; \ ++ \ ++ __asm__ ("nsb %1, %0" : "=r" (c_) : "r" (x_)); \ ++ (count) = c_ - 31; \ ++ } \ ++ while (0) ++#define COUNT_LEADING_ZEROS_0 32 ++#endif ++ ++#if defined (__sparc__) && !defined (__arch64__) && !defined (__sparcv9) \ ++ && W_TYPE_SIZE == 32 ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("addcc %r4,%5,%1\n\taddx %r2,%3,%0" \ ++ : "=r" ((USItype) (sh)), \ ++ "=&r" ((USItype) (sl)) \ ++ : "%rJ" ((USItype) (ah)), \ ++ "rI" ((USItype) (bh)), \ ++ "%rJ" ((USItype) (al)), \ ++ "rI" ((USItype) (bl)) \ ++ __CLOBBER_CC) ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("subcc %r4,%5,%1\n\tsubx %r2,%3,%0" \ ++ : "=r" ((USItype) (sh)), \ ++ "=&r" ((USItype) (sl)) \ ++ : "rJ" ((USItype) (ah)), \ ++ "rI" ((USItype) (bh)), \ ++ "rJ" ((USItype) (al)), \ ++ "rI" ((USItype) (bl)) \ ++ __CLOBBER_CC) ++#if defined (__sparc_v8__) ++#define umul_ppmm(w1, w0, u, v) \ ++ __asm__ ("umul %2,%3,%1;rd %%y,%0" \ ++ : "=r" ((USItype) (w1)), \ ++ "=r" ((USItype) (w0)) \ ++ : "r" ((USItype) (u)), \ ++ "r" ((USItype) (v))) ++#define udiv_qrnnd(__q, __r, __n1, __n0, __d) \ ++ __asm__ ("mov %2,%%y;nop;nop;nop;udiv %3,%4,%0;umul %0,%4,%1;sub %3,%1,%1"\ ++ : "=&r" ((USItype) (__q)), \ ++ "=&r" ((USItype) (__r)) \ ++ : "r" ((USItype) (__n1)), \ ++ "r" ((USItype) (__n0)), \ ++ "r" ((USItype) (__d))) ++#else ++#if defined (__sparclite__) ++/* This has hardware multiply but not divide. It also has two additional ++ instructions scan (ffs from high bit) and divscc. */ ++#define umul_ppmm(w1, w0, u, v) \ ++ __asm__ ("umul %2,%3,%1;rd %%y,%0" \ ++ : "=r" ((USItype) (w1)), \ ++ "=r" ((USItype) (w0)) \ ++ : "r" ((USItype) (u)), \ ++ "r" ((USItype) (v))) ++#define udiv_qrnnd(q, r, n1, n0, d) \ ++ __asm__ ("! Inlined udiv_qrnnd\n" \ ++" wr %%g0,%2,%%y ! Not a delayed write for sparclite\n" \ ++" tst %%g0\n" \ ++" divscc %3,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%%g1\n" \ ++" divscc %%g1,%4,%0\n" \ ++" rd %%y,%1\n" \ ++" bl,a 1f\n" \ ++" add %1,%4,%1\n" \ ++"1: ! End of inline udiv_qrnnd" \ ++ : "=r" ((USItype) (q)), \ ++ "=r" ((USItype) (r)) \ ++ : "r" ((USItype) (n1)), \ ++ "r" ((USItype) (n0)), \ ++ "rI" ((USItype) (d)) \ ++ : "g1" __AND_CLOBBER_CC) ++#define UDIV_TIME 37 ++#define count_leading_zeros(count, x) \ ++ do { \ ++ __asm__ ("scan %1,1,%0" \ ++ : "=r" ((USItype) (count)) \ ++ : "r" ((USItype) (x))); \ ++ } while (0) ++/* Early sparclites return 63 for an argument of 0, but they warn that future ++ implementations might change this. Therefore, leave COUNT_LEADING_ZEROS_0 ++ undefined. */ ++#else ++/* SPARC without integer multiplication and divide instructions. ++ (i.e. at least Sun4/20,40,60,65,75,110,260,280,330,360,380,470,490) */ ++#define umul_ppmm(w1, w0, u, v) \ ++ __asm__ ("! Inlined umul_ppmm\n" \ ++" wr %%g0,%2,%%y ! SPARC has 0-3 delay insn after a wr\n"\ ++" sra %3,31,%%o5 ! Don't move this insn\n" \ ++" and %2,%%o5,%%o5 ! Don't move this insn\n" \ ++" andcc %%g0,0,%%g1 ! Don't move this insn\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,%3,%%g1\n" \ ++" mulscc %%g1,0,%%g1\n" \ ++" add %%g1,%%o5,%0\n" \ ++" rd %%y,%1" \ ++ : "=r" ((USItype) (w1)), \ ++ "=r" ((USItype) (w0)) \ ++ : "%rI" ((USItype) (u)), \ ++ "r" ((USItype) (v)) \ ++ : "g1", "o5" __AND_CLOBBER_CC) ++#define UMUL_TIME 39 /* 39 instructions */ ++/* It's quite necessary to add this much assembler for the sparc. ++ The default udiv_qrnnd (in C) is more than 10 times slower! */ ++#define udiv_qrnnd(__q, __r, __n1, __n0, __d) \ ++ __asm__ ("! Inlined udiv_qrnnd\n" \ ++" mov 32,%%g1\n" \ ++" subcc %1,%2,%%g0\n" \ ++"1: bcs 5f\n" \ ++" addxcc %0,%0,%0 ! shift n1n0 and a q-bit in lsb\n" \ ++" sub %1,%2,%1 ! this kills msb of n\n" \ ++" addx %1,%1,%1 ! so this can't give carry\n" \ ++" subcc %%g1,1,%%g1\n" \ ++"2: bne 1b\n" \ ++" subcc %1,%2,%%g0\n" \ ++" bcs 3f\n" \ ++" addxcc %0,%0,%0 ! shift n1n0 and a q-bit in lsb\n" \ ++" b 3f\n" \ ++" sub %1,%2,%1 ! this kills msb of n\n" \ ++"4: sub %1,%2,%1\n" \ ++"5: addxcc %1,%1,%1\n" \ ++" bcc 2b\n" \ ++" subcc %%g1,1,%%g1\n" \ ++"! Got carry from n. Subtract next step to cancel this carry.\n" \ ++" bne 4b\n" \ ++" addcc %0,%0,%0 ! shift n1n0 and a 0-bit in lsb\n" \ ++" sub %1,%2,%1\n" \ ++"3: xnor %0,0,%0\n" \ ++" ! End of inline udiv_qrnnd" \ ++ : "=&r" ((USItype) (__q)), \ ++ "=&r" ((USItype) (__r)) \ ++ : "r" ((USItype) (__d)), \ ++ "1" ((USItype) (__n1)), \ ++ "0" ((USItype) (__n0)) : "g1" __AND_CLOBBER_CC) ++#define UDIV_TIME (3+7*32) /* 7 instructions/iteration. 32 iterations. */ ++#endif /* __sparclite__ */ ++#endif /* __sparc_v8__ */ ++#endif /* sparc32 */ ++ ++#if ((defined (__sparc__) && defined (__arch64__)) || defined (__sparcv9)) \ ++ && W_TYPE_SIZE == 64 ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("addcc %r4,%5,%1\n\t" \ ++ "add %r2,%3,%0\n\t" \ ++ "bcs,a,pn %%xcc, 1f\n\t" \ ++ "add %0, 1, %0\n" \ ++ "1:" \ ++ : "=r" ((UDItype)(sh)), \ ++ "=&r" ((UDItype)(sl)) \ ++ : "%rJ" ((UDItype)(ah)), \ ++ "rI" ((UDItype)(bh)), \ ++ "%rJ" ((UDItype)(al)), \ ++ "rI" ((UDItype)(bl)) \ ++ __CLOBBER_CC) ++ ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("subcc %r4,%5,%1\n\t" \ ++ "sub %r2,%3,%0\n\t" \ ++ "bcs,a,pn %%xcc, 1f\n\t" \ ++ "sub %0, 1, %0\n\t" \ ++ "1:" \ ++ : "=r" ((UDItype)(sh)), \ ++ "=&r" ((UDItype)(sl)) \ ++ : "rJ" ((UDItype)(ah)), \ ++ "rI" ((UDItype)(bh)), \ ++ "rJ" ((UDItype)(al)), \ ++ "rI" ((UDItype)(bl)) \ ++ __CLOBBER_CC) ++ ++#define umul_ppmm(wh, wl, u, v) \ ++ do { \ ++ UDItype tmp1, tmp2, tmp3, tmp4; \ ++ __asm__ __volatile__ ( \ ++ "srl %7,0,%3\n\t" \ ++ "mulx %3,%6,%1\n\t" \ ++ "srlx %6,32,%2\n\t" \ ++ "mulx %2,%3,%4\n\t" \ ++ "sllx %4,32,%5\n\t" \ ++ "srl %6,0,%3\n\t" \ ++ "sub %1,%5,%5\n\t" \ ++ "srlx %5,32,%5\n\t" \ ++ "addcc %4,%5,%4\n\t" \ ++ "srlx %7,32,%5\n\t" \ ++ "mulx %3,%5,%3\n\t" \ ++ "mulx %2,%5,%5\n\t" \ ++ "sethi %%hi(0x80000000),%2\n\t" \ ++ "addcc %4,%3,%4\n\t" \ ++ "srlx %4,32,%4\n\t" \ ++ "add %2,%2,%2\n\t" \ ++ "movcc %%xcc,%%g0,%2\n\t" \ ++ "addcc %5,%4,%5\n\t" \ ++ "sllx %3,32,%3\n\t" \ ++ "add %1,%3,%1\n\t" \ ++ "add %5,%2,%0" \ ++ : "=r" ((UDItype)(wh)), \ ++ "=&r" ((UDItype)(wl)), \ ++ "=&r" (tmp1), "=&r" (tmp2), "=&r" (tmp3), "=&r" (tmp4) \ ++ : "r" ((UDItype)(u)), \ ++ "r" ((UDItype)(v)) \ ++ __CLOBBER_CC); \ ++ } while (0) ++#define UMUL_TIME 96 ++#define UDIV_TIME 230 ++#endif /* sparc64 */ ++ ++#if defined (__vax__) && W_TYPE_SIZE == 32 ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("addl2 %5,%1\n\tadwc %3,%0" \ ++ : "=g" ((USItype) (sh)), \ ++ "=&g" ((USItype) (sl)) \ ++ : "%0" ((USItype) (ah)), \ ++ "g" ((USItype) (bh)), \ ++ "%1" ((USItype) (al)), \ ++ "g" ((USItype) (bl))) ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("subl2 %5,%1\n\tsbwc %3,%0" \ ++ : "=g" ((USItype) (sh)), \ ++ "=&g" ((USItype) (sl)) \ ++ : "0" ((USItype) (ah)), \ ++ "g" ((USItype) (bh)), \ ++ "1" ((USItype) (al)), \ ++ "g" ((USItype) (bl))) ++#define umul_ppmm(xh, xl, m0, m1) \ ++ do { \ ++ union { \ ++ UDItype __ll; \ ++ struct {USItype __l, __h;} __i; \ ++ } __xx; \ ++ USItype __m0 = (m0), __m1 = (m1); \ ++ __asm__ ("emul %1,%2,$0,%0" \ ++ : "=r" (__xx.__ll) \ ++ : "g" (__m0), \ ++ "g" (__m1)); \ ++ (xh) = __xx.__i.__h; \ ++ (xl) = __xx.__i.__l; \ ++ (xh) += ((((SItype) __m0 >> 31) & __m1) \ ++ + (((SItype) __m1 >> 31) & __m0)); \ ++ } while (0) ++#define sdiv_qrnnd(q, r, n1, n0, d) \ ++ do { \ ++ union {DItype __ll; \ ++ struct {SItype __l, __h;} __i; \ ++ } __xx; \ ++ __xx.__i.__h = n1; __xx.__i.__l = n0; \ ++ __asm__ ("ediv %3,%2,%0,%1" \ ++ : "=g" (q), "=g" (r) \ ++ : "g" (__xx.__ll), "g" (d)); \ ++ } while (0) ++#endif /* __vax__ */ ++ ++#if defined (__z8000__) && W_TYPE_SIZE == 16 ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("add %H1,%H5\n\tadc %H0,%H3" \ ++ : "=r" ((unsigned int)(sh)), \ ++ "=&r" ((unsigned int)(sl)) \ ++ : "%0" ((unsigned int)(ah)), \ ++ "r" ((unsigned int)(bh)), \ ++ "%1" ((unsigned int)(al)), \ ++ "rQR" ((unsigned int)(bl))) ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ __asm__ ("sub %H1,%H5\n\tsbc %H0,%H3" \ ++ : "=r" ((unsigned int)(sh)), \ ++ "=&r" ((unsigned int)(sl)) \ ++ : "0" ((unsigned int)(ah)), \ ++ "r" ((unsigned int)(bh)), \ ++ "1" ((unsigned int)(al)), \ ++ "rQR" ((unsigned int)(bl))) ++#define umul_ppmm(xh, xl, m0, m1) \ ++ do { \ ++ union {long int __ll; \ ++ struct {unsigned int __h, __l;} __i; \ ++ } __xx; \ ++ unsigned int __m0 = (m0), __m1 = (m1); \ ++ __asm__ ("mult %S0,%H3" \ ++ : "=r" (__xx.__i.__h), \ ++ "=r" (__xx.__i.__l) \ ++ : "%1" (__m0), \ ++ "rQR" (__m1)); \ ++ (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \ ++ (xh) += ((((signed int) __m0 >> 15) & __m1) \ ++ + (((signed int) __m1 >> 15) & __m0)); \ ++ } while (0) ++#endif /* __z8000__ */ ++ ++#endif /* __GNUC__ */ ++ ++/* If this machine has no inline assembler, use C macros. */ ++ ++#if !defined (add_ssaaaa) ++#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ ++ do { \ ++ UWtype __x; \ ++ __x = (al) + (bl); \ ++ (sh) = (ah) + (bh) + (__x < (al)); \ ++ (sl) = __x; \ ++ } while (0) ++#endif ++ ++#if !defined (sub_ddmmss) ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ do { \ ++ UWtype __x; \ ++ __x = (al) - (bl); \ ++ (sh) = (ah) - (bh) - (__x > (al)); \ ++ (sl) = __x; \ ++ } while (0) ++#endif ++ ++#if !defined (umul_ppmm) ++#define umul_ppmm(w1, w0, u, v) \ ++ do { \ ++ UWtype __x0, __x1, __x2, __x3; \ ++ UHWtype __ul, __vl, __uh, __vh; \ ++ \ ++ __ul = __ll_lowpart (u); \ ++ __uh = __ll_highpart (u); \ ++ __vl = __ll_lowpart (v); \ ++ __vh = __ll_highpart (v); \ ++ \ ++ __x0 = (UWtype) __ul * __vl; \ ++ __x1 = (UWtype) __ul * __vh; \ ++ __x2 = (UWtype) __uh * __vl; \ ++ __x3 = (UWtype) __uh * __vh; \ ++ \ ++ __x1 += __ll_highpart (__x0);/* this can't give carry */ \ ++ __x1 += __x2; /* but this indeed can */ \ ++ if (__x1 < __x2) /* did we get it? */ \ ++ __x3 += __ll_B; /* yes, add it in the proper pos. */ \ ++ \ ++ (w1) = __x3 + __ll_highpart (__x1); \ ++ (w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0); \ ++ } while (0) ++#endif ++ ++#if !defined (__umulsidi3) ++#define __umulsidi3(u, v) \ ++ ({DWunion __w; \ ++ umul_ppmm (__w.s.high, __w.s.low, u, v); \ ++ __w.ll; }) ++#endif ++ ++/* Define this unconditionally, so it can be used for debugging. */ ++#define __udiv_qrnnd_c(q, r, n1, n0, d) \ ++ do { \ ++ UWtype __d1, __d0, __q1, __q0; \ ++ UWtype __r1, __r0, __m; \ ++ __d1 = __ll_highpart (d); \ ++ __d0 = __ll_lowpart (d); \ ++ \ ++ __r1 = (n1) % __d1; \ ++ __q1 = (n1) / __d1; \ ++ __m = (UWtype) __q1 * __d0; \ ++ __r1 = __r1 * __ll_B | __ll_highpart (n0); \ ++ if (__r1 < __m) \ ++ { \ ++ __q1--, __r1 += (d); \ ++ if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\ ++ if (__r1 < __m) \ ++ __q1--, __r1 += (d); \ ++ } \ ++ __r1 -= __m; \ ++ \ ++ __r0 = __r1 % __d1; \ ++ __q0 = __r1 / __d1; \ ++ __m = (UWtype) __q0 * __d0; \ ++ __r0 = __r0 * __ll_B | __ll_lowpart (n0); \ ++ if (__r0 < __m) \ ++ { \ ++ __q0--, __r0 += (d); \ ++ if (__r0 >= (d)) \ ++ if (__r0 < __m) \ ++ __q0--, __r0 += (d); \ ++ } \ ++ __r0 -= __m; \ ++ \ ++ (q) = (UWtype) __q1 * __ll_B | __q0; \ ++ (r) = __r0; \ ++ } while (0) ++ ++/* If the processor has no udiv_qrnnd but sdiv_qrnnd, go through ++ __udiv_w_sdiv (defined in libgcc or elsewhere). */ ++#if !defined (udiv_qrnnd) && defined (sdiv_qrnnd) ++#define udiv_qrnnd(q, r, nh, nl, d) \ ++ do { \ ++ USItype __r; \ ++ (q) = __udiv_w_sdiv (&__r, nh, nl, d); \ ++ (r) = __r; \ ++ } while (0) ++#endif ++ ++/* If udiv_qrnnd was not defined for this processor, use __udiv_qrnnd_c. */ ++#if !defined (udiv_qrnnd) ++#define UDIV_NEEDS_NORMALIZATION 1 ++#define udiv_qrnnd __udiv_qrnnd_c ++#endif ++ ++#if !defined (count_leading_zeros) ++extern const UQItype __clz_tab[]; ++#define count_leading_zeros(count, x) \ ++ do { \ ++ UWtype __xr = (x); \ ++ UWtype __a; \ ++ \ ++ if (W_TYPE_SIZE <= 32) \ ++ { \ ++ __a = __xr < ((UWtype)1<<2*__BITS4) \ ++ ? (__xr < ((UWtype)1<<__BITS4) ? 0 : __BITS4) \ ++ : (__xr < ((UWtype)1<<3*__BITS4) ? 2*__BITS4 : 3*__BITS4); \ ++ } \ ++ else \ ++ { \ ++ for (__a = W_TYPE_SIZE - 8; __a > 0; __a -= 8) \ ++ if (((__xr >> __a) & 0xff) != 0) \ ++ break; \ ++ } \ ++ \ ++ (count) = W_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a); \ ++ } while (0) ++#define COUNT_LEADING_ZEROS_0 W_TYPE_SIZE ++#endif ++ ++#if !defined (count_trailing_zeros) ++/* Define count_trailing_zeros using count_leading_zeros. The latter might be ++ defined in asm, but if it is not, the C version above is good enough. */ ++#define count_trailing_zeros(count, x) \ ++ do { \ ++ UWtype __ctz_x = (x); \ ++ UWtype __ctz_c; \ ++ count_leading_zeros (__ctz_c, __ctz_x & -__ctz_x); \ ++ (count) = W_TYPE_SIZE - 1 - __ctz_c; \ ++ } while (0) ++#endif ++ ++#ifndef UDIV_NEEDS_NORMALIZATION ++#define UDIV_NEEDS_NORMALIZATION 0 ++#endif +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/Makefile linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/Makefile +--- linux-3.12.2/3rdparty/ndiswrapper/Makefile 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/Makefile 2013-11-28 21:42:10.000000000 +0200 +@@ -0,0 +1,213 @@ ++# Name of the module ++MODNAME = ndiswrapper ++ ++DISTFILES = \ ++ Makefile crt.c divdi3.c hal.c iw_ndis.c iw_ndis.h lin2win.S lin2win.h \ ++ loader.c loader.h longlong.h mkexport.sh mkstubs.sh ndis.c ndis.h \ ++ ndiswrapper.h ntoskernel.c ntoskernel.h ntoskernel_io.c pe_linker.c \ ++ pe_linker.h pnp.c pnp.h proc.c rtl.c usb.c usb.h win2lin_stubs.S \ ++ winnt_types.h workqueue.c wrapmem.c wrapmem.h wrapndis.c wrapndis.h \ ++ wrapper.c wrapper.h ++ ++# By default, we try to compile the modules for the currently running ++# kernel. But it's the first approximation, as we will re-read the ++# version from the kernel sources. ++KVERS_UNAME ?= $(shell uname -r) ++ ++# KBUILD is the path to the Linux kernel build tree. It is usually the ++# same as the kernel source tree, except when the kernel was compiled in ++# a separate directory. ++KBUILD ?= $(shell readlink -f /lib/modules/$(KVERS_UNAME)/build) ++ ++ifeq (,$(KBUILD)) ++$(error Kernel build tree not found - please set KBUILD to configured kernel) ++endif ++ ++KCONFIG := $(KBUILD)/.config ++ifeq (,$(wildcard $(KCONFIG))) ++$(error No .config found in $(KBUILD), please set KBUILD to configured kernel) ++endif ++ ++ifneq (,$(wildcard $(KBUILD)/include/linux/version.h)) ++ifneq (,$(wildcard $(KBUILD)/include/generated/uapi/linux/version.h)) ++$(error Multiple copies of version.h found, please clean your build tree) ++endif ++endif ++ ++# Kernel Makefile doesn't always know the exact kernel version, so we ++# get it from the kernel headers instead and pass it to make. ++VERSION_H := $(KBUILD)/include/generated/utsrelease.h ++ifeq (,$(wildcard $(VERSION_H))) ++VERSION_H := $(KBUILD)/include/linux/utsrelease.h ++endif ++ifeq (,$(wildcard $(VERSION_H))) ++VERSION_H := $(KBUILD)/include/linux/version.h ++endif ++ifeq (,$(wildcard $(VERSION_H))) ++$(error Please run 'make modules_prepare' in $(KBUILD)) ++endif ++ ++KVERS := $(shell sed -ne 's/"//g;s/^\#define UTS_RELEASE //p' $(VERSION_H)) ++ ++ifeq (,$(KVERS)) ++$(error Cannot find UTS_RELEASE in $(VERSION_H), please report) ++endif ++ ++INST_DIR = /lib/modules/$(KVERS)/misc ++ ++SRC_DIR=$(shell pwd) ++ ++include $(KCONFIG) ++ ++# returns of structs and unions in registers when possible, like Windows ++EXTRA_CFLAGS += -freg-struct-return ++ ++# to produce debug trace, add option "DEBUG=" where is 1 to 6 ++ifdef DEBUG ++EXTRA_CFLAGS += -DDEBUG=$(DEBUG) -g ++endif ++ ++# to debug timers, add option "TIMER_DEBUG=1" ++ifdef TIMER_DEBUG ++EXTRA_CFLAGS += -DTIMER_DEBUG ++endif ++ ++# to debug event layer, add option "EVENT_DEBUG=1" ++ifdef EVENT_DEBUG ++EXTRA_CFLAGS += -DEVENT_DEBUG ++endif ++ ++# to debug USB layer, add option "USB_DEBUG=1" ++ifdef USB_DEBUG ++EXTRA_CFLAGS += -DUSB_DEBUG ++endif ++ ++# to debug I/O layer, add option "IO_DEBUG=1" ++ifdef IO_DEBUG ++EXTRA_CFLAGS += -DIO_DEBUG ++endif ++ ++# to debug worker threads, add option "WORK_DEBUG=1" ++ifdef WORK_DEBUG ++EXTRA_CFLAGS += -DWORK_DEBUG ++endif ++ ++# to debug memory allocation, add option "ALLOC_DEBUG=" where is 1 or 2 ++ifdef ALLOC_DEBUG ++EXTRA_CFLAGS += -DALLOC_DEBUG=$(ALLOC_DEBUG) ++endif ++ ++OBJS = crt.o hal.o iw_ndis.o loader.o ndis.o ntoskernel.o ntoskernel_io.o \ ++ pe_linker.o pnp.o proc.o rtl.o wrapmem.o wrapndis.o wrapper.o ++ ++EXPORT_SRCS = crt.c hal.c ndis.c ntoskernel.c ntoskernel_io.c rtl.c ++ ++STUB_SRCS = crt.c hal.c ndis.c ntoskernel.c ntoskernel_io.c \ ++ pnp.c rtl.c wrapndis.c ++ ++ ++# By default, USB layer is compiled in if USB support is in kernel; ++# to disable USB support in ndiswrapper even if USB support is in kernel, ++# add option "DISABLE_USB=1" ++ifndef DISABLE_USB ++ifeq ($(CONFIG_USB),y) ++ENABLE_USB = 1 ++endif ++ifeq ($(CONFIG_USB),m) ++ENABLE_USB = 1 ++endif ++endif ++ ++ifdef ENABLE_USB ++EXPORT_SRCS += usb.c ++STUB_SRCS += usb.c ++OBJS += usb.o ++EXTRA_CFLAGS += -DENABLE_USB ++endif ++ ++ifdef WRAP_WQ ++EXTRA_CFLAGS += -DWRAP_WQ ++OBJS += workqueue.o ++endif ++ ++ ++all: config_check modules ++ ++# generate exports symbol table from C files ++quiet_cmd_mkexport = MKEXPORT $@ ++cmd_mkexport = $(SHELL) $(obj)/mkexport.sh $< $@ ++ ++extra-y += $(EXPORT_SRCS:.c=_exports.h) ++%_exports.h: %.c $(obj)/mkexport.sh FORCE ++ $(call if_changed,mkexport) ++ ++$(addprefix $(obj)/,$(EXPORT_SRCS:.c=.o)): %.o: %_exports.h ++ ++ifeq ($(CONFIG_X86_64),y) ++quiet_cmd_mkstubs = MKSTUBS $@ ++cmd_mkstubs = $(SHELL) $(obj)/mkstubs.sh $(addprefix $(src)/,$(STUB_SRCS)) >$@ ++ ++extra-y += win2lin_stubs.h ++$(obj)/win2lin_stubs.h: $(addprefix $(src)/,$(STUB_SRCS)) FORCE ++ $(call if_changed,mkstubs) ++ ++$(obj)/win2lin_stubs.o: $(obj)/win2lin_stubs.h ++OBJS += win2lin_stubs.o lin2win.o ++else ++OBJS += divdi3.o ++endif ++ ++MODULE := $(MODNAME).ko ++obj-m := $(MODNAME).o ++ ++$(MODNAME)-objs := $(OBJS) ++ ++ ++config_check: ++ @if [ -z "$(CONFIG_WIRELESS_EXT)$(CONFIG_NET_RADIO)" ]; then \ ++ echo; echo; \ ++ echo "*** WARNING: This kernel lacks wireless extensions."; \ ++ echo "Wireless drivers will not work properly."; \ ++ echo; echo; \ ++ fi ++ @if [ -z "$(CONFIG_X86_64)" ] && [ -n "$(CONFIG_4KSTACKS)" ]; then \ ++ echo; echo; \ ++ echo "*** WARNING: This kernel uses 4K stack size option"; \ ++ echo "(CONFIG_4KSTACKS); many Windows drivers will not work"; \ ++ echo "with this option enabled. Disable CONFIG_4KSTACKS"; \ ++ echo "in kernel's .config file, recompile and install kernel"; \ ++ echo; echo; \ ++ fi ++ ++modules: ++ $(MAKE) -C $(KBUILD) M=$(SRC_DIR) ++ ++$(MODULE): ++ $(MAKE) modules ++ ++clean: ++ rm -f *.o *.ko .*.cmd *.mod.c *.symvers modules.order *~ .\#* ++ rm -f *_exports.h win2lin_stubs.h ++ rm -rf .tmp_versions ++ ++install: config_check $(MODULE) ++ @/sbin/modinfo $(MODULE) | grep -q "^vermagic: *$(KVERS) " || \ ++ { echo "$(MODULE)" is not for Linux $(KVERS); exit 1; } ++ mkdir -p -m 755 $(DESTDIR)$(INST_DIR) ++ install -m 0644 $(MODULE) $(DESTDIR)$(INST_DIR) ++ifndef DESTDIR ++ -/sbin/depmod -a $(KVERS) ++endif ++ ++uninstall: ++ rm -f $(DESTDIR)$(INST_DIR)/$(MODULE) ++ifndef DESTDIR ++ -/sbin/depmod -a $(KVERS) ++endif ++ ++dist: ++ @for file in $(DISTFILES); do \ ++ cp $$file $(distdir)/$$file || exit 1; \ ++ done ++ ++.PHONY: all modules clean install config_check dist +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/mkexport.sh linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/mkexport.sh +--- linux-3.12.2/3rdparty/ndiswrapper/mkexport.sh 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/mkexport.sh 2013-11-28 21:42:11.000000000 +0200 +@@ -0,0 +1,42 @@ ++#! /bin/sh ++ ++# Generate exports symbol table from C files ++ ++input="$1" ++output="$2" ++exports=$(basename "$output" .h) ++exec >"$output" ++ ++echo "/* automatically generated from src */"; ++ ++sed -n -e '/^\(wstdcall\|wfastcall\|noregparm\|regparm3\|__attribute__\)/{ ++:more ++N ++s/\([^{]\)$/\1/ ++t more ++s/\n{$/;/ ++p ++}' $input ++ ++echo "#ifdef CONFIG_X86_64"; ++ ++sed -n \ ++ -e 's/.*WIN_FUNC(\([^\,]\+\) *\, *\([0-9]\+\)).*/'\ ++'WIN_FUNC_DECL(\1, \2)/p' \ ++ -e 's/.*WIN_FUNC_PTR(\([^\,]\+\) *\, *\([0-9]\+\)).*/'\ ++'WIN_FUNC_DECL(\1, \2)/p' $input | sort -u ++ ++echo "#endif" ++echo "extern struct wrap_export $exports[];" ++echo "struct wrap_export $exports[] = {" ++ ++sed -n \ ++ -e 's/.*WIN_FUNC(_win_\([^\,]\+\) *\, *\([0-9]\+\)).*/'\ ++' WIN_WIN_SYMBOL(\1, \2),/p' \ ++ -e 's/.*WIN_FUNC(\([^\,]\+\) *\, *\([0-9]\+\)).*/'\ ++' WIN_SYMBOL(\1, \2),/p' \ ++ -e 's/.*WIN_SYMBOL_MAP(\("[^"]\+"\)[ ,\n]\+\([^)]\+\)).*/'\ ++' {\1, (generic_func)\2},/p' $input | sort -u ++ ++echo " {NULL, NULL}" ++echo "};" +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/mkstubs.sh linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/mkstubs.sh +--- linux-3.12.2/3rdparty/ndiswrapper/mkstubs.sh 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/mkstubs.sh 2013-11-28 21:42:11.000000000 +0200 +@@ -0,0 +1,12 @@ ++#! /bin/sh ++ ++for file in "$@"; do ++ echo ++ echo "# automatically generated from $file" ++ sed -n \ ++ -e 's/.*WIN_FUNC(\([^\,]\+\) *\, *\([0-9]\+\)).*/\ ++ win2lin(\1, \2)/p' \ ++ -e 's/.*WIN_FUNC_PTR(\([^\,]\+\) *\, *\([0-9]\+\)).*/\ ++ win2lin(\1, \2)/p' \ ++ $file | sed -e 's/[ \t ]\+//' | sort -u; \ ++done +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/ndis.c linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/ndis.c +--- linux-3.12.2/3rdparty/ndiswrapper/ndis.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/ndis.c 2013-11-28 21:42:11.000000000 +0200 +@@ -0,0 +1,3025 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * 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 "ndis.h" ++#include "iw_ndis.h" ++#include "wrapndis.h" ++#include "pnp.h" ++#include "loader.h" ++#include ++#include ++#include "ndis_exports.h" ++ ++#define MAX_ALLOCATED_NDIS_PACKETS TX_RING_SIZE ++#define MAX_ALLOCATED_NDIS_BUFFERS TX_RING_SIZE ++ ++static struct work_struct ndis_work; ++static struct nt_list ndis_work_list; ++static spinlock_t ndis_work_list_lock; ++ ++struct workqueue_struct *ndis_wq; ++ ++static void *ndis_get_routine_address(char *name); ++ ++wstdcall void WIN_FUNC(NdisInitializeWrapper,4) ++ (void **driver_handle, struct driver_object *driver, ++ struct unicode_string *reg_path, void *unused) ++{ ++ ENTER1("handle: %p, driver: %p", driver_handle, driver); ++ *driver_handle = driver; ++ EXIT1(return); ++} ++ ++wstdcall void WIN_FUNC(NdisTerminateWrapper,2) ++ (struct device_object *dev_obj, void *system_specific) ++{ ++ EXIT1(return); ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMRegisterMiniport,3) ++ (struct driver_object *drv_obj, struct miniport *mp, UINT length) ++{ ++ int min_length; ++ struct wrap_driver *wrap_driver; ++ struct ndis_driver *ndis_driver; ++ ++ min_length = ((char *)&mp->co_create_vc) - ((char *)mp); ++ ++ ENTER1("%p %p %d", drv_obj, mp, length); ++ ++ if (mp->major_version < 4) { ++ ERROR("Driver is using ndis version %d which is too old.", ++ mp->major_version); ++ EXIT1(return NDIS_STATUS_BAD_VERSION); ++ } ++ ++ if (length < min_length) { ++ ERROR("Characteristics length %d is too small", length); ++ EXIT1(return NDIS_STATUS_BAD_CHARACTERISTICS); ++ } ++ ++ TRACE1("%d.%d, %d, %u", mp->major_version, mp->minor_version, length, ++ (u32)sizeof(struct miniport)); ++ wrap_driver = IoGetDriverObjectExtension(drv_obj, ++ (void *)WRAP_DRIVER_CLIENT_ID); ++ if (!wrap_driver) { ++ ERROR("couldn't get wrap_driver"); ++ EXIT1(return NDIS_STATUS_RESOURCES); ++ } ++ if (IoAllocateDriverObjectExtension( ++ drv_obj, (void *)NDIS_DRIVER_CLIENT_ID, ++ sizeof(*ndis_driver), (void **)&ndis_driver) != ++ STATUS_SUCCESS) ++ EXIT1(return NDIS_STATUS_RESOURCES); ++ wrap_driver->ndis_driver = ndis_driver; ++ TRACE1("driver: %p", ndis_driver); ++ memcpy(&ndis_driver->mp, mp, min_t(int, sizeof(*mp), length)); ++ ++ DBG_BLOCK(2) { ++ int i; ++ void **func; ++ char *mp_funcs[] = { ++ "queryinfo", "reconfig", "reset", "send", "setinfo", ++ "tx_data", "return_packet", "send_packets", ++ "alloc_complete", "co_create_vc", "co_delete_vc", ++ "co_activate_vc", "co_deactivate_vc", ++ "co_send_packets", "co_request", "cancel_send_packets", ++ "pnp_event_notify", "shutdown", ++ }; ++ func = (void **)&ndis_driver->mp.queryinfo; ++ for (i = 0; i < ARRAY_SIZE(mp_funcs); i++) ++ TRACE0("function '%s' is at %p", mp_funcs[i], func[i]); ++ } ++ EXIT1(return NDIS_STATUS_SUCCESS); ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMRegisterDevice,6) ++ (struct driver_object *drv_obj, struct unicode_string *dev_name, ++ struct unicode_string *link, void **funcs, ++ struct device_object **dev_obj, void **dev_obj_handle) ++{ ++ NTSTATUS status; ++ struct device_object *tmp; ++ int i; ++ ++ ENTER1("%p, %p, %p", drv_obj, dev_name, link); ++ status = IoCreateDevice(drv_obj, 0, dev_name, FILE_DEVICE_NETWORK, 0, ++ FALSE, &tmp); ++ ++ if (status != STATUS_SUCCESS) ++ EXIT1(return NDIS_STATUS_RESOURCES); ++ if (link) ++ status = IoCreateSymbolicLink(link, dev_name); ++ if (status != STATUS_SUCCESS) { ++ IoDeleteDevice(tmp); ++ EXIT1(return NDIS_STATUS_RESOURCES); ++ } ++ ++ *dev_obj = tmp; ++ *dev_obj_handle = *dev_obj; ++ for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) ++ if (funcs[i] && i != IRP_MJ_PNP && i != IRP_MJ_POWER) { ++ drv_obj->major_func[i] = funcs[i]; ++ TRACE1("mj_fn for 0x%x is at %p", i, funcs[i]); ++ } ++ EXIT1(return NDIS_STATUS_SUCCESS); ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMDeregisterDevice,1) ++ (struct device_object *dev_obj) ++{ ++ ENTER2("%p", dev_obj); ++ IoDeleteDevice(dev_obj); ++ return NDIS_STATUS_SUCCESS; ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisAllocateMemoryWithTag,3) ++ (void **dest, UINT length, ULONG tag) ++{ ++ void *addr; ++ ++ assert_irql(_irql_ <= DISPATCH_LEVEL); ++ addr = ExAllocatePoolWithTag(NonPagedPool, length, tag); ++ TRACE4("%p", addr); ++ if (addr) { ++ *dest = addr; ++ EXIT4(return NDIS_STATUS_SUCCESS); ++ } else ++ EXIT4(return NDIS_STATUS_FAILURE); ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisAllocateMemory,4) ++ (void **dest, UINT length, UINT flags, NDIS_PHY_ADDRESS highest_address) ++{ ++ return NdisAllocateMemoryWithTag(dest, length, 0); ++} ++ ++/* length_tag is either length or tag, depending on if ++ * NdisAllocateMemory or NdisAllocateMemoryTag is used to allocate ++ * memory */ ++wstdcall void WIN_FUNC(NdisFreeMemory,3) ++ (void *addr, UINT length_tag, UINT flags) ++{ ++ TRACE4("%p", addr); ++ ExFreePool(addr); ++} ++ ++noregparm void WIN_FUNC(NdisWriteErrorLogEntry,12) ++ (struct driver_object *drv_obj, ULONG error, ULONG count, ...) ++{ ++ va_list args; ++ int i; ++ ULONG code; ++ ++ va_start(args, count); ++ ERROR("log: %08X, count: %d, return_address: %p", ++ error, count, __builtin_return_address(0)); ++ for (i = 0; i < count; i++) { ++ code = va_arg(args, ULONG); ++ ERROR("code: 0x%x", code); ++ } ++ va_end(args); ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisOpenConfiguration,3) ++ (NDIS_STATUS *status, struct ndis_mp_block **conf_handle, ++ struct ndis_mp_block *handle) ++{ ++ ENTER2("%p", conf_handle); ++ *conf_handle = handle; ++ *status = NDIS_STATUS_SUCCESS; ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisOpenProtocolConfiguration,3) ++ (NDIS_STATUS *status, void **confhandle, ++ struct unicode_string *section) ++{ ++ ENTER2("%p", confhandle); ++ *status = NDIS_STATUS_SUCCESS; ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisOpenConfigurationKeyByName,4) ++ (NDIS_STATUS *status, void *handle, ++ struct unicode_string *key, void **subkeyhandle) ++{ ++ struct ansi_string ansi; ++ ENTER2(""); ++ if (RtlUnicodeStringToAnsiString(&ansi, key, TRUE) == STATUS_SUCCESS) { ++ TRACE2("%s", ansi.buf); ++ RtlFreeAnsiString(&ansi); ++ } ++ *subkeyhandle = handle; ++ *status = NDIS_STATUS_SUCCESS; ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisOpenConfigurationKeyByIndex,5) ++ (NDIS_STATUS *status, void *handle, ULONG index, ++ struct unicode_string *key, void **subkeyhandle) ++{ ++ ENTER2("%u", index); ++// *subkeyhandle = handle; ++ *status = NDIS_STATUS_FAILURE; ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisCloseConfiguration,1) ++ (void *handle) ++{ ++ /* instead of freeing all configuration parameters as we are ++ * supposed to do here, we free them when the device is ++ * removed */ ++ ENTER2("%p", handle); ++ return; ++} ++ ++wstdcall void WIN_FUNC(NdisOpenFile,5) ++ (NDIS_STATUS *status, struct wrap_bin_file **file, ++ UINT *filelength, struct unicode_string *filename, ++ NDIS_PHY_ADDRESS highest_address) ++{ ++ struct ansi_string ansi; ++ struct wrap_bin_file *bin_file; ++ ++ ENTER2("%p, %d, %llx, %p", status, *filelength, highest_address, *file); ++ if (RtlUnicodeStringToAnsiString(&ansi, filename, TRUE) != ++ STATUS_SUCCESS) { ++ *status = NDIS_STATUS_RESOURCES; ++ EXIT2(return); ++ } ++ TRACE2("%s", ansi.buf); ++ bin_file = get_bin_file(ansi.buf); ++ if (bin_file) { ++ *file = bin_file; ++ *filelength = bin_file->size; ++ *status = NDIS_STATUS_SUCCESS; ++ } else ++ *status = NDIS_STATUS_FILE_NOT_FOUND; ++ ++ RtlFreeAnsiString(&ansi); ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisMapFile,3) ++ (NDIS_STATUS *status, void **mappedbuffer, struct wrap_bin_file *file) ++{ ++ ENTER2("%p", file); ++ ++ if (!file) { ++ *status = NDIS_STATUS_ALREADY_MAPPED; ++ EXIT2(return); ++ } ++ ++ *status = NDIS_STATUS_SUCCESS; ++ *mappedbuffer = file->data; ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisUnmapFile,1) ++ (struct wrap_bin_file *file) ++{ ++ ENTER2("%p", file); ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisCloseFile,1) ++ (struct wrap_bin_file *file) ++{ ++ ENTER2("%p", file); ++ free_bin_file(file); ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisGetSystemUpTime,1) ++ (ULONG *ms) ++{ ++ *ms = 1000 * jiffies / HZ; ++ EXIT5(return); ++} ++ ++wstdcall ULONG WIN_FUNC(NDIS_BUFFER_TO_SPAN_PAGES,1) ++ (ndis_buffer *buffer) ++{ ++ ULONG n, length; ++ ++ if (buffer == NULL) ++ EXIT2(return 0); ++ if (MmGetMdlByteCount(buffer) == 0) ++ EXIT2(return 1); ++ ++ length = MmGetMdlByteCount(buffer); ++ n = SPAN_PAGES(MmGetMdlVirtualAddress(buffer), length); ++ TRACE4("%p, %p, %d, %d", buffer->startva, buffer->mappedsystemva, ++ length, n); ++ EXIT3(return n); ++} ++ ++wstdcall void WIN_FUNC(NdisGetBufferPhysicalArraySize,2) ++ (ndis_buffer *buffer, UINT *arraysize) ++{ ++ ENTER3("%p", buffer); ++ *arraysize = NDIS_BUFFER_TO_SPAN_PAGES(buffer); ++ EXIT3(return); ++} ++ ++static struct ndis_configuration_parameter * ++ndis_encode_setting(struct wrap_device_setting *setting, ++ enum ndis_parameter_type type) ++{ ++ struct ansi_string ansi; ++ struct ndis_configuration_parameter *param; ++ ++ param = setting->encoded; ++ if (param) { ++ if (param->type == type) ++ EXIT2(return param); ++ if (param->type == NdisParameterString) ++ RtlFreeUnicodeString(¶m->data.string); ++ setting->encoded = NULL; ++ } else ++ param = ExAllocatePoolWithTag(NonPagedPool, sizeof(*param), 0); ++ if (!param) { ++ ERROR("couldn't allocate memory"); ++ return NULL; ++ } ++ switch (type) { ++ case NdisParameterInteger: ++ param->data.integer = simple_strtol(setting->value, NULL, 0); ++ TRACE2("0x%x", param->data.integer); ++ break; ++ case NdisParameterHexInteger: ++ param->data.integer = simple_strtol(setting->value, NULL, 16); ++ TRACE2("0x%x", param->data.integer); ++ break; ++ case NdisParameterString: ++ RtlInitAnsiString(&ansi, setting->value); ++ TRACE2("'%s'", ansi.buf); ++ if (RtlAnsiStringToUnicodeString(¶m->data.string, ++ &ansi, TRUE)) { ++ ExFreePool(param); ++ EXIT2(return NULL); ++ } ++ break; ++ case NdisParameterBinary: ++ param->data.integer = simple_strtol(setting->value, NULL, 2); ++ TRACE2("0x%x", param->data.integer); ++ break; ++ default: ++ ERROR("unknown type: %d", type); ++ ExFreePool(param); ++ return NULL; ++ } ++ param->type = type; ++ setting->encoded = param; ++ EXIT2(return param); ++} ++ ++static int ndis_decode_setting(struct wrap_device_setting *setting, ++ struct ndis_configuration_parameter *param) ++{ ++ struct ansi_string ansi; ++ struct ndis_configuration_parameter *prev; ++ ++ ENTER2("%p, %p", setting, param); ++ prev = setting->encoded; ++ if (prev && prev->type == NdisParameterString) { ++ RtlFreeUnicodeString(&prev->data.string); ++ setting->encoded = NULL; ++ } ++ switch (param->type) { ++ case NdisParameterInteger: ++ snprintf(setting->value, MAX_SETTING_VALUE_LEN, "%u", ++ param->data.integer); ++ break; ++ case NdisParameterHexInteger: ++ snprintf(setting->value, MAX_SETTING_VALUE_LEN, "%x", ++ param->data.integer); ++ break; ++ case NdisParameterString: ++ ansi.buf = setting->value; ++ ansi.max_length = MAX_SETTING_VALUE_LEN; ++ if ((RtlUnicodeStringToAnsiString(&ansi, ¶m->data.string, ++ FALSE) != STATUS_SUCCESS) ++ || ansi.length >= MAX_SETTING_VALUE_LEN) { ++ EXIT1(return -1); ++ } ++ if (ansi.length == ansi.max_length) ++ ansi.length--; ++ setting->value[ansi.length] = 0; ++ break; ++ default: ++ TRACE2("unknown setting type: %d", param->type); ++ return -1; ++ } ++ TRACE2("setting changed %s='%s', %d", setting->name, setting->value, ++ ansi.length); ++ return 0; ++} ++ ++static int read_setting(struct nt_list *setting_list, char *keyname, int length, ++ struct ndis_configuration_parameter **param, ++ enum ndis_parameter_type type) ++{ ++ struct wrap_device_setting *setting; ++ mutex_lock(&loader_mutex); ++ nt_list_for_each_entry(setting, setting_list, list) { ++ if (strnicmp(keyname, setting->name, length) == 0) { ++ TRACE2("setting %s='%s'", keyname, setting->value); ++ mutex_unlock(&loader_mutex); ++ *param = ndis_encode_setting(setting, type); ++ if (*param) ++ EXIT2(return 0); ++ else ++ EXIT2(return -1); ++ } ++ } ++ mutex_unlock(&loader_mutex); ++ EXIT2(return -1); ++} ++ ++wstdcall void WIN_FUNC(NdisReadConfiguration,5) ++ (NDIS_STATUS *status, struct ndis_configuration_parameter **param, ++ struct ndis_mp_block *nmb, struct unicode_string *key, ++ enum ndis_parameter_type type) ++{ ++ struct ansi_string ansi; ++ int ret; ++ ++ ENTER2("nmb: %p", nmb); ++ ret = RtlUnicodeStringToAnsiString(&ansi, key, TRUE); ++ if (ret != STATUS_SUCCESS || ansi.buf == NULL) { ++ *param = NULL; ++ *status = NDIS_STATUS_FAILURE; ++ RtlFreeAnsiString(&ansi); ++ EXIT2(return); ++ } ++ TRACE2("%d, %s", type, ansi.buf); ++ ++ if (read_setting(&nmb->wnd->wd->settings, ansi.buf, ++ ansi.length, param, type) == 0 || ++ read_setting(&nmb->wnd->wd->driver->settings, ansi.buf, ++ ansi.length, param, type) == 0) ++ *status = NDIS_STATUS_SUCCESS; ++ else { ++ TRACE2("setting %s not found (type:%d)", ansi.buf, type); ++ *status = NDIS_STATUS_FAILURE; ++ } ++ RtlFreeAnsiString(&ansi); ++ EXIT2(return); ++ ++} ++ ++wstdcall void WIN_FUNC(NdisWriteConfiguration,4) ++ (NDIS_STATUS *status, struct ndis_mp_block *nmb, ++ struct unicode_string *key, struct ndis_configuration_parameter *param) ++{ ++ struct ansi_string ansi; ++ char *keyname; ++ struct wrap_device_setting *setting; ++ ++ ENTER2("nmb: %p", nmb); ++ if (RtlUnicodeStringToAnsiString(&ansi, key, TRUE)) { ++ *status = NDIS_STATUS_FAILURE; ++ EXIT2(return); ++ } ++ keyname = ansi.buf; ++ TRACE2("%s", keyname); ++ ++ mutex_lock(&loader_mutex); ++ nt_list_for_each_entry(setting, &nmb->wnd->wd->settings, list) { ++ if (strnicmp(keyname, setting->name, ansi.length) == 0) { ++ mutex_unlock(&loader_mutex); ++ if (ndis_decode_setting(setting, param)) ++ *status = NDIS_STATUS_FAILURE; ++ else ++ *status = NDIS_STATUS_SUCCESS; ++ RtlFreeAnsiString(&ansi); ++ EXIT2(return); ++ } ++ } ++ mutex_unlock(&loader_mutex); ++ setting = kzalloc(sizeof(*setting), GFP_KERNEL); ++ if (setting) { ++ if (ansi.length == ansi.max_length) ++ ansi.length--; ++ memcpy(setting->name, keyname, ansi.length); ++ setting->name[ansi.length] = 0; ++ if (ndis_decode_setting(setting, param)) ++ *status = NDIS_STATUS_FAILURE; ++ else { ++ *status = NDIS_STATUS_SUCCESS; ++ mutex_lock(&loader_mutex); ++ InsertTailList(&nmb->wnd->wd->settings, &setting->list); ++ mutex_unlock(&loader_mutex); ++ } ++ } else ++ *status = NDIS_STATUS_RESOURCES; ++ ++ RtlFreeAnsiString(&ansi); ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisReadNetworkAddress,4) ++ (NDIS_STATUS *status, void **addr, UINT *len, ++ struct ndis_mp_block *nmb) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ struct ndis_configuration_parameter *param; ++ struct unicode_string key; ++ struct ansi_string ansi; ++ typeof(wnd->mac) mac; ++ int i, ret; ++ ++ ENTER2("%p", nmb); ++ RtlInitAnsiString(&ansi, "NetworkAddress"); ++ *status = NDIS_STATUS_FAILURE; ++ if (RtlAnsiStringToUnicodeString(&key, &ansi, TRUE) != STATUS_SUCCESS) ++ EXIT1(return); ++ ++ NdisReadConfiguration(&ret, ¶m, nmb, &key, NdisParameterString); ++ RtlFreeUnicodeString(&key); ++ if (ret != NDIS_STATUS_SUCCESS) ++ EXIT1(return); ++ ret = RtlUnicodeStringToAnsiString(&ansi, ¶m->data.string, TRUE); ++ if (ret != STATUS_SUCCESS) ++ EXIT1(return); ++ ++ i = 0; ++ if (ansi.length >= 2 * sizeof(mac)) { ++ for (i = 0; i < sizeof(mac); i++) { ++ char c[3]; ++ int x; ++ c[0] = ansi.buf[i*2]; ++ c[1] = ansi.buf[i*2+1]; ++ c[2] = 0; ++ ret = sscanf(c, "%x", &x); ++ if (ret != 1) ++ break; ++ mac[i] = x; ++ } ++ } ++ TRACE2("%s, %d, " MACSTR, ansi.buf, i, MAC2STR(mac)); ++ RtlFreeAnsiString(&ansi); ++ if (i == sizeof(mac)) { ++ memcpy(wnd->mac, mac, sizeof(wnd->mac)); ++ *len = sizeof(mac); ++ *addr = wnd->mac; ++ *status = NDIS_STATUS_SUCCESS; ++ } ++ EXIT1(return); ++} ++ ++wstdcall void WIN_FUNC(NdisInitializeString,2) ++ (struct unicode_string *dest, UCHAR *src) ++{ ++ struct ansi_string ansi; ++ ++ ENTER2(""); ++ if (src == NULL) { ++ dest->length = dest->max_length = 0; ++ dest->buf = NULL; ++ } else { ++ RtlInitAnsiString(&ansi, src); ++ /* the string is freed with NdisFreeMemory */ ++ RtlAnsiStringToUnicodeString(dest, &ansi, TRUE); ++ } ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisInitAnsiString,2) ++ (struct ansi_string *dst, CHAR *src) ++{ ++ RtlInitAnsiString(dst, src); ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisInitUnicodeString,2) ++ (struct unicode_string *dest, const wchar_t *src) ++{ ++ RtlInitUnicodeString(dest, src); ++ return; ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisAnsiStringToUnicodeString,2) ++ (struct unicode_string *dst, struct ansi_string *src) ++{ ++ ENTER2(""); ++ if (dst == NULL || src == NULL) ++ EXIT2(return NDIS_STATUS_FAILURE); ++ if (RtlAnsiStringToUnicodeString(dst, src, FALSE) == STATUS_SUCCESS) ++ return NDIS_STATUS_SUCCESS; ++ else ++ return NDIS_STATUS_FAILURE; ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisUnicodeStringToAnsiString,2) ++ (struct ansi_string *dst, struct unicode_string *src) ++{ ++ ENTER2(""); ++ if (dst == NULL || src == NULL) ++ EXIT2(return NDIS_STATUS_FAILURE); ++ if (RtlUnicodeStringToAnsiString(dst, src, FALSE) == STATUS_SUCCESS) ++ return NDIS_STATUS_SUCCESS; ++ else ++ return NDIS_STATUS_FAILURE; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(NdisUpcaseUnicodeString,2) ++ (struct unicode_string *dst, struct unicode_string *src) ++{ ++ EXIT2(return RtlUpcaseUnicodeString(dst, src, FALSE)); ++} ++ ++wstdcall void WIN_FUNC(NdisMSetAttributesEx,5) ++ (struct ndis_mp_block *nmb, void *mp_ctx, ++ UINT hangcheck_interval, UINT attributes, ULONG adaptertype) ++{ ++ struct ndis_device *wnd; ++ ++ ENTER1("%p, %p, %d, %08x, %d", nmb, mp_ctx, hangcheck_interval, ++ attributes, adaptertype); ++ wnd = nmb->wnd; ++ nmb->mp_ctx = mp_ctx; ++ wnd->attributes = attributes; ++ ++ if ((attributes & NDIS_ATTRIBUTE_BUS_MASTER) && ++ wrap_is_pci_bus(wnd->wd->dev_bus)) ++ pci_set_master(wnd->wd->pci.pdev); ++ ++ if (hangcheck_interval > 0) ++ wnd->hangcheck_interval = 2 * hangcheck_interval * HZ; ++ else ++ wnd->hangcheck_interval = 2 * HZ; ++ ++ EXIT1(return); ++} ++ ++wstdcall ULONG WIN_FUNC(NdisReadPciSlotInformation,5) ++ (struct ndis_mp_block *nmb, ULONG slot, ++ ULONG offset, char *buf, ULONG len) ++{ ++ struct wrap_device *wd = nmb->wnd->wd; ++ ULONG i; ++ if (!wrap_is_pci_bus(wd->dev_bus)) { ++ ERROR("used on a non-PCI device"); ++ return 0; ++ } ++ for (i = 0; i < len; i++) ++ if (pci_read_config_byte(wd->pci.pdev, offset + i, &buf[i]) != ++ PCIBIOS_SUCCESSFUL) ++ break; ++ DBG_BLOCK(2) { ++ if (i != len) ++ WARNING("%u, %u", i, len); ++ } ++ return i; ++} ++ ++wstdcall ULONG WIN_FUNC(NdisImmediateReadPciSlotInformation,5) ++ (struct ndis_mp_block *nmb, ULONG slot, ++ ULONG offset, char *buf, ULONG len) ++{ ++ return NdisReadPciSlotInformation(nmb, slot, offset, buf, len); ++} ++ ++wstdcall ULONG WIN_FUNC(NdisWritePciSlotInformation,5) ++ (struct ndis_mp_block *nmb, ULONG slot, ++ ULONG offset, char *buf, ULONG len) ++{ ++ struct wrap_device *wd = nmb->wnd->wd; ++ ULONG i; ++ if (!wrap_is_pci_bus(wd->dev_bus)) { ++ ERROR("used on a non-PCI device"); ++ return 0; ++ } ++ for (i = 0; i < len; i++) ++ if (pci_write_config_byte(wd->pci.pdev, offset + i, buf[i]) != ++ PCIBIOS_SUCCESSFUL) ++ break; ++ DBG_BLOCK(2) { ++ if (i != len) ++ WARNING("%u, %u", i, len); ++ } ++ return i; ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMRegisterIoPortRange,4) ++ (void **virt, struct ndis_mp_block *nmb, UINT start, UINT len) ++{ ++ ENTER3("%08x %08x", start, len); ++ *virt = (void *)(ULONG_PTR)start; ++ return NDIS_STATUS_SUCCESS; ++} ++ ++wstdcall void WIN_FUNC(NdisMDeregisterIoPortRange,4) ++ (struct ndis_mp_block *nmb, UINT start, UINT len, void* virt) ++{ ++ ENTER1("%08x %08x", start, len); ++} ++ ++wstdcall void WIN_FUNC(NdisReadPortUchar,3) ++ (struct ndis_mp_block *nmb, ULONG port, char *data) ++{ ++ *data = inb(port); ++} ++ ++wstdcall void WIN_FUNC(NdisImmediateReadPortUchar,3) ++ (struct ndis_mp_block *nmb, ULONG port, char *data) ++{ ++ *data = inb(port); ++} ++ ++wstdcall void WIN_FUNC(NdisWritePortUchar,3) ++ (struct ndis_mp_block *nmb, ULONG port, char data) ++{ ++ outb(data, port); ++} ++ ++wstdcall void WIN_FUNC(NdisImmediateWritePortUchar,3) ++ (struct ndis_mp_block *nmb, ULONG port, char data) ++{ ++ outb(data, port); ++} ++ ++wstdcall void WIN_FUNC(NdisMQueryAdapterResources,4) ++ (NDIS_STATUS *status, struct ndis_mp_block *nmb, ++ NDIS_RESOURCE_LIST *resource_list, UINT *size) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ NDIS_RESOURCE_LIST *list; ++ UINT resource_length; ++ ++ list = &wnd->wd->resource_list->list->partial_resource_list; ++ resource_length = sizeof(struct cm_partial_resource_list) + ++ sizeof(struct cm_partial_resource_descriptor) * ++ (list->count - 1); ++ TRACE2("%p, %p,%d (%d), %p %d %d", wnd, resource_list, *size, ++ resource_length, &list->partial_descriptors[list->count-1], ++ list->partial_descriptors[list->count-1].u.interrupt.level, ++ list->partial_descriptors[list->count-1].u.interrupt.vector); ++ if (*size < sizeof(*list)) { ++ *size = resource_length; ++ *status = NDIS_STATUS_BUFFER_TOO_SHORT; ++ } else { ++ ULONG count; ++ if (*size >= resource_length) { ++ *size = resource_length; ++ count = list->count; ++ } else { ++ UINT n = sizeof(*list); ++ count = 1; ++ while (count++ < list->count && n < *size) ++ n += sizeof(list->partial_descriptors); ++ *size = n; ++ } ++ memcpy(resource_list, list, *size); ++ resource_list->count = count; ++ *status = NDIS_STATUS_SUCCESS; ++ } ++ EXIT2(return); ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMPciAssignResources,3) ++ (struct ndis_mp_block *nmb, ULONG slot_number, ++ NDIS_RESOURCE_LIST **resources) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ ++ ENTER2("%p, %p", wnd, wnd->wd->resource_list); ++ *resources = &wnd->wd->resource_list->list->partial_resource_list; ++ EXIT2(return NDIS_STATUS_SUCCESS); ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMMapIoSpace,4) ++ (void __iomem **virt, struct ndis_mp_block *nmb, ++ NDIS_PHY_ADDRESS phy_addr, UINT len) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ ++ ENTER2("%llx, %d", phy_addr, len); ++ *virt = MmMapIoSpace(phy_addr, len, MmCached); ++ if (*virt == NULL) { ++ ERROR("ioremap failed"); ++ EXIT2(return NDIS_STATUS_FAILURE); ++ } ++ wnd->mem_start = phy_addr; ++ wnd->mem_end = phy_addr + len; ++ TRACE2("%p", *virt); ++ EXIT2(return NDIS_STATUS_SUCCESS); ++} ++ ++wstdcall void WIN_FUNC(NdisMUnmapIoSpace,3) ++ (struct ndis_mp_block *nmb, void __iomem *virt, UINT len) ++{ ++ ENTER2("%p, %d", virt, len); ++ MmUnmapIoSpace(virt, len); ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisAllocateSpinLock,1) ++ (struct ndis_spinlock *lock) ++{ ++ TRACE4("lock %p, %p", lock, &lock->klock); ++ KeInitializeSpinLock(&lock->klock); ++ lock->irql = PASSIVE_LEVEL; ++ return; ++} ++ ++wstdcall void WIN_FUNC(NdisFreeSpinLock,1) ++ (struct ndis_spinlock *lock) ++{ ++ TRACE4("lock %p, %p", lock, &lock->klock); ++ return; ++} ++ ++wstdcall void WIN_FUNC(NdisAcquireSpinLock,1) ++ (struct ndis_spinlock *lock) ++{ ++ ENTER6("lock %p, %p", lock, &lock->klock); ++// assert_irql(_irql_ <= DISPATCH_LEVEL); ++ lock->irql = nt_spin_lock_irql(&lock->klock, DISPATCH_LEVEL); ++ return; ++} ++ ++wstdcall void WIN_FUNC(NdisReleaseSpinLock,1) ++ (struct ndis_spinlock *lock) ++{ ++ ENTER6("lock %p, %p", lock, &lock->klock); ++// assert_irql(_irql_ == DISPATCH_LEVEL); ++ nt_spin_unlock_irql(&lock->klock, lock->irql); ++ return; ++} ++ ++wstdcall void WIN_FUNC(NdisDprAcquireSpinLock,1) ++ (struct ndis_spinlock *lock) ++{ ++ ENTER6("lock %p", &lock->klock); ++// assert_irql(_irql_ == DISPATCH_LEVEL); ++ nt_spin_lock(&lock->klock); ++ return; ++} ++ ++wstdcall void WIN_FUNC(NdisDprReleaseSpinLock,1) ++ (struct ndis_spinlock *lock) ++{ ++ ENTER6("lock %p", &lock->klock); ++// assert_irql(_irql_ == DISPATCH_LEVEL); ++ nt_spin_unlock(&lock->klock); ++ return; ++} ++ ++wstdcall void WIN_FUNC(NdisInitializeReadWriteLock,1) ++ (struct ndis_rw_lock *rw_lock) ++{ ++ ENTER3("%p", rw_lock); ++ memset(rw_lock, 0, sizeof(*rw_lock)); ++ KeInitializeSpinLock(&rw_lock->klock); ++ return; ++} ++ ++/* read/write locks are implemented in a rather simplistic way - we ++ * should probably use Linux's rw_lock implementation */ ++ ++wstdcall void WIN_FUNC(NdisAcquireReadWriteLock,3) ++ (struct ndis_rw_lock *rw_lock, BOOLEAN write, ++ struct lock_state *lock_state) ++{ ++ if (write) { ++ while (1) { ++ if (cmpxchg(&rw_lock->count, 0, -1) == 0) ++ return; ++ while (rw_lock->count) ++ cpu_relax(); ++ } ++ return; ++ } ++ while (1) { ++ typeof(rw_lock->count) count; ++ while ((count = rw_lock->count) < 0) ++ cpu_relax(); ++ if (cmpxchg(&rw_lock->count, count, count + 1) == count) ++ return; ++ } ++} ++ ++wstdcall void WIN_FUNC(NdisReleaseReadWriteLock,2) ++ (struct ndis_rw_lock *rw_lock, struct lock_state *lock_state) ++{ ++ if (rw_lock->count > 0) ++ pre_atomic_add(rw_lock->count, -1); ++ else if (rw_lock->count == -1) ++ rw_lock->count = 0; ++ else ++ WARNING("invalid state: %d", rw_lock->count); ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMAllocateMapRegisters,5) ++ (struct ndis_mp_block *nmb, UINT dmachan, ++ NDIS_DMA_SIZE dmasize, ULONG basemap, ULONG max_buf_size) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ ++ ENTER2("%p, %d %d %d %d", wnd, dmachan, dmasize, basemap, max_buf_size); ++ if (!wrap_is_pci_bus(wnd->wd->dev_bus)) { ++ ERROR("used on a non-PCI device"); ++ return NDIS_STATUS_NOT_SUPPORTED; ++ } ++ if (wnd->dma_map_count > 0) { ++ WARNING("%s: map registers already allocated: %u", ++ wnd->net_dev->name, wnd->dma_map_count); ++ EXIT2(return NDIS_STATUS_RESOURCES); ++ } ++ if (dmasize == NDIS_DMA_24BITS) { ++ if (pci_set_dma_mask(wnd->wd->pci.pdev, DMA_BIT_MASK(24)) || ++ pci_set_consistent_dma_mask(wnd->wd->pci.pdev, ++ DMA_BIT_MASK(24))) ++ WARNING("setting dma mask failed"); ++ } else if (dmasize == NDIS_DMA_32BITS) { ++ /* consistent dma is in low 32-bits by default */ ++ if (pci_set_dma_mask(wnd->wd->pci.pdev, DMA_BIT_MASK(32))) ++ WARNING("setting dma mask failed"); ++#ifdef CONFIG_X86_64 ++ } else if (dmasize == NDIS_DMA_64BITS) { ++ if (pci_set_dma_mask(wnd->wd->pci.pdev, DMA_BIT_MASK(64)) || ++ pci_set_consistent_dma_mask(wnd->wd->pci.pdev, ++ DMA_BIT_MASK(64))) ++ WARNING("setting dma mask failed"); ++ else ++ wnd->net_dev->features |= NETIF_F_HIGHDMA; ++#endif ++ } else { ++ ERROR("dmasize %d not supported", dmasize); ++ EXIT2(return NDIS_STATUS_NOT_SUPPORTED); ++ } ++ /* since memory for buffer is allocated with kmalloc, buffer ++ * is physically contiguous, so entire map will fit in one ++ * register */ ++ if (basemap > 64) { ++ WARNING("Windows driver %s requesting too many (%u) " ++ "map registers", wnd->wd->driver->name, basemap); ++ /* As per NDIS, NDIS_STATUS_RESOURCES should be ++ * returned, but with that Atheros PCI driver fails - ++ * for now tolerate it */ ++// EXIT2(return NDIS_STATUS_RESOURCES); ++ } ++ ++ wnd->dma_map_addr = kzalloc(basemap * sizeof(*(wnd->dma_map_addr)), ++ GFP_KERNEL); ++ if (!wnd->dma_map_addr) ++ EXIT2(return NDIS_STATUS_RESOURCES); ++ wnd->dma_map_count = basemap; ++ TRACE2("%u", wnd->dma_map_count); ++ EXIT2(return NDIS_STATUS_SUCCESS); ++} ++ ++wstdcall void WIN_FUNC(NdisMFreeMapRegisters,1) ++ (struct ndis_mp_block *nmb) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ int i; ++ ++ ENTER2("wnd: %p", wnd); ++ if (wnd->dma_map_addr) { ++ for (i = 0; i < wnd->dma_map_count; i++) { ++ if (wnd->dma_map_addr[i]) ++ WARNING("%s: dma addr 0x%llx not freed by " ++ "Windows driver", wnd->net_dev->name, ++ (unsigned long long)wnd->dma_map_addr[i]); ++ } ++ kfree(wnd->dma_map_addr); ++ wnd->dma_map_addr = NULL; ++ } else ++ WARNING("map registers already freed?"); ++ wnd->dma_map_count = 0; ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisMStartBufferPhysicalMapping,6) ++ (struct ndis_mp_block *nmb, ndis_buffer *buf, ++ ULONG index, BOOLEAN write_to_dev, ++ struct ndis_phy_addr_unit *phy_addr_array, UINT *array_size) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ ++ ENTER3("%p, %p, %u, %u", wnd, buf, index, wnd->dma_map_count); ++ if (!wrap_is_pci_bus(wnd->wd->dev_bus)) { ++ ERROR("used on a non-PCI device"); ++ return; ++ } ++ if (unlikely(wnd->sg_dma_size || !write_to_dev || ++ index >= wnd->dma_map_count)) { ++ WARNING("invalid request: %d, %d, %d, %d", wnd->sg_dma_size, ++ write_to_dev, index, wnd->dma_map_count); ++ phy_addr_array[0].phy_addr = 0; ++ phy_addr_array[0].length = 0; ++ *array_size = 0; ++ return; ++ } ++ if (wnd->dma_map_addr[index]) { ++ TRACE2("buffer %p at %d is already mapped: %llx", buf, index, ++ (unsigned long long)wnd->dma_map_addr[index]); ++// *array_size = 1; ++ return; ++ } ++ TRACE3("%p, %p, %u", buf, MmGetSystemAddressForMdl(buf), ++ MmGetMdlByteCount(buf)); ++ DBG_BLOCK(4) { ++ dump_bytes(__func__, MmGetSystemAddressForMdl(buf), ++ MmGetMdlByteCount(buf)); ++ } ++ wnd->dma_map_addr[index] = ++ PCI_DMA_MAP_SINGLE(wnd->wd->pci.pdev, ++ MmGetSystemAddressForMdl(buf), ++ MmGetMdlByteCount(buf), PCI_DMA_TODEVICE); ++ phy_addr_array[0].phy_addr = wnd->dma_map_addr[index]; ++ phy_addr_array[0].length = MmGetMdlByteCount(buf); ++ TRACE4("%llx, %d, %d", phy_addr_array[0].phy_addr, ++ phy_addr_array[0].length, index); ++ *array_size = 1; ++} ++ ++wstdcall void WIN_FUNC(NdisMCompleteBufferPhysicalMapping,3) ++ (struct ndis_mp_block *nmb, ndis_buffer *buf, ULONG index) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ ++ ENTER3("%p, %p %u (%u)", wnd, buf, index, wnd->dma_map_count); ++ ++ if (!wrap_is_pci_bus(wnd->wd->dev_bus)) { ++ ERROR("used on a non-PCI device"); ++ return; ++ } ++ if (unlikely(wnd->sg_dma_size)) ++ WARNING("buffer %p may have been unmapped already", buf); ++ if (index >= wnd->dma_map_count) { ++ ERROR("invalid map register (%u >= %u)", ++ index, wnd->dma_map_count); ++ return; ++ } ++ TRACE4("%llx", (unsigned long long)wnd->dma_map_addr[index]); ++ if (wnd->dma_map_addr[index]) { ++ PCI_DMA_UNMAP_SINGLE(wnd->wd->pci.pdev, wnd->dma_map_addr[index], ++ MmGetMdlByteCount(buf), PCI_DMA_TODEVICE); ++ wnd->dma_map_addr[index] = 0; ++ } else ++ WARNING("map registers at %u not used", index); ++} ++ ++wstdcall void WIN_FUNC(NdisMAllocateSharedMemory,5) ++ (struct ndis_mp_block *nmb, ULONG size, ++ BOOLEAN cached, void **virt, NDIS_PHY_ADDRESS *phys) ++{ ++ dma_addr_t dma_addr; ++ struct wrap_device *wd = nmb->wnd->wd; ++ ++ ENTER3("size: %u, cached: %d", size, cached); ++ if (!wrap_is_pci_bus(wd->dev_bus)) { ++ ERROR("used on a non-PCI device"); ++ return; ++ } ++ *virt = PCI_DMA_ALLOC_COHERENT(wd->pci.pdev, size, &dma_addr); ++ if (*virt) ++ *phys = dma_addr; ++ else ++ WARNING("couldn't allocate %d bytes of %scached DMA memory", ++ size, cached ? "" : "un-"); ++ EXIT3(return); ++} ++ ++wstdcall void WIN_FUNC(NdisMFreeSharedMemory,5) ++ (struct ndis_mp_block *nmb, ULONG size, BOOLEAN cached, ++ void *virt, NDIS_PHY_ADDRESS addr) ++{ ++ struct wrap_device *wd = nmb->wnd->wd; ++ ENTER3("%p, %llx, %u", virt, addr, size); ++ if (!wrap_is_pci_bus(wd->dev_bus)) { ++ ERROR("used on a non-PCI device"); ++ return; ++ } ++ PCI_DMA_FREE_COHERENT(wd->pci.pdev, size, virt, addr); ++ EXIT3(return); ++} ++ ++wstdcall void alloc_shared_memory_async(void *arg1, void *arg2) ++{ ++ struct ndis_device *wnd; ++ struct alloc_shared_mem *alloc_shared_mem; ++ struct miniport *mp; ++ void *virt; ++ NDIS_PHY_ADDRESS phys; ++ KIRQL irql; ++ ++ wnd = arg1; ++ alloc_shared_mem = arg2; ++ mp = &wnd->wd->driver->ndis_driver->mp; ++ NdisMAllocateSharedMemory(wnd->nmb, alloc_shared_mem->size, ++ alloc_shared_mem->cached, &virt, &phys); ++ irql = serialize_lock_irql(wnd); ++ assert_irql(_irql_ == DISPATCH_LEVEL); ++ LIN2WIN5(mp->alloc_complete, wnd->nmb, virt, ++ &phys, alloc_shared_mem->size, alloc_shared_mem->ctx); ++ serialize_unlock_irql(wnd, irql); ++ kfree(alloc_shared_mem); ++} ++WIN_FUNC_DECL(alloc_shared_memory_async,2) ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMAllocateSharedMemoryAsync,4) ++ (struct ndis_mp_block *nmb, ULONG size, BOOLEAN cached, void *ctx) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ struct alloc_shared_mem *alloc_shared_mem; ++ ++ ENTER3("wnd: %p", wnd); ++ alloc_shared_mem = kmalloc(sizeof(*alloc_shared_mem), irql_gfp()); ++ if (!alloc_shared_mem) { ++ WARNING("couldn't allocate memory"); ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ alloc_shared_mem->size = size; ++ alloc_shared_mem->cached = cached; ++ alloc_shared_mem->ctx = ctx; ++ if (schedule_ntos_work_item(WIN_FUNC_PTR(alloc_shared_memory_async,2), ++ wnd, alloc_shared_mem)) ++ EXIT3(return NDIS_STATUS_FAILURE); ++ EXIT3(return NDIS_STATUS_PENDING); ++} ++ ++/* Some drivers allocate NDIS_BUFFER (aka MDL) very often; instead of ++ * allocating and freeing with kernel functions, we chain them into ++ * ndis_buffer_pool. When an MDL is freed, it is added to the list of ++ * free MDLs. When allocated, we first check if there is one in free ++ * list and if so just return it; otherwise, we allocate a new one and ++ * return that. This reduces memory fragmentation. Windows DDK says ++ * that the driver itself shouldn't check what is returned in ++ * pool_handle, presumably because buffer pools are not used in ++ * XP. However, as long as driver follows rest of the semantics - that ++ * it should indicate maximum number of MDLs used with num_descr and ++ * pass the same pool_handle in other buffer functions, this should ++ * work. Sadly, though, NdisFreeBuffer doesn't pass the pool_handle, ++ * so we use 'process' field of MDL to store pool_handle. */ ++ ++wstdcall void WIN_FUNC(NdisAllocateBufferPool,3) ++ (NDIS_STATUS *status, struct ndis_buffer_pool **pool_handle, ++ UINT num_descr) ++{ ++ struct ndis_buffer_pool *pool; ++ ++ ENTER1("buffers: %d", num_descr); ++ pool = kmalloc(sizeof(*pool), irql_gfp()); ++ if (!pool) { ++ *status = NDIS_STATUS_RESOURCES; ++ EXIT3(return); ++ } ++ spin_lock_init(&pool->lock); ++ pool->max_descr = num_descr; ++ pool->num_allocated_descr = 0; ++ pool->free_descr = NULL; ++ *pool_handle = pool; ++ *status = NDIS_STATUS_SUCCESS; ++ TRACE1("pool: %p, num_descr: %d", pool, num_descr); ++ EXIT1(return); ++} ++ ++wstdcall void WIN_FUNC(NdisAllocateBuffer,5) ++ (NDIS_STATUS *status, ndis_buffer **buffer, ++ struct ndis_buffer_pool *pool, void *virt, UINT length) ++{ ++ ndis_buffer *descr; ++ ++ ENTER4("pool: %p (%d)", pool, pool->num_allocated_descr); ++ /* NDIS drivers should call this at DISPATCH_LEVEL, but ++ * alloc_tx_packet calls at SOFT_IRQL */ ++ assert_irql(_irql_ <= SOFT_LEVEL); ++ if (!pool) { ++ *status = NDIS_STATUS_FAILURE; ++ *buffer = NULL; ++ EXIT4(return); ++ } ++ spin_lock_bh(&pool->lock); ++ if ((descr = pool->free_descr)) ++ pool->free_descr = descr->next; ++ spin_unlock_bh(&pool->lock); ++ if (descr) { ++ typeof(descr->flags) flags; ++ flags = descr->flags; ++ memset(descr, 0, sizeof(*descr)); ++ MmInitializeMdl(descr, virt, length); ++ if (flags & MDL_CACHE_ALLOCATED) ++ descr->flags |= MDL_CACHE_ALLOCATED; ++ } else { ++ if (pool->num_allocated_descr > pool->max_descr) { ++ TRACE2("pool %p is full: %d(%d)", pool, ++ pool->num_allocated_descr, pool->max_descr); ++#ifndef ALLOW_POOL_OVERFLOW ++ *status = NDIS_STATUS_FAILURE; ++ *buffer = NULL; ++ return; ++#endif ++ } ++ descr = allocate_init_mdl(virt, length); ++ if (!descr) { ++ WARNING("couldn't allocate buffer"); ++ *status = NDIS_STATUS_FAILURE; ++ *buffer = NULL; ++ EXIT4(return); ++ } ++ TRACE4("buffer %p for %p, %d", descr, virt, length); ++ atomic_inc_var(pool->num_allocated_descr); ++ } ++ /* TODO: make sure this mdl can map given buffer */ ++ MmBuildMdlForNonPagedPool(descr); ++// descr->flags |= MDL_ALLOCATED_FIXED_SIZE | ++// MDL_MAPPED_TO_SYSTEM_VA | MDL_PAGES_LOCKED; ++ descr->pool = pool; ++ *buffer = descr; ++ *status = NDIS_STATUS_SUCCESS; ++ TRACE4("buffer: %p", descr); ++ EXIT4(return); ++} ++ ++wstdcall void WIN_FUNC(NdisFreeBuffer,1) ++ (ndis_buffer *buffer) ++{ ++ struct ndis_buffer_pool *pool; ++ ++ ENTER4("%p", buffer); ++ if (!buffer || !buffer->pool) { ++ ERROR("invalid buffer"); ++ EXIT4(return); ++ } ++ pool = buffer->pool; ++ if (pool->num_allocated_descr > MAX_ALLOCATED_NDIS_BUFFERS) { ++ /* NB NB NB: set mdl's 'pool' field to NULL before ++ * calling free_mdl; otherwise free_mdl calls ++ * NdisFreeBuffer back */ ++ atomic_dec_var(pool->num_allocated_descr); ++ buffer->pool = NULL; ++ free_mdl(buffer); ++ } else { ++ spin_lock_bh(&pool->lock); ++ buffer->next = pool->free_descr; ++ pool->free_descr = buffer; ++ spin_unlock_bh(&pool->lock); ++ } ++ EXIT4(return); ++} ++ ++wstdcall void WIN_FUNC(NdisFreeBufferPool,1) ++ (struct ndis_buffer_pool *pool) ++{ ++ ndis_buffer *cur, *next; ++ ++ TRACE3("pool: %p", pool); ++ if (!pool) { ++ WARNING("invalid pool"); ++ EXIT3(return); ++ } ++ spin_lock_bh(&pool->lock); ++ cur = pool->free_descr; ++ while (cur) { ++ next = cur->next; ++ cur->pool = NULL; ++ free_mdl(cur); ++ cur = next; ++ } ++ spin_unlock_bh(&pool->lock); ++ kfree(pool); ++ pool = NULL; ++ EXIT3(return); ++} ++ ++wstdcall void WIN_FUNC(NdisAdjustBufferLength,2) ++ (ndis_buffer *buffer, UINT length) ++{ ++ ENTER4("%p, %d", buffer, length); ++ buffer->bytecount = length; ++} ++ ++wstdcall void WIN_FUNC(NdisQueryBuffer,3) ++ (ndis_buffer *buffer, void **virt, UINT *length) ++{ ++ ENTER4("buffer: %p", buffer); ++ if (virt) ++ *virt = MmGetSystemAddressForMdl(buffer); ++ *length = MmGetMdlByteCount(buffer); ++ TRACE4("%p, %u", virt ? *virt : NULL, *length); ++ return; ++} ++ ++wstdcall void WIN_FUNC(NdisQueryBufferSafe,4) ++ (ndis_buffer *buffer, void **virt, UINT *length, ++ enum mm_page_priority priority) ++{ ++ ENTER4("%p, %p, %p, %d", buffer, virt, length, priority); ++ if (virt) ++ *virt = MmGetSystemAddressForMdlSafe(buffer, priority); ++ *length = MmGetMdlByteCount(buffer); ++ TRACE4("%p, %u", virt ? *virt : NULL, *length); ++} ++ ++wstdcall void *WIN_FUNC(NdisBufferVirtualAddress,1) ++ (ndis_buffer *buffer) ++{ ++ ENTER3("%p", buffer); ++ return MmGetSystemAddressForMdl(buffer); ++} ++ ++wstdcall ULONG WIN_FUNC(NdisBufferLength,1) ++ (ndis_buffer *buffer) ++{ ++ ENTER3("%p", buffer); ++ return MmGetMdlByteCount(buffer); ++} ++ ++wstdcall void WIN_FUNC(NdisQueryBufferOffset,3) ++ (ndis_buffer *buffer, UINT *offset, UINT *length) ++{ ++ ENTER3("%p", buffer); ++ *offset = MmGetMdlByteOffset(buffer); ++ *length = MmGetMdlByteCount(buffer); ++ TRACE3("%d, %d", *offset, *length); ++} ++ ++wstdcall void WIN_FUNC(NdisUnchainBufferAtBack,2) ++ (struct ndis_packet *packet, ndis_buffer **buffer) ++{ ++ ndis_buffer *b, *btail; ++ ++ ENTER3("%p", packet); ++ b = packet->private.buffer_head; ++ if (!b) { ++ /* no buffer in packet */ ++ *buffer = NULL; ++ EXIT3(return); ++ } ++ btail = packet->private.buffer_tail; ++ *buffer = btail; ++ if (b == btail) { ++ /* one buffer in packet */ ++ packet->private.buffer_head = NULL; ++ packet->private.buffer_tail = NULL; ++ } else { ++ while (b->next != btail) ++ b = b->next; ++ packet->private.buffer_tail = b; ++ b->next = NULL; ++ } ++ packet->private.valid_counts = FALSE; ++ EXIT3(return); ++} ++ ++wstdcall void WIN_FUNC(NdisUnchainBufferAtFront,2) ++ (struct ndis_packet *packet, ndis_buffer **buffer) ++{ ++ ENTER3("%p", packet); ++ if (packet->private.buffer_head == NULL) { ++ /* no buffer in packet */ ++ *buffer = NULL; ++ EXIT3(return); ++ } ++ ++ *buffer = packet->private.buffer_head; ++ if (packet->private.buffer_head == packet->private.buffer_tail) { ++ /* one buffer in packet */ ++ packet->private.buffer_head = NULL; ++ packet->private.buffer_tail = NULL; ++ } else ++ packet->private.buffer_head = (*buffer)->next; ++ ++ packet->private.valid_counts = FALSE; ++ EXIT3(return); ++} ++ ++wstdcall void WIN_FUNC(NdisGetFirstBufferFromPacketSafe,6) ++ (struct ndis_packet *packet, ndis_buffer **first_buffer, ++ void **first_buffer_va, UINT *first_buffer_length, ++ UINT *total_buffer_length, enum mm_page_priority priority) ++{ ++ ndis_buffer *b = packet->private.buffer_head; ++ ++ ENTER3("%p(%p)", packet, b); ++ *first_buffer = b; ++ if (b) { ++ *first_buffer_va = MmGetSystemAddressForMdlSafe(b, priority); ++ *first_buffer_length = *total_buffer_length = ++ MmGetMdlByteCount(b); ++ for (b = b->next; b; b = b->next) ++ *total_buffer_length += MmGetMdlByteCount(b); ++ } else { ++ *first_buffer_va = NULL; ++ *first_buffer_length = 0; ++ *total_buffer_length = 0; ++ } ++ TRACE3("%p, %d, %d", *first_buffer_va, *first_buffer_length, ++ *total_buffer_length); ++ EXIT3(return); ++} ++ ++wstdcall void WIN_FUNC(NdisGetFirstBufferFromPacket,6) ++ (struct ndis_packet *packet, ndis_buffer **first_buffer, ++ void **first_buffer_va, UINT *first_buffer_length, ++ UINT *total_buffer_length, enum mm_page_priority priority) ++{ ++ NdisGetFirstBufferFromPacketSafe(packet, first_buffer, ++ first_buffer_va, first_buffer_length, ++ total_buffer_length, ++ NormalPagePriority); ++} ++ ++wstdcall void WIN_FUNC(NdisAllocatePacketPoolEx,5) ++ (NDIS_STATUS *status, struct ndis_packet_pool **pool_handle, ++ UINT num_descr, UINT overflowsize, UINT proto_rsvd_length) ++{ ++ struct ndis_packet_pool *pool; ++ ++ ENTER3("buffers: %d, length: %d", num_descr, proto_rsvd_length); ++ pool = kzalloc(sizeof(*pool), irql_gfp()); ++ if (!pool) { ++ *status = NDIS_STATUS_RESOURCES; ++ EXIT3(return); ++ } ++ spin_lock_init(&pool->lock); ++ pool->max_descr = num_descr; ++ pool->num_allocated_descr = 0; ++ pool->num_used_descr = 0; ++ pool->free_descr = NULL; ++ pool->proto_rsvd_length = proto_rsvd_length; ++ *pool_handle = pool; ++ *status = NDIS_STATUS_SUCCESS; ++ TRACE3("pool: %p", pool); ++ EXIT3(return); ++} ++ ++wstdcall void WIN_FUNC(NdisAllocatePacketPool,4) ++ (NDIS_STATUS *status, struct ndis_packet_pool **pool_handle, ++ UINT num_descr, UINT proto_rsvd_length) ++{ ++ NdisAllocatePacketPoolEx(status, pool_handle, num_descr, 0, ++ proto_rsvd_length); ++ EXIT3(return); ++} ++ ++wstdcall void WIN_FUNC(NdisFreePacketPool,1) ++ (struct ndis_packet_pool *pool) ++{ ++ struct ndis_packet *packet, *next; ++ ++ ENTER3("pool: %p", pool); ++ if (!pool) { ++ WARNING("invalid pool"); ++ EXIT3(return); ++ } ++ spin_lock_bh(&pool->lock); ++ packet = pool->free_descr; ++ while (packet) { ++ next = (struct ndis_packet *)packet->reserved[0]; ++ kfree(packet); ++ packet = next; ++ } ++ pool->num_allocated_descr = 0; ++ pool->num_used_descr = 0; ++ pool->free_descr = NULL; ++ spin_unlock_bh(&pool->lock); ++ kfree(pool); ++ EXIT3(return); ++} ++ ++wstdcall UINT WIN_FUNC(NdisPacketPoolUsage,1) ++ (struct ndis_packet_pool *pool) ++{ ++ EXIT4(return pool->num_used_descr); ++} ++ ++wstdcall void WIN_FUNC(NdisAllocatePacket,3) ++ (NDIS_STATUS *status, struct ndis_packet **ndis_packet, ++ struct ndis_packet_pool *pool) ++{ ++ struct ndis_packet *packet; ++ int packet_length; ++ ++ ENTER4("pool: %p", pool); ++ if (!pool) { ++ *status = NDIS_STATUS_RESOURCES; ++ *ndis_packet = NULL; ++ EXIT4(return); ++ } ++ assert_irql(_irql_ <= SOFT_LEVEL); ++ if (pool->num_used_descr > pool->max_descr) { ++ TRACE3("pool %p is full: %d(%d)", pool, ++ pool->num_used_descr, pool->max_descr); ++#ifndef ALLOW_POOL_OVERFLOW ++ *status = NDIS_STATUS_RESOURCES; ++ *ndis_packet = NULL; ++ return; ++#endif ++ } ++ /* packet has space for 1 byte in protocol_reserved field */ ++ packet_length = sizeof(*packet) - 1 + pool->proto_rsvd_length + ++ sizeof(struct ndis_packet_oob_data); ++ spin_lock_bh(&pool->lock); ++ if ((packet = pool->free_descr)) ++ pool->free_descr = (void *)packet->reserved[0]; ++ spin_unlock_bh(&pool->lock); ++ if (!packet) { ++ packet = kmalloc(packet_length, irql_gfp()); ++ if (!packet) { ++ WARNING("couldn't allocate packet"); ++ *status = NDIS_STATUS_RESOURCES; ++ *ndis_packet = NULL; ++ return; ++ } ++ atomic_inc_var(pool->num_allocated_descr); ++ } ++ TRACE4("%p, %p", pool, packet); ++ atomic_inc_var(pool->num_used_descr); ++ memset(packet, 0, packet_length); ++ packet->private.oob_offset = ++ packet_length - sizeof(struct ndis_packet_oob_data); ++ packet->private.packet_flags = fPACKET_ALLOCATED_BY_NDIS; ++ packet->private.pool = pool; ++ *ndis_packet = packet; ++ *status = NDIS_STATUS_SUCCESS; ++ EXIT4(return); ++} ++ ++wstdcall void WIN_FUNC(NdisDprAllocatePacket,3) ++ (NDIS_STATUS *status, struct ndis_packet **packet, ++ struct ndis_packet_pool *pool) ++{ ++ NdisAllocatePacket(status, packet, pool); ++} ++ ++wstdcall void WIN_FUNC(NdisFreePacket,1) ++ (struct ndis_packet *packet) ++{ ++ struct ndis_packet_pool *pool; ++ ++ ENTER4("%p, %p", packet, packet->private.pool); ++ pool = packet->private.pool; ++ if (!pool) { ++ ERROR("invalid pool %p", packet); ++ EXIT4(return); ++ } ++ assert((int)pool->num_used_descr > 0); ++ atomic_dec_var(pool->num_used_descr); ++ if (packet->reserved[1]) { ++ TRACE3("%p, %p", packet, (void *)packet->reserved[1]); ++ kfree((void *)packet->reserved[1]); ++ packet->reserved[1] = 0; ++ } ++ if (pool->num_allocated_descr > MAX_ALLOCATED_NDIS_PACKETS) { ++ TRACE3("%p", pool); ++ atomic_dec_var(pool->num_allocated_descr); ++ kfree(packet); ++ } else { ++ TRACE4("%p, %p, %p", pool, packet, pool->free_descr); ++ spin_lock_bh(&pool->lock); ++ packet->reserved[0] = ++ (typeof(packet->reserved[0]))pool->free_descr; ++ pool->free_descr = packet; ++ spin_unlock_bh(&pool->lock); ++ } ++ EXIT4(return); ++} ++ ++wstdcall struct ndis_packet_stack *WIN_FUNC(NdisIMGetCurrentPacketStack,2) ++ (struct ndis_packet *packet, BOOLEAN *stacks_remain) ++{ ++ struct ndis_packet_stack *stack; ++ ++ if (!packet->reserved[1]) { ++ stack = kzalloc(2 * sizeof(*stack), irql_gfp()); ++ TRACE3("%p, %p", packet, stack); ++ packet->reserved[1] = (typeof(packet->reserved[1]))stack; ++ } else { ++ stack = (void *)packet->reserved[1];; ++ if (xchg(&stack->ndis_reserved[0], 1)) { ++ stack++; ++ if (xchg(&stack->ndis_reserved[0], 1)) ++ stack = NULL; ++ } ++ TRACE3("%p", stack); ++ } ++ if (stack) ++ *stacks_remain = TRUE; ++ else ++ *stacks_remain = FALSE; ++ ++ EXIT3(return stack); ++} ++ ++wstdcall void WIN_FUNC(NdisCopyFromPacketToPacketSafe,7) ++ (struct ndis_packet *dst, UINT dst_offset, UINT num_to_copy, ++ struct ndis_packet *src, UINT src_offset, UINT *num_copied, ++ enum mm_page_priority priority) ++{ ++ UINT dst_n, src_n, n, left; ++ ndis_buffer *dst_buf; ++ ndis_buffer *src_buf; ++ ++ ENTER4(""); ++ if (!dst || !src) { ++ *num_copied = 0; ++ EXIT4(return); ++ } ++ ++ dst_buf = dst->private.buffer_head; ++ src_buf = src->private.buffer_head; ++ ++ if (!dst_buf || !src_buf) { ++ *num_copied = 0; ++ EXIT4(return); ++ } ++ dst_n = MmGetMdlByteCount(dst_buf) - dst_offset; ++ src_n = MmGetMdlByteCount(src_buf) - src_offset; ++ ++ n = min(src_n, dst_n); ++ n = min(n, num_to_copy); ++ memcpy(MmGetSystemAddressForMdl(dst_buf) + dst_offset, ++ MmGetSystemAddressForMdl(src_buf) + src_offset, n); ++ ++ left = num_to_copy - n; ++ while (left > 0) { ++ src_offset += n; ++ dst_offset += n; ++ dst_n -= n; ++ src_n -= n; ++ if (dst_n == 0) { ++ dst_buf = dst_buf->next; ++ if (!dst_buf) ++ break; ++ dst_n = MmGetMdlByteCount(dst_buf); ++ dst_offset = 0; ++ } ++ if (src_n == 0) { ++ src_buf = src_buf->next; ++ if (!src_buf) ++ break; ++ src_n = MmGetMdlByteCount(src_buf); ++ src_offset = 0; ++ } ++ ++ n = min(src_n, dst_n); ++ n = min(n, left); ++ memcpy(MmGetSystemAddressForMdl(dst_buf) + dst_offset, ++ MmGetSystemAddressForMdl(src_buf) + src_offset, n); ++ left -= n; ++ } ++ *num_copied = num_to_copy - left; ++ EXIT4(return); ++} ++ ++wstdcall void WIN_FUNC(NdisCopyFromPacketToPacket,6) ++ (struct ndis_packet *dst, UINT dst_offset, UINT num_to_copy, ++ struct ndis_packet *src, UINT src_offset, UINT *num_copied) ++{ ++ NdisCopyFromPacketToPacketSafe(dst, dst_offset, num_to_copy, ++ src, src_offset, num_copied, ++ NormalPagePriority); ++ return; ++} ++ ++wstdcall void WIN_FUNC(NdisIMCopySendPerPacketInfo,2) ++ (struct ndis_packet *dst, struct ndis_packet *src) ++{ ++ struct ndis_packet_oob_data *dst_oob, *src_oob; ++ dst_oob = NDIS_PACKET_OOB_DATA(dst); ++ src_oob = NDIS_PACKET_OOB_DATA(src); ++ memcpy(&dst_oob->ext, &src_oob->ext, sizeof(dst_oob->ext)); ++ return; ++} ++ ++wstdcall void WIN_FUNC(NdisSend,3) ++ (NDIS_STATUS *status, struct ndis_mp_block *nmb, ++ struct ndis_packet *packet) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ struct miniport *mp; ++ KIRQL irql; ++ ++ mp = &wnd->wd->driver->ndis_driver->mp; ++ if (mp->send_packets) { ++ irql = serialize_lock_irql(wnd); ++ assert_irql(_irql_ == DISPATCH_LEVEL); ++ LIN2WIN3(mp->send_packets, wnd->nmb->mp_ctx, &packet, 1); ++ serialize_unlock_irql(wnd, irql); ++ if (deserialized_driver(wnd)) ++ *status = NDIS_STATUS_PENDING; ++ else { ++ struct ndis_packet_oob_data *oob_data; ++ oob_data = NDIS_PACKET_OOB_DATA(packet); ++ *status = oob_data->status; ++ switch (*status) { ++ case NDIS_STATUS_SUCCESS: ++ free_tx_packet(wnd, packet, *status); ++ break; ++ case NDIS_STATUS_PENDING: ++ break; ++ case NDIS_STATUS_RESOURCES: ++ wnd->tx_ok = 0; ++ break; ++ case NDIS_STATUS_FAILURE: ++ default: ++ free_tx_packet(wnd, packet, *status); ++ break; ++ } ++ } ++ } else { ++ irql = serialize_lock_irql(wnd); ++ assert_irql(_irql_ == DISPATCH_LEVEL); ++ *status = LIN2WIN3(mp->send, wnd->nmb->mp_ctx, packet, 0); ++ serialize_unlock_irql(wnd, irql); ++ switch (*status) { ++ case NDIS_STATUS_SUCCESS: ++ free_tx_packet(wnd, packet, *status); ++ break; ++ case NDIS_STATUS_PENDING: ++ break; ++ case NDIS_STATUS_RESOURCES: ++ wnd->tx_ok = 0; ++ break; ++ case NDIS_STATUS_FAILURE: ++ default: ++ free_tx_packet(wnd, packet, *status); ++ break; ++ } ++ } ++ EXIT3(return); ++} ++ ++/* called for serialized drivers only */ ++wstdcall void mp_timer_dpc(struct kdpc *kdpc, void *ctx, void *arg1, void *arg2) ++{ ++ struct ndis_mp_timer *timer; ++ struct ndis_mp_block *nmb; ++ ++ timer = ctx; ++ TIMERENTER("%p, %p, %p, %p", timer, timer->func, timer->ctx, timer->nmb); ++ assert_irql(_irql_ == DISPATCH_LEVEL); ++ nmb = timer->nmb; ++ serialize_lock(nmb->wnd); ++ LIN2WIN4(timer->func, NULL, timer->ctx, NULL, NULL); ++ serialize_unlock(nmb->wnd); ++ TIMEREXIT(return); ++} ++WIN_FUNC_DECL(mp_timer_dpc,4) ++ ++wstdcall void WIN_FUNC(NdisMInitializeTimer,4) ++ (struct ndis_mp_timer *timer, struct ndis_mp_block *nmb, ++ DPC func, void *ctx) ++{ ++ TIMERENTER("%p, %p, %p, %p", timer, func, ctx, nmb); ++ assert_irql(_irql_ == PASSIVE_LEVEL); ++ timer->func = func; ++ timer->ctx = ctx; ++ timer->nmb = nmb; ++ if (deserialized_driver(nmb->wnd)) ++ KeInitializeDpc(&timer->kdpc, func, ctx); ++ else ++ KeInitializeDpc(&timer->kdpc, WIN_FUNC_PTR(mp_timer_dpc,4), ++ timer); ++ wrap_init_timer(&timer->nt_timer, NotificationTimer, nmb); ++ TIMEREXIT(return); ++} ++ ++wstdcall void WIN_FUNC(NdisMSetPeriodicTimer,2) ++ (struct ndis_mp_timer *timer, UINT period_ms) ++{ ++ unsigned long expires = MSEC_TO_HZ(period_ms); ++ ++ TIMERENTER("%p, %u, %ld", timer, period_ms, expires); ++ assert_irql(_irql_ <= DISPATCH_LEVEL); ++ wrap_set_timer(&timer->nt_timer, expires, expires, &timer->kdpc); ++ TIMEREXIT(return); ++} ++ ++wstdcall void WIN_FUNC(NdisMCancelTimer,2) ++ (struct ndis_mp_timer *timer, BOOLEAN *canceled) ++{ ++ TIMERENTER("%p", timer); ++ assert_irql(_irql_ <= DISPATCH_LEVEL); ++ *canceled = KeCancelTimer(&timer->nt_timer); ++ TIMERTRACE("%d", *canceled); ++ return; ++} ++ ++wstdcall void WIN_FUNC(NdisInitializeTimer,3) ++ (struct ndis_timer *timer, void *func, void *ctx) ++{ ++ TIMERENTER("%p, %p, %p", timer, func, ctx); ++ assert_irql(_irql_ == PASSIVE_LEVEL); ++ KeInitializeDpc(&timer->kdpc, func, ctx); ++ wrap_init_timer(&timer->nt_timer, NotificationTimer, NULL); ++ TIMEREXIT(return); ++} ++ ++/* NdisMSetTimer is a macro that calls NdisSetTimer with ++ * ndis_mp_timer typecast to ndis_timer */ ++ ++wstdcall void WIN_FUNC(NdisSetTimer,2) ++ (struct ndis_timer *timer, UINT duetime_ms) ++{ ++ unsigned long expires = MSEC_TO_HZ(duetime_ms); ++ ++ TIMERENTER("%p, %p, %u, %ld", timer, timer->nt_timer.wrap_timer, ++ duetime_ms, expires); ++ assert_irql(_irql_ <= DISPATCH_LEVEL); ++ wrap_set_timer(&timer->nt_timer, expires, 0, &timer->kdpc); ++ TIMEREXIT(return); ++} ++ ++wstdcall void WIN_FUNC(NdisCancelTimer,2) ++ (struct ndis_timer *timer, BOOLEAN *canceled) ++{ ++ TIMERENTER("%p", timer); ++ assert_irql(_irql_ <= DISPATCH_LEVEL); ++ *canceled = KeCancelTimer(&timer->nt_timer); ++ TIMEREXIT(return); ++} ++ ++wstdcall void WIN_FUNC(NdisMRegisterAdapterShutdownHandler,3) ++ (struct ndis_mp_block *nmb, void *ctx, void *func) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ ENTER1("%p", func); ++ wnd->wd->driver->ndis_driver->mp.shutdown = func; ++ wnd->shutdown_ctx = ctx; ++} ++ ++wstdcall void WIN_FUNC(NdisMDeregisterAdapterShutdownHandler,1) ++ (struct ndis_mp_block *nmb) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ wnd->wd->driver->ndis_driver->mp.shutdown = NULL; ++ wnd->shutdown_ctx = NULL; ++} ++ ++/* TODO: rt61 (serialized) driver doesn't want MiniportEnableInterrupt ++ * to be called in irq handler, but mrv800c (deserialized) driver ++ * wants. NDIS is confusing about when to call MiniportEnableInterrupt ++ * For now, handle these cases with two separate irq handlers based on ++ * observation of these two drivers. However, it is likely not ++ * correct. */ ++wstdcall void deserialized_irq_handler(struct kdpc *kdpc, void *ctx, ++ void *arg1, void *arg2) ++{ ++ struct ndis_device *wnd = ctx; ++ ndis_interrupt_handler irq_handler = arg1; ++ struct miniport *mp = arg2; ++ ++ TRACE6("%p", irq_handler); ++ assert_irql(_irql_ == DISPATCH_LEVEL); ++ LIN2WIN1(irq_handler, wnd->nmb->mp_ctx); ++ if (mp->enable_interrupt) ++ LIN2WIN1(mp->enable_interrupt, wnd->nmb->mp_ctx); ++ EXIT6(return); ++} ++WIN_FUNC_DECL(deserialized_irq_handler,4) ++ ++wstdcall void serialized_irq_handler(struct kdpc *kdpc, void *ctx, ++ void *arg1, void *arg2) ++{ ++ struct ndis_device *wnd = ctx; ++ ndis_interrupt_handler irq_handler = arg1; ++ ++ TRACE6("%p, %p, %p", wnd, irq_handler, arg2); ++ assert_irql(_irql_ == DISPATCH_LEVEL); ++ serialize_lock(wnd); ++ LIN2WIN1(irq_handler, arg2); ++ serialize_unlock(wnd); ++ EXIT6(return); ++} ++WIN_FUNC_DECL(serialized_irq_handler,4) ++ ++wstdcall BOOLEAN ndis_isr(struct kinterrupt *kinterrupt, void *ctx) ++{ ++ struct ndis_mp_interrupt *mp_interrupt = ctx; ++ struct ndis_device *wnd = mp_interrupt->nmb->wnd; ++ BOOLEAN recognized = TRUE, queue_handler = TRUE; ++ ++ TRACE6("%p", wnd); ++ /* kernel may call ISR when registering interrupt, in ++ * the same context if DEBUG_SHIRQ is enabled */ ++ assert_irql(_irql_ == DIRQL || _irql_ == PASSIVE_LEVEL); ++ if (mp_interrupt->shared) ++ LIN2WIN3(mp_interrupt->isr, &recognized, &queue_handler, ++ wnd->nmb->mp_ctx); ++ else { ++ struct miniport *mp; ++ mp = &wnd->wd->driver->ndis_driver->mp; ++ LIN2WIN1(mp->disable_interrupt, wnd->nmb->mp_ctx); ++ /* it is not shared interrupt, so handler must be called */ ++ recognized = queue_handler = TRUE; ++ } ++ if (recognized) { ++ if (queue_handler) { ++ TRACE5("%p", &wnd->irq_kdpc); ++ queue_kdpc(&wnd->irq_kdpc); ++ } ++ EXIT6(return TRUE); ++ } ++ EXIT6(return FALSE); ++} ++WIN_FUNC_DECL(ndis_isr,2) ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMRegisterInterrupt,7) ++ (struct ndis_mp_interrupt *mp_interrupt, ++ struct ndis_mp_block *nmb, UINT vector, UINT level, ++ BOOLEAN req_isr, BOOLEAN shared, enum kinterrupt_mode mode) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ struct miniport *mp; ++ ++ ENTER1("%p, vector:%d, level:%d, req_isr:%d, shared:%d, mode:%d", ++ mp_interrupt, vector, level, req_isr, shared, mode); ++ ++ mp = &wnd->wd->driver->ndis_driver->mp; ++ nt_spin_lock_init(&mp_interrupt->lock); ++ mp_interrupt->irq = vector; ++ mp_interrupt->isr = mp->isr; ++ mp_interrupt->mp_dpc = mp->handle_interrupt; ++ mp_interrupt->nmb = nmb; ++ mp_interrupt->req_isr = req_isr; ++ if (shared && !req_isr) ++ WARNING("shared but dynamic interrupt!"); ++ mp_interrupt->shared = shared; ++ wnd->mp_interrupt = mp_interrupt; ++ if (mp->enable_interrupt) ++ mp_interrupt->enable = TRUE; ++ else ++ mp_interrupt->enable = FALSE; ++ ++ if (deserialized_driver(wnd)) { ++ KeInitializeDpc(&wnd->irq_kdpc, ++ WIN_FUNC_PTR(deserialized_irq_handler,4), ++ nmb->wnd); ++ wnd->irq_kdpc.arg1 = mp->handle_interrupt; ++ wnd->irq_kdpc.arg2 = mp; ++ TRACE2("%p, %p, %p, %p", wnd->irq_kdpc.arg1, wnd->irq_kdpc.arg2, ++ nmb->wnd, nmb->mp_ctx); ++ } else { ++ KeInitializeDpc(&wnd->irq_kdpc, ++ WIN_FUNC_PTR(serialized_irq_handler,4), ++ nmb->wnd); ++ wnd->irq_kdpc.arg1 = mp->handle_interrupt; ++ wnd->irq_kdpc.arg2 = nmb->mp_ctx; ++ TRACE2("%p, %p, %p", wnd->irq_kdpc.arg1, wnd->irq_kdpc.arg2, ++ nmb->wnd); ++ } ++ ++ if (IoConnectInterrupt(&mp_interrupt->kinterrupt, ++ WIN_FUNC_PTR(ndis_isr,2), mp_interrupt, NULL, ++ vector, DIRQL, DIRQL, mode, shared, 0, FALSE) != ++ STATUS_SUCCESS) { ++ printk(KERN_WARNING "%s: request for IRQ %d failed\n", ++ DRIVER_NAME, vector); ++ return NDIS_STATUS_RESOURCES; ++ } ++ printk(KERN_INFO "%s: using IRQ %d\n", DRIVER_NAME, vector); ++ EXIT1(return NDIS_STATUS_SUCCESS); ++} ++ ++wstdcall void WIN_FUNC(NdisMDeregisterInterrupt,1) ++ (struct ndis_mp_interrupt *mp_interrupt) ++{ ++ struct ndis_mp_block *nmb; ++ ++ ENTER1("%p", mp_interrupt); ++ nmb = xchg(&mp_interrupt->nmb, NULL); ++ TRACE1("%p", nmb); ++ if (!nmb) { ++ WARNING("interrupt already freed?"); ++ return; ++ } ++ nmb->wnd->mp_interrupt = NULL; ++ if (dequeue_kdpc(&nmb->wnd->irq_kdpc)) ++ TRACE2("interrupt kdpc was pending"); ++ flush_workqueue(wrapndis_wq); ++ IoDisconnectInterrupt(mp_interrupt->kinterrupt); ++ EXIT1(return); ++} ++ ++wstdcall BOOLEAN WIN_FUNC(NdisMSynchronizeWithInterrupt,3) ++ (struct ndis_mp_interrupt *mp_interrupt, ++ PKSYNCHRONIZE_ROUTINE sync_func, void *ctx) ++{ ++ return KeSynchronizeExecution(mp_interrupt->kinterrupt, sync_func, ctx); ++} ++ ++/* called via function pointer; but 64-bit RNDIS driver calls directly */ ++wstdcall void WIN_FUNC(NdisMIndicateStatus,4) ++ (struct ndis_mp_block *nmb, NDIS_STATUS status, void *buf, UINT len) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ struct ndis_status_indication *si; ++ ++ ENTER2("status=0x%x len=%d", status, len); ++ switch (status) { ++ case NDIS_STATUS_MEDIA_CONNECT: ++ set_media_state(wnd, NdisMediaStateConnected); ++ break; ++ case NDIS_STATUS_MEDIA_DISCONNECT: ++ set_media_state(wnd, NdisMediaStateDisconnected); ++ break; ++ case NDIS_STATUS_MEDIA_SPECIFIC_INDICATION: ++ if (!buf) ++ break; ++ si = buf; ++ TRACE2("status_type=%d", si->status_type); ++ switch (si->status_type) { ++ case Ndis802_11StatusType_MediaStreamMode: ++ break; ++#ifdef CONFIG_WIRELESS_EXT ++ case Ndis802_11StatusType_Authentication: ++ buf = (char *)buf + sizeof(*si); ++ len -= sizeof(*si); ++ while (len > 0) { ++ int pairwise_error = 0, group_error = 0; ++ struct ndis_auth_req *auth_req = ++ (struct ndis_auth_req *)buf; ++ TRACE1(MACSTRSEP, MAC2STR(auth_req->bssid)); ++ if (auth_req->flags & 0x01) ++ TRACE2("reauth request"); ++ if (auth_req->flags & 0x02) ++ TRACE2("key update request"); ++ if (auth_req->flags & 0x06) { ++ pairwise_error = 1; ++ TRACE2("pairwise_error"); ++ } ++ if (auth_req->flags & 0x0E) { ++ group_error = 1; ++ TRACE2("group_error"); ++ } ++ if (pairwise_error || group_error) { ++ union iwreq_data wrqu; ++ struct iw_michaelmicfailure micfailure; ++ ++ memset(&micfailure, 0, sizeof(micfailure)); ++ if (pairwise_error) ++ micfailure.flags |= ++ IW_MICFAILURE_PAIRWISE; ++ if (group_error) ++ micfailure.flags |= ++ IW_MICFAILURE_GROUP; ++ memcpy(micfailure.src_addr.sa_data, ++ auth_req->bssid, ETH_ALEN); ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.length = sizeof(micfailure); ++ wireless_send_event(wnd->net_dev, ++ IWEVMICHAELMICFAILURE, ++ &wrqu, (u8 *)&micfailure); ++ } ++ len -= auth_req->length; ++ buf = (char *)buf + auth_req->length; ++ } ++ break; ++ case Ndis802_11StatusType_PMKID_CandidateList: ++ { ++ u8 *end; ++ unsigned long i; ++ struct ndis_pmkid_candidate_list *cand; ++ ++ cand = buf + sizeof(struct ndis_status_indication); ++ if (len < sizeof(struct ndis_status_indication) + ++ sizeof(struct ndis_pmkid_candidate_list) || ++ cand->version != 1) { ++ WARNING("unrecognized PMKID ignored"); ++ EXIT1(return); ++ } ++ ++ end = (u8 *)buf + len; ++ TRACE2("PMKID ver %d num_cand %d", ++ cand->version, cand->num_candidates); ++ for (i = 0; i < cand->num_candidates; i++) { ++ struct iw_pmkid_cand pcand; ++ union iwreq_data wrqu; ++ struct ndis_pmkid_candidate *c = ++ &cand->candidates[i]; ++ if ((u8 *)(c + 1) > end) { ++ TRACE2("truncated PMKID"); ++ break; ++ } ++ TRACE2("%ld: " MACSTRSEP " 0x%x", ++ i, MAC2STR(c->bssid), c->flags); ++ memset(&pcand, 0, sizeof(pcand)); ++ if (c->flags & 0x01) ++ pcand.flags |= IW_PMKID_CAND_PREAUTH; ++ pcand.index = i; ++ memcpy(pcand.bssid.sa_data, c->bssid, ETH_ALEN); ++ ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.data.length = sizeof(pcand); ++ wireless_send_event(wnd->net_dev, IWEVPMKIDCAND, ++ &wrqu, (u8 *)&pcand); ++ } ++ break; ++ } ++ case Ndis802_11StatusType_RadioState: ++ { ++ struct ndis_radio_status_indication *radio_status = buf; ++ if (radio_status->radio_state == ++ Ndis802_11RadioStatusOn) ++ INFO("radio is turned on"); ++ else if (radio_status->radio_state == ++ Ndis802_11RadioStatusHardwareOff) ++ INFO("radio is turned off by hardware"); ++ else if (radio_status->radio_state == ++ Ndis802_11RadioStatusSoftwareOff) ++ INFO("radio is turned off by software"); ++ break; ++ } ++#endif ++ default: ++ /* is this RSSI indication? */ ++ TRACE2("unknown indication: %x", si->status_type); ++ break; ++ } ++ break; ++ default: ++ TRACE2("unknown status: %08X", status); ++ break; ++ } ++ ++ EXIT2(return); ++} ++ ++/* called via function pointer; but 64-bit RNDIS driver calls directly */ ++wstdcall void WIN_FUNC(NdisMIndicateStatusComplete,1) ++ (struct ndis_mp_block *nmb) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ ENTER2("%p", wnd); ++ if (wnd->tx_ok) ++ queue_work(wrapndis_wq, &wnd->tx_work); ++} ++ ++/* called via function pointer */ ++wstdcall void NdisMSendComplete(struct ndis_mp_block *nmb, ++ struct ndis_packet *packet, NDIS_STATUS status) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ ENTER4("%p, %08X", packet, status); ++ assert_irql(_irql_ <= DISPATCH_LEVEL); ++ if (deserialized_driver(wnd)) ++ free_tx_packet(wnd, packet, status); ++ else { ++ struct ndis_packet_oob_data *oob_data; ++ NDIS_STATUS pkt_status; ++ TRACE3("%p, %08x", packet, status); ++ oob_data = NDIS_PACKET_OOB_DATA(packet); ++ switch ((pkt_status = xchg(&oob_data->status, status))) { ++ case NDIS_STATUS_NOT_RECOGNIZED: ++ free_tx_packet(wnd, packet, status); ++ break; ++ case NDIS_STATUS_PENDING: ++ case 0: ++ break; ++ default: ++ WARNING("%p: invalid status: %08X", packet, pkt_status); ++ break; ++ } ++ /* In case a serialized driver has earlier requested a ++ * pause by returning NDIS_STATUS_RESOURCES during ++ * MiniportSend(Packets), wakeup tx worker now. ++ */ ++ if (xchg(&wnd->tx_ok, 1) == 0) { ++ TRACE3("%d, %d", wnd->tx_ring_start, wnd->tx_ring_end); ++ queue_work(wrapndis_wq, &wnd->tx_work); ++ } ++ } ++ EXIT3(return); ++} ++ ++/* called via function pointer */ ++wstdcall void NdisMSendResourcesAvailable(struct ndis_mp_block *nmb) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ ENTER3("%d, %d", wnd->tx_ring_start, wnd->tx_ring_end); ++ wnd->tx_ok = 1; ++ queue_work(wrapndis_wq, &wnd->tx_work); ++ EXIT3(return); ++} ++ ++wstdcall void return_packet(void *arg1, void *arg2) ++{ ++ struct ndis_device *wnd; ++ struct ndis_packet *packet; ++ struct miniport *mp; ++ KIRQL irql; ++ ++ wnd = arg1; ++ packet = arg2; ++ ENTER4("%p, %p", wnd, packet); ++ mp = &wnd->wd->driver->ndis_driver->mp; ++ irql = serialize_lock_irql(wnd); ++ assert_irql(_irql_ == DISPATCH_LEVEL); ++ LIN2WIN2(mp->return_packet, wnd->nmb->mp_ctx, packet); ++ serialize_unlock_irql(wnd, irql); ++ EXIT4(return); ++} ++WIN_FUNC_DECL(return_packet,2) ++ ++/* called via function pointer */ ++wstdcall void NdisMIndicateReceivePacket(struct ndis_mp_block *nmb, ++ struct ndis_packet **packets, ++ UINT nr_packets) ++{ ++ struct ndis_device *wnd; ++ ndis_buffer *buffer; ++ struct ndis_packet *packet; ++ struct sk_buff *skb; ++ ULONG i, length, total_length; ++ struct ndis_packet_oob_data *oob_data; ++ void *virt; ++ struct ndis_tcp_ip_checksum_packet_info csum; ++ ++ ENTER3("%p, %d", nmb, nr_packets); ++ assert_irql(_irql_ <= DISPATCH_LEVEL); ++ wnd = nmb->wnd; ++ for (i = 0; i < nr_packets; i++) { ++ packet = packets[i]; ++ if (!packet) { ++ WARNING("empty packet ignored"); ++ continue; ++ } ++ wnd->net_dev->last_rx = jiffies; ++ /* get total number of bytes in packet */ ++ NdisGetFirstBufferFromPacketSafe(packet, &buffer, &virt, ++ &length, &total_length, ++ NormalPagePriority); ++ TRACE3("%d, %d", length, total_length); ++ oob_data = NDIS_PACKET_OOB_DATA(packet); ++ TRACE3("0x%x, 0x%x, %llu", packet->private.flags, ++ packet->private.packet_flags, oob_data->time_rxed); ++ skb = dev_alloc_skb(total_length); ++ if (skb) { ++ while (buffer) { ++ memcpy_skb(skb, MmGetSystemAddressForMdl(buffer), ++ MmGetMdlByteCount(buffer)); ++ buffer = buffer->next; ++ } ++ skb->dev = wnd->net_dev; ++ skb->protocol = eth_type_trans(skb, wnd->net_dev); ++ pre_atomic_add(wnd->net_stats.rx_bytes, total_length); ++ atomic_inc_var(wnd->net_stats.rx_packets); ++ csum.value = (typeof(csum.value))(ULONG_PTR) ++ oob_data->ext.info[TcpIpChecksumPacketInfo]; ++ TRACE3("0x%05x", csum.value); ++ if (wnd->rx_csum.value && ++ (csum.rx.tcp_succeeded || csum.rx.udp_succeeded || ++ csum.rx.ip_succeeded)) ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ else ++ skb->ip_summed = CHECKSUM_NONE; ++ ++ if (in_interrupt()) ++ netif_rx(skb); ++ else ++ netif_rx_ni(skb); ++ } else { ++ WARNING("couldn't allocate skb; packet dropped"); ++ atomic_inc_var(wnd->net_stats.rx_dropped); ++ } ++ ++ /* serialized drivers check the status upon return ++ * from this function */ ++ if (!deserialized_driver(wnd)) { ++ oob_data->status = NDIS_STATUS_SUCCESS; ++ continue; ++ } ++ ++ /* if a deserialized driver sets ++ * NDIS_STATUS_RESOURCES, then it reclaims the packet ++ * upon return from this function */ ++ if (oob_data->status == NDIS_STATUS_RESOURCES) ++ continue; ++ ++ assert(oob_data->status == NDIS_STATUS_SUCCESS); ++ /* deserialized driver doesn't check the status upon ++ * return from this function; we need to call ++ * MiniportReturnPacket later for this packet. Calling ++ * MiniportReturnPacket from here is not correct - the ++ * driver doesn't expect it (at least Centrino driver ++ * crashes) */ ++ schedule_ntos_work_item(WIN_FUNC_PTR(return_packet,2), ++ wnd, packet); ++ } ++ EXIT3(return); ++} ++ ++/* called via function pointer (by NdisMEthIndicateReceive macro); the ++ * first argument is nmb->eth_db */ ++wstdcall void EthRxIndicateHandler(struct ndis_mp_block *nmb, void *rx_ctx, ++ char *header1, char *header, UINT header_size, ++ void *look_ahead, UINT look_ahead_size, ++ UINT packet_size) ++{ ++ struct sk_buff *skb = NULL; ++ struct ndis_device *wnd; ++ unsigned int skb_size = 0; ++ KIRQL irql; ++ struct ndis_packet_oob_data *oob_data; ++ ++ ENTER3("nmb = %p, rx_ctx = %p, buf = %p, size = %d, buf = %p, " ++ "size = %d, packet = %d", nmb, rx_ctx, header, header_size, ++ look_ahead, look_ahead_size, packet_size); ++ ++ wnd = nmb->wnd; ++ TRACE3("wnd = %p", wnd); ++ if (!wnd) { ++ ERROR("nmb is NULL"); ++ EXIT3(return); ++ } ++ wnd->net_dev->last_rx = jiffies; ++ ++ if (look_ahead_size < packet_size) { ++ struct ndis_packet *packet; ++ struct miniport *mp; ++ unsigned int bytes_txed; ++ NDIS_STATUS res; ++ ++ NdisAllocatePacket(&res, &packet, wnd->tx_packet_pool); ++ if (res != NDIS_STATUS_SUCCESS) { ++ atomic_inc_var(wnd->net_stats.rx_dropped); ++ EXIT3(return); ++ } ++ oob_data = NDIS_PACKET_OOB_DATA(packet); ++ mp = &wnd->wd->driver->ndis_driver->mp; ++ irql = serialize_lock_irql(wnd); ++ assert_irql(_irql_ == DISPATCH_LEVEL); ++ res = LIN2WIN6(mp->tx_data, packet, &bytes_txed, nmb, ++ rx_ctx, look_ahead_size, packet_size); ++ serialize_unlock_irql(wnd, irql); ++ TRACE3("%d, %d, %d", header_size, look_ahead_size, bytes_txed); ++ if (res == NDIS_STATUS_SUCCESS) { ++ ndis_buffer *buffer; ++ struct ndis_tcp_ip_checksum_packet_info csum; ++ skb = dev_alloc_skb(header_size + look_ahead_size + ++ bytes_txed); ++ if (!skb) { ++ ERROR("couldn't allocate skb; packet dropped"); ++ atomic_inc_var(wnd->net_stats.rx_dropped); ++ NdisFreePacket(packet); ++ return; ++ } ++ memcpy_skb(skb, header, header_size); ++ memcpy_skb(skb, look_ahead, look_ahead_size); ++ buffer = packet->private.buffer_head; ++ while (buffer) { ++ memcpy_skb(skb, ++ MmGetSystemAddressForMdl(buffer), ++ MmGetMdlByteCount(buffer)); ++ buffer = buffer->next; ++ } ++ skb_size = header_size + look_ahead_size + bytes_txed; ++ csum.value = (typeof(csum.value))(ULONG_PTR) ++ oob_data->ext.info[TcpIpChecksumPacketInfo]; ++ TRACE3("0x%05x", csum.value); ++ if (wnd->rx_csum.value && ++ (csum.rx.tcp_succeeded || csum.rx.udp_succeeded)) ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ else ++ skb->ip_summed = CHECKSUM_NONE; ++ NdisFreePacket(packet); ++ } else if (res == NDIS_STATUS_PENDING) { ++ /* driver will call td_complete */ ++ oob_data->look_ahead = kmalloc(look_ahead_size, ++ GFP_ATOMIC); ++ if (!oob_data->look_ahead) { ++ NdisFreePacket(packet); ++ ERROR("packet dropped"); ++ atomic_inc_var(wnd->net_stats.rx_dropped); ++ EXIT3(return); ++ } ++ assert(sizeof(oob_data->header) == header_size); ++ memcpy(oob_data->header, header, ++ sizeof(oob_data->header)); ++ memcpy(oob_data->look_ahead, look_ahead, ++ look_ahead_size); ++ oob_data->look_ahead_size = look_ahead_size; ++ EXIT3(return); ++ } else { ++ WARNING("packet dropped: %08X", res); ++ atomic_inc_var(wnd->net_stats.rx_dropped); ++ NdisFreePacket(packet); ++ EXIT3(return); ++ } ++ } else { ++ skb_size = header_size + packet_size; ++ skb = dev_alloc_skb(skb_size); ++ if (skb) { ++ memcpy_skb(skb, header, header_size); ++ memcpy_skb(skb, look_ahead, packet_size); ++ } ++ } ++ ++ if (skb) { ++ skb->dev = wnd->net_dev; ++ skb->protocol = eth_type_trans(skb, wnd->net_dev); ++ pre_atomic_add(wnd->net_stats.rx_bytes, skb_size); ++ atomic_inc_var(wnd->net_stats.rx_packets); ++ if (in_interrupt()) ++ netif_rx(skb); ++ else ++ netif_rx_ni(skb); ++ } ++ ++ EXIT3(return); ++} ++ ++/* called via function pointer */ ++wstdcall void NdisMTransferDataComplete(struct ndis_mp_block *nmb, ++ struct ndis_packet *packet, ++ NDIS_STATUS status, UINT bytes_txed) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ struct sk_buff *skb; ++ unsigned int skb_size; ++ struct ndis_packet_oob_data *oob_data; ++ ndis_buffer *buffer; ++ struct ndis_tcp_ip_checksum_packet_info csum; ++ ++ ENTER3("wnd = %p, packet = %p, bytes_txed = %d", ++ wnd, packet, bytes_txed); ++ if (!packet) { ++ WARNING("illegal packet"); ++ EXIT3(return); ++ } ++ wnd->net_dev->last_rx = jiffies; ++ oob_data = NDIS_PACKET_OOB_DATA(packet); ++ skb_size = sizeof(oob_data->header) + oob_data->look_ahead_size + ++ bytes_txed; ++ skb = dev_alloc_skb(skb_size); ++ if (!skb) { ++ kfree(oob_data->look_ahead); ++ NdisFreePacket(packet); ++ ERROR("couldn't allocate skb; packet dropped"); ++ atomic_inc_var(wnd->net_stats.rx_dropped); ++ EXIT3(return); ++ } ++ memcpy_skb(skb, oob_data->header, sizeof(oob_data->header)); ++ memcpy_skb(skb, oob_data->look_ahead, oob_data->look_ahead_size); ++ buffer = packet->private.buffer_head; ++ while (buffer) { ++ memcpy_skb(skb, MmGetSystemAddressForMdl(buffer), ++ MmGetMdlByteCount(buffer)); ++ buffer = buffer->next; ++ } ++ kfree(oob_data->look_ahead); ++ NdisFreePacket(packet); ++ skb->dev = wnd->net_dev; ++ skb->protocol = eth_type_trans(skb, wnd->net_dev); ++ pre_atomic_add(wnd->net_stats.rx_bytes, skb_size); ++ atomic_inc_var(wnd->net_stats.rx_packets); ++ ++ csum.value = (typeof(csum.value))(ULONG_PTR) ++ oob_data->ext.info[TcpIpChecksumPacketInfo]; ++ TRACE3("0x%05x", csum.value); ++ if (wnd->rx_csum.value && ++ (csum.rx.tcp_succeeded || csum.rx.udp_succeeded)) ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ else ++ skb->ip_summed = CHECKSUM_NONE; ++ ++ if (in_interrupt()) ++ netif_rx(skb); ++ else ++ netif_rx_ni(skb); ++} ++ ++/* called via function pointer */ ++wstdcall void EthRxComplete(struct ndis_mp_block *nmb) ++{ ++ TRACE3(""); ++} ++ ++/* called via function pointer */ ++wstdcall void NdisMQueryInformationComplete(struct ndis_mp_block *nmb, ++ NDIS_STATUS status) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ typeof(wnd->ndis_req_task) task; ++ ++ ENTER2("nmb: %p, wnd: %p, %08X", nmb, wnd, status); ++ wnd->ndis_req_status = status; ++ wnd->ndis_req_done = 1; ++ if ((task = xchg(&wnd->ndis_req_task, NULL))) ++ wake_up_process(task); ++ else ++ WARNING("invalid task"); ++ EXIT2(return); ++} ++ ++/* called via function pointer */ ++wstdcall void NdisMSetInformationComplete(struct ndis_mp_block *nmb, ++ NDIS_STATUS status) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ typeof(wnd->ndis_req_task) task; ++ ++ ENTER2("status = %08X", status); ++ wnd->ndis_req_status = status; ++ wnd->ndis_req_done = 1; ++ if ((task = xchg(&wnd->ndis_req_task, NULL))) ++ wake_up_process(task); ++ else ++ WARNING("invalid task"); ++ EXIT2(return); ++} ++ ++/* called via function pointer */ ++wstdcall void NdisMResetComplete(struct ndis_mp_block *nmb, ++ NDIS_STATUS status, BOOLEAN address_reset) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ typeof(wnd->ndis_req_task) task; ++ ++ ENTER2("status: %08X, %u", status, address_reset); ++ wnd->ndis_req_status = status; ++ wnd->ndis_req_done = address_reset + 1; ++ if ((task = xchg(&wnd->ndis_req_task, NULL))) ++ wake_up_process(task); ++ else ++ WARNING("invalid task"); ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(NdisMSleep,1) ++ (ULONG us) ++{ ++ unsigned long delay; ++ ++ ENTER4("%p: us: %u", current, us); ++ delay = USEC_TO_HZ(us); ++ sleep_hz(delay); ++ TRACE4("%p: done", current); ++} ++ ++wstdcall void WIN_FUNC(NdisGetCurrentSystemTime,1) ++ (LARGE_INTEGER *time) ++{ ++ *time = ticks_1601(); ++ TRACE5("%llu, %lu", *time, jiffies); ++} ++ ++wstdcall LONG WIN_FUNC(NdisInterlockedDecrement,1) ++ (LONG *val) ++{ ++ return InterlockedDecrement(val); ++} ++ ++wstdcall LONG WIN_FUNC(NdisInterlockedIncrement,1) ++ (LONG *val) ++{ ++ return InterlockedIncrement(val); ++} ++ ++wstdcall struct nt_list *WIN_FUNC(NdisInterlockedInsertHeadList,3) ++ (struct nt_list *head, struct nt_list *entry, ++ struct ndis_spinlock *lock) ++{ ++ return ExInterlockedInsertHeadList(head, entry, &lock->klock); ++} ++ ++wstdcall struct nt_list *WIN_FUNC(NdisInterlockedInsertTailList,3) ++ (struct nt_list *head, struct nt_list *entry, ++ struct ndis_spinlock *lock) ++{ ++ return ExInterlockedInsertTailList(head, entry, &lock->klock); ++} ++ ++wstdcall struct nt_list *WIN_FUNC(NdisInterlockedRemoveHeadList,2) ++ (struct nt_list *head, struct ndis_spinlock *lock) ++{ ++ return ExInterlockedRemoveHeadList(head, &lock->klock); ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMInitializeScatterGatherDma,3) ++ (struct ndis_mp_block *nmb, BOOLEAN dma64_supported, ULONG max_phy_map) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ ENTER2("dma64_supported=%d, maxtransfer=%u", dma64_supported, ++ max_phy_map); ++ if (!wrap_is_pci_bus(wnd->wd->dev_bus)) { ++ ERROR("used on a non-PCI device"); ++ return NDIS_STATUS_NOT_SUPPORTED; ++ } ++#ifdef CONFIG_X86_64 ++ if (!dma64_supported) { ++ TRACE1("64-bit DMA size is not supported"); ++ if (pci_set_dma_mask(wnd->wd->pci.pdev, DMA_BIT_MASK(32)) || ++ pci_set_consistent_dma_mask(wnd->wd->pci.pdev, ++ DMA_BIT_MASK(32))) ++ WARNING("setting dma mask failed"); ++ } ++#endif ++ if ((wnd->attributes & NDIS_ATTRIBUTE_BUS_MASTER) && ++ wrap_is_pci_bus(wnd->wd->dev_bus)) { ++ wnd->sg_dma_size = max_phy_map; ++ return NDIS_STATUS_SUCCESS; ++ } else ++ EXIT1(return NDIS_STATUS_NOT_SUPPORTED); ++} ++ ++wstdcall ULONG WIN_FUNC(NdisMGetDmaAlignment,1) ++ (struct ndis_mp_block *nmb) ++{ ++ ENTER3(""); ++ return dma_get_cache_alignment(); ++} ++ ++wstdcall CHAR WIN_FUNC(NdisSystemProcessorCount,0) ++ (void) ++{ ++ return num_online_cpus(); ++} ++ ++wstdcall void WIN_FUNC(NdisGetCurrentProcessorCounts,3) ++ (ULONG *idle, ULONG *kernel_user, ULONG *index) ++{ ++ int cpu = smp_processor_id(); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0) ++ *idle = kcpustat_cpu(cpu).cpustat[CPUTIME_IDLE]; ++ *kernel_user = kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM] + ++ kcpustat_cpu(cpu).cpustat[CPUTIME_USER]; ++#else ++ *idle = kstat_cpu(cpu).cpustat.idle; ++ *kernel_user = kstat_cpu(cpu).cpustat.system + ++ kstat_cpu(cpu).cpustat.user; ++#endif ++ *index = cpu; ++} ++ ++wstdcall void WIN_FUNC(NdisInitializeEvent,1) ++ (struct ndis_event *ndis_event) ++{ ++ EVENTENTER("%p", ndis_event); ++ KeInitializeEvent(&ndis_event->nt_event, NotificationEvent, 0); ++} ++ ++wstdcall BOOLEAN WIN_FUNC(NdisWaitEvent,2) ++ (struct ndis_event *ndis_event, UINT ms) ++{ ++ LARGE_INTEGER ticks; ++ NTSTATUS res; ++ ++ EVENTENTER("%p %u", ndis_event, ms); ++ ticks = -((LARGE_INTEGER)ms * TICKSPERMSEC); ++ res = KeWaitForSingleObject(&ndis_event->nt_event, 0, 0, TRUE, ++ ms == 0 ? NULL : &ticks); ++ if (res == STATUS_SUCCESS) ++ EXIT3(return TRUE); ++ else ++ EXIT3(return FALSE); ++} ++ ++wstdcall void WIN_FUNC(NdisSetEvent,1) ++ (struct ndis_event *ndis_event) ++{ ++ EVENTENTER("%p", ndis_event); ++ KeSetEvent(&ndis_event->nt_event, 0, 0); ++} ++ ++wstdcall void WIN_FUNC(NdisResetEvent,1) ++ (struct ndis_event *ndis_event) ++{ ++ EVENTENTER("%p", ndis_event); ++ KeResetEvent(&ndis_event->nt_event); ++} ++ ++static void ndis_worker(struct work_struct *dummy) ++{ ++ struct nt_list *ent; ++ struct ndis_work_item *ndis_work_item; ++ ++ WORKENTER(""); ++ while (1) { ++ spin_lock_bh(&ndis_work_list_lock); ++ ent = RemoveHeadList(&ndis_work_list); ++ spin_unlock_bh(&ndis_work_list_lock); ++ if (!ent) ++ break; ++ ndis_work_item = container_of(ent, struct ndis_work_item, list); ++ WORKTRACE("%p: %p, %p", ndis_work_item, ++ ndis_work_item->func, ndis_work_item->ctx); ++ LIN2WIN2(ndis_work_item->func, ndis_work_item, ++ ndis_work_item->ctx); ++ WORKTRACE("%p done", ndis_work_item); ++ } ++ WORKEXIT(return); ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisScheduleWorkItem,1) ++ (struct ndis_work_item *ndis_work_item) ++{ ++ ENTER3("%p", ndis_work_item); ++ spin_lock_bh(&ndis_work_list_lock); ++ InsertTailList(&ndis_work_list, &ndis_work_item->list); ++ spin_unlock_bh(&ndis_work_list_lock); ++ WORKTRACE("scheduling %p", ndis_work_item); ++ queue_work(ndis_wq, &ndis_work); ++ EXIT3(return NDIS_STATUS_SUCCESS); ++} ++ ++wstdcall void WIN_FUNC(NdisMGetDeviceProperty,6) ++ (struct ndis_mp_block *nmb, void **phy_dev, void **func_dev, ++ void **next_dev, void **alloc_res, void**trans_res) ++{ ++ ENTER2("nmb: %p, phy_dev = %p, func_dev = %p, next_dev = %p, " ++ "alloc_res = %p, trans_res = %p", nmb, phy_dev, func_dev, ++ next_dev, alloc_res, trans_res); ++ if (phy_dev) ++ *phy_dev = nmb->pdo; ++ if (func_dev) ++ *func_dev = nmb->fdo; ++ if (next_dev) ++ *next_dev = nmb->next_device; ++} ++ ++wstdcall void WIN_FUNC(NdisMRegisterUnloadHandler,2) ++ (struct driver_object *drv_obj, void *unload) ++{ ++ if (drv_obj) ++ drv_obj->unload = unload; ++ return; ++} ++ ++wstdcall UINT WIN_FUNC(NdisGetVersion,0) ++ (void) ++{ ++ return 0x00050001; ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMQueryAdapterInstanceName,2) ++ (struct unicode_string *name, struct ndis_mp_block *nmb) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ struct ansi_string ansi; ++ ++ if (wrap_is_pci_bus(wnd->wd->dev_bus)) ++ RtlInitAnsiString(&ansi, "PCI Ethernet Adapter"); ++ else ++ RtlInitAnsiString(&ansi, "USB Ethernet Adapter"); ++ ++ if (RtlAnsiStringToUnicodeString(name, &ansi, TRUE)) ++ EXIT2(return NDIS_STATUS_RESOURCES); ++ else ++ EXIT2(return NDIS_STATUS_SUCCESS); ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisWriteEventLogEntry,7) ++ (void *handle, NDIS_STATUS code, ULONG value, USHORT n, ++ void *strings, ULONG datasize, void *data) ++{ ++ TRACE1("0x%x, 0x%x, %u, %u", code, value, n, datasize); ++ return NDIS_STATUS_SUCCESS; ++} ++ ++wstdcall void *WIN_FUNC(NdisGetRoutineAddress,1) ++ (struct unicode_string *unicode_string) ++{ ++ struct ansi_string ansi_string; ++ void *address; ++ ++ if (RtlUnicodeStringToAnsiString(&ansi_string, unicode_string, TRUE) != ++ STATUS_SUCCESS) ++ EXIT1(return NULL); ++ INFO("%s", ansi_string.buf); ++ address = ndis_get_routine_address(ansi_string.buf); ++ RtlFreeAnsiString(&ansi_string); ++ return address; ++} ++ ++wstdcall ULONG WIN_FUNC(NdisReadPcmciaAttributeMemory,4) ++ (struct ndis_mp_block *nmb, ULONG offset, void *buffer, ++ ULONG length) ++{ ++ TODO(); ++ return 0; ++} ++ ++wstdcall ULONG WIN_FUNC(NdisWritePcmciaAttributeMemory,4) ++ (struct ndis_mp_block *nmb, ULONG offset, void *buffer, ++ ULONG length) ++{ ++ TODO(); ++ return 0; ++} ++ ++wstdcall void WIN_FUNC(NdisMCoIndicateReceivePacket,3) ++ (struct ndis_mp_block *nmb, struct ndis_packet **packets, ++ UINT nr_packets) ++{ ++ ENTER3("nmb = %p", nmb); ++ NdisMIndicateReceivePacket(nmb, packets, nr_packets); ++ EXIT3(return); ++} ++ ++wstdcall void WIN_FUNC(NdisMCoSendComplete,3) ++ (NDIS_STATUS status, struct ndis_mp_block *nmb, ++ struct ndis_packet *packet) ++{ ++ ENTER3("%08x", status); ++ NdisMSendComplete(nmb, packet, status); ++ EXIT3(return); ++} ++ ++wstdcall void WIN_FUNC(NdisMCoRequestComplete,3) ++ (NDIS_STATUS status, struct ndis_mp_block *nmb, ++ struct ndis_request *ndis_request) ++{ ++ struct ndis_device *wnd = nmb->wnd; ++ typeof(wnd->ndis_req_task) task; ++ ++ ENTER3("%08X", status); ++ wnd->ndis_req_status = status; ++ wnd->ndis_req_done = 1; ++ if ((task = xchg(&wnd->ndis_req_task, NULL))) ++ wake_up_process(task); ++ else ++ WARNING("invalid task"); ++ EXIT3(return); ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisIMNotifiyPnPEvent,2) ++ (struct ndis_mp_block *nmb, struct net_pnp_event *event) ++{ ++ ENTER2("%p, %d", nmb, event->code); ++ /* NdisWrapper never calls protocol's pnp event notifier, so ++ * nothing to do here */ ++ EXIT2(return NDIS_STATUS_SUCCESS); ++} ++ ++wstdcall void WIN_FUNC(NdisCompletePnPEvent,3) ++ (NDIS_STATUS status, void *handle, struct net_pnp_event *event) ++{ ++ ENTER2("%d, %p, %d", status, handle, event->code); ++ /* NdisWrapper never calls protocol's pnp event notifier, so ++ * nothing to do here */ ++ EXIT2(return); ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMSetMiniportSecondary,2) ++ (struct ndis_mp_block *nmb2, struct ndis_mp_block *nmb1) ++{ ++ ENTER3("%p, %p", nmb1, nmb2); ++ TODO(); ++ EXIT3(return NDIS_STATUS_SUCCESS); ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMPromoteMiniport,1) ++ (struct ndis_mp_block *nmb) ++{ ++ ENTER3("%p", nmb); ++ TODO(); ++ EXIT3(return NDIS_STATUS_SUCCESS); ++} ++ ++wstdcall void WIN_FUNC(NdisMCoActivateVcComplete,3) ++ (NDIS_STATUS status, void *handle, void *params) ++{ ++ TODO(); ++} ++ ++wstdcall void WIN_FUNC(NdisMCoDeactivateVcComplete,2) ++ (NDIS_STATUS status, void *handle) ++{ ++ TODO(); ++} ++ ++wstdcall void WIN_FUNC(NdisMRemoveMiniport,1) ++ (void *handle) ++{ ++ TODO(); ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMOpenLog,3) ++ (struct ndis_device *wnd, UINT size, void *handle) ++{ ++ if (size >= sizeof(int)) ++ *((int *)handle) = 42; ++ return NDIS_STATUS_SUCCESS; ++} ++ ++wstdcall NDIS_STATUS WIN_FUNC(NdisMWriteLogData,3) ++ (void *handle, char *buffer, UINT buffer_size) ++{ ++ TODO(); ++ return NDIS_STATUS_SUCCESS; ++} ++ ++wstdcall void WIN_FUNC(NdisMFlushLog,1) ++ (void *handle) ++{ ++ TODO(); ++} ++ ++wstdcall void WIN_FUNC(NdisMCloseLog,1) ++ (void *handle) ++{ ++ TODO(); ++} ++ ++static void *ndis_get_routine_address(char *name) ++{ ++ int i; ++ ENTER2("%p", name); ++ for (i = 0; i < ARRAY_SIZE(ndis_exports); i++) { ++ if (strcmp(name, ndis_exports[i].name) == 0) { ++ TRACE2("%p", ndis_exports[i].func); ++ return ndis_exports[i].func; ++ } ++ } ++ EXIT2(return NULL); ++} ++ ++/* ndis_init_device is called for each device */ ++int ndis_init_device(struct ndis_device *wnd) ++{ ++ struct ndis_mp_block *nmb = wnd->nmb; ++ ++ KeInitializeSpinLock(&nmb->lock); ++ wnd->mp_interrupt = NULL; ++ wnd->wrap_timer_slist.next = NULL; ++ if (wnd->wd->driver->ndis_driver) ++ wnd->wd->driver->ndis_driver->mp.shutdown = NULL; ++ ++ nmb->filterdbs.eth_db = nmb; ++ nmb->filterdbs.tr_db = nmb; ++ nmb->filterdbs.fddi_db = nmb; ++ nmb->filterdbs.arc_db = nmb; ++ ++ nmb->rx_packet = WIN_FUNC_PTR(NdisMIndicateReceivePacket,3); ++ nmb->send_complete = WIN_FUNC_PTR(NdisMSendComplete,3); ++ nmb->send_resource_avail = WIN_FUNC_PTR(NdisMSendResourcesAvailable,1); ++ nmb->status = WIN_FUNC_PTR(NdisMIndicateStatus,4); ++ nmb->status_complete = WIN_FUNC_PTR(NdisMIndicateStatusComplete,1); ++ nmb->queryinfo_complete = WIN_FUNC_PTR(NdisMQueryInformationComplete,2); ++ nmb->setinfo_complete = WIN_FUNC_PTR(NdisMSetInformationComplete,2); ++ nmb->reset_complete = WIN_FUNC_PTR(NdisMResetComplete,3); ++ nmb->eth_rx_indicate = WIN_FUNC_PTR(EthRxIndicateHandler,8); ++ nmb->eth_rx_complete = WIN_FUNC_PTR(EthRxComplete,1); ++ nmb->td_complete = WIN_FUNC_PTR(NdisMTransferDataComplete,4); ++ return 0; ++} ++ ++/* ndis_exit_device is called for each device */ ++void ndis_exit_device(struct ndis_device *wnd) ++{ ++ struct wrap_device_setting *setting; ++ ENTER2("%p", wnd); ++ mutex_lock(&loader_mutex); ++ nt_list_for_each_entry(setting, &wnd->wd->settings, list) { ++ struct ndis_configuration_parameter *param; ++ param = setting->encoded; ++ if (param) { ++ if (param->type == NdisParameterString) ++ RtlFreeUnicodeString(¶m->data.string); ++ ExFreePool(param); ++ setting->encoded = NULL; ++ } ++ } ++ mutex_unlock(&loader_mutex); ++} ++ ++/* ndis_init is called once when module is loaded */ ++int ndis_init(void) ++{ ++ InitializeListHead(&ndis_work_list); ++ spin_lock_init(&ndis_work_list_lock); ++ INIT_WORK(&ndis_work, ndis_worker); ++ ++ ndis_wq = create_singlethread_workqueue("ndis_wq"); ++ if (!ndis_wq) { ++ WARNING("couldn't create worker thread"); ++ EXIT1(return -ENOMEM); ++ } ++ ++ TRACE1("ndis_wq: %p", ndis_wq); ++ return 0; ++} ++ ++/* ndis_exit is called once when module is removed */ ++void ndis_exit(void) ++{ ++ ENTER1(""); ++ if (ndis_wq) ++ destroy_workqueue(ndis_wq); ++ EXIT1(return); ++} +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/ndis.h linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/ndis.h +--- linux-3.12.2/3rdparty/ndiswrapper/ndis.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/ndis.h 2013-11-28 21:42:11.000000000 +0200 +@@ -0,0 +1,1309 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * 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 _NDIS_H_ ++#define _NDIS_H_ ++ ++#include "ntoskernel.h" ++ ++//#define ALLOW_POOL_OVERFLOW 1 ++ ++#define NDIS_DMA_24BITS 0 ++#define NDIS_DMA_32BITS 1 ++#define NDIS_DMA_64BITS 2 ++ ++#ifdef CONFIG_X86_64 ++#define MAXIMUM_PROCESSORS 64 ++#else ++#define MAXIMUM_PROCESSORS 32 ++#endif ++ ++typedef UINT NDIS_STATUS; ++typedef UCHAR NDIS_DMA_SIZE; ++typedef LONG ndis_rssi; ++typedef ULONG ndis_key_index; ++typedef ULONG ndis_tx_power_level; ++typedef ULONGULONG ndis_key_rsc; ++typedef UCHAR mac_address[ETH_ALEN]; ++typedef ULONG ndis_fragmentation_threshold; ++typedef ULONG ndis_rts_threshold; ++typedef ULONG ndis_antenna; ++typedef ULONG ndis_oid; ++ ++typedef uint64_t NDIS_PHY_ADDRESS; ++ ++struct ndis_sg_element { ++ PHYSICAL_ADDRESS address; ++ ULONG length; ++ ULONG_PTR reserved; ++}; ++ ++struct ndis_sg_list { ++ ULONG nent; ++ ULONG_PTR reserved; ++ struct ndis_sg_element elements[]; ++}; ++ ++/* when sending packets, ndiswrapper associates exactly one sg element ++ * in sg list */ ++struct wrap_tx_sg_list { ++ ULONG nent; ++ ULONG_PTR reserved; ++ struct ndis_sg_element elements[1]; ++}; ++ ++struct ndis_phy_addr_unit { ++ NDIS_PHY_ADDRESS phy_addr; ++ UINT length; ++}; ++ ++typedef struct mdl ndis_buffer; ++ ++struct ndis_buffer_pool { ++ ndis_buffer *free_descr; ++// NT_SPIN_LOCK lock; ++ spinlock_t lock; ++ UINT max_descr; ++ UINT num_allocated_descr; ++}; ++ ++#define NDIS_PROTOCOL_ID_DEFAULT 0x00 ++#define NDIS_PROTOCOL_ID_TCP_IP 0x02 ++#define NDIS_PROTOCOL_ID_IPX 0x06 ++#define NDIS_PROTOCOL_ID_NBF 0x07 ++#define NDIS_PROTOCOL_ID_MAX 0x0F ++#define NDIS_PROTOCOL_ID_MASK 0x0F ++ ++#define fPACKET_WRAPPER_RESERVED 0x3F ++#define fPACKET_CONTAINS_MEDIA_SPECIFIC_INFO 0x40 ++#define fPACKET_ALLOCATED_BY_NDIS 0x80 ++ ++#define PROTOCOL_RESERVED_SIZE_IN_PACKET (4 * sizeof(void *)) ++ ++struct transport_header_offset { ++ USHORT protocol_type; ++ USHORT header_offset; ++}; ++ ++struct ndis_network_address { ++ USHORT length; ++ USHORT type; ++ UCHAR address[1]; ++}; ++ ++struct ndis_network_address_list { ++ LONG count; ++ USHORT type; ++ struct ndis_network_address address[1]; ++}; ++ ++struct ndis_tcp_ip_checksum_packet_info { ++ union { ++ struct { ++ ULONG v4:1; ++ ULONG v6:1; ++ ULONG tcp:1; ++ ULONG udp:1; ++ ULONG ip:1; ++ } tx; ++ struct { ++ ULONG tcp_failed:1; ++ ULONG udp_failed:1; ++ ULONG ip_failed:1; ++ ULONG tcp_succeeded:1; ++ ULONG udp_succeeded:1; ++ ULONG ip_succeeded:1; ++ ULONG loopback:1; ++ } rx; ++ ULONG value; ++ }; ++}; ++ ++enum ndis_task { ++ TcpIpChecksumNdisTask, IpSecNdisTask, TcpLargeSendNdisTask, MaxNdisTask ++}; ++ ++enum ndis_encapsulation { ++ UNSPECIFIED_Encapsulation, NULL_Encapsulation, ++ IEEE_802_3_Encapsulation, IEEE_802_5_Encapsulation, ++ LLC_SNAP_ROUTED_Encapsulation, LLC_SNAP_BRIDGED_Encapsulation ++}; ++ ++#define NDIS_TASK_OFFLOAD_VERSION 1 ++ ++struct ndis_encapsulation_format { ++ enum ndis_encapsulation encap; ++ struct { ++ ULONG fixed_header_size:1; ++ ULONG reserved:31; ++ } flags; ++ ULONG header_size; ++}; ++ ++struct ndis_task_offload_header { ++ ULONG version; ++ ULONG size; ++ ULONG reserved; ++ ULONG offset_first_task; ++ struct ndis_encapsulation_format encap_format; ++}; ++ ++struct ndis_task_offload { ++ ULONG version; ++ ULONG size; ++ enum ndis_task task; ++ ULONG offset_next_task; ++ ULONG task_buf_length; ++ UCHAR task_buf[1]; ++}; ++ ++struct v4_checksum { ++ union { ++ struct { ++ ULONG ip_opts:1; ++ ULONG tcp_opts:1; ++ ULONG tcp_csum:1; ++ ULONG udp_csum:1; ++ ULONG ip_csum:1; ++ }; ++ ULONG value; ++ }; ++}; ++ ++struct v6_checksum { ++ ULONG ip_supported:1; ++ ULONG tcp_supported:1; ++ ULONG tcp_csum:1; ++ ULONG udp_csum:1; ++}; ++ ++struct ndis_task_tcp_ip_checksum { ++ struct v4_checksum v4_tx; ++ struct v4_checksum v4_rx; ++ struct v6_checksum v6_tx; ++ struct v6_checksum v6_rx; ++}; ++ ++struct ndis_task_tcp_large_send { ++ ULONG version; ++ ULONG max_size; ++ ULONG min_seg_count; ++ BOOLEAN tcp_opts; ++ BOOLEAN ip_opts; ++}; ++ ++struct ndis_packet; ++ ++struct ndis_packet_pool { ++ struct ndis_packet *free_descr; ++// NT_SPIN_LOCK lock; ++ spinlock_t lock; ++ UINT max_descr; ++ UINT num_allocated_descr; ++ UINT num_used_descr; ++ UINT proto_rsvd_length; ++}; ++ ++struct ndis_packet_stack { ++ ULONG_PTR IM_reserved[2]; ++ ULONG_PTR ndis_reserved[4]; ++}; ++ ++enum ndis_per_packet_info { ++ TcpIpChecksumPacketInfo, IpSecPacketInfo, TcpLargeSendPacketInfo, ++ ClassificationHandlePacketInfo, NdisReserved, ++ ScatterGatherListPacketInfo, Ieee8021QInfo, OriginalPacketInfo, ++ PacketCancelId, MaxPerPacketInfo ++}; ++ ++struct ndis_packet_extension { ++ void *info[MaxPerPacketInfo]; ++}; ++ ++struct ndis_packet_private { ++ UINT nr_pages; ++ UINT len; ++ ndis_buffer *buffer_head; ++ ndis_buffer *buffer_tail; ++ struct ndis_packet_pool *pool; ++ UINT count; ++ ULONG flags; ++ BOOLEAN valid_counts; ++ UCHAR packet_flags; ++ USHORT oob_offset; ++}; ++ ++struct ndis_packet { ++ struct ndis_packet_private private; ++ /* for use by miniport */ ++ union { ++ /* for connectionless mininports */ ++ struct { ++ UCHAR miniport_reserved[2 * sizeof(void *)]; ++ UCHAR wrapper_reserved[2 * sizeof(void *)]; ++ } cl_reserved; ++ /* for deserialized miniports */ ++ struct { ++ UCHAR miniport_reserved_ex[3 * sizeof(void *)]; ++ UCHAR wrapper_reserved_ex[sizeof(void *)]; ++ } deserialized_reserved; ++ struct { ++ UCHAR mac_reserved[4 * sizeof(void *)]; ++ } mac_reserved; ++ }; ++ ULONG_PTR reserved[2]; ++ UCHAR protocol_reserved[1]; ++}; ++ ++/* OOB data */ ++struct ndis_packet_oob_data { ++ union { ++ ULONGLONG time_to_tx; ++ ULONGLONG time_txed; ++ }; ++ ULONGLONG time_rxed; ++ UINT header_size; ++ UINT media_size; ++ void *media; ++ NDIS_STATUS status; ++ ++ /* ndiswrapper specific info; extension should be right after ++ * ndis's oob_data */ ++ struct ndis_packet_extension ext; ++ union { ++ /* used for tx only */ ++ struct { ++ struct sk_buff *tx_skb; ++ union { ++ struct wrap_tx_sg_list wrap_tx_sg_list; ++ struct ndis_sg_list *tx_sg_list; ++ }; ++ }; ++ /* used for rx only */ ++ struct { ++ unsigned char header[ETH_HLEN]; ++ unsigned char *look_ahead; ++ UINT look_ahead_size; ++ }; ++ }; ++}; ++ ++#define NDIS_PACKET_OOB_DATA(packet) \ ++ (struct ndis_packet_oob_data *)(((void *)(packet)) + \ ++ (packet)->private.oob_offset) ++ ++enum ndis_device_pnp_event { ++ NdisDevicePnPEventQueryRemoved, NdisDevicePnPEventRemoved, ++ NdisDevicePnPEventSurpriseRemoved, NdisDevicePnPEventQueryStopped, ++ NdisDevicePnPEventStopped, NdisDevicePnPEventPowerProfileChanged, ++ NdisDevicePnPEventMaximum ++}; ++ ++enum ndis_request_type { ++ NdisRequestQueryInformation, NdisRequestSetInformation, ++ NdisRequestQueryStatistics, NdisRequestOpen, NdisRequestClose, ++ NdisRequestSend, NdisRequestTransferData, NdisRequestReset, ++ NdisRequestGeneric1, NdisRequestGeneric2, NdisRequestGeneric3, ++ NdisRequestGeneric4 ++}; ++ ++struct ndis_request { ++ mac_address mac; ++ enum ndis_request_type request_type; ++ union data { ++ struct query_info { ++ UINT oid; ++ void *buf; ++ UINT buf_len; ++ UINT written; ++ UINT needed; ++ } query_info; ++ struct set_info { ++ UINT oid; ++ void *buf; ++ UINT buf_len; ++ UINT written; ++ UINT needed; ++ } set_info; ++ } data; ++}; ++ ++enum ndis_medium { ++ NdisMedium802_3, NdisMedium802_5, NdisMediumFddi, NdisMediumWan, ++ NdisMediumLocalTalk, NdisMediumDix, NdisMediumArcnetRaw, ++ NdisMediumArcnet878_2, NdisMediumAtm, NdisMediumWirelessWan, ++ NdisMediumIrda, NdisMediumBpc, NdisMediumCoWan, ++ NdisMedium1394, NdisMediumMax ++}; ++ ++enum ndis_physical_medium { ++ NdisPhysicalMediumUnspecified, NdisPhysicalMediumWirelessLan, ++ NdisPhysicalMediumCableModem, NdisPhysicalMediumPhoneLine, ++ NdisPhysicalMediumPowerLine, NdisPhysicalMediumDSL, ++ NdisPhysicalMediumFibreChannel, NdisPhysicalMedium1394, ++ NdisPhysicalMediumWirelessWan, NdisPhysicalMediumMax ++}; ++ ++enum ndis_power_state { ++ NdisDeviceStateUnspecified = 0, ++ NdisDeviceStateD0, NdisDeviceStateD1, NdisDeviceStateD2, ++ NdisDeviceStateD3, NdisDeviceStateMaximum ++}; ++ ++enum ndis_power_profile { ++ NdisPowerProfileBattery, NdisPowerProfileAcOnLine ++}; ++ ++struct ndis_pm_wakeup_capabilities { ++ enum ndis_power_state min_magic_packet_wakeup; ++ enum ndis_power_state min_pattern_wakeup; ++ enum ndis_power_state min_link_change_wakeup; ++}; ++ ++#define NDIS_PNP_WAKE_UP_MAGIC_PACKET 0x00000001 ++#define NDIS_PNP_WAKE_UP_PATTERN_MATCH 0x00000002 ++#define NDIS_PNP_WAKE_UP_LINK_CHANGE 0x00000004 ++ ++enum net_pnp_event_code { ++ NetEventSetPower, NetEventQueryPower, NetEventQueryRemoveDevice, ++ NetEventCancelRemoveDevice, NetEventReconfigure, NetEventBindList, ++ NetEventBindsComplete, NetEventPnPCapabilities, NetEventMaximum ++}; ++ ++struct net_pnp_event { ++ enum net_pnp_event_code code; ++ void *buf; ++ ULONG buf_length; ++ ULONG_PTR ndis_reserved[4]; ++ ULONG_PTR transport_reserved[4]; ++ ULONG_PTR tdi_reserved[4]; ++ ULONG_PTR tdi_client_reserved[4]; ++}; ++ ++struct ndis_pnp_capabilities { ++ ULONG flags; ++ struct ndis_pm_wakeup_capabilities wakeup; ++}; ++ ++typedef void (*ndis_isr_handler)(BOOLEAN *recognized, BOOLEAN *queue_handler, ++ void *handle) wstdcall; ++typedef void (*ndis_interrupt_handler)(void *ctx) wstdcall; ++ ++struct miniport { ++ /* NDIS 3.0 */ ++ UCHAR major_version; ++ UCHAR minor_version; ++ USHORT filler; ++ UINT reserved; ++ BOOLEAN (*hangcheck)(void *ctx) wstdcall; ++ void (*disable_interrupt)(void *ctx) wstdcall; ++ void (*enable_interrupt)(void *ctx) wstdcall; ++ void (*mp_halt)(void *ctx) wstdcall; ++ ndis_interrupt_handler handle_interrupt; ++ NDIS_STATUS (*init)(NDIS_STATUS *error_status, UINT *medium_index, ++ enum ndis_medium medium[], UINT medium_array_size, ++ void *handle, void *conf_handle) wstdcall; ++ ndis_isr_handler isr; ++ NDIS_STATUS (*queryinfo)(void *ctx, ndis_oid oid, void *buffer, ++ ULONG buflen, ULONG *written, ++ ULONG *needed) wstdcall; ++ void *reconfig; ++ NDIS_STATUS (*reset)(BOOLEAN *reset_address, void *ctx) wstdcall; ++ NDIS_STATUS (*send)(void *ctx, struct ndis_packet *packet, ++ UINT flags) wstdcall; ++ NDIS_STATUS (*setinfo)(void *ctx, ndis_oid oid, void *buffer, ++ ULONG buflen, ULONG *written, ++ ULONG *needed) wstdcall; ++ NDIS_STATUS (*tx_data)(struct ndis_packet *ndis_packet, ++ UINT *bytes_txed, void *mp_ctx, void *rx_ctx, ++ UINT offset, UINT bytes_to_tx) wstdcall; ++ /* NDIS 4.0 extensions */ ++ void (*return_packet)(void *ctx, void *packet) wstdcall; ++ void (*send_packets)(void *ctx, struct ndis_packet **packets, ++ INT nr_of_packets) wstdcall; ++ void (*alloc_complete)(void *handle, void *virt, ++ NDIS_PHY_ADDRESS *phys, ++ ULONG size, void *ctx) wstdcall; ++ /* NDIS 5.0 extensions */ ++ NDIS_STATUS (*co_create_vc)(void *ctx, void *vc_handle, ++ void *vc_ctx) wstdcall; ++ NDIS_STATUS (*co_delete_vc)(void *vc_ctx) wstdcall; ++ NDIS_STATUS (*co_activate_vc)(void *vc_ctx, void *call_params) wstdcall; ++ NDIS_STATUS (*co_deactivate_vc)(void *vc_ctx) wstdcall; ++ NDIS_STATUS (*co_send_packets)(void *vc_ctx, void **packets, ++ UINT nr_of_packets) wstdcall; ++ NDIS_STATUS (*co_request)(void *ctx, void *vc_ctx, UINT *req) wstdcall; ++ /* NDIS 5.1 extensions */ ++ void (*cancel_send_packets)(void *ctx, void *id) wstdcall; ++ void (*pnp_event_notify)(void *ctx, enum ndis_device_pnp_event event, ++ void *inf_buf, ULONG inf_buf_len) wstdcall; ++ void (*shutdown)(void *ctx) wstdcall; ++ void *reserved1; ++ void *reserved2; ++ void *reserved3; ++ void *reserved4; ++}; ++ ++struct ndis_spinlock { ++ NT_SPIN_LOCK klock; ++ KIRQL irql; ++}; ++ ++union ndis_rw_lock_refcount { ++ UCHAR cache_line[16]; ++}; ++ ++struct ndis_rw_lock { ++ union { ++ struct { ++ NT_SPIN_LOCK klock; ++ void *context; ++ }; ++ UCHAR reserved[16]; ++ }; ++ union { ++ union ndis_rw_lock_refcount ref_count[MAXIMUM_PROCESSORS]; ++ /* ndiswrapper specific */ ++ volatile int count; ++ }; ++}; ++ ++struct lock_state { ++ USHORT state; ++ KIRQL irql; ++}; ++ ++struct ndis_work_item; ++typedef void (*NDIS_PROC)(struct ndis_work_item *, void *) wstdcall; ++ ++struct ndis_work_item { ++ void *ctx; ++ NDIS_PROC func; ++ union { ++ UCHAR reserved[8 * sizeof(void *)]; ++ /* ndiswrapper specific */ ++ struct nt_list list; ++ }; ++}; ++ ++struct alloc_shared_mem { ++ void *ctx; ++ ULONG size; ++ BOOLEAN cached; ++}; ++ ++struct ndis_mp_block; ++ ++/* this is opaque to drivers, so we can use it as we please */ ++struct ndis_mp_interrupt { ++ struct kinterrupt *kinterrupt; ++ NT_SPIN_LOCK lock; ++ union { ++ void *reserved; ++ unsigned int irq; ++ }; ++ ndis_isr_handler isr; ++ ndis_interrupt_handler mp_dpc; ++ struct kdpc intr_dpc; ++ struct ndis_mp_block *nmb; ++ UCHAR dpc_count; ++ BOOLEAN enable; ++ struct nt_event dpc_completed_event; ++ BOOLEAN shared; ++ BOOLEAN req_isr; ++}; ++ ++struct ndis_binary_data { ++ USHORT len; ++ void *buf; ++}; ++ ++enum ndis_parameter_type { ++ NdisParameterInteger, NdisParameterHexInteger, ++ NdisParameterString, NdisParameterMultiString, NdisParameterBinary, ++}; ++ ++typedef struct unicode_string NDIS_STRING; ++ ++struct ndis_configuration_parameter { ++ enum ndis_parameter_type type; ++ union { ++ ULONG integer; ++ NDIS_STRING string; ++ } data; ++}; ++ ++struct ndis_driver { ++ struct miniport mp; ++}; ++ ++/* IDs used to store extensions in driver_object's custom extension */ ++#define NDIS_DRIVER_CLIENT_ID 10 ++ ++struct ndis_wireless_stats { ++ ULONG length; ++ LARGE_INTEGER tx_frag; ++ LARGE_INTEGER tx_multi_frag; ++ LARGE_INTEGER failed; ++ LARGE_INTEGER retry; ++ LARGE_INTEGER multi_retry; ++ LARGE_INTEGER rtss_succ; ++ LARGE_INTEGER rtss_fail; ++ LARGE_INTEGER ack_fail; ++ LARGE_INTEGER frame_dup; ++ LARGE_INTEGER rx_frag; ++ LARGE_INTEGER rx_multi_frag; ++ LARGE_INTEGER fcs_err; ++ LARGE_INTEGER tkip_local_mic_failures; ++ LARGE_INTEGER tkip_icv_errors; ++ LARGE_INTEGER tkip_counter_measures_invoked; ++ LARGE_INTEGER tkip_replays; ++ LARGE_INTEGER ccmp_format_errors; ++ LARGE_INTEGER ccmp_replays; ++ LARGE_INTEGER ccmp_decrypt_errors; ++ LARGE_INTEGER fourway_handshake_failures; ++ LARGE_INTEGER wep_undecryptable_count; ++ LARGE_INTEGER wep_icv_errorcount; ++ LARGE_INTEGER decrypt_success_count; ++ LARGE_INTEGER decrypt_failure_count; ++}; ++ ++enum ndis_status_type { ++ Ndis802_11StatusType_Authentication, ++ Ndis802_11StatusType_MediaStreamMode, ++ Ndis802_11StatusType_PMKID_CandidateList, ++ Ndis802_11StatusType_RadioState, ++}; ++ ++struct ndis_status_indication { ++ enum ndis_status_type status_type; ++}; ++ ++enum ndis_radio_status { ++ Ndis802_11RadioStatusOn, Ndis802_11RadioStatusHardwareOff, ++ Ndis802_11RadioStatusSoftwareOff, ++}; ++ ++struct ndis_radio_status_indication ++{ ++ enum ndis_status_type status_type; ++ enum ndis_radio_status radio_state; ++}; ++ ++enum ndis_media_state { ++ NdisMediaStateConnected, ++ NdisMediaStateDisconnected, ++}; ++ ++enum ndis_media_stream_mode { ++ Ndis802_11MediaStreamOff, Ndis802_11MediaStreamOn ++}; ++ ++enum wrapper_work { ++ LINK_STATUS_OFF, LINK_STATUS_ON, SET_MULTICAST_LIST, COLLECT_IW_STATS, ++ HANGCHECK, NETIF_WAKEQ, ++}; ++ ++struct encr_info { ++ struct encr_key { ++ ULONG length; ++ UCHAR key[NDIS_ENCODING_TOKEN_MAX]; ++ } keys[MAX_ENCR_KEYS]; ++ unsigned short tx_key_index; ++}; ++ ++struct ndis_essid { ++ ULONG length; ++ UCHAR essid[NDIS_ESSID_MAX_SIZE]; ++}; ++ ++enum ndis_infrastructure_mode { ++ Ndis802_11IBSS, Ndis802_11Infrastructure, Ndis802_11AutoUnknown, ++ Ndis802_11InfrastructureMax ++}; ++ ++enum authentication_mode { ++ Ndis802_11AuthModeOpen, Ndis802_11AuthModeShared, ++ Ndis802_11AuthModeAutoSwitch, Ndis802_11AuthModeWPA, ++ Ndis802_11AuthModeWPAPSK, Ndis802_11AuthModeWPANone, ++ Ndis802_11AuthModeWPA2, Ndis802_11AuthModeWPA2PSK, ++ Ndis802_11AuthModeMax ++}; ++ ++enum encryption_status { ++ Ndis802_11WEPEnabled, ++ Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled, ++ Ndis802_11WEPDisabled, ++ Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled, ++ Ndis802_11WEPKeyAbsent, ++ Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent, ++ Ndis802_11WEPNotSupported, ++ Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported, ++ Ndis802_11Encryption2Enabled, Ndis802_11Encryption2KeyAbsent, ++ Ndis802_11Encryption3Enabled, Ndis802_11Encryption3KeyAbsent ++}; ++ ++struct ndis_auth_encr_pair { ++ enum authentication_mode auth_mode; ++ enum encryption_status encr_mode; ++}; ++ ++struct ndis_capability { ++ ULONG length; ++ ULONG version; ++ ULONG num_PMKIDs; ++ ULONG num_auth_encr_pair; ++ struct ndis_auth_encr_pair auth_encr_pair[1]; ++}; ++ ++struct ndis_guid { ++ struct guid guid; ++ union { ++ ndis_oid oid; ++ NDIS_STATUS status; ++ }; ++ ULONG size; ++ ULONG flags; ++}; ++ ++struct ndis_timer { ++ struct nt_timer nt_timer; ++ struct kdpc kdpc; ++}; ++ ++struct ndis_mp_timer { ++ struct nt_timer nt_timer; ++ struct kdpc kdpc; ++ DPC func; ++ void *ctx; ++ struct ndis_mp_block *nmb; ++ struct ndis_mp_timer *next; ++}; ++ ++typedef struct cm_partial_resource_list NDIS_RESOURCE_LIST; ++ ++struct ndis_event { ++ struct nt_event nt_event; ++}; ++ ++struct ndis_bind_paths { ++ UINT number; ++ struct unicode_string paths[1]; ++}; ++ ++struct ndis_reference { ++ NT_SPIN_LOCK lock; ++ USHORT ref_count; ++ BOOLEAN closing; ++}; ++ ++struct ndis_filterdbs { ++ union { ++ void *eth_db; ++ void *null_db; ++ }; ++ void *tr_db; ++ void *fddi_db; ++ void *arc_db; ++}; ++ ++enum ndis_interface_type { ++ NdisInterfaceInternal, NdisInterfaceIsa, NdisInterfaceEisa, ++ NdisInterfaceMca, NdisInterfaceTurboChannel, NdisInterfacePci, ++ NdisInterfacePcMcia, ++}; ++ ++struct auth_encr_capa { ++ unsigned long auth; ++ unsigned long encr; ++}; ++ ++struct ndis_pmkid_candidate { ++ mac_address bssid; ++ DWORD flags; ++}; ++ ++struct ndis_pmkid_candidate_list { ++ ULONG version; ++ ULONG num_candidates; ++ struct ndis_pmkid_candidate candidates[1]; ++}; ++ ++/* ++ * This struct contains function pointers that the drivers references ++ * directly via macros, so it's important that they are at the correct ++ * position. ++ */ ++struct ndis_mp_block { ++ void *signature; ++ struct ndis_mp_block *next; ++ struct driver_object *drv_obj; ++ void *mp_ctx; ++ struct unicode_string name; ++ struct ndis_bind_paths *bindpaths; ++ void *openqueue; ++ struct ndis_reference reference; ++ void *device_ctx; ++ UCHAR padding; ++ UCHAR lock_acquired; ++ UCHAR pmode_opens; ++ UCHAR assigned_cpu; ++ NT_SPIN_LOCK lock; ++ enum ndis_request_type *mediarequest; ++ struct ndis_mp_interrupt *interrupt; ++ ULONG flags; ++ ULONG pnp_flags; ++ struct nt_list packet_list; ++ struct ndis_packet *first_pending_tx_packet; ++ struct ndis_packet *return_packet_queue; ++ ULONG request_buffer; ++ void *set_mcast_buffer; ++ struct ndis_mp_block *primary_mp; ++ void *wrapper_ctx; ++ void *bus_data_ctx; ++ ULONG pnp_capa; ++ void *resources; ++ struct ndis_timer wakeup_dpc_timer; ++ struct unicode_string basename; ++ struct unicode_string symlink_name; ++ ULONG ndis_hangcheck_interval; ++ USHORT hangcheck_ticks; ++ USHORT hangcheck_tick; ++ NDIS_STATUS ndis_reset_status; ++ void *resetopen; ++ struct ndis_filterdbs filterdbs; ++ void *rx_packet; ++ void *send_complete; ++ void *send_resource_avail; ++ void *reset_complete; ++ ++ enum ndis_medium media_type; ++ ULONG bus_number; ++ enum ndis_interface_type bus_type; ++ enum ndis_interface_type adapter_type; ++ struct device_object *fdo; ++ struct device_object *pdo; ++ struct device_object *next_device; ++ void *mapreg; ++ void *call_mgraflist; ++ void *mp_thread; ++ void *setinfobuf; ++ USHORT setinfo_buf_len; ++ USHORT max_send_pkts; ++ NDIS_STATUS fake_status; ++ void *lock_handler; ++ struct unicode_string *adapter_instance_name; ++ void *timer_queue; ++ UINT mac_options; ++ void *pending_req; ++ UINT max_long_addrs; ++ UINT max_short_addrs; ++ UINT cur_lookahead; ++ UINT max_lookahead; ++ ++ ndis_interrupt_handler irq_bh; ++ void *disable_intr; ++ void *enable_intr; ++ void *send_pkts; ++ void *deferred_send; ++ void *eth_rx_indicate; ++ void *tr_rx_indicate; ++ void *fddi_rx_indicate; ++ void *eth_rx_complete; ++ void *tr_rx_complete; ++ void *fddi_rx_complete; ++ ++ void *status; ++ void *status_complete; ++ void *td_complete; ++ ++ void *queryinfo_complete; ++ void *setinfo_complete; ++ void *wan_tx_complete; ++ void *wan_rx; ++ void *wan_rx_complete; ++ /* ndiswrapper specific */ ++ struct ndis_device *wnd; ++}; ++ ++struct ndis_device { ++ struct ndis_mp_block *nmb; ++ struct wrap_device *wd; ++ struct net_device *net_dev; ++ void *shutdown_ctx; ++ struct ndis_mp_interrupt *mp_interrupt; ++ struct kdpc irq_kdpc; ++ unsigned long mem_start; ++ unsigned long mem_end; ++ ++ struct net_device_stats net_stats; ++ struct iw_statistics iw_stats; ++ BOOLEAN iw_stats_enabled; ++ struct ndis_wireless_stats ndis_stats; ++ ++ struct work_struct tx_work; ++ struct ndis_packet *tx_ring[TX_RING_SIZE]; ++ u8 tx_ring_start; ++ u8 tx_ring_end; ++ u8 is_tx_ring_full; ++ u8 tx_ok; ++ spinlock_t tx_ring_lock; ++ struct mutex tx_ring_mutex; ++ unsigned int max_tx_packets; ++ struct mutex ndis_req_mutex; ++ struct task_struct *ndis_req_task; ++ int ndis_req_done; ++ NDIS_STATUS ndis_req_status; ++ ULONG packet_filter; ++ ++ ULONG sg_dma_size; ++ ULONG dma_map_count; ++ dma_addr_t *dma_map_addr; ++ ++ int hangcheck_interval; ++ struct timer_list hangcheck_timer; ++ int iw_stats_interval; ++ struct timer_list iw_stats_timer; ++ unsigned long scan_timestamp; ++ struct encr_info encr_info; ++ char nick[IW_ESSID_MAX_SIZE + 1]; ++ struct ndis_essid essid; ++ struct auth_encr_capa capa; ++ enum ndis_infrastructure_mode infrastructure_mode; ++ int max_pmkids; ++ int num_pmkids; ++ struct ndis_pmkid *pmkids; ++ mac_address mac; ++ struct proc_dir_entry *procfs_iface; ++ ++ struct work_struct ndis_work; ++ unsigned long ndis_pending_work; ++ UINT attributes; ++ int iw_auth_wpa_version; ++ int iw_auth_cipher_pairwise; ++ int iw_auth_cipher_group; ++ int iw_auth_key_mgmt; ++ int iw_auth_80211_alg; ++ struct ndis_packet_pool *tx_packet_pool; ++ struct ndis_buffer_pool *tx_buffer_pool; ++ int multicast_size; ++ struct v4_checksum rx_csum; ++ struct v4_checksum tx_csum; ++ enum ndis_physical_medium physical_medium; ++ ULONG ndis_wolopts; ++ struct nt_slist wrap_timer_slist; ++ int drv_ndis_version; ++ struct ndis_pnp_capabilities pnp_capa; ++}; ++ ++BOOLEAN ndis_isr(struct kinterrupt *kinterrupt, void *ctx) wstdcall; ++ ++int ndis_init(void); ++void ndis_exit(void); ++int ndis_init_device(struct ndis_device *wnd); ++void ndis_exit_device(struct ndis_device *wnd); ++ ++int wrap_procfs_add_ndis_device(struct ndis_device *wnd); ++void wrap_procfs_remove_ndis_device(struct ndis_device *wnd); ++ ++void NdisAllocatePacketPoolEx(NDIS_STATUS *status, ++ struct ndis_packet_pool **pool_handle, ++ UINT num_descr, UINT overflowsize, ++ UINT proto_rsvd_length) wstdcall; ++void NdisFreePacketPool(struct ndis_packet_pool *pool) wstdcall; ++void NdisAllocatePacket(NDIS_STATUS *status, struct ndis_packet **packet, ++ struct ndis_packet_pool *pool) wstdcall; ++void NdisFreePacket(struct ndis_packet *descr) wstdcall; ++void NdisAllocateBufferPool(NDIS_STATUS *status, ++ struct ndis_buffer_pool **pool_handle, ++ UINT num_descr) wstdcall; ++void NdisFreeBufferPool(struct ndis_buffer_pool *pool) wstdcall; ++void NdisAllocateBuffer(NDIS_STATUS *status, ndis_buffer **buffer, ++ struct ndis_buffer_pool *pool, void *virt, ++ UINT length) wstdcall; ++void NdisFreeBuffer(ndis_buffer *descr) wstdcall; ++void NdisMIndicateReceivePacket(struct ndis_mp_block *nmb, ++ struct ndis_packet **packets, ++ UINT nr_packets) wstdcall; ++void NdisMSendComplete(struct ndis_mp_block *nmb, struct ndis_packet *packet, ++ NDIS_STATUS status) wstdcall; ++void NdisMSendResourcesAvailable(struct ndis_mp_block *nmb) wstdcall; ++void NdisMIndicateStatus(struct ndis_mp_block *nmb, ++ NDIS_STATUS status, void *buf, UINT len) wstdcall; ++void NdisMIndicateStatusComplete(struct ndis_mp_block *nmb) wstdcall; ++void NdisMQueryInformationComplete(struct ndis_mp_block *nmb, ++ NDIS_STATUS status) wstdcall; ++void NdisMSetInformationComplete(struct ndis_mp_block *nmb, ++ NDIS_STATUS status) wstdcall; ++void NdisMResetComplete(struct ndis_mp_block *nmb, NDIS_STATUS status, ++ BOOLEAN address_reset) wstdcall; ++ULONG NDIS_BUFFER_TO_SPAN_PAGES(ndis_buffer *buffer) wstdcall; ++BOOLEAN NdisWaitEvent(struct ndis_event *event, UINT timeout) wstdcall; ++void NdisSetEvent(struct ndis_event *event) wstdcall; ++void NdisMDeregisterInterrupt(struct ndis_mp_interrupt *mp_interrupt) wstdcall; ++void EthRxIndicateHandler(struct ndis_mp_block *nmb, void *rx_ctx, ++ char *header1, char *header, UINT header_size, ++ void *look_ahead, UINT look_ahead_size, ++ UINT packet_size) wstdcall; ++void EthRxComplete(struct ndis_mp_block *nmb) wstdcall; ++void NdisMTransferDataComplete(struct ndis_mp_block *nmb, ++ struct ndis_packet *packet, NDIS_STATUS status, ++ UINT bytes_txed) wstdcall; ++void NdisWriteConfiguration(NDIS_STATUS *status, struct ndis_mp_block *nmb, ++ struct unicode_string *key, ++ struct ndis_configuration_parameter *param) wstdcall; ++void NdisReadConfiguration(NDIS_STATUS *status, ++ struct ndis_configuration_parameter **param, ++ struct ndis_mp_block *nmb, ++ struct unicode_string *key, ++ enum ndis_parameter_type type) wstdcall; ++ ++/* Required OIDs */ ++#define OID_GEN_SUPPORTED_LIST 0x00010101 ++#define OID_GEN_HARDWARE_STATUS 0x00010102 ++#define OID_GEN_MEDIA_SUPPORTED 0x00010103 ++#define OID_GEN_MEDIA_IN_USE 0x00010104 ++#define OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105 ++#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106 ++#define OID_GEN_LINK_SPEED 0x00010107 ++#define OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108 ++#define OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109 ++#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A ++#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B ++#define OID_GEN_VENDOR_ID 0x0001010C ++#define OID_GEN_VENDOR_DESCRIPTION 0x0001010D ++#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E ++#define OID_GEN_CURRENT_LOOKAHEAD 0x0001010F ++#define OID_GEN_DRIVER_VERSION 0x00010110 ++#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111 ++#define OID_GEN_PROTOCOL_OPTIONS 0x00010112 ++#define OID_GEN_MAC_OPTIONS 0x00010113 ++#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114 ++#define OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115 ++#define OID_GEN_VENDOR_DRIVER_VERSION 0x00010116 ++#define OID_GEN_SUPPORTED_GUIDS 0x00010117 ++#define OID_GEN_NETWORK_LAYER_ADDRESSES 0x00010118 /* Set only */ ++#define OID_GEN_TRANSPORT_HEADER_OFFSET 0x00010119 /* Set only */ ++#define OID_GEN_MACHINE_NAME 0x0001021A ++#define OID_GEN_RNDIS_CONFIG_PARAMETER 0x0001021B /* Set only */ ++#define OID_GEN_VLAN_ID 0x0001021C ++ ++/* Optional OIDs. */ ++#define OID_GEN_MEDIA_CAPABILITIES 0x00010201 ++#define OID_GEN_PHYSICAL_MEDIUM 0x00010202 ++ ++/* Required statistics OIDs. */ ++#define OID_GEN_XMIT_OK 0x00020101 ++#define OID_GEN_RCV_OK 0x00020102 ++#define OID_GEN_XMIT_ERROR 0x00020103 ++#define OID_GEN_RCV_ERROR 0x00020104 ++#define OID_GEN_RCV_NO_BUFFER 0x00020105 ++ ++/* Optional OID statistics */ ++#define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201 ++#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202 ++#define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203 ++#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204 ++#define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205 ++#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206 ++#define OID_GEN_DIRECTED_BYTES_RCV 0x00020207 ++#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208 ++#define OID_GEN_MULTICAST_BYTES_RCV 0x00020209 ++#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A ++#define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B ++#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C ++#define OID_GEN_RCV_CRC_ERROR 0x0002020D ++#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E ++#define OID_GEN_GET_TIME_CAPS 0x0002020F ++#define OID_GEN_GET_NETCARD_TIME 0x00020210 ++#define OID_GEN_NETCARD_LOAD 0x00020211 ++#define OID_GEN_DEVICE_PROFILE 0x00020212 ++ ++/* 802.3 (ethernet) OIDs */ ++#define OID_802_3_PERMANENT_ADDRESS 0x01010101 ++#define OID_802_3_CURRENT_ADDRESS 0x01010102 ++#define OID_802_3_MULTICAST_LIST 0x01010103 ++#define OID_802_3_MAXIMUM_LIST_SIZE 0x01010104 ++#define OID_802_3_MAC_OPTIONS 0x01010105 ++#define NDIS_802_3_MAC_OPTION_PRIORITY 0x00000001 ++#define OID_802_3_RCV_ERROR_ALIGNMENT 0x01020101 ++#define OID_802_3_XMIT_ONE_COLLISION 0x01020102 ++#define OID_802_3_XMIT_MORE_COLLISIONS 0x01020103 ++#define OID_802_3_XMIT_DEFERRED 0x01020201 ++#define OID_802_3_XMIT_MAX_COLLISIONS 0x01020202 ++#define OID_802_3_RCV_OVERRUN 0x01020203 ++#define OID_802_3_XMIT_UNDERRUN 0x01020204 ++#define OID_802_3_XMIT_HEARTBEAT_FAILURE 0x01020205 ++#define OID_802_3_XMIT_TIMES_CRS_LOST 0x01020206 ++#define OID_802_3_XMIT_LATE_COLLISIONS 0x01020207 ++ ++/* PnP and power management OIDs */ ++#define OID_PNP_CAPABILITIES 0xFD010100 ++#define OID_PNP_SET_POWER 0xFD010101 ++#define OID_PNP_QUERY_POWER 0xFD010102 ++#define OID_PNP_ADD_WAKE_UP_PATTERN 0xFD010103 ++#define OID_PNP_REMOVE_WAKE_UP_PATTERN 0xFD010104 ++#define OID_PNP_WAKE_UP_PATTERN_LIST 0xFD010105 ++#define OID_PNP_ENABLE_WAKE_UP 0xFD010106 ++ ++/* PnP/PM Statistics (Optional). */ ++#define OID_PNP_WAKE_UP_OK 0xFD020200 ++#define OID_PNP_WAKE_UP_ERROR 0xFD020201 ++ ++/* The following bits are defined for OID_PNP_ENABLE_WAKE_UP */ ++#define NDIS_PNP_WAKE_UP_MAGIC_PACKET 0x00000001 ++#define NDIS_PNP_WAKE_UP_PATTERN_MATCH 0x00000002 ++#define NDIS_PNP_WAKE_UP_LINK_CHANGE 0x00000004 ++ ++/* 802.11 OIDs */ ++#define OID_802_11_BSSID 0x0D010101 ++#define OID_802_11_SSID 0x0D010102 ++#define OID_802_11_NETWORK_TYPES_SUPPORTED 0x0D010203 ++#define OID_802_11_NETWORK_TYPE_IN_USE 0x0D010204 ++#define OID_802_11_TX_POWER_LEVEL 0x0D010205 ++#define OID_802_11_RSSI 0x0D010206 ++#define OID_802_11_RSSI_TRIGGER 0x0D010207 ++#define OID_802_11_INFRASTRUCTURE_MODE 0x0D010108 ++#define OID_802_11_FRAGMENTATION_THRESHOLD 0x0D010209 ++#define OID_802_11_RTS_THRESHOLD 0x0D01020A ++#define OID_802_11_NUMBER_OF_ANTENNAS 0x0D01020B ++#define OID_802_11_RX_ANTENNA_SELECTED 0x0D01020C ++#define OID_802_11_TX_ANTENNA_SELECTED 0x0D01020D ++#define OID_802_11_SUPPORTED_RATES 0x0D01020E ++#define OID_802_11_DESIRED_RATES 0x0D010210 ++#define OID_802_11_CONFIGURATION 0x0D010211 ++#define OID_802_11_STATISTICS 0x0D020212 ++#define OID_802_11_ADD_WEP 0x0D010113 ++#define OID_802_11_REMOVE_WEP 0x0D010114 ++#define OID_802_11_DISASSOCIATE 0x0D010115 ++#define OID_802_11_POWER_MODE 0x0D010216 ++#define OID_802_11_BSSID_LIST 0x0D010217 ++#define OID_802_11_AUTHENTICATION_MODE 0x0D010118 ++#define OID_802_11_PRIVACY_FILTER 0x0D010119 ++#define OID_802_11_BSSID_LIST_SCAN 0x0D01011A ++#define OID_802_11_WEP_STATUS 0x0D01011B ++#define OID_802_11_ENCRYPTION_STATUS OID_802_11_WEP_STATUS ++#define OID_802_11_RELOAD_DEFAULTS 0x0D01011C ++#define OID_802_11_ADD_KEY 0x0D01011D ++#define OID_802_11_REMOVE_KEY 0x0D01011E ++#define OID_802_11_ASSOCIATION_INFORMATION 0x0D01011F ++#define OID_802_11_TEST 0x0D010120 ++#define OID_802_11_MEDIA_STREAM_MODE 0x0D010121 ++#define OID_802_11_CAPABILITY 0x0D010122 ++#define OID_802_11_PMKID 0x0D010123 ++ ++#define NDIS_STATUS_SUCCESS 0 ++#define NDIS_STATUS_PENDING 0x00000103 ++#define NDIS_STATUS_NOT_RECOGNIZED 0x00010001 ++#define NDIS_STATUS_NOT_COPIED 0x00010002 ++#define NDIS_STATUS_NOT_ACCEPTED 0x00010003 ++#define NDIS_STATUS_CALL_ACTIVE 0x00010007 ++#define NDIS_STATUS_ONLINE 0x40010003 ++#define NDIS_STATUS_RESET_START 0x40010004 ++#define NDIS_STATUS_RESET_END 0x40010005 ++#define NDIS_STATUS_RING_STATUS 0x40010006 ++#define NDIS_STATUS_CLOSED 0x40010007 ++#define NDIS_STATUS_WAN_LINE_UP 0x40010008 ++#define NDIS_STATUS_WAN_LINE_DOWN 0x40010009 ++#define NDIS_STATUS_WAN_FRAGMENT 0x4001000A ++#define NDIS_STATUS_MEDIA_CONNECT 0x4001000B ++#define NDIS_STATUS_MEDIA_DISCONNECT 0x4001000C ++#define NDIS_STATUS_HARDWARE_LINE_UP 0x4001000D ++#define NDIS_STATUS_HARDWARE_LINE_DOWN 0x4001000E ++#define NDIS_STATUS_INTERFACE_UP 0x4001000F ++#define NDIS_STATUS_INTERFACE_DOWN 0x40010010 ++#define NDIS_STATUS_MEDIA_BUSY 0x40010011 ++#define NDIS_STATUS_MEDIA_SPECIFIC_INDICATION 0x40010012 ++#define NDIS_STATUS_WW_INDICATION NDIS_STATUS_MEDIA_SPECIFIC_INDICATION ++#define NDIS_STATUS_LINK_SPEED_CHANGE 0x40010013 ++#define NDIS_STATUS_WAN_GET_STATS 0x40010014 ++#define NDIS_STATUS_WAN_CO_FRAGMENT 0x40010015 ++#define NDIS_STATUS_WAN_CO_LINKPARAMS 0x40010016 ++#define NDIS_STATUS_NOT_RESETTABLE 0x80010001 ++#define NDIS_STATUS_SOFT_ERRORS 0x80010003 ++#define NDIS_STATUS_HARD_ERRORS 0x80010004 ++#define NDIS_STATUS_BUFFER_OVERFLOW 0x80000005 ++#define NDIS_STATUS_FAILURE 0xC0000001 ++#define NDIS_STATUS_INVALID_PARAMETER 0xC000000D ++#define NDIS_STATUS_RESOURCES 0xC000009A ++#define NDIS_STATUS_CLOSING 0xC0010002 ++#define NDIS_STATUS_BAD_VERSION 0xC0010004 ++#define NDIS_STATUS_BAD_CHARACTERISTICS 0xC0010005 ++#define NDIS_STATUS_ADAPTER_NOT_FOUND 0xC0010006 ++#define NDIS_STATUS_OPEN_FAILED 0xC0010007 ++#define NDIS_STATUS_DEVICE_FAILED 0xC0010008 ++#define NDIS_STATUS_MULTICAST_FULL 0xC0010009 ++#define NDIS_STATUS_MULTICAST_EXISTS 0xC001000A ++#define NDIS_STATUS_MULTICAST_NOT_FOUND 0xC001000B ++#define NDIS_STATUS_REQUEST_ABORTED 0xC001000C ++#define NDIS_STATUS_RESET_IN_PROGRESS 0xC001000D ++#define NDIS_STATUS_CLOSING_INDICATING 0xC001000E ++#define NDIS_STATUS_BAD_VERSION 0xC0010004 ++#define NDIS_STATUS_NOT_SUPPORTED 0xC00000BB ++#define NDIS_STATUS_INVALID_PACKET 0xC001000F ++#define NDIS_STATUS_OPEN_LIST_FULL 0xC0010010 ++#define NDIS_STATUS_ADAPTER_NOT_READY 0xC0010011 ++#define NDIS_STATUS_ADAPTER_NOT_OPEN 0xC0010012 ++#define NDIS_STATUS_NOT_INDICATING 0xC0010013 ++#define NDIS_STATUS_INVALID_LENGTH 0xC0010014 ++#define NDIS_STATUS_INVALID_DATA 0xC0010015 ++#define NDIS_STATUS_BUFFER_TOO_SHORT 0xC0010016 ++#define NDIS_STATUS_INVALID_OID 0xC0010017 ++#define NDIS_STATUS_ADAPTER_REMOVED 0xC0010018 ++#define NDIS_STATUS_UNSUPPORTED_MEDIA 0xC0010019 ++#define NDIS_STATUS_GROUP_ADDRESS_IN_USE 0xC001001A ++#define NDIS_STATUS_FILE_NOT_FOUND 0xC001001B ++#define NDIS_STATUS_ERROR_READING_FILE 0xC001001C ++#define NDIS_STATUS_ALREADY_MAPPED 0xC001001D ++#define NDIS_STATUS_RESOURCE_CONFLICT 0xC001001E ++#define NDIS_STATUS_NO_CABLE 0xC001001F ++#define NDIS_STATUS_INVALID_SAP 0xC0010020 ++#define NDIS_STATUS_SAP_IN_USE 0xC0010021 ++#define NDIS_STATUS_INVALID_ADDRESS 0xC0010022 ++#define NDIS_STATUS_VC_NOT_ACTIVATED 0xC0010023 ++#define NDIS_STATUS_DEST_OUT_OF_ORDER 0xC0010024 ++#define NDIS_STATUS_VC_NOT_AVAILABLE 0xC0010025 ++#define NDIS_STATUS_CELLRATE_NOT_AVAILABLE 0xC0010026 ++#define NDIS_STATUS_INCOMPATABLE_QOS 0xC0010027 ++#define NDIS_STATUS_AAL_PARAMS_UNSUPPORTED 0xC0010028 ++#define NDIS_STATUS_NO_ROUTE_TO_DESTINATION 0xC0010029 ++#define NDIS_STATUS_TOKEN_RING_OPEN_ERROR 0xC0011000 ++#define NDIS_STATUS_INVALID_DEVICE_REQUEST 0xC0000010 ++#define NDIS_STATUS_NETWORK_UNREACHABLE 0xC000023C ++ ++/* Event codes */ ++ ++#define EVENT_NDIS_RESOURCE_CONFLICT 0xC0001388 ++#define EVENT_NDIS_OUT_OF_RESOURCE 0xC0001389 ++#define EVENT_NDIS_HARDWARE_FAILURE 0xC000138A ++#define EVENT_NDIS_ADAPTER_NOT_FOUND 0xC000138B ++#define EVENT_NDIS_INTERRUPT_CONNECT 0xC000138C ++#define EVENT_NDIS_DRIVER_FAILURE 0xC000138D ++#define EVENT_NDIS_BAD_VERSION 0xC000138E ++#define EVENT_NDIS_TIMEOUT 0x8000138F ++#define EVENT_NDIS_NETWORK_ADDRESS 0xC0001390 ++#define EVENT_NDIS_UNSUPPORTED_CONFIGURATION 0xC0001391 ++#define EVENT_NDIS_INVALID_VALUE_FROM_ADAPTER 0xC0001392 ++#define EVENT_NDIS_MISSING_CONFIGURATION_PARAMETER 0xC0001393 ++#define EVENT_NDIS_BAD_IO_BASE_ADDRESS 0xC0001394 ++#define EVENT_NDIS_RECEIVE_SPACE_SMALL 0x40001395 ++#define EVENT_NDIS_ADAPTER_DISABLED 0x80001396 ++#define EVENT_NDIS_IO_PORT_CONFLICT 0x80001397 ++#define EVENT_NDIS_PORT_OR_DMA_CONFLICT 0x80001398 ++#define EVENT_NDIS_MEMORY_CONFLICT 0x80001399 ++#define EVENT_NDIS_INTERRUPT_CONFLICT 0x8000139A ++#define EVENT_NDIS_DMA_CONFLICT 0x8000139B ++#define EVENT_NDIS_INVALID_DOWNLOAD_FILE_ERROR 0xC000139C ++#define EVENT_NDIS_MAXRECEIVES_ERROR 0x8000139D ++#define EVENT_NDIS_MAXTRANSMITS_ERROR 0x8000139E ++#define EVENT_NDIS_MAXFRAMESIZE_ERROR 0x8000139F ++#define EVENT_NDIS_MAXINTERNALBUFS_ERROR 0x800013A0 ++#define EVENT_NDIS_MAXMULTICAST_ERROR 0x800013A1 ++#define EVENT_NDIS_PRODUCTID_ERROR 0x800013A2 ++#define EVENT_NDIS_LOBE_FAILUE_ERROR 0x800013A3 ++#define EVENT_NDIS_SIGNAL_LOSS_ERROR 0x800013A4 ++#define EVENT_NDIS_REMOVE_RECEIVED_ERROR 0x800013A5 ++#define EVENT_NDIS_TOKEN_RING_CORRECTION 0x400013A6 ++#define EVENT_NDIS_ADAPTER_CHECK_ERROR 0xC00013A7 ++#define EVENT_NDIS_RESET_FAILURE_ERROR 0x800013A8 ++#define EVENT_NDIS_CABLE_DISCONNECTED_ERROR 0x800013A9 ++#define EVENT_NDIS_RESET_FAILURE_CORRECTION 0x800013AA ++ ++/* packet filter bits used by NDIS_OID_PACKET_FILTER */ ++#define NDIS_PACKET_TYPE_DIRECTED 0x00000001 ++#define NDIS_PACKET_TYPE_MULTICAST 0x00000002 ++#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x00000004 ++#define NDIS_PACKET_TYPE_BROADCAST 0x00000008 ++#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x00000010 ++#define NDIS_PACKET_TYPE_PROMISCUOUS 0x00000020 ++#define NDIS_PACKET_TYPE_SMT 0x00000040 ++#define NDIS_PACKET_TYPE_ALL_LOCAL 0x00000080 ++#define NDIS_PACKET_TYPE_GROUP 0x00001000 ++#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x00002000 ++#define NDIS_PACKET_TYPE_FUNCTIONAL 0x00004000 ++#define NDIS_PACKET_TYPE_MAC_FRAME 0x00008000 ++ ++/* memory allocation flags */ ++#define NDIS_MEMORY_CONTIGUOUS 0x00000001 ++#define NDIS_MEMORY_NONCACHED 0x00000002 ++ ++/* Attribute flags to NdisMSetAtrributesEx */ ++#define NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT 0x00000001 ++#define NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT 0x00000002 ++#define NDIS_ATTRIBUTE_IGNORE_TOKEN_RING_ERRORS 0x00000004 ++#define NDIS_ATTRIBUTE_BUS_MASTER 0x00000008 ++#define NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER 0x00000010 ++#define NDIS_ATTRIBUTE_DESERIALIZE 0x00000020 ++#define NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND 0x00000040 ++#define NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK 0x00000080 ++#define NDIS_ATTRIBUTE_NOT_CO_NDIS 0x00000100 ++#define NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS 0x00000200 ++ ++#define OID_TCP_TASK_OFFLOAD 0xFC010201 ++ ++#define NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA 0x00000001 ++#define NDIS_MAC_OPTION_RECEIVE_SERIALIZED 0x00000002 ++#define NDIS_MAC_OPTION_TRANSFERS_NOT_PEND 0x00000004 ++#define NDIS_MAC_OPTION_NO_LOOPBACK 0x00000008 ++#define NDIS_MAC_OPTION_FULL_DUPLEX 0x00000010 ++#define NDIS_MAC_OPTION_EOTX_INDICATION 0x00000020 ++#define NDIS_MAC_OPTION_8021P_PRIORITY 0x00000040 ++#define NDIS_MAC_OPTION_SUPPORTS_MAC_ADDRESS_OVERWRITE 0x00000080 ++#define NDIS_MAC_OPTION_RECEIVE_AT_DPC 0x00000100 ++#define NDIS_MAC_OPTION_8021Q_VLAN 0x00000200 ++#define NDIS_MAC_OPTION_RESERVED 0x80000000 ++ ++#define deserialized_driver(wnd) (wnd->attributes & NDIS_ATTRIBUTE_DESERIALIZE) ++ ++static inline void serialize_lock(struct ndis_device *wnd) ++{ ++ nt_spin_lock(&wnd->nmb->lock); ++} ++ ++static inline void serialize_unlock(struct ndis_device *wnd) ++{ ++ nt_spin_unlock(&wnd->nmb->lock); ++} ++ ++static inline KIRQL serialize_lock_irql(struct ndis_device *wnd) ++{ ++ if (deserialized_driver(wnd)) ++ return raise_irql(DISPATCH_LEVEL); ++ else ++ return nt_spin_lock_irql(&wnd->nmb->lock, DISPATCH_LEVEL); ++} ++ ++static inline void serialize_unlock_irql(struct ndis_device *wnd, ++ KIRQL irql) ++{ ++ if (deserialized_driver(wnd)) ++ lower_irql(irql); ++ else ++ nt_spin_unlock_irql(&wnd->nmb->lock, irql); ++} ++ ++static inline void if_serialize_lock(struct ndis_device *wnd) ++{ ++ if (!deserialized_driver(wnd)) ++ nt_spin_lock(&wnd->nmb->lock); ++} ++ ++static inline void if_serialize_unlock(struct ndis_device *wnd) ++{ ++ if (!deserialized_driver(wnd)) ++ nt_spin_unlock(&wnd->nmb->lock); ++} ++ ++#endif /* NDIS_H */ +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/ndiswrapper.h linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/ndiswrapper.h +--- linux-3.12.2/3rdparty/ndiswrapper/ndiswrapper.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/ndiswrapper.h 2013-11-28 21:42:11.000000000 +0200 +@@ -0,0 +1,219 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * 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 _NDISWRAPPER_H_ ++#define _NDISWRAPPER_H_ ++ ++#define DRIVER_VERSION "1.59" ++#define UTILS_VERSION "1.9" ++ ++#define DRIVER_NAME "ndiswrapper" ++#define DRIVER_CONFIG_DIR "/etc/ndiswrapper" ++ ++#define NDIS_ESSID_MAX_SIZE 32 ++#define NDIS_ENCODING_TOKEN_MAX 32 ++#define MAX_ENCR_KEYS 4 ++#define TX_RING_SIZE 16 ++#define NDIS_MAX_RATES 8 ++#define NDIS_MAX_RATES_EX 16 ++ ++#define WRAP_PCI_BUS 5 ++#define WRAP_PCMCIA_BUS 8 ++/* some USB devices, e.g., DWL-G120 have BusType as 0 */ ++#define WRAP_INTERNAL_BUS 0 ++/* documentation at msdn says 15 is PNP bus, but inf files from all ++ * vendors say 15 is USB; which is correct? */ ++#define WRAP_USB_BUS 15 ++ ++/* NDIS device must be 0, for compatibility with old versions of ++ * ndiswrapper where device type for NDIS drivers is 0 */ ++#define WRAP_NDIS_DEVICE 0 ++#define WRAP_USB_DEVICE 1 ++#define WRAP_BLUETOOTH_DEVICE1 2 ++#define WRAP_BLUETOOTH_DEVICE2 3 ++ ++#define WRAP_DEVICE_BUS(dev, bus) ((dev) << 8 | (bus)) ++#define WRAP_BUS(dev_bus) ((dev_bus) & 0x000FF) ++#define WRAP_DEVICE(dev_bus) ((dev_bus) >> 8) ++ ++#define MAX_DRIVER_NAME_LEN 32 ++#define MAX_VERSION_STRING_LEN 64 ++#define MAX_SETTING_NAME_LEN 128 ++#define MAX_SETTING_VALUE_LEN 256 ++ ++#define MAX_DRIVER_PE_IMAGES 4 ++#define MAX_DRIVER_BIN_FILES 5 ++#define MAX_DEVICE_SETTINGS 512 ++ ++#define MAX_ALLOCATED_URBS 15 ++ ++#define DEV_ANY_ID -1 ++ ++#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] ++#define MACSTRSEP "%02x:%02x:%02x:%02x:%02x:%02x" ++#define MACSTR "%02x%02x%02x%02x%02x%02x" ++#define MACINTADR(a) (int*)&((a)[0]), (int*)&((a)[1]), (int*)&((a)[2]), \ ++ (int*)&((a)[3]), (int*)&((a)[4]), (int*)&((a)[5]) ++ ++#ifdef __KERNEL__ ++/* DEBUG macros */ ++ ++#define MSG(level, fmt, ...) \ ++ printk(level DRIVER_NAME " (%s:%d): " fmt "\n", \ ++ __func__, __LINE__ , ## __VA_ARGS__) ++ ++#define WARNING(fmt, ...) MSG(KERN_WARNING, fmt, ## __VA_ARGS__) ++#define ERROR(fmt, ...) MSG(KERN_ERR, fmt , ## __VA_ARGS__) ++#define INFO(fmt, ...) MSG(KERN_INFO, fmt , ## __VA_ARGS__) ++#define TODO() WARNING("not fully implemented (yet)") ++ ++#define TRACE(level, fmt, ...) \ ++do { \ ++ if (debug >= level) \ ++ printk(KERN_INFO "%s (%s:%d): " fmt "\n", DRIVER_NAME, \ ++ __func__, __LINE__ , ## __VA_ARGS__); \ ++} while (0) ++#define TRACE0(fmt, ...) TRACE(0, fmt , ## __VA_ARGS__) ++ ++extern int debug; ++ ++#ifndef DEBUG ++#define DEBUG 0 ++#endif ++ ++/* for a block of code */ ++#if DEBUG >= 1 ++#define DBG_BLOCK(level) if (debug >= level) ++#else ++#define DBG_BLOCK(level) while (0) ++#endif ++ ++#if DEBUG >= 1 ++#define TRACE1(fmt, ...) TRACE(1, fmt , ## __VA_ARGS__) ++#else ++#define TRACE1(fmt, ...) do { } while (0) ++#endif ++ ++#if DEBUG >= 2 ++#define TRACE2(fmt, ...) TRACE(2, fmt , ## __VA_ARGS__) ++#else ++#define TRACE2(fmt, ...) do { } while (0) ++#endif ++ ++#if DEBUG >= 3 ++#define TRACE3(fmt, ...) TRACE(3, fmt , ## __VA_ARGS__) ++#else ++#define TRACE3(fmt, ...) do { } while (0) ++#endif ++ ++#if DEBUG >= 4 ++#define TRACE4(fmt, ...) TRACE(4, fmt , ## __VA_ARGS__) ++#else ++#define TRACE4(fmt, ...) do { } while (0) ++#endif ++ ++#if DEBUG >= 5 ++#define TRACE5(fmt, ...) TRACE(5, fmt , ## __VA_ARGS__) ++#else ++#define TRACE5(fmt, ...) do { } while (0) ++#endif ++ ++#if DEBUG >= 6 ++#define TRACE6(fmt, ...) TRACE(6, fmt , ## __VA_ARGS__) ++#else ++#define TRACE6(fmt, ...) do { } while (0) ++#endif ++ ++#define ENTER0(fmt, ...) TRACE0("Enter " fmt , ## __VA_ARGS__) ++#define ENTER1(fmt, ...) TRACE1("Enter " fmt , ## __VA_ARGS__) ++#define ENTER2(fmt, ...) TRACE2("Enter " fmt , ## __VA_ARGS__) ++#define ENTER3(fmt, ...) TRACE3("Enter " fmt , ## __VA_ARGS__) ++#define ENTER4(fmt, ...) TRACE4("Enter " fmt , ## __VA_ARGS__) ++#define ENTER5(fmt, ...) TRACE5("Enter " fmt , ## __VA_ARGS__) ++#define ENTER6(fmt, ...) TRACE6("Enter " fmt , ## __VA_ARGS__) ++ ++#define EXIT0(stmt) do { TRACE0("Exit"); stmt; } while (0) ++#define EXIT1(stmt) do { TRACE1("Exit"); stmt; } while (0) ++#define EXIT2(stmt) do { TRACE2("Exit"); stmt; } while (0) ++#define EXIT3(stmt) do { TRACE3("Exit"); stmt; } while (0) ++#define EXIT4(stmt) do { TRACE4("Exit"); stmt; } while (0) ++#define EXIT5(stmt) do { TRACE5("Exit"); stmt; } while (0) ++#define EXIT6(stmt) do { TRACE6("Exit"); stmt; } while (0) ++ ++#if defined(USB_DEBUG) ++#define USBTRACE TRACE0 ++#define USBENTER ENTER0 ++#define USBEXIT EXIT0 ++#else ++#define USBTRACE(fmt, ...) do { } while (0) ++#define USBENTER(fmt, ...) ++#define USBEXIT(stmt) stmt ++#endif ++ ++#if defined(EVENT_DEBUG) ++#define EVENTTRACE TRACE0 ++#define EVENTENTER ENTER0 ++#define EVENTEXIT EXIT0 ++#else ++#define EVENTTRACE(fmt, ...) do { } while (0) ++#define EVENTENTER(fmt, ...) ++#define EVENTEXIT(stmt) stmt ++#endif ++ ++#if defined(TIMER_DEBUG) ++#define TIMERTRACE TRACE0 ++#define TIMERENTER ENTER0 ++#define TIMEREXIT EXIT0 ++#else ++#define TIMERTRACE(fmt, ...) do { } while (0) ++#define TIMERENTER(fmt, ...) ++#define TIMEREXIT(stmt) stmt ++#endif ++ ++#if defined(IO_DEBUG) ++#define IOTRACE TRACE0 ++#define IOENTER ENTER0 ++#define IOEXIT EXIT0 ++#else ++#define IOTRACE(fmt, ...) do { } while (0) ++#define IOENTER(fmt, ...) ++#define IOEXIT(stmt) stmt ++#endif ++ ++#if defined(WORK_DEBUG) ++#define WORKTRACE TRACE0 ++#define WORKENTER ENTER0 ++#define WORKEXIT EXIT0 ++#else ++#define WORKTRACE(fmt, ...) do { } while (0) ++#define WORKENTER(fmt, ...) ++#define WORKEXIT(stmt) stmt ++#endif ++ ++#if DEBUG >= 1 ++#define assert(expr) \ ++do { \ ++ if (!(expr)) { \ ++ ERROR("assertion '%s' failed", #expr); \ ++ dump_stack(); \ ++ } \ ++} while (0) ++#else ++#define assert(expr) do { } while (0) ++#endif ++ ++#endif // __KERNEL__ ++ ++#endif // NDISWRAPPER_H +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/ntoskernel.c linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/ntoskernel.c +--- linux-3.12.2/3rdparty/ndiswrapper/ntoskernel.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/ntoskernel.c 2013-11-28 21:42:11.000000000 +0200 +@@ -0,0 +1,2677 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * 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 "ntoskernel.h" ++#include "ndis.h" ++#include "usb.h" ++#include "pnp.h" ++#include "loader.h" ++#include "ntoskernel_exports.h" ++ ++/* MDLs describe a range of virtual address with an array of physical ++ * pages right after the header. For different ranges of virtual ++ * addresses, the number of entries of physical pages may be different ++ * (depending on number of entries required). If we want to allocate ++ * MDLs from a pool, the size has to be constant. So we assume that ++ * maximum range used by a driver is MDL_CACHE_PAGES; if a driver ++ * requests an MDL for a bigger region, we allocate it with kmalloc; ++ * otherwise, we allocate from the pool */ ++ ++#define MDL_CACHE_PAGES 3 ++#define MDL_CACHE_SIZE (sizeof(struct mdl) + \ ++ (sizeof(PFN_NUMBER) * MDL_CACHE_PAGES)) ++struct wrap_mdl { ++ struct nt_list list; ++ struct mdl mdl[0]; ++}; ++ ++/* everything here is for all drivers/devices - not per driver/device */ ++static spinlock_t dispatcher_lock; ++spinlock_t ntoskernel_lock; ++static void *mdl_cache; ++static struct nt_list wrap_mdl_list; ++ ++static struct work_struct kdpc_work; ++static void kdpc_worker(struct work_struct *dummy); ++ ++static struct nt_list kdpc_list; ++static spinlock_t kdpc_list_lock; ++ ++static struct nt_list callback_objects; ++ ++struct nt_list object_list; ++ ++struct bus_driver { ++ struct nt_list list; ++ char name[MAX_DRIVER_NAME_LEN]; ++ struct driver_object drv_obj; ++}; ++ ++static struct nt_list bus_driver_list; ++ ++static struct work_struct ntos_work; ++static struct nt_list ntos_work_list; ++static spinlock_t ntos_work_lock; ++static void ntos_work_worker(struct work_struct *dummy); ++spinlock_t irp_cancel_lock; ++static NT_SPIN_LOCK nt_list_lock; ++static struct nt_slist wrap_timer_slist; ++CCHAR cpu_count; ++ ++/* compute ticks (100ns) since 1601 until when system booted into ++ * wrap_ticks_to_boot */ ++u64 wrap_ticks_to_boot; ++ ++#if defined(CONFIG_X86_64) ++static struct timer_list shared_data_timer; ++struct kuser_shared_data kuser_shared_data; ++static void update_user_shared_data_proc(unsigned long data); ++#endif ++ ++WIN_SYMBOL_MAP("KeTickCount", &jiffies) ++WIN_SYMBOL_MAP("KeNumberProcessors", &cpu_count) ++WIN_SYMBOL_MAP("NlsMbCodePageTag", FALSE) ++ ++struct workqueue_struct *ntos_wq; ++ ++#ifdef WRAP_PREEMPT ++DEFINE_PER_CPU(struct irql_info, irql_info); ++#endif ++ ++#if defined(CONFIG_X86_64) ++static void update_user_shared_data_proc(unsigned long data) ++{ ++ /* timer is supposed to be scheduled every 10ms, but bigger ++ * intervals seem to work (tried up to 50ms) */ ++ *((ULONG64 *)&kuser_shared_data.system_time) = ticks_1601(); ++ *((ULONG64 *)&kuser_shared_data.interrupt_time) = ++ jiffies * TICKSPERSEC / HZ; ++ *((ULONG64 *)&kuser_shared_data.tick) = jiffies; ++ ++ mod_timer(&shared_data_timer, jiffies + MSEC_TO_HZ(30)); ++} ++#endif ++ ++void *allocate_object(ULONG size, enum common_object_type type, ++ struct unicode_string *name) ++{ ++ struct common_object_header *hdr; ++ void *body; ++ ++ /* we pad header as prefix to body */ ++ hdr = ExAllocatePoolWithTag(NonPagedPool, OBJECT_SIZE(size), 0); ++ if (!hdr) { ++ WARNING("couldn't allocate memory"); ++ return NULL; ++ } ++ memset(hdr, 0, OBJECT_SIZE(size)); ++ if (name) { ++ hdr->name.buf = ExAllocatePoolWithTag(NonPagedPool, ++ name->max_length, 0); ++ if (!hdr->name.buf) { ++ ExFreePool(hdr); ++ return NULL; ++ } ++ memcpy(hdr->name.buf, name->buf, name->max_length); ++ hdr->name.length = name->length; ++ hdr->name.max_length = name->max_length; ++ } ++ hdr->type = type; ++ hdr->ref_count = 1; ++ spin_lock_bh(&ntoskernel_lock); ++ /* threads are looked up often (in KeWaitForXXX), so optimize ++ * for fast lookups of threads */ ++ if (type == OBJECT_TYPE_NT_THREAD) ++ InsertHeadList(&object_list, &hdr->list); ++ else ++ InsertTailList(&object_list, &hdr->list); ++ spin_unlock_bh(&ntoskernel_lock); ++ body = HEADER_TO_OBJECT(hdr); ++ TRACE3("allocated hdr: %p, body: %p", hdr, body); ++ return body; ++} ++ ++static void free_object(void *object) ++{ ++ struct common_object_header *hdr; ++ ++ hdr = OBJECT_TO_HEADER(object); ++ spin_lock_bh(&ntoskernel_lock); ++ RemoveEntryList(&hdr->list); ++ spin_unlock_bh(&ntoskernel_lock); ++ TRACE3("freed hdr: %p, body: %p", hdr, object); ++ if (hdr->name.buf) ++ ExFreePool(hdr->name.buf); ++ ExFreePool(hdr); ++} ++ ++static int add_bus_driver(const char *name) ++{ ++ struct bus_driver *bus_driver; ++ ++ bus_driver = kzalloc(sizeof(*bus_driver), GFP_KERNEL); ++ if (!bus_driver) { ++ ERROR("couldn't allocate memory"); ++ return -ENOMEM; ++ } ++ strncpy(bus_driver->name, name, sizeof(bus_driver->name)); ++ bus_driver->name[sizeof(bus_driver->name)-1] = 0; ++ spin_lock_bh(&ntoskernel_lock); ++ InsertTailList(&bus_driver_list, &bus_driver->list); ++ spin_unlock_bh(&ntoskernel_lock); ++ TRACE1("bus driver %s is at %p", name, &bus_driver->drv_obj); ++ return STATUS_SUCCESS; ++} ++ ++struct driver_object *find_bus_driver(const char *name) ++{ ++ struct bus_driver *bus_driver; ++ struct driver_object *drv_obj; ++ ++ spin_lock_bh(&ntoskernel_lock); ++ drv_obj = NULL; ++ nt_list_for_each_entry(bus_driver, &bus_driver_list, list) { ++ if (strcmp(bus_driver->name, name) == 0) { ++ drv_obj = &bus_driver->drv_obj; ++ break; ++ } ++ } ++ spin_unlock_bh(&ntoskernel_lock); ++ return drv_obj; ++} ++ ++wfastcall struct nt_list *WIN_FUNC(ExfInterlockedInsertHeadList,3) ++ (struct nt_list *head, struct nt_list *entry, NT_SPIN_LOCK *lock) ++{ ++ struct nt_list *first; ++ unsigned long flags; ++ ++ ENTER5("head = %p, entry = %p", head, entry); ++ nt_spin_lock_irqsave(lock, flags); ++ first = InsertHeadList(head, entry); ++ nt_spin_unlock_irqrestore(lock, flags); ++ TRACE5("head = %p, old = %p", head, first); ++ return first; ++} ++ ++wfastcall struct nt_list *WIN_FUNC(ExInterlockedInsertHeadList,3) ++ (struct nt_list *head, struct nt_list *entry, NT_SPIN_LOCK *lock) ++{ ++ ENTER5("%p", head); ++ return ExfInterlockedInsertHeadList(head, entry, lock); ++} ++ ++wfastcall struct nt_list *WIN_FUNC(ExfInterlockedInsertTailList,3) ++ (struct nt_list *head, struct nt_list *entry, NT_SPIN_LOCK *lock) ++{ ++ struct nt_list *last; ++ unsigned long flags; ++ ++ ENTER5("head = %p, entry = %p", head, entry); ++ nt_spin_lock_irqsave(lock, flags); ++ last = InsertTailList(head, entry); ++ nt_spin_unlock_irqrestore(lock, flags); ++ TRACE5("head = %p, old = %p", head, last); ++ return last; ++} ++ ++wfastcall struct nt_list *WIN_FUNC(ExInterlockedInsertTailList,3) ++ (struct nt_list *head, struct nt_list *entry, NT_SPIN_LOCK *lock) ++{ ++ ENTER5("%p", head); ++ return ExfInterlockedInsertTailList(head, entry, lock); ++} ++ ++wfastcall struct nt_list *WIN_FUNC(ExfInterlockedRemoveHeadList,2) ++ (struct nt_list *head, NT_SPIN_LOCK *lock) ++{ ++ struct nt_list *ret; ++ unsigned long flags; ++ ++ ENTER5("head = %p", head); ++ nt_spin_lock_irqsave(lock, flags); ++ ret = RemoveHeadList(head); ++ nt_spin_unlock_irqrestore(lock, flags); ++ TRACE5("head = %p, ret = %p", head, ret); ++ return ret; ++} ++ ++wfastcall struct nt_list *WIN_FUNC(ExInterlockedRemoveHeadList,2) ++ (struct nt_list *head, NT_SPIN_LOCK *lock) ++{ ++ ENTER5("%p", head); ++ return ExfInterlockedRemoveHeadList(head, lock); ++} ++ ++wfastcall struct nt_list *WIN_FUNC(ExfInterlockedRemoveTailList,2) ++ (struct nt_list *head, NT_SPIN_LOCK *lock) ++{ ++ struct nt_list *ret; ++ unsigned long flags; ++ ++ ENTER5("head = %p", head); ++ nt_spin_lock_irqsave(lock, flags); ++ ret = RemoveTailList(head); ++ nt_spin_unlock_irqrestore(lock, flags); ++ TRACE5("head = %p, ret = %p", head, ret); ++ return ret; ++} ++ ++wfastcall struct nt_list *WIN_FUNC(ExInterlockedRemoveTailList,2) ++ (struct nt_list *head, NT_SPIN_LOCK *lock) ++{ ++ ENTER5("%p", head); ++ return ExfInterlockedRemoveTailList(head, lock); ++} ++ ++wfastcall void WIN_FUNC(InitializeSListHead,1) ++ (nt_slist_header *head) ++{ ++ memset(head, 0, sizeof(*head)); ++} ++ ++wfastcall struct nt_slist *WIN_FUNC(ExInterlockedPushEntrySList,3) ++ (nt_slist_header *head, struct nt_slist *entry, NT_SPIN_LOCK *lock) ++{ ++ struct nt_slist *ret; ++ ++ ret = PushEntrySList(head, entry, lock); ++ return ret; ++} ++ ++wstdcall struct nt_slist *WIN_FUNC(ExpInterlockedPushEntrySList,2) ++ (nt_slist_header *head, struct nt_slist *entry) ++{ ++ struct nt_slist *ret; ++ ++ ret = PushEntrySList(head, entry, &nt_list_lock); ++ return ret; ++} ++ ++wfastcall struct nt_slist *WIN_FUNC(InterlockedPushEntrySList,2) ++ (nt_slist_header *head, struct nt_slist *entry) ++{ ++ struct nt_slist *ret; ++ ++ ret = PushEntrySList(head, entry, &nt_list_lock); ++ return ret; ++} ++ ++wfastcall struct nt_slist *WIN_FUNC(ExInterlockedPopEntrySList,2) ++ (nt_slist_header *head, NT_SPIN_LOCK *lock) ++{ ++ struct nt_slist *ret; ++ ++ ret = PopEntrySList(head, lock); ++ return ret; ++} ++ ++wstdcall struct nt_slist *WIN_FUNC(ExpInterlockedPopEntrySList,1) ++ (nt_slist_header *head) ++{ ++ struct nt_slist *ret; ++ ++ ret = PopEntrySList(head, &nt_list_lock); ++ return ret; ++} ++ ++wfastcall struct nt_slist *WIN_FUNC(InterlockedPopEntrySList,1) ++ (nt_slist_header *head) ++{ ++ struct nt_slist *ret; ++ ++ ret = PopEntrySList(head, &nt_list_lock); ++ return ret; ++} ++ ++wstdcall USHORT WIN_FUNC(ExQueryDepthSList,1) ++ (nt_slist_header *head) ++{ ++ USHORT depth; ++ ENTER5("%p", head); ++ depth = head->depth; ++ TRACE5("%d, %p", depth, head->next); ++ return depth; ++} ++ ++wfastcall LONG WIN_FUNC(InterlockedIncrement,1) ++ (LONG volatile *val) ++{ ++ return post_atomic_add(*val, 1); ++} ++ ++wfastcall LONG WIN_FUNC(InterlockedDecrement,1) ++ (LONG volatile *val) ++{ ++ return post_atomic_add(*val, -1); ++} ++ ++wfastcall LONG WIN_FUNC(InterlockedExchange,2) ++ (LONG volatile *target, LONG val) ++{ ++ return xchg(target, val); ++} ++ ++wfastcall LONG WIN_FUNC(InterlockedCompareExchange,3) ++ (LONG volatile *dest, LONG new, LONG old) ++{ ++ return cmpxchg(dest, old, new); ++} ++ ++wfastcall void WIN_FUNC(ExInterlockedAddLargeStatistic,2) ++ (LARGE_INTEGER volatile *plint, ULONG n) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++#ifdef CONFIG_X86_64 ++ __asm__ __volatile__( ++ "\n" ++ LOCK_PREFIX "add %1, %0\n\t" ++ : "+m" (*plint) ++ : "r" (n)); ++#else ++ __asm__ __volatile__( ++ "1:\t" ++ " movl %1, %%ebx\n\t" ++ " movl %%edx, %%ecx\n\t" ++ " addl %%eax, %%ebx\n\t" ++ " adcl $0, %%ecx\n\t" ++ LOCK_PREFIX "cmpxchg8b %0\n\t" ++ " jnz 1b\n\t" ++ : "+m" (*plint) ++ : "m" (n), "A" (*plint) ++ : "ebx", "ecx"); ++#endif ++ local_irq_restore(flags); ++} ++ ++static void initialize_object(struct dispatcher_header *dh, enum dh_type type, ++ int state) ++{ ++ memset(dh, 0, sizeof(*dh)); ++ set_object_type(dh, type); ++ dh->signal_state = state; ++ InitializeListHead(&dh->wait_blocks); ++} ++ ++static void timer_proc(unsigned long data) ++{ ++ struct wrap_timer *wrap_timer = (struct wrap_timer *)data; ++ struct nt_timer *nt_timer; ++ struct kdpc *kdpc; ++ ++ nt_timer = wrap_timer->nt_timer; ++ TIMERENTER("%p(%p), %lu", wrap_timer, nt_timer, jiffies); ++#ifdef TIMER_DEBUG ++ BUG_ON(wrap_timer->wrap_timer_magic != WRAP_TIMER_MAGIC); ++ BUG_ON(nt_timer->wrap_timer_magic != WRAP_TIMER_MAGIC); ++#endif ++ KeSetEvent((struct nt_event *)nt_timer, 0, FALSE); ++ if (wrap_timer->repeat) ++ mod_timer(&wrap_timer->timer, jiffies + wrap_timer->repeat); ++ kdpc = nt_timer->kdpc; ++ if (kdpc) ++ queue_kdpc(kdpc); ++ TIMEREXIT(return); ++} ++ ++void wrap_init_timer(struct nt_timer *nt_timer, enum timer_type type, ++ struct ndis_mp_block *nmb) ++{ ++ struct wrap_timer *wrap_timer; ++ ++ /* TODO: if a timer is initialized more than once, we allocate ++ * memory for wrap_timer more than once for the same nt_timer, ++ * wasting memory. We can check if nt_timer->wrap_timer_magic is ++ * set and not allocate, but it is not guaranteed always to be ++ * safe */ ++ TIMERENTER("%p", nt_timer); ++ /* we allocate memory for wrap_timer behind driver's back and ++ * there is no NDIS/DDK function where this memory can be ++ * freed, so we use slack_kmalloc so it gets freed when driver ++ * is unloaded */ ++ if (nmb) ++ wrap_timer = kzalloc(sizeof(*wrap_timer), irql_gfp()); ++ else ++ wrap_timer = slack_kzalloc(sizeof(*wrap_timer)); ++ if (!wrap_timer) { ++ ERROR("couldn't allocate memory for timer"); ++ return; ++ } ++ ++ init_timer(&wrap_timer->timer); ++ wrap_timer->timer.data = (unsigned long)wrap_timer; ++ wrap_timer->timer.function = timer_proc; ++ wrap_timer->nt_timer = nt_timer; ++#ifdef TIMER_DEBUG ++ wrap_timer->wrap_timer_magic = WRAP_TIMER_MAGIC; ++#endif ++ nt_timer->wrap_timer = wrap_timer; ++ nt_timer->kdpc = NULL; ++ initialize_object(&nt_timer->dh, (enum dh_type)type, 0); ++ nt_timer->wrap_timer_magic = WRAP_TIMER_MAGIC; ++ TIMERTRACE("timer %p (%p)", wrap_timer, nt_timer); ++ spin_lock_bh(&ntoskernel_lock); ++ if (nmb) { ++ wrap_timer->slist.next = nmb->wnd->wrap_timer_slist.next; ++ nmb->wnd->wrap_timer_slist.next = &wrap_timer->slist; ++ } else { ++ wrap_timer->slist.next = wrap_timer_slist.next; ++ wrap_timer_slist.next = &wrap_timer->slist; ++ } ++ spin_unlock_bh(&ntoskernel_lock); ++ TIMEREXIT(return); ++} ++ ++wstdcall void WIN_FUNC(KeInitializeTimerEx,2) ++ (struct nt_timer *nt_timer, enum timer_type type) ++{ ++ TIMERENTER("%p", nt_timer); ++ wrap_init_timer(nt_timer, type, NULL); ++} ++ ++wstdcall void WIN_FUNC(KeInitializeTimer,1) ++ (struct nt_timer *nt_timer) ++{ ++ TIMERENTER("%p", nt_timer); ++ wrap_init_timer(nt_timer, NotificationTimer, NULL); ++} ++ ++/* expires and repeat are in HZ */ ++BOOLEAN wrap_set_timer(struct nt_timer *nt_timer, unsigned long expires_hz, ++ unsigned long repeat_hz, struct kdpc *kdpc) ++{ ++ struct wrap_timer *wrap_timer; ++ ++ TIMERENTER("%p, %lu, %lu, %p, %lu", ++ nt_timer, expires_hz, repeat_hz, kdpc, jiffies); ++ ++ wrap_timer = nt_timer->wrap_timer; ++ TIMERTRACE("%p", wrap_timer); ++#ifdef TIMER_DEBUG ++ if (wrap_timer->nt_timer != nt_timer) ++ WARNING("bad timers: %p, %p, %p", wrap_timer, nt_timer, ++ wrap_timer->nt_timer); ++ if (nt_timer->wrap_timer_magic != WRAP_TIMER_MAGIC) { ++ WARNING("buggy Windows timer didn't initialize timer %p", ++ nt_timer); ++ return FALSE; ++ } ++ if (wrap_timer->wrap_timer_magic != WRAP_TIMER_MAGIC) { ++ WARNING("timer %p is not initialized (%lx)?", ++ wrap_timer, wrap_timer->wrap_timer_magic); ++ wrap_timer->wrap_timer_magic = WRAP_TIMER_MAGIC; ++ } ++#endif ++ KeClearEvent((struct nt_event *)nt_timer); ++ nt_timer->kdpc = kdpc; ++ wrap_timer->repeat = repeat_hz; ++ if (mod_timer(&wrap_timer->timer, jiffies + expires_hz)) ++ TIMEREXIT(return TRUE); ++ else ++ TIMEREXIT(return FALSE); ++} ++ ++wstdcall BOOLEAN WIN_FUNC(KeSetTimerEx,4) ++ (struct nt_timer *nt_timer, LARGE_INTEGER duetime_ticks, ++ LONG period_ms, struct kdpc *kdpc) ++{ ++ unsigned long expires_hz, repeat_hz; ++ ++ TIMERENTER("%p, %lld, %d", nt_timer, duetime_ticks, period_ms); ++ expires_hz = SYSTEM_TIME_TO_HZ(duetime_ticks); ++ repeat_hz = MSEC_TO_HZ(period_ms); ++ return wrap_set_timer(nt_timer, expires_hz, repeat_hz, kdpc); ++} ++ ++wstdcall BOOLEAN WIN_FUNC(KeSetTimer,3) ++ (struct nt_timer *nt_timer, LARGE_INTEGER duetime_ticks, ++ struct kdpc *kdpc) ++{ ++ TIMERENTER("%p, %lld, %p", nt_timer, duetime_ticks, kdpc); ++ return KeSetTimerEx(nt_timer, duetime_ticks, 0, kdpc); ++} ++ ++wstdcall BOOLEAN WIN_FUNC(KeCancelTimer,1) ++ (struct nt_timer *nt_timer) ++{ ++ struct wrap_timer *wrap_timer; ++ int ret; ++ ++ TIMERENTER("%p", nt_timer); ++ wrap_timer = nt_timer->wrap_timer; ++ if (!wrap_timer) { ++ ERROR("invalid wrap_timer"); ++ return TRUE; ++ } ++#ifdef TIMER_DEBUG ++ BUG_ON(wrap_timer->wrap_timer_magic != WRAP_TIMER_MAGIC); ++#endif ++ /* disable timer before deleting so if it is periodic timer, it ++ * won't be re-armed after deleting */ ++ wrap_timer->repeat = 0; ++ ret = del_timer_sync(&wrap_timer->timer); ++ /* the documentation for KeCancelTimer suggests the DPC is ++ * deqeued, but actually DPC is left to run */ ++ if (ret) ++ TIMEREXIT(return TRUE); ++ else ++ TIMEREXIT(return FALSE); ++} ++ ++wstdcall BOOLEAN WIN_FUNC(KeReadStateTimer,1) ++ (struct nt_timer *nt_timer) ++{ ++ if (nt_timer->dh.signal_state) ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++wstdcall void WIN_FUNC(KeInitializeDpc,3) ++ (struct kdpc *kdpc, void *func, void *ctx) ++{ ++ ENTER3("%p, %p, %p", kdpc, func, ctx); ++ memset(kdpc, 0, sizeof(*kdpc)); ++ kdpc->func = func; ++ kdpc->ctx = ctx; ++ InitializeListHead(&kdpc->list); ++} ++ ++static void kdpc_worker(struct work_struct *dummy) ++{ ++ struct nt_list *entry; ++ struct kdpc *kdpc; ++ unsigned long flags; ++ KIRQL irql; ++ ++ WORKENTER(""); ++ irql = raise_irql(DISPATCH_LEVEL); ++ while (1) { ++ spin_lock_irqsave(&kdpc_list_lock, flags); ++ entry = RemoveHeadList(&kdpc_list); ++ if (entry) { ++ kdpc = container_of(entry, struct kdpc, list); ++ assert(kdpc->queued); ++ kdpc->queued = 0; ++ } else ++ kdpc = NULL; ++ spin_unlock_irqrestore(&kdpc_list_lock, flags); ++ if (!kdpc) ++ break; ++ WORKTRACE("%p, %p, %p, %p, %p", kdpc, kdpc->func, kdpc->ctx, ++ kdpc->arg1, kdpc->arg2); ++ assert_irql(_irql_ == DISPATCH_LEVEL); ++ LIN2WIN4(kdpc->func, kdpc, kdpc->ctx, kdpc->arg1, kdpc->arg2); ++ assert_irql(_irql_ == DISPATCH_LEVEL); ++ } ++ lower_irql(irql); ++ WORKEXIT(return); ++} ++ ++wstdcall void WIN_FUNC(KeFlushQueuedDpcs,0) ++ (void) ++{ ++ kdpc_worker(NULL); ++} ++ ++BOOLEAN queue_kdpc(struct kdpc *kdpc) ++{ ++ BOOLEAN ret; ++ unsigned long flags; ++ ++ WORKENTER("%p", kdpc); ++ spin_lock_irqsave(&kdpc_list_lock, flags); ++ if (kdpc->queued) ++ ret = FALSE; ++ else { ++ if (unlikely(kdpc->importance == HighImportance)) ++ InsertHeadList(&kdpc_list, &kdpc->list); ++ else ++ InsertTailList(&kdpc_list, &kdpc->list); ++ kdpc->queued = 1; ++ ret = TRUE; ++ } ++ spin_unlock_irqrestore(&kdpc_list_lock, flags); ++ if (ret == TRUE) ++ queue_work(ntos_wq, &kdpc_work); ++ WORKTRACE("%d", ret); ++ return ret; ++} ++ ++BOOLEAN dequeue_kdpc(struct kdpc *kdpc) ++{ ++ BOOLEAN ret; ++ unsigned long flags; ++ ++ WORKENTER("%p", kdpc); ++ spin_lock_irqsave(&kdpc_list_lock, flags); ++ if (kdpc->queued) { ++ RemoveEntryList(&kdpc->list); ++ kdpc->queued = 0; ++ ret = TRUE; ++ } else ++ ret = FALSE; ++ spin_unlock_irqrestore(&kdpc_list_lock, flags); ++ WORKTRACE("%d", ret); ++ return ret; ++} ++ ++wstdcall BOOLEAN WIN_FUNC(KeInsertQueueDpc,3) ++ (struct kdpc *kdpc, void *arg1, void *arg2) ++{ ++ WORKENTER("%p, %p, %p", kdpc, arg1, arg2); ++ kdpc->arg1 = arg1; ++ kdpc->arg2 = arg2; ++ return queue_kdpc(kdpc); ++} ++ ++wstdcall BOOLEAN WIN_FUNC(KeRemoveQueueDpc,1) ++ (struct kdpc *kdpc) ++{ ++ return dequeue_kdpc(kdpc); ++} ++ ++wstdcall void WIN_FUNC(KeSetImportanceDpc,2) ++ (struct kdpc *kdpc, enum kdpc_importance importance) ++{ ++ kdpc->importance = importance; ++} ++ ++static void ntos_work_worker(struct work_struct *dummy) ++{ ++ struct ntos_work_item *ntos_work_item; ++ struct nt_list *cur; ++ ++ while (1) { ++ spin_lock_bh(&ntos_work_lock); ++ cur = RemoveHeadList(&ntos_work_list); ++ spin_unlock_bh(&ntos_work_lock); ++ if (!cur) ++ break; ++ ntos_work_item = container_of(cur, struct ntos_work_item, list); ++ WORKTRACE("%p: executing %p, %p, %p", current, ++ ntos_work_item->func, ntos_work_item->arg1, ++ ntos_work_item->arg2); ++ LIN2WIN2(ntos_work_item->func, ntos_work_item->arg1, ++ ntos_work_item->arg2); ++ kfree(ntos_work_item); ++ } ++ WORKEXIT(return); ++} ++ ++int schedule_ntos_work_item(NTOS_WORK_FUNC func, void *arg1, void *arg2) ++{ ++ struct ntos_work_item *ntos_work_item; ++ ++ WORKENTER("adding work: %p, %p, %p", func, arg1, arg2); ++ ntos_work_item = kmalloc(sizeof(*ntos_work_item), irql_gfp()); ++ if (!ntos_work_item) { ++ ERROR("couldn't allocate memory"); ++ return -ENOMEM; ++ } ++ ntos_work_item->func = func; ++ ntos_work_item->arg1 = arg1; ++ ntos_work_item->arg2 = arg2; ++ spin_lock_bh(&ntos_work_lock); ++ InsertTailList(&ntos_work_list, &ntos_work_item->list); ++ spin_unlock_bh(&ntos_work_lock); ++ queue_work(ntos_wq, &ntos_work); ++ WORKEXIT(return 0); ++} ++ ++wstdcall void WIN_FUNC(KeInitializeSpinLock,1) ++ (NT_SPIN_LOCK *lock) ++{ ++ ENTER6("%p", lock); ++ nt_spin_lock_init(lock); ++} ++ ++wstdcall void WIN_FUNC(KeAcquireSpinLock,2) ++ (NT_SPIN_LOCK *lock, KIRQL *irql) ++{ ++ ENTER6("%p", lock); ++ *irql = nt_spin_lock_irql(lock, DISPATCH_LEVEL); ++} ++ ++wstdcall void WIN_FUNC(KeReleaseSpinLock,2) ++ (NT_SPIN_LOCK *lock, KIRQL oldirql) ++{ ++ ENTER6("%p", lock); ++ nt_spin_unlock_irql(lock, oldirql); ++} ++ ++wstdcall void WIN_FUNC(KeAcquireSpinLockAtDpcLevel,1) ++ (NT_SPIN_LOCK *lock) ++{ ++ ENTER6("%p", lock); ++ nt_spin_lock(lock); ++} ++ ++wstdcall void WIN_FUNC(KeReleaseSpinLockFromDpcLevel,1) ++ (NT_SPIN_LOCK *lock) ++{ ++ ENTER6("%p", lock); ++ nt_spin_unlock(lock); ++} ++ ++wstdcall void WIN_FUNC(KeRaiseIrql,2) ++ (KIRQL newirql, KIRQL *oldirql) ++{ ++ ENTER6("%d", newirql); ++ *oldirql = raise_irql(newirql); ++} ++ ++wstdcall KIRQL WIN_FUNC(KeRaiseIrqlToDpcLevel,0) ++ (void) ++{ ++ return raise_irql(DISPATCH_LEVEL); ++} ++ ++wstdcall void WIN_FUNC(KeLowerIrql,1) ++ (KIRQL irql) ++{ ++ ENTER6("%d", irql); ++ lower_irql(irql); ++} ++ ++wstdcall KIRQL WIN_FUNC(KeAcquireSpinLockRaiseToDpc,1) ++ (NT_SPIN_LOCK *lock) ++{ ++ ENTER6("%p", lock); ++ return nt_spin_lock_irql(lock, DISPATCH_LEVEL); ++} ++ ++wstdcall void *WIN_FUNC(ExAllocatePoolWithTag,3) ++ (enum pool_type pool_type, SIZE_T size, ULONG tag) ++{ ++ void *addr; ++ ++ ENTER4("pool_type: %d, size: %zu, tag: 0x%x", pool_type, size, tag); ++ assert_irql(_irql_ <= DISPATCH_LEVEL); ++ if (size < PAGE_SIZE) ++ addr = kmalloc(size, irql_gfp()); ++ else { ++ if (irql_gfp() & GFP_ATOMIC) { ++ addr = __vmalloc(size, GFP_ATOMIC | __GFP_HIGHMEM, ++ PAGE_KERNEL); ++ TRACE1("%p, %zu", addr, size); ++ } else { ++ addr = vmalloc(size); ++ TRACE1("%p, %zu", addr, size); ++ } ++ } ++ DBG_BLOCK(1) { ++ if (addr) ++ TRACE4("addr: %p, %zu", addr, size); ++ else ++ TRACE1("failed: %zu", size); ++ } ++ return addr; ++} ++WIN_FUNC_DECL(ExAllocatePoolWithTag,3) ++ ++wstdcall void WIN_FUNC(ExFreePoolWithTag,2) ++ (void *addr, ULONG tag) ++{ ++ TRACE4("%p", addr); ++ if ((unsigned long)addr < VMALLOC_START || ++ (unsigned long)addr >= VMALLOC_END) ++ kfree(addr); ++ else ++ vfree(addr); ++ ++ EXIT4(return); ++} ++ ++wstdcall void WIN_FUNC(ExFreePool,1) ++ (void *addr) ++{ ++ ExFreePoolWithTag(addr, 0); ++} ++WIN_FUNC_DECL(ExFreePool,1) ++ ++wstdcall void WIN_FUNC(ExInitializeNPagedLookasideList,7) ++ (struct npaged_lookaside_list *lookaside, ++ LOOKASIDE_ALLOC_FUNC *alloc_func, LOOKASIDE_FREE_FUNC *free_func, ++ ULONG flags, SIZE_T size, ULONG tag, USHORT depth) ++{ ++ ENTER3("lookaside: %p, size: %zu, flags: %u, head: %p, " ++ "alloc: %p, free: %p", lookaside, size, flags, ++ lookaside, alloc_func, free_func); ++ ++ memset(lookaside, 0, sizeof(*lookaside)); ++ ++ lookaside->size = size; ++ lookaside->tag = tag; ++ lookaside->depth = 4; ++ lookaside->maxdepth = 256; ++ lookaside->pool_type = NonPagedPool; ++ ++ if (alloc_func) ++ lookaside->alloc_func = alloc_func; ++ else ++ lookaside->alloc_func = WIN_FUNC_PTR(ExAllocatePoolWithTag,3); ++ if (free_func) ++ lookaside->free_func = free_func; ++ else ++ lookaside->free_func = WIN_FUNC_PTR(ExFreePool,1); ++ ++#ifndef CONFIG_X86_64 ++ nt_spin_lock_init(&lookaside->obsolete); ++#endif ++ EXIT3(return); ++} ++ ++wstdcall void WIN_FUNC(ExDeleteNPagedLookasideList,1) ++ (struct npaged_lookaside_list *lookaside) ++{ ++ struct nt_slist *entry; ++ ++ ENTER3("lookaside = %p", lookaside); ++ while ((entry = ExpInterlockedPopEntrySList(&lookaside->head))) ++ LIN2WIN1(lookaside->free_func, entry); ++ EXIT3(return); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ExCreateCallback,4) ++ (struct callback_object **object, struct object_attributes *attributes, ++ BOOLEAN create, BOOLEAN allow_multiple_callbacks) ++{ ++ struct callback_object *obj; ++ ++ ENTER2(""); ++ spin_lock_bh(&ntoskernel_lock); ++ nt_list_for_each_entry(obj, &callback_objects, callback_funcs) { ++ if (obj->attributes == attributes) { ++ spin_unlock_bh(&ntoskernel_lock); ++ *object = obj; ++ return STATUS_SUCCESS; ++ } ++ } ++ spin_unlock_bh(&ntoskernel_lock); ++ obj = allocate_object(sizeof(struct callback_object), ++ OBJECT_TYPE_CALLBACK, NULL); ++ if (!obj) ++ EXIT2(return STATUS_INSUFFICIENT_RESOURCES); ++ InitializeListHead(&obj->callback_funcs); ++ nt_spin_lock_init(&obj->lock); ++ obj->allow_multiple_callbacks = allow_multiple_callbacks; ++ obj->attributes = attributes; ++ *object = obj; ++ EXIT2(return STATUS_SUCCESS); ++} ++ ++wstdcall void *WIN_FUNC(ExRegisterCallback,3) ++ (struct callback_object *object, PCALLBACK_FUNCTION func, void *context) ++{ ++ struct callback_func *callback; ++ KIRQL irql; ++ ++ ENTER2(""); ++ irql = nt_spin_lock_irql(&object->lock, DISPATCH_LEVEL); ++ if (object->allow_multiple_callbacks == FALSE && ++ !IsListEmpty(&object->callback_funcs)) { ++ nt_spin_unlock_irql(&object->lock, irql); ++ EXIT2(return NULL); ++ } ++ nt_spin_unlock_irql(&object->lock, irql); ++ callback = kmalloc(sizeof(*callback), GFP_KERNEL); ++ if (!callback) { ++ ERROR("couldn't allocate memory"); ++ return NULL; ++ } ++ callback->func = func; ++ callback->context = context; ++ callback->object = object; ++ irql = nt_spin_lock_irql(&object->lock, DISPATCH_LEVEL); ++ InsertTailList(&object->callback_funcs, &callback->list); ++ nt_spin_unlock_irql(&object->lock, irql); ++ EXIT2(return callback); ++} ++ ++wstdcall void WIN_FUNC(ExUnregisterCallback,1) ++ (struct callback_func *callback) ++{ ++ struct callback_object *object; ++ KIRQL irql; ++ ++ ENTER3("%p", callback); ++ if (!callback) ++ return; ++ object = callback->object; ++ irql = nt_spin_lock_irql(&object->lock, DISPATCH_LEVEL); ++ RemoveEntryList(&callback->list); ++ nt_spin_unlock_irql(&object->lock, irql); ++ kfree(callback); ++ return; ++} ++ ++wstdcall void WIN_FUNC(ExNotifyCallback,3) ++ (struct callback_object *object, void *arg1, void *arg2) ++{ ++ struct callback_func *callback; ++ KIRQL irql; ++ ++ ENTER3("%p", object); ++ irql = nt_spin_lock_irql(&object->lock, DISPATCH_LEVEL); ++ nt_list_for_each_entry(callback, &object->callback_funcs, list) { ++ LIN2WIN3(callback->func, callback->context, arg1, arg2); ++ } ++ nt_spin_unlock_irql(&object->lock, irql); ++ return; ++} ++ ++/* check and set signaled state; should be called with dispatcher_lock held */ ++/* @grab indicates if the event should be grabbed or checked ++ * - note that a semaphore may stay in signaled state for multiple ++ * 'grabs' if the count is > 1 */ ++static int grab_object(struct dispatcher_header *dh, ++ struct task_struct *thread, int grab) ++{ ++ EVENTTRACE("%p, %p, %d, %d", dh, thread, grab, dh->signal_state); ++ if (unlikely(is_mutex_object(dh))) { ++ struct nt_mutex *nt_mutex; ++ nt_mutex = container_of(dh, struct nt_mutex, dh); ++ EVENTTRACE("%p, %p, %d, %p, %d", nt_mutex, ++ nt_mutex->owner_thread, dh->signal_state, ++ thread, grab); ++ /* either no thread owns the mutex or this thread owns ++ * it */ ++ assert(dh->signal_state == 1 && nt_mutex->owner_thread == NULL); ++ assert(dh->signal_state < 1 && nt_mutex->owner_thread != NULL); ++ if ((dh->signal_state == 1 && nt_mutex->owner_thread == NULL) || ++ nt_mutex->owner_thread == thread) { ++ if (grab) { ++ dh->signal_state--; ++ nt_mutex->owner_thread = thread; ++ } ++ EVENTEXIT(return 1); ++ } ++ } else if (dh->signal_state > 0) { ++ /* to grab, decrement signal_state for synchronization ++ * or semaphore objects */ ++ if (grab && (is_synch_object(dh) || is_semaphore_object(dh))) ++ dh->signal_state--; ++ EVENTEXIT(return 1); ++ } ++ EVENTEXIT(return 0); ++} ++ ++/* this function should be called holding dispatcher_lock */ ++static void object_signaled(struct dispatcher_header *dh) ++{ ++ struct nt_list *cur, *next; ++ struct wait_block *wb; ++ ++ EVENTENTER("%p", dh); ++ nt_list_for_each_safe(cur, next, &dh->wait_blocks) { ++ wb = container_of(cur, struct wait_block, list); ++ assert(wb->thread != NULL); ++ assert(wb->object == NULL); ++ if (!grab_object(dh, wb->thread, 1)) ++ continue; ++ EVENTTRACE("%p (%p): waking %p", dh, wb, wb->thread); ++ RemoveEntryList(cur); ++ wb->object = dh; ++ *(wb->wait_done) = 1; ++ wake_up_process(wb->thread); ++ } ++ EVENTEXIT(return); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(KeWaitForMultipleObjects,8) ++ (ULONG count, void *object[], enum wait_type wait_type, ++ KWAIT_REASON wait_reason, KPROCESSOR_MODE wait_mode, ++ BOOLEAN alertable, LARGE_INTEGER *timeout, ++ struct wait_block *wait_block_array) ++{ ++ int i, res = 0, wait_count, wait_done; ++ typeof(jiffies) wait_hz = 0; ++ struct wait_block *wb, wb_array[THREAD_WAIT_OBJECTS]; ++ struct dispatcher_header *dh; ++ KIRQL irql = current_irql(); ++ ++ EVENTENTER("%p, %d, %u, %p", current, count, wait_type, timeout); ++ ++ if (count > MAX_WAIT_OBJECTS || ++ (count > THREAD_WAIT_OBJECTS && wait_block_array == NULL)) ++ EVENTEXIT(return STATUS_INVALID_PARAMETER); ++ ++ if (wait_block_array == NULL) ++ wb = wb_array; ++ else ++ wb = wait_block_array; ++ ++ /* If *timeout == 0: In the case of WaitAny, if an object can ++ * be grabbed (object is in signaled state), grab and ++ * return. In the case of WaitAll, we have to first make sure ++ * all objects can be grabbed. If any/some of them can't be ++ * grabbed, either we return STATUS_TIMEOUT or wait for them, ++ * depending on how to satisfy wait. If all of them can be ++ * grabbed, we will grab them in the next loop below */ ++ ++ spin_lock_bh(&dispatcher_lock); ++ for (i = wait_count = 0; i < count; i++) { ++ dh = object[i]; ++ EVENTTRACE("%p: event %p (%d)", current, dh, dh->signal_state); ++ /* wait_type == 1 for WaitAny, 0 for WaitAll */ ++ if (grab_object(dh, current, wait_type)) { ++ if (wait_type == WaitAny) { ++ spin_unlock_bh(&dispatcher_lock); ++ EVENTEXIT(return STATUS_WAIT_0 + i); ++ } ++ } else { ++ EVENTTRACE("%p: wait for %p", current, dh); ++ wait_count++; ++ } ++ } ++ ++ if (timeout && *timeout == 0 && wait_count) { ++ spin_unlock_bh(&dispatcher_lock); ++ EVENTEXIT(return STATUS_TIMEOUT); ++ } ++ ++ /* get the list of objects the thread needs to wait on and add ++ * the thread on the wait list for each such object */ ++ /* if *timeout == 0, this step will grab all the objects */ ++ wait_done = 0; ++ for (i = 0; i < count; i++) { ++ dh = object[i]; ++ EVENTTRACE("%p: event %p (%d)", current, dh, dh->signal_state); ++ wb[i].object = NULL; ++ if (grab_object(dh, current, 1)) { ++ EVENTTRACE("%p: no wait for %p (%d)", ++ current, dh, dh->signal_state); ++ /* mark that we are not waiting on this object */ ++ wb[i].thread = NULL; ++ } else { ++ wb[i].wait_done = &wait_done; ++ wb[i].thread = current; ++ EVENTTRACE("%p: wait for %p", current, dh); ++ InsertTailList(&dh->wait_blocks, &wb[i].list); ++ } ++ } ++ spin_unlock_bh(&dispatcher_lock); ++ if (wait_count == 0) ++ EVENTEXIT(return STATUS_SUCCESS); ++ ++ assert(timeout == NULL || *timeout != 0); ++ if (timeout == NULL) ++ wait_hz = 0; ++ else ++ wait_hz = SYSTEM_TIME_TO_HZ(*timeout); ++ ++ if (irql >= DISPATCH_LEVEL) { ++ WARNING("attempt to wait with irql %d", irql); ++ EVENTEXIT(return STATUS_INVALID_PARAMETER); ++ } ++ EVENTTRACE("%p: sleep for %ld on %p", current, wait_hz, &wait_done); ++ /* we don't honor 'alertable' - according to description for ++ * this, even if waiting in non-alertable state, thread may be ++ * alerted in some circumstances */ ++ while (wait_count) { ++ res = wait_condition(wait_done, wait_hz, TASK_INTERRUPTIBLE); ++ spin_lock_bh(&dispatcher_lock); ++ EVENTTRACE("%p woke up: %d, %d", current, res, wait_done); ++ /* the event may have been set by the time ++ * wrap_wait_event returned and spinlock obtained, so ++ * don't rely on value of 'res' - check event status */ ++ if (!wait_done) { ++ assert(res <= 0); ++ /* timed out or interrupted; remove from wait list */ ++ for (i = 0; i < count; i++) { ++ if (!wb[i].thread) ++ continue; ++ EVENTTRACE("%p: timedout, dequeue %p (%p)", ++ current, object[i], wb[i].object); ++ assert(wb[i].object == NULL); ++ RemoveEntryList(&wb[i].list); ++ } ++ spin_unlock_bh(&dispatcher_lock); ++ if (res < 0) ++ EVENTEXIT(return STATUS_ALERTED); ++ else ++ EVENTEXIT(return STATUS_TIMEOUT); ++ } ++ assert(res > 0); ++ /* woken because object(s) signaled */ ++ for (i = 0; wait_count && i < count; i++) { ++ if (!wb[i].thread || !wb[i].object) ++ continue; ++ DBG_BLOCK(1) { ++ if (wb[i].object != object[i]) { ++ EVENTTRACE("oops %p != %p", ++ wb[i].object, object[i]); ++ continue; ++ } ++ } ++ wait_count--; ++ if (wait_type == WaitAny) { ++ int j; ++ /* done; remove from rest of wait list */ ++ for (j = i + 1; j < count; j++) { ++ if (wb[j].thread && !wb[j].object) ++ RemoveEntryList(&wb[j].list); ++ } ++ spin_unlock_bh(&dispatcher_lock); ++ EVENTEXIT(return STATUS_WAIT_0 + i); ++ } ++ } ++ wait_done = 0; ++ spin_unlock_bh(&dispatcher_lock); ++ if (wait_count == 0) ++ EVENTEXIT(return STATUS_SUCCESS); ++ ++ /* this thread is still waiting for more objects, so ++ * let it wait for remaining time and those objects */ ++ if (timeout) ++ wait_hz = res; ++ else ++ wait_hz = 0; ++ } ++ /* should never reach here, but compiler wants return value */ ++ ERROR("%p: wait_hz: %ld", current, wait_hz); ++ EVENTEXIT(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(KeWaitForSingleObject,5) ++ (void *object, KWAIT_REASON wait_reason, KPROCESSOR_MODE wait_mode, ++ BOOLEAN alertable, LARGE_INTEGER *timeout) ++{ ++ return KeWaitForMultipleObjects(1, &object, WaitAny, wait_reason, ++ wait_mode, alertable, timeout, NULL); ++} ++ ++wstdcall void WIN_FUNC(KeInitializeEvent,3) ++ (struct nt_event *nt_event, enum event_type type, BOOLEAN state) ++{ ++ EVENTENTER("event = %p, type = %d, state = %d", nt_event, type, state); ++ initialize_object(&nt_event->dh, (enum dh_type)type, state); ++ EVENTEXIT(return); ++} ++ ++wstdcall LONG WIN_FUNC(KeSetEvent,3) ++ (struct nt_event *nt_event, KPRIORITY incr, BOOLEAN wait) ++{ ++ LONG old_state; ++ ++ EVENTENTER("%p, %d", nt_event, nt_event->dh.type); ++ if (wait == TRUE) ++ WARNING("wait = %d, not yet implemented", wait); ++ spin_lock_bh(&dispatcher_lock); ++ old_state = nt_event->dh.signal_state; ++ nt_event->dh.signal_state = 1; ++ if (old_state == 0) ++ object_signaled(&nt_event->dh); ++ spin_unlock_bh(&dispatcher_lock); ++ EVENTEXIT(return old_state); ++} ++ ++wstdcall void WIN_FUNC(KeClearEvent,1) ++ (struct nt_event *nt_event) ++{ ++ EVENTENTER("%p", nt_event); ++ nt_event->dh.signal_state = 0; ++ EVENTEXIT(return); ++} ++ ++wstdcall LONG WIN_FUNC(KeResetEvent,1) ++ (struct nt_event *nt_event) ++{ ++ LONG old_state; ++ ++ EVENTENTER("%p", nt_event); ++ old_state = xchg(&nt_event->dh.signal_state, 0); ++ EVENTEXIT(return old_state); ++} ++ ++wstdcall LONG WIN_FUNC(KeReadStateEvent,1) ++ (struct nt_event *nt_event) ++{ ++ LONG state; ++ ++ state = nt_event->dh.signal_state; ++ EVENTTRACE("%d", state); ++ return state; ++} ++ ++wstdcall void WIN_FUNC(KeInitializeMutex,2) ++ (struct nt_mutex *mutex, ULONG level) ++{ ++ EVENTENTER("%p", mutex); ++ initialize_object(&mutex->dh, MutexObject, 1); ++ mutex->dh.size = sizeof(*mutex); ++ InitializeListHead(&mutex->list); ++ mutex->abandoned = FALSE; ++ mutex->apc_disable = 1; ++ mutex->owner_thread = NULL; ++ EVENTEXIT(return); ++} ++ ++wstdcall LONG WIN_FUNC(KeReleaseMutex,2) ++ (struct nt_mutex *mutex, BOOLEAN wait) ++{ ++ LONG ret; ++ struct task_struct *thread; ++ ++ EVENTENTER("%p, %d, %p", mutex, wait, current); ++ if (wait == TRUE) ++ WARNING("wait: %d", wait); ++ thread = current; ++ spin_lock_bh(&dispatcher_lock); ++ EVENTTRACE("%p, %p, %p, %d", mutex, thread, mutex->owner_thread, ++ mutex->dh.signal_state); ++ if ((mutex->owner_thread == thread) && (mutex->dh.signal_state <= 0)) { ++ ret = mutex->dh.signal_state++; ++ if (ret == 0) { ++ mutex->owner_thread = NULL; ++ object_signaled(&mutex->dh); ++ } ++ } else { ++ ret = STATUS_MUTANT_NOT_OWNED; ++ WARNING("invalid mutex: %p, %p, %p", mutex, mutex->owner_thread, ++ thread); ++ } ++ EVENTTRACE("%p, %p, %p, %d", mutex, thread, mutex->owner_thread, ++ mutex->dh.signal_state); ++ spin_unlock_bh(&dispatcher_lock); ++ EVENTEXIT(return ret); ++} ++ ++wstdcall void WIN_FUNC(KeInitializeSemaphore,3) ++ (struct nt_semaphore *semaphore, LONG count, LONG limit) ++{ ++ EVENTENTER("%p: %d", semaphore, count); ++ /* if limit > 1, we need to satisfy as many waits (until count ++ * becomes 0); so we keep decrementing count every time a wait ++ * is satisfied */ ++ initialize_object(&semaphore->dh, SemaphoreObject, count); ++ semaphore->dh.size = sizeof(*semaphore); ++ semaphore->limit = limit; ++ EVENTEXIT(return); ++} ++ ++wstdcall LONG WIN_FUNC(KeReleaseSemaphore,4) ++ (struct nt_semaphore *semaphore, KPRIORITY incr, LONG adjustment, ++ BOOLEAN wait) ++{ ++ LONG ret; ++ ++ EVENTENTER("%p", semaphore); ++ spin_lock_bh(&dispatcher_lock); ++ ret = semaphore->dh.signal_state; ++ assert(ret >= 0); ++ if (semaphore->dh.signal_state + adjustment <= semaphore->limit) ++ semaphore->dh.signal_state += adjustment; ++ else { ++ WARNING("releasing %d over limit %d", adjustment, ++ semaphore->limit); ++ semaphore->dh.signal_state = semaphore->limit; ++ } ++ if (semaphore->dh.signal_state > 0) ++ object_signaled(&semaphore->dh); ++ spin_unlock_bh(&dispatcher_lock); ++ EVENTEXIT(return ret); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(KeDelayExecutionThread,3) ++ (KPROCESSOR_MODE wait_mode, BOOLEAN alertable, LARGE_INTEGER *interval) ++{ ++ int res; ++ long timeout; ++ ++ if (wait_mode != 0) ++ ERROR("invalid wait_mode %d", wait_mode); ++ ++ timeout = SYSTEM_TIME_TO_HZ(*interval); ++ EVENTTRACE("%p, %lld, %ld", current, *interval, timeout); ++ if (timeout <= 0) ++ EVENTEXIT(return STATUS_SUCCESS); ++ ++ if (alertable) ++ set_current_state(TASK_INTERRUPTIBLE); ++ else ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ ++ res = schedule_timeout(timeout); ++ EVENTTRACE("%p, %d", current, res); ++ if (res == 0) ++ EVENTEXIT(return STATUS_SUCCESS); ++ else ++ EVENTEXIT(return STATUS_ALERTED); ++} ++ ++wstdcall ULONGLONG WIN_FUNC(KeQueryInterruptTime,0) ++ (void) ++{ ++ EXIT5(return jiffies * TICKSPERJIFFY); ++} ++ ++wstdcall ULONG WIN_FUNC(KeQueryTimeIncrement,0) ++ (void) ++{ ++ EXIT5(return TICKSPERSEC / HZ); ++} ++ ++wstdcall void WIN_FUNC(KeQuerySystemTime,1) ++ (LARGE_INTEGER *time) ++{ ++ *time = ticks_1601(); ++ TRACE5("%llu, %lu", *time, jiffies); ++} ++ ++wstdcall void WIN_FUNC(KeQueryTickCount,1) ++ (LARGE_INTEGER *count) ++{ ++ *count = jiffies; ++} ++ ++wstdcall LARGE_INTEGER WIN_FUNC(KeQueryPerformanceCounter,1) ++ (LARGE_INTEGER *counter) ++{ ++ if (counter) ++ *counter = HZ; ++ return jiffies; ++} ++ ++wstdcall KAFFINITY WIN_FUNC(KeQueryActiveProcessors,0) ++ (void) ++{ ++ int i, n; ++ KAFFINITY bits = 0; ++ n = num_online_cpus(); ++ for (i = 0; i < n; i++) ++ bits = (bits << 1) | 1; ++ return bits; ++} ++ ++struct nt_thread *get_current_nt_thread(void) ++{ ++ struct task_struct *task = current; ++ struct nt_thread *thread; ++ struct common_object_header *header; ++ ++ TRACE6("task: %p", task); ++ thread = NULL; ++ spin_lock_bh(&ntoskernel_lock); ++ nt_list_for_each_entry(header, &object_list, list) { ++ TRACE6("%p, %d", header, header->type); ++ if (header->type != OBJECT_TYPE_NT_THREAD) ++ break; ++ thread = HEADER_TO_OBJECT(header); ++ TRACE6("%p, %p", thread, thread->task); ++ if (thread->task == task) ++ break; ++ else ++ thread = NULL; ++ } ++ spin_unlock_bh(&ntoskernel_lock); ++ if (thread == NULL) ++ TRACE4("couldn't find thread for task %p, %d", task, task->pid); ++ TRACE6("%p", thread); ++ return thread; ++} ++ ++static struct task_struct *get_nt_thread_task(struct nt_thread *thread) ++{ ++ struct task_struct *task; ++ struct common_object_header *header; ++ ++ TRACE6("%p", thread); ++ task = NULL; ++ spin_lock_bh(&ntoskernel_lock); ++ nt_list_for_each_entry(header, &object_list, list) { ++ TRACE6("%p, %d", header, header->type); ++ if (header->type != OBJECT_TYPE_NT_THREAD) ++ break; ++ if (thread == HEADER_TO_OBJECT(header)) { ++ task = thread->task; ++ break; ++ } ++ } ++ spin_unlock_bh(&ntoskernel_lock); ++ if (task == NULL) ++ TRACE2("%p: couldn't find task for %p", current, thread); ++ return task; ++} ++ ++static struct nt_thread *create_nt_thread(struct task_struct *task) ++{ ++ struct nt_thread *thread; ++ thread = allocate_object(sizeof(*thread), OBJECT_TYPE_NT_THREAD, NULL); ++ if (!thread) { ++ ERROR("couldn't allocate thread object"); ++ EXIT2(return NULL); ++ } ++ thread->task = task; ++ if (task) ++ thread->pid = task->pid; ++ else ++ thread->pid = 0; ++ nt_spin_lock_init(&thread->lock); ++ InitializeListHead(&thread->irps); ++ initialize_object(&thread->dh, ThreadObject, 0); ++ thread->dh.size = sizeof(*thread); ++ thread->prio = LOW_PRIORITY; ++ return thread; ++} ++ ++wstdcall struct nt_thread *WIN_FUNC(KeGetCurrentThread,0) ++ (void) ++{ ++ struct nt_thread *thread = get_current_nt_thread(); ++ TRACE2("%p, %p", thread, current); ++ return thread; ++} ++ ++wstdcall KPRIORITY WIN_FUNC(KeQueryPriorityThread,1) ++ (struct nt_thread *thread) ++{ ++ KPRIORITY prio; ++ struct task_struct *task; ++ ++ TRACE2("%p", thread); ++#ifdef CONFIG_X86_64 ++ /* sis163u driver for amd64 passes 0x1f from thread created by ++ * PsCreateSystemThread - no idea what is 0x1f */ ++ if (thread == (void *)0x1f) ++ thread = get_current_nt_thread(); ++#endif ++ if (!thread) { ++ TRACE2("invalid thread"); ++ EXIT2(return LOW_REALTIME_PRIORITY); ++ } ++ task = get_nt_thread_task(thread); ++ if (!task) { ++ TRACE2("couldn't find task for thread: %p", thread); ++ EXIT2(return LOW_REALTIME_PRIORITY); ++ } ++ ++ prio = thread->prio; ++ ++ TRACE2("%d", prio); ++ return prio; ++} ++ ++wstdcall KPRIORITY WIN_FUNC(KeSetPriorityThread,2) ++ (struct nt_thread *thread, KPRIORITY prio) ++{ ++ KPRIORITY old_prio; ++ struct task_struct *task; ++ ++ TRACE2("thread: %p, priority = %u", thread, prio); ++#ifdef CONFIG_X86_64 ++ if (thread == (void *)0x1f) ++ thread = get_current_nt_thread(); ++#endif ++ if (!thread) { ++ TRACE2("invalid thread"); ++ EXIT2(return LOW_REALTIME_PRIORITY); ++ } ++ task = get_nt_thread_task(thread); ++ if (!task) { ++ TRACE2("couldn't find task for thread: %p", thread); ++ EXIT2(return LOW_REALTIME_PRIORITY); ++ } ++ ++ old_prio = thread->prio; ++ thread->prio = prio; ++ ++ TRACE2("%d, %d", old_prio, thread->prio); ++ return old_prio; ++} ++ ++struct thread_trampoline { ++ void (*func)(void *) wstdcall; ++ void *ctx; ++ struct nt_thread *thread; ++ struct completion started; ++}; ++ ++static int ntdriver_thread(void *data) ++{ ++ struct thread_trampoline *thread_tramp = data; ++ /* yes, a tramp! */ ++ typeof(thread_tramp->func) func = thread_tramp->func; ++ typeof(thread_tramp->ctx) ctx = thread_tramp->ctx; ++ ++ thread_tramp->thread->task = current; ++ thread_tramp->thread->pid = current->pid; ++ TRACE2("thread: %p, task: %p (%d)", thread_tramp->thread, ++ current, current->pid); ++ complete(&thread_tramp->started); ++ ++#ifdef PF_NOFREEZE ++ current->flags |= PF_NOFREEZE; ++#endif ++ strncpy(current->comm, "ntdriver", sizeof(current->comm)); ++ current->comm[sizeof(current->comm)-1] = 0; ++ LIN2WIN1(func, ctx); ++ ERROR("task: %p", current); ++ return 0; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(PsCreateSystemThread,7) ++ (void **handle, ULONG access, void *obj_attr, void *process, ++ void *client_id, void (*func)(void *) wstdcall, void *ctx) ++{ ++ struct thread_trampoline thread_tramp; ++ ++ ENTER2("handle = %p, access = %u, obj_attr = %p, process = %p, " ++ "client_id = %p, func = %p, context = %p", handle, access, ++ obj_attr, process, client_id, func, ctx); ++ ++ thread_tramp.thread = create_nt_thread(NULL); ++ if (!thread_tramp.thread) { ++ ERROR("couldn't allocate thread object"); ++ EXIT2(return STATUS_RESOURCES); ++ } ++ TRACE2("thread: %p", thread_tramp.thread); ++ thread_tramp.func = func; ++ thread_tramp.ctx = ctx; ++ init_completion(&thread_tramp.started); ++ ++ thread_tramp.thread->task = kthread_run(ntdriver_thread, ++ &thread_tramp, "ntdriver"); ++ if (IS_ERR(thread_tramp.thread->task)) { ++ free_object(thread_tramp.thread); ++ EXIT2(return STATUS_FAILURE); ++ } ++ TRACE2("created task: %p", thread_tramp.thread->task); ++ ++ wait_for_completion(&thread_tramp.started); ++ *handle = OBJECT_TO_HEADER(thread_tramp.thread); ++ TRACE2("created thread: %p, %p", thread_tramp.thread, *handle); ++ EXIT2(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(PsTerminateSystemThread,1) ++ (NTSTATUS status) ++{ ++ struct nt_thread *thread; ++ ++ TRACE2("%p, %08X", current, status); ++ thread = get_current_nt_thread(); ++ TRACE2("%p", thread); ++ if (thread) { ++ KeSetEvent((struct nt_event *)&thread->dh, 0, FALSE); ++ while (1) { ++ struct nt_list *ent; ++ struct irp *irp; ++ KIRQL irql; ++ irql = nt_spin_lock_irql(&thread->lock, DISPATCH_LEVEL); ++ ent = RemoveHeadList(&thread->irps); ++ nt_spin_unlock_irql(&thread->lock, irql); ++ if (!ent) ++ break; ++ irp = container_of(ent, struct irp, thread_list); ++ IOTRACE("%p", irp); ++ IoCancelIrp(irp); ++ } ++ /* the driver may later query this status with ++ * ZwQueryInformationThread */ ++ thread->status = status; ++ } else ++ ERROR("couldn't find thread for task: %p", current); ++ ++ complete_and_exit(NULL, status); ++ ERROR("oops: %p, %d", thread->task, thread->pid); ++ return STATUS_FAILURE; ++} ++ ++wstdcall BOOLEAN WIN_FUNC(KeRemoveEntryDeviceQueue,2) ++ (struct kdevice_queue *dev_queue, struct kdevice_queue_entry *entry) ++{ ++ struct kdevice_queue_entry *e; ++ KIRQL irql; ++ ++ irql = nt_spin_lock_irql(&dev_queue->lock, DISPATCH_LEVEL); ++ nt_list_for_each_entry(e, &dev_queue->list, list) { ++ if (e == entry) { ++ RemoveEntryList(&e->list); ++ nt_spin_unlock_irql(&dev_queue->lock, irql); ++ return TRUE; ++ } ++ } ++ nt_spin_unlock_irql(&dev_queue->lock, irql); ++ return FALSE; ++} ++ ++wstdcall BOOLEAN WIN_FUNC(KeSynchronizeExecution,3) ++ (struct kinterrupt *interrupt, PKSYNCHRONIZE_ROUTINE synch_routine, ++ void *ctx) ++{ ++ BOOLEAN ret; ++ unsigned long flags; ++ ++ nt_spin_lock_irqsave(interrupt->actual_lock, flags); ++ ret = LIN2WIN1(synch_routine, ctx); ++ nt_spin_unlock_irqrestore(interrupt->actual_lock, flags); ++ TRACE6("%d", ret); ++ return ret; ++} ++ ++wstdcall BOOLEAN WIN_FUNC(KeRegisterBugCheckReasonCallback,4) ++ (void *callback_record, void *callback_routine, UINT reason, ++ char *component) ++{ ++ TRACE1("callback_record: %p, callback_routine: %p, reason: %d, " ++ "component: %s", callback_record, callback_routine, reason, ++ component); ++ TODO(); ++ return FALSE; ++} ++ ++wstdcall BOOLEAN WIN_FUNC(KeDeregisterBugCheckReasonCallback,1) ++ (void *callback_record) ++{ ++ TRACE1("callback_record: %p", callback_record); ++ TODO(); ++ return TRUE; ++} ++ ++wstdcall void *WIN_FUNC(MmAllocateContiguousMemorySpecifyCache,5) ++ (SIZE_T size, PHYSICAL_ADDRESS lowest, PHYSICAL_ADDRESS highest, ++ PHYSICAL_ADDRESS boundary, enum memory_caching_type cache_type) ++{ ++ void *addr; ++ gfp_t flags; ++ ++ ENTER2("%zu, 0x%llx, 0x%llx, 0x%llx, %d", size, lowest, ++ highest, boundary, cache_type); ++ flags = irql_gfp(); ++ addr = wrap_get_free_pages(flags, size); ++ TRACE2("%p, %zu, 0x%x", addr, size, flags); ++ if (addr && ((virt_to_phys(addr) + size) <= highest)) ++ EXIT2(return addr); ++#ifdef CONFIG_X86_64 ++ /* GFP_DMA is really only 16MB even on x86-64, but there is no ++ * other zone available */ ++ if (highest <= DMA_BIT_MASK(31)) ++ flags |= __GFP_DMA; ++ else if (highest <= DMA_BIT_MASK(32)) ++ flags |= __GFP_DMA32; ++#else ++ if (highest <= DMA_BIT_MASK(24)) ++ flags |= __GFP_DMA; ++ else if (highest > DMA_BIT_MASK(30)) ++ flags |= __GFP_HIGHMEM; ++#endif ++ if (addr) ++ free_pages((unsigned long)addr, get_order(size)); ++ addr = wrap_get_free_pages(flags, size); ++ TRACE2("%p, %zu, 0x%x", addr, size, flags); ++ return addr; ++} ++ ++wstdcall void WIN_FUNC(MmFreeContiguousMemorySpecifyCache,3) ++ (void *base, SIZE_T size, enum memory_caching_type cache_type) ++{ ++ TRACE2("%p, %zu", base, size); ++ free_pages((unsigned long)base, get_order(size)); ++} ++ ++wstdcall PHYSICAL_ADDRESS WIN_FUNC(MmGetPhysicalAddress,1) ++ (void *base) ++{ ++ unsigned long phy = virt_to_phys(base); ++ TRACE2("%p, %p", base, (void *)phy); ++ return phy; ++} ++ ++/* Atheros card with pciid 168C:0014 calls this function with 0xf0000 ++ * and 0xf6ef0 address, and then check for things that seem to be ++ * related to ACPI: "_SM_" and "_DMI_". This may be the hack they do ++ * to check if this card is installed in IBM thinkpads; we can ++ * probably get this device to work if we create a buffer with the ++ * strings as required by the driver and return virtual address for ++ * that address instead */ ++wstdcall void __iomem *WIN_FUNC(MmMapIoSpace,3) ++ (PHYSICAL_ADDRESS phys_addr, SIZE_T size, ++ enum memory_caching_type cache) ++{ ++ void __iomem *virt; ++ ENTER1("cache type: %d", cache); ++ if (cache == MmCached) ++ virt = ioremap(phys_addr, size); ++ else ++ virt = ioremap_nocache(phys_addr, size); ++ TRACE1("%llx, %zu, %p", phys_addr, size, virt); ++ return virt; ++} ++ ++wstdcall void WIN_FUNC(MmUnmapIoSpace,2) ++ (void __iomem *addr, SIZE_T size) ++{ ++ ENTER1("%p, %zu", addr, size); ++ iounmap(addr); ++ return; ++} ++ ++wstdcall ULONG WIN_FUNC(MmSizeOfMdl,2) ++ (void *base, ULONG length) ++{ ++ return sizeof(struct mdl) + ++ (sizeof(PFN_NUMBER) * SPAN_PAGES(base, length)); ++} ++ ++struct mdl *allocate_init_mdl(void *virt, ULONG length) ++{ ++ struct wrap_mdl *wrap_mdl; ++ struct mdl *mdl; ++ int mdl_size = MmSizeOfMdl(virt, length); ++ ++ if (mdl_size <= MDL_CACHE_SIZE) { ++ wrap_mdl = kmem_cache_alloc(mdl_cache, irql_gfp()); ++ if (!wrap_mdl) ++ return NULL; ++ spin_lock_bh(&dispatcher_lock); ++ InsertHeadList(&wrap_mdl_list, &wrap_mdl->list); ++ spin_unlock_bh(&dispatcher_lock); ++ mdl = wrap_mdl->mdl; ++ TRACE3("allocated mdl from cache: %p(%p), %p(%d)", ++ wrap_mdl, mdl, virt, length); ++ memset(mdl, 0, MDL_CACHE_SIZE); ++ MmInitializeMdl(mdl, virt, length); ++ /* mark the MDL as allocated from cache pool so when ++ * it is freed, we free it back to the pool */ ++ mdl->flags = MDL_ALLOCATED_FIXED_SIZE | MDL_CACHE_ALLOCATED; ++ } else { ++ wrap_mdl = ++ kmalloc(sizeof(*wrap_mdl) + mdl_size, irql_gfp()); ++ if (!wrap_mdl) ++ return NULL; ++ mdl = wrap_mdl->mdl; ++ TRACE3("allocated mdl from memory: %p(%p), %p(%d)", ++ wrap_mdl, mdl, virt, length); ++ spin_lock_bh(&dispatcher_lock); ++ InsertHeadList(&wrap_mdl_list, &wrap_mdl->list); ++ spin_unlock_bh(&dispatcher_lock); ++ memset(mdl, 0, mdl_size); ++ MmInitializeMdl(mdl, virt, length); ++ mdl->flags = MDL_ALLOCATED_FIXED_SIZE; ++ } ++ return mdl; ++} ++ ++void free_mdl(struct mdl *mdl) ++{ ++ /* A driver may allocate Mdl with NdisAllocateBuffer and free ++ * with IoFreeMdl (e.g., 64-bit Broadcom). Since we need to ++ * treat buffers allocated with Ndis calls differently, we ++ * must call NdisFreeBuffer if it is allocated with Ndis ++ * function. We set 'pool' field in Ndis functions. */ ++ if (!mdl) ++ return; ++ if (mdl->pool) ++ NdisFreeBuffer(mdl); ++ else { ++ struct wrap_mdl *wrap_mdl = (struct wrap_mdl *) ++ ((char *)mdl - offsetof(struct wrap_mdl, mdl)); ++ spin_lock_bh(&dispatcher_lock); ++ RemoveEntryList(&wrap_mdl->list); ++ spin_unlock_bh(&dispatcher_lock); ++ ++ if (mdl->flags & MDL_CACHE_ALLOCATED) { ++ TRACE3("freeing mdl cache: %p, %p, %p", ++ wrap_mdl, mdl, mdl->mappedsystemva); ++ kmem_cache_free(mdl_cache, wrap_mdl); ++ } else { ++ TRACE3("freeing mdl: %p, %p, %p", ++ wrap_mdl, mdl, mdl->mappedsystemva); ++ kfree(wrap_mdl); ++ } ++ } ++ return; ++} ++ ++wstdcall void WIN_FUNC(IoBuildPartialMdl,4) ++ (struct mdl *source, struct mdl *target, void *virt, ULONG length) ++{ ++ MmInitializeMdl(target, virt, length); ++ target->flags |= MDL_PARTIAL; ++} ++ ++wstdcall void WIN_FUNC(MmBuildMdlForNonPagedPool,1) ++ (struct mdl *mdl) ++{ ++ PFN_NUMBER *mdl_pages; ++ int i, n; ++ ++ ENTER4("%p", mdl); ++ /* already mapped */ ++// mdl->mappedsystemva = MmGetMdlVirtualAddress(mdl); ++ mdl->flags |= MDL_SOURCE_IS_NONPAGED_POOL; ++ TRACE4("%p, %p, %p, %d, %d", mdl, mdl->mappedsystemva, mdl->startva, ++ mdl->byteoffset, mdl->bytecount); ++ n = SPAN_PAGES(MmGetSystemAddressForMdl(mdl), MmGetMdlByteCount(mdl)); ++ if (n > MDL_CACHE_PAGES) ++ WARNING("%p, %d, %d", MmGetSystemAddressForMdl(mdl), ++ MmGetMdlByteCount(mdl), n); ++ mdl_pages = MmGetMdlPfnArray(mdl); ++ for (i = 0; i < n; i++) ++ mdl_pages[i] = (ULONG_PTR)mdl->startva + (i * PAGE_SIZE); ++ EXIT4(return); ++} ++ ++wstdcall void *WIN_FUNC(MmMapLockedPages,2) ++ (struct mdl *mdl, KPROCESSOR_MODE access_mode) ++{ ++ /* already mapped */ ++// mdl->mappedsystemva = MmGetMdlVirtualAddress(mdl); ++ mdl->flags |= MDL_MAPPED_TO_SYSTEM_VA; ++ /* what is the need for MDL_PARTIAL_HAS_BEEN_MAPPED? */ ++ if (mdl->flags & MDL_PARTIAL) ++ mdl->flags |= MDL_PARTIAL_HAS_BEEN_MAPPED; ++ return mdl->mappedsystemva; ++} ++ ++wstdcall void *WIN_FUNC(MmMapLockedPagesSpecifyCache,6) ++ (struct mdl *mdl, KPROCESSOR_MODE access_mode, ++ enum memory_caching_type cache_type, void *base_address, ++ ULONG bug_check, enum mm_page_priority priority) ++{ ++ return MmMapLockedPages(mdl, access_mode); ++} ++ ++wstdcall void WIN_FUNC(MmUnmapLockedPages,2) ++ (void *base, struct mdl *mdl) ++{ ++ mdl->flags &= ~MDL_MAPPED_TO_SYSTEM_VA; ++ return; ++} ++ ++wstdcall void WIN_FUNC(MmProbeAndLockPages,3) ++ (struct mdl *mdl, KPROCESSOR_MODE access_mode, ++ enum lock_operation operation) ++{ ++ /* already locked */ ++ mdl->flags |= MDL_PAGES_LOCKED; ++ return; ++} ++ ++wstdcall void WIN_FUNC(MmUnlockPages,1) ++ (struct mdl *mdl) ++{ ++ mdl->flags &= ~MDL_PAGES_LOCKED; ++ return; ++} ++ ++wstdcall BOOLEAN WIN_FUNC(MmIsAddressValid,1) ++ (void *virt_addr) ++{ ++ if (virt_addr_valid(virt_addr)) ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++wstdcall void *WIN_FUNC(MmLockPagableDataSection,1) ++ (void *address) ++{ ++ return address; ++} ++ ++wstdcall void WIN_FUNC(MmUnlockPagableImageSection,1) ++ (void *handle) ++{ ++ return; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ObReferenceObjectByHandle,6) ++ (void *handle, ACCESS_MASK desired_access, void *obj_type, ++ KPROCESSOR_MODE access_mode, void **object, void *handle_info) ++{ ++ struct common_object_header *hdr; ++ ++ TRACE2("%p", handle); ++ hdr = HANDLE_TO_HEADER(handle); ++ atomic_inc_var(hdr->ref_count); ++ *object = HEADER_TO_OBJECT(hdr); ++ TRACE2("%p, %p, %d, %p", hdr, object, hdr->ref_count, *object); ++ return STATUS_SUCCESS; ++} ++ ++/* DDK doesn't say if return value should be before incrementing or ++ * after incrementing reference count, but according to #reactos ++ * developers, it should be return value after incrementing */ ++wfastcall LONG WIN_FUNC(ObfReferenceObject,1) ++ (void *object) ++{ ++ struct common_object_header *hdr; ++ LONG ret; ++ ++ hdr = OBJECT_TO_HEADER(object); ++ ret = post_atomic_add(hdr->ref_count, 1); ++ TRACE2("%p, %d, %p", hdr, hdr->ref_count, object); ++ return ret; ++} ++ ++static int dereference_object(void *object) ++{ ++ struct common_object_header *hdr; ++ int ref_count; ++ ++ ENTER2("object: %p", object); ++ hdr = OBJECT_TO_HEADER(object); ++ TRACE2("hdr: %p", hdr); ++ ref_count = post_atomic_add(hdr->ref_count, -1); ++ TRACE2("object: %p, %d", object, ref_count); ++ if (ref_count < 0) ++ ERROR("invalid object: %p (%d)", object, ref_count); ++ if (ref_count <= 0) { ++ free_object(object); ++ return 1; ++ } else ++ return 0; ++} ++ ++wfastcall void WIN_FUNC(ObfDereferenceObject,1) ++ (void *object) ++{ ++ TRACE2("%p", object); ++ dereference_object(object); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwCreateFile,11) ++ (void **handle, ACCESS_MASK access_mask, ++ struct object_attributes *obj_attr, struct io_status_block *iosb, ++ LARGE_INTEGER *size, ULONG file_attr, ULONG share_access, ++ ULONG create_disposition, ULONG create_options, void *ea_buffer, ++ ULONG ea_length) ++{ ++ struct common_object_header *coh; ++ struct file_object *fo; ++ struct ansi_string ansi; ++ struct wrap_bin_file *bin_file; ++ char *file_basename; ++ NTSTATUS status; ++ ++ spin_lock_bh(&ntoskernel_lock); ++ nt_list_for_each_entry(coh, &object_list, list) { ++ if (coh->type != OBJECT_TYPE_FILE) ++ continue; ++ /* TODO: check if file is opened in shared mode */ ++ if (!RtlCompareUnicodeString(&coh->name, obj_attr->name, TRUE)) { ++ fo = HEADER_TO_OBJECT(coh); ++ bin_file = fo->wrap_bin_file; ++ *handle = coh; ++ spin_unlock_bh(&ntoskernel_lock); ++ ObReferenceObject(fo); ++ iosb->status = FILE_OPENED; ++ iosb->info = bin_file->size; ++ EXIT2(return STATUS_SUCCESS); ++ } ++ } ++ spin_unlock_bh(&ntoskernel_lock); ++ ++ if (RtlUnicodeStringToAnsiString(&ansi, obj_attr->name, TRUE) != ++ STATUS_SUCCESS) ++ EXIT2(return STATUS_INSUFFICIENT_RESOURCES); ++ ++ file_basename = strrchr(ansi.buf, '\\'); ++ if (file_basename) ++ file_basename++; ++ else ++ file_basename = ansi.buf; ++ TRACE2("file: '%s', '%s'", ansi.buf, file_basename); ++ ++ fo = allocate_object(sizeof(struct file_object), OBJECT_TYPE_FILE, ++ obj_attr->name); ++ if (!fo) { ++ RtlFreeAnsiString(&ansi); ++ iosb->status = STATUS_INSUFFICIENT_RESOURCES; ++ iosb->info = 0; ++ EXIT2(return STATUS_FAILURE); ++ } ++ coh = OBJECT_TO_HEADER(fo); ++ bin_file = get_bin_file(file_basename); ++ if (bin_file) { ++ TRACE2("%s, %s", bin_file->name, file_basename); ++ fo->flags = FILE_OPENED; ++ } else if (access_mask & FILE_WRITE_DATA) { ++ bin_file = kzalloc(sizeof(*bin_file), GFP_KERNEL); ++ if (bin_file) { ++ strncpy(bin_file->name, file_basename, ++ sizeof(bin_file->name)); ++ bin_file->name[sizeof(bin_file->name)-1] = 0; ++ bin_file->data = vmalloc(*size); ++ if (bin_file->data) { ++ memset(bin_file->data, 0, *size); ++ bin_file->size = *size; ++ fo->flags = FILE_CREATED; ++ } else { ++ kfree(bin_file); ++ bin_file = NULL; ++ } ++ } ++ } else ++ bin_file = NULL; ++ ++ RtlFreeAnsiString(&ansi); ++ if (!bin_file) { ++ iosb->status = FILE_DOES_NOT_EXIST; ++ iosb->info = 0; ++ free_object(fo); ++ EXIT2(return STATUS_FAILURE); ++ } ++ ++ fo->wrap_bin_file = bin_file; ++ fo->current_byte_offset = 0; ++ if (access_mask & FILE_READ_DATA) ++ fo->read_access = TRUE; ++ if (access_mask & FILE_WRITE_DATA) ++ fo->write_access = TRUE; ++ iosb->status = FILE_OPENED; ++ iosb->info = bin_file->size; ++ *handle = coh; ++ TRACE2("handle: %p", *handle); ++ status = STATUS_SUCCESS; ++ EXIT2(return status); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwOpenFile,6) ++ (void **handle, ACCESS_MASK access_mask, ++ struct object_attributes *obj_attr, struct io_status_block *iosb, ++ ULONG share_access, ULONG open_options) ++{ ++ LARGE_INTEGER size; ++ return ZwCreateFile(handle, access_mask, obj_attr, iosb, &size, 0, ++ share_access, 0, open_options, NULL, 0); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwReadFile,9) ++ (void *handle, struct nt_event *event, void *apc_routine, ++ void *apc_context, struct io_status_block *iosb, void *buffer, ++ ULONG length, LARGE_INTEGER *byte_offset, ULONG *key) ++{ ++ struct file_object *fo; ++ struct common_object_header *coh; ++ ULONG count; ++ size_t offset; ++ struct wrap_bin_file *file; ++ ++ TRACE2("%p", handle); ++ coh = handle; ++ if (coh->type != OBJECT_TYPE_FILE) { ++ ERROR("handle %p is invalid: %d", handle, coh->type); ++ EXIT2(return STATUS_FAILURE); ++ } ++ fo = HANDLE_TO_OBJECT(coh); ++ file = fo->wrap_bin_file; ++ TRACE2("file: %s (%zu)", file->name, file->size); ++ spin_lock_bh(&ntoskernel_lock); ++ if (byte_offset) ++ offset = *byte_offset; ++ else ++ offset = fo->current_byte_offset; ++ count = min((size_t)length, file->size - offset); ++ TRACE2("count: %u, offset: %zu, length: %u", count, offset, length); ++ memcpy(buffer, ((void *)file->data) + offset, count); ++ fo->current_byte_offset = offset + count; ++ spin_unlock_bh(&ntoskernel_lock); ++ iosb->status = STATUS_SUCCESS; ++ iosb->info = count; ++ EXIT2(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwWriteFile,9) ++ (void *handle, struct nt_event *event, void *apc_routine, ++ void *apc_context, struct io_status_block *iosb, void *buffer, ++ ULONG length, LARGE_INTEGER *byte_offset, ULONG *key) ++{ ++ struct file_object *fo; ++ struct common_object_header *coh; ++ struct wrap_bin_file *file; ++ unsigned long offset; ++ ++ TRACE2("%p", handle); ++ coh = handle; ++ if (coh->type != OBJECT_TYPE_FILE) { ++ ERROR("handle %p is invalid: %d", handle, coh->type); ++ EXIT2(return STATUS_FAILURE); ++ } ++ fo = HANDLE_TO_OBJECT(coh); ++ file = fo->wrap_bin_file; ++ TRACE2("file: %zu, %u", file->size, length); ++ spin_lock_bh(&ntoskernel_lock); ++ if (byte_offset) ++ offset = *byte_offset; ++ else ++ offset = fo->current_byte_offset; ++ if (length + offset > file->size) { ++ WARNING("%lu, %zu", length + offset, file->size); ++ /* TODO: implement writing past end of current size */ ++ iosb->status = STATUS_FAILURE; ++ iosb->info = 0; ++ } else { ++ memcpy(file->data + offset, buffer, length); ++ iosb->status = STATUS_SUCCESS; ++ iosb->info = length; ++ fo->current_byte_offset = offset + length; ++ } ++ spin_unlock_bh(&ntoskernel_lock); ++ EXIT2(return iosb->status); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwClose,1) ++ (void *handle) ++{ ++ struct common_object_header *coh; ++ ++ TRACE2("%p", handle); ++ if (handle == NULL) { ++ TRACE1(""); ++ EXIT2(return STATUS_SUCCESS); ++ } ++ coh = handle; ++ if (coh->type == OBJECT_TYPE_FILE) { ++ struct file_object *fo; ++ struct wrap_bin_file *bin_file; ++ typeof(fo->flags) flags; ++ ++ fo = HANDLE_TO_OBJECT(handle); ++ flags = fo->flags; ++ bin_file = fo->wrap_bin_file; ++ if (dereference_object(fo)) { ++ if (flags == FILE_CREATED) { ++ vfree(bin_file->data); ++ kfree(bin_file); ++ } else ++ free_bin_file(bin_file); ++ } ++ } else if (coh->type == OBJECT_TYPE_NT_THREAD) { ++ struct nt_thread *thread = HANDLE_TO_OBJECT(handle); ++ TRACE2("thread: %p (%p)", thread, handle); ++ ObDereferenceObject(thread); ++ } else { ++ /* TODO: can we just dereference object here? */ ++ WARNING("closing handle 0x%x not implemented", coh->type); ++ } ++ EXIT2(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwQueryInformationFile,5) ++ (void *handle, struct io_status_block *iosb, void *info, ++ ULONG length, enum file_info_class class) ++{ ++ struct file_object *fo; ++ struct file_name_info *fni; ++ struct file_std_info *fsi; ++ struct wrap_bin_file *file; ++ struct common_object_header *coh; ++ ++ ENTER2("%p", handle); ++ coh = handle; ++ if (coh->type != OBJECT_TYPE_FILE) { ++ ERROR("handle %p is invalid: %d", coh, coh->type); ++ EXIT2(return STATUS_FAILURE); ++ } ++ fo = HANDLE_TO_OBJECT(handle); ++ TRACE2("fo: %p, %d", fo, class); ++ switch (class) { ++ case FileNameInformation: ++ fni = info; ++ fni->length = min(length, (typeof(length))coh->name.length); ++ memcpy(fni->name, coh->name.buf, fni->length); ++ iosb->status = STATUS_SUCCESS; ++ iosb->info = fni->length; ++ break; ++ case FileStandardInformation: ++ fsi = info; ++ file = fo->wrap_bin_file; ++ fsi->alloc_size = file->size; ++ fsi->eof = file->size; ++ fsi->num_links = 1; ++ fsi->delete_pending = FALSE; ++ fsi->dir = FALSE; ++ iosb->status = STATUS_SUCCESS; ++ iosb->info = 0; ++ break; ++ default: ++ WARNING("type %d not implemented yet", class); ++ iosb->status = STATUS_FAILURE; ++ iosb->info = 0; ++ break; ++ } ++ EXIT2(return iosb->status); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwOpenSection,3) ++ (void **handle, ACCESS_MASK access, struct object_attributes *obj_attrs) ++{ ++ INFO("%p, 0x%x, %d", obj_attrs, obj_attrs->attributes, access); ++ TODO(); ++ *handle = obj_attrs; ++ return STATUS_SUCCESS; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwMapViewOfSection,10) ++ (void *secn_handle, void *process_handle, void **base_address, ++ ULONG zero_bits, SIZE_T commit_size, LARGE_INTEGER *secn_offset, ++ SIZE_T *view_size, enum section_inherit inherit, ULONG alloc_type, ++ ULONG protect) ++{ ++ INFO("%p, %p, %p", secn_handle, process_handle, base_address); ++ TODO(); ++ *base_address = (void *)0xdeadbeef; ++ return STATUS_SUCCESS; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwUnmapViewOfSection,2) ++ (void *process_handle, void *base_address) ++{ ++ INFO("%p, %p", process_handle, base_address); ++ TODO(); ++ return STATUS_SUCCESS; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwCreateKey,7) ++ (void **handle, ACCESS_MASK desired_access, ++ struct object_attributes *attr, ULONG title_index, ++ struct unicode_string *class, ULONG create_options, ++ ULONG *disposition) ++{ ++ struct ansi_string ansi; ++ if (RtlUnicodeStringToAnsiString(&ansi, attr->name, TRUE) == ++ STATUS_SUCCESS) { ++ TRACE1("key: %s", ansi.buf); ++ RtlFreeAnsiString(&ansi); ++ } ++ *handle = NULL; ++ return STATUS_SUCCESS; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwOpenKey,3) ++ (void **handle, ACCESS_MASK desired_access, ++ struct object_attributes *attr) ++{ ++ struct ansi_string ansi; ++ if (RtlUnicodeStringToAnsiString(&ansi, attr->name, TRUE) == ++ STATUS_SUCCESS) { ++ TRACE1("key: %s", ansi.buf); ++ RtlFreeAnsiString(&ansi); ++ } ++ *handle = NULL; ++ return STATUS_SUCCESS; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwSetValueKey,6) ++ (void *handle, struct unicode_string *name, ULONG title_index, ++ ULONG type, void *data, ULONG data_size) ++{ ++ struct ansi_string ansi; ++ if (RtlUnicodeStringToAnsiString(&ansi, name, TRUE) == ++ STATUS_SUCCESS) { ++ TRACE1("key: %s", ansi.buf); ++ RtlFreeAnsiString(&ansi); ++ } ++ return STATUS_SUCCESS; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwQueryValueKey,6) ++ (void *handle, struct unicode_string *name, ++ enum key_value_information_class class, void *info, ++ ULONG length, ULONG *res_length) ++{ ++ struct ansi_string ansi; ++ if (RtlUnicodeStringToAnsiString(&ansi, name, TRUE) == STATUS_SUCCESS) { ++ TRACE1("key: %s", ansi.buf); ++ RtlFreeAnsiString(&ansi); ++ } ++ TODO(); ++ return STATUS_INVALID_PARAMETER; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwDeleteKey,1) ++ (void *handle) ++{ ++ ENTER2("%p", handle); ++ return STATUS_SUCCESS; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(ZwPowerInformation,5) ++ (INT info_level, void *in_buf, ULONG in_buf_len, void *out_buf, ++ ULONG out_buf_len) ++{ ++ INFO("%d, %u, %u", info_level, in_buf_len, out_buf_len); ++ TODO(); ++ return STATUS_ACCESS_DENIED; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(WmiSystemControl,4) ++ (struct wmilib_context *info, struct device_object *dev_obj, ++ struct irp *irp, void *irp_disposition) ++{ ++ TODO(); ++ return STATUS_SUCCESS; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(WmiCompleteRequest,5) ++ (struct device_object *dev_obj, struct irp *irp, NTSTATUS status, ++ ULONG buffer_used, CCHAR priority_boost) ++{ ++ TODO(); ++ return STATUS_SUCCESS; ++} ++ ++noregparm NTSTATUS WIN_FUNC(WmiTraceMessage,12) ++ (void *tracehandle, ULONG message_flags, ++ void *message_guid, USHORT message_no, ...) ++{ ++ TODO(); ++ EXIT2(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(WmiQueryTraceInformation,4) ++ (enum trace_information_class trace_info_class, void *trace_info, ++ ULONG *req_length, void *buf) ++{ ++ TODO(); ++ EXIT2(return STATUS_SUCCESS); ++} ++ ++/* this function can't be wstdcall as it takes variable number of args */ ++__attribute__((format(printf, 1, 2))) ++noregparm ULONG WIN_FUNC(DbgPrint,12) ++ (char *format, ...) ++{ ++#if DEBUG >= 1 ++ va_list args; ++ static char buf[100]; ++ ++ va_start(args, format); ++ vsnprintf(buf, sizeof(buf), format, args); ++ printk(KERN_DEBUG "%s (%s): %s", DRIVER_NAME, __func__, buf); ++ va_end(args); ++#endif ++ return STATUS_SUCCESS; ++} ++ ++__attribute__((format(printf, 3, 4))) ++noregparm ULONG WIN_FUNC(DbgPrintEx,12) ++ (ULONG component_id, ULONG severity, char *format, ...) ++{ ++#if DEBUG >= 1 ++ va_list args; ++ static char buf[100]; ++ ++ va_start(args, format); ++ vsnprintf(buf, sizeof(buf), format, args); ++ TRACE1("component_id: %d, severity: %d\n", component_id, severity); ++ printk(KERN_DEBUG "%s (%s): %s", DRIVER_NAME, __func__, buf); ++ va_end(args); ++#endif ++ return STATUS_SUCCESS; ++} ++ ++wstdcall void WIN_FUNC(KeBugCheck,1) ++ (ULONG code) ++{ ++ ERROR("Unrecoverable error reported by the driver"); ++ ERROR("code: 0x%x\n", code); ++ dump_stack(); ++ return; ++} ++ ++wstdcall void WIN_FUNC(KeBugCheckEx,5) ++ (ULONG code, ULONG_PTR param1, ULONG_PTR param2, ++ ULONG_PTR param3, ULONG_PTR param4) ++{ ++ ERROR("Unrecoverable error reported by the driver"); ++ ERROR("code: 0x%x, params: 0x%lx 0x%lx 0x%lx 0x%lx\n", code, param1, ++ param2, param3, param4); ++ dump_stack(); ++ return; ++} ++ ++wstdcall void WIN_FUNC(ExSystemTimeToLocalTime,2) ++ (LARGE_INTEGER *system_time, LARGE_INTEGER *local_time) ++{ ++ *local_time = *system_time; ++} ++ ++wstdcall ULONG WIN_FUNC(ExSetTimerResolution,2) ++ (ULONG time, BOOLEAN set) ++{ ++ /* why a driver should change system wide timer resolution is ++ * beyond me */ ++ return time; ++} ++ ++wstdcall void WIN_FUNC(DbgBreakPoint,0) ++ (void) ++{ ++ TODO(); ++} ++ ++wstdcall void WIN_FUNC(_except_handler3,0) ++ (void) ++{ ++ TODO(); ++} ++ ++wstdcall void WIN_FUNC(__C_specific_handler,0) ++ (void) ++{ ++ TODO(); ++} ++ ++wstdcall void WIN_FUNC(_purecall,0) ++ (void) ++{ ++ TODO(); ++} ++ ++struct worker_init_struct { ++ struct work_struct work; ++ struct completion completion; ++ struct nt_thread *nt_thread; ++}; ++ ++int ntoskernel_init(void) ++{ ++ struct timeval now; ++ ++ spin_lock_init(&dispatcher_lock); ++ spin_lock_init(&ntoskernel_lock); ++ spin_lock_init(&ntos_work_lock); ++ spin_lock_init(&kdpc_list_lock); ++ spin_lock_init(&irp_cancel_lock); ++ InitializeListHead(&wrap_mdl_list); ++ InitializeListHead(&kdpc_list); ++ InitializeListHead(&callback_objects); ++ InitializeListHead(&bus_driver_list); ++ InitializeListHead(&object_list); ++ InitializeListHead(&ntos_work_list); ++ ++ nt_spin_lock_init(&nt_list_lock); ++ ++ INIT_WORK(&kdpc_work, kdpc_worker); ++ INIT_WORK(&ntos_work, ntos_work_worker); ++ wrap_timer_slist.next = NULL; ++ ++ do_gettimeofday(&now); ++ wrap_ticks_to_boot = TICKS_1601_TO_1970; ++ wrap_ticks_to_boot += (u64)now.tv_sec * TICKSPERSEC; ++ wrap_ticks_to_boot += now.tv_usec * 10; ++ wrap_ticks_to_boot -= jiffies * TICKSPERJIFFY; ++ TRACE2("%llu", wrap_ticks_to_boot); ++ ++ cpu_count = num_online_cpus(); ++ ++#ifdef WRAP_PREEMPT ++ do { ++ int cpu; ++ for_each_possible_cpu(cpu) { ++ struct irql_info *info; ++ info = &per_cpu(irql_info, cpu); ++ mutex_init(&(info->lock)); ++ info->task = NULL; ++ info->count = 0; ++#ifdef CONFIG_SMP ++ cpumask_setall(&info->cpus_allowed); ++#endif ++ } ++ } while (0); ++#endif ++ ++ ntos_wq = create_singlethread_workqueue("ntos_wq"); ++ if (!ntos_wq) { ++ WARNING("couldn't create ntos_wq thread"); ++ return -ENOMEM; ++ } ++ TRACE1("ntos_wq: %p", ntos_wq); ++ ++ if (add_bus_driver("PCI") ++#ifdef ENABLE_USB ++ || add_bus_driver("USB") ++#endif ++ ) { ++ ntoskernel_exit(); ++ return -ENOMEM; ++ } ++ mdl_cache = ++ wrap_kmem_cache_create(DRIVER_NAME "_mdl", ++ sizeof(struct wrap_mdl) + MDL_CACHE_SIZE, ++ 0, 0); ++ TRACE2("%p", mdl_cache); ++ if (!mdl_cache) { ++ ERROR("couldn't allocate MDL cache"); ++ ntoskernel_exit(); ++ return -ENOMEM; ++ } ++ ++#if defined(CONFIG_X86_64) ++ memset(&kuser_shared_data, 0, sizeof(kuser_shared_data)); ++ *((ULONG64 *)&kuser_shared_data.system_time) = ticks_1601(); ++ init_timer(&shared_data_timer); ++ shared_data_timer.function = update_user_shared_data_proc; ++ shared_data_timer.data = 0; ++#endif ++ return 0; ++} ++ ++int ntoskernel_init_device(struct wrap_device *wd) ++{ ++#if defined(CONFIG_X86_64) ++ if (kuser_shared_data.reserved1) ++ mod_timer(&shared_data_timer, jiffies + MSEC_TO_HZ(30)); ++#endif ++ return 0; ++} ++ ++void ntoskernel_exit_device(struct wrap_device *wd) ++{ ++ ENTER2(""); ++ ++ KeFlushQueuedDpcs(); ++ EXIT2(return); ++} ++ ++void ntoskernel_exit(void) ++{ ++ struct nt_list *cur; ++ ++ ENTER2(""); ++ ++ /* free kernel (Ke) timers */ ++ TRACE2("freeing timers"); ++ while (1) { ++ struct wrap_timer *wrap_timer; ++ struct nt_slist *slist; ++ ++ spin_lock_bh(&ntoskernel_lock); ++ if ((slist = wrap_timer_slist.next)) ++ wrap_timer_slist.next = slist->next; ++ spin_unlock_bh(&ntoskernel_lock); ++ TIMERTRACE("%p", slist); ++ if (!slist) ++ break; ++ wrap_timer = container_of(slist, struct wrap_timer, slist); ++ if (del_timer_sync(&wrap_timer->timer)) ++ WARNING("Buggy Windows driver left timer %p running", ++ wrap_timer->nt_timer); ++ memset(wrap_timer, 0, sizeof(*wrap_timer)); ++ slack_kfree(wrap_timer); ++ } ++ ++ TRACE2("freeing MDLs"); ++ if (mdl_cache) { ++ spin_lock_bh(&ntoskernel_lock); ++ if (!IsListEmpty(&wrap_mdl_list)) ++ ERROR("Windows driver didn't free all MDLs; " ++ "freeing them now"); ++ while ((cur = RemoveHeadList(&wrap_mdl_list))) { ++ struct wrap_mdl *wrap_mdl; ++ wrap_mdl = container_of(cur, struct wrap_mdl, list); ++ if (wrap_mdl->mdl->flags & MDL_CACHE_ALLOCATED) ++ kmem_cache_free(mdl_cache, wrap_mdl); ++ else ++ kfree(wrap_mdl); ++ } ++ spin_unlock_bh(&ntoskernel_lock); ++ kmem_cache_destroy(mdl_cache); ++ mdl_cache = NULL; ++ } ++ ++ TRACE2("freeing callbacks"); ++ spin_lock_bh(&ntoskernel_lock); ++ while ((cur = RemoveHeadList(&callback_objects))) { ++ struct callback_object *object; ++ struct nt_list *ent; ++ object = container_of(cur, struct callback_object, list); ++ while ((ent = RemoveHeadList(&object->callback_funcs))) { ++ struct callback_func *f; ++ f = container_of(ent, struct callback_func, list); ++ kfree(f); ++ } ++ kfree(object); ++ } ++ spin_unlock_bh(&ntoskernel_lock); ++ ++ spin_lock_bh(&ntoskernel_lock); ++ while ((cur = RemoveHeadList(&bus_driver_list))) { ++ struct bus_driver *bus_driver; ++ bus_driver = container_of(cur, struct bus_driver, list); ++ /* TODO: make sure all all drivers are shutdown/removed */ ++ kfree(bus_driver); ++ } ++ spin_unlock_bh(&ntoskernel_lock); ++ ++#if defined(CONFIG_X86_64) ++ del_timer_sync(&shared_data_timer); ++#endif ++ if (ntos_wq) ++ destroy_workqueue(ntos_wq); ++ ENTER2("freeing objects"); ++ spin_lock_bh(&ntoskernel_lock); ++ while ((cur = RemoveHeadList(&object_list))) { ++ struct common_object_header *hdr; ++ hdr = container_of(cur, struct common_object_header, list); ++ if (hdr->type == OBJECT_TYPE_NT_THREAD) ++ TRACE1("object %p(%d) was not freed, freeing it now", ++ HEADER_TO_OBJECT(hdr), hdr->type); ++ else ++ WARNING("object %p(%d) was not freed, freeing it now", ++ HEADER_TO_OBJECT(hdr), hdr->type); ++ ExFreePool(hdr); ++ } ++ spin_unlock_bh(&ntoskernel_lock); ++ ++ EXIT2(return); ++} +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/ntoskernel.h linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/ntoskernel.h +--- linux-3.12.2/3rdparty/ndiswrapper/ntoskernel.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/ntoskernel.h 2013-11-28 21:42:11.000000000 +0200 +@@ -0,0 +1,1083 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * 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 _NTOSKERNEL_H_ ++#define _NTOSKERNEL_H_ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if !defined(CONFIG_X86) && !defined(CONFIG_X86_64) ++#error "this module is for x86 or x86_64 architectures only" ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) ++#define gfp_t unsigned int __nocast ++ ++static inline void *_kzalloc(size_t size, gfp_t flags) ++{ ++ void *p = kmalloc(size, flags); ++ if (likely(p != NULL)) ++ memset(p, 0, size); ++ return p; ++} ++ ++#define kzalloc(size, flags) _kzalloc(size, flags) ++#endif ++ ++/* Interrupt backwards compatibility stuff */ ++#include ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) ++#ifndef IRQ_HANDLED ++#define IRQ_HANDLED ++#define IRQ_NONE ++#define irqreturn_t void ++#endif ++#endif /* Linux < 2.6.29 */ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16) ++#ifndef mutex_init ++#define mutex semaphore ++#define mutex_init(m) sema_init(m, 1) ++#define mutex_lock(m) down(m) ++#define mutex_trylock(m) (!down_trylock(m)) ++#define mutex_unlock(m) up(m) ++#define mutex_is_locked(m) (atomic_read(m.count) == 0) ++#endif ++#endif /* Linux < 2.6.16 */ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) ++#define set_cpus_allowed_ptr(task, mask) set_cpus_allowed(task, *mask) ++#endif /* Linux < 2.6.26 */ ++ ++#ifdef CONFIG_SMP ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) ++#define cpumask_copy(dst, src) do { *dst = *src; } while (0) ++#define cpumask_equal(mask1, mask2) cpus_equal(*mask1, *mask2) ++#define cpumask_setall(mask) cpus_setall(*mask) ++static cpumask_t cpumasks[NR_CPUS]; ++#define cpumask_of(cpu) \ ++({ \ ++ cpumasks[cpu] = cpumask_of_cpu(cpu); \ ++ &cpumasks[cpu]; \ ++}) ++#endif /* Linux < 2.6.28 */ ++#endif /* CONFIG_SMP */ ++ ++#ifndef tsk_cpus_allowed ++#define tsk_cpus_allowed(tsk) (&(tsk)->cpus_allowed) ++#endif ++ ++#ifndef __packed ++#define __packed __attribute__((packed)) ++#endif ++ ++/* pci functions in 2.6 kernels have problems allocating dma buffers, ++ * but seem to work fine with dma functions ++ */ ++#include ++ ++#define PCI_DMA_ALLOC_COHERENT(pci_dev,size,dma_handle) \ ++ dma_alloc_coherent(&pci_dev->dev,size,dma_handle, \ ++ GFP_KERNEL | __GFP_REPEAT) ++#define PCI_DMA_FREE_COHERENT(pci_dev,size,cpu_addr,dma_handle) \ ++ dma_free_coherent(&pci_dev->dev,size,cpu_addr,dma_handle) ++#define PCI_DMA_MAP_SINGLE(pci_dev,addr,size,direction) \ ++ dma_map_single(&pci_dev->dev,addr,size,direction) ++#define PCI_DMA_UNMAP_SINGLE(pci_dev,dma_handle,size,direction) \ ++ dma_unmap_single(&pci_dev->dev,dma_handle,size,direction) ++#define MAP_SG(pci_dev, sglist, nents, direction) \ ++ dma_map_sg(&pci_dev->dev, sglist, nents, direction) ++#define UNMAP_SG(pci_dev, sglist, nents, direction) \ ++ dma_unmap_sg(&pci_dev->dev, sglist, nents, direction) ++#define PCI_DMA_MAP_ERROR(dma_addr) dma_mapping_error(dma_addr) ++ ++ ++#if defined(CONFIG_NET_RADIO) && !defined(CONFIG_WIRELESS_EXT) ++#define CONFIG_WIRELESS_EXT ++#endif ++ ++#define prepare_wait_condition(task, var, value) \ ++do { \ ++ var = value; \ ++ task = current; \ ++ barrier(); \ ++} while (0) ++ ++/* Wait in wait_state (e.g., TASK_INTERRUPTIBLE) for condition to ++ * become true; timeout is either jiffies (> 0) to wait or 0 to wait ++ * forever. ++ * When timeout == 0, return value is ++ * > 0 if condition becomes true, or ++ * < 0 if signal is pending on the thread. ++ * When timeout > 0, return value is ++ * > 0 if condition becomes true before timeout, ++ * < 0 if signal is pending on the thread before timeout, or ++ * 0 if timedout (condition may have become true at the same time) ++ */ ++ ++#define wait_condition(condition, timeout, wait_state) \ ++({ \ ++ long ret = timeout ? timeout : 1; \ ++ while (1) { \ ++ if (signal_pending(current)) { \ ++ ret = -ERESTARTSYS; \ ++ break; \ ++ } \ ++ set_current_state(wait_state); \ ++ if (condition) { \ ++ __set_current_state(TASK_RUNNING); \ ++ break; \ ++ } \ ++ if (timeout) { \ ++ ret = schedule_timeout(ret); \ ++ if (!ret) \ ++ break; \ ++ } else \ ++ schedule(); \ ++ } \ ++ ret; \ ++}) ++ ++#ifdef WRAP_WQ ++ ++struct wrap_workqueue_struct; ++ ++struct wrap_work_struct { ++ struct list_head list; ++ void (*func)(struct wrap_work_struct *data); ++ void *data; ++ /* whether/on which thread scheduled */ ++ struct workqueue_thread *thread; ++}; ++ ++#define work_struct wrap_work_struct ++#define workqueue_struct wrap_workqueue_struct ++ ++#undef INIT_WORK ++#define INIT_WORK(work, pfunc) \ ++ do { \ ++ (work)->func = (pfunc); \ ++ (work)->data = (work); \ ++ (work)->thread = NULL; \ ++ } while (0) ++ ++#undef create_singlethread_workqueue ++#define create_singlethread_workqueue(wq) wrap_create_wq(wq, 1, 0) ++#undef create_workqueue ++#define create_workqueue(wq) wrap_create_wq(wq, 0, 0) ++#undef destroy_workqueue ++#define destroy_workqueue(wq) wrap_destroy_wq(wq) ++#undef queue_work ++#define queue_work(wq, work) wrap_queue_work(wq, work) ++#undef flush_workqueue ++#define flush_workqueue(wq) wrap_flush_wq(wq) ++ ++struct workqueue_struct *wrap_create_wq(const char *name, u8 singlethread, ++ u8 freeze); ++void wrap_destroy_wq(struct workqueue_struct *workq); ++int wrap_queue_work(struct workqueue_struct *workq, struct work_struct *work); ++void wrap_cancel_work(struct work_struct *work); ++void wrap_flush_wq(struct workqueue_struct *workq); ++ ++#else // WRAP_WQ ++ ++/* Compatibility for Linux before 2.6.20 where INIT_WORK takes 3 arguments */ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) && \ ++ !defined(INIT_WORK_NAR) && \ ++ !defined(INIT_DELAYED_WORK_DEFERRABLE) ++typedef void (*compat_work_func_t)(void *work); ++typedef void (*work_func_t)(struct work_struct *work); ++static inline void (INIT_WORK)(struct work_struct *work, work_func_t func) ++{ ++ INIT_WORK(work, (compat_work_func_t)func, work); ++} ++#undef INIT_WORK ++#endif ++ ++#endif // WRAP_WQ ++ ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18) ++#define ISR_PT_REGS_PARAM_DECL ++#else ++#define ISR_PT_REGS_PARAM_DECL , struct pt_regs *regs ++#endif ++ ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,16) ++#define for_each_possible_cpu(_cpu) for_each_cpu(_cpu) ++#endif ++ ++#ifndef CHECKSUM_PARTIAL ++#define CHECKSUM_PARTIAL CHECKSUM_HW ++#endif ++ ++#ifndef IRQF_SHARED ++#define IRQF_SHARED SA_SHIRQ ++#endif ++ ++#ifndef UMH_WAIT_PROC ++#define UMH_WAIT_PROC 1 ++#endif ++ ++#define memcpy_skb(skb, from, length) \ ++ memcpy(skb_put(skb, length), from, length) ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) ++#ifndef DMA_BIT_MASK ++#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1)) ++#endif ++#endif ++ ++#ifndef __GFP_DMA32 ++#define __GFP_DMA32 GFP_DMA ++#endif ++ ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22) ++#define wrap_kmem_cache_create(name, size, align, flags) \ ++ kmem_cache_create(name, size, align, flags, NULL, NULL) ++#else ++#define wrap_kmem_cache_create(name, size, align, flags) \ ++ kmem_cache_create(name, size, align, flags, NULL) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) ++#define netdev_mc_count(dev) ((dev)->mc_count) ++#define usb_alloc_coherent(dev, size, mem_flags, dma) (usb_buffer_alloc((dev), (size), (mem_flags), (dma))) ++#define usb_free_coherent(dev, size, addr, dma) (usb_buffer_free((dev), (size), (addr), (dma))) ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,8,0) ++#define daemonize(name, ...) do {} while (0) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0) ++#define add_taint(flag, lockdep_ok) add_taint(flag) ++#endif ++ ++#include "winnt_types.h" ++#include "ndiswrapper.h" ++#include "pe_linker.h" ++#include "wrapmem.h" ++#include "lin2win.h" ++#include "loader.h" ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) ++static inline void netif_tx_lock(struct net_device *dev) ++{ ++ spin_lock(&dev->xmit_lock); ++} ++static inline void netif_tx_unlock(struct net_device *dev) ++{ ++ spin_unlock(&dev->xmit_lock); ++} ++static inline void netif_tx_lock_bh(struct net_device *dev) ++{ ++ spin_lock_bh(&dev->xmit_lock); ++} ++static inline void netif_tx_unlock_bh(struct net_device *dev) ++{ ++ spin_unlock_bh(&dev->xmit_lock); ++} ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) ++static inline void netif_poll_enable(struct net_device *dev) ++{ ++} ++static inline void netif_poll_disable(struct net_device *dev) ++{ ++} ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) ++#define proc_net_root init_net.proc_net ++#else ++#define proc_net_root proc_net ++#endif ++ ++#if ((LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0)) && \ ++ (LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0))) || \ ++ (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,42)) ++#ifndef skb_frag_page ++#define skb_frag_page(frag) ((frag)->page) ++#endif ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0) ++#define netdev_notifier_info_to_dev(x) ((struct net_device *)(x)) ++#endif ++ ++#ifdef INIT_COMPLETION ++static inline void reinit_completion(struct completion *x) ++{ ++ INIT_COMPLETION(*x); ++} ++#endif ++ ++/* TICK is 100ns */ ++#define TICKSPERSEC 10000000 ++#define TICKSPERMSEC 10000 ++#define SECSPERDAY 86400 ++#define TICKSPERJIFFY ((TICKSPERSEC + HZ - 1) / HZ) ++ ++#define int_div_round(x, y) (((x) + (y - 1)) / (y)) ++ ++/* 1601 to 1970 is 369 years plus 89 leap days */ ++#define SECS_1601_TO_1970 ((369 * 365 + 89) * (u64)SECSPERDAY) ++#define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC) ++ ++/* 100ns units to HZ; if sys_time is negative, relative to current ++ * clock, otherwise from year 1601 */ ++#define SYSTEM_TIME_TO_HZ(sys_time) \ ++ (((sys_time) <= 0) ? \ ++ int_div_round(((u64)HZ * (-(sys_time))), TICKSPERSEC) : \ ++ int_div_round(((s64)HZ * ((sys_time) - ticks_1601())), TICKSPERSEC)) ++ ++#define MSEC_TO_HZ(ms) int_div_round((ms * HZ), 1000) ++#define USEC_TO_HZ(us) int_div_round((us * HZ), 1000000) ++ ++extern u64 wrap_ticks_to_boot; ++ ++static inline u64 ticks_1601(void) ++{ ++ return wrap_ticks_to_boot + (u64)jiffies * TICKSPERJIFFY; ++} ++ ++typedef void (*generic_func)(void); ++ ++struct wrap_export { ++ const char *name; ++ generic_func func; ++}; ++ ++#ifdef CONFIG_X86_64 ++ ++#define WIN_SYMBOL(name, argc) \ ++ {#name, (generic_func) win2lin_ ## name ## _ ## argc} ++#define WIN_WIN_SYMBOL(name, argc) \ ++ {#name, (generic_func) win2lin__win_ ## name ## _ ## argc} ++#define WIN_FUNC_DECL(name, argc) \ ++ extern typeof(name) win2lin_ ## name ## _ ## argc; ++#define WIN_FUNC_PTR(name, argc) win2lin_ ## name ## _ ## argc ++ ++#else ++ ++#define WIN_SYMBOL(name, argc) {#name, (generic_func)name} ++#define WIN_WIN_SYMBOL(name, argc) {#name, (generic_func)_win_ ## name} ++#define WIN_FUNC_DECL(name, argc) ++#define WIN_FUNC_PTR(name, argc) name ++ ++#endif ++ ++#define WIN_FUNC(name, argc) (name) ++/* map name s to f - if f is different from s */ ++#define WIN_SYMBOL_MAP(s, f) ++ ++#define POOL_TAG(A, B, C, D) \ ++ ((ULONG)((A) + ((B) << 8) + ((C) << 16) + ((D) << 24))) ++ ++struct pe_image { ++ char name[MAX_DRIVER_NAME_LEN]; ++ UINT (*entry)(struct driver_object *, struct unicode_string *) wstdcall; ++ void *image; ++ int size; ++ int type; ++ ++ IMAGE_NT_HEADERS *nt_hdr; ++ IMAGE_OPTIONAL_HEADER *opt_hdr; ++}; ++ ++struct ndis_mp_block; ++ ++struct wrap_timer { ++ struct nt_slist slist; ++ struct timer_list timer; ++ struct nt_timer *nt_timer; ++ long repeat; ++#ifdef TIMER_DEBUG ++ unsigned long wrap_timer_magic; ++#endif ++}; ++ ++struct ntos_work_item { ++ struct nt_list list; ++ void *arg1; ++ void *arg2; ++ NTOS_WORK_FUNC func; ++}; ++ ++struct wrap_device_setting { ++ struct nt_list list; ++ char name[MAX_SETTING_NAME_LEN]; ++ char value[MAX_SETTING_VALUE_LEN]; ++ void *encoded; ++}; ++ ++struct wrap_bin_file { ++ char name[MAX_DRIVER_NAME_LEN]; ++ size_t size; ++ void *data; ++}; ++ ++#define WRAP_DRIVER_CLIENT_ID 1 ++ ++struct wrap_driver { ++ struct nt_list list; ++ struct driver_object *drv_obj; ++ char name[MAX_DRIVER_NAME_LEN]; ++ char version[MAX_SETTING_VALUE_LEN]; ++ unsigned short num_pe_images; ++ struct pe_image pe_images[MAX_DRIVER_PE_IMAGES]; ++ unsigned short num_bin_files; ++ struct wrap_bin_file *bin_files; ++ struct nt_list settings; ++ int dev_type; ++ struct ndis_driver *ndis_driver; ++}; ++ ++enum hw_status { ++ HW_INITIALIZED = 1, HW_SUSPENDED, HW_HALTED, HW_DISABLED, ++}; ++ ++struct wrap_device { ++ /* first part is (de)initialized once by loader */ ++ struct nt_list list; ++ int dev_bus; ++ int vendor; ++ int device; ++ int subvendor; ++ int subdevice; ++ char conf_file_name[MAX_DRIVER_NAME_LEN]; ++ char driver_name[MAX_DRIVER_NAME_LEN]; ++ struct wrap_driver *driver; ++ struct nt_list settings; ++ ++ /* rest should be (de)initialized when a device is ++ * (un)plugged */ ++ struct cm_resource_list *resource_list; ++ unsigned long hw_status; ++ struct device_object *pdo; ++ union { ++ struct { ++ struct pci_dev *pdev; ++ enum device_power_state wake_state; ++ } pci; ++ struct { ++ struct usb_device *udev; ++ struct usb_interface *intf; ++ int num_alloc_urbs; ++ struct nt_list wrap_urb_list; ++ } usb; ++ }; ++}; ++ ++#define wrap_is_pci_bus(dev_bus) \ ++ (WRAP_BUS(dev_bus) == WRAP_PCI_BUS || \ ++ WRAP_BUS(dev_bus) == WRAP_PCMCIA_BUS) ++#ifdef ENABLE_USB ++/* earlier versions of ndiswrapper used 0 as USB_BUS */ ++#define wrap_is_usb_bus(dev_bus) \ ++ (WRAP_BUS(dev_bus) == WRAP_USB_BUS || \ ++ WRAP_BUS(dev_bus) == WRAP_INTERNAL_BUS) ++#else ++#define wrap_is_usb_bus(dev_bus) 0 ++#endif ++#define wrap_is_bluetooth_device(dev_bus) \ ++ (WRAP_DEVICE(dev_bus) == WRAP_BLUETOOTH_DEVICE1 || \ ++ WRAP_DEVICE(dev_bus) == WRAP_BLUETOOTH_DEVICE2) ++ ++extern struct workqueue_struct *ntos_wq; ++extern struct workqueue_struct *ndis_wq; ++extern struct workqueue_struct *wrapndis_wq; ++ ++#define atomic_unary_op(var, size, oper) \ ++do { \ ++ if (size == 1) \ ++ __asm__ __volatile__( \ ++ LOCK_PREFIX oper "b %b0\n\t" : "+m" (var)); \ ++ else if (size == 2) \ ++ __asm__ __volatile__( \ ++ LOCK_PREFIX oper "w %w0\n\t" : "+m" (var)); \ ++ else if (size == 4) \ ++ __asm__ __volatile__( \ ++ LOCK_PREFIX oper "l %0\n\t" : "+m" (var)); \ ++ else if (size == 8) \ ++ __asm__ __volatile__( \ ++ LOCK_PREFIX oper "q %q0\n\t" : "+m" (var)); \ ++ else { \ ++ extern void _invalid_op_size_(void); \ ++ _invalid_op_size_(); \ ++ } \ ++} while (0) ++ ++#define atomic_inc_var_size(var, size) atomic_unary_op(var, size, "inc") ++ ++#define atomic_inc_var(var) atomic_inc_var_size(var, sizeof(var)) ++ ++#define atomic_dec_var_size(var, size) atomic_unary_op(var, size, "dec") ++ ++#define atomic_dec_var(var) atomic_dec_var_size(var, sizeof(var)) ++ ++#define pre_atomic_add(var, i) \ ++({ \ ++ typeof(var) pre; \ ++ __asm__ __volatile__( \ ++ LOCK_PREFIX "xadd %0, %1\n\t" \ ++ : "=r"(pre), "+m"(var) \ ++ : "0"(i)); \ ++ pre; \ ++}) ++ ++#define post_atomic_add(var, i) (pre_atomic_add(var, i) + i) ++ ++//#define DEBUG_IRQL 1 ++ ++#ifdef DEBUG_IRQL ++#define assert_irql(cond) \ ++do { \ ++ KIRQL _irql_ = current_irql(); \ ++ if (!(cond)) { \ ++ WARNING("assertion '%s' failed: %d", #cond, _irql_); \ ++ DBG_BLOCK(4) { \ ++ dump_stack(); \ ++ } \ ++ } \ ++} while (0) ++#else ++#define assert_irql(cond) do { } while (0) ++#endif ++ ++/* When preempt is enabled, we should preempt_disable to raise IRQL to ++ * DISPATCH_LEVEL, to be consistent with the semantics. However, using ++ * a mutex instead, so that only ndiswrapper threads run one at a time ++ * on a processor when at DISPATCH_LEVEL seems to be enough. So that ++ * is what we will use until we learn otherwise. If ++ * preempt_(en|dis)able is required for some reason, comment out ++ * following #define. */ ++ ++#define WRAP_PREEMPT 1 ++ ++#if !defined(CONFIG_PREEMPT) || defined(CONFIG_PREEMPT_RT) ++#ifndef WRAP_PREEMPT ++#define WRAP_PREEMPT 1 ++#endif ++#endif ++ ++//#undef WRAP_PREEMPT ++ ++#ifdef WRAP_PREEMPT ++ ++struct irql_info { ++ int count; ++ struct mutex lock; ++#ifdef CONFIG_SMP ++ cpumask_t cpus_allowed; ++#endif ++ struct task_struct *task; ++}; ++ ++DECLARE_PER_CPU(struct irql_info, irql_info); ++ ++static inline KIRQL raise_irql(KIRQL newirql) ++{ ++ struct irql_info *info; ++ ++ assert(newirql == DISPATCH_LEVEL); ++ info = &get_cpu_var(irql_info); ++ if (info->task == current) { ++ assert(info->count > 0); ++ assert(mutex_is_locked(&info->lock)); ++#if defined(CONFIG_SMP) && DEBUG >= 1 ++ assert(cpumask_equal(tsk_cpus_allowed(current), ++ cpumask_of(smp_processor_id()))); ++#endif ++ info->count++; ++ put_cpu_var(irql_info); ++ return DISPATCH_LEVEL; ++ } ++ /* TODO: is this enough to pin down to current cpu? */ ++#ifdef CONFIG_SMP ++ assert(task_cpu(current) == smp_processor_id()); ++ cpumask_copy(&info->cpus_allowed, tsk_cpus_allowed(current)); ++ set_cpus_allowed_ptr(current, cpumask_of(smp_processor_id())); ++#endif ++ put_cpu_var(irql_info); ++ mutex_lock(&info->lock); ++ assert(info->count == 0); ++ assert(info->task == NULL); ++ info->count = 1; ++ info->task = current; ++ return PASSIVE_LEVEL; ++} ++ ++static inline void lower_irql(KIRQL oldirql) ++{ ++ struct irql_info *info; ++ ++ assert(oldirql <= DISPATCH_LEVEL); ++ info = &get_cpu_var(irql_info); ++ assert(info->task == current); ++ assert(mutex_is_locked(&info->lock)); ++ assert(info->count > 0); ++ if (--info->count == 0) { ++ info->task = NULL; ++#ifdef CONFIG_SMP ++ set_cpus_allowed_ptr(current, &info->cpus_allowed); ++#endif ++ mutex_unlock(&info->lock); ++ } ++ put_cpu_var(irql_info); ++} ++ ++static inline KIRQL current_irql(void) ++{ ++ int count; ++ if (in_irq() || irqs_disabled()) ++ EXIT4(return DIRQL); ++ if (in_atomic() || in_interrupt()) ++ EXIT4(return SOFT_IRQL); ++ count = get_cpu_var(irql_info).count; ++ put_cpu_var(irql_info); ++ if (count) ++ EXIT6(return DISPATCH_LEVEL); ++ else ++ EXIT6(return PASSIVE_LEVEL); ++} ++ ++#else ++ ++static inline KIRQL current_irql(void) ++{ ++ if (in_irq() || irqs_disabled()) ++ EXIT4(return DIRQL); ++ if (in_interrupt()) ++ EXIT4(return SOFT_IRQL); ++ if (in_atomic()) ++ EXIT6(return DISPATCH_LEVEL); ++ else ++ EXIT6(return PASSIVE_LEVEL); ++} ++ ++static inline KIRQL raise_irql(KIRQL newirql) ++{ ++ KIRQL ret = in_atomic() ? DISPATCH_LEVEL : PASSIVE_LEVEL; ++ assert(newirql == DISPATCH_LEVEL); ++ assert(current_irql() <= DISPATCH_LEVEL); ++ preempt_disable(); ++ return ret; ++} ++ ++static inline void lower_irql(KIRQL oldirql) ++{ ++ assert(current_irql() == DISPATCH_LEVEL); ++ preempt_enable(); ++} ++ ++#endif ++ ++#define irql_gfp() (in_atomic() ? GFP_ATOMIC : GFP_KERNEL) ++ ++/* Windows spinlocks are of type ULONG_PTR which is not big enough to ++ * store Linux spinlocks; so we implement Windows spinlocks using ++ * ULONG_PTR space with our own functions/macros */ ++ ++/* Windows seems to use 0 for unlocked state of spinlock - if Linux ++ * convention of 1 for unlocked state is used, at least prism54 driver ++ * crashes */ ++ ++#define NT_SPIN_LOCK_UNLOCKED 0 ++#define NT_SPIN_LOCK_LOCKED 1 ++ ++static inline void nt_spin_lock_init(NT_SPIN_LOCK *lock) ++{ ++ *lock = NT_SPIN_LOCK_UNLOCKED; ++} ++ ++#ifdef CONFIG_SMP ++ ++static inline void nt_spin_lock(NT_SPIN_LOCK *lock) ++{ ++ while (1) { ++ unsigned long lockval = xchg(lock, NT_SPIN_LOCK_LOCKED); ++ ++ if (likely(lockval == NT_SPIN_LOCK_UNLOCKED)) ++ break; ++ if (unlikely(lockval > NT_SPIN_LOCK_LOCKED)) { ++ ERROR("bad spinlock: 0x%lx at %p", lockval, lock); ++ return; ++ } ++ /* "rep; nop" doesn't change cx register, it's a "pause" */ ++ __asm__ __volatile__("rep; nop"); ++ } ++} ++ ++static inline void nt_spin_unlock(NT_SPIN_LOCK *lock) ++{ ++ unsigned long lockval = xchg(lock, NT_SPIN_LOCK_UNLOCKED); ++ ++ if (likely(lockval == NT_SPIN_LOCK_LOCKED)) ++ return; ++ WARNING("unlocking unlocked spinlock: 0x%lx at %p", lockval, lock); ++} ++ ++#else // CONFIG_SMP ++ ++#define nt_spin_lock(lock) do { } while (0) ++ ++#define nt_spin_unlock(lock) do { } while (0) ++ ++#endif // CONFIG_SMP ++ ++/* When kernel would've disabled preempt (e.g., in interrupt ++ * handlers), we need to fake preempt so driver thinks it is running ++ * at right IRQL */ ++ ++/* raise IRQL to given (higher) IRQL if necessary before locking */ ++static inline KIRQL nt_spin_lock_irql(NT_SPIN_LOCK *lock, KIRQL newirql) ++{ ++ KIRQL oldirql = raise_irql(newirql); ++ nt_spin_lock(lock); ++ return oldirql; ++} ++ ++/* lower IRQL to given (lower) IRQL if necessary after unlocking */ ++static inline void nt_spin_unlock_irql(NT_SPIN_LOCK *lock, KIRQL oldirql) ++{ ++ nt_spin_unlock(lock); ++ lower_irql(oldirql); ++} ++ ++#define nt_spin_lock_irqsave(lock, flags) \ ++do { \ ++ local_irq_save(flags); \ ++ preempt_disable(); \ ++ nt_spin_lock(lock); \ ++} while (0) ++ ++#define nt_spin_unlock_irqrestore(lock, flags) \ ++do { \ ++ nt_spin_unlock(lock); \ ++ preempt_enable_no_resched(); \ ++ local_irq_restore(flags); \ ++ preempt_check_resched(); \ ++} while (0) ++ ++static inline ULONG SPAN_PAGES(void *ptr, SIZE_T length) ++{ ++ return PAGE_ALIGN(((unsigned long)ptr & (PAGE_SIZE - 1)) + length) ++ >> PAGE_SHIFT; ++} ++ ++#ifdef CONFIG_X86_64 ++ ++/* TODO: can these be implemented without using spinlock? */ ++ ++static inline struct nt_slist *PushEntrySList(nt_slist_header *head, ++ struct nt_slist *entry, ++ NT_SPIN_LOCK *lock) ++{ ++ KIRQL irql = nt_spin_lock_irql(lock, DISPATCH_LEVEL); ++ entry->next = head->next; ++ head->next = entry; ++ head->depth++; ++ nt_spin_unlock_irql(lock, irql); ++ TRACE4("%p, %p, %p", head, entry, entry->next); ++ return entry->next; ++} ++ ++static inline struct nt_slist *PopEntrySList(nt_slist_header *head, ++ NT_SPIN_LOCK *lock) ++{ ++ struct nt_slist *entry; ++ KIRQL irql = nt_spin_lock_irql(lock, DISPATCH_LEVEL); ++ entry = head->next; ++ if (entry) { ++ head->next = entry->next; ++ head->depth--; ++ } ++ nt_spin_unlock_irql(lock, irql); ++ TRACE4("%p, %p", head, entry); ++ return entry; ++} ++ ++#else ++ ++#define u64_low_32(x) ((u32)x) ++#define u64_high_32(x) ((u32)(x >> 32)) ++ ++static inline u64 nt_cmpxchg8b(volatile u64 *ptr, u64 old, u64 new) ++{ ++ u64 prev; ++ ++ __asm__ __volatile__( ++ "\n" ++ LOCK_PREFIX "cmpxchg8b %0\n" ++ : "+m" (*ptr), "=A" (prev) ++ : "A" (old), "b" (u64_low_32(new)), "c" (u64_high_32(new))); ++ return prev; ++} ++ ++/* slist routines below update slist atomically - no need for ++ * spinlocks */ ++ ++static inline struct nt_slist *PushEntrySList(nt_slist_header *head, ++ struct nt_slist *entry, ++ NT_SPIN_LOCK *lock) ++{ ++ nt_slist_header old, new; ++ do { ++ old.align = head->align; ++ entry->next = old.next; ++ new.next = entry; ++ new.depth = old.depth + 1; ++ } while (nt_cmpxchg8b(&head->align, old.align, new.align) != old.align); ++ TRACE4("%p, %p, %p", head, entry, old.next); ++ return old.next; ++} ++ ++static inline struct nt_slist *PopEntrySList(nt_slist_header *head, ++ NT_SPIN_LOCK *lock) ++{ ++ struct nt_slist *entry; ++ nt_slist_header old, new; ++ do { ++ old.align = head->align; ++ entry = old.next; ++ if (!entry) ++ break; ++ new.next = entry->next; ++ new.depth = old.depth - 1; ++ } while (nt_cmpxchg8b(&head->align, old.align, new.align) != old.align); ++ TRACE4("%p, %p", head, entry); ++ return entry; ++} ++ ++#endif ++ ++#define sleep_hz(n) \ ++do { \ ++ set_current_state(TASK_INTERRUPTIBLE); \ ++ schedule_timeout(n); \ ++} while (0) ++ ++int ntoskernel_init(void); ++void ntoskernel_exit(void); ++int ntoskernel_init_device(struct wrap_device *wd); ++void ntoskernel_exit_device(struct wrap_device *wd); ++void *allocate_object(ULONG size, enum common_object_type type, ++ struct unicode_string *name); ++ ++#ifdef ENABLE_USB ++int usb_init(void); ++void usb_exit(void); ++#else ++static inline int usb_init(void) { return 0; } ++static inline void usb_exit(void) {} ++#endif ++int usb_init_device(struct wrap_device *wd); ++void usb_exit_device(struct wrap_device *wd); ++ ++int wrap_procfs_init(void); ++void wrap_procfs_remove(void); ++ ++int link_pe_images(struct pe_image *pe_image, unsigned short n); ++ ++int stricmp(const char *s1, const char *s2); ++void dump_bytes(const char *name, const u8 *from, int len); ++struct mdl *allocate_init_mdl(void *virt, ULONG length); ++void free_mdl(struct mdl *mdl); ++struct driver_object *find_bus_driver(const char *name); ++void free_custom_extensions(struct driver_extension *drv_obj_ext); ++struct nt_thread *get_current_nt_thread(void); ++u64 ticks_1601(void); ++int schedule_ntos_work_item(NTOS_WORK_FUNC func, void *arg1, void *arg2); ++void wrap_init_timer(struct nt_timer *nt_timer, enum timer_type type, ++ struct ndis_mp_block *nmb); ++BOOLEAN wrap_set_timer(struct nt_timer *nt_timer, unsigned long expires_hz, ++ unsigned long repeat_hz, struct kdpc *kdpc); ++ ++LONG InterlockedDecrement(LONG volatile *val) wfastcall; ++LONG InterlockedIncrement(LONG volatile *val) wfastcall; ++struct nt_list *ExInterlockedInsertHeadList ++ (struct nt_list *head, struct nt_list *entry, ++ NT_SPIN_LOCK *lock) wfastcall; ++struct nt_list *ExInterlockedInsertTailList ++ (struct nt_list *head, struct nt_list *entry, ++ NT_SPIN_LOCK *lock) wfastcall; ++struct nt_list *ExInterlockedRemoveHeadList ++ (struct nt_list *head, NT_SPIN_LOCK *lock) wfastcall; ++NTSTATUS IofCallDriver(struct device_object *dev_obj, struct irp *irp) wfastcall; ++KIRQL KfRaiseIrql(KIRQL newirql) wfastcall; ++void KfLowerIrql(KIRQL oldirql) wfastcall; ++KIRQL KfAcquireSpinLock(NT_SPIN_LOCK *lock) wfastcall; ++void KfReleaseSpinLock(NT_SPIN_LOCK *lock, KIRQL oldirql) wfastcall; ++void IofCompleteRequest(struct irp *irp, CHAR prio_boost) wfastcall; ++void KefReleaseSpinLockFromDpcLevel(NT_SPIN_LOCK *lock) wfastcall; ++ ++LONG ObfReferenceObject(void *object) wfastcall; ++void ObfDereferenceObject(void *object) wfastcall; ++ ++#define ObReferenceObject(object) ObfReferenceObject(object) ++#define ObDereferenceObject(object) ObfDereferenceObject(object) ++ ++/* prevent expansion of ExAllocatePoolWithTag macro */ ++void *(ExAllocatePoolWithTag)(enum pool_type pool_type, SIZE_T size, ++ ULONG tag) wstdcall; ++ ++void ExFreePool(void *p) wstdcall; ++ULONG MmSizeOfMdl(void *base, ULONG length) wstdcall; ++void __iomem *MmMapIoSpace(PHYSICAL_ADDRESS phys_addr, SIZE_T size, ++ enum memory_caching_type cache) wstdcall; ++void MmUnmapIoSpace(void __iomem *addr, SIZE_T size) wstdcall; ++void MmProbeAndLockPages(struct mdl *mdl, KPROCESSOR_MODE access_mode, ++ enum lock_operation operation) wstdcall; ++void MmUnlockPages(struct mdl *mdl) wstdcall; ++void KeInitializeEvent(struct nt_event *nt_event, ++ enum event_type type, BOOLEAN state) wstdcall; ++LONG KeSetEvent(struct nt_event *nt_event, KPRIORITY incr, ++ BOOLEAN wait) wstdcall; ++LONG KeResetEvent(struct nt_event *nt_event) wstdcall; ++BOOLEAN queue_kdpc(struct kdpc *kdpc); ++BOOLEAN dequeue_kdpc(struct kdpc *kdpc); ++ ++NTSTATUS IoConnectInterrupt(struct kinterrupt **kinterrupt, ++ PKSERVICE_ROUTINE service_routine, ++ void *service_context, NT_SPIN_LOCK *lock, ++ ULONG vector, KIRQL irql, KIRQL synch_irql, ++ enum kinterrupt_mode interrupt_mode, ++ BOOLEAN shareable, KAFFINITY processor_enable_mask, ++ BOOLEAN floating_save) wstdcall; ++void IoDisconnectInterrupt(struct kinterrupt *interrupt) wstdcall; ++BOOLEAN KeSynchronizeExecution(struct kinterrupt *interrupt, ++ PKSYNCHRONIZE_ROUTINE synch_routine, ++ void *ctx) wstdcall; ++ ++NTSTATUS KeWaitForSingleObject(void *object, KWAIT_REASON reason, ++ KPROCESSOR_MODE waitmode, BOOLEAN alertable, ++ LARGE_INTEGER *timeout) wstdcall; ++void MmBuildMdlForNonPagedPool(struct mdl *mdl) wstdcall; ++NTSTATUS IoCreateDevice(struct driver_object *driver, ULONG dev_ext_length, ++ struct unicode_string *dev_name, DEVICE_TYPE dev_type, ++ ULONG dev_chars, BOOLEAN exclusive, ++ struct device_object **dev_obj) wstdcall; ++NTSTATUS IoCreateSymbolicLink(struct unicode_string *link, ++ struct unicode_string *dev_name) wstdcall; ++void IoDeleteDevice(struct device_object *dev) wstdcall; ++void IoDetachDevice(struct device_object *topdev) wstdcall; ++struct device_object *IoGetAttachedDevice(struct device_object *dev) wstdcall; ++struct device_object *IoGetAttachedDeviceReference ++ (struct device_object *dev) wstdcall; ++NTSTATUS IoAllocateDriverObjectExtension ++ (struct driver_object *drv_obj, void *client_id, ULONG extlen, ++ void **ext) wstdcall; ++void *IoGetDriverObjectExtension(struct driver_object *drv, ++ void *client_id) wstdcall; ++struct device_object *IoAttachDeviceToDeviceStack ++ (struct device_object *src, struct device_object *dst) wstdcall; ++BOOLEAN IoCancelIrp(struct irp *irp) wstdcall; ++struct irp *IoBuildSynchronousFsdRequest ++ (ULONG major_func, struct device_object *dev_obj, void *buf, ++ ULONG length, LARGE_INTEGER *offset, struct nt_event *event, ++ struct io_status_block *status) wstdcall; ++ ++NTSTATUS IoPassIrpDown(struct device_object *dev_obj, struct irp *irp) wstdcall; ++WIN_FUNC_DECL(IoPassIrpDown,2); ++NTSTATUS IoSyncForwardIrp(struct device_object *dev_obj, ++ struct irp *irp) wstdcall; ++NTSTATUS IoAsyncForwardIrp(struct device_object *dev_obj, ++ struct irp *irp) wstdcall; ++NTSTATUS IoInvalidDeviceRequest(struct device_object *dev_obj, ++ struct irp *irp) wstdcall; ++ ++void KeInitializeSpinLock(NT_SPIN_LOCK *lock) wstdcall; ++void IoAcquireCancelSpinLock(KIRQL *irql) wstdcall; ++void IoReleaseCancelSpinLock(KIRQL irql) wstdcall; ++ ++NTSTATUS RtlUnicodeStringToAnsiString ++ (struct ansi_string *dst, const struct unicode_string *src, ++ BOOLEAN dup) wstdcall; ++NTSTATUS RtlAnsiStringToUnicodeString ++ (struct unicode_string *dst, const struct ansi_string *src, ++ BOOLEAN dup) wstdcall; ++void RtlInitAnsiString(struct ansi_string *dst, const char *src) wstdcall; ++void RtlInitUnicodeString(struct unicode_string *dest, ++ const wchar_t *src) wstdcall; ++void RtlFreeUnicodeString(struct unicode_string *string) wstdcall; ++void RtlFreeAnsiString(struct ansi_string *string) wstdcall; ++LONG RtlCompareUnicodeString(const struct unicode_string *s1, ++ const struct unicode_string *s2, ++ BOOLEAN case_insensitive) wstdcall; ++NTSTATUS RtlUpcaseUnicodeString(struct unicode_string *dst, ++ struct unicode_string *src, ++ BOOLEAN alloc) wstdcall; ++BOOLEAN KeCancelTimer(struct nt_timer *nt_timer) wstdcall; ++void KeInitializeDpc(struct kdpc *kdpc, void *func, void *ctx) wstdcall; ++ ++extern spinlock_t ntoskernel_lock; ++extern spinlock_t irp_cancel_lock; ++extern struct nt_list object_list; ++extern CCHAR cpu_count; ++#ifdef CONFIG_X86_64 ++extern struct kuser_shared_data kuser_shared_data; ++#endif ++ ++#define IoCompleteRequest(irp, prio) IofCompleteRequest(irp, prio) ++#define IoCallDriver(dev, irp) IofCallDriver(dev, irp) ++ ++#if defined(IO_DEBUG) ++#define DUMP_IRP(_irp) \ ++do { \ ++ struct io_stack_location *_irp_sl; \ ++ _irp_sl = IoGetCurrentIrpStackLocation(_irp); \ ++ IOTRACE("irp: %p, stack size: %d, cl: %d, sl: %p, dev_obj: %p, " \ ++ "mj_fn: %d, minor_fn: %d, nt_urb: %p, event: %p", \ ++ _irp, _irp->stack_count, (_irp)->current_location, \ ++ _irp_sl, _irp_sl->dev_obj, _irp_sl->major_fn, \ ++ _irp_sl->minor_fn, IRP_URB(_irp), \ ++ (_irp)->user_event); \ ++} while (0) ++#else ++#define DUMP_IRP(_irp) do { } while (0) ++#endif ++ ++#endif // _NTOSKERNEL_H_ +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/ntoskernel_io.c linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/ntoskernel_io.c +--- linux-3.12.2/3rdparty/ndiswrapper/ntoskernel_io.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/ntoskernel_io.c 2013-11-28 21:42:11.000000000 +0200 +@@ -0,0 +1,1161 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * 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 "ntoskernel.h" ++#include "ndis.h" ++#include "wrapndis.h" ++#include "usb.h" ++#include "loader.h" ++#include "ntoskernel_io_exports.h" ++ ++wstdcall void WIN_FUNC(IoAcquireCancelSpinLock,1) ++ (KIRQL *irql) __acquires(irql) ++{ ++ spin_lock_bh(&irp_cancel_lock); ++ *irql = 0; ++} ++ ++wstdcall void WIN_FUNC(IoReleaseCancelSpinLock,1) ++ (KIRQL irql) __releases(irql) ++{ ++ spin_unlock_bh(&irp_cancel_lock); ++} ++ ++wstdcall int WIN_FUNC(IoIsWdmVersionAvailable,2) ++ (UCHAR major, UCHAR minor) ++{ ++ IOENTER("%d, %x", major, minor); ++ if (major == 1 && ++ (minor == 0x30 || // Windows 2003 ++ minor == 0x20 || // Windows XP ++ minor == 0x10)) // Windows 2000 ++ IOEXIT(return TRUE); ++ IOEXIT(return FALSE); ++} ++ ++wstdcall BOOLEAN WIN_FUNC(IoIs32bitProcess,1) ++ (struct irp *irp) ++{ ++#ifdef CONFIG_X86_64 ++ return FALSE; ++#else ++ return TRUE; ++#endif ++} ++ ++wstdcall void WIN_FUNC(IoInitializeIrp,3) ++ (struct irp *irp, USHORT size, CCHAR stack_count) ++{ ++ IOENTER("irp: %p, %d, %d", irp, size, stack_count); ++ ++ memset(irp, 0, size); ++ irp->size = size; ++ irp->stack_count = stack_count; ++ irp->current_location = stack_count; ++ IoGetCurrentIrpStackLocation(irp) = IRP_SL(irp, stack_count); ++ IOEXIT(return); ++} ++ ++wstdcall void WIN_FUNC(IoReuseIrp,2) ++ (struct irp *irp, NTSTATUS status) ++{ ++ IOENTER("%p, %d", irp, status); ++ if (irp) { ++ UCHAR alloc_flags; ++ ++ alloc_flags = irp->alloc_flags; ++ IoInitializeIrp(irp, irp->size, irp->stack_count); ++ irp->alloc_flags = alloc_flags; ++ irp->io_status.status = status; ++ } ++ IOEXIT(return); ++} ++ ++wstdcall struct irp *WIN_FUNC(IoAllocateIrp,2) ++ (char stack_count, BOOLEAN charge_quota) ++{ ++ struct irp *irp; ++ int irp_size; ++ ++ IOENTER("count: %d", stack_count); ++ stack_count++; ++ irp_size = IoSizeOfIrp(stack_count); ++ irp = kmalloc(irp_size, irql_gfp()); ++ if (irp) ++ IoInitializeIrp(irp, irp_size, stack_count); ++ IOTRACE("irp %p", irp); ++ IOEXIT(return irp); ++} ++ ++wstdcall BOOLEAN WIN_FUNC(IoCancelIrp,1) ++ (struct irp *irp) ++{ ++ typeof(irp->cancel_routine) cancel_routine; ++ ++ /* NB: this function may be called at DISPATCH_LEVEL */ ++ IOTRACE("irp: %p", irp); ++ if (!irp) ++ return FALSE; ++ DUMP_IRP(irp); ++ IoAcquireCancelSpinLock(&irp->cancel_irql); ++ cancel_routine = xchg(&irp->cancel_routine, NULL); ++ IOTRACE("%p", cancel_routine); ++ irp->cancel = TRUE; ++ if (cancel_routine) { ++ struct device_object *dev_obj; ++ ++ if (irp->current_location >= 0 && ++ irp->current_location < irp->stack_count) ++ dev_obj = IoGetCurrentIrpStackLocation(irp)->dev_obj; ++ else ++ dev_obj = NULL; ++ IOTRACE("current_location: %d, dev_obj: %p", ++ irp->current_location, dev_obj); ++ /* cancel_routine will release the spin lock */ ++ __release(irp->cancel_irql); ++ LIN2WIN2(cancel_routine, dev_obj, irp); ++ /* in usb's cancel, irp->cancel is set to indicate ++ * status of cancel */ ++ IOEXIT(return xchg(&irp->cancel, TRUE)); ++ } else { ++ IOTRACE("irp %p already canceled", irp); ++ IoReleaseCancelSpinLock(irp->cancel_irql); ++ IOEXIT(return FALSE); ++ } ++} ++ ++wstdcall void IoQueueThreadIrp(struct irp *irp) ++{ ++ struct nt_thread *thread; ++ KIRQL irql; ++ ++ thread = get_current_nt_thread(); ++ if (thread) { ++ IOTRACE("thread: %p, task: %p", thread, thread->task); ++ irp->flags |= IRP_SYNCHRONOUS_API; ++ irql = nt_spin_lock_irql(&thread->lock, DISPATCH_LEVEL); ++ InsertTailList(&thread->irps, &irp->thread_list); ++ IoIrpThread(irp) = thread; ++ nt_spin_unlock_irql(&thread->lock, irql); ++ } else ++ IoIrpThread(irp) = NULL; ++} ++ ++wstdcall void IoDequeueThreadIrp(struct irp *irp) ++{ ++ struct nt_thread *thread; ++ KIRQL irql; ++ ++ thread = IoIrpThread(irp); ++ if (thread) { ++ irql = nt_spin_lock_irql(&thread->lock, DISPATCH_LEVEL); ++ RemoveEntryList(&irp->thread_list); ++ nt_spin_unlock_irql(&thread->lock, irql); ++ } ++} ++ ++wstdcall void WIN_FUNC(IoFreeIrp,1) ++ (struct irp *irp) ++{ ++ IOENTER("irp = %p", irp); ++ if (!irp) { ++ WARNING("irp is NULL"); ++ return; ++ } ++ ++ if (irp->flags & IRP_SYNCHRONOUS_API) ++ IoDequeueThreadIrp(irp); ++ IoCancelIrp(irp); ++ kfree(irp); ++ ++ IOEXIT(return); ++} ++ ++wstdcall struct irp *WIN_FUNC(IoBuildAsynchronousFsdRequest,6) ++ (ULONG major_fn, struct device_object *dev_obj, void *buffer, ++ ULONG length, LARGE_INTEGER *offset, ++ struct io_status_block *user_status) ++{ ++ struct irp *irp; ++ struct io_stack_location *irp_sl; ++ ++ IOENTER("%p", dev_obj); ++ if (!dev_obj) ++ IOEXIT(return NULL); ++ irp = IoAllocateIrp(dev_obj->stack_count, FALSE); ++ if (irp == NULL) { ++ WARNING("couldn't allocate irp"); ++ IOEXIT(return NULL); ++ } ++ ++ irp_sl = IoGetNextIrpStackLocation(irp); ++ irp_sl->major_fn = major_fn; ++ IOTRACE("major_fn: %d", major_fn); ++ irp_sl->minor_fn = 0; ++ irp_sl->flags = 0; ++ irp_sl->control = 0; ++ irp_sl->dev_obj = dev_obj; ++ irp_sl->file_obj = NULL; ++ irp_sl->completion_routine = NULL; ++ ++ if (dev_obj->flags & DO_DIRECT_IO) { ++ irp->mdl = IoAllocateMdl(buffer, length, FALSE, FALSE, irp); ++ if (irp->mdl == NULL) { ++ IoFreeIrp(irp); ++ return NULL; ++ } ++ MmProbeAndLockPages(irp->mdl, KernelMode, ++ major_fn == IRP_MJ_WRITE ? ++ IoReadAccess : IoWriteAccess); ++ IOTRACE("mdl: %p", irp->mdl); ++ } else if (dev_obj->flags & DO_BUFFERED_IO) { ++ irp->associated_irp.system_buffer = buffer; ++ irp->flags = IRP_BUFFERED_IO; ++ irp->mdl = NULL; ++ IOTRACE("buffer: %p", buffer); ++ } ++ if (major_fn == IRP_MJ_READ) { ++ irp_sl->params.read.length = length; ++ irp_sl->params.read.byte_offset = *offset; ++ } else if (major_fn == IRP_MJ_WRITE) { ++ irp_sl->params.write.length = length; ++ irp_sl->params.write.byte_offset = *offset; ++ } ++ irp->user_status = user_status; ++ IOTRACE("irp: %p", irp); ++ return irp; ++} ++ ++wstdcall struct irp *WIN_FUNC(IoBuildSynchronousFsdRequest,7) ++ (ULONG major_fn, struct device_object *dev_obj, void *buf, ++ ULONG length, LARGE_INTEGER *offset, struct nt_event *event, ++ struct io_status_block *user_status) ++{ ++ struct irp *irp; ++ ++ irp = IoBuildAsynchronousFsdRequest(major_fn, dev_obj, buf, length, ++ offset, user_status); ++ if (irp == NULL) ++ return NULL; ++ irp->user_event = event; ++ IoQueueThreadIrp(irp); ++ return irp; ++} ++ ++wstdcall struct irp *WIN_FUNC(IoBuildDeviceIoControlRequest,9) ++ (ULONG ioctl, struct device_object *dev_obj, ++ void *input_buf, ULONG input_buf_len, void *output_buf, ++ ULONG output_buf_len, BOOLEAN internal_ioctl, ++ struct nt_event *event, struct io_status_block *io_status) ++{ ++ struct irp *irp; ++ struct io_stack_location *irp_sl; ++ ULONG buf_len; ++ ++ IOENTER("%p, 0x%08x, %d", dev_obj, ioctl, internal_ioctl); ++ if (!dev_obj) ++ IOEXIT(return NULL); ++ irp = IoAllocateIrp(dev_obj->stack_count, FALSE); ++ if (irp == NULL) { ++ WARNING("couldn't allocate irp"); ++ return NULL; ++ } ++ irp_sl = IoGetNextIrpStackLocation(irp); ++ irp_sl->params.dev_ioctl.code = ioctl; ++ irp_sl->params.dev_ioctl.input_buf_len = input_buf_len; ++ irp_sl->params.dev_ioctl.output_buf_len = output_buf_len; ++ irp_sl->major_fn = (internal_ioctl) ? ++ IRP_MJ_INTERNAL_DEVICE_CONTROL : IRP_MJ_DEVICE_CONTROL; ++ IOTRACE("%d", IO_METHOD_FROM_CTL_CODE(ioctl)); ++ ++ switch (IO_METHOD_FROM_CTL_CODE(ioctl)) { ++ case METHOD_BUFFERED: ++ buf_len = max(input_buf_len, output_buf_len); ++ if (buf_len) { ++ irp->associated_irp.system_buffer = ++ ExAllocatePoolWithTag(NonPagedPool, buf_len, 0); ++ if (!irp->associated_irp.system_buffer) { ++ IoFreeIrp(irp); ++ IOEXIT(return NULL); ++ } ++ irp->associated_irp.system_buffer = input_buf; ++ if (input_buf) ++ memcpy(irp->associated_irp.system_buffer, ++ input_buf, input_buf_len); ++ irp->flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER; ++ if (output_buf) ++ irp->flags = IRP_INPUT_OPERATION; ++ irp->user_buf = output_buf; ++ } else ++ irp->user_buf = NULL; ++ break; ++ case METHOD_IN_DIRECT: ++ case METHOD_OUT_DIRECT: ++ if (input_buf) { ++ irp->associated_irp.system_buffer = ++ ExAllocatePoolWithTag(NonPagedPool, ++ input_buf_len, 0); ++ if (!irp->associated_irp.system_buffer) { ++ IoFreeIrp(irp); ++ IOEXIT(return NULL); ++ } ++ memcpy(irp->associated_irp.system_buffer, ++ input_buf, input_buf_len); ++ irp->flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER; ++ } ++ /* TODO: we are supposed to setup MDL, but USB layer ++ * doesn't use MDLs. Moreover, USB layer mirrors ++ * non-DMAable buffers, so no need to allocate ++ * DMAable buffer here */ ++ if (output_buf) { ++ irp->associated_irp.system_buffer = ++ ExAllocatePoolWithTag(NonPagedPool, ++ output_buf_len, 0); ++ if (!irp->associated_irp.system_buffer) { ++ IoFreeIrp(irp); ++ IOEXIT(return NULL); ++ } ++ irp->flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER; ++ } ++ break; ++ case METHOD_NEITHER: ++ irp->user_buf = output_buf; ++ irp_sl->params.dev_ioctl.type3_input_buf = input_buf; ++ break; ++ } ++ ++ irp->user_status = io_status; ++ irp->user_event = event; ++ IoQueueThreadIrp(irp); ++ ++ IOTRACE("irp: %p", irp); ++ IOEXIT(return irp); ++} ++ ++wfastcall NTSTATUS WIN_FUNC(IofCallDriver,2) ++ (struct device_object *dev_obj, struct irp *irp) ++{ ++ struct io_stack_location *irp_sl; ++ NTSTATUS status; ++ driver_dispatch_t *major_func; ++ struct driver_object *drv_obj; ++ ++ if (irp->current_location <= 0) { ++ ERROR("invalid irp: %p, %d", irp, irp->current_location); ++ return STATUS_INVALID_PARAMETER; ++ } ++ IOTRACE("%p, %p, %p, %d, %d, %p", dev_obj, irp, dev_obj->drv_obj, ++ irp->current_location, irp->stack_count, ++ IoGetCurrentIrpStackLocation(irp)); ++ IoSetNextIrpStackLocation(irp); ++ DUMP_IRP(irp); ++ irp_sl = IoGetCurrentIrpStackLocation(irp); ++ drv_obj = dev_obj->drv_obj; ++ irp_sl->dev_obj = dev_obj; ++ major_func = drv_obj->major_func[irp_sl->major_fn]; ++ IOTRACE("major_func: %p, dev_obj: %p", major_func, dev_obj); ++ if (major_func) ++ status = LIN2WIN2(major_func, dev_obj, irp); ++ else { ++ ERROR("major_function %d is not implemented", ++ irp_sl->major_fn); ++ status = STATUS_NOT_SUPPORTED; ++ } ++ IOEXIT(return status); ++} ++ ++wfastcall void WIN_FUNC(IofCompleteRequest,2) ++ (struct irp *irp, CHAR prio_boost) ++{ ++ struct io_stack_location *irp_sl; ++ ++#ifdef IO_DEBUG ++ DUMP_IRP(irp); ++ if (irp->io_status.status == STATUS_PENDING) { ++ ERROR("invalid irp: %p, STATUS_PENDING", irp); ++ return; ++ } ++ if (irp->current_location < 0 || ++ irp->current_location >= irp->stack_count) { ++ ERROR("invalid irp: %p, %d", irp, irp->current_location); ++ return; ++ } ++#endif ++ for (irp_sl = IoGetCurrentIrpStackLocation(irp); ++ irp->current_location < irp->stack_count; irp_sl++) { ++ struct device_object *dev_obj; ++ NTSTATUS status; ++ ++ DUMP_IRP(irp); ++ if (irp_sl->control & SL_PENDING_RETURNED) ++ irp->pending_returned = TRUE; ++ ++ /* current_location and dev_obj must be same as when ++ * driver called IoSetCompletionRoutine, which sets ++ * completion routine at next (lower) location, which ++ * is what we are going to call below; so we set ++ * current_location and dev_obj for the previous ++ * (higher) location */ ++ IoSkipCurrentIrpStackLocation(irp); ++ if (irp->current_location < irp->stack_count) ++ dev_obj = IoGetCurrentIrpStackLocation(irp)->dev_obj; ++ else ++ dev_obj = NULL; ++ ++ IOTRACE("%d, %d, %p", irp->current_location, irp->stack_count, ++ dev_obj); ++ if (irp_sl->completion_routine && ++ ((irp->io_status.status == STATUS_SUCCESS && ++ irp_sl->control & SL_INVOKE_ON_SUCCESS) || ++ (irp->io_status.status != STATUS_SUCCESS && ++ irp_sl->control & SL_INVOKE_ON_ERROR) || ++ (irp->cancel == TRUE && ++ irp_sl->control & SL_INVOKE_ON_CANCEL))) { ++ IOTRACE("calling completion_routine at: %p, %p", ++ irp_sl->completion_routine, irp_sl->context); ++ status = LIN2WIN3(irp_sl->completion_routine, ++ dev_obj, irp, irp_sl->context); ++ IOTRACE("status: %08X", status); ++ if (status == STATUS_MORE_PROCESSING_REQUIRED) ++ IOEXIT(return); ++ } else { ++ /* propagate pending status to next irp_sl */ ++ if (irp->pending_returned && ++ irp->current_location < irp->stack_count) ++ IoMarkIrpPending(irp); ++ } ++ } ++ ++ if (irp->user_status) { ++ irp->user_status->status = irp->io_status.status; ++ irp->user_status->info = irp->io_status.info; ++ } ++ ++ if (irp->user_event) { ++ IOTRACE("setting event %p", irp->user_event); ++ KeSetEvent(irp->user_event, prio_boost, FALSE); ++ } ++ ++ if (irp->associated_irp.system_buffer && ++ (irp->flags & IRP_DEALLOCATE_BUFFER)) ++ ExFreePool(irp->associated_irp.system_buffer); ++ else { ++ struct mdl *mdl; ++ while ((mdl = irp->mdl)) { ++ irp->mdl = mdl->next; ++ MmUnlockPages(mdl); ++ IoFreeMdl(mdl); ++ } ++ } ++ IOTRACE("freeing irp %p", irp); ++ IoFreeIrp(irp); ++ IOEXIT(return); ++} ++ ++wstdcall NTSTATUS IoPassIrpDown(struct device_object *dev_obj, struct irp *irp) ++{ ++ IoSkipCurrentIrpStackLocation(irp); ++ IOEXIT(return IoCallDriver(dev_obj, irp)); ++} ++ ++wstdcall NTSTATUS IoIrpSyncComplete(struct device_object *dev_obj, ++ struct irp *irp, void *context) ++{ ++ if (irp->pending_returned == TRUE) ++ KeSetEvent(context, IO_NO_INCREMENT, FALSE); ++ IOEXIT(return STATUS_MORE_PROCESSING_REQUIRED); ++} ++WIN_FUNC_DECL(IoIrpSyncComplete,3) ++ ++wstdcall NTSTATUS IoSyncForwardIrp(struct device_object *dev_obj, ++ struct irp *irp) ++{ ++ struct nt_event event; ++ NTSTATUS status; ++ ++ IoCopyCurrentIrpStackLocationToNext(irp); ++ KeInitializeEvent(&event, SynchronizationEvent, FALSE); ++ /* completion function is called as Windows function */ ++ IoSetCompletionRoutine(irp, WIN_FUNC_PTR(IoIrpSyncComplete,3), &event, ++ TRUE, TRUE, TRUE); ++ status = IoCallDriver(dev_obj, irp); ++ IOTRACE("%08X", status); ++ if (status == STATUS_PENDING) { ++ KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, ++ NULL); ++ status = irp->io_status.status; ++ } ++ IOTRACE("%08X", status); ++ IOEXIT(return status); ++} ++WIN_FUNC_DECL(IoSyncForwardIrp,2) ++ ++wstdcall NTSTATUS IoAsyncForwardIrp(struct device_object *dev_obj, ++ struct irp *irp) ++{ ++ NTSTATUS status; ++ ++ IoCopyCurrentIrpStackLocationToNext(irp); ++ status = IoCallDriver(dev_obj, irp); ++ IOEXIT(return status); ++} ++WIN_FUNC_DECL(IoAsyncForwardIrp,2) ++ ++wstdcall NTSTATUS IoInvalidDeviceRequest(struct device_object *dev_obj, ++ struct irp *irp) ++{ ++ struct io_stack_location *irp_sl; ++ NTSTATUS status; ++ ++ irp_sl = IoGetCurrentIrpStackLocation(irp); ++ WARNING("%d:%d not implemented", irp_sl->major_fn, irp_sl->minor_fn); ++ irp->io_status.status = STATUS_SUCCESS; ++ irp->io_status.info = 0; ++ status = irp->io_status.status; ++ IoCompleteRequest(irp, IO_NO_INCREMENT); ++ IOEXIT(return status); ++} ++WIN_FUNC_DECL(IoInvalidDeviceRequest,2) ++ ++static irqreturn_t io_irq_isr(int irq, void *data ISR_PT_REGS_PARAM_DECL) ++{ ++ struct kinterrupt *interrupt = data; ++ BOOLEAN ret; ++ ++#ifdef CONFIG_DEBUG_SHIRQ ++ if (!interrupt->u.enabled) ++ EXIT1(return IRQ_NONE); ++#endif ++ TRACE6("%p", interrupt); ++ nt_spin_lock(interrupt->actual_lock); ++ ret = LIN2WIN2(interrupt->isr, interrupt, interrupt->isr_ctx); ++ nt_spin_unlock(interrupt->actual_lock); ++ if (ret == TRUE) ++ EXIT6(return IRQ_HANDLED); ++ else ++ EXIT6(return IRQ_NONE); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoConnectInterrupt,11) ++ (struct kinterrupt **kinterrupt, PKSERVICE_ROUTINE isr, void *isr_ctx, ++ NT_SPIN_LOCK *lock, ULONG vector, KIRQL irql, KIRQL synch_irql, ++ enum kinterrupt_mode mode, BOOLEAN shared, KAFFINITY cpu_mask, ++ BOOLEAN save_fp) ++{ ++ struct kinterrupt *interrupt; ++ IOENTER(""); ++ interrupt = kzalloc(sizeof(*interrupt), GFP_KERNEL); ++ if (!interrupt) ++ IOEXIT(return STATUS_INSUFFICIENT_RESOURCES); ++ interrupt->vector = vector; ++ interrupt->cpu_mask = cpu_mask; ++ nt_spin_lock_init(&interrupt->lock); ++ if (lock) ++ interrupt->actual_lock = lock; ++ else ++ interrupt->actual_lock = &interrupt->lock; ++ interrupt->shared = shared; ++ interrupt->save_fp = save_fp; ++ interrupt->isr = isr; ++ interrupt->isr_ctx = isr_ctx; ++ InitializeListHead(&interrupt->list); ++ interrupt->irql = irql; ++ interrupt->synch_irql = synch_irql; ++ interrupt->mode = mode; ++ if (request_irq(vector, io_irq_isr, shared ? IRQF_SHARED : 0, ++ DRIVER_NAME, interrupt)) { ++ WARNING("request for irq %d failed", vector); ++ kfree(interrupt); ++ IOEXIT(return STATUS_INSUFFICIENT_RESOURCES); ++ } ++ *kinterrupt = interrupt; ++#ifdef CONFIG_DEBUG_SHIRQ ++ interrupt->u.enabled = 1; ++#endif ++ IOEXIT(return STATUS_SUCCESS); ++} ++ ++wstdcall void WIN_FUNC(IoDisconnectInterrupt,1) ++ (struct kinterrupt *interrupt) ++{ ++#ifdef CONFIG_DEBUG_SHIRQ ++ interrupt->u.enabled = 0; ++#endif ++ free_irq(interrupt->vector, interrupt); ++ kfree(interrupt); ++} ++ ++wstdcall struct mdl *WIN_FUNC(IoAllocateMdl,5) ++ (void *virt, ULONG length, BOOLEAN second_buf, BOOLEAN charge_quota, ++ struct irp *irp) ++{ ++ struct mdl *mdl; ++ mdl = allocate_init_mdl(virt, length); ++ if (!mdl) ++ return NULL; ++ if (irp) { ++ if (second_buf == TRUE) { ++ struct mdl *last; ++ ++ last = irp->mdl; ++ while (last->next) ++ last = last->next; ++ last->next = mdl; ++ } else ++ irp->mdl = mdl; ++ } ++ IOTRACE("%p", mdl); ++ return mdl; ++} ++ ++wstdcall void WIN_FUNC(IoFreeMdl,1) ++ (struct mdl *mdl) ++{ ++ IOTRACE("%p", mdl); ++ free_mdl(mdl); ++} ++ ++wstdcall struct io_workitem *WIN_FUNC(IoAllocateWorkItem,1) ++ (struct device_object *dev_obj) ++{ ++ struct io_workitem *io_workitem; ++ ++ IOENTER("%p", dev_obj); ++ io_workitem = kmalloc(sizeof(*io_workitem), irql_gfp()); ++ if (!io_workitem) ++ IOEXIT(return NULL); ++ io_workitem->dev_obj = dev_obj; ++ IOEXIT(return io_workitem); ++} ++ ++wstdcall void WIN_FUNC(IoFreeWorkItem,1) ++ (struct io_workitem *io_workitem) ++{ ++ kfree(io_workitem); ++ IOEXIT(return); ++} ++ ++wstdcall void WIN_FUNC(IoQueueWorkItem,4) ++ (struct io_workitem *io_workitem, void *func, ++ enum work_queue_type queue_type, void *context) ++{ ++ IOENTER("%p, %p", io_workitem, io_workitem->dev_obj); ++ io_workitem->worker_routine = func; ++ io_workitem->context = context; ++ schedule_ntos_work_item(func, io_workitem->dev_obj, context); ++ IOEXIT(return); ++} ++ ++wstdcall void WIN_FUNC(ExQueueWorkItem,2) ++ (struct io_workitem *io_workitem, enum work_queue_type queue_type) ++{ ++ IOENTER("%p", io_workitem); ++ schedule_ntos_work_item(io_workitem->worker_routine, ++ io_workitem->dev_obj, io_workitem->context); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoAllocateDriverObjectExtension,4) ++ (struct driver_object *drv_obj, void *client_id, ULONG extlen, ++ void **ext) ++{ ++ struct custom_ext *ce; ++ ++ IOENTER("%p, %p", drv_obj, client_id); ++ ce = kmalloc(sizeof(*ce) + extlen, irql_gfp()); ++ if (ce == NULL) ++ return STATUS_INSUFFICIENT_RESOURCES; ++ ++ IOTRACE("custom_ext: %p", ce); ++ ce->client_id = client_id; ++ spin_lock_bh(&ntoskernel_lock); ++ InsertTailList(&drv_obj->drv_ext->custom_ext, &ce->list); ++ spin_unlock_bh(&ntoskernel_lock); ++ ++ *ext = (void *)ce + sizeof(*ce); ++ IOTRACE("ext: %p", *ext); ++ IOEXIT(return STATUS_SUCCESS); ++} ++ ++wstdcall void *WIN_FUNC(IoGetDriverObjectExtension,2) ++ (struct driver_object *drv_obj, void *client_id) ++{ ++ struct custom_ext *ce; ++ void *ret; ++ ++ IOENTER("drv_obj: %p, client_id: %p", drv_obj, client_id); ++ ret = NULL; ++ spin_lock_bh(&ntoskernel_lock); ++ nt_list_for_each_entry(ce, &drv_obj->drv_ext->custom_ext, list) { ++ if (ce->client_id == client_id) { ++ ret = (void *)ce + sizeof(*ce); ++ break; ++ } ++ } ++ spin_unlock_bh(&ntoskernel_lock); ++ IOTRACE("ret: %p", ret); ++ return ret; ++} ++ ++void free_custom_extensions(struct driver_extension *drv_ext) ++{ ++ struct nt_list *ent; ++ ++ IOENTER("%p", drv_ext); ++ spin_lock_bh(&ntoskernel_lock); ++ while ((ent = RemoveHeadList(&drv_ext->custom_ext))) ++ kfree(ent); ++ spin_unlock_bh(&ntoskernel_lock); ++ IOEXIT(return); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoCreateDevice,7) ++ (struct driver_object *drv_obj, ULONG dev_ext_length, ++ struct unicode_string *dev_name, DEVICE_TYPE dev_type, ++ ULONG dev_chars, BOOLEAN exclusive, struct device_object **newdev) ++{ ++ struct device_object *dev; ++ struct dev_obj_ext *dev_obj_ext; ++ int size; ++ ++ IOENTER("%p, %u, %p", drv_obj, dev_ext_length, dev_name); ++ ++ size = sizeof(*dev) + dev_ext_length + sizeof(*dev_obj_ext); ++ dev = allocate_object(size, OBJECT_TYPE_DEVICE, dev_name); ++ if (!dev) ++ IOEXIT(return STATUS_INSUFFICIENT_RESOURCES); ++ if (dev_ext_length) ++ dev->dev_ext = dev + 1; ++ else ++ dev->dev_ext = NULL; ++ ++ dev_obj_ext = ((void *)(dev + 1)) + dev_ext_length; ++ dev_obj_ext->dev_obj = dev; ++ dev_obj_ext->size = 0; ++ dev_obj_ext->type = IO_TYPE_DEVICE; ++ dev->dev_obj_ext = dev_obj_ext; ++ ++ dev->type = dev_type; ++ dev->flags = 0; ++ dev->size = sizeof(*dev) + dev_ext_length; ++ dev->ref_count = 1; ++ dev->attached = NULL; ++ dev->stack_count = 1; ++ ++ dev->drv_obj = drv_obj; ++ dev->next = drv_obj->dev_obj; ++ drv_obj->dev_obj = dev; ++ ++ dev->align_req = 1; ++ dev->characteristics = dev_chars; ++ dev->io_timer = NULL; ++ KeInitializeEvent(&dev->lock, SynchronizationEvent, TRUE); ++ dev->vpb = NULL; ++ ++ IOTRACE("dev: %p, ext: %p", dev, dev->dev_ext); ++ *newdev = dev; ++ IOEXIT(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoCreateUnprotectedSymbolicLink,2) ++ (struct unicode_string *link, struct unicode_string *dev_name) ++{ ++ struct ansi_string ansi; ++ ++ IOENTER("%p, %p", dev_name, link); ++ if (dev_name && (RtlUnicodeStringToAnsiString(&ansi, dev_name, TRUE) == ++ STATUS_SUCCESS)) { ++ IOTRACE("dev_name: %s", ansi.buf); ++ RtlFreeAnsiString(&ansi); ++ } ++ if (link && (RtlUnicodeStringToAnsiString(&ansi, link, TRUE) == ++ STATUS_SUCCESS)) { ++ IOTRACE("link: %s", ansi.buf); ++ RtlFreeAnsiString(&ansi); ++ } ++// TODO(); ++ IOEXIT(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoCreateSymbolicLink,2) ++ (struct unicode_string *link, struct unicode_string *dev_name) ++{ ++ IOEXIT(return IoCreateUnprotectedSymbolicLink(link, dev_name)); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoDeleteSymbolicLink,1) ++ (struct unicode_string *link) ++{ ++ struct ansi_string ansi; ++ ++ IOENTER("%p", link); ++ if (link && (RtlUnicodeStringToAnsiString(&ansi, link, TRUE) == ++ STATUS_SUCCESS)) { ++ IOTRACE("dev_name: %s", ansi.buf); ++ RtlFreeAnsiString(&ansi); ++ } ++ IOEXIT(return STATUS_SUCCESS); ++} ++ ++wstdcall void WIN_FUNC(IoDeleteDevice,1) ++ (struct device_object *dev) ++{ ++ IOENTER("%p", dev); ++ if (dev == NULL) ++ IOEXIT(return); ++ IOTRACE("drv_obj: %p", dev->drv_obj); ++ if (dev->drv_obj) { ++ struct device_object *prev; ++ ++ prev = dev->drv_obj->dev_obj; ++ IOTRACE("dev_obj: %p", prev); ++ if (prev == dev) ++ dev->drv_obj->dev_obj = dev->next; ++ else if (prev) { ++ while (prev->next != dev) ++ prev = prev->next; ++ prev->next = dev->next; ++ } ++ } ++ ObDereferenceObject(dev); ++ IOEXIT(return); ++} ++ ++wstdcall void WIN_FUNC(IoDetachDevice,1) ++ (struct device_object *tgt) ++{ ++ struct device_object *tail; ++ ++ IOENTER("%p", tgt); ++ if (!tgt) ++ IOEXIT(return); ++ tail = tgt->attached; ++ if (!tail) ++ IOEXIT(return); ++ IOTRACE("tail: %p", tail); ++ ++ spin_lock_bh(&ntoskernel_lock); ++ tgt->attached = tail->attached; ++ IOTRACE("attached:%p", tgt->attached); ++ for ( ; tail; tail = tail->attached) { ++ IOTRACE("tail:%p", tail); ++ tail->stack_count--; ++ } ++ spin_unlock_bh(&ntoskernel_lock); ++ IOEXIT(return); ++} ++ ++wstdcall struct device_object *WIN_FUNC(IoGetAttachedDevice,1) ++ (struct device_object *dev) ++{ ++ IOENTER("%p", dev); ++ if (!dev) ++ IOEXIT(return NULL); ++ spin_lock_bh(&ntoskernel_lock); ++ while (dev->attached) ++ dev = dev->attached; ++ spin_unlock_bh(&ntoskernel_lock); ++ IOEXIT(return dev); ++} ++ ++wstdcall struct device_object *WIN_FUNC(IoGetAttachedDeviceReference,1) ++ (struct device_object *dev) ++{ ++ IOENTER("%p", dev); ++ if (!dev) ++ IOEXIT(return NULL); ++ dev = IoGetAttachedDevice(dev); ++ ObReferenceObject(dev); ++ IOEXIT(return dev); ++} ++ ++wstdcall struct device_object *WIN_FUNC(IoAttachDeviceToDeviceStack,2) ++ (struct device_object *src, struct device_object *tgt) ++{ ++ struct device_object *attached; ++ struct dev_obj_ext *src_dev_ext; ++ ++ IOENTER("%p, %p", src, tgt); ++ attached = IoGetAttachedDevice(tgt); ++ IOTRACE("%p", attached); ++ src_dev_ext = src->dev_obj_ext; ++ spin_lock_bh(&ntoskernel_lock); ++ if (attached) ++ attached->attached = src; ++ src->attached = NULL; ++ src->stack_count = attached->stack_count + 1; ++ src_dev_ext->attached_to = attached; ++ spin_unlock_bh(&ntoskernel_lock); ++ IOTRACE("stack_count: %d -> %d", attached->stack_count, ++ src->stack_count); ++ IOEXIT(return attached); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoGetDeviceProperty,5) ++ (struct device_object *pdo, enum device_registry_property dev_property, ++ ULONG buffer_len, void *buffer, ULONG *result_len) ++{ ++ struct ansi_string ansi; ++ struct unicode_string unicode; ++ struct wrap_device *wd; ++ ULONG need; ++ ++ IOENTER("dev_obj = %p, dev_property = %d, buffer_len = %u, " ++ "buffer = %p, result_len = %p", pdo, dev_property, ++ buffer_len, buffer, result_len); ++ ++ wd = pdo->reserved; ++ switch (dev_property) { ++ case DevicePropertyDeviceDescription: ++ case DevicePropertyFriendlyName: ++ case DevicePropertyDriverKeyName: ++ if (wrap_is_pci_bus(wd->dev_bus)) ++ RtlInitAnsiString(&ansi, "PCI"); ++ else // if (wrap_is_usb_bus(wd->dev_bus)) ++ RtlInitAnsiString(&ansi, "USB"); ++ need = sizeof(wchar_t) * (ansi.max_length + 1); ++ if (buffer_len < need) { ++ *result_len = need; ++ IOEXIT(return STATUS_BUFFER_TOO_SMALL); ++ } ++ unicode.max_length = buffer_len; ++ unicode.buf = buffer; ++ if (RtlAnsiStringToUnicodeString(&unicode, &ansi, ++ FALSE) != STATUS_SUCCESS) { ++ *result_len = unicode.length; ++ IOEXIT(return STATUS_BUFFER_TOO_SMALL); ++ } ++ IOEXIT(return STATUS_SUCCESS); ++ default: ++ WARNING("%d not implemented", dev_property); ++ IOEXIT(return STATUS_INVALID_PARAMETER_2); ++ } ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoGetDeviceObjectPointer,4) ++ (struct unicode_string *name, ACCESS_MASK desired_access, ++ struct file_object *file_obj, struct device_object *dev_obj) ++{ ++ struct common_object_header *coh; ++ ++ dev_obj = NULL; ++ /* TODO: access is not checked and file_obj is filled with zeroes */ ++ spin_lock_bh(&ntoskernel_lock); ++ nt_list_for_each_entry(coh, &object_list, list) { ++ TRACE5("header: %p, type: %d", coh, coh->type); ++ if (coh->type != OBJECT_TYPE_DEVICE) ++ continue; ++ if (!RtlCompareUnicodeString(&coh->name, name, TRUE)) { ++ dev_obj = HEADER_TO_OBJECT(coh); ++ TRACE5("dev_obj: %p", dev_obj); ++ break; ++ } ++ } ++ spin_unlock_bh(&ntoskernel_lock); ++ if (dev_obj) { ++ memset(file_obj, 0, sizeof(*file_obj)); ++ WARNING("file_obj filled with zeroes"); ++ IOEXIT(return STATUS_SUCCESS); ++ } else ++ IOEXIT(return STATUS_OBJECT_NAME_INVALID); ++} ++ ++/* NOTE: Make sure to compile with -freg-struct-return, so gcc will ++ * return union in register, like Windows */ ++wstdcall union power_state WIN_FUNC(PoSetPowerState,3) ++ (struct device_object *dev_obj, enum power_state_type type, ++ union power_state state) ++{ ++ IOEXIT(return state); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(PoCallDriver,2) ++ (struct device_object *dev_obj, struct irp *irp) ++{ ++ return IoCallDriver(dev_obj, irp); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(PoRequestPowerIrp,6) ++ (struct device_object *dev_obj, UCHAR minor_fn, ++ union power_state power_state, void *completion_func, ++ void *context, struct irp **pirp) ++{ ++ struct irp *irp; ++ struct io_stack_location *irp_sl; ++ ++ TRACE1("%p, %d, %p", dev_obj, dev_obj->stack_count, dev_obj->drv_obj); ++ irp = IoAllocateIrp(dev_obj->stack_count, FALSE); ++ if (!irp) ++ return STATUS_INSUFFICIENT_RESOURCES; ++ irp_sl = IoGetNextIrpStackLocation(irp); ++ irp_sl->major_fn = IRP_MJ_POWER; ++ irp_sl->minor_fn = minor_fn; ++ if (minor_fn == IRP_MN_WAIT_WAKE) ++ irp_sl->params.power.type = SystemPowerState; ++ else ++ irp_sl->params.power.type = DevicePowerState; ++ irp_sl->params.power.state = power_state; ++ irp_sl->completion_routine = completion_func; ++ irp->io_status.status = STATUS_NOT_SUPPORTED; ++ *pirp = irp; ++ return PoCallDriver(dev_obj, irp); ++} ++ ++wstdcall void WIN_FUNC(PoStartNextPowerIrp,1) ++ (struct irp *irp) ++{ ++ IOENTER("irp = %p", irp); ++ IOEXIT(return); ++} ++ ++wstdcall void WIN_FUNC(IoInitializeRemoveLockEx,5) ++ (struct io_remove_lock *lock, ULONG alloc_tag, ULONG max_locked_min, ++ ULONG high_mark, ULONG lock_size) ++{ ++ TODO(); ++} ++ ++wstdcall void *WIN_FUNC(IoAllocateErrorLogEntry,2) ++ (void *io_object, UCHAR entry_size) ++{ ++ /* not implemented fully */ ++ void *ret = kmalloc(sizeof(struct io_error_log_packet) + entry_size, ++ irql_gfp()); ++ TRACE2("%p", ret); ++ if (ret) ++ return ret + sizeof(struct io_error_log_packet); ++ else ++ return NULL; ++} ++ ++wstdcall void WIN_FUNC(IoWriteErrorLogEntry,1) ++ (void *entry) ++{ ++ /* TODO: log error with codes and message */ ++ ERROR(""); ++} ++ ++wstdcall void WIN_FUNC(IoFreeErrorLogEntry,1) ++ (void *entry) ++{ ++ TRACE2("%p", entry); ++ kfree(entry - sizeof(struct io_error_log_packet)); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoAcquireRemoveLockEx,5) ++ (struct io_remove_lock *lock, void *tag, char *file, ULONG line, ++ ULONG lock_size) ++{ ++ TODO(); ++ IOEXIT(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoReleaseRemoveLockEx,3) ++ (struct io_remove_lock *lock, void *tag, ULONG lock_size) ++{ ++ TODO(); ++ IOEXIT(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoRegisterDeviceInterface,4) ++ (struct device_object *pdo, struct guid *guid_class, ++ struct unicode_string *reference, struct unicode_string *link) ++{ ++ struct ansi_string ansi; ++ ++ /* TODO: check if pdo is valid */ ++ RtlInitAnsiString(&ansi, "ndis"); ++ ENTER1("pdo: %p, ref: %p, link: %p, %x, %x, %x", pdo, reference, link, ++ guid_class->data1, guid_class->data2, guid_class->data3); ++ return RtlAnsiStringToUnicodeString(link, &ansi, TRUE); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoSetDeviceInterfaceState,2) ++ (struct unicode_string *link, BOOLEAN enable) ++{ ++ ENTER1("link: %p, enable: %d", link, enable); ++ return STATUS_SUCCESS; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoOpenDeviceRegistryKey,4) ++ (struct device_object *dev_obj, ULONG type, ACCESS_MASK mask, ++ void **handle) ++{ ++ ENTER1("dev_obj: %p", dev_obj); ++ *handle = dev_obj; ++ return STATUS_SUCCESS; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoWMIRegistrationControl,2) ++ (struct device_object *dev_obj, ULONG action) ++{ ++ ENTER2("%p, %d", dev_obj, action); ++ EXIT2(return STATUS_SUCCESS); ++} ++ ++wstdcall void WIN_FUNC(IoInvalidateDeviceRelations,2) ++ (struct device_object *dev_obj, enum device_relation_type type) ++{ ++ INFO("%p, %d", dev_obj, type); ++ TODO(); ++} ++ ++wstdcall void WIN_FUNC(IoInvalidateDeviceState,1) ++ (struct device_object *pdo) ++{ ++ INFO("%p", pdo); ++ TODO(); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoRegisterPlugPlayNotification,7) ++ (UINT category, ULONG flags, void *data, struct driver_object *object, ++ void *callback, void *context, void **notification_entry) ++{ ++ TRACE2("category: %d, flags 0x%x, data: %p, object: %p, callback: %p, " ++ "context: %p, notification_entry: %p", category, flags, data, ++ object, callback, context, notification_entry); ++ TODO(); ++ IOEXIT(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoUnregisterPlugPlayNotification,1) ++ (void *notification_entry) ++{ ++ TRACE2("%p", notification_entry); ++ TODO(); ++ IOEXIT(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoWMIOpenBlock,3) ++ (struct guid *guid, ULONG access, void *object) ++{ ++ TODO(); ++ IOEXIT(return STATUS_NOT_IMPLEMENTED); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(IoWMIQueryAllData,3) ++ (void *data_block_object, UINT *buffer_size, void *buffer) ++{ ++ TODO(); ++ IOEXIT(return STATUS_NOT_IMPLEMENTED); ++} ++ ++wstdcall void WIN_FUNC(IoGetStackLimits,2) ++ (ULONG_PTR *LowLimit, ULONG_PTR *HighLimit) ++{ ++ *LowLimit = (ULONG_PTR)&LowLimit & ~(THREAD_SIZE - 1); ++ *HighLimit = *LowLimit + THREAD_SIZE; ++ IOTRACE("LowLimit: 0x%lx, HighLimit: 0x%lx", *LowLimit, *HighLimit); ++ IOEXIT(return); ++} +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/pe_linker.c linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/pe_linker.c +--- linux-3.12.2/3rdparty/ndiswrapper/pe_linker.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/pe_linker.c 2013-11-28 21:42:11.000000000 +0200 +@@ -0,0 +1,600 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * 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. ++ * ++ */ ++ ++#ifdef TEST_LOADER ++ ++#include "usr_linker.h" ++ ++#else ++ ++#include ++#include ++ ++//#define DEBUGLINKER 2 ++ ++#include "ntoskernel.h" ++ ++#endif ++ ++struct pe_exports { ++ char *dll; ++ char *name; ++ generic_func addr; ++}; ++ ++static struct pe_exports pe_exports[40]; ++static int num_pe_exports; ++ ++#define RVA2VA(image, rva, type) (type)(ULONG_PTR)((void *)image + rva) ++#define CHECK_SZ(a,b) { if (sizeof(a) != b) { \ ++ ERROR("%s is bad, got %zd, expected %d", \ ++ #a , sizeof(a), (b)); return -EINVAL; } } ++ ++#if defined(DEBUGLINKER) && DEBUGLINKER > 0 ++#define DBGLINKER(fmt, ...) printk(KERN_INFO "%s (%s:%d): " fmt "\n", \ ++ DRIVER_NAME, __func__, \ ++ __LINE__ , ## __VA_ARGS__); ++static const char *image_directory_name[] = { ++ "EXPORT", ++ "IMPORT", ++ "RESOURCE", ++ "EXCEPTION", ++ "SECURITY", ++ "BASERELOC", ++ "DEBUG", ++ "COPYRIGHT", ++ "GLOBALPTR", ++ "TLS", ++ "LOAD_CONFIG", ++ "BOUND_IMPORT", ++ "IAT", ++ "DELAY_IMPORT", ++ "COM_DESCRIPTOR" }; ++#else ++#define DBGLINKER(fmt, ...) do { } while (0) ++#endif ++ ++#ifndef TEST_LOADER ++extern struct wrap_export ntoskernel_exports[], ntoskernel_io_exports[], ++ ndis_exports[], crt_exports[], hal_exports[], rtl_exports[]; ++#ifdef ENABLE_USB ++extern struct wrap_export usb_exports[]; ++#endif ++ ++static int get_export(char *name, generic_func *func) ++{ ++ int i, j; ++ ++ struct wrap_export *exports[] = { ++ ntoskernel_exports, ++ ntoskernel_io_exports, ++ ndis_exports, ++ crt_exports, ++ hal_exports, ++ rtl_exports, ++#ifdef ENABLE_USB ++ usb_exports, ++#endif ++ }; ++ ++ for (j = 0; j < ARRAY_SIZE(exports); j++) ++ for (i = 0; exports[j][i].name != NULL; i++) ++ if (strcmp(exports[j][i].name, name) == 0) { ++ *func = exports[j][i].func; ++ return 0; ++ } ++ ++ for (i = 0; i < num_pe_exports; i++) ++ if (strcmp(pe_exports[i].name, name) == 0) { ++ *func = pe_exports[i].addr; ++ return 0; ++ } ++ ++ return -1; ++} ++#endif // TEST_LOADER ++ ++static void *get_dll_init(char *name) ++{ ++ int i; ++ for (i = 0; i < num_pe_exports; i++) ++ if ((strcmp(pe_exports[i].dll, name) == 0) && ++ (strcmp(pe_exports[i].name, "DllInitialize") == 0)) ++ return (void *)pe_exports[i].addr; ++ return NULL; ++} ++ ++/* ++ * Find and validate the coff header ++ * ++ */ ++static int check_nt_hdr(IMAGE_NT_HEADERS *nt_hdr) ++{ ++ int i; ++ WORD attr; ++ PIMAGE_OPTIONAL_HEADER opt_hdr; ++ ++ /* Validate the "PE\0\0" signature */ ++ if (nt_hdr->Signature != IMAGE_NT_SIGNATURE) { ++ ERROR("is this driver file? bad signature %08x", ++ nt_hdr->Signature); ++ return -EINVAL; ++ } ++ ++ opt_hdr = &nt_hdr->OptionalHeader; ++ /* Make sure Image is PE32 or PE32+ */ ++#ifdef CONFIG_X86_64 ++ if (opt_hdr->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) { ++ ERROR("kernel is 64-bit, but Windows driver is not 64-bit;" ++ "bad magic: %04X", opt_hdr->Magic); ++ return -EINVAL; ++ } ++#else ++ if (opt_hdr->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) { ++ ERROR("kernel is 32-bit, but Windows driver is not 32-bit;" ++ "bad magic: %04X", opt_hdr->Magic); ++ return -EINVAL; ++ } ++#endif ++ ++ /* Validate the image for the current architecture. */ ++#ifdef CONFIG_X86_64 ++ if (nt_hdr->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64) { ++ ERROR("kernel is 64-bit, but Windows driver is not 64-bit;" ++ " (PE signature is %04X)", nt_hdr->FileHeader.Machine); ++ return -EINVAL; ++ } ++#else ++ if (nt_hdr->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) { ++ ERROR("kernel is 32-bit, but Windows driver is not 32-bit;" ++ " (PE signature is %04X)", nt_hdr->FileHeader.Machine); ++ return -EINVAL; ++ } ++#endif ++ ++ /* Must have attributes */ ++#ifdef CONFIG_X86_64 ++ attr = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LARGE_ADDRESS_AWARE; ++#else ++ attr = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_32BIT_MACHINE; ++#endif ++ if ((nt_hdr->FileHeader.Characteristics & attr) != attr) ++ return -EINVAL; ++ ++ /* Must be relocatable */ ++ attr = IMAGE_FILE_RELOCS_STRIPPED; ++ if ((nt_hdr->FileHeader.Characteristics & attr)) ++ return -EINVAL; ++ ++ /* Make sure we have at least one section */ ++ if (nt_hdr->FileHeader.NumberOfSections == 0) ++ return -EINVAL; ++ ++ if (opt_hdr->SectionAlignment < opt_hdr->FileAlignment) { ++ ERROR("alignment mismatch: section: 0x%x, file: 0x%x", ++ opt_hdr->SectionAlignment, opt_hdr->FileAlignment); ++ return -EINVAL; ++ } ++ ++ DBGLINKER("number of datadictionary entries %d", ++ opt_hdr->NumberOfRvaAndSizes); ++ for (i = 0; i < opt_hdr->NumberOfRvaAndSizes; i++) { ++ DBGLINKER("datadirectory %s RVA:%X Size:%d", ++ (i <= IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR) ? ++ image_directory_name[i] : "unknown", ++ opt_hdr->DataDirectory[i].VirtualAddress, ++ opt_hdr->DataDirectory[i].Size); ++ } ++ ++ if ((nt_hdr->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)) ++ return IMAGE_FILE_EXECUTABLE_IMAGE; ++ if ((nt_hdr->FileHeader.Characteristics & IMAGE_FILE_DLL)) ++ return IMAGE_FILE_DLL; ++ return -EINVAL; ++} ++ ++static int import(void *image, IMAGE_IMPORT_DESCRIPTOR *dirent, char *dll) ++{ ++ ULONG_PTR *lookup_tbl, *address_tbl; ++ char *symname = NULL; ++ int i; ++ int ret = 0; ++ generic_func adr; ++ ++ lookup_tbl = RVA2VA(image, dirent->u.OriginalFirstThunk, ULONG_PTR *); ++ address_tbl = RVA2VA(image, dirent->FirstThunk, ULONG_PTR *); ++ ++ for (i = 0; lookup_tbl[i]; i++) { ++ if (IMAGE_SNAP_BY_ORDINAL(lookup_tbl[i])) { ++ ERROR("ordinal import not supported: %llu", ++ (uint64_t)lookup_tbl[i]); ++ return -1; ++ } ++ else { ++ symname = RVA2VA(image, ++ ((lookup_tbl[i] & ++ ~IMAGE_ORDINAL_FLAG) + 2), char *); ++ } ++ ++ if (get_export(symname, &adr) < 0) { ++ ERROR("unknown symbol: %s:'%s'", dll, symname); ++ ret = -1; ++ } else { ++ DBGLINKER("found symbol: %s:%s: addr: %p, rva = %llu", ++ dll, symname, adr, (uint64_t)address_tbl[i]); ++ address_tbl[i] = (ULONG_PTR)adr; ++ } ++ } ++ return ret; ++} ++ ++static int read_exports(struct pe_image *pe) ++{ ++ IMAGE_EXPORT_DIRECTORY *export_dir_table; ++ uint32_t *export_addr_table; ++ int i; ++ uint32_t *name_table; ++ PIMAGE_OPTIONAL_HEADER opt_hdr; ++ IMAGE_DATA_DIRECTORY *export_data_dir; ++ ++ opt_hdr = &pe->nt_hdr->OptionalHeader; ++ export_data_dir = ++ &opt_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; ++ ++ if (export_data_dir->Size == 0) { ++ DBGLINKER("no exports"); ++ return 0; ++ } ++ ++ export_dir_table = ++ RVA2VA(pe->image, export_data_dir->VirtualAddress, ++ IMAGE_EXPORT_DIRECTORY *); ++ ++ name_table = (unsigned int *)(pe->image + ++ export_dir_table->AddressOfNames); ++ export_addr_table = (uint32_t *) ++ (pe->image + export_dir_table->AddressOfFunctions); ++ ++ for (i = 0; i < export_dir_table->NumberOfNames; i++) { ++ ++ if (export_data_dir->VirtualAddress <= *export_addr_table || ++ *export_addr_table >= (export_data_dir->VirtualAddress + ++ export_data_dir->Size)) ++ DBGLINKER("forwarder rva"); ++ ++ DBGLINKER("export symbol: %s, at %p", ++ (char *)(pe->image + *name_table), ++ pe->image + *export_addr_table); ++ ++ pe_exports[num_pe_exports].dll = pe->name; ++ pe_exports[num_pe_exports].name = pe->image + *name_table; ++ pe_exports[num_pe_exports].addr = ++ pe->image + *export_addr_table; ++ ++ num_pe_exports++; ++ name_table++; ++ export_addr_table++; ++ } ++ return 0; ++} ++ ++static int fixup_imports(void *image, IMAGE_NT_HEADERS *nt_hdr) ++{ ++ int i; ++ char *name; ++ int ret = 0; ++ IMAGE_IMPORT_DESCRIPTOR *dirent; ++ IMAGE_DATA_DIRECTORY *import_data_dir; ++ PIMAGE_OPTIONAL_HEADER opt_hdr; ++ ++ opt_hdr = &nt_hdr->OptionalHeader; ++ import_data_dir = ++ &opt_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; ++ dirent = RVA2VA(image, import_data_dir->VirtualAddress, ++ IMAGE_IMPORT_DESCRIPTOR *); ++ ++ for (i = 0; dirent[i].Name; i++) { ++ name = RVA2VA(image, dirent[i].Name, char*); ++ ++ DBGLINKER("imports from dll: %s", name); ++ ret += import(image, &dirent[i], name); ++ } ++ return ret; ++} ++ ++static int fixup_reloc(void *image, IMAGE_NT_HEADERS *nt_hdr) ++{ ++ ULONG_PTR base; ++ ULONG_PTR size; ++ IMAGE_BASE_RELOCATION *fixup_block; ++ IMAGE_DATA_DIRECTORY *base_reloc_data_dir; ++ PIMAGE_OPTIONAL_HEADER opt_hdr; ++ ++ opt_hdr = &nt_hdr->OptionalHeader; ++ base = opt_hdr->ImageBase; ++ base_reloc_data_dir = ++ &opt_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; ++ if (base_reloc_data_dir->Size == 0) ++ return 0; ++ ++ fixup_block = RVA2VA(image, base_reloc_data_dir->VirtualAddress, ++ IMAGE_BASE_RELOCATION *); ++ DBGLINKER("fixup_block=%p, image=%p", fixup_block, image); ++ DBGLINKER("fixup_block info: %x %d", ++ fixup_block->VirtualAddress, fixup_block->SizeOfBlock); ++ ++ while (fixup_block->SizeOfBlock) { ++ int i; ++ WORD fixup, offset; ++ ++ size = (fixup_block->SizeOfBlock - ++ sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD); ++ DBGLINKER("found %llu relocations in this block", ++ (uint64_t)size); ++ ++ for (i = 0; i < size; i++) { ++ fixup = fixup_block->TypeOffset[i]; ++ offset = fixup & 0xfff; ++ switch ((fixup >> 12) & 0x0f) { ++ case IMAGE_REL_BASED_ABSOLUTE: ++ break; ++ ++ case IMAGE_REL_BASED_HIGHLOW: { ++ uint32_t addr; ++ uint32_t *loc = ++ RVA2VA(image, ++ fixup_block->VirtualAddress + ++ offset, uint32_t *); ++ addr = RVA2VA(image, (*loc - base), uint32_t); ++ DBGLINKER("relocation: *%p (Val:%X)= %X", ++ loc, *loc, addr); ++ *loc = addr; ++ } ++ break; ++ ++ case IMAGE_REL_BASED_DIR64: { ++ uint64_t addr; ++ uint64_t *loc = ++ RVA2VA(image, ++ fixup_block->VirtualAddress + ++ offset, uint64_t *); ++ addr = RVA2VA(image, (*loc - base), uint64_t); ++ DBGLINKER("relocation: *%p (Val:%llX)= %llx", ++ loc, *loc, addr); ++ *loc = addr; ++ } ++ break; ++ ++ default: ++ ERROR("unknown fixup: %08X", ++ (fixup >> 12) & 0x0f); ++ return -EOPNOTSUPP; ++ break; ++ } ++ } ++ DBGLINKER("finished relocating block"); ++ ++ fixup_block = (IMAGE_BASE_RELOCATION *) ++ ((void *)fixup_block + fixup_block->SizeOfBlock); ++ }; ++ DBGLINKER("done relocating all"); ++ ++ return 0; ++} ++ ++/* Expand the image in memory if necessary. The image on disk does not ++ * necessarily maps the image of the driver in memory, so we have to ++ * re-write it in order to fulfill the sections alignments. The ++ * advantage to do that is that rva_to_va becomes a simple ++ * addition. */ ++static int fix_pe_image(struct pe_image *pe) ++{ ++ void *image; ++ IMAGE_SECTION_HEADER *sect_hdr; ++ int i, sections; ++ int image_size; ++ ++ if (pe->size == pe->opt_hdr->SizeOfImage) { ++ /* Nothing to do */ ++ return 0; ++ } ++ ++ image_size = pe->opt_hdr->SizeOfImage; ++#ifdef CONFIG_X86_64 ++#ifdef PAGE_KERNEL_EXECUTABLE ++ image = __vmalloc(image_size, GFP_KERNEL | __GFP_HIGHMEM, ++ PAGE_KERNEL_EXECUTABLE); ++#elif defined PAGE_KERNEL_EXEC ++ image = __vmalloc(image_size, GFP_KERNEL | __GFP_HIGHMEM, ++ PAGE_KERNEL_EXEC); ++#else ++#error x86_64 should have either PAGE_KERNEL_EXECUTABLE or PAGE_KERNEL_EXEC ++#endif ++#else ++#ifdef cpu_has_nx ++ /* hate to play with kernel macros, but PAGE_KERNEL_EXEC is ++ * not available to modules! */ ++ if (cpu_has_nx) ++ image = __vmalloc(image_size, GFP_KERNEL | __GFP_HIGHMEM, ++ __pgprot(__PAGE_KERNEL & ~_PAGE_NX)); ++ else ++ image = vmalloc(image_size); ++#else ++ image = vmalloc(image_size); ++#endif ++#endif ++ if (image == NULL) { ++ ERROR("failed to allocate enough space for new image:" ++ " %d bytes", image_size); ++ return -ENOMEM; ++ } ++ memset(image, 0, image_size); ++ ++ /* Copy all the headers, ie everything before the first section. */ ++ ++ sections = pe->nt_hdr->FileHeader.NumberOfSections; ++ sect_hdr = IMAGE_FIRST_SECTION(pe->nt_hdr); ++ ++ DBGLINKER("copying headers: %u bytes", sect_hdr->PointerToRawData); ++ ++ memcpy(image, pe->image, sect_hdr->PointerToRawData); ++ ++ /* Copy all the sections */ ++ for (i = 0; i < sections; i++) { ++ DBGLINKER("Copy section %s from %x to %x", ++ sect_hdr->Name, sect_hdr->PointerToRawData, ++ sect_hdr->VirtualAddress); ++ if (sect_hdr->VirtualAddress+sect_hdr->SizeOfRawData > ++ image_size) { ++ ERROR("Invalid section %s in driver", sect_hdr->Name); ++ vfree(image); ++ return -EINVAL; ++ } ++ ++ memcpy(image+sect_hdr->VirtualAddress, ++ pe->image + sect_hdr->PointerToRawData, ++ sect_hdr->SizeOfRawData); ++ sect_hdr++; ++ } ++ ++ vfree(pe->image); ++ pe->image = image; ++ pe->size = image_size; ++ ++ /* Update our internal pointers */ ++ pe->nt_hdr = (IMAGE_NT_HEADERS *) ++ (pe->image + ((IMAGE_DOS_HEADER *)pe->image)->e_lfanew); ++ pe->opt_hdr = &pe->nt_hdr->OptionalHeader; ++ ++ DBGLINKER("set nt headers: nt_hdr=%p, opt_hdr=%p, image=%p", ++ pe->nt_hdr, pe->opt_hdr, pe->image); ++ ++ return 0; ++} ++ ++#if defined(CONFIG_X86_64) ++static void fix_user_shared_data_addr(char *driver, unsigned long length) ++{ ++ unsigned long i, n, max_addr, *addr; ++ ++ TRACE1("fixing KI_USER_SHARED_DATA address in the driver"); ++ n = length - sizeof(unsigned long); ++ max_addr = KI_USER_SHARED_DATA + sizeof(kuser_shared_data); ++ for (i = 0; i < n; i++) { ++ addr = (unsigned long *)(driver + i); ++ if (*addr >= KI_USER_SHARED_DATA && *addr < max_addr) { ++ *addr -= KI_USER_SHARED_DATA; ++ *addr += (unsigned long)&kuser_shared_data; ++ kuser_shared_data.reserved1 = 1; ++ } ++ } ++} ++#endif ++ ++int link_pe_images(struct pe_image *pe_image, unsigned short n) ++{ ++ int i; ++ struct pe_image *pe; ++ ++#if DEBUG >= 1 ++ /* Sanity checks */ ++ CHECK_SZ(IMAGE_SECTION_HEADER, IMAGE_SIZEOF_SECTION_HEADER); ++ CHECK_SZ(IMAGE_FILE_HEADER, IMAGE_SIZEOF_FILE_HEADER); ++ CHECK_SZ(IMAGE_OPTIONAL_HEADER, IMAGE_SIZEOF_NT_OPTIONAL_HEADER); ++ CHECK_SZ(IMAGE_NT_HEADERS, 4 + IMAGE_SIZEOF_FILE_HEADER + ++ IMAGE_SIZEOF_NT_OPTIONAL_HEADER); ++ CHECK_SZ(IMAGE_DOS_HEADER, 0x40); ++ CHECK_SZ(IMAGE_EXPORT_DIRECTORY, 40); ++ CHECK_SZ(IMAGE_BASE_RELOCATION, 8); ++ CHECK_SZ(IMAGE_IMPORT_DESCRIPTOR, 20); ++#endif ++ ++ for (i = 0; i < n; i++) { ++ IMAGE_DOS_HEADER *dos_hdr; ++ pe = &pe_image[i]; ++ dos_hdr = pe->image; ++ ++ if (pe->size < sizeof(IMAGE_DOS_HEADER)) { ++ TRACE1("image too small: %d", pe->size); ++ return -EINVAL; ++ } ++ ++ pe->nt_hdr = ++ (IMAGE_NT_HEADERS *)(pe->image + dos_hdr->e_lfanew); ++ pe->opt_hdr = &pe->nt_hdr->OptionalHeader; ++ ++ pe->type = check_nt_hdr(pe->nt_hdr); ++ if (pe->type <= 0) { ++ TRACE1("type <= 0"); ++ return -EINVAL; ++ } ++ ++ if (fix_pe_image(pe)) { ++ TRACE1("bad PE image"); ++ return -EINVAL; ++ } ++ ++ if (read_exports(pe)) { ++ TRACE1("read exports failed"); ++ return -EINVAL; ++ } ++ } ++ ++ for (i = 0; i < n; i++) { ++ pe = &pe_image[i]; ++ ++ if (fixup_reloc(pe->image, pe->nt_hdr)) { ++ TRACE1("fixup reloc failed"); ++ return -EINVAL; ++ } ++ if (fixup_imports(pe->image, pe->nt_hdr)) { ++ TRACE1("fixup imports failed"); ++ return -EINVAL; ++ } ++#if defined(CONFIG_X86_64) ++ fix_user_shared_data_addr(pe_image[i].image, pe_image[i].size); ++#endif ++ flush_icache_range((unsigned long)pe->image, pe->size); ++ ++ pe->entry = ++ RVA2VA(pe->image, ++ pe->opt_hdr->AddressOfEntryPoint, void *); ++ TRACE1("entry is at %p, rva at %08X", pe->entry, ++ pe->opt_hdr->AddressOfEntryPoint); ++ } ++ ++ for (i = 0; i < n; i++) { ++ pe = &pe_image[i]; ++ ++ if (pe->type == IMAGE_FILE_DLL) { ++ struct unicode_string ustring; ++ char *buf = "0/0t0m0p00"; ++ int (*dll_entry)(struct unicode_string *ustring) ++ wstdcall; ++ ++ memset(&ustring, 0, sizeof(ustring)); ++ ustring.buf = (wchar_t *)buf; ++ dll_entry = (void *)get_dll_init(pe->name); ++ ++ TRACE1("calling dll_init at %p", dll_entry); ++ if (!dll_entry || dll_entry(&ustring)) ++ ERROR("DLL initialize failed for %s", ++ pe->name); ++ } ++ else if (pe->type != IMAGE_FILE_EXECUTABLE_IMAGE) ++ ERROR("illegal image type: %d", pe->type); ++ } ++ return 0; ++} +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/pe_linker.h linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/pe_linker.h +--- linux-3.12.2/3rdparty/ndiswrapper/pe_linker.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/pe_linker.h 2013-11-28 21:42:11.000000000 +0200 +@@ -0,0 +1,992 @@ ++/* ++ * This file is an excerpt of winnt.h from WINE, which bears the ++ * following copyright: ++ * ++ * Win32 definitions for Windows NT ++ * ++ * Copyright 1996 Alexandre Julliard ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++/* ++ * File formats definitions ++ */ ++typedef struct _IMAGE_DOS_HEADER { ++ WORD e_magic; /* 00: MZ Header signature */ ++ WORD e_cblp; /* 02: Bytes on last page of file */ ++ WORD e_cp; /* 04: Pages in file */ ++ WORD e_crlc; /* 06: Relocations */ ++ WORD e_cparhdr; /* 08: Size of header in paragraphs */ ++ WORD e_minalloc; /* 0a: Minimum extra paragraphs needed */ ++ WORD e_maxalloc; /* 0c: Maximum extra paragraphs needed */ ++ WORD e_ss; /* 0e: Initial (relative) SS value */ ++ WORD e_sp; /* 10: Initial SP value */ ++ WORD e_csum; /* 12: Checksum */ ++ WORD e_ip; /* 14: Initial IP value */ ++ WORD e_cs; /* 16: Initial (relative) CS value */ ++ WORD e_lfarlc; /* 18: File address of relocation table */ ++ WORD e_ovno; /* 1a: Overlay number */ ++ WORD e_res[4]; /* 1c: Reserved words */ ++ WORD e_oemid; /* 24: OEM identifier (for e_oeminfo) */ ++ WORD e_oeminfo; /* 26: OEM information; e_oemid specific */ ++ WORD e_res2[10]; /* 28: Reserved words */ ++ DWORD e_lfanew; /* 3c: Offset to extended header */ ++} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; ++ ++#define IMAGE_DOS_SIGNATURE 0x5A4D /* MZ */ ++#define IMAGE_OS2_SIGNATURE 0x454E /* NE */ ++#define IMAGE_OS2_SIGNATURE_LE 0x454C /* LE */ ++#define IMAGE_OS2_SIGNATURE_LX 0x584C /* LX */ ++#define IMAGE_VXD_SIGNATURE 0x454C /* LE */ ++#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */ ++ ++/* ++ * This is the Windows executable (NE) header. ++ * the name IMAGE_OS2_HEADER is misleading, but in the SDK this way. ++ */ ++typedef struct ++{ ++ WORD ne_magic; /* 00 NE signature 'NE' */ ++ BYTE ne_ver; /* 02 Linker version number */ ++ BYTE ne_rev; /* 03 Linker revision number */ ++ WORD ne_enttab; /* 04 Offset to entry table relative to NE */ ++ WORD ne_cbenttab; /* 06 Length of entry table in bytes */ ++ LONG ne_crc; /* 08 Checksum */ ++ WORD ne_flags; /* 0c Flags about segments in this file */ ++ WORD ne_autodata; /* 0e Automatic data segment number */ ++ WORD ne_heap; /* 10 Initial size of local heap */ ++ WORD ne_stack; /* 12 Initial size of stack */ ++ DWORD ne_csip; /* 14 Initial CS:IP */ ++ DWORD ne_sssp; /* 18 Initial SS:SP */ ++ WORD ne_cseg; /* 1c # of entries in segment table */ ++ WORD ne_cmod; /* 1e # of entries in module reference tab. */ ++ WORD ne_cbnrestab; /* 20 Length of nonresident-name table */ ++ WORD ne_segtab; /* 22 Offset to segment table */ ++ WORD ne_rsrctab; /* 24 Offset to resource table */ ++ WORD ne_restab; /* 26 Offset to resident-name table */ ++ WORD ne_modtab; /* 28 Offset to module reference table */ ++ WORD ne_imptab; /* 2a Offset to imported name table */ ++ DWORD ne_nrestab; /* 2c Offset to nonresident-name table */ ++ WORD ne_cmovent; /* 30 # of movable entry points */ ++ WORD ne_align; /* 32 Logical sector alignment shift count */ ++ WORD ne_cres; /* 34 # of resource segments */ ++ BYTE ne_exetyp; /* 36 Flags indicating target OS */ ++ BYTE ne_flagsothers; /* 37 Additional information flags */ ++ WORD ne_pretthunks; /* 38 Offset to return thunks */ ++ WORD ne_psegrefbytes; /* 3a Offset to segment ref. bytes */ ++ WORD ne_swaparea; /* 3c Reserved by Microsoft */ ++ WORD ne_expver; /* 3e Expected Windows version number */ ++} IMAGE_OS2_HEADER, *PIMAGE_OS2_HEADER; ++ ++typedef struct _IMAGE_VXD_HEADER { ++ WORD e32_magic; ++ BYTE e32_border; ++ BYTE e32_worder; ++ DWORD e32_level; ++ WORD e32_cpu; ++ WORD e32_os; ++ DWORD e32_ver; ++ DWORD e32_mflags; ++ DWORD e32_mpages; ++ DWORD e32_startobj; ++ DWORD e32_eip; ++ DWORD e32_stackobj; ++ DWORD e32_esp; ++ DWORD e32_pagesize; ++ DWORD e32_lastpagesize; ++ DWORD e32_fixupsize; ++ DWORD e32_fixupsum; ++ DWORD e32_ldrsize; ++ DWORD e32_ldrsum; ++ DWORD e32_objtab; ++ DWORD e32_objcnt; ++ DWORD e32_objmap; ++ DWORD e32_itermap; ++ DWORD e32_rsrctab; ++ DWORD e32_rsrccnt; ++ DWORD e32_restab; ++ DWORD e32_enttab; ++ DWORD e32_dirtab; ++ DWORD e32_dircnt; ++ DWORD e32_fpagetab; ++ DWORD e32_frectab; ++ DWORD e32_impmod; ++ DWORD e32_impmodcnt; ++ DWORD e32_impproc; ++ DWORD e32_pagesum; ++ DWORD e32_datapage; ++ DWORD e32_preload; ++ DWORD e32_nrestab; ++ DWORD e32_cbnrestab; ++ DWORD e32_nressum; ++ DWORD e32_autodata; ++ DWORD e32_debuginfo; ++ DWORD e32_debuglen; ++ DWORD e32_instpreload; ++ DWORD e32_instdemand; ++ DWORD e32_heapsize; ++ BYTE e32_res3[12]; ++ DWORD e32_winresoff; ++ DWORD e32_winreslen; ++ WORD e32_devid; ++ WORD e32_ddkver; ++} IMAGE_VXD_HEADER, *PIMAGE_VXD_HEADER; ++ ++/* These defines describe the meanings of the bits in the ++ Characteristics field */ ++ ++#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 /* No relocation info */ ++#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 ++#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 ++#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 ++#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 ++#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 ++#define IMAGE_FILE_16BIT_MACHINE 0x0040 ++#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 ++#define IMAGE_FILE_32BIT_MACHINE 0x0100 ++#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 ++#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 ++#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 ++#define IMAGE_FILE_SYSTEM 0x1000 ++#define IMAGE_FILE_DLL 0x2000 ++#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 ++#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 ++ ++/* These are the settings of the Machine field. */ ++#define IMAGE_FILE_MACHINE_UNKNOWN 0 ++#define IMAGE_FILE_MACHINE_I860 0x014d ++#define IMAGE_FILE_MACHINE_I386 0x014c ++#define IMAGE_FILE_MACHINE_R3000 0x0162 ++#define IMAGE_FILE_MACHINE_R4000 0x0166 ++#define IMAGE_FILE_MACHINE_R10000 0x0168 ++#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 ++#define IMAGE_FILE_MACHINE_ALPHA 0x0184 ++#define IMAGE_FILE_MACHINE_SH3 0x01a2 ++#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3 ++#define IMAGE_FILE_MACHINE_SH3E 0x01a4 ++#define IMAGE_FILE_MACHINE_SH4 0x01a6 ++#define IMAGE_FILE_MACHINE_SH5 0x01a8 ++#define IMAGE_FILE_MACHINE_ARM 0x01c0 ++#define IMAGE_FILE_MACHINE_THUMB 0x01c2 ++#define IMAGE_FILE_MACHINE_AM33 0x01d3 ++#define IMAGE_FILE_MACHINE_POWERPC 0x01f0 ++#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 ++#define IMAGE_FILE_MACHINE_IA64 0x0200 ++#define IMAGE_FILE_MACHINE_MIPS16 0x0266 ++#define IMAGE_FILE_MACHINE_ALPHA64 0x0284 ++#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 ++#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 ++#define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64 ++#define IMAGE_FILE_MACHINE_TRICORE 0x0520 ++#define IMAGE_FILE_MACHINE_CEF 0x0cef ++#define IMAGE_FILE_MACHINE_EBC 0x0ebc ++#define IMAGE_FILE_MACHINE_AMD64 0x8664 ++#define IMAGE_FILE_MACHINE_M32R 0x9041 ++#define IMAGE_FILE_MACHINE_CEE 0xc0ee ++ ++#define IMAGE_SIZEOF_FILE_HEADER 20 ++#define IMAGE_SIZEOF_ROM_OPTIONAL_HEADER 56 ++#define IMAGE_SIZEOF_STD_OPTIONAL_HEADER 28 ++#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER32 224 ++#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER64 240 ++#define IMAGE_SIZEOF_SHORT_NAME 8 ++#define IMAGE_SIZEOF_SECTION_HEADER 40 ++#define IMAGE_SIZEOF_SYMBOL 18 ++#define IMAGE_SIZEOF_AUX_SYMBOL 18 ++#define IMAGE_SIZEOF_RELOCATION 10 ++#define IMAGE_SIZEOF_BASE_RELOCATION 8 ++#define IMAGE_SIZEOF_LINENUMBER 6 ++#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 ++ ++/* Possible Magic values */ ++#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x010b ++#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x020b ++#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x0107 ++ ++#ifdef CONFIG_X86_64 ++#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER IMAGE_SIZEOF_NT_OPTIONAL_HEADER64 ++#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR64_MAGIC ++#else ++#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER IMAGE_SIZEOF_NT_OPTIONAL_HEADER32 ++#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR32_MAGIC ++#endif ++ ++/* These are indexes into the DataDirectory array */ ++#define IMAGE_FILE_EXPORT_DIRECTORY 0 ++#define IMAGE_FILE_IMPORT_DIRECTORY 1 ++#define IMAGE_FILE_RESOURCE_DIRECTORY 2 ++#define IMAGE_FILE_EXCEPTION_DIRECTORY 3 ++#define IMAGE_FILE_SECURITY_DIRECTORY 4 ++#define IMAGE_FILE_BASE_RELOCATION_TABLE 5 ++#define IMAGE_FILE_DEBUG_DIRECTORY 6 ++#define IMAGE_FILE_DESCRIPTION_STRING 7 ++#define IMAGE_FILE_MACHINE_VALUE 8 /* Mips */ ++#define IMAGE_FILE_THREAD_LOCAL_STORAGE 9 ++#define IMAGE_FILE_CALLBACK_DIRECTORY 10 ++ ++/* Directory Entries, indices into the DataDirectory array */ ++ ++#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 ++#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 ++#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 ++#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 ++#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 ++#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 ++#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 ++#define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 ++#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 /* (MIPS GP) */ ++#define IMAGE_DIRECTORY_ENTRY_TLS 9 ++#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 ++#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 ++#define IMAGE_DIRECTORY_ENTRY_IAT 12 /* Import Address Table */ ++#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 ++#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 ++ ++/* Subsystem Values */ ++ ++#define IMAGE_SUBSYSTEM_UNKNOWN 0 ++#define IMAGE_SUBSYSTEM_NATIVE 1 ++#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 /* Windows GUI subsystem */ ++#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 /* Windows character subsystem */ ++#define IMAGE_SUBSYSTEM_OS2_CUI 5 ++#define IMAGE_SUBSYSTEM_POSIX_CUI 7 ++#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS 8 /* native Win9x driver */ ++#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 /* Windows CE subsystem */ ++#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 ++#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 ++#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 ++#define IMAGE_SUBSYSTEM_EFI_ROM 13 ++#define IMAGE_SUBSYSTEM_XBOX 14 ++ ++typedef struct _IMAGE_FILE_HEADER { ++ WORD Machine; ++ WORD NumberOfSections; ++ DWORD TimeDateStamp; ++ DWORD PointerToSymbolTable; ++ DWORD NumberOfSymbols; ++ WORD SizeOfOptionalHeader; ++ WORD Characteristics; ++} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; ++ ++typedef struct _IMAGE_DATA_DIRECTORY { ++ DWORD VirtualAddress; ++ DWORD Size; ++} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; ++ ++#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 ++ ++typedef struct _IMAGE_OPTIONAL_HEADER32 { ++ ++ /* Standard fields */ ++ ++ WORD Magic; ++ BYTE MajorLinkerVersion; ++ BYTE MinorLinkerVersion; ++ DWORD SizeOfCode; ++ DWORD SizeOfInitializedData; ++ DWORD SizeOfUninitializedData; ++ DWORD AddressOfEntryPoint; ++ DWORD BaseOfCode; ++ DWORD BaseOfData; ++ ++ /* NT additional fields */ ++ DWORD ImageBase; ++ DWORD SectionAlignment; ++ DWORD FileAlignment; ++ WORD MajorOperatingSystemVersion; ++ WORD MinorOperatingSystemVersion; ++ WORD MajorImageVersion; ++ WORD MinorImageVersion; ++ WORD MajorSubsystemVersion; ++ WORD MinorSubsystemVersion; ++ DWORD Win32VersionValue; ++ DWORD SizeOfImage; ++ DWORD SizeOfHeaders; ++ DWORD CheckSum; ++ WORD Subsystem; ++ WORD DllCharacteristics; ++ DWORD SizeOfStackReserve; ++ DWORD SizeOfStackCommit; ++ DWORD SizeOfHeapReserve; ++ DWORD SizeOfHeapCommit; ++ DWORD LoaderFlags; ++ DWORD NumberOfRvaAndSizes; ++ IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; ++} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; ++ ++typedef struct _IMAGE_OPTIONAL_HEADER64 { ++ ++ /* Standard fields */ ++ ++ WORD Magic; ++ BYTE MajorLinkerVersion; ++ BYTE MinorLinkerVersion; ++ DWORD SizeOfCode; ++ DWORD SizeOfInitializedData; ++ DWORD SizeOfUninitializedData; ++ DWORD AddressOfEntryPoint; ++ DWORD BaseOfCode; ++ ++ /* NT additional fields */ ++ ULONGLONG ImageBase; ++ DWORD SectionAlignment; ++ DWORD FileAlignment; ++ WORD MajorOperatingSystemVersion; ++ WORD MinorOperatingSystemVersion; ++ WORD MajorImageVersion; ++ WORD MinorImageVersion; ++ WORD MajorSubsystemVersion; ++ WORD MinorSubsystemVersion; ++ DWORD Win32VersionValue; ++ DWORD SizeOfImage; ++ DWORD SizeOfHeaders; ++ DWORD CheckSum; ++ WORD Subsystem; ++ WORD DllCharacteristics; ++ ULONGLONG SizeOfStackReserve; ++ ULONGLONG SizeOfStackCommit; ++ ULONGLONG SizeOfHeapReserve; ++ ULONGLONG SizeOfHeapCommit; ++ DWORD LoaderFlags; ++ DWORD NumberOfRvaAndSizes; ++ IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; ++} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64; ++ ++#ifdef CONFIG_X86_64 ++typedef IMAGE_OPTIONAL_HEADER64 IMAGE_OPTIONAL_HEADER; ++typedef PIMAGE_OPTIONAL_HEADER64 PIMAGE_OPTIONAL_HEADER; ++#else ++typedef IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER; ++typedef PIMAGE_OPTIONAL_HEADER32 PIMAGE_OPTIONAL_HEADER; ++#endif ++ ++typedef struct _IMAGE_NT_HEADERS32 { ++ DWORD Signature; /* "PE"\0\0 */ /* 0x00 */ ++ IMAGE_FILE_HEADER FileHeader; /* 0x04 */ ++ IMAGE_OPTIONAL_HEADER32 OptionalHeader; /* 0x18 */ ++} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32; ++ ++typedef struct _IMAGE_NT_HEADERS64 { ++ DWORD Signature; /* "PE"\0\0 */ /* 0x00 */ ++ IMAGE_FILE_HEADER FileHeader; /* 0x04 */ ++ IMAGE_OPTIONAL_HEADER64 OptionalHeader; /* 0x18 */ ++} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64; ++ ++#ifdef CONFIG_X86_64 ++typedef IMAGE_NT_HEADERS64 IMAGE_NT_HEADERS; ++typedef PIMAGE_NT_HEADERS64 PIMAGE_NT_HEADERS; ++#else ++typedef IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS; ++typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS; ++#endif ++ ++#define IMAGE_SIZEOF_SHORT_NAME 8 ++ ++typedef struct _IMAGE_SECTION_HEADER { ++ BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; ++ union { ++ DWORD PhysicalAddress; ++ DWORD VirtualSize; ++ } Misc; ++ DWORD VirtualAddress; ++ DWORD SizeOfRawData; ++ DWORD PointerToRawData; ++ DWORD PointerToRelocations; ++ DWORD PointerToLinenumbers; ++ WORD NumberOfRelocations; ++ WORD NumberOfLinenumbers; ++ DWORD Characteristics; ++} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; ++ ++#define IMAGE_SIZEOF_SECTION_HEADER 40 ++ ++#define IMAGE_FIRST_SECTION(ntheader) \ ++((PIMAGE_SECTION_HEADER)((LPBYTE)&((PIMAGE_NT_HEADERS)(ntheader))->OptionalHeader + \ ++((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader)) ++ ++/* These defines are for the Characteristics bitfield. */ ++/* #define IMAGE_SCN_TYPE_REG 0x00000000 - Reserved */ ++/* #define IMAGE_SCN_TYPE_DSECT 0x00000001 - Reserved */ ++/* #define IMAGE_SCN_TYPE_NOLOAD 0x00000002 - Reserved */ ++/* #define IMAGE_SCN_TYPE_GROUP 0x00000004 - Reserved */ ++#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 /* Reserved */ ++/* #define IMAGE_SCN_TYPE_COPY 0x00000010 - Reserved */ ++ ++#define IMAGE_SCN_CNT_CODE 0x00000020 ++#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 ++#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 ++ ++#define IMAGE_SCN_LNK_OTHER 0x00000100 ++#define IMAGE_SCN_LNK_INFO 0x00000200 ++/* #define IMAGE_SCN_TYPE_OVER 0x00000400 - Reserved */ ++#define IMAGE_SCN_LNK_REMOVE 0x00000800 ++#define IMAGE_SCN_LNK_COMDAT 0x00001000 ++ ++/* 0x00002000 - Reserved */ ++/* #define IMAGE_SCN_MEM_PROTECTED 0x00004000 - Obsolete */ ++#define IMAGE_SCN_MEM_FARDATA 0x00008000 ++ ++/* #define IMAGE_SCN_MEM_SYSHEAP 0x00010000 - Obsolete */ ++#define IMAGE_SCN_MEM_PURGEABLE 0x00020000 ++#define IMAGE_SCN_MEM_16BIT 0x00020000 ++#define IMAGE_SCN_MEM_LOCKED 0x00040000 ++#define IMAGE_SCN_MEM_PRELOAD 0x00080000 ++ ++#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 ++#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 ++#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 ++#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 ++#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 /* Default */ ++#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 ++#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 ++#define IMAGE_SCN_ALIGN_128BYTES 0x00800000 ++#define IMAGE_SCN_ALIGN_256BYTES 0x00900000 ++#define IMAGE_SCN_ALIGN_512BYTES 0x00A00000 ++#define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000 ++#define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000 ++#define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000 ++#define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000 ++/* 0x00F00000 - Unused */ ++#define IMAGE_SCN_ALIGN_MASK 0x00F00000 ++ ++#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 ++ ++ ++#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 ++#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 ++#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 ++#define IMAGE_SCN_MEM_SHARED 0x10000000 ++#define IMAGE_SCN_MEM_EXECUTE 0x20000000 ++#define IMAGE_SCN_MEM_READ 0x40000000 ++#define IMAGE_SCN_MEM_WRITE 0x80000000 ++ ++typedef struct _IMAGE_SYMBOL { ++ union { ++ BYTE ShortName[8]; ++ struct { ++ DWORD Short; ++ DWORD Long; ++ } Name; ++ DWORD LongName[2]; ++ } N; ++ DWORD Value; ++ SHORT SectionNumber; ++ WORD Type; ++ BYTE StorageClass; ++ BYTE NumberOfAuxSymbols; ++} IMAGE_SYMBOL; ++typedef IMAGE_SYMBOL *PIMAGE_SYMBOL; ++ ++#define IMAGE_SIZEOF_SYMBOL 18 ++ ++typedef struct _IMAGE_LINENUMBER { ++ union { ++ DWORD SymbolTableIndex; ++ DWORD VirtualAddress; ++ } Type; ++ WORD Linenumber; ++} IMAGE_LINENUMBER; ++typedef IMAGE_LINENUMBER *PIMAGE_LINENUMBER; ++ ++#define IMAGE_SIZEOF_LINENUMBER 6 ++ ++typedef union _IMAGE_AUX_SYMBOL { ++ struct { ++ DWORD TagIndex; ++ union { ++ struct { ++ WORD Linenumber; ++ WORD Size; ++ } LnSz; ++ DWORD TotalSize; ++ } Misc; ++ union { ++ struct { ++ DWORD PointerToLinenumber; ++ DWORD PointerToNextFunction; ++ } Function; ++ struct { ++ WORD Dimension[4]; ++ } Array; ++ } FcnAry; ++ WORD TvIndex; ++ } Sym; ++ struct { ++ BYTE Name[IMAGE_SIZEOF_SYMBOL]; ++ } File; ++ struct { ++ DWORD Length; ++ WORD NumberOfRelocations; ++ WORD NumberOfLinenumbers; ++ DWORD CheckSum; ++ SHORT Number; ++ BYTE Selection; ++ } Section; ++} IMAGE_AUX_SYMBOL; ++typedef IMAGE_AUX_SYMBOL *PIMAGE_AUX_SYMBOL; ++ ++#define IMAGE_SIZEOF_AUX_SYMBOL 18 ++ ++#define IMAGE_SYM_UNDEFINED (SHORT)0 ++#define IMAGE_SYM_ABSOLUTE (SHORT)-1 ++#define IMAGE_SYM_DEBUG (SHORT)-2 ++ ++#define IMAGE_SYM_TYPE_NULL 0x0000 ++#define IMAGE_SYM_TYPE_VOID 0x0001 ++#define IMAGE_SYM_TYPE_CHAR 0x0002 ++#define IMAGE_SYM_TYPE_SHORT 0x0003 ++#define IMAGE_SYM_TYPE_INT 0x0004 ++#define IMAGE_SYM_TYPE_LONG 0x0005 ++#define IMAGE_SYM_TYPE_FLOAT 0x0006 ++#define IMAGE_SYM_TYPE_DOUBLE 0x0007 ++#define IMAGE_SYM_TYPE_STRUCT 0x0008 ++#define IMAGE_SYM_TYPE_UNION 0x0009 ++#define IMAGE_SYM_TYPE_ENUM 0x000A ++#define IMAGE_SYM_TYPE_MOE 0x000B ++#define IMAGE_SYM_TYPE_BYTE 0x000C ++#define IMAGE_SYM_TYPE_WORD 0x000D ++#define IMAGE_SYM_TYPE_UINT 0x000E ++#define IMAGE_SYM_TYPE_DWORD 0x000F ++#define IMAGE_SYM_TYPE_PCODE 0x8000 ++ ++#define IMAGE_SYM_DTYPE_NULL 0 ++#define IMAGE_SYM_DTYPE_POINTER 1 ++#define IMAGE_SYM_DTYPE_FUNCTION 2 ++#define IMAGE_SYM_DTYPE_ARRAY 3 ++ ++#define IMAGE_SYM_CLASS_END_OF_FUNCTION (BYTE )-1 ++#define IMAGE_SYM_CLASS_NULL 0x0000 ++#define IMAGE_SYM_CLASS_AUTOMATIC 0x0001 ++#define IMAGE_SYM_CLASS_EXTERNAL 0x0002 ++#define IMAGE_SYM_CLASS_STATIC 0x0003 ++#define IMAGE_SYM_CLASS_REGISTER 0x0004 ++#define IMAGE_SYM_CLASS_EXTERNAL_DEF 0x0005 ++#define IMAGE_SYM_CLASS_LABEL 0x0006 ++#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 0x0007 ++#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 0x0008 ++#define IMAGE_SYM_CLASS_ARGUMENT 0x0009 ++#define IMAGE_SYM_CLASS_STRUCT_TAG 0x000A ++#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 0x000B ++#define IMAGE_SYM_CLASS_UNION_TAG 0x000C ++#define IMAGE_SYM_CLASS_TYPE_DEFINITION 0x000D ++#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 0x000E ++#define IMAGE_SYM_CLASS_ENUM_TAG 0x000F ++#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 0x0010 ++#define IMAGE_SYM_CLASS_REGISTER_PARAM 0x0011 ++#define IMAGE_SYM_CLASS_BIT_FIELD 0x0012 ++ ++#define IMAGE_SYM_CLASS_FAR_EXTERNAL 0x0044 ++#define IMAGE_SYM_CLASS_BLOCK 0x0064 ++#define IMAGE_SYM_CLASS_FUNCTION 0x0065 ++#define IMAGE_SYM_CLASS_END_OF_STRUCT 0x0066 ++#define IMAGE_SYM_CLASS_FILE 0x0067 ++#define IMAGE_SYM_CLASS_SECTION 0x0068 ++#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 0x0069 ++ ++#define N_BTMASK 0x000F ++#define N_TMASK 0x0030 ++#define N_TMASK1 0x00C0 ++#define N_TMASK2 0x00F0 ++#define N_BTSHFT 4 ++#define N_TSHIFT 2 ++ ++#define BTYPE(x) ((x) & N_BTMASK) ++ ++#ifndef ISPTR ++#define ISPTR(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_POINTER << N_BTSHFT)) ++#endif ++ ++#ifndef ISFCN ++#define ISFCN(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_FUNCTION << N_BTSHFT)) ++#endif ++ ++#ifndef ISARY ++#define ISARY(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_ARRAY << N_BTSHFT)) ++#endif ++ ++#ifndef ISTAG ++#define ISTAG(x) ((x)==IMAGE_SYM_CLASS_STRUCT_TAG || (x)==IMAGE_SYM_CLASS_UNION_TAG || (x)==IMAGE_SYM_CLASS_ENUM_TAG) ++#endif ++ ++#ifndef INCREF ++#define INCREF(x) ((((x)&~N_BTMASK)<>N_TSHIFT)&~N_BTMASK)|((x)&N_BTMASK)) ++#endif ++ ++#define IMAGE_COMDAT_SELECT_NODUPLICATES 1 ++#define IMAGE_COMDAT_SELECT_ANY 2 ++#define IMAGE_COMDAT_SELECT_SAME_SIZE 3 ++#define IMAGE_COMDAT_SELECT_EXACT_MATCH 4 ++#define IMAGE_COMDAT_SELECT_ASSOCIATIVE 5 ++#define IMAGE_COMDAT_SELECT_LARGEST 6 ++#define IMAGE_COMDAT_SELECT_NEWEST 7 ++ ++#define IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1 ++#define IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 ++#define IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 ++ ++/* Export module directory */ ++ ++typedef struct _IMAGE_EXPORT_DIRECTORY { ++ DWORD Characteristics; ++ DWORD TimeDateStamp; ++ WORD MajorVersion; ++ WORD MinorVersion; ++ DWORD Name; ++ DWORD Base; ++ DWORD NumberOfFunctions; ++ DWORD NumberOfNames; ++ DWORD AddressOfFunctions; ++ DWORD AddressOfNames; ++ DWORD AddressOfNameOrdinals; ++} IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY; ++ ++/* Import name entry */ ++typedef struct _IMAGE_IMPORT_BY_NAME { ++ WORD Hint; ++ BYTE Name[1]; ++} IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME; ++ ++/* Import thunk */ ++typedef struct _IMAGE_THUNK_DATA32 { ++ union { ++ DWORD ForwarderString; ++ DWORD Function; ++ DWORD Ordinal; ++ DWORD AddressOfData; ++ } u1; ++} IMAGE_THUNK_DATA32,*PIMAGE_THUNK_DATA32; ++ ++typedef struct _IMAGE_THUNK_DATA64 { ++ union { ++ ULONGLONG ForwarderString; ++ ULONGLONG Function; ++ ULONGLONG Ordinal; ++ ULONGLONG AddressOfData; ++ } u1; ++} IMAGE_THUNK_DATA64,*PIMAGE_THUNK_DATA64; ++ ++#ifdef CONFIG_X86_64 ++typedef IMAGE_THUNK_DATA32 IMAGE_THUNK_DATA; ++typedef PIMAGE_THUNK_DATA32 PIMAGE_THUNK_DATA; ++#else ++typedef IMAGE_THUNK_DATA64 IMAGE_THUNK_DATA; ++typedef PIMAGE_THUNK_DATA64 PIMAGE_THUNK_DATA; ++#endif ++ ++/* Import module directory */ ++ ++typedef struct __packed _IMAGE_IMPORT_DESCRIPTOR { ++ union { ++ DWORD Characteristics; /* 0 for terminating null ++ * import descriptor */ ++ DWORD OriginalFirstThunk; /* RVA to original unbound ++ * IAT */ ++ } u; ++ DWORD TimeDateStamp; /* 0 if not bound, ++ * -1 if bound, and real date\time stamp ++ * in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT ++ * (new BIND) ++ * otherwise date/time stamp of DLL bound to ++ * (Old BIND) ++ */ ++ DWORD ForwarderChain; /* -1 if no forwarders */ ++ DWORD Name; ++ /* RVA to IAT (if bound this IAT has actual addresses) */ ++ DWORD FirstThunk; ++} IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR; ++ ++#define IMAGE_ORDINAL_FLAG32 0x80000000 ++#define IMAGE_ORDINAL_FLAG64 0x8000000000000000UL ++#define IMAGE_SNAP_BY_ORDINAL32(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG32) != 0) ++#define IMAGE_SNAP_BY_ORDINAL64(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG64) != 0) ++#define IMAGE_ORDINAL(Ordinal) (Ordinal & 0xffff) ++ ++#ifdef CONFIG_X86_64 ++#define IMAGE_ORDINAL_FLAG IMAGE_ORDINAL_FLAG64 ++#define IMAGE_SNAP_BY_ORDINAL IMAGE_SNAP_BY_ORDINAL64 ++#else ++#define IMAGE_ORDINAL_FLAG IMAGE_ORDINAL_FLAG32 ++#define IMAGE_SNAP_BY_ORDINAL IMAGE_SNAP_BY_ORDINAL32 ++#endif ++ ++typedef struct _IMAGE_BOUND_IMPORT_DESCRIPTOR ++{ ++ DWORD TimeDateStamp; ++ WORD OffsetModuleName; ++ WORD NumberOfModuleForwarderRefs; ++/* Array of zero or more IMAGE_BOUND_FORWARDER_REF follows */ ++} IMAGE_BOUND_IMPORT_DESCRIPTOR, *PIMAGE_BOUND_IMPORT_DESCRIPTOR; ++ ++typedef struct _IMAGE_BOUND_FORWARDER_REF ++{ ++ DWORD TimeDateStamp; ++ WORD OffsetModuleName; ++ WORD Reserved; ++} IMAGE_BOUND_FORWARDER_REF, *PIMAGE_BOUND_FORWARDER_REF; ++ ++typedef struct _IMAGE_BASE_RELOCATION ++{ ++ DWORD VirtualAddress; ++ DWORD SizeOfBlock; ++ WORD TypeOffset[0]; ++} IMAGE_BASE_RELOCATION,*PIMAGE_BASE_RELOCATION; ++ ++typedef struct _IMAGE_RELOCATION ++{ ++ union { ++ DWORD VirtualAddress; ++ DWORD RelocCount; ++ } DUMMYUNIONNAME; ++ DWORD SymbolTableIndex; ++ WORD Type; ++} IMAGE_RELOCATION, *PIMAGE_RELOCATION; ++ ++#define IMAGE_SIZEOF_RELOCATION 10 ++ ++/* generic relocation types */ ++#define IMAGE_REL_BASED_ABSOLUTE 0 ++#define IMAGE_REL_BASED_HIGH 1 ++#define IMAGE_REL_BASED_LOW 2 ++#define IMAGE_REL_BASED_HIGHLOW 3 ++#define IMAGE_REL_BASED_HIGHADJ 4 ++#define IMAGE_REL_BASED_MIPS_JMPADDR 5 ++#define IMAGE_REL_BASED_SECTION 6 ++#define IMAGE_REL_BASED_REL 7 ++#define IMAGE_REL_BASED_MIPS_JMPADDR16 9 ++#define IMAGE_REL_BASED_IA64_IMM64 9 /* yes, 9 too */ ++#define IMAGE_REL_BASED_DIR64 10 ++#define IMAGE_REL_BASED_HIGH3ADJ 11 ++ ++/* I386 relocation types */ ++#define IMAGE_REL_I386_ABSOLUTE 0 ++#define IMAGE_REL_I386_DIR16 1 ++#define IMAGE_REL_I386_REL16 2 ++#define IMAGE_REL_I386_DIR32 6 ++#define IMAGE_REL_I386_DIR32NB 7 ++#define IMAGE_REL_I386_SEG12 9 ++#define IMAGE_REL_I386_SECTION 10 ++#define IMAGE_REL_I386_SECREL 11 ++#define IMAGE_REL_I386_REL32 20 ++ ++/* MIPS relocation types */ ++#define IMAGE_REL_MIPS_ABSOLUTE 0x0000 ++#define IMAGE_REL_MIPS_REFHALF 0x0001 ++#define IMAGE_REL_MIPS_REFWORD 0x0002 ++#define IMAGE_REL_MIPS_JMPADDR 0x0003 ++#define IMAGE_REL_MIPS_REFHI 0x0004 ++#define IMAGE_REL_MIPS_REFLO 0x0005 ++#define IMAGE_REL_MIPS_GPREL 0x0006 ++#define IMAGE_REL_MIPS_LITERAL 0x0007 ++#define IMAGE_REL_MIPS_SECTION 0x000A ++#define IMAGE_REL_MIPS_SECREL 0x000B ++#define IMAGE_REL_MIPS_SECRELLO 0x000C ++#define IMAGE_REL_MIPS_SECRELHI 0x000D ++#define IMAGE_REL_MIPS_JMPADDR16 0x0010 ++#define IMAGE_REL_MIPS_REFWORDNB 0x0022 ++#define IMAGE_REL_MIPS_PAIR 0x0025 ++ ++/* ALPHA relocation types */ ++#define IMAGE_REL_ALPHA_ABSOLUTE 0x0000 ++#define IMAGE_REL_ALPHA_REFLONG 0x0001 ++#define IMAGE_REL_ALPHA_REFQUAD 0x0002 ++#define IMAGE_REL_ALPHA_GPREL 0x0003 ++#define IMAGE_REL_ALPHA_LITERAL 0x0004 ++#define IMAGE_REL_ALPHA_LITUSE 0x0005 ++#define IMAGE_REL_ALPHA_GPDISP 0x0006 ++#define IMAGE_REL_ALPHA_BRADDR 0x0007 ++#define IMAGE_REL_ALPHA_HINT 0x0008 ++#define IMAGE_REL_ALPHA_INLINE_REFLONG 0x0009 ++#define IMAGE_REL_ALPHA_REFHI 0x000A ++#define IMAGE_REL_ALPHA_REFLO 0x000B ++#define IMAGE_REL_ALPHA_PAIR 0x000C ++#define IMAGE_REL_ALPHA_MATCH 0x000D ++#define IMAGE_REL_ALPHA_SECTION 0x000E ++#define IMAGE_REL_ALPHA_SECREL 0x000F ++#define IMAGE_REL_ALPHA_REFLONGNB 0x0010 ++#define IMAGE_REL_ALPHA_SECRELLO 0x0011 ++#define IMAGE_REL_ALPHA_SECRELHI 0x0012 ++#define IMAGE_REL_ALPHA_REFQ3 0x0013 ++#define IMAGE_REL_ALPHA_REFQ2 0x0014 ++#define IMAGE_REL_ALPHA_REFQ1 0x0015 ++#define IMAGE_REL_ALPHA_GPRELLO 0x0016 ++#define IMAGE_REL_ALPHA_GPRELHI 0x0017 ++ ++/* PowerPC relocation types */ ++#define IMAGE_REL_PPC_ABSOLUTE 0x0000 ++#define IMAGE_REL_PPC_ADDR64 0x0001 ++#define IMAGE_REL_PPC_ADDR 0x0002 ++#define IMAGE_REL_PPC_ADDR24 0x0003 ++#define IMAGE_REL_PPC_ADDR16 0x0004 ++#define IMAGE_REL_PPC_ADDR14 0x0005 ++#define IMAGE_REL_PPC_REL24 0x0006 ++#define IMAGE_REL_PPC_REL14 0x0007 ++#define IMAGE_REL_PPC_TOCREL16 0x0008 ++#define IMAGE_REL_PPC_TOCREL14 0x0009 ++#define IMAGE_REL_PPC_ADDR32NB 0x000A ++#define IMAGE_REL_PPC_SECREL 0x000B ++#define IMAGE_REL_PPC_SECTION 0x000C ++#define IMAGE_REL_PPC_IFGLUE 0x000D ++#define IMAGE_REL_PPC_IMGLUE 0x000E ++#define IMAGE_REL_PPC_SECREL16 0x000F ++#define IMAGE_REL_PPC_REFHI 0x0010 ++#define IMAGE_REL_PPC_REFLO 0x0011 ++#define IMAGE_REL_PPC_PAIR 0x0012 ++#define IMAGE_REL_PPC_SECRELLO 0x0013 ++#define IMAGE_REL_PPC_SECRELHI 0x0014 ++#define IMAGE_REL_PPC_GPREL 0x0015 ++#define IMAGE_REL_PPC_TYPEMASK 0x00FF ++/* modifier bits */ ++#define IMAGE_REL_PPC_NEG 0x0100 ++#define IMAGE_REL_PPC_BRTAKEN 0x0200 ++#define IMAGE_REL_PPC_BRNTAKEN 0x0400 ++#define IMAGE_REL_PPC_TOCDEFN 0x0800 ++ ++/* SH3 ? relocation type */ ++#define IMAGE_REL_SH3_ABSOLUTE 0x0000 ++#define IMAGE_REL_SH3_DIRECT16 0x0001 ++#define IMAGE_REL_SH3_DIRECT 0x0002 ++#define IMAGE_REL_SH3_DIRECT8 0x0003 ++#define IMAGE_REL_SH3_DIRECT8_WORD 0x0004 ++#define IMAGE_REL_SH3_DIRECT8_LONG 0x0005 ++#define IMAGE_REL_SH3_DIRECT4 0x0006 ++#define IMAGE_REL_SH3_DIRECT4_WORD 0x0007 ++#define IMAGE_REL_SH3_DIRECT4_LONG 0x0008 ++#define IMAGE_REL_SH3_PCREL8_WORD 0x0009 ++#define IMAGE_REL_SH3_PCREL8_LONG 0x000A ++#define IMAGE_REL_SH3_PCREL12_WORD 0x000B ++#define IMAGE_REL_SH3_STARTOF_SECTION 0x000C ++#define IMAGE_REL_SH3_SIZEOF_SECTION 0x000D ++#define IMAGE_REL_SH3_SECTION 0x000E ++#define IMAGE_REL_SH3_SECREL 0x000F ++#define IMAGE_REL_SH3_DIRECT32_NB 0x0010 ++ ++/* ARM (Archimedes?) relocation types */ ++#define IMAGE_REL_ARM_ABSOLUTE 0x0000 ++#define IMAGE_REL_ARM_ADDR 0x0001 ++#define IMAGE_REL_ARM_ADDR32NB 0x0002 ++#define IMAGE_REL_ARM_BRANCH24 0x0003 ++#define IMAGE_REL_ARM_BRANCH11 0x0004 ++#define IMAGE_REL_ARM_SECTION 0x000E ++#define IMAGE_REL_ARM_SECREL 0x000F ++ ++/* IA64 relocation types */ ++#define IMAGE_REL_IA64_ABSOLUTE 0x0000 ++#define IMAGE_REL_IA64_IMM14 0x0001 ++#define IMAGE_REL_IA64_IMM22 0x0002 ++#define IMAGE_REL_IA64_IMM64 0x0003 ++#define IMAGE_REL_IA64_DIR 0x0004 ++#define IMAGE_REL_IA64_DIR64 0x0005 ++#define IMAGE_REL_IA64_PCREL21B 0x0006 ++#define IMAGE_REL_IA64_PCREL21M 0x0007 ++#define IMAGE_REL_IA64_PCREL21F 0x0008 ++#define IMAGE_REL_IA64_GPREL22 0x0009 ++#define IMAGE_REL_IA64_LTOFF22 0x000A ++#define IMAGE_REL_IA64_SECTION 0x000B ++#define IMAGE_REL_IA64_SECREL22 0x000C ++#define IMAGE_REL_IA64_SECREL64I 0x000D ++#define IMAGE_REL_IA64_SECREL 0x000E ++#define IMAGE_REL_IA64_LTOFF64 0x000F ++#define IMAGE_REL_IA64_DIR32NB 0x0010 ++#define IMAGE_REL_IA64_RESERVED_11 0x0011 ++#define IMAGE_REL_IA64_RESERVED_12 0x0012 ++#define IMAGE_REL_IA64_RESERVED_13 0x0013 ++#define IMAGE_REL_IA64_RESERVED_14 0x0014 ++#define IMAGE_REL_IA64_RESERVED_15 0x0015 ++#define IMAGE_REL_IA64_RESERVED_16 0x0016 ++#define IMAGE_REL_IA64_ADDEND 0x001F ++ ++/* archive format */ ++ ++#define IMAGE_ARCHIVE_START_SIZE 8 ++#define IMAGE_ARCHIVE_START "!\n" ++#define IMAGE_ARCHIVE_END "`\n" ++#define IMAGE_ARCHIVE_PAD "\n" ++#define IMAGE_ARCHIVE_LINKER_MEMBER "/ " ++#define IMAGE_ARCHIVE_LONGNAMES_MEMBER "// " ++ ++typedef struct _IMAGE_ARCHIVE_MEMBER_HEADER ++{ ++ BYTE Name[16]; ++ BYTE Date[12]; ++ BYTE UserID[6]; ++ BYTE GroupID[6]; ++ BYTE Mode[8]; ++ BYTE Size[10]; ++ BYTE EndHeader[2]; ++} IMAGE_ARCHIVE_MEMBER_HEADER, *PIMAGE_ARCHIVE_MEMBER_HEADER; ++ ++#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 ++ ++/* ++ * Resource directory stuff ++ */ ++typedef struct _IMAGE_RESOURCE_DIRECTORY { ++ DWORD Characteristics; ++ DWORD TimeDateStamp; ++ WORD MajorVersion; ++ WORD MinorVersion; ++ WORD NumberOfNamedEntries; ++ WORD NumberOfIdEntries; ++ /* IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[]; */ ++} IMAGE_RESOURCE_DIRECTORY,*PIMAGE_RESOURCE_DIRECTORY; ++ ++#define IMAGE_RESOURCE_NAME_IS_STRING 0x80000000 ++#define IMAGE_RESOURCE_DATA_IS_DIRECTORY 0x80000000 ++ ++typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY { ++ union { ++ struct { ++#ifdef BITFIELDS_BIGENDIAN ++ unsigned NameIsString:1; ++ unsigned NameOffset:31; ++#else ++ unsigned NameOffset:31; ++ unsigned NameIsString:1; ++#endif ++ } DUMMYSTRUCTNAME1; ++ DWORD Name; ++ struct { ++#ifdef WORDS_BIGENDIAN ++ WORD __pad; ++ WORD Id; ++#else ++ WORD Id; ++ WORD __pad; ++#endif ++ } DUMMYSTRUCTNAME2; ++ } DUMMYUNIONNAME1; ++ union { ++ DWORD OffsetToData; ++ struct { ++#ifdef BITFIELDS_BIGENDIAN ++ unsigned DataIsDirectory:1; ++ unsigned OffsetToDirectory:31; ++#else ++ unsigned OffsetToDirectory:31; ++ unsigned DataIsDirectory:1; ++#endif ++ } DUMMYSTRUCTNAME3; ++ } DUMMYUNIONNAME2; ++} IMAGE_RESOURCE_DIRECTORY_ENTRY,*PIMAGE_RESOURCE_DIRECTORY_ENTRY; ++ ++ ++typedef struct _IMAGE_RESOURCE_DIRECTORY_STRING { ++ WORD Length; ++ CHAR NameString[ 1 ]; ++} IMAGE_RESOURCE_DIRECTORY_STRING,*PIMAGE_RESOURCE_DIRECTORY_STRING; +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/pnp.c linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/pnp.c +--- linux-3.12.2/3rdparty/ndiswrapper/pnp.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/pnp.c 2013-11-28 21:42:11.000000000 +0200 +@@ -0,0 +1,697 @@ ++/* ++ * Copyright (C) 2005 Giridhar Pemmasani ++ * ++ * 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 "usb.h" ++#include "pnp.h" ++#include "wrapndis.h" ++#include "loader.h" ++ ++/* Functions callable from the NDIS driver */ ++wstdcall NTSTATUS pdoDispatchDeviceControl(struct device_object *pdo, ++ struct irp *irp); ++wstdcall NTSTATUS pdoDispatchPnp(struct device_object *pdo, struct irp *irp); ++wstdcall NTSTATUS pdoDispatchPower(struct device_object *pdo, struct irp *irp); ++ ++static NTSTATUS start_pdo(struct device_object *pdo) ++{ ++ int i, ret, count, resources_size; ++ struct wrap_device *wd; ++ struct pci_dev *pdev; ++ struct cm_partial_resource_descriptor *entry; ++ struct cm_partial_resource_list *partial_resource_list; ++ ++ ENTER1("%p, %p", pdo, pdo->reserved); ++ wd = pdo->reserved; ++ if (ntoskernel_init_device(wd)) ++ EXIT1(return STATUS_FAILURE); ++ if (wrap_is_usb_bus(wd->dev_bus)) { ++ if (usb_init_device(wd)) { ++ ntoskernel_exit_device(wd); ++ EXIT1(return STATUS_FAILURE); ++ } ++ EXIT1(return STATUS_SUCCESS); ++ } ++ if (!wrap_is_pci_bus(wd->dev_bus)) ++ EXIT1(return STATUS_SUCCESS); ++ pdev = wd->pci.pdev; ++ ret = pci_enable_device(pdev); ++ if (ret) { ++ ERROR("couldn't enable PCI device: %x", ret); ++ return STATUS_FAILURE; ++ } ++ ret = pci_request_regions(pdev, DRIVER_NAME); ++ if (ret) { ++ ERROR("couldn't request PCI regions: %x", ret); ++ goto err_enable; ++ } ++ pci_set_power_state(pdev, PCI_D0); ++#ifdef CONFIG_X86_64 ++ /* 64-bit broadcom driver doesn't work if DMA is allocated ++ * from over 1GB */ ++ if (wd->vendor == 0x14e4) { ++ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(30)) || ++ pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(30))) ++ WARNING("couldn't set DMA mask; this driver " ++ "may not work with more than 1GB RAM"); ++ } ++#endif ++ /* IRQ resource entry is filled in from pdev, instead of ++ * pci_resource macros */ ++ for (i = count = 0; pci_resource_start(pdev, i); i++) ++ if ((pci_resource_flags(pdev, i) & IORESOURCE_MEM) || ++ (pci_resource_flags(pdev, i) & IORESOURCE_IO)) ++ count++; ++ /* space for entry for IRQ is already in ++ * cm_partial_resource_list */ ++ resources_size = sizeof(struct cm_resource_list) + ++ sizeof(struct cm_partial_resource_descriptor) * count; ++ TRACE2("resources: %d, %d", count, resources_size); ++ wd->resource_list = kzalloc(resources_size, GFP_KERNEL); ++ if (!wd->resource_list) { ++ WARNING("couldn't allocate memory"); ++ goto err_regions; ++ } ++ wd->resource_list->count = 1; ++ wd->resource_list->list[0].interface_type = PCIBus; ++ /* bus_number is not used by WDM drivers */ ++ wd->resource_list->list[0].bus_number = pdev->bus->number; ++ ++ partial_resource_list = ++ &wd->resource_list->list->partial_resource_list; ++ partial_resource_list->version = 1; ++ partial_resource_list->revision = 1; ++ partial_resource_list->count = count + 1; ++ ++ for (i = count = 0; pci_resource_start(pdev, i); i++) { ++ entry = &partial_resource_list->partial_descriptors[count]; ++ TRACE2("%d", count); ++ if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { ++ entry->type = CmResourceTypeMemory; ++ entry->flags = CM_RESOURCE_MEMORY_READ_WRITE; ++ entry->share = CmResourceShareDeviceExclusive; ++ } else if (pci_resource_flags(pdev, i) & IORESOURCE_IO) { ++ entry->type = CmResourceTypePort; ++ entry->flags = CM_RESOURCE_PORT_IO; ++ entry->share = CmResourceShareDeviceExclusive; ++#if 0 ++ } else if (pci_resource_flags(pdev, i) & IORESOURCE_DMA) { ++ /* it looks like no driver uses this resource */ ++ typeof(pci_resource_flags(pdev, 0)) flags; ++ entry->type = CmResourceTypeDma; ++ flags = pci_resource_flags(pdev, i); ++ if (flags & IORESOURCE_DMA_TYPEA) ++ entry->flags |= CM_RESOURCE_DMA_TYPE_A; ++ else if (flags & IORESOURCE_DMA_TYPEB) ++ entry->flags |= CM_RESOURCE_DMA_TYPE_B; ++ else if (flags & IORESOURCE_DMA_TYPEF) ++ entry->flags |= CM_RESOURCE_DMA_TYPE_F; ++ if (flags & IORESOURCE_DMA_8BIT) ++ entry->flags |= CM_RESOURCE_DMA_8; ++ else if (flags & IORESOURCE_DMA_16BIT) ++ entry->flags |= CM_RESOURCE_DMA_16; ++ /* what about 32bit DMA? */ ++ else if (flags & IORESOURCE_DMA_8AND16BIT) ++ entry->flags |= CM_RESOURCE_DMA_8_AND_16; ++ if (flags & IORESOURCE_DMA_MASTER) ++ entry->flags |= CM_RESOURCE_DMA_BUS_MASTER; ++ entry->u.dma.channel = pci_resource_start(pdev, i); ++ /* what should this be? */ ++ entry->u.dma.port = 1; ++#endif ++ } else ++ continue; ++ /* TODO: Add other resource types? */ ++ entry->u.generic.start = ++ (ULONG_PTR)pci_resource_start(pdev, i); ++ entry->u.generic.length = pci_resource_len(pdev, i); ++ count++; ++ } ++ ++ /* put IRQ resource at the end */ ++ entry = &partial_resource_list->partial_descriptors[count++]; ++ entry->type = CmResourceTypeInterrupt; ++ entry->flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; ++ /* we assume all devices use shared IRQ */ ++ entry->share = CmResourceShareShared; ++ /* as per documentation, interrupt level should be DIRQL, but ++ * examples from DDK as well some drivers, such as AR5211, ++ * RT8180L use interrupt level as interrupt vector also in ++ * NdisMRegisterInterrupt */ ++ entry->u.interrupt.level = pdev->irq; ++ entry->u.interrupt.vector = pdev->irq; ++ entry->u.interrupt.affinity = -1; ++ ++ TRACE2("resource list count %d, irq: %d", ++ partial_resource_list->count, pdev->irq); ++ pci_set_drvdata(pdev, wd); ++ EXIT1(return STATUS_SUCCESS); ++err_regions: ++ pci_release_regions(pdev); ++err_enable: ++ pci_disable_device(pdev); ++ wd->pci.pdev = NULL; ++ wd->pdo = NULL; ++ EXIT1(return STATUS_FAILURE); ++} ++ ++static void remove_pdo(struct device_object *pdo) ++{ ++ struct wrap_device *wd = pdo->reserved; ++ ++ ntoskernel_exit_device(wd); ++ if (wrap_is_pci_bus(wd->dev_bus)) { ++ struct pci_dev *pdev = wd->pci.pdev; ++ pci_release_regions(pdev); ++ pci_disable_device(pdev); ++ wd->pci.pdev = NULL; ++ pci_set_drvdata(pdev, NULL); ++ } else if (wrap_is_usb_bus(wd->dev_bus)) { ++ usb_exit_device(wd); ++ } ++ kfree(wd->resource_list); ++ wd->resource_list = NULL; ++ return; ++} ++ ++static NTSTATUS IoSendIrpTopDev(struct device_object *dev_obj, ULONG major_fn, ++ ULONG minor_fn, struct io_stack_location *sl) ++{ ++ NTSTATUS status; ++ struct nt_event event; ++ struct irp *irp; ++ struct io_stack_location *irp_sl; ++ struct device_object *top_dev = IoGetAttachedDeviceReference(dev_obj); ++ ++ KeInitializeEvent(&event, NotificationEvent, FALSE); ++ irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, top_dev, NULL, 0, NULL, ++ &event, NULL); ++ irp->io_status.status = STATUS_NOT_IMPLEMENTED; ++ irp->io_status.info = 0; ++ irp_sl = IoGetNextIrpStackLocation(irp); ++ if (sl) ++ memcpy(irp_sl, sl, sizeof(*irp_sl)); ++ irp_sl->major_fn = major_fn; ++ irp_sl->minor_fn = minor_fn; ++ status = IoCallDriver(top_dev, irp); ++ if (status == STATUS_PENDING) { ++ KeWaitForSingleObject(&event, Executive, KernelMode, ++ FALSE, NULL); ++ status = irp->io_status.status; ++ } ++ ObDereferenceObject(top_dev); ++ return status; ++} ++ ++wstdcall NTSTATUS pdoDispatchDeviceControl(struct device_object *pdo, ++ struct irp *irp) ++{ ++ NTSTATUS status; ++ struct wrap_device *wd = pdo->reserved; ++ ++ DUMP_IRP(irp); ++ (void)wd; ++ if (wrap_is_usb_bus(wd->dev_bus)) { ++ status = wrap_submit_irp(pdo, irp); ++ IOTRACE("status: %08X", status); ++ if (status != STATUS_PENDING) ++ IoCompleteRequest(irp, IO_NO_INCREMENT); ++ } else { ++ status = irp->io_status.status = STATUS_NOT_IMPLEMENTED; ++ IoCompleteRequest(irp, IO_NO_INCREMENT); ++ } ++ IOEXIT(return status); ++} ++WIN_FUNC_DECL(pdoDispatchDeviceControl,2) ++ ++wstdcall NTSTATUS pdoDispatchPnp(struct device_object *pdo, struct irp *irp) ++{ ++ struct io_stack_location *irp_sl; ++ NTSTATUS status; ++ struct wrap_device *wd = pdo->reserved; ++ ++ irp_sl = IoGetCurrentIrpStackLocation(irp); ++ TRACE2("%p %d:%d", pdo, irp_sl->major_fn, irp_sl->minor_fn); ++ switch (irp_sl->minor_fn) { ++ case IRP_MN_START_DEVICE: ++ status = start_pdo(pdo); ++ break; ++ case IRP_MN_QUERY_STOP_DEVICE: ++ case IRP_MN_STOP_DEVICE: ++ case IRP_MN_QUERY_REMOVE_DEVICE: ++ status = STATUS_SUCCESS; ++ break; ++ case IRP_MN_REMOVE_DEVICE: ++ remove_pdo(pdo); ++ status = STATUS_SUCCESS; ++ break; ++ case IRP_MN_QUERY_INTERFACE: ++ if (wrap_is_usb_bus(wd->dev_bus)) ++ status = usb_query_interface(wd, irp_sl); ++ else ++ status = STATUS_NOT_IMPLEMENTED; ++ break; ++ default: ++ TRACE2("fn %d not implemented", irp_sl->minor_fn); ++ status = STATUS_SUCCESS; ++ break; ++ } ++ irp->io_status.status = status; ++ TRACE2("status: %08X", status); ++ IoCompleteRequest(irp, IO_NO_INCREMENT); ++ IOEXIT(return status); ++} ++WIN_FUNC_DECL(pdoDispatchPnp,2) ++ ++wstdcall NTSTATUS pdoDispatchPower(struct device_object *pdo, struct irp *irp) ++{ ++ struct io_stack_location *irp_sl; ++ struct wrap_device *wd; ++ union power_state power_state; ++ struct pci_dev *pdev; ++ NTSTATUS status; ++ ++ irp_sl = IoGetCurrentIrpStackLocation(irp); ++ wd = pdo->reserved; ++ TRACE2("pdo: %p, fn: %d:%d, wd: %p", ++ pdo, irp_sl->major_fn, irp_sl->minor_fn, wd); ++ switch (irp_sl->minor_fn) { ++ case IRP_MN_WAIT_WAKE: ++ /* TODO: this is not complete/correct */ ++ TRACE2("state: %d, completion: %p", ++ irp_sl->params.power.state.system_state, ++ irp_sl->completion_routine); ++ IoMarkIrpPending(irp); ++ status = STATUS_PENDING; ++ break; ++ case IRP_MN_SET_POWER: ++ power_state = irp_sl->params.power.state; ++ if (power_state.device_state == PowerDeviceD0) { ++ TRACE2("resuming %p", wd); ++ if (wrap_is_pci_bus(wd->dev_bus)) { ++ pdev = wd->pci.pdev; ++ pci_restore_state(pdev); ++ if (wd->pci.wake_state == PowerDeviceD3) { ++ pci_enable_wake(wd->pci.pdev, ++ PCI_D3hot, 0); ++ pci_enable_wake(wd->pci.pdev, ++ PCI_D3cold, 0); ++ } ++ pci_set_power_state(pdev, PCI_D0); ++ } else if (wrap_is_usb_bus(wd->dev_bus)) { ++ wrap_resume_urbs(wd); ++ } ++ } else { ++ TRACE2("suspending device %p", wd); ++ if (wrap_is_pci_bus(wd->dev_bus)) { ++ pdev = wd->pci.pdev; ++ pci_save_state(pdev); ++ TRACE2("%d", wd->pci.wake_state); ++ if (wd->pci.wake_state == PowerDeviceD3) { ++ pci_enable_wake(wd->pci.pdev, ++ PCI_D3hot, 1); ++ pci_enable_wake(wd->pci.pdev, ++ PCI_D3cold, 1); ++ } ++ pci_set_power_state(pdev, PCI_D3hot); ++ } else if (wrap_is_usb_bus(wd->dev_bus)) { ++ wrap_suspend_urbs(wd); ++ } ++ } ++ status = STATUS_SUCCESS; ++ break; ++ case IRP_MN_QUERY_POWER: ++ status = STATUS_SUCCESS; ++ break; ++ default: ++ TRACE2("fn %d not implemented", irp_sl->minor_fn); ++ status = STATUS_SUCCESS; ++ break; ++ } ++ irp->io_status.status = status; ++ IoCompleteRequest(irp, IO_NO_INCREMENT); ++ return status; ++} ++WIN_FUNC_DECL(pdoDispatchPower,2) ++ ++static NTSTATUS pnp_set_device_power_state(struct wrap_device *wd, ++ enum device_power_state state) ++{ ++ NTSTATUS status; ++ struct device_object *pdo; ++ struct io_stack_location irp_sl; ++ ++ pdo = wd->pdo; ++ IOTRACE("%p, %p", pdo, IoGetAttachedDevice(pdo)); ++ memset(&irp_sl, 0, sizeof(irp_sl)); ++ irp_sl.params.power.state.device_state = state; ++ irp_sl.params.power.type = DevicePowerState; ++ if (state > PowerDeviceD0) { ++ status = IoSendIrpTopDev(pdo, IRP_MJ_POWER, IRP_MN_QUERY_POWER, ++ &irp_sl); ++ if (status != STATUS_SUCCESS) { ++ TRACE1("query of power to %d returns %08X", ++ state, status); ++ EXIT1(return status); ++ } ++ } ++ status = IoSendIrpTopDev(pdo, IRP_MJ_POWER, IRP_MN_SET_POWER, &irp_sl); ++ if (status != STATUS_SUCCESS) ++ WARNING("setting power to %d failed: %08X", state, status); ++ EXIT1(return status); ++} ++ ++static NTSTATUS pnp_start_device(struct wrap_device *wd) ++{ ++ struct device_object *fdo; ++ struct device_object *pdo; ++ struct io_stack_location irp_sl; ++ NTSTATUS status; ++ ++ pdo = wd->pdo; ++ /* TODO: for now we use same resources for both translated ++ * resources and raw resources */ ++ memset(&irp_sl, 0, sizeof(irp_sl)); ++ irp_sl.params.start_device.allocated_resources = ++ wd->resource_list; ++ irp_sl.params.start_device.allocated_resources_translated = ++ wd->resource_list; ++ status = IoSendIrpTopDev(pdo, IRP_MJ_PNP, IRP_MN_START_DEVICE, &irp_sl); ++ fdo = IoGetAttachedDevice(pdo); ++ fdo->drv_obj->drv_ext->count++; ++ if (status != STATUS_SUCCESS) ++ WARNING("Windows driver couldn't initialize the device (%08X)", ++ status); ++ EXIT1(return status); ++} ++ ++#if 0 ++static NTSTATUS pnp_stop_device(struct wrap_device *wd) ++{ ++ struct device_object *pdo; ++ NTSTATUS status; ++ ++ pdo = wd->pdo; ++ status = IoSendIrpTopDev(pdo, IRP_MJ_PNP, IRP_MN_QUERY_STOP_DEVICE, ++ NULL); ++ if (status != STATUS_SUCCESS) ++ WARNING("status: %08X", status); ++ /* for now we ignore query status */ ++ status = IoSendIrpTopDev(pdo, IRP_MJ_PNP, IRP_MN_STOP_DEVICE, NULL); ++ if (status != STATUS_SUCCESS) ++ WARNING("status: %08X", status); ++ if (status != STATUS_SUCCESS) ++ WARNING("status: %08X", status); ++ EXIT2(return status); ++} ++#endif ++ ++static NTSTATUS pnp_remove_device(struct wrap_device *wd) ++{ ++ struct device_object *pdo, *fdo; ++ struct driver_object *fdo_drv_obj; ++ NTSTATUS status; ++ ++ pdo = wd->pdo; ++ fdo = IoGetAttachedDevice(pdo); ++ fdo_drv_obj = fdo->drv_obj; ++ TRACE2("%p, %p, %p", pdo, fdo, fdo_drv_obj); ++ status = IoSendIrpTopDev(pdo, IRP_MJ_PNP, IRP_MN_QUERY_REMOVE_DEVICE, ++ NULL); ++ if (status != STATUS_SUCCESS) ++ WARNING("status: %08X", status); ++ ++ status = IoSendIrpTopDev(pdo, IRP_MJ_PNP, IRP_MN_REMOVE_DEVICE, NULL); ++ if (status != STATUS_SUCCESS) ++ WARNING("status: %08X", status); ++ /* TODO: should we use count in drv_ext or driver's Object ++ * header reference count to keep count of devices associated ++ * with a driver? */ ++ if (status == STATUS_SUCCESS) ++ fdo_drv_obj->drv_ext->count--; ++ TRACE1("count: %d", fdo_drv_obj->drv_ext->count); ++ if ((LONG)fdo_drv_obj->drv_ext->count < 0) ++ WARNING("wrong count: %d", fdo_drv_obj->drv_ext->count); ++ if (fdo_drv_obj->drv_ext->count == 0) { ++ struct wrap_driver *wrap_driver; ++ TRACE1("unloading driver: %p", fdo_drv_obj); ++ wrap_driver = ++ IoGetDriverObjectExtension(fdo_drv_obj, ++ (void *)WRAP_DRIVER_CLIENT_ID); ++ if (fdo_drv_obj->unload) ++ LIN2WIN1(fdo_drv_obj->unload, fdo_drv_obj); ++ if (wrap_driver) { ++ mutex_lock(&loader_mutex); ++ unload_wrap_driver(wrap_driver); ++ mutex_unlock(&loader_mutex); ++ } else ++ ERROR("couldn't get wrap_driver"); ++ ObDereferenceObject(fdo_drv_obj); ++ } ++ IoDeleteDevice(pdo); ++ unload_wrap_device(wd); ++ EXIT1(return status); ++} ++ ++WIN_FUNC_DECL(IoInvalidDeviceRequest,2) ++ ++static struct device_object *alloc_pdo(struct driver_object *drv_obj) ++{ ++ struct device_object *pdo; ++ NTSTATUS status; ++ int i; ++ struct ansi_string ansi_name; ++ struct unicode_string unicode_name; ++ ++ RtlInitAnsiString(&ansi_name, "NDISpdo"); ++ if (RtlAnsiStringToUnicodeString(&unicode_name, &ansi_name, TRUE) == ++ STATUS_SUCCESS) { ++ status = IoCreateDevice(drv_obj, 0, &unicode_name, ++ FILE_DEVICE_UNKNOWN, ++ FILE_AUTOGENERATED_DEVICE_NAME, ++ FALSE, &pdo); ++ RtlFreeUnicodeString(&unicode_name); ++ } else { ++ status = IoCreateDevice(drv_obj, 0, NULL, ++ FILE_DEVICE_UNKNOWN, ++ FILE_AUTOGENERATED_DEVICE_NAME, ++ FALSE, &pdo); ++ } ++ TRACE1("%p, %d, %p", drv_obj, status, pdo); ++ if (status != STATUS_SUCCESS) ++ return NULL; ++ /* dispatch routines are called as Windows functions */ ++ for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) ++ drv_obj->major_func[i] = WIN_FUNC_PTR(IoInvalidDeviceRequest,2); ++ drv_obj->major_func[IRP_MJ_INTERNAL_DEVICE_CONTROL] = ++ WIN_FUNC_PTR(pdoDispatchDeviceControl,2); ++ drv_obj->major_func[IRP_MJ_DEVICE_CONTROL] = ++ WIN_FUNC_PTR(pdoDispatchDeviceControl,2); ++ drv_obj->major_func[IRP_MJ_POWER] = WIN_FUNC_PTR(pdoDispatchPower,2); ++ drv_obj->major_func[IRP_MJ_PNP] = WIN_FUNC_PTR(pdoDispatchPnp,2); ++ return pdo; ++} ++ ++static int wrap_pnp_start_device(struct wrap_device *wd) ++{ ++ struct wrap_driver *driver; ++ struct device_object *pdo; ++ struct driver_object *pdo_drv_obj; ++ ++ ENTER1("wd: %p", wd); ++ ++ if (!((wrap_is_pci_bus(wd->dev_bus)) || ++ (wrap_is_usb_bus(wd->dev_bus)))) { ++ ERROR("bus type %d (%d) not supported", ++ WRAP_BUS(wd->dev_bus), wd->dev_bus); ++ EXIT1(return -EINVAL); ++ } ++ driver = load_wrap_driver(wd); ++ if (!driver) ++ return -ENODEV; ++ ++ wd->driver = driver; ++ wd->dev_bus = WRAP_DEVICE_BUS(driver->dev_type, WRAP_BUS(wd->dev_bus)); ++ TRACE1("dev type: %d, bus type: %d, %d", WRAP_DEVICE(wd->dev_bus), ++ WRAP_BUS(wd->dev_bus), wd->dev_bus); ++ TRACE1("%d, %d", driver->dev_type, wrap_is_usb_bus(wd->dev_bus)); ++ /* first create pdo */ ++ if (wrap_is_pci_bus(wd->dev_bus)) ++ pdo_drv_obj = find_bus_driver("PCI"); ++ else // if (wrap_is_usb_bus(wd->dev_bus)) ++ pdo_drv_obj = find_bus_driver("USB"); ++ if (!pdo_drv_obj) ++ return -EINVAL; ++ pdo = alloc_pdo(pdo_drv_obj); ++ if (!pdo) ++ return -ENOMEM; ++ wd->pdo = pdo; ++ pdo->reserved = wd; ++ if (WRAP_DEVICE(wd->dev_bus) == WRAP_NDIS_DEVICE) { ++ if (init_ndis_driver(driver->drv_obj)) { ++ IoDeleteDevice(pdo); ++ return -EINVAL; ++ } ++ } ++ TRACE1("%p", driver->drv_obj->drv_ext->add_device); ++ if (driver->drv_obj->drv_ext->add_device(driver->drv_obj, pdo) != ++ STATUS_SUCCESS) { ++ IoDeleteDevice(pdo); ++ return -ENOMEM; ++ } ++ if (pnp_start_device(wd) != STATUS_SUCCESS) { ++ /* TODO: we need proper cleanup, to deallocate memory, ++ * for example */ ++ pnp_remove_device(wd); ++ return -EINVAL; ++ } ++ return 0; ++} ++ ++int wrap_pnp_start_pci_device(struct pci_dev *pdev, ++ const struct pci_device_id *ent) ++{ ++ struct load_device load_device; ++ struct wrap_device *wd; ++ ++ ENTER1("called for %04x:%04x:%04x:%04x", pdev->vendor, pdev->device, ++ pdev->subsystem_vendor, pdev->subsystem_device); ++ ++ load_device.bus = WRAP_PCI_BUS; ++ load_device.vendor = pdev->vendor; ++ load_device.device = pdev->device; ++ load_device.subvendor = pdev->subsystem_vendor; ++ load_device.subdevice = pdev->subsystem_device; ++ wd = load_wrap_device(&load_device); ++ if (!wd) ++ EXIT1(return -ENODEV); ++ wd->pci.pdev = pdev; ++ return wrap_pnp_start_device(wd); ++} ++ ++void wrap_pnp_remove_pci_device(struct pci_dev *pdev) ++{ ++ struct wrap_device *wd; ++ ++ wd = (struct wrap_device *)pci_get_drvdata(pdev); ++ ENTER1("%p, %p", pdev, wd); ++ if (!wd) ++ EXIT1(return); ++ pnp_remove_device(wd); ++} ++ ++int wrap_pnp_suspend_pci_device(struct pci_dev *pdev, pm_message_t state) ++{ ++ struct wrap_device *wd; ++ ++ wd = (struct wrap_device *)pci_get_drvdata(pdev); ++ return pnp_set_device_power_state(wd, PowerDeviceD3); ++} ++ ++int wrap_pnp_resume_pci_device(struct pci_dev *pdev) ++{ ++ struct wrap_device *wd; ++ ++ wd = (struct wrap_device *)pci_get_drvdata(pdev); ++ return pnp_set_device_power_state(wd, PowerDeviceD0); ++} ++ ++#ifdef ENABLE_USB ++int wrap_pnp_start_usb_device(struct usb_interface *intf, ++ const struct usb_device_id *usb_id) ++{ ++ struct wrap_device *wd; ++ int ret; ++ struct usb_device *udev = interface_to_usbdev(intf); ++ ENTER1("%04x, %04x, %04x", udev->descriptor.idVendor, ++ udev->descriptor.idProduct, udev->descriptor.bDeviceClass); ++ ++ /* USB device (e.g., RNDIS) may have multiple interfaces; ++ initialize one interface only (is there a way to know which ++ of these interfaces is for network?) */ ++ ++ if ((wd = get_wrap_device(udev, WRAP_USB_BUS))) { ++ TRACE1("device already initialized: %p", wd); ++ usb_set_intfdata(intf, NULL); ++ ret = 0; ++ } else { ++ struct load_device load_device; ++ ++ load_device.bus = WRAP_USB_BUS; ++ load_device.vendor = le16_to_cpu(udev->descriptor.idVendor); ++ load_device.device = le16_to_cpu(udev->descriptor.idProduct); ++ load_device.subvendor = 0; ++ load_device.subdevice = 0; ++ wd = load_wrap_device(&load_device); ++ TRACE2("%p", wd); ++ if (wd) { ++ /* some devices (e.g., TI 4150, RNDIS) need ++ * full reset */ ++ ret = usb_reset_device(udev); ++ if (ret) ++ WARNING("reset failed: %d", ret); ++ usb_set_intfdata(intf, wd); ++ wd->usb.intf = intf; ++ wd->usb.udev = udev; ++ ret = wrap_pnp_start_device(wd); ++ } else ++ ret = -ENODEV; ++ } ++ ++ TRACE2("ret: %d", ret); ++ if (ret) ++ EXIT1(return ret); ++ else ++ return 0; ++} ++ ++void wrap_pnp_remove_usb_device(struct usb_interface *intf) ++{ ++ struct wrap_device *wd; ++ ++ wd = (struct wrap_device *)usb_get_intfdata(intf); ++ TRACE1("%p, %p", intf, wd); ++ if (wd == NULL) ++ EXIT1(return); ++ usb_set_intfdata(intf, NULL); ++ wd->usb.intf = NULL; ++ pnp_remove_device(wd); ++} ++ ++int wrap_pnp_suspend_usb_device(struct usb_interface *intf, pm_message_t state) ++{ ++ struct wrap_device *wd; ++ ++ wd = usb_get_intfdata(intf); ++ ENTER1("%p, %p", intf, wd); ++ if (!wd) ++ EXIT1(return 0); ++ if (pnp_set_device_power_state(wd, PowerDeviceD3)) ++ return -1; ++ return 0; ++} ++ ++int wrap_pnp_resume_usb_device(struct usb_interface *intf) ++{ ++ struct wrap_device *wd; ++ wd = usb_get_intfdata(intf); ++ ENTER1("%p, %p", intf, wd); ++ if (!wd) ++ EXIT1(return 0); ++ if (pnp_set_device_power_state(wd, PowerDeviceD0)) ++ return -1; ++ return 0; ++} ++ ++#endif // USB +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/pnp.h linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/pnp.h +--- linux-3.12.2/3rdparty/ndiswrapper/pnp.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/pnp.h 2013-11-28 21:42:11.000000000 +0200 +@@ -0,0 +1,36 @@ ++/* ++ * Copyright (C) 2005 Giridhar Pemmasani ++ * ++ * 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 _PNP_H_ ++#define _PNP_H_ ++ ++#include "ntoskernel.h" ++#include "ndis.h" ++#include "wrapndis.h" ++ ++int wrap_pnp_start_pci_device(struct pci_dev *pdev, ++ const struct pci_device_id *ent); ++void wrap_pnp_remove_pci_device(struct pci_dev *pdev); ++int wrap_pnp_suspend_pci_device(struct pci_dev *pdev, pm_message_t state); ++int wrap_pnp_resume_pci_device(struct pci_dev *pdev); ++ ++int wrap_pnp_start_usb_device(struct usb_interface *intf, ++ const struct usb_device_id *usb_id); ++void wrap_pnp_remove_usb_device(struct usb_interface *intf); ++int wrap_pnp_suspend_usb_device(struct usb_interface *intf, ++ pm_message_t state); ++int wrap_pnp_resume_usb_device(struct usb_interface *intf); ++ ++#endif +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/proc.c linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/proc.c +--- linux-3.12.2/3rdparty/ndiswrapper/proc.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/proc.c 2013-11-28 21:42:11.000000000 +0200 +@@ -0,0 +1,588 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * 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 ++#include ++#include ++#include ++ ++#include "ndis.h" ++#include "iw_ndis.h" ++#include "wrapndis.h" ++#include "pnp.h" ++#include "wrapper.h" ++ ++#define MAX_PROC_STR_LEN 32 ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) ++static kuid_t proc_kuid; ++static kgid_t proc_kgid; ++#else ++#define proc_kuid proc_uid ++#define proc_kgid proc_gid ++#define kuid_t uid_t ++#define kgid_t gid_t ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) ++static inline struct inode *file_inode(struct file *f) ++{ ++ return f->f_dentry->d_inode; ++} ++#elif LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0) ++static inline struct inode *file_inode(struct file *f) ++{ ++ return f->f_path.dentry->d_inode; ++} ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) ++static inline void proc_set_user(struct proc_dir_entry *de, kuid_t uid, ++ kgid_t gid) ++{ ++ de->uid = uid; ++ de->gid = gid; ++} ++ ++static inline void proc_remove(struct proc_dir_entry *de) ++{ ++ if (de) ++ remove_proc_entry(de->name, de->parent); ++} ++ ++static inline void *PDE_DATA(const struct inode *inode) ++{ ++ return PDE(inode)->data; ++} ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) ++static inline struct proc_dir_entry *proc_create_data(const char *name, ++ umode_t mode, struct proc_dir_entry *parent, ++ struct file_operations *fops, void *data) ++{ ++ struct proc_dir_entry *de; ++ ++ de = create_proc_entry(name, mode, parent); ++ if (de) { ++ de->data = data; ++ de->proc_fops = fops; ++ } ++ ++ return de; ++} ++#endif ++ ++static int do_proc_make_entry(const char *name, umode_t mode, ++ struct proc_dir_entry *parent, ++ struct file_operations *fops, kuid_t uid, ++ kgid_t gid, struct ndis_device *wnd) ++{ ++ struct proc_dir_entry *de; ++ ++ de = proc_create_data(name, mode, parent, fops, wnd); ++ if (de == NULL) { ++ ERROR("couldn't create proc entry for '%s'", name); ++ return -ENOMEM; ++ } ++ proc_set_user(de, uid, gid); ++ return 0; ++} ++ ++#define PROC_DECLARE_RO(name) \ ++ static int proc_##name##_open(struct inode *inode, struct file *file) \ ++ { \ ++ return single_open(file, proc_##name##_read, PDE_DATA(inode)); \ ++ } \ ++ static struct file_operations name##_fops = { \ ++ .owner = THIS_MODULE, \ ++ .open = proc_##name##_open, \ ++ .read = seq_read, \ ++ .llseek = seq_lseek, \ ++ .release = single_release, \ ++ }; ++ ++#define PROC_DECLARE_RW(name) \ ++ static int proc_##name##_open(struct inode *inode, struct file *file) \ ++ { \ ++ return single_open(file, proc_##name##_read, PDE_DATA(inode)); \ ++ } \ ++ static struct file_operations name##_fops = { \ ++ .owner = THIS_MODULE, \ ++ .open = proc_##name##_open, \ ++ .read = seq_read, \ ++ .llseek = seq_lseek, \ ++ .release = single_release, \ ++ .write = proc_##name##_write, \ ++ }; ++ ++#define proc_make_entry_ro(name, parent, wnd) \ ++ do_proc_make_entry(#name, S_IFREG | S_IRUSR | S_IRGRP, parent, \ ++ &name##_fops, proc_kuid, proc_kgid, wnd) ++#define proc_make_entry_rw(name, parent, wnd) \ ++ do_proc_make_entry(#name, \ ++ S_IFREG | S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP, \ ++ parent, &name##_fops, proc_kuid, proc_kgid, wnd) ++ ++#define add_text(fmt, ...) seq_printf(sf, fmt, ##__VA_ARGS__) ++ ++static struct proc_dir_entry *wrap_procfs_entry; ++ ++static int proc_stats_read(struct seq_file *sf, void *v) ++{ ++ struct ndis_device *wnd = (struct ndis_device *)sf->private; ++ struct ndis_wireless_stats stats; ++ NDIS_STATUS res; ++ ndis_rssi rssi; ++ ++ res = mp_query(wnd, OID_802_11_RSSI, &rssi, sizeof(rssi)); ++ if (!res) ++ add_text("signal_level=%d dBm\n", (s32)rssi); ++ ++ res = mp_query(wnd, OID_802_11_STATISTICS, &stats, sizeof(stats)); ++ if (!res) { ++ add_text("tx_frames=%llu\n", stats.tx_frag); ++ add_text("tx_multicast_frames=%llu\n", stats.tx_multi_frag); ++ add_text("tx_failed=%llu\n", stats.failed); ++ add_text("tx_retry=%llu\n", stats.retry); ++ add_text("tx_multi_retry=%llu\n", stats.multi_retry); ++ add_text("tx_rtss_success=%llu\n", stats.rtss_succ); ++ add_text("tx_rtss_fail=%llu\n", stats.rtss_fail); ++ add_text("ack_fail=%llu\n", stats.ack_fail); ++ add_text("frame_duplicates=%llu\n", stats.frame_dup); ++ add_text("rx_frames=%llu\n", stats.rx_frag); ++ add_text("rx_multicast_frames=%llu\n", stats.rx_multi_frag); ++ add_text("fcs_errors=%llu\n", stats.fcs_err); ++ } ++ ++ return 0; ++} ++ ++PROC_DECLARE_RO(stats) ++ ++static int proc_encr_read(struct seq_file *sf, void *v) ++{ ++ struct ndis_device *wnd = (struct ndis_device *)sf->private; ++ int i, encr_status, auth_mode, infra_mode; ++ NDIS_STATUS res; ++ struct ndis_essid essid; ++ mac_address ap_address; ++ ++ res = mp_query(wnd, OID_802_11_BSSID, ++ &ap_address, sizeof(ap_address)); ++ if (res) ++ memset(ap_address, 0, ETH_ALEN); ++ add_text("ap_address=" MACSTRSEP "\n", MAC2STR(ap_address)); ++ ++ res = mp_query(wnd, OID_802_11_SSID, &essid, sizeof(essid)); ++ if (!res) ++ add_text("essid=%.*s\n", essid.length, essid.essid); ++ ++ res = mp_query_int(wnd, OID_802_11_ENCRYPTION_STATUS, &encr_status); ++ if (!res) { ++ typeof(&wnd->encr_info.keys[0]) tx_key; ++ add_text("tx_key=%u\n", wnd->encr_info.tx_key_index); ++ add_text("key="); ++ tx_key = &wnd->encr_info.keys[wnd->encr_info.tx_key_index]; ++ if (tx_key->length > 0) ++ for (i = 0; i < tx_key->length; i++) ++ add_text("%2.2X", tx_key->key[i]); ++ else ++ add_text("off"); ++ add_text("\n"); ++ add_text("encr_mode=%d\n", encr_status); ++ } ++ res = mp_query_int(wnd, OID_802_11_AUTHENTICATION_MODE, &auth_mode); ++ if (!res) ++ add_text("auth_mode=%d\n", auth_mode); ++ res = mp_query_int(wnd, OID_802_11_INFRASTRUCTURE_MODE, &infra_mode); ++ add_text("mode=%s\n", (infra_mode == Ndis802_11IBSS) ? "adhoc" : ++ (infra_mode == Ndis802_11Infrastructure) ? "managed" : "auto"); ++ ++ return 0; ++} ++ ++PROC_DECLARE_RO(encr) ++ ++static int proc_hw_read(struct seq_file *sf, void *v) ++{ ++ struct ndis_device *wnd = (struct ndis_device *)sf->private; ++ struct ndis_configuration config; ++ enum ndis_power power_mode; ++ NDIS_STATUS res; ++ ndis_tx_power_level tx_power; ++ ULONG bit_rate; ++ ndis_rts_threshold rts_threshold; ++ ndis_fragmentation_threshold frag_threshold; ++ ndis_antenna antenna; ++ ULONG packet_filter; ++ int n; ++ mac_address mac; ++ char *hw_status[] = {"ready", "initializing", "resetting", "closing", ++ "not ready"}; ++ ++ res = mp_query_int(wnd, OID_GEN_HARDWARE_STATUS, &n); ++ if (res == NDIS_STATUS_SUCCESS && n >= 0 && n < ARRAY_SIZE(hw_status)) ++ add_text("status=%s\n", hw_status[n]); ++ ++ res = mp_query(wnd, OID_802_3_CURRENT_ADDRESS, mac, sizeof(mac)); ++ if (!res) ++ add_text("mac: " MACSTRSEP "\n", MAC2STR(mac)); ++ res = mp_query(wnd, OID_802_11_CONFIGURATION, &config, sizeof(config)); ++ if (!res) { ++ add_text("beacon_period=%u msec\n", config.beacon_period); ++ add_text("atim_window=%u msec\n", config.atim_window); ++ add_text("frequency=%u kHz\n", config.ds_config); ++ add_text("hop_pattern=%u\n", config.fh_config.hop_pattern); ++ add_text("hop_set=%u\n", config.fh_config.hop_set); ++ add_text("dwell_time=%u msec\n", config.fh_config.dwell_time); ++ } ++ ++ res = mp_query(wnd, OID_802_11_TX_POWER_LEVEL, ++ &tx_power, sizeof(tx_power)); ++ if (!res) ++ add_text("tx_power=%u mW\n", tx_power); ++ ++ res = mp_query(wnd, OID_GEN_LINK_SPEED, &bit_rate, sizeof(bit_rate)); ++ if (!res) ++ add_text("bit_rate=%u kBps\n", (u32)bit_rate / 10); ++ ++ res = mp_query(wnd, OID_802_11_RTS_THRESHOLD, ++ &rts_threshold, sizeof(rts_threshold)); ++ if (!res) ++ add_text("rts_threshold=%u bytes\n", rts_threshold); ++ ++ res = mp_query(wnd, OID_802_11_FRAGMENTATION_THRESHOLD, ++ &frag_threshold, sizeof(frag_threshold)); ++ if (!res) ++ add_text("frag_threshold=%u bytes\n", frag_threshold); ++ ++ res = mp_query_int(wnd, OID_802_11_POWER_MODE, &power_mode); ++ if (!res) ++ add_text("power_mode=%s\n", ++ (power_mode == NDIS_POWER_OFF) ? "always_on" : ++ (power_mode == NDIS_POWER_MAX) ? "max_savings" : ++ "min_savings"); ++ ++ res = mp_query(wnd, OID_802_11_NUMBER_OF_ANTENNAS, ++ &antenna, sizeof(antenna)); ++ if (!res) ++ add_text("num_antennas=%u\n", antenna); ++ ++ res = mp_query(wnd, OID_802_11_TX_ANTENNA_SELECTED, ++ &antenna, sizeof(antenna)); ++ if (!res) ++ add_text("tx_antenna=%u\n", antenna); ++ ++ res = mp_query(wnd, OID_802_11_RX_ANTENNA_SELECTED, ++ &antenna, sizeof(antenna)); ++ if (!res) ++ add_text("rx_antenna=%u\n", antenna); ++ ++ add_text("encryption_modes=%s%s%s%s%s%s%s\n", ++ test_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr) ? ++ "WEP" : "none", ++ test_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr) ? ++ "; TKIP with WPA" : "", ++ test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ? ++ ", WPA2" : "", ++ test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ? ++ ", WPA2PSK" : "", ++ test_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr) ? ++ "; AES/CCMP with WPA" : "", ++ test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ? ++ ", WPA2" : "", ++ test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ? ++ ", WPA2PSK" : ""); ++ ++ res = mp_query_int(wnd, OID_GEN_CURRENT_PACKET_FILTER, &packet_filter); ++ if (!res) { ++ if (packet_filter != wnd->packet_filter) ++ WARNING("wrong packet_filter? 0x%08x, 0x%08x\n", ++ packet_filter, wnd->packet_filter); ++ add_text("packet_filter: 0x%08x\n", packet_filter); ++ } ++ ++ return 0; ++} ++ ++PROC_DECLARE_RO(hw) ++ ++static int proc_settings_read(struct seq_file *sf, void *v) ++{ ++ struct ndis_device *wnd = (struct ndis_device *)sf->private; ++ struct wrap_device_setting *setting; ++ ++ add_text("hangcheck_interval=%d\n", (hangcheck_interval == 0) ? ++ (wnd->hangcheck_interval / HZ) : -1); ++ ++ list_for_each_entry(setting, &wnd->wd->settings, list) { ++ add_text("%s=%s\n", setting->name, setting->value); ++ } ++ ++ list_for_each_entry(setting, &wnd->wd->driver->settings, list) { ++ add_text("%s=%s\n", setting->name, setting->value); ++ } ++ ++ return 0; ++} ++ ++static ssize_t proc_settings_write(struct file *file, const char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ndis_device *wnd = PDE_DATA(file_inode(file)); ++ char setting[MAX_PROC_STR_LEN], *p; ++ unsigned int i; ++ NDIS_STATUS res; ++ ++ if (count > MAX_PROC_STR_LEN) ++ return -EINVAL; ++ ++ memset(setting, 0, sizeof(setting)); ++ if (copy_from_user(setting, buf, count)) ++ return -EFAULT; ++ ++ if ((p = strchr(setting, '\n'))) ++ *p = 0; ++ ++ if ((p = strchr(setting, '='))) ++ *p = 0; ++ ++ if (!strcmp(setting, "hangcheck_interval")) { ++ if (!p) ++ return -EINVAL; ++ p++; ++ i = simple_strtol(p, NULL, 10); ++ hangcheck_del(wnd); ++ if (i > 0) { ++ wnd->hangcheck_interval = i * HZ; ++ hangcheck_add(wnd); ++ } ++ } else if (!strcmp(setting, "suspend")) { ++ if (!p) ++ return -EINVAL; ++ p++; ++ i = simple_strtol(p, NULL, 10); ++ if (i <= 0 || i > 3) ++ return -EINVAL; ++ i = -1; ++ if (wrap_is_pci_bus(wnd->wd->dev_bus)) ++ i = wrap_pnp_suspend_pci_device(wnd->wd->pci.pdev, ++ PMSG_SUSPEND); ++ else if (wrap_is_usb_bus(wnd->wd->dev_bus)) ++ i = wrap_pnp_suspend_usb_device(wnd->wd->usb.intf, ++ PMSG_SUSPEND); ++ if (i) ++ return -EINVAL; ++ } else if (!strcmp(setting, "resume")) { ++ i = -1; ++ if (wrap_is_pci_bus(wnd->wd->dev_bus)) ++ i = wrap_pnp_resume_pci_device(wnd->wd->pci.pdev); ++ else if (wrap_is_usb_bus(wnd->wd->dev_bus)) ++ i = wrap_pnp_resume_usb_device(wnd->wd->usb.intf); ++ if (i) ++ return -EINVAL; ++ } else if (!strcmp(setting, "stats_enabled")) { ++ if (!p) ++ return -EINVAL; ++ p++; ++ i = simple_strtol(p, NULL, 10); ++ if (i > 0) ++ wnd->iw_stats_enabled = TRUE; ++ else ++ wnd->iw_stats_enabled = FALSE; ++ } else if (!strcmp(setting, "packet_filter")) { ++ if (!p) ++ return -EINVAL; ++ p++; ++ i = simple_strtol(p, NULL, 10); ++ res = mp_set_int(wnd, OID_GEN_CURRENT_PACKET_FILTER, i); ++ if (res) ++ WARNING("setting packet_filter failed: %08X", res); ++ } else if (!strcmp(setting, "reinit")) { ++ if (ndis_reinit(wnd) != NDIS_STATUS_SUCCESS) ++ return -EFAULT; ++ } else { ++ struct ndis_configuration_parameter param; ++ struct unicode_string key; ++ struct ansi_string ansi; ++ ++ if (!p) ++ return -EINVAL; ++ p++; ++ RtlInitAnsiString(&ansi, p); ++ if (RtlAnsiStringToUnicodeString(¶m.data.string, &ansi, ++ TRUE) != STATUS_SUCCESS) ++ EXIT1(return -EFAULT); ++ param.type = NdisParameterString; ++ RtlInitAnsiString(&ansi, setting); ++ if (RtlAnsiStringToUnicodeString(&key, &ansi, ++ TRUE) != STATUS_SUCCESS) { ++ RtlFreeUnicodeString(¶m.data.string); ++ EXIT1(return -EINVAL); ++ } ++ NdisWriteConfiguration(&res, wnd->nmb, &key, ¶m); ++ RtlFreeUnicodeString(&key); ++ RtlFreeUnicodeString(¶m.data.string); ++ if (res != NDIS_STATUS_SUCCESS) ++ return -EFAULT; ++ } ++ return count; ++} ++ ++PROC_DECLARE_RW(settings) ++ ++int wrap_procfs_add_ndis_device(struct ndis_device *wnd) ++{ ++ int ret; ++ ++ if (wrap_procfs_entry == NULL) ++ return -ENOMEM; ++ ++ if (wnd->procfs_iface) { ++ ERROR("%s already registered?", wnd->net_dev->name); ++ return -EINVAL; ++ } ++ wnd->procfs_iface = proc_mkdir(wnd->net_dev->name, wrap_procfs_entry); ++ if (wnd->procfs_iface == NULL) { ++ ERROR("couldn't create proc directory"); ++ return -ENOMEM; ++ } ++ proc_set_user(wnd->procfs_iface, proc_kuid, proc_kgid); ++ ++ ret = proc_make_entry_ro(hw, wnd->procfs_iface, wnd); ++ if (ret) ++ goto err_hw; ++ ++ ret = proc_make_entry_ro(stats, wnd->procfs_iface, wnd); ++ if (ret) ++ goto err_stats; ++ ++ ret = proc_make_entry_ro(encr, wnd->procfs_iface, wnd); ++ if (ret) ++ goto err_encr; ++ ++ ret = proc_make_entry_rw(settings, wnd->procfs_iface, wnd); ++ if (ret) ++ goto err_settings; ++ ++ return 0; ++ ++err_settings: ++ remove_proc_entry("encr", wnd->procfs_iface); ++err_encr: ++ remove_proc_entry("stats", wnd->procfs_iface); ++err_stats: ++ remove_proc_entry("hw", wnd->procfs_iface); ++err_hw: ++ proc_remove(wnd->procfs_iface); ++ wnd->procfs_iface = NULL; ++ return -ENOMEM; ++} ++ ++void wrap_procfs_remove_ndis_device(struct ndis_device *wnd) ++{ ++ struct proc_dir_entry *procfs_iface = xchg(&wnd->procfs_iface, NULL); ++ ++ if (procfs_iface == NULL) ++ return; ++ remove_proc_entry("hw", procfs_iface); ++ remove_proc_entry("stats", procfs_iface); ++ remove_proc_entry("encr", procfs_iface); ++ remove_proc_entry("settings", procfs_iface); ++ if (wrap_procfs_entry) ++ proc_remove(procfs_iface); ++} ++ ++static int proc_debug_read(struct seq_file *sf, void *v) ++{ ++#if ALLOC_DEBUG ++ enum alloc_type type; ++#endif ++ ++ add_text("%d\n", debug); ++#if ALLOC_DEBUG ++ for (type = 0; type < ALLOC_TYPE_MAX; type++) ++ add_text("total size of allocations in %s: %d\n", ++ alloc_type_name[type], alloc_size(type)); ++#endif ++ return 0; ++} ++ ++static ssize_t proc_debug_write(struct file *file, const char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ int i; ++ char setting[MAX_PROC_STR_LEN], *p; ++ ++ if (count > MAX_PROC_STR_LEN) ++ return -EINVAL; ++ ++ memset(setting, 0, sizeof(setting)); ++ if (copy_from_user(setting, buf, count)) ++ return -EFAULT; ++ ++ if ((p = strchr(setting, '\n'))) ++ *p = 0; ++ ++ if ((p = strchr(setting, '='))) ++ *p = 0; ++ ++ i = simple_strtol(setting, NULL, 10); ++ if (i >= 0 && i < 10) ++ debug = i; ++ else ++ return -EINVAL; ++ return count; ++} ++ ++PROC_DECLARE_RW(debug) ++ ++int wrap_procfs_init(void) ++{ ++ int ret; ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,5,0) ++ struct user_namespace *ns = current_user_ns(); ++ proc_kuid = make_kuid(ns, proc_uid); ++ if (!uid_valid(proc_kuid)) { ++ ERROR("invalid UID\n"); ++ return -EINVAL; ++ } ++ proc_kgid = make_kgid(ns, proc_gid); ++ if (!gid_valid(proc_kgid)) { ++ ERROR("invalid GID\n"); ++ return -EINVAL; ++ } ++#endif ++ ++ wrap_procfs_entry = proc_mkdir(DRIVER_NAME, proc_net_root); ++ if (wrap_procfs_entry == NULL) { ++ ERROR("couldn't create procfs directory"); ++ return -ENOMEM; ++ } ++ proc_set_user(wrap_procfs_entry, proc_kuid, proc_kgid); ++ ++ ret = proc_make_entry_rw(debug, wrap_procfs_entry, NULL); ++ ++ return ret; ++} ++ ++void wrap_procfs_remove(void) ++{ ++ if (wrap_procfs_entry == NULL) ++ return; ++ remove_proc_entry("debug", wrap_procfs_entry); ++ proc_remove(wrap_procfs_entry); ++} +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/rtl.c linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/rtl.c +--- linux-3.12.2/3rdparty/ndiswrapper/rtl.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/rtl.c 2013-11-28 21:42:11.000000000 +0200 +@@ -0,0 +1,715 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * Copyright (C) 2006-2007 Giridhar Pemmasani ++ * ++ * 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 "ntoskernel.h" ++#include "rtl_exports.h" ++ ++wstdcall SIZE_T WIN_FUNC(RtlCompareMemory,3) ++ (const void *a, const void *b, SIZE_T len) ++{ ++ size_t i; ++ char *x, *y; ++ ++ ENTER1("%p %p %zd", a, b, len); ++ x = (char *)a; ++ y = (char *)b; ++ /* MSDN says this should return number of bytes that compare as ++ * equal. This can be interpreted as either all bytes that are ++ * equal in 'len' bytes or that only until the bytes compare as ++ * not equal. Initially we had it the former way, but Realtek driver ++ * doesn't like it that way - it takes many attempts to associate ++ * with WPA. ReactOS returns the number of bytes that are equal ++ * before the first differing byte. ++ * According to lords at #reactos, that is the way it should be ++ * and that msdn is wrong about it! ++ */ ++ for (i = 0; i < len && x[i] == y[i]; i++) ++ ; ++ return i; ++} ++ ++wstdcall void WIN_FUNC(RtlCopyMemory,3) ++ (void *dst, const void *src, SIZE_T length) ++{ ++ memcpy(dst, src, length); ++} ++ ++wstdcall void WIN_FUNC(RtlZeroMemory,2) ++ (void *dst, SIZE_T length) ++{ ++ memset(dst, 0, length); ++} ++ ++wstdcall void WIN_FUNC(RtlSecureZeroMemory,2) ++ (void *dst, SIZE_T length) ++{ ++ memset(dst, 0, length); ++} ++ ++wstdcall void WIN_FUNC(RtlFillMemory,3) ++ (void *dest, SIZE_T length, UCHAR fill) ++{ ++ memset(dest, fill, length); ++} ++ ++wstdcall void WIN_FUNC(RtlMoveMemory,3) ++ (void *dest, const void *src, SIZE_T length) ++{ ++ memmove(dest, src, length); ++} ++ ++wstdcall LONG WIN_FUNC(RtlCompareString,3) ++ (const struct ansi_string *s1, const struct ansi_string *s2, ++ BOOLEAN case_insensitive) ++{ ++ unsigned int len; ++ LONG ret = 0; ++ const char *p1, *p2; ++ ++ ENTER2(""); ++ len = min(s1->length, s2->length); ++ p1 = s1->buf; ++ p2 = s2->buf; ++ if (case_insensitive) ++ while (!ret && len--) ++ ret = toupper(*p1++) - toupper(*p2++); ++ else ++ while (!ret && len--) ++ ret = *p1++ - *p2++; ++ if (!ret) ++ ret = s1->length - s2->length; ++ EXIT2(return ret); ++} ++ ++wstdcall LONG WIN_FUNC(RtlCompareUnicodeString,3) ++ (const struct unicode_string *s1, const struct unicode_string *s2, ++ BOOLEAN case_insensitive) ++{ ++ unsigned int len; ++ LONG ret = 0; ++ const wchar_t *p1, *p2; ++ ++ ENTER2(""); ++ ++ len = min(s1->length, s2->length) / sizeof(wchar_t); ++ p1 = s1->buf; ++ p2 = s2->buf; ++ if (case_insensitive) ++ while (!ret && len--) ++ ret = toupper((u8)*p1++) - toupper((u8)*p2++); ++ else ++ while (!ret && len--) ++ ret = (u8)*p1++ - (u8)*p2++; ++ if (!ret) ++ ret = s1->length - s2->length; ++ TRACE2("len: %d, ret: %d", len, ret); ++ EXIT2(return ret); ++} ++ ++wstdcall BOOLEAN WIN_FUNC(RtlEqualString,3) ++ (const struct ansi_string *s1, const struct ansi_string *s2, ++ BOOLEAN case_insensitive) ++{ ++ ENTER1(""); ++ if (s1->length != s2->length) ++ return FALSE; ++ return !RtlCompareString(s1, s2, case_insensitive); ++} ++ ++wstdcall BOOLEAN WIN_FUNC(RtlEqualUnicodeString,3) ++ (const struct unicode_string *s1, const struct unicode_string *s2, ++ BOOLEAN case_insensitive) ++{ ++ if (s1->length != s2->length) ++ return FALSE; ++ return !RtlCompareUnicodeString(s1, s2, case_insensitive); ++} ++ ++wstdcall void WIN_FUNC(RtlCopyUnicodeString,2) ++ (struct unicode_string *dst, struct unicode_string *src) ++{ ++ ENTER1("%p, %p", dst, src); ++ if (src && src->buf && dst->buf) { ++ dst->length = min(src->length, dst->max_length); ++ memcpy(dst->buf, src->buf, dst->length); ++ if (dst->length < dst->max_length) ++ dst->buf[dst->length / sizeof(dst->buf[0])] = 0; ++ } else ++ dst->length = 0; ++ EXIT1(return); ++} ++ ++wstdcall void WIN_FUNC(RtlCopyString,2) ++ (struct ansi_string *dst, struct ansi_string *src) ++{ ++ ENTER1("%p, %p", dst, src); ++ if (src && src->buf && dst->buf) { ++ dst->length = min(src->length, dst->max_length); ++ memcpy(dst->buf, src->buf, dst->length); ++ if (dst->length < dst->max_length) ++ dst->buf[dst->length] = 0; ++ } else ++ dst->length = 0; ++ EXIT1(return); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(RtlAppendUnicodeToString,2) ++ (struct unicode_string *dst, wchar_t *src) ++{ ++ if (src) { ++ int len; ++ for (len = 0; src[len]; len++) ++ ; ++ if (dst->length + (len * sizeof(dst->buf[0])) > dst->max_length) ++ return STATUS_BUFFER_TOO_SMALL; ++ memcpy(&dst->buf[dst->length], src, len * sizeof(dst->buf[0])); ++ dst->length += len * sizeof(dst->buf[0]); ++ if (dst->max_length > dst->length) ++ dst->buf[dst->length / sizeof(dst->buf[0])] = 0; ++ } ++ return STATUS_SUCCESS; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(RtlAppendUnicodeStringToString,2) ++ (struct unicode_string *dst, struct unicode_string *src) ++{ ++ if (dst->max_length < src->length + dst->length) ++ return STATUS_BUFFER_TOO_SMALL; ++ if (src->length) { ++ memcpy(&dst->buf[dst->length], src->buf, src->length); ++ dst->length += src->length; ++ if (dst->max_length > dst->length) ++ dst->buf[dst->length / sizeof(dst->buf[0])] = 0; ++ } ++ EXIT2(return STATUS_SUCCESS); ++} ++ ++wstdcall ULONG WIN_FUNC(RtlxAnsiStringToUnicodeSize,1) ++ (const struct ansi_string *string) ++{ ++ int i; ++ ++ for (i = 0; i < string->max_length && string->buf[i]; i++) ++ ; ++ return i * sizeof(wchar_t); ++} ++ ++wstdcall ULONG WIN_FUNC(RtlxUnicodeStringToAnsiSize,1) ++ (const struct unicode_string *string) ++{ ++ int i; ++ ++ for (i = 0; i < string->max_length && string->buf[i]; i++) ++ ; ++ return i; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(RtlAnsiStringToUnicodeString,3) ++ (struct unicode_string *dst, const struct ansi_string *src, ++ BOOLEAN alloc) ++{ ++ int i, n; ++ ++ n = RtlxAnsiStringToUnicodeSize(src); ++ TRACE2("%d, %d, %d, %d, %p", n, dst->max_length, src->length, ++ src->max_length, src->buf); ++ if (alloc == TRUE) { ++#if 0 ++ if (n == 0) { ++ dst->length = dst->max_length = 0; ++ dst->buf = NULL; ++ EXIT2(return STATUS_SUCCESS); ++ } ++#endif ++ dst->max_length = n + sizeof(dst->buf[0]); ++ dst->buf = ExAllocatePoolWithTag(NonPagedPool, ++ dst->max_length, 0); ++ if (!dst->buf) { ++ dst->max_length = dst->length = 0; ++ EXIT2(return STATUS_NO_MEMORY); ++ } ++ } else if (dst->max_length < n) ++ EXIT2(return STATUS_BUFFER_TOO_SMALL); ++ ++ dst->length = n; ++ n /= sizeof(dst->buf[0]); ++ for (i = 0; i < n; i++) ++ dst->buf[i] = src->buf[i]; ++ if (i * sizeof(dst->buf[0]) < dst->max_length) ++ dst->buf[i] = 0; ++ TRACE2("dst: length: %d, max_length: %d, string: %p", ++ dst->length, dst->max_length, src->buf); ++ EXIT2(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(RtlUnicodeStringToAnsiString,3) ++ (struct ansi_string *dst, const struct unicode_string *src, ++ BOOLEAN alloc) ++{ ++ int i, n; ++ ++ n = RtlxUnicodeStringToAnsiSize(src); ++ TRACE2("%d, %d, %d, %d, %p", n, dst->max_length, src->length, ++ src->max_length, src->buf); ++ if (alloc == TRUE) { ++#if 0 ++ if (n == 0) { ++ dst->length = dst->max_length = 0; ++ dst->buf = NULL; ++ EXIT2(return STATUS_SUCCESS); ++ } ++#endif ++ dst->max_length = n + sizeof(dst->buf[0]); ++ dst->buf = ExAllocatePoolWithTag(NonPagedPool, ++ dst->max_length, 0); ++ if (!dst->buf) { ++ dst->max_length = dst->length = 0; ++ EXIT1(return STATUS_NO_MEMORY); ++ } ++ } else if (dst->max_length < n) ++ EXIT2(return STATUS_BUFFER_TOO_SMALL); ++ ++ dst->length = n; ++ for (i = 0; i < n; i++) ++ dst->buf[i] = src->buf[i]; ++ if (i < dst->max_length) ++ dst->buf[i] = 0; ++ TRACE2("string: %p, len: %d(%d)", dst->buf, dst->length, ++ dst->max_length); ++ EXIT2(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(RtlUnicodeStringToInteger,3) ++ (struct unicode_string *ustring, ULONG base, ULONG *value) ++{ ++ int i, sign = 1; ++ ULONG res; ++ typeof(ustring->buf) string; ++ ++ if (ustring->length == 0) { ++ *value = 0; ++ return STATUS_SUCCESS; ++ } ++ ++ string = ustring->buf; ++ i = 0; ++ while (i < (ustring->length / sizeof(*string)) && string[i] == ' ') ++ i++; ++ if (string[i] == '+') ++ i++; ++ else if (string[i] == '-') { ++ i++; ++ sign = -1; ++ } ++ if (base == 0) { ++ base = 10; ++ if (i <= ((ustring->length / sizeof(*string)) - 2) && ++ string[i] == '0') { ++ i++; ++ if (string[i] == 'b') { ++ base = 2; ++ i++; ++ } else if (string[i] == 'o') { ++ base = 8; ++ i++; ++ } else if (string[i] == 'x') { ++ base = 16; ++ i++; ++ } ++ } ++ } ++ if (!(base == 2 || base == 8 || base == 10 || base == 16)) ++ EXIT2(return STATUS_INVALID_PARAMETER); ++ ++ for (res = 0; i < (ustring->length / sizeof(*string)); i++) { ++ int v; ++ if (isdigit((char)string[i])) ++ v = string[i] - '0'; ++ else if (isxdigit((char)string[i])) ++ v = tolower((char)string[i]) - 'a' + 10; ++ else ++ v = base; ++ if (v >= base) ++ EXIT2(return STATUS_INVALID_PARAMETER); ++ res = res * base + v; ++ } ++ *value = sign * res; ++ EXIT3(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(RtlCharToInteger,3) ++ (const char *string, ULONG base, ULONG *value) ++{ ++ int sign = 1; ++ ULONG res; ++ ++ if (!string || !value) ++ EXIT2(return STATUS_INVALID_PARAMETER); ++ while (*string == ' ') ++ string++; ++ if (*string == '+') ++ string++; ++ else if (*string == '-') { ++ string++; ++ sign = -1; ++ } ++ if (base == 0) { ++ base = 10; ++ if (*string == '0') { ++ string++; ++ if (*string == 'b') { ++ base = 2; ++ string++; ++ } else if (*string == 'o') { ++ base = 8; ++ string++; ++ } else if (*string == 'x') { ++ base = 16; ++ string++; ++ } ++ } ++ } ++ if (!(base == 2 || base == 8 || base == 10 || base == 16)) ++ EXIT2(return STATUS_INVALID_PARAMETER); ++ ++ for (res = 0; *string; string++) { ++ int v; ++ if (isdigit(*string)) ++ v = *string - '0'; ++ else if (isxdigit(*string)) ++ v = tolower(*string) - 'a' + 10; ++ else ++ v = base; ++ if (v >= base) ++ EXIT2(return STATUS_INVALID_PARAMETER); ++ res = res * base + v; ++ } ++ *value = sign * res; ++ EXIT3(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(RtlIntegerToUnicodeString,3) ++ (ULONG value, ULONG base, struct unicode_string *ustring) ++{ ++ typeof(ustring->buf) buf = ustring->buf; ++ int i; ++ ++ if (base == 0) ++ base = 10; ++ if (!(base == 2 || base == 8 || base == 10 || base == 16)) ++ return STATUS_INVALID_PARAMETER; ++ for (i = 0; value && i < ustring->max_length / sizeof(*buf); i++) { ++ int r; ++ r = value % base; ++ value /= base; ++ if (r < 10) ++ buf[i] = r + '0'; ++ else ++ buf[i] = r + 'a' - 10; ++ } ++ if (value) ++ return STATUS_BUFFER_OVERFLOW; ++ ustring->length = i * sizeof(*buf); ++ return STATUS_SUCCESS; ++} ++ ++wstdcall LARGE_INTEGER WIN_FUNC(RtlConvertUlongToLargeInteger,1) ++ (ULONG ul) ++{ ++ LARGE_INTEGER li = ul; ++ return li; ++} ++ ++wfastcall USHORT WIN_FUNC(RtlUshortByteSwap,1) ++ (USHORT src) ++{ ++ return __swab16(src); ++} ++ ++wfastcall ULONG WIN_FUNC(RtlUlongByteSwap,1) ++ (ULONG src) ++{ ++ /* ULONG is 32 bits for both 32-bit and 64-bit architectures */ ++ return __swab32(src); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(RtlUpcaseUnicodeString,3) ++ (struct unicode_string *dst, struct unicode_string *src, BOOLEAN alloc) ++{ ++ USHORT i, n; ++ ++ if (alloc) { ++ dst->buf = ExAllocatePoolWithTag(NonPagedPool, src->length, 0); ++ if (dst->buf) ++ dst->max_length = src->length; ++ else ++ EXIT2(return STATUS_NO_MEMORY); ++ } else { ++ if (dst->max_length < src->length) ++ EXIT2(return STATUS_BUFFER_OVERFLOW); ++ } ++ ++ n = src->length / sizeof(src->buf[0]); ++ for (i = 0; i < n; i++) ++ dst->buf[i] = toupper(src->buf[i]); ++ ++ dst->length = src->length; ++ EXIT3(return STATUS_SUCCESS); ++} ++ ++wstdcall void WIN_FUNC(RtlInitUnicodeString,2) ++ (struct unicode_string *dst, const wchar_t *src) ++{ ++ ENTER2("%p", dst); ++ if (dst == NULL) ++ EXIT1(return); ++ if (src == NULL) { ++ dst->max_length = dst->length = 0; ++ dst->buf = NULL; ++ } else { ++ int i; ++ for (i = 0; (char)src[i]; i++) ++ ; ++ dst->buf = (typeof(dst->buf))src; ++ dst->length = i * sizeof(dst->buf[0]); ++ dst->max_length = (i + 1) * sizeof(dst->buf[0]); ++ } ++ EXIT1(return); ++} ++ ++wstdcall void WIN_FUNC(RtlInitAnsiString,2) ++ (struct ansi_string *dst, const char *src) ++{ ++ ENTER2("%p", dst); ++ if (dst == NULL) ++ EXIT2(return); ++ if (src == NULL) { ++ dst->max_length = dst->length = 0; ++ dst->buf = NULL; ++ } else { ++ int i; ++ for (i = 0; src[i]; i++) ++ ; ++ dst->buf = (typeof(dst->buf))src; ++ dst->length = i; ++ dst->max_length = i + 1; ++ } ++ TRACE2("%p", dst->buf); ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(RtlInitString,2) ++ (struct ansi_string *dst, const char *src) ++{ ++ ENTER2("%p", dst); ++ RtlInitAnsiString(dst, src); ++ EXIT2(return); ++} ++ ++wstdcall void WIN_FUNC(RtlFreeUnicodeString,1) ++ (struct unicode_string *string) ++{ ++ ENTER2("%p", string); ++ if (string == NULL) ++ return; ++ if (string->buf) ++ ExFreePool(string->buf); ++ string->length = string->max_length = 0; ++ string->buf = NULL; ++ return; ++} ++ ++wstdcall void WIN_FUNC(RtlFreeAnsiString,1) ++ (struct ansi_string *string) ++{ ++ ENTER2("%p", string); ++ if (string == NULL) ++ return; ++ if (string->buf) ++ ExFreePool(string->buf); ++ string->length = string->max_length = 0; ++ string->buf = NULL; ++ return; ++} ++ ++/* guid string is of the form: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */ ++wstdcall NTSTATUS WIN_FUNC(RtlGUIDFromString,2) ++ (struct unicode_string *guid_string, struct guid *guid) ++{ ++ struct ansi_string ansi; ++ NTSTATUS ret; ++ int i, j, k, l, m; ++ ++ ret = RtlUnicodeStringToAnsiString(&ansi, guid_string, TRUE); ++ if (ret != STATUS_SUCCESS) ++ return ret; ++ if (ansi.length != 37 || ansi.buf[0] != '{' || ++ ansi.buf[36] != '}' || ansi.buf[9] != '-' || ++ ansi.buf[14] != '-' || ansi.buf[19] != '-' || ++ ansi.buf[24] != '-') { ++ RtlFreeAnsiString(&ansi); ++ EXIT2(return STATUS_INVALID_PARAMETER); ++ } ++ memcpy(&guid->data4, &ansi.buf[29], sizeof(guid->data3)); ++ /* set end of data3 for scanf */ ++ ansi.buf[29] = 0; ++ if (sscanf(&ansi.buf[1], "%x", &i) == 1 && ++ sscanf(&ansi.buf[10], "%x", &j) == 1 && ++ sscanf(&ansi.buf[15], "%x", &k) == 1 && ++ sscanf(&ansi.buf[20], "%x", &l) == 1 && ++ sscanf(&ansi.buf[25], "%x", &m) == 1) { ++ guid->data1 = (i << 16) | (j < 8) | k; ++ guid->data2 = l; ++ guid->data3 = m; ++ ret = STATUS_SUCCESS; ++ } else ++ ret = STATUS_INVALID_PARAMETER; ++ RtlFreeAnsiString(&ansi); ++ return ret; ++} ++ ++wstdcall NTSTATUS WIN_FUNC(RtlQueryRegistryValues,5) ++ (ULONG relative, wchar_t *path, struct rtl_query_registry_table *tbl, ++ void *context, void *env) ++{ ++ struct ansi_string ansi; ++ struct unicode_string unicode; ++ NTSTATUS status, ret; ++ static int i = 0; ++ ++ ENTER3("%x, %p", relative, tbl); ++// TODO(); ++ ++ RtlInitUnicodeString(&unicode, path); ++ if (RtlUnicodeStringToAnsiString(&ansi, &unicode, TRUE) == ++ STATUS_SUCCESS) { ++ TRACE2("%s", ansi.buf); ++ RtlFreeAnsiString(&ansi); ++ } ++ ret = STATUS_SUCCESS; ++ for (; tbl->name; tbl++) { ++ RtlInitUnicodeString(&unicode, tbl->name); ++ if (RtlUnicodeStringToAnsiString(&ansi, &unicode, TRUE) == ++ STATUS_SUCCESS) { ++ TRACE2("name: %s", ansi.buf); ++ RtlFreeAnsiString(&ansi); ++ } ++ TRACE2("flags: %08X", tbl->flags); ++ if (tbl->flags == RTL_QUERY_REGISTRY_DIRECT) { ++ TRACE2("type: %08X", tbl->def_type); ++ if (tbl->def_type == REG_DWORD) { ++ /* Atheros USB driver needs this, but ++ * don't know where and how to get its ++ * value */ ++ if (tbl->def_data) { ++ TRACE2("def_data: %x", ++ *(int *)tbl->def_data); ++ *(DWORD *)tbl->context = 0x5f292a + i++; ++// *(DWORD *)tbl->def_data; ++ } else ++ *(DWORD *)tbl->context = 0x2345dbe; ++ } ++ } else { ++ void *data; ++ ULONG type, length; ++ ++ if (!tbl->query_func) { ++ ERROR("oops: no query_func"); ++ ret = STATUS_INVALID_PARAMETER; ++ break; ++ } ++ if (tbl->flags & RTL_QUERY_REGISTRY_NOVALUE) { ++ data = NULL; ++ type = REG_NONE; ++ length = 0; ++ } else { ++ data = tbl->def_data; ++ type = tbl->def_type; ++ length = tbl->def_length;; ++ } ++ TRACE2("calling query_func: %p", tbl->query_func); ++ status = LIN2WIN6(tbl->query_func, tbl->name, type, ++ data, length, context, env); ++ TRACE2("status: %08X", status); ++ if (status) { ++ if (status == STATUS_BUFFER_TOO_SMALL) ++ ret = STATUS_BUFFER_TOO_SMALL; ++ else ++ EXIT2(return STATUS_INVALID_PARAMETER); ++ } ++ } ++ } ++ EXIT3(return ret); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(RtlWriteRegistryValue,6) ++ (ULONG relative, wchar_t *path, wchar_t *name, ULONG type, ++ void *data, ULONG length) ++{ ++ struct ansi_string ansi; ++ struct unicode_string unicode; ++ ++ ENTER3("%d", relative); ++ TODO(); ++ ++ RtlInitUnicodeString(&unicode, path); ++ if (RtlUnicodeStringToAnsiString(&ansi, &unicode, TRUE) == ++ STATUS_SUCCESS) { ++ TRACE2("%s", ansi.buf); ++ RtlFreeAnsiString(&ansi); ++ } ++ RtlInitUnicodeString(&unicode, name); ++ if (RtlUnicodeStringToAnsiString(&ansi, &unicode, TRUE) == ++ STATUS_SUCCESS) { ++ TRACE2("%s", ansi.buf); ++ RtlFreeAnsiString(&ansi); ++ } ++ EXIT5(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS WIN_FUNC(RtlDeleteRegistryValue,3) ++ (ULONG relative, wchar_t *path, wchar_t *name) ++{ ++ return STATUS_SUCCESS; ++} ++ ++wstdcall void WIN_FUNC(RtlAssert,4) ++ (char *failed_assertion, char *file_name, ULONG line_num, char *message) ++{ ++ ERROR("assertion '%s' failed at %s line %d%s", ++ failed_assertion, file_name, line_num, message ? message : ""); ++ return; ++} ++ ++wstdcall void WIN_FUNC(RtlUnwind,0) ++ (void) ++{ ++ TODO(); ++} ++ ++wstdcall void WIN_FUNC(RtlRaiseException,1) ++ (void *exception_record) ++{ ++ TODO(); ++} ++ ++wstdcall BOOLEAN WIN_FUNC(RtlIsServicePackVersionInstalled,1) ++ (ULONG version) ++{ ++ /* Assume we have all service packs */ ++ TRACE1("version: %d", version); ++ return TRUE; ++} +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/usb.c linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/usb.c +--- linux-3.12.2/3rdparty/ndiswrapper/usb.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/usb.c 2013-11-28 21:42:11.000000000 +0200 +@@ -0,0 +1,1496 @@ ++/* ++ * Copyright (C) 2004 Jan Kiszka ++ * Copyright (C) 2005 Giridhar Pemmasani ++ * ++ * 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 "ndis.h" ++#include "usb.h" ++#include "usb_exports.h" ++ ++#ifdef USB_DEBUG ++static unsigned int urb_id = 0; ++ ++#define DUMP_WRAP_URB(wrap_urb, dir) \ ++ USBTRACE("urb %p (%d) %s: buf: %p, len: %d, pipe: 0x%x, %d", \ ++ (wrap_urb)->urb, (wrap_urb)->id, \ ++ (dir == USB_DIR_OUT) ? "going down" : "coming back", \ ++ (wrap_urb)->urb->transfer_buffer, \ ++ (wrap_urb)->urb->transfer_buffer_length, \ ++ (wrap_urb)->urb->pipe, (wrap_urb)->urb->status) ++ ++#define DUMP_URB_BUFFER(urb, dir) \ ++ while (debug >= 2) { \ ++ int i; \ ++ char msg[20], *t; \ ++ if (!urb->transfer_buffer) \ ++ break; \ ++ if (!((usb_pipein(urb->pipe) && dir == USB_DIR_IN) || \ ++ (usb_pipeout(urb->pipe) && dir == USB_DIR_OUT))) \ ++ break; \ ++ t = msg; \ ++ t += sprintf(t, "%d: ", (urb)->actual_length); \ ++ for (i = 0; i < urb->actual_length && \ ++ t < &msg[sizeof(msg) - 4]; i++) \ ++ t += sprintf(t, "%02X ", \ ++ ((char *)urb->transfer_buffer)[i]); \ ++ *t = 0; \ ++ USBTRACE("%s", msg); \ ++ break; \ ++ } ++ ++#else ++ ++#define DUMP_WRAP_URB(wrap_urb, dir) (void)0 ++#define DUMP_URB_BUFFER(urb, dir) (void)0 ++ ++#endif ++ ++#define CUR_ALT_SETTING(intf) (intf)->cur_altsetting ++ ++#ifndef USB_CTRL_SET_TIMEOUT ++#define USB_CTRL_SET_TIMEOUT 5000 ++#endif ++ ++#ifndef USB_CTRL_GET_TIMEOUT ++#define USB_CTRL_GET_TIMEOUT 5000 ++#endif ++ ++#ifndef URB_NO_TRANSFER_DMA_MAP ++#define URB_NO_TRANSFER_DMA_MAP 0 ++#endif ++ ++/* wrap_urb->flags */ ++/* transfer_buffer for urb is allocated; free it in wrap_free_urb */ ++#define WRAP_URB_COPY_BUFFER 0x01 ++ ++static inline int wrap_cancel_urb(struct wrap_urb *wrap_urb) ++{ ++ int ret; ++ USBTRACE("%p, %p, %d", wrap_urb, wrap_urb->urb, wrap_urb->state); ++ if (wrap_urb->state != URB_SUBMITTED) ++ USBEXIT(return -1); ++ ret = usb_unlink_urb(wrap_urb->urb); ++ USBTRACE("ret: %d", ret); ++ if (ret == -EINPROGRESS) ++ return 0; ++ else { ++ WARNING("unlink failed: %d", ret); ++ return ret; ++ } ++} ++ ++#define URB_STATUS(wrap_urb) (wrap_urb->urb->status) ++ ++static struct nt_list wrap_urb_complete_list; ++static spinlock_t wrap_urb_complete_list_lock; ++ ++static struct work_struct wrap_urb_complete_work; ++static void wrap_urb_complete_worker(struct work_struct *dummy); ++ ++static void kill_all_urbs(struct wrap_device *wd, int complete) ++{ ++ struct nt_list *ent; ++ struct wrap_urb *wrap_urb; ++ KIRQL irql; ++ ++ USBTRACE("%d", wd->usb.num_alloc_urbs); ++ while (1) { ++ IoAcquireCancelSpinLock(&irql); ++ ent = RemoveHeadList(&wd->usb.wrap_urb_list); ++ IoReleaseCancelSpinLock(irql); ++ if (!ent) ++ break; ++ wrap_urb = container_of(ent, struct wrap_urb, list); ++ if (wrap_urb->state == URB_SUBMITTED) { ++ WARNING("Windows driver %s didn't free urb: %p", ++ wd->driver->name, wrap_urb->urb); ++ if (!complete) ++ wrap_urb->urb->complete = NULL; ++ usb_kill_urb(wrap_urb->urb); ++ } ++ USBTRACE("%p, %p", wrap_urb, wrap_urb->urb); ++ usb_free_urb(wrap_urb->urb); ++ kfree(wrap_urb); ++ } ++ wd->usb.num_alloc_urbs = 0; ++} ++ ++/* for a given Linux urb status code, return corresponding NT urb status */ ++static USBD_STATUS wrap_urb_status(int urb_status) ++{ ++ switch (urb_status) { ++ case 0: ++ return USBD_STATUS_SUCCESS; ++ case -EPROTO: ++ return USBD_STATUS_TIMEOUT; ++ case -EILSEQ: ++ return USBD_STATUS_CRC; ++ case -EPIPE: ++ return USBD_STATUS_INVALID_PIPE_HANDLE; ++ case -ECOMM: ++ return USBD_STATUS_DATA_OVERRUN; ++ case -ENOSR: ++ return USBD_STATUS_DATA_UNDERRUN; ++ case -EOVERFLOW: ++ return USBD_STATUS_BABBLE_DETECTED; ++ case -EREMOTEIO: ++ return USBD_STATUS_ERROR_SHORT_TRANSFER;; ++ case -ENODEV: ++ case -ESHUTDOWN: ++ case -ENOENT: ++ return USBD_STATUS_DEVICE_GONE; ++ case -ENOMEM: ++ return USBD_STATUS_NO_MEMORY; ++ case -EINVAL: ++ return USBD_STATUS_REQUEST_FAILED; ++ default: ++ return USBD_STATUS_NOT_SUPPORTED; ++ } ++} ++ ++/* for a given USBD_STATUS, return its corresponding NTSTATUS (for irp) */ ++static NTSTATUS nt_urb_irp_status(USBD_STATUS nt_urb_status) ++{ ++ switch (nt_urb_status) { ++ case USBD_STATUS_SUCCESS: ++ return STATUS_SUCCESS; ++ case USBD_STATUS_DEVICE_GONE: ++ return STATUS_DEVICE_REMOVED; ++ case USBD_STATUS_PENDING: ++ return STATUS_PENDING; ++ case USBD_STATUS_NOT_SUPPORTED: ++ return STATUS_NOT_IMPLEMENTED; ++ case USBD_STATUS_NO_MEMORY: ++ return STATUS_NO_MEMORY; ++ case USBD_STATUS_REQUEST_FAILED: ++ return STATUS_NOT_SUPPORTED; ++ default: ++ return STATUS_FAILURE; ++ } ++} ++ ++static void wrap_free_urb(struct urb *urb) ++{ ++ struct wrap_urb *wrap_urb = urb->context; ++ struct irp *irp = wrap_urb->irp; ++ struct wrap_device *wd = IRP_WRAP_DEVICE(irp); ++ ++ USBTRACE("freeing urb: %p", urb); ++ irp->cancel_routine = NULL; ++ IRP_WRAP_URB(irp) = NULL; ++ if (wrap_urb->flags & WRAP_URB_COPY_BUFFER) { ++ USBTRACE("freeing DMA buffer for URB: %p %p", ++ urb, urb->transfer_buffer); ++ usb_free_coherent(wd->usb.udev, urb->transfer_buffer_length, ++ urb->transfer_buffer, urb->transfer_dma); ++ } ++ kfree(urb->setup_packet); ++ if (wd->usb.num_alloc_urbs > MAX_ALLOCATED_URBS) { ++ IoAcquireCancelSpinLock(&irp->cancel_irql); ++ RemoveEntryList(&wrap_urb->list); ++ wd->usb.num_alloc_urbs--; ++ IoReleaseCancelSpinLock(irp->cancel_irql); ++ usb_free_urb(urb); ++ kfree(wrap_urb); ++ } else { ++ wrap_urb->state = URB_FREE; ++ wrap_urb->flags = 0; ++ wrap_urb->irp = NULL; ++ } ++ return; ++} ++ ++void wrap_suspend_urbs(struct wrap_device *wd) ++{ ++ /* TODO: do we need to cancel urbs? */ ++ USBTRACE("%p, %d", wd, wd->usb.num_alloc_urbs); ++} ++ ++void wrap_resume_urbs(struct wrap_device *wd) ++{ ++ /* TODO: do we need to resubmit urbs? */ ++ USBTRACE("%p, %d", wd, wd->usb.num_alloc_urbs); ++} ++ ++wstdcall void wrap_cancel_irp(struct device_object *dev_obj, struct irp *irp) ++{ ++ struct urb *urb; ++ struct wrap_urb *wrap_urb = IRP_WRAP_URB(irp); ++ ++ /* NB: this function is called holding Cancel spinlock */ ++ USBENTER("irp: %p", irp); ++ urb = wrap_urb->urb; ++ USBTRACE("canceling urb %p", urb); ++ if (wrap_cancel_urb(IRP_WRAP_URB(irp))) { ++ irp->cancel = FALSE; ++ ERROR("urb %p can't be canceled: %d", urb, wrap_urb->state); ++ } else ++ USBTRACE("urb %p canceled", urb); ++ IoReleaseCancelSpinLock(irp->cancel_irql); ++ return; ++} ++WIN_FUNC_DECL(wrap_cancel_irp,2) ++ ++static struct urb *wrap_alloc_urb(struct irp *irp, unsigned int pipe, ++ void *buf, unsigned int buf_len) ++{ ++ struct urb *urb; ++ gfp_t alloc_flags; ++ struct wrap_urb *wrap_urb; ++ struct wrap_device *wd; ++ ++ USBENTER("irp: %p", irp); ++ wd = IRP_WRAP_DEVICE(irp); ++ ++ /* Don't interfere with URB cleanup by the kernel */ ++ if (test_bit(HW_DISABLED, &wd->hw_status)) ++ return NULL; ++ ++ alloc_flags = irql_gfp(); ++ IoAcquireCancelSpinLock(&irp->cancel_irql); ++ urb = NULL; ++ nt_list_for_each_entry(wrap_urb, &wd->usb.wrap_urb_list, list) { ++ if (cmpxchg(&wrap_urb->state, URB_FREE, ++ URB_ALLOCATED) == URB_FREE) { ++ urb = wrap_urb->urb; ++ /* Clean URB but keep the refcount */ ++ memset((char *)urb + sizeof(urb->kref), 0, ++ sizeof(*urb) - sizeof(urb->kref)); ++ break; ++ } ++ } ++ if (!urb) { ++ IoReleaseCancelSpinLock(irp->cancel_irql); ++ wrap_urb = kzalloc(sizeof(*wrap_urb), alloc_flags); ++ if (!wrap_urb) { ++ WARNING("couldn't allocate memory"); ++ return NULL; ++ } ++ urb = usb_alloc_urb(0, alloc_flags); ++ if (!urb) { ++ WARNING("couldn't allocate urb"); ++ kfree(wrap_urb); ++ return NULL; ++ } ++ IoAcquireCancelSpinLock(&irp->cancel_irql); ++ wrap_urb->urb = urb; ++ wrap_urb->state = URB_ALLOCATED; ++ InsertTailList(&wd->usb.wrap_urb_list, &wrap_urb->list); ++ wd->usb.num_alloc_urbs++; ++ } ++ ++#ifdef URB_ASYNC_UNLINK ++ urb->transfer_flags |= URB_ASYNC_UNLINK; ++#elif defined(USB_ASYNC_UNLINK) ++ urb->transfer_flags |= USB_ASYNC_UNLINK; ++#endif ++ urb->context = wrap_urb; ++ wrap_urb->irp = irp; ++ IRP_WRAP_URB(irp) = wrap_urb; ++ /* called as Windows function */ ++ irp->cancel_routine = WIN_FUNC_PTR(wrap_cancel_irp,2); ++ IoReleaseCancelSpinLock(irp->cancel_irql); ++ USBTRACE("urb: %p", urb); ++ ++ urb->transfer_buffer_length = buf_len; ++ if (buf_len && buf && (!virt_addr_valid(buf) ++#if defined(CONFIG_HIGHMEM) || defined(CONFIG_HIGHMEM4G) ++ || PageHighMem(virt_to_page(buf)) ++#endif ++ )) { ++ urb->transfer_buffer = ++ usb_alloc_coherent(wd->usb.udev, buf_len, alloc_flags, ++ &urb->transfer_dma); ++ if (!urb->transfer_buffer) { ++ WARNING("couldn't allocate dma buf"); ++ IoAcquireCancelSpinLock(&irp->cancel_irql); ++ irp->cancel_routine = NULL; ++ wrap_urb->state = URB_FREE; ++ wrap_urb->irp = NULL; ++ IRP_WRAP_URB(irp) = NULL; ++ IoReleaseCancelSpinLock(irp->cancel_irql); ++ return NULL; ++ } ++ if (urb->transfer_dma) ++ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; ++ wrap_urb->flags |= WRAP_URB_COPY_BUFFER; ++ if (usb_pipeout(pipe)) ++ memcpy(urb->transfer_buffer, buf, buf_len); ++ USBTRACE("DMA buf for urb %p: %p", urb, urb->transfer_buffer); ++ } else ++ urb->transfer_buffer = buf; ++ return urb; ++} ++ ++static USBD_STATUS wrap_submit_urb(struct irp *irp) ++{ ++ int ret; ++ struct wrap_urb *wrap_urb = IRP_WRAP_URB(irp); ++ struct urb *urb = wrap_urb->urb; ++ union nt_urb *nt_urb = IRP_URB(irp); ++ ++#ifdef USB_DEBUG ++ if (wrap_urb->state != URB_ALLOCATED) { ++ ERROR("urb %p is in wrong state: %d", ++ urb, wrap_urb->state); ++ NT_URB_STATUS(nt_urb) = USBD_STATUS_REQUEST_FAILED; ++ return NT_URB_STATUS(nt_urb); ++ } ++ wrap_urb->id = pre_atomic_add(urb_id, 1); ++#endif ++ DUMP_WRAP_URB(IRP_WRAP_URB(irp), USB_DIR_OUT); ++ irp->io_status.status = STATUS_PENDING; ++ irp->io_status.info = 0; ++ NT_URB_STATUS(nt_urb) = USBD_STATUS_PENDING; ++ IoMarkIrpPending(irp); ++ DUMP_URB_BUFFER(urb, USB_DIR_OUT); ++ USBTRACE("%p", urb); ++ wrap_urb->state = URB_SUBMITTED; ++ ret = usb_submit_urb(urb, irql_gfp()); ++ if (ret) { ++ USBTRACE("ret: %d", ret); ++ wrap_free_urb(urb); ++ /* we assume that IRP was not in pending state before */ ++ IoUnmarkIrpPending(irp); ++ NT_URB_STATUS(nt_urb) = wrap_urb_status(ret); ++ USBEXIT(return NT_URB_STATUS(nt_urb)); ++ } else ++ USBEXIT(return USBD_STATUS_PENDING); ++} ++ ++static void wrap_urb_complete(struct urb *urb ISR_PT_REGS_PARAM_DECL) ++{ ++ struct irp *irp; ++ struct wrap_urb *wrap_urb; ++ ++ wrap_urb = urb->context; ++ USBTRACE("%p (%p) completed", wrap_urb, urb); ++ irp = wrap_urb->irp; ++ DUMP_WRAP_URB(wrap_urb, USB_DIR_IN); ++ irp->cancel_routine = NULL; ++#ifdef USB_DEBUG ++ if (wrap_urb->state != URB_SUBMITTED) { ++ WARNING("urb %p in wrong state: %d (%d)", urb, wrap_urb->state, ++ urb->status); ++ return; ++ } ++#endif ++ wrap_urb->state = URB_COMPLETED; ++ spin_lock(&wrap_urb_complete_list_lock); ++ InsertTailList(&wrap_urb_complete_list, &wrap_urb->complete_list); ++ spin_unlock(&wrap_urb_complete_list_lock); ++ queue_work(ntos_wq, &wrap_urb_complete_work); ++} ++ ++/* one worker for all devices */ ++static void wrap_urb_complete_worker(struct work_struct *dummy) ++{ ++ struct irp *irp; ++ struct urb *urb; ++ struct usbd_bulk_or_intr_transfer *bulk_int_tx; ++ struct usbd_vendor_or_class_request *vc_req; ++ union nt_urb *nt_urb; ++ struct wrap_urb *wrap_urb; ++ struct nt_list *ent; ++ unsigned long flags; ++ ++ USBENTER(""); ++ while (1) { ++ spin_lock_irqsave(&wrap_urb_complete_list_lock, flags); ++ ent = RemoveHeadList(&wrap_urb_complete_list); ++ spin_unlock_irqrestore(&wrap_urb_complete_list_lock, flags); ++ if (!ent) ++ break; ++ wrap_urb = container_of(ent, struct wrap_urb, complete_list); ++ urb = wrap_urb->urb; ++#ifdef USB_DEBUG ++ if (wrap_urb->state != URB_COMPLETED && ++ wrap_urb->state != URB_INT_UNLINKED) ++ WARNING("urb %p in wrong state: %d", ++ urb, wrap_urb->state); ++#endif ++ irp = wrap_urb->irp; ++ DUMP_IRP(irp); ++ nt_urb = IRP_URB(irp); ++ USBTRACE("urb: %p, nt_urb: %p, status: %d", ++ urb, nt_urb, urb->status); ++ switch (urb->status) { ++ case 0: ++ /* successfully transferred */ ++ irp->io_status.info = urb->actual_length; ++ if (nt_urb->header.function == ++ URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER) { ++ bulk_int_tx = &nt_urb->bulk_int_transfer; ++ bulk_int_tx->transfer_buffer_length = ++ urb->actual_length; ++ DUMP_URB_BUFFER(urb, USB_DIR_IN); ++ if ((wrap_urb->flags & WRAP_URB_COPY_BUFFER) && ++ usb_pipein(urb->pipe)) ++ memcpy(bulk_int_tx->transfer_buffer, ++ urb->transfer_buffer, ++ urb->actual_length); ++ } else { // vendor or class request ++ vc_req = &nt_urb->vendor_class_request; ++ vc_req->transfer_buffer_length = ++ urb->actual_length; ++ DUMP_URB_BUFFER(urb, USB_DIR_IN); ++ if ((wrap_urb->flags & WRAP_URB_COPY_BUFFER) && ++ usb_pipein(urb->pipe)) ++ memcpy(vc_req->transfer_buffer, ++ urb->transfer_buffer, ++ urb->actual_length); ++ } ++ NT_URB_STATUS(nt_urb) = USBD_STATUS_SUCCESS; ++ irp->io_status.status = STATUS_SUCCESS; ++ break; ++ case -ENOENT: ++ case -ECONNRESET: ++ /* urb canceled */ ++ irp->io_status.info = 0; ++ TRACE2("urb %p canceled", urb); ++ NT_URB_STATUS(nt_urb) = USBD_STATUS_SUCCESS; ++ irp->io_status.status = STATUS_CANCELLED; ++ break; ++ default: ++ TRACE2("irp: %p, urb: %p, status: %d/%d", ++ irp, urb, urb->status, wrap_urb->state); ++ irp->io_status.info = 0; ++ NT_URB_STATUS(nt_urb) = wrap_urb_status(urb->status); ++ irp->io_status.status = ++ nt_urb_irp_status(NT_URB_STATUS(nt_urb)); ++ break; ++ } ++ wrap_free_urb(urb); ++ IoCompleteRequest(irp, IO_NO_INCREMENT); ++ } ++ USBEXIT(return); ++} ++ ++static USBD_STATUS wrap_bulk_or_intr_trans(struct irp *irp) ++{ ++ struct usb_endpoint_descriptor *pipe_handle; ++ struct urb *urb; ++ unsigned int pipe; ++ struct usbd_bulk_or_intr_transfer *bulk_int_tx; ++ USBD_STATUS status; ++ struct wrap_device *wd = IRP_WRAP_DEVICE(irp); ++ struct usb_device *udev = wd->usb.udev; ++ union nt_urb *nt_urb = IRP_URB(irp); ++ ++ bulk_int_tx = &nt_urb->bulk_int_transfer; ++ pipe_handle = bulk_int_tx->pipe_handle; ++ USBTRACE("flags: 0x%x, length: %u, buffer: %p, handle: %p", ++ bulk_int_tx->transfer_flags, ++ bulk_int_tx->transfer_buffer_length, ++ bulk_int_tx->transfer_buffer, pipe_handle); ++ ++ if (USBD_IS_BULK_PIPE(pipe_handle)) { ++ if (bulk_int_tx->transfer_flags & USBD_TRANSFER_DIRECTION_IN) ++ pipe = usb_rcvbulkpipe(udev, ++ pipe_handle->bEndpointAddress); ++ else ++ pipe = usb_sndbulkpipe(udev, ++ pipe_handle->bEndpointAddress); ++ } else { ++ if (bulk_int_tx->transfer_flags & USBD_TRANSFER_DIRECTION_IN) ++ pipe = usb_rcvintpipe(udev, ++ pipe_handle->bEndpointAddress); ++ else ++ pipe = usb_sndintpipe(udev, ++ pipe_handle->bEndpointAddress); ++ } ++ ++ DUMP_IRP(irp); ++ urb = wrap_alloc_urb(irp, pipe, bulk_int_tx->transfer_buffer, ++ bulk_int_tx->transfer_buffer_length); ++ if (!urb) { ++ ERROR("couldn't allocate urb"); ++ return USBD_STATUS_NO_MEMORY; ++ } ++ if (usb_pipein(pipe) && ++ (!(bulk_int_tx->transfer_flags & USBD_SHORT_TRANSFER_OK))) { ++ USBTRACE("short not ok"); ++ urb->transfer_flags |= URB_SHORT_NOT_OK; ++ } ++ if (usb_pipebulk(pipe)) { ++ usb_fill_bulk_urb(urb, udev, pipe, urb->transfer_buffer, ++ bulk_int_tx->transfer_buffer_length, ++ wrap_urb_complete, urb->context); ++ USBTRACE("submitting bulk urb %p on pipe 0x%x (ep 0x%x)", ++ urb, urb->pipe, pipe_handle->bEndpointAddress); ++ } else { ++ usb_fill_int_urb(urb, udev, pipe, urb->transfer_buffer, ++ bulk_int_tx->transfer_buffer_length, ++ wrap_urb_complete, urb->context, ++ pipe_handle->bInterval); ++ USBTRACE("submitting interrupt urb %p on pipe 0x%x (ep 0x%x), " ++ "intvl: %d", urb, urb->pipe, ++ pipe_handle->bEndpointAddress, pipe_handle->bInterval); ++ } ++ status = wrap_submit_urb(irp); ++ USBTRACE("status: %08X", status); ++ USBEXIT(return status); ++} ++ ++static USBD_STATUS wrap_vendor_or_class_req(struct irp *irp) ++{ ++ u8 req_type; ++ unsigned int pipe; ++ struct usbd_vendor_or_class_request *vc_req; ++ USBD_STATUS status; ++ struct urb *urb; ++ struct usb_ctrlrequest *dr; ++ struct wrap_device *wd = IRP_WRAP_DEVICE(irp); ++ struct usb_device *udev = wd->usb.udev; ++ union nt_urb *nt_urb = IRP_URB(irp); ++ ++ vc_req = &nt_urb->vendor_class_request; ++ USBTRACE("bits: %x, req: %x, val: %08x, index: %08x, flags: %x," ++ "buf: %p, len: %d", vc_req->reserved_bits, vc_req->request, ++ vc_req->value, vc_req->index, vc_req->transfer_flags, ++ vc_req->transfer_buffer, vc_req->transfer_buffer_length); ++ ++ USBTRACE("%x", nt_urb->header.function); ++ switch (nt_urb->header.function) { ++ case URB_FUNCTION_VENDOR_DEVICE: ++ req_type = USB_TYPE_VENDOR | USB_RECIP_DEVICE; ++ break; ++ case URB_FUNCTION_VENDOR_INTERFACE: ++ req_type = USB_TYPE_VENDOR | USB_RECIP_INTERFACE; ++ break; ++ case URB_FUNCTION_VENDOR_ENDPOINT: ++ req_type = USB_TYPE_VENDOR | USB_RECIP_ENDPOINT; ++ break; ++ case URB_FUNCTION_VENDOR_OTHER: ++ req_type = USB_TYPE_VENDOR | USB_RECIP_OTHER; ++ break; ++ case URB_FUNCTION_CLASS_DEVICE: ++ req_type = USB_TYPE_CLASS | USB_RECIP_DEVICE; ++ break; ++ case URB_FUNCTION_CLASS_INTERFACE: ++ req_type = USB_TYPE_CLASS | USB_RECIP_INTERFACE; ++ break; ++ case URB_FUNCTION_CLASS_ENDPOINT: ++ req_type = USB_TYPE_CLASS | USB_RECIP_ENDPOINT; ++ break; ++ case URB_FUNCTION_CLASS_OTHER: ++ req_type = USB_TYPE_CLASS | USB_RECIP_OTHER; ++ break; ++ default: ++ ERROR("unknown request type: %x", nt_urb->header.function); ++ req_type = 0; ++ break; ++ } ++ ++ req_type |= vc_req->reserved_bits; ++ USBTRACE("req type: %08x", req_type); ++ ++ if (vc_req->transfer_flags & USBD_TRANSFER_DIRECTION_IN) { ++ pipe = usb_rcvctrlpipe(udev, 0); ++ req_type |= USB_DIR_IN; ++ USBTRACE("pipe: %x, dir in", pipe); ++ } else { ++ pipe = usb_sndctrlpipe(udev, 0); ++ req_type |= USB_DIR_OUT; ++ USBTRACE("pipe: %x, dir out", pipe); ++ } ++ urb = wrap_alloc_urb(irp, pipe, vc_req->transfer_buffer, ++ vc_req->transfer_buffer_length); ++ if (!urb) { ++ ERROR("couldn't allocate urb"); ++ return USBD_STATUS_NO_MEMORY; ++ } ++ ++ if (usb_pipein(pipe) && ++ (!(vc_req->transfer_flags & USBD_SHORT_TRANSFER_OK))) { ++ USBTRACE("short not ok"); ++ urb->transfer_flags |= URB_SHORT_NOT_OK; ++ } ++ ++ dr = kzalloc(sizeof(*dr), irql_gfp()); ++ if (!dr) { ++ ERROR("couldn't allocate memory"); ++ wrap_free_urb(urb); ++ return USBD_STATUS_NO_MEMORY; ++ } ++ dr->bRequestType = req_type; ++ dr->bRequest = vc_req->request; ++ dr->wValue = cpu_to_le16(vc_req->value); ++ dr->wIndex = cpu_to_le16((u16)vc_req->index); ++ dr->wLength = cpu_to_le16((u16)urb->transfer_buffer_length); ++ ++ usb_fill_control_urb(urb, udev, pipe, (unsigned char *)dr, ++ urb->transfer_buffer, urb->transfer_buffer_length, ++ wrap_urb_complete, urb->context); ++ status = wrap_submit_urb(irp); ++ USBTRACE("status: %08X", status); ++ USBEXIT(return status); ++} ++ ++static USBD_STATUS wrap_reset_pipe(struct usb_device *udev, struct irp *irp) ++{ ++ int ret; ++ union nt_urb *nt_urb; ++ struct usb_endpoint_descriptor *pipe_handle; ++ unsigned int pipe1, pipe2; ++ ++ nt_urb = IRP_URB(irp); ++ pipe_handle = nt_urb->pipe_req.pipe_handle; ++ /* TODO: not clear if both directions should be cleared? */ ++ if (USBD_IS_BULK_PIPE(pipe_handle)) { ++ pipe1 = usb_rcvbulkpipe(udev, pipe_handle->bEndpointAddress); ++ pipe2 = usb_sndbulkpipe(udev, pipe_handle->bEndpointAddress); ++ } else if (USBD_IS_INT_PIPE(pipe_handle)) { ++ pipe1 = usb_rcvintpipe(udev, pipe_handle->bEndpointAddress); ++ pipe2 = pipe1; ++ } else { ++ WARNING("invalid pipe %d", pipe_handle->bEndpointAddress); ++ return USBD_STATUS_INVALID_PIPE_HANDLE; ++ } ++ USBTRACE("ep: %d, pipe: 0x%x", pipe_handle->bEndpointAddress, pipe1); ++ ret = usb_clear_halt(udev, pipe1); ++ if (ret) ++ USBTRACE("resetting pipe %d failed: %d", pipe1, ret); ++ if (pipe2 != pipe1) { ++ ret = usb_clear_halt(udev, pipe2); ++ if (ret) ++ USBTRACE("resetting pipe %d failed: %d", pipe2, ret); ++ } ++// return wrap_urb_status(ret); ++ return USBD_STATUS_SUCCESS; ++} ++ ++static USBD_STATUS wrap_abort_pipe(struct usb_device *udev, struct irp *irp) ++{ ++ union nt_urb *nt_urb; ++ struct usb_endpoint_descriptor *pipe_handle; ++ struct wrap_urb *wrap_urb; ++ struct wrap_device *wd; ++ KIRQL irql; ++ ++ wd = IRP_WRAP_DEVICE(irp); ++ nt_urb = IRP_URB(irp); ++ pipe_handle = nt_urb->pipe_req.pipe_handle; ++ USBENTER("%p, %x", irp, pipe_handle->bEndpointAddress); ++ IoAcquireCancelSpinLock(&irql); ++ nt_list_for_each_entry(wrap_urb, &wd->usb.wrap_urb_list, list) { ++ USBTRACE("%p, %p, %d, %x, %x", wrap_urb, wrap_urb->urb, ++ wrap_urb->state, wrap_urb->urb->pipe, ++ usb_pipeendpoint(wrap_urb->urb->pipe)); ++ /* for WG111T driver, urbs for endpoint 0 should also ++ * be canceled */ ++ if ((usb_pipeendpoint(wrap_urb->urb->pipe) == ++ pipe_handle->bEndpointAddress) || ++ (usb_pipeendpoint(wrap_urb->urb->pipe) == 0)) { ++ if (wrap_cancel_urb(wrap_urb) == 0) ++ USBTRACE("canceled wrap_urb: %p", wrap_urb); ++ } ++ } ++ IoReleaseCancelSpinLock(irql); ++ NT_URB_STATUS(nt_urb) = USBD_STATUS_CANCELED; ++ USBEXIT(return USBD_STATUS_SUCCESS); ++} ++ ++static USBD_STATUS wrap_set_clear_feature(struct usb_device *udev, ++ struct irp *irp) ++{ ++ union nt_urb *nt_urb; ++ struct urb_control_feature_request *feat_req; ++ int ret = 0; ++ __u8 request, type; ++ __u16 feature; ++ ++ nt_urb = IRP_URB(irp); ++ feat_req = &nt_urb->feat_req; ++ feature = feat_req->feature_selector; ++ switch (nt_urb->header.function) { ++ case URB_FUNCTION_SET_FEATURE_TO_DEVICE: ++ request = USB_REQ_SET_FEATURE; ++ type = USB_DT_DEVICE; ++ break; ++ case URB_FUNCTION_SET_FEATURE_TO_INTERFACE: ++ request = USB_REQ_SET_FEATURE; ++ type = USB_DT_INTERFACE; ++ break; ++ case URB_FUNCTION_SET_FEATURE_TO_ENDPOINT: ++ request = USB_REQ_SET_FEATURE; ++ type = USB_DT_ENDPOINT; ++ break; ++ case URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE: ++ request = USB_REQ_CLEAR_FEATURE; ++ type = USB_DT_DEVICE; ++ break; ++ case URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE: ++ request = USB_REQ_CLEAR_FEATURE; ++ type = USB_DT_INTERFACE; ++ break; ++ case URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT: ++ request = USB_REQ_CLEAR_FEATURE; ++ type = USB_DT_ENDPOINT; ++ break; ++ default: ++ WARNING("invalid function: %x", nt_urb->header.function); ++ NT_URB_STATUS(nt_urb) = USBD_STATUS_NOT_SUPPORTED; ++ return NT_URB_STATUS(nt_urb); ++ } ++ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), request, type, ++ feature, feat_req->index, NULL, 0, 1000); ++ NT_URB_STATUS(nt_urb) = wrap_urb_status(ret); ++ USBEXIT(return NT_URB_STATUS(nt_urb)); ++} ++ ++static USBD_STATUS wrap_get_status_request(struct usb_device *udev, ++ struct irp *irp) ++{ ++ union nt_urb *nt_urb; ++ struct urb_control_get_status_request *status_req; ++ int ret = 0; ++ __u8 type; ++ ++ nt_urb = IRP_URB(irp); ++ status_req = &nt_urb->status_req; ++ switch (nt_urb->header.function) { ++ case URB_FUNCTION_GET_STATUS_FROM_DEVICE: ++ type = USB_RECIP_DEVICE; ++ break; ++ case URB_FUNCTION_GET_STATUS_FROM_INTERFACE: ++ type = USB_RECIP_INTERFACE; ++ break; ++ case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT: ++ type = USB_RECIP_ENDPOINT; ++ break; ++ default: ++ WARNING("invalid function: %x", nt_urb->header.function); ++ NT_URB_STATUS(nt_urb) = USBD_STATUS_NOT_SUPPORTED; ++ return NT_URB_STATUS(nt_urb); ++ } ++ assert(status_req->transfer_buffer_length == sizeof(u16)); ++ ret = usb_get_status(udev, type, status_req->index, ++ status_req->transfer_buffer); ++ if (ret >= 0) { ++ assert(ret <= status_req->transfer_buffer_length); ++ status_req->transfer_buffer_length = ret; ++ NT_URB_STATUS(nt_urb) = USBD_STATUS_SUCCESS; ++ } else ++ NT_URB_STATUS(nt_urb) = wrap_urb_status(ret); ++ USBEXIT(return NT_URB_STATUS(nt_urb)); ++} ++ ++static void set_intf_pipe_info(struct wrap_device *wd, ++ struct usb_interface *usb_intf, ++ struct usbd_interface_information *intf) ++{ ++ int i; ++ struct usb_endpoint_descriptor *ep; ++ struct usbd_pipe_information *pipe; ++ ++ for (i = 0; i < CUR_ALT_SETTING(usb_intf)->desc.bNumEndpoints; i++) { ++ ep = &(CUR_ALT_SETTING(usb_intf)->endpoint[i]).desc; ++ if (i >= intf->bNumEndpoints) { ++ ERROR("intf %p has only %d endpoints, " ++ "ignoring endpoints above %d", ++ intf, intf->bNumEndpoints, i); ++ break; ++ } ++ pipe = &intf->pipes[i]; ++ ++ if (pipe->flags & USBD_PF_CHANGE_MAX_PACKET) ++ USBTRACE("pkt_sz: %d: %d", pipe->wMaxPacketSize, ++ pipe->max_tx_size); ++ USBTRACE("driver wants max_tx_size to %d", ++ pipe->max_tx_size); ++ ++ pipe->wMaxPacketSize = le16_to_cpu(ep->wMaxPacketSize); ++ pipe->bEndpointAddress = ep->bEndpointAddress; ++ pipe->type = ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; ++ if (pipe->type == UsbdPipeTypeInterrupt) { ++ /* Windows and Linux differ in how the ++ * bInterval is interpreted */ ++ /* for low speed: ++ interval (Windows) -> frames per ms (Linux) ++ 0 to 15 -> 8 ++ 16 to 35 -> 16 ++ 36 to 255 -> 32 ++ ++ for full speed: interval -> frames per ms ++ 1 -> 1 ++ 2 to 3 -> 2 ++ 4 to 7 -> 4 ++ 8 to 15 -> 8 ++ 16 to 31 -> 16 ++ 32 to 255 -> 32 ++ ++ for high speed: interval -> microframes ++ 1 -> 1 ++ 2 -> 2 ++ 3 -> 4 ++ 4 -> 8 ++ 5 -> 16 ++ 6 -> 32 ++ 7 to 255 -> 32 ++ */ ++ if (wd->usb.udev->speed == USB_SPEED_LOW) ++ pipe->bInterval = ep->bInterval + 5; ++ else if (wd->usb.udev->speed == USB_SPEED_FULL) ++ pipe->bInterval = ep->bInterval; ++ else { ++ int j, k; ++ for (j = k = 1; j < ep->bInterval; k++) ++ j *= 2; ++ pipe->bInterval = k; ++ } ++ } ++ pipe->handle = ep; ++ USBTRACE("%d: ep 0x%x, type %d, pkt_sz %d, intv %d (%d)," ++ "type: %d, handle %p", i, ep->bEndpointAddress, ++ ep->bmAttributes, pipe->wMaxPacketSize, ep->bInterval, ++ pipe->bInterval, pipe->type, pipe->handle); ++ } ++} ++ ++static USBD_STATUS wrap_select_configuration(struct wrap_device *wd, ++ union nt_urb *nt_urb, ++ struct irp *irp) ++{ ++ int i, ret; ++ struct usbd_select_configuration *sel_conf; ++ struct usb_device *udev; ++ struct usbd_interface_information *intf; ++ struct usb_config_descriptor *config; ++ struct usb_interface *usb_intf; ++ ++ udev = wd->usb.udev; ++ sel_conf = &nt_urb->select_conf; ++ config = sel_conf->config; ++ USBTRACE("%p", config); ++ if (config == NULL) { ++ kill_all_urbs(wd, 1); ++ ret = usb_reset_configuration(udev); ++ return wrap_urb_status(ret); ++ } ++ ++ USBTRACE("conf: %d, type: %d, length: %d, numif: %d, attr: %08x", ++ config->bConfigurationValue, config->bDescriptorType, ++ config->wTotalLength, config->bNumInterfaces, ++ config->bmAttributes); ++ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), ++ USB_REQ_SET_CONFIGURATION, 0, ++ config->bConfigurationValue, 0, ++ NULL, 0, USB_CTRL_SET_TIMEOUT); ++ if (ret < 0) { ++ ERROR("ret: %d", ret); ++ return wrap_urb_status(ret); ++ } ++ sel_conf->handle = udev->actconfig; ++ intf = &sel_conf->intf; ++ for (i = 0; i < config->bNumInterfaces && intf->bLength > 0; ++ i++, intf = (((void *)intf) + intf->bLength)) { ++ ++ USBTRACE("intf: %d, alt setting: %d", ++ intf->bInterfaceNumber, intf->bAlternateSetting); ++ ret = usb_set_interface(udev, intf->bInterfaceNumber, ++ intf->bAlternateSetting); ++ if (ret < 0) { ++ ERROR("failed with %d", ret); ++ return wrap_urb_status(ret); ++ } ++ usb_intf = usb_ifnum_to_if(udev, intf->bInterfaceNumber); ++ if (!usb_intf) { ++ ERROR("couldn't obtain ifnum"); ++ return USBD_STATUS_REQUEST_FAILED; ++ } ++ USBTRACE("intf: %p, num ep: %d", intf, intf->bNumEndpoints); ++ set_intf_pipe_info(wd, usb_intf, intf); ++ } ++ return USBD_STATUS_SUCCESS; ++} ++ ++static USBD_STATUS wrap_select_interface(struct wrap_device *wd, ++ union nt_urb *nt_urb, ++ struct irp *irp) ++{ ++ int ret; ++ struct usbd_select_interface *sel_intf; ++ struct usb_device *udev; ++ struct usbd_interface_information *intf; ++ struct usb_interface *usb_intf; ++ ++ udev = wd->usb.udev; ++ sel_intf = &nt_urb->select_intf; ++ intf = &sel_intf->intf; ++ ++ ret = usb_set_interface(udev, intf->bInterfaceNumber, ++ intf->bAlternateSetting); ++ if (ret < 0) { ++ ERROR("failed with %d", ret); ++ return wrap_urb_status(ret); ++ } ++ usb_intf = usb_ifnum_to_if(udev, intf->bInterfaceNumber); ++ if (!usb_intf) { ++ ERROR("couldn't get interface information"); ++ return USBD_STATUS_REQUEST_FAILED; ++ } ++ USBTRACE("intf: %p, num ep: %d", usb_intf, intf->bNumEndpoints); ++ set_intf_pipe_info(wd, usb_intf, intf); ++ return USBD_STATUS_SUCCESS; ++} ++ ++static int wrap_usb_get_string(struct usb_device *udev, unsigned short langid, ++ unsigned char index, void *buf, int size) ++{ ++ int i, ret; ++ /* if langid is 0, return array of languages supported in ++ * buf */ ++ for (i = 0; i < 3; i++) { ++ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), ++ USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, ++ (USB_DT_STRING << 8) + index, langid, ++ buf, size, USB_CTRL_GET_TIMEOUT); ++ if (ret > 0 || ret == -EPIPE) ++ break; ++ } ++ return ret; ++} ++ ++static USBD_STATUS wrap_get_descriptor(struct wrap_device *wd, ++ union nt_urb *nt_urb, struct irp *irp) ++{ ++ struct usbd_control_descriptor_request *control_desc; ++ int ret = 0; ++ struct usb_device *udev; ++ ++ udev = wd->usb.udev; ++ control_desc = &nt_urb->control_desc; ++ USBTRACE("desctype = %d, descindex = %d, transfer_buffer = %p," ++ "transfer_buffer_length = %d", control_desc->desc_type, ++ control_desc->index, control_desc->transfer_buffer, ++ control_desc->transfer_buffer_length); ++ ++ if (control_desc->desc_type == USB_DT_STRING) { ++ USBTRACE("langid: %x", control_desc->language_id); ++ ret = wrap_usb_get_string(udev, control_desc->language_id, ++ control_desc->index, ++ control_desc->transfer_buffer, ++ control_desc->transfer_buffer_length); ++ } else { ++ ret = usb_get_descriptor(udev, control_desc->desc_type, ++ control_desc->index, ++ control_desc->transfer_buffer, ++ control_desc->transfer_buffer_length); ++ } ++ if (ret < 0) { ++ USBTRACE("request %d failed: %d", control_desc->desc_type, ret); ++ control_desc->transfer_buffer_length = 0; ++ return wrap_urb_status(ret); ++ } else { ++ USBTRACE("ret: %08x", ret); ++ control_desc->transfer_buffer_length = ret; ++ irp->io_status.info = ret; ++ return USBD_STATUS_SUCCESS; ++ } ++} ++ ++static USBD_STATUS wrap_process_nt_urb(struct irp *irp) ++{ ++ USBD_STATUS status; ++ struct wrap_device *wd = IRP_WRAP_DEVICE(irp); ++ struct usb_device *udev = wd->usb.udev; ++ union nt_urb *nt_urb = IRP_URB(irp); ++ ++ USBENTER("nt_urb = %p, irp = %p, length = %d, function = %x", ++ nt_urb, irp, nt_urb->header.length, nt_urb->header.function); ++ ++ if (test_bit(HW_DISABLED, &wd->hw_status)) { ++ status = USBD_STATUS_DEVICE_GONE; ++ NT_URB_STATUS(nt_urb) = status; ++ return status; ++ } ++ ++ DUMP_IRP(irp); ++ switch (nt_urb->header.function) { ++ /* bulk/int and vendor/class urbs are submitted to ++ * Linux USB core; if the call is successful, urb's ++ * completion worker will return IRP later */ ++ case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER: ++ USBTRACE("submitting bulk/int irp: %p", irp); ++ status = wrap_bulk_or_intr_trans(irp); ++ break; ++ ++ case URB_FUNCTION_VENDOR_DEVICE: ++ case URB_FUNCTION_VENDOR_INTERFACE: ++ case URB_FUNCTION_VENDOR_ENDPOINT: ++ case URB_FUNCTION_VENDOR_OTHER: ++ case URB_FUNCTION_CLASS_DEVICE: ++ case URB_FUNCTION_CLASS_INTERFACE: ++ case URB_FUNCTION_CLASS_ENDPOINT: ++ case URB_FUNCTION_CLASS_OTHER: ++ USBTRACE("submitting vendor/class irp: %p", irp); ++ status = wrap_vendor_or_class_req(irp); ++ break; ++ ++ /* rest are synchronous */ ++ case URB_FUNCTION_SELECT_CONFIGURATION: ++ status = wrap_select_configuration(wd, nt_urb, irp); ++ NT_URB_STATUS(nt_urb) = status; ++ break; ++ ++ case URB_FUNCTION_SELECT_INTERFACE: ++ status = wrap_select_interface(wd, nt_urb, irp); ++ NT_URB_STATUS(nt_urb) = status; ++ break; ++ ++ case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: ++ status = wrap_get_descriptor(wd, nt_urb, irp); ++ NT_URB_STATUS(nt_urb) = status; ++ break; ++ ++ case URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL: ++ status = wrap_reset_pipe(udev, irp); ++ NT_URB_STATUS(nt_urb) = status; ++ break; ++ ++ case URB_FUNCTION_ABORT_PIPE: ++ status = wrap_abort_pipe(udev, irp); ++ break; ++ ++ case URB_FUNCTION_SET_FEATURE_TO_DEVICE: ++ case URB_FUNCTION_SET_FEATURE_TO_INTERFACE: ++ case URB_FUNCTION_SET_FEATURE_TO_ENDPOINT: ++ case URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE: ++ case URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE: ++ case URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT: ++ status = wrap_set_clear_feature(udev, irp); ++ break; ++ ++ case URB_FUNCTION_GET_STATUS_FROM_DEVICE: ++ case URB_FUNCTION_GET_STATUS_FROM_INTERFACE: ++ case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT: ++ status = wrap_get_status_request(udev, irp); ++ break; ++ ++ default: ++ ERROR("function %x not implemented", nt_urb->header.function); ++ status = NT_URB_STATUS(nt_urb) = USBD_STATUS_NOT_SUPPORTED; ++ break; ++ } ++ USBTRACE("status: %08X", status); ++ return status; ++} ++ ++static USBD_STATUS wrap_reset_port(struct irp *irp) ++{ ++ int ret, lock = 0; ++ struct wrap_device *wd; ++ ++ wd = IRP_WRAP_DEVICE(irp); ++ USBENTER("%p, %p", wd, wd->usb.udev); ++ lock = usb_lock_device_for_reset(wd->usb.udev, wd->usb.intf); ++ if (lock < 0) { ++ WARNING("locking failed: %d", lock); ++// return wrap_urb_status(lock); ++ return USBD_STATUS_SUCCESS; ++ } ++ ret = usb_reset_device(wd->usb.udev); ++ if (ret < 0) ++ USBTRACE("reset failed: %d", ret); ++ /* TODO: should reconfigure? */ ++ if (lock) ++ usb_unlock_device(wd->usb.udev); ++// return wrap_urb_status(ret); ++ return USBD_STATUS_SUCCESS; ++} ++ ++static USBD_STATUS wrap_get_port_status(struct irp *irp) ++{ ++ struct wrap_device *wd; ++ ULONG *status; ++ enum usb_device_state state; ++ ++ wd = IRP_WRAP_DEVICE(irp); ++ USBENTER("%p, %p", wd, wd->usb.udev); ++ status = IoGetCurrentIrpStackLocation(irp)->params.others.arg1; ++ state = wd->usb.udev->state; ++ if (state != USB_STATE_NOTATTACHED && ++ state != USB_STATE_SUSPENDED) { ++ *status |= USBD_PORT_CONNECTED; ++ if (state == USB_STATE_CONFIGURED) ++ *status |= USBD_PORT_ENABLED; ++ } ++ USBTRACE("state: %d, *status: %08X", state, *status); ++ return USBD_STATUS_SUCCESS; ++} ++ ++NTSTATUS wrap_submit_irp(struct device_object *pdo, struct irp *irp) ++{ ++ struct io_stack_location *irp_sl; ++ struct wrap_device *wd; ++ USBD_STATUS status; ++ struct usbd_idle_callback *idle_callback; ++ ++ USBENTER("%p, %p", pdo, irp); ++ wd = pdo->reserved; ++ if (wd->usb.intf == NULL) { ++ USBTRACE("%p", irp); ++ irp->io_status.status = STATUS_DEVICE_REMOVED; ++ irp->io_status.info = 0; ++ USBEXIT(return STATUS_DEVICE_REMOVED); ++ } ++ IRP_WRAP_DEVICE(irp) = wd; ++ irp_sl = IoGetCurrentIrpStackLocation(irp); ++ switch (irp_sl->params.dev_ioctl.code) { ++ case IOCTL_INTERNAL_USB_SUBMIT_URB: ++ status = wrap_process_nt_urb(irp); ++ break; ++ case IOCTL_INTERNAL_USB_RESET_PORT: ++ status = wrap_reset_port(irp); ++ break; ++ case IOCTL_INTERNAL_USB_GET_PORT_STATUS: ++ status = wrap_get_port_status(irp); ++ break; ++ case IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION: ++ idle_callback = irp_sl->params.dev_ioctl.type3_input_buf; ++ (void)idle_callback; ++ USBTRACE("suspend function: %p", idle_callback->callback); ++ status = USBD_STATUS_NOT_SUPPORTED; ++ break; ++ default: ++ ERROR("ioctl %08X NOT IMPLEMENTED", ++ irp_sl->params.dev_ioctl.code); ++ status = USBD_STATUS_NOT_SUPPORTED; ++ break; ++ } ++ ++ USBTRACE("status: %08X", status); ++ if (status == USBD_STATUS_PENDING) { ++ /* don't touch this IRP - it may have been already ++ * completed/returned */ ++ return STATUS_PENDING; ++ } else { ++ irp->io_status.status = nt_urb_irp_status(status); ++ if (status != USBD_STATUS_SUCCESS) ++ irp->io_status.info = 0; ++ USBEXIT(return irp->io_status.status); ++ } ++} ++ ++/* TODO: The example on msdn in reference section suggests that second ++ * argument should be an array of usbd_interface_information, but ++ * description and examples elsewhere suggest that it should be ++ * usbd_interface_list_entry structre. Which is correct? */ ++ ++wstdcall union nt_urb *WIN_FUNC(USBD_CreateConfigurationRequestEx,2) ++ (struct usb_config_descriptor *config, ++ struct usbd_interface_list_entry *intf_list) ++{ ++ int size, i, n; ++ struct usbd_interface_information *intf; ++ struct usbd_pipe_information *pipe; ++ struct usb_interface_descriptor *intf_desc; ++ struct usbd_select_configuration *select_conf; ++ ++ USBENTER("config = %p, intf_list = %p", config, intf_list); ++ ++ /* calculate size required; select_conf already has space for ++ * one intf structure */ ++ size = sizeof(*select_conf) - sizeof(*intf); ++ for (n = 0; n < config->bNumInterfaces; n++) { ++ i = intf_list[n].intf_desc->bNumEndpoints; ++ /* intf already has space for one pipe */ ++ size += sizeof(*intf) + (i - 1) * sizeof(*pipe); ++ } ++ /* don't use kmalloc - driver frees it with ExFreePool */ ++ select_conf = ExAllocatePoolWithTag(NonPagedPool, size, ++ POOL_TAG('L', 'U', 'S', 'B')); ++ if (!select_conf) { ++ WARNING("couldn't allocate memory"); ++ return NULL; ++ } ++ memset(select_conf, 0, size); ++ intf = &select_conf->intf; ++ select_conf->handle = config; ++ for (n = 0; n < config->bNumInterfaces && intf_list[n].intf_desc; n++) { ++ /* initialize 'intf' fields in intf_list so they point ++ * to appropriate entry; these may be read/written by ++ * driver after this function returns */ ++ intf_list[n].intf = intf; ++ intf_desc = intf_list[n].intf_desc; ++ ++ i = intf_desc->bNumEndpoints; ++ intf->bLength = sizeof(*intf) + (i - 1) * sizeof(*pipe); ++ ++ intf->bInterfaceNumber = intf_desc->bInterfaceNumber; ++ intf->bAlternateSetting = intf_desc->bAlternateSetting; ++ intf->bInterfaceClass = intf_desc->bInterfaceClass; ++ intf->bInterfaceSubClass = intf_desc->bInterfaceSubClass; ++ intf->bInterfaceProtocol = intf_desc->bInterfaceProtocol; ++ intf->bNumEndpoints = intf_desc->bNumEndpoints; ++ ++ pipe = &intf->pipes[0]; ++ for (i = 0; i < intf->bNumEndpoints; i++) { ++ memset(&pipe[i], 0, sizeof(*pipe)); ++ pipe[i].max_tx_size = ++ USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE; ++ } ++ intf->handle = intf_desc; ++ intf = (((void *)intf) + intf->bLength); ++ } ++ select_conf->header.function = URB_FUNCTION_SELECT_CONFIGURATION; ++ select_conf->header.length = size; ++ select_conf->config = config; ++ USBEXIT(return (union nt_urb *)select_conf); ++} ++ ++WIN_SYMBOL_MAP("_USBD_CreateConfigurationRequestEx@8", USBD_CreateConfigurationRequestEx) ++ ++wstdcall struct usb_interface_descriptor * ++WIN_FUNC(USBD_ParseConfigurationDescriptorEx,7) ++ (struct usb_config_descriptor *config, void *start, ++ LONG bInterfaceNumber, LONG bAlternateSetting, LONG bInterfaceClass, ++ LONG bInterfaceSubClass, LONG bInterfaceProtocol) ++{ ++ void *pos; ++ struct usb_interface_descriptor *intf; ++ ++ USBENTER("config = %p, start = %p, ifnum = %d, alt_setting = %d," ++ " class = %d, subclass = %d, proto = %d", config, start, ++ bInterfaceNumber, bAlternateSetting, bInterfaceClass, ++ bInterfaceSubClass, bInterfaceProtocol); ++ ++ for (pos = start; ++ pos < ((void *)config + le16_to_cpu(config->wTotalLength)); ++ pos += intf->bLength) { ++ ++ intf = pos; ++ ++ if ((intf->bDescriptorType == USB_DT_INTERFACE) && ++ ((bInterfaceNumber == -1) || ++ (intf->bInterfaceNumber == bInterfaceNumber)) && ++ ((bAlternateSetting == -1) || ++ (intf->bAlternateSetting == bAlternateSetting)) && ++ ((bInterfaceClass == -1) || ++ (intf->bInterfaceClass == bInterfaceClass)) && ++ ((bInterfaceSubClass == -1) || ++ (intf->bInterfaceSubClass == bInterfaceSubClass)) && ++ ((bInterfaceProtocol == -1) || ++ (intf->bInterfaceProtocol == bInterfaceProtocol))) { ++ USBTRACE("selected interface = %p", intf); ++ USBEXIT(return intf); ++ } ++ } ++ USBEXIT(return NULL); ++} ++ ++WIN_SYMBOL_MAP("_USBD_ParseConfigurationDescriptorEx@28", USBD_ParseConfigurationDescriptorEx) ++ ++wstdcall union nt_urb *WIN_FUNC(USBD_CreateConfigurationRequest,2) ++ (struct usb_config_descriptor *config, USHORT *size) ++{ ++ union nt_urb *nt_urb; ++ struct usbd_interface_list_entry intf_list[2]; ++ struct usb_interface_descriptor *intf_desc; ++ ++ USBENTER("config = %p, urb_size = %p", config, size); ++ ++ intf_desc = USBD_ParseConfigurationDescriptorEx(config, config, -1, -1, ++ -1, -1, -1); ++ intf_list[0].intf_desc = intf_desc; ++ intf_list[0].intf = NULL; ++ intf_list[1].intf_desc = NULL; ++ intf_list[1].intf = NULL; ++ nt_urb = USBD_CreateConfigurationRequestEx(config, intf_list); ++ if (!nt_urb) ++ return NULL; ++ ++ *size = nt_urb->select_conf.header.length; ++ USBEXIT(return nt_urb); ++} ++ ++wstdcall struct usb_interface_descriptor * ++WIN_FUNC(USBD_ParseConfigurationDescriptor,3) ++ (struct usb_config_descriptor *config, UCHAR bInterfaceNumber, ++ UCHAR bAlternateSetting) ++{ ++ return USBD_ParseConfigurationDescriptorEx(config, config, ++ bInterfaceNumber, ++ bAlternateSetting, ++ -1, -1, -1); ++} ++ ++wstdcall struct usb_descriptor_header *WIN_FUNC(USBD_ParseDescriptors,4) ++ (void *buf, ULONG length, struct usb_descriptor_header *descr, ++ LONG type) ++{ ++ while ((void *)descr < buf + length) { ++ if (descr->bDescriptorType == type) ++ return descr; ++ if (descr->bLength == 0) ++ break; ++ descr = (void *)descr + descr->bLength; ++ } ++ USBEXIT(return NULL); ++} ++ ++WIN_SYMBOL_MAP("_USBD_ParseDescriptors@16", USBD_ParseDescriptors) ++ ++wstdcall void WIN_FUNC(USBD_GetUSBDIVersion,1) ++ (struct usbd_version_info *version_info) ++{ ++ /* this function is obsolete in Windows XP */ ++ if (version_info) { ++ version_info->usbdi_version = USBDI_VERSION_XP; ++ /* TODO: how do we get this correctly? */ ++ version_info->supported_usb_version = 0x110; ++ } ++ USBEXIT(return); ++} ++ ++wstdcall void ++USBD_InterfaceGetUSBDIVersion(void *context, ++ struct usbd_version_info *version_info, ++ ULONG *hcd_capa) ++{ ++ struct wrap_device *wd = context; ++ ++ if (version_info) { ++ version_info->usbdi_version = USBDI_VERSION_XP; ++ if (wd->usb.udev->speed == USB_SPEED_HIGH) ++ version_info->supported_usb_version = 0x200; ++ else ++ version_info->supported_usb_version = 0x110; ++ } ++ *hcd_capa = USB_HCD_CAPS_SUPPORTS_RT_THREADS; ++ USBEXIT(return); ++} ++ ++wstdcall BOOLEAN USBD_InterfaceIsDeviceHighSpeed(void *context) ++{ ++ struct wrap_device *wd = context; ++ ++ USBTRACE("wd: %p", wd); ++ if (wd->usb.udev->speed == USB_SPEED_HIGH) ++ USBEXIT(return TRUE); ++ else ++ USBEXIT(return FALSE); ++} ++ ++wstdcall void USBD_InterfaceReference(void *context) ++{ ++ USBTRACE("%p", context); ++ TODO(); ++} ++ ++wstdcall void USBD_InterfaceDereference(void *context) ++{ ++ USBTRACE("%p", context); ++ TODO(); ++} ++ ++wstdcall NTSTATUS USBD_InterfaceQueryBusTime(void *context, ULONG *frame) ++{ ++ struct wrap_device *wd = context; ++ ++ *frame = usb_get_current_frame_number(wd->usb.udev); ++ USBEXIT(return STATUS_SUCCESS); ++} ++ ++wstdcall NTSTATUS USBD_InterfaceSubmitIsoOutUrb(void *context, ++ union nt_urb *nt_urb) ++{ ++ /* TODO: implement this */ ++ TODO(); ++ USBEXIT(return STATUS_NOT_IMPLEMENTED); ++} ++ ++wstdcall NTSTATUS ++USBD_InterfaceQueryBusInformation(void *context, ULONG level, void *buf, ++ ULONG *buf_length, ULONG *buf_actual_length) ++{ ++#if 0 ++ struct wrap_device *wd = context; ++ struct usb_bus *bus = wd->usb.udev->bus; ++ struct usb_bus_information_level *bus_info = buf; ++#endif ++ ++ TODO(); ++ USBEXIT(return STATUS_NOT_IMPLEMENTED); ++} ++ ++wstdcall NTSTATUS ++USBD_InterfaceLogEntry(void *context, ULONG driver_tag, ULONG enum_tag, ++ ULONG p1, ULONG p2) ++{ ++ ERROR("%p, %x, %x, %x, %x", context, driver_tag, enum_tag, p1, p2); ++ USBEXIT(return STATUS_SUCCESS); ++} ++ ++NTSTATUS ++usb_query_interface(struct wrap_device *wd, struct io_stack_location *irp_sl) ++{ ++ struct usbd_bus_interface_usbdi *intf = ++ (struct usbd_bus_interface_usbdi *) ++ irp_sl->params.query_intf.intf; ++ ++ TRACE2("type: %x, size: %d, version: %d", ++ irp_sl->params.query_intf.type->data1, ++ irp_sl->params.query_intf.size, ++ irp_sl->params.query_intf.version); ++ intf->Context = wd; ++ intf->InterfaceReference = ++ WIN_FUNC_PTR(USBD_InterfaceReference, 1); ++ intf->InterfaceDereference = ++ WIN_FUNC_PTR(USBD_InterfaceDereference, 1); ++ intf->GetUSBDIVersion = ++ WIN_FUNC_PTR(USBD_InterfaceGetUSBDIVersion, 3); ++ intf->QueryBusTime = ++ WIN_FUNC_PTR(USBD_InterfaceQueryBusTime, 2); ++ intf->SubmitIsoOutUrb = ++ WIN_FUNC_PTR(USBD_InterfaceSubmitIsoOutUrb, 2); ++ intf->QueryBusInformation = ++ WIN_FUNC_PTR(USBD_InterfaceQueryBusInformation, 5); ++ if (irp_sl->params.query_intf.version >= USB_BUSIF_USBDI_VERSION_1) ++ intf->IsDeviceHighSpeed = ++ WIN_FUNC_PTR(USBD_InterfaceIsDeviceHighSpeed, 1); ++ if (irp_sl->params.query_intf.version >= USB_BUSIF_USBDI_VERSION_2) ++ intf->LogEntry = WIN_FUNC_PTR(USBD_InterfaceLogEntry, 5); ++ return STATUS_SUCCESS; ++} ++ ++int usb_init(void) ++{ ++ InitializeListHead(&wrap_urb_complete_list); ++ spin_lock_init(&wrap_urb_complete_list_lock); ++ INIT_WORK(&wrap_urb_complete_work, wrap_urb_complete_worker); ++#ifdef USB_DEBUG ++ urb_id = 0; ++#endif ++ return 0; ++} ++ ++void usb_exit(void) ++{ ++ USBEXIT(return); ++} ++ ++int usb_init_device(struct wrap_device *wd) ++{ ++ InitializeListHead(&wd->usb.wrap_urb_list); ++ wd->usb.num_alloc_urbs = 0; ++ USBEXIT(return 0); ++} ++ ++void usb_exit_device(struct wrap_device *wd) ++{ ++ kill_all_urbs(wd, 0); ++ USBEXIT(return); ++} +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/usb.h linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/usb.h +--- linux-3.12.2/3rdparty/ndiswrapper/usb.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/usb.h 2013-11-28 21:42:11.000000000 +0200 +@@ -0,0 +1,360 @@ ++/* ++ * Copyright (C) 2004 Jan Kiszka ++ * Copyright (C) 2005 Giridhar Pemmasani ++ * ++ * 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 _USB_H_ ++#define _USB_H_ ++ ++#include "ntoskernel.h" ++ ++#define IOCTL_INTERNAL_USB_SUBMIT_URB 0x00220003 ++#define IOCTL_INTERNAL_USB_RESET_PORT 0x00220007 ++#define IOCTL_INTERNAL_USB_GET_PORT_STATUS 0x00220013 ++#define IOCTL_INTERNAL_USB_CYCLE_PORT 0x0022001F ++#define IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION 0x00220027 ++ ++#define URB_FUNCTION_SELECT_CONFIGURATION 0x0000 ++#define URB_FUNCTION_SELECT_INTERFACE 0x0001 ++#define URB_FUNCTION_ABORT_PIPE 0x0002 ++#define URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL 0x0003 ++#define URB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL 0x0004 ++#define URB_FUNCTION_GET_FRAME_LENGTH 0x0005 ++#define URB_FUNCTION_SET_FRAME_LENGTH 0x0006 ++#define URB_FUNCTION_GET_CURRENT_FRAME_NUMBER 0x0007 ++#define URB_FUNCTION_CONTROL_TRANSFER 0x0008 ++#define URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER 0x0009 ++#define URB_FUNCTION_ISOCH_TRANSFER 0x000A ++#define URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE 0x000B ++#define URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE 0x000C ++#define URB_FUNCTION_SET_FEATURE_TO_DEVICE 0x000D ++#define URB_FUNCTION_SET_FEATURE_TO_INTERFACE 0x000E ++#define URB_FUNCTION_SET_FEATURE_TO_ENDPOINT 0x000F ++#define URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE 0x0010 ++#define URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE 0x0011 ++#define URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT 0x0012 ++#define URB_FUNCTION_GET_STATUS_FROM_DEVICE 0x0013 ++#define URB_FUNCTION_GET_STATUS_FROM_INTERFACE 0x0014 ++#define URB_FUNCTION_GET_STATUS_FROM_ENDPOINT 0x0015 ++#define URB_FUNCTION_RESERVED_0X0016 0x0016 ++#define URB_FUNCTION_VENDOR_DEVICE 0x0017 ++#define URB_FUNCTION_VENDOR_INTERFACE 0x0018 ++#define URB_FUNCTION_VENDOR_ENDPOINT 0x0019 ++#define URB_FUNCTION_CLASS_DEVICE 0x001A ++#define URB_FUNCTION_CLASS_INTERFACE 0x001B ++#define URB_FUNCTION_CLASS_ENDPOINT 0x001C ++#define URB_FUNCTION_RESERVE_0X001D 0x001D ++#define URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL 0x001E ++#define URB_FUNCTION_CLASS_OTHER 0x001F ++#define URB_FUNCTION_VENDOR_OTHER 0x0020 ++#define URB_FUNCTION_GET_STATUS_FROM_OTHER 0x0021 ++#define URB_FUNCTION_CLEAR_FEATURE_TO_OTHER 0x0022 ++#define URB_FUNCTION_SET_FEATURE_TO_OTHER 0x0023 ++#define URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT 0x0024 ++#define URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT 0x0025 ++#define URB_FUNCTION_GET_CONFIGURATION 0x0026 ++#define URB_FUNCTION_GET_INTERFACE 0x0027 ++#define URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE 0x0028 ++#define URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE 0x0029 ++#define URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR 0x002A ++#define URB_FUNCTION_RESERVE_0X002B 0x002B ++#define URB_FUNCTION_RESERVE_0X002C 0x002C ++#define URB_FUNCTION_RESERVE_0X002D 0x002D ++#define URB_FUNCTION_RESERVE_0X002E 0x002E ++#define URB_FUNCTION_RESERVE_0X002F 0x002F ++// USB 2.0 calls start at 0x0030 ++#define URB_FUNCTION_SYNC_RESET_PIPE 0x0030 ++#define URB_FUNCTION_SYNC_CLEAR_STALL 0x0031 ++#define URB_FUNCTION_CONTROL_TRANSFER_EX 0x0032 ++ ++#define USBD_PF_CHANGE_MAX_PACKET 0x00000001 ++ ++#define USBD_TRANSFER_DIRECTION_OUT 0 ++#define USBD_TRANSFER_DIRECTION_IN 1 ++ ++#define USBD_SHORT_TRANSFER_OK 0x00000002 ++#define USBD_START_ISO_TRANSFER_ASAP 0x00000004 ++#define USBD_DEFAULT_PIPE_TRANSFER 0x00000008 ++ ++#define USBD_TRANSFER_DIRECTION(flags) \ ++ ((flags) & USBD_TRANSFER_DIRECTION_IN) ++ ++enum pipe_type {UsbdPipeTypeControl = USB_ENDPOINT_XFER_CONTROL, ++ UsbdPipeTypeIsochronous = USB_ENDPOINT_XFER_ISOC, ++ UsbdPipeTypeBulk = USB_ENDPOINT_XFER_BULK, ++ UsbdPipeTypeInterrupt = USB_ENDPOINT_XFER_INT}; ++ ++#define USBD_IS_BULK_PIPE(pipe_handle) \ ++ (((pipe_handle)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) \ ++ == USB_ENDPOINT_XFER_BULK) ++ ++#define USBD_IS_INT_PIPE(pipe_handle) \ ++ (((pipe_handle)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) \ ++ == USB_ENDPOINT_XFER_INT) ++ ++#define USBD_PORT_ENABLED 0x00000001 ++#define USBD_PORT_CONNECTED 0x00000002 ++ ++typedef LONG USBD_STATUS; ++ ++#define USBD_STATUS_SUCCESS 0x0 ++#define USBD_STATUS_PENDING 0x40000000 ++#define USBD_STATUS_CANCELED 0x00010000 ++ ++#define USBD_STATUS_CRC 0xC0000001 ++#define USBD_STATUS_BTSTUFF 0xC0000002 ++#define USBD_STATUS_DATA_TOGGLE_MISMATCH 0xC0000003 ++#define USBD_STATUS_STALL_PID 0xC0000004 ++#define USBD_STATUS_DEV_NOT_RESPONDING 0xC0000005 ++#define USBD_STATUS_PID_CHECK_FAILURE 0xC0000006 ++#define USBD_STATUS_UNEXPECTED_PID 0xC0000007 ++#define USBD_STATUS_DATA_OVERRUN 0xC0000008 ++#define USBD_STATUS_DATA_UNDERRUN 0xC0000009 ++#define USBD_STATUS_RESERVED1 0xC000000A ++#define USBD_STATUS_RESERVED2 0xC000000B ++#define USBD_STATUS_BUFFER_OVERRUN 0xC000000C ++#define USBD_STATUS_BUFFER_UNDERRUN 0xC000000D ++#define USBD_STATUS_NOT_ACCESSED 0xC000000F ++#define USBD_STATUS_FIFO 0xC0000010 ++#define USBD_STATUS_XACT_ERROR 0xC0000011 ++#define USBD_STATUS_BABBLE_DETECTED 0xC0000012 ++#define USBD_STATUS_DATA_BUFFER_ERROR 0xC0000013 ++ ++#define USBD_STATUS_NOT_SUPPORTED 0xC0000E00 ++#define USBD_STATUS_BUFFER_TOO_SMALL 0xC0003000 ++#define USBD_STATUS_TIMEOUT 0xC0006000 ++#define USBD_STATUS_DEVICE_GONE 0xC0007000 ++ ++#define USBD_STATUS_NO_MEMORY 0x80000100 ++#define USBD_STATUS_INVALID_URB_FUNCTION 0x80000200 ++#define USBD_STATUS_INVALID_PARAMETER 0x80000300 ++#define USBD_STATUS_REQUEST_FAILED 0x80000500 ++#define USBD_STATUS_INVALID_PIPE_HANDLE 0x80000600 ++#define USBD_STATUS_ERROR_SHORT_TRANSFER 0x80000900 ++ ++#define USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE PAGE_SIZE ++ ++struct urb_hcd_area { ++ void *reserved8[8]; ++}; ++ ++struct usbd_pipe_information { ++ USHORT wMaxPacketSize; ++ UCHAR bEndpointAddress; ++ UCHAR bInterval; ++ enum pipe_type type; ++ struct usb_endpoint_descriptor *handle; ++ ULONG max_tx_size; ++ ULONG flags; ++}; ++ ++struct usbd_interface_information { ++ USHORT bLength; ++ UCHAR bInterfaceNumber; ++ UCHAR bAlternateSetting; ++ UCHAR bInterfaceClass; ++ UCHAR bInterfaceSubClass; ++ UCHAR bInterfaceProtocol; ++ UCHAR reserved; ++ void *handle; ++ ULONG bNumEndpoints; ++ struct usbd_pipe_information pipes[1]; ++}; ++ ++struct usbd_interface_list_entry { ++ struct usb_interface_descriptor *intf_desc; ++ struct usbd_interface_information *intf; ++}; ++ ++struct nt_urb_header { ++ USHORT length; ++ USHORT function; ++ USBD_STATUS status; ++ void *usbd_dev_handle; ++ ULONG usbd_flags; ++}; ++ ++struct usbd_select_interface { ++ struct nt_urb_header header; ++ void *handle; ++ struct usbd_interface_information intf; ++}; ++ ++struct usbd_select_configuration { ++ struct nt_urb_header header; ++ struct usb_config_descriptor *config; ++ void *handle; ++ struct usbd_interface_information intf; ++}; ++ ++struct usbd_control_descriptor_request { ++ struct nt_urb_header header; ++ void *reserved; ++ ULONG reserved0; ++ ULONG transfer_buffer_length; ++ void *transfer_buffer; ++ struct mdl *mdl; ++ union nt_urb *urb_link; ++ struct urb_hcd_area hca; ++ USHORT reserved1; ++ UCHAR index; ++ UCHAR desc_type; ++ USHORT language_id; ++ USHORT reserved2; ++}; ++ ++struct usbd_bulk_or_intr_transfer { ++ struct nt_urb_header header; ++ struct usb_endpoint_descriptor *pipe_handle; ++ ULONG transfer_flags; ++ ULONG transfer_buffer_length; ++ void *transfer_buffer; ++ struct mdl *mdl; ++ union nt_urb *urb_link; ++ struct urb_hcd_area hca; ++}; ++ ++struct usbd_pipe_request { ++ struct nt_urb_header header; ++ struct usb_endpoint_descriptor *pipe_handle; ++}; ++ ++struct usbd_vendor_or_class_request { ++ struct nt_urb_header header; ++ void *reserved; ++ ULONG transfer_flags; ++ ULONG transfer_buffer_length; ++ void *transfer_buffer; ++ struct mdl *mdl; ++ union nt_urb *link; ++ struct urb_hcd_area hca; ++ UCHAR reserved_bits; ++ UCHAR request; ++ USHORT value; ++ USHORT index; ++ USHORT reserved1; ++}; ++ ++struct urb_control_feature_request { ++ struct nt_urb_header header; ++ void *reserved; ++ ULONG reserved2; ++ ULONG reserved3; ++ void *reserved4; ++ struct mdl *reserved5; ++ union nt_urb *link; ++ struct urb_hcd_area hca; ++ USHORT reserved0; ++ USHORT feature_selector; ++ USHORT index; ++ USHORT reserved1; ++}; ++ ++struct urb_control_get_status_request { ++ struct nt_urb_header header; ++ void *reserved; ++ ULONG reserved0; ++ ULONG transfer_buffer_length; ++ void *transfer_buffer; ++ struct mdl *mdl; ++ union nt_urb *link; ++ struct urb_hcd_area hca; ++ UCHAR reserved1[4]; ++ USHORT index; ++ USHORT reserved2; ++}; ++ ++struct usbd_iso_packet_desc { ++ ULONG offset; ++ ULONG length; ++ USBD_STATUS status; ++}; ++ ++struct usbd_isochronous_transfer { ++ struct nt_urb_header header; ++ struct usb_endpoint_descriptor *pipe_handle; ++ ULONG transfer_flags; ++ ULONG transfer_buffer_length; ++ void *transfer_buffer; ++ struct mdl *mdl; ++ union nt_urb *urb_link; ++ struct urb_hcd_area hca; ++ ULONG start_frame; ++ ULONG number_of_packets; ++ ULONG error_count; ++ struct usbd_iso_packet_desc iso_packet[1]; ++}; ++ ++union nt_urb { ++ struct nt_urb_header header; ++ struct usbd_select_interface select_intf; ++ struct usbd_select_configuration select_conf; ++ struct usbd_bulk_or_intr_transfer bulk_int_transfer; ++ struct usbd_control_descriptor_request control_desc; ++ struct usbd_vendor_or_class_request vendor_class_request; ++ struct usbd_isochronous_transfer isochronous; ++ struct usbd_pipe_request pipe_req; ++ struct urb_control_feature_request feat_req; ++ struct urb_control_get_status_request status_req; ++}; ++ ++struct usbd_bus_interface_usbdi { ++ USHORT Size; ++ USHORT Version; ++ void *Context; ++ void *InterfaceReference; ++ void *InterfaceDereference; ++ void *GetUSBDIVersion; ++ void *QueryBusTime; ++ void *SubmitIsoOutUrb; ++ void *QueryBusInformation; ++ /* version 1 and above have following field */ ++ void *IsDeviceHighSpeed; ++ /* version 2 (and above) have following field */ ++ void *LogEntry; ++}; ++ ++struct usbd_bus_information_level { ++ ULONG TotalBandwidth; ++ ULONG ConsumedBandwidth; ++ /* level 1 and above have following fields */ ++ ULONG ControllerNameLength; ++ wchar_t ControllerName[1]; ++}; ++ ++#define USBDI_VERSION_XP 0x00000500 // Windows XP ++#define USB_HCD_CAPS_SUPPORTS_RT_THREADS 0x00000001 ++#define USB_BUSIF_USBDI_VERSION_0 0x0000 ++#define USB_BUSIF_USBDI_VERSION_1 0x0001 ++#define USB_BUSIF_USBDI_VERSION_2 0x0002 ++ ++struct usbd_version_info { ++ ULONG usbdi_version; ++ ULONG supported_usb_version; ++}; ++ ++struct usbd_idle_callback { ++ void *callback; ++ void *context; ++}; ++ ++#define NT_URB_STATUS(nt_urb) ((nt_urb)->header.status) ++ ++NTSTATUS wrap_submit_irp(struct device_object *pdo, struct irp *irp); ++void wrap_suspend_urbs(struct wrap_device *wd); ++void wrap_resume_urbs(struct wrap_device *wd); ++NTSTATUS usb_query_interface(struct wrap_device *wd, ++ struct io_stack_location *irp_sl); ++ ++#endif /* USB_H */ +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/win2lin_stubs.S linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/win2lin_stubs.S +--- linux-3.12.2/3rdparty/ndiswrapper/win2lin_stubs.S 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/win2lin_stubs.S 2013-11-28 21:42:11.000000000 +0200 +@@ -0,0 +1,253 @@ ++/* ++ * Copyright (C) 2005 Karl Vogel, Giridhar Pemmasani ++ * ++ * 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 ++ ++#ifdef CONFIG_X86_64 ++ ++/* ++# Windows <---> Linux register usage conversion when calling functions ++# V = Volatile ++# NV = Non Volatile (needs to be saved) ++# ++# Win Lin ++# --------------------------------------- ++# Rax Return V Return V ++# Rbx NV NV ++# Rcx Arg1 V Arg4 V ++# Rdx Arg2 V Arg3 V ++# Rsi NV Arg2 V ++# Rdi NV Arg1 V ++# Rsp NV NV ++# Rbp NV NV ++# R8 Arg3 V Arg5 V ++# R9 Arg4 V Arg6 V ++# R10 V V ++# R11 V V ++# R12 NV NV ++# R13 NV NV ++# R14 NV NV ++# R15 NV NV ++# ++# In addition, Linux uses %rax to indicate number of SSE registers used ++# when variadic functions are called. Since there is no way to obtain this ++# from Windows, for now, we just assume this is 0 (hence %rax is cleared). ++# ++# Windows pushes arguments 5 and higher onto stack in case of integer ++# variables and 4 and higher in case of floating point variables (passed ++# in SSE registers). ++ ++In a windows function, the stackframe/registers look like this: ++ ++# 0x0048 .... ++# 0x0040 arg8 ++# 0x0038 arg7 ++# 0x0030 arg6 ++# 0x0028 arg5 ++# 0x0020 shadow/spill space for arg4 ++# 0x0018 shadow/spill space for arg3 ++# 0x0010 shadow/spill space for arg2 ++# 0x0008 shadow/spill space for arg1 ++# 0x0000 ret ++ ++# register spill space is same irrespective of number of arguments - even ++# if Windows function takes less than 4 arguments, 32 bytes above return ++# address is reserved for the function ++ ++In Linux it should look like: ++ ++# 0x0018 .... ++# 0x0010 arg8 ++# 0x0008 arg7 ++# 0x0000 ret ++ ++*/ ++ ++ .text ++ ++#define LINUX_REG_ARGS 6 ++#define LOOP_THRESHOLD 9 ++#define WORD_BYTES 8 ++ ++/* ++ * %rsi and %rdi must be saved because they are not saved by Linux calls, but ++ * Windows callers expect them to be saved. %rbp is saved to create a stack ++ * frame, which can help with debugging. We need to reserve space for an odd ++ * number of registers anyway to keep 16-bit alignment of the stack (one more ++ * position is used by the return address). ++ */ ++#define SAVED_REGS 3 ++ ++/* ++ * When calling the Linux function, several registers are saved on the stack. ++ * When passing more than 6 arguments, arguments starting with argument 7 are ++ * pushed to the stack as well. ++ * ++ * We also need to allocate an additional word on the stack to keep it aligned ++ * to the 16-bit boundary if the number of saved arguments plus one (for the ++ * return address) is odd. ++ */ ++ ++/* ++ * Number of arguments we pass on stack to the Linux function. ++ * The value of true is -1 in assembler, so we multiply it by another true ++ * value. ++ */ ++#define stack_args(argc) \ ++ ((0 < 1) * (argc > LINUX_REG_ARGS) * (argc - LINUX_REG_ARGS)) ++ ++/* Full required change of stack pointer, in words */ ++#define stack_words_raw(argc) (stack_args(argc) + SAVED_REGS + 1) ++ ++/* Full actual change of stack pointer, in words (must be even) */ ++#define stack_words_aligned(argc) ((stack_words_raw(argc) + 1) & ~1) ++ ++/* Space allocated for Linux arguments on stack */ ++#define stack_space(argc) \ ++ ((stack_words_aligned(argc) - SAVED_REGS - 1) * WORD_BYTES) ++ ++/* ++ * win2lin_win_arg(N, ARGC) gives the address of the Windows argument N out of ++ * total ARGC after the stack has been prepared for the Linux function call. ++ * ++ * When called from Windows, the Nth argument is at (N * 8)(%rsp). We add the ++ * stack space allocated by the Linux function to compensate for %rsp change. ++ * ++ * Don't call with N less than 5! ++ */ ++#define win2lin_win_arg(n, argc) \ ++ ((n + SAVED_REGS) * WORD_BYTES + stack_space(argc))(%rsp) ++ ++/* ++ * win2lin_lin_arg(N) gives the address of the Nth Linux argument on the extra ++ * Linux stack frame. When more than 6 arguments are used, %rsp points to the ++ * 7th argument. The Nth argument is therefore at ((N - 7) * 8)(%rsp). ++ * ++ * Don't call with N less than 7! ++ */ ++#define win2lin_lin_arg(n) ((n - 1 - LINUX_REG_ARGS) * WORD_BYTES)(%rsp) ++ ++/* Declare function LONGNAME, call function SHORTNAME with ARGC arguments */ ++.macro win2linm longname, shortname, argc ++ .type \longname, @function ++ ENTRY(\longname) ++ ++ /* Create a call frame - it's optional, but good for debugging */ ++ .cfi_startproc ++ push %rbp ++ .cfi_def_cfa %rsp, 2 * WORD_BYTES ++ .cfi_offset %rbp, -2 * WORD_BYTES ++ mov %rsp, %rbp ++ .cfi_def_cfa %rbp, 2 * WORD_BYTES ++ ++ /* ++ * Registers %rdi and %rsi are volatile on Linux, but not on Windows, ++ * so save them on the stack. ++ */ ++ push %rsi ++ push %rdi ++ ++ /* Allocate extra stack space for arguments 7 and up */ ++ sub $stack_space(\argc), %rsp ++ ++ /* ++ * Copy arguments 7 and up. We do it early, before %rdi and %rsi ++ * are used for arguments 1 and 2, so we don't have to save them. ++ * We still need to save %rcx if using a string copy. ++ */ ++ .if (\argc < LOOP_THRESHOLD) ++ /* If a few arguments, copy them individually through %r11 */ ++ .if (\argc >= 7) ++ mov win2lin_win_arg(7, \argc), %r11 ++ mov %r11, win2lin_lin_arg(7) ++ .endif ++ .if (\argc >= 8) ++ mov win2lin_win_arg(8, \argc), %r11 ++ mov %r11, win2lin_lin_arg(8) ++ .endif ++ .else ++ /* If there are many arguments, copy them in a loop */ ++ /* Save arg1 to %r11 */ ++ mov %rcx, %r11 ++ /* Source and destination */ ++ lea win2lin_win_arg(LINUX_REG_ARGS + 1, \argc), %rsi ++ lea win2lin_lin_arg(LINUX_REG_ARGS + 1), %rdi ++ /* Number of arguments to copy (%ecx zero-extends to %rcx) */ ++ mov $(\argc - LINUX_REG_ARGS), %ecx ++ rep movsq ++ /* Restore arg1 directly to %rdi */ ++ mov %r11, %rdi ++ .endif ++ ++ /* ++ * Argument 1 - %rcx on Windows, %rdi on Linux ++ * Micro-optimization - if we used loop, arg1 is already in %rdi ++ */ ++ .if (\argc >= 1) && (\argc < LOOP_THRESHOLD) ++ mov %rcx, %rdi ++ .endif ++ ++ /* Argument 2 - %rdx on Windows, %rsi on Linux */ ++ .if (\argc >= 2) ++ mov %rdx, %rsi ++ .endif ++ ++ /* Argument 3 - %r8 on Windows, %rdx on Linux */ ++ .if (\argc >= 3) ++ mov %r8, %rdx ++ .endif ++ ++ /* Argument 4 - %r9 on Windows, %rcx on Linux */ ++ .if (\argc >= 4) ++ mov %r9, %rcx ++ .endif ++ ++ /* Argument 5 - first argument on stack on Windows, %r8 Linux */ ++ .if (\argc >= 5) ++ mov win2lin_win_arg(5, \argc), %r8 ++ .endif ++ ++ /* Argument 6 - second argument on stack on Windows, %r9 Linux */ ++ .if (\argc >= 6) ++ mov win2lin_win_arg(6, \argc), %r9 ++ .endif ++ ++ /* %rax on Linux is the number of arguments in SSE registers (zero) */ ++ xor %rax, %rax ++ ++ /* Call the function */ ++ call \shortname ++ ++ /* Free stack space for arguments 7 and up */ ++ add $stack_space(\argc), %rsp ++ ++ /* Restore saved registers */ ++ pop %rdi ++ pop %rsi ++ ++ /* Return to Windows code */ ++ leave ++ .cfi_def_cfa %rsp, WORD_BYTES ++ .cfi_restore %rbp ++ ret ++ .cfi_endproc ++ .size \longname, (. - \longname) ++.endm ++ ++#define win2lin(name, argc) win2linm win2lin_ ## name ## _ ## argc, name, argc ++ ++#include "win2lin_stubs.h" ++ ++#endif /* CONFIG_X86_64 */ +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/winnt_types.h linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/winnt_types.h +--- linux-3.12.2/3rdparty/ndiswrapper/winnt_types.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/winnt_types.h 2013-11-28 21:42:11.000000000 +0200 +@@ -0,0 +1,1701 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * 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 _WINNT_TYPES_H_ ++#define _WINNT_TYPES_H_ ++ ++#define TRUE 1 ++#define FALSE 0 ++ ++#define PASSIVE_LEVEL 0 ++#define APC_LEVEL 1 ++#define DISPATCH_LEVEL 2 ++#define DEVICE_LEVEL_BASE 4 ++ ++/* soft interrupts / bottom-half's are disabled at SOFT_IRQL */ ++#define SOFT_IRQL (DEVICE_LEVEL_BASE + 1) ++#define DIRQL (DEVICE_LEVEL_BASE + 2) ++ ++#define STATUS_WAIT_0 0 ++#define STATUS_SUCCESS 0 ++#define STATUS_ALERTED 0x00000101 ++#define STATUS_TIMEOUT 0x00000102 ++#define STATUS_PENDING 0x00000103 ++#define STATUS_FAILURE 0xC0000001 ++#define STATUS_NOT_IMPLEMENTED 0xC0000002 ++#define STATUS_INVALID_PARAMETER 0xC000000D ++#define STATUS_INVALID_DEVICE_REQUEST 0xC0000010 ++#define STATUS_MORE_PROCESSING_REQUIRED 0xC0000016 ++#define STATUS_ACCESS_DENIED 0xC0000022 ++#define STATUS_BUFFER_TOO_SMALL 0xC0000023 ++#define STATUS_OBJECT_NAME_INVALID 0xC0000023 ++#define STATUS_MUTANT_NOT_OWNED 0xC0000046 ++#define STATUS_RESOURCES 0xC000009A ++#define STATUS_DELETE_PENDING 0xC0000056 ++#define STATUS_INSUFFICIENT_RESOURCES 0xC000009A ++#define STATUS_NOT_SUPPORTED 0xC00000BB ++#define STATUS_INVALID_PARAMETER_2 0xC00000F0 ++#define STATUS_NO_MEMORY 0xC0000017 ++#define STATUS_CANCELLED 0xC0000120 ++#define STATUS_DEVICE_REMOVED 0xC00002B6 ++#define STATUS_DEVICE_NOT_CONNECTED 0xC000009D ++ ++#define STATUS_BUFFER_OVERFLOW 0x80000005 ++ ++#define SL_PENDING_RETURNED 0x01 ++#define SL_INVOKE_ON_CANCEL 0x20 ++#define SL_INVOKE_ON_SUCCESS 0x40 ++#define SL_INVOKE_ON_ERROR 0x80 ++ ++#define IRP_MJ_CREATE 0x00 ++#define IRP_MJ_CREATE_NAMED_PIPE 0x01 ++#define IRP_MJ_CLOSE 0x02 ++#define IRP_MJ_READ 0x03 ++#define IRP_MJ_WRITE 0x04 ++ ++#define IRP_MJ_DEVICE_CONTROL 0x0E ++#define IRP_MJ_INTERNAL_DEVICE_CONTROL 0x0F ++#define IRP_MJ_POWER 0x16 ++#define IRP_MJ_SYSTEM_CONTROL 0x0E ++#define IRP_MJ_PNP 0x1b ++#define IRP_MJ_MAXIMUM_FUNCTION 0x1b ++ ++#define IRP_MN_WAIT_WAKE 0x00 ++#define IRP_MN_POWER_SEQUENCE 0x01 ++#define IRP_MN_SET_POWER 0x02 ++#define IRP_MN_QUERY_POWER 0x03 ++ ++#define IRP_MN_REGINFO 0x08 ++#define IRP_MN_REGINFO_EX 0x0b ++ ++#define IRP_MN_START_DEVICE 0x00 ++#define IRP_MN_QUERY_REMOVE_DEVICE 0x01 ++#define IRP_MN_REMOVE_DEVICE 0x02 ++#define IRP_MN_CANCEL_REMOVE_DEVICE 0x03 ++#define IRP_MN_STOP_DEVICE 0x04 ++#define IRP_MN_QUERY_STOP_DEVICE 0x05 ++#define IRP_MN_CANCEL_STOP_DEVICE 0x06 ++#define IRP_MN_QUERY_DEVICE_RELATIONS 0x07 ++#define IRP_MN_QUERY_INTERFACE 0x08 ++ ++#define IRP_BUFFERED_IO 0x00000010 ++#define IRP_DEALLOCATE_BUFFER 0x00000020 ++#define IRP_INPUT_OPERATION 0x00000040 ++ ++#define IRP_DEFFER_IO_COMPLETION 0x00000800 ++ ++#define THREAD_WAIT_OBJECTS 3 ++#define MAX_WAIT_OBJECTS 64 ++ ++#define LOW_PRIORITY 0 ++#define LOW_REALTIME_PRIORITY 16 ++#define HIGH_PRIORITY 31 ++#define MAXIMUM_PRIORITY 32 ++ ++#define PROCESSOR_FEATURE_MAX 64 ++ ++#define IO_NO_INCREMENT 0 ++ ++#define WMIREG_ACTION_REGISTER 1 ++#define WMIREG_ACTION_DEREGISTER 2 ++#define WMIREG_ACTION_REREGISTER 3 ++#define WMIREG_ACTION_UPDATE_GUIDS 4 ++ ++#define WMIREGISTER 0 ++#define WMIUPDATE 1 ++ ++#ifdef CONFIG_X86_64 ++#define wstdcall ++#define wfastcall ++#define noregparm ++#define regparm3 ++ ++#define KI_USER_SHARED_DATA 0xfffff78000000000UL ++ ++#else ++ ++#define noregparm __attribute__((regparm(0))) ++#define regparm3 __attribute__((regparm(3))) ++#define wstdcall __attribute__((__stdcall__, regparm(0))) ++#if defined(__GNUC__) && ((__GNUC__ == 3 && __GNUC_MINOR__ > 3) || __GNUC__ > 3) ++#undef fastcall ++#define wfastcall __attribute__((fastcall)) ++#else ++#error "gcc 3.4 or newer should be used for compiling this module" ++#endif ++ ++#define KI_USER_SHARED_DATA 0xffdf0000 ++ ++#endif ++ ++typedef u8 BOOLEAN; ++typedef u8 BYTE; ++typedef u8 *LPBYTE; ++typedef s8 CHAR; ++typedef u8 UCHAR; ++typedef s16 SHORT; ++typedef u16 USHORT; ++typedef u16 WORD; ++typedef s32 INT; ++typedef u32 UINT; ++typedef u32 DWORD; ++typedef s32 LONG; ++typedef u32 ULONG; ++typedef s64 LONGLONG; ++typedef u64 ULONGLONG; ++typedef u64 ULONGULONG; ++typedef u64 ULONG64; ++ ++typedef CHAR CCHAR; ++typedef USHORT wchar_t; ++typedef SHORT CSHORT; ++typedef LONGLONG LARGE_INTEGER; ++ ++typedef LONG NTSTATUS; ++ ++typedef LONG KPRIORITY; ++typedef LARGE_INTEGER PHYSICAL_ADDRESS; ++typedef UCHAR KIRQL; ++typedef CHAR KPROCESSOR_MODE; ++ ++/* ULONG_PTR is 32 bits on 32-bit platforms and 64 bits on 64-bit ++ * platform, which is same as 'unsigned long' in Linux */ ++typedef unsigned long ULONG_PTR; ++ ++typedef size_t SIZE_T; ++typedef ULONG_PTR KAFFINITY; ++typedef ULONG ACCESS_MASK; ++ ++typedef ULONG_PTR PFN_NUMBER; ++typedef ULONG SECURITY_INFORMATION; ++ ++/* non-negative numbers indicate success */ ++#define NT_SUCCESS(status) ((NTSTATUS)(status) >= 0) ++ ++struct ansi_string { ++ USHORT length; ++ USHORT max_length; ++ char *buf; ++}; ++ ++struct unicode_string { ++ USHORT length; ++ USHORT max_length; ++ wchar_t *buf; ++}; ++ ++struct nt_slist { ++ struct nt_slist *next; ++}; ++ ++#ifdef CONFIG_X86_64 ++/* it is not clear how nt_slist_head is used to store pointer to ++ * slists and depth; here we assume 'align' field is used to store ++ * depth and 'region' field is used to store slist pointers */ ++struct nt_slist_head { ++ union { ++ USHORT depth; ++ ULONGLONG align; ++ }; ++ union { ++ ULONGLONG region; ++ struct nt_slist *next; ++ }; ++} __attribute__((aligned(16))); ++typedef struct nt_slist_head nt_slist_header; ++#else ++union nt_slist_head { ++ ULONGLONG align; ++ struct { ++ struct nt_slist *next; ++ USHORT depth; ++ USHORT sequence; ++ }; ++}; ++typedef union nt_slist_head nt_slist_header; ++#endif ++ ++struct nt_list { ++ struct nt_list *next; ++ struct nt_list *prev; ++}; ++ ++typedef ULONG_PTR NT_SPIN_LOCK; ++ ++enum kdpc_importance {LowImportance, MediumImportance, HighImportance}; ++ ++struct kdpc; ++typedef void (*DPC)(struct kdpc *kdpc, void *ctx, void *arg1, ++ void *arg2) wstdcall; ++struct kdpc { ++ SHORT type; ++ UCHAR nr_cpu; ++ UCHAR importance; ++ struct nt_list list; ++ DPC func; ++ void *ctx; ++ void *arg1; ++ void *arg2; ++ union { ++ NT_SPIN_LOCK *lock; ++ /* 'lock' is not used; 'queued' represents whether ++ * kdpc is queued or not */ ++ int queued; ++ }; ++}; ++ ++enum pool_type { ++ NonPagedPool, PagedPool, NonPagedPoolMustSucceed, DontUseThisType, ++ NonPagedPoolCacheAligned, PagedPoolCacheAligned, ++ NonPagedPoolCacheAlignedMustS, MaxPoolType, ++ NonPagedPoolSession = 32, ++ PagedPoolSession = NonPagedPoolSession + 1, ++ NonPagedPoolMustSucceedSession = PagedPoolSession + 1, ++ DontUseThisTypeSession = NonPagedPoolMustSucceedSession + 1, ++ NonPagedPoolCacheAlignedSession = DontUseThisTypeSession + 1, ++ PagedPoolCacheAlignedSession = NonPagedPoolCacheAlignedSession + 1, ++ NonPagedPoolCacheAlignedMustSSession = PagedPoolCacheAlignedSession + 1 ++}; ++ ++enum memory_caching_type_orig { ++ MmFrameBufferCached = 2 ++}; ++ ++enum memory_caching_type { ++ MmNonCached = FALSE, MmCached = TRUE, ++ MmWriteCombined = MmFrameBufferCached, MmHardwareCoherentCached, ++ MmNonCachedUnordered, MmUSWCCached, MmMaximumCacheType ++}; ++ ++enum lock_operation { ++ IoReadAccess, IoWriteAccess, IoModifyAccess ++}; ++ ++enum mode { ++ KernelMode, UserMode, MaximumMode ++}; ++ ++struct mdl { ++ struct mdl *next; ++ CSHORT size; ++ CSHORT flags; ++ /* NdisFreeBuffer doesn't pass pool, so we store pool in ++ * unused field 'process' */ ++ union { ++ void *process; ++ void *pool; ++ }; ++ void *mappedsystemva; ++ void *startva; ++ ULONG bytecount; ++ ULONG byteoffset; ++}; ++ ++#define MDL_MAPPED_TO_SYSTEM_VA 0x0001 ++#define MDL_PAGES_LOCKED 0x0002 ++#define MDL_SOURCE_IS_NONPAGED_POOL 0x0004 ++#define MDL_ALLOCATED_FIXED_SIZE 0x0008 ++#define MDL_PARTIAL 0x0010 ++#define MDL_PARTIAL_HAS_BEEN_MAPPED 0x0020 ++#define MDL_IO_PAGE_READ 0x0040 ++#define MDL_WRITE_OPERATION 0x0080 ++#define MDL_PARENT_MAPPED_SYSTEM_VA 0x0100 ++#define MDL_FREE_EXTRA_PTES 0x0200 ++#define MDL_IO_SPACE 0x0800 ++#define MDL_NETWORK_HEADER 0x1000 ++#define MDL_MAPPING_CAN_FAIL 0x2000 ++#define MDL_ALLOCATED_MUST_SUCCEED 0x4000 ++ ++#define MDL_POOL_ALLOCATED 0x0400 ++#define MDL_CACHE_ALLOCATED 0x8000 ++ ++#define PAGE_START(ptr) ((void *)((ULONG_PTR)(ptr) & ~(PAGE_SIZE - 1))) ++#define BYTE_OFFSET(ptr) ((ULONG)((ULONG_PTR)(ptr) & (PAGE_SIZE - 1))) ++ ++#define MmGetMdlByteCount(mdl) ((mdl)->bytecount) ++#define MmGetMdlVirtualAddress(mdl) ((mdl)->startva + (mdl)->byteoffset) ++#define MmGetMdlByteOffset(mdl) ((mdl)->byteoffset) ++#define MmGetSystemAddressForMdl(mdl) ((mdl)->mappedsystemva) ++#define MmGetSystemAddressForMdlSafe(mdl, priority) ((mdl)->mappedsystemva) ++#define MmGetMdlPfnArray(mdl) ((PFN_NUMBER *)(mdl + 1)) ++#define MmInitializeMdl(mdl, baseva, length) \ ++do { \ ++ (mdl)->next = NULL; \ ++ (mdl)->size = MmSizeOfMdl(baseva, length); \ ++ (mdl)->flags = 0; \ ++ (mdl)->startva = PAGE_START(baseva); \ ++ (mdl)->byteoffset = BYTE_OFFSET(baseva); \ ++ (mdl)->bytecount = length; \ ++ (mdl)->mappedsystemva = baseva; \ ++ TRACE4("%p %p %p %d %d", (mdl), baseva, (mdl)->startva, \ ++ (mdl)->byteoffset, length); \ ++} while (0) ++ ++struct kdevice_queue_entry { ++ struct nt_list list; ++ ULONG sort_key; ++ BOOLEAN inserted; ++}; ++ ++struct kdevice_queue { ++ USHORT type; ++ USHORT size; ++ struct nt_list list; ++ NT_SPIN_LOCK lock; ++ BOOLEAN busy; ++}; ++ ++struct wait_context_block { ++ struct kdevice_queue_entry wait_queue_entry; ++ void *device_routine; ++ void *device_context; ++ ULONG num_regs; ++ void *device_object; ++ void *current_irp; ++ void *buffer_chaining_dpc; ++}; ++ ++struct wait_block { ++ struct nt_list list; ++ struct task_struct *thread; ++ void *object; ++ int *wait_done; ++ USHORT wait_key; ++ USHORT wait_type; ++}; ++ ++struct dispatcher_header { ++ UCHAR type; ++ UCHAR absolute; ++ UCHAR size; ++ UCHAR inserted; ++ LONG signal_state; ++ struct nt_list wait_blocks; ++}; ++ ++enum event_type { ++ NotificationEvent, ++ SynchronizationEvent, ++}; ++ ++enum timer_type { ++ NotificationTimer = NotificationEvent, ++ SynchronizationTimer = SynchronizationEvent, ++}; ++ ++enum dh_type { ++ NotificationObject = NotificationEvent, ++ SynchronizationObject = SynchronizationEvent, ++ MutexObject, ++ SemaphoreObject, ++ ThreadObject, ++}; ++ ++enum wait_type { ++ WaitAll, WaitAny ++}; ++ ++/* objects that use dispatcher_header have it as the first field, so ++ * whenever we need to initialize dispatcher_header, we can convert ++ * that object into a nt_event and access dispatcher_header */ ++struct nt_event { ++ struct dispatcher_header dh; ++}; ++ ++struct wrap_timer; ++ ++#define WRAP_TIMER_MAGIC 47697249 ++ ++struct nt_timer { ++ struct dispatcher_header dh; ++ /* We can't fit Linux timer in this structure. Instead of ++ * padding the nt_timer structure, we replace due_time field ++ * with *wrap_timer and allocate memory for it when nt_timer is ++ * initialized */ ++ union { ++ ULONGLONG due_time; ++ struct wrap_timer *wrap_timer; ++ }; ++ struct nt_list nt_timer_list; ++ struct kdpc *kdpc; ++ union { ++ LONG period; ++ LONG wrap_timer_magic; ++ }; ++}; ++ ++struct nt_mutex { ++ struct dispatcher_header dh; ++ struct nt_list list; ++ struct task_struct *owner_thread; ++ BOOLEAN abandoned; ++ BOOLEAN apc_disable; ++}; ++ ++struct nt_semaphore { ++ struct dispatcher_header dh; ++ LONG limit; ++}; ++ ++struct nt_thread { ++ struct dispatcher_header dh; ++ /* the rest in Windows is a long structure; since this ++ * structure is opaque to drivers, we just define what we ++ * need */ ++ int pid; ++ NTSTATUS status; ++ struct task_struct *task; ++ struct nt_list irps; ++ NT_SPIN_LOCK lock; ++ KPRIORITY prio; ++}; ++ ++#define set_object_type(dh, type) ((dh)->type = (type)) ++#define is_notify_object(dh) ((dh)->type == NotificationObject) ++#define is_synch_object(dh) ((dh)->type == SynchronizationObject) ++#define is_mutex_object(dh) ((dh)->type == MutexObject) ++#define is_semaphore_object(dh) ((dh)->type == SemaphoreObject) ++#define is_nt_thread_object(dh) ((dh)->type == ThreadObject) ++ ++#define IO_TYPE_ADAPTER 1 ++#define IO_TYPE_CONTROLLER 2 ++#define IO_TYPE_DEVICE 3 ++#define IO_TYPE_DRIVER 4 ++#define IO_TYPE_FILE 5 ++#define IO_TYPE_IRP 6 ++#define IO_TYPE_DEVICE_OBJECT_EXTENSION 13 ++ ++struct irp; ++struct dev_obj_ext; ++struct driver_object; ++ ++struct device_object { ++ CSHORT type; ++ USHORT size; ++ LONG ref_count; ++ struct driver_object *drv_obj; ++ struct device_object *next; ++ struct device_object *attached; ++ struct irp *current_irp; ++ void *io_timer; ++ ULONG flags; ++ ULONG characteristics; ++ void *vpb; ++ void *dev_ext; ++ CCHAR stack_count; ++ union { ++ struct nt_list queue_list; ++ struct wait_context_block wcb; ++ } queue; ++ ULONG align_req; ++ struct kdevice_queue dev_queue; ++ struct kdpc dpc; ++ ULONG active_threads; ++ void *security_desc; ++ struct nt_event lock; ++ USHORT sector_size; ++ USHORT spare1; ++ struct dev_obj_ext *dev_obj_ext; ++ void *reserved; ++}; ++ ++struct dev_obj_ext { ++ CSHORT type; ++ CSHORT size; ++ struct device_object *dev_obj; ++ struct device_object *attached_to; ++}; ++ ++struct io_status_block { ++ union { ++ NTSTATUS status; ++ void *pointer; ++ }; ++ ULONG_PTR info; ++}; ++ ++#ifdef CONFIG_X86_64 ++struct io_status_block32 { ++ NTSTATUS status; ++ ULONG info; ++}; ++#endif ++ ++#define DEVICE_TYPE ULONG ++ ++struct driver_extension; ++ ++typedef NTSTATUS driver_dispatch_t(struct device_object *dev_obj, ++ struct irp *irp) wstdcall; ++ ++struct driver_object { ++ CSHORT type; ++ CSHORT size; ++ struct device_object *dev_obj; ++ ULONG flags; ++ void *start; ++ ULONG driver_size; ++ void *section; ++ struct driver_extension *drv_ext; ++ struct unicode_string name; ++ struct unicode_string *hardware_database; ++ void *fast_io_dispatch; ++ void *init; ++ void *start_io; ++ void (*unload)(struct driver_object *driver) wstdcall; ++ driver_dispatch_t *major_func[IRP_MJ_MAXIMUM_FUNCTION + 1]; ++}; ++ ++struct driver_extension { ++ struct driver_object *drv_obj; ++ NTSTATUS (*add_device)(struct driver_object *drv_obj, ++ struct device_object *dev_obj); ++ ULONG count; ++ struct unicode_string service_key_name; ++ struct nt_list custom_ext; ++}; ++ ++struct custom_ext { ++ struct nt_list list; ++ void *client_id; ++}; ++ ++struct wrap_bin_file; ++ ++struct file_object { ++ CSHORT type; ++ CSHORT size; ++ struct device_object *dev_obj; ++ void *volume_parameter_block; ++ void *fs_context; ++ void *fs_context2; ++ void *section_object_pointer; ++ void *private_cache_map; ++ NTSTATUS final_status; ++ union { ++ struct file_object *related_file_object; ++ struct wrap_bin_file *wrap_bin_file; ++ }; ++ BOOLEAN lock_operation; ++ BOOLEAN delete_pending; ++ BOOLEAN read_access; ++ BOOLEAN write_access; ++ BOOLEAN delete_access; ++ BOOLEAN shared_read; ++ BOOLEAN shared_write; ++ BOOLEAN shared_delete; ++ ULONG flags; ++ struct unicode_string _name_; ++ LARGE_INTEGER current_byte_offset; ++ ULONG waiters; ++ ULONG busy; ++ void *last_lock; ++ struct nt_event lock; ++ struct nt_event event; ++ void *completion_context; ++}; ++ ++#ifdef CONFIG_X86_64 ++#define POINTER_ALIGN __attribute__((aligned(8))) ++#else ++#define POINTER_ALIGN ++#endif ++ ++#define CACHE_ALIGN __attribute__((aligned(128))) ++ ++enum system_power_state { ++ PowerSystemUnspecified = 0, ++ PowerSystemWorking, PowerSystemSleeping1, PowerSystemSleeping2, ++ PowerSystemSleeping3, PowerSystemHibernate, PowerSystemShutdown, ++ PowerSystemMaximum, ++}; ++ ++enum device_power_state { ++ PowerDeviceUnspecified = 0, ++ PowerDeviceD0, PowerDeviceD1, PowerDeviceD2, PowerDeviceD3, ++ PowerDeviceMaximum, ++}; ++ ++union power_state { ++ enum system_power_state system_state; ++ enum device_power_state device_state; ++}; ++ ++enum power_state_type { ++ SystemPowerState = 0, DevicePowerState, ++}; ++ ++enum power_action { ++ PowerActionNone = 0, ++ PowerActionReserved, PowerActionSleep, PowerActionHibernate, ++ PowerActionShutdown, PowerActionShutdownReset, PowerActionShutdownOff, ++ PowerActionWarmEject, ++}; ++ ++struct guid { ++ ULONG data1; ++ USHORT data2; ++ USHORT data3; ++ UCHAR data4[8]; ++}; ++ ++struct nt_interface { ++ USHORT size; ++ USHORT version; ++ void *context; ++ void (*reference)(void *context) wstdcall; ++ void (*dereference)(void *context) wstdcall; ++}; ++ ++enum interface_type { ++ InterfaceTypeUndefined = -1, Internal, Isa, Eisa, MicroChannel, ++ TurboChannel, PCIBus, VMEBus, NuBus, PCMCIABus, CBus, MPIBus, ++ MPSABus, ProcessorInternal, InternalPowerBus, PNPISABus, ++ PNPBus, MaximumInterfaceType, ++}; ++ ++#define CmResourceTypeNull 0 ++#define CmResourceTypePort 1 ++#define CmResourceTypeInterrupt 2 ++#define CmResourceTypeMemory 3 ++#define CmResourceTypeDma 4 ++#define CmResourceTypeDeviceSpecific 5 ++#define CmResourceTypeBusNumber 6 ++#define CmResourceTypeMaximum 7 ++ ++#define CmResourceTypeNonArbitrated 128 ++#define CmResourceTypeConfigData 128 ++#define CmResourceTypeDevicePrivate 129 ++#define CmResourceTypePcCardConfig 130 ++#define CmResourceTypeMfCardConfig 131 ++ ++enum cm_share_disposition { ++ CmResourceShareUndetermined = 0, CmResourceShareDeviceExclusive, ++ CmResourceShareDriverExclusive, CmResourceShareShared ++}; ++ ++#define CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE 0 ++#define CM_RESOURCE_INTERRUPT_LATCHED 1 ++#define CM_RESOURCE_MEMORY_READ_WRITE 0x0000 ++#define CM_RESOURCE_MEMORY_READ_ONLY 0x0001 ++#define CM_RESOURCE_MEMORY_WRITE_ONLY 0x0002 ++#define CM_RESOURCE_MEMORY_PREFETCHABLE 0x0004 ++ ++#define CM_RESOURCE_MEMORY_COMBINEDWRITE 0x0008 ++#define CM_RESOURCE_MEMORY_24 0x0010 ++#define CM_RESOURCE_MEMORY_CACHEABLE 0x0020 ++ ++#define CM_RESOURCE_PORT_MEMORY 0x0000 ++#define CM_RESOURCE_PORT_IO 0x0001 ++#define CM_RESOURCE_PORT_10_BIT_DECODE 0x0004 ++#define CM_RESOURCE_PORT_12_BIT_DECODE 0x0008 ++#define CM_RESOURCE_PORT_16_BIT_DECODE 0x0010 ++#define CM_RESOURCE_PORT_POSITIVE_DECODE 0x0020 ++#define CM_RESOURCE_PORT_PASSIVE_DECODE 0x0040 ++#define CM_RESOURCE_PORT_WINDOW_DECODE 0x0080 ++ ++#define CM_RESOURCE_DMA_8 0x0000 ++#define CM_RESOURCE_DMA_16 0x0001 ++#define CM_RESOURCE_DMA_32 0x0002 ++#define CM_RESOURCE_DMA_8_AND_16 0x0004 ++#define CM_RESOURCE_DMA_BUS_MASTER 0x0008 ++#define CM_RESOURCE_DMA_TYPE_A 0x0010 ++#define CM_RESOURCE_DMA_TYPE_B 0x0020 ++#define CM_RESOURCE_DMA_TYPE_F 0x0040 ++ ++#define MAX_RESOURCES 20 ++ ++#pragma pack(push,4) ++struct cm_partial_resource_descriptor { ++ UCHAR type; ++ UCHAR share; ++ USHORT flags; ++ union { ++ struct { ++ PHYSICAL_ADDRESS start; ++ ULONG length; ++ } generic; ++ struct { ++ PHYSICAL_ADDRESS start; ++ ULONG length; ++ } port; ++ struct { ++ ULONG level; ++ ULONG vector; ++ KAFFINITY affinity; ++ } interrupt; ++ struct { ++ PHYSICAL_ADDRESS start; ++ ULONG length; ++ } memory; ++ struct { ++ ULONG channel; ++ ULONG port; ++ ULONG reserved1; ++ } dma; ++ struct { ++ ULONG data[3]; ++ } device_private; ++ struct { ++ ULONG start; ++ ULONG length; ++ ULONG reserved; ++ } bus_number; ++ struct { ++ ULONG data_size; ++ ULONG reserved1; ++ ULONG reserved2; ++ } device_specific_data; ++ } u; ++}; ++#pragma pack(pop) ++ ++struct cm_partial_resource_list { ++ USHORT version; ++ USHORT revision; ++ ULONG count; ++ struct cm_partial_resource_descriptor partial_descriptors[1]; ++}; ++ ++struct cm_full_resource_descriptor { ++ enum interface_type interface_type; ++ ULONG bus_number; ++ struct cm_partial_resource_list partial_resource_list; ++}; ++ ++struct cm_resource_list { ++ ULONG count; ++ struct cm_full_resource_descriptor list[1]; ++}; ++ ++enum file_info_class { ++ FileDirectoryInformation = 1, ++ FileBasicInformation = 4, ++ FileStandardInformation = 5, ++ FileNameInformation = 9, ++ FilePositionInformation = 14, ++ FileAlignmentInformation = 17, ++ FileNetworkOpenInformation = 34, ++ FileAttributeTagInformation = 35, ++ FileMaximumInformation = 41, ++}; ++ ++enum fs_info_class { ++ FileFsVolumeInformation = 1, ++ /* ... */ ++ FileFsMaximumInformation = 9, ++}; ++ ++enum device_relation_type { ++ BusRelations, EjectionRelations, PowerRelations, RemovalRelations, ++ TargetDeviceRelation, SingleBusRelations, ++}; ++ ++enum bus_query_id_type { ++ BusQueryDeviceID = 0, BusQueryHardwareIDs = 1, ++ BusQueryCompatibleIDs = 2, BusQueryInstanceID = 3, ++ BusQueryDeviceSerialNumber = 4, ++}; ++ ++enum device_text_type { ++ DeviceTextDescription = 0, DeviceTextLocationInformation = 1, ++}; ++ ++enum device_usage_notification_type { ++ DeviceUsageTypeUndefined, DeviceUsageTypePaging, ++ DeviceUsageTypeHibernation, DevbiceUsageTypeDumpFile, ++}; ++ ++#define METHOD_BUFFERED 0 ++#define METHOD_IN_DIRECT 1 ++#define METHOD_OUT_DIRECT 2 ++#define METHOD_NEITHER 3 ++ ++#define CTL_CODE(dev_type, func, method, access) \ ++ (((dev_type) << 16) | ((access) << 14) | ((func) << 2) | (method)) ++ ++#define IO_METHOD_FROM_CTL_CODE(code) (code & 0x3) ++ ++#ifndef CONFIG_X86_64 ++#pragma pack(push,4) ++#endif ++struct io_stack_location { ++ UCHAR major_fn; ++ UCHAR minor_fn; ++ UCHAR flags; ++ UCHAR control; ++ union { ++ struct { ++ void *security_context; ++ ULONG options; ++ USHORT POINTER_ALIGN file_attributes; ++ USHORT share_access; ++ ULONG POINTER_ALIGN ea_length; ++ } create; ++ struct { ++ ULONG length; ++ ULONG POINTER_ALIGN key; ++ LARGE_INTEGER byte_offset; ++ } read; ++ struct { ++ ULONG length; ++ ULONG POINTER_ALIGN key; ++ LARGE_INTEGER byte_offset; ++ } write; ++ struct { ++ ULONG length; ++ enum file_info_class POINTER_ALIGN file_info_class; ++ } query_file; ++ struct { ++ ULONG length; ++ enum file_info_class POINTER_ALIGN file_info_class; ++ struct file_object *file_object; ++ union { ++ struct { ++ BOOLEAN replace_if_exists; ++ BOOLEAN advance_only; ++ }; ++ ULONG cluster_count; ++ void *delete_handle; ++ }; ++ } set_file; ++ struct { ++ ULONG length; ++ enum fs_info_class POINTER_ALIGN fs_info_class; ++ } query_volume; ++ struct { ++ ULONG output_buf_len; ++ ULONG POINTER_ALIGN input_buf_len; ++ ULONG POINTER_ALIGN code; ++ void *type3_input_buf; ++ } dev_ioctl; ++ struct { ++ SECURITY_INFORMATION security_info; ++ ULONG POINTER_ALIGN length; ++ } query_security; ++ struct { ++ SECURITY_INFORMATION security_info; ++ void *security_descriptor; ++ } set_security; ++ struct { ++ void *vpb; ++ struct device_object *device_object; ++ } mount_volume; ++ struct { ++ void *vpb; ++ struct device_object *device_object; ++ } verify_volume; ++ struct { ++ void *srb; ++ } scsi; ++ struct { ++ enum device_relation_type type; ++ } query_device_relations; ++ struct { ++ const struct guid *type; ++ USHORT size; ++ USHORT version; ++ struct nt_interface *intf; ++ void *intf_data; ++ } query_intf; ++ struct { ++ void *capabilities; ++ } device_capabilities; ++ struct { ++ void *io_resource_requirement_list; ++ } filter_resource_requirements; ++ struct { ++ ULONG which_space; ++ void *buffer; ++ ULONG offset; ++ ULONG POINTER_ALIGN length; ++ } read_write_config; ++ struct { ++ BOOLEAN lock; ++ } set_lock; ++ struct { ++ enum bus_query_id_type id_type; ++ } query_id; ++ struct { ++ enum device_text_type device_text_type; ++ ULONG POINTER_ALIGN locale_id; ++ } query_device_text; ++ struct { ++ BOOLEAN in_path; ++ BOOLEAN reserved[3]; ++ enum device_usage_notification_type POINTER_ALIGN type; ++ } usage_notification; ++ struct { ++ enum system_power_state power_state; ++ } wait_wake; ++ struct { ++ void *power_sequence; ++ } power_sequence; ++ struct { ++ ULONG sys_context; ++ enum power_state_type POINTER_ALIGN type; ++ union power_state POINTER_ALIGN state; ++ enum power_action POINTER_ALIGN shutdown_type; ++ } power; ++ struct { ++ struct cm_resource_list *allocated_resources; ++ struct cm_resource_list *allocated_resources_translated; ++ } start_device; ++ struct { ++ ULONG_PTR provider_id; ++ void *data_path; ++ ULONG buf_len; ++ void *buf; ++ } wmi; ++ struct { ++ void *arg1; ++ void *arg2; ++ void *arg3; ++ void *arg4; ++ } others; ++ } params; ++ struct device_object *dev_obj; ++ struct file_object *file_obj; ++ NTSTATUS (*completion_routine)(struct device_object *, ++ struct irp *, void *) wstdcall; ++ void *context; ++}; ++#ifndef CONFIG_X86_64 ++#pragma pack(pop) ++#endif ++ ++struct kapc { ++ CSHORT type; ++ CSHORT size; ++ ULONG spare0; ++ struct nt_thread *thread; ++ struct nt_list list; ++ void *kernele_routine; ++ void *rundown_routine; ++ void *normal_routine; ++ void *normal_context; ++ void *sys_arg1; ++ void *sys_arg2; ++ CCHAR apc_state_index; ++ KPROCESSOR_MODE apc_mode; ++ BOOLEAN inserted; ++}; ++ ++#define IRP_NOCACHE 0x00000001 ++#define IRP_SYNCHRONOUS_API 0x00000004 ++#define IRP_ASSOCIATED_IRP 0x00000008 ++ ++enum urb_state { ++ URB_INVALID = 1, URB_ALLOCATED, URB_SUBMITTED, ++ URB_COMPLETED, URB_FREE, URB_SUSPEND, URB_INT_UNLINKED }; ++ ++struct wrap_urb { ++ struct nt_list list; ++ enum urb_state state; ++ struct nt_list complete_list; ++ unsigned int flags; ++ struct urb *urb; ++ struct irp *irp; ++#ifdef USB_DEBUG ++ unsigned int id; ++#endif ++}; ++ ++struct irp { ++ SHORT type; ++ USHORT size; ++ struct mdl *mdl; ++ ULONG flags; ++ union { ++ struct irp *master_irp; ++ LONG irp_count; ++ void *system_buffer; ++ } associated_irp; ++ struct nt_list thread_list; ++ struct io_status_block io_status; ++ KPROCESSOR_MODE requestor_mode; ++ BOOLEAN pending_returned; ++ CHAR stack_count; ++ CHAR current_location; ++ BOOLEAN cancel; ++ KIRQL cancel_irql; ++ CCHAR apc_env; ++ UCHAR alloc_flags; ++ struct io_status_block *user_status; ++ struct nt_event *user_event; ++ union { ++ struct { ++ void *user_apc_routine; ++ void *user_apc_context; ++ } async_params; ++ LARGE_INTEGER alloc_size; ++ } overlay; ++ void (*cancel_routine)(struct device_object *, struct irp *) wstdcall; ++ void *user_buf; ++ union { ++ struct { ++ union { ++ struct kdevice_queue_entry dev_q_entry; ++ struct { ++ void *driver_context[4]; ++ }; ++ }; ++ void *thread; ++ char *aux_buf; ++ struct { ++ struct nt_list list; ++ union { ++ struct io_stack_location *csl; ++ ULONG packet_type; ++ }; ++ }; ++ struct file_object *file_object; ++ } overlay; ++ union { ++ struct kapc apc; ++ /* space for apc is used for ndiswrapper ++ * specific fields */ ++ struct { ++ struct wrap_urb *wrap_urb; ++ struct wrap_device *wrap_device; ++ }; ++ }; ++ void *completion_key; ++ } tail; ++}; ++ ++#define IoSizeOfIrp(stack_count) \ ++ ((USHORT)(sizeof(struct irp) + \ ++ ((stack_count) * sizeof(struct io_stack_location)))) ++#define IoGetCurrentIrpStackLocation(irp) \ ++ (irp)->tail.overlay.csl ++#define IoGetNextIrpStackLocation(irp) \ ++ (IoGetCurrentIrpStackLocation(irp) - 1) ++#define IoGetPreviousIrpStackLocation(irp) \ ++ (IoGetCurrentIrpStackLocation(irp) + 1) ++ ++#define IoSetNextIrpStackLocation(irp) \ ++do { \ ++ KIRQL _irql_; \ ++ IoAcquireCancelSpinLock(&_irql_); \ ++ (irp)->current_location--; \ ++ IoGetCurrentIrpStackLocation(irp)--; \ ++ IoReleaseCancelSpinLock(_irql_); \ ++} while (0) ++ ++#define IoSkipCurrentIrpStackLocation(irp) \ ++do { \ ++ KIRQL _irql_; \ ++ IoAcquireCancelSpinLock(&_irql_); \ ++ (irp)->current_location++; \ ++ IoGetCurrentIrpStackLocation(irp)++; \ ++ IoReleaseCancelSpinLock(_irql_); \ ++} while (0) ++ ++static inline void ++IoCopyCurrentIrpStackLocationToNext(struct irp *irp) ++{ ++ struct io_stack_location *next; ++ next = IoGetNextIrpStackLocation(irp); ++ memcpy(next, IoGetCurrentIrpStackLocation(irp), ++ offsetof(struct io_stack_location, completion_routine)); ++ next->control = 0; ++} ++ ++static inline void ++IoSetCompletionRoutine(struct irp *irp, void *routine, void *context, ++ BOOLEAN success, BOOLEAN error, BOOLEAN cancel) ++{ ++ struct io_stack_location *irp_sl = IoGetNextIrpStackLocation(irp); ++ irp_sl->completion_routine = routine; ++ irp_sl->context = context; ++ irp_sl->control = 0; ++ if (success) ++ irp_sl->control |= SL_INVOKE_ON_SUCCESS; ++ if (error) ++ irp_sl->control |= SL_INVOKE_ON_ERROR; ++ if (cancel) ++ irp_sl->control |= SL_INVOKE_ON_CANCEL; ++} ++ ++#define IoMarkIrpPending(irp) \ ++ (IoGetCurrentIrpStackLocation((irp))->control |= SL_PENDING_RETURNED) ++#define IoUnmarkIrpPending(irp) \ ++ (IoGetCurrentIrpStackLocation((irp))->control &= ~SL_PENDING_RETURNED) ++ ++#define IRP_SL(irp, n) (((struct io_stack_location *)((irp) + 1)) + (n)) ++#define IRP_DRIVER_CONTEXT(irp) (irp)->tail.overlay.driver_context ++#define IoIrpThread(irp) ((irp)->tail.overlay.thread) ++ ++#define IRP_URB(irp) \ ++ (union nt_urb *)(IoGetCurrentIrpStackLocation(irp)->params.others.arg1) ++ ++#define IRP_WRAP_DEVICE(irp) (irp)->tail.wrap_device ++#define IRP_WRAP_URB(irp) (irp)->tail.wrap_urb ++ ++struct wmi_guid_reg_info { ++ struct guid *guid; ++ ULONG instance_count; ++ ULONG flags; ++}; ++ ++struct wmilib_context { ++ ULONG guid_count; ++ struct wmi_guid_reg_info *guid_list; ++ void *query_wmi_reg_info; ++ void *query_wmi_data_block; ++ void *set_wmi_data_block; ++ void *set_wmi_data_item; ++ void *execute_wmi_method; ++ void *wmi_function_control; ++}; ++ ++enum key_value_information_class { ++ KeyValueBasicInformation, KeyValueFullInformation, ++ KeyValuePartialInformation, KeyValueFullInformationAlign64, ++ KeyValuePartialInformationAlign64 ++}; ++ ++struct file_name_info { ++ ULONG length; ++ wchar_t *name; ++}; ++ ++struct file_std_info { ++ LARGE_INTEGER alloc_size; ++ LARGE_INTEGER eof; ++ ULONG num_links; ++ BOOLEAN delete_pending; ++ BOOLEAN dir; ++}; ++ ++enum nt_obj_type { ++ NT_OBJ_EVENT = 10, NT_OBJ_MUTEX, NT_OBJ_THREAD, NT_OBJ_TIMER, ++ NT_OBJ_SEMAPHORE, ++}; ++ ++enum common_object_type { ++ OBJECT_TYPE_NONE, OBJECT_TYPE_DEVICE, OBJECT_TYPE_DRIVER, ++ OBJECT_TYPE_NT_THREAD, OBJECT_TYPE_FILE, OBJECT_TYPE_CALLBACK, ++}; ++ ++struct common_object_header { ++ struct nt_list list; ++ enum common_object_type type; ++ UINT size; ++ UINT ref_count; ++ BOOLEAN close_in_process; ++ BOOLEAN permanent; ++ struct unicode_string name; ++}; ++ ++#define OBJECT_TO_HEADER(object) \ ++ (struct common_object_header *)((void *)(object) - \ ++ sizeof(struct common_object_header)) ++#define OBJECT_SIZE(size) \ ++ ((size) + sizeof(struct common_object_header)) ++#define HEADER_TO_OBJECT(hdr) \ ++ ((void *)(hdr) + sizeof(struct common_object_header)) ++#define HANDLE_TO_OBJECT(handle) HEADER_TO_OBJECT(handle) ++#define HANDLE_TO_HEADER(handle) (handle) ++ ++enum work_queue_type { ++ CriticalWorkQueue, DelayedWorkQueue, HyperCriticalWorkQueue, ++ MaximumWorkQueue ++}; ++ ++typedef void (*NTOS_WORK_FUNC)(void *arg1, void *arg2) wstdcall; ++ ++struct io_workitem { ++ enum work_queue_type type; ++ struct device_object *dev_obj; ++ NTOS_WORK_FUNC worker_routine; ++ void *context; ++}; ++ ++struct io_workitem_entry { ++ struct nt_list list; ++ struct io_workitem *io_workitem; ++}; ++ ++enum mm_page_priority { ++ LowPagePriority, NormalPagePriority = 16, HighPagePriority = 32 ++}; ++ ++enum kinterrupt_mode { ++ LevelSensitive, Latched ++}; ++ ++enum ntos_wait_reason { ++ Executive, FreePage, PageIn, PoolAllocation, DelayExecution, ++ Suspended, UserRequest, WrExecutive, WrFreePage, WrPageIn, ++ WrPoolAllocation, WrDelayExecution, WrSuspended, WrUserRequest, ++ WrEventPair, WrQueue, WrLpcReceive, WrLpcReply, WrVirtualMemory, ++ WrPageOut, WrRendezvous, Spare2, Spare3, Spare4, Spare5, Spare6, ++ WrKernel, MaximumWaitReason ++}; ++ ++typedef enum ntos_wait_reason KWAIT_REASON; ++ ++typedef void *LOOKASIDE_ALLOC_FUNC(enum pool_type pool_type, ++ SIZE_T size, ULONG tag) wstdcall; ++typedef void LOOKASIDE_FREE_FUNC(void *) wstdcall; ++ ++struct npaged_lookaside_list { ++ nt_slist_header head; ++ USHORT depth; ++ USHORT maxdepth; ++ ULONG totalallocs; ++ union { ++ ULONG allocmisses; ++ ULONG allochits; ++ } u1; ++ ULONG totalfrees; ++ union { ++ ULONG freemisses; ++ ULONG freehits; ++ } u2; ++ enum pool_type pool_type; ++ ULONG tag; ++ ULONG size; ++ LOOKASIDE_ALLOC_FUNC *alloc_func; ++ LOOKASIDE_FREE_FUNC *free_func; ++ struct nt_list list; ++ ULONG lasttotallocs; ++ union { ++ ULONG lastallocmisses; ++ ULONG lastallochits; ++ } u3; ++ ULONG pad[2]; ++#ifndef CONFIG_X86_64 ++ NT_SPIN_LOCK obsolete; ++#endif ++} ++#ifdef CONFIG_X86_64 ++CACHE_ALIGN ++#endif ++; ++ ++enum device_registry_property { ++ DevicePropertyDeviceDescription, DevicePropertyHardwareID, ++ DevicePropertyCompatibleIDs, DevicePropertyBootConfiguration, ++ DevicePropertyBootConfigurationTranslated, ++ DevicePropertyClassName, DevicePropertyClassGuid, ++ DevicePropertyDriverKeyName, DevicePropertyManufacturer, ++ DevicePropertyFriendlyName, DevicePropertyLocationInformation, ++ DevicePropertyPhysicalDeviceObjectName, DevicePropertyBusTypeGuid, ++ DevicePropertyLegacyBusType, DevicePropertyBusNumber, ++ DevicePropertyEnumeratorName, DevicePropertyAddress, ++ DevicePropertyUINumber, DevicePropertyInstallState, ++ DevicePropertyRemovalPolicy ++}; ++ ++enum trace_information_class { ++ TraceIdClass, TraceHandleClass, TraceEnableFlagsClass, ++ TraceEnableLevelClass, GlobalLoggerHandleClass, EventLoggerHandleClass, ++ AllLoggerHandlesClass, TraceHandleByNameClass ++}; ++ ++struct kinterrupt; ++typedef BOOLEAN (*PKSERVICE_ROUTINE)(struct kinterrupt *interrupt, ++ void *context) wstdcall; ++typedef BOOLEAN (*PKSYNCHRONIZE_ROUTINE)(void *context) wstdcall; ++ ++struct kinterrupt { ++ ULONG vector; ++ KAFFINITY cpu_mask; ++ NT_SPIN_LOCK lock; ++ NT_SPIN_LOCK *actual_lock; ++ BOOLEAN shared; ++ BOOLEAN save_fp; ++ union { ++ CHAR processor_number; ++#ifdef CONFIG_DEBUG_SHIRQ ++ CHAR enabled; ++#endif ++ } u; ++ PKSERVICE_ROUTINE isr; ++ void *isr_ctx; ++ struct nt_list list; ++ KIRQL irql; ++ KIRQL synch_irql; ++ enum kinterrupt_mode mode; ++}; ++ ++struct time_fields { ++ CSHORT year; ++ CSHORT month; ++ CSHORT day; ++ CSHORT hour; ++ CSHORT minute; ++ CSHORT second; ++ CSHORT milliseconds; ++ CSHORT weekday; ++}; ++ ++struct object_attributes { ++ ULONG length; ++ void *root_dir; ++ struct unicode_string *name; ++ ULONG attributes; ++ void *security_descr; ++ void *security_qos; ++}; ++ ++typedef void (*PCALLBACK_FUNCTION)(void *context, void *arg1, ++ void *arg2) wstdcall; ++ ++struct callback_object; ++struct callback_func { ++ PCALLBACK_FUNCTION func; ++ void *context; ++ struct nt_list list; ++ struct callback_object *object; ++}; ++ ++struct callback_object { ++ NT_SPIN_LOCK lock; ++ struct nt_list list; ++ struct nt_list callback_funcs; ++ BOOLEAN allow_multiple_callbacks; ++ struct object_attributes *attributes; ++}; ++ ++enum section_inherit { ++ ViewShare = 1, ViewUnmap = 2 ++}; ++ ++struct ksystem_time { ++ ULONG low_part; ++ LONG high1_time; ++ LONG high2_time; ++}; ++ ++enum nt_product_type { ++ nt_product_win_nt = 1, nt_product_lan_man_nt, nt_product_server ++}; ++ ++enum alt_arch_type { ++ arch_type_standard, arch_type_nex98x86, end_alternatives ++}; ++ ++struct kuser_shared_data { ++ ULONG tick_count; ++ ULONG tick_count_multiplier; ++ volatile struct ksystem_time interrupt_time; ++ volatile struct ksystem_time system_time; ++ volatile struct ksystem_time time_zone_bias; ++ USHORT image_number_low; ++ USHORT image_number_high; ++ wchar_t nt_system_root[260]; ++ ULONG max_stack_trace_depth; ++ ULONG crypto_exponent; ++ ULONG time_zone_id; ++ ULONG large_page_min; ++ ULONG reserved2[7]; ++ enum nt_product_type nt_product_type; ++ BOOLEAN product_type_is_valid; ++ ULONG nt_major_version; ++ ULONG nt_minor_version; ++ BOOLEAN processor_features[PROCESSOR_FEATURE_MAX]; ++ ULONG reserved1; ++ ULONG reserved3; ++ volatile LONG time_slip; ++ enum alt_arch_type alt_arch_type; ++ LARGE_INTEGER system_expiration_date; ++ ULONG suite_mask; ++ BOOLEAN kdbg_enabled; ++ volatile ULONG active_console; ++ volatile ULONG dismount_count; ++ ULONG com_plus_package; ++ ULONG last_system_rite_event_tick_count; ++ ULONG num_phys_pages; ++ BOOLEAN safe_boot_mode; ++ ULONG trace_log; ++ ULONGLONG fill0; ++ ULONGLONG sys_call[4]; ++ union { ++ volatile struct ksystem_time tick_count; ++ volatile ULONG64 tick_count_quad; ++ } tick; ++}; ++ ++#define REG_NONE (0) ++#define REG_SZ (1) ++#define REG_EXPAND_SZ (2) ++#define REG_BINARY (3) ++#define REG_DWORD (4) ++ ++#define RTL_REGISTRY_ABSOLUTE 0 ++#define RTL_REGISTRY_SERVICES 1 ++#define RTL_REGISTRY_CONTROL 2 ++#define RTL_REGISTRY_WINDOWS_NT 3 ++#define RTL_REGISTRY_DEVICEMAP 4 ++#define RTL_REGISTRY_USER 5 ++#define RTL_REGISTRY_MAXIMUM 6 ++#define RTL_REGISTRY_HANDLE 0x40000000 ++#define RTL_REGISTRY_OPTIONAL 0x80000000 ++ ++#define RTL_QUERY_REGISTRY_SUBKEY 0x00000001 ++#define RTL_QUERY_REGISTRY_TOPKEY 0x00000002 ++#define RTL_QUERY_REGISTRY_REQUIRED 0x00000004 ++#define RTL_QUERY_REGISTRY_NOVALUE 0x00000008 ++#define RTL_QUERY_REGISTRY_NOEXPAND 0x00000010 ++#define RTL_QUERY_REGISTRY_DIRECT 0x00000020 ++#define RTL_QUERY_REGISTRY_DELETE 0x00000040 ++ ++typedef NTSTATUS (*PRTL_QUERY_REGISTRY_ROUTINE)(wchar_t *name, ULONG type, ++ void *data, ULONG length, ++ void *context, ++ void *entry) wstdcall; ++ ++struct rtl_query_registry_table { ++ PRTL_QUERY_REGISTRY_ROUTINE query_func; ++ ULONG flags; ++ wchar_t *name; ++ void *context; ++ ULONG def_type; ++ void *def_data; ++ ULONG def_length; ++}; ++ ++struct io_remove_lock { ++ BOOLEAN removed; ++ BOOLEAN reserved[3]; ++ LONG io_count; ++ struct nt_event remove_event; ++}; ++ ++struct io_error_log_packet { ++ UCHAR major_fn_code; ++ UCHAR retry_count; ++ USHORT dump_data_size; ++ USHORT nr_of_strings; ++ USHORT string_offset; ++ USHORT event_category; ++ NTSTATUS error_code; ++ ULONG unique_error_value; ++ NTSTATUS final_status; ++ ULONG sequence_number; ++ ULONG io_control_code; ++ LARGE_INTEGER device_offset; ++ ULONG dump_data[1]; ++}; ++ ++/* some of the functions below are slightly different from DDK's ++ * implementation; e.g., Insert functions return appropriate ++ * pointer */ ++ ++/* instead of using Linux's lists, we implement list manipulation ++ * functions because nt_list is used by drivers and we don't want to ++ * worry about Linux's list being different from nt_list (right now ++ * they are same, but in future they could be different) */ ++ ++static inline void InitializeListHead(struct nt_list *head) ++{ ++ head->next = head->prev = head; ++} ++ ++static inline BOOLEAN IsListEmpty(struct nt_list *head) ++{ ++ if (head == head->next) ++ return TRUE; ++ else ++ return FALSE; ++} ++ ++static inline void RemoveEntryList(struct nt_list *entry) ++{ ++ entry->prev->next = entry->next; ++ entry->next->prev = entry->prev; ++} ++ ++static inline struct nt_list *RemoveHeadList(struct nt_list *head) ++{ ++ struct nt_list *entry; ++ ++ entry = head->next; ++ if (entry == head) ++ return NULL; ++ else { ++ RemoveEntryList(entry); ++ return entry; ++ } ++} ++ ++static inline struct nt_list *RemoveTailList(struct nt_list *head) ++{ ++ struct nt_list *entry; ++ ++ entry = head->prev; ++ if (entry == head) ++ return NULL; ++ else { ++ RemoveEntryList(entry); ++ return entry; ++ } ++} ++ ++static inline void InsertListEntry(struct nt_list *entry, struct nt_list *prev, ++ struct nt_list *next) ++{ ++ next->prev = entry; ++ entry->next = next; ++ entry->prev = prev; ++ prev->next = entry; ++} ++ ++static inline struct nt_list *InsertHeadList(struct nt_list *head, ++ struct nt_list *entry) ++{ ++ struct nt_list *ret; ++ ++ if (IsListEmpty(head)) ++ ret = NULL; ++ else ++ ret = head->next; ++ ++ InsertListEntry(entry, head, head->next); ++ return ret; ++} ++ ++static inline struct nt_list *InsertTailList(struct nt_list *head, ++ struct nt_list *entry) ++{ ++ struct nt_list *ret; ++ ++ if (IsListEmpty(head)) ++ ret = NULL; ++ else ++ ret = head->prev; ++ ++ InsertListEntry(entry, head->prev, head); ++ return ret; ++} ++ ++#define nt_list_for_each(pos, head) \ ++ for (pos = (head)->next; pos != (head); pos = pos->next) ++ ++#define nt_list_for_each_entry(pos, head, member) \ ++ for (pos = container_of((head)->next, typeof(*pos), member); \ ++ &pos->member != (head); \ ++ pos = container_of(pos->member.next, typeof(*pos), member)) ++ ++#define nt_list_for_each_safe(pos, n, head) \ ++ for (pos = (head)->next, n = pos->next; pos != (head); \ ++ pos = n, n = pos->next) ++ ++/* device object flags */ ++#define DO_VERIFY_VOLUME 0x00000002 ++#define DO_BUFFERED_IO 0x00000004 ++#define DO_EXCLUSIVE 0x00000008 ++#define DO_DIRECT_IO 0x00000010 ++#define DO_MAP_IO_BUFFER 0x00000020 ++#define DO_DEVICE_HAS_NAME 0x00000040 ++#define DO_DEVICE_INITIALIZING 0x00000080 ++#define DO_SYSTEM_BOOT_PARTITION 0x00000100 ++#define DO_LONG_TERM_REQUESTS 0x00000200 ++#define DO_NEVER_LAST_DEVICE 0x00000400 ++#define DO_SHUTDOWN_REGISTERED 0x00000800 ++#define DO_BUS_ENUMERATED_DEVICE 0x00001000 ++#define DO_POWER_PAGABLE 0x00002000 ++#define DO_POWER_INRUSH 0x00004000 ++#define DO_LOW_PRIORITY_FILESYSTEM 0x00010000 ++ ++/* Various supported device types (used with IoCreateDevice()) */ ++ ++#define FILE_DEVICE_BEEP 0x00000001 ++#define FILE_DEVICE_CD_ROM 0x00000002 ++#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003 ++#define FILE_DEVICE_CONTROLLER 0x00000004 ++#define FILE_DEVICE_DATALINK 0x00000005 ++#define FILE_DEVICE_DFS 0x00000006 ++#define FILE_DEVICE_DISK 0x00000007 ++#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008 ++#define FILE_DEVICE_FILE_SYSTEM 0x00000009 ++#define FILE_DEVICE_INPORT_PORT 0x0000000A ++#define FILE_DEVICE_KEYBOARD 0x0000000B ++#define FILE_DEVICE_MAILSLOT 0x0000000C ++#define FILE_DEVICE_MIDI_IN 0x0000000D ++#define FILE_DEVICE_MIDI_OUT 0x0000000E ++#define FILE_DEVICE_MOUSE 0x0000000F ++#define FILE_DEVICE_MULTI_UNC_PROVIDER 0x00000010 ++#define FILE_DEVICE_NAMED_PIPE 0x00000011 ++#define FILE_DEVICE_NETWORK 0x00000012 ++#define FILE_DEVICE_NETWORK_BROWSER 0x00000013 ++#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014 ++#define FILE_DEVICE_NULL 0x00000015 ++#define FILE_DEVICE_PARALLEL_PORT 0x00000016 ++#define FILE_DEVICE_PHYSICAL_NETCARD 0x00000017 ++#define FILE_DEVICE_PRINTER 0x00000018 ++#define FILE_DEVICE_SCANNER 0x00000019 ++#define FILE_DEVICE_SERIAL_MOUSE_PORT 0x0000001A ++#define FILE_DEVICE_SERIAL_PORT 0x0000001B ++#define FILE_DEVICE_SCREEN 0x0000001C ++#define FILE_DEVICE_SOUND 0x0000001D ++#define FILE_DEVICE_STREAMS 0x0000001E ++#define FILE_DEVICE_TAPE 0x0000001F ++#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020 ++#define FILE_DEVICE_TRANSPORT 0x00000021 ++#define FILE_DEVICE_UNKNOWN 0x00000022 ++#define FILE_DEVICE_VIDEO 0x00000023 ++#define FILE_DEVICE_VIRTUAL_DISK 0x00000024 ++#define FILE_DEVICE_WAVE_IN 0x00000025 ++#define FILE_DEVICE_WAVE_OUT 0x00000026 ++#define FILE_DEVICE_8042_PORT 0x00000027 ++#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028 ++#define FILE_DEVICE_BATTERY 0x00000029 ++#define FILE_DEVICE_BUS_EXTENDER 0x0000002A ++#define FILE_DEVICE_MODEM 0x0000002B ++#define FILE_DEVICE_VDM 0x0000002C ++#define FILE_DEVICE_MASS_STORAGE 0x0000002D ++#define FILE_DEVICE_SMB 0x0000002E ++#define FILE_DEVICE_KS 0x0000002F ++#define FILE_DEVICE_CHANGER 0x00000030 ++#define FILE_DEVICE_SMARTCARD 0x00000031 ++#define FILE_DEVICE_ACPI 0x00000032 ++#define FILE_DEVICE_DVD 0x00000033 ++#define FILE_DEVICE_FULLSCREEN_VIDEO 0x00000034 ++#define FILE_DEVICE_DFS_FILE_SYSTEM 0x00000035 ++#define FILE_DEVICE_DFS_VOLUME 0x00000036 ++#define FILE_DEVICE_SERENUM 0x00000037 ++#define FILE_DEVICE_TERMSRV 0x00000038 ++#define FILE_DEVICE_KSEC 0x00000039 ++#define FILE_DEVICE_FIPS 0x0000003A ++ ++/* Device characteristics */ ++ ++#define FILE_REMOVABLE_MEDIA 0x00000001 ++#define FILE_READ_ONLY_DEVICE 0x00000002 ++#define FILE_FLOPPY_DISKETTE 0x00000004 ++#define FILE_WRITE_ONCE_MEDIA 0x00000008 ++#define FILE_REMOTE_DEVICE 0x00000010 ++#define FILE_DEVICE_IS_MOUNTED 0x00000020 ++#define FILE_VIRTUAL_VOLUME 0x00000040 ++#define FILE_AUTOGENERATED_DEVICE_NAME 0x00000080 ++#define FILE_DEVICE_SECURE_OPEN 0x00000100 ++ ++#define FILE_READ_DATA 0x0001 ++#define FILE_WRITE_DATA 0x0002 ++ ++#define FILE_SUPERSEDED 0x00000000 ++#define FILE_OPENED 0x00000001 ++#define FILE_CREATED 0x00000002 ++#define FILE_OVERWRITTEN 0x00000003 ++#define FILE_EXISTS 0x00000004 ++#define FILE_DOES_NOT_EXIST 0x00000005 ++ ++ ++#endif /* WINNT_TYPES_H */ +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/workqueue.c linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/workqueue.c +--- linux-3.12.2/3rdparty/ndiswrapper/workqueue.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/workqueue.c 2013-11-28 21:42:11.000000000 +0200 +@@ -0,0 +1,279 @@ ++/* ++ * Copyright (C) 2006 Giridhar Pemmasani ++ * ++ * 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 "ntoskernel.h" ++ ++struct workqueue_thread { ++ spinlock_t lock; ++ struct task_struct *task; ++ struct completion *completion; ++ char name[16]; ++ int pid; ++ /* whether any work_structs pending? <0 implies quit */ ++ s8 pending; ++ /* list of work_structs pending */ ++ struct list_head work_list; ++}; ++ ++struct workq_thread_data { ++ struct workqueue_struct *workq; ++ int index; ++}; ++ ++struct wrap_workqueue_struct { ++ u8 singlethread; ++ u8 qon; ++ int num_cpus; ++ struct workqueue_thread threads[0]; ++}; ++ ++static void wrap_destroy_wq_on(struct workqueue_struct *workq, int cpu); ++ ++static int workq_thread(void *data) ++{ ++ struct workq_thread_data *thread_data = data; ++ struct workqueue_thread *thread; ++ struct workqueue_struct *workq; ++ struct work_struct *work; ++ ++ workq = thread_data->workq; ++ thread = &workq->threads[thread_data->index]; ++ WORKTRACE("%p, %d, %p", workq, thread_data->index, thread); ++ strncpy(thread->name, current->comm, sizeof(thread->name)); ++ ++ daemonize(thread->name); ++ set_user_nice(current, -5); ++ ++ if (thread->task != current) { ++ WARNING("invalid task: %p, %p", thread->task, current); ++ thread->task = current; ++ } ++ thread->pid = current->pid; ++ complete(xchg(&thread->completion, NULL)); ++ WORKTRACE("%s (%d) started", thread->name, thread->pid); ++ while (1) { ++ if (wait_condition(thread->pending, 0, TASK_INTERRUPTIBLE) < 0) { ++ /* TODO: deal with signal */ ++ WARNING("signal not blocked?"); ++ flush_signals(current); ++ continue; ++ } ++ while (1) { ++ struct list_head *entry; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&thread->lock, flags); ++ if (list_empty(&thread->work_list)) { ++ struct completion *completion; ++ if (thread->pending < 0) { ++ spin_unlock_irqrestore(&thread->lock, ++ flags); ++ goto out; ++ } ++ thread->pending = 0; ++ completion = thread->completion; ++ thread->completion = NULL; ++ spin_unlock_irqrestore(&thread->lock, flags); ++ if (completion) ++ complete(completion); ++ break; ++ } ++ entry = thread->work_list.next; ++ work = list_entry(entry, struct work_struct, list); ++ if (xchg(&work->thread, NULL)) ++ list_del(entry); ++ else ++ work = NULL; ++ spin_unlock_irqrestore(&thread->lock, flags); ++ DBG_BLOCK(4) { ++ WORKTRACE("%p, %p", work, thread); ++ } ++ if (work) ++ work->func(work->data); ++ } ++ } ++ ++out: ++ WORKTRACE("%s exiting", thread->name); ++ thread->pid = 0; ++ return 0; ++} ++ ++static int wrap_queue_work_on(struct workqueue_struct *workq, ++ struct work_struct *work, int cpu) ++{ ++ struct workqueue_thread *thread = &workq->threads[cpu]; ++ unsigned long flags; ++ int ret; ++ ++ assert(thread->pid > 0); ++ DBG_BLOCK(4) { ++ WORKTRACE("%p, %d", workq, cpu); ++ } ++ spin_lock_irqsave(&thread->lock, flags); ++ if (work->thread) ++ ret = 0; ++ else { ++ work->thread = thread; ++ list_add_tail(&work->list, &thread->work_list); ++ thread->pending = 1; ++ wake_up_process(thread->task); ++ ret = 1; ++ } ++ spin_unlock_irqrestore(&thread->lock, flags); ++ return ret; ++} ++ ++int wrap_queue_work(struct workqueue_struct *workq, struct work_struct *work) ++{ ++ if (num_online_cpus() == 1 || workq->singlethread) ++ return wrap_queue_work_on(workq, work, 0); ++ else { ++ typeof(workq->qon) qon; ++ /* work is queued on threads in a round-robin fashion */ ++ do { ++ qon = workq->qon % workq->num_cpus; ++ atomic_inc_var(workq->qon); ++ } while (!workq->threads[qon].pid); ++ return wrap_queue_work_on(workq, work, qon); ++ } ++} ++ ++void wrap_cancel_work(struct work_struct *work) ++{ ++ struct workqueue_thread *thread; ++ unsigned long flags; ++ ++ WORKTRACE("%p", work); ++ if ((thread = xchg(&work->thread, NULL))) { ++ WORKTRACE("%p", thread); ++ spin_lock_irqsave(&thread->lock, flags); ++ list_del(&work->list); ++ spin_unlock_irqrestore(&thread->lock, flags); ++ } ++} ++ ++struct workqueue_struct *wrap_create_wq(const char *name, u8 singlethread, ++ u8 freeze) ++{ ++ struct completion started; ++ struct workqueue_struct *workq; ++ int i, n; ++ ++ if (singlethread) ++ n = 1; ++ else ++ n = num_online_cpus(); ++ workq = kzalloc(sizeof(*workq) + n * sizeof(workq->threads[0]), ++ GFP_KERNEL); ++ if (!workq) { ++ WARNING("couldn't allocate memory"); ++ return NULL; ++ } ++ WORKTRACE("%p", workq); ++ workq->singlethread = singlethread; ++ init_completion(&started); ++ for_each_online_cpu(i) { ++ struct workq_thread_data thread_data; ++ spin_lock_init(&workq->threads[i].lock); ++ INIT_LIST_HEAD(&workq->threads[i].work_list); ++ reinit_completion(&started); ++ workq->threads[i].completion = &started; ++ thread_data.workq = workq; ++ thread_data.index = i; ++ WORKTRACE("%p, %d, %p", workq, i, &workq->threads[i]); ++ workq->threads[i].task = ++ kthread_create(workq_thread, &thread_data, ++ "%s/%d", name, i); ++ if (IS_ERR(workq->threads[i].task)) { ++ int j; ++ for (j = 0; j < i; j++) ++ wrap_destroy_wq_on(workq, j); ++ kfree(workq); ++ WARNING("couldn't start thread %s", name); ++ return NULL; ++ } ++#ifdef PF_NOFREEZE ++ if (!freeze) ++ workq->threads[i].task->flags |= PF_NOFREEZE; ++#endif ++ kthread_bind(workq->threads[i].task, i); ++ workq->num_cpus = max(workq->num_cpus, i); ++ wake_up_process(workq->threads[i].task); ++ wait_for_completion(&started); ++ WORKTRACE("%s, %d: %p, %d", name, i, ++ workq, workq->threads[i].pid); ++ if (singlethread) ++ break; ++ } ++ workq->num_cpus++; ++ return workq; ++} ++ ++static void wrap_flush_wq_on(struct workqueue_struct *workq, int cpu) ++{ ++ struct workqueue_thread *thread = &workq->threads[cpu]; ++ struct completion done; ++ ++ WORKTRACE("%p: %d, %s", workq, cpu, thread->name); ++ init_completion(&done); ++ thread->completion = &done; ++ thread->pending = 1; ++ wake_up_process(thread->task); ++ wait_for_completion(&done); ++ return; ++} ++ ++void wrap_flush_wq(struct workqueue_struct *workq) ++{ ++ int i, n; ++ ++ WORKTRACE("%p", workq); ++ if (workq->singlethread) ++ n = 1; ++ else ++ n = num_online_cpus(); ++ for (i = 0; i < n; i++) ++ wrap_flush_wq_on(workq, i); ++} ++ ++static void wrap_destroy_wq_on(struct workqueue_struct *workq, int cpu) ++{ ++ struct workqueue_thread *thread = &workq->threads[cpu]; ++ ++ WORKTRACE("%p: %d, %s", workq, cpu, thread->name); ++ if (!thread->pid) ++ return; ++ thread->pending = -1; ++ wake_up_process(thread->task); ++ while (thread->pid) { ++ WORKTRACE("%d", thread->pid); ++ schedule(); ++ } ++} ++ ++void wrap_destroy_wq(struct workqueue_struct *workq) ++{ ++ int i, n; ++ ++ WORKTRACE("%p", workq); ++ if (workq->singlethread) ++ n = 1; ++ else ++ n = num_online_cpus(); ++ for (i = 0; i < n; i++) ++ wrap_destroy_wq_on(workq, i); ++ kfree(workq); ++} +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/wrapmem.c linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/wrapmem.c +--- linux-3.12.2/3rdparty/ndiswrapper/wrapmem.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/wrapmem.c 2013-11-28 21:42:11.000000000 +0200 +@@ -0,0 +1,366 @@ ++/* ++ * Copyright (C) 2006 Giridhar Pemmasani ++ * ++ * 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. ++ * ++ */ ++ ++#define _WRAPMEM_C_ ++ ++#include "ntoskernel.h" ++#include "wrapmem.h" ++ ++struct slack_alloc_info { ++ struct nt_list list; ++ size_t size; ++}; ++ ++#if ALLOC_DEBUG > 1 ++static struct nt_list allocs; ++#endif ++ ++static struct nt_list slack_allocs; ++static spinlock_t alloc_lock; ++ ++#if ALLOC_DEBUG ++const char *alloc_type_name[ALLOC_TYPE_MAX] = { ++ "kmalloc_atomic", ++ "kmalloc_nonatomic", ++ "vmalloc_atomic", ++ "vmalloc_nonatomic", ++ "kmalloc_slack", ++ "pages" ++}; ++ ++struct alloc_info { ++ enum alloc_type type; ++ size_t size; ++#if ALLOC_DEBUG > 1 ++ struct nt_list list; ++ const char *file; ++ int line; ++ ULONG tag; ++#endif ++}; ++ ++static atomic_t alloc_sizes[ALLOC_TYPE_MAX]; ++#endif ++ ++/* allocate memory and add it to list of allocated pointers; if a ++ * driver doesn't free this memory for any reason (buggy driver or we ++ * allocate space behind driver's back since we need more space than ++ * corresponding Windows structure provides etc.), this gets freed ++ * automatically when module is unloaded ++ */ ++void *slack_kmalloc(size_t size) ++{ ++ struct slack_alloc_info *info; ++ ++ ENTER4("size = %zu", size); ++ info = kmalloc(size + sizeof(*info), irql_gfp()); ++ if (!info) ++ return NULL; ++ info->size = size; ++ spin_lock_bh(&alloc_lock); ++ InsertTailList(&slack_allocs, &info->list); ++ spin_unlock_bh(&alloc_lock); ++#if ALLOC_DEBUG ++ atomic_add(size, &alloc_sizes[ALLOC_TYPE_SLACK]); ++#endif ++ TRACE4("%p, %p", info, info + 1); ++ EXIT4(return info + 1); ++} ++ ++/* free pointer and remove from list of allocated pointers */ ++void slack_kfree(void *ptr) ++{ ++ struct slack_alloc_info *info; ++ ++ ENTER4("%p", ptr); ++ info = ptr - sizeof(*info); ++ spin_lock_bh(&alloc_lock); ++ RemoveEntryList(&info->list); ++ spin_unlock_bh(&alloc_lock); ++#if ALLOC_DEBUG ++ atomic_sub(info->size, &alloc_sizes[ALLOC_TYPE_SLACK]); ++#endif ++ kfree(info); ++ EXIT4(return); ++} ++ ++void *slack_kzalloc(size_t size) ++{ ++ void *ptr = slack_kmalloc(size); ++ if (ptr) ++ memset(ptr, 0, size); ++ return ptr; ++} ++ ++#if ALLOC_DEBUG ++void *wrap_kmalloc(size_t size, gfp_t flags, const char *file, int line) ++{ ++ struct alloc_info *info; ++ ++ info = kmalloc(size + sizeof(*info), flags); ++ if (!info) ++ return NULL; ++ if (flags & GFP_ATOMIC) ++ info->type = ALLOC_TYPE_KMALLOC_ATOMIC; ++ else ++ info->type = ALLOC_TYPE_KMALLOC_NON_ATOMIC; ++ info->size = size; ++ atomic_add(size, &alloc_sizes[info->type]); ++#if ALLOC_DEBUG > 1 ++ info->file = file; ++ info->line = line; ++ info->tag = 0; ++ spin_lock_bh(&alloc_lock); ++ InsertTailList(&allocs, &info->list); ++ spin_unlock_bh(&alloc_lock); ++#endif ++ TRACE4("%p", info + 1); ++ return info + 1; ++} ++ ++void *wrap_kzalloc(size_t size, gfp_t flags, const char *file, int line) ++{ ++ void *ptr = wrap_kmalloc(size, flags, file, line); ++ if (ptr) ++ memset(ptr, 0, size); ++ return ptr; ++} ++ ++void wrap_kfree(void *ptr) ++{ ++ struct alloc_info *info; ++ ++ TRACE4("%p", ptr); ++ if (!ptr) ++ return; ++ info = ptr - sizeof(*info); ++ atomic_sub(info->size, &alloc_sizes[info->type]); ++#if ALLOC_DEBUG > 1 ++ spin_lock_bh(&alloc_lock); ++ RemoveEntryList(&info->list); ++ spin_unlock_bh(&alloc_lock); ++ if (!(info->type == ALLOC_TYPE_KMALLOC_ATOMIC || ++ info->type == ALLOC_TYPE_KMALLOC_NON_ATOMIC)) { ++ WARNING("invalid type: %d", info->type); ++ return; ++ } ++#endif ++ kfree(info); ++} ++ ++void *wrap_vmalloc(unsigned long size, const char *file, int line) ++{ ++ struct alloc_info *info; ++ ++ info = vmalloc(size + sizeof(*info)); ++ if (!info) ++ return NULL; ++ info->type = ALLOC_TYPE_VMALLOC_NON_ATOMIC; ++ info->size = size; ++ atomic_add(size, &alloc_sizes[info->type]); ++#if ALLOC_DEBUG > 1 ++ info->file = file; ++ info->line = line; ++ info->tag = 0; ++ spin_lock_bh(&alloc_lock); ++ InsertTailList(&allocs, &info->list); ++ spin_unlock_bh(&alloc_lock); ++#endif ++ return info + 1; ++} ++ ++void *wrap__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot, ++ const char *file, int line) ++{ ++ struct alloc_info *info; ++ ++ info = __vmalloc(size + sizeof(*info), gfp_mask, prot); ++ if (!info) ++ return NULL; ++ if (gfp_mask & GFP_ATOMIC) ++ info->type = ALLOC_TYPE_VMALLOC_ATOMIC; ++ else ++ info->type = ALLOC_TYPE_VMALLOC_NON_ATOMIC; ++ info->size = size; ++ atomic_add(size, &alloc_sizes[info->type]); ++#if ALLOC_DEBUG > 1 ++ info->file = file; ++ info->line = line; ++ info->tag = 0; ++ spin_lock_bh(&alloc_lock); ++ InsertTailList(&allocs, &info->list); ++ spin_unlock_bh(&alloc_lock); ++#endif ++ return info + 1; ++} ++ ++void wrap_vfree(void *ptr) ++{ ++ struct alloc_info *info; ++ ++ info = ptr - sizeof(*info); ++ atomic_sub(info->size, &alloc_sizes[info->type]); ++#if ALLOC_DEBUG > 1 ++ spin_lock_bh(&alloc_lock); ++ RemoveEntryList(&info->list); ++ spin_unlock_bh(&alloc_lock); ++ if (!(info->type == ALLOC_TYPE_VMALLOC_ATOMIC || ++ info->type == ALLOC_TYPE_VMALLOC_NON_ATOMIC)) { ++ WARNING("invalid type: %d", info->type); ++ return; ++ } ++#endif ++ vfree(info); ++} ++ ++void *wrap_alloc_pages(gfp_t flags, unsigned int size, ++ const char *file, int line) ++{ ++ struct alloc_info *info; ++ ++ size += sizeof(*info); ++ info = (struct alloc_info *)__get_free_pages(flags, get_order(size)); ++ if (!info) ++ return NULL; ++ info->type = ALLOC_TYPE_PAGES; ++ info->size = size; ++ atomic_add(size, &alloc_sizes[info->type]); ++#if ALLOC_DEBUG > 1 ++ info->file = file; ++ info->line = line; ++ info->tag = 0; ++ spin_lock_bh(&alloc_lock); ++ InsertTailList(&allocs, &info->list); ++ spin_unlock_bh(&alloc_lock); ++#endif ++ return info + 1; ++} ++ ++void wrap_free_pages(unsigned long ptr, int order) ++{ ++ struct alloc_info *info; ++ ++ info = (void *)ptr - sizeof(*info); ++ atomic_sub(info->size, &alloc_sizes[info->type]); ++#if ALLOC_DEBUG > 1 ++ spin_lock_bh(&alloc_lock); ++ RemoveEntryList(&info->list); ++ spin_unlock_bh(&alloc_lock); ++ if (info->type != ALLOC_TYPE_PAGES) { ++ WARNING("invalid type: %d", info->type); ++ return; ++ } ++#endif ++ free_pages((unsigned long)info, get_order(info->size)); ++} ++ ++#if ALLOC_DEBUG > 1 ++void *wrap_ExAllocatePoolWithTag(enum pool_type pool_type, SIZE_T size, ++ ULONG tag, const char *file, int line) ++{ ++ void *addr; ++ struct alloc_info *info; ++ ++ ENTER4("pool_type: %d, size: %zu, tag: %u", pool_type, size, tag); ++ addr = (ExAllocatePoolWithTag)(pool_type, size, tag); ++ if (!addr) ++ return NULL; ++ info = addr - sizeof(*info); ++ info->file = file; ++ info->line = line; ++ info->tag = tag; ++ EXIT4(return addr); ++} ++#endif ++ ++int alloc_size(enum alloc_type type) ++{ ++ if ((int)type >= 0 && type < ALLOC_TYPE_MAX) ++ return atomic_read(&alloc_sizes[type]); ++ else ++ return -EINVAL; ++} ++ ++#endif // ALLOC_DEBUG ++ ++int wrapmem_init(void) ++{ ++#if ALLOC_DEBUG > 1 ++ InitializeListHead(&allocs); ++#endif ++ InitializeListHead(&slack_allocs); ++ spin_lock_init(&alloc_lock); ++ return 0; ++} ++ ++void wrapmem_exit(void) ++{ ++#if ALLOC_DEBUG ++ enum alloc_type type; ++#endif ++ struct nt_list *ent; ++ ++ /* free all pointers on the slack list */ ++ while (1) { ++ struct slack_alloc_info *info; ++ spin_lock_bh(&alloc_lock); ++ ent = RemoveHeadList(&slack_allocs); ++ spin_unlock_bh(&alloc_lock); ++ if (!ent) ++ break; ++ info = container_of(ent, struct slack_alloc_info, list); ++#if ALLOC_DEBUG ++ atomic_sub(info->size, &alloc_sizes[ALLOC_TYPE_SLACK]); ++#endif ++ kfree(info); ++ } ++#if ALLOC_DEBUG ++ for (type = 0; type < ALLOC_TYPE_MAX; type++) { ++ int n = atomic_read(&alloc_sizes[type]); ++ if (n) ++ WARNING("%d bytes of memory in %s leaking", n, ++ alloc_type_name[type]); ++ } ++ ++#if ALLOC_DEBUG > 1 ++ while (1) { ++ struct alloc_info *info; ++ ++ spin_lock_bh(&alloc_lock); ++ ent = RemoveHeadList(&allocs); ++ spin_unlock_bh(&alloc_lock); ++ if (!ent) ++ break; ++ info = container_of(ent, struct alloc_info, list); ++ atomic_sub(info->size, &alloc_sizes[ALLOC_TYPE_SLACK]); ++ printk(KERN_DEBUG DRIVER_NAME ++ ": %s:%d leaked %zd bytes at %p (%s, tag 0x%08X)\n", ++ info->file, info->line, info->size, info + 1, ++ alloc_type_name[info->type], info->tag); ++ if (info->type == ALLOC_TYPE_KMALLOC_ATOMIC || ++ info->type == ALLOC_TYPE_KMALLOC_NON_ATOMIC) ++ kfree(info); ++ else if (info->type == ALLOC_TYPE_VMALLOC_ATOMIC || ++ info->type == ALLOC_TYPE_VMALLOC_NON_ATOMIC) ++ vfree(info); ++ else if (info->type == ALLOC_TYPE_PAGES) ++ free_pages((unsigned long)info, get_order(info->size)); ++ else ++ WARNING("invalid type: %d; not freed", info->type); ++ } ++#endif ++#endif ++ return; ++} +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/wrapmem.h linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/wrapmem.h +--- linux-3.12.2/3rdparty/ndiswrapper/wrapmem.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/wrapmem.h 2013-11-28 21:42:11.000000000 +0200 +@@ -0,0 +1,97 @@ ++/* ++ * Copyright (C) 2006 Giridhar Pemmasani ++ * ++ * 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 _WRAPMEM_H_ ++#define _WRAPMEM_H_ ++ ++/* ++ * Set ALLOC_DEBUG to 1 to show information about memory used by both ++ * ndiswrapper and Windows driver in /proc/net/ndiswrapper/debug ++ * This will also show memory leaks (memory allocated but not freed) when ++ * ndiswrapper module is unloaded. ++ * ++ * Set ALLOC_DEBUG to 2 to see details about every leaking allocation. ++*/ ++ ++#ifndef ALLOC_DEBUG ++#define ALLOC_DEBUG 0 ++#endif ++ ++int wrapmem_init(void); ++void wrapmem_exit(void); ++void *slack_kmalloc(size_t size); ++void *slack_kzalloc(size_t size); ++void slack_kfree(void *ptr); ++ ++#if ALLOC_DEBUG ++enum alloc_type { ALLOC_TYPE_KMALLOC_ATOMIC, ++ ALLOC_TYPE_KMALLOC_NON_ATOMIC, ++ ALLOC_TYPE_VMALLOC_ATOMIC, ALLOC_TYPE_VMALLOC_NON_ATOMIC, ++ ALLOC_TYPE_SLACK, ALLOC_TYPE_PAGES, ALLOC_TYPE_MAX }; ++ ++extern const char *alloc_type_name[ALLOC_TYPE_MAX]; ++ ++void *wrap_kmalloc(size_t size, gfp_t flags, const char *file, int line); ++void *wrap_kzalloc(size_t size, gfp_t flags, const char *file, int line); ++void wrap_kfree(void *ptr); ++void *wrap_vmalloc(unsigned long size, const char *file, int line); ++void *wrap__vmalloc(unsigned long size, gfp_t flags, pgprot_t prot, ++ const char *file, int line); ++void wrap_vfree(void *ptr); ++void *wrap_alloc_pages(gfp_t flags, unsigned int size, ++ const char *file, int line); ++void wrap_free_pages(unsigned long ptr, int order); ++int alloc_size(enum alloc_type type); ++ ++#if ALLOC_DEBUG > 1 ++void *wrap_ExAllocatePoolWithTag(enum pool_type pool_type, SIZE_T size, ++ ULONG tag, const char *file, int line); ++#define ExAllocatePoolWithTag(pool_type, size, tag) \ ++ wrap_ExAllocatePoolWithTag(pool_type, size, tag, __FILE__, __LINE__) ++#endif ++ ++#ifndef _WRAPMEM_C_ ++#undef kmalloc ++#undef kzalloc ++#undef kfree ++#undef vmalloc ++#undef __vmalloc ++#undef vfree ++#define kmalloc(size, flags) \ ++ wrap_kmalloc(size, flags, __FILE__, __LINE__) ++#define kzalloc(size, flags) \ ++ wrap_kzalloc(size, flags, __FILE__, __LINE__) ++#define vmalloc(size) \ ++ wrap_vmalloc(size, __FILE__, __LINE__) ++#define __vmalloc(size, flags, prot) \ ++ wrap__vmalloc(size, flags, prot, __FILE__, __LINE__) ++#define kfree(ptr) wrap_kfree(ptr) ++#define vfree(ptr) wrap_vfree(ptr) ++ ++#define wrap_get_free_pages(flags, size) \ ++ wrap_alloc_pages(flags, size, __FILE__, __LINE__) ++#undef free_pages ++#define free_pages(ptr, order) wrap_free_pages(ptr, order) ++ ++#endif // _WRAPMEM_C_ ++ ++#else ++ ++#define wrap_get_free_pages(flags, size) \ ++ (void *)__get_free_pages(flags, get_order(size)) ++ ++#endif // ALLOC_DEBUG ++ ++#endif +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/wrapndis.c linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/wrapndis.c +--- linux-3.12.2/3rdparty/ndiswrapper/wrapndis.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/wrapndis.c 2013-11-28 21:42:11.000000000 +0200 +@@ -0,0 +1,2186 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * 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 ++#include ++#include ++#include ++#include "ndis.h" ++#include "iw_ndis.h" ++#include "pnp.h" ++#include "loader.h" ++#include "wrapndis.h" ++#include "wrapper.h" ++ ++/* Functions callable from the NDIS driver */ ++wstdcall NTSTATUS NdisDispatchDeviceControl(struct device_object *fdo, ++ struct irp *irp); ++wstdcall NTSTATUS NdisDispatchPnp(struct device_object *fdo, struct irp *irp); ++wstdcall NTSTATUS NdisDispatchPower(struct device_object *fdo, struct irp *irp); ++ ++struct workqueue_struct *wrapndis_wq; ++ ++static int set_packet_filter(struct ndis_device *wnd, ++ ULONG packet_filter); ++static void add_iw_stats_timer(struct ndis_device *wnd); ++static void del_iw_stats_timer(struct ndis_device *wnd); ++static NDIS_STATUS ndis_start_device(struct ndis_device *wnd); ++static int ndis_remove_device(struct ndis_device *wnd); ++static void set_multicast_list(struct ndis_device *wnd); ++static int ndis_net_dev_open(struct net_device *net_dev); ++static int ndis_net_dev_close(struct net_device *net_dev); ++ ++/* MiniportReset */ ++NDIS_STATUS mp_reset(struct ndis_device *wnd) ++{ ++ NDIS_STATUS res; ++ struct miniport *mp; ++ BOOLEAN reset_address; ++ KIRQL irql; ++ ++ ENTER2("wnd: %p", wnd); ++ mutex_lock(&wnd->tx_ring_mutex); ++ mutex_lock(&wnd->ndis_req_mutex); ++ mp = &wnd->wd->driver->ndis_driver->mp; ++ prepare_wait_condition(wnd->ndis_req_task, wnd->ndis_req_done, 0); ++ WARNING("%s is being reset", wnd->net_dev->name); ++ irql = serialize_lock_irql(wnd); ++ assert_irql(_irql_ == DISPATCH_LEVEL); ++ res = LIN2WIN2(mp->reset, &reset_address, wnd->nmb->mp_ctx); ++ serialize_unlock_irql(wnd, irql); ++ ++ TRACE2("%08X, %08X", res, reset_address); ++ if (res == NDIS_STATUS_PENDING) { ++ /* wait for NdisMResetComplete */ ++ if (wait_condition((wnd->ndis_req_done > 0), 0, ++ TASK_INTERRUPTIBLE) < 0) ++ res = NDIS_STATUS_FAILURE; ++ else { ++ res = wnd->ndis_req_status; ++ reset_address = wnd->ndis_req_done - 1; ++ } ++ TRACE2("%08X, %08X", res, reset_address); ++ } ++ mutex_unlock(&wnd->ndis_req_mutex); ++ if (res == NDIS_STATUS_SUCCESS && reset_address) { ++ set_packet_filter(wnd, wnd->packet_filter); ++ set_multicast_list(wnd); ++ } ++ mutex_unlock(&wnd->tx_ring_mutex); ++ EXIT3(return res); ++} ++ ++/* MiniportRequest(Query/Set)Information */ ++NDIS_STATUS mp_request(enum ndis_request_type request, ++ struct ndis_device *wnd, ndis_oid oid, ++ void *buf, ULONG buflen, ULONG *written, ULONG *needed) ++{ ++ NDIS_STATUS res; ++ ULONG w, n; ++ struct miniport *mp; ++ KIRQL irql; ++ ++ mutex_lock(&wnd->ndis_req_mutex); ++ if (!written) ++ written = &w; ++ if (!needed) ++ needed = &n; ++ mp = &wnd->wd->driver->ndis_driver->mp; ++ prepare_wait_condition(wnd->ndis_req_task, wnd->ndis_req_done, 0); ++ irql = serialize_lock_irql(wnd); ++ assert_irql(_irql_ == DISPATCH_LEVEL); ++ switch (request) { ++ case NdisRequestQueryInformation: ++ TRACE2("%p, %08X, %p", mp->queryinfo, oid, wnd->nmb->mp_ctx); ++ res = LIN2WIN6(mp->queryinfo, wnd->nmb->mp_ctx, oid, buf, ++ buflen, written, needed); ++ break; ++ case NdisRequestSetInformation: ++ TRACE2("%p, %08X, %p", mp->setinfo, oid, wnd->nmb->mp_ctx); ++ res = LIN2WIN6(mp->setinfo, wnd->nmb->mp_ctx, oid, buf, ++ buflen, written, needed); ++ break; ++ default: ++ WARNING("invalid request %d, %08X", request, oid); ++ res = NDIS_STATUS_NOT_SUPPORTED; ++ break; ++ } ++ serialize_unlock_irql(wnd, irql); ++ TRACE2("%08X, %08X", res, oid); ++ if (res == NDIS_STATUS_PENDING) { ++ /* wait for NdisMQueryInformationComplete */ ++ if (wait_condition((wnd->ndis_req_done > 0), 0, ++ TASK_INTERRUPTIBLE) < 0) ++ res = NDIS_STATUS_FAILURE; ++ else ++ res = wnd->ndis_req_status; ++ TRACE2("%08X, %08X", res, oid); ++ } ++ mutex_unlock(&wnd->ndis_req_mutex); ++ DBG_BLOCK(2) { ++ if (res || needed) ++ TRACE2("%08X, %d, %d, %d", res, buflen, *written, ++ *needed); ++ } ++ EXIT3(return res); ++} ++ ++/* MiniportPnPEventNotify */ ++static NDIS_STATUS mp_pnp_event(struct ndis_device *wnd, ++ enum ndis_device_pnp_event event, ++ ULONG power_profile) ++{ ++ struct miniport *mp; ++ ++ ENTER1("%p, %d", wnd, event); ++ mp = &wnd->wd->driver->ndis_driver->mp; ++ if (!mp->pnp_event_notify) { ++ TRACE1("Windows driver %s doesn't support " ++ "MiniportPnpEventNotify", wnd->wd->driver->name); ++ return NDIS_STATUS_FAILURE; ++ } ++ /* RNDIS driver doesn't like to be notified if device is ++ * already halted */ ++ if (!test_bit(HW_INITIALIZED, &wnd->wd->hw_status)) ++ EXIT1(return NDIS_STATUS_SUCCESS); ++ switch (event) { ++ case NdisDevicePnPEventSurpriseRemoved: ++ TRACE1("%u, %p", ++ (wnd->attributes & NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK), ++ mp->pnp_event_notify); ++ if ((wnd->attributes & NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK) && ++ !test_bit(HW_DISABLED, &wnd->wd->hw_status) && ++ mp->pnp_event_notify) { ++ TRACE1("calling surprise_removed"); ++ LIN2WIN4(mp->pnp_event_notify, wnd->nmb->mp_ctx, ++ NdisDevicePnPEventSurpriseRemoved, NULL, 0); ++ } else ++ TRACE1("Windows driver %s doesn't support " ++ "MiniportPnpEventNotify for safe unplugging", ++ wnd->wd->driver->name); ++ return NDIS_STATUS_SUCCESS; ++ case NdisDevicePnPEventPowerProfileChanged: ++ if (power_profile) ++ power_profile = NdisPowerProfileAcOnLine; ++ LIN2WIN4(mp->pnp_event_notify, wnd->nmb->mp_ctx, ++ NdisDevicePnPEventPowerProfileChanged, ++ &power_profile, sizeof(power_profile)); ++ return NDIS_STATUS_SUCCESS; ++ default: ++ WARNING("event %d not yet implemented", event); ++ return NDIS_STATUS_SUCCESS; ++ } ++} ++ ++/* MiniportInitialize */ ++static NDIS_STATUS mp_init(struct ndis_device *wnd) ++{ ++ NDIS_STATUS error_status, status; ++ UINT medium_index; ++ enum ndis_medium medium_array[] = {NdisMedium802_3}; ++ struct miniport *mp; ++ ++ ENTER1("irql: %d", current_irql()); ++ if (test_bit(HW_INITIALIZED, &wnd->wd->hw_status)) { ++ WARNING("device %p already initialized!", wnd); ++ return NDIS_STATUS_FAILURE; ++ } ++ ++ if (!wnd->wd->driver->ndis_driver || ++ !wnd->wd->driver->ndis_driver->mp.init) { ++ WARNING("assuming WDM (non-NDIS) driver"); ++ EXIT1(return NDIS_STATUS_NOT_RECOGNIZED); ++ } ++ mp = &wnd->wd->driver->ndis_driver->mp; ++ status = LIN2WIN6(mp->init, &error_status, &medium_index, medium_array, ++ ARRAY_SIZE(medium_array), wnd->nmb, wnd->nmb); ++ TRACE1("init returns: %08X, irql: %d", status, current_irql()); ++ if (status != NDIS_STATUS_SUCCESS) { ++ WARNING("couldn't initialize device: %08X", status); ++ EXIT1(return NDIS_STATUS_FAILURE); ++ } ++ ++ /* Wait a little to let card power up otherwise ifup might ++ * fail after boot */ ++ sleep_hz(HZ / 5); ++ status = mp_pnp_event(wnd, NdisDevicePnPEventPowerProfileChanged, ++ NdisPowerProfileAcOnLine); ++ if (status != NDIS_STATUS_SUCCESS) ++ TRACE1("setting power failed: %08X", status); ++ set_bit(HW_INITIALIZED, &wnd->wd->hw_status); ++ /* the description about NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND is ++ * misleading/confusing */ ++ status = mp_query(wnd, OID_PNP_CAPABILITIES, ++ &wnd->pnp_capa, sizeof(wnd->pnp_capa)); ++ if (status == NDIS_STATUS_SUCCESS) { ++ TRACE1("%d, %d", wnd->pnp_capa.wakeup.min_magic_packet_wakeup, ++ wnd->pnp_capa.wakeup.min_pattern_wakeup); ++ wnd->attributes |= NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND; ++ status = mp_query_int(wnd, OID_PNP_ENABLE_WAKE_UP, ++ &wnd->ndis_wolopts); ++ TRACE1("%08X, %x", status, wnd->ndis_wolopts); ++ } else if (status == NDIS_STATUS_NOT_SUPPORTED) ++ wnd->attributes &= ~NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND; ++ TRACE1("%d", wnd->pnp_capa.wakeup.min_magic_packet_wakeup); ++ /* although some NDIS drivers support suspend, Linux kernel ++ * has issues with suspending USB devices */ ++ if (wrap_is_usb_bus(wnd->wd->dev_bus)) { ++ wnd->attributes &= ~NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND; ++ wnd->ndis_wolopts = 0; ++ } ++ mp_set_int(wnd, OID_802_11_POWER_MODE, NDIS_POWER_OFF); ++ EXIT1(return NDIS_STATUS_SUCCESS); ++} ++ ++/* MiniportHalt */ ++static void mp_halt(struct ndis_device *wnd) ++{ ++ struct miniport *mp; ++ ++ ENTER1("%p", wnd); ++ if (!test_and_clear_bit(HW_INITIALIZED, &wnd->wd->hw_status)) { ++ WARNING("device %p is not initialized - not halting", wnd); ++ return; ++ } ++ hangcheck_del(wnd); ++ del_iw_stats_timer(wnd); ++#ifdef CONFIG_WIRELESS_EXT ++ if (wnd->physical_medium == NdisPhysicalMediumWirelessLan && ++ wrap_is_pci_bus(wnd->wd->dev_bus)) { ++ mutex_unlock(&wnd->ndis_req_mutex); ++ disassociate(wnd, 0); ++ mutex_lock(&wnd->ndis_req_mutex); ++ } ++#endif ++ mp = &wnd->wd->driver->ndis_driver->mp; ++ TRACE1("halt: %p", mp->mp_halt); ++ LIN2WIN1(mp->mp_halt, wnd->nmb->mp_ctx); ++ /* if a driver doesn't call NdisMDeregisterInterrupt during ++ * halt, deregister it now */ ++ if (wnd->mp_interrupt) ++ NdisMDeregisterInterrupt(wnd->mp_interrupt); ++ /* cancel any timers left by buggy windows driver; also free ++ * the memory for timers */ ++ while (1) { ++ struct nt_slist *slist; ++ struct wrap_timer *wrap_timer; ++ ++ spin_lock_bh(&ntoskernel_lock); ++ if ((slist = wnd->wrap_timer_slist.next)) ++ wnd->wrap_timer_slist.next = slist->next; ++ spin_unlock_bh(&ntoskernel_lock); ++ TIMERTRACE("%p", slist); ++ if (!slist) ++ break; ++ wrap_timer = container_of(slist, struct wrap_timer, slist); ++ wrap_timer->repeat = 0; ++ /* ktimer that this wrap_timer is associated to can't ++ * be touched, as it may have been freed by the driver ++ * already */ ++ if (del_timer_sync(&wrap_timer->timer)) ++ WARNING("Buggy Windows driver left timer %p " ++ "running", wrap_timer->nt_timer); ++ memset(wrap_timer, 0, sizeof(*wrap_timer)); ++ kfree(wrap_timer); ++ } ++ EXIT1(return); ++} ++ ++static NDIS_STATUS mp_set_power_state(struct ndis_device *wnd, ++ enum ndis_power_state state) ++{ ++ NDIS_STATUS status; ++ ++ TRACE1("%d", state); ++ if (state == NdisDeviceStateD0) { ++ status = NDIS_STATUS_SUCCESS; ++ mutex_unlock(&wnd->ndis_req_mutex); ++ if (test_and_clear_bit(HW_HALTED, &wnd->wd->hw_status)) { ++ status = mp_init(wnd); ++ if (status == NDIS_STATUS_SUCCESS) { ++ set_packet_filter(wnd, wnd->packet_filter); ++ set_multicast_list(wnd); ++ } ++ } else if (test_and_clear_bit(HW_SUSPENDED, ++ &wnd->wd->hw_status)) { ++ status = mp_set_int(wnd, OID_PNP_SET_POWER, state); ++ if (status != NDIS_STATUS_SUCCESS) ++ WARNING("%s: setting power to state %d failed? " ++ "%08X", wnd->net_dev->name, state, ++ status); ++ } else ++ return NDIS_STATUS_FAILURE; ++ ++ if (wrap_is_pci_bus(wnd->wd->dev_bus)) { ++ pci_enable_wake(wnd->wd->pci.pdev, PCI_D3hot, 0); ++ pci_enable_wake(wnd->wd->pci.pdev, PCI_D3cold, 0); ++ } ++ if (status == NDIS_STATUS_SUCCESS) { ++ mutex_unlock(&wnd->tx_ring_mutex); ++ netif_device_attach(wnd->net_dev); ++ hangcheck_add(wnd); ++ add_iw_stats_timer(wnd); ++ } else ++ WARNING("%s: couldn't set power to state %d; device not" ++ " resumed", wnd->net_dev->name, state); ++ EXIT1(return status); ++ } else { ++ mutex_lock(&wnd->tx_ring_mutex); ++ netif_device_detach(wnd->net_dev); ++ hangcheck_del(wnd); ++ del_iw_stats_timer(wnd); ++ status = NDIS_STATUS_NOT_SUPPORTED; ++ if (wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND) { ++ status = mp_set_int(wnd, OID_PNP_ENABLE_WAKE_UP, ++ wnd->ndis_wolopts); ++ TRACE2("0x%x, 0x%x", status, wnd->ndis_wolopts); ++ if (status == NDIS_STATUS_SUCCESS && ++ wrap_is_pci_bus(wnd->wd->dev_bus)) { ++ if (wnd->ndis_wolopts) ++ wnd->wd->pci.wake_state = ++ PowerDeviceD3; ++ else ++ wnd->wd->pci.wake_state = ++ PowerDeviceUnspecified; ++ } else ++ WARNING("couldn't set wake-on-lan options: " ++ "0x%x, %08X", wnd->ndis_wolopts, status); ++ status = mp_set_int(wnd, OID_PNP_SET_POWER, state); ++ if (status == NDIS_STATUS_SUCCESS) ++ set_bit(HW_SUSPENDED, &wnd->wd->hw_status); ++ else ++ WARNING("suspend failed: %08X", status); ++ } ++ if (status != NDIS_STATUS_SUCCESS) { ++ WARNING("%s does not support power management; " ++ "halting the device", wnd->net_dev->name); ++ mp_halt(wnd); ++ set_bit(HW_HALTED, &wnd->wd->hw_status); ++ status = STATUS_SUCCESS; ++ } ++ mutex_lock(&wnd->ndis_req_mutex); ++ EXIT1(return status); ++ } ++} ++ ++static int ndis_set_mac_address(struct net_device *dev, void *p) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ struct sockaddr *addr = p; ++ struct ndis_configuration_parameter param; ++ struct unicode_string key; ++ struct ansi_string ansi; ++ NDIS_STATUS res; ++ unsigned char mac_string[2 * ETH_ALEN + 1]; ++ mac_address mac; ++ ++ memcpy(mac, addr->sa_data, sizeof(mac)); ++ memset(mac_string, 0, sizeof(mac_string)); ++ res = snprintf(mac_string, sizeof(mac_string), MACSTR, MAC2STR(mac)); ++ if (res != (sizeof(mac_string) - 1)) ++ EXIT1(return -EINVAL); ++ TRACE1("new mac: %s", mac_string); ++ ++ RtlInitAnsiString(&ansi, mac_string); ++ if (RtlAnsiStringToUnicodeString(¶m.data.string, &ansi, ++ TRUE) != STATUS_SUCCESS) ++ EXIT1(return -EINVAL); ++ ++ param.type = NdisParameterString; ++ RtlInitAnsiString(&ansi, "NetworkAddress"); ++ if (RtlAnsiStringToUnicodeString(&key, &ansi, TRUE) != STATUS_SUCCESS) { ++ RtlFreeUnicodeString(¶m.data.string); ++ EXIT1(return -EINVAL); ++ } ++ NdisWriteConfiguration(&res, wnd->nmb, &key, ¶m); ++ RtlFreeUnicodeString(&key); ++ RtlFreeUnicodeString(¶m.data.string); ++ ++ if (res != NDIS_STATUS_SUCCESS) ++ EXIT1(return -EFAULT); ++ if (ndis_reinit(wnd) == NDIS_STATUS_SUCCESS) { ++ res = mp_query(wnd, OID_802_3_CURRENT_ADDRESS, ++ mac, sizeof(mac)); ++ if (res == NDIS_STATUS_SUCCESS) { ++ TRACE1("mac:" MACSTRSEP, MAC2STR(mac)); ++ memcpy(dev->dev_addr, mac, sizeof(mac)); ++ } else ++ ERROR("couldn't get mac address: %08X", res); ++ } ++ EXIT1(return 0); ++} ++ ++static int setup_tx_sg_list(struct ndis_device *wnd, struct sk_buff *skb, ++ struct ndis_packet_oob_data *oob_data) ++{ ++ struct ndis_sg_element *sg_element; ++ struct ndis_sg_list *sg_list; ++ int i; ++ ++ ENTER3("%p, %d", skb, skb_shinfo(skb)->nr_frags); ++ if (skb_shinfo(skb)->nr_frags <= 1) { ++ sg_element = &oob_data->wrap_tx_sg_list.elements[0]; ++ sg_element->address = ++ PCI_DMA_MAP_SINGLE(wnd->wd->pci.pdev, skb->data, ++ skb->len, PCI_DMA_TODEVICE); ++ sg_element->length = skb->len; ++ oob_data->wrap_tx_sg_list.nent = 1; ++ oob_data->ext.info[ScatterGatherListPacketInfo] = ++ &oob_data->wrap_tx_sg_list; ++ TRACE3("%llx, %u", sg_element->address, sg_element->length); ++ return 0; ++ } ++ sg_list = kmalloc(sizeof(*sg_list) + ++ (skb_shinfo(skb)->nr_frags + 1) * sizeof(*sg_element), ++ GFP_ATOMIC); ++ if (!sg_list) ++ return -ENOMEM; ++ sg_list->nent = skb_shinfo(skb)->nr_frags + 1; ++ TRACE3("%p, %d", sg_list, sg_list->nent); ++ sg_element = sg_list->elements; ++ sg_element->length = skb_headlen(skb); ++ sg_element->address = ++ PCI_DMA_MAP_SINGLE(wnd->wd->pci.pdev, skb->data, ++ skb_headlen(skb), PCI_DMA_TODEVICE); ++ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { ++ skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; ++ sg_element++; ++ sg_element->length = frag->size; ++ sg_element->address = ++ pci_map_page(wnd->wd->pci.pdev, skb_frag_page(frag), ++ frag->page_offset, frag->size, ++ PCI_DMA_TODEVICE); ++ TRACE3("%llx, %u", sg_element->address, sg_element->length); ++ } ++ oob_data->ext.info[ScatterGatherListPacketInfo] = sg_list; ++ return 0; ++} ++ ++static void free_tx_sg_list(struct ndis_device *wnd, ++ struct ndis_packet_oob_data *oob_data) ++{ ++ int i; ++ struct ndis_sg_element *sg_element; ++ struct ndis_sg_list *sg_list = ++ oob_data->ext.info[ScatterGatherListPacketInfo]; ++ sg_element = sg_list->elements; ++ TRACE3("%p, %d", sg_list, sg_list->nent); ++ PCI_DMA_UNMAP_SINGLE(wnd->wd->pci.pdev, sg_element->address, ++ sg_element->length, PCI_DMA_TODEVICE); ++ if (sg_list->nent == 1) ++ EXIT3(return); ++ for (i = 1; i < sg_list->nent; i++, sg_element++) { ++ TRACE3("%llx, %u", sg_element->address, sg_element->length); ++ pci_unmap_page(wnd->wd->pci.pdev, sg_element->address, ++ sg_element->length, PCI_DMA_TODEVICE); ++ } ++ TRACE3("%p", sg_list); ++ kfree(sg_list); ++} ++ ++static struct ndis_packet *alloc_tx_packet(struct ndis_device *wnd, ++ struct sk_buff *skb) ++{ ++ struct ndis_packet *packet; ++ ndis_buffer *buffer; ++ struct ndis_packet_oob_data *oob_data; ++ NDIS_STATUS status; ++ ++ NdisAllocatePacket(&status, &packet, wnd->tx_packet_pool); ++ if (status != NDIS_STATUS_SUCCESS) ++ return NULL; ++ NdisAllocateBuffer(&status, &buffer, wnd->tx_buffer_pool, ++ skb->data, skb->len); ++ if (status != NDIS_STATUS_SUCCESS) { ++ NdisFreePacket(packet); ++ return NULL; ++ } ++ packet->private.buffer_head = buffer; ++ packet->private.buffer_tail = buffer; ++ ++ oob_data = NDIS_PACKET_OOB_DATA(packet); ++ oob_data->tx_skb = skb; ++ if (wnd->sg_dma_size) { ++ if (setup_tx_sg_list(wnd, skb, oob_data)) { ++ NdisFreeBuffer(buffer); ++ NdisFreePacket(packet); ++ return NULL; ++ } ++ } ++ if (skb->ip_summed == CHECKSUM_PARTIAL) { ++ struct ndis_tcp_ip_checksum_packet_info csum; ++ int protocol; ++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,21) ++ protocol = ntohs(skb->protocol); ++#else ++ protocol = skb->nh.iph->protocol; ++#endif ++ csum.value = 0; ++ csum.tx.v4 = 1; ++ if (protocol == IPPROTO_TCP) ++ csum.tx.tcp = 1; ++ else if (protocol == IPPROTO_UDP) ++ csum.tx.udp = 1; ++// csum->tx.ip = 1; ++ packet->private.flags |= NDIS_PROTOCOL_ID_TCP_IP; ++ oob_data->ext.info[TcpIpChecksumPacketInfo] = ++ (void *)(ULONG_PTR)csum.value; ++ } ++ DBG_BLOCK(4) { ++ dump_bytes(__func__, skb->data, skb->len); ++ } ++ TRACE4("%p, %p, %p", packet, buffer, skb); ++ return packet; ++} ++ ++void free_tx_packet(struct ndis_device *wnd, struct ndis_packet *packet, ++ NDIS_STATUS status) ++{ ++ ndis_buffer *buffer; ++ struct ndis_packet_oob_data *oob_data; ++ struct sk_buff *skb; ++ struct ndis_packet_pool *pool; ++ ++ assert_irql(_irql_ <= DISPATCH_LEVEL); ++ assert(packet->private.packet_flags); ++ oob_data = NDIS_PACKET_OOB_DATA(packet); ++ skb = oob_data->tx_skb; ++ buffer = packet->private.buffer_head; ++ TRACE4("%p, %p, %p, %08X", packet, buffer, skb, status); ++ if (status == NDIS_STATUS_SUCCESS) { ++ pre_atomic_add(wnd->net_stats.tx_bytes, packet->private.len); ++ atomic_inc_var(wnd->net_stats.tx_packets); ++ } else { ++ TRACE1("packet dropped: %08X", status); ++ atomic_inc_var(wnd->net_stats.tx_dropped); ++ } ++ if (wnd->sg_dma_size) ++ free_tx_sg_list(wnd, oob_data); ++ NdisFreeBuffer(buffer); ++ dev_kfree_skb_any(skb); ++ pool = packet->private.pool; ++ NdisFreePacket(packet); ++ if (netif_queue_stopped(wnd->net_dev) && ++ ((pool->max_descr - pool->num_used_descr) >= ++ (wnd->max_tx_packets / 4))) { ++ set_bit(NETIF_WAKEQ, &wnd->ndis_pending_work); ++ queue_work(wrapndis_wq, &wnd->ndis_work); ++ } ++ EXIT4(return); ++} ++ ++/* MiniportSend and MiniportSendPackets */ ++/* this function is called holding tx_ring_mutex. start and n are such ++ * that start + n < TX_RING_SIZE; i.e., packets don't wrap around ++ * ring */ ++static u8 mp_tx_packets(struct ndis_device *wnd, u8 start, u8 n) ++{ ++ NDIS_STATUS res; ++ struct miniport *mp; ++ struct ndis_packet *packet; ++ u8 sent; ++ KIRQL irql; ++ ++ ENTER3("%d, %d", start, n); ++ mp = &wnd->wd->driver->ndis_driver->mp; ++ if (mp->send_packets) { ++ if (deserialized_driver(wnd)) { ++ LIN2WIN3(mp->send_packets, wnd->nmb->mp_ctx, ++ &wnd->tx_ring[start], n); ++ sent = n; ++ } else { ++ irql = serialize_lock_irql(wnd); ++ LIN2WIN3(mp->send_packets, wnd->nmb->mp_ctx, ++ &wnd->tx_ring[start], n); ++ serialize_unlock_irql(wnd, irql); ++ for (sent = 0; sent < n && wnd->tx_ok; sent++) { ++ struct ndis_packet_oob_data *oob_data; ++ packet = wnd->tx_ring[start + sent]; ++ oob_data = NDIS_PACKET_OOB_DATA(packet); ++ switch ((res = ++ xchg(&oob_data->status, ++ NDIS_STATUS_NOT_RECOGNIZED))) { ++ case NDIS_STATUS_SUCCESS: ++ free_tx_packet(wnd, packet, ++ NDIS_STATUS_SUCCESS); ++ break; ++ case NDIS_STATUS_PENDING: ++ break; ++ case NDIS_STATUS_RESOURCES: ++ wnd->tx_ok = 0; ++ /* resubmit this packet and ++ * the rest when resources ++ * become available */ ++ sent--; ++ break; ++ case NDIS_STATUS_FAILURE: ++ free_tx_packet(wnd, packet, ++ NDIS_STATUS_FAILURE); ++ break; ++ default: ++ ERROR("%p: invalid status: %08X", ++ packet, res); ++ free_tx_packet(wnd, packet, ++ oob_data->status); ++ break; ++ } ++ TRACE3("%p, %d", packet, res); ++ } ++ } ++ TRACE3("sent: %d(%d)", sent, n); ++ } else { ++ for (sent = 0; sent < n && wnd->tx_ok; sent++) { ++ struct ndis_packet_oob_data *oob_data; ++ packet = wnd->tx_ring[start + sent]; ++ oob_data = NDIS_PACKET_OOB_DATA(packet); ++ oob_data->status = NDIS_STATUS_NOT_RECOGNIZED; ++ irql = serialize_lock_irql(wnd); ++ res = LIN2WIN3(mp->send, wnd->nmb->mp_ctx, ++ packet, packet->private.flags); ++ serialize_unlock_irql(wnd, irql); ++ switch (res) { ++ case NDIS_STATUS_SUCCESS: ++ free_tx_packet(wnd, packet, res); ++ break; ++ case NDIS_STATUS_PENDING: ++ break; ++ case NDIS_STATUS_RESOURCES: ++ wnd->tx_ok = 0; ++ /* resend this packet when resources ++ * become available */ ++ sent--; ++ break; ++ case NDIS_STATUS_FAILURE: ++ free_tx_packet(wnd, packet, res); ++ break; ++ default: ++ ERROR("packet %p: invalid status: %08X", ++ packet, res); ++ break; ++ } ++ } ++ } ++ EXIT3(return sent); ++} ++ ++static void tx_worker(struct work_struct *work) ++{ ++ struct ndis_device *wnd; ++ s8 n; ++ ++ wnd = container_of(work, struct ndis_device, tx_work); ++ ENTER3("tx_ok %d", wnd->tx_ok); ++ while (wnd->tx_ok) { ++ mutex_lock(&wnd->tx_ring_mutex); ++ spin_lock_bh(&wnd->tx_ring_lock); ++ n = wnd->tx_ring_end - wnd->tx_ring_start; ++ TRACE3("%d, %d, %d", wnd->tx_ring_start, wnd->tx_ring_end, n); ++ /* end == start if either ring is empty or full; in ++ * the latter case is_tx_ring_full is set */ ++ if (n == 0) { ++ if (wnd->is_tx_ring_full) ++ n = TX_RING_SIZE - wnd->tx_ring_start; ++ else { ++ spin_unlock_bh(&wnd->tx_ring_lock); ++ mutex_unlock(&wnd->tx_ring_mutex); ++ break; ++ } ++ } else if (n < 0) ++ n = TX_RING_SIZE - wnd->tx_ring_start; ++ spin_unlock_bh(&wnd->tx_ring_lock); ++ if (unlikely(n > wnd->max_tx_packets)) ++ n = wnd->max_tx_packets; ++ n = mp_tx_packets(wnd, wnd->tx_ring_start, n); ++ if (n) { ++ wnd->net_dev->trans_start = jiffies; ++ wnd->tx_ring_start = ++ (wnd->tx_ring_start + n) % TX_RING_SIZE; ++ wnd->is_tx_ring_full = 0; ++ } ++ mutex_unlock(&wnd->tx_ring_mutex); ++ TRACE3("%d, %d, %d", wnd->tx_ring_start, wnd->tx_ring_end, n); ++ } ++ EXIT3(return); ++} ++ ++static int tx_skbuff(struct sk_buff *skb, struct net_device *dev) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ struct ndis_packet *packet; ++ ++ packet = alloc_tx_packet(wnd, skb); ++ if (!packet) { ++ TRACE2("couldn't allocate packet"); ++ netif_tx_lock(dev); ++ netif_stop_queue(dev); ++ netif_tx_unlock(dev); ++ return NETDEV_TX_BUSY; ++ } ++ spin_lock(&wnd->tx_ring_lock); ++ wnd->tx_ring[wnd->tx_ring_end++] = packet; ++ if (wnd->tx_ring_end == TX_RING_SIZE) ++ wnd->tx_ring_end = 0; ++ if (wnd->tx_ring_end == wnd->tx_ring_start) { ++ netif_tx_lock(dev); ++ wnd->is_tx_ring_full = 1; ++ netif_stop_queue(dev); ++ netif_tx_unlock(dev); ++ } ++ spin_unlock(&wnd->tx_ring_lock); ++ TRACE4("ring: %d, %d", wnd->tx_ring_start, wnd->tx_ring_end); ++ queue_work(wrapndis_wq, &wnd->tx_work); ++ return NETDEV_TX_OK; ++} ++ ++static int set_packet_filter(struct ndis_device *wnd, ULONG packet_filter) ++{ ++ NDIS_STATUS res; ++ ++ while (1) { ++ res = mp_set_int(wnd, OID_GEN_CURRENT_PACKET_FILTER, ++ packet_filter); ++ if (res == NDIS_STATUS_SUCCESS) ++ break; ++ TRACE2("couldn't set filter 0x%08x", packet_filter); ++ /* NDIS_PACKET_TYPE_PROMISCUOUS may not work with 802.11 */ ++ if (packet_filter & NDIS_PACKET_TYPE_PROMISCUOUS) { ++ packet_filter &= ~NDIS_PACKET_TYPE_PROMISCUOUS; ++ continue; ++ } ++ if (packet_filter & NDIS_PACKET_TYPE_ALL_LOCAL) { ++ packet_filter &= ~NDIS_PACKET_TYPE_ALL_LOCAL; ++ continue; ++ } ++ if (packet_filter & NDIS_PACKET_TYPE_ALL_FUNCTIONAL) { ++ packet_filter &= ~NDIS_PACKET_TYPE_ALL_FUNCTIONAL; ++ continue; ++ } ++ if (packet_filter & NDIS_PACKET_TYPE_MULTICAST) { ++ packet_filter &= ~NDIS_PACKET_TYPE_MULTICAST; ++ packet_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; ++ continue; ++ } ++ if (packet_filter & NDIS_PACKET_TYPE_ALL_MULTICAST) { ++ packet_filter &= ~NDIS_PACKET_TYPE_ALL_MULTICAST; ++ continue; ++ } ++ break; ++ } ++ ++ wnd->packet_filter = packet_filter; ++ res = mp_query_int(wnd, OID_GEN_CURRENT_PACKET_FILTER, &packet_filter); ++ if (packet_filter != wnd->packet_filter) { ++ WARNING("filter not set: 0x%08x, 0x%08x", ++ packet_filter, wnd->packet_filter); ++ wnd->packet_filter = packet_filter; ++ } ++ if (wnd->packet_filter) ++ EXIT3(return 0); ++ else ++ EXIT3(return -1); ++} ++ ++void set_media_state(struct ndis_device *wnd, enum ndis_media_state state) ++{ ++ struct net_device *net_dev = wnd->net_dev; ++ ++ ENTER2("state: 0x%x, carrier %d", state, netif_carrier_ok(net_dev)); ++ switch (state) { ++ case NdisMediaStateConnected: ++ if (netif_carrier_ok(net_dev)) ++ return; ++ netif_carrier_on(net_dev); ++ wnd->tx_ok = 1; ++ if (netif_queue_stopped(net_dev)) ++ netif_wake_queue(net_dev); ++ if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) { ++ set_bit(LINK_STATUS_ON, &wnd->ndis_pending_work); ++ queue_work(wrapndis_wq, &wnd->ndis_work); ++ } ++ break; ++ case NdisMediaStateDisconnected: ++ if (!netif_carrier_ok(net_dev)) ++ return; ++ netif_carrier_off(net_dev); ++ netif_stop_queue(net_dev); ++ wnd->tx_ok = 0; ++ if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) { ++ memset(&wnd->essid, 0, sizeof(wnd->essid)); ++ set_bit(LINK_STATUS_OFF, &wnd->ndis_pending_work); ++ queue_work(wrapndis_wq, &wnd->ndis_work); ++ } ++ break; ++ default: ++ WARNING("invalid media state: 0x%x", state); ++ break; ++ } ++} ++ ++static int ndis_net_dev_init(struct net_device *net_dev) ++{ ++ struct ndis_device *wnd = netdev_priv(net_dev); ++ ++ ENTER1("%p", wnd); ++ wrap_procfs_add_ndis_device(wnd); ++ EXIT1(return 0); ++} ++ ++static void ndis_net_dev_uninit(struct net_device *net_dev) ++{ ++ struct ndis_device *wnd = netdev_priv(net_dev); ++ ++ ENTER1("%p", wnd); ++ wrap_procfs_remove_ndis_device(wnd); ++ EXIT1(return); ++} ++ ++static int ndis_net_dev_open(struct net_device *net_dev) ++{ ++ int status, res; ++ struct ndis_device *wnd = netdev_priv(net_dev); ++ ++ ENTER1("%p", wnd); ++ res = mp_query_int(wnd, OID_GEN_MEDIA_CONNECT_STATUS, &status); ++ if (res == NDIS_STATUS_SUCCESS && status >= NdisMediaStateConnected && ++ status <= NdisMediaStateDisconnected) ++ set_media_state(wnd, status); ++ netif_start_queue(net_dev); ++ netif_poll_enable(net_dev); ++ EXIT1(return 0); ++} ++ ++static int ndis_net_dev_close(struct net_device *net_dev) ++{ ++ ENTER1("%p", netdev_priv(net_dev)); ++ netif_poll_disable(net_dev); ++ netif_tx_disable(net_dev); ++ EXIT1(return 0); ++} ++ ++static int ndis_change_mtu(struct net_device *net_dev, int mtu) ++{ ++ struct ndis_device *wnd = netdev_priv(net_dev); ++ int max; ++ ++ if (mtu < ETH_ZLEN) ++ return -EINVAL; ++ if (mp_query_int(wnd, OID_GEN_MAXIMUM_TOTAL_SIZE, &max) != ++ NDIS_STATUS_SUCCESS) ++ return -EOPNOTSUPP; ++ TRACE1("%d", max); ++ max -= ETH_HLEN; ++ if (max <= ETH_ZLEN) ++ return -EINVAL; ++ if (mtu + ETH_HLEN > max) ++ return -EINVAL; ++ net_dev->mtu = mtu; ++ return 0; ++} ++ ++#ifdef CONFIG_NET_POLL_CONTROLLER ++static void ndis_poll_controller(struct net_device *dev) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ++ disable_irq(dev->irq); ++ ndis_isr(wnd->mp_interrupt->kinterrupt, wnd->mp_interrupt); ++ enable_irq(dev->irq); ++} ++#endif ++ ++/* called from BH context */ ++static struct net_device_stats *ndis_get_stats(struct net_device *dev) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ return &wnd->net_stats; ++} ++ ++/* called from BH context */ ++static void ndis_set_multicast_list(struct net_device *dev) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ set_bit(SET_MULTICAST_LIST, &wnd->ndis_pending_work); ++ queue_work(wrapndis_wq, &wnd->ndis_work); ++} ++ ++/* called from BH context */ ++struct iw_statistics *get_iw_stats(struct net_device *dev) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ return &wnd->iw_stats; ++} ++ ++static void update_iw_stats(struct ndis_device *wnd) ++{ ++ struct iw_statistics *iw_stats = &wnd->iw_stats; ++ struct ndis_wireless_stats ndis_stats; ++ NDIS_STATUS res; ++ ndis_rssi rssi; ++ int qual; ++ ++ ENTER2("%p", wnd); ++ if (wnd->iw_stats_enabled == FALSE || !netif_carrier_ok(wnd->net_dev)) { ++ memset(iw_stats, 0, sizeof(*iw_stats)); ++ EXIT2(return); ++ } ++ res = mp_query(wnd, OID_802_11_RSSI, &rssi, sizeof(rssi)); ++ if (res == NDIS_STATUS_SUCCESS) ++ iw_stats->qual.level = rssi; ++ ++ qual = 100 * (rssi - WL_NOISE) / (WL_SIGMAX - WL_NOISE); ++ if (qual < 0) ++ qual = 0; ++ else if (qual > 100) ++ qual = 100; ++ ++ iw_stats->qual.noise = WL_NOISE; ++ iw_stats->qual.qual = qual; ++ ++ res = mp_query(wnd, OID_802_11_STATISTICS, ++ &ndis_stats, sizeof(ndis_stats)); ++ if (res != NDIS_STATUS_SUCCESS) ++ EXIT2(return); ++ iw_stats->discard.retries = (unsigned long)ndis_stats.retry + ++ (unsigned long)ndis_stats.multi_retry; ++ iw_stats->discard.misc = (unsigned long)ndis_stats.fcs_err + ++ (unsigned long)ndis_stats.rtss_fail + ++ (unsigned long)ndis_stats.ack_fail + ++ (unsigned long)ndis_stats.frame_dup; ++ ++ EXIT2(return); ++} ++ ++static void set_multicast_list(struct ndis_device *wnd) ++{ ++ struct net_device *net_dev; ++ ULONG packet_filter; ++ NDIS_STATUS res; ++ ++ net_dev = wnd->net_dev; ++ packet_filter = wnd->packet_filter; ++ ++ TRACE2("0x%08x", packet_filter); ++ if (net_dev->flags & IFF_PROMISC) { ++ packet_filter |= NDIS_PACKET_TYPE_PROMISCUOUS | ++ NDIS_PACKET_TYPE_ALL_LOCAL; ++ } else if (net_dev->flags & IFF_ALLMULTI || ++ netdev_mc_count(net_dev) > wnd->multicast_size) { ++ packet_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; ++ TRACE2("0x%08x", packet_filter); ++ } else if (netdev_mc_count(net_dev) > 0) { ++ int i, size; ++ char *buf; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) ++ struct netdev_hw_addr *ha; ++#else ++ struct dev_mc_list *mclist; ++#endif ++ size = min(wnd->multicast_size, netdev_mc_count(net_dev)); ++ TRACE2("%d, %d", wnd->multicast_size, netdev_mc_count(net_dev)); ++ buf = kmalloc(size * ETH_ALEN, GFP_KERNEL); ++ if (!buf) { ++ WARNING("couldn't allocate memory"); ++ EXIT2(return); ++ } ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) ++ i = 0; ++ netdev_for_each_mc_addr(ha, net_dev) { ++ if (i >= size) ++ break; ++ memcpy(buf + i * ETH_ALEN, ha->addr, ETH_ALEN); ++ TRACE2(MACSTRSEP, MAC2STR(ha->addr)); ++ i++; ++ } ++#else ++ mclist = net_dev->mc_list; ++ for (i = 0; i < size && mclist; mclist = mclist->next) { ++ if (mclist->dmi_addrlen != ETH_ALEN) ++ continue; ++ memcpy(buf + i * ETH_ALEN, mclist->dmi_addr, ETH_ALEN); ++ TRACE2(MACSTRSEP, MAC2STR(mclist->dmi_addr)); ++ i++; ++ } ++#endif ++ res = mp_set(wnd, OID_802_3_MULTICAST_LIST, buf, i * ETH_ALEN); ++ if (res == NDIS_STATUS_SUCCESS && i > 0) ++ packet_filter |= NDIS_PACKET_TYPE_MULTICAST; ++ else ++ packet_filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; ++ kfree(buf); ++ } ++ TRACE2("0x%08x", packet_filter); ++ res = set_packet_filter(wnd, packet_filter); ++ if (res) ++ TRACE1("couldn't set packet filter (%08X)", res); ++ EXIT2(return); ++} ++ ++static void link_status_off(struct ndis_device *wnd) ++{ ++#ifdef CONFIG_WIRELESS_EXT ++ union iwreq_data wrqu; ++ ++ memset(&wrqu, 0, sizeof(wrqu)); ++ wrqu.ap_addr.sa_family = ARPHRD_ETHER; ++ wireless_send_event(wnd->net_dev, SIOCGIWAP, &wrqu, NULL); ++#endif ++ EXIT2(return); ++} ++ ++static void link_status_on(struct ndis_device *wnd) ++{ ++#ifdef CONFIG_WIRELESS_EXT ++ struct ndis_assoc_info *ndis_assoc_info; ++ union iwreq_data wrqu; ++ NDIS_STATUS res; ++ const int assoc_size = sizeof(*ndis_assoc_info) + IW_CUSTOM_MAX + 32; ++#endif ++ ++ ENTER2(""); ++#ifdef CONFIG_WIRELESS_EXT ++ memset(&wrqu, 0, sizeof(wrqu)); ++ ndis_assoc_info = kzalloc(assoc_size, GFP_KERNEL); ++ if (!ndis_assoc_info) { ++ ERROR("couldn't allocate memory"); ++ goto send_assoc_event; ++ } ++ res = mp_query(wnd, OID_802_11_ASSOCIATION_INFORMATION, ++ ndis_assoc_info, assoc_size); ++ if (res) { ++ TRACE2("query assoc_info failed (%08X)", res); ++ kfree(ndis_assoc_info); ++ goto send_assoc_event; ++ } ++ TRACE2("%u, 0x%x, %u, 0x%x, %u", ndis_assoc_info->length, ++ ndis_assoc_info->req_ies, ndis_assoc_info->req_ie_length, ++ ndis_assoc_info->resp_ies, ndis_assoc_info->resp_ie_length); ++ if (ndis_assoc_info->req_ie_length > 0) { ++ wrqu.data.length = ndis_assoc_info->req_ie_length; ++ wireless_send_event(wnd->net_dev, IWEVASSOCREQIE, &wrqu, ++ ((char *)ndis_assoc_info) + ++ ndis_assoc_info->offset_req_ies); ++ } ++ if (ndis_assoc_info->resp_ie_length > 0) { ++ wrqu.data.length = ndis_assoc_info->resp_ie_length; ++ wireless_send_event(wnd->net_dev, IWEVASSOCRESPIE, &wrqu, ++ ((char *)ndis_assoc_info) + ++ ndis_assoc_info->offset_resp_ies); ++ } ++ kfree(ndis_assoc_info); ++ ++send_assoc_event: ++ get_ap_address(wnd, wrqu.ap_addr.sa_data); ++ wrqu.ap_addr.sa_family = ARPHRD_ETHER; ++ TRACE2(MACSTRSEP, MAC2STR(wrqu.ap_addr.sa_data)); ++ wireless_send_event(wnd->net_dev, SIOCGIWAP, &wrqu, NULL); ++#endif ++ EXIT2(return); ++} ++ ++static void iw_stats_timer_proc(unsigned long data) ++{ ++ struct ndis_device *wnd = (struct ndis_device *)data; ++ ++ ENTER2("%d", wnd->iw_stats_interval); ++ if (wnd->iw_stats_interval > 0) { ++ set_bit(COLLECT_IW_STATS, &wnd->ndis_pending_work); ++ queue_work(wrapndis_wq, &wnd->ndis_work); ++ } ++ mod_timer(&wnd->iw_stats_timer, jiffies + wnd->iw_stats_interval); ++} ++ ++static void add_iw_stats_timer(struct ndis_device *wnd) ++{ ++ if (wnd->physical_medium != NdisPhysicalMediumWirelessLan) ++ return; ++ if (wnd->iw_stats_interval < 0) ++ wnd->iw_stats_interval *= -1; ++ wnd->iw_stats_timer.data = (unsigned long)wnd; ++ wnd->iw_stats_timer.function = iw_stats_timer_proc; ++ mod_timer(&wnd->iw_stats_timer, jiffies + wnd->iw_stats_interval); ++} ++ ++static void del_iw_stats_timer(struct ndis_device *wnd) ++{ ++ ENTER2("%d", wnd->iw_stats_interval); ++ wnd->iw_stats_interval *= -1; ++ del_timer_sync(&wnd->iw_stats_timer); ++ EXIT2(return); ++} ++ ++static void hangcheck_proc(unsigned long data) ++{ ++ struct ndis_device *wnd = (struct ndis_device *)data; ++ ++ ENTER3("%d", wnd->hangcheck_interval); ++ if (wnd->hangcheck_interval > 0) { ++ set_bit(HANGCHECK, &wnd->ndis_pending_work); ++ queue_work(wrapndis_wq, &wnd->ndis_work); ++ } ++ mod_timer(&wnd->hangcheck_timer, jiffies + wnd->hangcheck_interval); ++ EXIT3(return); ++} ++ ++void hangcheck_add(struct ndis_device *wnd) ++{ ++ if (!wnd->wd->driver->ndis_driver->mp.hangcheck || ++ hangcheck_interval < 0) ++ EXIT2(return); ++ ++ if (hangcheck_interval > 0) ++ wnd->hangcheck_interval = hangcheck_interval * HZ; ++ if (wnd->hangcheck_interval < 0) ++ wnd->hangcheck_interval *= -1; ++ wnd->hangcheck_timer.data = (unsigned long)wnd; ++ wnd->hangcheck_timer.function = hangcheck_proc; ++ mod_timer(&wnd->hangcheck_timer, jiffies + wnd->hangcheck_interval); ++ EXIT2(return); ++} ++ ++void hangcheck_del(struct ndis_device *wnd) ++{ ++ ENTER2("%d", wnd->hangcheck_interval); ++ if (wnd->hangcheck_interval > 0) ++ wnd->hangcheck_interval *= -1; ++ del_timer_sync(&wnd->hangcheck_timer); ++ EXIT2(return); ++} ++ ++/* worker procedure to take care of setting/checking various states */ ++static void wrapndis_worker(struct work_struct *work) ++{ ++ struct ndis_device *wnd; ++ ++ wnd = container_of(work, struct ndis_device, ndis_work); ++ WORKTRACE("0x%lx", wnd->ndis_pending_work); ++ ++ if (test_and_clear_bit(NETIF_WAKEQ, &wnd->ndis_pending_work)) { ++ netif_tx_lock_bh(wnd->net_dev); ++ netif_wake_queue(wnd->net_dev); ++ netif_tx_unlock_bh(wnd->net_dev); ++ } ++ ++ if (test_and_clear_bit(LINK_STATUS_OFF, &wnd->ndis_pending_work)) ++ link_status_off(wnd); ++ ++ if (test_and_clear_bit(LINK_STATUS_ON, &wnd->ndis_pending_work)) ++ link_status_on(wnd); ++ ++ if (test_and_clear_bit(COLLECT_IW_STATS, &wnd->ndis_pending_work)) ++ update_iw_stats(wnd); ++ ++ if (test_and_clear_bit(SET_MULTICAST_LIST, ++ &wnd->ndis_pending_work)) ++ set_multicast_list(wnd); ++ ++ if (test_and_clear_bit(HANGCHECK, &wnd->ndis_pending_work)) { ++ struct miniport *mp; ++ BOOLEAN reset; ++ KIRQL irql; ++ ++ mp = &wnd->wd->driver->ndis_driver->mp; ++ irql = serialize_lock_irql(wnd); ++ reset = LIN2WIN1(mp->hangcheck, wnd->nmb->mp_ctx); ++ serialize_unlock_irql(wnd, irql); ++ if (reset) { ++ TRACE2("%s needs reset", wnd->net_dev->name); ++ mp_reset(wnd); ++ } ++ } ++ WORKEXIT(return); ++} ++ ++NDIS_STATUS ndis_reinit(struct ndis_device *wnd) ++{ ++ NDIS_STATUS status; ++ ++ wnd->attributes &= ~NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND; ++ status = mp_set_power_state(wnd, NdisDeviceStateD3); ++ if (status != NDIS_STATUS_SUCCESS) { ++ ERROR("halting device %s failed: %08X", wnd->net_dev->name, ++ status); ++ return status; ++ } ++ status = mp_set_power_state(wnd, NdisDeviceStateD0); ++ if (status != NDIS_STATUS_SUCCESS) ++ ERROR("starting device %s failed: %08X", wnd->net_dev->name, ++ status); ++ return status; ++} ++ ++#ifdef CONFIG_WIRELESS_EXT ++static void get_encryption_capa(struct ndis_device *wnd, char *buf, ++ const int buf_len) ++{ ++ int i, mode; ++ NDIS_STATUS res; ++ struct ndis_assoc_info ndis_assoc_info; ++ struct ndis_add_key ndis_key; ++ struct ndis_capability *c; ++ ++ ENTER1("%p", wnd); ++ /* set network type to g, b, or a, in that order */ ++ res = mp_query(wnd, OID_802_11_NETWORK_TYPES_SUPPORTED, buf, buf_len); ++ if (res == NDIS_STATUS_SUCCESS) { ++ struct network_type_list *net_types; ++ unsigned long types = 0; ++ net_types = (typeof(net_types))buf; ++ for (i = 0; i < net_types->num; i++) { ++ TRACE2("%d", net_types->types[i]); ++ set_bit(net_types->types[i], &types); ++ } ++ if (test_bit(Ndis802_11OFDM24, &types)) ++ mode = Ndis802_11OFDM24; ++ else if (test_bit(Ndis802_11DS, &types)) ++ mode = Ndis802_11DS; ++ else if (test_bit(Ndis802_11OFDM5, &types)) ++ mode = Ndis802_11OFDM5; ++ else ++ mode = Ndis802_11DS; ++ mp_set_int(wnd, OID_802_11_NETWORK_TYPE_IN_USE, mode); ++ } ++ /* check if WEP is supported */ ++ if (set_iw_encr_mode(wnd, IW_AUTH_CIPHER_WEP104, ++ IW_AUTH_CIPHER_NONE) == 0 && ++ get_ndis_encr_mode(wnd) == Ndis802_11Encryption1KeyAbsent) ++ set_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr); ++ ++ /* check if WPA is supported */ ++ if (set_ndis_auth_mode(wnd, Ndis802_11AuthModeWPA) == 0 && ++ get_ndis_auth_mode(wnd) == Ndis802_11AuthModeWPA) ++ set_bit(Ndis802_11AuthModeWPA, &wnd->capa.encr); ++ else ++ EXIT1(return); ++ ++ if (set_ndis_auth_mode(wnd, Ndis802_11AuthModeWPAPSK) == 0 && ++ get_ndis_auth_mode(wnd) == Ndis802_11AuthModeWPAPSK) ++ set_bit(Ndis802_11AuthModeWPAPSK, &wnd->capa.encr); ++ ++ /* check for highest encryption */ ++ mode = 0; ++ if (set_iw_encr_mode(wnd, IW_AUTH_CIPHER_CCMP, ++ IW_AUTH_CIPHER_NONE) == 0 && ++ (i = get_ndis_encr_mode(wnd)) > 0 && ++ (i == Ndis802_11Encryption3KeyAbsent || ++ i == Ndis802_11Encryption3Enabled)) ++ mode = Ndis802_11Encryption3Enabled; ++ else if (set_iw_encr_mode(wnd, IW_AUTH_CIPHER_TKIP, ++ IW_AUTH_CIPHER_NONE) == 0 && ++ (i = get_ndis_encr_mode(wnd)) > 0 && ++ (i == Ndis802_11Encryption2KeyAbsent || ++ i == Ndis802_11Encryption2Enabled)) ++ mode = Ndis802_11Encryption2Enabled; ++ else if (set_iw_encr_mode(wnd, IW_AUTH_CIPHER_WEP104, ++ IW_AUTH_CIPHER_NONE) == 0 && ++ (i = get_ndis_encr_mode(wnd)) > 0 && ++ (i == Ndis802_11Encryption1KeyAbsent || ++ i == Ndis802_11Encryption1Enabled)) ++ mode = Ndis802_11Encryption1Enabled; ++ ++ TRACE1("mode: %d", mode); ++ if (mode == 0) ++ EXIT1(return); ++ set_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr); ++ if (mode == Ndis802_11Encryption1Enabled) ++ EXIT1(return); ++ ++ ndis_key.length = 32; ++ ndis_key.index = 0xC0000001; ++ ndis_key.struct_size = sizeof(ndis_key); ++ res = mp_set(wnd, OID_802_11_ADD_KEY, &ndis_key, ndis_key.struct_size); ++ TRACE2("%08X, %zu", res, sizeof(ndis_key)); ++ if (res && res != NDIS_STATUS_INVALID_DATA) ++ EXIT1(return); ++ res = mp_query(wnd, OID_802_11_ASSOCIATION_INFORMATION, ++ &ndis_assoc_info, sizeof(ndis_assoc_info)); ++ TRACE1("%08X", res); ++ if (res == NDIS_STATUS_NOT_SUPPORTED) ++ EXIT1(return); ++ ++ set_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr); ++ if (mode == Ndis802_11Encryption3Enabled) ++ set_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr); ++ /* not all drivers support OID_802_11_CAPABILITY, so we don't ++ * know for sure if driver support WPA or WPAPSK; assume ++ * WPAPSK */ ++ set_bit(Ndis802_11AuthModeWPAPSK, &wnd->capa.auth); ++ wnd->max_pmkids = 1; ++ ++ memset(buf, 0, buf_len); ++ c = (struct ndis_capability *)buf; ++ res = mp_query(wnd, OID_802_11_CAPABILITY, buf, buf_len); ++ if (!(res == NDIS_STATUS_SUCCESS && c->version == 2)) ++ EXIT1(return); ++ wnd->max_pmkids = c->num_PMKIDs; ++ ++ for (i = 0; i < c->num_auth_encr_pair; i++) { ++ struct ndis_auth_encr_pair *ae; ++ ++ ae = &c->auth_encr_pair[i]; ++ if ((char *)(ae + 1) > buf + buf_len) ++ break; ++ switch (ae->auth_mode) { ++ case Ndis802_11AuthModeOpen: ++ case Ndis802_11AuthModeShared: ++ case Ndis802_11AuthModeWPA: ++ case Ndis802_11AuthModeWPAPSK: ++ case Ndis802_11AuthModeWPANone: ++ case Ndis802_11AuthModeWPA2: ++ case Ndis802_11AuthModeWPA2PSK: ++ set_bit(ae->auth_mode, &wnd->capa.auth); ++ break; ++ default: ++ WARNING("unknown auth_mode: %d", ae->auth_mode); ++ break; ++ } ++ switch (ae->encr_mode) { ++ case Ndis802_11EncryptionDisabled: ++ case Ndis802_11Encryption1Enabled: ++ case Ndis802_11Encryption2Enabled: ++ case Ndis802_11Encryption3Enabled: ++ set_bit(ae->encr_mode, &wnd->capa.encr); ++ break; ++ default: ++ WARNING("unknown encr_mode: %d", ae->encr_mode); ++ break; ++ } ++ } ++ EXIT1(return); ++} ++#endif ++ ++wstdcall NTSTATUS NdisDispatchDeviceControl(struct device_object *fdo, ++ struct irp *irp) ++{ ++ struct ndis_device *wnd; ++ ++ TRACE3("fdo: %p", fdo); ++ /* for now, we don't have anything interesting here, so pass it ++ * down to bus driver */ ++ wnd = fdo->reserved; ++ return IoPassIrpDown(wnd->nmb->pdo, irp); ++} ++WIN_FUNC_DECL(NdisDispatchDeviceControl,2) ++ ++wstdcall NTSTATUS NdisDispatchPower(struct device_object *fdo, struct irp *irp) ++{ ++ struct io_stack_location *irp_sl; ++ struct ndis_device *wnd; ++ enum ndis_power_state state; ++ NTSTATUS status; ++ NDIS_STATUS ndis_status; ++ ++ irp_sl = IoGetCurrentIrpStackLocation(irp); ++ wnd = fdo->reserved; ++ IOTRACE("fdo: %p, fn: %d:%d, wnd: %p", fdo, irp_sl->major_fn, ++ irp_sl->minor_fn, wnd); ++ if ((irp_sl->params.power.type == SystemPowerState && ++ irp_sl->params.power.state.system_state > PowerSystemWorking) || ++ (irp_sl->params.power.type == DevicePowerState && ++ irp_sl->params.power.state.device_state > PowerDeviceD0)) ++ state = NdisDeviceStateD3; ++ else ++ state = NdisDeviceStateD0; ++ switch (irp_sl->minor_fn) { ++ case IRP_MN_SET_POWER: ++ if (state == NdisDeviceStateD0) { ++ status = IoSyncForwardIrp(wnd->nmb->pdo, irp); ++ if (status != STATUS_SUCCESS) ++ break; ++ ndis_status = mp_set_power_state(wnd, state); ++ if (ndis_status != NDIS_STATUS_SUCCESS) ++ WARNING("couldn't set power to %d: %08X", ++ state, ndis_status); ++ TRACE2("%s: device resumed", wnd->net_dev->name); ++ irp->io_status.status = status = STATUS_SUCCESS; ++ IoCompleteRequest(irp, IO_NO_INCREMENT); ++ break; ++ } else { ++ ndis_status = mp_set_power_state(wnd, state); ++ /* TODO: handle error case */ ++ if (ndis_status != NDIS_STATUS_SUCCESS) ++ WARNING("setting power to %d failed: %08X", ++ state, ndis_status); ++ status = IoAsyncForwardIrp(wnd->nmb->pdo, irp); ++ } ++ break; ++ case IRP_MN_QUERY_POWER: ++ if (wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND) { ++ ndis_status = mp_query(wnd, OID_PNP_QUERY_POWER, ++ &state, sizeof(state)); ++ TRACE2("%d, %08X", state, ndis_status); ++ /* this OID must always succeed */ ++ if (ndis_status != NDIS_STATUS_SUCCESS) ++ TRACE1("query power returns %08X", ndis_status); ++ irp->io_status.status = STATUS_SUCCESS; ++ } else ++ irp->io_status.status = STATUS_SUCCESS; ++ status = IoPassIrpDown(wnd->nmb->pdo, irp); ++ break; ++ case IRP_MN_WAIT_WAKE: ++ case IRP_MN_POWER_SEQUENCE: ++ /* TODO: implement WAIT_WAKE */ ++ status = IoPassIrpDown(wnd->nmb->pdo, irp); ++ break; ++ default: ++ status = IoPassIrpDown(wnd->nmb->pdo, irp); ++ break; ++ } ++ IOEXIT(return status); ++} ++WIN_FUNC_DECL(NdisDispatchPower,2) ++ ++wstdcall NTSTATUS NdisDispatchPnp(struct device_object *fdo, struct irp *irp) ++{ ++ struct io_stack_location *irp_sl; ++ struct ndis_device *wnd; ++ struct device_object *pdo; ++ NTSTATUS status; ++ ++ IOTRACE("fdo: %p, irp: %p", fdo, irp); ++ irp_sl = IoGetCurrentIrpStackLocation(irp); ++ wnd = fdo->reserved; ++ pdo = wnd->nmb->pdo; ++ switch (irp_sl->minor_fn) { ++ case IRP_MN_START_DEVICE: ++ status = IoSyncForwardIrp(pdo, irp); ++ if (status != STATUS_SUCCESS) ++ break; ++ if (ndis_start_device(wnd) == NDIS_STATUS_SUCCESS) ++ status = STATUS_SUCCESS; ++ else ++ status = STATUS_FAILURE; ++ irp->io_status.status = status; ++ IoCompleteRequest(irp, IO_NO_INCREMENT); ++ break; ++ case IRP_MN_QUERY_STOP_DEVICE: ++ /* TODO: implement in NDIS */ ++ status = IoPassIrpDown(wnd->nmb->pdo, irp); ++ break; ++ case IRP_MN_STOP_DEVICE: ++ mp_halt(wnd); ++ irp->io_status.status = STATUS_SUCCESS; ++ status = IoAsyncForwardIrp(pdo, irp); ++ break; ++ case IRP_MN_REMOVE_DEVICE: ++ TRACE1("%s", wnd->net_dev->name); ++ mp_pnp_event(wnd, NdisDevicePnPEventSurpriseRemoved, 0); ++ if (ndis_remove_device(wnd)) { ++ status = STATUS_FAILURE; ++ break; ++ } ++ /* wnd is already freed */ ++ status = IoAsyncForwardIrp(pdo, irp); ++ IoDetachDevice(fdo); ++ IoDeleteDevice(fdo); ++ break; ++ default: ++ status = IoAsyncForwardIrp(pdo, irp); ++ break; ++ } ++ IOTRACE("status: %08X", status); ++ IOEXIT(return status); ++} ++WIN_FUNC_DECL(NdisDispatchPnp,2) ++ ++static void set_task_offload(struct ndis_device *wnd, void *buf, ++ const int buf_size) ++{ ++ struct ndis_task_offload_header *task_offload_header; ++ struct ndis_task_offload *task_offload; ++ struct ndis_task_tcp_ip_checksum *csum = NULL; ++ struct ndis_task_tcp_large_send *tso = NULL; ++ NDIS_STATUS status; ++ ++ memset(buf, 0, buf_size); ++ task_offload_header = buf; ++ task_offload_header->version = NDIS_TASK_OFFLOAD_VERSION; ++ task_offload_header->size = sizeof(*task_offload_header); ++ task_offload_header->encap_format.flags.fixed_header_size = 1; ++ task_offload_header->encap_format.header_size = sizeof(struct ethhdr); ++ task_offload_header->encap_format.encap = IEEE_802_3_Encapsulation; ++ status = mp_query(wnd, OID_TCP_TASK_OFFLOAD, buf, buf_size); ++ TRACE1("%08X", status); ++ if (status != NDIS_STATUS_SUCCESS) ++ EXIT1(return); ++ if (task_offload_header->offset_first_task == 0) ++ EXIT1(return); ++ task_offload = ((void *)task_offload_header + ++ task_offload_header->offset_first_task); ++ while (1) { ++ TRACE1("%d, %d", task_offload->version, task_offload->task); ++ switch (task_offload->task) { ++ case TcpIpChecksumNdisTask: ++ csum = (void *)task_offload->task_buf; ++ break; ++ case TcpLargeSendNdisTask: ++ tso = (void *)task_offload->task_buf; ++ break; ++ default: ++ TRACE1("%d", task_offload->task); ++ break; ++ } ++ if (task_offload->offset_next_task == 0) ++ break; ++ task_offload = (void *)task_offload + ++ task_offload->offset_next_task; ++ } ++ if (tso) ++ TRACE1("%u, %u, %d, %d", tso->max_size, tso->min_seg_count, ++ tso->tcp_opts, tso->ip_opts); ++ if (!csum) ++ EXIT1(return); ++ TRACE1("%08x, %08x", csum->v4_tx.value, csum->v4_rx.value); ++ task_offload_header->encap_format.flags.fixed_header_size = 1; ++ task_offload_header->encap_format.header_size = sizeof(struct ethhdr); ++ task_offload_header->offset_first_task = sizeof(*task_offload_header); ++ task_offload = ((void *)task_offload_header + ++ task_offload_header->offset_first_task); ++ task_offload->offset_next_task = 0; ++ task_offload->size = sizeof(*task_offload); ++ task_offload->task = TcpIpChecksumNdisTask; ++ memcpy(task_offload->task_buf, csum, sizeof(*csum)); ++ task_offload->task_buf_length = sizeof(*csum); ++ status = mp_set(wnd, OID_TCP_TASK_OFFLOAD, task_offload_header, ++ sizeof(*task_offload_header) + ++ sizeof(*task_offload) + sizeof(*csum)); ++ TRACE1("%08X", status); ++ if (status != NDIS_STATUS_SUCCESS) ++ EXIT2(return); ++ wnd->tx_csum = csum->v4_tx; ++ if (csum->v4_tx.tcp_csum && csum->v4_tx.udp_csum) { ++ if (csum->v4_tx.ip_csum) { ++ wnd->net_dev->features |= NETIF_F_HW_CSUM; ++ TRACE1("hw checksum enabled"); ++ } else { ++ wnd->net_dev->features |= NETIF_F_IP_CSUM; ++ TRACE1("IP checksum enabled"); ++ } ++ if (wnd->sg_dma_size) ++ wnd->net_dev->features |= NETIF_F_SG; ++ } ++ wnd->rx_csum = csum->v4_rx; ++ EXIT1(return); ++} ++ ++static void get_supported_oids(struct ndis_device *wnd) ++{ ++ NDIS_STATUS res; ++ int i, n, needed; ++ ndis_oid *oids; ++ ++ res = mp_query_info(wnd, OID_GEN_SUPPORTED_LIST, NULL, 0, NULL, ++ &needed); ++ if (!(res == NDIS_STATUS_BUFFER_TOO_SHORT || ++ res == NDIS_STATUS_INVALID_LENGTH)) ++ EXIT1(return); ++ oids = kmalloc(needed, GFP_KERNEL); ++ if (!oids) { ++ TRACE1("couldn't allocate memory"); ++ EXIT1(return); ++ } ++ res = mp_query(wnd, OID_GEN_SUPPORTED_LIST, oids, needed); ++ if (res) { ++ TRACE1("failed: %08X", res); ++ kfree(oids); ++ EXIT1(return); ++ } ++ for (i = 0, n = needed / sizeof(*oids); i < n; i++) { ++ TRACE1("oid: %08X", oids[i]); ++ /* if a wireless device didn't say so for ++ * OID_GEN_PHYSICAL_MEDIUM (they should, but in case) */ ++ if (wnd->physical_medium != NdisPhysicalMediumWirelessLan && ++ oids[i] == OID_802_11_SSID) ++ wnd->physical_medium = NdisPhysicalMediumWirelessLan; ++ } ++ kfree(oids); ++ EXIT1(return); ++} ++ ++static void ndis_get_drvinfo(struct net_device *dev, ++ struct ethtool_drvinfo *info) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 2); ++ strcat(info->driver, "+"); ++ strncat(info->driver, wnd->wd->driver->name, ++ sizeof(info->driver) - strlen(DRIVER_NAME) - 1); ++ strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 2); ++ strcat(info->version, "+"); ++ strncat(info->version, wnd->wd->driver->version, ++ sizeof(info->version) - strlen(DRIVER_VERSION) - 1); ++ if (wrap_is_pci_bus(wnd->wd->dev_bus)) ++ strncpy(info->bus_info, pci_name(wnd->wd->pci.pdev), ++ sizeof(info->bus_info) - 1); ++#ifdef ENABLE_USB ++ else ++ usb_make_path(wnd->wd->usb.udev, info->bus_info, ++ sizeof(info->bus_info) - 1); ++#endif ++ return; ++} ++ ++static u32 ndis_get_link(struct net_device *dev) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ return netif_carrier_ok(wnd->net_dev); ++} ++ ++static void ndis_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ++ wol->supported = 0; ++ wol->wolopts = 0; ++ if (!(wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND)) ++ EXIT2(return); ++ if (!wrap_is_pci_bus(wnd->wd->dev_bus)) ++ EXIT2(return); ++ /* we always suspend to D3 */ ++ if (wnd->pnp_capa.wakeup.min_magic_packet_wakeup < NdisDeviceStateD3) ++ return; ++ wol->supported |= WAKE_MAGIC; ++ if (wnd->ndis_wolopts & NDIS_PNP_WAKE_UP_MAGIC_PACKET) ++ wol->wolopts |= WAKE_MAGIC; ++ return; ++} ++ ++static int ndis_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ++ if (!(wnd->attributes & NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND)) ++ return -EOPNOTSUPP; ++ if (wnd->pnp_capa.wakeup.min_magic_packet_wakeup < NdisDeviceStateD3) ++ EXIT2(return -EOPNOTSUPP); ++ TRACE2("0x%x", wol->wolopts); ++ if (wol->wolopts & WAKE_MAGIC) { ++ wnd->ndis_wolopts |= NDIS_PNP_WAKE_UP_MAGIC_PACKET; ++ if (wol->wolopts != WAKE_MAGIC) ++ WARNING("ignored wake-on-lan options: 0x%x", ++ wol->wolopts & ~WAKE_MAGIC); ++ } else if (!wol->wolopts) ++ wnd->ndis_wolopts = 0; ++ else ++ return -EOPNOTSUPP; ++ TRACE2("0x%x", wnd->ndis_wolopts); ++ return 0; ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0) ++static u32 ndis_get_tx_csum(struct net_device *dev) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ if (wnd->tx_csum.tcp_csum && wnd->tx_csum.udp_csum) ++ return 1; ++ else ++ return 0; ++} ++ ++static u32 ndis_get_rx_csum(struct net_device *dev) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ if (wnd->rx_csum.value) ++ return 1; ++ else ++ return 0; ++} ++ ++static int ndis_set_tx_csum(struct net_device *dev, u32 data) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ++ if (data && (wnd->tx_csum.value == 0)) ++ return -EOPNOTSUPP; ++ ++ if (wnd->tx_csum.ip_csum) ++ ethtool_op_set_tx_hw_csum(dev, data); ++ else ++ ethtool_op_set_tx_csum(dev, data); ++ return 0; ++} ++ ++static int ndis_set_rx_csum(struct net_device *dev, u32 data) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ ++ if (data && (wnd->tx_csum.value == 0)) ++ return -EOPNOTSUPP; ++ ++ /* TODO: enable/disable rx csum through NDIS */ ++ return 0; ++} ++ ++static u32 ndis_get_sg(struct net_device *dev) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ if (wnd->sg_dma_size) ++ return ethtool_op_get_sg(dev); ++ else ++ return 0; ++} ++ ++static int ndis_set_sg(struct net_device *dev, u32 data) ++{ ++ struct ndis_device *wnd = netdev_priv(dev); ++ if (wnd->sg_dma_size) ++ return ethtool_op_set_sg(dev, data); ++ else ++ return -EOPNOTSUPP; ++} ++#endif ++ ++static struct ethtool_ops ndis_ethtool_ops = { ++ .get_drvinfo = ndis_get_drvinfo, ++ .get_link = ndis_get_link, ++ .get_wol = ndis_get_wol, ++ .set_wol = ndis_set_wol, ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0) ++ .get_tx_csum = ndis_get_tx_csum, ++ .get_rx_csum = ndis_get_rx_csum, ++ .set_tx_csum = ndis_set_tx_csum, ++ .set_rx_csum = ndis_set_rx_csum, ++ .get_sg = ndis_get_sg, ++ .set_sg = ndis_set_sg, ++#endif ++}; ++ ++static int notifier_event(struct notifier_block *notifier, unsigned long event, ++ void *ptr) ++{ ++ struct net_device *net_dev = netdev_notifier_info_to_dev(ptr); ++ ++ ENTER2("0x%lx", event); ++ if (net_dev->ethtool_ops == &ndis_ethtool_ops ++ && event == NETDEV_CHANGENAME) { ++ struct ndis_device *wnd = netdev_priv(net_dev); ++ ++ /* called with rtnl lock held, so no need to lock */ ++ if (likely(wnd->procfs_iface)) { ++ printk(KERN_INFO "%s: interface renamed to '%s'\n", ++ DRIVER_NAME, net_dev->name); ++ wrap_procfs_remove_ndis_device(wnd); ++ wrap_procfs_add_ndis_device(wnd); ++ } ++ } ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block netdev_notifier = { ++ .notifier_call = notifier_event, ++}; ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) ++static const struct net_device_ops ndis_netdev_ops = { ++ .ndo_init = ndis_net_dev_init, ++ .ndo_uninit = ndis_net_dev_uninit, ++ .ndo_open = ndis_net_dev_open, ++ .ndo_stop = ndis_net_dev_close, ++ .ndo_start_xmit = tx_skbuff, ++ .ndo_change_mtu = ndis_change_mtu, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) ++ .ndo_set_rx_mode = ndis_set_multicast_list, ++#else ++ .ndo_set_multicast_list = ndis_set_multicast_list, ++#endif ++ .ndo_set_mac_address = ndis_set_mac_address, ++ .ndo_get_stats = ndis_get_stats, ++#ifdef CONFIG_NET_POLL_CONTROLLER ++ .ndo_poll_controller = ndis_poll_controller, ++#endif ++}; ++#endif ++ ++static NDIS_STATUS ndis_start_device(struct ndis_device *wnd) ++{ ++ struct wrap_device *wd; ++ struct net_device *net_dev; ++ NDIS_STATUS status; ++ char *buf; ++ const int buf_len = 256; ++ mac_address mac; ++ struct transport_header_offset *tx_header_offset; ++ int n; ++ ++ ENTER2("%d", in_atomic()); ++ status = mp_init(wnd); ++ if (status == NDIS_STATUS_NOT_RECOGNIZED) ++ EXIT1(return NDIS_STATUS_SUCCESS); ++ if (status != NDIS_STATUS_SUCCESS) ++ EXIT1(return status); ++ wd = wnd->wd; ++ net_dev = wnd->net_dev; ++ ++ get_supported_oids(wnd); ++ memset(mac, 0, sizeof(mac)); ++ status = mp_query(wnd, OID_802_3_CURRENT_ADDRESS, mac, sizeof(mac)); ++ if (memcmp(mac, "\x00\x00\x00\x00\x00\x00", sizeof(mac)) == 0) { ++ status = mp_query(wnd, OID_802_3_PERMANENT_ADDRESS, mac, ++ sizeof(mac)); ++ if (status != NDIS_STATUS_SUCCESS) { ++ ERROR("couldn't get mac address: %08X", status); ++ goto err_start; ++ } ++ } ++ TRACE1("mac:" MACSTRSEP, MAC2STR(mac)); ++ memcpy(net_dev->dev_addr, mac, ETH_ALEN); ++ ++ strncpy(net_dev->name, if_name, IFNAMSIZ - 1); ++ net_dev->name[IFNAMSIZ - 1] = 0; ++ ++ wnd->packet_filter = NDIS_PACKET_TYPE_DIRECTED | ++ NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_MULTICAST; ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) ++ net_dev->netdev_ops = &ndis_netdev_ops; ++#else ++ net_dev->init = ndis_net_dev_init; ++ net_dev->uninit = ndis_net_dev_uninit; ++ net_dev->open = ndis_net_dev_open; ++ net_dev->hard_start_xmit = tx_skbuff; ++ net_dev->stop = ndis_net_dev_close; ++ net_dev->get_stats = ndis_get_stats; ++ net_dev->change_mtu = ndis_change_mtu; ++ net_dev->set_multicast_list = ndis_set_multicast_list; ++ net_dev->set_mac_address = ndis_set_mac_address; ++#ifdef CONFIG_NET_POLL_CONTROLLER ++ net_dev->poll_controller = ndis_poll_controller; ++#endif ++#endif ++#ifdef CONFIG_WIRELESS_EXT ++ if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) { ++ net_dev->wireless_handlers = &ndis_handler_def; ++ } ++#endif ++ net_dev->ethtool_ops = &ndis_ethtool_ops; ++ if (wnd->mp_interrupt) ++ net_dev->irq = wnd->mp_interrupt->irq; ++ net_dev->mem_start = wnd->mem_start; ++ net_dev->mem_end = wnd->mem_end; ++ status = mp_query_int(wnd, OID_802_3_MAXIMUM_LIST_SIZE, ++ &wnd->multicast_size); ++ if (status != NDIS_STATUS_SUCCESS || wnd->multicast_size < 0) ++ wnd->multicast_size = 0; ++ if (wnd->multicast_size > 0) ++ net_dev->flags |= IFF_MULTICAST; ++ else ++ net_dev->flags &= ~IFF_MULTICAST; ++ ++ buf = kmalloc(buf_len, GFP_KERNEL); ++ if (!buf) { ++ WARNING("couldn't allocate memory"); ++ goto err_start; ++ } ++ ++ set_task_offload(wnd, buf, buf_len); ++#ifdef NETIF_F_LLTX ++ net_dev->features |= NETIF_F_LLTX; ++#endif ++ ++ if (register_netdev(net_dev)) { ++ ERROR("cannot register net device %s", net_dev->name); ++ goto err_register; ++ } ++ memset(buf, 0, buf_len); ++ status = mp_query(wnd, OID_GEN_VENDOR_DESCRIPTION, buf, buf_len); ++ if (status != NDIS_STATUS_SUCCESS) { ++ WARNING("couldn't get vendor information: 0x%x", status); ++ buf[0] = 0; ++ } ++ wnd->drv_ndis_version = n = 0; ++ mp_query_int(wnd, OID_GEN_DRIVER_VERSION, &wnd->drv_ndis_version); ++ mp_query_int(wnd, OID_GEN_VENDOR_DRIVER_VERSION, &n); ++ ++ printk(KERN_INFO "%s: ethernet device " MACSTRSEP " using %sNDIS " ++ "driver: %s, version: 0x%x, NDIS version: 0x%x, vendor: '%s', " ++ "%s\n", net_dev->name, MAC2STR(net_dev->dev_addr), ++ deserialized_driver(wnd) ? "" : "serialized ", ++ wd->driver->name, n, wnd->drv_ndis_version, buf, ++ wd->conf_file_name); ++ ++ if (deserialized_driver(wnd)) { ++ /* deserialized drivers don't have a limit, but we ++ * keep max at TX_RING_SIZE */ ++ wnd->max_tx_packets = TX_RING_SIZE; ++ } else { ++ status = mp_query_int(wnd, OID_GEN_MAXIMUM_SEND_PACKETS, ++ &wnd->max_tx_packets); ++ if (status != NDIS_STATUS_SUCCESS) ++ wnd->max_tx_packets = 1; ++ if (wnd->max_tx_packets > TX_RING_SIZE) ++ wnd->max_tx_packets = TX_RING_SIZE; ++ } ++ TRACE2("maximum send packets: %d", wnd->max_tx_packets); ++ NdisAllocatePacketPoolEx(&status, &wnd->tx_packet_pool, ++ wnd->max_tx_packets, 0, ++ PROTOCOL_RESERVED_SIZE_IN_PACKET); ++ if (status != NDIS_STATUS_SUCCESS) { ++ ERROR("couldn't allocate packet pool"); ++ goto packet_pool_err; ++ } ++ NdisAllocateBufferPool(&status, &wnd->tx_buffer_pool, ++ wnd->max_tx_packets + 4); ++ if (status != NDIS_STATUS_SUCCESS) { ++ ERROR("couldn't allocate buffer pool"); ++ goto buffer_pool_err; ++ } ++ TRACE1("pool: %p", wnd->tx_buffer_pool); ++ ++ if (mp_query_int(wnd, OID_GEN_MAXIMUM_TOTAL_SIZE, &n) == ++ NDIS_STATUS_SUCCESS && n > ETH_HLEN) ++ ndis_change_mtu(wnd->net_dev, n - ETH_HLEN); ++ ++ if (mp_query_int(wnd, OID_GEN_MAC_OPTIONS, &n) == NDIS_STATUS_SUCCESS) ++ TRACE2("mac options supported: 0x%x", n); ++ ++ tx_header_offset = (typeof(tx_header_offset))buf; ++ tx_header_offset->protocol_type = NDIS_PROTOCOL_ID_TCP_IP; ++ tx_header_offset->header_offset = sizeof(ETH_HLEN); ++ status = mp_set(wnd, OID_GEN_TRANSPORT_HEADER_OFFSET, ++ tx_header_offset, sizeof(*tx_header_offset)); ++ TRACE2("%08X", status); ++ ++ status = mp_query_int(wnd, OID_GEN_PHYSICAL_MEDIUM, ++ &wnd->physical_medium); ++ if (status != NDIS_STATUS_SUCCESS) ++ wnd->physical_medium = NdisPhysicalMediumUnspecified; ++ ++#ifdef CONFIG_WIRELESS_EXT ++ if (wnd->physical_medium == NdisPhysicalMediumWirelessLan) { ++ mp_set_int(wnd, OID_802_11_POWER_MODE, NDIS_POWER_OFF); ++ get_encryption_capa(wnd, buf, buf_len); ++ TRACE1("capabilities = %ld", wnd->capa.encr); ++ printk(KERN_INFO "%s: encryption modes supported: " ++ "%s%s%s%s%s%s%s\n", net_dev->name, ++ test_bit(Ndis802_11Encryption1Enabled, &wnd->capa.encr) ? ++ "WEP" : "none", ++ ++ test_bit(Ndis802_11Encryption2Enabled, &wnd->capa.encr) ? ++ "; TKIP with WPA" : "", ++ test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ? ++ ", WPA2" : "", ++ test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ? ++ ", WPA2-PSK" : "", ++ ++ test_bit(Ndis802_11Encryption3Enabled, &wnd->capa.encr) ? ++ "; AES/CCMP with WPA" : "", ++ test_bit(Ndis802_11AuthModeWPA2, &wnd->capa.auth) ? ++ ", WPA2" : "", ++ test_bit(Ndis802_11AuthModeWPA2PSK, &wnd->capa.auth) ? ++ ", WPA2-PSK" : ""); ++ ++ set_default_iw_params(wnd); ++ } ++#endif ++ kfree(buf); ++ hangcheck_add(wnd); ++ add_iw_stats_timer(wnd); ++ EXIT1(return NDIS_STATUS_SUCCESS); ++ ++buffer_pool_err: ++ wnd->tx_buffer_pool = NULL; ++ if (wnd->tx_packet_pool) { ++ NdisFreePacketPool(wnd->tx_packet_pool); ++ wnd->tx_packet_pool = NULL; ++ } ++packet_pool_err: ++ unregister_netdev(net_dev); ++ wnd->max_tx_packets = 0; ++err_register: ++ kfree(buf); ++err_start: ++ mp_halt(wnd); ++ EXIT1(return NDIS_STATUS_FAILURE); ++} ++ ++static int ndis_remove_device(struct ndis_device *wnd) ++{ ++ s8 tx_pending; ++ int our_mutex; ++ ++ /* prevent setting essid during disassociation */ ++ memset(&wnd->essid, 0, sizeof(wnd->essid)); ++ wnd->tx_ok = 0; ++ netif_carrier_off(wnd->net_dev); ++ if (wnd->max_tx_packets) ++ unregister_netdev(wnd->net_dev); ++ /* if device is suspended, but resume failed, tx_ring_mutex ++ * may already be locked */ ++ our_mutex = mutex_trylock(&wnd->tx_ring_mutex); ++ if (!our_mutex) ++ WARNING("couldn't obtain tx_ring_mutex"); ++ spin_lock_bh(&wnd->tx_ring_lock); ++ tx_pending = wnd->tx_ring_end - wnd->tx_ring_start; ++ if (tx_pending < 0) ++ tx_pending += TX_RING_SIZE; ++ else if (tx_pending == 0 && wnd->is_tx_ring_full) ++ tx_pending = TX_RING_SIZE - 1; ++ wnd->is_tx_ring_full = 0; ++ /* throw away pending packets */ ++ while (tx_pending-- > 0) { ++ struct ndis_packet *packet; ++ ++ packet = wnd->tx_ring[wnd->tx_ring_start]; ++ free_tx_packet(wnd, packet, NDIS_STATUS_CLOSING); ++ wnd->tx_ring_start = (wnd->tx_ring_start + 1) % TX_RING_SIZE; ++ } ++ spin_unlock_bh(&wnd->tx_ring_lock); ++ if (our_mutex) ++ mutex_unlock(&wnd->tx_ring_mutex); ++ mp_halt(wnd); ++ ndis_exit_device(wnd); ++ ++ if (wnd->tx_packet_pool) { ++ NdisFreePacketPool(wnd->tx_packet_pool); ++ wnd->tx_packet_pool = NULL; ++ } ++ if (wnd->tx_buffer_pool) { ++ NdisFreeBufferPool(wnd->tx_buffer_pool); ++ wnd->tx_buffer_pool = NULL; ++ } ++ kfree(wnd->pmkids); ++ printk(KERN_INFO "%s: device %s removed\n", DRIVER_NAME, ++ wnd->net_dev->name); ++ kfree(wnd->nmb); ++ free_netdev(wnd->net_dev); ++ EXIT2(return 0); ++} ++ ++static NTSTATUS ndis_add_device(struct driver_object *drv_obj, ++ struct device_object *pdo) ++{ ++ struct device_object *fdo; ++ struct ndis_mp_block *nmb; ++ NTSTATUS status; ++ struct ndis_device *wnd; ++ struct net_device *net_dev; ++ struct wrap_device *wd; ++ unsigned long i; ++ ++ ENTER2("%p, %p", drv_obj, pdo); ++ if (strlen(if_name) >= IFNAMSIZ) { ++ ERROR("interface name '%s' is too long", if_name); ++ return STATUS_INVALID_PARAMETER; ++ } ++ net_dev = alloc_etherdev(sizeof(*wnd)); ++ if (!net_dev) { ++ ERROR("couldn't allocate device"); ++ return STATUS_RESOURCES; ++ } ++ wd = pdo->reserved; ++ if (wrap_is_pci_bus(wd->dev_bus)) ++ SET_NETDEV_DEV(net_dev, &wd->pci.pdev->dev); ++ if (wrap_is_usb_bus(wd->dev_bus)) ++ SET_NETDEV_DEV(net_dev, &wd->usb.intf->dev); ++ status = IoCreateDevice(drv_obj, 0, NULL, FILE_DEVICE_UNKNOWN, 0, ++ FALSE, &fdo); ++ if (status != STATUS_SUCCESS) { ++ free_netdev(net_dev); ++ EXIT2(return status); ++ } ++ wnd = netdev_priv(net_dev); ++ TRACE1("wnd: %p", wnd); ++ ++ nmb = kmalloc(sizeof(*nmb), GFP_KERNEL); ++ if (!nmb) { ++ WARNING("couldn't allocate memory"); ++ IoDeleteDevice(fdo); ++ free_netdev(net_dev); ++ return STATUS_RESOURCES; ++ } ++#if DEBUG >= 6 ++ /* poison nmb so if a driver accesses uninitialized pointers, we ++ * know what it is */ ++ for (i = 0; i < sizeof(*nmb) / sizeof(unsigned long); i++) ++ ((unsigned long *)nmb)[i] = i + 0x8a3fc1; ++#endif ++ ++ wnd->nmb = nmb; ++ nmb->wnd = wnd; ++ nmb->pdo = pdo; ++ wnd->wd = wd; ++ wnd->net_dev = net_dev; ++ fdo->reserved = wnd; ++ nmb->fdo = fdo; ++ if (ndis_init_device(wnd)) { ++ IoDeleteDevice(fdo); ++ kfree(nmb); ++ free_netdev(net_dev); ++ EXIT1(return STATUS_RESOURCES); ++ } ++ nmb->next_device = IoAttachDeviceToDeviceStack(fdo, pdo); ++ spin_lock_init(&wnd->tx_ring_lock); ++ mutex_init(&wnd->tx_ring_mutex); ++ mutex_init(&wnd->ndis_req_mutex); ++ wnd->ndis_req_done = 0; ++ INIT_WORK(&wnd->tx_work, tx_worker); ++ wnd->tx_ring_start = 0; ++ wnd->tx_ring_end = 0; ++ wnd->is_tx_ring_full = 0; ++ wnd->capa.encr = 0; ++ wnd->capa.auth = 0; ++ wnd->attributes = 0; ++ wnd->dma_map_count = 0; ++ wnd->dma_map_addr = NULL; ++ wnd->nick[0] = 0; ++ init_timer(&wnd->hangcheck_timer); ++ wnd->scan_timestamp = 0; ++ init_timer(&wnd->iw_stats_timer); ++ wnd->iw_stats_interval = 10 * HZ; ++ wnd->ndis_pending_work = 0; ++ memset(&wnd->essid, 0, sizeof(wnd->essid)); ++ memset(&wnd->encr_info, 0, sizeof(wnd->encr_info)); ++ wnd->infrastructure_mode = Ndis802_11Infrastructure; ++ INIT_WORK(&wnd->ndis_work, wrapndis_worker); ++ wnd->iw_stats_enabled = TRUE; ++ ++ TRACE1("nmb: %p, pdo: %p, fdo: %p, attached: %p, next: %p", ++ nmb, pdo, fdo, fdo->attached, nmb->next_device); ++ ++ /* dispatch routines are called as Windows functions */ ++ for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) ++ drv_obj->major_func[i] = WIN_FUNC_PTR(IoPassIrpDown,2); ++ ++ drv_obj->major_func[IRP_MJ_PNP] = WIN_FUNC_PTR(NdisDispatchPnp,2); ++ drv_obj->major_func[IRP_MJ_POWER] = WIN_FUNC_PTR(NdisDispatchPower,2); ++ drv_obj->major_func[IRP_MJ_INTERNAL_DEVICE_CONTROL] = ++ WIN_FUNC_PTR(NdisDispatchDeviceControl,2); ++// drv_obj->major_func[IRP_MJ_DEVICE_CONTROL] = ++// WIN_FUNC_PTR(NdisDispatchDeviceControl,2); ++ EXIT2(return STATUS_SUCCESS); ++} ++ ++int init_ndis_driver(struct driver_object *drv_obj) ++{ ++ ENTER1("%p", drv_obj); ++ drv_obj->drv_ext->add_device = ndis_add_device; ++ return 0; ++} ++ ++int wrapndis_init(void) ++{ ++ wrapndis_wq = create_singlethread_workqueue("wrapndis_wq"); ++ if (!wrapndis_wq) ++ EXIT1(return -ENOMEM); ++ TRACE1("wrapndis_wq: %p", wrapndis_wq); ++ register_netdevice_notifier(&netdev_notifier); ++ return 0; ++} ++ ++void wrapndis_exit(void) ++{ ++ unregister_netdevice_notifier(&netdev_notifier); ++ if (wrapndis_wq) ++ destroy_workqueue(wrapndis_wq); ++} +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/wrapndis.h linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/wrapndis.h +--- linux-3.12.2/3rdparty/ndiswrapper/wrapndis.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/wrapndis.h 2013-11-28 21:42:11.000000000 +0200 +@@ -0,0 +1,86 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * 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 _WRAPNDIS_H_ ++#define _WRAPNDIS_H_ ++ ++#include "ndis.h" ++#include "pnp.h" ++ ++int wrapndis_init(void); ++void wrapndis_exit(void); ++ ++NDIS_STATUS mp_reset(struct ndis_device *wnd); ++ ++NDIS_STATUS mp_request(enum ndis_request_type request, ++ struct ndis_device *wnd, ndis_oid oid, ++ void *buf, ULONG buflen, ULONG *written, ULONG *needed); ++ ++static inline NDIS_STATUS mp_query_info(struct ndis_device *wnd, ++ ndis_oid oid, void *buf, ULONG buflen, ++ ULONG *written, ULONG *needed) ++{ ++ return mp_request(NdisRequestQueryInformation, wnd, oid, ++ buf, buflen, written, needed); ++} ++ ++static inline NDIS_STATUS mp_set_info(struct ndis_device *wnd, ++ ndis_oid oid, void *buf, ULONG buflen, ++ ULONG *written, ULONG *needed) ++{ ++ return mp_request(NdisRequestSetInformation, wnd, oid, ++ buf, buflen, written, needed); ++} ++ ++static inline NDIS_STATUS mp_query(struct ndis_device *wnd, ndis_oid oid, ++ void *buf, ULONG buflen) ++{ ++ return mp_request(NdisRequestQueryInformation, wnd, oid, ++ buf, buflen, NULL, NULL); ++} ++ ++static inline NDIS_STATUS mp_query_int(struct ndis_device *wnd, ++ ndis_oid oid, ULONG *data) ++{ ++ return mp_request(NdisRequestQueryInformation, wnd, oid, ++ data, sizeof(ULONG), NULL, NULL); ++} ++ ++static inline NDIS_STATUS mp_set(struct ndis_device *wnd, ndis_oid oid, ++ void *buf, ULONG buflen) ++{ ++ return mp_request(NdisRequestSetInformation, wnd, oid, ++ buf, buflen, NULL, NULL); ++} ++ ++static inline NDIS_STATUS mp_set_int(struct ndis_device *wnd, ++ ndis_oid oid, ULONG data) ++{ ++ return mp_request(NdisRequestSetInformation, wnd, oid, ++ &data, sizeof(ULONG), NULL, NULL); ++} ++ ++void free_tx_packet(struct ndis_device *wnd, struct ndis_packet *packet, ++ NDIS_STATUS status); ++int init_ndis_driver(struct driver_object *drv_obj); ++NDIS_STATUS ndis_reinit(struct ndis_device *wnd); ++void set_media_state(struct ndis_device *wnd, enum ndis_media_state state); ++ ++void hangcheck_add(struct ndis_device *wnd); ++void hangcheck_del(struct ndis_device *wnd); ++ ++struct iw_statistics *get_iw_stats(struct net_device *dev); ++ ++#endif +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/wrapper.c linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/wrapper.c +--- linux-3.12.2/3rdparty/ndiswrapper/wrapper.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/wrapper.c 2013-11-28 21:42:11.000000000 +0200 +@@ -0,0 +1,111 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * 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 "ndis.h" ++#include "iw_ndis.h" ++#include "loader.h" ++#include "pnp.h" ++#include "wrapper.h" ++ ++char *if_name = "wlan%d"; ++int proc_uid, proc_gid; ++int hangcheck_interval; ++static char *utils_version = UTILS_VERSION; ++int debug = DEBUG; ++ ++module_param(if_name, charp, 0400); ++MODULE_PARM_DESC(if_name, "Network interface name or template " ++ "(default: wlan%d)"); ++module_param(proc_uid, int, 0600); ++MODULE_PARM_DESC(proc_uid, "The uid of the files created in /proc " ++ "(default: 0)."); ++module_param(proc_gid, int, 0600); ++MODULE_PARM_DESC(proc_gid, "The gid of the files created in /proc " ++ "(default: 0)."); ++module_param(debug, int, 0600); ++MODULE_PARM_DESC(debug, "debug level"); ++ ++/* 0 - default value provided by NDIS driver, ++ * positive value - force hangcheck interval to that many seconds ++ * negative value - disable hangcheck ++ */ ++module_param(hangcheck_interval, int, 0600); ++MODULE_PARM_DESC(hangcheck_interval, "The interval, in seconds, for checking" ++ " if driver is hung. (default: 0)"); ++ ++module_param(utils_version, charp, 0400); ++MODULE_PARM_DESC(utils_version, "Compatible version of utils " ++ "(read only: " UTILS_VERSION ")"); ++ ++MODULE_AUTHOR("ndiswrapper team "); ++#ifdef MODULE_DESCRIPTION ++MODULE_DESCRIPTION("NDIS wrapper driver"); ++#endif ++#ifdef MODULE_VERSION ++MODULE_VERSION(DRIVER_VERSION); ++#endif ++MODULE_LICENSE("GPL"); ++ ++static void module_cleanup(void) ++{ ++ loader_exit(); ++ usb_exit(); ++ wrap_procfs_remove(); ++ wrapndis_exit(); ++ ndis_exit(); ++ ntoskernel_exit(); ++ wrapmem_exit(); ++} ++ ++static int __init wrapper_init(void) ++{ ++#ifdef TAINT_OOT_MODULE ++ add_taint(TAINT_OOT_MODULE, LOCKDEP_NOW_UNRELIABLE); ++#endif ++ printk(KERN_INFO "%s version %s loaded (smp=%s, preempt=%s)\n", ++ DRIVER_NAME, DRIVER_VERSION, ++#ifdef CONFIG_SMP ++ "yes" ++#else ++ "no" ++#endif ++ , ++#ifdef CONFIG_PREEMPT_RT ++ "rt" ++#elif defined(CONFIG_PREEMPT) ++ "yes" ++#else ++ "no" ++#endif ++ ); ++ ++ if (wrapmem_init() || ntoskernel_init() || ndis_init() || ++ wrapndis_init() || usb_init() || wrap_procfs_init() || ++ loader_init()) { ++ module_cleanup(); ++ ERROR("%s: initialization failed", DRIVER_NAME); ++ return -EINVAL; ++ } ++ EXIT1(return 0); ++} ++ ++static void __exit wrapper_exit(void) ++{ ++ ENTER1(""); ++ module_cleanup(); ++} ++ ++module_init(wrapper_init); ++module_exit(wrapper_exit); +diff -Nurp linux-3.12.2/3rdparty/ndiswrapper/wrapper.h linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/wrapper.h +--- linux-3.12.2/3rdparty/ndiswrapper/wrapper.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/wrapper.h 2013-11-28 21:42:11.000000000 +0200 +@@ -0,0 +1,24 @@ ++/* ++ * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani ++ * ++ * 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 WRAPPER_H ++#define WRAPPER_H ++ ++extern char *if_name; ++extern int proc_uid; ++extern int proc_gid; ++extern int hangcheck_interval; ++ ++#endif /* WRAPPER_H */ diff --git a/kernel/kernel/files/patches/mageia.old/3rd-ndiswrapper-4.0-buildfix.patch b/kernel/kernel/files/patches/mageia.old/3rd-ndiswrapper-4.0-buildfix.patch new file mode 100644 index 00000000..52f39680 --- /dev/null +++ b/kernel/kernel/files/patches/mageia.old/3rd-ndiswrapper-4.0-buildfix.patch @@ -0,0 +1,32 @@ + +Adapt for strnicmp has been replaced by strncasecmp, +and removed upstream in v4.0-rc1~98: + +From af3cd13501eb04ca61d017ff4406f1cbffafdc04 Mon Sep 17 00:00:00 2001 +From: Rasmus Villemoes +Date: Thu, 12 Feb 2015 15:02:15 -0800 +Subject: lib/string.c: remove strnicmp() + + +Signed-off-by: Thomas Backlund + +--- linux/3rdparty/ndiswrapper/ndis.c.orig ++++ linux/3rdparty/ndiswrapper/ndis.c +@@ -438,7 +438,7 @@ static int read_setting(struct nt_list * + struct wrap_device_setting *setting; + mutex_lock(&loader_mutex); + nt_list_for_each_entry(setting, setting_list, list) { +- if (strnicmp(keyname, setting->name, length) == 0) { ++ if (strncasecmp(keyname, setting->name, length) == 0) { + TRACE2("setting %s='%s'", keyname, setting->value); + mutex_unlock(&loader_mutex); + *param = ndis_encode_setting(setting, type); +@@ -502,7 +502,7 @@ wstdcall void WIN_FUNC(NdisWriteConfigur + + mutex_lock(&loader_mutex); + nt_list_for_each_entry(setting, &nmb->wnd->wd->settings, list) { +- if (strnicmp(keyname, setting->name, ansi.length) == 0) { ++ if (strncasecmp(keyname, setting->name, ansi.length) == 0) { + mutex_unlock(&loader_mutex); + if (ndis_decode_setting(setting, param)) + *status = NDIS_STATUS_FAILURE; diff --git a/kernel/kernel/files/patches/mageia.old/3rd-ndiswrapper-Kconfig.patch b/kernel/kernel/files/patches/mageia.old/3rd-ndiswrapper-Kconfig.patch new file mode 100644 index 00000000..f7d26e62 --- /dev/null +++ b/kernel/kernel/files/patches/mageia.old/3rd-ndiswrapper-Kconfig.patch @@ -0,0 +1,7 @@ +--- linux-2.6.24.orig/3rdparty/ndiswrapper/Kconfig 1969-12-31 21:00:00.000000000 -0300 ++++ linux-2.6.24/3rdparty/ndiswrapper/Kconfig 2007-11-26 15:11:31.000000000 -0200 +@@ -0,0 +1,4 @@ ++ ++config NDISWRAPPER ++ tristate "NDIS driver wrapper support" ++ depends on PCI && USB && !X86_64_XEN diff --git a/kernel/kernel/files/patches/mageia.old/3rd-ndiswrapper-Makefile-build-fix.patch b/kernel/kernel/files/patches/mageia.old/3rd-ndiswrapper-Makefile-build-fix.patch new file mode 100644 index 00000000..b44f4b29 --- /dev/null +++ b/kernel/kernel/files/patches/mageia.old/3rd-ndiswrapper-Makefile-build-fix.patch @@ -0,0 +1,45 @@ +--- linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/Makefile.orig 2013-11-28 21:42:10.000000000 +0200 ++++ linux-3.12.2-ndiswrapper-1.59/3rdparty/ndiswrapper/Makefile 2013-11-30 21:41:19.550504380 +0200 +@@ -9,24 +9,10 @@ DISTFILES = \ + winnt_types.h workqueue.c wrapmem.c wrapmem.h wrapndis.c wrapndis.h \ + wrapper.c wrapper.h + +-# By default, we try to compile the modules for the currently running +-# kernel. But it's the first approximation, as we will re-read the +-# version from the kernel sources. +-KVERS_UNAME ?= $(shell uname -r) +- + # KBUILD is the path to the Linux kernel build tree. It is usually the + # same as the kernel source tree, except when the kernel was compiled in + # a separate directory. +-KBUILD ?= $(shell readlink -f /lib/modules/$(KVERS_UNAME)/build) +- +-ifeq (,$(KBUILD)) +-$(error Kernel build tree not found - please set KBUILD to configured kernel) +-endif +- +-KCONFIG := $(KBUILD)/.config +-ifeq (,$(wildcard $(KCONFIG))) +-$(error No .config found in $(KBUILD), please set KBUILD to configured kernel) +-endif ++KBUILD ?= $(srctree) + + ifneq (,$(wildcard $(KBUILD)/include/linux/version.h)) + ifneq (,$(wildcard $(KBUILD)/include/generated/uapi/linux/version.h)) +@@ -43,16 +29,9 @@ endif + ifeq (,$(wildcard $(VERSION_H))) + VERSION_H := $(KBUILD)/include/linux/version.h + endif +-ifeq (,$(wildcard $(VERSION_H))) +-$(error Please run 'make modules_prepare' in $(KBUILD)) +-endif + + KVERS := $(shell sed -ne 's/"//g;s/^\#define UTS_RELEASE //p' $(VERSION_H)) + +-ifeq (,$(KVERS)) +-$(error Cannot find UTS_RELEASE in $(VERSION_H), please report) +-endif +- + INST_DIR = /lib/modules/$(KVERS)/misc + + SRC_DIR=$(shell pwd) diff --git a/kernel/kernel/files/patches/mageia.old/3rd-ndiswrapper-linux-3.14-buildfix.patch b/kernel/kernel/files/patches/mageia.old/3rd-ndiswrapper-linux-3.14-buildfix.patch new file mode 100644 index 00000000..6550b9f2 --- /dev/null +++ b/kernel/kernel/files/patches/mageia.old/3rd-ndiswrapper-linux-3.14-buildfix.patch @@ -0,0 +1,33 @@ + +Fix build with kernel-3.14 + +Signed-off-by: Thomas Backlund + + 3rdparty/ndiswrapper/crt.c | 2 +- + 3rdparty/ndiswrapper/ntoskernel.h | 3 +-- + 2 files changed, 2 insertions(+), 3 deletions(-) + +--- linux/3rdparty/ndiswrapper/crt.c.orig 2014-04-26 19:10:55.000000000 +0300 ++++ linux/3rdparty/ndiswrapper/crt.c 2014-04-26 19:25:27.766116082 +0300 +@@ -467,7 +467,7 @@ noregparm int WIN_FUNC(_win_memcmp,3) + noregparm void WIN_FUNC(_win_srand,1) + (UINT seed) + { +- net_srandom(seed); ++ prandom_seed((__force u32) seed); + } + + noregparm int WIN_FUNC(rand,0) +--- linux/3rdparty/ndiswrapper/ntoskernel.h.orig 2014-04-26 19:42:32.000000000 +0300 ++++ linux/3rdparty/ndiswrapper/ntoskernel.h 2014-04-26 19:59:13.662522942 +0300 +@@ -798,9 +798,8 @@ do { \ + #define nt_spin_unlock_irqrestore(lock, flags) \ + do { \ + nt_spin_unlock(lock); \ +- preempt_enable_no_resched(); \ ++ preempt_enable(); \ + local_irq_restore(flags); \ +- preempt_check_resched(); \ + } while (0) + + static inline ULONG SPAN_PAGES(void *ptr, SIZE_T length) diff --git a/kernel/kernel/files/patches/mageia.old/3rd-rfswitch-1.3.patch b/kernel/kernel/files/patches/mageia.old/3rd-rfswitch-1.3.patch new file mode 100644 index 00000000..e87bf7e0 --- /dev/null +++ b/kernel/kernel/files/patches/mageia.old/3rd-rfswitch-1.3.patch @@ -0,0 +1,978 @@ + 3rdparty/rfswitch/FILES | 6 + 3rdparty/rfswitch/ISSUES | 28 +++ + 3rdparty/rfswitch/Kconfig | 22 ++ + 3rdparty/rfswitch/LICENSE | 339 +++++++++++++++++++++++++++++++++++++++++++++ + 3rdparty/rfswitch/Makefile | 119 +++++++++++++++ + 3rdparty/rfswitch/README | 44 +++++ + 3rdparty/rfswitch/av5100.c | 174 +++++++++++++++++++++++ + 3rdparty/rfswitch/pbe5.c | 205 +++++++++++++++++++++++++++ + 8 files changed, 937 insertions(+) +diff -Nurp linux-2.6.37/3rdparty/rfswitch/av5100.c linux-2.6.37.3rdparty/3rdparty/rfswitch/av5100.c +--- linux-2.6.37/3rdparty/rfswitch/av5100.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/rfswitch/av5100.c 2008-03-28 05:25:28.000000000 +0200 +@@ -0,0 +1,174 @@ ++/******************************************************************************* ++ ++ Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved. ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms of version 2 of the GNU General Public License as ++ published by the Free Software Foundation. ++ ++ 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. ++ ++ The full GNU General Public License is included in this distribution in the ++ file called LICENSE. ++ ++ Contact Information: ++ James P. Ketrenos ++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 ++ ++*******************************************************************************/ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define DRV_NAME "av5100" ++#define DRV_VERSION "1.3" ++#define DRV_DESCRIPTION "SW RF kill switch for Averatec 5100P" ++#define DRV_COPYRIGHT "Copyright(c) 2003-2004 Intel Corporation" ++ ++static int radio = 1; ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++ ++MODULE_PARM(radio, "i"); ++ ++#else /* LINUX_VERSION_CODE < 2.6.0 */ ++ ++#include ++module_param(radio, int, 1); ++ ++#endif /* LINUX_VERSION_CODE < 2.6.0 */ ++ ++MODULE_PARM_DESC(radio, "controls state of radio (1=on, 0=off)"); ++ ++MODULE_DESCRIPTION(DRV_DESCRIPTION); ++MODULE_AUTHOR(DRV_COPYRIGHT); ++MODULE_LICENSE("GPL"); ++ ++#define AV5100_RADIO_ON (0xe0) ++#define AV5100_RADIO_OFF (0xe1) ++ ++static int av5100_radio = AV5100_RADIO_OFF; ++ ++static void av5100_set_radio(int state) ++{ ++ printk(KERN_INFO DRV_NAME ": Radio being turned %s\n", ++ (state == AV5100_RADIO_ON) ? "ON" : "OFF"); ++ outl(0x80020800, 0xcf8); ++ outb(0x6f, 0x0072); ++ outl(0x1800ffff, 0x1184); ++ outb(state, 0x00b2); ++ av5100_radio = state; ++} ++ ++ ++/* ++ * proc stuff ++ */ ++static struct proc_dir_entry *dir_base = NULL; ++ ++static int proc_set_radio(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ av5100_set_radio(buffer[0] == '0' ? AV5100_RADIO_OFF : AV5100_RADIO_ON); ++ ++ return count; ++} ++ ++static int proc_get_radio(char *page, char **start, off_t offset, ++ int count, int *eof, void *data) ++{ ++ int len = 0; ++ ++ len += snprintf(page, count, DRV_NAME ": %d\n", ++ av5100_radio == AV5100_RADIO_OFF ? 0 : 1); ++ ++ *eof = 1; ++ return len; ++} ++ ++ ++static void av5100_proc_cleanup(void) ++{ ++ if (dir_base) { ++ remove_proc_entry("radio", dir_base); ++ remove_proc_entry(DRV_NAME, &proc_root); ++ dir_base = NULL; ++ } ++} ++ ++ ++static int av5100_proc_init(void) ++{ ++ struct proc_dir_entry *ent; ++ int err = 0; ++ ++ dir_base = create_proc_entry(DRV_NAME, S_IFDIR, &proc_root); ++ if (dir_base == NULL) { ++ printk(KERN_ERR DRV_NAME ": Unable to initialise /proc/" ++ DRV_NAME "\n"); ++ err = -ENOMEM; ++ goto fail; ++ } ++ ++ ++ ent = create_proc_entry("radio", S_IFREG | S_IRUGO | S_IWUSR, ++ dir_base); ++ if (ent) { ++ ent->read_proc = proc_get_radio; ++ ent->write_proc = proc_set_radio; ++ } else { ++ printk(KERN_ERR ++ "Unable to initialize /proc/" DRV_NAME "/radio\n"); ++ err = -ENOMEM; ++ goto fail; ++ } ++ ++ return 0; ++ ++ fail: ++ av5100_proc_cleanup(); ++ return err; ++} ++ ++/* ++ * module stuff ++ */ ++static int __init av5100_init(void) ++{ ++ av5100_proc_init(); ++ ++ av5100_set_radio((radio == 1) ? AV5100_RADIO_ON : AV5100_RADIO_OFF); ++ ++ return 0; ++} ++ ++static void __exit av5100_exit(void) ++{ ++ av5100_set_radio(AV5100_RADIO_OFF); ++ ++ av5100_proc_cleanup(); ++} ++ ++module_init(av5100_init); ++module_exit(av5100_exit); ++ ++/* ++ 1 2 3 4 5 6 7 ++12345678901234567890123456789012345678901234567890123456789012345678901234567890 ++*/ +diff -Nurp linux-2.6.37/3rdparty/rfswitch/FILES linux-2.6.37.3rdparty/3rdparty/rfswitch/FILES +--- linux-2.6.37/3rdparty/rfswitch/FILES 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/rfswitch/FILES 2004-07-09 07:44:19.000000000 +0300 +@@ -0,0 +1,6 @@ ++Makefile Used for building on 2.4, 2.6, internally and exteranlly ++ ++FILES This file ++ ++av5100.c Averatec 5100P SW Switch Module ++pbe5.c Packard Bell Easynote SW Switch Module +diff -Nurp linux-2.6.37/3rdparty/rfswitch/ISSUES linux-2.6.37.3rdparty/3rdparty/rfswitch/ISSUES +--- linux-2.6.37/3rdparty/rfswitch/ISSUES 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/rfswitch/ISSUES 2004-07-09 07:43:22.000000000 +0300 +@@ -0,0 +1,28 @@ ++ ++ISSUES ++------------ ----- ----- ---- --- -- - ++ ++No packets! - RF kill switch ++ ++If the module loads, but no packets are transferred you may have a SW based ++radio kill switch. All laptops have some capability to disable the radio ++via a button or switch. On some laptops that switch is physically tied to the ++IPW2100; simply toggling the switch should enable the radio. ++ ++On other laptops, the switch is a button that when pressed requires some ++software driver to send some hardware command to some other piece of hardware ++on the laptop, that then controls the radio. The driver currently has support ++for the Averatec 5100P laptop's SW switch. Support will be added for other ++laptop vendors as we become aware of them and figure out how to enable the ++radio. ++ ++To know if the radio is being disabled via the RF switch, perform the following: ++ ++% cat /proc/net/ipw2100/eth1/state ++Radio is disabled by RF switch ++ ++If it says that, then your RF switch is currently disabling the radio. The ++driver doesn't currently support switching back to the on state if you have a ++physical RF switch (the radio may turn on and packets will work, but the proc ++entry won't be updated) ++ +diff -Nurp linux-2.6.37/3rdparty/rfswitch/Kconfig linux-2.6.37.3rdparty/3rdparty/rfswitch/Kconfig +--- linux-2.6.37/3rdparty/rfswitch/Kconfig 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/rfswitch/Kconfig 2008-05-27 23:39:10.000000000 +0300 +@@ -0,0 +1,22 @@ ++menu "RF Switch" ++ depends on EXPERIMENTAL ++ ++config RFSWITCH ++ tristate "RF Switch" ++ depends on EXPERIMENTAL ++ ++config AVERATEC_5100P ++ tristate "averatec 5100P driver" ++ depends on RFSWITCH ++ ---help--- ++ This is an experimental driver for the wireless switch ++ of some laptops (usefull with some ipw2x00 cards) ++ ++config PACKARDBELL_E5 ++ tristate "pbe5 driver" ++ depends on RFSWITCH ++ ---help--- ++ This is an experimental driver for the wireless switch ++ of some laptops (usefull with some ipw2x00 cards) ++ ++endmenu +diff -Nurp linux-2.6.37/3rdparty/rfswitch/LICENSE linux-2.6.37.3rdparty/3rdparty/rfswitch/LICENSE +--- linux-2.6.37/3rdparty/rfswitch/LICENSE 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/rfswitch/LICENSE 2004-07-09 07:43:22.000000000 +0300 +@@ -0,0 +1,339 @@ ++ ++"This software program is licensed subject to the GNU General Public License ++(GPL). Version 2, June 1991, available at ++" ++ ++GNU General Public License ++ ++Version 2, June 1991 ++ ++Copyright (C) 1989, 1991 Free Software Foundation, Inc. ++59 Temple Place - Suite 330, Boston, MA 02111-1307, USA ++ ++Everyone is permitted to copy and distribute verbatim copies of this license ++document, but changing it is not allowed. ++ ++Preamble ++ ++The licenses for most software are designed to take away your freedom to ++share and change it. By contrast, the GNU General Public License is intended ++to guarantee your freedom to share and change free software--to make sure ++the software is free for all its users. This General Public License applies ++to most of the Free Software Foundation's software and to any other program ++whose authors commit to using it. (Some other Free Software Foundation ++software is covered by the GNU Library General Public License instead.) You ++can apply it to your programs, too. ++ ++When we speak of free software, we are referring to freedom, not price. Our ++General Public Licenses are designed to make sure that you have the freedom ++to distribute copies of free software (and charge for this service if you ++wish), that you receive source code or can get it if you want it, that you ++can change the software or use pieces of it in new free programs; and that ++you know you can do these things. ++ ++To protect your rights, we need to make restrictions that forbid anyone to ++deny you these rights or to ask you to surrender the rights. These ++restrictions translate to certain responsibilities for you if you distribute ++copies of the software, or if you modify it. ++ ++For example, if you distribute copies of such a program, whether gratis or ++for a fee, you must give the recipients all the rights that you have. You ++must make sure that they, too, receive or can get the source code. And you ++must show them these terms so they know their rights. ++ ++We protect your rights with two steps: (1) copyright the software, and (2) ++offer you this license which gives you legal permission to copy, distribute ++and/or modify the software. ++ ++Also, for each author's protection and ours, we want to make certain that ++everyone understands that there is no warranty for this free software. If ++the software is modified by someone else and passed on, we want its ++recipients to know that what they have is not the original, so that any ++problems introduced by others will not reflect on the original authors' ++reputations. ++ ++Finally, any free program is threatened constantly by software patents. We ++wish to avoid the danger that redistributors of a free program will ++individually obtain patent licenses, in effect making the program ++proprietary. To prevent this, we have made it clear that any patent must be ++licensed for everyone's free use or not licensed at all. ++ ++The precise terms and conditions for copying, distribution and modification ++follow. ++ ++TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION ++ ++0. This License applies to any program or other work which contains a notice ++ placed by the copyright holder saying it may be distributed under the ++ terms of this General Public License. The "Program", below, refers to any ++ such program or work, and a "work based on the Program" means either the ++ Program or any derivative work under copyright law: that is to say, a ++ work containing the Program or a portion of it, either verbatim or with ++ modifications and/or translated into another language. (Hereinafter, ++ translation is included without limitation in the term "modification".) ++ Each licensee is addressed as "you". ++ ++ Activities other than copying, distribution and modification are not ++ covered by this License; they are outside its scope. The act of running ++ the Program is not restricted, and the output from the Program is covered ++ only if its contents constitute a work based on the Program (independent ++ of having been made by running the Program). Whether that is true depends ++ on what the Program does. ++ ++1. You may copy and distribute verbatim copies of the Program's source code ++ as you receive it, in any medium, provided that you conspicuously and ++ appropriately publish on each copy an appropriate copyright notice and ++ disclaimer of warranty; keep intact all the notices that refer to this ++ License and to the absence of any warranty; and give any other recipients ++ of the Program a copy of this License along with the Program. ++ ++ You may charge a fee for the physical act of transferring a copy, and you ++ may at your option offer warranty protection in exchange for a fee. ++ ++2. You may modify your copy or copies of the Program or any portion of it, ++ thus forming a work based on the Program, and copy and distribute such ++ modifications or work under the terms of Section 1 above, provided that ++ you also meet all of these conditions: ++ ++ * a) You must cause the modified files to carry prominent notices stating ++ that you changed the files and the date of any change. ++ ++ * b) You must cause any work that you distribute or publish, that in ++ whole or in part contains or is derived from the Program or any part ++ thereof, to be licensed as a whole at no charge to all third parties ++ under the terms of this License. ++ ++ * c) If the modified program normally reads commands interactively when ++ run, you must cause it, when started running for such interactive ++ use in the most ordinary way, to print or display an announcement ++ including an appropriate copyright notice and a notice that there is ++ no warranty (or else, saying that you provide a warranty) and that ++ users may redistribute the program under these conditions, and ++ telling the user how to view a copy of this License. (Exception: if ++ the Program itself is interactive but does not normally print such ++ an announcement, your work based on the Program is not required to ++ print an announcement.) ++ ++ These requirements apply to the modified work as a whole. If identifiable ++ sections of that work are not derived from the Program, and can be ++ reasonably considered independent and separate works in themselves, then ++ this License, and its terms, do not apply to those sections when you ++ distribute them as separate works. But when you distribute the same ++ sections as part of a whole which is a work based on the Program, the ++ distribution of the whole must be on the terms of this License, whose ++ permissions for other licensees extend to the entire whole, and thus to ++ each and every part regardless of who wrote it. ++ ++ Thus, it is not the intent of this section to claim rights or contest ++ your rights to work written entirely by you; rather, the intent is to ++ exercise the right to control the distribution of derivative or ++ collective works based on the Program. ++ ++ In addition, mere aggregation of another work not based on the Program ++ with the Program (or with a work based on the Program) on a volume of a ++ storage or distribution medium does not bring the other work under the ++ scope of this License. ++ ++3. You may copy and distribute the Program (or a work based on it, under ++ Section 2) in object code or executable form under the terms of Sections ++ 1 and 2 above provided that you also do one of the following: ++ ++ * a) Accompany it with the complete corresponding machine-readable source ++ code, which must be distributed under the terms of Sections 1 and 2 ++ above on a medium customarily used for software interchange; or, ++ ++ * b) Accompany it with a written offer, valid for at least three years, ++ to give any third party, for a charge no more than your cost of ++ physically performing source distribution, a complete machine- ++ readable copy of the corresponding source code, to be distributed ++ under the terms of Sections 1 and 2 above on a medium customarily ++ used for software interchange; or, ++ ++ * c) Accompany it with the information you received as to the offer to ++ distribute corresponding source code. (This alternative is allowed ++ only for noncommercial distribution and only if you received the ++ program in object code or executable form with such an offer, in ++ accord with Subsection b above.) ++ ++ The source code for a work means the preferred form of the work for ++ making modifications to it. For an executable work, complete source code ++ means all the source code for all modules it contains, plus any ++ associated interface definition files, plus the scripts used to control ++ compilation and installation of the executable. However, as a special ++ exception, the source code distributed need not include anything that is ++ normally distributed (in either source or binary form) with the major ++ components (compiler, kernel, and so on) of the operating system on which ++ the executable runs, unless that component itself accompanies the ++ executable. ++ ++ If distribution of executable or object code is made by offering access ++ to copy from a designated place, then offering equivalent access to copy ++ the source code from the same place counts as distribution of the source ++ code, even though third parties are not compelled to copy the source ++ along with the object code. ++ ++4. You may not copy, modify, sublicense, or distribute the Program except as ++ expressly provided under this License. Any attempt otherwise to copy, ++ modify, sublicense or distribute the Program is void, and will ++ automatically terminate your rights under this License. However, parties ++ who have received copies, or rights, from you under this License will not ++ have their licenses terminated so long as such parties remain in full ++ compliance. ++ ++5. You are not required to accept this License, since you have not signed ++ it. However, nothing else grants you permission to modify or distribute ++ the Program or its derivative works. These actions are prohibited by law ++ if you do not accept this License. Therefore, by modifying or ++ distributing the Program (or any work based on the Program), you ++ indicate your acceptance of this License to do so, and all its terms and ++ conditions for copying, distributing or modifying the Program or works ++ based on it. ++ ++6. Each time you redistribute the Program (or any work based on the ++ Program), the recipient automatically receives a license from the ++ original licensor to copy, distribute or modify the Program subject to ++ these terms and conditions. You may not impose any further restrictions ++ on the recipients' exercise of the rights granted herein. You are not ++ responsible for enforcing compliance by third parties to this License. ++ ++7. If, as a consequence of a court judgment or allegation of patent ++ infringement or for any other reason (not limited to patent issues), ++ conditions are imposed on you (whether by court order, agreement or ++ otherwise) that contradict the conditions of this License, they do not ++ excuse you from the conditions of this License. If you cannot distribute ++ so as to satisfy simultaneously your obligations under this License and ++ any other pertinent obligations, then as a consequence you may not ++ distribute the Program at all. For example, if a patent license would ++ not permit royalty-free redistribution of the Program by all those who ++ receive copies directly or indirectly through you, then the only way you ++ could satisfy both it and this License would be to refrain entirely from ++ distribution of the Program. ++ ++ If any portion of this section is held invalid or unenforceable under any ++ particular circumstance, the balance of the section is intended to apply ++ and the section as a whole is intended to apply in other circumstances. ++ ++ It is not the purpose of this section to induce you to infringe any ++ patents or other property right claims or to contest validity of any ++ such claims; this section has the sole purpose of protecting the ++ integrity of the free software distribution system, which is implemented ++ by public license practices. Many people have made generous contributions ++ to the wide range of software distributed through that system in ++ reliance on consistent application of that system; it is up to the ++ author/donor to decide if he or she is willing to distribute software ++ through any other system and a licensee cannot impose that choice. ++ ++ This section is intended to make thoroughly clear what is believed to be ++ a consequence of the rest of this License. ++ ++8. If the distribution and/or use of the Program is restricted in certain ++ countries either by patents or by copyrighted interfaces, the original ++ copyright holder who places the Program under this License may add an ++ explicit geographical distribution limitation excluding those countries, ++ so that distribution is permitted only in or among countries not thus ++ excluded. In such case, this License incorporates the limitation as if ++ written in the body of this License. ++ ++9. The Free Software Foundation may publish revised and/or new versions of ++ the General Public License from time to time. Such new versions will be ++ similar in spirit to the present version, but may differ in detail to ++ address new problems or concerns. ++ ++ Each version is given a distinguishing version number. If the Program ++ specifies a version number of this License which applies to it and "any ++ later version", you have the option of following the terms and ++ conditions either of that version or of any later version published by ++ the Free Software Foundation. If the Program does not specify a version ++ number of this License, you may choose any version ever published by the ++ Free Software Foundation. ++ ++10. If you wish to incorporate parts of the Program into other free programs ++ whose distribution conditions are different, write to the author to ask ++ for permission. For software which is copyrighted by the Free Software ++ Foundation, write to the Free Software Foundation; we sometimes make ++ exceptions for this. Our decision will be guided by the two goals of ++ preserving the free status of all derivatives of our free software and ++ of promoting the sharing and reuse of software generally. ++ ++ NO WARRANTY ++ ++11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY ++ FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN ++ OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES ++ PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER ++ EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ++ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ++ ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH ++ YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL ++ NECESSARY SERVICING, REPAIR OR CORRECTION. ++ ++12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING ++ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR ++ REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR ++ DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL ++ DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM ++ (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED ++ INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF ++ THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR ++ OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. ++ ++END OF TERMS AND CONDITIONS ++ ++How to Apply These Terms to Your New Programs ++ ++If you develop a new program, and you want it to be of the greatest ++possible use to the public, the best way to achieve this is to make it free ++software which everyone can redistribute and change under these terms. ++ ++To do so, attach the following notices to the program. It is safest to ++attach them to the start of each source file to most effectively convey the ++exclusion of warranty; and each file should have at least the "copyright" ++line and a pointer to where the full notice is found. ++ ++one line to give the program's name and an idea of what it does. ++Copyright (C) yyyy name of author ++ ++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. ++ ++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. ++ ++Also add information on how to contact you by electronic and paper mail. ++ ++If the program is interactive, make it output a short notice like this when ++it starts in an interactive mode: ++ ++Gnomovision version 69, Copyright (C) year name of author Gnomovision comes ++with ABSOLUTELY NO WARRANTY; for details type 'show w'. This is free ++software, and you are welcome to redistribute it under certain conditions; ++type 'show c' for details. ++ ++The hypothetical commands 'show w' and 'show c' should show the appropriate ++parts of the General Public License. Of course, the commands you use may be ++called something other than 'show w' and 'show c'; they could even be ++mouse-clicks or menu items--whatever suits your program. ++ ++You should also get your employer (if you work as a programmer) or your ++school, if any, to sign a "copyright disclaimer" for the program, if ++necessary. Here is a sample; alter the names: ++ ++Yoyodyne, Inc., hereby disclaims all copyright interest in the program ++'Gnomovision' (which makes passes at compilers) written by James Hacker. ++ ++signature of Ty Coon, 1 April 1989 ++Ty Coon, President of Vice ++ ++This General Public License does not permit incorporating your program into ++proprietary programs. If your program is a subroutine library, you may ++consider it more useful to permit linking proprietary applications with the ++library. If this is what you want to do, use the GNU Library General Public ++License instead of this License. +diff -Nurp linux-2.6.37/3rdparty/rfswitch/Makefile linux-2.6.37.3rdparty/3rdparty/rfswitch/Makefile +--- linux-2.6.37/3rdparty/rfswitch/Makefile 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/rfswitch/Makefile 2008-03-28 05:17:16.000000000 +0200 +@@ -0,0 +1,119 @@ ++# ++# Makefile for the SW RF Switch kernel modules ++# ++# NOTE: This make file can serve as both an external Makefile (launched ++# directly by the user), or as the sub-dir Makefile used by the kernel ++# build system. ++ ++ ++CONFIG_AVERATEC_5100P=m ++CONFIG_PACKARDBELL_E5=m ++ ++ ++ ++list-m := ++list-$(CONFIG_AVERATEC_5100P) += av5100 ++list-$(CONFIG_PACKARDBELL_E5) += pbe5 ++ ++ ++obj-$(CONFIG_AVERATEC_5100P) += av5100.o ++obj-$(CONFIG_PACKARDBELL_E5) += pbe5.o ++ ++# ++# Begin dual Makefile mode here. First we provide support for when we ++# are being invoked by the kernel build system ++# ++ifneq ($(KERNELRELEASE),) ++ ++ifneq ($(PATCHLEVEL),6) # If we are not on a 2.6, then do 2.4 specific things ++ ++O_TARGET := rfswitch.o ++ ++include $(TOPDIR)/Rules.make ++ ++endif # End if 2.4 specific settings ++ ++else ++# Here we begin the portion that is executed if the user invoked this Makefile ++# directly. ++ ++# KSRC should be set to the path to your sources ++# modules are installed into KMISC ++KVER := $(shell uname -r) ++KSRC := /lib/modules/$(KVER)/build ++KMISC := /lib/modules/$(KVER)/kernel/drivers/net/wireless/ ++ ++# KSRC_OUTPUT should be overridden if you are using a 2.6 kernel that ++# has it's output sent elsewhere via KBUILD_OUTPUT= or O= ++KSRC_OUTPUT := $(KSRC) ++ ++# If we find Rules.make, we can assume we're using the old 2.4 style building ++OLDMAKE=$(wildcard $(KSRC)/Rules.make) ++PWD=$(shell pwd) ++ ++VERFILE := $(KSRC_OUTPUT)/include/linux/version.h ++KERNELRELEASE := $(shell \ ++ if [ -r $(VERFILE) ]; then \ ++ (cat $(VERFILE); echo UTS_RELEASE) | \ ++ $(CC) -I$(KSRC_OUTPUT) $(CFLAGS) -E - | \ ++ tail -n 1 | \ ++ xargs echo; \ ++ else \ ++ uname -r; \ ++ fi) ++ ++MODPATH := $(DESTDIR)/lib/modules/$(KERNELRELEASE) ++ ++all: modules ++ ++clean: ++ rm -f *.mod.c *.mod *.o *.ko .*.cmd .*.flags Modules.symvers ++ rm -rf $(PWD)/tmp ++ ++ ++ifeq ($(OLDMAKE),) ++ ++TMP=$(PWD)/tmp ++MODVERDIR=$(TMP)/.tmp_versions ++ ++modules: ++ifdef ($(KSRC_OUTPUT)/.tmp_versions) ++ mkdir -p $(MODVERDIR) ++ -cp $(KSRC_OUTPUT)/.tmp_versions/*.mod $(MODVERDIR) ++endif ++ifeq ($(KSRC),$(KSRC_OUTPUT)) # We're not outputting elsewhere ++ifdef ($(KSRC)/.tmp_versions) ++ -cp $(KSRC)/.tmp_versions/*.mod $(MODVERDIR) ++endif ++ $(MAKE) -C $(KSRC) SUBDIRS=$(PWD) MODVERDIR=$(MODVERDIR) modules ++else # We've got a kernel with seperate output, copy the config, and use O= ++ mkdir -p $(TMP) ++ cp $(KSRC_OUTPUT)/.config $(TMP) ++ $(MAKE) -C $(KSRC) SUBDIRS=$(PWD) MODVERDIR=$(MODVERDIR) O=$(PWD)/tmp modules ++endif ++ ++install: modules ++ install -d $(KMISC) ++ install -m 644 -c $(addsuffix .ko,$(list-m)) $(KMISC) ++ /sbin/depmod -a ++ ++ ++else # We're on 2.4, and things are slightly different ++ ++modules: ++ $(MAKE) -C $(KSRC) SUBDIRS=$(PWD) BUILD_DIR=$(PWD) modules ++ ++install: modules ++ install -d $(KMISC) ++ install -m 644 -c $(addsuffix .o,$(list-m)) $(KMISC) ++ /sbin/depmod -a ++ ++endif ++ ++uninstall: ++ cd $(KMISC) ++ rm -rf $(addsuffix .ko,$(list-m)) ++ cd - ++ /sbin/depmod -a ++ ++endif +diff -Nurp linux-2.6.37/3rdparty/rfswitch/pbe5.c linux-2.6.37.3rdparty/3rdparty/rfswitch/pbe5.c +--- linux-2.6.37/3rdparty/rfswitch/pbe5.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/rfswitch/pbe5.c 2008-03-28 05:25:16.000000000 +0200 +@@ -0,0 +1,205 @@ ++/******************************************************************************* ++ ++ This program is free software; you can redistribute it and/or modify it ++ under the terms of version 2 of the GNU General Public License as ++ published by the Free Software Foundation. ++ ++ 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. ++ ++ The full GNU General Public License is included in this distribution in the ++ file called LICENSE. ++ ++ Author: ++ Pedro Ramalhais ++ ++ Based on: ++ av5100.c from http://ipw2100.sourceforge.net/ ++ ++*******************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DRV_NAME "pbe5" ++#define DRV_VERSION "1.3" ++#define DRV_DESCRIPTION "SW RF kill switch for Packard Bell EasyNote E5" ++#define DRV_AUTHOR "Pedro Ramalhais" ++#define DRV_LICENSE "GPL" ++ ++static int radio = 1; ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) ++ ++MODULE_PARM(radio, "i"); ++ ++#else /* LINUX_VERSION_CODE < 2.6.0 */ ++ ++#include ++module_param(radio, int, 1); ++ ++#endif /* LINUX_VERSION_CODE < 2.6.0 */ ++ ++MODULE_PARM_DESC(radio, "controls state of radio (1=on, 0=off)"); ++ ++MODULE_DESCRIPTION(DRV_DESCRIPTION); ++MODULE_AUTHOR(DRV_AUTHOR); ++MODULE_LICENSE(DRV_LICENSE); ++ ++/* ++ * NOTE: These values were obtained from disassembling the Icon.exe program ++ * installed in the Packard Bell EasyNote E5 laptop. The names were guessed, ++ * so don't rely on them. ++ */ ++#define PBE5_PORT_TOGGLE 0x0b3 ++#define PBE5_VALUE_TOGGLE_ON 0x01 ++#define PBE5_VALUE_TOGGLE_OFF 0x00 ++#define PBE5_PORT_APPLY 0x0b2 ++#define PBE5_VALUE_APPLY 0xef ++ ++// Some "booleans" =;-) ++#define PBE5_RADIO_OFF 0 ++#define PBE5_RADIO_ON 1 ++ ++static int pbe5_radio_status = PBE5_RADIO_ON; ++ ++unsigned char pbe5_get_radio(void) ++{ ++ unsigned char val = 0x00; ++ ++ val = inb(PBE5_PORT_TOGGLE); ++ ++ return val; ++} ++ ++static void pbe5_set_radio(int state_set) ++{ ++ pbe5_radio_status = pbe5_get_radio(); ++ ++ if (pbe5_radio_status != state_set) { ++ // Set the radio toggle register ++ outb(PBE5_VALUE_TOGGLE_ON, PBE5_PORT_TOGGLE); ++ // Commit the radio toggle register value ++ outb(PBE5_VALUE_APPLY, PBE5_PORT_APPLY); ++ // Update the radio status ++ pbe5_radio_status = pbe5_get_radio(); ++ ++ printk(KERN_INFO DRV_NAME ": Radio turned %s\n", ++ (state_set == PBE5_RADIO_ON) ? "ON" : "OFF"); ++ } else { ++ printk(KERN_INFO DRV_NAME ": Radio already %s\n", ++ (state_set == PBE5_RADIO_ON) ? "ON" : "OFF"); ++ } ++} ++ ++ ++/* ++ * proc stuff ++ */ ++static struct proc_dir_entry *dir_base = NULL; ++ ++static int proc_set_radio(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ pbe5_set_radio(buffer[0] == '0' ? PBE5_RADIO_OFF : PBE5_RADIO_ON); ++ ++ return count; ++} ++ ++static int proc_get_radio(char *page, char **start, off_t offset, ++ int count, int *eof, void *data) ++{ ++ int len = 0; ++ ++ len += snprintf(page, count, DRV_NAME ": %d\n", ++ pbe5_radio_status == PBE5_RADIO_OFF ? 0 : 1); ++ ++ *eof = 1; ++ return len; ++} ++ ++ ++static void pbe5_proc_cleanup(void) ++{ ++ if (dir_base) { ++ remove_proc_entry("radio", dir_base); ++ remove_proc_entry(DRV_NAME, &proc_root); ++ dir_base = NULL; ++ } ++} ++ ++ ++static int pbe5_proc_init(void) ++{ ++ struct proc_dir_entry *ent; ++ int err = 0; ++ ++ dir_base = create_proc_entry(DRV_NAME, S_IFDIR, &proc_root); ++ if (dir_base == NULL) { ++ printk(KERN_ERR DRV_NAME ": Unable to initialise /proc/" ++ DRV_NAME "\n"); ++ err = -ENOMEM; ++ goto fail; ++ } ++ ++ ++ ent = create_proc_entry("radio", S_IFREG | S_IRUGO | S_IWUSR, ++ dir_base); ++ if (ent) { ++ ent->read_proc = proc_get_radio; ++ ent->write_proc = proc_set_radio; ++ } else { ++ printk(KERN_ERR ++ "Unable to initialize /proc/" DRV_NAME "/radio\n"); ++ err = -ENOMEM; ++ goto fail; ++ } ++ ++ return 0; ++ ++ fail: ++ pbe5_proc_cleanup(); ++ return err; ++} ++ ++/* ++ * module stuff ++ */ ++static int __init pbe5_init(void) ++{ ++ pbe5_proc_init(); ++ ++ pbe5_set_radio((radio == 1) ? PBE5_RADIO_ON : PBE5_RADIO_OFF); ++ ++ return 0; ++} ++ ++static void __exit pbe5_exit(void) ++{ ++ pbe5_set_radio(PBE5_RADIO_OFF); ++ ++ pbe5_proc_cleanup(); ++} ++ ++module_init(pbe5_init); ++module_exit(pbe5_exit); ++ ++/* ++ 1 2 3 4 5 6 7 ++12345678901234567890123456789012345678901234567890123456789012345678901234567890 ++*/ +diff -Nurp linux-2.6.37/3rdparty/rfswitch/README linux-2.6.37.3rdparty/3rdparty/rfswitch/README +--- linux-2.6.37/3rdparty/rfswitch/README 1970-01-01 02:00:00.000000000 +0200 ++++ linux-2.6.37.3rdparty/3rdparty/rfswitch/README 2004-07-09 17:26:20.000000000 +0300 +@@ -0,0 +1,44 @@ ++Radio Kill Switch ++------------ ----- ----- ---- --- -- - ++Most laptops provide the ability for the user to physically disable the radio. ++Some vendors have implemented this as a physical switch that requires no ++software to turn the radio off and on. On other laptops, however, the switch ++is controlled through a button being pressed and a software driver then making ++calls to turn the radio off and on. This is referred to as a "software based ++RF kill switch" ++ ++Currently this project provides modules for controlling the software RF kill ++switch on the Averatec 5100P and Packard Bell EasyNote E5. The code may work ++on other laptops, but these are the only models on which it has been tested. ++ ++To determine if you have a system that might be compatible with one of the ++provided SW RF Kill switch modules, you can run: ++ ++ ++ To check for the Packard Bell (to use module pbe) -- ++ ++ % dd if=/dev/mem bs=1 skip=983040 count=65535 2>/dev/null | strings | egrep "NEW-PC|Insyde Software MobilePRO BIOS" ++ ++ To check for the Averatec (to use module av5100) -- ++ ++ % dd if=/dev/mem bs=1 skip=983040 count=65535 2>/dev/null | strings | egrep "AVERATEC" ++ ++If you have one of those laptop models you can imply loading the av5100/pbe5 ++module and the radio will be toggled on and off. In addition, you can turn ++the driver on and off by writing either a 1 or 0 to /proc/av5100/radio or ++/proc/pbe5/radio. If you automatically load the av5100/pbe5 module when your ++system boots, you may wish to use the radio module parameter to control the ++state of the radio upon loading: ++ ++ modprobe av5100 radio=0 ++ modprobe pbe5 radio=0 ++ ++results in the module loading with the radio turned off. You can then turn the ++radio on by: ++ ++ echo 1 > /proc/av5100/radio ++ echo 1 > /proc/pbe5/radio ++ ++If you have a SW RF kill switch and can not use one of the above modules, ++please join us on IRC (irc.freenode.net) on channel #ipw2100 and someone may ++be able to help. diff --git a/kernel/kernel/files/patches/mageia.old/3rd-rfswitch-3.0-buildfix.patch b/kernel/kernel/files/patches/mageia.old/3rd-rfswitch-3.0-buildfix.patch new file mode 100644 index 00000000..7bfc2c64 --- /dev/null +++ b/kernel/kernel/files/patches/mageia.old/3rd-rfswitch-3.0-buildfix.patch @@ -0,0 +1,19 @@ + +fix build with 3.0 + +Signed-off-by: Thomas Backlund + + 3rdparty/rfswitch/Makefile | 2 -- + 1 file changed, 2 deletions(-) + +--- a/3rdparty/rfswitch/Makefile.orig 2011-07-15 02:37:27.000000000 +0300 ++++ a/3rdparty/rfswitch/Makefile 2011-07-15 13:47:10.463914526 +0300 +@@ -29,8 +29,6 @@ ifneq ($(PATCHLEVEL),6) # If we are not + + O_TARGET := rfswitch.o + +-include $(TOPDIR)/Rules.make +- + endif # End if 2.4 specific settings + + else diff --git a/kernel/kernel/files/patches/mageia.old/3rd-rfswitch-build-fix.patch b/kernel/kernel/files/patches/mageia.old/3rd-rfswitch-build-fix.patch new file mode 100644 index 00000000..ab1c279c --- /dev/null +++ b/kernel/kernel/files/patches/mageia.old/3rd-rfswitch-build-fix.patch @@ -0,0 +1,51 @@ +Remove 'proc_root' usage + +Commit c74c120a21d87b0b6925ada5830d8cac21e852d9 (Linus's tree) removed +the export of 'proc_root' variable, because you can create on the proc's +root directory by passing NULL where you would pass 'proc_root'. + +Signed-off-by: Luiz Fernando N. Capitulino +Index: linux-2.6.25/3rdparty/rfswitch/av5100.c +=================================================================== +--- linux-2.6.25.orig/3rdparty/rfswitch/av5100.c ++++ linux-2.6.25/3rdparty/rfswitch/av5100.c +@@ -107,7 +107,7 @@ static void av5100_proc_cleanup(void) + { + if (dir_base) { + remove_proc_entry("radio", dir_base); +- remove_proc_entry(DRV_NAME, &proc_root); ++ remove_proc_entry(DRV_NAME, NULL); + dir_base = NULL; + } + } +@@ -118,7 +118,7 @@ static int av5100_proc_init(void) + struct proc_dir_entry *ent; + int err = 0; + +- dir_base = create_proc_entry(DRV_NAME, S_IFDIR, &proc_root); ++ dir_base = create_proc_entry(DRV_NAME, S_IFDIR, NULL); + if (dir_base == NULL) { + printk(KERN_ERR DRV_NAME ": Unable to initialise /proc/" + DRV_NAME "\n"); +Index: linux-2.6.25/3rdparty/rfswitch/pbe5.c +=================================================================== +--- linux-2.6.25.orig/3rdparty/rfswitch/pbe5.c ++++ linux-2.6.25/3rdparty/rfswitch/pbe5.c +@@ -138,7 +138,7 @@ static void pbe5_proc_cleanup(void) + { + if (dir_base) { + remove_proc_entry("radio", dir_base); +- remove_proc_entry(DRV_NAME, &proc_root); ++ remove_proc_entry(DRV_NAME, NULL); + dir_base = NULL; + } + } +@@ -149,7 +149,7 @@ static int pbe5_proc_init(void) + struct proc_dir_entry *ent; + int err = 0; + +- dir_base = create_proc_entry(DRV_NAME, S_IFDIR, &proc_root); ++ dir_base = create_proc_entry(DRV_NAME, S_IFDIR, NULL); + if (dir_base == NULL) { + printk(KERN_ERR DRV_NAME ": Unable to initialise /proc/" + DRV_NAME "\n"); diff --git a/kernel/kernel/files/patches/mageia.old/3rd-rtl8723bs-buildfix.patch b/kernel/kernel/files/patches/mageia.old/3rd-rtl8723bs-buildfix.patch new file mode 100644 index 00000000..61c96c46 --- /dev/null +++ b/kernel/kernel/files/patches/mageia.old/3rd-rtl8723bs-buildfix.patch @@ -0,0 +1,23 @@ +From 842e61cb85813b1ed8a1646cbe6739950c0c9822 Mon Sep 17 00:00:00 2001 +From: Larry Finger +Date: Thu, 7 May 2015 19:08:17 +0000 +Subject: [PATCH] rtl8723bs: Fix Makefile to allow warnings + +Signed-off-by: Larry Finger +--- + Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git linux.old/3rdparty/rtl8723bs/Makefile linux/3rdparty/rtl8723bs/Makefile +index a4d9f45..4da73fa 100644 +--- linux.old/3rdparty/rtl8723bs/Makefile ++++ linux/3rdparty/rtl8723bs/Makefile +@@ -3,7 +3,7 @@ EXTRA_CFLAGS += -O1 + #EXTRA_CFLAGS += -O3 + #EXTRA_CFLAGS += -Wall + #EXTRA_CFLAGS += -Wextra +-EXTRA_CFLAGS += -Werror ++#EXTRA_CFLAGS += -Werror + #EXTRA_CFLAGS += -pedantic + #EXTRA_CFLAGS += -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes + diff --git a/kernel/kernel/files/patches/mageia.old/3rd-rtl8723bs-updates.patch b/kernel/kernel/files/patches/mageia.old/3rd-rtl8723bs-updates.patch new file mode 100644 index 00000000..a620e888 --- /dev/null +++ b/kernel/kernel/files/patches/mageia.old/3rd-rtl8723bs-updates.patch @@ -0,0 +1,28991 @@ + +Updates / cleanups from: + +git://github.com/hadess/rtl8723bs.git + +Topmost commit: + +commit 8d329c00dba5d8805a738ecea2bddde8eb0e4945 +Author: Bastien Nocera +Date: Tue May 5 18:30:38 2015 +0200 + + ioctl_linux: Fix compiling with Wake-On-LAN support + + + +Signed-off-by: Thomas backlund + +diff -Nurp linux/3rdparty/rtl8723bs.old/core/rtw_ap.c linux/3rdparty/rtl8723bs/core/rtw_ap.c +--- linux/3rdparty/rtl8723bs.old/core/rtw_ap.c 2015-05-10 14:36:05.663667846 +0300 ++++ linux/3rdparty/rtl8723bs/core/rtw_ap.c 2015-05-07 17:46:55.000000000 +0300 +@@ -21,9 +21,6 @@ + + #include + +- +-#ifdef CONFIG_AP_MODE +- + extern unsigned char RTW_WPA_OUI[]; + extern unsigned char WMM_OUI[]; + extern unsigned char WPS_OUI[]; +@@ -32,7 +29,6 @@ extern unsigned char WFD_OUI[]; + + void init_mlme_ap_info(_adapter *padapter) + { +- struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + struct sta_priv *pstapriv = &padapter->stapriv; + struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; +@@ -71,9 +67,9 @@ void free_mlme_ap_info(_adapter *padapte + + //free bc/mc sta_info + psta = rtw_get_bcmc_stainfo(padapter); +- _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ spin_lock_bh(&(pstapriv->sta_hash_lock)); + rtw_free_stainfo(padapter, psta); +- _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ spin_unlock_bh(&(pstapriv->sta_hash_lock)); + } + + static void update_BCNTIM(_adapter *padapter) +@@ -191,7 +187,7 @@ static void update_BCNTIM(_adapter *pada + { + memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen); + +- rtw_mfree(pbackup_remainder_ie, remainder_ielen); ++ kfree(pbackup_remainder_ie); + } + + offset = (uint)(dst_ie - pie); +@@ -200,122 +196,6 @@ static void update_BCNTIM(_adapter *pada + } + } + +-void rtw_add_bcn_ie(_adapter *padapter, WLAN_BSSID_EX *pnetwork, u8 index, u8 *data, u8 len) +-{ +- PNDIS_802_11_VARIABLE_IEs pIE; +- u8 bmatch = false; +- u8 *pie = pnetwork->IEs; +- u8 *p=NULL, *dst_ie=NULL, *premainder_ie=NULL, *pbackup_remainder_ie=NULL; +- u32 i, offset, ielen, ie_offset, remainder_ielen = 0; +- +- for (i = sizeof(NDIS_802_11_FIXED_IEs); i < pnetwork->IELength;) +- { +- pIE = (PNDIS_802_11_VARIABLE_IEs)(pnetwork->IEs + i); +- +- if (pIE->ElementID > index) +- { +- break; +- } +- else if(pIE->ElementID == index) // already exist the same IE +- { +- p = (u8 *)pIE; +- ielen = pIE->Length; +- bmatch = true; +- break; +- } +- +- p = (u8 *)pIE; +- ielen = pIE->Length; +- i += (pIE->Length + 2); +- } +- +- if (p != NULL && ielen>0) +- { +- ielen += 2; +- +- premainder_ie = p+ielen; +- +- ie_offset = (sint)(p -pie); +- +- remainder_ielen = pnetwork->IELength - ie_offset - ielen; +- +- if(bmatch) +- dst_ie = p; +- else +- dst_ie = (p+ielen); +- } +- +- if(dst_ie == NULL) +- return; +- +- if(remainder_ielen>0) +- { +- pbackup_remainder_ie = rtw_malloc(remainder_ielen); +- if(pbackup_remainder_ie && premainder_ie) +- memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen); +- } +- +- *dst_ie++=index; +- *dst_ie++=len; +- +- memcpy(dst_ie, data, len); +- dst_ie+=len; +- +- //copy remainder IE +- if(pbackup_remainder_ie) +- { +- memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen); +- +- rtw_mfree(pbackup_remainder_ie, remainder_ielen); +- } +- +- offset = (uint)(dst_ie - pie); +- pnetwork->IELength = offset + remainder_ielen; +-} +- +-void rtw_remove_bcn_ie(_adapter *padapter, WLAN_BSSID_EX *pnetwork, u8 index) +-{ +- u8 *p, *dst_ie=NULL, *premainder_ie=NULL, *pbackup_remainder_ie=NULL; +- uint offset, ielen, ie_offset, remainder_ielen = 0; +- u8 *pie = pnetwork->IEs; +- +- p = rtw_get_ie(pie + _FIXED_IE_LENGTH_, index, &ielen, pnetwork->IELength - _FIXED_IE_LENGTH_); +- if (p != NULL && ielen>0) +- { +- ielen += 2; +- +- premainder_ie = p+ielen; +- +- ie_offset = (sint)(p -pie); +- +- remainder_ielen = pnetwork->IELength - ie_offset - ielen; +- +- dst_ie = p; +- } +- else { +- return; +- } +- +- if(remainder_ielen>0) +- { +- pbackup_remainder_ie = rtw_malloc(remainder_ielen); +- if(pbackup_remainder_ie && premainder_ie) +- memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen); +- } +- +- //copy remainder IE +- if(pbackup_remainder_ie) +- { +- memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen); +- +- rtw_mfree(pbackup_remainder_ie, remainder_ielen); +- } +- +- offset = (uint)(dst_ie - pie); +- pnetwork->IELength = offset + remainder_ielen; +-} +- +- + u8 chk_sta_is_alive(struct sta_info *psta); + u8 chk_sta_is_alive(struct sta_info *psta) + { +@@ -349,19 +229,19 @@ void expire_timeout_chk(_adapter *padapt + int i; + + +- _enter_critical_bh(&pstapriv->auth_list_lock, &irqL); ++ spin_lock_bh(&pstapriv->auth_list_lock); + + phead = &pstapriv->auth_list; + plist = get_next(phead); + + //check auth_queue + #ifdef DBG_EXPIRATION_CHK +- if (rtw_end_of_queue_search(phead, plist) == false) { ++ if (phead != plist) { + DBG_871X(FUNC_NDEV_FMT" auth_list, cnt:%u\n" + , FUNC_NDEV_ARG(padapter->pnetdev), pstapriv->auth_list_cnt); + } + #endif +- while ((rtw_end_of_queue_search(phead, plist)) == false) ++ while (phead != plist) + { + psta = LIST_CONTAINOR(plist, struct sta_info, auth_list); + +@@ -372,41 +252,41 @@ void expire_timeout_chk(_adapter *padapt + psta->expire_to--; + if (psta->expire_to == 0) + { +- rtw_list_delete(&psta->auth_list); ++ list_del_init(&psta->auth_list); + pstapriv->auth_list_cnt--; + + DBG_871X("auth expire %02X%02X%02X%02X%02X%02X\n", + psta->hwaddr[0],psta->hwaddr[1],psta->hwaddr[2],psta->hwaddr[3],psta->hwaddr[4],psta->hwaddr[5]); + +- _exit_critical_bh(&pstapriv->auth_list_lock, &irqL); ++ spin_unlock_bh(&pstapriv->auth_list_lock); + +- _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ spin_lock_bh(&(pstapriv->sta_hash_lock)); + rtw_free_stainfo(padapter, psta); +- _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ spin_unlock_bh(&(pstapriv->sta_hash_lock)); + +- _enter_critical_bh(&pstapriv->auth_list_lock, &irqL); ++ spin_lock_bh(&pstapriv->auth_list_lock); + } + } + + } + +- _exit_critical_bh(&pstapriv->auth_list_lock, &irqL); ++ spin_unlock_bh(&pstapriv->auth_list_lock); + psta = NULL; + + +- _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ spin_lock_bh(&pstapriv->asoc_list_lock); + + phead = &pstapriv->asoc_list; + plist = get_next(phead); + + //check asoc_queue + #ifdef DBG_EXPIRATION_CHK +- if (rtw_end_of_queue_search(phead, plist) == false) { ++ if (phead != plist) { + DBG_871X(FUNC_NDEV_FMT" asoc_list, cnt:%u\n" + , FUNC_NDEV_ARG(padapter->pnetdev), pstapriv->asoc_list_cnt); + } + #endif +- while ((rtw_end_of_queue_search(phead, plist)) == false) ++ while (phead != plist) + { + psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); + plist = get_next(plist); +@@ -417,14 +297,13 @@ void expire_timeout_chk(_adapter *padapt + if (chk_sta_is_alive(psta) || !psta->expire_to) { + psta->expire_to = pstapriv->expire_to; + psta->keep_alive_trycnt = 0; +- #ifdef CONFIG_TX_MCAST2UNI + psta->under_exist_checking = 0; +- #endif // CONFIG_TX_MCAST2UNI + } else { +- psta->expire_to--; ++ if (psta->expire_to > 0) ++ psta->expire_to--; + } + +- if (psta->expire_to <= 0) ++ if (psta->expire_to == 0) + { + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + +@@ -460,7 +339,7 @@ void expire_timeout_chk(_adapter *padapt + + continue; + } +- rtw_list_delete(&psta->asoc_list); ++ list_del_init(&psta->asoc_list); + pstapriv->asoc_list_cnt--; + DBG_871X("asoc expire "MAC_FMT", state=0x%x\n", MAC_ARG(psta->hwaddr), psta->state); + updated = ap_free_sta(padapter, psta, false, WLAN_REASON_DEAUTH_LEAVING); +@@ -479,7 +358,7 @@ void expire_timeout_chk(_adapter *padapt + } + } + +- _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ spin_unlock_bh(&pstapriv->asoc_list_lock); + + if (chk_alive_num) { + +@@ -521,13 +400,13 @@ if (chk_alive_num) { + + psta->keep_alive_trycnt = 0; + DBG_871X("asoc expire "MAC_FMT", state=0x%x\n", MAC_ARG(psta->hwaddr), psta->state); +- _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); +- if (rtw_is_list_empty(&psta->asoc_list)==false) { +- rtw_list_delete(&psta->asoc_list); ++ spin_lock_bh(&pstapriv->asoc_list_lock); ++ if (list_empty(&psta->asoc_list)==false) { ++ list_del_init(&psta->asoc_list); + pstapriv->asoc_list_cnt--; + updated = ap_free_sta(padapter, psta, false, WLAN_REASON_DEAUTH_LEAVING); + } +- _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ spin_unlock_bh(&pstapriv->asoc_list_lock); + + } + +@@ -544,13 +423,10 @@ void add_RATid(_adapter *padapter, struc + u8 rf_type; + unsigned char sta_band = 0, shortGIrate = false; + unsigned int tx_ra_bitmap=0; +- struct ht_priv *psta_ht = NULL; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + WLAN_BSSID_EX *pcur_network = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network; + +- if(psta) +- psta_ht = &psta->htpriv; +- else ++ if(!psta) + return; + + if(!(psta->state & _FW_LINKED)) +@@ -672,9 +548,9 @@ void update_bmc_sta(_adapter *padapter) + + rtw_sta_media_status_rpt(padapter, psta, 1); + +- _enter_critical_bh(&psta->lock, &irqL); ++ spin_lock_bh(&psta->lock); + psta->state = _FW_LINKED; +- _exit_critical_bh(&psta->lock, &irqL); ++ spin_unlock_bh(&psta->lock); + + } + else +@@ -815,9 +691,9 @@ void update_sta_info_apmode(_adapter *pa + //add_RATid(padapter, psta);//move to ap_sta_info_defer_update() + + +- _enter_critical_bh(&psta->lock, &irqL); ++ spin_lock_bh(&psta->lock); + psta->state |= _FW_LINKED; +- _exit_critical_bh(&psta->lock, &irqL); ++ spin_unlock_bh(&psta->lock); + + + } +@@ -826,7 +702,6 @@ static void update_ap_info(_adapter *pad + { + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + WLAN_BSSID_EX *pnetwork = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network; +- struct security_priv *psecuritypriv = &padapter->securitypriv; + struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct ht_priv *phtpriv_ap = &pmlmepriv->htpriv; + +@@ -875,7 +750,6 @@ static void update_hw_ht_param(_adapter + { + unsigned char max_AMPDU_len; + unsigned char min_MPDU_spacing; +- struct registry_priv *pregpriv = &padapter->registrypriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + +@@ -933,8 +807,7 @@ void start_bss_network(_adapter *padapte + WLAN_BSSID_EX *pnetwork_mlmeext = &(pmlmeinfo->network); + struct HT_info_element *pht_info=NULL; + u8 cbw40_enable=0; +- u8 change_band = false; +- ++ + //DBG_871X("%s\n", __FUNCTION__); + + bcn_interval = (u16)pnetwork->Configuration.BeaconPeriod; +@@ -1114,15 +987,12 @@ int rtw_check_beacon_data(_adapter *pada + u8 channel, network_type, supportRate[NDIS_802_11_LENGTH_RATES_EX]; + int supportRateNum = 0; + u8 OUI1[] = {0x00, 0x50, 0xf2,0x01}; +- u8 wps_oui[4]={0x0,0x50,0xf2,0x04}; + u8 WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01}; + struct registry_priv *pregistrypriv = &padapter->registrypriv; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); + WLAN_BSSID_EX *pbss_network = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network; +- struct sta_priv *pstapriv = &padapter->stapriv; + u8 *ie = pbss_network->IEs; +- u8 vht_cap=false; + + /* SSID */ + /* Supported rates */ +@@ -1483,12 +1353,12 @@ int rtw_acl_add_sta(_adapter *padapter, + return (-1); + + +- _enter_critical_bh(&(pacl_node_q->lock), &irqL); ++ spin_lock_bh(&(pacl_node_q->lock)); + + phead = get_list_head(pacl_node_q); + plist = get_next(phead); + +- while ((rtw_end_of_queue_search(phead, plist)) == false) ++ while (phead != plist) + { + paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list); + plist = get_next(plist); +@@ -1504,14 +1374,14 @@ int rtw_acl_add_sta(_adapter *padapter, + } + } + +- _exit_critical_bh(&(pacl_node_q->lock), &irqL); ++ spin_unlock_bh(&(pacl_node_q->lock)); + + + if(added == true) + return ret; + + +- _enter_critical_bh(&(pacl_node_q->lock), &irqL); ++ spin_lock_bh(&(pacl_node_q->lock)); + + for(i=0; i< NUM_ACL; i++) + { +@@ -1519,13 +1389,13 @@ int rtw_acl_add_sta(_adapter *padapter, + + if(paclnode->valid == false) + { +- _rtw_init_listhead(&paclnode->list); ++ INIT_LIST_HEAD(&paclnode->list); + + memcpy(paclnode->addr, addr, ETH_ALEN); + + paclnode->valid = true; + +- rtw_list_insert_tail(&paclnode->list, get_list_head(pacl_node_q)); ++ list_add_tail(&paclnode->list, get_list_head(pacl_node_q)); + + pacl_list->num++; + +@@ -1535,7 +1405,7 @@ int rtw_acl_add_sta(_adapter *padapter, + + DBG_871X("%s, acl_num=%d\n", __func__, pacl_list->num); + +- _exit_critical_bh(&(pacl_node_q->lock), &irqL); ++ spin_unlock_bh(&(pacl_node_q->lock)); + + return ret; + } +@@ -1553,12 +1423,12 @@ int rtw_acl_remove_sta(_adapter *padapte + + DBG_871X("%s(acl_num=%d)=" MAC_FMT "\n", __func__, pacl_list->num, MAC_ARG(addr)); + +- _enter_critical_bh(&(pacl_node_q->lock), &irqL); ++ spin_lock_bh(&(pacl_node_q->lock)); + + phead = get_list_head(pacl_node_q); + plist = get_next(phead); + +- while ((rtw_end_of_queue_search(phead, plist)) == false) ++ while (phead != plist) + { + paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list); + plist = get_next(plist); +@@ -1569,14 +1439,14 @@ int rtw_acl_remove_sta(_adapter *padapte + { + paclnode->valid = false; + +- rtw_list_delete(&paclnode->list); ++ list_del_init(&paclnode->list); + + pacl_list->num--; + } + } + } + +- _exit_critical_bh(&(pacl_node_q->lock), &irqL); ++ spin_unlock_bh(&(pacl_node_q->lock)); + + DBG_871X("%s, acl_num=%d\n", __func__, pacl_list->num); + +@@ -1599,7 +1469,7 @@ u8 rtw_ap_set_pairwise_key(_adapter *pad + + psetstakey_para = (struct set_stakey_parm*)rtw_zmalloc(sizeof(struct set_stakey_parm)); + if(psetstakey_para==NULL){ +- rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); ++ kfree((u8 *) ph2c); + res=_FAIL; + goto exit; + } +@@ -1639,7 +1509,7 @@ static int rtw_ap_set_key(_adapter *pada + } + psetkeyparm=(struct setkey_parm*)rtw_zmalloc(sizeof(struct setkey_parm)); + if(psetkeyparm==NULL){ +- rtw_mfree((unsigned char *)pcmd, sizeof(struct cmd_obj)); ++ kfree((unsigned char *)pcmd); + res= _FAIL; + goto exit; + } +@@ -1678,7 +1548,7 @@ static int rtw_ap_set_key(_adapter *pada + pcmd->rspsz = 0; + + +- _rtw_init_listhead(&pcmd->list); ++ INIT_LIST_HEAD(&pcmd->list); + + res = rtw_enqueue_cmd(pcmdpriv, pcmd); + +@@ -1715,8 +1585,6 @@ int rtw_ap_set_wep_key(_adapter *padapte + return rtw_ap_set_key(padapter, key, alg, keyid, set_tx); + } + +-#ifdef CONFIG_NATIVEAP_MLME +- + static void update_bcn_fixed_ie(_adapter *padapter) + { + DBG_871X("%s\n", __FUNCTION__); +@@ -1838,7 +1706,7 @@ static void update_bcn_wps_ie(_adapter * + } + + if(pbackup_remainder_ie) +- rtw_mfree(pbackup_remainder_ie, remainder_ielen); ++ kfree(pbackup_remainder_ie); + + // deal with the case without set_tx_beacon_cmd() in update_beacon() + #if defined( CONFIG_INTERRUPT_BASED_TXBCN ) +@@ -1907,7 +1775,7 @@ void update_beacon(_adapter *padapter, u + if(false == pmlmeext->bstart_bss) + return; + +- _enter_critical_bh(&pmlmepriv->bcn_update_lock, &irqL); ++ spin_lock_bh(&pmlmepriv->bcn_update_lock); + + switch(ie_id) + { +@@ -1959,7 +1827,7 @@ void update_beacon(_adapter *padapter, u + + pmlmepriv->update_bcn = true; + +- _exit_critical_bh(&pmlmepriv->bcn_update_lock, &irqL); ++ spin_unlock_bh(&pmlmepriv->bcn_update_lock); + + #ifndef CONFIG_INTERRUPT_BASED_TXBCN + if(tx) +@@ -2064,13 +1932,13 @@ void associated_clients_update(_adapter + struct sta_info *psta=NULL; + struct sta_priv *pstapriv = &padapter->stapriv; + +- _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ spin_lock_bh(&pstapriv->asoc_list_lock); + + phead = &pstapriv->asoc_list; + plist = get_next(phead); + + //check asoc_queue +- while ((rtw_end_of_queue_search(phead, plist)) == false) ++ while (phead != plist) + { + psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); + +@@ -2079,7 +1947,7 @@ void associated_clients_update(_adapter + VCS_update(padapter, psta); + } + +- _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ spin_unlock_bh(&pstapriv->asoc_list_lock); + + } + +@@ -2332,8 +2200,6 @@ u8 ap_free_sta(_adapter *padapter, struc + { + _irqL irqL; + u8 beacon_updated = false; +- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); +- struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); + struct sta_priv *pstapriv = &padapter->stapriv; + + if(!psta) +@@ -2360,9 +2226,9 @@ u8 ap_free_sta(_adapter *padapter, struc + rtw_clearstakey_cmd(padapter, psta, true); + + +- _enter_critical_bh(&psta->lock, &irqL); ++ spin_lock_bh(&psta->lock); + psta->state &= ~_FW_LINKED; +- _exit_critical_bh(&psta->lock, &irqL); ++ spin_unlock_bh(&psta->lock); + + rtw_cfg80211_indicate_sta_disassoc(padapter, psta->hwaddr, reason); + +@@ -2370,52 +2236,15 @@ u8 ap_free_sta(_adapter *padapter, struc + + beacon_updated = bss_cap_update_on_sta_leave(padapter, psta); + +- _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ spin_lock_bh(&(pstapriv->sta_hash_lock)); + rtw_free_stainfo(padapter, psta); +- _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ spin_unlock_bh(&(pstapriv->sta_hash_lock)); + + + return beacon_updated; + + } + +-int rtw_ap_inform_ch_switch(_adapter *padapter, u8 new_ch, u8 ch_offset) +-{ +- _irqL irqL; +- _list *phead, *plist; +- int ret=0; +- struct sta_info *psta = NULL; +- struct sta_priv *pstapriv = &padapter->stapriv; +- struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; +- struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); +- u8 bc_addr[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; +- +- if((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE) +- return ret; +- +- DBG_871X(FUNC_NDEV_FMT" with ch:%u, offset:%u\n", +- FUNC_NDEV_ARG(padapter->pnetdev), new_ch, ch_offset); +- +- _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); +- phead = &pstapriv->asoc_list; +- plist = get_next(phead); +- +- /* for each sta in asoc_queue */ +- while ((rtw_end_of_queue_search(phead, plist)) == false) +- { +- psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); +- plist = get_next(plist); +- +- issue_action_spct_ch_switch(padapter, psta->hwaddr, new_ch, ch_offset); +- psta->expire_to = ((pstapriv->expire_to * 2) > 5) ? 5 : (pstapriv->expire_to * 2); +- } +- _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); +- +- issue_action_spct_ch_switch(padapter, bc_addr, new_ch, ch_offset); +- +- return ret; +-} +- + int rtw_sta_flush(_adapter *padapter) + { + _irqL irqL; +@@ -2433,25 +2262,25 @@ int rtw_sta_flush(_adapter *padapter) + return ret; + + +- _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ spin_lock_bh(&pstapriv->asoc_list_lock); + phead = &pstapriv->asoc_list; + plist = get_next(phead); + + //free sta asoc_queue +- while ((rtw_end_of_queue_search(phead, plist)) == false) ++ while (phead != plist) + { + psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); + + plist = get_next(plist); + +- rtw_list_delete(&psta->asoc_list); ++ list_del_init(&psta->asoc_list); + pstapriv->asoc_list_cnt--; + +- //_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ //spin_unlock_bh(&pstapriv->asoc_list_lock); + ap_free_sta(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING); +- //_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ //spin_lock_bh(&pstapriv->asoc_list_lock); + } +- _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ spin_unlock_bh(&pstapriv->asoc_list_lock); + + + issue_deauth(padapter, bc_addr, WLAN_REASON_DEAUTH_LEAVING); +@@ -2516,7 +2345,6 @@ void rtw_ap_restore_network(_adapter *pa + { + struct mlme_priv *mlmepriv = &padapter->mlmepriv; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; +- struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct sta_priv * pstapriv = &padapter->stapriv; + struct sta_info *psta; + struct security_priv* psecuritypriv=&(padapter->securitypriv); +@@ -2539,12 +2367,12 @@ void rtw_ap_restore_network(_adapter *pa + rtw_set_key(padapter, psecuritypriv, psecuritypriv->dot118021XGrpKeyid, 0,false); + } + +- _enter_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ spin_lock_bh(&pstapriv->asoc_list_lock); + + phead = &pstapriv->asoc_list; + plist = get_next(phead); + +- while ((rtw_end_of_queue_search(phead, plist)) == false) { ++ while (phead != plist) { + int stainfo_offset; + + psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); +@@ -2556,7 +2384,7 @@ void rtw_ap_restore_network(_adapter *pa + } + } + +- _exit_critical_bh(&pstapriv->asoc_list_lock, &irqL); ++ spin_unlock_bh(&pstapriv->asoc_list_lock); + + for (i = 0; i < chk_alive_num; i++) { + psta = rtw_get_stainfo_by_offset(pstapriv, chk_alive_list[i]); +@@ -2619,12 +2447,12 @@ void start_ap_mode(_adapter *padapter) + + + //for ACL +- _rtw_init_listhead(&(pacl_list->acl_node_q.queue)); ++ INIT_LIST_HEAD(&(pacl_list->acl_node_q.queue)); + pacl_list->num = 0; + pacl_list->mode = 0; + for(i = 0; i < NUM_ACL; i++) + { +- _rtw_init_listhead(&pacl_list->aclnode[i].list); ++ INIT_LIST_HEAD(&pacl_list->aclnode[i].list); + pacl_list->aclnode[i].valid = false; + } + +@@ -2651,10 +2479,10 @@ void stop_ap_mode(_adapter *padapter) + padapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled; + + //for ACL +- _enter_critical_bh(&(pacl_node_q->lock), &irqL); ++ spin_lock_bh(&(pacl_node_q->lock)); + phead = get_list_head(pacl_node_q); + plist = get_next(phead); +- while ((rtw_end_of_queue_search(phead, plist)) == false) ++ while (phead != plist) + { + paclnode = LIST_CONTAINOR(plist, struct rtw_wlan_acl_node, list); + plist = get_next(plist); +@@ -2663,12 +2491,12 @@ void stop_ap_mode(_adapter *padapter) + { + paclnode->valid = false; + +- rtw_list_delete(&paclnode->list); ++ list_del_init(&paclnode->list); + + pacl_list->num--; + } + } +- _exit_critical_bh(&(pacl_node_q->lock), &irqL); ++ spin_unlock_bh(&(pacl_node_q->lock)); + + DBG_871X("%s, free acl_node_queue, num=%d\n", __func__, pacl_list->num); + +@@ -2678,9 +2506,9 @@ void stop_ap_mode(_adapter *padapter) + rtw_free_all_stainfo(padapter); + + psta = rtw_get_bcmc_stainfo(padapter); +- _enter_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ spin_lock_bh(&(pstapriv->sta_hash_lock)); + rtw_free_stainfo(padapter, psta); +- _exit_critical_bh(&(pstapriv->sta_hash_lock), &irqL); ++ spin_unlock_bh(&(pstapriv->sta_hash_lock)); + + rtw_init_bcmc_stainfo(padapter); + +@@ -2688,8 +2516,3 @@ void stop_ap_mode(_adapter *padapter) + + rtw_btcoex_MediaStatusNotify(padapter, 0); //disconnect + } +- +-#endif //CONFIG_NATIVEAP_MLME +- +-#endif //CONFIG_AP_MODE +- +diff -Nurp linux/3rdparty/rtl8723bs.old/core/rtw_btcoex.c linux/3rdparty/rtl8723bs/core/rtw_btcoex.c +--- linux/3rdparty/rtl8723bs.old/core/rtw_btcoex.c 2015-05-10 14:36:05.663667846 +0300 ++++ linux/3rdparty/rtl8723bs/core/rtw_btcoex.c 2015-05-07 17:46:55.000000000 +0300 +@@ -108,16 +108,6 @@ void rtw_btcoex_HaltNotify(PADAPTER pada + hal_btcoex_HaltNotify(padapter); + } + +-void rtw_btcoex_SwitchBtTRxMask(PADAPTER padapter) +-{ +- hal_btcoex_SwitchBtTRxMask(padapter); +-} +- +-void rtw_btcoex_Switch(PADAPTER padapter, u8 enable) +-{ +- hal_btcoex_SetBTCoexist(padapter, enable); +-} +- + u8 rtw_btcoex_IsBtDisabled(PADAPTER padapter) + { + return hal_btcoex_IsBtDisabled(padapter); +@@ -137,15 +127,6 @@ s32 rtw_btcoex_IsBTCoexCtrlAMPDUSize(PAD + return coexctrl; + } + +-u32 rtw_btcoex_GetAMPDUSize(PADAPTER padapter) +-{ +- u32 size; +- +- size = hal_btcoex_GetAMPDUSize(padapter); +- +- return size; +-} +- + void rtw_btcoex_SetManualControl(PADAPTER padapter, u8 manual) + { + if (true == manual) +@@ -158,11 +139,6 @@ void rtw_btcoex_SetManualControl(PADAPTE + } + } + +-u8 rtw_btcoex_1Ant(PADAPTER padapter) +-{ +- return hal_btcoex_1Ant(padapter); +-} +- + u8 rtw_btcoex_IsBtControlLps(PADAPTER padapter) + { + return hal_btcoex_IsBtControlLps(padapter); +@@ -198,11 +174,6 @@ void rtw_btcoex_SetPGAntNum(PADAPTER pad + hal_btcoex_SetPgAntNum(padapter, antNum); + } + +-u8 rtw_btcoex_GetPGAntNum(PADAPTER padapter) +-{ +- return hal_btcoex_GetPgAntNum(padapter); +-} +- + void rtw_btcoex_SetSingleAntPath(PADAPTER padapter, u8 singleAntPath) + { + hal_btcoex_SetSingleAntPath(padapter, singleAntPath); +@@ -233,16 +204,6 @@ u32 rtw_btcoex_GetDBG(PADAPTER padapter, + return hal_btcoex_GetDBG(padapter, pStrBuf, bufSize); + } + +-u8 rtw_btcoex_IncreaseScanDeviceNum(PADAPTER padapter) +-{ +- return hal_btcoex_IncreaseScanDeviceNum(padapter); +-} +- +-u8 rtw_btcoex_IsBtLinkExist(PADAPTER padapter) +-{ +- return hal_btcoex_IsBtLinkExist(padapter); +-} +- + // ================================================== + // Below Functions are called by BT-Coex + // ================================================== +diff -Nurp linux/3rdparty/rtl8723bs.old/core/rtw_cmd.c linux/3rdparty/rtl8723bs/core/rtw_cmd.c +--- linux/3rdparty/rtl8723bs.old/core/rtw_cmd.c 2015-05-10 14:36:05.665667868 +0300 ++++ linux/3rdparty/rtl8723bs/core/rtw_cmd.c 2015-05-07 17:46:55.000000000 +0300 +@@ -255,10 +255,10 @@ _func_enter_; + void *c2h; + if ((c2h = rtw_cbuf_pop(pevtpriv->c2h_queue)) != NULL + && c2h != (void *)pevtpriv) { +- rtw_mfree(c2h, 16); ++ kfree(c2h); + } + } +- rtw_cbuf_free(pevtpriv->c2h_queue); ++ kfree(pevtpriv->c2h_queue); + + RT_TRACE(_module_rtl871x_cmd_c_,_drv_info_,("-_rtw_free_evt_priv \n")); + +@@ -272,10 +272,10 @@ _func_enter_; + + if(pcmdpriv){ + if (pcmdpriv->cmd_allocated_buf) +- rtw_mfree(pcmdpriv->cmd_allocated_buf, MAX_CMDSZ + CMDBUFF_ALIGN_SZ); ++ kfree(pcmdpriv->cmd_allocated_buf); + + if (pcmdpriv->rsp_allocated_buf) +- rtw_mfree(pcmdpriv->rsp_allocated_buf, MAX_RSPSZ + 4); ++ kfree(pcmdpriv->rsp_allocated_buf); + + mutex_destroy(&pcmdpriv->sctx_mutex); + } +@@ -301,13 +301,13 @@ _func_enter_; + if (obj == NULL) + goto exit; + +- //_enter_critical_bh(&queue->lock, &irqL); +- _enter_critical(&queue->lock, &irqL); ++ //spin_lock_bh(&queue->lock); ++ spin_lock_irqsave(&queue->lock, irqL); + +- rtw_list_insert_tail(&obj->list, &queue->queue); ++ list_add_tail(&obj->list, &queue->queue); + +- //_exit_critical_bh(&queue->lock, &irqL); +- _exit_critical(&queue->lock, &irqL); ++ //spin_unlock_bh(&queue->lock); ++ spin_unlock_irqrestore(&queue->lock, irqL); + + exit: + +@@ -323,18 +323,18 @@ struct cmd_obj *_rtw_dequeue_cmd(_queue + + _func_enter_; + +- //_enter_critical_bh(&(queue->lock), &irqL); +- _enter_critical(&queue->lock, &irqL); +- if (rtw_is_list_empty(&(queue->queue))) ++ //spin_lock_bh(&(queue->lock)); ++ spin_lock_irqsave(&queue->lock, irqL); ++ if (list_empty(&(queue->queue))) + obj = NULL; + else + { + obj = LIST_CONTAINOR(get_next(&(queue->queue)), struct cmd_obj, list); +- rtw_list_delete(&obj->list); ++ list_del_init(&obj->list); + } + +- //_exit_critical_bh(&(queue->lock), &irqL); +- _exit_critical(&queue->lock, &irqL); ++ //spin_unlock_bh(&(queue->lock)); ++ spin_unlock_irqrestore(&queue->lock, irqL); + + _func_exit_; + +@@ -442,14 +442,6 @@ _func_exit_; + return cmd_obj; + } + +-void rtw_cmd_clr_isr(struct cmd_priv *pcmdpriv) +-{ +-_func_enter_; +- pcmdpriv->cmd_done_cnt++; +- //up(&(pcmdpriv->cmd_done_sema)); +-_func_exit_; +-} +- + void rtw_free_cmd_obj(struct cmd_obj *pcmd) + { + _func_enter_; +@@ -457,7 +449,7 @@ _func_enter_; + if((pcmd->cmdcode!=_JoinBss_CMD_) &&(pcmd->cmdcode!= _CreateBss_CMD_)) + { + //free parmbuf in cmd_obj +- rtw_mfree((unsigned char*)pcmd->parmbuf, pcmd->cmdsz); ++ kfree((unsigned char*)pcmd->parmbuf); + } + + if(pcmd->rsp!=NULL) +@@ -465,12 +457,12 @@ _func_enter_; + if(pcmd->rspsz!= 0) + { + //free rsp in cmd_obj +- rtw_mfree((unsigned char*)pcmd->rsp, pcmd->rspsz); ++ kfree((unsigned char*)pcmd->rsp); + } + } + + //free cmd_obj +- rtw_mfree((unsigned char*)pcmd, sizeof(struct cmd_obj)); ++ kfree((unsigned char*)pcmd); + + _func_exit_; + } +@@ -533,7 +525,7 @@ _func_enter_; + break; + } + +- if(rtw_is_list_empty(&(pcmdpriv->cmd_queue.queue))) ++ if(list_empty(&(pcmdpriv->cmd_queue.queue))) + { + //DBG_871X("%s: cmd queue is empty!\n", __func__); + continue; +@@ -573,7 +565,7 @@ _next: + + memcpy(pcmdbuf, pcmd->parmbuf, pcmd->cmdsz); + +- if(pcmd->cmdcode < (sizeof(wlancmds) /sizeof(struct cmd_hdl))) ++ if(pcmd->cmdcode < ARRAY_SIZE(wlancmds)) + { + cmd_hdl = wlancmds[pcmd->cmdcode].h2cfuns; + +@@ -594,18 +586,18 @@ _next: + + post_process: + +- _enter_critical_mutex(&(pcmd->padapter->cmdpriv.sctx_mutex), NULL); +- if (pcmd->sctx) { +- DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" pcmd->sctx\n", +- FUNC_ADPT_ARG(pcmd->padapter)); +- +- if (pcmd->res == H2C_SUCCESS) +- rtw_sctx_done(&pcmd->sctx); +- else +- rtw_sctx_done_err(&pcmd->sctx, RTW_SCTX_DONE_CMD_ERROR); ++ if (mutex_lock_interruptible(&(pcmd->padapter->cmdpriv.sctx_mutex)) == 0) { ++ if (pcmd->sctx) { ++ DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" pcmd->sctx\n", ++ FUNC_ADPT_ARG(pcmd->padapter)); ++ ++ if (pcmd->res == H2C_SUCCESS) ++ rtw_sctx_done(&pcmd->sctx); ++ else ++ rtw_sctx_done_err(&pcmd->sctx, RTW_SCTX_DONE_CMD_ERROR); ++ } ++ mutex_unlock(&(pcmd->padapter->cmdpriv.sctx_mutex)); + } +- _exit_critical_mutex(&(pcmd->padapter->cmdpriv.sctx_mutex), NULL); +- + + if((cmd_process_time = jiffies_to_msecs(jiffies - cmd_start_time)) > 1000) + { +@@ -627,7 +619,7 @@ post_process: + } + + //call callback function for post-processed +- if(pcmd->cmdcode < (sizeof(rtw_cmd_callback) /sizeof(struct _cmd_callback))) ++ if(pcmd->cmdcode < ARRAY_SIZE(rtw_cmd_callback)) + { + pcmd_callback = rtw_cmd_callback[pcmd->cmdcode].callback; + if(pcmd_callback == NULL) +@@ -666,7 +658,7 @@ post_process: + if (pcmd->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) { + extra_parm = (struct drvextra_cmd_parm *)pcmd->parmbuf; + if(extra_parm->pbuf && extra_parm->size > 0) { +- rtw_mfree(extra_parm->pbuf, extra_parm->size); ++ kfree(extra_parm->pbuf); + } + } + +@@ -682,42 +674,6 @@ _func_exit_; + + } + +-u8 rtw_setstandby_cmd(_adapter *padapter, uint action) +-{ +- struct cmd_obj* ph2c; +- struct usb_suspend_parm* psetusbsuspend; +- struct cmd_priv *pcmdpriv=&padapter->cmdpriv; +- +- u8 ret = _SUCCESS; +- +-_func_enter_; +- +- ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); +- if (ph2c == NULL) { +- ret = _FAIL; +- goto exit; +- } +- +- psetusbsuspend = (struct usb_suspend_parm*)rtw_zmalloc(sizeof(struct usb_suspend_parm)); +- if (psetusbsuspend == NULL) { +- rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); +- ret = _FAIL; +- goto exit; +- } +- +- psetusbsuspend->action = action; +- +- init_h2fwcmd_w_parm_no_rsp(ph2c, psetusbsuspend, GEN_CMD_CODE(_SetUsbSuspend)); +- +- ret = rtw_enqueue_cmd(pcmdpriv, ph2c); +- +-exit: +- +-_func_exit_; +- +- return ret; +-} +- + /* + rtw_sitesurvey_cmd(~) + ### NOTE:#### (!!!!) +@@ -744,7 +700,7 @@ _func_enter_; + + psurveyPara = (struct sitesurvey_parm*)rtw_zmalloc(sizeof(struct sitesurvey_parm)); + if (psurveyPara == NULL) { +- rtw_mfree((unsigned char*) ph2c, sizeof(struct cmd_obj)); ++ kfree((unsigned char*) ph2c); + return _FAIL; + } + +@@ -793,8 +749,6 @@ _func_enter_; + + pmlmepriv->scan_start_time = jiffies; + _set_timer(&pmlmepriv->scan_to_timer, SCANNING_TIMEOUT); +- +- rtw_led_control(padapter, LED_CTL_SITE_SURVEY); + } else { + _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); + } +@@ -821,7 +775,7 @@ _func_enter_; + + pbsetdataratepara = (struct setdatarate_parm*)rtw_zmalloc(sizeof(struct setdatarate_parm)); + if (pbsetdataratepara == NULL) { +- rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); ++ kfree((u8 *) ph2c); + res = _FAIL; + goto exit; + } +@@ -838,243 +792,17 @@ _func_exit_; + return res; + } + +-u8 rtw_setbasicrate_cmd(_adapter *padapter, u8 *rateset) +-{ +- struct cmd_obj* ph2c; +- struct setbasicrate_parm* pssetbasicratepara; +- struct cmd_priv* pcmdpriv=&padapter->cmdpriv; +- u8 res = _SUCCESS; +- +-_func_enter_; +- +- ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); +- if (ph2c == NULL) { +- res= _FAIL; +- goto exit; +- } +- pssetbasicratepara = (struct setbasicrate_parm*)rtw_zmalloc(sizeof(struct setbasicrate_parm)); +- +- if (pssetbasicratepara == NULL) { +- rtw_mfree((u8*) ph2c, sizeof(struct cmd_obj)); +- res = _FAIL; +- goto exit; +- } +- +- init_h2fwcmd_w_parm_no_rsp(ph2c, pssetbasicratepara, _SetBasicRate_CMD_); +- +- memcpy(pssetbasicratepara->basicrates, rateset, NumRates); +- +- res = rtw_enqueue_cmd(pcmdpriv, ph2c); +-exit: +- +-_func_exit_; +- +- return res; +-} +- +- +-/* +-unsigned char rtw_setphy_cmd(unsigned char *adapter) +- +-1. be called only after rtw_update_registrypriv_dev_network( ~) or mp testing program +-2. for AdHoc/Ap mode or mp mode? +- +-*/ +-u8 rtw_setphy_cmd(_adapter *padapter, u8 modem, u8 ch) +-{ +- struct cmd_obj* ph2c; +- struct setphy_parm* psetphypara; +- struct cmd_priv *pcmdpriv=&padapter->cmdpriv; +-// struct mlme_priv *pmlmepriv = &padapter->mlmepriv; +-// struct registry_priv* pregistry_priv = &padapter->registrypriv; +- u8 res=_SUCCESS; +- +-_func_enter_; +- +- ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); +- if(ph2c==NULL){ +- res= _FAIL; +- goto exit; +- } +- psetphypara = (struct setphy_parm*)rtw_zmalloc(sizeof(struct setphy_parm)); +- +- if(psetphypara==NULL){ +- rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); +- res= _FAIL; +- goto exit; +- } +- +- init_h2fwcmd_w_parm_no_rsp(ph2c, psetphypara, _SetPhy_CMD_); +- +- RT_TRACE(_module_rtl871x_cmd_c_,_drv_info_,("CH=%d, modem=%d", ch, modem)); +- +- psetphypara->modem = modem; +- psetphypara->rfchannel = ch; +- +- res = rtw_enqueue_cmd(pcmdpriv, ph2c); +-exit: +-_func_exit_; +- return res; +-} +- +-u8 rtw_setbbreg_cmd(_adapter*padapter, u8 offset, u8 val) +-{ +- struct cmd_obj* ph2c; +- struct writeBB_parm* pwritebbparm; +- struct cmd_priv *pcmdpriv=&padapter->cmdpriv; +- u8 res=_SUCCESS; +-_func_enter_; +- ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); +- if(ph2c==NULL){ +- res= _FAIL; +- goto exit; +- } +- pwritebbparm = (struct writeBB_parm*)rtw_zmalloc(sizeof(struct writeBB_parm)); +- +- if(pwritebbparm==NULL){ +- rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); +- res= _FAIL; +- goto exit; +- } +- +- init_h2fwcmd_w_parm_no_rsp(ph2c, pwritebbparm, GEN_CMD_CODE(_SetBBReg)); +- +- pwritebbparm->offset = offset; +- pwritebbparm->value = val; +- +- res = rtw_enqueue_cmd(pcmdpriv, ph2c); +-exit: +-_func_exit_; +- return res; +-} +- +-u8 rtw_getbbreg_cmd(_adapter *padapter, u8 offset, u8 *pval) +-{ +- struct cmd_obj* ph2c; +- struct readBB_parm* prdbbparm; +- struct cmd_priv *pcmdpriv=&padapter->cmdpriv; +- u8 res=_SUCCESS; +- +-_func_enter_; +- ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); +- if(ph2c==NULL){ +- res=_FAIL; +- goto exit; +- } +- prdbbparm = (struct readBB_parm*)rtw_zmalloc(sizeof(struct readBB_parm)); +- +- if(prdbbparm ==NULL){ +- rtw_mfree((unsigned char *) ph2c, sizeof(struct cmd_obj)); +- return _FAIL; +- } +- +- _rtw_init_listhead(&ph2c->list); +- ph2c->cmdcode =GEN_CMD_CODE(_GetBBReg); +- ph2c->parmbuf = (unsigned char *)prdbbparm; +- ph2c->cmdsz = sizeof(struct readBB_parm); +- ph2c->rsp = pval; +- ph2c->rspsz = sizeof(struct readBB_rsp); +- +- prdbbparm ->offset = offset; +- +- res = rtw_enqueue_cmd(pcmdpriv, ph2c); +-exit: +-_func_exit_; +- return res; +-} +- +-u8 rtw_setrfreg_cmd(_adapter *padapter, u8 offset, u32 val) +-{ +- struct cmd_obj* ph2c; +- struct writeRF_parm* pwriterfparm; +- struct cmd_priv *pcmdpriv=&padapter->cmdpriv; +- u8 res=_SUCCESS; +-_func_enter_; +- ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); +- if(ph2c==NULL){ +- res= _FAIL; +- goto exit; +- } +- pwriterfparm = (struct writeRF_parm*)rtw_zmalloc(sizeof(struct writeRF_parm)); +- +- if(pwriterfparm==NULL){ +- rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); +- res= _FAIL; +- goto exit; +- } +- +- init_h2fwcmd_w_parm_no_rsp(ph2c, pwriterfparm, GEN_CMD_CODE(_SetRFReg)); +- +- pwriterfparm->offset = offset; +- pwriterfparm->value = val; +- +- res = rtw_enqueue_cmd(pcmdpriv, ph2c); +-exit: +-_func_exit_; +- return res; +-} +- +-u8 rtw_getrfreg_cmd(_adapter *padapter, u8 offset, u8 *pval) +-{ +- struct cmd_obj* ph2c; +- struct readRF_parm* prdrfparm; +- struct cmd_priv *pcmdpriv=&padapter->cmdpriv; +- u8 res=_SUCCESS; +- +-_func_enter_; +- +- ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); +- if(ph2c==NULL){ +- res= _FAIL; +- goto exit; +- } +- +- prdrfparm = (struct readRF_parm*)rtw_zmalloc(sizeof(struct readRF_parm)); +- if(prdrfparm ==NULL){ +- rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); +- res= _FAIL; +- goto exit; +- } +- +- _rtw_init_listhead(&ph2c->list); +- ph2c->cmdcode =GEN_CMD_CODE(_GetRFReg); +- ph2c->parmbuf = (unsigned char *)prdrfparm; +- ph2c->cmdsz = sizeof(struct readRF_parm); +- ph2c->rsp = pval; +- ph2c->rspsz = sizeof(struct readRF_rsp); +- +- prdrfparm ->offset = offset; +- +- res = rtw_enqueue_cmd(pcmdpriv, ph2c); +- +-exit: +- +-_func_exit_; +- +- return res; +-} +- + void rtw_getbbrfreg_cmdrsp_callback(_adapter* padapter, struct cmd_obj *pcmd) + { + _func_enter_; + + //rtw_free_cmd_obj(pcmd); +- rtw_mfree((unsigned char*) pcmd->parmbuf, pcmd->cmdsz); +- rtw_mfree((unsigned char*) pcmd, sizeof(struct cmd_obj)); ++ kfree((unsigned char*) pcmd->parmbuf); ++ kfree((unsigned char*) pcmd); + + _func_exit_; + } + +-void rtw_readtssi_cmdrsp_callback(_adapter* padapter, struct cmd_obj *pcmd) +-{ +- _func_enter_; +- +- rtw_mfree((unsigned char*) pcmd->parmbuf, pcmd->cmdsz); +- rtw_mfree((unsigned char*) pcmd, sizeof(struct cmd_obj)); +- +-_func_exit_; +-} +- + u8 rtw_createbss_cmd(_adapter *padapter) + { + struct cmd_obj* pcmd; +@@ -1085,8 +813,6 @@ u8 rtw_createbss_cmd(_adapter *padapter + + _func_enter_; + +- rtw_led_control(padapter, LED_CTL_START_TO_LINK); +- + if (pmlmepriv->assoc_ssid.SsidLength == 0){ + RT_TRACE(_module_rtl871x_cmd_c_,_drv_info_,(" createbss for Any SSid:%s\n",pmlmepriv->assoc_ssid.Ssid)); + } else { +@@ -1099,7 +825,7 @@ _func_enter_; + goto exit; + } + +- _rtw_init_listhead(&pcmd->list); ++ INIT_LIST_HEAD(&pcmd->list); + pcmd->cmdcode = _CreateBss_CMD_; + pcmd->parmbuf = (unsigned char *)pdev_network; + pcmd->cmdsz = get_WLAN_BSSID_EX_sz((WLAN_BSSID_EX*)pdev_network); +@@ -1117,36 +843,6 @@ _func_exit_; + return res; + } + +-u8 rtw_createbss_cmd_ex(_adapter *padapter, unsigned char *pbss, unsigned int sz) +-{ +- struct cmd_obj* pcmd; +- struct cmd_priv *pcmdpriv=&padapter->cmdpriv; +- u8 res=_SUCCESS; +- +-_func_enter_; +- +- pcmd = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); +- if(pcmd==NULL){ +- res= _FAIL; +- goto exit; +- } +- +- _rtw_init_listhead(&pcmd->list); +- pcmd->cmdcode = GEN_CMD_CODE(_CreateBss); +- pcmd->parmbuf = pbss; +- pcmd->cmdsz = sz; +- pcmd->rsp = NULL; +- pcmd->rspsz = 0; +- +- res = rtw_enqueue_cmd(pcmdpriv, pcmd); +- +-exit: +- +-_func_exit_; +- +- return res; +-} +- + u8 rtw_startbss_cmd(_adapter *padapter, int flags) + { + struct cmd_obj* pcmd; +@@ -1167,7 +863,7 @@ _func_enter_; + goto exit; + } + +- _rtw_init_listhead(&pcmd->list); ++ INIT_LIST_HEAD(&pcmd->list); + pcmd->cmdcode = GEN_CMD_CODE(_CreateBss); + pcmd->parmbuf = NULL; + pcmd->cmdsz = 0; +@@ -1183,10 +879,11 @@ _func_enter_; + + if (res == _SUCCESS && (flags & RTW_CMDF_WAIT_ACK)) { + rtw_sctx_wait(&sctx, __func__); +- _enter_critical_mutex(&pcmdpriv->sctx_mutex, NULL); +- if (sctx.status == RTW_SCTX_SUBMITTED) +- pcmd->sctx = NULL; +- _exit_critical_mutex(&pcmdpriv->sctx_mutex, NULL); ++ if (mutex_lock_interruptible(&pcmdpriv->sctx_mutex) == 0) { ++ if (sctx.status == RTW_SCTX_SUBMITTED) ++ pcmd->sctx = NULL; ++ mutex_unlock(&pcmdpriv->sctx_mutex); ++ } + } + } + +@@ -1216,8 +913,6 @@ u8 rtw_joinbss_cmd(_adapter *padapter, + u8 *ptmp=NULL; + _func_enter_; + +- rtw_led_control(padapter, LED_CTL_START_TO_LINK); +- + if (pmlmepriv->assoc_ssid.SsidLength == 0){ + RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("+Join cmd: Any SSid\n")); + } else { +@@ -1267,7 +962,7 @@ _func_enter_; + if(psecnetwork==NULL) + { + if(pcmd !=NULL) +- rtw_mfree((unsigned char *)pcmd, sizeof(struct cmd_obj)); ++ kfree((unsigned char *)pcmd); + + res=_FAIL; + +@@ -1348,7 +1043,7 @@ _func_enter_; + + pcmd->cmdsz = get_WLAN_BSSID_EX_sz(psecnetwork);//get cmdsz before endian conversion + +- _rtw_init_listhead(&pcmd->list); ++ INIT_LIST_HEAD(&pcmd->list); + pcmd->cmdcode = _JoinBss_CMD_;//GEN_CMD_CODE(_JoinBss) + pcmd->parmbuf = (unsigned char *)psecnetwork; + pcmd->rsp = NULL; +@@ -1387,7 +1082,7 @@ _func_enter_; + cmdobj = (struct cmd_obj *)rtw_zmalloc(sizeof(*cmdobj)); + if (cmdobj == NULL) { + res = _FAIL; +- rtw_mfree((u8 *)param, sizeof(*param)); ++ kfree((u8 *)param); + goto exit; + } + init_h2fwcmd_w_parm_no_rsp(cmdobj, param, _DisConnect_CMD_); +@@ -1396,7 +1091,7 @@ _func_enter_; + /* no need to enqueue, do the cmd hdl directly and free cmd parameter */ + if (H2C_SUCCESS != disconnect_hdl(padapter, (u8 *)param)) + res = _FAIL; +- rtw_mfree((u8 *)param, sizeof(*param)); ++ kfree((u8 *)param); + } + + exit: +@@ -1426,7 +1121,7 @@ _func_enter_; + if(enqueue){ + ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); + if(ph2c==NULL){ +- rtw_mfree((u8 *)psetop, sizeof(*psetop)); ++ kfree((u8 *)psetop); + res= _FAIL; + goto exit; + } +@@ -1436,7 +1131,7 @@ _func_enter_; + } + else{ + setopmode_hdl(padapter, (u8 *)psetop); +- rtw_mfree((u8 *)psetop, sizeof(*psetop)); ++ kfree((u8 *)psetop); + } + exit: + +@@ -1486,15 +1181,15 @@ _func_enter_; + { + ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); + if ( ph2c == NULL){ +- rtw_mfree((u8 *) psetstakey_para, sizeof(struct set_stakey_parm)); ++ kfree((u8 *) psetstakey_para); + res= _FAIL; + goto exit; + } + + psetstakey_rsp = (struct set_stakey_rsp*)rtw_zmalloc(sizeof(struct set_stakey_rsp)); + if(psetstakey_rsp == NULL){ +- rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); +- rtw_mfree((u8 *) psetstakey_para, sizeof(struct set_stakey_parm)); ++ kfree((u8 *) ph2c); ++ kfree((u8 *) psetstakey_para); + res=_FAIL; + goto exit; + } +@@ -1506,7 +1201,7 @@ _func_enter_; + } + else{ + set_stakey_hdl(padapter, (u8 *)psetstakey_para); +- rtw_mfree((u8 *) psetstakey_para, sizeof(struct set_stakey_parm)); ++ kfree((u8 *) psetstakey_para); + } + exit: + +@@ -1546,15 +1241,15 @@ _func_enter_; + + psetstakey_para = (struct set_stakey_parm*)rtw_zmalloc(sizeof(struct set_stakey_parm)); + if(psetstakey_para==NULL){ +- rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); ++ kfree((u8 *) ph2c); + res=_FAIL; + goto exit; + } + + psetstakey_rsp = (struct set_stakey_rsp*)rtw_zmalloc(sizeof(struct set_stakey_rsp)); + if(psetstakey_rsp == NULL){ +- rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); +- rtw_mfree((u8 *) psetstakey_para, sizeof(struct set_stakey_parm)); ++ kfree((u8 *) ph2c); ++ kfree((u8 *) psetstakey_para); + res=_FAIL; + goto exit; + } +@@ -1578,123 +1273,6 @@ _func_exit_; + return res; + } + +-u8 rtw_setrttbl_cmd(_adapter *padapter, struct setratable_parm *prate_table) +-{ +- struct cmd_obj* ph2c; +- struct setratable_parm * psetrttblparm; +- struct cmd_priv *pcmdpriv=&padapter->cmdpriv; +- u8 res=_SUCCESS; +-_func_enter_; +- +- ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); +- if(ph2c==NULL){ +- res= _FAIL; +- goto exit; +- } +- psetrttblparm = (struct setratable_parm*)rtw_zmalloc(sizeof(struct setratable_parm)); +- +- if(psetrttblparm==NULL){ +- rtw_mfree((unsigned char *) ph2c, sizeof(struct cmd_obj)); +- res= _FAIL; +- goto exit; +- } +- +- init_h2fwcmd_w_parm_no_rsp(ph2c, psetrttblparm, GEN_CMD_CODE(_SetRaTable)); +- +- memcpy(psetrttblparm,prate_table,sizeof(struct setratable_parm)); +- +- res = rtw_enqueue_cmd(pcmdpriv, ph2c); +-exit: +-_func_exit_; +- return res; +- +-} +- +-u8 rtw_getrttbl_cmd(_adapter *padapter, struct getratable_rsp *pval) +-{ +- struct cmd_obj* ph2c; +- struct getratable_parm * pgetrttblparm; +- struct cmd_priv *pcmdpriv=&padapter->cmdpriv; +- u8 res=_SUCCESS; +-_func_enter_; +- +- ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); +- if(ph2c==NULL){ +- res= _FAIL; +- goto exit; +- } +- pgetrttblparm = (struct getratable_parm*)rtw_zmalloc(sizeof(struct getratable_parm)); +- +- if(pgetrttblparm==NULL){ +- rtw_mfree((unsigned char *) ph2c, sizeof(struct cmd_obj)); +- res= _FAIL; +- goto exit; +- } +- +-// init_h2fwcmd_w_parm_no_rsp(ph2c, psetrttblparm, GEN_CMD_CODE(_SetRaTable)); +- +- _rtw_init_listhead(&ph2c->list); +- ph2c->cmdcode =GEN_CMD_CODE(_GetRaTable); +- ph2c->parmbuf = (unsigned char *)pgetrttblparm; +- ph2c->cmdsz = sizeof(struct getratable_parm); +- ph2c->rsp = (u8*)pval; +- ph2c->rspsz = sizeof(struct getratable_rsp); +- +- pgetrttblparm ->rsvd = 0x0; +- +- res = rtw_enqueue_cmd(pcmdpriv, ph2c); +-exit: +-_func_exit_; +- return res; +- +-} +- +-u8 rtw_setassocsta_cmd(_adapter *padapter, u8 *mac_addr) +-{ +- struct cmd_priv *pcmdpriv = &padapter->cmdpriv; +- struct cmd_obj* ph2c; +- struct set_assocsta_parm *psetassocsta_para; +- struct set_stakey_rsp *psetassocsta_rsp = NULL; +- +- u8 res=_SUCCESS; +- +-_func_enter_; +- +- ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); +- if(ph2c==NULL){ +- res= _FAIL; +- goto exit; +- } +- +- psetassocsta_para = (struct set_assocsta_parm*)rtw_zmalloc(sizeof(struct set_assocsta_parm)); +- if(psetassocsta_para==NULL){ +- rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); +- res=_FAIL; +- goto exit; +- } +- +- psetassocsta_rsp = (struct set_stakey_rsp*)rtw_zmalloc(sizeof(struct set_assocsta_rsp)); +- if(psetassocsta_rsp==NULL){ +- rtw_mfree((u8 *) ph2c, sizeof(struct cmd_obj)); +- rtw_mfree((u8 *) psetassocsta_para, sizeof(struct set_assocsta_parm)); +- return _FAIL; +- } +- +- init_h2fwcmd_w_parm_no_rsp(ph2c, psetassocsta_para, _SetAssocSta_CMD_); +- ph2c->rsp = (u8 *) psetassocsta_rsp; +- ph2c->rspsz = sizeof(struct set_assocsta_rsp); +- +- memcpy(psetassocsta_para->addr, mac_addr,ETH_ALEN); +- +- res = rtw_enqueue_cmd(pcmdpriv, ph2c); +- +-exit: +- +-_func_exit_; +- +- return res; +- } +- + u8 rtw_addbareq_cmd(_adapter*padapter, u8 tid, u8 *addr) + { + struct cmd_priv *pcmdpriv = &padapter->cmdpriv; +@@ -1713,7 +1291,7 @@ _func_enter_; + + paddbareq_parm = (struct addBaReq_parm*)rtw_zmalloc(sizeof(struct addBaReq_parm)); + if(paddbareq_parm==NULL){ +- rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); ++ kfree((unsigned char *)ph2c); + res= _FAIL; + goto exit; + } +@@ -1752,7 +1330,7 @@ _func_enter_; + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if(pdrvextra_cmd_parm==NULL){ +- rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); ++ kfree((unsigned char *)ph2c); + res= _FAIL; + goto exit; + } +@@ -1793,7 +1371,7 @@ _func_enter_; + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if(pdrvextra_cmd_parm==NULL){ +- rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); ++ kfree((unsigned char *)ph2c); + res= _FAIL; + goto exit; + } +@@ -1835,7 +1413,7 @@ _func_enter_; + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if(pdrvextra_cmd_parm==NULL){ +- rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); ++ kfree((unsigned char *)ph2c); + res= _FAIL; + goto exit; + } +@@ -1858,61 +1436,6 @@ _func_exit_; + + } + +-u8 rtw_set_ch_cmd(_adapter*padapter, u8 ch, u8 bw, u8 ch_offset, u8 enqueue) +-{ +- struct cmd_obj *pcmdobj; +- struct set_ch_parm *set_ch_parm; +- struct cmd_priv *pcmdpriv = &padapter->cmdpriv; +- +- u8 res=_SUCCESS; +- +-_func_enter_; +- +- DBG_871X(FUNC_NDEV_FMT" ch:%u, bw:%u, ch_offset:%u\n", +- FUNC_NDEV_ARG(padapter->pnetdev), ch, bw, ch_offset); +- +- /* check input parameter */ +- +- /* prepare cmd parameter */ +- set_ch_parm = (struct set_ch_parm *)rtw_zmalloc(sizeof(*set_ch_parm)); +- if (set_ch_parm == NULL) { +- res= _FAIL; +- goto exit; +- } +- set_ch_parm->ch = ch; +- set_ch_parm->bw = bw; +- set_ch_parm->ch_offset = ch_offset; +- +- if (enqueue) { +- /* need enqueue, prepare cmd_obj and enqueue */ +- pcmdobj = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); +- if(pcmdobj == NULL){ +- rtw_mfree((u8 *)set_ch_parm, sizeof(*set_ch_parm)); +- res=_FAIL; +- goto exit; +- } +- +- init_h2fwcmd_w_parm_no_rsp(pcmdobj, set_ch_parm, GEN_CMD_CODE(_SetChannel)); +- res = rtw_enqueue_cmd(pcmdpriv, pcmdobj); +- } else { +- /* no need to enqueue, do the cmd hdl directly and free cmd parameter */ +- if( H2C_SUCCESS !=set_ch_hdl(padapter, (u8 *)set_ch_parm) ) +- res = _FAIL; +- +- rtw_mfree((u8 *)set_ch_parm, sizeof(*set_ch_parm)); +- } +- +- /* do something based on res... */ +- +-exit: +- +- DBG_871X(FUNC_NDEV_FMT" res:%u\n", FUNC_NDEV_ARG(padapter->pnetdev), res); +- +-_func_exit_; +- +- return res; +-} +- + u8 rtw_set_chplan_cmd(_adapter*padapter, u8 chplan, u8 enqueue, u8 swconfig) + { + struct cmd_obj* pcmdobj; +@@ -1951,7 +1474,7 @@ _func_enter_; + //need enqueue, prepare cmd_obj and enqueue + pcmdobj = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); + if(pcmdobj == NULL){ +- rtw_mfree((u8 *)setChannelPlan_param, sizeof(struct SetChannelPlan_param)); ++ kfree((u8 *)setChannelPlan_param); + res=_FAIL; + goto exit; + } +@@ -1965,7 +1488,7 @@ _func_enter_; + if( H2C_SUCCESS !=set_chplan_hdl(padapter, (unsigned char *)setChannelPlan_param) ) + res = _FAIL; + +- rtw_mfree((u8 *)setChannelPlan_param, sizeof(struct SetChannelPlan_param)); ++ kfree((u8 *)setChannelPlan_param); + } + + //do something based on res... +@@ -1979,92 +1502,6 @@ _func_exit_; + return res; + } + +-u8 rtw_led_blink_cmd(_adapter*padapter, void * pLed) +-{ +- struct cmd_obj* pcmdobj; +- struct LedBlink_param *ledBlink_param; +- struct cmd_priv *pcmdpriv = &padapter->cmdpriv; +- +- u8 res=_SUCCESS; +- +-_func_enter_; +- +- RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_led_blink_cmd\n")); +- +- pcmdobj = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); +- if(pcmdobj == NULL){ +- res=_FAIL; +- goto exit; +- } +- +- ledBlink_param = (struct LedBlink_param *)rtw_zmalloc(sizeof(struct LedBlink_param)); +- if(ledBlink_param == NULL) { +- rtw_mfree((u8 *)pcmdobj, sizeof(struct cmd_obj)); +- res= _FAIL; +- goto exit; +- } +- +- ledBlink_param->pLed=pLed; +- +- init_h2fwcmd_w_parm_no_rsp(pcmdobj, ledBlink_param, GEN_CMD_CODE(_LedBlink)); +- res = rtw_enqueue_cmd(pcmdpriv, pcmdobj); +- +-exit: +- +-_func_exit_; +- +- return res; +-} +- +-u8 rtw_set_csa_cmd(_adapter*padapter, u8 new_ch_no) +-{ +- struct cmd_obj* pcmdobj; +- struct SetChannelSwitch_param*setChannelSwitch_param; +- struct mlme_priv *pmlmepriv = &padapter->mlmepriv; +- struct cmd_priv *pcmdpriv = &padapter->cmdpriv; +- +- u8 res=_SUCCESS; +- +-_func_enter_; +- +- RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+rtw_set_csa_cmd\n")); +- +- pcmdobj = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); +- if(pcmdobj == NULL){ +- res=_FAIL; +- goto exit; +- } +- +- setChannelSwitch_param = (struct SetChannelSwitch_param *)rtw_zmalloc(sizeof(struct SetChannelSwitch_param)); +- if(setChannelSwitch_param == NULL) { +- rtw_mfree((u8 *)pcmdobj, sizeof(struct cmd_obj)); +- res= _FAIL; +- goto exit; +- } +- +- setChannelSwitch_param->new_ch_no=new_ch_no; +- +- init_h2fwcmd_w_parm_no_rsp(pcmdobj, setChannelSwitch_param, GEN_CMD_CODE(_SetChannelSwitch)); +- res = rtw_enqueue_cmd(pcmdpriv, pcmdobj); +- +-exit: +- +-_func_exit_; +- +- return res; +-} +- +-u8 rtw_tdls_cmd(_adapter *padapter, u8 *addr, u8 option) +-{ +- u8 res=_SUCCESS; +- +-_func_enter_; +- +-_func_exit_; +- +- return res; +-} +- + static void collect_traffic_statistics(_adapter *padapter) + { + struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter); +@@ -2150,8 +1587,6 @@ u8 traffic_status_watchdog(_adapter *pad + TRAFFIC_PROTECT_PERIOD_MS, + link_detect->NumTxOkInPeriod, + link_detect->NumRxUnicastOkInPeriod); +- +- rtw_lock_traffic_suspend_timeout(TRAFFIC_PROTECT_PERIOD_MS); + } + #endif + +@@ -2250,12 +1685,10 @@ static void dynamic_chk_wk_hdl(_adapter + struct mlme_priv *pmlmepriv; + pmlmepriv = &(padapter->mlmepriv); + +-#ifdef CONFIG_AP_MODE + if(check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) + { + expire_timeout_chk(padapter); + } +-#endif + + //for debug purpose + _linked_info_dump(padapter); +@@ -2370,7 +1803,7 @@ _func_enter_; + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if(pdrvextra_cmd_parm==NULL){ +- rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); ++ kfree((unsigned char *)ph2c); + res= _FAIL; + goto exit; + } +@@ -2418,7 +1851,7 @@ u8 rtw_dm_in_lps_wk_cmd(_adapter*padapte + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if(pdrvextra_cmd_parm==NULL){ +- rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); ++ kfree((unsigned char *)ph2c); + res= _FAIL; + goto exit; + } +@@ -2470,43 +1903,6 @@ static void rtw_lps_change_dtim_hdl(_ada + up(&pwrpriv->lock); + } + +-u8 rtw_lps_change_dtim_cmd(_adapter*padapter, u8 dtim) +-{ +- struct cmd_obj *ph2c; +- struct drvextra_cmd_parm *pdrvextra_cmd_parm; +- struct cmd_priv *pcmdpriv = &padapter->cmdpriv; +- u8 res = _SUCCESS; +- +- { +- ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); +- if(ph2c==NULL){ +- res= _FAIL; +- goto exit; +- } +- +- pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); +- if(pdrvextra_cmd_parm==NULL){ +- rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); +- res= _FAIL; +- goto exit; +- } +- +- pdrvextra_cmd_parm->ec_id = LPS_CHANGE_DTIM_CID; +- pdrvextra_cmd_parm->type = dtim; +- pdrvextra_cmd_parm->size = 0; +- pdrvextra_cmd_parm->pbuf = NULL; +- +- init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); +- +- res = rtw_enqueue_cmd(pcmdpriv, ph2c); +- } +- +-exit: +- +- return res; +- +-} +- + static void rtw_dm_ra_mask_hdl(_adapter *padapter, struct sta_info *psta) + { + if (psta) { +@@ -2530,7 +1926,7 @@ u8 rtw_dm_ra_mask_wk_cmd(_adapter*padapt + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if(pdrvextra_cmd_parm==NULL){ +- rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); ++ kfree((unsigned char *)ph2c); + res= _FAIL; + goto exit; + } +@@ -2583,7 +1979,7 @@ _func_enter_; + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if(pdrvextra_cmd_parm==NULL){ +- rtw_mfree((unsigned char *)ppscmd, sizeof(struct cmd_obj)); ++ kfree((unsigned char *)ppscmd); + res= _FAIL; + goto exit; + } +@@ -2604,8 +2000,6 @@ _func_exit_; + + } + +-#ifdef CONFIG_AP_MODE +- + extern u32 g_wait_hiq_empty; + + static void rtw_chk_hi_queue_hdl(_adapter *padapter) +@@ -2666,7 +2060,7 @@ u8 rtw_chk_hi_queue_cmd(_adapter*padapte + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if(pdrvextra_cmd_parm==NULL){ +- rtw_mfree((unsigned char *)ph2c, sizeof(struct cmd_obj)); ++ kfree((unsigned char *)ph2c); + res= _FAIL; + goto exit; + } +@@ -2685,7 +2079,6 @@ exit: + return res; + + } +-#endif + + struct btinfo { + u8 cid; +@@ -2751,50 +2144,6 @@ static void rtw_btinfo_hdl(_adapter *ada + rtw_btcoex_BtInfoNotify(adapter ,len+1, &buf[1]); + } + +-u8 rtw_btinfo_cmd(_adapter *adapter, u8 *buf, u16 len) +-{ +- struct cmd_obj *ph2c; +- struct drvextra_cmd_parm *pdrvextra_cmd_parm; +- u8 *btinfo; +- struct cmd_priv *pcmdpriv = &adapter->cmdpriv; +- u8 res = _SUCCESS; +- +- ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); +- if (ph2c == NULL) { +- res = _FAIL; +- goto exit; +- } +- +- pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); +- if (pdrvextra_cmd_parm == NULL) { +- rtw_mfree((u8*)ph2c, sizeof(struct cmd_obj)); +- res = _FAIL; +- goto exit; +- } +- +- btinfo = rtw_zmalloc(len); +- if (btinfo == NULL) { +- rtw_mfree((u8*)ph2c, sizeof(struct cmd_obj)); +- rtw_mfree((u8*)pdrvextra_cmd_parm, sizeof(struct drvextra_cmd_parm)); +- res = _FAIL; +- goto exit; +- } +- +- pdrvextra_cmd_parm->ec_id = BTINFO_WK_CID; +- pdrvextra_cmd_parm->type = 0; +- pdrvextra_cmd_parm->size = len; +- pdrvextra_cmd_parm->pbuf = btinfo; +- +- memcpy(btinfo, buf, len); +- +- init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra)); +- +- res = rtw_enqueue_cmd(pcmdpriv, ph2c); +- +-exit: +- return res; +-} +- + u8 rtw_c2h_packet_wk_cmd(PADAPTER padapter, u8 *pbuf, u16 length) + { + struct cmd_obj *ph2c; +@@ -2810,7 +2159,7 @@ u8 rtw_c2h_packet_wk_cmd(PADAPTER padapt + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if (pdrvextra_cmd_parm == NULL) { +- rtw_mfree((u8*)ph2c, sizeof(struct cmd_obj)); ++ kfree((u8*)ph2c); + res = _FAIL; + goto exit; + } +@@ -2845,7 +2194,7 @@ u8 rtw_c2h_wk_cmd(PADAPTER padapter, u8 + + pdrvextra_cmd_parm = (struct drvextra_cmd_parm*)rtw_zmalloc(sizeof(struct drvextra_cmd_parm)); + if (pdrvextra_cmd_parm == NULL) { +- rtw_mfree((u8*)ph2c, sizeof(struct cmd_obj)); ++ kfree((u8*)ph2c); + res = _FAIL; + goto exit; + } +@@ -2864,42 +2213,6 @@ exit: + return res; + } + +-u8 rtw_run_in_thread_cmd(PADAPTER padapter, void (*func)(void*), void* context) +-{ +- struct cmd_priv *pcmdpriv; +- struct cmd_obj *ph2c; +- struct RunInThread_param *parm; +- s32 res = _SUCCESS; +- +-_func_enter_; +- +- pcmdpriv = &padapter->cmdpriv; +- +- ph2c = (struct cmd_obj*)rtw_zmalloc(sizeof(struct cmd_obj)); +- if (NULL == ph2c) { +- res = _FAIL; +- goto exit; +- } +- +- parm = (struct RunInThread_param*)rtw_zmalloc(sizeof(struct RunInThread_param)); +- if (NULL == parm) { +- rtw_mfree((u8*)ph2c, sizeof(struct cmd_obj)); +- res = _FAIL; +- goto exit; +- } +- +- parm->func = func; +- parm->context = context; +- init_h2fwcmd_w_parm_no_rsp(ph2c, parm, GEN_CMD_CODE(_RunInThreadCMD)); +- +- res = rtw_enqueue_cmd(pcmdpriv, ph2c); +-exit: +- +-_func_exit_; +- +- return res; +-} +- + static void c2h_wk_callback(_workitem *work) + { + struct evt_priv *evtpriv = container_of(work, struct evt_priv, c2h_wk); +@@ -2916,7 +2229,7 @@ static void c2h_wk_callback(_workitem *w + } else if ((c2h_evt = (u8 *)rtw_malloc(16)) != NULL) { + /* This C2H event is not read, read & clear now */ + if (rtw_hal_c2h_evt_read(adapter, c2h_evt) != _SUCCESS) { +- rtw_mfree(c2h_evt, 16); ++ kfree(c2h_evt); + continue; + } + } +@@ -2926,14 +2239,14 @@ static void c2h_wk_callback(_workitem *w + continue; + + if (!rtw_hal_c2h_valid(adapter, c2h_evt)) { +- rtw_mfree(c2h_evt, 16); ++ kfree(c2h_evt); + continue; + } + + if (ccx_id_filter(c2h_evt) == true) { + /* Handle CCX report here */ + rtw_hal_c2h_handler(adapter, c2h_evt); +- rtw_mfree(c2h_evt, 16); ++ kfree(c2h_evt); + } else { + /* Enqueue into cmd_thread for others */ + rtw_c2h_wk_cmd(adapter, c2h_evt); +@@ -2969,11 +2282,9 @@ u8 rtw_drvextra_cmd_hdl(_adapter *padapt + case LPS_CHANGE_DTIM_CID: + rtw_lps_change_dtim_hdl(padapter, (u8)pdrvextra_cmd->type); + break; +-#ifdef CONFIG_AP_MODE + case CHECK_HIQ_WK_CID: + rtw_chk_hi_queue_hdl(padapter); + break; +-#endif //CONFIG_AP_MODE + #ifdef CONFIG_INTEL_WIDI + case INTEl_WIDI_WK_CID: + intel_widi_wk_hdl(padapter, pdrvextra_cmd->type, pdrvextra_cmd->pbuf); +@@ -3001,7 +2312,7 @@ u8 rtw_drvextra_cmd_hdl(_adapter *padapt + + if (pdrvextra_cmd->pbuf && pdrvextra_cmd->size>0) + { +- rtw_mfree(pdrvextra_cmd->pbuf, pdrvextra_cmd->size); ++ kfree(pdrvextra_cmd->pbuf); + } + + return H2C_SUCCESS; +@@ -3038,9 +2349,9 @@ _func_enter_; + + if (pcmd->res != H2C_SUCCESS) + { +- _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ spin_lock_bh(&pmlmepriv->lock); + set_fwstate(pmlmepriv, _FW_LINKED); +- _exit_critical_bh(&pmlmepriv->lock, &irqL); ++ spin_unlock_bh(&pmlmepriv->lock); + + RT_TRACE(_module_rtl871x_cmd_c_,_drv_err_,("\n ***Error: disconnect_cmd_callback Fail ***\n.")); + +@@ -3100,7 +2411,7 @@ _func_enter_; + + _cancel_timer(&pmlmepriv->assoc_timer, &timer_cancelled); + +- _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ spin_lock_bh(&pmlmepriv->lock); + + + if(check_fwstate(pmlmepriv, WIFI_AP_STATE) ) +@@ -3123,28 +2434,28 @@ _func_enter_; + _irqL irqL; + + pwlan = _rtw_alloc_network(pmlmepriv); +- _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); + if ( pwlan == NULL) + { + pwlan = rtw_get_oldest_wlan_network(&pmlmepriv->scanned_queue); + if( pwlan == NULL) + { + RT_TRACE(_module_rtl871x_cmd_c_,_drv_err_,("\n Error: can't get pwlan in rtw_joinbss_event_callback \n")); +- _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); + goto createbss_cmd_fail; + } + pwlan->last_scanned = jiffies; + } + else + { +- rtw_list_insert_tail(&(pwlan->list), &pmlmepriv->scanned_queue.queue); ++ list_add_tail(&(pwlan->list), &pmlmepriv->scanned_queue.queue); + } + + pnetwork->Length = get_WLAN_BSSID_EX_sz(pnetwork); + memcpy(&(pwlan->network), pnetwork, pnetwork->Length); + //pwlan->fixed = true; + +- //rtw_list_insert_tail(&(pwlan->list), &pmlmepriv->scanned_queue.queue); ++ //list_add_tail(&(pwlan->list), &pmlmepriv->scanned_queue.queue); + + // copy pdev_network information to pmlmepriv->cur_network + memcpy(&tgt_network->network, pnetwork, (get_WLAN_BSSID_EX_sz(pnetwork))); +@@ -3154,14 +2465,14 @@ _func_enter_; + + _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); + +- _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); + // we will set _FW_LINKED when there is one more sat to join us (rtw_stassoc_event_callback) + + } + + createbss_cmd_fail: + +- _exit_critical_bh(&pmlmepriv->lock, &irqL); ++ spin_unlock_bh(&pmlmepriv->lock); + exit: + rtw_free_cmd_obj(pcmd); + +@@ -3214,28 +2525,16 @@ _func_enter_; + + psta->aid = psta->mac_id = passocsta_rsp->cam_id; + +- _enter_critical_bh(&pmlmepriv->lock, &irqL); ++ spin_lock_bh(&pmlmepriv->lock); + + if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) && (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true)) + _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING); + + set_fwstate(pmlmepriv, _FW_LINKED); +- _exit_critical_bh(&pmlmepriv->lock, &irqL); ++ spin_unlock_bh(&pmlmepriv->lock); + + exit: + rtw_free_cmd_obj(pcmd); + + _func_exit_; + } +- +-void rtw_getrttbl_cmd_cmdrsp_callback(_adapter* padapter, struct cmd_obj *pcmd); +-void rtw_getrttbl_cmd_cmdrsp_callback(_adapter* padapter, struct cmd_obj *pcmd) +-{ +-_func_enter_; +- +- rtw_free_cmd_obj(pcmd); +- +-_func_exit_; +- +-} +- +diff -Nurp linux/3rdparty/rtl8723bs.old/core/rtw_debug.c linux/3rdparty/rtl8723bs/core/rtw_debug.c +--- linux/3rdparty/rtl8723bs.old/core/rtw_debug.c 2015-05-10 14:36:05.666667879 +0300 ++++ linux/3rdparty/rtl8723bs/core/rtw_debug.c 2015-05-07 17:46:55.000000000 +0300 +@@ -62,7 +62,7 @@ u32 GlobalDebugLevel = _drv_err_; + + void dump_drv_version(void *sel) + { +- DBG_871X_SEL_NL(sel, "%s %s\n", DRV_NAME, DRIVERVERSION); ++ DBG_871X_SEL_NL(sel, "%s %s\n", "rtl8723bs", DRIVERVERSION); + } + + void dump_log_level(void *sel) +@@ -309,7 +309,6 @@ int proc_get_mlmext_state(struct seq_fil + return 0; + } + +-#ifdef CONFIG_LAYER2_ROAMING + int proc_get_roam_flags(struct seq_file *m, void *v) + { + struct net_device *dev = m->private; +@@ -411,7 +410,6 @@ ssize_t proc_set_roam_tgt_addr(struct fi + + return count; + } +-#endif /* CONFIG_LAYER2_ROAMING */ + + int proc_get_qos_option(struct seq_file *m, void *v) + { +@@ -463,18 +461,19 @@ int proc_get_survey_info(struct seq_file + s16 notify_noise = 0; + u16 index = 0; + +- _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ spin_lock_bh(&(pmlmepriv->scanned_queue.lock)); + phead = get_list_head(queue); ++ plist = phead ? get_next(phead) : NULL; + plist = get_next(phead); + if ((!phead) || (!plist)) { +- _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); + return 0; + } + + DBG_871X_SEL_NL(m, "%5s %-17s %3s %-3s %-4s %-4s %5s %s\n","index", "bssid", "ch", "RSSI", "SdBm", "Noise", "age", "ssid"); + while(1) + { +- if (rtw_end_of_queue_search(phead,plist)== true) ++ if (phead == plist) + break; + + pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list); +@@ -504,7 +503,7 @@ int proc_get_survey_info(struct seq_file + pnetwork->network.Ssid.Ssid); + plist = get_next(plist); + } +- _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL); ++ spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); + + return 0; + } +@@ -1325,9 +1324,6 @@ ssize_t proc_set_rssi_disp(struct file * + + } + +- +-#ifdef CONFIG_AP_MODE +- + int proc_get_all_sta_info(struct seq_file *m, void *v) + { + struct net_device *dev = m->private; +@@ -1341,14 +1337,14 @@ int proc_get_all_sta_info(struct seq_fil + + DBG_871X_SEL_NL(m, "sta_dz_bitmap=0x%x, tim_bitmap=0x%x\n", pstapriv->sta_dz_bitmap, pstapriv->tim_bitmap); + +- _enter_critical_bh(&pstapriv->sta_hash_lock, &irqL); ++ spin_lock_bh(&pstapriv->sta_hash_lock); + + for(i=0; i< NUM_STA; i++) + { + phead = &(pstapriv->sta_hash[i]); + plist = get_next(phead); + +- while ((rtw_end_of_queue_search(phead, plist)) == false) ++ while (phead != plist) + { + psta = LIST_CONTAINOR(plist, struct sta_info, hash_list); + +@@ -1394,12 +1390,10 @@ int proc_get_all_sta_info(struct seq_fil + + } + +- _exit_critical_bh(&pstapriv->sta_hash_lock, &irqL); ++ spin_unlock_bh(&pstapriv->sta_hash_lock); + + return 0; + } +- +-#endif + + int proc_get_btcoex_dbg(struct seq_file *m, void *v) + { +@@ -1497,7 +1491,7 @@ int proc_get_btcoex_info(struct seq_file + + DBG_871X_SEL(m, "%s\n", pbuf); + +- rtw_mfree(pbuf, bufsize); ++ kfree(pbuf); + + return 0; + } +diff -Nurp linux/3rdparty/rtl8723bs.old/core/rtw_eeprom.c linux/3rdparty/rtl8723bs/core/rtw_eeprom.c +--- linux/3rdparty/rtl8723bs.old/core/rtw_eeprom.c 2015-05-10 14:36:05.666667879 +0300 ++++ linux/3rdparty/rtl8723bs/core/rtw_eeprom.c 1970-01-01 02:00:00.000000000 +0200 +@@ -1,381 +0,0 @@ +-/****************************************************************************** +- * +- * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms of version 2 of the GNU General Public License as +- * published by the Free Software Foundation. +- * +- * 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., +- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA +- * +- * +- ******************************************************************************/ +-#define _RTW_EEPROM_C_ +- +-#include +-#include +-#include +- +-void up_clk(_adapter* padapter, u16 *x) +-{ +-_func_enter_; +- *x = *x | _EESK; +- rtw_write8(padapter, EE_9346CR, (u8)*x); +- udelay(CLOCK_RATE); +- +-_func_exit_; +- +-} +- +-void down_clk(_adapter * padapter, u16 *x ) +-{ +-_func_enter_; +- *x = *x & ~_EESK; +- rtw_write8(padapter, EE_9346CR, (u8)*x); +- udelay(CLOCK_RATE); +-_func_exit_; +-} +- +-void shift_out_bits(_adapter * padapter, u16 data, u16 count) +-{ +- u16 x,mask; +-_func_enter_; +- +- if(padapter->bSurpriseRemoved==true){ +- RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==true")); +- goto out; +- } +- mask = 0x01 << (count - 1); +- x = rtw_read8(padapter, EE_9346CR); +- +- x &= ~(_EEDO | _EEDI); +- +- do +- { +- x &= ~_EEDI; +- if(data & mask) +- x |= _EEDI; +- if(padapter->bSurpriseRemoved==true){ +- RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==true")); +- goto out; +- } +- rtw_write8(padapter, EE_9346CR, (u8)x); +- udelay(CLOCK_RATE); +- up_clk(padapter, &x); +- down_clk(padapter, &x); +- mask = mask >> 1; +- } while(mask); +- if(padapter->bSurpriseRemoved==true){ +- RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==true")); +- goto out; +- } +- x &= ~_EEDI; +- rtw_write8(padapter, EE_9346CR, (u8)x); +-out: +-_func_exit_; +-} +- +-u16 shift_in_bits (_adapter * padapter) +-{ +- u16 x,d=0,i; +-_func_enter_; +- if(padapter->bSurpriseRemoved==true){ +- RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==true")); +- goto out; +- } +- x = rtw_read8(padapter, EE_9346CR); +- +- x &= ~( _EEDO | _EEDI); +- d = 0; +- +- for(i=0; i<16; i++) +- { +- d = d << 1; +- up_clk(padapter, &x); +- if(padapter->bSurpriseRemoved==true){ +- RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==true")); +- goto out; +- } +- x = rtw_read8(padapter, EE_9346CR); +- +- x &= ~(_EEDI); +- if(x & _EEDO) +- d |= 1; +- +- down_clk(padapter, &x); +- } +-out: +-_func_exit_; +- +- return d; +-} +- +-void standby(_adapter * padapter ) +-{ +- u8 x; +-_func_enter_; +- x = rtw_read8(padapter, EE_9346CR); +- +- x &= ~(_EECS | _EESK); +- rtw_write8(padapter, EE_9346CR,x); +- +- udelay(CLOCK_RATE); +- x |= _EECS; +- rtw_write8(padapter, EE_9346CR, x); +- udelay(CLOCK_RATE); +-_func_exit_; +-} +- +-u16 wait_eeprom_cmd_done(_adapter* padapter) +-{ +- u8 x; +- u16 i,res=false; +-_func_enter_; +- standby(padapter ); +- for (i=0; i<200; i++) +- { +- x = rtw_read8(padapter, EE_9346CR); +- if (x & _EEDO){ +- res=true; +- goto exit; +- } +- udelay(CLOCK_RATE); +- } +-exit: +-_func_exit_; +- return res; +-} +- +-void eeprom_clean(_adapter * padapter) +-{ +- u16 x; +-_func_enter_; +- if(padapter->bSurpriseRemoved==true){ +- RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==true")); +- goto out; +- } +- x = rtw_read8(padapter, EE_9346CR); +- if(padapter->bSurpriseRemoved==true){ +- RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==true")); +- goto out; +- } +- x &= ~(_EECS | _EEDI); +- rtw_write8(padapter, EE_9346CR, (u8)x); +- if(padapter->bSurpriseRemoved==true){ +- RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==true")); +- goto out; +- } +- up_clk(padapter, &x); +- if(padapter->bSurpriseRemoved==true){ +- RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==true")); +- goto out; +- } +- down_clk(padapter, &x); +-out: +-_func_exit_; +-} +- +-void eeprom_write16(_adapter * padapter, u16 reg, u16 data) +-{ +- u8 x; +- +-_func_enter_; +- +- x = rtw_read8(padapter, EE_9346CR); +- +- x &= ~(_EEDI | _EEDO | _EESK | _EEM0); +- x |= _EEM1 | _EECS; +- rtw_write8(padapter, EE_9346CR, x); +- +- shift_out_bits(padapter, EEPROM_EWEN_OPCODE, 5); +- +- if(padapter->EepromAddressSize==8) //CF+ and SDIO +- shift_out_bits(padapter, 0, 6); +- else //USB +- shift_out_bits(padapter, 0, 4); +- +- standby( padapter); +- +-// Commented out by rcnjko, 2004.0 +-// // Erase this particular word. Write the erase opcode and register +-// // number in that order. The opcode is 3bits in length; reg is 6 bits long. +-// shift_out_bits(Adapter, EEPROM_ERASE_OPCODE, 3); +-// shift_out_bits(Adapter, reg, Adapter->EepromAddressSize); +-// +-// if (wait_eeprom_cmd_done(Adapter ) == false) +-// { +-// return; +-// } +- +- +- standby(padapter ); +- +- // write the new word to the EEPROM +- +- // send the write opcode the EEPORM +- shift_out_bits(padapter, EEPROM_WRITE_OPCODE, 3); +- +- // select which word in the EEPROM that we are writing to. +- shift_out_bits(padapter, reg, padapter->EepromAddressSize); +- +- // write the data to the selected EEPROM word. +- shift_out_bits(padapter, data, 16); +- +- if (wait_eeprom_cmd_done(padapter ) == false) +- { +- +- goto exit; +- } +- +- standby(padapter ); +- +- shift_out_bits(padapter, EEPROM_EWDS_OPCODE, 5); +- shift_out_bits(padapter, reg, 4); +- +- eeprom_clean(padapter ); +-exit: +-_func_exit_; +- return; +-} +- +-u16 eeprom_read16(_adapter * padapter, u16 reg) //ReadEEprom +-{ +- +- u16 x; +- u16 data=0; +- +-_func_enter_; +- +- if(padapter->bSurpriseRemoved==true){ +- RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==true")); +- goto out; +- } +- // select EEPROM, reset bits, set _EECS +- x = rtw_read8(padapter, EE_9346CR); +- +- if(padapter->bSurpriseRemoved==true){ +- RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==true")); +- goto out; +- } +- +- x &= ~(_EEDI | _EEDO | _EESK | _EEM0); +- x |= _EEM1 | _EECS; +- rtw_write8(padapter, EE_9346CR, (unsigned char)x); +- +- // write the read opcode and register number in that order +- // The opcode is 3bits in length, reg is 6 bits long +- shift_out_bits(padapter, EEPROM_READ_OPCODE, 3); +- shift_out_bits(padapter, reg, padapter->EepromAddressSize); +- +- // Now read the data (16 bits) in from the selected EEPROM word +- data = shift_in_bits(padapter); +- +- eeprom_clean(padapter); +-out: +-_func_exit_; +- return data; +- +- +-} +- +- +- +- +-//From even offset +-void eeprom_read_sz(_adapter * padapter, u16 reg, u8* data, u32 sz) +-{ +- +- u16 x, data16; +- u32 i; +-_func_enter_; +- if(padapter->bSurpriseRemoved==true){ +- RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==true")); +- goto out; +- } +- // select EEPROM, reset bits, set _EECS +- x = rtw_read8(padapter, EE_9346CR); +- +- if(padapter->bSurpriseRemoved==true){ +- RT_TRACE(_module_rtl871x_eeprom_c_,_drv_err_,("padapter->bSurpriseRemoved==true")); +- goto out; +- } +- +- x &= ~(_EEDI | _EEDO | _EESK | _EEM0); +- x |= _EEM1 | _EECS; +- rtw_write8(padapter, EE_9346CR, (unsigned char)x); +- +- // write the read opcode and register number in that order +- // The opcode is 3bits in length, reg is 6 bits long +- shift_out_bits(padapter, EEPROM_READ_OPCODE, 3); +- shift_out_bits(padapter, reg, padapter->EepromAddressSize); +- +- +- for(i=0; i>8; +- } +- +- eeprom_clean(padapter); +-out: +-_func_exit_; +- +- +- +-} +- +- +-//addr_off : address offset of the entry in eeprom (not the tuple number of eeprom (reg); that is addr_off !=reg) +-u8 eeprom_read(_adapter * padapter, u32 addr_off, u8 sz, u8* rbuf) +-{ +- u8 quotient, remainder, addr_2align_odd; +- u16 reg, stmp , i=0, idx = 0; +-_func_enter_; +- reg = (u16)(addr_off >> 1); +- addr_2align_odd = (u8)(addr_off & 0x1); +- +- if(addr_2align_odd) //read that start at high part: e.g 1,3,5,7,9,... +- { +- stmp = eeprom_read16(padapter, reg); +- rbuf[idx++] = (u8) ((stmp>>8)&0xff); //return hogh-part of the short +- reg++; sz--; +- } +- +- quotient = sz >> 1; +- remainder = sz & 0x1; +- +- for( i=0 ; i < quotient; i++) +- { +- stmp = eeprom_read16(padapter, reg+i); +- rbuf[idx++] = (u8) (stmp&0xff); +- rbuf[idx++] = (u8) ((stmp>>8)&0xff); +- } +- +- reg = reg+i; +- if(remainder){ //end of read at lower part of short : 0,2,4,6,... +- stmp = eeprom_read16(padapter, reg); +- rbuf[idx] = (u8)(stmp & 0xff); +- } +-_func_exit_; +- return true; +-} +- +- +- +-void read_eeprom_content(_adapter * padapter) +-{ +- +-_func_enter_; +- +- +-_func_exit_; +-} +- +diff -Nurp linux/3rdparty/rtl8723bs.old/core/rtw_efuse.c linux/3rdparty/rtl8723bs/core/rtw_efuse.c +--- linux/3rdparty/rtl8723bs.old/core/rtw_efuse.c 2015-05-10 14:36:05.666667879 +0300 ++++ linux/3rdparty/rtl8723bs/core/rtw_efuse.c 2015-05-07 17:46:55.000000000 +0300 +@@ -121,18 +121,8 @@ Efuse_PowerSwitch( + pAdapter->HalFunc.EfusePowerSwitch(pAdapter, bWrite, PwrState); + } + +-void +-BTEfuse_PowerSwitch( +- IN PADAPTER pAdapter, +- IN u8 bWrite, +- IN u8 PwrState) +-{ +- if(pAdapter->HalFunc.BTEfusePowerSwitch) +- pAdapter->HalFunc.BTEfusePowerSwitch(pAdapter, bWrite, PwrState); +-} +- + /*----------------------------------------------------------------------------- +- * Function: efuse_GetCurrentSize ++ * Function: Efuse_GetCurrentSize + * + * Overview: Get current efuse size!!! + * +@@ -174,68 +164,6 @@ Efuse_CalculateWordCnts(IN u8 word_en) + + // + // Description: +-// Execute E-Fuse read byte operation. +-// Refered from SD1 Richard. +-// +-// Assumption: +-// 1. Boot from E-Fuse and successfully auto-load. +-// 2. PASSIVE_LEVEL (USB interface) +-// +-// Created by Roger, 2008.10.21. +-// +-void +-ReadEFuseByte( +- PADAPTER Adapter, +- u16 _offset, +- u8 *pbuf, +- IN bool bPseudoTest) +-{ +- u32 value32; +- u8 readbyte; +- u16 retry; +- +- if(bPseudoTest) +- { +- Efuse_Read1ByteFromFakeContent(Adapter, _offset, pbuf); +- return; +- } +- // <20130121, Kordan> For SMIC S55 EFUSE specificatoin. +- //0x34[11]: SW force PGMEN input of efuse to high. (for the bank selected by 0x34[9:8]) +- PHY_SetMacReg(Adapter, EFUSE_TEST, BIT11, 0); +- +- //Write Address +- rtw_write8(Adapter, EFUSE_CTRL+1, (_offset & 0xff)); +- readbyte = rtw_read8(Adapter, EFUSE_CTRL+2); +- rtw_write8(Adapter, EFUSE_CTRL+2, ((_offset >> 8) & 0x03) | (readbyte & 0xfc)); +- +- //Write bit 32 0 +- readbyte = rtw_read8(Adapter, EFUSE_CTRL+3); +- rtw_write8(Adapter, EFUSE_CTRL+3, (readbyte & 0x7f)); +- +- //Check bit 32 read-ready +- retry = 0; +- value32 = rtw_read32(Adapter, EFUSE_CTRL); +- //while(!(((value32 >> 24) & 0xff) & 0x80) && (retry<10)) +- while(!(((value32 >> 24) & 0xff) & 0x80) && (retry<10000)) +- { +- value32 = rtw_read32(Adapter, EFUSE_CTRL); +- retry++; +- } +- +- // 20100205 Joseph: Add delay suggested by SD1 Victor. +- // This fix the problem that Efuse read error in high temperature condition. +- // Designer says that there shall be some delay after ready bit is set, or the +- // result will always stay on last data we read. +- udelay(50); +- value32 = rtw_read32(Adapter, EFUSE_CTRL); +- +- *pbuf = (u8)(value32 & 0xff); +- //DBG_871X("ReadEFuseByte _offset:%08u, in %d ms\n",_offset ,jiffies_to_msecs(jiffies - start)); +- +-} +- +-// +-// Description: + // 1. Execute E-Fuse read byte operation according as map offset and + // save to E-Fuse table. + // 2. Refered from SD1 Richard. +@@ -350,76 +278,6 @@ EFUSE_Read1Byte( + + }/* EFUSE_Read1Byte */ + +-/*----------------------------------------------------------------------------- +- * Function: EFUSE_Write1Byte +- * +- * Overview: Copy from WMAC fot EFUSE write 1 byte. +- * +- * Input: NONE +- * +- * Output: NONE +- * +- * Return: NONE +- * +- * Revised History: +- * When Who Remark +- * 09/23/2008 MHC Copy from WMAC. +- * +- *---------------------------------------------------------------------------*/ +- +-void +-EFUSE_Write1Byte( +- IN PADAPTER Adapter, +- IN u16 Address, +- IN u8 Value); +-void +-EFUSE_Write1Byte( +- IN PADAPTER Adapter, +- IN u16 Address, +- IN u8 Value) +-{ +- u8 Bytetemp = {0x00}; +- u8 temp = {0x00}; +- u32 k=0; +- u16 contentLen=0; +- +- //RT_TRACE(COMP_EFUSE, DBG_LOUD, ("Addr=%x Data =%x\n", Address, Value)); +- EFUSE_GetEfuseDefinition(Adapter, EFUSE_WIFI , TYPE_EFUSE_REAL_CONTENT_LEN, (void *)&contentLen, false); +- +- if( Address < contentLen) //E-fuse 512Byte +- { +- rtw_write8(Adapter, EFUSE_CTRL, Value); +- +- //Write E-fuse Register address bit0~7 +- temp = Address & 0xFF; +- rtw_write8(Adapter, EFUSE_CTRL+1, temp); +- Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+2); +- +- //Write E-fuse Register address bit8~9 +- temp = ((Address >> 8) & 0x03) | (Bytetemp & 0xFC); +- rtw_write8(Adapter, EFUSE_CTRL+2, temp); +- +- //Write 0x30[31]=1 +- Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3); +- temp = Bytetemp | 0x80; +- rtw_write8(Adapter, EFUSE_CTRL+3, temp); +- +- //Wait Write-ready (0x30[31]=0) +- Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3); +- while(Bytetemp & 0x80) +- { +- Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3); +- k++; +- if(k==100) +- { +- k=0; +- break; +- } +- } +- } +-}/* EFUSE_Write1Byte */ +- +- + /* 11/16/2008 MH Read one byte from real Efuse. */ + u8 + efuse_OneByteRead( +@@ -642,289 +500,6 @@ Efuse_WordEnableDataWrite( IN PADAPTER p + return ret; + } + +-static u8 efuse_read8(PADAPTER padapter, u16 address, u8 *value) +-{ +- return efuse_OneByteRead(padapter,address, value, false); +-} +- +-static u8 efuse_write8(PADAPTER padapter, u16 address, u8 *value) +-{ +- return efuse_OneByteWrite(padapter,address, *value, false); +-} +- +-/* +- * read/wirte raw efuse data +- */ +-u8 rtw_efuse_access(PADAPTER padapter, u8 bWrite, u16 start_addr, u16 cnts, u8 *data) +-{ +- int i = 0; +- u16 real_content_len = 0, max_available_size = 0; +- u8 res = _FAIL ; +- u8 (*rw8)(PADAPTER, u16, u8*); +- +- EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_REAL_CONTENT_LEN, (void *)&real_content_len, false); +- EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_available_size, false); +- +- if (start_addr > real_content_len) +- return _FAIL; +- +- if (true == bWrite) { +- if ((start_addr + cnts) > max_available_size) +- return _FAIL; +- rw8 = &efuse_write8; +- } else +- rw8 = &efuse_read8; +- +- Efuse_PowerSwitch(padapter, bWrite, true); +- +- // e-fuse one byte read / write +- for (i = 0; i < cnts; i++) { +- if (start_addr >= real_content_len) { +- res = _FAIL; +- break; +- } +- +- res = rw8(padapter, start_addr++, data++); +- if (_FAIL == res) break; +- } +- +- Efuse_PowerSwitch(padapter, bWrite, false); +- +- return res; +-} +-//------------------------------------------------------------------------------ +-u16 efuse_GetMaxSize(PADAPTER padapter) +-{ +- u16 max_size; +- EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI , TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, (void *)&max_size, false); +- return max_size; +-} +-//------------------------------------------------------------------------------ +-u8 efuse_GetCurrentSize(PADAPTER padapter, u16 *size) +-{ +- Efuse_PowerSwitch(padapter, false, true); +- *size = Efuse_GetCurrentSize(padapter, EFUSE_WIFI, false); +- Efuse_PowerSwitch(padapter, false, false); +- +- return _SUCCESS; +-} +-//------------------------------------------------------------------------------ +-u8 rtw_efuse_map_read(PADAPTER padapter, u16 addr, u16 cnts, u8 *data) +-{ +- u16 mapLen=0; +- +- EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false); +- +- if ((addr + cnts) > mapLen) +- return _FAIL; +- +- Efuse_PowerSwitch(padapter, false, true); +- +- efuse_ReadEFuse(padapter, EFUSE_WIFI, addr, cnts, data, false); +- +- Efuse_PowerSwitch(padapter, false, false); +- +- return _SUCCESS; +-} +- +-u8 rtw_BT_efuse_map_read(PADAPTER padapter, u16 addr, u16 cnts, u8 *data) +-{ +- u16 mapLen=0; +- +- EFUSE_GetEfuseDefinition(padapter, EFUSE_BT, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false); +- +- if ((addr + cnts) > mapLen) +- return _FAIL; +- +- Efuse_PowerSwitch(padapter, false, true); +- +- efuse_ReadEFuse(padapter, EFUSE_BT, addr, cnts, data, false); +- +- Efuse_PowerSwitch(padapter, false, false); +- +- return _SUCCESS; +-} +-//------------------------------------------------------------------------------ +-u8 rtw_efuse_map_write(PADAPTER padapter, u16 addr, u16 cnts, u8 *data) +-{ +-#define RT_ASSERT_RET(expr) \ +- if(!(expr)) { \ +- printk( "Assertion failed! %s at ......\n", #expr); \ +- printk( " ......%s,%s,line=%d\n",__FILE__,__FUNCTION__,__LINE__); \ +- return _FAIL; \ +- } +- +- u8 offset, word_en; +- u8 *map; +- u8 newdata[PGPKT_DATA_SIZE]; +- s32 i, j, idx; +- u8 ret = _SUCCESS; +- u16 mapLen=0; +- EEPROM_EFUSE_PRIV *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); +- HAL_DATA_TYPE *pHalData = GET_HAL_DATA(padapter); +- +- EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, false); +- +- if ((addr + cnts) > mapLen) +- return _FAIL; +- +- RT_ASSERT_RET(PGPKT_DATA_SIZE == 8); // have to be 8 byte alignment +- RT_ASSERT_RET((mapLen & 0x7) == 0); // have to be PGPKT_DATA_SIZE alignment for memcpy +- +- map = rtw_zmalloc(mapLen); +- if(map == NULL){ +- return _FAIL; +- } +- +- memset(map, 0xFF, mapLen); +- +- ret = rtw_efuse_map_read(padapter, 0, mapLen, map); +- if (ret == _FAIL) goto exit; +- +- Efuse_PowerSwitch(padapter, true, true); +- +- idx = 0; +- offset = (addr >> 3); +- while (idx < cnts) +- { +- word_en = 0xF; +- j = (addr + idx) & 0x7; +- memcpy(newdata, &map[offset << 3], PGPKT_DATA_SIZE); +- for (i = j; i> 1); +- newdata[i] = data[idx]; +- +- if( addr + idx == 0x8) +- { +- if (IS_C_CUT(pHalData->VersionID) || IS_B_CUT(pHalData->VersionID)) +- { +- if(pEEPROM->adjuseVoltageVal == 6) +- { +- newdata[i] = map[addr + idx]; +- DBG_8192C(" %s ,\n adjuseVoltageVal = %d ,newdata[%d] = %x \n",__func__,pEEPROM->adjuseVoltageVal,i,newdata[i]); +- } +- } +- } +- } +- } +- +- if (word_en != 0xF) { +- ret = Efuse_PgPacketWrite(padapter, offset, word_en, newdata, false); +- DBG_871X("offset=%x \n",offset); +- DBG_871X("word_en=%x \n",word_en); +- +- for(i=0;i mapLen) +- return _FAIL; +- +- RT_ASSERT_RET(PGPKT_DATA_SIZE == 8); // have to be 8 byte alignment +- RT_ASSERT_RET((mapLen & 0x7) == 0); // have to be PGPKT_DATA_SIZE alignment for memcpy +- +- map = rtw_zmalloc(mapLen); +- if(map == NULL){ +- return _FAIL; +- } +- +- ret = rtw_BT_efuse_map_read(padapter, 0, mapLen, map); +- if (ret == _FAIL) goto exit; +- DBG_871X("OFFSET\tVALUE(hex)\n"); +- for (i=0; i<1024; i+=16) // set 512 because the iwpriv's extra size have limit 0x7FF +- { +- DBG_871X("0x%03x\t", i); +- for (j=0; j<8; j++) { +- DBG_871X("%02X ", map[i+j]); +- } +- DBG_871X("\t"); +- for (; j<16; j++) { +- DBG_871X("%02X ", map[i+j]); +- } +- DBG_871X("\n"); +- } +- DBG_871X("\n"); +- Efuse_PowerSwitch(padapter, true, true); +- +- idx = 0; +- offset = (addr >> 3); +- while (idx < cnts) +- { +- word_en = 0xF; +- j = (addr + idx) & 0x7; +- memcpy(newdata, &map[offset << 3], PGPKT_DATA_SIZE); +- for (i = j; i> 1); +- newdata[i] = data[idx]; +- } +- } +- +- if (word_en != 0xF) { +- DBG_871X("offset=%x \n",offset); +- DBG_871X("word_en=%x \n",word_en); +- DBG_871X("%s: data=", __FUNCTION__); +- for(i=0;i