* [PATCH 01/23] Staging: add TAINT_CRAP for all drivers/staging code
2008-10-10 22:41 [GIT PATCH] STAGING patches for 2.6.28 Greg KH
@ 2008-10-10 22:42 ` Greg KH
2008-10-10 22:42 ` [PATCH 02/23] Staging: add TAINT_CRAP flag to drivers/staging modules Greg KH
` (18 subsequent siblings)
19 siblings, 0 replies; 37+ messages in thread
From: Greg KH @ 2008-10-10 22:42 UTC (permalink / raw)
To: linux-kernel; +Cc: Greg Kroah-Hartman, Andreas Gruenbacher, Jeff Mahoney
From: Greg Kroah-Hartman <gregkh@suse.de>
We need to add a flag for all code that is in the drivers/staging/
directory to prevent all other kernel developers from worrying about
issues here, and to notify users that the drivers might not be as good
as they are normally used to.
Based on code from Andreas Gruenbacher and Jeff Mahoney to provide a
TAINT flag for the support level of a kernel module in the Novell
enterprise kernel release.
This is the kernel portion of this feature, the ability for the flag to
be set needs to be done in the build process and will happen in a
follow-up patch.
Cc: Andreas Gruenbacher <agruen@suse.de>
Cc: Jeff Mahoney <jeffm@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
Documentation/sysctl/kernel.txt | 1 +
include/linux/kernel.h | 1 +
kernel/module.c | 11 +++++++++++
kernel/panic.c | 6 ++++--
4 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
index e1ff0d9..bde799e 100644
--- a/Documentation/sysctl/kernel.txt
+++ b/Documentation/sysctl/kernel.txt
@@ -369,4 +369,5 @@ can be ORed together:
2 - A module was force loaded by insmod -f.
Set by modutils >= 2.4.9 and module-init-tools.
4 - Unsafe SMP processors: SMP with CPUs not designed for SMP.
+ 64 - A module from drivers/staging was loaded.
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 2651f80..b36805c 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -260,6 +260,7 @@ extern enum system_states {
#define TAINT_DIE (1<<7)
#define TAINT_OVERRIDDEN_ACPI_TABLE (1<<8)
#define TAINT_WARN (1<<9)
+#define TAINT_CRAP (1<<10)
extern void dump_stack(void) __cold;
diff --git a/kernel/module.c b/kernel/module.c
index 9db1191..152b165 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1806,6 +1806,7 @@ static noinline struct module *load_module(void __user *umod,
Elf_Ehdr *hdr;
Elf_Shdr *sechdrs;
char *secstrings, *args, *modmagic, *strtab = NULL;
+ char *staging;
unsigned int i;
unsigned int symindex = 0;
unsigned int strindex = 0;
@@ -1960,6 +1961,14 @@ static noinline struct module *load_module(void __user *umod,
goto free_hdr;
}
+ staging = get_modinfo(sechdrs, infoindex, "staging");
+ if (staging) {
+ add_taint_module(mod, TAINT_CRAP);
+ printk(KERN_WARNING "%s: module is from the staging directory,"
+ " the quality is unknown, you have been warned.\n",
+ mod->name);
+ }
+
/* Now copy in args */
args = strndup_user(uargs, ~0UL >> 1);
if (IS_ERR(args)) {
@@ -2556,6 +2565,8 @@ static char *module_flags(struct module *mod, char *buf)
buf[bx++] = 'P';
if (mod->taints & TAINT_FORCED_MODULE)
buf[bx++] = 'F';
+ if (mod->taints & TAINT_CRAP)
+ buf[bx++] = 'C';
/*
* TAINT_FORCED_RMMOD: could be added.
* TAINT_UNSAFE_SMP, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't
diff --git a/kernel/panic.c b/kernel/panic.c
index 12c5a0a..98e2047 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -155,6 +155,7 @@ EXPORT_SYMBOL(panic);
* 'U' - Userspace-defined naughtiness.
* 'A' - ACPI table overridden.
* 'W' - Taint on warning.
+ * 'C' - modules from drivers/staging are loaded.
*
* The string is overwritten by the next call to print_taint().
*/
@@ -163,7 +164,7 @@ const char *print_tainted(void)
{
static char buf[20];
if (tainted) {
- snprintf(buf, sizeof(buf), "Tainted: %c%c%c%c%c%c%c%c%c%c",
+ snprintf(buf, sizeof(buf), "Tainted: %c%c%c%c%c%c%c%c%c%c%c",
tainted & TAINT_PROPRIETARY_MODULE ? 'P' : 'G',
tainted & TAINT_FORCED_MODULE ? 'F' : ' ',
tainted & TAINT_UNSAFE_SMP ? 'S' : ' ',
@@ -173,7 +174,8 @@ const char *print_tainted(void)
tainted & TAINT_USER ? 'U' : ' ',
tainted & TAINT_DIE ? 'D' : ' ',
tainted & TAINT_OVERRIDDEN_ACPI_TABLE ? 'A' : ' ',
- tainted & TAINT_WARN ? 'W' : ' ');
+ tainted & TAINT_WARN ? 'W' : ' ',
+ tainted & TAINT_CRAP ? 'C' : ' ');
}
else
snprintf(buf, sizeof(buf), "Not tainted");
--
1.6.0.2
^ permalink raw reply related [flat|nested] 37+ messages in thread* [PATCH 02/23] Staging: add TAINT_CRAP flag to drivers/staging modules
2008-10-10 22:41 [GIT PATCH] STAGING patches for 2.6.28 Greg KH
2008-10-10 22:42 ` [PATCH 01/23] Staging: add TAINT_CRAP for all drivers/staging code Greg KH
@ 2008-10-10 22:42 ` Greg KH
2008-10-10 22:42 ` [PATCH 03/23] Staging: add Kconfig entries and Makefile infrastructure Greg KH
` (17 subsequent siblings)
19 siblings, 0 replies; 37+ messages in thread
From: Greg KH @ 2008-10-10 22:42 UTC (permalink / raw)
To: linux-kernel; +Cc: Greg Kroah-Hartman, Andreas Gruenbacher, Jeff Mahoney
From: Greg Kroah-Hartman <gregkh@suse.de>
We need to add a flag for all code that is in the drivers/staging/
directory to prevent all other kernel developers from worrying about
issues here, and to notify users that the drivers might not be as good
as they are normally used to.
Based on code from Andreas Gruenbacher and Jeff Mahoney to provide a
TAINT flag for the support level of a kernel module in the Novell
enterprise kernel release.
This is the code that actually modifies the modules, adding the flag to
any files in the drivers/staging directory.
Cc: Andreas Gruenbacher <agruen@suse.de>
Cc: Jeff Mahoney <jeffm@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
scripts/mod/modpost.c | 9 +++++++++
1 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 8e0de6a..8892161 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -1726,6 +1726,14 @@ static void add_header(struct buffer *b, struct module *mod)
buf_printf(b, "};\n");
}
+void add_staging_flag(struct buffer *b, const char *name)
+{
+ static const char *staging_dir = "drivers/staging";
+
+ if (strncmp(staging_dir, name, strlen(staging_dir)) == 0)
+ buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
+}
+
/**
* Record CRCs for unresolved symbols
**/
@@ -2135,6 +2143,7 @@ int main(int argc, char **argv)
buf.pos = 0;
add_header(&buf, mod);
+ add_staging_flag(&buf, mod->name);
err |= add_versions(&buf, mod);
add_depends(&buf, mod, modules);
add_moddevtable(&buf, mod);
--
1.6.0.2
^ permalink raw reply related [flat|nested] 37+ messages in thread* [PATCH 03/23] Staging: add Kconfig entries and Makefile infrastructure
2008-10-10 22:41 [GIT PATCH] STAGING patches for 2.6.28 Greg KH
2008-10-10 22:42 ` [PATCH 01/23] Staging: add TAINT_CRAP for all drivers/staging code Greg KH
2008-10-10 22:42 ` [PATCH 02/23] Staging: add TAINT_CRAP flag to drivers/staging modules Greg KH
@ 2008-10-10 22:42 ` Greg KH
2008-10-10 22:42 ` [PATCH 04/23] Staging: add MAINTAINERS entry Greg KH
` (16 subsequent siblings)
19 siblings, 0 replies; 37+ messages in thread
From: Greg KH @ 2008-10-10 22:42 UTC (permalink / raw)
To: linux-kernel; +Cc: Greg Kroah-Hartman
From: Greg Kroah-Hartman <gregkh@suse.de>
This hooks up the drivers/staging directory to the build system
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/Kconfig | 2 ++
drivers/Makefile | 1 +
drivers/staging/Kconfig | 27 +++++++++++++++++++++++++++
drivers/staging/Makefile | 2 ++
4 files changed, 32 insertions(+), 0 deletions(-)
create mode 100644 drivers/staging/Kconfig
create mode 100644 drivers/staging/Makefile
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 59f33fa..d19b6f5 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -101,4 +101,6 @@ source "drivers/auxdisplay/Kconfig"
source "drivers/uio/Kconfig"
source "drivers/xen/Kconfig"
+
+source "drivers/staging/Kconfig"
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 2735bde..46c8681 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -99,3 +99,4 @@ obj-$(CONFIG_OF) += of/
obj-$(CONFIG_SSB) += ssb/
obj-$(CONFIG_VIRTIO) += virtio/
obj-$(CONFIG_REGULATOR) += regulator/
+obj-$(CONFIG_STAGING) += staging/
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
new file mode 100644
index 0000000..84832fe
--- /dev/null
+++ b/drivers/staging/Kconfig
@@ -0,0 +1,27 @@
+menuconfig STAGING
+ bool "Staging drivers"
+ default n
+ ---help---
+ This option allows you to select a number of drivers that are
+ not of the "normal" Linux kernel quality level. These drivers
+ are placed here in order to get a wider audience for use of
+ them. Please note that these drivers are under heavy
+ development, may or may not work, and may contain userspace
+ interfaces that most likely will be changed in the near
+ future.
+
+ Using any of these drivers will taint your kernel which might
+ affect support options from both the community, and various
+ commercial support orginizations.
+
+ If you wish to work on these drivers, to help improve them, or
+ to report problems you have with them, please see the
+ driver_name.README file in the drivers/staging/ directory to
+ see what needs to be worked on, and who to contact.
+
+ If in doubt, say N here.
+
+if STAGING
+
+
+endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
new file mode 100644
index 0000000..ceb0328
--- /dev/null
+++ b/drivers/staging/Makefile
@@ -0,0 +1,2 @@
+# Makefile for staging directory
+
--
1.6.0.2
^ permalink raw reply related [flat|nested] 37+ messages in thread* [PATCH 04/23] Staging: add MAINTAINERS entry
2008-10-10 22:41 [GIT PATCH] STAGING patches for 2.6.28 Greg KH
` (2 preceding siblings ...)
2008-10-10 22:42 ` [PATCH 03/23] Staging: add Kconfig entries and Makefile infrastructure Greg KH
@ 2008-10-10 22:42 ` Greg KH
2008-10-10 22:42 ` [PATCH 05/23] Staging: add et131x network driver Greg KH
` (15 subsequent siblings)
19 siblings, 0 replies; 37+ messages in thread
From: Greg KH @ 2008-10-10 22:42 UTC (permalink / raw)
To: linux-kernel; +Cc: Greg Kroah-Hartman
From: Greg Kroah-Hartman <gregkh@suse.de>
Someone has to claim this mess, might as well let everyone know who to
blame.
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
MAINTAINERS | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index 7a03bd5..ea6b478 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3863,6 +3863,13 @@ M: chrisw@sous-sol.org
L: stable@kernel.org
S: Maintained
+STAGING SUBSYSTEM:
+P: Greg Kroah-Hartman
+M: gregkh@suse.de
+L: linux-kernel@vger.kernel.org
+T: quilt kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
+S: Maintained
+
SHARP LH SUPPORT (LH7952X & LH7A40X)
P: Marc Singer
M: elf@buici.com
--
1.6.0.2
^ permalink raw reply related [flat|nested] 37+ messages in thread* [PATCH 05/23] Staging: add et131x network driver
2008-10-10 22:41 [GIT PATCH] STAGING patches for 2.6.28 Greg KH
` (3 preceding siblings ...)
2008-10-10 22:42 ` [PATCH 04/23] Staging: add MAINTAINERS entry Greg KH
@ 2008-10-10 22:42 ` Greg KH
2008-10-10 22:42 ` [PATCH 09/23] Staging: add me4000 pci data collection driver Greg KH
` (14 subsequent siblings)
19 siblings, 0 replies; 37+ messages in thread
From: Greg KH @ 2008-10-10 22:42 UTC (permalink / raw)
To: linux-kernel
Cc: Greg Kroah-Hartman, Olaf Hartmann, Christoph Hellwig, Dean Adams,
Victor Soriano, Andre-Sebastian Liebe
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 451124 bytes --]
From: Greg Kroah-Hartman <gregkh@suse.de>
This is a driver for the ET1310 network device.
Based on the driver found at https://sourceforge.net/projects/et131x/
Cleaned up immensely by Olaf Hartman <o.hartmann@telovital.com> and Christoph
Hellwig <hch@infradead.org>
Note, the powermanagement options were removed from the vendor provided
driver as they did not build properly at the time.
TODO:
- kernel coding style cleanups
- forward port for latest network driver changes
- kill useless typecasts (e.g. in et1310_phy.c)
- alloc_etherdev is initializing memory with zero?!?
- add_timer call in et131x_netdev.c is correct?
- Add power saving functionality (suspend, sleep, resume)
- Implement a few more kernel Parameter (set mac )
Cc: Olaf Hartmann <o.hartmann@telovital.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Dean Adams <dadams1969@gmail.com>
Cc: Victor Soriano <vjsoriano@agere.com>
Cc: Andre-Sebastian Liebe <andre@lianse.eu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/Kconfig | 1 +
drivers/staging/Makefile | 1 +
drivers/staging/et131x/Kconfig | 18 +
drivers/staging/et131x/Makefile | 18 +
drivers/staging/et131x/README | 25 +
drivers/staging/et131x/et1310_address_map.h | 2399 +++++++++++++++++++++++++++
drivers/staging/et131x/et1310_eeprom.c | 480 ++++++
drivers/staging/et131x/et1310_eeprom.h | 89 +
drivers/staging/et131x/et1310_jagcore.c | 220 +++
drivers/staging/et131x/et1310_jagcore.h | 112 ++
drivers/staging/et131x/et1310_mac.c | 792 +++++++++
drivers/staging/et131x/et1310_mac.h | 93 +
drivers/staging/et131x/et1310_phy.c | 1281 ++++++++++++++
drivers/staging/et131x/et1310_phy.h | 910 ++++++++++
drivers/staging/et131x/et1310_pm.c | 207 +++
drivers/staging/et131x/et1310_pm.h | 125 ++
drivers/staging/et131x/et1310_rx.c | 1391 ++++++++++++++++
drivers/staging/et131x/et1310_rx.h | 373 +++++
drivers/staging/et131x/et1310_tx.c | 1525 +++++++++++++++++
drivers/staging/et131x/et1310_tx.h | 242 +++
drivers/staging/et131x/et131x_adapter.h | 347 ++++
drivers/staging/et131x/et131x_config.c | 325 ++++
drivers/staging/et131x/et131x_config.h | 67 +
drivers/staging/et131x/et131x_debug.c | 218 +++
drivers/staging/et131x/et131x_debug.h | 201 +++
drivers/staging/et131x/et131x_defs.h | 128 ++
drivers/staging/et131x/et131x_initpci.c | 1046 ++++++++++++
drivers/staging/et131x/et131x_initpci.h | 73 +
drivers/staging/et131x/et131x_isr.c | 488 ++++++
drivers/staging/et131x/et131x_isr.h | 65 +
drivers/staging/et131x/et131x_netdev.c | 856 ++++++++++
drivers/staging/et131x/et131x_netdev.h | 64 +
drivers/staging/et131x/et131x_version.h | 81 +
33 files changed, 14261 insertions(+), 0 deletions(-)
create mode 100644 drivers/staging/et131x/Kconfig
create mode 100644 drivers/staging/et131x/Makefile
create mode 100644 drivers/staging/et131x/README
create mode 100644 drivers/staging/et131x/et1310_address_map.h
create mode 100644 drivers/staging/et131x/et1310_eeprom.c
create mode 100644 drivers/staging/et131x/et1310_eeprom.h
create mode 100644 drivers/staging/et131x/et1310_jagcore.c
create mode 100644 drivers/staging/et131x/et1310_jagcore.h
create mode 100644 drivers/staging/et131x/et1310_mac.c
create mode 100644 drivers/staging/et131x/et1310_mac.h
create mode 100644 drivers/staging/et131x/et1310_phy.c
create mode 100644 drivers/staging/et131x/et1310_phy.h
create mode 100644 drivers/staging/et131x/et1310_pm.c
create mode 100644 drivers/staging/et131x/et1310_pm.h
create mode 100644 drivers/staging/et131x/et1310_rx.c
create mode 100644 drivers/staging/et131x/et1310_rx.h
create mode 100644 drivers/staging/et131x/et1310_tx.c
create mode 100644 drivers/staging/et131x/et1310_tx.h
create mode 100644 drivers/staging/et131x/et131x_adapter.h
create mode 100644 drivers/staging/et131x/et131x_config.c
create mode 100644 drivers/staging/et131x/et131x_config.h
create mode 100644 drivers/staging/et131x/et131x_debug.c
create mode 100644 drivers/staging/et131x/et131x_debug.h
create mode 100644 drivers/staging/et131x/et131x_defs.h
create mode 100644 drivers/staging/et131x/et131x_initpci.c
create mode 100644 drivers/staging/et131x/et131x_initpci.h
create mode 100644 drivers/staging/et131x/et131x_isr.c
create mode 100644 drivers/staging/et131x/et131x_isr.h
create mode 100644 drivers/staging/et131x/et131x_netdev.c
create mode 100644 drivers/staging/et131x/et131x_netdev.h
create mode 100644 drivers/staging/et131x/et131x_version.h
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 84832fe..4c3789d 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -23,5 +23,6 @@ menuconfig STAGING
if STAGING
+source "drivers/staging/et131x/Kconfig"
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index ceb0328..933b984 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -1,2 +1,3 @@
# Makefile for staging directory
+obj-$(CONFIG_ET131X) += et131x/
diff --git a/drivers/staging/et131x/Kconfig b/drivers/staging/et131x/Kconfig
new file mode 100644
index 0000000..e11cf34
--- /dev/null
+++ b/drivers/staging/et131x/Kconfig
@@ -0,0 +1,18 @@
+config ET131X
+ tristate "Agere ET-1310 Gigabit Ethernet support"
+ depends on NETDEV_1000 && PCI
+ default n
+ ---help---
+ This driver supports Agere ET-1310 ethernet adapters.
+
+ To compile this driver as a module, choose M here. The module
+ will be called et131x.
+
+config ET131X_DEBUG
+ bool "Enable et131x debugging"
+ depends on ET131X
+ default n
+ ---help---
+ Say Y for detailed debug information.
+
+ If in doubt, say N.
diff --git a/drivers/staging/et131x/Makefile b/drivers/staging/et131x/Makefile
new file mode 100644
index 0000000..3ad571d
--- /dev/null
+++ b/drivers/staging/et131x/Makefile
@@ -0,0 +1,18 @@
+#
+# Makefile for the Agere ET-131x ethernet driver
+#
+
+obj-$(CONFIG_ET131X) += et131x.o
+
+et131x-objs := et1310_eeprom.o \
+ et1310_jagcore.o \
+ et1310_mac.o \
+ et1310_phy.o \
+ et1310_pm.o \
+ et1310_rx.o \
+ et1310_tx.o \
+ et131x_config.o \
+ et131x_debug.o \
+ et131x_initpci.o \
+ et131x_isr.o \
+ et131x_netdev.o
diff --git a/drivers/staging/et131x/README b/drivers/staging/et131x/README
new file mode 100644
index 0000000..28752a5
--- /dev/null
+++ b/drivers/staging/et131x/README
@@ -0,0 +1,25 @@
+This is a driver for the ET1310 network device.
+
+Based on the driver found at https://sourceforge.net/projects/et131x/
+
+Cleaned up immensely by Olaf Hartman <o.hartmann@telovital.com> and Christoph
+Hellwig <hch@infradead.org>
+
+Note, the powermanagement options were removed from the vendor provided
+driver as they did not build properly at the time.
+
+TODO:
+ - kernel coding style cleanups
+ - forward port for latest network driver changes
+ - kill useless typecasts (e.g. in et1310_phy.c)
+ - alloc_etherdev is initializing memory with zero?!?
+ - add_timer call in et131x_netdev.c is correct?
+ - Add power saving functionality (suspend, sleep, resume)
+ - Implement a few more kernel Parameter (set mac )
+
+Please send patches to:
+ Greg Kroah-Hartman <gregkh@suse.de>
+
+And Cc: Olaf Hartmann <o.hartmann@telovital.com> as he has this device and can
+test any changes.
+
diff --git a/drivers/staging/et131x/et1310_address_map.h b/drivers/staging/et131x/et1310_address_map.h
new file mode 100644
index 0000000..3c85999
--- /dev/null
+++ b/drivers/staging/et131x/et1310_address_map.h
@@ -0,0 +1,2399 @@
+/*
+ * Agere Systems Inc.
+ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * et1310_address_map.h - Contains the register mapping for the ET1310
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#ifndef _ET1310_ADDRESS_MAP_H_
+#define _ET1310_ADDRESS_MAP_H_
+
+
+/* START OF GLOBAL REGISTER ADDRESS MAP */
+
+typedef union _Q_ADDR_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused:22; // bits 10-31
+ u32 addr:10; // bits 0-9
+#else
+ u32 addr:10; // bits 0-9
+ u32 unused:22; // bits 10-31
+#endif
+ } bits;
+} Q_ADDR_t, *PQ_ADDR_t;
+
+/*
+ * structure for tx queue start address reg in global address map
+ * located at address 0x0000
+ * Defined earlier (Q_ADDR_t)
+ */
+
+/*
+ * structure for tx queue end address reg in global address map
+ * located at address 0x0004
+ * Defined earlier (Q_ADDR_t)
+ */
+
+/*
+ * structure for rx queue start address reg in global address map
+ * located at address 0x0008
+ * Defined earlier (Q_ADDR_t)
+ */
+
+/*
+ * structure for rx queue end address reg in global address map
+ * located at address 0x000C
+ * Defined earlier (Q_ADDR_t)
+ */
+
+/*
+ * structure for power management control status reg in global address map
+ * located at address 0x0010
+ */
+typedef union _PM_CSR_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused:22; // bits 10-31
+ u32 pm_jagcore_rx_rdy:1; // bit 9
+ u32 pm_jagcore_tx_rdy:1; // bit 8
+ u32 pm_phy_lped_en:1; // bit 7
+ u32 pm_phy_sw_coma:1; // bit 6
+ u32 pm_rxclk_gate:1; // bit 5
+ u32 pm_txclk_gate:1; // bit 4
+ u32 pm_sysclk_gate:1; // bit 3
+ u32 pm_jagcore_rx_en:1; // bit 2
+ u32 pm_jagcore_tx_en:1; // bit 1
+ u32 pm_gigephy_en:1; // bit 0
+#else
+ u32 pm_gigephy_en:1; // bit 0
+ u32 pm_jagcore_tx_en:1; // bit 1
+ u32 pm_jagcore_rx_en:1; // bit 2
+ u32 pm_sysclk_gate:1; // bit 3
+ u32 pm_txclk_gate:1; // bit 4
+ u32 pm_rxclk_gate:1; // bit 5
+ u32 pm_phy_sw_coma:1; // bit 6
+ u32 pm_phy_lped_en:1; // bit 7
+ u32 pm_jagcore_tx_rdy:1; // bit 8
+ u32 pm_jagcore_rx_rdy:1; // bit 9
+ u32 unused:22; // bits 10-31
+#endif
+ } bits;
+} PM_CSR_t, *PPM_CSR_t;
+
+/*
+ * structure for interrupt status reg in global address map
+ * located at address 0x0018
+ */
+typedef union _INTERRUPT_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused5:11; // bits 21-31
+ u32 slv_timeout:1; // bit 20
+ u32 mac_stat_interrupt:1; // bit 19
+ u32 rxmac_interrupt:1; // bit 18
+ u32 txmac_interrupt:1; // bit 17
+ u32 phy_interrupt:1; // bit 16
+ u32 wake_on_lan:1; // bit 15
+ u32 watchdog_interrupt:1; // bit 14
+ u32 unused4:4; // bits 10-13
+ u32 rxdma_err:1; // bit 9
+ u32 rxdma_pkt_stat_ring_low:1; // bit 8
+ u32 rxdma_fb_ring1_low:1; // bit 7
+ u32 rxdma_fb_ring0_low:1; // bit 6
+ u32 rxdma_xfr_done:1; // bit 5
+ u32 txdma_err:1; // bit 4
+ u32 txdma_isr:1; // bit 3
+ u32 unused3:1; // bit 2
+ u32 unused2:1; // bit 1
+ u32 unused1:1; // bit 0
+#else
+ u32 unused1:1; // bit 0
+ u32 unused2:1; // bit 1
+ u32 unused3:1; // bit 2
+ u32 txdma_isr:1; // bit 3
+ u32 txdma_err:1; // bit 4
+ u32 rxdma_xfr_done:1; // bit 5
+ u32 rxdma_fb_ring0_low:1; // bit 6
+ u32 rxdma_fb_ring1_low:1; // bit 7
+ u32 rxdma_pkt_stat_ring_low:1; // bit 8
+ u32 rxdma_err:1; // bit 9
+ u32 unused4:4; // bits 10-13
+ u32 watchdog_interrupt:1; // bit 14
+ u32 wake_on_lan:1; // bit 15
+ u32 phy_interrupt:1; // bit 16
+ u32 txmac_interrupt:1; // bit 17
+ u32 rxmac_interrupt:1; // bit 18
+ u32 mac_stat_interrupt:1; // bit 19
+ u32 slv_timeout:1; // bit 20
+ u32 unused5:11; // bits 21-31
+#endif
+ } bits;
+} INTERRUPT_t, *PINTERRUPT_t;
+
+/*
+ * structure for interrupt mask reg in global address map
+ * located at address 0x001C
+ * Defined earlier (INTERRUPT_t), but 'watchdog_interrupt' is not used.
+ */
+
+/*
+ * structure for interrupt alias clear mask reg in global address map
+ * located at address 0x0020
+ * Defined earlier (INTERRUPT_t)
+ */
+
+/*
+ * structure for interrupt status alias reg in global address map
+ * located at address 0x0024
+ * Defined earlier (INTERRUPT_t)
+ */
+
+/*
+ * structure for software reset reg in global address map
+ * located at address 0x0028
+ */
+typedef union _SW_RESET_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 selfclr_disable:1; // bit 31
+ u32 unused:24; // bits 7-30
+ u32 mmc_sw_reset:1; // bit 6
+ u32 mac_stat_sw_reset:1; // bit 5
+ u32 mac_sw_reset:1; // bit 4
+ u32 rxmac_sw_reset:1; // bit 3
+ u32 txmac_sw_reset:1; // bit 2
+ u32 rxdma_sw_reset:1; // bit 1
+ u32 txdma_sw_reset:1; // bit 0
+#else
+ u32 txdma_sw_reset:1; // bit 0
+ u32 rxdma_sw_reset:1; // bit 1
+ u32 txmac_sw_reset:1; // bit 2
+ u32 rxmac_sw_reset:1; // bit 3
+ u32 mac_sw_reset:1; // bit 4
+ u32 mac_stat_sw_reset:1; // bit 5
+ u32 mmc_sw_reset:1; // bit 6
+ u32 unused:24; // bits 7-30
+ u32 selfclr_disable:1; // bit 31
+#endif
+ } bits;
+} SW_RESET_t, *PSW_RESET_t;
+
+/*
+ * structure for SLV Timer reg in global address map
+ * located at address 0x002C
+ */
+typedef union _SLV_TIMER_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused:8; // bits 24-31
+ u32 timer_ini:24; // bits 0-23
+#else
+ u32 timer_ini:24; // bits 0-23
+ u32 unused:8; // bits 24-31
+#endif
+ } bits;
+} SLV_TIMER_t, *PSLV_TIMER_t;
+
+/*
+ * structure for MSI Configuration reg in global address map
+ * located at address 0x0030
+ */
+typedef union _MSI_CONFIG_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused1:13; // bits 19-31
+ u32 msi_tc:3; // bits 16-18
+ u32 unused2:11; // bits 5-15
+ u32 msi_vector:5; // bits 0-4
+#else
+ u32 msi_vector:5; // bits 0-4
+ u32 unused2:11; // bits 5-15
+ u32 msi_tc:3; // bits 16-18
+ u32 unused1:13; // bits 19-31
+#endif
+ } bits;
+} MSI_CONFIG_t, *PMSI_CONFIG_t;
+
+/*
+ * structure for Loopback reg in global address map
+ * located at address 0x0034
+ */
+typedef union _LOOPBACK_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused:30; // bits 2-31
+ u32 dma_loopback:1; // bit 1
+ u32 mac_loopback:1; // bit 0
+#else
+ u32 mac_loopback:1; // bit 0
+ u32 dma_loopback:1; // bit 1
+ u32 unused:30; // bits 2-31
+#endif
+ } bits;
+} LOOPBACK_t, *PLOOPBACK_t;
+
+/*
+ * GLOBAL Module of JAGCore Address Mapping
+ * Located at address 0x0000
+ */
+typedef struct _GLOBAL_t { // Location:
+ Q_ADDR_t txq_start_addr; // 0x0000
+ Q_ADDR_t txq_end_addr; // 0x0004
+ Q_ADDR_t rxq_start_addr; // 0x0008
+ Q_ADDR_t rxq_end_addr; // 0x000C
+ PM_CSR_t pm_csr; // 0x0010
+ u32 unused; // 0x0014
+ INTERRUPT_t int_status; // 0x0018
+ INTERRUPT_t int_mask; // 0x001C
+ INTERRUPT_t int_alias_clr_en; // 0x0020
+ INTERRUPT_t int_status_alias; // 0x0024
+ SW_RESET_t sw_reset; // 0x0028
+ SLV_TIMER_t slv_timer; // 0x002C
+ MSI_CONFIG_t msi_config; // 0x0030
+ LOOPBACK_t loopback; // 0x0034
+ u32 watchdog_timer; // 0x0038
+} GLOBAL_t, *PGLOBAL_t;
+
+/* END OF GLOBAL REGISTER ADDRESS MAP */
+
+
+/* START OF TXDMA REGISTER ADDRESS MAP */
+
+/*
+ * structure for txdma control status reg in txdma address map
+ * located at address 0x1000
+ */
+typedef union _TXDMA_CSR_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused2:19; // bits 13-31
+ u32 traffic_class:4; // bits 9-12
+ u32 sngl_epkt_mode:1; // bit 8
+ u32 cache_thrshld:4; // bits 4-7
+ u32 unused1:2; // bits 2-3
+ u32 drop_TLP_disable:1; // bit 1
+ u32 halt:1; // bit 0
+#else
+ u32 halt:1; // bit 0
+ u32 drop_TLP_disable:1; // bit 1
+ u32 unused1:2; // bits 2-3
+ u32 cache_thrshld:4; // bits 4-7
+ u32 sngl_epkt_mode:1; // bit 8
+ u32 traffic_class:4; // bits 9-12
+ u32 unused2:19; // bits 13-31
+#endif
+ } bits;
+} TXDMA_CSR_t, *PTXDMA_CSR_t;
+
+/*
+ * structure for txdma packet ring base address hi reg in txdma address map
+ * located at address 0x1004
+ * Defined earlier (u32)
+ */
+
+/*
+ * structure for txdma packet ring base address low reg in txdma address map
+ * located at address 0x1008
+ * Defined earlier (u32)
+ */
+
+/*
+ * structure for txdma packet ring number of descriptor reg in txdma address
+ * map. Located at address 0x100C
+ */
+typedef union _TXDMA_PR_NUM_DES_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused:22; // bits 10-31
+ u32 pr_ndes:10; // bits 0-9
+#else
+ u32 pr_ndes:10; // bits 0-9
+ u32 unused:22; // bits 10-31
+#endif
+ } bits;
+} TXDMA_PR_NUM_DES_t, *PTXDMA_PR_NUM_DES_t;
+
+
+typedef union _DMA10W_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused:21; // bits 11-31
+ u32 wrap:1; // bit 10
+ u32 val:10; // bits 0-9
+#else
+ u32 val:10; // bits 0-9
+ u32 wrap:1; // bit 10
+ u32 unused:21; // bits 11-31
+#endif
+ } bits;
+} DMA10W_t, *PDMA10W_t;
+
+/*
+ * structure for txdma tx queue write address reg in txdma address map
+ * located at address 0x1010
+ * Defined earlier (DMA10W_t)
+ */
+
+/*
+ * structure for txdma tx queue write address external reg in txdma address map
+ * located at address 0x1014
+ * Defined earlier (DMA10W_t)
+ */
+
+/*
+ * structure for txdma tx queue read address reg in txdma address map
+ * located at address 0x1018
+ * Defined earlier (DMA10W_t)
+ */
+
+/*
+ * structure for txdma status writeback address hi reg in txdma address map
+ * located at address 0x101C
+ * Defined earlier (u32)
+ */
+
+/*
+ * structure for txdma status writeback address lo reg in txdma address map
+ * located at address 0x1020
+ * Defined earlier (u32)
+ */
+
+/*
+ * structure for txdma service request reg in txdma address map
+ * located at address 0x1024
+ * Defined earlier (DMA10W_t)
+ */
+
+/*
+ * structure for txdma service complete reg in txdma address map
+ * located at address 0x1028
+ * Defined earlier (DMA10W_t)
+ */
+
+typedef union _DMA4W_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused:27; // bits 5-31
+ u32 wrap:1; // bit 4
+ u32 val:4; // bit 0-3
+#else
+ u32 val:4; // bits 0-3
+ u32 wrap:1; // bit 4
+ u32 unused:27; // bits 5-31
+#endif
+ } bits;
+} DMA4W_t, *PDMA4W_t;
+
+/*
+ * structure for txdma tx descriptor cache read index reg in txdma address map
+ * located at address 0x102C
+ * Defined earlier (DMA4W_t)
+ */
+
+/*
+ * structure for txdma tx descriptor cache write index reg in txdma address map
+ * located at address 0x1030
+ * Defined earlier (DMA4W_t)
+ */
+
+/*
+ * structure for txdma error reg in txdma address map
+ * located at address 0x1034
+ */
+typedef union _TXDMA_ERROR_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused3:22; // bits 10-31
+ u32 WrbkRewind:1; // bit 9
+ u32 WrbkResend:1; // bit 8
+ u32 unused2:2; // bits 6-7
+ u32 DescrRewind:1; // bit 5
+ u32 DescrResend:1; // bit 4
+ u32 unused1:2; // bits 2-3
+ u32 PyldRewind:1; // bit 1
+ u32 PyldResend:1; // bit 0
+#else
+ u32 PyldResend:1; // bit 0
+ u32 PyldRewind:1; // bit 1
+ u32 unused1:2; // bits 2-3
+ u32 DescrResend:1; // bit 4
+ u32 DescrRewind:1; // bit 5
+ u32 unused2:2; // bits 6-7
+ u32 WrbkResend:1; // bit 8
+ u32 WrbkRewind:1; // bit 9
+ u32 unused3:22; // bits 10-31
+#endif
+ } bits;
+} TXDMA_ERROR_t, *PTXDMA_ERROR_t;
+
+/*
+ * Tx DMA Module of JAGCore Address Mapping
+ * Located at address 0x1000
+ */
+typedef struct _TXDMA_t { // Location:
+ TXDMA_CSR_t csr; // 0x1000
+ u32 pr_base_hi; // 0x1004
+ u32 pr_base_lo; // 0x1008
+ TXDMA_PR_NUM_DES_t pr_num_des; // 0x100C
+ DMA10W_t txq_wr_addr; // 0x1010
+ DMA10W_t txq_wr_addr_ext; // 0x1014
+ DMA10W_t txq_rd_addr; // 0x1018
+ u32 dma_wb_base_hi; // 0x101C
+ u32 dma_wb_base_lo; // 0x1020
+ DMA10W_t service_request; // 0x1024
+ DMA10W_t service_complete; // 0x1028
+ DMA4W_t cache_rd_index; // 0x102C
+ DMA4W_t cache_wr_index; // 0x1030
+ TXDMA_ERROR_t TxDmaError; // 0x1034
+ u32 DescAbortCount; // 0x1038
+ u32 PayloadAbortCnt; // 0x103c
+ u32 WriteBackAbortCnt; // 0x1040
+ u32 DescTimeoutCnt; // 0x1044
+ u32 PayloadTimeoutCnt; // 0x1048
+ u32 WriteBackTimeoutCnt; // 0x104c
+ u32 DescErrorCount; // 0x1050
+ u32 PayloadErrorCnt; // 0x1054
+ u32 WriteBackErrorCnt; // 0x1058
+ u32 DroppedTLPCount; // 0x105c
+ DMA10W_t NewServiceComplete; // 0x1060
+ u32 EthernetPacketCount; // 0x1064
+} TXDMA_t, *PTXDMA_t;
+
+/* END OF TXDMA REGISTER ADDRESS MAP */
+
+
+/* START OF RXDMA REGISTER ADDRESS MAP */
+
+/*
+ * structure for control status reg in rxdma address map
+ * Located at address 0x2000
+ */
+typedef union _RXDMA_CSR_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused2:14; // bits 18-31
+ u32 halt_status:1; // bit 17
+ u32 pkt_done_flush:1; // bit 16
+ u32 pkt_drop_disable:1; // bit 15
+ u32 unused1:1; // bit 14
+ u32 fbr1_enable:1; // bit 13
+ u32 fbr1_size:2; // bits 11-12
+ u32 fbr0_enable:1; // bit 10
+ u32 fbr0_size:2; // bits 8-9
+ u32 dma_big_endian:1; // bit 7
+ u32 pkt_big_endian:1; // bit 6
+ u32 psr_big_endian:1; // bit 5
+ u32 fbr_big_endian:1; // bit 4
+ u32 tc:3; // bits 1-3
+ u32 halt:1; // bit 0
+#else
+ u32 halt:1; // bit 0
+ u32 tc:3; // bits 1-3
+ u32 fbr_big_endian:1; // bit 4
+ u32 psr_big_endian:1; // bit 5
+ u32 pkt_big_endian:1; // bit 6
+ u32 dma_big_endian:1; // bit 7
+ u32 fbr0_size:2; // bits 8-9
+ u32 fbr0_enable:1; // bit 10
+ u32 fbr1_size:2; // bits 11-12
+ u32 fbr1_enable:1; // bit 13
+ u32 unused1:1; // bit 14
+ u32 pkt_drop_disable:1; // bit 15
+ u32 pkt_done_flush:1; // bit 16
+ u32 halt_status:1; // bit 17
+ u32 unused2:14; // bits 18-31
+#endif
+ } bits;
+} RXDMA_CSR_t, *PRXDMA_CSR_t;
+
+/*
+ * structure for dma writeback lo reg in rxdma address map
+ * located at address 0x2004
+ * Defined earlier (u32)
+ */
+
+/*
+ * structure for dma writeback hi reg in rxdma address map
+ * located at address 0x2008
+ * Defined earlier (u32)
+ */
+
+/*
+ * structure for number of packets done reg in rxdma address map
+ * located at address 0x200C
+ */
+typedef union _RXDMA_NUM_PKT_DONE_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused:24; // bits 8-31
+ u32 num_done:8; // bits 0-7
+#else
+ u32 num_done:8; // bits 0-7
+ u32 unused:24; // bits 8-31
+#endif
+ } bits;
+} RXDMA_NUM_PKT_DONE_t, *PRXDMA_NUM_PKT_DONE_t;
+
+/*
+ * structure for max packet time reg in rxdma address map
+ * located at address 0x2010
+ */
+typedef union _RXDMA_MAX_PKT_TIME_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused:14; // bits 18-31
+ u32 time_done:18; // bits 0-17
+#else
+ u32 time_done:18; // bits 0-17
+ u32 unused:14; // bits 18-31
+#endif
+ } bits;
+} RXDMA_MAX_PKT_TIME_t, *PRXDMA_MAX_PKT_TIME_t;
+
+/*
+ * structure for rx queue read address reg in rxdma address map
+ * located at address 0x2014
+ * Defined earlier (DMA10W_t)
+ */
+
+/*
+ * structure for rx queue read address external reg in rxdma address map
+ * located at address 0x2018
+ * Defined earlier (DMA10W_t)
+ */
+
+/*
+ * structure for rx queue write address reg in rxdma address map
+ * located at address 0x201C
+ * Defined earlier (DMA10W_t)
+ */
+
+/*
+ * structure for packet status ring base address lo reg in rxdma address map
+ * located at address 0x2020
+ * Defined earlier (u32)
+ */
+
+/*
+ * structure for packet status ring base address hi reg in rxdma address map
+ * located at address 0x2024
+ * Defined earlier (u32)
+ */
+
+/*
+ * structure for packet status ring number of descriptors reg in rxdma address
+ * map. Located at address 0x2028
+ */
+typedef union _RXDMA_PSR_NUM_DES_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused:20; // bits 12-31
+ u32 psr_ndes:12; // bit 0-11
+#else
+ u32 psr_ndes:12; // bit 0-11
+ u32 unused:20; // bits 12-31
+#endif
+ } bits;
+} RXDMA_PSR_NUM_DES_t, *PRXDMA_PSR_NUM_DES_t;
+
+/*
+ * structure for packet status ring available offset reg in rxdma address map
+ * located at address 0x202C
+ */
+typedef union _RXDMA_PSR_AVAIL_OFFSET_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused:19; // bits 13-31
+ u32 psr_avail_wrap:1; // bit 12
+ u32 psr_avail:12; // bit 0-11
+#else
+ u32 psr_avail:12; // bit 0-11
+ u32 psr_avail_wrap:1; // bit 12
+ u32 unused:19; // bits 13-31
+#endif
+ } bits;
+} RXDMA_PSR_AVAIL_OFFSET_t, *PRXDMA_PSR_AVAIL_OFFSET_t;
+
+/*
+ * structure for packet status ring full offset reg in rxdma address map
+ * located at address 0x2030
+ */
+typedef union _RXDMA_PSR_FULL_OFFSET_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused:19; // bits 13-31
+ u32 psr_full_wrap:1; // bit 12
+ u32 psr_full:12; // bit 0-11
+#else
+ u32 psr_full:12; // bit 0-11
+ u32 psr_full_wrap:1; // bit 12
+ u32 unused:19; // bits 13-31
+#endif
+ } bits;
+} RXDMA_PSR_FULL_OFFSET_t, *PRXDMA_PSR_FULL_OFFSET_t;
+
+/*
+ * structure for packet status ring access index reg in rxdma address map
+ * located at address 0x2034
+ */
+typedef union _RXDMA_PSR_ACCESS_INDEX_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused:27; // bits 5-31
+ u32 psr_ai:5; // bits 0-4
+#else
+ u32 psr_ai:5; // bits 0-4
+ u32 unused:27; // bits 5-31
+#endif
+ } bits;
+} RXDMA_PSR_ACCESS_INDEX_t, *PRXDMA_PSR_ACCESS_INDEX_t;
+
+/*
+ * structure for packet status ring minimum descriptors reg in rxdma address
+ * map. Located at address 0x2038
+ */
+typedef union _RXDMA_PSR_MIN_DES_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused:20; // bits 12-31
+ u32 psr_min:12; // bits 0-11
+#else
+ u32 psr_min:12; // bits 0-11
+ u32 unused:20; // bits 12-31
+#endif
+ } bits;
+} RXDMA_PSR_MIN_DES_t, *PRXDMA_PSR_MIN_DES_t;
+
+/*
+ * structure for free buffer ring base lo address reg in rxdma address map
+ * located at address 0x203C
+ * Defined earlier (u32)
+ */
+
+/*
+ * structure for free buffer ring base hi address reg in rxdma address map
+ * located at address 0x2040
+ * Defined earlier (u32)
+ */
+
+/*
+ * structure for free buffer ring number of descriptors reg in rxdma address
+ * map. Located at address 0x2044
+ */
+typedef union _RXDMA_FBR_NUM_DES_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused:22; // bits 10-31
+ u32 fbr_ndesc:10; // bits 0-9
+#else
+ u32 fbr_ndesc:10; // bits 0-9
+ u32 unused:22; // bits 10-31
+#endif
+ } bits;
+} RXDMA_FBR_NUM_DES_t, *PRXDMA_FBR_NUM_DES_t;
+
+/*
+ * structure for free buffer ring 0 available offset reg in rxdma address map
+ * located at address 0x2048
+ * Defined earlier (DMA10W_t)
+ */
+
+/*
+ * structure for free buffer ring 0 full offset reg in rxdma address map
+ * located at address 0x204C
+ * Defined earlier (DMA10W_t)
+ */
+
+/*
+ * structure for free buffer cache 0 full offset reg in rxdma address map
+ * located at address 0x2050
+ */
+typedef union _RXDMA_FBC_RD_INDEX_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused:27; // bits 5-31
+ u32 fbc_rdi:5; // bit 0-4
+#else
+ u32 fbc_rdi:5; // bit 0-4
+ u32 unused:27; // bits 5-31
+#endif
+ } bits;
+} RXDMA_FBC_RD_INDEX_t, *PRXDMA_FBC_RD_INDEX_t;
+
+/*
+ * structure for free buffer ring 0 minimum descriptor reg in rxdma address map
+ * located at address 0x2054
+ */
+typedef union _RXDMA_FBR_MIN_DES_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused:22; // bits 10-31
+ u32 fbr_min:10; // bits 0-9
+#else
+ u32 fbr_min:10; // bits 0-9
+ u32 unused:22; // bits 10-31
+#endif
+ } bits;
+} RXDMA_FBR_MIN_DES_t, *PRXDMA_FBR_MIN_DES_t;
+
+/*
+ * structure for free buffer ring 1 base address lo reg in rxdma address map
+ * located at address 0x2058 - 0x205C
+ * Defined earlier (RXDMA_FBR_BASE_LO_t and RXDMA_FBR_BASE_HI_t)
+ */
+
+/*
+ * structure for free buffer ring 1 number of descriptors reg in rxdma address
+ * map. Located at address 0x2060
+ * Defined earlier (RXDMA_FBR_NUM_DES_t)
+ */
+
+/*
+ * structure for free buffer ring 1 available offset reg in rxdma address map
+ * located at address 0x2064
+ * Defined Earlier (RXDMA_FBR_AVAIL_OFFSET_t)
+ */
+
+/*
+ * structure for free buffer ring 1 full offset reg in rxdma address map
+ * located at address 0x2068
+ * Defined Earlier (RXDMA_FBR_FULL_OFFSET_t)
+ */
+
+/*
+ * structure for free buffer cache 1 read index reg in rxdma address map
+ * located at address 0x206C
+ * Defined Earlier (RXDMA_FBC_RD_INDEX_t)
+ */
+
+/*
+ * structure for free buffer ring 1 minimum descriptor reg in rxdma address map
+ * located at address 0x2070
+ * Defined Earlier (RXDMA_FBR_MIN_DES_t)
+ */
+
+/*
+ * Rx DMA Module of JAGCore Address Mapping
+ * Located at address 0x2000
+ */
+typedef struct _RXDMA_t { // Location:
+ RXDMA_CSR_t csr; // 0x2000
+ u32 dma_wb_base_lo; // 0x2004
+ u32 dma_wb_base_hi; // 0x2008
+ RXDMA_NUM_PKT_DONE_t num_pkt_done; // 0x200C
+ RXDMA_MAX_PKT_TIME_t max_pkt_time; // 0x2010
+ DMA10W_t rxq_rd_addr; // 0x2014
+ DMA10W_t rxq_rd_addr_ext; // 0x2018
+ DMA10W_t rxq_wr_addr; // 0x201C
+ u32 psr_base_lo; // 0x2020
+ u32 psr_base_hi; // 0x2024
+ RXDMA_PSR_NUM_DES_t psr_num_des; // 0x2028
+ RXDMA_PSR_AVAIL_OFFSET_t psr_avail_offset; // 0x202C
+ RXDMA_PSR_FULL_OFFSET_t psr_full_offset; // 0x2030
+ RXDMA_PSR_ACCESS_INDEX_t psr_access_index; // 0x2034
+ RXDMA_PSR_MIN_DES_t psr_min_des; // 0x2038
+ u32 fbr0_base_lo; // 0x203C
+ u32 fbr0_base_hi; // 0x2040
+ RXDMA_FBR_NUM_DES_t fbr0_num_des; // 0x2044
+ DMA10W_t fbr0_avail_offset; // 0x2048
+ DMA10W_t fbr0_full_offset; // 0x204C
+ RXDMA_FBC_RD_INDEX_t fbr0_rd_index; // 0x2050
+ RXDMA_FBR_MIN_DES_t fbr0_min_des; // 0x2054
+ u32 fbr1_base_lo; // 0x2058
+ u32 fbr1_base_hi; // 0x205C
+ RXDMA_FBR_NUM_DES_t fbr1_num_des; // 0x2060
+ DMA10W_t fbr1_avail_offset; // 0x2064
+ DMA10W_t fbr1_full_offset; // 0x2068
+ RXDMA_FBC_RD_INDEX_t fbr1_rd_index; // 0x206C
+ RXDMA_FBR_MIN_DES_t fbr1_min_des; // 0x2070
+} RXDMA_t, *PRXDMA_t;
+
+/* END OF RXDMA REGISTER ADDRESS MAP */
+
+
+/* START OF TXMAC REGISTER ADDRESS MAP */
+
+/*
+ * structure for control reg in txmac address map
+ * located at address 0x3000
+ */
+typedef union _TXMAC_CTL_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused:24; // bits 8-31
+ u32 cklseg_diable:1; // bit 7
+ u32 ckbcnt_disable:1; // bit 6
+ u32 cksegnum:1; // bit 5
+ u32 async_disable:1; // bit 4
+ u32 fc_disable:1; // bit 3
+ u32 mcif_disable:1; // bit 2
+ u32 mif_disable:1; // bit 1
+ u32 txmac_en:1; // bit 0
+#else
+ u32 txmac_en:1; // bit 0
+ u32 mif_disable:1; // bit 1 mac interface
+ u32 mcif_disable:1; // bit 2 mem. contr. interface
+ u32 fc_disable:1; // bit 3
+ u32 async_disable:1; // bit 4
+ u32 cksegnum:1; // bit 5
+ u32 ckbcnt_disable:1; // bit 6
+ u32 cklseg_diable:1; // bit 7
+ u32 unused:24; // bits 8-31
+#endif
+ } bits;
+} TXMAC_CTL_t, *PTXMAC_CTL_t;
+
+/*
+ * structure for shadow pointer reg in txmac address map
+ * located at address 0x3004
+ */
+typedef union _TXMAC_SHADOW_PTR_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 reserved2:5; // bits 27-31
+ u32 txq_rd_ptr:11; // bits 16-26
+ u32 reserved:5; // bits 11-15
+ u32 txq_wr_ptr:11; // bits 0-10
+#else
+ u32 txq_wr_ptr:11; // bits 0-10
+ u32 reserved:5; // bits 11-15
+ u32 txq_rd_ptr:11; // bits 16-26
+ u32 reserved2:5; // bits 27-31
+#endif
+ } bits;
+} TXMAC_SHADOW_PTR_t, *PTXMAC_SHADOW_PTR_t;
+
+/*
+ * structure for error count reg in txmac address map
+ * located at address 0x3008
+ */
+typedef union _TXMAC_ERR_CNT_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused:20; // bits 12-31
+ u32 reserved:4; // bits 8-11
+ u32 txq_underrun:4; // bits 4-7
+ u32 fifo_underrun:4; // bits 0-3
+#else
+ u32 fifo_underrun:4; // bits 0-3
+ u32 txq_underrun:4; // bits 4-7
+ u32 reserved:4; // bits 8-11
+ u32 unused:20; // bits 12-31
+#endif
+ } bits;
+} TXMAC_ERR_CNT_t, *PTXMAC_ERR_CNT_t;
+
+/*
+ * structure for max fill reg in txmac address map
+ * located at address 0x300C
+ */
+typedef union _TXMAC_MAX_FILL_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused:20; // bits 12-31
+ u32 max_fill:12; // bits 0-11
+#else
+ u32 max_fill:12; // bits 0-11
+ u32 unused:20; // bits 12-31
+#endif
+ } bits;
+} TXMAC_MAX_FILL_t, *PTXMAC_MAX_FILL_t;
+
+/*
+ * structure for cf parameter reg in txmac address map
+ * located at address 0x3010
+ */
+typedef union _TXMAC_CF_PARAM_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 cfep:16; // bits 16-31
+ u32 cfpt:16; // bits 0-15
+#else
+ u32 cfpt:16; // bits 0-15
+ u32 cfep:16; // bits 16-31
+#endif
+ } bits;
+} TXMAC_CF_PARAM_t, *PTXMAC_CF_PARAM_t;
+
+/*
+ * structure for tx test reg in txmac address map
+ * located at address 0x3014
+ */
+typedef union _TXMAC_TXTEST_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused2:15; // bits 17-31
+ u32 reserved1:1; // bit 16
+ u32 txtest_en:1; // bit 15
+ u32 unused1:4; // bits 11-14
+ u32 txqtest_ptr:11; // bits 0-11
+#else
+ u32 txqtest_ptr:11; // bits 0-10
+ u32 unused1:4; // bits 11-14
+ u32 txtest_en:1; // bit 15
+ u32 reserved1:1; // bit 16
+ u32 unused2:15; // bits 17-31
+#endif
+ } bits;
+} TXMAC_TXTEST_t, *PTXMAC_TXTEST_t;
+
+/*
+ * structure for error reg in txmac address map
+ * located at address 0x3018
+ */
+typedef union _TXMAC_ERR_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused2:23; // bits 9-31
+ u32 fifo_underrun:1; // bit 8
+ u32 unused1:2; // bits 6-7
+ u32 ctrl2_err:1; // bit 5
+ u32 txq_underrun:1; // bit 4
+ u32 bcnt_err:1; // bit 3
+ u32 lseg_err:1; // bit 2
+ u32 segnum_err:1; // bit 1
+ u32 seg0_err:1; // bit 0
+#else
+ u32 seg0_err:1; // bit 0
+ u32 segnum_err:1; // bit 1
+ u32 lseg_err:1; // bit 2
+ u32 bcnt_err:1; // bit 3
+ u32 txq_underrun:1; // bit 4
+ u32 ctrl2_err:1; // bit 5
+ u32 unused1:2; // bits 6-7
+ u32 fifo_underrun:1; // bit 8
+ u32 unused2:23; // bits 9-31
+#endif
+ } bits;
+} TXMAC_ERR_t, *PTXMAC_ERR_t;
+
+/*
+ * structure for error interrupt reg in txmac address map
+ * located at address 0x301C
+ */
+typedef union _TXMAC_ERR_INT_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused2:23; // bits 9-31
+ u32 fifo_underrun:1; // bit 8
+ u32 unused1:2; // bits 6-7
+ u32 ctrl2_err:1; // bit 5
+ u32 txq_underrun:1; // bit 4
+ u32 bcnt_err:1; // bit 3
+ u32 lseg_err:1; // bit 2
+ u32 segnum_err:1; // bit 1
+ u32 seg0_err:1; // bit 0
+#else
+ u32 seg0_err:1; // bit 0
+ u32 segnum_err:1; // bit 1
+ u32 lseg_err:1; // bit 2
+ u32 bcnt_err:1; // bit 3
+ u32 txq_underrun:1; // bit 4
+ u32 ctrl2_err:1; // bit 5
+ u32 unused1:2; // bits 6-7
+ u32 fifo_underrun:1; // bit 8
+ u32 unused2:23; // bits 9-31
+#endif
+ } bits;
+} TXMAC_ERR_INT_t, *PTXMAC_ERR_INT_t;
+
+/*
+ * structure for error interrupt reg in txmac address map
+ * located at address 0x3020
+ */
+typedef union _TXMAC_CP_CTRL_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused:30; // bits 2-31
+ u32 bp_req:1; // bit 1
+ u32 bp_xonxoff:1; // bit 0
+#else
+ u32 bp_xonxoff:1; // bit 0
+ u32 bp_req:1; // bit 1
+ u32 unused:30; // bits 2-31
+#endif
+ } bits;
+} TXMAC_BP_CTRL_t, *PTXMAC_BP_CTRL_t;
+
+/*
+ * Tx MAC Module of JAGCore Address Mapping
+ */
+typedef struct _TXMAC_t { // Location:
+ TXMAC_CTL_t ctl; // 0x3000
+ TXMAC_SHADOW_PTR_t shadow_ptr; // 0x3004
+ TXMAC_ERR_CNT_t err_cnt; // 0x3008
+ TXMAC_MAX_FILL_t max_fill; // 0x300C
+ TXMAC_CF_PARAM_t cf_param; // 0x3010
+ TXMAC_TXTEST_t tx_test; // 0x3014
+ TXMAC_ERR_t err; // 0x3018
+ TXMAC_ERR_INT_t err_int; // 0x301C
+ TXMAC_BP_CTRL_t bp_ctrl; // 0x3020
+} TXMAC_t, *PTXMAC_t;
+
+/* END OF TXMAC REGISTER ADDRESS MAP */
+
+/* START OF RXMAC REGISTER ADDRESS MAP */
+
+/*
+ * structure for rxmac control reg in rxmac address map
+ * located at address 0x4000
+ */
+typedef union _RXMAC_CTRL_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 reserved:25; // bits 7-31
+ u32 rxmac_int_disable:1; // bit 6
+ u32 async_disable:1; // bit 5
+ u32 mif_disable:1; // bit 4
+ u32 wol_disable:1; // bit 3
+ u32 pkt_filter_disable:1; // bit 2
+ u32 mcif_disable:1; // bit 1
+ u32 rxmac_en:1; // bit 0
+#else
+ u32 rxmac_en:1; // bit 0
+ u32 mcif_disable:1; // bit 1
+ u32 pkt_filter_disable:1; // bit 2
+ u32 wol_disable:1; // bit 3
+ u32 mif_disable:1; // bit 4
+ u32 async_disable:1; // bit 5
+ u32 rxmac_int_disable:1; // bit 6
+ u32 reserved:25; // bits 7-31
+#endif
+ } bits;
+} RXMAC_CTRL_t, *PRXMAC_CTRL_t;
+
+/*
+ * structure for Wake On Lan Control and CRC 0 reg in rxmac address map
+ * located at address 0x4004
+ */
+typedef union _RXMAC_WOL_CTL_CRC0_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 crc0:16; // bits 16-31
+ u32 reserve:4; // bits 12-15
+ u32 ignore_pp:1; // bit 11
+ u32 ignore_mp:1; // bit 10
+ u32 clr_intr:1; // bit 9
+ u32 ignore_link_chg:1; // bit 8
+ u32 ignore_uni:1; // bit 7
+ u32 ignore_multi:1; // bit 6
+ u32 ignore_broad:1; // bit 5
+ u32 valid_crc4:1; // bit 4
+ u32 valid_crc3:1; // bit 3
+ u32 valid_crc2:1; // bit 2
+ u32 valid_crc1:1; // bit 1
+ u32 valid_crc0:1; // bit 0
+#else
+ u32 valid_crc0:1; // bit 0
+ u32 valid_crc1:1; // bit 1
+ u32 valid_crc2:1; // bit 2
+ u32 valid_crc3:1; // bit 3
+ u32 valid_crc4:1; // bit 4
+ u32 ignore_broad:1; // bit 5
+ u32 ignore_multi:1; // bit 6
+ u32 ignore_uni:1; // bit 7
+ u32 ignore_link_chg:1; // bit 8
+ u32 clr_intr:1; // bit 9
+ u32 ignore_mp:1; // bit 10
+ u32 ignore_pp:1; // bit 11
+ u32 reserve:4; // bits 12-15
+ u32 crc0:16; // bits 16-31
+#endif
+ } bits;
+} RXMAC_WOL_CTL_CRC0_t, *PRXMAC_WOL_CTL_CRC0_t;
+
+/*
+ * structure for CRC 1 and CRC 2 reg in rxmac address map
+ * located at address 0x4008
+ */
+typedef union _RXMAC_WOL_CRC12_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 crc2:16; // bits 16-31
+ u32 crc1:16; // bits 0-15
+#else
+ u32 crc1:16; // bits 0-15
+ u32 crc2:16; // bits 16-31
+#endif
+ } bits;
+} RXMAC_WOL_CRC12_t, *PRXMAC_WOL_CRC12_t;
+
+/*
+ * structure for CRC 3 and CRC 4 reg in rxmac address map
+ * located at address 0x400C
+ */
+typedef union _RXMAC_WOL_CRC34_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 crc4:16; // bits 16-31
+ u32 crc3:16; // bits 0-15
+#else
+ u32 crc3:16; // bits 0-15
+ u32 crc4:16; // bits 16-31
+#endif
+ } bits;
+} RXMAC_WOL_CRC34_t, *PRXMAC_WOL_CRC34_t;
+
+/*
+ * structure for Wake On Lan Source Address Lo reg in rxmac address map
+ * located at address 0x4010
+ */
+typedef union _RXMAC_WOL_SA_LO_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 sa3:8; // bits 24-31
+ u32 sa4:8; // bits 16-23
+ u32 sa5:8; // bits 8-15
+ u32 sa6:8; // bits 0-7
+#else
+ u32 sa6:8; // bits 0-7
+ u32 sa5:8; // bits 8-15
+ u32 sa4:8; // bits 16-23
+ u32 sa3:8; // bits 24-31
+#endif
+ } bits;
+} RXMAC_WOL_SA_LO_t, *PRXMAC_WOL_SA_LO_t;
+
+/*
+ * structure for Wake On Lan Source Address Hi reg in rxmac address map
+ * located at address 0x4014
+ */
+typedef union _RXMAC_WOL_SA_HI_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 reserved:16; // bits 16-31
+ u32 sa1:8; // bits 8-15
+ u32 sa2:8; // bits 0-7
+#else
+ u32 sa2:8; // bits 0-7
+ u32 sa1:8; // bits 8-15
+ u32 reserved:16; // bits 16-31
+#endif
+ } bits;
+} RXMAC_WOL_SA_HI_t, *PRXMAC_WOL_SA_HI_t;
+
+/*
+ * structure for Wake On Lan mask reg in rxmac address map
+ * located at address 0x4018 - 0x4064
+ * Defined earlier (u32)
+ */
+
+/*
+ * structure for Unicast Paket Filter Address 1 reg in rxmac address map
+ * located at address 0x4068
+ */
+typedef union _RXMAC_UNI_PF_ADDR1_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 addr1_3:8; // bits 24-31
+ u32 addr1_4:8; // bits 16-23
+ u32 addr1_5:8; // bits 8-15
+ u32 addr1_6:8; // bits 0-7
+#else
+ u32 addr1_6:8; // bits 0-7
+ u32 addr1_5:8; // bits 8-15
+ u32 addr1_4:8; // bits 16-23
+ u32 addr1_3:8; // bits 24-31
+#endif
+ } bits;
+} RXMAC_UNI_PF_ADDR1_t, *PRXMAC_UNI_PF_ADDR1_t;
+
+/*
+ * structure for Unicast Paket Filter Address 2 reg in rxmac address map
+ * located at address 0x406C
+ */
+typedef union _RXMAC_UNI_PF_ADDR2_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 addr2_3:8; // bits 24-31
+ u32 addr2_4:8; // bits 16-23
+ u32 addr2_5:8; // bits 8-15
+ u32 addr2_6:8; // bits 0-7
+#else
+ u32 addr2_6:8; // bits 0-7
+ u32 addr2_5:8; // bits 8-15
+ u32 addr2_4:8; // bits 16-23
+ u32 addr2_3:8; // bits 24-31
+#endif
+ } bits;
+} RXMAC_UNI_PF_ADDR2_t, *PRXMAC_UNI_PF_ADDR2_t;
+
+/*
+ * structure for Unicast Paket Filter Address 1 & 2 reg in rxmac address map
+ * located at address 0x4070
+ */
+typedef union _RXMAC_UNI_PF_ADDR3_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 addr2_1:8; // bits 24-31
+ u32 addr2_2:8; // bits 16-23
+ u32 addr1_1:8; // bits 8-15
+ u32 addr1_2:8; // bits 0-7
+#else
+ u32 addr1_2:8; // bits 0-7
+ u32 addr1_1:8; // bits 8-15
+ u32 addr2_2:8; // bits 16-23
+ u32 addr2_1:8; // bits 24-31
+#endif
+ } bits;
+} RXMAC_UNI_PF_ADDR3_t, *PRXMAC_UNI_PF_ADDR3_t;
+
+/*
+ * structure for Multicast Hash reg in rxmac address map
+ * located at address 0x4074 - 0x4080
+ * Defined earlier (u32)
+ */
+
+/*
+ * structure for Packet Filter Control reg in rxmac address map
+ * located at address 0x4084
+ */
+typedef union _RXMAC_PF_CTRL_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused2:9; // bits 23-31
+ u32 min_pkt_size:7; // bits 16-22
+ u32 unused1:12; // bits 4-15
+ u32 filter_frag_en:1; // bit 3
+ u32 filter_uni_en:1; // bit 2
+ u32 filter_multi_en:1; // bit 1
+ u32 filter_broad_en:1; // bit 0
+#else
+ u32 filter_broad_en:1; // bit 0
+ u32 filter_multi_en:1; // bit 1
+ u32 filter_uni_en:1; // bit 2
+ u32 filter_frag_en:1; // bit 3
+ u32 unused1:12; // bits 4-15
+ u32 min_pkt_size:7; // bits 16-22
+ u32 unused2:9; // bits 23-31
+#endif
+ } bits;
+} RXMAC_PF_CTRL_t, *PRXMAC_PF_CTRL_t;
+
+/*
+ * structure for Memory Controller Interface Control Max Segment reg in rxmac
+ * address map. Located at address 0x4088
+ */
+typedef union _RXMAC_MCIF_CTRL_MAX_SEG_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 reserved:22; // bits 10-31
+ u32 max_size:8; // bits 2-9
+ u32 fc_en:1; // bit 1
+ u32 seg_en:1; // bit 0
+#else
+ u32 seg_en:1; // bit 0
+ u32 fc_en:1; // bit 1
+ u32 max_size:8; // bits 2-9
+ u32 reserved:22; // bits 10-31
+#endif
+ } bits;
+} RXMAC_MCIF_CTRL_MAX_SEG_t, *PRXMAC_MCIF_CTRL_MAX_SEG_t;
+
+/*
+ * structure for Memory Controller Interface Water Mark reg in rxmac address
+ * map. Located at address 0x408C
+ */
+typedef union _RXMAC_MCIF_WATER_MARK_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 reserved2:6; // bits 26-31
+ u32 mark_hi:10; // bits 16-25
+ u32 reserved1:6; // bits 10-15
+ u32 mark_lo:10; // bits 0-9
+#else
+ u32 mark_lo:10; // bits 0-9
+ u32 reserved1:6; // bits 10-15
+ u32 mark_hi:10; // bits 16-25
+ u32 reserved2:6; // bits 26-31
+#endif
+ } bits;
+} RXMAC_MCIF_WATER_MARK_t, *PRXMAC_MCIF_WATER_MARK_t;
+
+/*
+ * structure for Rx Queue Dialog reg in rxmac address map.
+ * located at address 0x4090
+ */
+typedef union _RXMAC_RXQ_DIAG_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 reserved2:6; // bits 26-31
+ u32 rd_ptr:10; // bits 16-25
+ u32 reserved1:6; // bits 10-15
+ u32 wr_ptr:10; // bits 0-9
+#else
+ u32 wr_ptr:10; // bits 0-9
+ u32 reserved1:6; // bits 10-15
+ u32 rd_ptr:10; // bits 16-25
+ u32 reserved2:6; // bits 26-31
+#endif
+ } bits;
+} RXMAC_RXQ_DIAG_t, *PRXMAC_RXQ_DIAG_t;
+
+/*
+ * structure for space availiable reg in rxmac address map.
+ * located at address 0x4094
+ */
+typedef union _RXMAC_SPACE_AVAIL_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 reserved2:15; // bits 17-31
+ u32 space_avail_en:1; // bit 16
+ u32 reserved1:6; // bits 10-15
+ u32 space_avail:10; // bits 0-9
+#else
+ u32 space_avail:10; // bits 0-9
+ u32 reserved1:6; // bits 10-15
+ u32 space_avail_en:1; // bit 16
+ u32 reserved2:15; // bits 17-31
+#endif
+ } bits;
+} RXMAC_SPACE_AVAIL_t, *PRXMAC_SPACE_AVAIL_t;
+
+/*
+ * structure for management interface reg in rxmac address map.
+ * located at address 0x4098
+ */
+typedef union _RXMAC_MIF_CTL_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 reserve:14; // bits 18-31
+ u32 drop_pkt_en:1; // bit 17
+ u32 drop_pkt_mask:17; // bits 0-16
+#else
+ u32 drop_pkt_mask:17; // bits 0-16
+ u32 drop_pkt_en:1; // bit 17
+ u32 reserve:14; // bits 18-31
+#endif
+ } bits;
+} RXMAC_MIF_CTL_t, *PRXMAC_MIF_CTL_t;
+
+/*
+ * structure for Error reg in rxmac address map.
+ * located at address 0x409C
+ */
+typedef union _RXMAC_ERROR_REG_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 reserve:28; // bits 4-31
+ u32 mif:1; // bit 3
+ u32 async:1; // bit 2
+ u32 pkt_filter:1; // bit 1
+ u32 mcif:1; // bit 0
+#else
+ u32 mcif:1; // bit 0
+ u32 pkt_filter:1; // bit 1
+ u32 async:1; // bit 2
+ u32 mif:1; // bit 3
+ u32 reserve:28; // bits 4-31
+#endif
+ } bits;
+} RXMAC_ERROR_REG_t, *PRXMAC_ERROR_REG_t;
+
+/*
+ * Rx MAC Module of JAGCore Address Mapping
+ */
+typedef struct _RXMAC_t { // Location:
+ RXMAC_CTRL_t ctrl; // 0x4000
+ RXMAC_WOL_CTL_CRC0_t crc0; // 0x4004
+ RXMAC_WOL_CRC12_t crc12; // 0x4008
+ RXMAC_WOL_CRC34_t crc34; // 0x400C
+ RXMAC_WOL_SA_LO_t sa_lo; // 0x4010
+ RXMAC_WOL_SA_HI_t sa_hi; // 0x4014
+ u32 mask0_word0; // 0x4018
+ u32 mask0_word1; // 0x401C
+ u32 mask0_word2; // 0x4020
+ u32 mask0_word3; // 0x4024
+ u32 mask1_word0; // 0x4028
+ u32 mask1_word1; // 0x402C
+ u32 mask1_word2; // 0x4030
+ u32 mask1_word3; // 0x4034
+ u32 mask2_word0; // 0x4038
+ u32 mask2_word1; // 0x403C
+ u32 mask2_word2; // 0x4040
+ u32 mask2_word3; // 0x4044
+ u32 mask3_word0; // 0x4048
+ u32 mask3_word1; // 0x404C
+ u32 mask3_word2; // 0x4050
+ u32 mask3_word3; // 0x4054
+ u32 mask4_word0; // 0x4058
+ u32 mask4_word1; // 0x405C
+ u32 mask4_word2; // 0x4060
+ u32 mask4_word3; // 0x4064
+ RXMAC_UNI_PF_ADDR1_t uni_pf_addr1; // 0x4068
+ RXMAC_UNI_PF_ADDR2_t uni_pf_addr2; // 0x406C
+ RXMAC_UNI_PF_ADDR3_t uni_pf_addr3; // 0x4070
+ u32 multi_hash1; // 0x4074
+ u32 multi_hash2; // 0x4078
+ u32 multi_hash3; // 0x407C
+ u32 multi_hash4; // 0x4080
+ RXMAC_PF_CTRL_t pf_ctrl; // 0x4084
+ RXMAC_MCIF_CTRL_MAX_SEG_t mcif_ctrl_max_seg; // 0x4088
+ RXMAC_MCIF_WATER_MARK_t mcif_water_mark; // 0x408C
+ RXMAC_RXQ_DIAG_t rxq_diag; // 0x4090
+ RXMAC_SPACE_AVAIL_t space_avail; // 0x4094
+
+ RXMAC_MIF_CTL_t mif_ctrl; // 0x4098
+ RXMAC_ERROR_REG_t err_reg; // 0x409C
+} RXMAC_t, *PRXMAC_t;
+
+/* END OF TXMAC REGISTER ADDRESS MAP */
+
+
+/* START OF MAC REGISTER ADDRESS MAP */
+
+/*
+ * structure for configuration #1 reg in mac address map.
+ * located at address 0x5000
+ */
+typedef union _MAC_CFG1_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 soft_reset:1; // bit 31
+ u32 sim_reset:1; // bit 30
+ u32 reserved3:10; // bits 20-29
+ u32 reset_rx_mc:1; // bit 19
+ u32 reset_tx_mc:1; // bit 18
+ u32 reset_rx_fun:1; // bit 17
+ u32 reset_tx_fun:1; // bit 16
+ u32 reserved2:7; // bits 9-15
+ u32 loop_back:1; // bit 8
+ u32 reserved1:2; // bits 6-7
+ u32 rx_flow:1; // bit 5
+ u32 tx_flow:1; // bit 4
+ u32 syncd_rx_en:1; // bit 3
+ u32 rx_enable:1; // bit 2
+ u32 syncd_tx_en:1; // bit 1
+ u32 tx_enable:1; // bit 0
+#else
+ u32 tx_enable:1; // bit 0
+ u32 syncd_tx_en:1; // bit 1
+ u32 rx_enable:1; // bit 2
+ u32 syncd_rx_en:1; // bit 3
+ u32 tx_flow:1; // bit 4
+ u32 rx_flow:1; // bit 5
+ u32 reserved1:2; // bits 6-7
+ u32 loop_back:1; // bit 8
+ u32 reserved2:7; // bits 9-15
+ u32 reset_tx_fun:1; // bit 16
+ u32 reset_rx_fun:1; // bit 17
+ u32 reset_tx_mc:1; // bit 18
+ u32 reset_rx_mc:1; // bit 19
+ u32 reserved3:10; // bits 20-29
+ u32 sim_reset:1; // bit 30
+ u32 soft_reset:1; // bit 31
+#endif
+ } bits;
+} MAC_CFG1_t, *PMAC_CFG1_t;
+
+/*
+ * structure for configuration #2 reg in mac address map.
+ * located at address 0x5004
+ */
+typedef union _MAC_CFG2_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 reserved3:16; // bits 16-31
+ u32 preamble_len:4; // bits 12-15
+ u32 reserved2:2; // bits 10-11
+ u32 if_mode:2; // bits 8-9
+ u32 reserved1:2; // bits 6-7
+ u32 huge_frame:1; // bit 5
+ u32 len_check:1; // bit 4
+ u32 undefined:1; // bit 3
+ u32 pad_crc:1; // bit 2
+ u32 crc_enable:1; // bit 1
+ u32 full_duplex:1; // bit 0
+#else
+ u32 full_duplex:1; // bit 0
+ u32 crc_enable:1; // bit 1
+ u32 pad_crc:1; // bit 2
+ u32 undefined:1; // bit 3
+ u32 len_check:1; // bit 4
+ u32 huge_frame:1; // bit 5
+ u32 reserved1:2; // bits 6-7
+ u32 if_mode:2; // bits 8-9
+ u32 reserved2:2; // bits 10-11
+ u32 preamble_len:4; // bits 12-15
+ u32 reserved3:16; // bits 16-31
+#endif
+ } bits;
+} MAC_CFG2_t, *PMAC_CFG2_t;
+
+/*
+ * structure for Interpacket gap reg in mac address map.
+ * located at address 0x5008
+ */
+typedef union _MAC_IPG_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 reserved:1; // bit 31
+ u32 non_B2B_ipg_1:7; // bits 24-30
+ u32 undefined2:1; // bit 23
+ u32 non_B2B_ipg_2:7; // bits 16-22
+ u32 min_ifg_enforce:8; // bits 8-15
+ u32 undefined1:1; // bit 7
+ u32 B2B_ipg:7; // bits 0-6
+#else
+ u32 B2B_ipg:7; // bits 0-6
+ u32 undefined1:1; // bit 7
+ u32 min_ifg_enforce:8; // bits 8-15
+ u32 non_B2B_ipg_2:7; // bits 16-22
+ u32 undefined2:1; // bit 23
+ u32 non_B2B_ipg_1:7; // bits 24-30
+ u32 reserved:1; // bit 31
+#endif
+ } bits;
+} MAC_IPG_t, *PMAC_IPG_t;
+
+/*
+ * structure for half duplex reg in mac address map.
+ * located at address 0x500C
+ */
+typedef union _MAC_HFDP_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 reserved2:8; // bits 24-31
+ u32 alt_beb_trunc:4; // bits 23-20
+ u32 alt_beb_enable:1; // bit 19
+ u32 bp_no_backoff:1; // bit 18
+ u32 no_backoff:1; // bit 17
+ u32 excess_defer:1; // bit 16
+ u32 rexmit_max:4; // bits 12-15
+ u32 reserved1:2; // bits 10-11
+ u32 coll_window:10; // bits 0-9
+#else
+ u32 coll_window:10; // bits 0-9
+ u32 reserved1:2; // bits 10-11
+ u32 rexmit_max:4; // bits 12-15
+ u32 excess_defer:1; // bit 16
+ u32 no_backoff:1; // bit 17
+ u32 bp_no_backoff:1; // bit 18
+ u32 alt_beb_enable:1; // bit 19
+ u32 alt_beb_trunc:4; // bits 23-20
+ u32 reserved2:8; // bits 24-31
+#endif
+ } bits;
+} MAC_HFDP_t, *PMAC_HFDP_t;
+
+/*
+ * structure for Maximum Frame Length reg in mac address map.
+ * located at address 0x5010
+ */
+typedef union _MAC_MAX_FM_LEN_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 reserved:16; // bits 16-31
+ u32 max_len:16; // bits 0-15
+#else
+ u32 max_len:16; // bits 0-15
+ u32 reserved:16; // bits 16-31
+#endif
+ } bits;
+} MAC_MAX_FM_LEN_t, *PMAC_MAX_FM_LEN_t;
+
+/*
+ * structure for Reserve 1 reg in mac address map.
+ * located at address 0x5014 - 0x5018
+ * Defined earlier (u32)
+ */
+
+/*
+ * structure for Test reg in mac address map.
+ * located at address 0x501C
+ */
+typedef union _MAC_TEST_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused:29; // bits 3-31
+ u32 mac_test:3; // bits 0-2
+#else
+ u32 mac_test:3; // bits 0-2
+ u32 unused:29; // bits 3-31
+#endif
+ } bits;
+} MAC_TEST_t, *PMAC_TEST_t;
+
+/*
+ * structure for MII Management Configuration reg in mac address map.
+ * located at address 0x5020
+ */
+typedef union _MII_MGMT_CFG_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 reset_mii_mgmt:1; // bit 31
+ u32 reserved:25; // bits 6-30
+ u32 scan_auto_incremt:1; // bit 5
+ u32 preamble_suppress:1; // bit 4
+ u32 undefined:1; // bit 3
+ u32 mgmt_clk_reset:3; // bits 0-2
+#else
+ u32 mgmt_clk_reset:3; // bits 0-2
+ u32 undefined:1; // bit 3
+ u32 preamble_suppress:1; // bit 4
+ u32 scan_auto_incremt:1; // bit 5
+ u32 reserved:25; // bits 6-30
+ u32 reset_mii_mgmt:1; // bit 31
+#endif
+ } bits;
+} MII_MGMT_CFG_t, *PMII_MGMT_CFG_t;
+
+/*
+ * structure for MII Management Command reg in mac address map.
+ * located at address 0x5024
+ */
+typedef union _MII_MGMT_CMD_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 reserved:30; // bits 2-31
+ u32 scan_cycle:1; // bit 1
+ u32 read_cycle:1; // bit 0
+#else
+ u32 read_cycle:1; // bit 0
+ u32 scan_cycle:1; // bit 1
+ u32 reserved:30; // bits 2-31
+#endif
+ } bits;
+} MII_MGMT_CMD_t, *PMII_MGMT_CMD_t;
+
+/*
+ * structure for MII Management Address reg in mac address map.
+ * located at address 0x5028
+ */
+typedef union _MII_MGMT_ADDR_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 reserved2:19; // bit 13-31
+ u32 phy_addr:5; // bits 8-12
+ u32 reserved1:3; // bits 5-7
+ u32 reg_addr:5; // bits 0-4
+#else
+ u32 reg_addr:5; // bits 0-4
+ u32 reserved1:3; // bits 5-7
+ u32 phy_addr:5; // bits 8-12
+ u32 reserved2:19; // bit 13-31
+#endif
+ } bits;
+} MII_MGMT_ADDR_t, *PMII_MGMT_ADDR_t;
+
+/*
+ * structure for MII Management Control reg in mac address map.
+ * located at address 0x502C
+ */
+typedef union _MII_MGMT_CTRL_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 reserved:16; // bits 16-31
+ u32 phy_ctrl:16; // bits 0-15
+#else
+ u32 phy_ctrl:16; // bits 0-15
+ u32 reserved:16; // bits 16-31
+#endif
+ } bits;
+} MII_MGMT_CTRL_t, *PMII_MGMT_CTRL_t;
+
+/*
+ * structure for MII Management Status reg in mac address map.
+ * located at address 0x5030
+ */
+typedef union _MII_MGMT_STAT_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 reserved:16; // bits 16-31
+ u32 phy_stat:16; // bits 0-15
+#else
+ u32 phy_stat:16; // bits 0-15
+ u32 reserved:16; // bits 16-31
+#endif
+ } bits;
+} MII_MGMT_STAT_t, *PMII_MGMT_STAT_t;
+
+/*
+ * structure for MII Management Indicators reg in mac address map.
+ * located at address 0x5034
+ */
+typedef union _MII_MGMT_INDICATOR_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 reserved:29; // bits 3-31
+ u32 not_valid:1; // bit 2
+ u32 scanning:1; // bit 1
+ u32 busy:1; // bit 0
+#else
+ u32 busy:1; // bit 0
+ u32 scanning:1; // bit 1
+ u32 not_valid:1; // bit 2
+ u32 reserved:29; // bits 3-31
+#endif
+ } bits;
+} MII_MGMT_INDICATOR_t, *PMII_MGMT_INDICATOR_t;
+
+/*
+ * structure for Interface Control reg in mac address map.
+ * located at address 0x5038
+ */
+typedef union _MAC_IF_CTRL_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 reset_if_module:1; // bit 31
+ u32 reserved4:3; // bit 28-30
+ u32 tbi_mode:1; // bit 27
+ u32 ghd_mode:1; // bit 26
+ u32 lhd_mode:1; // bit 25
+ u32 phy_mode:1; // bit 24
+ u32 reset_per_mii:1; // bit 23
+ u32 reserved3:6; // bits 17-22
+ u32 speed:1; // bit 16
+ u32 reset_pe100x:1; // bit 15
+ u32 reserved2:4; // bits 11-14
+ u32 force_quiet:1; // bit 10
+ u32 no_cipher:1; // bit 9
+ u32 disable_link_fail:1; // bit 8
+ u32 reset_gpsi:1; // bit 7
+ u32 reserved1:6; // bits 1-6
+ u32 enab_jab_protect:1; // bit 0
+#else
+ u32 enab_jab_protect:1; // bit 0
+ u32 reserved1:6; // bits 1-6
+ u32 reset_gpsi:1; // bit 7
+ u32 disable_link_fail:1; // bit 8
+ u32 no_cipher:1; // bit 9
+ u32 force_quiet:1; // bit 10
+ u32 reserved2:4; // bits 11-14
+ u32 reset_pe100x:1; // bit 15
+ u32 speed:1; // bit 16
+ u32 reserved3:6; // bits 17-22
+ u32 reset_per_mii:1; // bit 23
+ u32 phy_mode:1; // bit 24
+ u32 lhd_mode:1; // bit 25
+ u32 ghd_mode:1; // bit 26
+ u32 tbi_mode:1; // bit 27
+ u32 reserved4:3; // bit 28-30
+ u32 reset_if_module:1; // bit 31
+#endif
+ } bits;
+} MAC_IF_CTRL_t, *PMAC_IF_CTRL_t;
+
+/*
+ * structure for Interface Status reg in mac address map.
+ * located at address 0x503C
+ */
+typedef union _MAC_IF_STAT_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 reserved:22; // bits 10-31
+ u32 excess_defer:1; // bit 9
+ u32 clash:1; // bit 8
+ u32 phy_jabber:1; // bit 7
+ u32 phy_link_ok:1; // bit 6
+ u32 phy_full_duplex:1; // bit 5
+ u32 phy_speed:1; // bit 4
+ u32 pe100x_link_fail:1; // bit 3
+ u32 pe10t_loss_carrie:1; // bit 2
+ u32 pe10t_sqe_error:1; // bit 1
+ u32 pe10t_jabber:1; // bit 0
+#else
+ u32 pe10t_jabber:1; // bit 0
+ u32 pe10t_sqe_error:1; // bit 1
+ u32 pe10t_loss_carrie:1; // bit 2
+ u32 pe100x_link_fail:1; // bit 3
+ u32 phy_speed:1; // bit 4
+ u32 phy_full_duplex:1; // bit 5
+ u32 phy_link_ok:1; // bit 6
+ u32 phy_jabber:1; // bit 7
+ u32 clash:1; // bit 8
+ u32 excess_defer:1; // bit 9
+ u32 reserved:22; // bits 10-31
+#endif
+ } bits;
+} MAC_IF_STAT_t, *PMAC_IF_STAT_t;
+
+/*
+ * structure for Mac Station Address, Part 1 reg in mac address map.
+ * located at address 0x5040
+ */
+typedef union _MAC_STATION_ADDR1_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 Octet6:8; // bits 24-31
+ u32 Octet5:8; // bits 16-23
+ u32 Octet4:8; // bits 8-15
+ u32 Octet3:8; // bits 0-7
+#else
+ u32 Octet3:8; // bits 0-7
+ u32 Octet4:8; // bits 8-15
+ u32 Octet5:8; // bits 16-23
+ u32 Octet6:8; // bits 24-31
+#endif
+ } bits;
+} MAC_STATION_ADDR1_t, *PMAC_STATION_ADDR1_t;
+
+/*
+ * structure for Mac Station Address, Part 2 reg in mac address map.
+ * located at address 0x5044
+ */
+typedef union _MAC_STATION_ADDR2_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 Octet2:8; // bits 24-31
+ u32 Octet1:8; // bits 16-23
+ u32 reserved:16; // bits 0-15
+#else
+ u32 reserved:16; // bit 0-15
+ u32 Octet1:8; // bits 16-23
+ u32 Octet2:8; // bits 24-31
+#endif
+ } bits;
+} MAC_STATION_ADDR2_t, *PMAC_STATION_ADDR2_t;
+
+/*
+ * MAC Module of JAGCore Address Mapping
+ */
+typedef struct _MAC_t { // Location:
+ MAC_CFG1_t cfg1; // 0x5000
+ MAC_CFG2_t cfg2; // 0x5004
+ MAC_IPG_t ipg; // 0x5008
+ MAC_HFDP_t hfdp; // 0x500C
+ MAC_MAX_FM_LEN_t max_fm_len; // 0x5010
+ u32 rsv1; // 0x5014
+ u32 rsv2; // 0x5018
+ MAC_TEST_t mac_test; // 0x501C
+ MII_MGMT_CFG_t mii_mgmt_cfg; // 0x5020
+ MII_MGMT_CMD_t mii_mgmt_cmd; // 0x5024
+ MII_MGMT_ADDR_t mii_mgmt_addr; // 0x5028
+ MII_MGMT_CTRL_t mii_mgmt_ctrl; // 0x502C
+ MII_MGMT_STAT_t mii_mgmt_stat; // 0x5030
+ MII_MGMT_INDICATOR_t mii_mgmt_indicator; // 0x5034
+ MAC_IF_CTRL_t if_ctrl; // 0x5038
+ MAC_IF_STAT_t if_stat; // 0x503C
+ MAC_STATION_ADDR1_t station_addr_1; // 0x5040
+ MAC_STATION_ADDR2_t station_addr_2; // 0x5044
+} MAC_t, *PMAC_t;
+
+/* END OF MAC REGISTER ADDRESS MAP */
+
+/* START OF MAC STAT REGISTER ADDRESS MAP */
+
+/*
+ * structure for Carry Register One and it's Mask Register reg located in mac
+ * stat address map address 0x6130 and 0x6138.
+ */
+typedef union _MAC_STAT_REG_1_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 tr64:1; // bit 31
+ u32 tr127:1; // bit 30
+ u32 tr255:1; // bit 29
+ u32 tr511:1; // bit 28
+ u32 tr1k:1; // bit 27
+ u32 trmax:1; // bit 26
+ u32 trmgv:1; // bit 25
+ u32 unused:8; // bits 17-24
+ u32 rbyt:1; // bit 16
+ u32 rpkt:1; // bit 15
+ u32 rfcs:1; // bit 14
+ u32 rmca:1; // bit 13
+ u32 rbca:1; // bit 12
+ u32 rxcf:1; // bit 11
+ u32 rxpf:1; // bit 10
+ u32 rxuo:1; // bit 9
+ u32 raln:1; // bit 8
+ u32 rflr:1; // bit 7
+ u32 rcde:1; // bit 6
+ u32 rcse:1; // bit 5
+ u32 rund:1; // bit 4
+ u32 rovr:1; // bit 3
+ u32 rfrg:1; // bit 2
+ u32 rjbr:1; // bit 1
+ u32 rdrp:1; // bit 0
+#else
+ u32 rdrp:1; // bit 0
+ u32 rjbr:1; // bit 1
+ u32 rfrg:1; // bit 2
+ u32 rovr:1; // bit 3
+ u32 rund:1; // bit 4
+ u32 rcse:1; // bit 5
+ u32 rcde:1; // bit 6
+ u32 rflr:1; // bit 7
+ u32 raln:1; // bit 8
+ u32 rxuo:1; // bit 9
+ u32 rxpf:1; // bit 10
+ u32 rxcf:1; // bit 11
+ u32 rbca:1; // bit 12
+ u32 rmca:1; // bit 13
+ u32 rfcs:1; // bit 14
+ u32 rpkt:1; // bit 15
+ u32 rbyt:1; // bit 16
+ u32 unused:8; // bits 17-24
+ u32 trmgv:1; // bit 25
+ u32 trmax:1; // bit 26
+ u32 tr1k:1; // bit 27
+ u32 tr511:1; // bit 28
+ u32 tr255:1; // bit 29
+ u32 tr127:1; // bit 30
+ u32 tr64:1; // bit 31
+#endif
+ } bits;
+} MAC_STAT_REG_1_t, *PMAC_STAT_REG_1_t;
+
+/*
+ * structure for Carry Register Two Mask Register reg in mac stat address map.
+ * located at address 0x613C
+ */
+typedef union _MAC_STAT_REG_2_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused:12; // bit 20-31
+ u32 tjbr:1; // bit 19
+ u32 tfcs:1; // bit 18
+ u32 txcf:1; // bit 17
+ u32 tovr:1; // bit 16
+ u32 tund:1; // bit 15
+ u32 tfrg:1; // bit 14
+ u32 tbyt:1; // bit 13
+ u32 tpkt:1; // bit 12
+ u32 tmca:1; // bit 11
+ u32 tbca:1; // bit 10
+ u32 txpf:1; // bit 9
+ u32 tdfr:1; // bit 8
+ u32 tedf:1; // bit 7
+ u32 tscl:1; // bit 6
+ u32 tmcl:1; // bit 5
+ u32 tlcl:1; // bit 4
+ u32 txcl:1; // bit 3
+ u32 tncl:1; // bit 2
+ u32 tpfh:1; // bit 1
+ u32 tdrp:1; // bit 0
+#else
+ u32 tdrp:1; // bit 0
+ u32 tpfh:1; // bit 1
+ u32 tncl:1; // bit 2
+ u32 txcl:1; // bit 3
+ u32 tlcl:1; // bit 4
+ u32 tmcl:1; // bit 5
+ u32 tscl:1; // bit 6
+ u32 tedf:1; // bit 7
+ u32 tdfr:1; // bit 8
+ u32 txpf:1; // bit 9
+ u32 tbca:1; // bit 10
+ u32 tmca:1; // bit 11
+ u32 tpkt:1; // bit 12
+ u32 tbyt:1; // bit 13
+ u32 tfrg:1; // bit 14
+ u32 tund:1; // bit 15
+ u32 tovr:1; // bit 16
+ u32 txcf:1; // bit 17
+ u32 tfcs:1; // bit 18
+ u32 tjbr:1; // bit 19
+ u32 unused:12; // bit 20-31
+#endif
+ } bits;
+} MAC_STAT_REG_2_t, *PMAC_STAT_REG_2_t;
+
+/*
+ * MAC STATS Module of JAGCore Address Mapping
+ */
+typedef struct _MAC_STAT_t { // Location:
+ u32 pad[32]; // 0x6000 - 607C
+
+ // Tx/Rx 0-64 Byte Frame Counter
+ u32 TR64; // 0x6080
+
+ // Tx/Rx 65-127 Byte Frame Counter
+ u32 TR127; // 0x6084
+
+ // Tx/Rx 128-255 Byte Frame Counter
+ u32 TR255; // 0x6088
+
+ // Tx/Rx 256-511 Byte Frame Counter
+ u32 TR511; // 0x608C
+
+ // Tx/Rx 512-1023 Byte Frame Counter
+ u32 TR1K; // 0x6090
+
+ // Tx/Rx 1024-1518 Byte Frame Counter
+ u32 TRMax; // 0x6094
+
+ // Tx/Rx 1519-1522 Byte Good VLAN Frame Count
+ u32 TRMgv; // 0x6098
+
+ // Rx Byte Counter
+ u32 RByt; // 0x609C
+
+ // Rx Packet Counter
+ u32 RPkt; // 0x60A0
+
+ // Rx FCS Error Counter
+ u32 RFcs; // 0x60A4
+
+ // Rx Multicast Packet Counter
+ u32 RMca; // 0x60A8
+
+ // Rx Broadcast Packet Counter
+ u32 RBca; // 0x60AC
+
+ // Rx Control Frame Packet Counter
+ u32 RxCf; // 0x60B0
+
+ // Rx Pause Frame Packet Counter
+ u32 RxPf; // 0x60B4
+
+ // Rx Unknown OP Code Counter
+ u32 RxUo; // 0x60B8
+
+ // Rx Alignment Error Counter
+ u32 RAln; // 0x60BC
+
+ // Rx Frame Length Error Counter
+ u32 RFlr; // 0x60C0
+
+ // Rx Code Error Counter
+ u32 RCde; // 0x60C4
+
+ // Rx Carrier Sense Error Counter
+ u32 RCse; // 0x60C8
+
+ // Rx Undersize Packet Counter
+ u32 RUnd; // 0x60CC
+
+ // Rx Oversize Packet Counter
+ u32 ROvr; // 0x60D0
+
+ // Rx Fragment Counter
+ u32 RFrg; // 0x60D4
+
+ // Rx Jabber Counter
+ u32 RJbr; // 0x60D8
+
+ // Rx Drop
+ u32 RDrp; // 0x60DC
+
+ // Tx Byte Counter
+ u32 TByt; // 0x60E0
+
+ // Tx Packet Counter
+ u32 TPkt; // 0x60E4
+
+ // Tx Multicast Packet Counter
+ u32 TMca; // 0x60E8
+
+ // Tx Broadcast Packet Counter
+ u32 TBca; // 0x60EC
+
+ // Tx Pause Control Frame Counter
+ u32 TxPf; // 0x60F0
+
+ // Tx Deferral Packet Counter
+ u32 TDfr; // 0x60F4
+
+ // Tx Excessive Deferral Packet Counter
+ u32 TEdf; // 0x60F8
+
+ // Tx Single Collision Packet Counter
+ u32 TScl; // 0x60FC
+
+ // Tx Multiple Collision Packet Counter
+ u32 TMcl; // 0x6100
+
+ // Tx Late Collision Packet Counter
+ u32 TLcl; // 0x6104
+
+ // Tx Excessive Collision Packet Counter
+ u32 TXcl; // 0x6108
+
+ // Tx Total Collision Packet Counter
+ u32 TNcl; // 0x610C
+
+ // Tx Pause Frame Honored Counter
+ u32 TPfh; // 0x6110
+
+ // Tx Drop Frame Counter
+ u32 TDrp; // 0x6114
+
+ // Tx Jabber Frame Counter
+ u32 TJbr; // 0x6118
+
+ // Tx FCS Error Counter
+ u32 TFcs; // 0x611C
+
+ // Tx Control Frame Counter
+ u32 TxCf; // 0x6120
+
+ // Tx Oversize Frame Counter
+ u32 TOvr; // 0x6124
+
+ // Tx Undersize Frame Counter
+ u32 TUnd; // 0x6128
+
+ // Tx Fragments Frame Counter
+ u32 TFrg; // 0x612C
+
+ // Carry Register One Register
+ MAC_STAT_REG_1_t Carry1; // 0x6130
+
+ // Carry Register Two Register
+ MAC_STAT_REG_2_t Carry2; // 0x6134
+
+ // Carry Register One Mask Register
+ MAC_STAT_REG_1_t Carry1M; // 0x6138
+
+ // Carry Register Two Mask Register
+ MAC_STAT_REG_2_t Carry2M; // 0x613C
+} MAC_STAT_t, *PMAC_STAT_t;
+
+/* END OF MAC STAT REGISTER ADDRESS MAP */
+
+
+/* START OF MMC REGISTER ADDRESS MAP */
+
+/*
+ * structure for Main Memory Controller Control reg in mmc address map.
+ * located at address 0x7000
+ */
+typedef union _MMC_CTRL_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 reserved:25; // bits 7-31
+ u32 force_ce:1; // bit 6
+ u32 rxdma_disable:1; // bit 5
+ u32 txdma_disable:1; // bit 4
+ u32 txmac_disable:1; // bit 3
+ u32 rxmac_disable:1; // bit 2
+ u32 arb_disable:1; // bit 1
+ u32 mmc_enable:1; // bit 0
+#else
+ u32 mmc_enable:1; // bit 0
+ u32 arb_disable:1; // bit 1
+ u32 rxmac_disable:1; // bit 2
+ u32 txmac_disable:1; // bit 3
+ u32 txdma_disable:1; // bit 4
+ u32 rxdma_disable:1; // bit 5
+ u32 force_ce:1; // bit 6
+ u32 reserved:25; // bits 7-31
+#endif
+ } bits;
+} MMC_CTRL_t, *PMMC_CTRL_t;
+
+/*
+ * structure for Main Memory Controller Host Memory Access Address reg in mmc
+ * address map. Located at address 0x7004
+ */
+typedef union _MMC_SRAM_ACCESS_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 byte_enable:16; // bits 16-31
+ u32 reserved2:2; // bits 14-15
+ u32 req_addr:10; // bits 4-13
+ u32 reserved1:1; // bit 3
+ u32 is_ctrl_word:1; // bit 2
+ u32 wr_access:1; // bit 1
+ u32 req_access:1; // bit 0
+#else
+ u32 req_access:1; // bit 0
+ u32 wr_access:1; // bit 1
+ u32 is_ctrl_word:1; // bit 2
+ u32 reserved1:1; // bit 3
+ u32 req_addr:10; // bits 4-13
+ u32 reserved2:2; // bits 14-15
+ u32 byte_enable:16; // bits 16-31
+#endif
+ } bits;
+} MMC_SRAM_ACCESS_t, *PMMC_SRAM_ACCESS_t;
+
+/*
+ * structure for Main Memory Controller Host Memory Access Data reg in mmc
+ * address map. Located at address 0x7008 - 0x7014
+ * Defined earlier (u32)
+ */
+
+/*
+ * Memory Control Module of JAGCore Address Mapping
+ */
+typedef struct _MMC_t { // Location:
+ MMC_CTRL_t mmc_ctrl; // 0x7000
+ MMC_SRAM_ACCESS_t sram_access; // 0x7004
+ u32 sram_word1; // 0x7008
+ u32 sram_word2; // 0x700C
+ u32 sram_word3; // 0x7010
+ u32 sram_word4; // 0x7014
+} MMC_t, *PMMC_t;
+
+/* END OF MMC REGISTER ADDRESS MAP */
+
+
+/* START OF EXP ROM REGISTER ADDRESS MAP */
+
+/*
+ * Expansion ROM Module of JAGCore Address Mapping
+ */
+
+/* Take this out until it is not empty */
+#if 0
+typedef struct _EXP_ROM_t {
+
+} EXP_ROM_t, *PEXP_ROM_t;
+#endif
+
+/* END OF EXP ROM REGISTER ADDRESS MAP */
+
+
+/*
+ * JAGCore Address Mapping
+ */
+typedef struct _ADDRESS_MAP_t {
+ GLOBAL_t global;
+ // unused section of global address map
+ u8 unused_global[4096 - sizeof(GLOBAL_t)];
+ TXDMA_t txdma;
+ // unused section of txdma address map
+ u8 unused_txdma[4096 - sizeof(TXDMA_t)];
+ RXDMA_t rxdma;
+ // unused section of rxdma address map
+ u8 unused_rxdma[4096 - sizeof(RXDMA_t)];
+ TXMAC_t txmac;
+ // unused section of txmac address map
+ u8 unused_txmac[4096 - sizeof(TXMAC_t)];
+ RXMAC_t rxmac;
+ // unused section of rxmac address map
+ u8 unused_rxmac[4096 - sizeof(RXMAC_t)];
+ MAC_t mac;
+ // unused section of mac address map
+ u8 unused_mac[4096 - sizeof(MAC_t)];
+ MAC_STAT_t macStat;
+ // unused section of mac stat address map
+ u8 unused_mac_stat[4096 - sizeof(MAC_STAT_t)];
+ MMC_t mmc;
+ // unused section of mmc address map
+ u8 unused_mmc[4096 - sizeof(MMC_t)];
+ // unused section of address map
+ u8 unused_[1015808];
+
+/* Take this out until it is not empty */
+#if 0
+ EXP_ROM_t exp_rom;
+#endif
+
+ u8 unused_exp_rom[4096]; // MGS-size TBD
+ u8 unused__[524288]; // unused section of address map
+} ADDRESS_MAP_t, *PADDRESS_MAP_t;
+
+#endif /* _ET1310_ADDRESS_MAP_H_ */
diff --git a/drivers/staging/et131x/et1310_eeprom.c b/drivers/staging/et131x/et1310_eeprom.c
new file mode 100644
index 0000000..c2b194e
--- /dev/null
+++ b/drivers/staging/et131x/et1310_eeprom.c
@@ -0,0 +1,480 @@
+/*
+ * Agere Systems Inc.
+ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * et1310_eeprom.c - Code used to access the device's EEPROM
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#include "et131x_version.h"
+#include "et131x_debug.h"
+#include "et131x_defs.h"
+
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+
+#include "et1310_phy.h"
+#include "et1310_pm.h"
+#include "et1310_jagcore.h"
+#include "et1310_eeprom.h"
+
+#include "et131x_adapter.h"
+#include "et131x_initpci.h"
+#include "et131x_isr.h"
+
+#include "et1310_tx.h"
+
+
+/*
+ * EEPROM Defines
+ */
+
+/* LBCIF Register Groups (addressed via 32-bit offsets) */
+#define LBCIF_DWORD0_GROUP_OFFSET 0xAC
+#define LBCIF_DWORD1_GROUP_OFFSET 0xB0
+
+/* LBCIF Registers (addressed via 8-bit offsets) */
+#define LBCIF_ADDRESS_REGISTER_OFFSET 0xAC
+#define LBCIF_DATA_REGISTER_OFFSET 0xB0
+#define LBCIF_CONTROL_REGISTER_OFFSET 0xB1
+#define LBCIF_STATUS_REGISTER_OFFSET 0xB2
+
+/* LBCIF Control Register Bits */
+#define LBCIF_CONTROL_SEQUENTIAL_READ 0x01
+#define LBCIF_CONTROL_PAGE_WRITE 0x02
+#define LBCIF_CONTROL_UNUSED1 0x04
+#define LBCIF_CONTROL_EEPROM_RELOAD 0x08
+#define LBCIF_CONTROL_UNUSED2 0x10
+#define LBCIF_CONTROL_TWO_BYTE_ADDR 0x20
+#define LBCIF_CONTROL_I2C_WRITE 0x40
+#define LBCIF_CONTROL_LBCIF_ENABLE 0x80
+
+/* LBCIF Status Register Bits */
+#define LBCIF_STATUS_PHY_QUEUE_AVAIL 0x01
+#define LBCIF_STATUS_I2C_IDLE 0x02
+#define LBCIF_STATUS_ACK_ERROR 0x04
+#define LBCIF_STATUS_GENERAL_ERROR 0x08
+#define LBCIF_STATUS_UNUSED 0x30
+#define LBCIF_STATUS_CHECKSUM_ERROR 0x40
+#define LBCIF_STATUS_EEPROM_PRESENT 0x80
+
+/* Miscellaneous Constraints */
+#define MAX_NUM_REGISTER_POLLS 1000
+#define MAX_NUM_WRITE_RETRIES 2
+
+/*
+ * Define macros that allow individual register values to be extracted from a
+ * DWORD1 register grouping
+ */
+#define EXTRACT_DATA_REGISTER(x) (uint8_t)(x & 0xFF)
+#define EXTRACT_STATUS_REGISTER(x) (uint8_t)((x >> 16) & 0xFF)
+#define EXTRACT_CONTROL_REG(x) (uint8_t)((x >> 8) & 0xFF)
+
+/**
+ * EepromWriteByte - Write a byte to the ET1310's EEPROM
+ * @pAdapter: pointer to our private adapter structure
+ * @unAddress: the address to write
+ * @bData: the value to write
+ * @unEepronId: the ID of the EEPROM
+ * @unAddressingMode: how the EEPROM is to be accessed
+ *
+ * Returns SUCCESS or FAILURE
+ */
+int32_t EepromWriteByte(struct et131x_adapter *pAdapter, uint32_t unAddress,
+ uint8_t bData, uint32_t unEepromId,
+ uint32_t unAddressingMode)
+{
+ struct pci_dev *pdev = pAdapter->pdev;
+ int32_t nIndex;
+ int32_t nRetries;
+ int32_t nError = false;
+ int32_t nI2CWriteActive = 0;
+ int32_t nWriteSuccessful = 0;
+ uint8_t bControl;
+ uint8_t bStatus = 0;
+ uint32_t unDword1 = 0;
+ uint32_t unData = 0;
+
+ /*
+ * The following excerpt is from "Serial EEPROM HW Design
+ * Specification" Version 0.92 (9/20/2004):
+ *
+ * Single Byte Writes
+ *
+ * For an EEPROM, an I2C single byte write is defined as a START
+ * condition followed by the device address, EEPROM address, one byte
+ * of data and a STOP condition. The STOP condition will trigger the
+ * EEPROM's internally timed write cycle to the nonvolatile memory.
+ * All inputs are disabled during this write cycle and the EEPROM will
+ * not respond to any access until the internal write is complete.
+ * The steps to execute a single byte write are as follows:
+ *
+ * 1. Check LBCIF Status Register for bits 6 & 3:2 all equal to 0 and
+ * bits 7,1:0 both equal to 1, at least once after reset.
+ * Subsequent operations need only to check that bits 1:0 are
+ * equal to 1 prior to starting a single byte write.
+ *
+ * 2. Write to the LBCIF Control Register: bit 7=1, bit 6=1, bit 3=0,
+ * and bits 1:0 both =0. Bit 5 should be set according to the
+ * type of EEPROM being accessed (1=two byte addressing, 0=one
+ * byte addressing).
+ *
+ * 3. Write the address to the LBCIF Address Register.
+ *
+ * 4. Write the data to the LBCIF Data Register (the I2C write will
+ * begin).
+ *
+ * 5. Monitor bit 1:0 of the LBCIF Status Register. When bits 1:0 are
+ * both equal to 1, the I2C write has completed and the internal
+ * write cycle of the EEPROM is about to start. (bits 1:0 = 01 is
+ * a legal state while waiting from both equal to 1, but bits
+ * 1:0 = 10 is invalid and implies that something is broken).
+ *
+ * 6. Check bit 3 of the LBCIF Status Register. If equal to 1, an
+ * error has occurred.
+ *
+ * 7. Check bit 2 of the LBCIF Status Register. If equal to 1 an ACK
+ * error has occurred on the address phase of the write. This
+ * could be due to an actual hardware failure or the EEPROM may
+ * still be in its internal write cycle from a previous write.
+ * This write operation was ignored and must be repeated later.
+ *
+ * 8. Set bit 6 of the LBCIF Control Register = 0. If another write is
+ * required, go to step 1.
+ */
+
+ /* Step 1: */
+ for (nIndex = 0; nIndex < MAX_NUM_REGISTER_POLLS; nIndex++) {
+ /* Read registers grouped in DWORD1 */
+ if (pci_read_config_dword(pdev, LBCIF_DWORD1_GROUP_OFFSET,
+ &unDword1)) {
+ nError = 1;
+ break;
+ }
+
+ bStatus = EXTRACT_STATUS_REGISTER(unDword1);
+
+ if (bStatus & LBCIF_STATUS_PHY_QUEUE_AVAIL &&
+ bStatus & LBCIF_STATUS_I2C_IDLE) {
+ /* bits 1:0 are equal to 1 */
+ break;
+ }
+ }
+
+ if (nError || (nIndex >= MAX_NUM_REGISTER_POLLS)) {
+ return FAILURE;
+ }
+
+ /* Step 2: */
+ bControl = 0;
+ bControl |= LBCIF_CONTROL_LBCIF_ENABLE | LBCIF_CONTROL_I2C_WRITE;
+
+ if (unAddressingMode == DUAL_BYTE) {
+ bControl |= LBCIF_CONTROL_TWO_BYTE_ADDR;
+ }
+
+ if (pci_write_config_byte(pdev, LBCIF_CONTROL_REGISTER_OFFSET,
+ bControl)) {
+ return FAILURE;
+ }
+
+ nI2CWriteActive = 1;
+
+ /* Prepare EEPROM address for Step 3 */
+ unAddress |= (unAddressingMode == DUAL_BYTE) ?
+ (unEepromId << 16) : (unEepromId << 8);
+
+ for (nRetries = 0; nRetries < MAX_NUM_WRITE_RETRIES; nRetries++) {
+ /* Step 3:*/
+ if (pci_write_config_dword(pdev, LBCIF_ADDRESS_REGISTER_OFFSET,
+ unAddress)) {
+ break;
+ }
+
+ /* Step 4: */
+ if (pci_write_config_byte(pdev, LBCIF_DATA_REGISTER_OFFSET,
+ bData)) {
+ break;
+ }
+
+ /* Step 5: */
+ for (nIndex = 0; nIndex < MAX_NUM_REGISTER_POLLS; nIndex++) {
+ /* Read registers grouped in DWORD1 */
+ if (pci_read_config_dword(pdev,
+ LBCIF_DWORD1_GROUP_OFFSET,
+ &unDword1)) {
+ nError = 1;
+ break;
+ }
+
+ bStatus = EXTRACT_STATUS_REGISTER(unDword1);
+
+ if (bStatus & LBCIF_STATUS_PHY_QUEUE_AVAIL &&
+ bStatus & LBCIF_STATUS_I2C_IDLE) {
+ /* I2C write complete */
+ break;
+ }
+ }
+
+ if (nError || (nIndex >= MAX_NUM_REGISTER_POLLS)) {
+ break;
+ }
+
+ /*
+ * Step 6: Don't break here if we are revision 1, this is
+ * so we do a blind write for load bug.
+ */
+ if (bStatus & LBCIF_STATUS_GENERAL_ERROR
+ && pAdapter->RevisionID == 0) {
+ break;
+ }
+
+ /* Step 7 */
+ if (bStatus & LBCIF_STATUS_ACK_ERROR) {
+ /*
+ * This could be due to an actual hardware failure
+ * or the EEPROM may still be in its internal write
+ * cycle from a previous write. This write operation
+ * was ignored and must be repeated later.
+ */
+ udelay(10);
+ continue;
+ }
+
+ nWriteSuccessful = 1;
+ break;
+ }
+
+ /* Step 8: */
+ udelay(10);
+ nIndex = 0;
+ while (nI2CWriteActive) {
+ bControl &= ~LBCIF_CONTROL_I2C_WRITE;
+
+ if (pci_write_config_byte(pdev, LBCIF_CONTROL_REGISTER_OFFSET,
+ bControl)) {
+ nWriteSuccessful = 0;
+ }
+
+ /* Do read until internal ACK_ERROR goes away meaning write
+ * completed
+ */
+ do {
+ pci_write_config_dword(pdev,
+ LBCIF_ADDRESS_REGISTER_OFFSET,
+ unAddress);
+ do {
+ pci_read_config_dword(pdev,
+ LBCIF_DATA_REGISTER_OFFSET, &unData);
+ } while ((unData & 0x00010000) == 0);
+ } while (unData & 0x00040000);
+
+ bControl = EXTRACT_CONTROL_REG(unData);
+
+ if (bControl != 0xC0 || nIndex == 10000) {
+ break;
+ }
+
+ nIndex++;
+ }
+
+ return nWriteSuccessful ? SUCCESS : FAILURE;
+}
+
+/**
+ * EepromReadByte - Read a byte from the ET1310's EEPROM
+ * @pAdapter: pointer to our private adapter structure
+ * @unAddress: the address from which to read
+ * @pbData: a pointer to a byte in which to store the value of the read
+ * @unEepronId: the ID of the EEPROM
+ * @unAddressingMode: how the EEPROM is to be accessed
+ *
+ * Returns SUCCESS or FAILURE
+ */
+int32_t EepromReadByte(struct et131x_adapter *pAdapter, uint32_t unAddress,
+ uint8_t *pbData, uint32_t unEepromId,
+ uint32_t unAddressingMode)
+{
+ struct pci_dev *pdev = pAdapter->pdev;
+ int32_t nIndex;
+ int32_t nError = 0;
+ uint8_t bControl;
+ uint8_t bStatus = 0;
+ uint32_t unDword1 = 0;
+
+ /*
+ * The following excerpt is from "Serial EEPROM HW Design
+ * Specification" Version 0.92 (9/20/2004):
+ *
+ * Single Byte Reads
+ *
+ * A single byte read is similar to the single byte write, with the
+ * exception of the data flow:
+ *
+ * 1. Check LBCIF Status Register for bits 6 & 3:2 all equal to 0 and
+ * bits 7,1:0 both equal to 1, at least once after reset.
+ * Subsequent operations need only to check that bits 1:0 are equal
+ * to 1 prior to starting a single byte read.
+ *
+ * 2. Write to the LBCIF Control Register: bit 7=1, bit 6=0, bit 3=0,
+ * and bits 1:0 both =0. Bit 5 should be set according to the type
+ * of EEPROM being accessed (1=two byte addressing, 0=one byte
+ * addressing).
+ *
+ * 3. Write the address to the LBCIF Address Register (I2C read will
+ * begin).
+ *
+ * 4. Monitor bit 0 of the LBCIF Status Register. When =1, I2C read
+ * is complete. (if bit 1 =1 and bit 0 stays =0, a hardware failure
+ * has occurred).
+ *
+ * 5. Check bit 2 of the LBCIF Status Register. If =1, then an error
+ * has occurred. The data that has been returned from the PHY may
+ * be invalid.
+ *
+ * 6. Regardless of error status, read data byte from LBCIF Data
+ * Register. If another byte is required, go to step 1.
+ */
+
+ /* Step 1: */
+ for (nIndex = 0; nIndex < MAX_NUM_REGISTER_POLLS; nIndex++) {
+ /* Read registers grouped in DWORD1 */
+ if (pci_read_config_dword(pdev, LBCIF_DWORD1_GROUP_OFFSET,
+ &unDword1)) {
+ nError = 1;
+ break;
+ }
+
+ bStatus = EXTRACT_STATUS_REGISTER(unDword1);
+
+ if (bStatus & LBCIF_STATUS_PHY_QUEUE_AVAIL &&
+ bStatus & LBCIF_STATUS_I2C_IDLE) {
+ /* bits 1:0 are equal to 1 */
+ break;
+ }
+ }
+
+ if (nError || (nIndex >= MAX_NUM_REGISTER_POLLS)) {
+ return FAILURE;
+ }
+
+ /* Step 2: */
+ bControl = 0;
+ bControl |= LBCIF_CONTROL_LBCIF_ENABLE;
+
+ if (unAddressingMode == DUAL_BYTE) {
+ bControl |= LBCIF_CONTROL_TWO_BYTE_ADDR;
+ }
+
+ if (pci_write_config_byte(pdev, LBCIF_CONTROL_REGISTER_OFFSET,
+ bControl)) {
+ return FAILURE;
+ }
+
+ /* Step 3: */
+ unAddress |= (unAddressingMode == DUAL_BYTE) ?
+ (unEepromId << 16) : (unEepromId << 8);
+
+ if (pci_write_config_dword(pdev, LBCIF_ADDRESS_REGISTER_OFFSET,
+ unAddress)) {
+ return FAILURE;
+ }
+
+ /* Step 4: */
+ for (nIndex = 0; nIndex < MAX_NUM_REGISTER_POLLS; nIndex++) {
+ /* Read registers grouped in DWORD1 */
+ if (pci_read_config_dword(pdev, LBCIF_DWORD1_GROUP_OFFSET,
+ &unDword1)) {
+ nError = 1;
+ break;
+ }
+
+ bStatus = EXTRACT_STATUS_REGISTER(unDword1);
+
+ if (bStatus & LBCIF_STATUS_PHY_QUEUE_AVAIL
+ && bStatus & LBCIF_STATUS_I2C_IDLE) {
+ /* I2C read complete */
+ break;
+ }
+ }
+
+ if (nError || (nIndex >= MAX_NUM_REGISTER_POLLS)) {
+ return FAILURE;
+ }
+
+ /* Step 6: */
+ *pbData = EXTRACT_DATA_REGISTER(unDword1);
+
+ return (bStatus & LBCIF_STATUS_ACK_ERROR) ? FAILURE : SUCCESS;
+}
diff --git a/drivers/staging/et131x/et1310_eeprom.h b/drivers/staging/et131x/et1310_eeprom.h
new file mode 100644
index 0000000..9b6f8ad
--- /dev/null
+++ b/drivers/staging/et131x/et1310_eeprom.h
@@ -0,0 +1,89 @@
+/*
+ * Agere Systems Inc.
+ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * et1310_eeprom.h - Defines, structs, enums, prototypes, etc. used for EEPROM
+ * access routines
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#ifndef __ET1310_EEPROM_H__
+#define __ET1310_EEPROM_H__
+
+#include "et1310_address_map.h"
+
+#ifndef SUCCESS
+#define SUCCESS 0
+#define FAILURE 1
+#endif
+
+#ifndef READ
+#define READ 0
+#define WRITE 1
+#endif
+
+#ifndef SINGLE_BYTE
+#define SINGLE_BYTE 0
+#define DUAL_BYTE 1
+#endif
+
+/* Forward declaration of the private adapter structure */
+struct et131x_adapter;
+
+int32_t EepromWriteByte(struct et131x_adapter *adapter, u32 unAddress,
+ u8 bData, u32 unEepromId,
+ u32 unAddressingMode);
+int32_t EepromReadByte(struct et131x_adapter *adapter, u32 unAddress,
+ u8 *pbData, u32 unEepromId,
+ u32 unAddressingMode);
+
+#endif /* _ET1310_EEPROM_H_ */
diff --git a/drivers/staging/et131x/et1310_jagcore.c b/drivers/staging/et131x/et1310_jagcore.c
new file mode 100644
index 0000000..993b30e
--- /dev/null
+++ b/drivers/staging/et131x/et1310_jagcore.c
@@ -0,0 +1,220 @@
+/*
+ * Agere Systems Inc.
+ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * et1310_jagcore.c - All code pertaining to the ET1301/ET131x's JAGcore
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#include "et131x_version.h"
+#include "et131x_debug.h"
+#include "et131x_defs.h"
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+
+#include "et1310_phy.h"
+#include "et1310_pm.h"
+#include "et1310_jagcore.h"
+
+#include "et131x_adapter.h"
+#include "et131x_initpci.h"
+
+/* Data for debugging facilities */
+#ifdef CONFIG_ET131X_DEBUG
+extern dbg_info_t *et131x_dbginfo;
+#endif /* CONFIG_ET131X_DEBUG */
+
+/**
+ * ConfigGlobalRegs - Used to configure the global registers on the JAGCore
+ * @pAdpater: pointer to our adapter structure
+ */
+void ConfigGlobalRegs(struct et131x_adapter *pAdapter)
+{
+ struct _GLOBAL_t __iomem *pGbl = &pAdapter->CSRAddress->global;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ if (pAdapter->RegistryPhyLoopbk == false) {
+ if (pAdapter->RegistryJumboPacket < 2048) {
+ /* Tx / RxDMA and Tx/Rx MAC interfaces have a 1k word
+ * block of RAM that the driver can split between Tx
+ * and Rx as it desires. Our default is to split it
+ * 50/50:
+ */
+ writel(0, &pGbl->rxq_start_addr.value);
+ writel(pAdapter->RegistryRxMemEnd,
+ &pGbl->rxq_end_addr.value);
+ writel(pAdapter->RegistryRxMemEnd + 1,
+ &pGbl->txq_start_addr.value);
+ writel(INTERNAL_MEM_SIZE - 1,
+ &pGbl->txq_end_addr.value);
+ } else if (pAdapter->RegistryJumboPacket < 8192) {
+ /* For jumbo packets > 2k but < 8k, split 50-50. */
+ writel(0, &pGbl->rxq_start_addr.value);
+ writel(INTERNAL_MEM_RX_OFFSET,
+ &pGbl->rxq_end_addr.value);
+ writel(INTERNAL_MEM_RX_OFFSET + 1,
+ &pGbl->txq_start_addr.value);
+ writel(INTERNAL_MEM_SIZE - 1,
+ &pGbl->txq_end_addr.value);
+ } else {
+ /* 9216 is the only packet size greater than 8k that
+ * is available. The Tx buffer has to be big enough
+ * for one whole packet on the Tx side. We'll make
+ * the Tx 9408, and give the rest to Rx
+ */
+ writel(0x0000, &pGbl->rxq_start_addr.value);
+ writel(0x01b3, &pGbl->rxq_end_addr.value);
+ writel(0x01b4, &pGbl->txq_start_addr.value);
+ writel(INTERNAL_MEM_SIZE - 1,
+ &pGbl->txq_end_addr.value);
+ }
+
+ /* Initialize the loopback register. Disable all loopbacks. */
+ writel(0, &pGbl->loopback.value);
+ } else {
+ /* For PHY Line loopback, the memory is configured as if Tx
+ * and Rx both have all the memory. This is because the
+ * RxMAC will write data into the space, and the TxMAC will
+ * read it out.
+ */
+ writel(0, &pGbl->rxq_start_addr.value);
+ writel(INTERNAL_MEM_SIZE - 1, &pGbl->rxq_end_addr.value);
+ writel(0, &pGbl->txq_start_addr.value);
+ writel(INTERNAL_MEM_SIZE - 1, &pGbl->txq_end_addr.value);
+
+ /* Initialize the loopback register (MAC loopback). */
+ writel(1, &pGbl->loopback.value);
+ }
+
+ /* MSI Register */
+ writel(0, &pGbl->msi_config.value);
+
+ /* By default, disable the watchdog timer. It will be enabled when
+ * a packet is queued.
+ */
+ writel(0, &pGbl->watchdog_timer);
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * ConfigMMCRegs - Used to configure the main memory registers in the JAGCore
+ * @pAdapter: pointer to our adapter structure
+ */
+void ConfigMMCRegs(struct et131x_adapter *pAdapter)
+{
+ MMC_CTRL_t mmc_ctrl = { 0 };
+
+ DBG_ENTER(et131x_dbginfo);
+
+ /* All we need to do is initialize the Memory Control Register */
+ mmc_ctrl.bits.force_ce = 0x0;
+ mmc_ctrl.bits.rxdma_disable = 0x0;
+ mmc_ctrl.bits.txdma_disable = 0x0;
+ mmc_ctrl.bits.txmac_disable = 0x0;
+ mmc_ctrl.bits.rxmac_disable = 0x0;
+ mmc_ctrl.bits.arb_disable = 0x0;
+ mmc_ctrl.bits.mmc_enable = 0x1;
+
+ writel(mmc_ctrl.value, &pAdapter->CSRAddress->mmc.mmc_ctrl.value);
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+void et131x_enable_interrupts(struct et131x_adapter *adapter)
+{
+ uint32_t MaskValue;
+
+ /* Enable all global interrupts */
+ if ((adapter->FlowControl == TxOnly) || (adapter->FlowControl == Both)) {
+ MaskValue = INT_MASK_ENABLE;
+ } else {
+ MaskValue = INT_MASK_ENABLE_NO_FLOW;
+ }
+
+ if (adapter->DriverNoPhyAccess) {
+ MaskValue |= 0x10000;
+ }
+
+ adapter->CachedMaskValue.value = MaskValue;
+ writel(MaskValue, &adapter->CSRAddress->global.int_mask.value);
+}
+
+void et131x_disable_interrupts(struct et131x_adapter * adapter)
+{
+ /* Disable all global interrupts */
+ adapter->CachedMaskValue.value = INT_MASK_DISABLE;
+ writel(INT_MASK_DISABLE, &adapter->CSRAddress->global.int_mask.value);
+}
diff --git a/drivers/staging/et131x/et1310_jagcore.h b/drivers/staging/et131x/et1310_jagcore.h
new file mode 100644
index 0000000..9fc8293
--- /dev/null
+++ b/drivers/staging/et131x/et1310_jagcore.h
@@ -0,0 +1,112 @@
+/*
+ * Agere Systems Inc.
+ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * et1310_jagcore.h - Defines, structs, enums, prototypes, etc. pertaining to
+ * the JAGCore
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#ifndef __ET1310_JAGCORE_H__
+#define __ET1310_JAGCORE_H__
+
+#include "et1310_address_map.h"
+
+
+#define INTERNAL_MEM_SIZE 0x400 //1024 of internal memory
+#define INTERNAL_MEM_RX_OFFSET 0x1FF //50% Tx, 50% Rx
+
+#define REGS_MAX_ARRAY 4096
+
+/*
+ * For interrupts, normal running is:
+ * rxdma_xfr_done, phy_interrupt, mac_stat_interrupt,
+ * watchdog_interrupt & txdma_xfer_done
+ *
+ * In both cases, when flow control is enabled for either Tx or bi-direction,
+ * we additional enable rx_fbr0_low and rx_fbr1_low, so we know when the
+ * buffer rings are running low.
+ */
+#define INT_MASK_DISABLE 0xffffffff
+
+// NOTE: Masking out MAC_STAT Interrupt for now...
+//#define INT_MASK_ENABLE 0xfff6bf17
+//#define INT_MASK_ENABLE_NO_FLOW 0xfff6bfd7
+#define INT_MASK_ENABLE 0xfffebf17
+#define INT_MASK_ENABLE_NO_FLOW 0xfffebfd7
+
+/* DATA STRUCTURES FOR DIRECT REGISTER ACCESS */
+
+typedef struct {
+ u8 bReadWrite;
+ u32 nRegCount;
+ u32 nData[REGS_MAX_ARRAY];
+ u32 nOffsets[REGS_MAX_ARRAY];
+} JAGCORE_ACCESS_REGS, *PJAGCORE_ACCESS_REGS;
+
+typedef struct {
+ u8 bReadWrite;
+ u32 nDataWidth;
+ u32 nRegCount;
+ u32 nOffsets[REGS_MAX_ARRAY];
+ u32 nData[REGS_MAX_ARRAY];
+} PCI_CFG_SPACE_REGS, *PPCI_CFG_SPACE_REGS;
+
+/* Forward declaration of the private adapter structure */
+struct et131x_adapter;
+
+void ConfigGlobalRegs(struct et131x_adapter *pAdapter);
+void ConfigMMCRegs(struct et131x_adapter *pAdapter);
+void et131x_enable_interrupts(struct et131x_adapter *adapter);
+void et131x_disable_interrupts(struct et131x_adapter *adapter);
+
+#endif /* __ET1310_JAGCORE_H__ */
diff --git a/drivers/staging/et131x/et1310_mac.c b/drivers/staging/et131x/et1310_mac.c
new file mode 100644
index 0000000..1924968
--- /dev/null
+++ b/drivers/staging/et131x/et1310_mac.c
@@ -0,0 +1,792 @@
+/*
+ * Agere Systems Inc.
+ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * et1310_mac.c - All code and routines pertaining to the MAC
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#include "et131x_version.h"
+#include "et131x_debug.h"
+#include "et131x_defs.h"
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+#include <linux/crc32.h>
+
+#include "et1310_phy.h"
+#include "et1310_pm.h"
+#include "et1310_jagcore.h"
+#include "et1310_mac.h"
+
+#include "et131x_adapter.h"
+#include "et131x_initpci.h"
+
+/* Data for debugging facilities */
+#ifdef CONFIG_ET131X_DEBUG
+extern dbg_info_t *et131x_dbginfo;
+#endif /* CONFIG_ET131X_DEBUG */
+
+/**
+ * ConfigMacRegs1 - Initialize the first part of MAC regs
+ * @pAdpater: pointer to our adapter structure
+ */
+void ConfigMACRegs1(struct et131x_adapter *pAdapter)
+{
+ struct _MAC_t __iomem *pMac = &pAdapter->CSRAddress->mac;
+ MAC_STATION_ADDR1_t station1;
+ MAC_STATION_ADDR2_t station2;
+ MAC_IPG_t ipg;
+ MAC_HFDP_t hfdp;
+ MII_MGMT_CFG_t mii_mgmt_cfg;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ /* First we need to reset everything. Write to MAC configuration
+ * register 1 to perform reset.
+ */
+ writel(0xC00F0000, &pMac->cfg1.value);
+
+ /* Next lets configure the MAC Inter-packet gap register */
+ ipg.bits.non_B2B_ipg_1 = 0x38; // 58d
+ ipg.bits.non_B2B_ipg_2 = 0x58; // 88d
+ ipg.bits.min_ifg_enforce = 0x50; // 80d
+ ipg.bits.B2B_ipg = 0x60; // 96d
+ writel(ipg.value, &pMac->ipg.value);
+
+ /* Next lets configure the MAC Half Duplex register */
+ hfdp.bits.alt_beb_trunc = 0xA;
+ hfdp.bits.alt_beb_enable = 0x0;
+ hfdp.bits.bp_no_backoff = 0x0;
+ hfdp.bits.no_backoff = 0x0;
+ hfdp.bits.excess_defer = 0x1;
+ hfdp.bits.rexmit_max = 0xF;
+ hfdp.bits.coll_window = 0x37; // 55d
+ writel(hfdp.value, &pMac->hfdp.value);
+
+ /* Next lets configure the MAC Interface Control register */
+ writel(0, &pMac->if_ctrl.value);
+
+ /* Let's move on to setting up the mii managment configuration */
+ mii_mgmt_cfg.bits.reset_mii_mgmt = 0;
+ mii_mgmt_cfg.bits.scan_auto_incremt = 0;
+ mii_mgmt_cfg.bits.preamble_suppress = 0;
+ mii_mgmt_cfg.bits.mgmt_clk_reset = 0x7;
+ writel(mii_mgmt_cfg.value, &pMac->mii_mgmt_cfg.value);
+
+ /* Next lets configure the MAC Station Address register. These
+ * values are read from the EEPROM during initialization and stored
+ * in the adapter structure. We write what is stored in the adapter
+ * structure to the MAC Station Address registers high and low. This
+ * station address is used for generating and checking pause control
+ * packets.
+ */
+ station2.bits.Octet1 = pAdapter->CurrentAddress[0];
+ station2.bits.Octet2 = pAdapter->CurrentAddress[1];
+ station1.bits.Octet3 = pAdapter->CurrentAddress[2];
+ station1.bits.Octet4 = pAdapter->CurrentAddress[3];
+ station1.bits.Octet5 = pAdapter->CurrentAddress[4];
+ station1.bits.Octet6 = pAdapter->CurrentAddress[5];
+ writel(station1.value, &pMac->station_addr_1.value);
+ writel(station2.value, &pMac->station_addr_2.value);
+
+ /* Max ethernet packet in bytes that will passed by the mac without
+ * being truncated. Allow the MAC to pass 4 more than our max packet
+ * size. This is 4 for the Ethernet CRC.
+ *
+ * Packets larger than (RegistryJumboPacket) that do not contain a
+ * VLAN ID will be dropped by the Rx function.
+ */
+ writel(pAdapter->RegistryJumboPacket + 4, &pMac->max_fm_len.value);
+
+ /* clear out MAC config reset */
+ writel(0, &pMac->cfg1.value);
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * ConfigMacRegs2 - Initialize the second part of MAC regs
+ * @pAdpater: pointer to our adapter structure
+ */
+void ConfigMACRegs2(struct et131x_adapter *pAdapter)
+{
+ int32_t delay = 0;
+ struct _MAC_t __iomem *pMac = &pAdapter->CSRAddress->mac;
+ MAC_CFG1_t cfg1;
+ MAC_CFG2_t cfg2;
+ MAC_IF_CTRL_t ifctrl;
+ TXMAC_CTL_t ctl;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ ctl.value = readl(&pAdapter->CSRAddress->txmac.ctl.value);
+ cfg1.value = readl(&pMac->cfg1.value);
+ cfg2.value = readl(&pMac->cfg2.value);
+ ifctrl.value = readl(&pMac->if_ctrl.value);
+
+ if (pAdapter->uiLinkSpeed == TRUEPHY_SPEED_1000MBPS) {
+ cfg2.bits.if_mode = 0x2;
+ ifctrl.bits.phy_mode = 0x0;
+ } else {
+ cfg2.bits.if_mode = 0x1;
+ ifctrl.bits.phy_mode = 0x1;
+ }
+
+ /* We need to enable Rx/Tx */
+ cfg1.bits.rx_enable = 0x1;
+ cfg1.bits.tx_enable = 0x1;
+
+ /* Set up flow control */
+ cfg1.bits.tx_flow = 0x1;
+
+ if ((pAdapter->FlowControl == RxOnly) ||
+ (pAdapter->FlowControl == Both)) {
+ cfg1.bits.rx_flow = 0x1;
+ } else {
+ cfg1.bits.rx_flow = 0x0;
+ }
+
+ /* Initialize loop back to off */
+ cfg1.bits.loop_back = 0;
+
+ writel(cfg1.value, &pMac->cfg1.value);
+
+ /* Now we need to initialize the MAC Configuration 2 register */
+ cfg2.bits.preamble_len = 0x7;
+ cfg2.bits.huge_frame = 0x0;
+ /* LENGTH FIELD CHECKING bit4: Set this bit to cause the MAC to check
+ * the frame's length field to ensure it matches the actual data
+ * field length. Clear this bit if no length field checking is
+ * desired. Its default is 0.
+ */
+ cfg2.bits.len_check = 0x1;
+
+ if (pAdapter->RegistryPhyLoopbk == false) {
+ cfg2.bits.pad_crc = 0x1;
+ cfg2.bits.crc_enable = 0x1;
+ } else {
+ cfg2.bits.pad_crc = 0;
+ cfg2.bits.crc_enable = 0;
+ }
+
+ /* 1 - full duplex, 0 - half-duplex */
+ cfg2.bits.full_duplex = pAdapter->uiDuplexMode;
+ ifctrl.bits.ghd_mode = !pAdapter->uiDuplexMode;
+
+ writel(ifctrl.value, &pMac->if_ctrl.value);
+ writel(cfg2.value, &pMac->cfg2.value);
+
+ do {
+ udelay(10);
+ delay++;
+ cfg1.value = readl(&pMac->cfg1.value);
+ } while ((!cfg1.bits.syncd_rx_en ||
+ !cfg1.bits.syncd_tx_en) &&
+ delay < 100);
+
+ if (delay == 100) {
+ DBG_ERROR(et131x_dbginfo,
+ "Syncd bits did not respond correctly cfg1 word 0x%08x\n",
+ cfg1.value);
+ }
+
+ DBG_TRACE(et131x_dbginfo,
+ "Speed %d, Dup %d, CFG1 0x%08x, CFG2 0x%08x, if_ctrl 0x%08x\n",
+ pAdapter->uiLinkSpeed, pAdapter->uiDuplexMode,
+ readl(&pMac->cfg1.value), readl(&pMac->cfg2.value),
+ readl(&pMac->if_ctrl.value));
+
+ /* Enable TXMAC */
+ ctl.bits.txmac_en = 0x1;
+ ctl.bits.fc_disable = 0x1;
+ writel(ctl.value, &pAdapter->CSRAddress->txmac.ctl.value);
+
+ /* Ready to start the RXDMA/TXDMA engine */
+ if (!MP_TEST_FLAG(pAdapter, fMP_ADAPTER_LOWER_POWER)) {
+ et131x_rx_dma_enable(pAdapter);
+ et131x_tx_dma_enable(pAdapter);
+ } else {
+ DBG_WARNING(et131x_dbginfo,
+ "Didn't enable Rx/Tx due to low-power mode\n");
+ }
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+void ConfigRxMacRegs(struct et131x_adapter *pAdapter)
+{
+ struct _RXMAC_t __iomem *pRxMac = &pAdapter->CSRAddress->rxmac;
+ RXMAC_WOL_SA_LO_t sa_lo;
+ RXMAC_WOL_SA_HI_t sa_hi;
+ RXMAC_PF_CTRL_t pf_ctrl = { 0 };
+
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Disable the MAC while it is being configured (also disable WOL) */
+ writel(0x8, &pRxMac->ctrl.value);
+
+ /* Initialize WOL to disabled. */
+ writel(0, &pRxMac->crc0.value);
+ writel(0, &pRxMac->crc12.value);
+ writel(0, &pRxMac->crc34.value);
+
+ /* We need to set the WOL mask0 - mask4 next. We initialize it to
+ * its default Values of 0x00000000 because there are not WOL masks
+ * as of this time.
+ */
+ writel(0, &pRxMac->mask0_word0);
+ writel(0, &pRxMac->mask0_word1);
+ writel(0, &pRxMac->mask0_word2);
+ writel(0, &pRxMac->mask0_word3);
+
+ writel(0, &pRxMac->mask1_word0);
+ writel(0, &pRxMac->mask1_word1);
+ writel(0, &pRxMac->mask1_word2);
+ writel(0, &pRxMac->mask1_word3);
+
+ writel(0, &pRxMac->mask2_word0);
+ writel(0, &pRxMac->mask2_word1);
+ writel(0, &pRxMac->mask2_word2);
+ writel(0, &pRxMac->mask2_word3);
+
+ writel(0, &pRxMac->mask3_word0);
+ writel(0, &pRxMac->mask3_word1);
+ writel(0, &pRxMac->mask3_word2);
+ writel(0, &pRxMac->mask3_word3);
+
+ writel(0, &pRxMac->mask4_word0);
+ writel(0, &pRxMac->mask4_word1);
+ writel(0, &pRxMac->mask4_word2);
+ writel(0, &pRxMac->mask4_word3);
+
+ /* Lets setup the WOL Source Address */
+ sa_lo.bits.sa3 = pAdapter->CurrentAddress[2];
+ sa_lo.bits.sa4 = pAdapter->CurrentAddress[3];
+ sa_lo.bits.sa5 = pAdapter->CurrentAddress[4];
+ sa_lo.bits.sa6 = pAdapter->CurrentAddress[5];
+ writel(sa_lo.value, &pRxMac->sa_lo.value);
+
+ sa_hi.bits.sa1 = pAdapter->CurrentAddress[0];
+ sa_hi.bits.sa2 = pAdapter->CurrentAddress[1];
+ writel(sa_hi.value, &pRxMac->sa_hi.value);
+
+ /* Disable all Packet Filtering */
+ writel(0, &pRxMac->pf_ctrl.value);
+
+ /* Let's initialize the Unicast Packet filtering address */
+ if (pAdapter->PacketFilter & ET131X_PACKET_TYPE_DIRECTED) {
+ SetupDeviceForUnicast(pAdapter);
+ pf_ctrl.bits.filter_uni_en = 1;
+ } else {
+ writel(0, &pRxMac->uni_pf_addr1.value);
+ writel(0, &pRxMac->uni_pf_addr2.value);
+ writel(0, &pRxMac->uni_pf_addr3.value);
+ }
+
+ /* Let's initialize the Multicast hash */
+ if (pAdapter->PacketFilter & ET131X_PACKET_TYPE_ALL_MULTICAST) {
+ pf_ctrl.bits.filter_multi_en = 0;
+ } else {
+ pf_ctrl.bits.filter_multi_en = 1;
+ SetupDeviceForMulticast(pAdapter);
+ }
+
+ /* Runt packet filtering. Didn't work in version A silicon. */
+ pf_ctrl.bits.min_pkt_size = NIC_MIN_PACKET_SIZE + 4;
+ pf_ctrl.bits.filter_frag_en = 1;
+
+ if (pAdapter->RegistryJumboPacket > 8192) {
+ RXMAC_MCIF_CTRL_MAX_SEG_t mcif_ctrl_max_seg;
+
+ /* In order to transmit jumbo packets greater than 8k, the
+ * FIFO between RxMAC and RxDMA needs to be reduced in size
+ * to (16k - Jumbo packet size). In order to implement this,
+ * we must use "cut through" mode in the RxMAC, which chops
+ * packets down into segments which are (max_size * 16). In
+ * this case we selected 256 bytes, since this is the size of
+ * the PCI-Express TLP's that the 1310 uses.
+ */
+ mcif_ctrl_max_seg.bits.seg_en = 0x1;
+ mcif_ctrl_max_seg.bits.fc_en = 0x0;
+ mcif_ctrl_max_seg.bits.max_size = 0x10;
+
+ writel(mcif_ctrl_max_seg.value,
+ &pRxMac->mcif_ctrl_max_seg.value);
+ } else {
+ writel(0, &pRxMac->mcif_ctrl_max_seg.value);
+ }
+
+ /* Initialize the MCIF water marks */
+ writel(0, &pRxMac->mcif_water_mark.value);
+
+ /* Initialize the MIF control */
+ writel(0, &pRxMac->mif_ctrl.value);
+
+ /* Initialize the Space Available Register */
+ writel(0, &pRxMac->space_avail.value);
+
+ /* Initialize the the mif_ctrl register
+ * bit 3: Receive code error. One or more nibbles were signaled as
+ * errors during the reception of the packet. Clear this
+ * bit in Gigabit, set it in 100Mbit. This was derived
+ * experimentally at UNH.
+ * bit 4: Receive CRC error. The packet's CRC did not match the
+ * internally generated CRC.
+ * bit 5: Receive length check error. Indicates that frame length
+ * field value in the packet does not match the actual data
+ * byte length and is not a type field.
+ * bit 16: Receive frame truncated.
+ * bit 17: Drop packet enable
+ */
+ if (pAdapter->uiLinkSpeed == TRUEPHY_SPEED_100MBPS) {
+ writel(0x30038, &pRxMac->mif_ctrl.value);
+ } else {
+ writel(0x30030, &pRxMac->mif_ctrl.value);
+ }
+
+ /* Finally we initialize RxMac to be enabled & WOL disabled. Packet
+ * filter is always enabled since it is where the runt packets are
+ * supposed to be dropped. For version A silicon, runt packet
+ * dropping doesn't work, so it is disabled in the pf_ctrl register,
+ * but we still leave the packet filter on.
+ */
+ writel(pf_ctrl.value, &pRxMac->pf_ctrl.value);
+ writel(0x9, &pRxMac->ctrl.value);
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+void ConfigTxMacRegs(struct et131x_adapter *pAdapter)
+{
+ struct _TXMAC_t __iomem *pTxMac = &pAdapter->CSRAddress->txmac;
+ TXMAC_CF_PARAM_t Local;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ /* We need to update the Control Frame Parameters
+ * cfpt - control frame pause timer set to 64 (0x40)
+ * cfep - control frame extended pause timer set to 0x0
+ */
+ if (pAdapter->FlowControl == None) {
+ writel(0, &pTxMac->cf_param.value);
+ } else {
+ Local.bits.cfpt = 0x40;
+ Local.bits.cfep = 0x0;
+ writel(Local.value, &pTxMac->cf_param.value);
+ }
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+void ConfigMacStatRegs(struct et131x_adapter *pAdapter)
+{
+ struct _MAC_STAT_t __iomem *pDevMacStat =
+ &pAdapter->CSRAddress->macStat;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Next we need to initialize all the MAC_STAT registers to zero on
+ * the device.
+ */
+ writel(0, &pDevMacStat->RFcs);
+ writel(0, &pDevMacStat->RAln);
+ writel(0, &pDevMacStat->RFlr);
+ writel(0, &pDevMacStat->RDrp);
+ writel(0, &pDevMacStat->RCde);
+ writel(0, &pDevMacStat->ROvr);
+ writel(0, &pDevMacStat->RFrg);
+
+ writel(0, &pDevMacStat->TScl);
+ writel(0, &pDevMacStat->TDfr);
+ writel(0, &pDevMacStat->TMcl);
+ writel(0, &pDevMacStat->TLcl);
+ writel(0, &pDevMacStat->TNcl);
+ writel(0, &pDevMacStat->TOvr);
+ writel(0, &pDevMacStat->TUnd);
+
+ /* Unmask any counters that we want to track the overflow of.
+ * Initially this will be all counters. It may become clear later
+ * that we do not need to track all counters.
+ */
+ {
+ MAC_STAT_REG_1_t Carry1M = { 0xffffffff };
+
+ Carry1M.bits.rdrp = 0;
+ Carry1M.bits.rjbr = 1;
+ Carry1M.bits.rfrg = 0;
+ Carry1M.bits.rovr = 0;
+ Carry1M.bits.rund = 1;
+ Carry1M.bits.rcse = 1;
+ Carry1M.bits.rcde = 0;
+ Carry1M.bits.rflr = 0;
+ Carry1M.bits.raln = 0;
+ Carry1M.bits.rxuo = 1;
+ Carry1M.bits.rxpf = 1;
+ Carry1M.bits.rxcf = 1;
+ Carry1M.bits.rbca = 1;
+ Carry1M.bits.rmca = 1;
+ Carry1M.bits.rfcs = 0;
+ Carry1M.bits.rpkt = 1;
+ Carry1M.bits.rbyt = 1;
+ Carry1M.bits.trmgv = 1;
+ Carry1M.bits.trmax = 1;
+ Carry1M.bits.tr1k = 1;
+ Carry1M.bits.tr511 = 1;
+ Carry1M.bits.tr255 = 1;
+ Carry1M.bits.tr127 = 1;
+ Carry1M.bits.tr64 = 1;
+
+ writel(Carry1M.value, &pDevMacStat->Carry1M.value);
+ }
+
+ {
+ MAC_STAT_REG_2_t Carry2M = { 0xffffffff };
+
+ Carry2M.bits.tdrp = 1;
+ Carry2M.bits.tpfh = 1;
+ Carry2M.bits.tncl = 0;
+ Carry2M.bits.txcl = 1;
+ Carry2M.bits.tlcl = 0;
+ Carry2M.bits.tmcl = 0;
+ Carry2M.bits.tscl = 0;
+ Carry2M.bits.tedf = 1;
+ Carry2M.bits.tdfr = 0;
+ Carry2M.bits.txpf = 1;
+ Carry2M.bits.tbca = 1;
+ Carry2M.bits.tmca = 1;
+ Carry2M.bits.tpkt = 1;
+ Carry2M.bits.tbyt = 1;
+ Carry2M.bits.tfrg = 1;
+ Carry2M.bits.tund = 0;
+ Carry2M.bits.tovr = 0;
+ Carry2M.bits.txcf = 1;
+ Carry2M.bits.tfcs = 1;
+ Carry2M.bits.tjbr = 1;
+
+ writel(Carry2M.value, &pDevMacStat->Carry2M.value);
+ }
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+void ConfigFlowControl(struct et131x_adapter * pAdapter)
+{
+ if (pAdapter->uiDuplexMode == 0) {
+ pAdapter->FlowControl = None;
+ } else {
+ char RemotePause, RemoteAsyncPause;
+
+ ET1310_PhyAccessMiBit(pAdapter,
+ TRUEPHY_BIT_READ, 5, 10, &RemotePause);
+ ET1310_PhyAccessMiBit(pAdapter,
+ TRUEPHY_BIT_READ, 5, 11,
+ &RemoteAsyncPause);
+
+ if ((RemotePause == TRUEPHY_BIT_SET) &&
+ (RemoteAsyncPause == TRUEPHY_BIT_SET)) {
+ pAdapter->FlowControl = pAdapter->RegistryFlowControl;
+ } else if ((RemotePause == TRUEPHY_BIT_SET) &&
+ (RemoteAsyncPause == TRUEPHY_BIT_CLEAR)) {
+ if (pAdapter->RegistryFlowControl == Both) {
+ pAdapter->FlowControl = Both;
+ } else {
+ pAdapter->FlowControl = None;
+ }
+ } else if ((RemotePause == TRUEPHY_BIT_CLEAR) &&
+ (RemoteAsyncPause == TRUEPHY_BIT_CLEAR)) {
+ pAdapter->FlowControl = None;
+ } else {/* if (RemotePause == TRUEPHY_CLEAR_BIT &&
+ RemoteAsyncPause == TRUEPHY_SET_BIT) */
+ if (pAdapter->RegistryFlowControl == Both) {
+ pAdapter->FlowControl = RxOnly;
+ } else {
+ pAdapter->FlowControl = None;
+ }
+ }
+ }
+}
+
+/**
+ * UpdateMacStatHostCounters - Update the local copy of the statistics
+ * @pAdapter: pointer to the adapter structure
+ */
+void UpdateMacStatHostCounters(struct et131x_adapter *pAdapter)
+{
+ struct _ce_stats_t *stats = &pAdapter->Stats;
+ struct _MAC_STAT_t __iomem *pDevMacStat =
+ &pAdapter->CSRAddress->macStat;
+
+ stats->collisions += readl(&pDevMacStat->TNcl);
+ stats->first_collision += readl(&pDevMacStat->TScl);
+ stats->tx_deferred += readl(&pDevMacStat->TDfr);
+ stats->excessive_collisions += readl(&pDevMacStat->TMcl);
+ stats->late_collisions += readl(&pDevMacStat->TLcl);
+ stats->tx_uflo += readl(&pDevMacStat->TUnd);
+ stats->max_pkt_error += readl(&pDevMacStat->TOvr);
+
+ stats->alignment_err += readl(&pDevMacStat->RAln);
+ stats->crc_err += readl(&pDevMacStat->RCde);
+ stats->norcvbuf += readl(&pDevMacStat->RDrp);
+ stats->rx_ov_flow += readl(&pDevMacStat->ROvr);
+ stats->code_violations += readl(&pDevMacStat->RFcs);
+ stats->length_err += readl(&pDevMacStat->RFlr);
+
+ stats->other_errors += readl(&pDevMacStat->RFrg);
+}
+
+/**
+ * HandleMacStatInterrupt
+ * @pAdapter: pointer to the adapter structure
+ *
+ * One of the MACSTAT counters has wrapped. Update the local copy of
+ * the statistics held in the adapter structure, checking the "wrap"
+ * bit for each counter.
+ */
+void HandleMacStatInterrupt(struct et131x_adapter *pAdapter)
+{
+ MAC_STAT_REG_1_t Carry1;
+ MAC_STAT_REG_2_t Carry2;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Read the interrupt bits from the register(s). These are Clear On
+ * Write.
+ */
+ Carry1.value = readl(&pAdapter->CSRAddress->macStat.Carry1.value);
+ Carry2.value = readl(&pAdapter->CSRAddress->macStat.Carry2.value);
+
+ writel(Carry1.value, &pAdapter->CSRAddress->macStat.Carry1.value);
+ writel(Carry2.value, &pAdapter->CSRAddress->macStat.Carry2.value);
+
+ /* We need to do update the host copy of all the MAC_STAT counters.
+ * For each counter, check it's overflow bit. If the overflow bit is
+ * set, then increment the host version of the count by one complete
+ * revolution of the counter. This routine is called when the counter
+ * block indicates that one of the counters has wrapped.
+ */
+ if (Carry1.bits.rfcs) {
+ pAdapter->Stats.code_violations += COUNTER_WRAP_16_BIT;
+ }
+ if (Carry1.bits.raln) {
+ pAdapter->Stats.alignment_err += COUNTER_WRAP_12_BIT;
+ }
+ if (Carry1.bits.rflr) {
+ pAdapter->Stats.length_err += COUNTER_WRAP_16_BIT;
+ }
+ if (Carry1.bits.rfrg) {
+ pAdapter->Stats.other_errors += COUNTER_WRAP_16_BIT;
+ }
+ if (Carry1.bits.rcde) {
+ pAdapter->Stats.crc_err += COUNTER_WRAP_16_BIT;
+ }
+ if (Carry1.bits.rovr) {
+ pAdapter->Stats.rx_ov_flow += COUNTER_WRAP_16_BIT;
+ }
+ if (Carry1.bits.rdrp) {
+ pAdapter->Stats.norcvbuf += COUNTER_WRAP_16_BIT;
+ }
+ if (Carry2.bits.tovr) {
+ pAdapter->Stats.max_pkt_error += COUNTER_WRAP_12_BIT;
+ }
+ if (Carry2.bits.tund) {
+ pAdapter->Stats.tx_uflo += COUNTER_WRAP_12_BIT;
+ }
+ if (Carry2.bits.tscl) {
+ pAdapter->Stats.first_collision += COUNTER_WRAP_12_BIT;
+ }
+ if (Carry2.bits.tdfr) {
+ pAdapter->Stats.tx_deferred += COUNTER_WRAP_12_BIT;
+ }
+ if (Carry2.bits.tmcl) {
+ pAdapter->Stats.excessive_collisions += COUNTER_WRAP_12_BIT;
+ }
+ if (Carry2.bits.tlcl) {
+ pAdapter->Stats.late_collisions += COUNTER_WRAP_12_BIT;
+ }
+ if (Carry2.bits.tncl) {
+ pAdapter->Stats.collisions += COUNTER_WRAP_12_BIT;
+ }
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+void SetupDeviceForMulticast(struct et131x_adapter *pAdapter)
+{
+ struct _RXMAC_t __iomem *rxmac = &pAdapter->CSRAddress->rxmac;
+ uint32_t nIndex;
+ uint32_t result;
+ uint32_t hash1 = 0;
+ uint32_t hash2 = 0;
+ uint32_t hash3 = 0;
+ uint32_t hash4 = 0;
+ PM_CSR_t pm_csr;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ /* If ET131X_PACKET_TYPE_MULTICAST is specified, then we provision
+ * the multi-cast LIST. If it is NOT specified, (and "ALL" is not
+ * specified) then we should pass NO multi-cast addresses to the
+ * driver.
+ */
+ if (pAdapter->PacketFilter & ET131X_PACKET_TYPE_MULTICAST) {
+ DBG_VERBOSE(et131x_dbginfo,
+ "MULTICAST flag is set, MCCount: %d\n",
+ pAdapter->MCAddressCount);
+
+ /* Loop through our multicast array and set up the device */
+ for (nIndex = 0; nIndex < pAdapter->MCAddressCount; nIndex++) {
+ DBG_VERBOSE(et131x_dbginfo,
+ "MCList[%d]: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ nIndex,
+ pAdapter->MCList[nIndex][0],
+ pAdapter->MCList[nIndex][1],
+ pAdapter->MCList[nIndex][2],
+ pAdapter->MCList[nIndex][3],
+ pAdapter->MCList[nIndex][4],
+ pAdapter->MCList[nIndex][5]);
+
+ result = ether_crc(6, pAdapter->MCList[nIndex]);
+
+ result = (result & 0x3F800000) >> 23;
+
+ if (result < 32) {
+ hash1 |= (1 << result);
+ } else if ((31 < result) && (result < 64)) {
+ result -= 32;
+ hash2 |= (1 << result);
+ } else if ((63 < result) && (result < 96)) {
+ result -= 64;
+ hash3 |= (1 << result);
+ } else {
+ result -= 96;
+ hash4 |= (1 << result);
+ }
+ }
+ }
+
+ /* Write out the new hash to the device */
+ pm_csr.value = readl(&pAdapter->CSRAddress->global.pm_csr.value);
+ if (pm_csr.bits.pm_phy_sw_coma == 0) {
+ writel(hash1, &rxmac->multi_hash1);
+ writel(hash2, &rxmac->multi_hash2);
+ writel(hash3, &rxmac->multi_hash3);
+ writel(hash4, &rxmac->multi_hash4);
+ }
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+void SetupDeviceForUnicast(struct et131x_adapter *pAdapter)
+{
+ struct _RXMAC_t __iomem *rxmac = &pAdapter->CSRAddress->rxmac;
+ RXMAC_UNI_PF_ADDR1_t uni_pf1;
+ RXMAC_UNI_PF_ADDR2_t uni_pf2;
+ RXMAC_UNI_PF_ADDR3_t uni_pf3;
+ PM_CSR_t pm_csr;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Set up unicast packet filter reg 3 to be the first two octets of
+ * the MAC address for both address
+ *
+ * Set up unicast packet filter reg 2 to be the octets 2 - 5 of the
+ * MAC address for second address
+ *
+ * Set up unicast packet filter reg 3 to be the octets 2 - 5 of the
+ * MAC address for first address
+ */
+ uni_pf3.bits.addr1_1 = pAdapter->CurrentAddress[0];
+ uni_pf3.bits.addr1_2 = pAdapter->CurrentAddress[1];
+ uni_pf3.bits.addr2_1 = pAdapter->CurrentAddress[0];
+ uni_pf3.bits.addr2_2 = pAdapter->CurrentAddress[1];
+
+ uni_pf2.bits.addr2_3 = pAdapter->CurrentAddress[2];
+ uni_pf2.bits.addr2_4 = pAdapter->CurrentAddress[3];
+ uni_pf2.bits.addr2_5 = pAdapter->CurrentAddress[4];
+ uni_pf2.bits.addr2_6 = pAdapter->CurrentAddress[5];
+
+ uni_pf1.bits.addr1_3 = pAdapter->CurrentAddress[2];
+ uni_pf1.bits.addr1_4 = pAdapter->CurrentAddress[3];
+ uni_pf1.bits.addr1_5 = pAdapter->CurrentAddress[4];
+ uni_pf1.bits.addr1_6 = pAdapter->CurrentAddress[5];
+
+ pm_csr.value = readl(&pAdapter->CSRAddress->global.pm_csr.value);
+ if (pm_csr.bits.pm_phy_sw_coma == 0) {
+ writel(uni_pf1.value, &rxmac->uni_pf_addr1.value);
+ writel(uni_pf2.value, &rxmac->uni_pf_addr2.value);
+ writel(uni_pf3.value, &rxmac->uni_pf_addr3.value);
+ }
+
+ DBG_LEAVE(et131x_dbginfo);
+}
diff --git a/drivers/staging/et131x/et1310_mac.h b/drivers/staging/et131x/et1310_mac.h
new file mode 100644
index 0000000..bd26cd3
--- /dev/null
+++ b/drivers/staging/et131x/et1310_mac.h
@@ -0,0 +1,93 @@
+/*
+ * Agere Systems Inc.
+ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * et1310_mac.h - Defines, structs, enums, prototypes, etc. pertaining to the
+ * MAC.
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#ifndef _ET1310_MAC_H_
+#define _ET1310_MAC_H_
+
+
+#include "et1310_address_map.h"
+
+
+#define COUNTER_WRAP_28_BIT 0x10000000
+#define COUNTER_WRAP_22_BIT 0x400000
+#define COUNTER_WRAP_16_BIT 0x10000
+#define COUNTER_WRAP_12_BIT 0x1000
+
+#define COUNTER_MASK_28_BIT (COUNTER_WRAP_28_BIT - 1)
+#define COUNTER_MASK_22_BIT (COUNTER_WRAP_22_BIT - 1)
+#define COUNTER_MASK_16_BIT (COUNTER_WRAP_16_BIT - 1)
+#define COUNTER_MASK_12_BIT (COUNTER_WRAP_12_BIT - 1)
+
+#define UPDATE_COUNTER(HostCnt,DevCnt) \
+ HostCnt = HostCnt + DevCnt;
+
+/* Forward declaration of the private adapter structure */
+struct et131x_adapter;
+
+void ConfigMACRegs1(struct et131x_adapter *adapter);
+void ConfigMACRegs2(struct et131x_adapter *adapter);
+void ConfigRxMacRegs(struct et131x_adapter *adapter);
+void ConfigTxMacRegs(struct et131x_adapter *adapter);
+void ConfigMacStatRegs(struct et131x_adapter *adapter);
+void ConfigFlowControl(struct et131x_adapter *adapter);
+void UpdateMacStatHostCounters(struct et131x_adapter *adapter);
+void HandleMacStatInterrupt(struct et131x_adapter *adapter);
+void SetupDeviceForMulticast(struct et131x_adapter *adapter);
+void SetupDeviceForUnicast(struct et131x_adapter *adapter);
+
+#endif /* _ET1310_MAC_H_ */
diff --git a/drivers/staging/et131x/et1310_phy.c b/drivers/staging/et131x/et1310_phy.c
new file mode 100644
index 0000000..6c4fa54
--- /dev/null
+++ b/drivers/staging/et131x/et1310_phy.c
@@ -0,0 +1,1281 @@
+/*
+ * Agere Systems Inc.
+ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * et1310_phy.c - Routines for configuring and accessing the PHY
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#include "et131x_version.h"
+#include "et131x_debug.h"
+#include "et131x_defs.h"
+
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+#include <linux/random.h>
+#include <linux/delay.h>
+
+#include "et1310_phy.h"
+#include "et1310_pm.h"
+#include "et1310_jagcore.h"
+
+#include "et131x_adapter.h"
+#include "et131x_netdev.h"
+#include "et131x_initpci.h"
+
+#include "et1310_address_map.h"
+#include "et1310_jagcore.h"
+#include "et1310_tx.h"
+#include "et1310_rx.h"
+#include "et1310_mac.h"
+
+/* Data for debugging facilities */
+#ifdef CONFIG_ET131X_DEBUG
+extern dbg_info_t *et131x_dbginfo;
+#endif /* CONFIG_ET131X_DEBUG */
+
+/* Prototypes for functions with local scope */
+static int et131x_xcvr_init(struct et131x_adapter *adapter);
+
+/**
+ * PhyMiRead - Read from the PHY through the MII Interface on the MAC
+ * @adapter: pointer to our private adapter structure
+ * @xcvrAddr: the address of the transciever
+ * @xcvrReg: the register to read
+ * @value: pointer to a 16-bit value in which the value will be stored
+ *
+ * Returns 0 on success, errno on failure (as defined in errno.h)
+ */
+int PhyMiRead(struct et131x_adapter *adapter, uint8_t xcvrAddr,
+ uint8_t xcvrReg, uint16_t *value)
+{
+ struct _MAC_t __iomem *mac = &adapter->CSRAddress->mac;
+ int status = 0;
+ uint32_t delay;
+ MII_MGMT_ADDR_t miiAddr;
+ MII_MGMT_CMD_t miiCmd;
+ MII_MGMT_INDICATOR_t miiIndicator;
+
+ /* Save a local copy of the registers we are dealing with so we can
+ * set them back
+ */
+ miiAddr.value = readl(&mac->mii_mgmt_addr.value);
+ miiCmd.value = readl(&mac->mii_mgmt_cmd.value);
+
+ /* Stop the current operation */
+ writel(0, &mac->mii_mgmt_cmd.value);
+
+ /* Set up the register we need to read from on the correct PHY */
+ {
+ MII_MGMT_ADDR_t mii_mgmt_addr = { 0 };
+
+ mii_mgmt_addr.bits.phy_addr = xcvrAddr;
+ mii_mgmt_addr.bits.reg_addr = xcvrReg;
+ writel(mii_mgmt_addr.value, &mac->mii_mgmt_addr.value);
+ }
+
+ /* Kick the read cycle off */
+ delay = 0;
+
+ writel(0x1, &mac->mii_mgmt_cmd.value);
+
+ do {
+ udelay(50);
+ delay++;
+ miiIndicator.value = readl(&mac->mii_mgmt_indicator.value);
+ } while ((miiIndicator.bits.not_valid || miiIndicator.bits.busy) &&
+ delay < 50);
+
+ /* If we hit the max delay, we could not read the register */
+ if (delay >= 50) {
+ DBG_WARNING(et131x_dbginfo,
+ "xcvrReg 0x%08x could not be read\n", xcvrReg);
+ DBG_WARNING(et131x_dbginfo, "status is 0x%08x\n",
+ miiIndicator.value);
+
+ status = -EIO;
+ }
+
+ /* If we hit here we were able to read the register and we need to
+ * return the value to the caller
+ */
+ /* TODO: make this stuff a simple readw()?! */
+ {
+ MII_MGMT_STAT_t mii_mgmt_stat;
+
+ mii_mgmt_stat.value = readl(&mac->mii_mgmt_stat.value);
+ *value = (uint16_t) mii_mgmt_stat.bits.phy_stat;
+ }
+
+ /* Stop the read operation */
+ writel(0, &mac->mii_mgmt_cmd.value);
+
+ DBG_VERBOSE(et131x_dbginfo, " xcvr_addr = 0x%02x, "
+ "xcvr_reg = 0x%02x, "
+ "value = 0x%04x.\n", xcvrAddr, xcvrReg, *value);
+
+ /* set the registers we touched back to the state at which we entered
+ * this function
+ */
+ writel(miiAddr.value, &mac->mii_mgmt_addr.value);
+ writel(miiCmd.value, &mac->mii_mgmt_cmd.value);
+
+ return status;
+}
+
+/**
+ * MiWrite - Write to a PHY register through the MII interface of the MAC
+ * @adapter: pointer to our private adapter structure
+ * @xcvrReg: the register to read
+ * @value: 16-bit value to write
+ *
+ * Return 0 on success, errno on failure (as defined in errno.h)
+ */
+int MiWrite(struct et131x_adapter *adapter, uint8_t xcvrReg, uint16_t value)
+{
+ struct _MAC_t __iomem *mac = &adapter->CSRAddress->mac;
+ int status = 0;
+ uint8_t xcvrAddr = adapter->Stats.xcvr_addr;
+ uint32_t delay;
+ MII_MGMT_ADDR_t miiAddr;
+ MII_MGMT_CMD_t miiCmd;
+ MII_MGMT_INDICATOR_t miiIndicator;
+
+ /* Save a local copy of the registers we are dealing with so we can
+ * set them back
+ */
+ miiAddr.value = readl(&mac->mii_mgmt_addr.value);
+ miiCmd.value = readl(&mac->mii_mgmt_cmd.value);
+
+ /* Stop the current operation */
+ writel(0, &mac->mii_mgmt_cmd.value);
+
+ /* Set up the register we need to write to on the correct PHY */
+ {
+ MII_MGMT_ADDR_t mii_mgmt_addr;
+
+ mii_mgmt_addr.bits.phy_addr = xcvrAddr;
+ mii_mgmt_addr.bits.reg_addr = xcvrReg;
+ writel(mii_mgmt_addr.value, &mac->mii_mgmt_addr.value);
+ }
+
+ /* Add the value to write to the registers to the mac */
+ writel(value, &mac->mii_mgmt_ctrl.value);
+ delay = 0;
+
+ do {
+ udelay(50);
+ delay++;
+ miiIndicator.value = readl(&mac->mii_mgmt_indicator.value);
+ } while (miiIndicator.bits.busy && delay < 100);
+
+ /* If we hit the max delay, we could not write the register */
+ if (delay == 100) {
+ uint16_t TempValue;
+
+ DBG_WARNING(et131x_dbginfo,
+ "xcvrReg 0x%08x could not be written", xcvrReg);
+ DBG_WARNING(et131x_dbginfo, "status is 0x%08x\n",
+ miiIndicator.value);
+ DBG_WARNING(et131x_dbginfo, "command is 0x%08x\n",
+ readl(&mac->mii_mgmt_cmd.value));
+
+ MiRead(adapter, xcvrReg, &TempValue);
+
+ status = -EIO;
+ }
+
+ /* Stop the write operation */
+ writel(0, &mac->mii_mgmt_cmd.value);
+
+ /* set the registers we touched back to the state at which we entered
+ * this function
+ */
+ writel(miiAddr.value, &mac->mii_mgmt_addr.value);
+ writel(miiCmd.value, &mac->mii_mgmt_cmd.value);
+
+ DBG_VERBOSE(et131x_dbginfo, " xcvr_addr = 0x%02x, "
+ "xcvr_reg = 0x%02x, "
+ "value = 0x%04x.\n", xcvrAddr, xcvrReg, value);
+
+ return status;
+}
+
+/**
+ * et131x_xcvr_find - Find the PHY ID
+ * @adapter: pointer to our private adapter structure
+ *
+ * Returns 0 on success, errno on failure (as defined in errno.h)
+ */
+int et131x_xcvr_find(struct et131x_adapter *adapter)
+{
+ int status = -ENODEV;
+ uint8_t xcvr_addr;
+ MI_IDR1_t idr1;
+ MI_IDR2_t idr2;
+ uint32_t xcvr_id;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ /* We need to get xcvr id and address we just get the first one */
+ for (xcvr_addr = 0; xcvr_addr < 32; xcvr_addr++) {
+ /* Read the ID from the PHY */
+ PhyMiRead(adapter, xcvr_addr,
+ (uint8_t) offsetof(MI_REGS_t, idr1),
+ &idr1.value);
+ PhyMiRead(adapter, xcvr_addr,
+ (uint8_t) offsetof(MI_REGS_t, idr2),
+ &idr2.value);
+
+ xcvr_id = (uint32_t) ((idr1.value << 16) | idr2.value);
+
+ if ((idr1.value != 0) && (idr1.value != 0xffff)) {
+ DBG_TRACE(et131x_dbginfo,
+ "Xcvr addr: 0x%02x\tXcvr_id: 0x%08x\n",
+ xcvr_addr, xcvr_id);
+
+ adapter->Stats.xcvr_id = xcvr_id;
+ adapter->Stats.xcvr_addr = xcvr_addr;
+
+ status = 0;
+ break;
+ }
+ }
+
+ DBG_LEAVE(et131x_dbginfo);
+ return status;
+}
+
+/**
+ * et131x_setphy_normal - Set PHY for normal operation.
+ * @adapter: pointer to our private adapter structure
+ *
+ * Used by Power Management to force the PHY into 10 Base T half-duplex mode,
+ * when going to D3 in WOL mode. Also used during initialization to set the
+ * PHY for normal operation.
+ */
+int et131x_setphy_normal(struct et131x_adapter *adapter)
+{
+ int status;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Make sure the PHY is powered up */
+ ET1310_PhyPowerDown(adapter, 0);
+ status = et131x_xcvr_init(adapter);
+
+ DBG_LEAVE(et131x_dbginfo);
+ return status;
+}
+
+/**
+ * et131x_xcvr_init - Init the phy if we are setting it into force mode
+ * @adapter: pointer to our private adapter structure
+ *
+ * Returns 0 on success, errno on failure (as defined in errno.h)
+ */
+static int et131x_xcvr_init(struct et131x_adapter *adapter)
+{
+ int status = 0;
+ MI_IMR_t imr;
+ MI_ISR_t isr;
+ MI_LCR2_t lcr2;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Zero out the adapter structure variable representing BMSR */
+ adapter->Bmsr.value = 0;
+
+ MiRead(adapter, (uint8_t) offsetof(MI_REGS_t, isr), &isr.value);
+
+ MiRead(adapter, (uint8_t) offsetof(MI_REGS_t, imr), &imr.value);
+
+ /* Set the link status interrupt only. Bad behavior when link status
+ * and auto neg are set, we run into a nested interrupt problem
+ */
+ imr.bits.int_en = 0x1;
+ imr.bits.link_status = 0x1;
+ imr.bits.autoneg_status = 0x1;
+
+ MiWrite(adapter, (uint8_t) offsetof(MI_REGS_t, imr), imr.value);
+
+ /* Set the LED behavior such that LED 1 indicates speed (off =
+ * 10Mbits, blink = 100Mbits, on = 1000Mbits) and LED 2 indicates
+ * link and activity (on for link, blink off for activity).
+ *
+ * NOTE: Some customizations have been added here for specific
+ * vendors; The LED behavior is now determined by vendor data in the
+ * EEPROM. However, the above description is the default.
+ */
+ if ((adapter->eepromData[1] & 0x4) == 0) {
+ MiRead(adapter, (uint8_t) offsetof(MI_REGS_t, lcr2),
+ &lcr2.value);
+ if ((adapter->eepromData[1] & 0x8) == 0)
+ lcr2.bits.led_tx_rx = 0x3;
+ else
+ lcr2.bits.led_tx_rx = 0x4;
+ lcr2.bits.led_link = 0xa;
+ MiWrite(adapter, (uint8_t) offsetof(MI_REGS_t, lcr2),
+ lcr2.value);
+ }
+
+ /* Determine if we need to go into a force mode and set it */
+ if (adapter->AiForceSpeed == 0 && adapter->AiForceDpx == 0) {
+ if ((adapter->RegistryFlowControl == TxOnly) ||
+ (adapter->RegistryFlowControl == Both)) {
+ ET1310_PhyAccessMiBit(adapter,
+ TRUEPHY_BIT_SET, 4, 11, NULL);
+ } else {
+ ET1310_PhyAccessMiBit(adapter,
+ TRUEPHY_BIT_CLEAR, 4, 11, NULL);
+ }
+
+ if (adapter->RegistryFlowControl == Both) {
+ ET1310_PhyAccessMiBit(adapter,
+ TRUEPHY_BIT_SET, 4, 10, NULL);
+ } else {
+ ET1310_PhyAccessMiBit(adapter,
+ TRUEPHY_BIT_CLEAR, 4, 10, NULL);
+ }
+
+ /* Set the phy to autonegotiation */
+ ET1310_PhyAutoNeg(adapter, true);
+
+ /* NOTE - Do we need this? */
+ ET1310_PhyAccessMiBit(adapter, TRUEPHY_BIT_SET, 0, 9, NULL);
+
+ DBG_LEAVE(et131x_dbginfo);
+ return status;
+ } else {
+ ET1310_PhyAutoNeg(adapter, false);
+
+ /* Set to the correct force mode. */
+ if (adapter->AiForceDpx != 1) {
+ if ((adapter->RegistryFlowControl == TxOnly) ||
+ (adapter->RegistryFlowControl == Both)) {
+ ET1310_PhyAccessMiBit(adapter,
+ TRUEPHY_BIT_SET, 4, 11,
+ NULL);
+ } else {
+ ET1310_PhyAccessMiBit(adapter,
+ TRUEPHY_BIT_CLEAR, 4, 11,
+ NULL);
+ }
+
+ if (adapter->RegistryFlowControl == Both) {
+ ET1310_PhyAccessMiBit(adapter,
+ TRUEPHY_BIT_SET, 4, 10,
+ NULL);
+ } else {
+ ET1310_PhyAccessMiBit(adapter,
+ TRUEPHY_BIT_CLEAR, 4, 10,
+ NULL);
+ }
+ } else {
+ ET1310_PhyAccessMiBit(adapter,
+ TRUEPHY_BIT_CLEAR, 4, 10, NULL);
+ ET1310_PhyAccessMiBit(adapter,
+ TRUEPHY_BIT_CLEAR, 4, 11, NULL);
+ }
+
+ switch (adapter->AiForceSpeed) {
+ case 10:
+ if (adapter->AiForceDpx == 1) {
+ TPAL_SetPhy10HalfDuplex(adapter);
+ } else if (adapter->AiForceDpx == 2) {
+ TPAL_SetPhy10FullDuplex(adapter);
+ } else {
+ TPAL_SetPhy10Force(adapter);
+ }
+ break;
+ case 100:
+ if (adapter->AiForceDpx == 1) {
+ TPAL_SetPhy100HalfDuplex(adapter);
+ } else if (adapter->AiForceDpx == 2) {
+ TPAL_SetPhy100FullDuplex(adapter);
+ } else {
+ TPAL_SetPhy100Force(adapter);
+ }
+ break;
+ case 1000:
+ TPAL_SetPhy1000FullDuplex(adapter);
+ break;
+ }
+
+ DBG_LEAVE(et131x_dbginfo);
+ return status;
+ }
+}
+
+void et131x_Mii_check(struct et131x_adapter *pAdapter,
+ MI_BMSR_t bmsr, MI_BMSR_t bmsr_ints)
+{
+ uint8_t ucLinkStatus;
+ uint32_t uiAutoNegStatus;
+ uint32_t uiSpeed;
+ uint32_t uiDuplex;
+ uint32_t uiMdiMdix;
+ uint32_t uiMasterSlave;
+ uint32_t uiPolarity;
+ unsigned long lockflags;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ if (bmsr_ints.bits.link_status) {
+ if (bmsr.bits.link_status) {
+ pAdapter->PoMgmt.TransPhyComaModeOnBoot = 20;
+
+ /* Update our state variables and indicate the
+ * connected state
+ */
+ spin_lock_irqsave(&pAdapter->Lock, lockflags);
+
+ pAdapter->MediaState = NETIF_STATUS_MEDIA_CONNECT;
+ MP_CLEAR_FLAG(pAdapter, fMP_ADAPTER_LINK_DETECTION);
+
+ spin_unlock_irqrestore(&pAdapter->Lock, lockflags);
+
+ /* Don't indicate state if we're in loopback mode */
+ if (pAdapter->RegistryPhyLoopbk == false) {
+ netif_carrier_on(pAdapter->netdev);
+ }
+ } else {
+ DBG_WARNING(et131x_dbginfo,
+ "Link down cable problem\n");
+
+ if (pAdapter->uiLinkSpeed == TRUEPHY_SPEED_10MBPS) {
+ // NOTE - Is there a way to query this without TruePHY?
+ // && TRU_QueryCoreType(pAdapter->hTruePhy, 0) == EMI_TRUEPHY_A13O) {
+ uint16_t Register18;
+
+ MiRead(pAdapter, 0x12, &Register18);
+ MiWrite(pAdapter, 0x12, Register18 | 0x4);
+ MiWrite(pAdapter, 0x10, Register18 | 0x8402);
+ MiWrite(pAdapter, 0x11, Register18 | 511);
+ MiWrite(pAdapter, 0x12, Register18);
+ }
+
+ /* For the first N seconds of life, we are in "link
+ * detection" When we are in this state, we should
+ * only report "connected". When the LinkDetection
+ * Timer expires, we can report disconnected (handled
+ * in the LinkDetectionDPC).
+ */
+ if ((MP_IS_FLAG_CLEAR
+ (pAdapter, fMP_ADAPTER_LINK_DETECTION))
+ || (pAdapter->MediaState ==
+ NETIF_STATUS_MEDIA_DISCONNECT)) {
+ spin_lock_irqsave(&pAdapter->Lock, lockflags);
+ pAdapter->MediaState =
+ NETIF_STATUS_MEDIA_DISCONNECT;
+ spin_unlock_irqrestore(&pAdapter->Lock,
+ lockflags);
+
+ /* Only indicate state if we're in loopback
+ * mode
+ */
+ if (pAdapter->RegistryPhyLoopbk == false) {
+ netif_carrier_off(pAdapter->netdev);
+ }
+ }
+
+ pAdapter->uiLinkSpeed = 0;
+ pAdapter->uiDuplexMode = 0;
+
+ /* Free the packets being actively sent & stopped */
+ et131x_free_busy_send_packets(pAdapter);
+
+ /* Re-initialize the send structures */
+ et131x_init_send(pAdapter);
+
+ /* Reset the RFD list and re-start RU */
+ et131x_reset_recv(pAdapter);
+
+ /*
+ * Bring the device back to the state it was during
+ * init prior to autonegotiation being complete. This
+ * way, when we get the auto-neg complete interrupt,
+ * we can complete init by calling ConfigMacREGS2.
+ */
+ et131x_soft_reset(pAdapter);
+
+ /* Setup ET1310 as per the documentation */
+ et131x_adapter_setup(pAdapter);
+
+ /* Setup the PHY into coma mode until the cable is
+ * plugged back in
+ */
+ if (pAdapter->RegistryPhyComa == 1) {
+ EnablePhyComa(pAdapter);
+ }
+ }
+ }
+
+ if (bmsr_ints.bits.auto_neg_complete ||
+ ((pAdapter->AiForceDpx == 3) && (bmsr_ints.bits.link_status))) {
+ if (bmsr.bits.auto_neg_complete || (pAdapter->AiForceDpx == 3)) {
+ ET1310_PhyLinkStatus(pAdapter,
+ &ucLinkStatus, &uiAutoNegStatus,
+ &uiSpeed, &uiDuplex, &uiMdiMdix,
+ &uiMasterSlave, &uiPolarity);
+
+ pAdapter->uiLinkSpeed = uiSpeed;
+ pAdapter->uiDuplexMode = uiDuplex;
+
+ DBG_TRACE(et131x_dbginfo,
+ "pAdapter->uiLinkSpeed 0x%04x, pAdapter->uiDuplex 0x%08x\n",
+ pAdapter->uiLinkSpeed,
+ pAdapter->uiDuplexMode);
+
+ pAdapter->PoMgmt.TransPhyComaModeOnBoot = 20;
+
+ if (pAdapter->uiLinkSpeed == TRUEPHY_SPEED_10MBPS) {
+ // NOTE - Is there a way to query this without TruePHY?
+ // && TRU_QueryCoreType(pAdapter->hTruePhy, 0) == EMI_TRUEPHY_A13O) {
+ uint16_t Register18;
+
+ MiRead(pAdapter, 0x12, &Register18);
+ MiWrite(pAdapter, 0x12, Register18 | 0x4);
+ MiWrite(pAdapter, 0x10, Register18 | 0x8402);
+ MiWrite(pAdapter, 0x11, Register18 | 511);
+ MiWrite(pAdapter, 0x12, Register18);
+ }
+
+ ConfigFlowControl(pAdapter);
+
+ if ((pAdapter->uiLinkSpeed == TRUEPHY_SPEED_1000MBPS) &&
+ (pAdapter->RegistryJumboPacket > 2048))
+ {
+ ET1310_PhyAndOrReg(pAdapter, 0x16, 0xcfff,
+ 0x2000);
+ }
+
+ SetRxDmaTimer(pAdapter);
+ ConfigMACRegs2(pAdapter);
+ }
+ }
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * TPAL_SetPhy10HalfDuplex - Force the phy into 10 Base T Half Duplex mode.
+ * @pAdapter: pointer to the adapter structure
+ *
+ * Also sets the MAC so it is syncd up properly
+ */
+void TPAL_SetPhy10HalfDuplex(struct et131x_adapter *pAdapter)
+{
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Power down PHY */
+ ET1310_PhyPowerDown(pAdapter, 1);
+
+ /* First we need to turn off all other advertisement */
+ ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE);
+
+ ET1310_PhyAdvertise100BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE);
+
+ /* Set our advertise values accordingly */
+ ET1310_PhyAdvertise10BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_HALF);
+
+ /* Power up PHY */
+ ET1310_PhyPowerDown(pAdapter, 0);
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * TPAL_SetPhy10FullDuplex - Force the phy into 10 Base T Full Duplex mode.
+ * @pAdapter: pointer to the adapter structure
+ *
+ * Also sets the MAC so it is syncd up properly
+ */
+void TPAL_SetPhy10FullDuplex(struct et131x_adapter *pAdapter)
+{
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Power down PHY */
+ ET1310_PhyPowerDown(pAdapter, 1);
+
+ /* First we need to turn off all other advertisement */
+ ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE);
+
+ ET1310_PhyAdvertise100BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE);
+
+ /* Set our advertise values accordingly */
+ ET1310_PhyAdvertise10BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_FULL);
+
+ /* Power up PHY */
+ ET1310_PhyPowerDown(pAdapter, 0);
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * TPAL_SetPhy10Force - Force Base-T FD mode WITHOUT using autonegotiation
+ * @pAdapter: pointer to the adapter structure
+ */
+void TPAL_SetPhy10Force(struct et131x_adapter *pAdapter)
+{
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Power down PHY */
+ ET1310_PhyPowerDown(pAdapter, 1);
+
+ /* Disable autoneg */
+ ET1310_PhyAutoNeg(pAdapter, false);
+
+ /* Disable all advertisement */
+ ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE);
+ ET1310_PhyAdvertise10BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE);
+ ET1310_PhyAdvertise100BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE);
+
+ /* Force 10 Mbps */
+ ET1310_PhySpeedSelect(pAdapter, TRUEPHY_SPEED_10MBPS);
+
+ /* Force Full duplex */
+ ET1310_PhyDuplexMode(pAdapter, TRUEPHY_DUPLEX_FULL);
+
+ /* Power up PHY */
+ ET1310_PhyPowerDown(pAdapter, 0);
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * TPAL_SetPhy100HalfDuplex - Force 100 Base T Half Duplex mode.
+ * @pAdapter: pointer to the adapter structure
+ *
+ * Also sets the MAC so it is syncd up properly.
+ */
+void TPAL_SetPhy100HalfDuplex(struct et131x_adapter *pAdapter)
+{
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Power down PHY */
+ ET1310_PhyPowerDown(pAdapter, 1);
+
+ /* first we need to turn off all other advertisement */
+ ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE);
+
+ ET1310_PhyAdvertise10BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE);
+
+ /* Set our advertise values accordingly */
+ ET1310_PhyAdvertise100BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_HALF);
+
+ /* Set speed */
+ ET1310_PhySpeedSelect(pAdapter, TRUEPHY_SPEED_100MBPS);
+
+ /* Power up PHY */
+ ET1310_PhyPowerDown(pAdapter, 0);
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * TPAL_SetPhy100FullDuplex - Force 100 Base T Full Duplex mode.
+ * @pAdapter: pointer to the adapter structure
+ *
+ * Also sets the MAC so it is syncd up properly
+ */
+void TPAL_SetPhy100FullDuplex(struct et131x_adapter *pAdapter)
+{
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Power down PHY */
+ ET1310_PhyPowerDown(pAdapter, 1);
+
+ /* First we need to turn off all other advertisement */
+ ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE);
+
+ ET1310_PhyAdvertise10BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE);
+
+ /* Set our advertise values accordingly */
+ ET1310_PhyAdvertise100BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_FULL);
+
+ /* Power up PHY */
+ ET1310_PhyPowerDown(pAdapter, 0);
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * TPAL_SetPhy100Force - Force 100 BaseT FD mode WITHOUT using autonegotiation
+ * @pAdapter: pointer to the adapter structure
+ */
+void TPAL_SetPhy100Force(struct et131x_adapter *pAdapter)
+{
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Power down PHY */
+ ET1310_PhyPowerDown(pAdapter, 1);
+
+ /* Disable autoneg */
+ ET1310_PhyAutoNeg(pAdapter, false);
+
+ /* Disable all advertisement */
+ ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE);
+ ET1310_PhyAdvertise10BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE);
+ ET1310_PhyAdvertise100BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE);
+
+ /* Force 100 Mbps */
+ ET1310_PhySpeedSelect(pAdapter, TRUEPHY_SPEED_100MBPS);
+
+ /* Force Full duplex */
+ ET1310_PhyDuplexMode(pAdapter, TRUEPHY_DUPLEX_FULL);
+
+ /* Power up PHY */
+ ET1310_PhyPowerDown(pAdapter, 0);
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * TPAL_SetPhy1000FullDuplex - Force 1000 Base T Full Duplex mode
+ * @pAdapter: pointer to the adapter structure
+ *
+ * Also sets the MAC so it is syncd up properly.
+ */
+void TPAL_SetPhy1000FullDuplex(struct et131x_adapter *pAdapter)
+{
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Power down PHY */
+ ET1310_PhyPowerDown(pAdapter, 1);
+
+ /* first we need to turn off all other advertisement */
+ ET1310_PhyAdvertise100BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE);
+
+ ET1310_PhyAdvertise10BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE);
+
+ /* set our advertise values accordingly */
+ ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_FULL);
+
+ /* power up PHY */
+ ET1310_PhyPowerDown(pAdapter, 0);
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * TPAL_SetPhyAutoNeg - Set phy to autonegotiation mode.
+ * @pAdapter: pointer to the adapter structure
+ */
+void TPAL_SetPhyAutoNeg(struct et131x_adapter *pAdapter)
+{
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Power down PHY */
+ ET1310_PhyPowerDown(pAdapter, 1);
+
+ /* Turn on advertisement of all capabilities */
+ ET1310_PhyAdvertise10BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_BOTH);
+
+ ET1310_PhyAdvertise100BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_BOTH);
+
+ if (pAdapter->DeviceID != ET131X_PCI_DEVICE_ID_FAST) {
+ ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_FULL);
+ } else {
+ ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE);
+ }
+
+ /* Make sure auto-neg is ON (it is disabled in FORCE modes) */
+ ET1310_PhyAutoNeg(pAdapter, true);
+
+ /* Power up PHY */
+ ET1310_PhyPowerDown(pAdapter, 0);
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+
+/*
+ * The routines which follow provide low-level access to the PHY, and are used
+ * primarily by the routines above (although there are a few places elsewhere
+ * in the driver where this level of access is required).
+ */
+
+static const uint16_t ConfigPhy[25][2] = {
+ /* Reg Value Register */
+ /* Addr */
+ {0x880B, 0x0926}, /* AfeIfCreg4B1000Msbs */
+ {0x880C, 0x0926}, /* AfeIfCreg4B100Msbs */
+ {0x880D, 0x0926}, /* AfeIfCreg4B10Msbs */
+
+ {0x880E, 0xB4D3}, /* AfeIfCreg4B1000Lsbs */
+ {0x880F, 0xB4D3}, /* AfeIfCreg4B100Lsbs */
+ {0x8810, 0xB4D3}, /* AfeIfCreg4B10Lsbs */
+
+ {0x8805, 0xB03E}, /* AfeIfCreg3B1000Msbs */
+ {0x8806, 0xB03E}, /* AfeIfCreg3B100Msbs */
+ {0x8807, 0xFF00}, /* AfeIfCreg3B10Msbs */
+
+ {0x8808, 0xE090}, /* AfeIfCreg3B1000Lsbs */
+ {0x8809, 0xE110}, /* AfeIfCreg3B100Lsbs */
+ {0x880A, 0x0000}, /* AfeIfCreg3B10Lsbs */
+
+ {0x300D, 1}, /* DisableNorm */
+
+ {0x280C, 0x0180}, /* LinkHoldEnd */
+
+ {0x1C21, 0x0002}, /* AlphaM */
+
+ {0x3821, 6}, /* FfeLkgTx0 */
+ {0x381D, 1}, /* FfeLkg1g4 */
+ {0x381E, 1}, /* FfeLkg1g5 */
+ {0x381F, 1}, /* FfeLkg1g6 */
+ {0x3820, 1}, /* FfeLkg1g7 */
+
+ {0x8402, 0x01F0}, /* Btinact */
+ {0x800E, 20}, /* LftrainTime */
+ {0x800F, 24}, /* DvguardTime */
+ {0x8010, 46}, /* IdlguardTime */
+
+ {0, 0}
+
+};
+
+/* condensed version of the phy initialization routine */
+void ET1310_PhyInit(struct et131x_adapter *pAdapter)
+{
+ uint16_t usData, usIndex;
+
+ if (pAdapter == NULL) {
+ return;
+ }
+
+ // get the identity (again ?)
+ MiRead(pAdapter, PHY_ID_1, &usData);
+ MiRead(pAdapter, PHY_ID_2, &usData);
+
+ // what does this do/achieve ?
+ MiRead(pAdapter, PHY_MPHY_CONTROL_REG, &usData); // should read 0002
+ MiWrite(pAdapter, PHY_MPHY_CONTROL_REG, 0x0006);
+
+ // read modem register 0402, should I do something with the return data ?
+ MiWrite(pAdapter, PHY_INDEX_REG, 0x0402);
+ MiRead(pAdapter, PHY_DATA_REG, &usData);
+
+ // what does this do/achieve ?
+ MiWrite(pAdapter, PHY_MPHY_CONTROL_REG, 0x0002);
+
+ // get the identity (again ?)
+ MiRead(pAdapter, PHY_ID_1, &usData);
+ MiRead(pAdapter, PHY_ID_2, &usData);
+
+ // what does this achieve ?
+ MiRead(pAdapter, PHY_MPHY_CONTROL_REG, &usData); // should read 0002
+ MiWrite(pAdapter, PHY_MPHY_CONTROL_REG, 0x0006);
+
+ // read modem register 0402, should I do something with the return data?
+ MiWrite(pAdapter, PHY_INDEX_REG, 0x0402);
+ MiRead(pAdapter, PHY_DATA_REG, &usData);
+
+ MiWrite(pAdapter, PHY_MPHY_CONTROL_REG, 0x0002);
+
+ // what does this achieve (should return 0x1040)
+ MiRead(pAdapter, PHY_CONTROL, &usData);
+ MiRead(pAdapter, PHY_MPHY_CONTROL_REG, &usData); // should read 0002
+ MiWrite(pAdapter, PHY_CONTROL, 0x1840);
+
+ MiWrite(pAdapter, PHY_MPHY_CONTROL_REG, 0x0007);
+
+ // here the writing of the array starts....
+ usIndex = 0;
+ while (ConfigPhy[usIndex][0] != 0x0000) {
+ // write value
+ MiWrite(pAdapter, PHY_INDEX_REG, ConfigPhy[usIndex][0]);
+ MiWrite(pAdapter, PHY_DATA_REG, ConfigPhy[usIndex][1]);
+
+ // read it back
+ MiWrite(pAdapter, PHY_INDEX_REG, ConfigPhy[usIndex][0]);
+ MiRead(pAdapter, PHY_DATA_REG, &usData);
+
+ // do a check on the value read back ?
+ usIndex++;
+ }
+ // here the writing of the array ends...
+
+ MiRead(pAdapter, PHY_CONTROL, &usData); // 0x1840
+ MiRead(pAdapter, PHY_MPHY_CONTROL_REG, &usData); // should read 0007
+ MiWrite(pAdapter, PHY_CONTROL, 0x1040);
+ MiWrite(pAdapter, PHY_MPHY_CONTROL_REG, 0x0002);
+}
+
+void ET1310_PhyReset(struct et131x_adapter *pAdapter)
+{
+ MiWrite(pAdapter, PHY_CONTROL, 0x8000);
+}
+
+void ET1310_PhyPowerDown(struct et131x_adapter *pAdapter, bool down)
+{
+ uint16_t usData;
+
+ MiRead(pAdapter, PHY_CONTROL, &usData);
+
+ if (down == false) {
+ // Power UP
+ usData &= ~0x0800;
+ MiWrite(pAdapter, PHY_CONTROL, usData);
+ } else {
+ // Power DOWN
+ usData |= 0x0800;
+ MiWrite(pAdapter, PHY_CONTROL, usData);
+ }
+}
+
+void ET1310_PhyAutoNeg(struct et131x_adapter *pAdapter, bool enable)
+{
+ uint16_t usData;
+
+ MiRead(pAdapter, PHY_CONTROL, &usData);
+
+ if (enable == true) {
+ // Autonegotiation ON
+ usData |= 0x1000;
+ MiWrite(pAdapter, PHY_CONTROL, usData);
+ } else {
+ // Autonegotiation OFF
+ usData &= ~0x1000;
+ MiWrite(pAdapter, PHY_CONTROL, usData);
+ }
+}
+
+void ET1310_PhyDuplexMode(struct et131x_adapter *pAdapter, uint16_t duplex)
+{
+ uint16_t usData;
+
+ MiRead(pAdapter, PHY_CONTROL, &usData);
+
+ if (duplex == TRUEPHY_DUPLEX_FULL) {
+ // Set Full Duplex
+ usData |= 0x100;
+ MiWrite(pAdapter, PHY_CONTROL, usData);
+ } else {
+ // Set Half Duplex
+ usData &= ~0x100;
+ MiWrite(pAdapter, PHY_CONTROL, usData);
+ }
+}
+
+void ET1310_PhySpeedSelect(struct et131x_adapter *pAdapter, uint16_t speed)
+{
+ uint16_t usData;
+
+ // Read the PHY control register
+ MiRead(pAdapter, PHY_CONTROL, &usData);
+
+ // Clear all Speed settings (Bits 6, 13)
+ usData &= ~0x2040;
+
+ // Reset the speed bits based on user selection
+ switch (speed) {
+ case TRUEPHY_SPEED_10MBPS:
+ // Bits already cleared above, do nothing
+ break;
+
+ case TRUEPHY_SPEED_100MBPS:
+ // 100M == Set bit 13
+ usData |= 0x2000;
+ break;
+
+ case TRUEPHY_SPEED_1000MBPS:
+ default:
+ usData |= 0x0040;
+ break;
+ }
+
+ // Write back the new speed
+ MiWrite(pAdapter, PHY_CONTROL, usData);
+}
+
+void ET1310_PhyAdvertise1000BaseT(struct et131x_adapter *pAdapter,
+ uint16_t duplex)
+{
+ uint16_t usData;
+
+ // Read the PHY 1000 Base-T Control Register
+ MiRead(pAdapter, PHY_1000_CONTROL, &usData);
+
+ // Clear Bits 8,9
+ usData &= ~0x0300;
+
+ switch (duplex) {
+ case TRUEPHY_ADV_DUPLEX_NONE:
+ // Duplex already cleared, do nothing
+ break;
+
+ case TRUEPHY_ADV_DUPLEX_FULL:
+ // Set Bit 9
+ usData |= 0x0200;
+ break;
+
+ case TRUEPHY_ADV_DUPLEX_HALF:
+ // Set Bit 8
+ usData |= 0x0100;
+ break;
+
+ case TRUEPHY_ADV_DUPLEX_BOTH:
+ default:
+ usData |= 0x0300;
+ break;
+ }
+
+ // Write back advertisement
+ MiWrite(pAdapter, PHY_1000_CONTROL, usData);
+}
+
+void ET1310_PhyAdvertise100BaseT(struct et131x_adapter *pAdapter,
+ uint16_t duplex)
+{
+ uint16_t usData;
+
+ // Read the Autonegotiation Register (10/100)
+ MiRead(pAdapter, PHY_AUTO_ADVERTISEMENT, &usData);
+
+ // Clear bits 7,8
+ usData &= ~0x0180;
+
+ switch (duplex) {
+ case TRUEPHY_ADV_DUPLEX_NONE:
+ // Duplex already cleared, do nothing
+ break;
+
+ case TRUEPHY_ADV_DUPLEX_FULL:
+ // Set Bit 8
+ usData |= 0x0100;
+ break;
+
+ case TRUEPHY_ADV_DUPLEX_HALF:
+ // Set Bit 7
+ usData |= 0x0080;
+ break;
+
+ case TRUEPHY_ADV_DUPLEX_BOTH:
+ default:
+ // Set Bits 7,8
+ usData |= 0x0180;
+ break;
+ }
+
+ // Write back advertisement
+ MiWrite(pAdapter, PHY_AUTO_ADVERTISEMENT, usData);
+}
+
+void ET1310_PhyAdvertise10BaseT(struct et131x_adapter *pAdapter,
+ uint16_t duplex)
+{
+ uint16_t usData;
+
+ // Read the Autonegotiation Register (10/100)
+ MiRead(pAdapter, PHY_AUTO_ADVERTISEMENT, &usData);
+
+ // Clear bits 5,6
+ usData &= ~0x0060;
+
+ switch (duplex) {
+ case TRUEPHY_ADV_DUPLEX_NONE:
+ // Duplex already cleared, do nothing
+ break;
+
+ case TRUEPHY_ADV_DUPLEX_FULL:
+ // Set Bit 6
+ usData |= 0x0040;
+ break;
+
+ case TRUEPHY_ADV_DUPLEX_HALF:
+ // Set Bit 5
+ usData |= 0x0020;
+ break;
+
+ case TRUEPHY_ADV_DUPLEX_BOTH:
+ default:
+ // Set Bits 5,6
+ usData |= 0x0060;
+ break;
+ }
+
+ // Write back advertisement
+ MiWrite(pAdapter, PHY_AUTO_ADVERTISEMENT, usData);
+}
+
+void ET1310_PhyLinkStatus(struct et131x_adapter *pAdapter,
+ uint8_t *ucLinkStatus,
+ uint32_t *uiAutoNeg,
+ uint32_t *uiLinkSpeed,
+ uint32_t *uiDuplexMode,
+ uint32_t *uiMdiMdix,
+ uint32_t *uiMasterSlave, uint32_t *uiPolarity)
+{
+ uint16_t usMiStatus = 0;
+ uint16_t us1000BaseT = 0;
+ uint16_t usVmiPhyStatus = 0;
+ uint16_t usControl = 0;
+
+ MiRead(pAdapter, PHY_STATUS, &usMiStatus);
+ MiRead(pAdapter, PHY_1000_STATUS, &us1000BaseT);
+ MiRead(pAdapter, PHY_PHY_STATUS, &usVmiPhyStatus);
+ MiRead(pAdapter, PHY_CONTROL, &usControl);
+
+ if (ucLinkStatus) {
+ *ucLinkStatus =
+ (unsigned char)((usVmiPhyStatus & 0x0040) ? 1 : 0);
+ }
+
+ if (uiAutoNeg) {
+ *uiAutoNeg =
+ (usControl & 0x1000) ? ((usVmiPhyStatus & 0x0020) ?
+ TRUEPHY_ANEG_COMPLETE :
+ TRUEPHY_ANEG_NOT_COMPLETE) :
+ TRUEPHY_ANEG_DISABLED;
+ }
+
+ if (uiLinkSpeed) {
+ *uiLinkSpeed = (usVmiPhyStatus & 0x0300) >> 8;
+ }
+
+ if (uiDuplexMode) {
+ *uiDuplexMode = (usVmiPhyStatus & 0x0080) >> 7;
+ }
+
+ if (uiMdiMdix) {
+ /* NOTE: Need to complete this */
+ *uiMdiMdix = 0;
+ }
+
+ if (uiMasterSlave) {
+ *uiMasterSlave =
+ (us1000BaseT & 0x4000) ? TRUEPHY_CFG_MASTER :
+ TRUEPHY_CFG_SLAVE;
+ }
+
+ if (uiPolarity) {
+ *uiPolarity =
+ (usVmiPhyStatus & 0x0400) ? TRUEPHY_POLARITY_INVERTED :
+ TRUEPHY_POLARITY_NORMAL;
+ }
+}
+
+void ET1310_PhyAndOrReg(struct et131x_adapter *pAdapter,
+ uint16_t regnum, uint16_t andMask, uint16_t orMask)
+{
+ uint16_t reg;
+
+ // Read the requested register
+ MiRead(pAdapter, regnum, ®);
+
+ // Apply the AND mask
+ reg &= andMask;
+
+ // Apply the OR mask
+ reg |= orMask;
+
+ // Write the value back to the register
+ MiWrite(pAdapter, regnum, reg);
+}
+
+void ET1310_PhyAccessMiBit(struct et131x_adapter *pAdapter, uint16_t action,
+ uint16_t regnum, uint16_t bitnum, uint8_t *value)
+{
+ uint16_t reg;
+ uint16_t mask = 0;
+
+ // Create a mask to isolate the requested bit
+ mask = 0x0001 << bitnum;
+
+ // Read the requested register
+ MiRead(pAdapter, regnum, ®);
+
+ switch (action) {
+ case TRUEPHY_BIT_READ:
+ if (value != NULL) {
+ *value = (reg & mask) >> bitnum;
+ }
+ break;
+
+ case TRUEPHY_BIT_SET:
+ reg |= mask;
+ MiWrite(pAdapter, regnum, reg);
+ break;
+
+ case TRUEPHY_BIT_CLEAR:
+ reg &= ~mask;
+ MiWrite(pAdapter, regnum, reg);
+ break;
+
+ default:
+ break;
+ }
+}
diff --git a/drivers/staging/et131x/et1310_phy.h b/drivers/staging/et131x/et1310_phy.h
new file mode 100644
index 0000000..d624cbb
--- /dev/null
+++ b/drivers/staging/et131x/et1310_phy.h
@@ -0,0 +1,910 @@
+/*
+ * Agere Systems Inc.
+ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * et1310_phy.h - Defines, structs, enums, prototypes, etc. pertaining to the
+ * PHY.
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#ifndef _ET1310_PHY_H_
+#define _ET1310_PHY_H_
+
+#include "et1310_address_map.h"
+
+#define TRUEPHY_SUCCESS 0
+#define TRUEPHY_FAILURE 1
+typedef void *TRUEPHY_HANDLE;
+typedef void *TRUEPHY_PLATFORM_HANDLE;
+typedef void *TRUEPHY_OSAL_HANDLE;
+
+/* MI Register Addresses */
+#define MI_CONTROL_REG 0
+#define MI_STATUS_REG 1
+#define MI_PHY_IDENTIFIER_1_REG 2
+#define MI_PHY_IDENTIFIER_2_REG 3
+#define MI_AUTONEG_ADVERTISEMENT_REG 4
+#define MI_AUTONEG_LINK_PARTNER_ABILITY_REG 5
+#define MI_AUTONEG_EXPANSION_REG 6
+#define MI_AUTONEG_NEXT_PAGE_TRANSMIT_REG 7
+#define MI_LINK_PARTNER_NEXT_PAGE_REG 8
+#define MI_1000BASET_CONTROL_REG 9
+#define MI_1000BASET_STATUS_REG 10
+#define MI_RESERVED11_REG 11
+#define MI_RESERVED12_REG 12
+#define MI_RESERVED13_REG 13
+#define MI_RESERVED14_REG 14
+#define MI_EXTENDED_STATUS_REG 15
+
+/* VMI Register Addresses */
+#define VMI_RESERVED16_REG 16
+#define VMI_RESERVED17_REG 17
+#define VMI_RESERVED18_REG 18
+#define VMI_LOOPBACK_CONTROL_REG 19
+#define VMI_RESERVED20_REG 20
+#define VMI_MI_CONTROL_REG 21
+#define VMI_PHY_CONFIGURATION_REG 22
+#define VMI_PHY_CONTROL_REG 23
+#define VMI_INTERRUPT_MASK_REG 24
+#define VMI_INTERRUPT_STATUS_REG 25
+#define VMI_PHY_STATUS_REG 26
+#define VMI_LED_CONTROL_1_REG 27
+#define VMI_LED_CONTROL_2_REG 28
+#define VMI_RESERVED29_REG 29
+#define VMI_RESERVED30_REG 30
+#define VMI_RESERVED31_REG 31
+
+/* PHY Register Mapping(MI) Management Interface Regs */
+typedef struct _MI_REGS_t {
+ u8 bmcr; // Basic mode control reg(Reg 0x00)
+ u8 bmsr; // Basic mode status reg(Reg 0x01)
+ u8 idr1; // Phy identifier reg 1(Reg 0x02)
+ u8 idr2; // Phy identifier reg 2(Reg 0x03)
+ u8 anar; // Auto-Negotiation advertisement(Reg 0x04)
+ u8 anlpar; // Auto-Negotiation link Partner Ability(Reg 0x05)
+ u8 aner; // Auto-Negotiation expansion reg(Reg 0x06)
+ u8 annptr; // Auto-Negotiation next page transmit reg(Reg 0x07)
+ u8 lpnpr; // link partner next page reg(Reg 0x08)
+ u8 gcr; // Gigabit basic mode control reg(Reg 0x09)
+ u8 gsr; // Gigabit basic mode status reg(Reg 0x0A)
+ u8 mi_res1[4]; // Future use by MI working group(Reg 0x0B - 0x0E)
+ u8 esr; // Extended status reg(Reg 0x0F)
+ u8 mi_res2[3]; // Future use by MI working group(Reg 0x10 - 0x12)
+ u8 loop_ctl; // Loopback Control Reg(Reg 0x13)
+ u8 mi_res3; // Future use by MI working group(Reg 0x14)
+ u8 mcr; // MI Control Reg(Reg 0x15)
+ u8 pcr; // Configuration Reg(Reg 0x16)
+ u8 phy_ctl; // PHY Control Reg(Reg 0x17)
+ u8 imr; // Interrupt Mask Reg(Reg 0x18)
+ u8 isr; // Interrupt Status Reg(Reg 0x19)
+ u8 psr; // PHY Status Reg(Reg 0x1A)
+ u8 lcr1; // LED Control 1 Reg(Reg 0x1B)
+ u8 lcr2; // LED Control 2 Reg(Reg 0x1C)
+ u8 mi_res4[3]; // Future use by MI working group(Reg 0x1D - 0x1F)
+} MI_REGS_t, *PMI_REGS_t;
+
+/* MI Register 0: Basic mode control register */
+typedef union _MI_BMCR_t {
+ u16 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u16 reset:1; // bit 15
+ u16 loopback:1; // bit 14
+ u16 speed_sel:1; // bit 13
+ u16 enable_autoneg:1; // bit 12
+ u16 power_down:1; // bit 11
+ u16 isolate:1; // bit 10
+ u16 restart_autoneg:1; // bit 9
+ u16 duplex_mode:1; // bit 8
+ u16 col_test:1; // bit 7
+ u16 speed_1000_sel:1; // bit 6
+ u16 res1:6; // bits 0-5
+#else
+ u16 res1:6; // bits 0-5
+ u16 speed_1000_sel:1; // bit 6
+ u16 col_test:1; // bit 7
+ u16 duplex_mode:1; // bit 8
+ u16 restart_autoneg:1; // bit 9
+ u16 isolate:1; // bit 10
+ u16 power_down:1; // bit 11
+ u16 enable_autoneg:1; // bit 12
+ u16 speed_sel:1; // bit 13
+ u16 loopback:1; // bit 14
+ u16 reset:1; // bit 15
+#endif
+ } bits;
+} MI_BMCR_t, *PMI_BMCR_t;
+
+/* MI Register 1: Basic mode status register */
+typedef union _MI_BMSR_t {
+ u16 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u16 link_100T4:1; // bit 15
+ u16 link_100fdx:1; // bit 14
+ u16 link_100hdx:1; // bit 13
+ u16 link_10fdx:1; // bit 12
+ u16 link_10hdx:1; // bit 11
+ u16 link_100T2fdx:1; // bit 10
+ u16 link_100T2hdx:1; // bit 9
+ u16 extend_status:1; // bit 8
+ u16 res1:1; // bit 7
+ u16 preamble_supress:1; // bit 6
+ u16 auto_neg_complete:1; // bit 5
+ u16 remote_fault:1; // bit 4
+ u16 auto_neg_able:1; // bit 3
+ u16 link_status:1; // bit 2
+ u16 jabber_detect:1; // bit 1
+ u16 ext_cap:1; // bit 0
+#else
+ u16 ext_cap:1; // bit 0
+ u16 jabber_detect:1; // bit 1
+ u16 link_status:1; // bit 2
+ u16 auto_neg_able:1; // bit 3
+ u16 remote_fault:1; // bit 4
+ u16 auto_neg_complete:1; // bit 5
+ u16 preamble_supress:1; // bit 6
+ u16 res1:1; // bit 7
+ u16 extend_status:1; // bit 8
+ u16 link_100T2hdx:1; // bit 9
+ u16 link_100T2fdx:1; // bit 10
+ u16 link_10hdx:1; // bit 11
+ u16 link_10fdx:1; // bit 12
+ u16 link_100hdx:1; // bit 13
+ u16 link_100fdx:1; // bit 14
+ u16 link_100T4:1; // bit 15
+#endif
+ } bits;
+} MI_BMSR_t, *PMI_BMSR_t;
+
+/* MI Register 2: Physical Identifier 1 */
+typedef union _MI_IDR1_t {
+ u16 value;
+ struct {
+ u16 ieee_address:16; // 0x0282 default(bits 0-15)
+ } bits;
+} MI_IDR1_t, *PMI_IDR1_t;
+
+/* MI Register 3: Physical Identifier 2 */
+typedef union _MI_IDR2_t {
+ u16 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u16 ieee_address:6; // 111100 default(bits 10-15)
+ u16 model_no:6; // 000001 default(bits 4-9)
+ u16 rev_no:4; // 0010 default(bits 0-3)
+#else
+ u16 rev_no:4; // 0010 default(bits 0-3)
+ u16 model_no:6; // 000001 default(bits 4-9)
+ u16 ieee_address:6; // 111100 default(bits 10-15)
+#endif
+ } bits;
+} MI_IDR2_t, *PMI_IDR2_t;
+
+/* MI Register 4: Auto-negotiation advertisement register */
+typedef union _MI_ANAR_t {
+ u16 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u16 np_indication:1; // bit 15
+ u16 res2:1; // bit 14
+ u16 remote_fault:1; // bit 13
+ u16 res1:1; // bit 12
+ u16 cap_asmpause:1; // bit 11
+ u16 cap_pause:1; // bit 10
+ u16 cap_100T4:1; // bit 9
+ u16 cap_100fdx:1; // bit 8
+ u16 cap_100hdx:1; // bit 7
+ u16 cap_10fdx:1; // bit 6
+ u16 cap_10hdx:1; // bit 5
+ u16 selector:5; // bits 0-4
+#else
+ u16 selector:5; // bits 0-4
+ u16 cap_10hdx:1; // bit 5
+ u16 cap_10fdx:1; // bit 6
+ u16 cap_100hdx:1; // bit 7
+ u16 cap_100fdx:1; // bit 8
+ u16 cap_100T4:1; // bit 9
+ u16 cap_pause:1; // bit 10
+ u16 cap_asmpause:1; // bit 11
+ u16 res1:1; // bit 12
+ u16 remote_fault:1; // bit 13
+ u16 res2:1; // bit 14
+ u16 np_indication:1; // bit 15
+#endif
+ } bits;
+} MI_ANAR_t, *PMI_ANAR_t;
+
+/* MI Register 5: Auto-negotiation link partner advertisement register */
+typedef struct _MI_ANLPAR_t {
+ u16 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u16 np_indication:1; // bit 15
+ u16 acknowledge:1; // bit 14
+ u16 remote_fault:1; // bit 13
+ u16 res1:1; // bit 12
+ u16 cap_asmpause:1; // bit 11
+ u16 cap_pause:1; // bit 10
+ u16 cap_100T4:1; // bit 9
+ u16 cap_100fdx:1; // bit 8
+ u16 cap_100hdx:1; // bit 7
+ u16 cap_10fdx:1; // bit 6
+ u16 cap_10hdx:1; // bit 5
+ u16 selector:5; // bits 0-4
+#else
+ u16 selector:5; // bits 0-4
+ u16 cap_10hdx:1; // bit 5
+ u16 cap_10fdx:1; // bit 6
+ u16 cap_100hdx:1; // bit 7
+ u16 cap_100fdx:1; // bit 8
+ u16 cap_100T4:1; // bit 9
+ u16 cap_pause:1; // bit 10
+ u16 cap_asmpause:1; // bit 11
+ u16 res1:1; // bit 12
+ u16 remote_fault:1; // bit 13
+ u16 acknowledge:1; // bit 14
+ u16 np_indication:1; // bit 15
+#endif
+ } bits;
+} MI_ANLPAR_t, *PMI_ANLPAR_t;
+
+/* MI Register 6: Auto-negotiation expansion register */
+typedef union _MI_ANER_t {
+ u16 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u16 res:11; // bits 5-15
+ u16 pdf:1; // bit 4
+ u16 lp_np_able:1; // bit 3
+ u16 np_able:1; // bit 2
+ u16 page_rx:1; // bit 1
+ u16 lp_an_able:1; // bit 0
+#else
+ u16 lp_an_able:1; // bit 0
+ u16 page_rx:1; // bit 1
+ u16 np_able:1; // bit 2
+ u16 lp_np_able:1; // bit 3
+ u16 pdf:1; // bit 4
+ u16 res:11; // bits 5-15
+#endif
+ } bits;
+} MI_ANER_t, *PMI_ANER_t;
+
+/* MI Register 7: Auto-negotiation next page transmit reg(0x07) */
+typedef union _MI_ANNPTR_t {
+ u16 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u16 np:1; // bit 15
+ u16 res1:1; // bit 14
+ u16 msg_page:1; // bit 13
+ u16 ack2:1; // bit 12
+ u16 toggle:1; // bit 11
+ u16 msg:11; // bits 0-10
+#else
+ u16 msg:11; // bits 0-10
+ u16 toggle:1; // bit 11
+ u16 ack2:1; // bit 12
+ u16 msg_page:1; // bit 13
+ u16 res1:1; // bit 14
+ u16 np:1; // bit 15
+#endif
+ } bits;
+} MI_ANNPTR_t, *PMI_ANNPTR_t;
+
+/* MI Register 8: Link Partner Next Page Reg(0x08) */
+typedef union _MI_LPNPR_t {
+ u16 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u16 np:1; // bit 15
+ u16 ack:1; // bit 14
+ u16 msg_page:1; // bit 13
+ u16 ack2:1; // bit 12
+ u16 toggle:1; // bit 11
+ u16 msg:11; // bits 0-10
+#else
+ u16 msg:11; // bits 0-10
+ u16 toggle:1; // bit 11
+ u16 ack2:1; // bit 12
+ u16 msg_page:1; // bit 13
+ u16 ack:1; // bit 14
+ u16 np:1; // bit 15
+#endif
+ } bits;
+} MI_LPNPR_t, *PMI_LPNPR_t;
+
+/* MI Register 9: 1000BaseT Control Reg(0x09) */
+typedef union _MI_GCR_t {
+ u16 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u16 test_mode:3; // bits 13-15
+ u16 ms_config_en:1; // bit 12
+ u16 ms_value:1; // bit 11
+ u16 port_type:1; // bit 10
+ u16 link_1000fdx:1; // bit 9
+ u16 link_1000hdx:1; // bit 8
+ u16 res:8; // bit 0-7
+#else
+ u16 res:8; // bit 0-7
+ u16 link_1000hdx:1; // bit 8
+ u16 link_1000fdx:1; // bit 9
+ u16 port_type:1; // bit 10
+ u16 ms_value:1; // bit 11
+ u16 ms_config_en:1; // bit 12
+ u16 test_mode:3; // bits 13-15
+#endif
+ } bits;
+} MI_GCR_t, *PMI_GCR_t;
+
+/* MI Register 10: 1000BaseT Status Reg(0x0A) */
+typedef union _MI_GSR_t {
+ u16 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u16 ms_config_fault:1; // bit 15
+ u16 ms_resolve:1; // bit 14
+ u16 local_rx_status:1; // bit 13
+ u16 remote_rx_status:1; // bit 12
+ u16 link_1000fdx:1; // bit 11
+ u16 link_1000hdx:1; // bit 10
+ u16 res:2; // bits 8-9
+ u16 idle_err_cnt:8; // bits 0-7
+#else
+ u16 idle_err_cnt:8; // bits 0-7
+ u16 res:2; // bits 8-9
+ u16 link_1000hdx:1; // bit 10
+ u16 link_1000fdx:1; // bit 11
+ u16 remote_rx_status:1; // bit 12
+ u16 local_rx_status:1; // bit 13
+ u16 ms_resolve:1; // bit 14
+ u16 ms_config_fault:1; // bit 15
+#endif
+ } bits;
+} MI_GSR_t, *PMI_GSR_t;
+
+/* MI Register 11 - 14: Reserved Regs(0x0B - 0x0E) */
+typedef union _MI_RES_t {
+ u16 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u16 res15:1; // bit 15
+ u16 res14:1; // bit 14
+ u16 res13:1; // bit 13
+ u16 res12:1; // bit 12
+ u16 res11:1; // bit 11
+ u16 res10:1; // bit 10
+ u16 res9:1; // bit 9
+ u16 res8:1; // bit 8
+ u16 res7:1; // bit 7
+ u16 res6:1; // bit 6
+ u16 res5:1; // bit 5
+ u16 res4:1; // bit 4
+ u16 res3:1; // bit 3
+ u16 res2:1; // bit 2
+ u16 res1:1; // bit 1
+ u16 res0:1; // bit 0
+#else
+ u16 res0:1; // bit 0
+ u16 res1:1; // bit 1
+ u16 res2:1; // bit 2
+ u16 res3:1; // bit 3
+ u16 res4:1; // bit 4
+ u16 res5:1; // bit 5
+ u16 res6:1; // bit 6
+ u16 res7:1; // bit 7
+ u16 res8:1; // bit 8
+ u16 res9:1; // bit 9
+ u16 res10:1; // bit 10
+ u16 res11:1; // bit 11
+ u16 res12:1; // bit 12
+ u16 res13:1; // bit 13
+ u16 res14:1; // bit 14
+ u16 res15:1; // bit 15
+#endif
+ } bits;
+} MI_RES_t, *PMI_RES_t;
+
+/* MI Register 15: Extended status Reg(0x0F) */
+typedef union _MI_ESR_t {
+ u16 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u16 link_1000Xfdx:1; // bit 15
+ u16 link_1000Xhdx:1; // bit 14
+ u16 link_1000fdx:1; // bit 13
+ u16 link_1000hdx:1; // bit 12
+ u16 res:12; // bit 0-11
+#else
+ u16 res:12; // bit 0-11
+ u16 link_1000hdx:1; // bit 12
+ u16 link_1000fdx:1; // bit 13
+ u16 link_1000Xhdx:1; // bit 14
+ u16 link_1000Xfdx:1; // bit 15
+#endif
+ } bits;
+} MI_ESR_t, *PMI_ESR_t;
+
+/* MI Register 16 - 18: Reserved Reg(0x10-0x12) */
+
+/* MI Register 19: Loopback Control Reg(0x13) */
+typedef union _MI_LCR_t {
+ u16 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u16 mii_en:1; // bit 15
+ u16 pcs_en:1; // bit 14
+ u16 pmd_en:1; // bit 13
+ u16 all_digital_en:1; // bit 12
+ u16 replica_en:1; // bit 11
+ u16 line_driver_en:1; // bit 10
+ u16 res:10; // bit 0-9
+#else
+ u16 res:10; // bit 0-9
+ u16 line_driver_en:1; // bit 10
+ u16 replica_en:1; // bit 11
+ u16 all_digital_en:1; // bit 12
+ u16 pmd_en:1; // bit 13
+ u16 pcs_en:1; // bit 14
+ u16 mii_en:1; // bit 15
+#endif
+ } bits;
+} MI_LCR_t, *PMI_LCR_t;
+
+/* MI Register 20: Reserved Reg(0x14) */
+
+/* MI Register 21: Management Interface Control Reg(0x15) */
+typedef union _MI_MICR_t {
+ u16 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u16 res1:5; // bits 11-15
+ u16 mi_error_count:7; // bits 4-10
+ u16 res2:1; // bit 3
+ u16 ignore_10g_fr:1; // bit 2
+ u16 res3:1; // bit 1
+ u16 preamble_supress_en:1; // bit 0
+#else
+ u16 preamble_supress_en:1; // bit 0
+ u16 res3:1; // bit 1
+ u16 ignore_10g_fr:1; // bit 2
+ u16 res2:1; // bit 3
+ u16 mi_error_count:7; // bits 4-10
+ u16 res1:5; // bits 11-15
+#endif
+ } bits;
+} MI_MICR_t, *PMI_MICR_t;
+
+/* MI Register 22: PHY Configuration Reg(0x16) */
+typedef union _MI_PHY_CONFIG_t {
+ u16 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u16 crs_tx_en:1; // bit 15
+ u16 res1:1; // bit 14
+ u16 tx_fifo_depth:2; // bits 12-13
+ u16 speed_downshift:2; // bits 10-11
+ u16 pbi_detect:1; // bit 9
+ u16 tbi_rate:1; // bit 8
+ u16 alternate_np:1; // bit 7
+ u16 group_mdio_en:1; // bit 6
+ u16 tx_clock_en:1; // bit 5
+ u16 sys_clock_en:1; // bit 4
+ u16 res2:1; // bit 3
+ u16 mac_if_mode:3; // bits 0-2
+#else
+ u16 mac_if_mode:3; // bits 0-2
+ u16 res2:1; // bit 3
+ u16 sys_clock_en:1; // bit 4
+ u16 tx_clock_en:1; // bit 5
+ u16 group_mdio_en:1; // bit 6
+ u16 alternate_np:1; // bit 7
+ u16 tbi_rate:1; // bit 8
+ u16 pbi_detect:1; // bit 9
+ u16 speed_downshift:2; // bits 10-11
+ u16 tx_fifo_depth:2; // bits 12-13
+ u16 res1:1; // bit 14
+ u16 crs_tx_en:1; // bit 15
+#endif
+ } bits;
+} MI_PHY_CONFIG_t, *PMI_PHY_CONFIG_t;
+
+/* MI Register 23: PHY CONTROL Reg(0x17) */
+typedef union _MI_PHY_CONTROL_t {
+ u16 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u16 res1:1; // bit 15
+ u16 tdr_en:1; // bit 14
+ u16 res2:1; // bit 13
+ u16 downshift_attempts:2; // bits 11-12
+ u16 res3:5; // bit 6-10
+ u16 jabber_10baseT:1; // bit 5
+ u16 sqe_10baseT:1; // bit 4
+ u16 tp_loopback_10baseT:1; // bit 3
+ u16 preamble_gen_en:1; // bit 2
+ u16 res4:1; // bit 1
+ u16 force_int:1; // bit 0
+#else
+ u16 force_int:1; // bit 0
+ u16 res4:1; // bit 1
+ u16 preamble_gen_en:1; // bit 2
+ u16 tp_loopback_10baseT:1; // bit 3
+ u16 sqe_10baseT:1; // bit 4
+ u16 jabber_10baseT:1; // bit 5
+ u16 res3:5; // bit 6-10
+ u16 downshift_attempts:2; // bits 11-12
+ u16 res2:1; // bit 13
+ u16 tdr_en:1; // bit 14
+ u16 res1:1; // bit 15
+#endif
+ } bits;
+} MI_PHY_CONTROL_t, *PMI_PHY_CONTROL_t;
+
+/* MI Register 24: Interrupt Mask Reg(0x18) */
+typedef union _MI_IMR_t {
+ u16 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u16 res1:6; // bits 10-15
+ u16 mdio_sync_lost:1; // bit 9
+ u16 autoneg_status:1; // bit 8
+ u16 hi_bit_err:1; // bit 7
+ u16 np_rx:1; // bit 6
+ u16 err_counter_full:1; // bit 5
+ u16 fifo_over_underflow:1; // bit 4
+ u16 rx_status:1; // bit 3
+ u16 link_status:1; // bit 2
+ u16 automatic_speed:1; // bit 1
+ u16 int_en:1; // bit 0
+#else
+ u16 int_en:1; // bit 0
+ u16 automatic_speed:1; // bit 1
+ u16 link_status:1; // bit 2
+ u16 rx_status:1; // bit 3
+ u16 fifo_over_underflow:1; // bit 4
+ u16 err_counter_full:1; // bit 5
+ u16 np_rx:1; // bit 6
+ u16 hi_bit_err:1; // bit 7
+ u16 autoneg_status:1; // bit 8
+ u16 mdio_sync_lost:1; // bit 9
+ u16 res1:6; // bits 10-15
+#endif
+ } bits;
+} MI_IMR_t, *PMI_IMR_t;
+
+/* MI Register 25: Interrupt Status Reg(0x19) */
+typedef union _MI_ISR_t {
+ u16 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u16 res1:6; // bits 10-15
+ u16 mdio_sync_lost:1; // bit 9
+ u16 autoneg_status:1; // bit 8
+ u16 hi_bit_err:1; // bit 7
+ u16 np_rx:1; // bit 6
+ u16 err_counter_full:1; // bit 5
+ u16 fifo_over_underflow:1; // bit 4
+ u16 rx_status:1; // bit 3
+ u16 link_status:1; // bit 2
+ u16 automatic_speed:1; // bit 1
+ u16 int_en:1; // bit 0
+#else
+ u16 int_en:1; // bit 0
+ u16 automatic_speed:1; // bit 1
+ u16 link_status:1; // bit 2
+ u16 rx_status:1; // bit 3
+ u16 fifo_over_underflow:1; // bit 4
+ u16 err_counter_full:1; // bit 5
+ u16 np_rx:1; // bit 6
+ u16 hi_bit_err:1; // bit 7
+ u16 autoneg_status:1; // bit 8
+ u16 mdio_sync_lost:1; // bit 9
+ u16 res1:6; // bits 10-15
+#endif
+ } bits;
+} MI_ISR_t, *PMI_ISR_t;
+
+/* MI Register 26: PHY Status Reg(0x1A) */
+typedef union _MI_PSR_t {
+ u16 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u16 res1:1; // bit 15
+ u16 autoneg_fault:2; // bit 13-14
+ u16 autoneg_status:1; // bit 12
+ u16 mdi_x_status:1; // bit 11
+ u16 polarity_status:1; // bit 10
+ u16 speed_status:2; // bits 8-9
+ u16 duplex_status:1; // bit 7
+ u16 link_status:1; // bit 6
+ u16 tx_status:1; // bit 5
+ u16 rx_status:1; // bit 4
+ u16 collision_status:1; // bit 3
+ u16 autoneg_en:1; // bit 2
+ u16 pause_en:1; // bit 1
+ u16 asymmetric_dir:1; // bit 0
+#else
+ u16 asymmetric_dir:1; // bit 0
+ u16 pause_en:1; // bit 1
+ u16 autoneg_en:1; // bit 2
+ u16 collision_status:1; // bit 3
+ u16 rx_status:1; // bit 4
+ u16 tx_status:1; // bit 5
+ u16 link_status:1; // bit 6
+ u16 duplex_status:1; // bit 7
+ u16 speed_status:2; // bits 8-9
+ u16 polarity_status:1; // bit 10
+ u16 mdi_x_status:1; // bit 11
+ u16 autoneg_status:1; // bit 12
+ u16 autoneg_fault:2; // bit 13-14
+ u16 res1:1; // bit 15
+#endif
+ } bits;
+} MI_PSR_t, *PMI_PSR_t;
+
+/* MI Register 27: LED Control Reg 1(0x1B) */
+typedef union _MI_LCR1_t {
+ u16 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u16 res1:2; // bits 14-15
+ u16 led_dup_indicate:2; // bits 12-13
+ u16 led_10baseT:2; // bits 10-11
+ u16 led_collision:2; // bits 8-9
+ u16 res2:2; // bits 6-7
+ u16 res3:2; // bits 4-5
+ u16 pulse_dur:2; // bits 2-3
+ u16 pulse_stretch1:1; // bit 1
+ u16 pulse_stretch0:1; // bit 0
+#else
+ u16 pulse_stretch0:1; // bit 0
+ u16 pulse_stretch1:1; // bit 1
+ u16 pulse_dur:2; // bits 2-3
+ u16 res3:2; // bits 4-5
+ u16 res2:2; // bits 6-7
+ u16 led_collision:2; // bits 8-9
+ u16 led_10baseT:2; // bits 10-11
+ u16 led_dup_indicate:2; // bits 12-13
+ u16 res1:2; // bits 14-15
+#endif
+ } bits;
+} MI_LCR1_t, *PMI_LCR1_t;
+
+/* MI Register 28: LED Control Reg 2(0x1C) */
+typedef union _MI_LCR2_t {
+ u16 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u16 led_link:4; // bits 12-15
+ u16 led_tx_rx:4; // bits 8-11
+ u16 led_100BaseTX:4; // bits 4-7
+ u16 led_1000BaseT:4; // bits 0-3
+#else
+ u16 led_1000BaseT:4; // bits 0-3
+ u16 led_100BaseTX:4; // bits 4-7
+ u16 led_tx_rx:4; // bits 8-11
+ u16 led_link:4; // bits 12-15
+#endif
+ } bits;
+} MI_LCR2_t, *PMI_LCR2_t;
+
+/* MI Register 29 - 31: Reserved Reg(0x1D - 0x1E) */
+
+/* TruePHY headers */
+typedef struct _TRUEPHY_ACCESS_MI_REGS_ {
+ TRUEPHY_HANDLE hTruePhy;
+ int32_t nPhyId;
+ u8 bReadWrite;
+ u8 *pbyRegs;
+ u8 *pwData;
+ int32_t nRegCount;
+} TRUEPHY_ACCESS_MI_REGS, *PTRUEPHY_ACCESS_MI_REGS;
+
+/* TruePHY headers */
+typedef struct _TAG_TPAL_ACCESS_MI_REGS_ {
+ u32 nPhyId;
+ u8 bReadWrite;
+ u32 nRegCount;
+ u16 Data[4096];
+ u8 Regs[4096];
+} TPAL_ACCESS_MI_REGS, *PTPAL_ACCESS_MI_REGS;
+
+
+typedef TRUEPHY_HANDLE TPAL_HANDLE;
+
+/* Forward declaration of the private adapter structure */
+struct et131x_adapter;
+
+/* OS Specific Functions*/
+void TPAL_SetPhy10HalfDuplex(struct et131x_adapter *adapter);
+void TPAL_SetPhy10FullDuplex(struct et131x_adapter *adapter);
+void TPAL_SetPhy10Force(struct et131x_adapter *pAdapter);
+void TPAL_SetPhy100HalfDuplex(struct et131x_adapter *adapter);
+void TPAL_SetPhy100FullDuplex(struct et131x_adapter *adapter);
+void TPAL_SetPhy100Force(struct et131x_adapter *pAdapter);
+void TPAL_SetPhy1000FullDuplex(struct et131x_adapter *adapter);
+void TPAL_SetPhyAutoNeg(struct et131x_adapter *adapter);
+
+/* Prototypes for ET1310_phy.c */
+int et131x_xcvr_find(struct et131x_adapter *adapter);
+int et131x_setphy_normal(struct et131x_adapter *adapter);
+int32_t PhyMiRead(struct et131x_adapter *adapter,
+ u8 xcvrAddr, u8 xcvrReg, u16 *value);
+
+/* static inline function does not work because et131x_adapter is not always
+ * defined
+ */
+#define MiRead(adapter, xcvrReg, value) \
+ PhyMiRead((adapter), (adapter)->Stats.xcvr_addr, (xcvrReg), (value))
+
+int32_t MiWrite(struct et131x_adapter *adapter,
+ u8 xcvReg, u16 value);
+void et131x_Mii_check(struct et131x_adapter *pAdapter,
+ MI_BMSR_t bmsr, MI_BMSR_t bmsr_ints);
+
+/* This last is not strictly required (the driver could call the TPAL
+ * version instead), but this sets the adapter up correctly, and calls the
+ * access routine indirectly. This protects the driver from changes in TPAL.
+ */
+void SetPhy_10BaseTHalfDuplex(struct et131x_adapter *adapter);
+
+/* Defines for PHY access routines */
+
+// Define bit operation flags
+#define TRUEPHY_BIT_CLEAR 0
+#define TRUEPHY_BIT_SET 1
+#define TRUEPHY_BIT_READ 2
+
+// Define read/write operation flags
+#ifndef TRUEPHY_READ
+#define TRUEPHY_READ 0
+#define TRUEPHY_WRITE 1
+#define TRUEPHY_MASK 2
+#endif
+
+// Define speeds
+#define TRUEPHY_SPEED_10MBPS 0
+#define TRUEPHY_SPEED_100MBPS 1
+#define TRUEPHY_SPEED_1000MBPS 2
+
+// Define duplex modes
+#define TRUEPHY_DUPLEX_HALF 0
+#define TRUEPHY_DUPLEX_FULL 1
+
+// Define master/slave configuration values
+#define TRUEPHY_CFG_SLAVE 0
+#define TRUEPHY_CFG_MASTER 1
+
+// Define MDI/MDI-X settings
+#define TRUEPHY_MDI 0
+#define TRUEPHY_MDIX 1
+#define TRUEPHY_AUTO_MDI_MDIX 2
+
+// Define 10Base-T link polarities
+#define TRUEPHY_POLARITY_NORMAL 0
+#define TRUEPHY_POLARITY_INVERTED 1
+
+// Define auto-negotiation results
+#define TRUEPHY_ANEG_NOT_COMPLETE 0
+#define TRUEPHY_ANEG_COMPLETE 1
+#define TRUEPHY_ANEG_DISABLED 2
+
+/* Define duplex advertisment flags */
+#define TRUEPHY_ADV_DUPLEX_NONE 0x00
+#define TRUEPHY_ADV_DUPLEX_FULL 0x01
+#define TRUEPHY_ADV_DUPLEX_HALF 0x02
+#define TRUEPHY_ADV_DUPLEX_BOTH \
+ (TRUEPHY_ADV_DUPLEX_FULL | TRUEPHY_ADV_DUPLEX_HALF)
+
+#define PHY_CONTROL 0x00 //#define TRU_MI_CONTROL_REGISTER 0
+#define PHY_STATUS 0x01 //#define TRU_MI_STATUS_REGISTER 1
+#define PHY_ID_1 0x02 //#define TRU_MI_PHY_IDENTIFIER_1_REGISTER 2
+#define PHY_ID_2 0x03 //#define TRU_MI_PHY_IDENTIFIER_2_REGISTER 3
+#define PHY_AUTO_ADVERTISEMENT 0x04 //#define TRU_MI_ADVERTISEMENT_REGISTER 4
+#define PHY_AUTO_LINK_PARTNER 0x05 //#define TRU_MI_LINK_PARTNER_ABILITY_REGISTER 5
+#define PHY_AUTO_EXPANSION 0x06 //#define TRU_MI_EXPANSION_REGISTER 6
+#define PHY_AUTO_NEXT_PAGE_TX 0x07 //#define TRU_MI_NEXT_PAGE_TRANSMIT_REGISTER 7
+#define PHY_LINK_PARTNER_NEXT_PAGE 0x08 //#define TRU_MI_LINK_PARTNER_NEXT_PAGE_REGISTER 8
+#define PHY_1000_CONTROL 0x09 //#define TRU_MI_1000BASET_CONTROL_REGISTER 9
+#define PHY_1000_STATUS 0x0A //#define TRU_MI_1000BASET_STATUS_REGISTER 10
+
+#define PHY_EXTENDED_STATUS 0x0F //#define TRU_MI_EXTENDED_STATUS_REGISTER 15
+
+// some defines for modem registers that seem to be 'reserved'
+#define PHY_INDEX_REG 0x10
+#define PHY_DATA_REG 0x11
+
+#define PHY_MPHY_CONTROL_REG 0x12 //#define TRU_VMI_MPHY_CONTROL_REGISTER 18
+
+#define PHY_LOOPBACK_CONTROL 0x13 //#define TRU_VMI_LOOPBACK_CONTROL_1_REGISTER 19
+ //#define TRU_VMI_LOOPBACK_CONTROL_2_REGISTER 20
+#define PHY_REGISTER_MGMT_CONTROL 0x15 //#define TRU_VMI_MI_SEQ_CONTROL_REGISTER 21
+#define PHY_CONFIG 0x16 //#define TRU_VMI_CONFIGURATION_REGISTER 22
+#define PHY_PHY_CONTROL 0x17 //#define TRU_VMI_PHY_CONTROL_REGISTER 23
+#define PHY_INTERRUPT_MASK 0x18 //#define TRU_VMI_INTERRUPT_MASK_REGISTER 24
+#define PHY_INTERRUPT_STATUS 0x19 //#define TRU_VMI_INTERRUPT_STATUS_REGISTER 25
+#define PHY_PHY_STATUS 0x1A //#define TRU_VMI_PHY_STATUS_REGISTER 26
+#define PHY_LED_1 0x1B //#define TRU_VMI_LED_CONTROL_1_REGISTER 27
+#define PHY_LED_2 0x1C //#define TRU_VMI_LED_CONTROL_2_REGISTER 28
+ //#define TRU_VMI_LINK_CONTROL_REGISTER 29
+ //#define TRU_VMI_TIMING_CONTROL_REGISTER
+
+/* Prototypes for PHY access routines */
+void ET1310_PhyInit(struct et131x_adapter *adapter);
+void ET1310_PhyReset(struct et131x_adapter *adapter);
+void ET1310_PhyPowerDown(struct et131x_adapter *adapter, bool down);
+void ET1310_PhyAutoNeg(struct et131x_adapter *adapter, bool enable);
+void ET1310_PhyDuplexMode(struct et131x_adapter *adapter, u16 duplex);
+void ET1310_PhySpeedSelect(struct et131x_adapter *adapter, u16 speed);
+void ET1310_PhyAdvertise1000BaseT(struct et131x_adapter *adapter,
+ u16 duplex);
+void ET1310_PhyAdvertise100BaseT(struct et131x_adapter *adapter,
+ u16 duplex);
+void ET1310_PhyAdvertise10BaseT(struct et131x_adapter *adapter,
+ u16 duplex);
+void ET1310_PhyLinkStatus(struct et131x_adapter *adapter,
+ u8 *ucLinkStatus,
+ u32 *uiAutoNeg,
+ u32 *uiLinkSpeed,
+ u32 *uiDuplexMode,
+ u32 *uiMdiMdix,
+ u32 *uiMasterSlave, u32 *uiPolarity);
+void ET1310_PhyAndOrReg(struct et131x_adapter *adapter,
+ u16 regnum, u16 andMask, u16 orMask);
+void ET1310_PhyAccessMiBit(struct et131x_adapter *adapter,
+ u16 action,
+ u16 regnum, u16 bitnum, u8 *value);
+
+#endif /* _ET1310_PHY_H_ */
diff --git a/drivers/staging/et131x/et1310_pm.c b/drivers/staging/et131x/et1310_pm.c
new file mode 100644
index 0000000..9539bc6
--- /dev/null
+++ b/drivers/staging/et131x/et1310_pm.c
@@ -0,0 +1,207 @@
+/*
+ * Agere Systems Inc.
+ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * et1310_pm.c - All power management related code (not completely implemented)
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#include "et131x_version.h"
+#include "et131x_debug.h"
+#include "et131x_defs.h"
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+
+#include "et1310_phy.h"
+#include "et1310_pm.h"
+#include "et1310_jagcore.h"
+#include "et1310_mac.h"
+#include "et1310_rx.h"
+
+#include "et131x_adapter.h"
+#include "et131x_initpci.h"
+
+/* Data for debugging facilities */
+#ifdef CONFIG_ET131X_DEBUG
+extern dbg_info_t *et131x_dbginfo;
+#endif /* CONFIG_ET131X_DEBUG */
+
+/**
+ * EnablePhyComa - called when network cable is unplugged
+ * @pAdapter: pointer to our adapter structure
+ *
+ * driver receive an phy status change interrupt while in D0 and check that
+ * phy_status is down.
+ *
+ * -- gate off JAGCore;
+ * -- set gigE PHY in Coma mode
+ * -- wake on phy_interrupt; Perform software reset JAGCore,
+ * re-initialize jagcore and gigE PHY
+ *
+ * Add D0-ASPM-PhyLinkDown Support:
+ * -- while in D0, when there is a phy_interrupt indicating phy link
+ * down status, call the MPSetPhyComa routine to enter this active
+ * state power saving mode
+ * -- while in D0-ASPM-PhyLinkDown mode, when there is a phy_interrupt
+ * indicating linkup status, call the MPDisablePhyComa routine to
+ * restore JAGCore and gigE PHY
+ */
+void EnablePhyComa(struct et131x_adapter *pAdapter)
+{
+ unsigned long lockflags;
+ PM_CSR_t GlobalPmCSR;
+ int32_t LoopCounter = 10;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ GlobalPmCSR.value = readl(&pAdapter->CSRAddress->global.pm_csr.value);
+
+ /* Save the GbE PHY speed and duplex modes. Need to restore this
+ * when cable is plugged back in
+ */
+ pAdapter->PoMgmt.PowerDownSpeed = pAdapter->AiForceSpeed;
+ pAdapter->PoMgmt.PowerDownDuplex = pAdapter->AiForceDpx;
+
+ /* Stop sending packets. */
+ spin_lock_irqsave(&pAdapter->SendHWLock, lockflags);
+ MP_SET_FLAG(pAdapter, fMP_ADAPTER_LOWER_POWER);
+ spin_unlock_irqrestore(&pAdapter->SendHWLock, lockflags);
+
+ /* Wait for outstanding Receive packets */
+ while ((MP_GET_RCV_REF(pAdapter) != 0) && (LoopCounter-- > 0)) {
+ mdelay(2);
+ }
+
+ /* Gate off JAGCore 3 clock domains */
+ GlobalPmCSR.bits.pm_sysclk_gate = 0;
+ GlobalPmCSR.bits.pm_txclk_gate = 0;
+ GlobalPmCSR.bits.pm_rxclk_gate = 0;
+ writel(GlobalPmCSR.value, &pAdapter->CSRAddress->global.pm_csr.value);
+
+ /* Program gigE PHY in to Coma mode */
+ GlobalPmCSR.bits.pm_phy_sw_coma = 1;
+ writel(GlobalPmCSR.value, &pAdapter->CSRAddress->global.pm_csr.value);
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * DisablePhyComa - Disable the Phy Coma Mode
+ * @pAdapter: pointer to our adapter structure
+ */
+void DisablePhyComa(struct et131x_adapter *pAdapter)
+{
+ PM_CSR_t GlobalPmCSR;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ GlobalPmCSR.value = readl(&pAdapter->CSRAddress->global.pm_csr.value);
+
+ /* Disable phy_sw_coma register and re-enable JAGCore clocks */
+ GlobalPmCSR.bits.pm_sysclk_gate = 1;
+ GlobalPmCSR.bits.pm_txclk_gate = 1;
+ GlobalPmCSR.bits.pm_rxclk_gate = 1;
+ GlobalPmCSR.bits.pm_phy_sw_coma = 0;
+ writel(GlobalPmCSR.value, &pAdapter->CSRAddress->global.pm_csr.value);
+
+ /* Restore the GbE PHY speed and duplex modes;
+ * Reset JAGCore; re-configure and initialize JAGCore and gigE PHY
+ */
+ pAdapter->AiForceSpeed = pAdapter->PoMgmt.PowerDownSpeed;
+ pAdapter->AiForceDpx = pAdapter->PoMgmt.PowerDownDuplex;
+
+ /* Re-initialize the send structures */
+ et131x_init_send(pAdapter);
+
+ /* Reset the RFD list and re-start RU */
+ et131x_reset_recv(pAdapter);
+
+ /* Bring the device back to the state it was during init prior to
+ * autonegotiation being complete. This way, when we get the auto-neg
+ * complete interrupt, we can complete init by calling ConfigMacREGS2.
+ */
+ et131x_soft_reset(pAdapter);
+
+ /* setup et1310 as per the documentation ?? */
+ et131x_adapter_setup(pAdapter);
+
+ /* Allow Tx to restart */
+ MP_CLEAR_FLAG(pAdapter, fMP_ADAPTER_LOWER_POWER);
+
+ /* Need to re-enable Rx. */
+ et131x_rx_dma_enable(pAdapter);
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
diff --git a/drivers/staging/et131x/et1310_pm.h b/drivers/staging/et131x/et1310_pm.h
new file mode 100644
index 0000000..6802338
--- /dev/null
+++ b/drivers/staging/et131x/et1310_pm.h
@@ -0,0 +1,125 @@
+/*
+ * Agere Systems Inc.
+ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * et1310_pm.h - Defines, structs, enums, prototypes, etc. pertaining to power
+ * management.
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#ifndef _ET1310_PM_H_
+#define _ET1310_PM_H_
+
+#include "et1310_address_map.h"
+
+#define MAX_WOL_PACKET_SIZE 0x80
+#define MAX_WOL_MASK_SIZE ( MAX_WOL_PACKET_SIZE / 8 )
+#define NUM_WOL_PATTERNS 0x5
+#define CRC16_POLY 0x1021
+
+/* Definition of NDIS_DEVICE_POWER_STATE */
+typedef enum {
+ NdisDeviceStateUnspecified = 0,
+ NdisDeviceStateD0,
+ NdisDeviceStateD1,
+ NdisDeviceStateD2,
+ NdisDeviceStateD3
+} NDIS_DEVICE_POWER_STATE;
+
+typedef struct _MP_POWER_MGMT {
+ /* variable putting the phy into coma mode when boot up with no cable
+ * plugged in after 5 seconds
+ */
+ u8 TransPhyComaModeOnBoot;
+
+ /* Array holding the five CRC values that the device is currently
+ * using for WOL. This will be queried when a pattern is to be
+ * removed.
+ */
+ u32 localWolAndCrc0;
+ u16 WOLPatternList[NUM_WOL_PATTERNS];
+ u8 WOLMaskList[NUM_WOL_PATTERNS][MAX_WOL_MASK_SIZE];
+ u32 WOLMaskSize[NUM_WOL_PATTERNS];
+
+ /* IP address */
+ union {
+ u32 u32;
+ u8 u8[4];
+ } IPAddress;
+
+ /* Current Power state of the adapter. */
+ NDIS_DEVICE_POWER_STATE PowerState;
+ bool WOLState;
+ bool WOLEnabled;
+ bool Failed10Half;
+ bool bFailedStateTransition;
+
+ /* Next two used to save power information at power down. This
+ * information will be used during power up to set up parts of Power
+ * Management in JAGCore
+ */
+ u32 tx_en;
+ u32 rx_en;
+ u16 PowerDownSpeed;
+ u8 PowerDownDuplex;
+} MP_POWER_MGMT, *PMP_POWER_MGMT;
+
+/* Forward declaration of the private adapter structure
+ * ( IS THERE A WAY TO DO THIS WITH A TYPEDEF??? )
+ */
+struct et131x_adapter;
+
+u16 CalculateCCITCRC16(u8 *Pattern, u8 *Mask, u32 MaskSize);
+void EnablePhyComa(struct et131x_adapter *adapter);
+void DisablePhyComa(struct et131x_adapter *adapter);
+
+#endif /* _ET1310_PM_H_ */
diff --git a/drivers/staging/et131x/et1310_rx.c b/drivers/staging/et131x/et1310_rx.c
new file mode 100644
index 0000000..ec98da5
--- /dev/null
+++ b/drivers/staging/et131x/et1310_rx.c
@@ -0,0 +1,1391 @@
+/*
+ * Agere Systems Inc.
+ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * et1310_rx.c - Routines used to perform data reception
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#include "et131x_version.h"
+#include "et131x_debug.h"
+#include "et131x_defs.h"
+
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+
+#include "et1310_phy.h"
+#include "et1310_pm.h"
+#include "et1310_jagcore.h"
+
+#include "et131x_adapter.h"
+#include "et131x_initpci.h"
+
+#include "et1310_rx.h"
+
+/* Data for debugging facilities */
+#ifdef CONFIG_ET131X_DEBUG
+extern dbg_info_t *et131x_dbginfo;
+#endif /* CONFIG_ET131X_DEBUG */
+
+
+void nic_return_rfd(struct et131x_adapter *pAdapter, PMP_RFD pMpRfd);
+
+/**
+ * et131x_rx_dma_memory_alloc
+ * @adapter: pointer to our private adapter structure
+ *
+ * Returns 0 on success and errno on failure (as defined in errno.h)
+ *
+ * Allocates Free buffer ring 1 for sure, free buffer ring 0 if required,
+ * and the Packet Status Ring.
+ */
+int et131x_rx_dma_memory_alloc(struct et131x_adapter *adapter)
+{
+ uint32_t OuterLoop, InnerLoop;
+ uint32_t bufsize;
+ uint32_t pktStatRingSize, FBRChunkSize;
+ RX_RING_t *rx_ring;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Setup some convenience pointers */
+ rx_ring = (RX_RING_t *) & adapter->RxRing;
+
+ /* Alloc memory for the lookup table */
+#ifdef USE_FBR0
+ rx_ring->Fbr[0] = kmalloc(sizeof(FBRLOOKUPTABLE), GFP_KERNEL);
+#endif
+
+ rx_ring->Fbr[1] = kmalloc(sizeof(FBRLOOKUPTABLE), GFP_KERNEL);
+
+ /* The first thing we will do is configure the sizes of the buffer
+ * rings. These will change based on jumbo packet support. Larger
+ * jumbo packets increases the size of each entry in FBR0, and the
+ * number of entries in FBR0, while at the same time decreasing the
+ * number of entries in FBR1.
+ *
+ * FBR1 holds "large" frames, FBR0 holds "small" frames. If FBR1
+ * entries are huge in order to accomodate a "jumbo" frame, then it
+ * will have less entries. Conversely, FBR1 will now be relied upon
+ * to carry more "normal" frames, thus it's entry size also increases
+ * and the number of entries goes up too (since it now carries
+ * "small" + "regular" packets.
+ *
+ * In this scheme, we try to maintain 512 entries between the two
+ * rings. Also, FBR1 remains a constant size - when it's size doubles
+ * the number of entries halves. FBR0 increases in size, however.
+ */
+
+ if (adapter->RegistryJumboPacket < 2048) {
+#ifdef USE_FBR0
+ rx_ring->Fbr0BufferSize = 256;
+ rx_ring->Fbr0NumEntries = 512;
+#endif
+ rx_ring->Fbr1BufferSize = 2048;
+ rx_ring->Fbr1NumEntries = 512;
+ } else if (adapter->RegistryJumboPacket < 4096) {
+#ifdef USE_FBR0
+ rx_ring->Fbr0BufferSize = 512;
+ rx_ring->Fbr0NumEntries = 1024;
+#endif
+ rx_ring->Fbr1BufferSize = 4096;
+ rx_ring->Fbr1NumEntries = 512;
+ } else {
+#ifdef USE_FBR0
+ rx_ring->Fbr0BufferSize = 1024;
+ rx_ring->Fbr0NumEntries = 768;
+#endif
+ rx_ring->Fbr1BufferSize = 16384;
+ rx_ring->Fbr1NumEntries = 128;
+ }
+
+#ifdef USE_FBR0
+ adapter->RxRing.PsrNumEntries = adapter->RxRing.Fbr0NumEntries +
+ adapter->RxRing.Fbr1NumEntries;
+#else
+ adapter->RxRing.PsrNumEntries = adapter->RxRing.Fbr1NumEntries;
+#endif
+
+ /* Allocate an area of memory for Free Buffer Ring 1 */
+ bufsize = (sizeof(FBR_DESC_t) * rx_ring->Fbr1NumEntries) + 0xfff;
+ rx_ring->pFbr1RingVa = pci_alloc_consistent(adapter->pdev,
+ bufsize,
+ &rx_ring->pFbr1RingPa);
+ if (!rx_ring->pFbr1RingVa) {
+ DBG_ERROR(et131x_dbginfo,
+ "Cannot alloc memory for Free Buffer Ring 1\n");
+ DBG_LEAVE(et131x_dbginfo);
+ return -ENOMEM;
+ }
+
+ /* Save physical address
+ *
+ * NOTE: pci_alloc_consistent(), used above to alloc DMA regions,
+ * ALWAYS returns SAC (32-bit) addresses. If DAC (64-bit) addresses
+ * are ever returned, make sure the high part is retrieved here
+ * before storing the adjusted address.
+ */
+ rx_ring->Fbr1Realpa = rx_ring->pFbr1RingPa;
+
+ /* Align Free Buffer Ring 1 on a 4K boundary */
+ et131x_align_allocated_memory(adapter,
+ &rx_ring->Fbr1Realpa,
+ &rx_ring->Fbr1offset, 0x0FFF);
+
+ rx_ring->pFbr1RingVa = (void *)((uint8_t *) rx_ring->pFbr1RingVa +
+ rx_ring->Fbr1offset);
+
+#ifdef USE_FBR0
+ /* Allocate an area of memory for Free Buffer Ring 0 */
+ bufsize = (sizeof(FBR_DESC_t) * rx_ring->Fbr0NumEntries) + 0xfff;
+ rx_ring->pFbr0RingVa = pci_alloc_consistent(adapter->pdev,
+ bufsize,
+ &rx_ring->pFbr0RingPa);
+ if (!rx_ring->pFbr0RingVa) {
+ DBG_ERROR(et131x_dbginfo,
+ "Cannot alloc memory for Free Buffer Ring 0\n");
+ DBG_LEAVE(et131x_dbginfo);
+ return -ENOMEM;
+ }
+
+ /* Save physical address
+ *
+ * NOTE: pci_alloc_consistent(), used above to alloc DMA regions,
+ * ALWAYS returns SAC (32-bit) addresses. If DAC (64-bit) addresses
+ * are ever returned, make sure the high part is retrieved here before
+ * storing the adjusted address.
+ */
+ rx_ring->Fbr0Realpa = rx_ring->pFbr0RingPa;
+
+ /* Align Free Buffer Ring 0 on a 4K boundary */
+ et131x_align_allocated_memory(adapter,
+ &rx_ring->Fbr0Realpa,
+ &rx_ring->Fbr0offset, 0x0FFF);
+
+ rx_ring->pFbr0RingVa = (void *)((uint8_t *) rx_ring->pFbr0RingVa +
+ rx_ring->Fbr0offset);
+#endif
+
+ for (OuterLoop = 0; OuterLoop < (rx_ring->Fbr1NumEntries / FBR_CHUNKS);
+ OuterLoop++) {
+ uint64_t Fbr1Offset;
+ uint64_t Fbr1TempPa;
+ uint32_t Fbr1Align;
+
+ /* This code allocates an area of memory big enough for N
+ * free buffers + (buffer_size - 1) so that the buffers can
+ * be aligned on 4k boundaries. If each buffer were aligned
+ * to a buffer_size boundary, the effect would be to double
+ * the size of FBR0. By allocating N buffers at once, we
+ * reduce this overhead.
+ */
+ if (rx_ring->Fbr1BufferSize > 4096) {
+ Fbr1Align = 4096;
+ } else {
+ Fbr1Align = rx_ring->Fbr1BufferSize;
+ }
+
+ FBRChunkSize =
+ (FBR_CHUNKS * rx_ring->Fbr1BufferSize) + Fbr1Align - 1;
+ rx_ring->Fbr1MemVa[OuterLoop] =
+ pci_alloc_consistent(adapter->pdev, FBRChunkSize,
+ &rx_ring->Fbr1MemPa[OuterLoop]);
+
+ if (!rx_ring->Fbr1MemVa[OuterLoop]) {
+ DBG_ERROR(et131x_dbginfo, "Could not alloc memory\n");
+ DBG_LEAVE(et131x_dbginfo);
+ return -ENOMEM;
+ }
+
+ /* See NOTE in "Save Physical Address" comment above */
+ Fbr1TempPa = rx_ring->Fbr1MemPa[OuterLoop];
+
+ et131x_align_allocated_memory(adapter,
+ &Fbr1TempPa,
+ &Fbr1Offset, (Fbr1Align - 1));
+
+ for (InnerLoop = 0; InnerLoop < FBR_CHUNKS; InnerLoop++) {
+ uint32_t index = (OuterLoop * FBR_CHUNKS) + InnerLoop;
+
+ /* Save the Virtual address of this index for quick
+ * access later
+ */
+ rx_ring->Fbr[1]->Va[index] =
+ (uint8_t *) rx_ring->Fbr1MemVa[OuterLoop] +
+ (InnerLoop * rx_ring->Fbr1BufferSize) + Fbr1Offset;
+
+ /* now store the physical address in the descriptor
+ * so the device can access it
+ */
+ rx_ring->Fbr[1]->PAHigh[index] =
+ (uint32_t) (Fbr1TempPa >> 32);
+ rx_ring->Fbr[1]->PALow[index] = (uint32_t) Fbr1TempPa;
+
+ Fbr1TempPa += rx_ring->Fbr1BufferSize;
+
+ rx_ring->Fbr[1]->Buffer1[index] =
+ rx_ring->Fbr[1]->Va[index];
+ rx_ring->Fbr[1]->Buffer2[index] =
+ rx_ring->Fbr[1]->Va[index] - 4;
+ }
+ }
+
+#ifdef USE_FBR0
+ /* Same for FBR0 (if in use) */
+ for (OuterLoop = 0; OuterLoop < (rx_ring->Fbr0NumEntries / FBR_CHUNKS);
+ OuterLoop++) {
+ uint64_t Fbr0Offset;
+ uint64_t Fbr0TempPa;
+
+ FBRChunkSize = ((FBR_CHUNKS + 1) * rx_ring->Fbr0BufferSize) - 1;
+ rx_ring->Fbr0MemVa[OuterLoop] =
+ pci_alloc_consistent(adapter->pdev, FBRChunkSize,
+ &rx_ring->Fbr0MemPa[OuterLoop]);
+
+ if (!rx_ring->Fbr0MemVa[OuterLoop]) {
+ DBG_ERROR(et131x_dbginfo, "Could not alloc memory\n");
+ DBG_LEAVE(et131x_dbginfo);
+ return -ENOMEM;
+ }
+
+ /* See NOTE in "Save Physical Address" comment above */
+ Fbr0TempPa = rx_ring->Fbr0MemPa[OuterLoop];
+
+ et131x_align_allocated_memory(adapter,
+ &Fbr0TempPa,
+ &Fbr0Offset,
+ rx_ring->Fbr0BufferSize - 1);
+
+ for (InnerLoop = 0; InnerLoop < FBR_CHUNKS; InnerLoop++) {
+ uint32_t index = (OuterLoop * FBR_CHUNKS) + InnerLoop;
+
+ rx_ring->Fbr[0]->Va[index] =
+ (uint8_t *) rx_ring->Fbr0MemVa[OuterLoop] +
+ (InnerLoop * rx_ring->Fbr0BufferSize) + Fbr0Offset;
+
+ rx_ring->Fbr[0]->PAHigh[index] =
+ (uint32_t) (Fbr0TempPa >> 32);
+ rx_ring->Fbr[0]->PALow[index] = (uint32_t) Fbr0TempPa;
+
+ Fbr0TempPa += rx_ring->Fbr0BufferSize;
+
+ rx_ring->Fbr[0]->Buffer1[index] =
+ rx_ring->Fbr[0]->Va[index];
+ rx_ring->Fbr[0]->Buffer2[index] =
+ rx_ring->Fbr[0]->Va[index] - 4;
+ }
+ }
+#endif
+
+ /* Allocate an area of memory for FIFO of Packet Status ring entries */
+ pktStatRingSize =
+ sizeof(PKT_STAT_DESC_t) * adapter->RxRing.PsrNumEntries;
+
+ rx_ring->pPSRingVa = pci_alloc_consistent(adapter->pdev,
+ pktStatRingSize + 0x0fff,
+ &rx_ring->pPSRingPa);
+
+ if (!rx_ring->pPSRingVa) {
+ DBG_ERROR(et131x_dbginfo,
+ "Cannot alloc memory for Packet Status Ring\n");
+ DBG_LEAVE(et131x_dbginfo);
+ return -ENOMEM;
+ }
+
+ /* Save physical address
+ *
+ * NOTE : pci_alloc_consistent(), used above to alloc DMA regions,
+ * ALWAYS returns SAC (32-bit) addresses. If DAC (64-bit) addresses
+ * are ever returned, make sure the high part is retrieved here before
+ * storing the adjusted address.
+ */
+ rx_ring->pPSRingRealPa = rx_ring->pPSRingPa;
+
+ /* Align Packet Status Ring on a 4K boundary */
+ et131x_align_allocated_memory(adapter,
+ &rx_ring->pPSRingRealPa,
+ &rx_ring->pPSRingOffset, 0x0FFF);
+
+ rx_ring->pPSRingVa = (void *)((uint8_t *) rx_ring->pPSRingVa +
+ rx_ring->pPSRingOffset);
+
+ /* Allocate an area of memory for writeback of status information */
+ rx_ring->pRxStatusVa = pci_alloc_consistent(adapter->pdev,
+ sizeof(RX_STATUS_BLOCK_t) +
+ 0x7, &rx_ring->pRxStatusPa);
+ if (!rx_ring->pRxStatusVa) {
+ DBG_ERROR(et131x_dbginfo,
+ "Cannot alloc memory for Status Block\n");
+ DBG_LEAVE(et131x_dbginfo);
+ return -ENOMEM;
+ }
+
+ /* Save physical address */
+ rx_ring->RxStatusRealPA = rx_ring->pRxStatusPa;
+
+ /* Align write back on an 8 byte boundary */
+ et131x_align_allocated_memory(adapter,
+ &rx_ring->RxStatusRealPA,
+ &rx_ring->RxStatusOffset, 0x07);
+
+ rx_ring->pRxStatusVa = (void *)((uint8_t *) rx_ring->pRxStatusVa +
+ rx_ring->RxStatusOffset);
+ rx_ring->NumRfd = NIC_DEFAULT_NUM_RFD;
+
+ /* Recv
+ * pci_pool_create initializes a lookaside list. After successful
+ * creation, nonpaged fixed-size blocks can be allocated from and
+ * freed to the lookaside list.
+ * RFDs will be allocated from this pool.
+ */
+ rx_ring->RecvLookaside = kmem_cache_create(adapter->netdev->name,
+ sizeof(MP_RFD),
+ 0,
+ SLAB_CACHE_DMA |
+ SLAB_HWCACHE_ALIGN,
+ NULL);
+
+ MP_SET_FLAG(adapter, fMP_ADAPTER_RECV_LOOKASIDE);
+
+ /* The RFDs are going to be put on lists later on, so initialize the
+ * lists now.
+ */
+ INIT_LIST_HEAD(&rx_ring->RecvList);
+ INIT_LIST_HEAD(&rx_ring->RecvPendingList);
+
+ DBG_LEAVE(et131x_dbginfo);
+ return 0;
+}
+
+/**
+ * et131x_rx_dma_memory_free - Free all memory allocated within this module.
+ * @adapter: pointer to our private adapter structure
+ */
+void et131x_rx_dma_memory_free(struct et131x_adapter *adapter)
+{
+ uint32_t index;
+ uint32_t bufsize;
+ uint32_t pktStatRingSize;
+ PMP_RFD pMpRfd;
+ RX_RING_t *rx_ring;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Setup some convenience pointers */
+ rx_ring = (RX_RING_t *) & adapter->RxRing;
+
+ /* Free RFDs and associated packet descriptors */
+ DBG_ASSERT(rx_ring->nReadyRecv == rx_ring->NumRfd);
+
+ while (!list_empty(&rx_ring->RecvList)) {
+ pMpRfd = (MP_RFD *) list_entry(rx_ring->RecvList.next,
+ MP_RFD, list_node);
+
+ list_del(&pMpRfd->list_node);
+ et131x_rfd_resources_free(adapter, pMpRfd);
+ }
+
+ while (!list_empty(&rx_ring->RecvPendingList)) {
+ pMpRfd = (MP_RFD *) list_entry(rx_ring->RecvPendingList.next,
+ MP_RFD, list_node);
+ list_del(&pMpRfd->list_node);
+ et131x_rfd_resources_free(adapter, pMpRfd);
+ }
+
+ /* Free Free Buffer Ring 1 */
+ if (rx_ring->pFbr1RingVa) {
+ /* First the packet memory */
+ for (index = 0; index <
+ (rx_ring->Fbr1NumEntries / FBR_CHUNKS); index++) {
+ if (rx_ring->Fbr1MemVa[index]) {
+ uint32_t Fbr1Align;
+
+ if (rx_ring->Fbr1BufferSize > 4096) {
+ Fbr1Align = 4096;
+ } else {
+ Fbr1Align = rx_ring->Fbr1BufferSize;
+ }
+
+ bufsize =
+ (rx_ring->Fbr1BufferSize * FBR_CHUNKS) +
+ Fbr1Align - 1;
+
+ pci_free_consistent(adapter->pdev,
+ bufsize,
+ rx_ring->Fbr1MemVa[index],
+ rx_ring->Fbr1MemPa[index]);
+
+ rx_ring->Fbr1MemVa[index] = NULL;
+ }
+ }
+
+ /* Now the FIFO itself */
+ rx_ring->pFbr1RingVa = (void *)((uint8_t *) rx_ring->pFbr1RingVa -
+ rx_ring->Fbr1offset);
+
+ bufsize =
+ (sizeof(FBR_DESC_t) * rx_ring->Fbr1NumEntries) + 0xfff;
+
+ pci_free_consistent(adapter->pdev,
+ bufsize,
+ rx_ring->pFbr1RingVa, rx_ring->pFbr1RingPa);
+
+ rx_ring->pFbr1RingVa = NULL;
+ }
+
+#ifdef USE_FBR0
+ /* Now the same for Free Buffer Ring 0 */
+ if (rx_ring->pFbr0RingVa) {
+ /* First the packet memory */
+ for (index = 0; index <
+ (rx_ring->Fbr0NumEntries / FBR_CHUNKS); index++) {
+ if (rx_ring->Fbr0MemVa[index]) {
+ bufsize =
+ (rx_ring->Fbr0BufferSize *
+ (FBR_CHUNKS + 1)) - 1;
+
+ pci_free_consistent(adapter->pdev,
+ bufsize,
+ rx_ring->Fbr0MemVa[index],
+ rx_ring->Fbr0MemPa[index]);
+
+ rx_ring->Fbr0MemVa[index] = NULL;
+ }
+ }
+
+ /* Now the FIFO itself */
+ rx_ring->pFbr0RingVa = (void *)((uint8_t *) rx_ring->pFbr0RingVa -
+ rx_ring->Fbr0offset);
+
+ bufsize =
+ (sizeof(FBR_DESC_t) * rx_ring->Fbr0NumEntries) + 0xfff;
+
+ pci_free_consistent(adapter->pdev,
+ bufsize,
+ rx_ring->pFbr0RingVa, rx_ring->pFbr0RingPa);
+
+ rx_ring->pFbr0RingVa = NULL;
+ }
+#endif
+
+ /* Free Packet Status Ring */
+ if (rx_ring->pPSRingVa) {
+ rx_ring->pPSRingVa = (void *)((uint8_t *) rx_ring->pPSRingVa -
+ rx_ring->pPSRingOffset);
+
+ pktStatRingSize =
+ sizeof(PKT_STAT_DESC_t) * adapter->RxRing.PsrNumEntries;
+
+ pci_free_consistent(adapter->pdev,
+ pktStatRingSize + 0x0fff,
+ rx_ring->pPSRingVa, rx_ring->pPSRingPa);
+
+ rx_ring->pPSRingVa = NULL;
+ }
+
+ /* Free area of memory for the writeback of status information */
+ if (rx_ring->pRxStatusVa) {
+ rx_ring->pRxStatusVa = (void *)((uint8_t *) rx_ring->pRxStatusVa -
+ rx_ring->RxStatusOffset);
+
+ pci_free_consistent(adapter->pdev,
+ sizeof(RX_STATUS_BLOCK_t) + 0x7,
+ rx_ring->pRxStatusVa, rx_ring->pRxStatusPa);
+
+ rx_ring->pRxStatusVa = NULL;
+ }
+
+ /* Free receive buffer pool */
+
+ /* Free receive packet pool */
+
+ /* Destroy the lookaside (RFD) pool */
+ if (MP_TEST_FLAG(adapter, fMP_ADAPTER_RECV_LOOKASIDE)) {
+ kmem_cache_destroy(rx_ring->RecvLookaside);
+ MP_CLEAR_FLAG(adapter, fMP_ADAPTER_RECV_LOOKASIDE);
+ }
+
+ /* Free the FBR Lookup Table */
+#ifdef USE_FBR0
+ kfree(rx_ring->Fbr[0]);
+#endif
+
+ kfree(rx_ring->Fbr[1]);
+
+ /* Reset Counters */
+ rx_ring->nReadyRecv = 0;
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * et131x_init_recv - Initialize receive data structures.
+ * @adapter: pointer to our private adapter structure
+ *
+ * Returns 0 on success and errno on failure (as defined in errno.h)
+ */
+int et131x_init_recv(struct et131x_adapter *adapter)
+{
+ int status = -ENOMEM;
+ PMP_RFD pMpRfd = NULL;
+ uint32_t RfdCount;
+ uint32_t TotalNumRfd = 0;
+ RX_RING_t *rx_ring = NULL;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Setup some convenience pointers */
+ rx_ring = (RX_RING_t *) & adapter->RxRing;
+
+ /* Setup each RFD */
+ for (RfdCount = 0; RfdCount < rx_ring->NumRfd; RfdCount++) {
+ pMpRfd = (MP_RFD *) kmem_cache_alloc(rx_ring->RecvLookaside,
+ GFP_ATOMIC | GFP_DMA);
+
+ if (!pMpRfd) {
+ DBG_ERROR(et131x_dbginfo,
+ "Couldn't alloc RFD out of kmem_cache\n");
+ status = -ENOMEM;
+ continue;
+ }
+
+ status = et131x_rfd_resources_alloc(adapter, pMpRfd);
+ if (status != 0) {
+ DBG_ERROR(et131x_dbginfo,
+ "Couldn't alloc packet for RFD\n");
+ kmem_cache_free(rx_ring->RecvLookaside, pMpRfd);
+ continue;
+ }
+
+ /* Add this RFD to the RecvList */
+ list_add_tail(&pMpRfd->list_node, &rx_ring->RecvList);
+
+ /* Increment both the available RFD's, and the total RFD's. */
+ rx_ring->nReadyRecv++;
+ TotalNumRfd++;
+ }
+
+ if (TotalNumRfd > NIC_MIN_NUM_RFD) {
+ status = 0;
+ }
+
+ rx_ring->NumRfd = TotalNumRfd;
+
+ if (status != 0) {
+ kmem_cache_free(rx_ring->RecvLookaside, pMpRfd);
+ DBG_ERROR(et131x_dbginfo,
+ "Allocation problems in et131x_init_recv\n");
+ }
+
+ DBG_LEAVE(et131x_dbginfo);
+ return status;
+}
+
+/**
+ * et131x_rfd_resources_alloc
+ * @adapter: pointer to our private adapter structure
+ * @pMpRfd: pointer to a RFD
+ *
+ * Returns 0 on success and errno on failure (as defined in errno.h)
+ */
+int et131x_rfd_resources_alloc(struct et131x_adapter *adapter, MP_RFD *pMpRfd)
+{
+ pMpRfd->Packet = NULL;
+
+ return 0;
+}
+
+/**
+ * et131x_rfd_resources_free - Free the packet allocated for the given RFD
+ * @adapter: pointer to our private adapter structure
+ * @pMpRfd: pointer to a RFD
+ */
+void et131x_rfd_resources_free(struct et131x_adapter *adapter, MP_RFD *pMpRfd)
+{
+ pMpRfd->Packet = NULL;
+ kmem_cache_free(adapter->RxRing.RecvLookaside, pMpRfd);
+}
+
+/**
+ * ConfigRxDmaRegs - Start of Rx_DMA init sequence
+ * @pAdapter: pointer to our adapter structure
+ */
+void ConfigRxDmaRegs(struct et131x_adapter *pAdapter)
+{
+ struct _RXDMA_t __iomem *pRxDma = &pAdapter->CSRAddress->rxdma;
+ struct _rx_ring_t *pRxLocal = &pAdapter->RxRing;
+ PFBR_DESC_t pFbrEntry;
+ uint32_t iEntry;
+ RXDMA_PSR_NUM_DES_t psr_num_des;
+ unsigned long lockflags;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Halt RXDMA to perform the reconfigure. */
+ et131x_rx_dma_disable(pAdapter);
+
+ /* Load the completion writeback physical address
+ *
+ * NOTE : pci_alloc_consistent(), used above to alloc DMA regions,
+ * ALWAYS returns SAC (32-bit) addresses. If DAC (64-bit) addresses
+ * are ever returned, make sure the high part is retrieved here
+ * before storing the adjusted address.
+ */
+ writel((uint32_t) (pRxLocal->RxStatusRealPA >> 32),
+ &pRxDma->dma_wb_base_hi);
+ writel((uint32_t) pRxLocal->RxStatusRealPA, &pRxDma->dma_wb_base_lo);
+
+ memset(pRxLocal->pRxStatusVa, 0, sizeof(RX_STATUS_BLOCK_t));
+
+ /* Set the address and parameters of the packet status ring into the
+ * 1310's registers
+ */
+ writel((uint32_t) (pRxLocal->pPSRingRealPa >> 32),
+ &pRxDma->psr_base_hi);
+ writel((uint32_t) pRxLocal->pPSRingRealPa, &pRxDma->psr_base_lo);
+ writel(pRxLocal->PsrNumEntries - 1, &pRxDma->psr_num_des.value);
+ writel(0, &pRxDma->psr_full_offset.value);
+
+ psr_num_des.value = readl(&pRxDma->psr_num_des.value);
+ writel((psr_num_des.bits.psr_ndes * LO_MARK_PERCENT_FOR_PSR) / 100,
+ &pRxDma->psr_min_des.value);
+
+ spin_lock_irqsave(&pAdapter->RcvLock, lockflags);
+
+ /* These local variables track the PSR in the adapter structure */
+ pRxLocal->local_psr_full.bits.psr_full = 0;
+ pRxLocal->local_psr_full.bits.psr_full_wrap = 0;
+
+ /* Now's the best time to initialize FBR1 contents */
+ pFbrEntry = (PFBR_DESC_t) pRxLocal->pFbr1RingVa;
+ for (iEntry = 0; iEntry < pRxLocal->Fbr1NumEntries; iEntry++) {
+ pFbrEntry->addr_hi = pRxLocal->Fbr[1]->PAHigh[iEntry];
+ pFbrEntry->addr_lo = pRxLocal->Fbr[1]->PALow[iEntry];
+ pFbrEntry->word2.bits.bi = iEntry;
+ pFbrEntry++;
+ }
+
+ /* Set the address and parameters of Free buffer ring 1 (and 0 if
+ * required) into the 1310's registers
+ */
+ writel((uint32_t) (pRxLocal->Fbr1Realpa >> 32), &pRxDma->fbr1_base_hi);
+ writel((uint32_t) pRxLocal->Fbr1Realpa, &pRxDma->fbr1_base_lo);
+ writel(pRxLocal->Fbr1NumEntries - 1, &pRxDma->fbr1_num_des.value);
+
+ {
+ DMA10W_t fbr1_full = { 0 };
+
+ fbr1_full.bits.val = 0;
+ fbr1_full.bits.wrap = 1;
+ writel(fbr1_full.value, &pRxDma->fbr1_full_offset.value);
+ }
+
+ /* This variable tracks the free buffer ring 1 full position, so it
+ * has to match the above.
+ */
+ pRxLocal->local_Fbr1_full.bits.val = 0;
+ pRxLocal->local_Fbr1_full.bits.wrap = 1;
+ writel(((pRxLocal->Fbr1NumEntries * LO_MARK_PERCENT_FOR_RX) / 100) - 1,
+ &pRxDma->fbr1_min_des.value);
+
+#ifdef USE_FBR0
+ /* Now's the best time to initialize FBR0 contents */
+ pFbrEntry = (PFBR_DESC_t) pRxLocal->pFbr0RingVa;
+ for (iEntry = 0; iEntry < pRxLocal->Fbr0NumEntries; iEntry++) {
+ pFbrEntry->addr_hi = pRxLocal->Fbr[0]->PAHigh[iEntry];
+ pFbrEntry->addr_lo = pRxLocal->Fbr[0]->PALow[iEntry];
+ pFbrEntry->word2.bits.bi = iEntry;
+ pFbrEntry++;
+ }
+
+ writel((uint32_t) (pRxLocal->Fbr0Realpa >> 32), &pRxDma->fbr0_base_hi);
+ writel((uint32_t) pRxLocal->Fbr0Realpa, &pRxDma->fbr0_base_lo);
+ writel(pRxLocal->Fbr0NumEntries - 1, &pRxDma->fbr0_num_des.value);
+
+ {
+ DMA10W_t fbr0_full = { 0 };
+
+ fbr0_full.bits.val = 0;
+ fbr0_full.bits.wrap = 1;
+ writel(fbr0_full.value, &pRxDma->fbr0_full_offset.value);
+ }
+
+ /* This variable tracks the free buffer ring 0 full position, so it
+ * has to match the above.
+ */
+ pRxLocal->local_Fbr0_full.bits.val = 0;
+ pRxLocal->local_Fbr0_full.bits.wrap = 1;
+ writel(((pRxLocal->Fbr0NumEntries * LO_MARK_PERCENT_FOR_RX) / 100) - 1,
+ &pRxDma->fbr0_min_des.value);
+#endif
+
+ /* Program the number of packets we will receive before generating an
+ * interrupt.
+ * For version B silicon, this value gets updated once autoneg is
+ *complete.
+ */
+ writel(pAdapter->RegistryRxNumBuffers, &pRxDma->num_pkt_done.value);
+
+ /* The "time_done" is not working correctly to coalesce interrupts
+ * after a given time period, but rather is giving us an interrupt
+ * regardless of whether we have received packets.
+ * This value gets updated once autoneg is complete.
+ */
+ writel(pAdapter->RegistryRxTimeInterval, &pRxDma->max_pkt_time.value);
+
+ spin_unlock_irqrestore(&pAdapter->RcvLock, lockflags);
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * SetRxDmaTimer - Set the heartbeat timer according to line rate.
+ * @pAdapter: pointer to our adapter structure
+ */
+void SetRxDmaTimer(struct et131x_adapter *pAdapter)
+{
+ /* For version B silicon, we do not use the RxDMA timer for 10 and 100
+ * Mbits/s line rates. We do not enable and RxDMA interrupt coalescing.
+ */
+ if ((pAdapter->uiLinkSpeed == TRUEPHY_SPEED_100MBPS) ||
+ (pAdapter->uiLinkSpeed == TRUEPHY_SPEED_10MBPS)) {
+ writel(0, &pAdapter->CSRAddress->rxdma.max_pkt_time.value);
+ writel(1, &pAdapter->CSRAddress->rxdma.num_pkt_done.value);
+ }
+}
+
+/**
+ * et131x_rx_dma_disable - Stop of Rx_DMA on the ET1310
+ * @pAdapter: pointer to our adapter structure
+ */
+void et131x_rx_dma_disable(struct et131x_adapter *pAdapter)
+{
+ RXDMA_CSR_t csr;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Setup the receive dma configuration register */
+ writel(0x00002001, &pAdapter->CSRAddress->rxdma.csr.value);
+ csr.value = readl(&pAdapter->CSRAddress->rxdma.csr.value);
+ if (csr.bits.halt_status != 1) {
+ udelay(5);
+ csr.value = readl(&pAdapter->CSRAddress->rxdma.csr.value);
+ if (csr.bits.halt_status != 1) {
+ DBG_ERROR(et131x_dbginfo,
+ "RX Dma failed to enter halt state. CSR 0x%08x\n",
+ csr.value);
+ }
+ }
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * et131x_rx_dma_enable - re-start of Rx_DMA on the ET1310.
+ * @pAdapter: pointer to our adapter structure
+ */
+void et131x_rx_dma_enable(struct et131x_adapter *pAdapter)
+{
+ DBG_RX_ENTER(et131x_dbginfo);
+
+ if (pAdapter->RegistryPhyLoopbk) {
+ /* RxDMA is disabled for loopback operation. */
+ writel(0x1, &pAdapter->CSRAddress->rxdma.csr.value);
+ } else {
+ /* Setup the receive dma configuration register for normal operation */
+ RXDMA_CSR_t csr = { 0 };
+
+ csr.bits.fbr1_enable = 1;
+ if (pAdapter->RxRing.Fbr1BufferSize == 4096) {
+ csr.bits.fbr1_size = 1;
+ } else if (pAdapter->RxRing.Fbr1BufferSize == 8192) {
+ csr.bits.fbr1_size = 2;
+ } else if (pAdapter->RxRing.Fbr1BufferSize == 16384) {
+ csr.bits.fbr1_size = 3;
+ }
+#ifdef USE_FBR0
+ csr.bits.fbr0_enable = 1;
+ if (pAdapter->RxRing.Fbr0BufferSize == 256) {
+ csr.bits.fbr0_size = 1;
+ } else if (pAdapter->RxRing.Fbr0BufferSize == 512) {
+ csr.bits.fbr0_size = 2;
+ } else if (pAdapter->RxRing.Fbr0BufferSize == 1024) {
+ csr.bits.fbr0_size = 3;
+ }
+#endif
+ writel(csr.value, &pAdapter->CSRAddress->rxdma.csr.value);
+
+ csr.value = readl(&pAdapter->CSRAddress->rxdma.csr.value);
+ if (csr.bits.halt_status != 0) {
+ udelay(5);
+ csr.value = readl(&pAdapter->CSRAddress->rxdma.csr.value);
+ if (csr.bits.halt_status != 0) {
+ DBG_ERROR(et131x_dbginfo,
+ "RX Dma failed to exit halt state. CSR 0x%08x\n",
+ csr.value);
+ }
+ }
+ }
+
+ DBG_RX_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * nic_rx_pkts - Checks the hardware for available packets
+ * @pAdapter: pointer to our adapter
+ *
+ * Returns pMpRfd, a pointer to our MPRFD.
+ *
+ * Checks the hardware for available packets, using completion ring
+ * If packets are available, it gets an RFD from the RecvList, attaches
+ * the packet to it, puts the RFD in the RecvPendList, and also returns
+ * the pointer to the RFD.
+ */
+PMP_RFD nic_rx_pkts(struct et131x_adapter *pAdapter)
+{
+ struct _rx_ring_t *pRxLocal = &pAdapter->RxRing;
+ PRX_STATUS_BLOCK_t pRxStatusBlock;
+ PPKT_STAT_DESC_t pPSREntry;
+ PMP_RFD pMpRfd;
+ uint32_t nIndex;
+ uint8_t *pBufVa;
+ unsigned long lockflags;
+ struct list_head *element;
+ uint8_t ringIndex;
+ uint16_t bufferIndex;
+ uint32_t localLen;
+ PKT_STAT_DESC_WORD0_t Word0;
+
+
+ DBG_RX_ENTER(et131x_dbginfo);
+
+ /* RX Status block is written by the DMA engine prior to every
+ * interrupt. It contains the next to be used entry in the Packet
+ * Status Ring, and also the two Free Buffer rings.
+ */
+ pRxStatusBlock = (PRX_STATUS_BLOCK_t) pRxLocal->pRxStatusVa;
+
+ if (pRxStatusBlock->Word1.bits.PSRoffset ==
+ pRxLocal->local_psr_full.bits.psr_full &&
+ pRxStatusBlock->Word1.bits.PSRwrap ==
+ pRxLocal->local_psr_full.bits.psr_full_wrap) {
+ /* Looks like this ring is not updated yet */
+ DBG_RX(et131x_dbginfo, "(0)\n");
+ DBG_RX_LEAVE(et131x_dbginfo);
+ return NULL;
+ }
+
+ /* The packet status ring indicates that data is available. */
+ pPSREntry = (PPKT_STAT_DESC_t) (pRxLocal->pPSRingVa) +
+ pRxLocal->local_psr_full.bits.psr_full;
+
+ /* Grab any information that is required once the PSR is
+ * advanced, since we can no longer rely on the memory being
+ * accurate
+ */
+ localLen = pPSREntry->word1.bits.length;
+ ringIndex = (uint8_t) pPSREntry->word1.bits.ri;
+ bufferIndex = (uint16_t) pPSREntry->word1.bits.bi;
+ Word0 = pPSREntry->word0;
+
+ DBG_RX(et131x_dbginfo, "RX PACKET STATUS\n");
+ DBG_RX(et131x_dbginfo, "\tlength : %d\n", localLen);
+ DBG_RX(et131x_dbginfo, "\tringIndex : %d\n", ringIndex);
+ DBG_RX(et131x_dbginfo, "\tbufferIndex : %d\n", bufferIndex);
+ DBG_RX(et131x_dbginfo, "\tword0 : 0x%08x\n", Word0.value);
+
+#if 0
+ /* Check the Status Word that the MAC has appended to the PSR
+ * entry in case the MAC has detected errors.
+ */
+ if (Word0.value & ALCATEL_BAD_STATUS) {
+ DBG_ERROR(et131x_dbginfo,
+ "NICRxPkts >> Alcatel Status Word error."
+ "Value 0x%08x\n", pPSREntry->word0.value);
+ }
+#endif
+
+ /* Indicate that we have used this PSR entry. */
+ if (++pRxLocal->local_psr_full.bits.psr_full >
+ pRxLocal->PsrNumEntries - 1) {
+ pRxLocal->local_psr_full.bits.psr_full = 0;
+ pRxLocal->local_psr_full.bits.psr_full_wrap ^= 1;
+ }
+
+ writel(pRxLocal->local_psr_full.value,
+ &pAdapter->CSRAddress->rxdma.psr_full_offset.value);
+
+#ifndef USE_FBR0
+ if (ringIndex != 1) {
+ DBG_ERROR(et131x_dbginfo,
+ "NICRxPkts PSR Entry %d indicates "
+ "Buffer Ring 0 in use\n",
+ pRxLocal->local_psr_full.bits.psr_full);
+ DBG_RX_LEAVE(et131x_dbginfo);
+ return NULL;
+ }
+#endif
+
+#ifdef USE_FBR0
+ if (ringIndex > 1 ||
+ (ringIndex == 0 &&
+ bufferIndex > pRxLocal->Fbr0NumEntries - 1) ||
+ (ringIndex == 1 &&
+ bufferIndex > pRxLocal->Fbr1NumEntries - 1))
+#else
+ if (ringIndex != 1 ||
+ bufferIndex > pRxLocal->Fbr1NumEntries - 1)
+#endif
+ {
+ /* Illegal buffer or ring index cannot be used by S/W*/
+ DBG_ERROR(et131x_dbginfo,
+ "NICRxPkts PSR Entry %d indicates "
+ "length of %d and/or bad bi(%d)\n",
+ pRxLocal->local_psr_full.bits.psr_full,
+ localLen, bufferIndex);
+ DBG_RX_LEAVE(et131x_dbginfo);
+ return NULL;
+ }
+
+ /* Get and fill the RFD. */
+ spin_lock_irqsave(&pAdapter->RcvLock, lockflags);
+
+ pMpRfd = NULL;
+ element = pRxLocal->RecvList.next;
+ pMpRfd = (PMP_RFD) list_entry(element, MP_RFD, list_node);
+
+ if (pMpRfd == NULL) {
+ DBG_RX(et131x_dbginfo,
+ "NULL RFD returned from RecvList via list_entry()\n");
+ DBG_RX_LEAVE(et131x_dbginfo);
+ spin_unlock_irqrestore(&pAdapter->RcvLock, lockflags);
+ return NULL;
+ }
+
+ list_del(&pMpRfd->list_node);
+ pRxLocal->nReadyRecv--;
+
+ spin_unlock_irqrestore(&pAdapter->RcvLock, lockflags);
+
+ pMpRfd->iBufferIndex = bufferIndex;
+ pMpRfd->iRingIndex = ringIndex;
+
+ /* In V1 silicon, there is a bug which screws up filtering of
+ * runt packets. Therefore runt packet filtering is disabled
+ * in the MAC and the packets are dropped here. They are
+ * also counted here.
+ */
+ if (localLen < (NIC_MIN_PACKET_SIZE + 4)) {
+ pAdapter->Stats.other_errors++;
+ localLen = 0;
+ }
+
+ if (localLen) {
+ if (pAdapter->ReplicaPhyLoopbk == 1) {
+ pBufVa = pRxLocal->Fbr[ringIndex]->Va[bufferIndex];
+
+ if (memcmp(&pBufVa[6], &pAdapter->CurrentAddress[0],
+ ETH_ALEN) == 0) {
+ if (memcmp(&pBufVa[42], "Replica packet",
+ ETH_HLEN)) {
+ pAdapter->ReplicaPhyLoopbkPF = 1;
+ }
+ }
+ DBG_WARNING(et131x_dbginfo,
+ "pBufVa:\t%02x:%02x:%02x:%02x:%02x:%02x\n",
+ pBufVa[6], pBufVa[7], pBufVa[8],
+ pBufVa[9], pBufVa[10], pBufVa[11]);
+
+ DBG_WARNING(et131x_dbginfo,
+ "CurrentAddr:\t%02x:%02x:%02x:%02x:%02x:%02x\n",
+ pAdapter->CurrentAddress[0],
+ pAdapter->CurrentAddress[1],
+ pAdapter->CurrentAddress[2],
+ pAdapter->CurrentAddress[3],
+ pAdapter->CurrentAddress[4],
+ pAdapter->CurrentAddress[5]);
+ }
+
+ /* Determine if this is a multicast packet coming in */
+ if ((Word0.value & ALCATEL_MULTICAST_PKT) &&
+ !(Word0.value & ALCATEL_BROADCAST_PKT)) {
+ /* Promiscuous mode and Multicast mode are
+ * not mutually exclusive as was first
+ * thought. I guess Promiscuous is just
+ * considered a super-set of the other
+ * filters. Generally filter is 0x2b when in
+ * promiscuous mode.
+ */
+ if ((pAdapter->PacketFilter & ET131X_PACKET_TYPE_MULTICAST)
+ && !(pAdapter->PacketFilter & ET131X_PACKET_TYPE_PROMISCUOUS)
+ && !(pAdapter->PacketFilter & ET131X_PACKET_TYPE_ALL_MULTICAST)) {
+ pBufVa = pRxLocal->Fbr[ringIndex]->
+ Va[bufferIndex];
+
+ /* Loop through our list to see if the
+ * destination address of this packet
+ * matches one in our list.
+ */
+ for (nIndex = 0;
+ nIndex < pAdapter->MCAddressCount;
+ nIndex++) {
+ if (pBufVa[0] ==
+ pAdapter->MCList[nIndex][0]
+ && pBufVa[1] ==
+ pAdapter->MCList[nIndex][1]
+ && pBufVa[2] ==
+ pAdapter->MCList[nIndex][2]
+ && pBufVa[3] ==
+ pAdapter->MCList[nIndex][3]
+ && pBufVa[4] ==
+ pAdapter->MCList[nIndex][4]
+ && pBufVa[5] ==
+ pAdapter->MCList[nIndex][5]) {
+ break;
+ }
+ }
+
+ /* If our index is equal to the number
+ * of Multicast address we have, then
+ * this means we did not find this
+ * packet's matching address in our
+ * list. Set the PacketSize to zero,
+ * so we free our RFD when we return
+ * from this function.
+ */
+ if (nIndex == pAdapter->MCAddressCount) {
+ localLen = 0;
+ }
+ }
+
+ if (localLen > 0) {
+ pAdapter->Stats.multircv++;
+ }
+ } else if (Word0.value & ALCATEL_BROADCAST_PKT) {
+ pAdapter->Stats.brdcstrcv++;
+ } else {
+ /* Not sure what this counter measures in
+ * promiscuous mode. Perhaps we should check
+ * the MAC address to see if it is directed
+ * to us in promiscuous mode.
+ */
+ pAdapter->Stats.unircv++;
+ }
+ }
+
+ if (localLen > 0) {
+ struct sk_buff *skb = NULL;
+
+ //pMpRfd->PacketSize = localLen - 4;
+ pMpRfd->PacketSize = localLen;
+
+ skb = dev_alloc_skb(pMpRfd->PacketSize + 2);
+ if (!skb) {
+ DBG_ERROR(et131x_dbginfo,
+ "Couldn't alloc an SKB for Rx\n");
+ DBG_RX_LEAVE(et131x_dbginfo);
+ return NULL;
+ }
+
+ pAdapter->net_stats.rx_bytes += pMpRfd->PacketSize;
+
+ memcpy(skb_put(skb, pMpRfd->PacketSize),
+ pRxLocal->Fbr[ringIndex]->Va[bufferIndex],
+ pMpRfd->PacketSize);
+
+ skb->dev = pAdapter->netdev;
+ skb->protocol = eth_type_trans(skb, pAdapter->netdev);
+ skb->ip_summed = CHECKSUM_NONE;
+
+ netif_rx(skb);
+ } else {
+ pMpRfd->PacketSize = 0;
+ }
+
+ nic_return_rfd(pAdapter, pMpRfd);
+
+ DBG_RX(et131x_dbginfo, "(1)\n");
+ DBG_RX_LEAVE(et131x_dbginfo);
+ return pMpRfd;
+}
+
+/**
+ * et131x_reset_recv - Reset the receive list
+ * @pAdapter: pointer to our adapter
+ *
+ * Assumption, Rcv spinlock has been acquired.
+ */
+void et131x_reset_recv(struct et131x_adapter *pAdapter)
+{
+ PMP_RFD pMpRfd;
+ struct list_head *element;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ DBG_ASSERT(!list_empty(&pAdapter->RxRing.RecvList));
+
+ /* Take all the RFD's from the pending list, and stick them on the
+ * RecvList.
+ */
+ while (!list_empty(&pAdapter->RxRing.RecvPendingList)) {
+ element = pAdapter->RxRing.RecvPendingList.next;
+
+ pMpRfd = (PMP_RFD) list_entry(element, MP_RFD, list_node);
+
+ list_del(&pMpRfd->list_node);
+ list_add_tail(&pMpRfd->list_node, &pAdapter->RxRing.RecvList);
+ }
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * et131x_handle_recv_interrupt - Interrupt handler for receive processing
+ * @pAdapter: pointer to our adapter
+ *
+ * Assumption, Rcv spinlock has been acquired.
+ */
+void et131x_handle_recv_interrupt(struct et131x_adapter *pAdapter)
+{
+ PMP_RFD pMpRfd = NULL;
+ struct sk_buff *PacketArray[NUM_PACKETS_HANDLED];
+ PMP_RFD RFDFreeArray[NUM_PACKETS_HANDLED];
+ uint32_t PacketArrayCount = 0;
+ uint32_t PacketsToHandle;
+ uint32_t PacketFreeCount = 0;
+ bool TempUnfinishedRec = false;
+
+ DBG_RX_ENTER(et131x_dbginfo);
+
+ PacketsToHandle = NUM_PACKETS_HANDLED;
+
+ /* Process up to available RFD's */
+ while (PacketArrayCount < PacketsToHandle) {
+ if (list_empty(&pAdapter->RxRing.RecvList)) {
+ DBG_ASSERT(pAdapter->RxRing.nReadyRecv == 0);
+ DBG_ERROR(et131x_dbginfo, "NO RFD's !!!!!!!!!!!!!\n");
+ TempUnfinishedRec = true;
+ break;
+ }
+
+ pMpRfd = nic_rx_pkts(pAdapter);
+
+ if (pMpRfd == NULL) {
+ break;
+ }
+
+ /* Do not receive any packets until a filter has been set.
+ * Do not receive any packets until we are at D0.
+ * Do not receive any packets until we have link.
+ * If length is zero, return the RFD in order to advance the
+ * Free buffer ring.
+ */
+ if ((!pAdapter->PacketFilter) ||
+ (pAdapter->PoMgmt.PowerState != NdisDeviceStateD0) ||
+ (!MP_LINK_DETECTED(pAdapter)) ||
+ (pMpRfd->PacketSize == 0)) {
+ continue;
+ }
+
+ /* Increment the number of packets we received */
+ pAdapter->Stats.ipackets++;
+
+ /* Set the status on the packet, either resources or success */
+ if (pAdapter->RxRing.nReadyRecv >= RFD_LOW_WATER_MARK) {
+ /* Put this RFD on the pending list
+ *
+ * NOTE: nic_rx_pkts() above is already returning the
+ * RFD to the RecvList, so don't additionally do that
+ * here.
+ * Besides, we don't really need (at this point) the
+ * pending list anyway.
+ */
+ //spin_lock_irqsave( &pAdapter->RcvPendLock, lockflags );
+ //list_add_tail( &pMpRfd->list_node, &pAdapter->RxRing.RecvPendingList );
+ //spin_unlock_irqrestore( &pAdapter->RcvPendLock, lockflags );
+
+ /* Update the number of outstanding Recvs */
+ //MP_INC_RCV_REF( pAdapter );
+ } else {
+ RFDFreeArray[PacketFreeCount] = pMpRfd;
+ PacketFreeCount++;
+
+ DBG_WARNING(et131x_dbginfo,
+ "RFD's are running out !!!!!!!!!!!!!\n");
+ }
+
+ PacketArray[PacketArrayCount] = pMpRfd->Packet;
+ PacketArrayCount++;
+ }
+
+ if ((PacketArrayCount == NUM_PACKETS_HANDLED) || TempUnfinishedRec) {
+ pAdapter->RxRing.UnfinishedReceives = true;
+ writel(pAdapter->RegistryTxTimeInterval * NANO_IN_A_MICRO,
+ &pAdapter->CSRAddress->global.watchdog_timer);
+ } else {
+ /* Watchdog timer will disable itself if appropriate. */
+ pAdapter->RxRing.UnfinishedReceives = false;
+ }
+
+ DBG_RX_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * NICReturnRFD - Recycle a RFD and put it back onto the receive list
+ * @pAdapter: pointer to our adapter
+ * @pMpRfd: pointer to the RFD
+ */
+void nic_return_rfd(struct et131x_adapter *pAdapter, PMP_RFD pMpRfd)
+{
+ struct _rx_ring_t *pRxLocal = &pAdapter->RxRing;
+ struct _RXDMA_t __iomem *pRxDma = &pAdapter->CSRAddress->rxdma;
+ uint16_t bi = pMpRfd->iBufferIndex;
+ uint8_t ri = pMpRfd->iRingIndex;
+ unsigned long lockflags;
+
+ DBG_RX_ENTER(et131x_dbginfo);
+
+ /* We don't use any of the OOB data besides status. Otherwise, we
+ * need to clean up OOB data
+ */
+ if (
+#ifdef USE_FBR0
+ (ri == 0 && bi < pRxLocal->Fbr0NumEntries) ||
+#endif
+ (ri == 1 && bi < pRxLocal->Fbr1NumEntries)) {
+ spin_lock_irqsave(&pAdapter->FbrLock, lockflags);
+
+ if (ri == 1) {
+ PFBR_DESC_t pNextDesc =
+ (PFBR_DESC_t) (pRxLocal->pFbr1RingVa) +
+ pRxLocal->local_Fbr1_full.bits.val;
+
+ /* Handle the Free Buffer Ring advancement here. Write
+ * the PA / Buffer Index for the returned buffer into
+ * the oldest (next to be freed)FBR entry
+ */
+ pNextDesc->addr_hi = pRxLocal->Fbr[1]->PAHigh[bi];
+ pNextDesc->addr_lo = pRxLocal->Fbr[1]->PALow[bi];
+ pNextDesc->word2.value = bi;
+
+ if (++pRxLocal->local_Fbr1_full.bits.val >
+ (pRxLocal->Fbr1NumEntries - 1)) {
+ pRxLocal->local_Fbr1_full.bits.val = 0;
+ pRxLocal->local_Fbr1_full.bits.wrap ^= 1;
+ }
+
+ writel(pRxLocal->local_Fbr1_full.value,
+ &pRxDma->fbr1_full_offset.value);
+ }
+#ifdef USE_FBR0
+ else {
+ PFBR_DESC_t pNextDesc =
+ (PFBR_DESC_t) pRxLocal->pFbr0RingVa +
+ pRxLocal->local_Fbr0_full.bits.val;
+
+ /* Handle the Free Buffer Ring advancement here. Write
+ * the PA / Buffer Index for the returned buffer into
+ * the oldest (next to be freed) FBR entry
+ */
+ pNextDesc->addr_hi = pRxLocal->Fbr[0]->PAHigh[bi];
+ pNextDesc->addr_lo = pRxLocal->Fbr[0]->PALow[bi];
+ pNextDesc->word2.value = bi;
+
+ if (++pRxLocal->local_Fbr0_full.bits.val >
+ (pRxLocal->Fbr0NumEntries - 1)) {
+ pRxLocal->local_Fbr0_full.bits.val = 0;
+ pRxLocal->local_Fbr0_full.bits.wrap ^= 1;
+ }
+
+ writel(pRxLocal->local_Fbr0_full.value,
+ &pRxDma->fbr0_full_offset.value);
+ }
+#endif
+ spin_unlock_irqrestore(&pAdapter->FbrLock, lockflags);
+ } else {
+ DBG_ERROR(et131x_dbginfo,
+ "NICReturnRFD illegal Buffer Index returned\n");
+ }
+
+ /* The processing on this RFD is done, so put it back on the tail of
+ * our list
+ */
+ spin_lock_irqsave(&pAdapter->RcvLock, lockflags);
+ list_add_tail(&pMpRfd->list_node, &pRxLocal->RecvList);
+ pRxLocal->nReadyRecv++;
+ spin_unlock_irqrestore(&pAdapter->RcvLock, lockflags);
+
+ DBG_ASSERT(pRxLocal->nReadyRecv <= pRxLocal->NumRfd);
+ DBG_RX_LEAVE(et131x_dbginfo);
+}
diff --git a/drivers/staging/et131x/et1310_rx.h b/drivers/staging/et131x/et1310_rx.h
new file mode 100644
index 0000000..ea66dbc
--- /dev/null
+++ b/drivers/staging/et131x/et1310_rx.h
@@ -0,0 +1,373 @@
+/*
+ * Agere Systems Inc.
+ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * et1310_rx.h - Defines, structs, enums, prototypes, etc. pertaining to data
+ * reception.
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#ifndef __ET1310_RX_H__
+#define __ET1310_RX_H__
+
+#include "et1310_address_map.h"
+
+#define USE_FBR0 true
+
+#ifdef USE_FBR0
+//#define FBR0_BUFFER_SIZE 256
+#endif
+
+//#define FBR1_BUFFER_SIZE 2048
+
+#define FBR_CHUNKS 32
+
+#define MAX_DESC_PER_RING_RX 1024
+
+/* number of RFDs - default and min */
+#ifdef USE_FBR0
+#define RFD_LOW_WATER_MARK 40
+#define NIC_MIN_NUM_RFD 64
+#define NIC_DEFAULT_NUM_RFD 1024
+#else
+#define RFD_LOW_WATER_MARK 20
+#define NIC_MIN_NUM_RFD 64
+#define NIC_DEFAULT_NUM_RFD 256
+#endif
+
+#define NUM_PACKETS_HANDLED 256
+
+#define ALCATEL_BAD_STATUS 0xe47f0000
+#define ALCATEL_MULTICAST_PKT 0x01000000
+#define ALCATEL_BROADCAST_PKT 0x02000000
+
+/* typedefs for Free Buffer Descriptors */
+typedef union _FBR_WORD2_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 reserved:22; // bits 10-31
+ u32 bi:10; // bits 0-9(Buffer Index)
+#else
+ u32 bi:10; // bits 0-9(Buffer Index)
+ u32 reserved:22; // bit 10-31
+#endif
+ } bits;
+} FBR_WORD2_t, *PFBR_WORD2_t;
+
+typedef struct _FBR_DESC_t {
+ u32 addr_lo;
+ u32 addr_hi;
+ FBR_WORD2_t word2;
+} FBR_DESC_t, *PFBR_DESC_t;
+
+/* Typedefs for Packet Status Ring Descriptors */
+typedef union _PKT_STAT_DESC_WORD0_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ // top 16 bits are from the Alcatel Status Word as enumerated in
+ // PE-MCXMAC Data Sheet IPD DS54 0210-1 (also IPD-DS80 0205-2)
+#if 0
+ u32 asw_trunc:1; // bit 31(Rx frame truncated)
+#endif
+ u32 asw_long_evt:1; // bit 31(Rx long event)
+ u32 asw_VLAN_tag:1; // bit 30(VLAN tag detected)
+ u32 asw_unsupported_op:1; // bit 29(unsupported OP code)
+ u32 asw_pause_frame:1; // bit 28(is a pause frame)
+ u32 asw_control_frame:1; // bit 27(is a control frame)
+ u32 asw_dribble_nibble:1; // bit 26(spurious bits after EOP)
+ u32 asw_broadcast:1; // bit 25(has a broadcast address)
+ u32 asw_multicast:1; // bit 24(has a multicast address)
+ u32 asw_OK:1; // bit 23(valid CRC + no code error)
+ u32 asw_too_long:1; // bit 22(frame length > 1518 bytes)
+ u32 asw_len_chk_err:1; // bit 21(frame length field incorrect)
+ u32 asw_CRC_err:1; // bit 20(CRC error)
+ u32 asw_code_err:1; // bit 19(one or more nibbles signalled as errors)
+ u32 asw_false_carrier_event:1; // bit 18(bad carrier since last good packet)
+ u32 asw_RX_DV_event:1; // bit 17(short receive event detected)
+ u32 asw_prev_pkt_dropped:1;// bit 16(e.g. IFG too small on previous)
+ u32 unused:5; // bits 11-15
+ u32 vp:1; // bit 10(VLAN Packet)
+ u32 jp:1; // bit 9(Jumbo Packet)
+ u32 ft:1; // bit 8(Frame Truncated)
+ u32 drop:1; // bit 7(Drop packet)
+ u32 rxmac_error:1; // bit 6(RXMAC Error Indicator)
+ u32 wol:1; // bit 5(WOL Event)
+ u32 tcpp:1; // bit 4(TCP checksum pass)
+ u32 tcpa:1; // bit 3(TCP checksum assist)
+ u32 ipp:1; // bit 2(IP checksum pass)
+ u32 ipa:1; // bit 1(IP checksum assist)
+ u32 hp:1; // bit 0(hash pass)
+#else
+ u32 hp:1; // bit 0(hash pass)
+ u32 ipa:1; // bit 1(IP checksum assist)
+ u32 ipp:1; // bit 2(IP checksum pass)
+ u32 tcpa:1; // bit 3(TCP checksum assist)
+ u32 tcpp:1; // bit 4(TCP checksum pass)
+ u32 wol:1; // bit 5(WOL Event)
+ u32 rxmac_error:1; // bit 6(RXMAC Error Indicator)
+ u32 drop:1; // bit 7(Drop packet)
+ u32 ft:1; // bit 8(Frame Truncated)
+ u32 jp:1; // bit 9(Jumbo Packet)
+ u32 vp:1; // bit 10(VLAN Packet)
+ u32 unused:5; // bits 11-15
+ u32 asw_prev_pkt_dropped:1;// bit 16(e.g. IFG too small on previous)
+ u32 asw_RX_DV_event:1; // bit 17(short receive event detected)
+ u32 asw_false_carrier_event:1; // bit 18(bad carrier since last good packet)
+ u32 asw_code_err:1; // bit 19(one or more nibbles signalled as errors)
+ u32 asw_CRC_err:1; // bit 20(CRC error)
+ u32 asw_len_chk_err:1; // bit 21(frame length field incorrect)
+ u32 asw_too_long:1; // bit 22(frame length > 1518 bytes)
+ u32 asw_OK:1; // bit 23(valid CRC + no code error)
+ u32 asw_multicast:1; // bit 24(has a multicast address)
+ u32 asw_broadcast:1; // bit 25(has a broadcast address)
+ u32 asw_dribble_nibble:1; // bit 26(spurious bits after EOP)
+ u32 asw_control_frame:1; // bit 27(is a control frame)
+ u32 asw_pause_frame:1; // bit 28(is a pause frame)
+ u32 asw_unsupported_op:1; // bit 29(unsupported OP code)
+ u32 asw_VLAN_tag:1; // bit 30(VLAN tag detected)
+ u32 asw_long_evt:1; // bit 31(Rx long event)
+#if 0
+ u32 asw_trunc:1; // bit 31(Rx frame truncated)
+#endif
+#endif
+ } bits;
+} PKT_STAT_DESC_WORD0_t, *PPKT_STAT_WORD0_t;
+
+typedef union _PKT_STAT_DESC_WORD1_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused:4; // bits 28-31
+ u32 ri:2; // bits 26-27(Ring Index)
+ u32 bi:10; // bits 16-25(Buffer Index)
+ u32 length:16; // bit 0-15(length in bytes)
+#else
+ u32 length:16; // bit 0-15(length in bytes)
+ u32 bi:10; // bits 16-25(Buffer Index)
+ u32 ri:2; // bits 26-27(Ring Index)
+ u32 unused:4; // bits 28-31
+#endif
+ } bits;
+} PKT_STAT_DESC_WORD1_t, *PPKT_STAT_WORD1_t;
+
+typedef struct _PKT_STAT_DESC_t {
+ PKT_STAT_DESC_WORD0_t word0;
+ PKT_STAT_DESC_WORD1_t word1;
+} PKT_STAT_DESC_t, *PPKT_STAT_DESC_t;
+
+/* Typedefs for the RX DMA status word */
+
+/*
+ * RXSTAT_WORD0_t structure holds part of the status bits of the Rx DMA engine
+ * that get copied out to memory by the ET-1310. Word 0 is a 32 bit word
+ * whichcontains Free Buffer ring 0 and 1 available offset.
+ */
+typedef union _rxstat_word0_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 FBR1unused:5; // bits 27-31
+ u32 FBR1wrap:1; // bit 26
+ u32 FBR1offset:10; // bits 16-25
+ u32 FBR0unused:5; // bits 11-15
+ u32 FBR0wrap:1; // bit 10
+ u32 FBR0offset:10; // bits 0-9
+#else
+ u32 FBR0offset:10; // bits 0-9
+ u32 FBR0wrap:1; // bit 10
+ u32 FBR0unused:5; // bits 11-15
+ u32 FBR1offset:10; // bits 16-25
+ u32 FBR1wrap:1; // bit 26
+ u32 FBR1unused:5; // bits 27-31
+#endif
+ } bits;
+} RXSTAT_WORD0_t, *PRXSTAT_WORD0_t;
+
+/*
+ * RXSTAT_WORD1_t structure holds part of the status bits of the Rx DMA engine
+ * that get copied out to memory by the ET-1310. Word 3 is a 32 bit word
+ * which contains the Packet Status Ring available offset.
+ */
+typedef union _rxstat_word1_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 PSRunused:3; // bits 29-31
+ u32 PSRwrap:1; // bit 28
+ u32 PSRoffset:12; // bits 16-27
+ u32 reserved:16; // bits 0-15
+#else
+ u32 reserved:16; // bits 0-15
+ u32 PSRoffset:12; // bits 16-27
+ u32 PSRwrap:1; // bit 28
+ u32 PSRunused:3; // bits 29-31
+#endif
+ } bits;
+} RXSTAT_WORD1_t, *PRXSTAT_WORD1_t;
+
+/*
+ * RX_STATUS_BLOCK_t is sructure representing the status of the Rx DMA engine
+ * it sits in free memory, and is pointed to by 0x101c / 0x1020
+ */
+typedef struct _rx_status_block_t {
+ RXSTAT_WORD0_t Word0;
+ RXSTAT_WORD1_t Word1;
+} RX_STATUS_BLOCK_t, *PRX_STATUS_BLOCK_t;
+
+/*
+ * Structure for look-up table holding free buffer ring pointers
+ */
+typedef struct _FbrLookupTable {
+ void *Va[MAX_DESC_PER_RING_RX];
+ void *Buffer1[MAX_DESC_PER_RING_RX];
+ void *Buffer2[MAX_DESC_PER_RING_RX];
+ u32 PAHigh[MAX_DESC_PER_RING_RX];
+ u32 PALow[MAX_DESC_PER_RING_RX];
+} FBRLOOKUPTABLE, *PFBRLOOKUPTABLE;
+
+typedef enum {
+ ONE_PACKET_INTERRUPT,
+ FOUR_PACKET_INTERRUPT
+} eRX_INTERRUPT_STATE_t, *PeRX_INTERRUPT_STATE_t;
+
+/*
+ * Structure to hold the skb's in a list
+ */
+typedef struct rx_skb_list_elem {
+ struct list_head skb_list_elem;
+ dma_addr_t dma_addr;
+ struct sk_buff *skb;
+} RX_SKB_LIST_ELEM, *PRX_SKB_LIST_ELEM;
+
+/*
+ * RX_RING_t is sructure representing the adaptor's local reference(s) to the
+ * rings
+ */
+typedef struct _rx_ring_t {
+#ifdef USE_FBR0
+ void *pFbr0RingVa;
+ dma_addr_t pFbr0RingPa;
+ void *Fbr0MemVa[MAX_DESC_PER_RING_RX / FBR_CHUNKS];
+ dma_addr_t Fbr0MemPa[MAX_DESC_PER_RING_RX / FBR_CHUNKS];
+ uint64_t Fbr0Realpa;
+ uint64_t Fbr0offset;
+ DMA10W_t local_Fbr0_full;
+ u32 Fbr0NumEntries;
+ u32 Fbr0BufferSize;
+#endif
+ void *pFbr1RingVa;
+ dma_addr_t pFbr1RingPa;
+ void *Fbr1MemVa[MAX_DESC_PER_RING_RX / FBR_CHUNKS];
+ dma_addr_t Fbr1MemPa[MAX_DESC_PER_RING_RX / FBR_CHUNKS];
+ uint64_t Fbr1Realpa;
+ uint64_t Fbr1offset;
+ FBRLOOKUPTABLE *Fbr[2];
+ DMA10W_t local_Fbr1_full;
+ u32 Fbr1NumEntries;
+ u32 Fbr1BufferSize;
+
+ void *pPSRingVa;
+ dma_addr_t pPSRingPa;
+ uint64_t pPSRingRealPa;
+ uint64_t pPSRingOffset;
+ RXDMA_PSR_FULL_OFFSET_t local_psr_full;
+ u32 PsrNumEntries;
+
+ void *pRxStatusVa;
+ dma_addr_t pRxStatusPa;
+ uint64_t RxStatusRealPA;
+ uint64_t RxStatusOffset;
+
+ struct list_head RecvBufferPool;
+
+ /* RECV */
+ struct list_head RecvList;
+ struct list_head RecvPendingList;
+ u32 nReadyRecv;
+
+ u32 NumRfd;
+
+ bool UnfinishedReceives;
+
+ struct list_head RecvPacketPool;
+
+ /* lookaside lists */
+ struct kmem_cache *RecvLookaside;
+} RX_RING_t, *PRX_RING_t;
+
+/* Forward reference of RFD */
+struct _MP_RFD;
+
+/* Forward declaration of the private adapter structure */
+struct et131x_adapter;
+
+/* PROTOTYPES for Initialization */
+int et131x_rx_dma_memory_alloc(struct et131x_adapter *adapter);
+void et131x_rx_dma_memory_free(struct et131x_adapter *adapter);
+int et131x_rfd_resources_alloc(struct et131x_adapter *adapter,
+ struct _MP_RFD *pMpRfd);
+void et131x_rfd_resources_free(struct et131x_adapter *adapter,
+ struct _MP_RFD *pMpRfd);
+int et131x_init_recv(struct et131x_adapter *adapter);
+
+void ConfigRxDmaRegs(struct et131x_adapter *adapter);
+void SetRxDmaTimer(struct et131x_adapter *adapter);
+void et131x_rx_dma_disable(struct et131x_adapter *adapter);
+void et131x_rx_dma_enable(struct et131x_adapter *adapter);
+
+void et131x_reset_recv(struct et131x_adapter *adapter);
+
+void et131x_handle_recv_interrupt(struct et131x_adapter *adapter);
+
+#endif /* __ET1310_RX_H__ */
diff --git a/drivers/staging/et131x/et1310_tx.c b/drivers/staging/et131x/et1310_tx.c
new file mode 100644
index 0000000..a95c260
--- /dev/null
+++ b/drivers/staging/et131x/et1310_tx.c
@@ -0,0 +1,1525 @@
+/*
+ * Agere Systems Inc.
+ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * et1310_tx.c - Routines used to perform data transmission.
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#include "et131x_version.h"
+#include "et131x_debug.h"
+#include "et131x_defs.h"
+
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+
+#include "et1310_phy.h"
+#include "et1310_pm.h"
+#include "et1310_jagcore.h"
+
+#include "et131x_adapter.h"
+#include "et131x_initpci.h"
+#include "et131x_isr.h"
+
+#include "et1310_tx.h"
+
+/* Data for debugging facilities */
+#ifdef CONFIG_ET131X_DEBUG
+extern dbg_info_t *et131x_dbginfo;
+#endif /* CONFIG_ET131X_DEBUG */
+
+static void et131x_update_tcb_list(struct et131x_adapter *pAdapter);
+static void et131x_check_send_wait_list(struct et131x_adapter *pAdapter);
+static inline void et131x_free_send_packet(struct et131x_adapter *pAdapter,
+ PMP_TCB pMpTcb);
+static int et131x_send_packet(struct sk_buff *skb,
+ struct et131x_adapter *pAdapter);
+static int nic_send_packet(struct et131x_adapter *pAdapter, PMP_TCB pMpTcb);
+
+/**
+ * et131x_tx_dma_memory_alloc
+ * @adapter: pointer to our private adapter structure
+ *
+ * Returns 0 on success and errno on failure (as defined in errno.h).
+ *
+ * Allocates memory that will be visible both to the device and to the CPU.
+ * The OS will pass us packets, pointers to which we will insert in the Tx
+ * Descriptor queue. The device will read this queue to find the packets in
+ * memory. The device will update the "status" in memory each time it xmits a
+ * packet.
+ */
+int et131x_tx_dma_memory_alloc(struct et131x_adapter *adapter)
+{
+ int desc_size = 0;
+ TX_RING_t *tx_ring = &adapter->TxRing;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Allocate memory for the TCB's (Transmit Control Block) */
+ adapter->TxRing.MpTcbMem = (MP_TCB *) kcalloc(NUM_TCB, sizeof(MP_TCB),
+ GFP_ATOMIC | GFP_DMA);
+ if (!adapter->TxRing.MpTcbMem) {
+ DBG_ERROR(et131x_dbginfo, "Cannot alloc memory for TCBs\n");
+ DBG_LEAVE(et131x_dbginfo);
+ return -ENOMEM;
+ }
+
+ /* Allocate enough memory for the Tx descriptor ring, and allocate
+ * some extra so that the ring can be aligned on a 4k boundary.
+ */
+ desc_size = (sizeof(TX_DESC_ENTRY_t) * NUM_DESC_PER_RING_TX) + 4096 - 1;
+ tx_ring->pTxDescRingVa =
+ (PTX_DESC_ENTRY_t) pci_alloc_consistent(adapter->pdev, desc_size,
+ &tx_ring->pTxDescRingPa);
+ if (!adapter->TxRing.pTxDescRingVa) {
+ DBG_ERROR(et131x_dbginfo, "Cannot alloc memory for Tx Ring\n");
+ DBG_LEAVE(et131x_dbginfo);
+ return -ENOMEM;
+ }
+
+ /* Save physical address
+ *
+ * NOTE: pci_alloc_consistent(), used above to alloc DMA regions,
+ * ALWAYS returns SAC (32-bit) addresses. If DAC (64-bit) addresses
+ * are ever returned, make sure the high part is retrieved here before
+ * storing the adjusted address.
+ */
+ tx_ring->pTxDescRingAdjustedPa = tx_ring->pTxDescRingPa;
+
+ /* Align Tx Descriptor Ring on a 4k (0x1000) byte boundary */
+ et131x_align_allocated_memory(adapter,
+ &tx_ring->pTxDescRingAdjustedPa,
+ &tx_ring->TxDescOffset, 0x0FFF);
+
+ tx_ring->pTxDescRingVa += tx_ring->TxDescOffset;
+
+ /* Allocate memory for the Tx status block */
+ tx_ring->pTxStatusVa = pci_alloc_consistent(adapter->pdev,
+ sizeof(TX_STATUS_BLOCK_t),
+ &tx_ring->pTxStatusPa);
+ if (!adapter->TxRing.pTxStatusPa) {
+ DBG_ERROR(et131x_dbginfo,
+ "Cannot alloc memory for Tx status block\n");
+ DBG_LEAVE(et131x_dbginfo);
+ return -ENOMEM;
+ }
+
+ /* Allocate memory for a dummy buffer */
+ tx_ring->pTxDummyBlkVa = pci_alloc_consistent(adapter->pdev,
+ NIC_MIN_PACKET_SIZE,
+ &tx_ring->pTxDummyBlkPa);
+ if (!adapter->TxRing.pTxDummyBlkPa) {
+ DBG_ERROR(et131x_dbginfo,
+ "Cannot alloc memory for Tx dummy buffer\n");
+ DBG_LEAVE(et131x_dbginfo);
+ return -ENOMEM;
+ }
+
+ DBG_LEAVE(et131x_dbginfo);
+ return 0;
+}
+
+/**
+ * et131x_tx_dma_memory_free - Free all memory allocated within this module
+ * @adapter: pointer to our private adapter structure
+ *
+ * Returns 0 on success and errno on failure (as defined in errno.h).
+ */
+void et131x_tx_dma_memory_free(struct et131x_adapter *adapter)
+{
+ int desc_size = 0;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ if (adapter->TxRing.pTxDescRingVa) {
+ /* Free memory relating to Tx rings here */
+ adapter->TxRing.pTxDescRingVa -= adapter->TxRing.TxDescOffset;
+
+ desc_size =
+ (sizeof(TX_DESC_ENTRY_t) * NUM_DESC_PER_RING_TX) + 4096 - 1;
+
+ pci_free_consistent(adapter->pdev,
+ desc_size,
+ adapter->TxRing.pTxDescRingVa,
+ adapter->TxRing.pTxDescRingPa);
+
+ adapter->TxRing.pTxDescRingVa = NULL;
+ }
+
+ /* Free memory for the Tx status block */
+ if (adapter->TxRing.pTxStatusVa) {
+ pci_free_consistent(adapter->pdev,
+ sizeof(TX_STATUS_BLOCK_t),
+ adapter->TxRing.pTxStatusVa,
+ adapter->TxRing.pTxStatusPa);
+
+ adapter->TxRing.pTxStatusVa = NULL;
+ }
+
+ /* Free memory for the dummy buffer */
+ if (adapter->TxRing.pTxDummyBlkVa) {
+ pci_free_consistent(adapter->pdev,
+ NIC_MIN_PACKET_SIZE,
+ adapter->TxRing.pTxDummyBlkVa,
+ adapter->TxRing.pTxDummyBlkPa);
+
+ adapter->TxRing.pTxDummyBlkVa = NULL;
+ }
+
+ /* Free the memory for MP_TCB structures */
+ if (adapter->TxRing.MpTcbMem) {
+ kfree(adapter->TxRing.MpTcbMem);
+ adapter->TxRing.MpTcbMem = NULL;
+ }
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * ConfigTxDmaRegs - Set up the tx dma section of the JAGCore.
+ * @adapter: pointer to our private adapter structure
+ */
+void ConfigTxDmaRegs(struct et131x_adapter *pAdapter)
+{
+ struct _TXDMA_t __iomem *pTxDma = &pAdapter->CSRAddress->txdma;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Load the hardware with the start of the transmit descriptor ring. */
+ writel((uint32_t) (pAdapter->TxRing.pTxDescRingAdjustedPa >> 32),
+ &pTxDma->pr_base_hi);
+ writel((uint32_t) pAdapter->TxRing.pTxDescRingAdjustedPa,
+ &pTxDma->pr_base_lo);
+
+ /* Initialise the transmit DMA engine */
+ writel(NUM_DESC_PER_RING_TX - 1, &pTxDma->pr_num_des.value);
+
+ /* Load the completion writeback physical address
+ *
+ * NOTE: pci_alloc_consistent(), used above to alloc DMA regions,
+ * ALWAYS returns SAC (32-bit) addresses. If DAC (64-bit) addresses
+ * are ever returned, make sure the high part is retrieved here before
+ * storing the adjusted address.
+ */
+ writel(0, &pTxDma->dma_wb_base_hi);
+ writel(pAdapter->TxRing.pTxStatusPa, &pTxDma->dma_wb_base_lo);
+
+ memset(pAdapter->TxRing.pTxStatusVa, 0, sizeof(TX_STATUS_BLOCK_t));
+
+ writel(0, &pTxDma->service_request.value);
+ pAdapter->TxRing.txDmaReadyToSend.value = 0;
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * et131x_tx_dma_disable - Stop of Tx_DMA on the ET1310
+ * @pAdapter: pointer to our adapter structure
+ */
+void et131x_tx_dma_disable(struct et131x_adapter *pAdapter)
+{
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Setup the tramsmit dma configuration register */
+ writel(0x101, &pAdapter->CSRAddress->txdma.csr.value);
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * et131x_tx_dma_enable - re-start of Tx_DMA on the ET1310.
+ * @pAdapter: pointer to our adapter structure
+ *
+ * Mainly used after a return to the D0 (full-power) state from a lower state.
+ */
+void et131x_tx_dma_enable(struct et131x_adapter *pAdapter)
+{
+ DBG_ENTER(et131x_dbginfo);
+
+ if (pAdapter->RegistryPhyLoopbk) {
+ /* TxDMA is disabled for loopback operation. */
+ writel(0x101, &pAdapter->CSRAddress->txdma.csr.value);
+ } else {
+ TXDMA_CSR_t csr = { 0 };
+
+ /* Setup the transmit dma configuration register for normal
+ * operation
+ */
+ csr.bits.sngl_epkt_mode = 1;
+ csr.bits.halt = 0;
+ csr.bits.cache_thrshld = pAdapter->RegistryDMACache;
+ writel(csr.value, &pAdapter->CSRAddress->txdma.csr.value);
+ }
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * et131x_init_send - Initialize send data structures
+ * @adapter: pointer to our private adapter structure
+ */
+void et131x_init_send(struct et131x_adapter *adapter)
+{
+ PMP_TCB pMpTcb;
+ uint32_t TcbCount;
+ TX_RING_t *tx_ring;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Setup some convenience pointers */
+ tx_ring = &adapter->TxRing;
+ pMpTcb = adapter->TxRing.MpTcbMem;
+
+ tx_ring->TCBReadyQueueHead = pMpTcb;
+
+ /* Go through and set up each TCB */
+ for (TcbCount = 0; TcbCount < NUM_TCB; TcbCount++) {
+ memset(pMpTcb, 0, sizeof(MP_TCB));
+
+ /* Set the link pointer in HW TCB to the next TCB in the
+ * chain. If this is the last TCB in the chain, also set the
+ * tail pointer.
+ */
+ if (TcbCount < NUM_TCB - 1) {
+ pMpTcb->Next = pMpTcb + 1;
+ } else {
+ tx_ring->TCBReadyQueueTail = pMpTcb;
+ pMpTcb->Next = (PMP_TCB) NULL;
+ }
+
+ pMpTcb++;
+ }
+
+ /* Curr send queue should now be empty */
+ tx_ring->CurrSendHead = (PMP_TCB) NULL;
+ tx_ring->CurrSendTail = (PMP_TCB) NULL;
+
+ INIT_LIST_HEAD(&adapter->TxRing.SendWaitQueue);
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * et131x_send_packets - This function is called by the OS to send packets
+ * @skb: the packet(s) to send
+ * @netdev:device on which to TX the above packet(s)
+ *
+ * Return 0 in almost all cases; non-zero value in extreme hard failure only
+ */
+int et131x_send_packets(struct sk_buff *skb, struct net_device *netdev)
+{
+ int status = 0;
+ struct et131x_adapter *pAdapter = NULL;
+
+ DBG_TX_ENTER(et131x_dbginfo);
+
+ pAdapter = netdev_priv(netdev);
+
+ /* Send these packets
+ *
+ * NOTE: The Linux Tx entry point is only given one packet at a time
+ * to Tx, so the PacketCount and it's array used makes no sense here
+ */
+
+ /* Queue is not empty or TCB is not available */
+ if (!list_empty(&pAdapter->TxRing.SendWaitQueue) ||
+ MP_TCB_RESOURCES_NOT_AVAILABLE(pAdapter)) {
+ /* NOTE: If there's an error on send, no need to queue the
+ * packet under Linux; if we just send an error up to the
+ * netif layer, it will resend the skb to us.
+ */
+ DBG_VERBOSE(et131x_dbginfo, "TCB Resources Not Available\n");
+ status = -ENOMEM;
+ } else {
+ /* We need to see if the link is up; if it's not, make the
+ * netif layer think we're good and drop the packet
+ */
+ //if( MP_SHOULD_FAIL_SEND( pAdapter ) || pAdapter->DriverNoPhyAccess )
+ if (MP_SHOULD_FAIL_SEND(pAdapter) || pAdapter->DriverNoPhyAccess
+ || !netif_carrier_ok(netdev)) {
+ DBG_VERBOSE(et131x_dbginfo,
+ "Can't Tx, Link is DOWN; drop the packet\n");
+
+ dev_kfree_skb_any(skb);
+ skb = NULL;
+
+ pAdapter->net_stats.tx_dropped++;
+ } else {
+ status = et131x_send_packet(skb, pAdapter);
+
+ if (status == -ENOMEM) {
+
+ /* NOTE: If there's an error on send, no need
+ * to queue the packet under Linux; if we just
+ * send an error up to the netif layer, it
+ * will resend the skb to us.
+ */
+ DBG_WARNING(et131x_dbginfo,
+ "Resources problem, Queue tx packet\n");
+ } else if (status != 0) {
+ /* On any other error, make netif think we're
+ * OK and drop the packet
+ */
+ DBG_WARNING(et131x_dbginfo,
+ "General error, drop packet\n");
+
+ dev_kfree_skb_any(skb);
+ skb = NULL;
+
+ pAdapter->net_stats.tx_dropped++;
+ }
+ }
+ }
+
+ DBG_TX_LEAVE(et131x_dbginfo);
+ return status;
+}
+
+/**
+ * et131x_send_packet - Do the work to send a packet
+ * @skb: the packet(s) to send
+ * @pAdapter: a pointer to the device's private adapter structure
+ *
+ * Return 0 in almost all cases; non-zero value in extreme hard failure only.
+ *
+ * Assumption: Send spinlock has been acquired
+ */
+static int et131x_send_packet(struct sk_buff *skb,
+ struct et131x_adapter *pAdapter)
+{
+ int status = 0;
+ PMP_TCB pMpTcb = NULL;
+ uint16_t *pShBufVa;
+ unsigned long lockflags;
+
+ DBG_TX_ENTER(et131x_dbginfo);
+
+ /* Is our buffer scattered, or continuous? */
+ if (skb_shinfo(skb)->nr_frags == 0) {
+ DBG_TX(et131x_dbginfo, "Scattered buffer: NO\n");
+ } else {
+ DBG_TX(et131x_dbginfo, "Scattered buffer: YES, Num Frags: %d\n",
+ skb_shinfo(skb)->nr_frags);
+ }
+
+ /* All packets must have at least a MAC address and a protocol type */
+ if (skb->len < ETH_HLEN) {
+ DBG_ERROR(et131x_dbginfo,
+ "Packet size < ETH_HLEN (14 bytes)\n");
+ DBG_LEAVE(et131x_dbginfo);
+ return -EIO;
+ }
+
+ /* Get a TCB for this packet */
+ spin_lock_irqsave(&pAdapter->TCBReadyQLock, lockflags);
+
+ pMpTcb = pAdapter->TxRing.TCBReadyQueueHead;
+
+ if (pMpTcb == NULL) {
+ spin_unlock_irqrestore(&pAdapter->TCBReadyQLock, lockflags);
+
+ DBG_WARNING(et131x_dbginfo, "Can't obtain a TCB\n");
+ DBG_TX_LEAVE(et131x_dbginfo);
+ return -ENOMEM;
+ }
+
+ pAdapter->TxRing.TCBReadyQueueHead = pMpTcb->Next;
+
+ if (pAdapter->TxRing.TCBReadyQueueHead == NULL) {
+ pAdapter->TxRing.TCBReadyQueueTail = NULL;
+ }
+
+ spin_unlock_irqrestore(&pAdapter->TCBReadyQLock, lockflags);
+
+ pMpTcb->PacketLength = skb->len;
+ pMpTcb->Packet = skb;
+
+ if ((skb->data != NULL) && ((skb->len - skb->data_len) >= 6)) {
+ pShBufVa = (uint16_t *) skb->data;
+
+ if ((pShBufVa[0] == 0xffff) &&
+ (pShBufVa[1] == 0xffff) && (pShBufVa[2] == 0xffff)) {
+ MP_SET_FLAG(pMpTcb, fMP_DEST_BROAD);
+ } else if ((pShBufVa[0] & 0x3) == 0x0001) {
+ MP_SET_FLAG(pMpTcb, fMP_DEST_MULTI);
+ }
+ }
+
+ pMpTcb->Next = NULL;
+
+ /* Call the NIC specific send handler. */
+ if (status == 0) {
+ status = nic_send_packet(pAdapter, pMpTcb);
+ }
+
+ if (status != 0) {
+ spin_lock_irqsave(&pAdapter->TCBReadyQLock, lockflags);
+
+ if (pAdapter->TxRing.TCBReadyQueueTail) {
+ pAdapter->TxRing.TCBReadyQueueTail->Next = pMpTcb;
+ } else {
+ /* Apparently ready Q is empty. */
+ pAdapter->TxRing.TCBReadyQueueHead = pMpTcb;
+ }
+
+ pAdapter->TxRing.TCBReadyQueueTail = pMpTcb;
+
+ spin_unlock_irqrestore(&pAdapter->TCBReadyQLock, lockflags);
+
+ DBG_TX_LEAVE(et131x_dbginfo);
+ return status;
+ }
+
+ DBG_ASSERT(pAdapter->TxRing.nBusySend <= NUM_TCB);
+
+ DBG_TX_LEAVE(et131x_dbginfo);
+ return 0;
+}
+
+/**
+ * nic_send_packet - NIC specific send handler for version B silicon.
+ * @pAdapter: pointer to our adapter
+ * @pMpTcb: pointer to MP_TCB
+ *
+ * Returns 0 or errno.
+ */
+static int nic_send_packet(struct et131x_adapter *pAdapter, PMP_TCB pMpTcb)
+{
+ uint32_t loopIndex;
+ TX_DESC_ENTRY_t CurDesc[24];
+ uint32_t FragmentNumber = 0;
+ uint32_t iThisCopy, iRemainder;
+ struct sk_buff *pPacket = pMpTcb->Packet;
+ uint32_t FragListCount = skb_shinfo(pPacket)->nr_frags + 1;
+ struct skb_frag_struct *pFragList = &skb_shinfo(pPacket)->frags[0];
+ unsigned long lockflags1, lockflags2;
+
+ DBG_TX_ENTER(et131x_dbginfo);
+
+ /* Part of the optimizations of this send routine restrict us to
+ * sending 24 fragments at a pass. In practice we should never see
+ * more than 5 fragments.
+ *
+ * NOTE: The older version of this function (below) can handle any
+ * number of fragments. If needed, we can call this function,
+ * although it is less efficient.
+ */
+ if (FragListCount > 23) {
+ DBG_TX_LEAVE(et131x_dbginfo);
+ return -EIO;
+ }
+
+ memset(CurDesc, 0, sizeof(TX_DESC_ENTRY_t) * (FragListCount + 1));
+
+ for (loopIndex = 0; loopIndex < FragListCount; loopIndex++) {
+ /* If there is something in this element, lets get a
+ * descriptor from the ring and get the necessary data
+ */
+ if (loopIndex == 0) {
+ /* If the fragments are smaller than a standard MTU,
+ * then map them to a single descriptor in the Tx
+ * Desc ring. However, if they're larger, as is
+ * possible with support for jumbo packets, then
+ * split them each across 2 descriptors.
+ *
+ * This will work until we determine why the hardware
+ * doesn't seem to like large fragments.
+ */
+ if ((pPacket->len - pPacket->data_len) <= 1514) {
+ DBG_TX(et131x_dbginfo,
+ "Got packet of length %d, "
+ "filling desc entry %d, "
+ "TCB: 0x%p\n",
+ (pPacket->len - pPacket->data_len),
+ pAdapter->TxRing.txDmaReadyToSend.bits.
+ val, pMpTcb);
+
+ CurDesc[FragmentNumber].DataBufferPtrHigh = 0;
+
+ CurDesc[FragmentNumber].word2.bits.
+ length_in_bytes =
+ pPacket->len - pPacket->data_len;
+
+ /* NOTE: Here, the dma_addr_t returned from
+ * pci_map_single() is implicitly cast as a
+ * uint32_t. Although dma_addr_t can be
+ * 64-bit, the address returned by
+ * pci_map_single() is always 32-bit
+ * addressable (as defined by the pci/dma
+ * subsystem)
+ */
+ CurDesc[FragmentNumber++].DataBufferPtrLow =
+ pci_map_single(pAdapter->pdev,
+ pPacket->data,
+ pPacket->len -
+ pPacket->data_len,
+ PCI_DMA_TODEVICE);
+ } else {
+ DBG_TX(et131x_dbginfo,
+ "Got packet of length %d, "
+ "filling desc entry %d, "
+ "TCB: 0x%p\n",
+ (pPacket->len - pPacket->data_len),
+ pAdapter->TxRing.txDmaReadyToSend.bits.
+ val, pMpTcb);
+
+ CurDesc[FragmentNumber].DataBufferPtrHigh = 0;
+
+ CurDesc[FragmentNumber].word2.bits.
+ length_in_bytes =
+ ((pPacket->len - pPacket->data_len) / 2);
+
+ /* NOTE: Here, the dma_addr_t returned from
+ * pci_map_single() is implicitly cast as a
+ * uint32_t. Although dma_addr_t can be
+ * 64-bit, the address returned by
+ * pci_map_single() is always 32-bit
+ * addressable (as defined by the pci/dma
+ * subsystem)
+ */
+ CurDesc[FragmentNumber++].DataBufferPtrLow =
+ pci_map_single(pAdapter->pdev,
+ pPacket->data,
+ ((pPacket->len -
+ pPacket->data_len) / 2),
+ PCI_DMA_TODEVICE);
+ CurDesc[FragmentNumber].DataBufferPtrHigh = 0;
+
+ CurDesc[FragmentNumber].word2.bits.
+ length_in_bytes =
+ ((pPacket->len - pPacket->data_len) / 2);
+
+ /* NOTE: Here, the dma_addr_t returned from
+ * pci_map_single() is implicitly cast as a
+ * uint32_t. Although dma_addr_t can be
+ * 64-bit, the address returned by
+ * pci_map_single() is always 32-bit
+ * addressable (as defined by the pci/dma
+ * subsystem)
+ */
+ CurDesc[FragmentNumber++].DataBufferPtrLow =
+ pci_map_single(pAdapter->pdev,
+ pPacket->data +
+ ((pPacket->len -
+ pPacket->data_len) / 2),
+ ((pPacket->len -
+ pPacket->data_len) / 2),
+ PCI_DMA_TODEVICE);
+ }
+ } else {
+ DBG_TX(et131x_dbginfo,
+ "Got packet of length %d,"
+ "filling desc entry %d\n"
+ "TCB: 0x%p\n",
+ pFragList[loopIndex].size,
+ pAdapter->TxRing.txDmaReadyToSend.bits.val,
+ pMpTcb);
+
+ CurDesc[FragmentNumber].DataBufferPtrHigh = 0;
+
+ CurDesc[FragmentNumber].word2.bits.length_in_bytes =
+ pFragList[loopIndex - 1].size;
+
+ /* NOTE: Here, the dma_addr_t returned from
+ * pci_map_page() is implicitly cast as a uint32_t.
+ * Although dma_addr_t can be 64-bit, the address
+ * returned by pci_map_page() is always 32-bit
+ * addressable (as defined by the pci/dma subsystem)
+ */
+ CurDesc[FragmentNumber++].DataBufferPtrLow =
+ pci_map_page(pAdapter->pdev,
+ pFragList[loopIndex - 1].page,
+ pFragList[loopIndex - 1].page_offset,
+ pFragList[loopIndex - 1].size,
+ PCI_DMA_TODEVICE);
+ }
+ }
+
+ if (FragmentNumber == 0) {
+ DBG_WARNING(et131x_dbginfo, "No. frags is 0\n");
+ return -EIO;
+ }
+
+ if (pAdapter->uiLinkSpeed == TRUEPHY_SPEED_1000MBPS) {
+ if (++pAdapter->TxRing.TxPacketsSinceLastinterrupt ==
+ pAdapter->RegistryTxNumBuffers) {
+ CurDesc[FragmentNumber - 1].word3.value = 0x5;
+ pAdapter->TxRing.TxPacketsSinceLastinterrupt = 0;
+ } else {
+ CurDesc[FragmentNumber - 1].word3.value = 0x1;
+ }
+ } else {
+ CurDesc[FragmentNumber - 1].word3.value = 0x5;
+ }
+
+ CurDesc[0].word3.bits.f = 1;
+
+ pMpTcb->WrIndexStart = pAdapter->TxRing.txDmaReadyToSend;
+ pMpTcb->PacketStaleCount = 0;
+
+ spin_lock_irqsave(&pAdapter->SendHWLock, lockflags1);
+
+ iThisCopy =
+ NUM_DESC_PER_RING_TX - pAdapter->TxRing.txDmaReadyToSend.bits.val;
+
+ if (iThisCopy >= FragmentNumber) {
+ iRemainder = 0;
+ iThisCopy = FragmentNumber;
+ } else {
+ iRemainder = FragmentNumber - iThisCopy;
+ }
+
+ memcpy(pAdapter->TxRing.pTxDescRingVa +
+ pAdapter->TxRing.txDmaReadyToSend.bits.val, CurDesc,
+ sizeof(TX_DESC_ENTRY_t) * iThisCopy);
+
+ pAdapter->TxRing.txDmaReadyToSend.bits.val += iThisCopy;
+
+ if ((pAdapter->TxRing.txDmaReadyToSend.bits.val == 0) ||
+ (pAdapter->TxRing.txDmaReadyToSend.bits.val ==
+ NUM_DESC_PER_RING_TX)) {
+ if (pAdapter->TxRing.txDmaReadyToSend.bits.wrap) {
+ pAdapter->TxRing.txDmaReadyToSend.value = 0;
+ } else {
+ pAdapter->TxRing.txDmaReadyToSend.value = 0x400;
+ }
+ }
+
+ if (iRemainder) {
+ memcpy(pAdapter->TxRing.pTxDescRingVa,
+ CurDesc + iThisCopy,
+ sizeof(TX_DESC_ENTRY_t) * iRemainder);
+
+ pAdapter->TxRing.txDmaReadyToSend.bits.val += iRemainder;
+ }
+
+ if (pAdapter->TxRing.txDmaReadyToSend.bits.val == 0) {
+ if (pAdapter->TxRing.txDmaReadyToSend.value) {
+ pMpTcb->WrIndex.value = NUM_DESC_PER_RING_TX - 1;
+ } else {
+ pMpTcb->WrIndex.value =
+ 0x400 | (NUM_DESC_PER_RING_TX - 1);
+ }
+ } else {
+ pMpTcb->WrIndex.value =
+ pAdapter->TxRing.txDmaReadyToSend.value - 1;
+ }
+
+ spin_lock_irqsave(&pAdapter->TCBSendQLock, lockflags2);
+
+ if (pAdapter->TxRing.CurrSendTail) {
+ pAdapter->TxRing.CurrSendTail->Next = pMpTcb;
+ } else {
+ pAdapter->TxRing.CurrSendHead = pMpTcb;
+ }
+
+ pAdapter->TxRing.CurrSendTail = pMpTcb;
+
+ DBG_ASSERT(pMpTcb->Next == NULL);
+
+ pAdapter->TxRing.nBusySend++;
+
+ spin_unlock_irqrestore(&pAdapter->TCBSendQLock, lockflags2);
+
+ /* Write the new write pointer back to the device. */
+ writel(pAdapter->TxRing.txDmaReadyToSend.value,
+ &pAdapter->CSRAddress->txdma.service_request.value);
+
+ /* For Gig only, we use Tx Interrupt coalescing. Enable the software
+ * timer to wake us up if this packet isn't followed by N more.
+ */
+ if (pAdapter->uiLinkSpeed == TRUEPHY_SPEED_1000MBPS) {
+ writel(pAdapter->RegistryTxTimeInterval * NANO_IN_A_MICRO,
+ &pAdapter->CSRAddress->global.watchdog_timer);
+ }
+
+ spin_unlock_irqrestore(&pAdapter->SendHWLock, lockflags1);
+
+ DBG_TX_LEAVE(et131x_dbginfo);
+ return 0;
+}
+
+/*
+ * NOTE: For now, keep this older version of NICSendPacket around for
+ * reference, even though it's not used
+ */
+#if 0
+
+/**
+ * NICSendPacket - NIC specific send handler.
+ * @pAdapter: pointer to our adapter
+ * @pMpTcb: pointer to MP_TCB
+ *
+ * Returns 0 on succes, errno on failure.
+ *
+ * This version of the send routine is designed for version A silicon.
+ * Assumption - Send spinlock has been acquired.
+ */
+static int nic_send_packet(struct et131x_adapter *pAdapter, PMP_TCB pMpTcb)
+{
+ uint32_t loopIndex, fragIndex, loopEnd;
+ uint32_t iSplitFirstElement = 0;
+ uint32_t SegmentSize = 0;
+ TX_DESC_ENTRY_t CurDesc;
+ TX_DESC_ENTRY_t *CurDescPostCopy = NULL;
+ uint32_t SlotsAvailable;
+ DMA10W_t ServiceComplete;
+ unsigned int lockflags1, lockflags2;
+ struct sk_buff *pPacket = pMpTcb->Packet;
+ uint32_t FragListCount = skb_shinfo(pPacket)->nr_frags + 1;
+ struct skb_frag_struct *pFragList = &skb_shinfo(pPacket)->frags[0];
+
+ DBG_TX_ENTER(et131x_dbginfo);
+
+ ServiceComplete.value =
+ readl(&pAdapter->CSRAddress->txdma.NewServiceComplete.value);
+
+ /*
+ * Attempt to fix TWO hardware bugs:
+ * 1) NEVER write an odd number of descriptors.
+ * 2) If packet length is less than NIC_MIN_PACKET_SIZE, then pad the
+ * packet to NIC_MIN_PACKET_SIZE bytes by adding a new last
+ * descriptor IN HALF DUPLEX MODE ONLY
+ * NOTE that (2) interacts with (1). If the packet is less than
+ * NIC_MIN_PACKET_SIZE bytes then we will append a descriptor.
+ * Therefore if it is even now, it will eventually end up odd, and
+ * so will need adjusting.
+ *
+ * VLAN tags get involved since VLAN tags add another one or two
+ * segments.
+ */
+ DBG_TX(et131x_dbginfo,
+ "pMpTcb->PacketLength: %d\n", pMpTcb->PacketLength);
+
+ if ((pAdapter->uiDuplexMode == 0)
+ && (pMpTcb->PacketLength < NIC_MIN_PACKET_SIZE)) {
+ DBG_TX(et131x_dbginfo,
+ "HALF DUPLEX mode AND len < MIN_PKT_SIZE\n");
+ if ((FragListCount & 0x1) == 0) {
+ DBG_TX(et131x_dbginfo,
+ "Even number of descs, split 1st elem\n");
+ iSplitFirstElement = 1;
+ //SegmentSize = pFragList[0].size / 2;
+ SegmentSize = (pPacket->len - pPacket->data_len) / 2;
+ }
+ } else if (FragListCount & 0x1) {
+ DBG_TX(et131x_dbginfo, "Odd number of descs, split 1st elem\n");
+
+ iSplitFirstElement = 1;
+ //SegmentSize = pFragList[0].size / 2;
+ SegmentSize = (pPacket->len - pPacket->data_len) / 2;
+ }
+
+ spin_lock_irqsave(&pAdapter->SendHWLock, lockflags1);
+
+ if (pAdapter->TxRing.txDmaReadyToSend.bits.serv_req_wrap ==
+ ServiceComplete.bits.serv_cpl_wrap) {
+ /* The ring hasn't wrapped. Slots available should be
+ * (RING_SIZE) - the difference between the two pointers.
+ */
+ SlotsAvailable = NUM_DESC_PER_RING_TX -
+ (pAdapter->TxRing.txDmaReadyToSend.bits.serv_req -
+ ServiceComplete.bits.serv_cpl);
+ } else {
+ /* The ring has wrapped. Slots available should be the
+ * difference between the two pointers.
+ */
+ SlotsAvailable = ServiceComplete.bits.serv_cpl -
+ pAdapter->TxRing.txDmaReadyToSend.bits.serv_req;
+ }
+
+ if ((FragListCount + iSplitFirstElement) > SlotsAvailable) {
+ DBG_WARNING(et131x_dbginfo,
+ "Not Enough Space in Tx Desc Ring\n");
+ spin_unlock_irqrestore(&pAdapter->SendHWLock, lockflags1);
+ return -ENOMEM;
+ }
+
+ loopEnd = (FragListCount) + iSplitFirstElement;
+ fragIndex = 0;
+
+ DBG_TX(et131x_dbginfo,
+ "TCB : 0x%p\n"
+ "Packet (SKB) : 0x%p\t Packet->len: %d\t Packet->data_len: %d\n"
+ "FragListCount : %d\t iSplitFirstElement: %d\t loopEnd:%d\n",
+ pMpTcb,
+ pPacket, pPacket->len, pPacket->data_len,
+ FragListCount, iSplitFirstElement, loopEnd);
+
+ for (loopIndex = 0; loopIndex < loopEnd; loopIndex++) {
+ if (loopIndex > iSplitFirstElement) {
+ fragIndex++;
+ }
+
+ DBG_TX(et131x_dbginfo,
+ "In loop, loopIndex: %d\t fragIndex: %d\n", loopIndex,
+ fragIndex);
+
+ /* If there is something in this element, let's get a
+ * descriptor from the ring and get the necessary data
+ */
+ DBG_TX(et131x_dbginfo,
+ "Packet Length %d,"
+ "filling desc entry %d\n",
+ pPacket->len,
+ pAdapter->TxRing.txDmaReadyToSend.bits.serv_req);
+
+ // NOTE - Should we do a paranoia check here to make sure the fragment
+ // actually has a length? It's HIGHLY unlikely the fragment would
+ // contain no data...
+ if (1) {
+ // NOTE - Currently always getting 32-bit addrs, and dma_addr_t is
+ // only 32-bit, so leave "high" ptr value out for now
+ CurDesc.DataBufferPtrHigh = 0;
+
+ CurDesc.word2.value = 0;
+ CurDesc.word3.value = 0;
+
+ if (fragIndex == 0) {
+ if (iSplitFirstElement) {
+ DBG_TX(et131x_dbginfo,
+ "Split first element: YES\n");
+
+ if (loopIndex == 0) {
+ DBG_TX(et131x_dbginfo,
+ "Got fragment of length %d, fragIndex: %d\n",
+ pPacket->len -
+ pPacket->data_len,
+ fragIndex);
+ DBG_TX(et131x_dbginfo,
+ "SegmentSize: %d\n",
+ SegmentSize);
+
+ CurDesc.word2.bits.
+ length_in_bytes =
+ SegmentSize;
+ CurDesc.DataBufferPtrLow =
+ pci_map_single(pAdapter->
+ pdev,
+ pPacket->
+ data,
+ SegmentSize,
+ PCI_DMA_TODEVICE);
+ DBG_TX(et131x_dbginfo,
+ "pci_map_single() returns: 0x%08x\n",
+ CurDesc.
+ DataBufferPtrLow);
+ } else {
+ DBG_TX(et131x_dbginfo,
+ "Got fragment of length %d, fragIndex: %d\n",
+ pPacket->len -
+ pPacket->data_len,
+ fragIndex);
+ DBG_TX(et131x_dbginfo,
+ "Leftover Size: %d\n",
+ (pPacket->len -
+ pPacket->data_len -
+ SegmentSize));
+
+ CurDesc.word2.bits.
+ length_in_bytes =
+ ((pPacket->len -
+ pPacket->data_len) -
+ SegmentSize);
+ CurDesc.DataBufferPtrLow =
+ pci_map_single(pAdapter->
+ pdev,
+ (pPacket->
+ data +
+ SegmentSize),
+ (pPacket->
+ len -
+ pPacket->
+ data_len -
+ SegmentSize),
+ PCI_DMA_TODEVICE);
+ DBG_TX(et131x_dbginfo,
+ "pci_map_single() returns: 0x%08x\n",
+ CurDesc.
+ DataBufferPtrLow);
+ }
+ } else {
+ DBG_TX(et131x_dbginfo,
+ "Split first element: NO\n");
+
+ CurDesc.word2.bits.length_in_bytes =
+ pPacket->len - pPacket->data_len;
+
+ CurDesc.DataBufferPtrLow =
+ pci_map_single(pAdapter->pdev,
+ pPacket->data,
+ (pPacket->len -
+ pPacket->data_len),
+ PCI_DMA_TODEVICE);
+ DBG_TX(et131x_dbginfo,
+ "pci_map_single() returns: 0x%08x\n",
+ CurDesc.DataBufferPtrLow);
+ }
+ } else {
+
+ CurDesc.word2.bits.length_in_bytes =
+ pFragList[fragIndex - 1].size;
+ CurDesc.DataBufferPtrLow =
+ pci_map_page(pAdapter->pdev,
+ pFragList[fragIndex - 1].page,
+ pFragList[fragIndex -
+ 1].page_offset,
+ pFragList[fragIndex - 1].size,
+ PCI_DMA_TODEVICE);
+ DBG_TX(et131x_dbginfo,
+ "pci_map_page() returns: 0x%08x\n",
+ CurDesc.DataBufferPtrLow);
+ }
+
+ if (loopIndex == 0) {
+ /* This is the first descriptor of the packet
+ *
+ * Set the "f" bit to indicate this is the
+ * first descriptor in the packet.
+ */
+ DBG_TX(et131x_dbginfo,
+ "This is our FIRST descriptor\n");
+ CurDesc.word3.bits.f = 1;
+
+ pMpTcb->WrIndexStart =
+ pAdapter->TxRing.txDmaReadyToSend;
+ }
+
+ if ((loopIndex == (loopEnd - 1)) &&
+ (pAdapter->uiDuplexMode ||
+ (pMpTcb->PacketLength >= NIC_MIN_PACKET_SIZE))) {
+ /* This is the Last descriptor of the packet */
+ DBG_TX(et131x_dbginfo,
+ "THIS is our LAST descriptor\n");
+
+ if (pAdapter->uiLinkSpeed ==
+ TRUEPHY_SPEED_1000MBPS) {
+ if (++pAdapter->TxRing.
+ TxPacketsSinceLastinterrupt >=
+ pAdapter->RegistryTxNumBuffers) {
+ CurDesc.word3.value = 0x5;
+ pAdapter->TxRing.
+ TxPacketsSinceLastinterrupt
+ = 0;
+ } else {
+ CurDesc.word3.value = 0x1;
+ }
+ } else {
+ CurDesc.word3.value = 0x5;
+ }
+
+ /* Following index will be used during freeing
+ * of packet
+ */
+ pMpTcb->WrIndex =
+ pAdapter->TxRing.txDmaReadyToSend;
+ pMpTcb->PacketStaleCount = 0;
+ }
+
+ /* Copy the descriptor (filled above) into the
+ * descriptor ring at the next free entry. Advance
+ * the "next free entry" variable
+ */
+ memcpy(pAdapter->TxRing.pTxDescRingVa +
+ pAdapter->TxRing.txDmaReadyToSend.bits.serv_req,
+ &CurDesc, sizeof(TX_DESC_ENTRY_t));
+
+ CurDescPostCopy =
+ pAdapter->TxRing.pTxDescRingVa +
+ pAdapter->TxRing.txDmaReadyToSend.bits.serv_req;
+
+ DBG_TX(et131x_dbginfo,
+ "CURRENT DESCRIPTOR\n"
+ "\tAddress : 0x%p\n"
+ "\tDataBufferPtrHigh : 0x%08x\n"
+ "\tDataBufferPtrLow : 0x%08x\n"
+ "\tword2 : 0x%08x\n"
+ "\tword3 : 0x%08x\n",
+ CurDescPostCopy,
+ CurDescPostCopy->DataBufferPtrHigh,
+ CurDescPostCopy->DataBufferPtrLow,
+ CurDescPostCopy->word2.value,
+ CurDescPostCopy->word3.value);
+
+ if (++pAdapter->TxRing.txDmaReadyToSend.bits.serv_req >=
+ NUM_DESC_PER_RING_TX) {
+ if (pAdapter->TxRing.txDmaReadyToSend.bits.
+ serv_req_wrap) {
+ pAdapter->TxRing.txDmaReadyToSend.
+ value = 0;
+ } else {
+ pAdapter->TxRing.txDmaReadyToSend.
+ value = 0x400;
+ }
+ }
+ }
+ }
+
+ if (pAdapter->uiDuplexMode == 0 &&
+ pMpTcb->PacketLength < NIC_MIN_PACKET_SIZE) {
+ // NOTE - Same 32/64-bit issue as above...
+ CurDesc.DataBufferPtrHigh = 0x0;
+ CurDesc.DataBufferPtrLow = pAdapter->TxRing.pTxDummyBlkPa;
+ CurDesc.word2.value = 0;
+
+ if (pAdapter->uiLinkSpeed == TRUEPHY_SPEED_1000MBPS) {
+ if (++pAdapter->TxRing.TxPacketsSinceLastinterrupt >=
+ pAdapter->RegistryTxNumBuffers) {
+ CurDesc.word3.value = 0x5;
+ pAdapter->TxRing.TxPacketsSinceLastinterrupt =
+ 0;
+ } else {
+ CurDesc.word3.value = 0x1;
+ }
+ } else {
+ CurDesc.word3.value = 0x5;
+ }
+
+ CurDesc.word2.bits.length_in_bytes =
+ NIC_MIN_PACKET_SIZE - pMpTcb->PacketLength;
+
+ pMpTcb->WrIndex = pAdapter->TxRing.txDmaReadyToSend;
+
+ memcpy(pAdapter->TxRing.pTxDescRingVa +
+ pAdapter->TxRing.txDmaReadyToSend.bits.serv_req,
+ &CurDesc, sizeof(TX_DESC_ENTRY_t));
+
+ CurDescPostCopy =
+ pAdapter->TxRing.pTxDescRingVa +
+ pAdapter->TxRing.txDmaReadyToSend.bits.serv_req;
+
+ DBG_TX(et131x_dbginfo,
+ "CURRENT DESCRIPTOR\n"
+ "\tAddress : 0x%p\n"
+ "\tDataBufferPtrHigh : 0x%08x\n"
+ "\tDataBufferPtrLow : 0x%08x\n"
+ "\tword2 : 0x%08x\n"
+ "\tword3 : 0x%08x\n",
+ CurDescPostCopy,
+ CurDescPostCopy->DataBufferPtrHigh,
+ CurDescPostCopy->DataBufferPtrLow,
+ CurDescPostCopy->word2.value,
+ CurDescPostCopy->word3.value);
+
+ if (++pAdapter->TxRing.txDmaReadyToSend.bits.serv_req >=
+ NUM_DESC_PER_RING_TX) {
+ if (pAdapter->TxRing.txDmaReadyToSend.bits.
+ serv_req_wrap) {
+ pAdapter->TxRing.txDmaReadyToSend.value = 0;
+ } else {
+ pAdapter->TxRing.txDmaReadyToSend.value = 0x400;
+ }
+ }
+
+ DBG_TX(et131x_dbginfo, "Padding descriptor %d by %d bytes\n",
+ //pAdapter->TxRing.txDmaReadyToSend.value,
+ pAdapter->TxRing.txDmaReadyToSend.bits.serv_req,
+ NIC_MIN_PACKET_SIZE - pMpTcb->PacketLength);
+ }
+
+ spin_lock_irqsave(&pAdapter->TCBSendQLock, lockflags2);
+
+ if (pAdapter->TxRing.CurrSendTail) {
+ pAdapter->TxRing.CurrSendTail->Next = pMpTcb;
+ } else {
+ pAdapter->TxRing.CurrSendHead = pMpTcb;
+ }
+
+ pAdapter->TxRing.CurrSendTail = pMpTcb;
+
+ DBG_ASSERT(pMpTcb->Next == NULL);
+
+ pAdapter->TxRing.nBusySend++;
+
+ spin_unlock_irqrestore(&pAdapter->TCBSendQLock, lockflags2);
+
+ /* Write the new write pointer back to the device. */
+ writel(pAdapter->TxRing.txDmaReadyToSend.value,
+ &pAdapter->CSRAddress->txdma.service_request.value);
+
+#ifdef CONFIG_ET131X_DEBUG
+ DumpDeviceBlock(DBG_TX_ON, pAdapter, 1);
+#endif
+
+ /* For Gig only, we use Tx Interrupt coalescing. Enable the software
+ * timer to wake us up if this packet isn't followed by N more.
+ */
+ if (pAdapter->uiLinkSpeed == TRUEPHY_SPEED_1000MBPS) {
+ writel(pAdapter->RegistryTxTimeInterval * NANO_IN_A_MICRO,
+ &pAdapter->CSRAddress->global.watchdog_timer);
+ }
+
+ spin_unlock_irqrestore(&pAdapter->SendHWLock, lockflags1);
+
+ DBG_TX_LEAVE(et131x_dbginfo);
+ return 0;
+}
+
+#endif
+
+/**
+ * et131x_free_send_packet - Recycle a MP_TCB, complete the packet if necessary
+ * @pAdapter: pointer to our adapter
+ * @pMpTcb: pointer to MP_TCB
+ *
+ * Assumption - Send spinlock has been acquired
+ */
+__inline void et131x_free_send_packet(struct et131x_adapter *pAdapter, PMP_TCB pMpTcb)
+{
+ unsigned long lockflags;
+ TX_DESC_ENTRY_t *desc = NULL;
+ struct net_device_stats *stats = &pAdapter->net_stats;
+
+ if (MP_TEST_FLAG(pMpTcb, fMP_DEST_BROAD)) {
+ atomic_inc(&pAdapter->Stats.brdcstxmt);
+ } else if (MP_TEST_FLAG(pMpTcb, fMP_DEST_MULTI)) {
+ atomic_inc(&pAdapter->Stats.multixmt);
+ } else {
+ atomic_inc(&pAdapter->Stats.unixmt);
+ }
+
+ if (pMpTcb->Packet) {
+ stats->tx_bytes += pMpTcb->Packet->len;
+
+ /* Iterate through the TX descriptors on the ring
+ * corresponding to this packet and umap the fragments
+ * they point to
+ */
+ DBG_TX(et131x_dbginfo,
+ "Unmap descriptors Here\n"
+ "TCB : 0x%p\n"
+ "TCB Next : 0x%p\n"
+ "TCB PacketLength : %d\n"
+ "TCB WrIndex.value : 0x%08x\n"
+ "TCB WrIndex.bits.val : %d\n"
+ "TCB WrIndex.value : 0x%08x\n"
+ "TCB WrIndex.bits.val : %d\n",
+ pMpTcb,
+ pMpTcb->Next,
+ pMpTcb->PacketLength,
+ pMpTcb->WrIndexStart.value,
+ pMpTcb->WrIndexStart.bits.val,
+ pMpTcb->WrIndex.value,
+ pMpTcb->WrIndex.bits.val);
+
+ do {
+ desc =
+ (TX_DESC_ENTRY_t *) (pAdapter->TxRing.
+ pTxDescRingVa +
+ pMpTcb->WrIndexStart.bits.val);
+
+ DBG_TX(et131x_dbginfo,
+ "CURRENT DESCRIPTOR\n"
+ "\tAddress : 0x%p\n"
+ "\tDataBufferPtrHigh : 0x%08x\n"
+ "\tDataBufferPtrLow : 0x%08x\n"
+ "\tword2 : 0x%08x\n"
+ "\tword3 : 0x%08x\n",
+ desc,
+ desc->DataBufferPtrHigh,
+ desc->DataBufferPtrLow,
+ desc->word2.value,
+ desc->word3.value);
+
+ pci_unmap_single(pAdapter->pdev,
+ desc->DataBufferPtrLow,
+ desc->word2.value, PCI_DMA_TODEVICE);
+
+ if (++pMpTcb->WrIndexStart.bits.val >=
+ NUM_DESC_PER_RING_TX) {
+ if (pMpTcb->WrIndexStart.bits.wrap) {
+ pMpTcb->WrIndexStart.value = 0;
+ } else {
+ pMpTcb->WrIndexStart.value = 0x400;
+ }
+ }
+ }
+ while (desc != (pAdapter->TxRing.pTxDescRingVa +
+ pMpTcb->WrIndex.bits.val));
+
+ DBG_TX(et131x_dbginfo,
+ "Free Packet (SKB) : 0x%p\n", pMpTcb->Packet);
+
+ dev_kfree_skb_any(pMpTcb->Packet);
+ }
+
+ memset(pMpTcb, 0, sizeof(MP_TCB));
+
+ /* Add the TCB to the Ready Q */
+ spin_lock_irqsave(&pAdapter->TCBReadyQLock, lockflags);
+
+ pAdapter->Stats.opackets++;
+
+ if (pAdapter->TxRing.TCBReadyQueueTail) {
+ pAdapter->TxRing.TCBReadyQueueTail->Next = pMpTcb;
+ } else {
+ /* Apparently ready Q is empty. */
+ pAdapter->TxRing.TCBReadyQueueHead = pMpTcb;
+ }
+
+ pAdapter->TxRing.TCBReadyQueueTail = pMpTcb;
+
+ spin_unlock_irqrestore(&pAdapter->TCBReadyQLock, lockflags);
+
+ DBG_ASSERT(pAdapter->TxRing.nBusySend >= 0);
+}
+
+/**
+ * et131x_free_busy_send_packets - Free and complete the stopped active sends
+ * @pAdapter: pointer to our adapter
+ *
+ * Assumption - Send spinlock has been acquired
+ */
+void et131x_free_busy_send_packets(struct et131x_adapter *pAdapter)
+{
+ PMP_TCB pMpTcb;
+ struct list_head *pEntry;
+ struct sk_buff *pPacket = NULL;
+ unsigned long lockflags;
+ uint32_t FreeCounter = 0;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ while (!list_empty(&pAdapter->TxRing.SendWaitQueue)) {
+ spin_lock_irqsave(&pAdapter->SendWaitLock, lockflags);
+
+ pAdapter->TxRing.nWaitSend--;
+ spin_unlock_irqrestore(&pAdapter->SendWaitLock, lockflags);
+
+ pEntry = pAdapter->TxRing.SendWaitQueue.next;
+
+ pPacket = NULL;
+ }
+
+ pAdapter->TxRing.nWaitSend = 0;
+
+ /* Any packets being sent? Check the first TCB on the send list */
+ spin_lock_irqsave(&pAdapter->TCBSendQLock, lockflags);
+
+ pMpTcb = pAdapter->TxRing.CurrSendHead;
+
+ while ((pMpTcb != NULL) && (FreeCounter < NUM_TCB)) {
+ PMP_TCB pNext = pMpTcb->Next;
+
+ pAdapter->TxRing.CurrSendHead = pNext;
+
+ if (pNext == NULL) {
+ pAdapter->TxRing.CurrSendTail = NULL;
+ }
+
+ pAdapter->TxRing.nBusySend--;
+
+ spin_unlock_irqrestore(&pAdapter->TCBSendQLock, lockflags);
+
+ DBG_VERBOSE(et131x_dbginfo, "pMpTcb = 0x%p\n", pMpTcb);
+
+ FreeCounter++;
+ MP_FREE_SEND_PACKET_FUN(pAdapter, pMpTcb);
+
+ spin_lock_irqsave(&pAdapter->TCBSendQLock, lockflags);
+
+ pMpTcb = pAdapter->TxRing.CurrSendHead;
+ }
+
+ if (FreeCounter == NUM_TCB) {
+ DBG_ERROR(et131x_dbginfo,
+ "MpFreeBusySendPackets exitted loop for a bad reason\n");
+ BUG();
+ }
+
+ spin_unlock_irqrestore(&pAdapter->TCBSendQLock, lockflags);
+
+ pAdapter->TxRing.nBusySend = 0;
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * et131x_handle_send_interrupt - Interrupt handler for sending processing
+ * @pAdapter: pointer to our adapter
+ *
+ * Re-claim the send resources, complete sends and get more to send from
+ * the send wait queue.
+ *
+ * Assumption - Send spinlock has been acquired
+ */
+void et131x_handle_send_interrupt(struct et131x_adapter *pAdapter)
+{
+ DBG_TX_ENTER(et131x_dbginfo);
+
+ /* Mark as completed any packets which have been sent by the device. */
+ et131x_update_tcb_list(pAdapter);
+
+ /* If we queued any transmits because we didn't have any TCBs earlier,
+ * dequeue and send those packets now, as long as we have free TCBs.
+ */
+ et131x_check_send_wait_list(pAdapter);
+
+ DBG_TX_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * et131x_update_tcb_list - Helper routine for Send Interrupt handler
+ * @pAdapter: pointer to our adapter
+ *
+ * Re-claims the send resources and completes sends. Can also be called as
+ * part of the NIC send routine when the "ServiceComplete" indication has
+ * wrapped.
+ */
+static void et131x_update_tcb_list(struct et131x_adapter *pAdapter)
+{
+ unsigned long lockflags;
+ DMA10W_t ServiceComplete;
+ PMP_TCB pMpTcb;
+
+ ServiceComplete.value =
+ readl(&pAdapter->CSRAddress->txdma.NewServiceComplete.value);
+
+ /* Has the ring wrapped? Process any descriptors that do not have
+ * the same "wrap" indicator as the current completion indicator
+ */
+ spin_lock_irqsave(&pAdapter->TCBSendQLock, lockflags);
+
+ pMpTcb = pAdapter->TxRing.CurrSendHead;
+ while (pMpTcb &&
+ ServiceComplete.bits.wrap != pMpTcb->WrIndex.bits.wrap &&
+ ServiceComplete.bits.val < pMpTcb->WrIndex.bits.val) {
+ pAdapter->TxRing.nBusySend--;
+ pAdapter->TxRing.CurrSendHead = pMpTcb->Next;
+ if (pMpTcb->Next == NULL) {
+ pAdapter->TxRing.CurrSendTail = NULL;
+ }
+
+ spin_unlock_irqrestore(&pAdapter->TCBSendQLock, lockflags);
+ MP_FREE_SEND_PACKET_FUN(pAdapter, pMpTcb);
+ spin_lock_irqsave(&pAdapter->TCBSendQLock, lockflags);
+
+ /* Goto the next packet */
+ pMpTcb = pAdapter->TxRing.CurrSendHead;
+ }
+ while (pMpTcb &&
+ ServiceComplete.bits.wrap == pMpTcb->WrIndex.bits.wrap &&
+ ServiceComplete.bits.val > pMpTcb->WrIndex.bits.val) {
+ pAdapter->TxRing.nBusySend--;
+ pAdapter->TxRing.CurrSendHead = pMpTcb->Next;
+ if (pMpTcb->Next == NULL) {
+ pAdapter->TxRing.CurrSendTail = NULL;
+ }
+
+ spin_unlock_irqrestore(&pAdapter->TCBSendQLock, lockflags);
+ MP_FREE_SEND_PACKET_FUN(pAdapter, pMpTcb);
+ spin_lock_irqsave(&pAdapter->TCBSendQLock, lockflags);
+
+ /* Goto the next packet */
+ pMpTcb = pAdapter->TxRing.CurrSendHead;
+ }
+
+ /* Wake up the queue when we hit a low-water mark */
+ if (pAdapter->TxRing.nBusySend <= (NUM_TCB / 3)) {
+ netif_wake_queue(pAdapter->netdev);
+ }
+
+ spin_unlock_irqrestore(&pAdapter->TCBSendQLock, lockflags);
+}
+
+/**
+ * et131x_check_send_wait_list - Helper routine for the interrupt handler
+ * @pAdapter: pointer to our adapter
+ *
+ * Takes packets from the send wait queue and posts them to the device (if
+ * room available).
+ */
+static void et131x_check_send_wait_list(struct et131x_adapter *pAdapter)
+{
+ unsigned long lockflags;
+
+ spin_lock_irqsave(&pAdapter->SendWaitLock, lockflags);
+
+ while (!list_empty(&pAdapter->TxRing.SendWaitQueue) &&
+ MP_TCB_RESOURCES_AVAILABLE(pAdapter)) {
+ struct list_head *pEntry;
+
+ DBG_VERBOSE(et131x_dbginfo, "Tx packets on the wait queue\n");
+
+ pEntry = pAdapter->TxRing.SendWaitQueue.next;
+
+ pAdapter->TxRing.nWaitSend--;
+
+ DBG_WARNING(et131x_dbginfo,
+ "MpHandleSendInterrupt - sent a queued pkt. Waiting %d\n",
+ pAdapter->TxRing.nWaitSend);
+ }
+
+ spin_unlock_irqrestore(&pAdapter->SendWaitLock, lockflags);
+}
diff --git a/drivers/staging/et131x/et1310_tx.h b/drivers/staging/et131x/et1310_tx.h
new file mode 100644
index 0000000..2819c78
--- /dev/null
+++ b/drivers/staging/et131x/et1310_tx.h
@@ -0,0 +1,242 @@
+/*
+ * Agere Systems Inc.
+ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * et1310_tx.h - Defines, structs, enums, prototypes, etc. pertaining to data
+ * transmission.
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#ifndef __ET1310_TX_H__
+#define __ET1310_TX_H__
+
+
+/* Typedefs for Tx Descriptor Ring */
+
+/*
+ * TXDESC_WORD2_t structure holds part of the control bits in the Tx Descriptor
+ * ring for the ET-1310
+ */
+typedef union _txdesc_word2_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 vlan_prio:3; // bits 29-31(VLAN priority)
+ u32 vlan_cfi:1; // bit 28(cfi)
+ u32 vlan_tag:12; // bits 16-27(VLAN tag)
+ u32 length_in_bytes:16; // bits 0-15(packet length)
+#else
+ u32 length_in_bytes:16; // bits 0-15(packet length)
+ u32 vlan_tag:12; // bits 16-27(VLAN tag)
+ u32 vlan_cfi:1; // bit 28(cfi)
+ u32 vlan_prio:3; // bits 29-31(VLAN priority)
+#endif /* _BIT_FIELDS_HTOL */
+ } bits;
+} TXDESC_WORD2_t, *PTXDESC_WORD2_t;
+
+/*
+ * TXDESC_WORD3_t structure holds part of the control bits in the Tx Descriptor
+ * ring for the ET-1310
+ */
+typedef union _txdesc_word3_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused:17; // bits 15-31
+ u32 udpa:1; // bit 14(UDP checksum assist)
+ u32 tcpa:1; // bit 13(TCP checksum assist)
+ u32 ipa:1; // bit 12(IP checksum assist)
+ u32 vlan:1; // bit 11(append VLAN tag)
+ u32 hp:1; // bit 10(Packet is a Huge packet)
+ u32 pp:1; // bit 9(pad packet)
+ u32 mac:1; // bit 8(MAC override)
+ u32 crc:1; // bit 7(append CRC)
+ u32 e:1; // bit 6(Tx frame has error)
+ u32 pf:1; // bit 5(send pause frame)
+ u32 bp:1; // bit 4(Issue half-duplex backpressure (XON/XOFF)
+ u32 cw:1; // bit 3(Control word - no packet data)
+ u32 ir:1; // bit 2(interrupt the processor when this pkt sent)
+ u32 f:1; // bit 1(first packet in the sequence)
+ u32 l:1; // bit 0(last packet in the sequence)
+#else
+ u32 l:1; // bit 0(last packet in the sequence)
+ u32 f:1; // bit 1(first packet in the sequence)
+ u32 ir:1; // bit 2(interrupt the processor when this pkt sent)
+ u32 cw:1; // bit 3(Control word - no packet data)
+ u32 bp:1; // bit 4(Issue half-duplex backpressure (XON/XOFF)
+ u32 pf:1; // bit 5(send pause frame)
+ u32 e:1; // bit 6(Tx frame has error)
+ u32 crc:1; // bit 7(append CRC)
+ u32 mac:1; // bit 8(MAC override)
+ u32 pp:1; // bit 9(pad packet)
+ u32 hp:1; // bit 10(Packet is a Huge packet)
+ u32 vlan:1; // bit 11(append VLAN tag)
+ u32 ipa:1; // bit 12(IP checksum assist)
+ u32 tcpa:1; // bit 13(TCP checksum assist)
+ u32 udpa:1; // bit 14(UDP checksum assist)
+ u32 unused:17; // bits 15-31
+#endif /* _BIT_FIELDS_HTOL */
+ } bits;
+} TXDESC_WORD3_t, *PTXDESC_WORD3_t;
+
+/* TX_DESC_ENTRY_t is sructure representing each descriptor on the ring */
+typedef struct _tx_desc_entry_t {
+ u32 DataBufferPtrHigh;
+ u32 DataBufferPtrLow;
+ TXDESC_WORD2_t word2; // control words how to xmit the
+ TXDESC_WORD3_t word3; // data (detailed above)
+} TX_DESC_ENTRY_t, *PTX_DESC_ENTRY_t;
+
+
+/* Typedefs for Tx DMA engine status writeback */
+
+/*
+ * TX_STATUS_BLOCK_t is sructure representing the status of the Tx DMA engine
+ * it sits in free memory, and is pointed to by 0x101c / 0x1020
+ */
+typedef union _tx_status_block_t {
+ u32 value;
+ struct {
+#ifdef _BIT_FIELDS_HTOL
+ u32 unused:21; // bits 11-31
+ u32 serv_cpl_wrap:1; // bit 10
+ u32 serv_cpl:10; // bits 0-9
+#else
+ u32 serv_cpl:10; // bits 0-9
+ u32 serv_cpl_wrap:1; // bit 10
+ u32 unused:21; // bits 11-31
+#endif
+ } bits;
+} TX_STATUS_BLOCK_t, *PTX_STATUS_BLOCK_t;
+
+/* TCB (Transmit Control Block) */
+typedef struct _MP_TCB {
+ struct _MP_TCB *Next;
+ u32 Flags;
+ u32 Count;
+ u32 PacketStaleCount;
+ struct sk_buff *Packet;
+ u32 PacketLength;
+ DMA10W_t WrIndex;
+ DMA10W_t WrIndexStart;
+} MP_TCB, *PMP_TCB;
+
+/* Structure to hold the skb's in a list */
+typedef struct tx_skb_list_elem {
+ struct list_head skb_list_elem;
+ struct sk_buff *skb;
+} TX_SKB_LIST_ELEM, *PTX_SKB_LIST_ELEM;
+
+/* TX_RING_t is sructure representing our local reference(s) to the ring */
+typedef struct _tx_ring_t {
+ /* TCB (Transmit Control Block) memory and lists */
+ PMP_TCB MpTcbMem;
+
+ /* List of TCBs that are ready to be used */
+ PMP_TCB TCBReadyQueueHead;
+ PMP_TCB TCBReadyQueueTail;
+
+ /* list of TCBs that are currently being sent. NOTE that access to all
+ * three of these (including nBusySend) are controlled via the
+ * TCBSendQLock. This lock should be secured prior to incementing /
+ * decrementing nBusySend, or any queue manipulation on CurrSendHead /
+ * Tail
+ */
+ PMP_TCB CurrSendHead;
+ PMP_TCB CurrSendTail;
+ int32_t nBusySend;
+
+ /* List of packets (not TCBs) that were queued for lack of resources */
+ struct list_head SendWaitQueue;
+ int32_t nWaitSend;
+
+ /* The actual descriptor ring */
+ PTX_DESC_ENTRY_t pTxDescRingVa;
+ dma_addr_t pTxDescRingPa;
+ uint64_t pTxDescRingAdjustedPa;
+ uint64_t TxDescOffset;
+
+ /* ReadyToSend indicates where we last wrote to in the descriptor ring. */
+ DMA10W_t txDmaReadyToSend;
+
+ /* The location of the write-back status block */
+ PTX_STATUS_BLOCK_t pTxStatusVa;
+ dma_addr_t pTxStatusPa;
+
+ /* A Block of zeroes used to pad packets that are less than 60 bytes */
+ void *pTxDummyBlkVa;
+ dma_addr_t pTxDummyBlkPa;
+
+ TXMAC_ERR_t TxMacErr;
+
+ /* Variables to track the Tx interrupt coalescing features */
+ int32_t TxPacketsSinceLastinterrupt;
+} TX_RING_t, *PTX_RING_t;
+
+/* Forward declaration of the frag-list for the following prototypes */
+typedef struct _MP_FRAG_LIST MP_FRAG_LIST, *PMP_FRAG_LIST;
+
+/* Forward declaration of the private adapter structure */
+struct et131x_adapter;
+
+/* PROTOTYPES for et1310_tx.c */
+int et131x_tx_dma_memory_alloc(struct et131x_adapter *adapter);
+void et131x_tx_dma_memory_free(struct et131x_adapter *adapter);
+void ConfigTxDmaRegs(struct et131x_adapter *pAdapter);
+void et131x_init_send(struct et131x_adapter *adapter);
+void et131x_tx_dma_disable(struct et131x_adapter *pAdapter);
+void et131x_tx_dma_enable(struct et131x_adapter *pAdapter);
+void et131x_handle_send_interrupt(struct et131x_adapter *pAdapter);
+void et131x_free_busy_send_packets(struct et131x_adapter *pAdapter);
+int et131x_send_packets(struct sk_buff *skb, struct net_device *netdev);
+
+#endif /* __ET1310_TX_H__ */
diff --git a/drivers/staging/et131x/et131x_adapter.h b/drivers/staging/et131x/et131x_adapter.h
new file mode 100644
index 0000000..36e61a4
--- /dev/null
+++ b/drivers/staging/et131x/et131x_adapter.h
@@ -0,0 +1,347 @@
+/*
+ * Agere Systems Inc.
+ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * et131x_adapter.h - Header which includes the private adapter structure, along
+ * with related support structures, macros, definitions, etc.
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#ifndef __ET131X_ADAPTER_H__
+#define __ET131X_ADAPTER_H__
+
+#include "et1310_address_map.h"
+#include "et1310_tx.h"
+#include "et1310_rx.h"
+
+/*
+ * Do not change these values: if changed, then change also in respective
+ * TXdma and Rxdma engines
+ */
+#define NUM_DESC_PER_RING_TX 512 // TX Do not change these values
+#define NUM_TCB 64
+
+/*
+ * These values are all superseded by registry entries to facilitate tuning.
+ * Once the desired performance has been achieved, the optimal registry values
+ * should be re-populated to these #defines:
+ */
+#define NUM_TRAFFIC_CLASSES 1
+
+/*
+ * There are three ways of counting errors - if there are more than X errors
+ * in Y packets (represented by the "SAMPLE" macros), if there are more than
+ * N errors in a S mSec time period (the "PERIOD" macros), or if there are
+ * consecutive packets with errors (CONSEC_ERRORED_THRESH). This last covers
+ * for "Bursty" errors, and the errored packets may well not be contiguous,
+ * but several errors where the packet counter has changed by less than a
+ * small amount will cause this count to increment.
+ */
+#define TX_PACKETS_IN_SAMPLE 10000
+#define TX_MAX_ERRORS_IN_SAMPLE 50
+
+#define TX_ERROR_PERIOD 1000
+#define TX_MAX_ERRORS_IN_PERIOD 10
+
+#define LINK_DETECTION_TIMER 5000
+
+#define TX_CONSEC_RANGE 5
+#define TX_CONSEC_ERRORED_THRESH 10
+
+#define LO_MARK_PERCENT_FOR_PSR 15
+#define LO_MARK_PERCENT_FOR_RX 15
+
+/* Macros for flag and ref count operations */
+#define MP_SET_FLAG(_M, _F) ((_M)->Flags |= (_F))
+#define MP_CLEAR_FLAG(_M, _F) ((_M)->Flags &= ~(_F))
+#define MP_CLEAR_FLAGS(_M) ((_M)->Flags = 0)
+#define MP_TEST_FLAG(_M, _F) (((_M)->Flags & (_F)) != 0)
+#define MP_TEST_FLAGS(_M, _F) (((_M)->Flags & (_F)) == (_F))
+#define MP_IS_FLAG_CLEAR(_M, _F) (((_M)->Flags & (_F)) == 0)
+
+#define MP_INC_RCV_REF(_A) atomic_inc(&(_A)->RcvRefCount)
+#define MP_DEC_RCV_REF(_A) atomic_dec(&(_A)->RcvRefCount)
+#define MP_GET_RCV_REF(_A) atomic_read(&(_A)->RcvRefCount)
+
+/* Macros specific to the private adapter structure */
+#define MP_TCB_RESOURCES_AVAILABLE(_M) ((_M)->TxRing.nBusySend < NUM_TCB)
+#define MP_TCB_RESOURCES_NOT_AVAILABLE(_M) ((_M)->TxRing.nBusySend >= NUM_TCB)
+
+#define MP_SHOULD_FAIL_SEND(_M) ((_M)->Flags & fMP_ADAPTER_FAIL_SEND_MASK)
+#define MP_IS_NOT_READY(_M) ((_M)->Flags & fMP_ADAPTER_NOT_READY_MASK)
+#define MP_IS_READY(_M) !((_M)->Flags & fMP_ADAPTER_NOT_READY_MASK)
+
+#define MP_HAS_CABLE(_M) !((_M)->Flags & fMP_ADAPTER_NO_CABLE)
+#define MP_LINK_DETECTED(_M) !((_M)->Flags & fMP_ADAPTER_LINK_DETECTION)
+
+/* Counters for error rate monitoring */
+typedef struct _MP_ERR_COUNTERS {
+ u32 PktCountTxPackets;
+ u32 PktCountTxErrors;
+ u32 TimerBasedTxErrors;
+ u32 PktCountLastError;
+ u32 ErredConsecPackets;
+} MP_ERR_COUNTERS, *PMP_ERR_COUNTERS;
+
+/* RFD (Receive Frame Descriptor) */
+typedef struct _MP_RFD {
+ struct list_head list_node;
+ struct sk_buff *Packet;
+ u32 PacketSize; // total size of receive frame
+ u16 iBufferIndex;
+ u8 iRingIndex;
+} MP_RFD, *PMP_RFD;
+
+/* Enum for Flow Control */
+typedef enum _eflow_control_t {
+ Both = 0,
+ TxOnly = 1,
+ RxOnly = 2,
+ None = 3
+} eFLOW_CONTROL_t, *PeFLOW_CONTROL_t;
+
+/* Struct to define some device statistics */
+typedef struct _ce_stats_t {
+ /* Link Input/Output stats */
+ uint64_t ipackets; // # of in packets
+ uint64_t opackets; // # of out packets
+
+ /* MIB II variables
+ *
+ * NOTE: atomic_t types are only guaranteed to store 24-bits; if we
+ * MUST have 32, then we'll need another way to perform atomic
+ * operations
+ */
+ u32 unircv; // # multicast packets received
+ atomic_t unixmt; // # multicast packets for Tx
+ u32 multircv; // # multicast packets received
+ atomic_t multixmt; // # multicast packets for Tx
+ u32 brdcstrcv; // # broadcast packets received
+ atomic_t brdcstxmt; // # broadcast packets for Tx
+ u32 norcvbuf; // # Rx packets discarded
+ u32 noxmtbuf; // # Tx packets discarded
+
+ /* Transciever state informations. */
+ u8 xcvr_addr;
+ u32 xcvr_id;
+
+ /* Tx Statistics. */
+ u32 tx_uflo; // Tx Underruns
+
+ u32 collisions;
+ u32 excessive_collisions;
+ u32 first_collision;
+ u32 late_collisions;
+ u32 max_pkt_error;
+ u32 tx_deferred;
+
+ /* Rx Statistics. */
+ u32 rx_ov_flow; // Rx Over Flow
+
+ u32 length_err;
+ u32 alignment_err;
+ u32 crc_err;
+ u32 code_violations;
+ u32 other_errors;
+
+#ifdef CONFIG_ET131X_DEBUG
+ u32 UnhandledInterruptsPerSec;
+ u32 RxDmaInterruptsPerSec;
+ u32 TxDmaInterruptsPerSec;
+ u32 WatchDogInterruptsPerSec;
+#endif /* CONFIG_ET131X_DEBUG */
+
+ u32 SynchrounousIterations;
+ INTERRUPT_t InterruptStatus;
+} CE_STATS_t, *PCE_STATS_t;
+
+/* The private adapter structure */
+struct et131x_adapter {
+ struct net_device *netdev;
+ struct pci_dev *pdev;
+
+ struct work_struct task;
+
+ /* Flags that indicate current state of the adapter */
+ u32 Flags;
+ u32 HwErrCount;
+
+ /* Configuration */
+ u8 PermanentAddress[ETH_ALEN];
+ u8 CurrentAddress[ETH_ALEN];
+ bool bOverrideAddress;
+ bool bEepromPresent;
+ u8 eepromData[2];
+
+ /* Spinlocks */
+ spinlock_t Lock;
+
+ spinlock_t TCBSendQLock;
+ spinlock_t TCBReadyQLock;
+ spinlock_t SendHWLock;
+ spinlock_t SendWaitLock;
+
+ spinlock_t RcvLock;
+ spinlock_t RcvPendLock;
+ spinlock_t FbrLock;
+
+ spinlock_t PHYLock;
+
+ /* Packet Filter and look ahead size */
+ u32 PacketFilter;
+ u32 ulLookAhead;
+ u32 uiLinkSpeed;
+ u32 uiDuplexMode;
+ u32 uiAutoNegStatus;
+ u8 ucLinkStatus;
+
+ /* multicast list */
+ u32 MCAddressCount;
+ u8 MCList[NIC_MAX_MCAST_LIST][ETH_ALEN];
+
+ /* MAC test */
+ TXMAC_TXTEST_t TxMacTest;
+
+ /* Pointer to the device's PCI register space */
+ ADDRESS_MAP_t __iomem *CSRAddress;
+
+ /* PCI config space info, for debug purposes only. */
+ u8 RevisionID;
+ u16 VendorID;
+ u16 DeviceID;
+ u16 SubVendorID;
+ u16 SubSystemID;
+ u32 CacheFillSize;
+ u16 PciXDevCtl;
+ u8 pci_lat_timer;
+ u8 pci_hdr_type;
+ u8 pci_bist;
+ u32 pci_cfg_state[64 / sizeof(u32)];
+
+ /* Registry parameters */
+ u8 SpeedDuplex; // speed/duplex
+ eFLOW_CONTROL_t RegistryFlowControl; // for 802.3x flow control
+ u8 RegistryWOLMatch; // Enable WOL pattern-matching
+ u8 RegistryWOLLink; // Link state change is independant
+ u8 RegistryPhyComa; // Phy Coma mode enable/disable
+
+ u32 RegistryRxMemEnd; // Size of internal rx memory
+ u8 RegistryMACStat; // If set, read MACSTAT, else don't
+ u32 RegistryVlanTag; // 802.1q Vlan TAG
+ u32 RegistryJumboPacket; // Max supported ethernet packet size
+
+ u32 RegistryTxNumBuffers;
+ u32 RegistryTxTimeInterval;
+
+ u32 RegistryRxNumBuffers;
+ u32 RegistryRxTimeInterval;
+
+ /* Validation helpers */
+ u8 RegistryPMWOL;
+ u8 RegistryNMIDisable;
+ u32 RegistryDMACache;
+ u32 RegistrySCGain;
+ u8 RegistryPhyLoopbk; // Enable Phy loopback
+
+ /* Derived from the registry: */
+ u8 AiForceDpx; // duplex setting
+ u16 AiForceSpeed; // 'Speed', user over-ride of line speed
+ eFLOW_CONTROL_t FlowControl; // flow control validated by the far-end
+ enum {
+ NETIF_STATUS_INVALID = 0,
+ NETIF_STATUS_MEDIA_CONNECT,
+ NETIF_STATUS_MEDIA_DISCONNECT,
+ NETIF_STATUS_MAX
+ } MediaState;
+ u8 DriverNoPhyAccess;
+
+ /* Minimize init-time */
+ bool bQueryPending;
+ bool bSetPending;
+ bool bResetPending;
+ struct timer_list ErrorTimer;
+ bool bLinkTimerActive;
+ MP_POWER_MGMT PoMgmt;
+ INTERRUPT_t CachedMaskValue;
+
+ atomic_t RcvRefCount; // Num packets not yet returned
+
+ /* Xcvr status at last poll */
+ MI_BMSR_t Bmsr;
+
+ /* Tx Memory Variables */
+ TX_RING_t TxRing;
+
+ /* Rx Memory Variables */
+ RX_RING_t RxRing;
+
+ /* ET1310 register Access */
+ JAGCORE_ACCESS_REGS JagCoreRegs;
+ PCI_CFG_SPACE_REGS PciCfgRegs;
+
+ /* Loopback specifics */
+ u8 ReplicaPhyLoopbk; // Replica Enable
+ u8 ReplicaPhyLoopbkPF; // Replica Enable Pass/Fail
+
+ /* Stats */
+ CE_STATS_t Stats;
+
+ struct net_device_stats net_stats;
+ struct net_device_stats net_stats_prev;
+};
+
+#define MPSendPacketsHandler MPSendPackets
+#define MP_FREE_SEND_PACKET_FUN(Adapter, pMpTcb) \
+ et131x_free_send_packet(Adapter, pMpTcb)
+#define MpSendPacketFun(Adapter, Packet) MpSendPacket(Adapter, Packet)
+
+#endif /* __ET131X_ADAPTER_H__ */
diff --git a/drivers/staging/et131x/et131x_config.c b/drivers/staging/et131x/et131x_config.c
new file mode 100644
index 0000000..0adbaa6
--- /dev/null
+++ b/drivers/staging/et131x/et131x_config.c
@@ -0,0 +1,325 @@
+/*
+ * Agere Systems Inc.
+ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * et131x_config.c - Handles parsing of configuration data during
+ * initialization.
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#include "et131x_version.h"
+#include "et131x_debug.h"
+#include "et131x_defs.h"
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+
+#include "et1310_phy.h"
+#include "et1310_pm.h"
+#include "et1310_jagcore.h"
+
+#include "et131x_adapter.h"
+#include "et131x_initpci.h"
+#include "et131x_config.h"
+
+#include "et1310_tx.h"
+
+/* Data for debugging facilities */
+#ifdef CONFIG_ET131X_DEBUG
+extern dbg_info_t *et131x_dbginfo;
+#endif /* CONFIG_ET131X_DEBUG */
+
+/* Defines for Parameter Default/Min/Max vaules */
+#define PARM_SPEED_DUPLEX_DEF 0
+#define PARM_SPEED_DUPLEX_MIN 0
+#define PARM_SPEED_DUPLEX_MAX 5
+
+#define PARM_VLAN_TAG_DEF 0
+#define PARM_VLAN_TAG_MIN 0
+#define PARM_VLAN_TAG_MAX 4095
+
+#define PARM_FLOW_CTL_DEF 0
+#define PARM_FLOW_CTL_MIN 0
+#define PARM_FLOW_CTL_MAX 3
+
+#define PARM_WOL_LINK_DEF 3
+#define PARM_WOL_LINK_MIN 0
+#define PARM_WOL_LINK_MAX 3
+
+#define PARM_WOL_MATCH_DEF 7
+#define PARM_WOL_MATCH_MIN 0
+#define PARM_WOL_MATCH_MAX 7
+
+#define PARM_JUMBO_PKT_DEF 1514
+#define PARM_JUMBO_PKT_MIN 1514
+#define PARM_JUMBO_PKT_MAX 9216
+
+#define PARM_PHY_COMA_DEF 0
+#define PARM_PHY_COMA_MIN 0
+#define PARM_PHY_COMA_MAX 1
+
+#define PARM_RX_NUM_BUFS_DEF 4
+#define PARM_RX_NUM_BUFS_MIN 1
+#define PARM_RX_NUM_BUFS_MAX 64
+
+#define PARM_RX_TIME_INT_DEF 10
+#define PARM_RX_TIME_INT_MIN 2
+#define PARM_RX_TIME_INT_MAX 320
+
+#define PARM_TX_NUM_BUFS_DEF 4
+#define PARM_TX_NUM_BUFS_MIN 1
+#define PARM_TX_NUM_BUFS_MAX 40
+
+#define PARM_TX_TIME_INT_DEF 40
+#define PARM_TX_TIME_INT_MIN 1
+#define PARM_TX_TIME_INT_MAX 140
+
+#define PARM_RX_MEM_END_DEF 0x2bc
+#define PARM_RX_MEM_END_MIN 0
+#define PARM_RX_MEM_END_MAX 0x3ff
+
+#define PARM_MAC_STAT_DEF 1
+#define PARM_MAC_STAT_MIN 0
+#define PARM_MAC_STAT_MAX 1
+
+#define PARM_SC_GAIN_DEF 7
+#define PARM_SC_GAIN_MIN 0
+#define PARM_SC_GAIN_MAX 7
+
+#define PARM_PM_WOL_DEF 0
+#define PARM_PM_WOL_MIN 0
+#define PARM_PM_WOL_MAX 1
+
+#define PARM_NMI_DISABLE_DEF 0
+#define PARM_NMI_DISABLE_MIN 0
+#define PARM_NMI_DISABLE_MAX 2
+
+#define PARM_DMA_CACHE_DEF 0
+#define PARM_DMA_CACHE_MIN 0
+#define PARM_DMA_CACHE_MAX 15
+
+#define PARM_PHY_LOOPBK_DEF 0
+#define PARM_PHY_LOOPBK_MIN 0
+#define PARM_PHY_LOOPBK_MAX 1
+
+#define PARM_MAC_ADDRESS_DEF { 0x00, 0x05, 0x3d, 0x00, 0x02, 0x00 }
+
+/* Module parameter for disabling NMI
+ * et131x_speed_set :
+ * Set Link speed and dublex manually (0-5) [0]
+ * 1 : 10Mb Half-Duplex
+ * 2 : 10Mb Full-Duplex
+ * 3 : 100Mb Half-Duplex
+ * 4 : 100Mb Full-Duplex
+ * 5 : 1000Mb Full-Duplex
+ * 0 : Auto Speed Auto Dublex // default
+ */
+static u32 et131x_nmi_disable = PARM_NMI_DISABLE_DEF;
+module_param(et131x_nmi_disable, uint, 0);
+MODULE_PARM_DESC(et131x_nmi_disable, "Disable NMI (0-2) [0]");
+
+/* Module parameter for manual speed setting
+ * et131x_nmi_disable :
+ * Disable NMI (0-2) [0]
+ * 0 :
+ * 1 :
+ * 2 :
+ */
+static u32 et131x_speed_set = PARM_SPEED_DUPLEX_DEF;
+module_param(et131x_speed_set, uint, 0);
+MODULE_PARM_DESC(et131x_speed_set,
+ "Set Link speed and dublex manually (0-5) [0] \n 1 : 10Mb Half-Duplex \n 2 : 10Mb Full-Duplex \n 3 : 100Mb Half-Duplex \n 4 : 100Mb Full-Duplex \n 5 : 1000Mb Full-Duplex \n 0 : Auto Speed Auto Dublex");
+
+/**
+ * et131x_config_parse
+ * @pAdapter: pointer to the private adapter struct
+ *
+ * Parses a configuration from some location (module parameters, for example)
+ * into the private adapter struct
+ */
+void et131x_config_parse(struct et131x_adapter *pAdapter)
+{
+ uint8_t macAddrDef[] = PARM_MAC_ADDRESS_DEF;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ /*
+ * The NDIS driver uses the registry to store persistent per-device
+ * configuration, and reads this configuration into the appropriate
+ * elements of the private adapter structure on initialization.
+ * Because Linux has no analog to the registry, use this function to
+ * initialize the private adapter structure with a default
+ * configuration.
+ *
+ * One other possibility is to use a series of module parameters which
+ * can be passed in by the caller when the module is initialized.
+ * However, this implementation does not allow for seperate
+ * configurations in the event multiple devices are present, and hence
+ * will not suffice.
+ *
+ * If another method is derived which addresses this problem, this is
+ * where it should be implemented.
+ */
+
+ /* Set the private adapter struct with default values for the
+ * corresponding parameters
+ */
+ if (et131x_speed_set != PARM_SPEED_DUPLEX_DEF) {
+ DBG_VERBOSE(et131x_dbginfo, "Speed set manually to : %d \n",
+ et131x_speed_set);
+ pAdapter->SpeedDuplex = et131x_speed_set;
+ } else {
+ pAdapter->SpeedDuplex = PARM_SPEED_DUPLEX_DEF;
+ }
+
+ // pAdapter->SpeedDuplex = PARM_SPEED_DUPLEX_DEF;
+
+ pAdapter->RegistryVlanTag = PARM_VLAN_TAG_DEF;
+ pAdapter->RegistryFlowControl = PARM_FLOW_CTL_DEF;
+ pAdapter->RegistryWOLLink = PARM_WOL_LINK_DEF;
+ pAdapter->RegistryWOLMatch = PARM_WOL_MATCH_DEF;
+ pAdapter->RegistryJumboPacket = PARM_JUMBO_PKT_DEF;
+ pAdapter->RegistryPhyComa = PARM_PHY_COMA_DEF;
+ pAdapter->RegistryRxNumBuffers = PARM_RX_NUM_BUFS_DEF;
+ pAdapter->RegistryRxTimeInterval = PARM_RX_TIME_INT_DEF;
+ pAdapter->RegistryTxNumBuffers = PARM_TX_NUM_BUFS_DEF;
+ pAdapter->RegistryTxTimeInterval = PARM_TX_TIME_INT_DEF;
+ pAdapter->RegistryRxMemEnd = PARM_RX_MEM_END_DEF;
+ pAdapter->RegistryMACStat = PARM_MAC_STAT_DEF;
+ pAdapter->RegistrySCGain = PARM_SC_GAIN_DEF;
+ pAdapter->RegistryPMWOL = PARM_PM_WOL_DEF;
+
+ if (et131x_nmi_disable != PARM_NMI_DISABLE_DEF) {
+ pAdapter->RegistryNMIDisable = et131x_nmi_disable;
+ } else {
+ pAdapter->RegistryNMIDisable = PARM_NMI_DISABLE_DEF;
+ }
+
+ pAdapter->RegistryDMACache = PARM_DMA_CACHE_DEF;
+ pAdapter->RegistryPhyLoopbk = PARM_PHY_LOOPBK_DEF;
+
+ /* Set the MAC address to a default */
+ memcpy(pAdapter->CurrentAddress, macAddrDef, ETH_ALEN);
+ pAdapter->bOverrideAddress = false;
+
+ DBG_TRACE(et131x_dbginfo,
+ "Default MAC Address : %02x:%02x:%02x:%02x:%02x:%02x\n",
+ pAdapter->CurrentAddress[0], pAdapter->CurrentAddress[1],
+ pAdapter->CurrentAddress[2], pAdapter->CurrentAddress[3],
+ pAdapter->CurrentAddress[4], pAdapter->CurrentAddress[5]);
+
+ /* Decode SpeedDuplex
+ *
+ * Set up as if we are auto negotiating always and then change if we
+ * go into force mode
+ */
+ pAdapter->AiForceSpeed = 0; // Auto speed
+ pAdapter->AiForceDpx = 0; // Auto FDX
+
+ /* If we are the 10/100 device, and gigabit is somehow requested then
+ * knock it down to 100 full.
+ */
+ if ((pAdapter->DeviceID == ET131X_PCI_DEVICE_ID_FAST) &&
+ (pAdapter->SpeedDuplex == 5)) {
+ pAdapter->SpeedDuplex = 4;
+ }
+
+ switch (pAdapter->SpeedDuplex) {
+ case 1: // 10Mb Half-Duplex
+ pAdapter->AiForceSpeed = 10;
+ pAdapter->AiForceDpx = 1;
+ break;
+
+ case 2: // 10Mb Full-Duplex
+ pAdapter->AiForceSpeed = 10;
+ pAdapter->AiForceDpx = 2;
+ break;
+
+ case 3: // 100Mb Half-Duplex
+ pAdapter->AiForceSpeed = 100;
+ pAdapter->AiForceDpx = 1;
+ break;
+
+ case 4: // 100Mb Full-Duplex
+ pAdapter->AiForceSpeed = 100;
+ pAdapter->AiForceDpx = 2;
+ break;
+
+ case 5: // 1000Mb Full-Duplex
+ pAdapter->AiForceSpeed = 1000;
+ pAdapter->AiForceDpx = 2;
+ break;
+ }
+
+ DBG_LEAVE(et131x_dbginfo);
+}
diff --git a/drivers/staging/et131x/et131x_config.h b/drivers/staging/et131x/et131x_config.h
new file mode 100644
index 0000000..642c0f6
--- /dev/null
+++ b/drivers/staging/et131x/et131x_config.h
@@ -0,0 +1,67 @@
+/*
+ * Agere Systems Inc.
+ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * et131x_config.h - Defines, structs, enums, prototypes, etc. to support
+ * et131x_config.c
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#ifndef __ET131X_CONFIG_H__
+#define __ET131X_CONFIG_H__
+
+/* Forward declaration of the private adapter structure */
+struct et131x_adapter;
+
+void et131x_config_parse(struct et131x_adapter *adapter);
+
+#endif /* __ET131X_CONFIG_H__ */
diff --git a/drivers/staging/et131x/et131x_debug.c b/drivers/staging/et131x/et131x_debug.c
new file mode 100644
index 0000000..9ee5bce
--- /dev/null
+++ b/drivers/staging/et131x/et131x_debug.c
@@ -0,0 +1,218 @@
+/*
+ * Agere Systems Inc.
+ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * et131x_debug.c - Routines used for debugging.
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#ifdef CONFIG_ET131X_DEBUG
+
+#include "et131x_version.h"
+#include "et131x_debug.h"
+#include "et131x_defs.h"
+
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+#include <linux/random.h>
+
+#include "et1310_phy.h"
+#include "et1310_pm.h"
+#include "et1310_jagcore.h"
+
+#include "et131x_adapter.h"
+#include "et131x_netdev.h"
+#include "et131x_config.h"
+#include "et131x_isr.h"
+
+#include "et1310_address_map.h"
+#include "et1310_jagcore.h"
+#include "et1310_tx.h"
+#include "et1310_rx.h"
+#include "et1310_mac.h"
+
+/* Data for debugging facilities */
+extern dbg_info_t *et131x_dbginfo;
+
+/**
+ * DumpTxQueueContents - Dump out the tx queue and the shadow pointers
+ * @pAdapter: pointer to our adapter structure
+ */
+void DumpTxQueueContents(int dbgLvl, struct et131x_adapter *pAdapter)
+{
+ MMC_t __iomem *mmc = &pAdapter->CSRAddress->mmc;
+ uint32_t TxQueueAddr;
+
+ if (DBG_FLAGS(et131x_dbginfo) & dbgLvl) {
+ for (TxQueueAddr = 0x200; TxQueueAddr < 0x3ff; TxQueueAddr++) {
+ MMC_SRAM_ACCESS_t sram_access;
+
+ sram_access.value = readl(&mmc->sram_access.value);
+ sram_access.bits.req_addr = TxQueueAddr;
+ sram_access.bits.req_access = 1;
+ writel(sram_access.value, &mmc->sram_access.value);
+
+ DBG_PRINT("Addr 0x%x, Access 0x%08x\t"
+ "Value 1 0x%08x, Value 2 0x%08x, "
+ "Value 3 0x%08x, Value 4 0x%08x, \n",
+ TxQueueAddr,
+ readl(&mmc->sram_access.value),
+ readl(&mmc->sram_word1),
+ readl(&mmc->sram_word2),
+ readl(&mmc->sram_word3),
+ readl(&mmc->sram_word4));
+ }
+
+ DBG_PRINT("Shadow Pointers 0x%08x\n",
+ readl(&pAdapter->CSRAddress->txmac.shadow_ptr.value));
+ }
+}
+
+/**
+ * DumpDeviceBlock
+ * @pAdapter: pointer to our adapter
+ *
+ * Dumps the first 64 regs of each block of the et-1310 (each block is
+ * mapped to a new page, each page is 4096 bytes).
+ */
+#define NUM_BLOCKS 8
+void DumpDeviceBlock(int dbgLvl, struct et131x_adapter *pAdapter,
+ uint32_t Block)
+{
+ uint32_t Address1, Address2;
+ uint32_t __iomem *BigDevicePointer =
+ (uint32_t __iomem *) pAdapter->CSRAddress;
+ const char *BlockNames[NUM_BLOCKS] = {
+ "Global", "Tx DMA", "Rx DMA", "Tx MAC",
+ "Rx MAC", "MAC", "MAC Stat", "MMC"
+ };
+
+ /* Output the debug counters to the debug terminal */
+ if (DBG_FLAGS(et131x_dbginfo) & dbgLvl) {
+ DBG_PRINT("%s block\n", BlockNames[Block]);
+ BigDevicePointer += Block * 1024;
+ for (Address1 = 0; Address1 < 8; Address1++) {
+ for (Address2 = 0; Address2 < 8; Address2++) {
+ if (Block == 0 &&
+ (Address1 * 8 + Address2) == 6) {
+ DBG_PRINT(" ISR , ");
+ } else {
+ DBG_PRINT("0x%08x, ",
+ readl(BigDevicePointer++));
+ }
+ }
+ DBG_PRINT("\n");
+ }
+ DBG_PRINT("\n");
+ }
+}
+
+/**
+ * DumpDeviceReg
+ * @pAdapter: pointer to our adapter
+ *
+ * Dumps the first 64 regs of each block of the et-1310 (each block is
+ * mapped to a new page, each page is 4096 bytes).
+ */
+void DumpDeviceReg(int dbgLvl, struct et131x_adapter *pAdapter)
+{
+ uint32_t Address1, Address2;
+ uint32_t Block;
+ uint32_t __iomem *BigDevicePointer =
+ (uint32_t __iomem *) pAdapter->CSRAddress;
+ uint32_t __iomem *Pointer;
+ const char *BlockNames[NUM_BLOCKS] = {
+ "Global", "Tx DMA", "Rx DMA", "Tx MAC",
+ "Rx MAC", "MAC", "MAC Stat", "MMC"
+ };
+
+ /* Output the debug counters to the debug terminal */
+ if (DBG_FLAGS(et131x_dbginfo) & dbgLvl) {
+ for (Block = 0; Block < NUM_BLOCKS; Block++) {
+ DBG_PRINT("%s block\n", BlockNames[Block]);
+ Pointer = BigDevicePointer + (Block * 1024);
+
+ for (Address1 = 0; Address1 < 8; Address1++) {
+ for (Address2 = 0; Address2 < 8; Address2++) {
+ DBG_PRINT("0x%08x, ",
+ readl(Pointer++));
+ }
+ DBG_PRINT("\n");
+ }
+ DBG_PRINT("\n");
+ }
+ }
+}
+
+#endif // CONFIG_ET131X_DEBUG
diff --git a/drivers/staging/et131x/et131x_debug.h b/drivers/staging/et131x/et131x_debug.h
new file mode 100644
index 0000000..dab6080
--- /dev/null
+++ b/drivers/staging/et131x/et131x_debug.h
@@ -0,0 +1,201 @@
+/*
+ * Agere Systems Inc.
+ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * et131x_debug.h - Defines, structs, enums, prototypes, etc. used for
+ * outputting debug messages to the system logging facility
+ * (ksyslogd)
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#ifndef __ET131X_DBG_H__
+#define __ET131X_DBG_H__
+
+/* Define Masks for debugging types/levels */
+#define DBG_ERROR_ON 0x00000001L
+#define DBG_WARNING_ON 0x00000002L
+#define DBG_NOTICE_ON 0x00000004L
+#define DBG_TRACE_ON 0x00000008L
+#define DBG_VERBOSE_ON 0x00000010L
+#define DBG_PARAM_ON 0x00000020L
+#define DBG_BREAK_ON 0x00000040L
+#define DBG_RX_ON 0x00000100L
+#define DBG_TX_ON 0x00000200L
+
+#ifdef CONFIG_ET131X_DEBUG
+
+/*
+ * Set the level of debugging if not done with a preprocessor define. See
+ * et131x_main.c, function et131x_init_module() for how the debug level
+ * translates into the types of messages displayed.
+ */
+#ifndef DBG_LVL
+#define DBG_LVL 3
+#endif /* DBG_LVL */
+
+#define DBG_DEFAULTS (DBG_ERROR_ON | DBG_WARNING_ON | DBG_BREAK_ON )
+
+#define DBG_FLAGS(A) (A)->dbgFlags
+#define DBG_NAME(A) (A)->dbgName
+#define DBG_LEVEL(A) (A)->dbgLevel
+
+#ifndef DBG_PRINT
+#define DBG_PRINT(S...) printk(KERN_DEBUG S)
+#endif /* DBG_PRINT */
+
+#ifndef DBG_PRINTC
+#define DBG_PRINTC(S...) printk(S)
+#endif /* DBG_PRINTC */
+
+#ifndef DBG_TRAP
+#define DBG_TRAP {} /* BUG() */
+#endif /* DBG_TRAP */
+
+#define _ENTER_STR ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
+#define _LEAVE_STR "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
+
+#define _DBG_ENTER(A) printk(KERN_DEBUG "%s:%.*s:%s\n", DBG_NAME(A), \
+ ++DBG_LEVEL(A), _ENTER_STR, __func__)
+#define _DBG_LEAVE(A) printk(KERN_DEBUG "%s:%.*s:%s\n", DBG_NAME(A), \
+ DBG_LEVEL(A)--, _LEAVE_STR, __func__)
+
+#define DBG_ENTER(A) {if (DBG_FLAGS(A) & DBG_TRACE_ON) \
+ _DBG_ENTER(A);}
+
+#define DBG_LEAVE(A) {if (DBG_FLAGS(A) & DBG_TRACE_ON) \
+ _DBG_LEAVE(A);}
+
+#define DBG_PARAM(A,N,F,S...) {if (DBG_FLAGS(A) & DBG_PARAM_ON) \
+ DBG_PRINT(" %s -- "F"\n",N,S);}
+
+#define DBG_ERROR(A,S...) \
+ if (DBG_FLAGS(A) & DBG_ERROR_ON) { \
+ DBG_PRINT("%s:ERROR:%s ",DBG_NAME(A), __func__); \
+ DBG_PRINTC(S); \
+ DBG_TRAP; \
+ }
+
+#define DBG_WARNING(A,S...) {if (DBG_FLAGS(A) & DBG_WARNING_ON) \
+ {DBG_PRINT("%s:WARNING:%s ",DBG_NAME(A),__func__);DBG_PRINTC(S);}}
+
+#define DBG_NOTICE(A,S...) {if (DBG_FLAGS(A) & DBG_NOTICE_ON) \
+ {DBG_PRINT("%s:NOTICE:%s ",DBG_NAME(A),__func__);DBG_PRINTC(S);}}
+
+#define DBG_TRACE(A,S...) {if (DBG_FLAGS(A) & DBG_TRACE_ON) \
+ {DBG_PRINT("%s:TRACE:%s ",DBG_NAME(A), __func__);DBG_PRINTC(S);}}
+
+#define DBG_VERBOSE(A,S...) {if (DBG_FLAGS(A) & DBG_VERBOSE_ON) \
+ {DBG_PRINT("%s:VERBOSE:%s ",DBG_NAME(A), __func__);DBG_PRINTC(S);}}
+
+#define DBG_RX(A,S...) {if (DBG_FLAGS(A) & DBG_RX_ON) \
+ {DBG_PRINT(S);}}
+
+#define DBG_RX_ENTER(A) {if (DBG_FLAGS(A) & DBG_RX_ON) \
+ _DBG_ENTER(A);}
+
+#define DBG_RX_LEAVE(A) {if (DBG_FLAGS(A) & DBG_RX_ON) \
+ _DBG_LEAVE(A);}
+
+#define DBG_TX(A,S...) {if (DBG_FLAGS(A) & DBG_TX_ON) \
+ {DBG_PRINT(S);}}
+
+#define DBG_TX_ENTER(A) {if (DBG_FLAGS(A) & DBG_TX_ON) \
+ _DBG_ENTER(A);}
+
+#define DBG_TX_LEAVE(A) {if (DBG_FLAGS(A) & DBG_TX_ON) \
+ _DBG_LEAVE(A);}
+
+#define DBG_ASSERT(C) {if (!(C)) \
+ {DBG_PRINT("ASSERT(%s) -- %s#%d (%s)\n", \
+ #C,__FILE__,__LINE__,__func__); \
+ DBG_TRAP;}}
+#define STATIC
+
+typedef struct {
+ char *dbgName;
+ int dbgLevel;
+ unsigned long dbgFlags;
+} dbg_info_t;
+
+#else /* CONFIG_ET131X_DEBUG */
+
+#define DBG_DEFN
+#define DBG_TRAP
+#define DBG_PRINT(S...)
+#define DBG_ENTER(A)
+#define DBG_LEAVE(A)
+#define DBG_PARAM(A,N,F,S...)
+#define DBG_ERROR(A,S...)
+#define DBG_WARNING(A,S...)
+#define DBG_NOTICE(A,S...)
+#define DBG_TRACE(A,S...)
+#define DBG_VERBOSE(A,S...)
+#define DBG_RX(A,S...)
+#define DBG_RX_ENTER(A)
+#define DBG_RX_LEAVE(A)
+#define DBG_TX(A,S...)
+#define DBG_TX_ENTER(A)
+#define DBG_TX_LEAVE(A)
+#define DBG_ASSERT(C)
+#define STATIC static
+
+#endif /* CONFIG_ET131X_DEBUG */
+
+/* Forward declaration of the private adapter structure */
+struct et131x_adapter;
+
+void DumpTxQueueContents(int dbgLvl, struct et131x_adapter *adapter);
+void DumpDeviceBlock(int dbgLvl, struct et131x_adapter *adapter,
+ unsigned int Block);
+void DumpDeviceReg(int dbgLvl, struct et131x_adapter *adapter);
+
+#endif /* __ET131X_DBG_H__ */
diff --git a/drivers/staging/et131x/et131x_defs.h b/drivers/staging/et131x/et131x_defs.h
new file mode 100644
index 0000000..886cb78
--- /dev/null
+++ b/drivers/staging/et131x/et131x_defs.h
@@ -0,0 +1,128 @@
+/*
+ * Agere Systems Inc.
+ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * et131x_defs.h - Defines, structs, enums, prototypes, etc. to assist with OS
+ * compatibility
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#ifndef __ET131X_DEFS_H__
+#define __ET131X_DEFS_H__
+
+/* Packet and header sizes */
+#define NIC_MIN_PACKET_SIZE 60
+#define NIC_HEADER_SIZE ETH_HLEN /* 14 */
+
+/* Multicast list size */
+#define NIC_MAX_MCAST_LIST 128
+
+/* Supported Filters */
+#define ET131X_PACKET_TYPE_DIRECTED 0x0001
+#define ET131X_PACKET_TYPE_MULTICAST 0x0002
+#define ET131X_PACKET_TYPE_BROADCAST 0x0004
+#define ET131X_PACKET_TYPE_PROMISCUOUS 0x0008
+#define ET131X_PACKET_TYPE_ALL_MULTICAST 0x0010
+
+/* Tx Timeout */
+#define ET131X_TX_TIMEOUT (1 * HZ)
+#define NIC_SEND_HANG_THRESHOLD 0
+
+/* MP_TCB flags */
+#define fMP_DEST_MULTI 0x00000001
+#define fMP_DEST_BROAD 0x00000002
+
+/* MP_ADAPTER flags */
+#define fMP_ADAPTER_RECV_LOOKASIDE 0x00000004
+#define fMP_ADAPTER_INTERRUPT_IN_USE 0x00000008
+#define fMP_ADAPTER_SECONDARY 0x00000010
+
+/* MP_SHARED flags */
+#define fMP_ADAPTER_SHUTDOWN 0x00100000
+#define fMP_ADAPTER_LOWER_POWER 0x00200000
+
+#define fMP_ADAPTER_NON_RECOVER_ERROR 0x00800000
+#define fMP_ADAPTER_RESET_IN_PROGRESS 0x01000000
+#define fMP_ADAPTER_NO_CABLE 0x02000000
+#define fMP_ADAPTER_HARDWARE_ERROR 0x04000000
+#define fMP_ADAPTER_REMOVE_IN_PROGRESS 0x08000000
+#define fMP_ADAPTER_HALT_IN_PROGRESS 0x10000000
+#define fMP_ADAPTER_LINK_DETECTION 0x20000000
+
+#define fMP_ADAPTER_FAIL_SEND_MASK 0x3ff00000
+#define fMP_ADAPTER_NOT_READY_MASK 0x3ff00000
+
+/* Some offsets in PCI config space that are actually used. */
+#define ET1310_PCI_PM_CAPABILITY 0x40
+#define ET1310_PCI_PM_CSR 0x44
+#define ET1310_PCI_MAX_PYLD 0x4C
+#define ET1310_PCI_DEV_CTRL 0x50
+#define ET1310_PCI_DEV_STAT 0x52
+#define ET1310_NMI_DISABLE 0x61
+#define ET1310_PCI_MAC_ADDRESS 0xA4
+#define ET1310_PCI_EEPROM_STATUS 0xB2
+#define ET1310_PCI_PHY_INDEX_REG 0xB4
+#define ET1310_PCI_ACK_NACK 0xC0
+#define ET1310_PCI_REPLAY 0xC2
+#define ET1310_PCI_L0L1LATENCY 0xCF
+#define ET1310_PCI_SEL_PHY_CTRL 0xE4
+#define ET1310_PCI_ADVANCED_ERR 0x100
+
+/* PCI Vendor/Product IDs */
+#define ET131X_PCI_VENDOR_ID 0x11C1 // Agere Systems
+#define ET131X_PCI_DEVICE_ID_GIG 0xED00 // ET1310 1000 Base-T
+#define ET131X_PCI_DEVICE_ID_FAST 0xED01 // ET1310 100 Base-T
+
+/* Define order of magnitude converter */
+#define NANO_IN_A_MICRO 1000
+
+#endif /* __ET131X_DEFS_H__ */
diff --git a/drivers/staging/et131x/et131x_initpci.c b/drivers/staging/et131x/et131x_initpci.c
new file mode 100644
index 0000000..4c6f171
--- /dev/null
+++ b/drivers/staging/et131x/et131x_initpci.c
@@ -0,0 +1,1046 @@
+/*
+ * Agere Systems Inc.
+ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * et131x_initpci.c - Routines and data used to register the driver with the
+ * PCI (and PCI Express) subsystem, as well as basic driver
+ * init and startup.
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#include "et131x_version.h"
+#include "et131x_debug.h"
+#include "et131x_defs.h"
+
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+#include <linux/random.h>
+
+#include "et1310_phy.h"
+#include "et1310_pm.h"
+#include "et1310_jagcore.h"
+
+#include "et131x_adapter.h"
+#include "et131x_netdev.h"
+#include "et131x_config.h"
+#include "et131x_isr.h"
+
+#include "et1310_address_map.h"
+#include "et1310_jagcore.h"
+#include "et1310_tx.h"
+#include "et1310_rx.h"
+#include "et1310_mac.h"
+#include "et1310_eeprom.h"
+
+
+int __devinit et131x_pci_setup(struct pci_dev *pdev,
+ const struct pci_device_id *ent);
+void __devexit et131x_pci_remove(struct pci_dev *pdev);
+
+
+/* Modinfo parameters (filled out using defines from et131x_version.h) */
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_INFO);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+/* Module Parameters and related data for debugging facilities */
+#ifdef CONFIG_ET131X_DEBUG
+static u32 et131x_debug_level = DBG_LVL;
+static u32 et131x_debug_flags = DBG_DEFAULTS;
+
+/*
+et131x_debug_level :
+ Level of debugging desired (0-7)
+ 7 : DBG_RX_ON | DBG_TX_ON
+ 6 : DBG_PARAM_ON
+ 5 : DBG_VERBOSE_ON
+ 4 : DBG_TRACE_ON
+ 3 : DBG_NOTICE_ON
+ 2 : no debug info
+ 1 : no debug info
+ 0 : no debug info
+*/
+
+module_param(et131x_debug_level, uint, 0);
+module_param(et131x_debug_flags, uint, 0);
+
+MODULE_PARM_DESC(et131x_debug_level, "Level of debugging desired (0-7)");
+
+static dbg_info_t et131x_info = { DRIVER_NAME_EXT, 0, 0 };
+dbg_info_t *et131x_dbginfo = &et131x_info;
+#endif /* CONFIG_ET131X_DEBUG */
+
+static struct pci_device_id et131x_pci_table[] __devinitdata = {
+ {ET131X_PCI_VENDOR_ID, ET131X_PCI_DEVICE_ID_GIG, PCI_ANY_ID,
+ PCI_ANY_ID, 0, 0, 0UL},
+ {ET131X_PCI_VENDOR_ID, ET131X_PCI_DEVICE_ID_FAST, PCI_ANY_ID,
+ PCI_ANY_ID, 0, 0, 0UL},
+ {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, et131x_pci_table);
+
+static struct pci_driver et131x_driver = {
+ .name = DRIVER_NAME,
+ .id_table = et131x_pci_table,
+ .probe = et131x_pci_setup,
+ .remove = __devexit_p(et131x_pci_remove),
+ .suspend = NULL, //et131x_pci_suspend,
+ .resume = NULL, //et131x_pci_resume,
+};
+
+
+/**
+ * et131x_init_module - The "main" entry point called on driver initialization
+ *
+ * Returns 0 on success, errno on failure (as defined in errno.h)
+ */
+int et131x_init_module(void)
+{
+ int result;
+
+#ifdef CONFIG_ET131X_DEBUG
+ /* Set the level of debug messages displayed using the module
+ * parameter
+ */
+ et131x_dbginfo->dbgFlags = et131x_debug_flags;
+
+ switch (et131x_debug_level) {
+ case 7:
+ et131x_dbginfo->dbgFlags |= (DBG_RX_ON | DBG_TX_ON);
+
+ case 6:
+ et131x_dbginfo->dbgFlags |= DBG_PARAM_ON;
+
+ case 5:
+ et131x_dbginfo->dbgFlags |= DBG_VERBOSE_ON;
+
+ case 4:
+ et131x_dbginfo->dbgFlags |= DBG_TRACE_ON;
+
+ case 3:
+ et131x_dbginfo->dbgFlags |= DBG_NOTICE_ON;
+
+ case 2:
+ case 1:
+ case 0:
+ default:
+ break;
+ }
+#endif /* CONFIG_ET131X_DEBUG */
+
+ DBG_ENTER(et131x_dbginfo);
+ DBG_PRINT("%s\n", DRIVER_INFO);
+
+ result = pci_register_driver(&et131x_driver);
+
+ DBG_LEAVE(et131x_dbginfo);
+ return result;
+}
+
+/**
+ * et131x_cleanup_module - The entry point called on driver cleanup
+ */
+void et131x_cleanup_module(void)
+{
+ DBG_ENTER(et131x_dbginfo);
+
+ pci_unregister_driver(&et131x_driver);
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+/*
+ * These macros map the driver-specific init_module() and cleanup_module()
+ * routines so they can be called by the kernel.
+ */
+module_init(et131x_init_module);
+module_exit(et131x_cleanup_module);
+
+
+/**
+ * et131x_find_adapter - Find the adapter and get all the assigned resources
+ * @adapter: pointer to our private adapter structure
+ *
+ * Returns 0 on success, errno on failure (as defined in errno.h)
+ */
+int et131x_find_adapter(struct et131x_adapter *adapter, struct pci_dev *pdev)
+{
+ int result;
+ uint8_t eepromStat;
+ uint8_t maxPayload = 0;
+ uint8_t read_size_reg;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Allow disabling of Non-Maskable Interrupts in I/O space, to
+ * support validation.
+ */
+ if (adapter->RegistryNMIDisable) {
+ uint8_t RegisterVal;
+
+ RegisterVal = inb(ET1310_NMI_DISABLE);
+ RegisterVal &= 0xf3;
+
+ if (adapter->RegistryNMIDisable == 2) {
+ RegisterVal |= 0xc;
+ }
+
+ outb(ET1310_NMI_DISABLE, RegisterVal);
+ }
+
+ /* We first need to check the EEPROM Status code located at offset
+ * 0xB2 of config space
+ */
+ result = pci_read_config_byte(pdev, ET1310_PCI_EEPROM_STATUS,
+ &eepromStat);
+
+ /* THIS IS A WORKAROUND:
+ * I need to call this function twice to get my card in a
+ * LG M1 Express Dual running. I tried also a msleep before this
+ * function, because I thougth there could be some time condidions
+ * but it didn't work. Call the whole function twice also work.
+ */
+ result = pci_read_config_byte(pdev, ET1310_PCI_EEPROM_STATUS,
+ &eepromStat);
+ if (result != PCIBIOS_SUCCESSFUL) {
+ DBG_ERROR(et131x_dbginfo, "Could not read PCI config space for "
+ "EEPROM Status\n");
+ DBG_LEAVE(et131x_dbginfo);
+ return -EIO;
+ }
+
+ /* Determine if the error(s) we care about are present. If they are
+ * present, we need to fail.
+ */
+ if (eepromStat & 0x4C) {
+ result = pci_read_config_byte(pdev, PCI_REVISION_ID,
+ &adapter->RevisionID);
+ if (result != PCIBIOS_SUCCESSFUL) {
+ DBG_ERROR(et131x_dbginfo,
+ "Could not read PCI config space for "
+ "Revision ID\n");
+ DBG_LEAVE(et131x_dbginfo);
+ return -EIO;
+ } else if (adapter->RevisionID == 0x01) {
+ int32_t nLoop;
+ uint8_t ucTemp[4] = { 0xFE, 0x13, 0x10, 0xFF };
+
+ /* Re-write the first 4 bytes if we have an eeprom
+ * present and the revision id is 1, this fixes the
+ * corruption seen with 1310 B Silicon
+ */
+ for (nLoop = 0; nLoop < 3; nLoop++) {
+ EepromWriteByte(adapter, nLoop, ucTemp[nLoop],
+ 0, SINGLE_BYTE);
+ }
+ }
+
+ DBG_ERROR(et131x_dbginfo,
+ "Fatal EEPROM Status Error - 0x%04x\n", eepromStat);
+
+ /* This error could mean that there was an error reading the
+ * eeprom or that the eeprom doesn't exist. We will treat
+ * each case the same and not try to gather additional
+ * information that normally would come from the eeprom, like
+ * MAC Address
+ */
+ adapter->bEepromPresent = false;
+
+ DBG_LEAVE(et131x_dbginfo);
+ return -EIO;
+ } else {
+ DBG_TRACE(et131x_dbginfo, "EEPROM Status Code - 0x%04x\n",
+ eepromStat);
+ adapter->bEepromPresent = true;
+ }
+
+ /* Read the EEPROM for information regarding LED behavior. Refer to
+ * ET1310_phy.c, et131x_xcvr_init(), for its use.
+ */
+ EepromReadByte(adapter, 0x70, &adapter->eepromData[0], 0, SINGLE_BYTE);
+ EepromReadByte(adapter, 0x71, &adapter->eepromData[1], 0, SINGLE_BYTE);
+
+ if (adapter->eepromData[0] != 0xcd) {
+ adapter->eepromData[1] = 0x00; // Disable all optional features
+ }
+
+ /* Let's set up the PORT LOGIC Register. First we need to know what
+ * the max_payload_size is
+ */
+ result = pci_read_config_byte(pdev, ET1310_PCI_MAX_PYLD, &maxPayload);
+ if (result != PCIBIOS_SUCCESSFUL) {
+ DBG_ERROR(et131x_dbginfo, "Could not read PCI config space for "
+ "Max Payload Size\n");
+ DBG_LEAVE(et131x_dbginfo);
+ return -EIO;
+ }
+
+ /* Program the Ack/Nak latency and replay timers */
+ maxPayload &= 0x07; // Only the lower 3 bits are valid
+
+ if (maxPayload < 2) {
+ const uint16_t AckNak[2] = { 0x76, 0xD0 };
+ const uint16_t Replay[2] = { 0x1E0, 0x2ED };
+
+ result = pci_write_config_word(pdev, ET1310_PCI_ACK_NACK,
+ AckNak[maxPayload]);
+ if (result != PCIBIOS_SUCCESSFUL) {
+ DBG_ERROR(et131x_dbginfo,
+ "Could not write PCI config space "
+ "for ACK/NAK\n");
+ DBG_LEAVE(et131x_dbginfo);
+ return -EIO;
+ }
+
+ result = pci_write_config_word(pdev, ET1310_PCI_REPLAY,
+ Replay[maxPayload]);
+ if (result != PCIBIOS_SUCCESSFUL) {
+ DBG_ERROR(et131x_dbginfo,
+ "Could not write PCI config space "
+ "for Replay Timer\n");
+ DBG_LEAVE(et131x_dbginfo);
+ return -EIO;
+ }
+ }
+
+ /* l0s and l1 latency timers. We are using default values.
+ * Representing 001 for L0s and 010 for L1
+ */
+ result = pci_write_config_byte(pdev, ET1310_PCI_L0L1LATENCY, 0x11);
+ if (result != PCIBIOS_SUCCESSFUL) {
+ DBG_ERROR(et131x_dbginfo,
+ "Could not write PCI config space for "
+ "Latency Timers\n");
+ DBG_LEAVE(et131x_dbginfo);
+ return -EIO;
+ }
+
+ /* Change the max read size to 2k */
+ result = pci_read_config_byte(pdev, 0x51, &read_size_reg);
+ if (result != PCIBIOS_SUCCESSFUL) {
+ DBG_ERROR(et131x_dbginfo,
+ "Could not read PCI config space for Max read size\n");
+ DBG_LEAVE(et131x_dbginfo);
+ return -EIO;
+ }
+
+ read_size_reg &= 0x8f;
+ read_size_reg |= 0x40;
+
+ result = pci_write_config_byte(pdev, 0x51, read_size_reg);
+ if (result != PCIBIOS_SUCCESSFUL) {
+ DBG_ERROR(et131x_dbginfo,
+ "Could not write PCI config space for Max read size\n");
+ DBG_LEAVE(et131x_dbginfo);
+ return -EIO;
+ }
+
+ /* PCI Express Configuration registers 0x48-0x5B (Device Control) */
+ result = pci_read_config_word(pdev, ET1310_PCI_DEV_CTRL,
+ &adapter->PciXDevCtl);
+ if (result != PCIBIOS_SUCCESSFUL) {
+ DBG_ERROR(et131x_dbginfo,
+ "Could not read PCI config space for PCI Express Dev Ctl\n");
+ DBG_LEAVE(et131x_dbginfo);
+ return -EIO;
+ }
+
+ /* Get MAC address from config space if an eeprom exists, otherwise
+ * the MAC address there will not be valid
+ */
+ if (adapter->bEepromPresent) {
+ int i;
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ result = pci_read_config_byte(
+ pdev, ET1310_PCI_MAC_ADDRESS + i,
+ adapter->PermanentAddress + i);
+ if (result != PCIBIOS_SUCCESSFUL) {
+ DBG_ERROR(et131x_dbginfo,
+ "Could not read PCI config space for MAC address\n");
+ DBG_LEAVE(et131x_dbginfo);
+ return -EIO;
+ }
+ }
+ }
+
+ DBG_LEAVE(et131x_dbginfo);
+ return 0;
+}
+
+/**
+ * et131x_error_timer_handler
+ * @data: timer-specific variable; here a pointer to our adapter structure
+ *
+ * The routine called when the error timer expires, to track the number of
+ * recurring errors.
+ */
+void et131x_error_timer_handler(unsigned long data)
+{
+ struct et131x_adapter *pAdapter = (struct et131x_adapter *) data;
+ PM_CSR_t pm_csr;
+
+ pm_csr.value = readl(&pAdapter->CSRAddress->global.pm_csr.value);
+
+ if (pm_csr.bits.pm_phy_sw_coma == 0) {
+ if (pAdapter->RegistryMACStat) {
+ UpdateMacStatHostCounters(pAdapter);
+ }
+ } else {
+ DBG_VERBOSE(et131x_dbginfo,
+ "No interrupts, in PHY coma, pm_csr = 0x%x\n",
+ pm_csr.value);
+ }
+
+ if (!pAdapter->Bmsr.bits.link_status &&
+ pAdapter->RegistryPhyComa &&
+ pAdapter->PoMgmt.TransPhyComaModeOnBoot < 11) {
+ pAdapter->PoMgmt.TransPhyComaModeOnBoot++;
+ }
+
+ if (pAdapter->PoMgmt.TransPhyComaModeOnBoot == 10) {
+ if (!pAdapter->Bmsr.bits.link_status
+ && pAdapter->RegistryPhyComa) {
+ if (pm_csr.bits.pm_phy_sw_coma == 0) {
+ // NOTE - This was originally a 'sync with interrupt'. How
+ // to do that under Linux?
+ et131x_enable_interrupts(pAdapter);
+ EnablePhyComa(pAdapter);
+ }
+ }
+ }
+
+ /* This is a periodic timer, so reschedule */
+ mod_timer(&pAdapter->ErrorTimer, jiffies +
+ TX_ERROR_PERIOD * HZ / 1000);
+}
+
+/**
+ * et131x_link_detection_handler
+ *
+ * Timer function for link up at driver load time
+ */
+void et131x_link_detection_handler(unsigned long data)
+{
+ struct et131x_adapter *pAdapter = (struct et131x_adapter *) data;
+ unsigned long lockflags;
+
+ /* Let everyone know that we have run */
+ pAdapter->bLinkTimerActive = false;
+
+ if (pAdapter->MediaState == 0) {
+ spin_lock_irqsave(&pAdapter->Lock, lockflags);
+
+ pAdapter->MediaState = NETIF_STATUS_MEDIA_DISCONNECT;
+ MP_CLEAR_FLAG(pAdapter, fMP_ADAPTER_LINK_DETECTION);
+
+ spin_unlock_irqrestore(&pAdapter->Lock, lockflags);
+
+ netif_carrier_off(pAdapter->netdev);
+
+ pAdapter->bSetPending = false;
+ }
+}
+
+/**
+ * et131x_adapter_setup - Set the adapter up as per cassini+ documentation
+ * @adapter: pointer to our private adapter structure
+ *
+ * Returns 0 on success, errno on failure (as defined in errno.h)
+ */
+int et131x_adapter_setup(struct et131x_adapter *pAdapter)
+{
+ int status = 0;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Configure the JAGCore */
+ ConfigGlobalRegs(pAdapter);
+
+ ConfigMACRegs1(pAdapter);
+ ConfigMMCRegs(pAdapter);
+
+ ConfigRxMacRegs(pAdapter);
+ ConfigTxMacRegs(pAdapter);
+
+ ConfigRxDmaRegs(pAdapter);
+ ConfigTxDmaRegs(pAdapter);
+
+ ConfigMacStatRegs(pAdapter);
+
+ /* Move the following code to Timer function?? */
+ status = et131x_xcvr_find(pAdapter);
+
+ if (status != 0) {
+ DBG_WARNING(et131x_dbginfo, "Could not find the xcvr\n");
+ }
+
+ /* Prepare the TRUEPHY library. */
+ ET1310_PhyInit(pAdapter);
+
+ /* Reset the phy now so changes take place */
+ ET1310_PhyReset(pAdapter);
+
+ /* Power down PHY */
+ ET1310_PhyPowerDown(pAdapter, 1);
+
+ /*
+ * We need to turn off 1000 base half dulplex, the mac does not
+ * support it. For the 10/100 part, turn off all gig advertisement
+ */
+ if (pAdapter->DeviceID != ET131X_PCI_DEVICE_ID_FAST) {
+ ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_FULL);
+ } else {
+ ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE);
+ }
+
+ /* Power up PHY */
+ ET1310_PhyPowerDown(pAdapter, 0);
+
+ et131x_setphy_normal(pAdapter);
+
+ DBG_LEAVE(et131x_dbginfo);
+ return status;
+}
+
+/**
+ * et131x_setup_hardware_properties - set up the MAC Address on the ET1310
+ * @adapter: pointer to our private adapter structure
+ */
+void et131x_setup_hardware_properties(struct et131x_adapter *adapter)
+{
+ DBG_ENTER(et131x_dbginfo);
+
+ /* If have our default mac from registry and no mac address from
+ * EEPROM then we need to generate the last octet and set it on the
+ * device
+ */
+ if (!adapter->bOverrideAddress) {
+ if (adapter->PermanentAddress[0] == 0x00 &&
+ adapter->PermanentAddress[1] == 0x00 &&
+ adapter->PermanentAddress[2] == 0x00 &&
+ adapter->PermanentAddress[3] == 0x00 &&
+ adapter->PermanentAddress[4] == 0x00 &&
+ adapter->PermanentAddress[5] == 0x00) {
+ /*
+ * We need to randomly generate the last octet so we
+ * decrease our chances of setting the mac address to
+ * same as another one of our cards in the system
+ */
+ get_random_bytes(&adapter->CurrentAddress[5], 1);
+
+ /*
+ * We have the default value in the register we are
+ * working with so we need to copy the current
+ * address into the permanent address
+ */
+ memcpy(adapter->PermanentAddress,
+ adapter->CurrentAddress, ETH_ALEN);
+ } else {
+ /* We do not have an override address, so set the
+ * current address to the permanent address and add
+ * it to the device
+ */
+ memcpy(adapter->CurrentAddress,
+ adapter->PermanentAddress, ETH_ALEN);
+ }
+ }
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * et131x_soft_reset - Issue a soft reset to the hardware, complete for ET1310
+ * @adapter: pointer to our private adapter structure
+ */
+void et131x_soft_reset(struct et131x_adapter *adapter)
+{
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Disable MAC Core */
+ writel(0xc00f0000, &adapter->CSRAddress->mac.cfg1.value);
+
+ /* Set everything to a reset value */
+ writel(0x7F, &adapter->CSRAddress->global.sw_reset.value);
+ writel(0x000f0000, &adapter->CSRAddress->mac.cfg1.value);
+ writel(0x00000000, &adapter->CSRAddress->mac.cfg1.value);
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * et131x_align_allocated_memory - Align allocated memory on a given boundary
+ * @adapter: pointer to our adapter structure
+ * @phys_addr: pointer to Physical address
+ * @offset: pointer to the offset variable
+ * @mask: correct mask
+ */
+void et131x_align_allocated_memory(struct et131x_adapter *adapter,
+ uint64_t *phys_addr,
+ uint64_t *offset, uint64_t mask)
+{
+ uint64_t new_addr;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ *offset = 0;
+
+ new_addr = *phys_addr & ~mask;
+
+ if (new_addr != *phys_addr) {
+ /* Move to next aligned block */
+ new_addr += mask + 1;
+ /* Return offset for adjusting virt addr */
+ *offset = new_addr - *phys_addr;
+ /* Return new physical address */
+ *phys_addr = new_addr;
+ }
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * et131x_adapter_memory_alloc
+ * @adapter: pointer to our private adapter structure
+ *
+ * Returns 0 on success, errno on failure (as defined in errno.h).
+ *
+ * Allocate all the memory blocks for send, receive and others.
+ */
+int et131x_adapter_memory_alloc(struct et131x_adapter *adapter)
+{
+ int status = 0;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ do {
+ /* Allocate memory for the Tx Ring */
+ status = et131x_tx_dma_memory_alloc(adapter);
+ if (status != 0) {
+ DBG_ERROR(et131x_dbginfo,
+ "et131x_tx_dma_memory_alloc FAILED\n");
+ break;
+ }
+
+ /* Receive buffer memory allocation */
+ status = et131x_rx_dma_memory_alloc(adapter);
+ if (status != 0) {
+ DBG_ERROR(et131x_dbginfo,
+ "et131x_rx_dma_memory_alloc FAILED\n");
+ et131x_tx_dma_memory_free(adapter);
+ break;
+ }
+
+ /* Init receive data structures */
+ status = et131x_init_recv(adapter);
+ if (status != 0) {
+ DBG_ERROR(et131x_dbginfo, "et131x_init_recv FAILED\n");
+ et131x_tx_dma_memory_free(adapter);
+ et131x_rx_dma_memory_free(adapter);
+ break;
+ }
+ } while (0);
+
+ DBG_LEAVE(et131x_dbginfo);
+ return status;
+}
+
+/**
+ * et131x_adapter_memory_free - Free all memory allocated for use by Tx & Rx
+ * @adapter: pointer to our private adapter structure
+ */
+void et131x_adapter_memory_free(struct et131x_adapter *adapter)
+{
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Free DMA memory */
+ et131x_tx_dma_memory_free(adapter);
+ et131x_rx_dma_memory_free(adapter);
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * et131x_pci_remove
+ * @pdev: a pointer to the device's pci_dev structure
+ *
+ * Registered in the pci_driver structure, this function is called when the
+ * PCI subsystem detects that a PCI device which matches the information
+ * contained in the pci_device_id table has been removed.
+ */
+void __devexit et131x_pci_remove(struct pci_dev *pdev)
+{
+ struct net_device *netdev;
+ struct et131x_adapter *adapter;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Retrieve the net_device pointer from the pci_dev struct, as well
+ * as the private adapter struct
+ */
+ netdev = (struct net_device *) pci_get_drvdata(pdev);
+ adapter = netdev_priv(netdev);
+
+ /* Perform device cleanup */
+ unregister_netdev(netdev);
+ et131x_adapter_memory_free(adapter);
+ iounmap(adapter->CSRAddress);
+ free_netdev(netdev);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * et131x_pci_setup - Perform device initialization
+ * @pdev: a pointer to the device's pci_dev structure
+ * @ent: this device's entry in the pci_device_id table
+ *
+ * Returns 0 on success, errno on failure (as defined in errno.h)
+ *
+ * Registered in the pci_driver structure, this function is called when the
+ * PCI subsystem finds a new PCI device which matches the information
+ * contained in the pci_device_id table. This routine is the equivalent to
+ * a device insertion routine.
+ */
+int __devinit et131x_pci_setup(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ int result = 0;
+ int pm_cap;
+ bool pci_using_dac;
+ struct net_device *netdev = NULL;
+ struct et131x_adapter *adapter = NULL;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Enable the device via the PCI subsystem */
+ result = pci_enable_device(pdev);
+ if (result != 0) {
+ DBG_ERROR(et131x_dbginfo, "pci_enable_device() failed\n");
+ goto out;
+ }
+
+ /* Perform some basic PCI checks */
+ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
+ DBG_ERROR(et131x_dbginfo,
+ "Can't find PCI device's base address\n");
+ result = -ENODEV;
+ goto out;
+ }
+
+ result = pci_request_regions(pdev, DRIVER_NAME);
+ if (result != 0) {
+ DBG_ERROR(et131x_dbginfo, "Can't get PCI resources\n");
+ goto err_disable;
+ }
+
+ /* Enable PCI bus mastering */
+ DBG_TRACE(et131x_dbginfo, "Setting PCI Bus Mastering...\n");
+ pci_set_master(pdev);
+
+ /* Query PCI for Power Mgmt Capabilities
+ *
+ * NOTE: Now reading PowerMgmt in another location; is this still
+ * needed?
+ */
+ pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
+ if (pm_cap == 0) {
+ DBG_ERROR(et131x_dbginfo,
+ "Cannot find Power Management capabilities\n");
+ result = -EIO;
+ goto err_release_res;
+ }
+
+ /* Check the DMA addressing support of this device */
+ if (!pci_set_dma_mask(pdev, 0xffffffffffffffffULL)) {
+ DBG_TRACE(et131x_dbginfo, "64-bit DMA addressing supported\n");
+ pci_using_dac = true;
+
+ result =
+ pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL);
+ if (result != 0) {
+ DBG_ERROR(et131x_dbginfo,
+ "Unable to obtain 64 bit DMA for consistent allocations\n");
+ goto err_release_res;
+ }
+ } else if (!pci_set_dma_mask(pdev, 0xffffffffULL)) {
+ DBG_TRACE(et131x_dbginfo,
+ "64-bit DMA addressing NOT supported\n");
+ DBG_TRACE(et131x_dbginfo,
+ "32-bit DMA addressing will be used\n");
+ pci_using_dac = false;
+ } else {
+ DBG_ERROR(et131x_dbginfo, "No usable DMA addressing method\n");
+ result = -EIO;
+ goto err_release_res;
+ }
+
+ /* Allocate netdev and private adapter structs */
+ DBG_TRACE(et131x_dbginfo,
+ "Allocate netdev and private adapter structs...\n");
+ netdev = et131x_device_alloc();
+ if (netdev == NULL) {
+ DBG_ERROR(et131x_dbginfo, "Couldn't alloc netdev struct\n");
+ result = -ENOMEM;
+ goto err_release_res;
+ }
+
+ /* Setup the fundamental net_device and private adapter structure elements */
+ DBG_TRACE(et131x_dbginfo, "Setting fundamental net_device info...\n");
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+ if (pci_using_dac) {
+ //netdev->features |= NETIF_F_HIGHDMA;
+ }
+
+ /*
+ * NOTE - Turn this on when we're ready to deal with SG-DMA
+ *
+ * NOTE: According to "Linux Device Drivers", 3rd ed, Rubini et al,
+ * if checksumming is not performed in HW, then the kernel will not
+ * use SG.
+ * From pp 510-511:
+ *
+ * "Note that the kernel does not perform scatter/gather I/O to your
+ * device if it does not also provide some form of checksumming as
+ * well. The reason is that, if the kernel has to make a pass over a
+ * fragmented ("nonlinear") packet to calculate the checksum, it
+ * might as well copy the data and coalesce the packet at the same
+ * time."
+ *
+ * This has been verified by setting the flags below and still not
+ * receiving a scattered buffer from the network stack, so leave it
+ * off until checksums are calculated in HW.
+ */
+ //netdev->features |= NETIF_F_SG;
+ //netdev->features |= NETIF_F_NO_CSUM;
+ //netdev->features |= NETIF_F_LLTX;
+
+ /* Allocate private adapter struct and copy in relevant information */
+ adapter = netdev_priv(netdev);
+ adapter->pdev = pdev;
+ adapter->netdev = netdev;
+ adapter->VendorID = pdev->vendor;
+ adapter->DeviceID = pdev->device;
+
+ /* Do the same for the netdev struct */
+ netdev->irq = pdev->irq;
+ netdev->base_addr = pdev->resource[0].start;
+
+ /* Initialize spinlocks here */
+ DBG_TRACE(et131x_dbginfo, "Initialize spinlocks...\n");
+
+ spin_lock_init(&adapter->Lock);
+ spin_lock_init(&adapter->TCBSendQLock);
+ spin_lock_init(&adapter->TCBReadyQLock);
+ spin_lock_init(&adapter->SendHWLock);
+ spin_lock_init(&adapter->SendWaitLock);
+ spin_lock_init(&adapter->RcvLock);
+ spin_lock_init(&adapter->RcvPendLock);
+ spin_lock_init(&adapter->FbrLock);
+ spin_lock_init(&adapter->PHYLock);
+
+ /* Parse configuration parameters into the private adapter struct */
+ et131x_config_parse(adapter);
+
+ /* Find the physical adapter
+ *
+ * NOTE: This is the equivalent of the MpFindAdapter() routine; can we
+ * lump it's init with the device specific init below into a
+ * single init function?
+ */
+ //while (et131x_find_adapter(adapter, pdev) != 0);
+ et131x_find_adapter(adapter, pdev);
+
+ /* Map the bus-relative registers to system virtual memory */
+ DBG_TRACE(et131x_dbginfo,
+ "Mapping bus-relative registers to virtual memory...\n");
+
+ adapter->CSRAddress = ioremap_nocache(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ if (adapter->CSRAddress == NULL) {
+ DBG_ERROR(et131x_dbginfo, "Cannot map device registers\n");
+ result = -ENOMEM;
+ goto err_free_dev;
+ }
+
+ /* Perform device-specific initialization here (See code below) */
+
+ /* If Phy COMA mode was enabled when we went down, disable it here. */
+ {
+ PM_CSR_t GlobalPmCSR = { 0 };
+
+ GlobalPmCSR.bits.pm_sysclk_gate = 1;
+ GlobalPmCSR.bits.pm_txclk_gate = 1;
+ GlobalPmCSR.bits.pm_rxclk_gate = 1;
+ writel(GlobalPmCSR.value,
+ &adapter->CSRAddress->global.pm_csr.value);
+ }
+
+ /* Issue a global reset to the et1310 */
+ DBG_TRACE(et131x_dbginfo, "Issuing soft reset...\n");
+ et131x_soft_reset(adapter);
+
+ /* Disable all interrupts (paranoid) */
+ DBG_TRACE(et131x_dbginfo, "Disable device interrupts...\n");
+ et131x_disable_interrupts(adapter);
+
+ /* Allocate DMA memory */
+ result = et131x_adapter_memory_alloc(adapter);
+ if (result != 0) {
+ DBG_ERROR(et131x_dbginfo,
+ "Could not alloc adapater memory (DMA)\n");
+ goto err_iounmap;
+ }
+
+ /* Init send data structures */
+ DBG_TRACE(et131x_dbginfo, "Init send data structures...\n");
+ et131x_init_send(adapter);
+
+ adapter->PoMgmt.PowerState = NdisDeviceStateD0;
+
+ /* Register the interrupt
+ *
+ * NOTE - This is being done in the open routine, where most other
+ * Linux drivers setup IRQ handlers. Make sure device
+ * interrupts are not turned on before the IRQ is registered!!
+ *
+ * What we will do here is setup the task structure for the
+ * ISR's deferred handler
+ */
+ INIT_WORK(&adapter->task, et131x_isr_handler);
+
+ /* Determine MAC Address, and copy into the net_device struct */
+ DBG_TRACE(et131x_dbginfo, "Retrieve MAC address...\n");
+ et131x_setup_hardware_properties(adapter);
+
+ memcpy(netdev->dev_addr, adapter->CurrentAddress, ETH_ALEN);
+
+ /* Setup et1310 as per the documentation */
+ DBG_TRACE(et131x_dbginfo, "Setup the adapter...\n");
+ et131x_adapter_setup(adapter);
+
+ /* Create a timer to count errors received by the NIC */
+ init_timer(&adapter->ErrorTimer);
+
+ adapter->ErrorTimer.expires = jiffies + TX_ERROR_PERIOD * HZ / 1000;
+ adapter->ErrorTimer.function = et131x_error_timer_handler;
+ adapter->ErrorTimer.data = (unsigned long)adapter;
+
+ /* Initialize link state */
+ et131x_link_detection_handler((unsigned long)adapter);
+
+ /* Intialize variable for counting how long we do not have link status */
+ adapter->PoMgmt.TransPhyComaModeOnBoot = 0;
+
+ /* We can enable interrupts now
+ *
+ * NOTE - Because registration of interrupt handler is done in the
+ * device's open(), defer enabling device interrupts to that
+ * point
+ */
+
+ /* Register the net_device struct with the Linux network layer */
+ DBG_TRACE(et131x_dbginfo, "Registering net_device...\n");
+ if ((result = register_netdev(netdev)) != 0) {
+ DBG_ERROR(et131x_dbginfo, "register_netdev() failed\n");
+ goto err_mem_free;
+ }
+
+ /* Register the net_device struct with the PCI subsystem. Save a copy
+ * of the PCI config space for this device now that the device has
+ * been initialized, just in case it needs to be quickly restored.
+ */
+ pci_set_drvdata(pdev, netdev);
+
+ pci_save_state(adapter->pdev);
+
+out:
+ DBG_LEAVE(et131x_dbginfo);
+ return result;
+
+err_mem_free:
+ et131x_adapter_memory_free(adapter);
+err_iounmap:
+ iounmap(adapter->CSRAddress);
+err_free_dev:
+ free_netdev(netdev);
+err_release_res:
+ pci_release_regions(pdev);
+err_disable:
+ pci_disable_device(pdev);
+ goto out;
+}
diff --git a/drivers/staging/et131x/et131x_initpci.h b/drivers/staging/et131x/et131x_initpci.h
new file mode 100644
index 0000000..bbacb62
--- /dev/null
+++ b/drivers/staging/et131x/et131x_initpci.h
@@ -0,0 +1,73 @@
+/*
+ * Agere Systems Inc.
+ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * et131x_initpci.h - Header which includes common data and function prototypes
+ * related to the driver's PCI (and PCI Express) information.
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#ifndef __ET131X_INITPCI_H__
+#define __ET131X_INITPCI_H__
+
+/* Function Prototypes */
+void et131x_align_allocated_memory(struct et131x_adapter *adapter,
+ u64 *phys_addr,
+ u64 *offset, u64 mask);
+
+int et131x_adapter_setup(struct et131x_adapter *adapter);
+int et131x_adapter_memory_alloc(struct et131x_adapter *adapter);
+void et131x_adapter_memory_free(struct et131x_adapter *adapter);
+void et131x_setup_hardware_properties(struct et131x_adapter *adapter);
+void et131x_soft_reset(struct et131x_adapter *adapter);
+
+#endif /* __ET131X_INITPCI_H__ */
diff --git a/drivers/staging/et131x/et131x_isr.c b/drivers/staging/et131x/et131x_isr.c
new file mode 100644
index 0000000..00afad1
--- /dev/null
+++ b/drivers/staging/et131x/et131x_isr.c
@@ -0,0 +1,488 @@
+/*
+ * Agere Systems Inc.
+ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * et131x_isr.c - File which contains the ISR, ISR handler, and related routines
+ * for processing interrupts from the device.
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#include "et131x_version.h"
+#include "et131x_debug.h"
+#include "et131x_defs.h"
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+
+#include "et1310_phy.h"
+#include "et1310_pm.h"
+#include "et1310_jagcore.h"
+#include "et1310_mac.h"
+
+#include "et131x_adapter.h"
+
+/* Data for debugging facilities */
+#ifdef CONFIG_ET131X_DEBUG
+extern dbg_info_t *et131x_dbginfo;
+#endif /* CONFIG_ET131X_DEBUG */
+
+/**
+ * et131x_isr - The Interrupt Service Routine for the driver.
+ * @irq: the IRQ on which the interrupt was received.
+ * @dev_id: device-specific info (here a pointer to a net_device struct)
+ *
+ * Returns a value indicating if the interrupt was handled.
+ */
+irqreturn_t et131x_isr(int irq, void *dev_id)
+{
+ bool handled = true;
+ struct net_device *netdev = (struct net_device *)dev_id;
+ struct et131x_adapter *adapter = NULL;
+ INTERRUPT_t status;
+
+ if (netdev == NULL || !netif_device_present(netdev)) {
+ DBG_WARNING(et131x_dbginfo,
+ "No net_device struct or device not present\n");
+ handled = false;
+ goto out;
+ }
+
+ adapter = netdev_priv(netdev);
+
+ /* If the adapter is in low power state, then it should not
+ * recognize any interrupt
+ */
+
+ /* Disable Device Interrupts */
+ et131x_disable_interrupts(adapter);
+
+ /* Get a copy of the value in the interrupt status register
+ * so we can process the interrupting section
+ */
+ status.value = readl(&adapter->CSRAddress->global.int_status.value);
+
+ if (adapter->FlowControl == TxOnly ||
+ adapter->FlowControl == Both) {
+ status.value &= ~INT_MASK_ENABLE;
+ } else {
+ status.value &= ~INT_MASK_ENABLE_NO_FLOW;
+ }
+
+ /* Make sure this is our interrupt */
+ if (!status.value) {
+#ifdef CONFIG_ET131X_DEBUG
+ adapter->Stats.UnhandledInterruptsPerSec++;
+#endif
+ handled = false;
+ DBG_VERBOSE(et131x_dbginfo, "NOT OUR INTERRUPT\n");
+ et131x_enable_interrupts(adapter);
+ goto out;
+ }
+
+ /* This is our interrupt, so process accordingly */
+#ifdef CONFIG_ET131X_DEBUG
+ if (status.bits.rxdma_xfr_done) {
+ adapter->Stats.RxDmaInterruptsPerSec++;
+ }
+
+ if (status.bits.txdma_isr) {
+ adapter->Stats.TxDmaInterruptsPerSec++;
+ }
+#endif
+
+ if (status.bits.watchdog_interrupt) {
+ PMP_TCB pMpTcb = adapter->TxRing.CurrSendHead;
+
+ if (pMpTcb) {
+ if (++pMpTcb->PacketStaleCount > 1) {
+ status.bits.txdma_isr = 1;
+ }
+ }
+
+ if (adapter->RxRing.UnfinishedReceives) {
+ status.bits.rxdma_xfr_done = 1;
+ } else if (pMpTcb == NULL) {
+ writel(0, &adapter->CSRAddress->global.watchdog_timer);
+ }
+
+ status.bits.watchdog_interrupt = 0;
+#ifdef CONFIG_ET131X_DEBUG
+ adapter->Stats.WatchDogInterruptsPerSec++;
+#endif
+ }
+
+ if (status.value == 0) {
+ /* This interrupt has in some way been "handled" by
+ * the ISR. Either it was a spurious Rx interrupt, or
+ * it was a Tx interrupt that has been filtered by
+ * the ISR.
+ */
+ et131x_enable_interrupts(adapter);
+ goto out;
+ }
+
+ /* We need to save the interrupt status value for use in our
+ * DPC. We will clear the software copy of that in that
+ * routine.
+ */
+ adapter->Stats.InterruptStatus = status;
+
+ /* Schedule the ISR handler as a bottom-half task in the
+ * kernel's tq_immediate queue, and mark the queue for
+ * execution
+ */
+ schedule_work(&adapter->task);
+
+out:
+ return IRQ_RETVAL(handled);
+}
+
+/**
+ * et131x_isr_handler - The ISR handler
+ * @p_adapter, a pointer to the device's private adapter structure
+ *
+ * scheduled to run in a deferred context by the ISR. This is where the ISR's
+ * work actually gets done.
+ */
+void et131x_isr_handler(struct work_struct *work)
+{
+ struct et131x_adapter *pAdapter =
+ container_of(work, struct et131x_adapter, task);
+ INTERRUPT_t GlobStatus = pAdapter->Stats.InterruptStatus;
+ ADDRESS_MAP_t __iomem *iomem = pAdapter->CSRAddress;
+
+ /*
+ * These first two are by far the most common. Once handled, we clear
+ * their two bits in the status word. If the word is now zero, we
+ * exit.
+ */
+ /* Handle all the completed Transmit interrupts */
+ if (GlobStatus.bits.txdma_isr) {
+ DBG_TX(et131x_dbginfo, "TXDMA_ISR interrupt\n");
+ et131x_handle_send_interrupt(pAdapter);
+ }
+
+ /* Handle all the completed Receives interrupts */
+ if (GlobStatus.bits.rxdma_xfr_done) {
+ DBG_RX(et131x_dbginfo, "RXDMA_XFR_DONE interrupt\n");
+ et131x_handle_recv_interrupt(pAdapter);
+ }
+
+ GlobStatus.value &= 0xffffffd7;
+
+ if (GlobStatus.value) {
+ /* Handle the TXDMA Error interrupt */
+ if (GlobStatus.bits.txdma_err) {
+ TXDMA_ERROR_t TxDmaErr;
+
+ /* Following read also clears the register (COR) */
+ TxDmaErr.value = readl(&iomem->txdma.TxDmaError.value);
+
+ DBG_WARNING(et131x_dbginfo,
+ "TXDMA_ERR interrupt, error = %d\n",
+ TxDmaErr.value);
+ }
+
+ /* Handle Free Buffer Ring 0 and 1 Low interrupt */
+ if (GlobStatus.bits.rxdma_fb_ring0_low ||
+ GlobStatus.bits.rxdma_fb_ring1_low) {
+ /*
+ * This indicates the number of unused buffers in
+ * RXDMA free buffer ring 0 is <= the limit you
+ * programmed. Free buffer resources need to be
+ * returned. Free buffers are consumed as packets
+ * are passed from the network to the host. The host
+ * becomes aware of the packets from the contents of
+ * the packet status ring. This ring is queried when
+ * the packet done interrupt occurs. Packets are then
+ * passed to the OS. When the OS is done with the
+ * packets the resources can be returned to the
+ * ET1310 for re-use. This interrupt is one method of
+ * returning resources.
+ */
+ DBG_WARNING(et131x_dbginfo,
+ "RXDMA_FB_RING0_LOW or "
+ "RXDMA_FB_RING1_LOW interrupt\n");
+
+ /* If the user has flow control on, then we will
+ * send a pause packet, otherwise just exit
+ */
+ if (pAdapter->FlowControl == TxOnly ||
+ pAdapter->FlowControl == Both) {
+ PM_CSR_t pm_csr;
+
+ /* Tell the device to send a pause packet via
+ * the back pressure register
+ */
+ pm_csr.value = readl(&iomem->global.pm_csr.value);
+ if (pm_csr.bits.pm_phy_sw_coma == 0) {
+ TXMAC_BP_CTRL_t bp_ctrl = { 0 };
+
+ bp_ctrl.bits.bp_req = 1;
+ bp_ctrl.bits.bp_xonxoff = 1;
+ writel(bp_ctrl.value,
+ &iomem->txmac.bp_ctrl.value);
+ }
+ }
+ }
+
+ /* Handle Packet Status Ring Low Interrupt */
+ if (GlobStatus.bits.rxdma_pkt_stat_ring_low) {
+ DBG_WARNING(et131x_dbginfo,
+ "RXDMA_PKT_STAT_RING_LOW interrupt\n");
+
+ /*
+ * Same idea as with the two Free Buffer Rings.
+ * Packets going from the network to the host each
+ * consume a free buffer resource and a packet status
+ * resource. These resoures are passed to the OS.
+ * When the OS is done with the resources, they need
+ * to be returned to the ET1310. This is one method
+ * of returning the resources.
+ */
+ }
+
+ /* Handle RXDMA Error Interrupt */
+ if (GlobStatus.bits.rxdma_err) {
+ /*
+ * The rxdma_error interrupt is sent when a time-out
+ * on a request issued by the JAGCore has occurred or
+ * a completion is returned with an un-successful
+ * status. In both cases the request is considered
+ * complete. The JAGCore will automatically re-try the
+ * request in question. Normally information on events
+ * like these are sent to the host using the "Advanced
+ * Error Reporting" capability. This interrupt is
+ * another way of getting similar information. The
+ * only thing required is to clear the interrupt by
+ * reading the ISR in the global resources. The
+ * JAGCore will do a re-try on the request. Normally
+ * you should never see this interrupt. If you start
+ * to see this interrupt occurring frequently then
+ * something bad has occurred. A reset might be the
+ * thing to do.
+ */
+ // TRAP();
+
+ pAdapter->TxMacTest.value =
+ readl(&iomem->txmac.tx_test.value);
+ DBG_WARNING(et131x_dbginfo,
+ "RxDMA_ERR interrupt, error %x\n",
+ pAdapter->TxMacTest.value);
+ }
+
+ /* Handle the Wake on LAN Event */
+ if (GlobStatus.bits.wake_on_lan) {
+ /*
+ * This is a secondary interrupt for wake on LAN.
+ * The driver should never see this, if it does,
+ * something serious is wrong. We will TRAP the
+ * message when we are in DBG mode, otherwise we
+ * will ignore it.
+ */
+ DBG_ERROR(et131x_dbginfo, "WAKE_ON_LAN interrupt\n");
+ }
+
+ /* Handle the PHY interrupt */
+ if (GlobStatus.bits.phy_interrupt) {
+ PM_CSR_t pm_csr;
+ MI_BMSR_t BmsrInts, BmsrData;
+ MI_ISR_t myIsr;
+
+ DBG_VERBOSE(et131x_dbginfo, "PHY interrupt\n");
+
+ /* If we are in coma mode when we get this interrupt,
+ * we need to disable it.
+ */
+ pm_csr.value = readl(&iomem->global.pm_csr.value);
+ if (pm_csr.bits.pm_phy_sw_coma == 1) {
+ /*
+ * Check to see if we are in coma mode and if
+ * so, disable it because we will not be able
+ * to read PHY values until we are out.
+ */
+ DBG_VERBOSE(et131x_dbginfo,
+ "Device is in COMA mode, "
+ "need to wake up\n");
+ DisablePhyComa(pAdapter);
+ }
+
+ /* Read the PHY ISR to clear the reason for the
+ * interrupt.
+ */
+ MiRead(pAdapter, (uint8_t) offsetof(MI_REGS_t, isr),
+ &myIsr.value);
+
+ if (!pAdapter->ReplicaPhyLoopbk) {
+ MiRead(pAdapter,
+ (uint8_t) offsetof(MI_REGS_t, bmsr),
+ &BmsrData.value);
+
+ BmsrInts.value =
+ pAdapter->Bmsr.value ^ BmsrData.value;
+ pAdapter->Bmsr.value = BmsrData.value;
+
+ DBG_VERBOSE(et131x_dbginfo,
+ "Bmsr.value = 0x%04x,"
+ "Bmsr_ints.value = 0x%04x\n",
+ BmsrData.value, BmsrInts.value);
+
+ /* Do all the cable in / cable out stuff */
+ et131x_Mii_check(pAdapter, BmsrData, BmsrInts);
+ }
+ }
+
+ /* Let's move on to the TxMac */
+ if (GlobStatus.bits.txmac_interrupt) {
+ pAdapter->TxRing.TxMacErr.value =
+ readl(&iomem->txmac.err.value);
+
+ /*
+ * When any of the errors occur and TXMAC generates
+ * an interrupt to report these errors, it usually
+ * means that TXMAC has detected an error in the data
+ * stream retrieved from the on-chip Tx Q. All of
+ * these errors are catastrophic and TXMAC won't be
+ * able to recover data when these errors occur. In
+ * a nutshell, the whole Tx path will have to be reset
+ * and re-configured afterwards.
+ */
+ DBG_WARNING(et131x_dbginfo,
+ "TXMAC interrupt, error 0x%08x\n",
+ pAdapter->TxRing.TxMacErr.value);
+
+ /* If we are debugging, we want to see this error,
+ * otherwise we just want the device to be reset and
+ * continue
+ */
+ //DBG_TRAP();
+ }
+
+ /* Handle RXMAC Interrupt */
+ if (GlobStatus.bits.rxmac_interrupt) {
+ /*
+ * These interrupts are catastrophic to the device,
+ * what we need to do is disable the interrupts and
+ * set the flag to cause us to reset so we can solve
+ * this issue.
+ */
+ // MP_SET_FLAG( pAdapter, fMP_ADAPTER_HARDWARE_ERROR );
+
+ DBG_WARNING(et131x_dbginfo,
+ "RXMAC interrupt, error 0x%08x. Requesting reset\n",
+ readl(&iomem->rxmac.err_reg.value));
+
+ DBG_WARNING(et131x_dbginfo,
+ "Enable 0x%08x, Diag 0x%08x\n",
+ readl(&iomem->rxmac.ctrl.value),
+ readl(&iomem->rxmac.rxq_diag.value));
+
+ /*
+ * If we are debugging, we want to see this error,
+ * otherwise we just want the device to be reset and
+ * continue
+ */
+ // TRAP();
+ }
+
+ /* Handle MAC_STAT Interrupt */
+ if (GlobStatus.bits.mac_stat_interrupt) {
+ /*
+ * This means at least one of the un-masked counters
+ * in the MAC_STAT block has rolled over. Use this
+ * to maintain the top, software managed bits of the
+ * counter(s).
+ */
+ DBG_VERBOSE(et131x_dbginfo, "MAC_STAT interrupt\n");
+ HandleMacStatInterrupt(pAdapter);
+ }
+
+ /* Handle SLV Timeout Interrupt */
+ if (GlobStatus.bits.slv_timeout) {
+ /*
+ * This means a timeout has occured on a read or
+ * write request to one of the JAGCore registers. The
+ * Global Resources block has terminated the request
+ * and on a read request, returned a "fake" value.
+ * The most likely reasons are: Bad Address or the
+ * addressed module is in a power-down state and
+ * can't respond.
+ */
+ DBG_VERBOSE(et131x_dbginfo, "SLV_TIMEOUT interrupt\n");
+ }
+ }
+
+ if (pAdapter->PoMgmt.PowerState == NdisDeviceStateD0) {
+ et131x_enable_interrupts(pAdapter);
+ }
+}
diff --git a/drivers/staging/et131x/et131x_isr.h b/drivers/staging/et131x/et131x_isr.h
new file mode 100644
index 0000000..76a51d5
--- /dev/null
+++ b/drivers/staging/et131x/et131x_isr.h
@@ -0,0 +1,65 @@
+/*
+ * Agere Systems Inc.
+ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * et131x_isr.h - Defines, structs, enums, prototypes, etc. pertaining to the
+ * ISR processing code.
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#ifndef __ET131X_ISR_H__
+#define __ET131X_ISR_H__
+
+irqreturn_t et131x_isr(int irq, void *dev_id);
+void et131x_isr_handler(struct work_struct *work);
+
+#endif /* __ET131X_ISR_H__ */
diff --git a/drivers/staging/et131x/et131x_netdev.c b/drivers/staging/et131x/et131x_netdev.c
new file mode 100644
index 0000000..de65972
--- /dev/null
+++ b/drivers/staging/et131x/et131x_netdev.c
@@ -0,0 +1,856 @@
+/*
+ * Agere Systems Inc.
+ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * et131x_netdev.c - Routines and data required by all Linux network devices.
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#include "et131x_version.h"
+#include "et131x_debug.h"
+#include "et131x_defs.h"
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <linux/mii.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+
+#include "et1310_phy.h"
+#include "et1310_pm.h"
+#include "et1310_jagcore.h"
+#include "et1310_mac.h"
+#include "et1310_tx.h"
+
+#include "et131x_adapter.h"
+#include "et131x_isr.h"
+#include "et131x_initpci.h"
+
+/* Data for debugging facilities */
+#ifdef CONFIG_ET131X_DEBUG
+extern dbg_info_t *et131x_dbginfo;
+#endif /* CONFIG_ET131X_DEBUG */
+
+struct net_device_stats *et131x_stats(struct net_device *netdev);
+int et131x_open(struct net_device *netdev);
+int et131x_close(struct net_device *netdev);
+int et131x_ioctl(struct net_device *netdev, struct ifreq *reqbuf, int cmd);
+void et131x_multicast(struct net_device *netdev);
+int et131x_tx(struct sk_buff *skb, struct net_device *netdev);
+void et131x_tx_timeout(struct net_device *netdev);
+int et131x_change_mtu(struct net_device *netdev, int new_mtu);
+int et131x_set_mac_addr(struct net_device *netdev, void *new_mac);
+void et131x_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp);
+void et131x_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid);
+void et131x_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
+
+/**
+ * et131x_device_alloc
+ *
+ * Returns pointer to the allocated and initialized net_device struct for
+ * this device.
+ *
+ * Create instances of net_device and wl_private for the new adapter and
+ * register the device's entry points in the net_device structure.
+ */
+struct net_device *et131x_device_alloc(void)
+{
+ struct net_device *netdev;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Alloc net_device and adapter structs */
+ netdev = alloc_etherdev(sizeof(struct et131x_adapter));
+
+ if (netdev == NULL) {
+ DBG_ERROR(et131x_dbginfo,
+ "Alloc of net_device struct failed\n");
+ DBG_LEAVE(et131x_dbginfo);
+ return NULL;
+ }
+
+ /* Setup the function registration table (and other data) for a
+ * net_device
+ */
+ //netdev->init = &et131x_init;
+ //netdev->set_config = &et131x_config;
+ netdev->get_stats = &et131x_stats;
+ netdev->open = &et131x_open;
+ netdev->stop = &et131x_close;
+ netdev->do_ioctl = &et131x_ioctl;
+ netdev->set_multicast_list = &et131x_multicast;
+ netdev->hard_start_xmit = &et131x_tx;
+ netdev->tx_timeout = &et131x_tx_timeout;
+ netdev->watchdog_timeo = ET131X_TX_TIMEOUT;
+ netdev->change_mtu = &et131x_change_mtu;
+ netdev->set_mac_address = &et131x_set_mac_addr;
+
+ //netdev->ethtool_ops = &et131x_ethtool_ops;
+
+ // Poll?
+ //netdev->poll = &et131x_poll;
+ //netdev->poll_controller = &et131x_poll_controller;
+
+ DBG_LEAVE(et131x_dbginfo);
+ return netdev;
+}
+
+/**
+ * et131x_stats - Return the current device statistics.
+ * @netdev: device whose stats are being queried
+ *
+ * Returns 0 on success, errno on failure (as defined in errno.h)
+ */
+struct net_device_stats *et131x_stats(struct net_device *netdev)
+{
+ struct et131x_adapter *adapter = netdev_priv(netdev);
+ struct net_device_stats *stats = &adapter->net_stats;
+ CE_STATS_t *devstat = &adapter->Stats;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ stats->rx_packets = devstat->ipackets;
+ stats->tx_packets = devstat->opackets;
+ stats->rx_errors = devstat->length_err + devstat->alignment_err +
+ devstat->crc_err + devstat->code_violations + devstat->other_errors;
+ stats->tx_errors = devstat->max_pkt_error;
+ stats->multicast = devstat->multircv;
+ stats->collisions = devstat->collisions;
+
+ stats->rx_length_errors = devstat->length_err;
+ stats->rx_over_errors = devstat->rx_ov_flow;
+ stats->rx_crc_errors = devstat->crc_err;
+
+ // NOTE: These stats don't have corresponding values in CE_STATS, so we're
+ // going to have to update these directly from within the TX/RX code
+ //stats->rx_bytes = 20; //devstat->;
+ //stats->tx_bytes = 20; //devstat->;
+ //stats->rx_dropped = devstat->;
+ //stats->tx_dropped = devstat->;
+
+ // NOTE: Not used, can't find analogous statistics
+ //stats->rx_frame_errors = devstat->;
+ //stats->rx_fifo_errors = devstat->;
+ //stats->rx_missed_errors = devstat->;
+
+ //stats->tx_aborted_errors = devstat->;
+ //stats->tx_carrier_errors = devstat->;
+ //stats->tx_fifo_errors = devstat->;
+ //stats->tx_heartbeat_errors = devstat->;
+ //stats->tx_window_errors = devstat->;
+
+ DBG_LEAVE(et131x_dbginfo);
+ return stats;
+}
+
+/**
+ * et131x_open - Open the device for use.
+ * @netdev: device to be opened
+ *
+ * Returns 0 on success, errno on failure (as defined in errno.h)
+ */
+int et131x_open(struct net_device *netdev)
+{
+ int result = 0;
+ struct et131x_adapter *adapter = netdev_priv(netdev);
+
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Start the timer to track NIC errors */
+ add_timer(&adapter->ErrorTimer);
+
+ /* Register our ISR */
+ DBG_TRACE(et131x_dbginfo, "Registering ISR...\n");
+
+ result =
+ request_irq(netdev->irq, et131x_isr, IRQF_SHARED, netdev->name,
+ netdev);
+ if (result) {
+ DBG_ERROR(et131x_dbginfo, "Could not register ISR\n");
+ DBG_LEAVE(et131x_dbginfo);
+ return result;
+ }
+
+ /* Enable the Tx and Rx DMA engines (if not already enabled) */
+ et131x_rx_dma_enable(adapter);
+ et131x_tx_dma_enable(adapter);
+
+ /* Enable device interrupts */
+ et131x_enable_interrupts(adapter);
+
+ MP_SET_FLAG(adapter, fMP_ADAPTER_INTERRUPT_IN_USE);
+
+ /* We're ready to move some data, so start the queue */
+ netif_start_queue(netdev);
+
+ DBG_LEAVE(et131x_dbginfo);
+ return result;
+}
+
+/**
+ * et131x_close - Close the device
+ * @netdev: device to be closed
+ *
+ * Returns 0 on success, errno on failure (as defined in errno.h)
+ */
+int et131x_close(struct net_device *netdev)
+{
+ struct et131x_adapter *adapter = netdev_priv(netdev);
+
+ DBG_ENTER(et131x_dbginfo);
+
+ /* First thing is to stop the queue */
+ netif_stop_queue(netdev);
+
+ /* Stop the Tx and Rx DMA engines */
+ et131x_rx_dma_disable(adapter);
+ et131x_tx_dma_disable(adapter);
+
+ /* Disable device interrupts */
+ et131x_disable_interrupts(adapter);
+
+ /* Deregistering ISR */
+ MP_CLEAR_FLAG(adapter, fMP_ADAPTER_INTERRUPT_IN_USE);
+
+ DBG_TRACE(et131x_dbginfo, "Deregistering ISR...\n");
+ free_irq(netdev->irq, netdev);
+
+ /* Stop the error timer */
+ del_timer_sync(&adapter->ErrorTimer);
+
+ DBG_LEAVE(et131x_dbginfo);
+ return 0;
+}
+
+/**
+ * et131x_ioctl_mii - The function which handles MII IOCTLs
+ * @netdev: device on which the query is being made
+ * @reqbuf: the request-specific data buffer
+ * @cmd: the command request code
+ *
+ * Returns 0 on success, errno on failure (as defined in errno.h)
+ */
+int et131x_ioctl_mii(struct net_device *netdev, struct ifreq *reqbuf, int cmd)
+{
+ int status = 0;
+ struct et131x_adapter *pAdapter = netdev_priv(netdev);
+ struct mii_ioctl_data *data = if_mii(reqbuf);
+
+ DBG_ENTER(et131x_dbginfo);
+
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ DBG_VERBOSE(et131x_dbginfo, "SIOCGMIIPHY\n");
+ data->phy_id = pAdapter->Stats.xcvr_addr;
+ break;
+
+ case SIOCGMIIREG:
+ DBG_VERBOSE(et131x_dbginfo, "SIOCGMIIREG\n");
+ if (!capable(CAP_NET_ADMIN)) {
+ status = -EPERM;
+ } else {
+ status = MiRead(pAdapter,
+ data->reg_num, &data->val_out);
+ }
+ break;
+
+ case SIOCSMIIREG:
+ DBG_VERBOSE(et131x_dbginfo, "SIOCSMIIREG\n");
+ if (!capable(CAP_NET_ADMIN)) {
+ status = -EPERM;
+ } else {
+ status = MiWrite(pAdapter, data->reg_num,
+ data->val_in);
+ }
+ break;
+
+ default:
+ status = -EOPNOTSUPP;
+ }
+
+ DBG_LEAVE(et131x_dbginfo);
+ return status;
+}
+
+/**
+ * et131x_ioctl - The I/O Control handler for the driver
+ * @netdev: device on which the control request is being made
+ * @reqbuf: a pointer to the IOCTL request buffer
+ * @cmd: the IOCTL command code
+ *
+ * Returns 0 on success, errno on failure (as defined in errno.h)
+ */
+int et131x_ioctl(struct net_device *netdev, struct ifreq *reqbuf, int cmd)
+{
+ int status = 0;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ case SIOCGMIIREG:
+ case SIOCSMIIREG:
+ status = et131x_ioctl_mii(netdev, reqbuf, cmd);
+ break;
+
+ default:
+ DBG_WARNING(et131x_dbginfo, "Unhandled IOCTL Code: 0x%04x\n",
+ cmd);
+ status = -EOPNOTSUPP;
+ }
+
+ DBG_LEAVE(et131x_dbginfo);
+ return status;
+}
+
+/**
+ * et131x_set_packet_filter - Configures the Rx Packet filtering on the device
+ * @adapter: pointer to our private adapter structure
+ *
+ * Returns 0 on success, errno on failure
+ */
+int et131x_set_packet_filter(struct et131x_adapter *adapter)
+{
+ int status = 0;
+ uint32_t filter = adapter->PacketFilter;
+ RXMAC_CTRL_t ctrl;
+ RXMAC_PF_CTRL_t pf_ctrl;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ ctrl.value = readl(&adapter->CSRAddress->rxmac.ctrl.value);
+ pf_ctrl.value = readl(&adapter->CSRAddress->rxmac.pf_ctrl.value);
+
+ /* Default to disabled packet filtering. Enable it in the individual
+ * case statements that require the device to filter something
+ */
+ ctrl.bits.pkt_filter_disable = 1;
+
+ /* Set us to be in promiscuous mode so we receive everything, this
+ * is also true when we get a packet filter of 0
+ */
+ if ((filter & ET131X_PACKET_TYPE_PROMISCUOUS) || filter == 0) {
+ pf_ctrl.bits.filter_broad_en = 0;
+ pf_ctrl.bits.filter_multi_en = 0;
+ pf_ctrl.bits.filter_uni_en = 0;
+ } else {
+ /*
+ * Set us up with Multicast packet filtering. Three cases are
+ * possible - (1) we have a multi-cast list, (2) we receive ALL
+ * multicast entries or (3) we receive none.
+ */
+ if (filter & ET131X_PACKET_TYPE_ALL_MULTICAST) {
+ DBG_VERBOSE(et131x_dbginfo,
+ "Multicast filtering OFF (Rx ALL MULTICAST)\n");
+ pf_ctrl.bits.filter_multi_en = 0;
+ } else {
+ DBG_VERBOSE(et131x_dbginfo, "Multicast filtering ON\n");
+ SetupDeviceForMulticast(adapter);
+ pf_ctrl.bits.filter_multi_en = 1;
+ ctrl.bits.pkt_filter_disable = 0;
+ }
+
+ /* Set us up with Unicast packet filtering */
+ if (filter & ET131X_PACKET_TYPE_DIRECTED) {
+ DBG_VERBOSE(et131x_dbginfo, "Unicast Filtering ON\n");
+ SetupDeviceForUnicast(adapter);
+ pf_ctrl.bits.filter_uni_en = 1;
+ ctrl.bits.pkt_filter_disable = 0;
+ }
+
+ /* Set us up with Broadcast packet filtering */
+ if (filter & ET131X_PACKET_TYPE_BROADCAST) {
+ DBG_VERBOSE(et131x_dbginfo, "Broadcast Filtering ON\n");
+ pf_ctrl.bits.filter_broad_en = 1;
+ ctrl.bits.pkt_filter_disable = 0;
+ } else {
+ DBG_VERBOSE(et131x_dbginfo,
+ "Broadcast Filtering OFF\n");
+ pf_ctrl.bits.filter_broad_en = 0;
+ }
+
+ /* Setup the receive mac configuration registers - Packet
+ * Filter control + the enable / disable for packet filter
+ * in the control reg.
+ */
+ writel(pf_ctrl.value,
+ &adapter->CSRAddress->rxmac.pf_ctrl.value);
+ writel(ctrl.value, &adapter->CSRAddress->rxmac.ctrl.value);
+ }
+
+ DBG_LEAVE(et131x_dbginfo);
+ return status;
+}
+
+/**
+ * et131x_multicast - The handler to configure multicasting on the interface
+ * @netdev: a pointer to a net_device struct representing the device
+ */
+void et131x_multicast(struct net_device *netdev)
+{
+ struct et131x_adapter *adapter = netdev_priv(netdev);
+ uint32_t PacketFilter = 0;
+ uint32_t count;
+ unsigned long lockflags;
+ struct dev_mc_list *mclist = netdev->mc_list;
+
+ DBG_ENTER(et131x_dbginfo);
+
+ spin_lock_irqsave(&adapter->Lock, lockflags);
+
+ /* Before we modify the platform-independent filter flags, store them
+ * locally. This allows us to determine if anything's changed and if
+ * we even need to bother the hardware
+ */
+ PacketFilter = adapter->PacketFilter;
+
+ /* Clear the 'multicast' flag locally; becuase we only have a single
+ * flag to check multicast, and multiple multicast addresses can be
+ * set, this is the easiest way to determine if more than one
+ * multicast address is being set.
+ */
+ PacketFilter &= ~ET131X_PACKET_TYPE_MULTICAST;
+
+ /* Check the net_device flags and set the device independent flags
+ * accordingly
+ */
+ DBG_VERBOSE(et131x_dbginfo,
+ "MULTICAST ADDR COUNT: %d\n", netdev->mc_count);
+
+ if (netdev->flags & IFF_PROMISC) {
+ DBG_VERBOSE(et131x_dbginfo, "Request: PROMISCUOUS MODE ON\n");
+ adapter->PacketFilter |= ET131X_PACKET_TYPE_PROMISCUOUS;
+ } else {
+ DBG_VERBOSE(et131x_dbginfo, "Request: PROMISCUOUS MODE OFF\n");
+ adapter->PacketFilter &= ~ET131X_PACKET_TYPE_PROMISCUOUS;
+ }
+
+ if (netdev->flags & IFF_ALLMULTI) {
+ DBG_VERBOSE(et131x_dbginfo, "Request: ACCEPT ALL MULTICAST\n");
+ adapter->PacketFilter |= ET131X_PACKET_TYPE_ALL_MULTICAST;
+ }
+
+ if (netdev->mc_count > NIC_MAX_MCAST_LIST) {
+ DBG_WARNING(et131x_dbginfo,
+ "ACCEPT ALL MULTICAST for now, as there's more Multicast "
+ "addresses than the HW supports\n");
+
+ adapter->PacketFilter |= ET131X_PACKET_TYPE_ALL_MULTICAST;
+ }
+
+ if (netdev->mc_count < 1) {
+ DBG_VERBOSE(et131x_dbginfo, "Request: REJECT ALL MULTICAST\n");
+ adapter->PacketFilter &= ~ET131X_PACKET_TYPE_ALL_MULTICAST;
+ adapter->PacketFilter &= ~ET131X_PACKET_TYPE_MULTICAST;
+ } else {
+ DBG_VERBOSE(et131x_dbginfo,
+ "Request: SET MULTICAST FILTER(S)\n");
+ adapter->PacketFilter |= ET131X_PACKET_TYPE_MULTICAST;
+ }
+
+ /* Set values in the private adapter struct */
+ adapter->MCAddressCount = netdev->mc_count;
+
+ if (netdev->mc_count) {
+ if (mclist->dmi_addrlen != ETH_ALEN) {
+ DBG_WARNING(et131x_dbginfo,
+ "Multicast addrs are not ETH_ALEN in size\n");
+ } else {
+ count = netdev->mc_count - 1;
+ memcpy(adapter->MCList[count], mclist->dmi_addr,
+ ETH_ALEN);
+ }
+ }
+
+ /* Are the new flags different from the previous ones? If not, then no
+ * action is required
+ *
+ * NOTE - This block will always update the MCList with the hardware,
+ * even if the addresses aren't the same.
+ */
+ if (PacketFilter != adapter->PacketFilter) {
+ /* Call the device's filter function */
+ DBG_VERBOSE(et131x_dbginfo, "UPDATE REQUIRED, FLAGS changed\n");
+
+ et131x_set_packet_filter(adapter);
+ } else {
+ DBG_VERBOSE(et131x_dbginfo,
+ "NO UPDATE REQUIRED, FLAGS didn't change\n");
+ }
+
+ spin_unlock_irqrestore(&adapter->Lock, lockflags);
+
+ DBG_LEAVE(et131x_dbginfo);
+}
+
+/**
+ * et131x_tx - The handler to tx a packet on the device
+ * @skb: data to be Tx'd
+ * @netdev: device on which data is to be Tx'd
+ *
+ * Returns 0 on success, errno on failure (as defined in errno.h)
+ */
+int et131x_tx(struct sk_buff *skb, struct net_device *netdev)
+{
+ int status = 0;
+
+ DBG_TX_ENTER(et131x_dbginfo);
+
+ /* Save the timestamp for the TX timeout watchdog */
+ netdev->trans_start = jiffies;
+
+ /* Call the device-specific data Tx routine */
+ status = et131x_send_packets(skb, netdev);
+
+ /* Check status and manage the netif queue if necessary */
+ if (status != 0) {
+ if (status == -ENOMEM) {
+ DBG_VERBOSE(et131x_dbginfo,
+ "OUT OF TCBs; STOP NETIF QUEUE\n");
+
+ /* Put the queue to sleep until resources are
+ * available
+ */
+ netif_stop_queue(netdev);
+ status = 1;
+ } else {
+ DBG_WARNING(et131x_dbginfo,
+ "Misc error; drop packet\n");
+ status = 0;
+ }
+ }
+
+ DBG_TX_LEAVE(et131x_dbginfo);
+ return status;
+}
+
+/**
+ * et131x_tx_timeout - Timeout handler
+ * @netdev: a pointer to a net_device struct representing the device
+ *
+ * The handler called when a Tx request times out. The timeout period is
+ * specified by the 'tx_timeo" element in the net_device structure (see
+ * et131x_alloc_device() to see how this value is set).
+ */
+void et131x_tx_timeout(struct net_device *netdev)
+{
+ struct et131x_adapter *pAdapter = netdev_priv(netdev);
+ PMP_TCB pMpTcb;
+ unsigned long lockflags;
+
+ DBG_WARNING(et131x_dbginfo, "TX TIMEOUT\n");
+
+ /* Just skip this part if the adapter is doing link detection */
+ if (MP_TEST_FLAG(pAdapter, fMP_ADAPTER_LINK_DETECTION)) {
+ DBG_ERROR(et131x_dbginfo, "Still doing link detection\n");
+ return;
+ }
+
+ /* Any nonrecoverable hardware error?
+ * Checks adapter->flags for any failure in phy reading
+ */
+ if (MP_TEST_FLAG(pAdapter, fMP_ADAPTER_NON_RECOVER_ERROR)) {
+ DBG_WARNING(et131x_dbginfo, "Non recoverable error - remove\n");
+ return;
+ }
+
+ /* Hardware failure? */
+ if (MP_TEST_FLAG(pAdapter, fMP_ADAPTER_HARDWARE_ERROR)) {
+ DBG_WARNING(et131x_dbginfo, "hardware error - reset\n");
+ return;
+ }
+
+ /* Is send stuck? */
+ spin_lock_irqsave(&pAdapter->TCBSendQLock, lockflags);
+
+ pMpTcb = pAdapter->TxRing.CurrSendHead;
+
+ if (pMpTcb != NULL) {
+ pMpTcb->Count++;
+
+ if (pMpTcb->Count > NIC_SEND_HANG_THRESHOLD) {
+#ifdef CONFIG_ET131X_DEBUG
+ TX_STATUS_BLOCK_t txDmaComplete =
+ *(pAdapter->TxRing.pTxStatusVa);
+ PTX_DESC_ENTRY_t pDesc =
+ pAdapter->TxRing.pTxDescRingVa +
+ pMpTcb->WrIndex.bits.val;
+#endif
+ TX_DESC_ENTRY_t StuckDescriptors[10];
+
+ if (pMpTcb->WrIndex.bits.val > 7) {
+ memcpy(StuckDescriptors,
+ pAdapter->TxRing.pTxDescRingVa +
+ pMpTcb->WrIndex.bits.val - 6,
+ sizeof(TX_DESC_ENTRY_t) * 10);
+ }
+
+ spin_unlock_irqrestore(&pAdapter->TCBSendQLock,
+ lockflags);
+
+ DBG_WARNING(et131x_dbginfo,
+ "Send stuck - reset. pMpTcb->WrIndex %x, Flags 0x%08x\n",
+ pMpTcb->WrIndex.bits.val,
+ pMpTcb->Flags);
+
+ DBG_WARNING(et131x_dbginfo,
+ "pDesc 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
+ pDesc->DataBufferPtrHigh,
+ pDesc->DataBufferPtrLow, pDesc->word2.value,
+ pDesc->word3.value);
+
+ DBG_WARNING(et131x_dbginfo,
+ "WbStatus 0x%08x\n", txDmaComplete.value);
+
+#ifdef CONFIG_ET131X_DEBUG
+ DumpDeviceBlock(DBG_WARNING_ON, pAdapter, 0);
+ DumpDeviceBlock(DBG_WARNING_ON, pAdapter, 1);
+ DumpDeviceBlock(DBG_WARNING_ON, pAdapter, 3);
+ DumpDeviceBlock(DBG_WARNING_ON, pAdapter, 5);
+#endif
+ et131x_close(netdev);
+ et131x_open(netdev);
+
+ return;
+ }
+ }
+
+ spin_unlock_irqrestore(&pAdapter->TCBSendQLock, lockflags);
+}
+
+/**
+ * et131x_change_mtu - The handler called to change the MTU for the device
+ * @netdev: device whose MTU is to be changed
+ * @new_mtu: the desired MTU
+ *
+ * Returns 0 on success, errno on failure (as defined in errno.h)
+ */
+int et131x_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ int result = 0;
+ struct et131x_adapter *adapter = netdev_priv(netdev);
+
+ DBG_ENTER(et131x_dbginfo);
+
+ /* Make sure the requested MTU is valid */
+ if (new_mtu == 0 || new_mtu > 9216) {
+ DBG_LEAVE(et131x_dbginfo);
+ return -EINVAL;
+ }
+
+ /* Stop the netif queue */
+ netif_stop_queue(netdev);
+
+ /* Stop the Tx and Rx DMA engines */
+ et131x_rx_dma_disable(adapter);
+ et131x_tx_dma_disable(adapter);
+
+ /* Disable device interrupts */
+ et131x_disable_interrupts(adapter);
+ et131x_handle_send_interrupt(adapter);
+ et131x_handle_recv_interrupt(adapter);
+
+ /* Set the new MTU */
+ netdev->mtu = new_mtu;
+
+ /* Free Rx DMA memory */
+ et131x_adapter_memory_free(adapter);
+
+ /* Set the config parameter for Jumbo Packet support */
+ adapter->RegistryJumboPacket = new_mtu + 14;
+ et131x_soft_reset(adapter);
+
+ /* Alloc and init Rx DMA memory */
+ result = et131x_adapter_memory_alloc(adapter);
+ if (result != 0) {
+ DBG_WARNING(et131x_dbginfo,
+ "Change MTU failed; couldn't re-alloc DMA memory\n");
+ return result;
+ }
+
+ et131x_init_send(adapter);
+
+ et131x_setup_hardware_properties(adapter);
+ memcpy(netdev->dev_addr, adapter->CurrentAddress, ETH_ALEN);
+
+ /* Init the device with the new settings */
+ et131x_adapter_setup(adapter);
+
+ /* Enable interrupts */
+ if (MP_TEST_FLAG(adapter, fMP_ADAPTER_INTERRUPT_IN_USE)) {
+ et131x_enable_interrupts(adapter);
+ }
+
+ /* Restart the Tx and Rx DMA engines */
+ et131x_rx_dma_enable(adapter);
+ et131x_tx_dma_enable(adapter);
+
+ /* Restart the netif queue */
+ netif_wake_queue(netdev);
+
+ DBG_LEAVE(et131x_dbginfo);
+ return result;
+}
+
+/**
+ * et131x_set_mac_addr - handler to change the MAC address for the device
+ * @netdev: device whose MAC is to be changed
+ * @new_mac: the desired MAC address
+ *
+ * Returns 0 on success, errno on failure (as defined in errno.h)
+ *
+ * IMPLEMENTED BY : blux http://berndlux.de 22.01.2007 21:14
+ */
+int et131x_set_mac_addr(struct net_device *netdev, void *new_mac)
+{
+ int result = 0;
+ struct et131x_adapter *adapter = netdev_priv(netdev);
+ struct sockaddr *address = new_mac;
+
+ DBG_ENTER(et131x_dbginfo);
+ // begin blux
+ // DBG_VERBOSE( et131x_dbginfo, "Function not implemented!!\n" );
+
+ if (adapter == NULL) {
+ DBG_LEAVE(et131x_dbginfo);
+ return -ENODEV;
+ }
+
+ /* Make sure the requested MAC is valid */
+ if (!is_valid_ether_addr(address->sa_data)) {
+ DBG_LEAVE(et131x_dbginfo);
+ return -EINVAL;
+ }
+
+ /* Stop the netif queue */
+ netif_stop_queue(netdev);
+
+ /* Stop the Tx and Rx DMA engines */
+ et131x_rx_dma_disable(adapter);
+ et131x_tx_dma_disable(adapter);
+
+ /* Disable device interrupts */
+ et131x_disable_interrupts(adapter);
+ et131x_handle_send_interrupt(adapter);
+ et131x_handle_recv_interrupt(adapter);
+
+ /* Set the new MAC */
+ // netdev->set_mac_address = &new_mac;
+ // netdev->mtu = new_mtu;
+
+ memcpy(netdev->dev_addr, address->sa_data, netdev->addr_len);
+
+ printk("%s: Setting MAC address to %02x:%02x:%02x:%02x:%02x:%02x\n",
+ netdev->name, netdev->dev_addr[0], netdev->dev_addr[1],
+ netdev->dev_addr[2], netdev->dev_addr[3], netdev->dev_addr[4],
+ netdev->dev_addr[5]);
+
+ /* Free Rx DMA memory */
+ et131x_adapter_memory_free(adapter);
+
+ /* Set the config parameter for Jumbo Packet support */
+ // adapter->RegistryJumboPacket = new_mtu + 14;
+ // blux: not needet here, w'll change the MAC
+
+ et131x_soft_reset(adapter);
+
+ /* Alloc and init Rx DMA memory */
+ result = et131x_adapter_memory_alloc(adapter);
+ if (result != 0) {
+ DBG_WARNING(et131x_dbginfo,
+ "Change MAC failed; couldn't re-alloc DMA memory\n");
+ return result;
+ }
+
+ et131x_init_send(adapter);
+
+ et131x_setup_hardware_properties(adapter);
+ // memcpy( netdev->dev_addr, adapter->CurrentAddress, ETH_ALEN );
+ // blux: no, do not override our nice address
+
+ /* Init the device with the new settings */
+ et131x_adapter_setup(adapter);
+
+ /* Enable interrupts */
+ if (MP_TEST_FLAG(adapter, fMP_ADAPTER_INTERRUPT_IN_USE)) {
+ et131x_enable_interrupts(adapter);
+ }
+
+ /* Restart the Tx and Rx DMA engines */
+ et131x_rx_dma_enable(adapter);
+ et131x_tx_dma_enable(adapter);
+
+ /* Restart the netif queue */
+ netif_wake_queue(netdev);
+
+ DBG_LEAVE(et131x_dbginfo);
+ return result;
+}
diff --git a/drivers/staging/et131x/et131x_netdev.h b/drivers/staging/et131x/et131x_netdev.h
new file mode 100644
index 0000000..b8acd14
--- /dev/null
+++ b/drivers/staging/et131x/et131x_netdev.h
@@ -0,0 +1,64 @@
+/*
+ * Agere Systems Inc.
+ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * et131x_netdev.h - Defines, structs, enums, prototypes, etc. related to the
+ * driver's net_device support.
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#ifndef __ET131X_NETDEV_H__
+#define __ET131X_NETDEV_H__
+
+struct net_device *et131x_device_alloc(void);
+
+#endif /* __ET131X_NETDEV_H__ */
diff --git a/drivers/staging/et131x/et131x_version.h b/drivers/staging/et131x/et131x_version.h
new file mode 100644
index 0000000..2ea645e
--- /dev/null
+++ b/drivers/staging/et131x/et131x_version.h
@@ -0,0 +1,81 @@
+/*
+ * Agere Systems Inc.
+ * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ * http://www.agere.com
+ *
+ *------------------------------------------------------------------------------
+ *
+ * et131x_version.h - This file provides system and device version information.
+ *
+ *------------------------------------------------------------------------------
+ *
+ * SOFTWARE LICENSE
+ *
+ * This software is provided subject to the following terms and conditions,
+ * which you should read carefully before using the software. Using this
+ * software indicates your acceptance of these terms and conditions. If you do
+ * not agree with these terms and conditions, do not use the software.
+ *
+ * Copyright © 2005 Agere Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source or binary forms, with or without
+ * modifications, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following Disclaimer as comments in the code as
+ * well as in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following Disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name of Agere Systems Inc. nor the names of the contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Disclaimer
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY
+ * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN
+ * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#ifndef __ET131X_VERSION_H__
+#define __ET131X_VERSION_H__
+
+#define DRIVER_AUTHOR "Victor Soriano (vjsoriano@agere.com)"
+#define DRIVER_LICENSE "Dual BSD/GPL"
+#define DRIVER_DEVICE_STRING "ET1310"
+#define DRIVER_NAME "et131x"
+#define DRIVER_MAJOR_VERSION 1
+#define DRIVER_MINOR_VERSION 2
+#define DRIVER_PATCH_VERSION 3
+#define DRIVER_VERSION_STRING "1.2.3"
+#define DRIVER_VENDOR "Agere Systems, http://www.agere.com"
+#define DRIVER_DESC "10/100/1000 Base-T Ethernet Driver"
+
+#define STRUCT_MODULE "net" /* blux: missed by the kernel */
+
+#define DRIVER_INFO DRIVER_DESC " for the "\
+ DRIVER_DEVICE_STRING ", v" \
+ DRIVER_VERSION_STRING " by " \
+ DRIVER_VENDOR
+
+#define DRIVER_NAME_EXT "et131x.ko"
+
+#endif /* __ET131X_VERSION_H__ */
--
1.6.0.2
^ permalink raw reply related [flat|nested] 37+ messages in thread* [PATCH 09/23] Staging: add me4000 pci data collection driver
2008-10-10 22:41 [GIT PATCH] STAGING patches for 2.6.28 Greg KH
` (4 preceding siblings ...)
2008-10-10 22:42 ` [PATCH 05/23] Staging: add et131x network driver Greg KH
@ 2008-10-10 22:42 ` Greg KH
2008-10-15 8:41 ` Andrew Morton
2008-10-10 22:42 ` [PATCH 10/23] Staging: add the go7007 video driver Greg KH
` (13 subsequent siblings)
19 siblings, 1 reply; 37+ messages in thread
From: Greg KH @ 2008-10-10 22:42 UTC (permalink / raw)
To: linux-kernel; +Cc: Greg Kroah-Hartman, Wolfgang Beiter, Guenter Gebhardt
From: Greg Kroah-Hartman <gregkh@suse.de>
Originally written by Guenter Gebhardt <g.gebhardt@meilhaus.de>
TODO:
- checkpatch.pl cleanups
- sparse cleanups
- possible /proc interaction cleanups
- more info needed for Kconfig entry
- real device id?
- module parameter cleanup
Cc: Wolfgang Beiter <w.beiter@aon.at>
Cc: Guenter Gebhardt <g.gebhardt@meilhaus.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/Kconfig | 2 +
drivers/staging/Makefile | 1 +
drivers/staging/me4000/Kconfig | 10 +
drivers/staging/me4000/Makefile | 1 +
drivers/staging/me4000/README | 13 +
drivers/staging/me4000/me4000.c | 6133 +++++++++++++++++++++++++++++++++++++++
drivers/staging/me4000/me4000.h | 954 ++++++
7 files changed, 7114 insertions(+), 0 deletions(-)
create mode 100644 drivers/staging/me4000/Kconfig
create mode 100644 drivers/staging/me4000/Makefile
create mode 100644 drivers/staging/me4000/README
create mode 100644 drivers/staging/me4000/me4000.c
create mode 100644 drivers/staging/me4000/me4000.h
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 6da7662..56c73bc 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -29,4 +29,6 @@ source "drivers/staging/slicoss/Kconfig"
source "drivers/staging/sxg/Kconfig"
+source "drivers/staging/me4000/Kconfig"
+
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index cd6d6a5..97df19b 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -3,3 +3,4 @@
obj-$(CONFIG_ET131X) += et131x/
obj-$(CONFIG_SLICOSS) += slicoss/
obj-$(CONFIG_SXG) += sxg/
+obj-$(CONFIG_ME4000) += me4000/
diff --git a/drivers/staging/me4000/Kconfig b/drivers/staging/me4000/Kconfig
new file mode 100644
index 0000000..5e6c9de
--- /dev/null
+++ b/drivers/staging/me4000/Kconfig
@@ -0,0 +1,10 @@
+config ME4000
+ tristate "Meilhaus ME-4000 support"
+ default n
+ depends on PCI
+ help
+ This driver supports the Meilhaus ME-4000 family of boards
+ that do data collection and multipurpose I/O.
+
+ To compile this driver as a module, choose M here: the module
+ will be called me4000.
diff --git a/drivers/staging/me4000/Makefile b/drivers/staging/me4000/Makefile
new file mode 100644
index 0000000..74487cd
--- /dev/null
+++ b/drivers/staging/me4000/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_ME4000) += me4000.o
diff --git a/drivers/staging/me4000/README b/drivers/staging/me4000/README
new file mode 100644
index 0000000..bbb8386
--- /dev/null
+++ b/drivers/staging/me4000/README
@@ -0,0 +1,13 @@
+
+TODO:
+ - checkpatch.pl cleanups
+ - sparse cleanups
+ - possible /proc interaction cleanups
+ - more info needed for Kconfig entry
+ - real device id?
+ - module parameter cleanup
+
+Please send patches to Greg Kroah-Hartman <gregkh@suse.de>
+and Cc: Wolfgang Beiter <w.beiter@aon.at> and
+Guenter Gebhardt <g.gebhardt@meilhaus.de>
+
diff --git a/drivers/staging/me4000/me4000.c b/drivers/staging/me4000/me4000.c
new file mode 100644
index 0000000..862dd7f
--- /dev/null
+++ b/drivers/staging/me4000/me4000.c
@@ -0,0 +1,6133 @@
+/* Device driver for Meilhaus ME-4000 board family.
+ * ================================================
+ *
+ * Copyright (C) 2003 Meilhaus Electronic GmbH (support@meilhaus.de)
+ *
+ * This file 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Guenter Gebhardt <g.gebhardt@meilhaus.de>
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/unistd.h>
+#include <linux/list.h>
+#include <linux/proc_fs.h>
+
+#include <linux/poll.h>
+#include <linux/vmalloc.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <linux/types.h>
+
+#include <linux/slab.h>
+
+/* Include-File for the Meilhaus ME-4000 I/O board */
+#include "me4000.h"
+#include "me4000_firmware.h"
+#include "me4610_firmware.h"
+
+/* Administrative stuff for modinfo */
+MODULE_AUTHOR("Guenter Gebhardt <g.gebhardt@meilhaus.de>");
+MODULE_DESCRIPTION
+ ("Device Driver Module for Meilhaus ME-4000 boards version 1.0.5");
+MODULE_SUPPORTED_DEVICE("Meilhaus ME-4000 Multi I/O boards");
+MODULE_LICENSE("GPL");
+
+/* Board specific data are kept in a global list */
+LIST_HEAD(me4000_board_info_list);
+
+/* Major Device Numbers. 0 means to get it automatically from the System */
+static int me4000_ao_major_driver_no = 0;
+static int me4000_ai_major_driver_no = 0;
+static int me4000_dio_major_driver_no = 0;
+static int me4000_cnt_major_driver_no = 0;
+static int me4000_ext_int_major_driver_no = 0;
+
+/* Let the user specify a custom major driver number */
+module_param(me4000_ao_major_driver_no, int, 0);
+MODULE_PARM_DESC(me4000_ao_major_driver_no,
+ "Major driver number for analog output (default 0)");
+
+module_param(me4000_ai_major_driver_no, int, 0);
+MODULE_PARM_DESC(me4000_ai_major_driver_no,
+ "Major driver number for analog input (default 0)");
+
+module_param(me4000_dio_major_driver_no, int, 0);
+MODULE_PARM_DESC(me4000_dio_major_driver_no,
+ "Major driver number digital I/O (default 0)");
+
+module_param(me4000_cnt_major_driver_no, int, 0);
+MODULE_PARM_DESC(me4000_cnt_major_driver_no,
+ "Major driver number for counter (default 0)");
+
+module_param(me4000_ext_int_major_driver_no, int, 0);
+MODULE_PARM_DESC(me4000_ext_int_major_driver_no,
+ "Major driver number for external interrupt (default 0)");
+
+/*-----------------------------------------------------------------------------
+ Module stuff
+ ---------------------------------------------------------------------------*/
+int init_module(void);
+void cleanup_module(void);
+
+/*-----------------------------------------------------------------------------
+ Board detection and initialization
+ ---------------------------------------------------------------------------*/
+static int me4000_probe(struct pci_dev *dev, const struct pci_device_id *id);
+static int me4000_xilinx_download(me4000_info_t *);
+static int me4000_reset_board(me4000_info_t *);
+
+static void clear_board_info_list(void);
+static int get_registers(struct pci_dev *dev, me4000_info_t * info);
+static int init_board_info(struct pci_dev *dev, me4000_info_t * board_info);
+static int alloc_ao_contexts(me4000_info_t * info);
+static void release_ao_contexts(me4000_info_t * board_info);
+static int alloc_ai_context(me4000_info_t * info);
+static int alloc_dio_context(me4000_info_t * info);
+static int alloc_cnt_context(me4000_info_t * info);
+static int alloc_ext_int_context(me4000_info_t * info);
+
+/*-----------------------------------------------------------------------------
+ Stuff used by all device parts
+ ---------------------------------------------------------------------------*/
+static int me4000_open(struct inode *, struct file *);
+static int me4000_release(struct inode *, struct file *);
+
+static int me4000_get_user_info(me4000_user_info_t *,
+ me4000_info_t * board_info);
+static int me4000_read_procmem(char *, char **, off_t, int, int *, void *);
+
+/*-----------------------------------------------------------------------------
+ Analog output stuff
+ ---------------------------------------------------------------------------*/
+static ssize_t me4000_ao_write_sing(struct file *, const char *, size_t,
+ loff_t *);
+static ssize_t me4000_ao_write_wrap(struct file *, const char *, size_t,
+ loff_t *);
+static ssize_t me4000_ao_write_cont(struct file *, const char *, size_t,
+ loff_t *);
+
+static int me4000_ao_ioctl_sing(struct inode *, struct file *, unsigned int,
+ unsigned long);
+static int me4000_ao_ioctl_wrap(struct inode *, struct file *, unsigned int,
+ unsigned long);
+static int me4000_ao_ioctl_cont(struct inode *, struct file *, unsigned int,
+ unsigned long);
+
+static unsigned int me4000_ao_poll_cont(struct file *, poll_table *);
+static int me4000_ao_fsync_cont(struct file *, struct dentry *, int);
+
+static int me4000_ao_start(unsigned long *, me4000_ao_context_t *);
+static int me4000_ao_stop(me4000_ao_context_t *);
+static int me4000_ao_immediate_stop(me4000_ao_context_t *);
+static int me4000_ao_timer_set_divisor(u32 *, me4000_ao_context_t *);
+static int me4000_ao_preload(me4000_ao_context_t *);
+static int me4000_ao_preload_update(me4000_ao_context_t *);
+static int me4000_ao_ex_trig_set_edge(int *, me4000_ao_context_t *);
+static int me4000_ao_ex_trig_enable(me4000_ao_context_t *);
+static int me4000_ao_ex_trig_disable(me4000_ao_context_t *);
+static int me4000_ao_prepare(me4000_ao_context_t * ao_info);
+static int me4000_ao_reset(me4000_ao_context_t * ao_info);
+static int me4000_ao_enable_do(me4000_ao_context_t *);
+static int me4000_ao_disable_do(me4000_ao_context_t *);
+static int me4000_ao_fsm_state(int *, me4000_ao_context_t *);
+
+static int me4000_ao_simultaneous_ex_trig(me4000_ao_context_t * ao_context);
+static int me4000_ao_simultaneous_sw(me4000_ao_context_t * ao_context);
+static int me4000_ao_simultaneous_disable(me4000_ao_context_t * ao_context);
+static int me4000_ao_simultaneous_update(me4000_ao_channel_list_t * channels,
+ me4000_ao_context_t * ao_context);
+
+static int me4000_ao_synchronous_ex_trig(me4000_ao_context_t * ao_context);
+static int me4000_ao_synchronous_sw(me4000_ao_context_t * ao_context);
+static int me4000_ao_synchronous_disable(me4000_ao_context_t * ao_context);
+
+static int me4000_ao_ex_trig_timeout(unsigned long *arg,
+ me4000_ao_context_t * ao_context);
+static int me4000_ao_get_free_buffer(unsigned long *arg,
+ me4000_ao_context_t * ao_context);
+
+/*-----------------------------------------------------------------------------
+ Analog input stuff
+ ---------------------------------------------------------------------------*/
+static int me4000_ai_single(me4000_ai_single_t *, me4000_ai_context_t *);
+static int me4000_ai_ioctl_sing(struct inode *, struct file *, unsigned int,
+ unsigned long);
+
+static ssize_t me4000_ai_read(struct file *, char *, size_t, loff_t *);
+static int me4000_ai_ioctl_sw(struct inode *, struct file *, unsigned int,
+ unsigned long);
+static unsigned int me4000_ai_poll(struct file *, poll_table *);
+static int me4000_ai_fasync(int fd, struct file *file_p, int mode);
+
+static int me4000_ai_ioctl_ext(struct inode *, struct file *, unsigned int,
+ unsigned long);
+
+static int me4000_ai_prepare(me4000_ai_context_t * ai_context);
+static int me4000_ai_reset(me4000_ai_context_t * ai_context);
+static int me4000_ai_config(me4000_ai_config_t *, me4000_ai_context_t *);
+static int me4000_ai_start(me4000_ai_context_t *);
+static int me4000_ai_start_ex(unsigned long *, me4000_ai_context_t *);
+static int me4000_ai_stop(me4000_ai_context_t *);
+static int me4000_ai_immediate_stop(me4000_ai_context_t *);
+static int me4000_ai_ex_trig_enable(me4000_ai_context_t *);
+static int me4000_ai_ex_trig_disable(me4000_ai_context_t *);
+static int me4000_ai_ex_trig_setup(me4000_ai_trigger_t *,
+ me4000_ai_context_t *);
+static int me4000_ai_sc_setup(me4000_ai_sc_t * arg,
+ me4000_ai_context_t * ai_context);
+static int me4000_ai_offset_enable(me4000_ai_context_t * ai_context);
+static int me4000_ai_offset_disable(me4000_ai_context_t * ai_context);
+static int me4000_ai_fullscale_enable(me4000_ai_context_t * ai_context);
+static int me4000_ai_fullscale_disable(me4000_ai_context_t * ai_context);
+static int me4000_ai_fsm_state(int *arg, me4000_ai_context_t * ai_context);
+static int me4000_ai_get_count_buffer(unsigned long *arg,
+ me4000_ai_context_t * ai_context);
+
+/*-----------------------------------------------------------------------------
+ EEPROM stuff
+ ---------------------------------------------------------------------------*/
+static int me4000_eeprom_read(me4000_eeprom_t * arg,
+ me4000_ai_context_t * ai_context);
+static int me4000_eeprom_write(me4000_eeprom_t * arg,
+ me4000_ai_context_t * ai_context);
+static unsigned short eeprom_read_cmd(me4000_ai_context_t * ai_context,
+ unsigned long cmd, int length);
+static int eeprom_write_cmd(me4000_ai_context_t * ai_context, unsigned long cmd,
+ int length);
+
+/*-----------------------------------------------------------------------------
+ Digital I/O stuff
+ ---------------------------------------------------------------------------*/
+static int me4000_dio_ioctl(struct inode *, struct file *, unsigned int,
+ unsigned long);
+static int me4000_dio_config(me4000_dio_config_t *, me4000_dio_context_t *);
+static int me4000_dio_get_byte(me4000_dio_byte_t *, me4000_dio_context_t *);
+static int me4000_dio_set_byte(me4000_dio_byte_t *, me4000_dio_context_t *);
+static int me4000_dio_reset(me4000_dio_context_t *);
+
+/*-----------------------------------------------------------------------------
+ Counter stuff
+ ---------------------------------------------------------------------------*/
+static int me4000_cnt_ioctl(struct inode *, struct file *, unsigned int,
+ unsigned long);
+static int me4000_cnt_config(me4000_cnt_config_t *, me4000_cnt_context_t *);
+static int me4000_cnt_read(me4000_cnt_t *, me4000_cnt_context_t *);
+static int me4000_cnt_write(me4000_cnt_t *, me4000_cnt_context_t *);
+static int me4000_cnt_reset(me4000_cnt_context_t *);
+
+/*-----------------------------------------------------------------------------
+ External interrupt routines
+ ---------------------------------------------------------------------------*/
+static int me4000_ext_int_ioctl(struct inode *, struct file *, unsigned int,
+ unsigned long);
+static int me4000_ext_int_enable(me4000_ext_int_context_t *);
+static int me4000_ext_int_disable(me4000_ext_int_context_t *);
+static int me4000_ext_int_count(unsigned long *arg,
+ me4000_ext_int_context_t * ext_int_context);
+static int me4000_ext_int_fasync(int fd, struct file *file_ptr, int mode);
+
+/*-----------------------------------------------------------------------------
+ The interrupt service routines
+ ---------------------------------------------------------------------------*/
+static irqreturn_t me4000_ao_isr(int, void *);
+static irqreturn_t me4000_ai_isr(int, void *);
+static irqreturn_t me4000_ext_int_isr(int, void *);
+
+/*-----------------------------------------------------------------------------
+ Inline functions
+ ---------------------------------------------------------------------------*/
+static int inline me4000_buf_count(me4000_circ_buf_t, int);
+static int inline me4000_buf_space(me4000_circ_buf_t, int);
+static int inline me4000_space_to_end(me4000_circ_buf_t, int);
+static int inline me4000_values_to_end(me4000_circ_buf_t, int);
+
+static void inline me4000_outb(unsigned char value, unsigned long port);
+static void inline me4000_outl(unsigned long value, unsigned long port);
+static unsigned long inline me4000_inl(unsigned long port);
+static unsigned char inline me4000_inb(unsigned long port);
+
+static int me4000_buf_count(me4000_circ_buf_t buf, int size)
+{
+ return ((buf.head - buf.tail) & (size - 1));
+}
+
+static int me4000_buf_space(me4000_circ_buf_t buf, int size)
+{
+ return ((buf.tail - (buf.head + 1)) & (size - 1));
+}
+
+static int me4000_values_to_end(me4000_circ_buf_t buf, int size)
+{
+ int end;
+ int n;
+ end = size - buf.tail;
+ n = (buf.head + end) & (size - 1);
+ return (n < end) ? n : end;
+}
+
+static int me4000_space_to_end(me4000_circ_buf_t buf, int size)
+{
+ int end;
+ int n;
+
+ end = size - 1 - buf.head;
+ n = (end + buf.tail) & (size - 1);
+ return (n <= end) ? n : (end + 1);
+}
+
+static void me4000_outb(unsigned char value, unsigned long port)
+{
+ PORT_PDEBUG("--> 0x%02X port 0x%04lX\n", value, port);
+ outb(value, port);
+}
+
+static void me4000_outl(unsigned long value, unsigned long port)
+{
+ PORT_PDEBUG("--> 0x%08lX port 0x%04lX\n", value, port);
+ outl(value, port);
+}
+
+static unsigned long me4000_inl(unsigned long port)
+{
+ unsigned long value;
+ value = inl(port);
+ PORT_PDEBUG("<-- 0x%08lX port 0x%04lX\n", value, port);
+ return value;
+}
+
+static unsigned char me4000_inb(unsigned long port)
+{
+ unsigned char value;
+ value = inb(port);
+ PORT_PDEBUG("<-- 0x%08X port 0x%04lX\n", value, port);
+ return value;
+}
+
+struct pci_driver me4000_driver = {
+ .name = ME4000_NAME,
+ .id_table = me4000_pci_table,
+ .probe = me4000_probe
+};
+
+static struct file_operations me4000_ao_fops_sing = {
+ owner:THIS_MODULE,
+ write:me4000_ao_write_sing,
+ ioctl:me4000_ao_ioctl_sing,
+ open:me4000_open,
+ release:me4000_release,
+};
+
+static struct file_operations me4000_ao_fops_wrap = {
+ owner:THIS_MODULE,
+ write:me4000_ao_write_wrap,
+ ioctl:me4000_ao_ioctl_wrap,
+ open:me4000_open,
+ release:me4000_release,
+};
+
+static struct file_operations me4000_ao_fops_cont = {
+ owner:THIS_MODULE,
+ write:me4000_ao_write_cont,
+ poll:me4000_ao_poll_cont,
+ ioctl:me4000_ao_ioctl_cont,
+ open:me4000_open,
+ release:me4000_release,
+ fsync:me4000_ao_fsync_cont,
+};
+
+static struct file_operations me4000_ai_fops_sing = {
+ owner:THIS_MODULE,
+ ioctl:me4000_ai_ioctl_sing,
+ open:me4000_open,
+ release:me4000_release,
+};
+
+static struct file_operations me4000_ai_fops_cont_sw = {
+ owner:THIS_MODULE,
+ read:me4000_ai_read,
+ poll:me4000_ai_poll,
+ ioctl:me4000_ai_ioctl_sw,
+ open:me4000_open,
+ release:me4000_release,
+ fasync:me4000_ai_fasync,
+};
+
+static struct file_operations me4000_ai_fops_cont_et = {
+ owner:THIS_MODULE,
+ read:me4000_ai_read,
+ poll:me4000_ai_poll,
+ ioctl:me4000_ai_ioctl_ext,
+ open:me4000_open,
+ release:me4000_release,
+};
+
+static struct file_operations me4000_ai_fops_cont_et_value = {
+ owner:THIS_MODULE,
+ read:me4000_ai_read,
+ poll:me4000_ai_poll,
+ ioctl:me4000_ai_ioctl_ext,
+ open:me4000_open,
+ release:me4000_release,
+};
+
+static struct file_operations me4000_ai_fops_cont_et_chanlist = {
+ owner:THIS_MODULE,
+ read:me4000_ai_read,
+ poll:me4000_ai_poll,
+ ioctl:me4000_ai_ioctl_ext,
+ open:me4000_open,
+ release:me4000_release,
+};
+
+static struct file_operations me4000_dio_fops = {
+ owner:THIS_MODULE,
+ ioctl:me4000_dio_ioctl,
+ open:me4000_open,
+ release:me4000_release,
+};
+
+static struct file_operations me4000_cnt_fops = {
+ owner:THIS_MODULE,
+ ioctl:me4000_cnt_ioctl,
+ open:me4000_open,
+ release:me4000_release,
+};
+
+static struct file_operations me4000_ext_int_fops = {
+ owner:THIS_MODULE,
+ ioctl:me4000_ext_int_ioctl,
+ open:me4000_open,
+ release:me4000_release,
+ fasync:me4000_ext_int_fasync,
+};
+
+static struct file_operations *me4000_ao_fops_array[] = {
+ &me4000_ao_fops_sing, // single operations
+ &me4000_ao_fops_wrap, // wraparound operations
+ &me4000_ao_fops_cont, // continous operations
+};
+
+static struct file_operations *me4000_ai_fops_array[] = {
+ &me4000_ai_fops_sing, // single operations
+ &me4000_ai_fops_cont_sw, // continuous operations with software start
+ &me4000_ai_fops_cont_et, // continous operations with external trigger
+ &me4000_ai_fops_cont_et_value, // sample values by external trigger
+ &me4000_ai_fops_cont_et_chanlist, // work through one channel list by external trigger
+};
+
+int __init me4000_init_module(void)
+{
+ int result = 0;
+
+ CALL_PDEBUG("init_module() is executed\n");
+
+ /* Register driver capabilities */
+ result = pci_register_driver(&me4000_driver);
+ PDEBUG("init_module():%d devices detected\n", result);
+ if (result < 0) {
+ printk(KERN_ERR "ME4000:init_module():Can't register driver\n");
+ goto INIT_ERROR_1;
+ }
+
+ /* Allocate major number for analog output */
+ result =
+ register_chrdev(me4000_ao_major_driver_no, ME4000_AO_NAME,
+ &me4000_ao_fops_sing);
+ if (result < 0) {
+ printk(KERN_ERR "ME4000:init_module():Can't get AO major no\n");
+ goto INIT_ERROR_2;
+ } else {
+ me4000_ao_major_driver_no = result;
+ }
+ PDEBUG("init_module():Major driver number for AO = %ld\n",
+ me4000_ao_major_driver_no);
+
+ /* Allocate major number for analog input */
+ result =
+ register_chrdev(me4000_ai_major_driver_no, ME4000_AI_NAME,
+ &me4000_ai_fops_sing);
+ if (result < 0) {
+ printk(KERN_ERR "ME4000:init_module():Can't get AI major no\n");
+ goto INIT_ERROR_3;
+ } else {
+ me4000_ai_major_driver_no = result;
+ }
+ PDEBUG("init_module():Major driver number for AI = %ld\n",
+ me4000_ai_major_driver_no);
+
+ /* Allocate major number for digital I/O */
+ result =
+ register_chrdev(me4000_dio_major_driver_no, ME4000_DIO_NAME,
+ &me4000_dio_fops);
+ if (result < 0) {
+ printk(KERN_ERR
+ "ME4000:init_module():Can't get DIO major no\n");
+ goto INIT_ERROR_4;
+ } else {
+ me4000_dio_major_driver_no = result;
+ }
+ PDEBUG("init_module():Major driver number for DIO = %ld\n",
+ me4000_dio_major_driver_no);
+
+ /* Allocate major number for counter */
+ result =
+ register_chrdev(me4000_cnt_major_driver_no, ME4000_CNT_NAME,
+ &me4000_cnt_fops);
+ if (result < 0) {
+ printk(KERN_ERR
+ "ME4000:init_module():Can't get CNT major no\n");
+ goto INIT_ERROR_5;
+ } else {
+ me4000_cnt_major_driver_no = result;
+ }
+ PDEBUG("init_module():Major driver number for CNT = %ld\n",
+ me4000_cnt_major_driver_no);
+
+ /* Allocate major number for external interrupt */
+ result =
+ register_chrdev(me4000_ext_int_major_driver_no, ME4000_EXT_INT_NAME,
+ &me4000_ext_int_fops);
+ if (result < 0) {
+ printk(KERN_ERR
+ "ME4000:init_module():Can't get major no for external interrupt\n");
+ goto INIT_ERROR_6;
+ } else {
+ me4000_ext_int_major_driver_no = result;
+ }
+ PDEBUG
+ ("init_module():Major driver number for external interrupt = %ld\n",
+ me4000_ext_int_major_driver_no);
+
+ /* Create the /proc/me4000 entry */
+ if (!create_proc_read_entry
+ ("me4000", 0, NULL, me4000_read_procmem, NULL)) {
+ result = -ENODEV;
+ printk(KERN_ERR
+ "ME4000:init_module():Can't create proc entry\n");
+ goto INIT_ERROR_7;
+ }
+
+ return 0;
+
+ INIT_ERROR_7:
+ unregister_chrdev(me4000_ext_int_major_driver_no, ME4000_EXT_INT_NAME);
+
+ INIT_ERROR_6:
+ unregister_chrdev(me4000_cnt_major_driver_no, ME4000_CNT_NAME);
+
+ INIT_ERROR_5:
+ unregister_chrdev(me4000_dio_major_driver_no, ME4000_DIO_NAME);
+
+ INIT_ERROR_4:
+ unregister_chrdev(me4000_ai_major_driver_no, ME4000_AI_NAME);
+
+ INIT_ERROR_3:
+ unregister_chrdev(me4000_ao_major_driver_no, ME4000_AO_NAME);
+
+ INIT_ERROR_2:
+ pci_unregister_driver(&me4000_driver);
+ clear_board_info_list();
+
+ INIT_ERROR_1:
+ return result;
+}
+
+module_init(me4000_init_module);
+
+static void clear_board_info_list(void)
+{
+ struct list_head *board_p;
+ struct list_head *dac_p;
+ me4000_info_t *board_info;
+ me4000_ao_context_t *ao_context;
+
+ /* Clear context lists */
+ for (board_p = me4000_board_info_list.next;
+ board_p != &me4000_board_info_list; board_p = board_p->next) {
+ board_info = list_entry(board_p, me4000_info_t, list);
+ /* Clear analog output context list */
+ while (!list_empty(&board_info->ao_context_list)) {
+ dac_p = board_info->ao_context_list.next;
+ ao_context =
+ list_entry(dac_p, me4000_ao_context_t, list);
+ me4000_ao_reset(ao_context);
+ free_irq(ao_context->irq, ao_context);
+ if (ao_context->circ_buf.buf)
+ kfree(ao_context->circ_buf.buf);
+ list_del(dac_p);
+ kfree(ao_context);
+ }
+
+ /* Clear analog input context */
+ if (board_info->ai_context->circ_buf.buf)
+ kfree(board_info->ai_context->circ_buf.buf);
+ kfree(board_info->ai_context);
+
+ /* Clear digital I/O context */
+ kfree(board_info->dio_context);
+
+ /* Clear counter context */
+ kfree(board_info->cnt_context);
+
+ /* Clear external interrupt context */
+ kfree(board_info->ext_int_context);
+ }
+
+ /* Clear the board info list */
+ while (!list_empty(&me4000_board_info_list)) {
+ board_p = me4000_board_info_list.next;
+ board_info = list_entry(board_p, me4000_info_t, list);
+ pci_release_regions(board_info->pci_dev_p);
+ list_del(board_p);
+ kfree(board_info);
+ }
+}
+
+static int get_registers(struct pci_dev *dev, me4000_info_t * board_info)
+{
+
+ /*--------------------------- plx regbase ---------------------------------*/
+
+ board_info->plx_regbase = pci_resource_start(dev, 1);
+ if (board_info->plx_regbase == 0) {
+ printk(KERN_ERR
+ "ME4000:get_registers():PCI base address 1 is not available\n");
+ return -ENODEV;
+ }
+ board_info->plx_regbase_size = pci_resource_len(dev, 1);
+
+ PDEBUG
+ ("get_registers():PLX configuration registers at address 0x%4lX [0x%4lX]\n",
+ board_info->plx_regbase, board_info->plx_regbase_size);
+
+ /*--------------------------- me4000 regbase ------------------------------*/
+
+ board_info->me4000_regbase = pci_resource_start(dev, 2);
+ if (board_info->me4000_regbase == 0) {
+ printk(KERN_ERR
+ "ME4000:get_registers():PCI base address 2 is not available\n");
+ return -ENODEV;
+ }
+ board_info->me4000_regbase_size = pci_resource_len(dev, 2);
+
+ PDEBUG("get_registers():ME4000 registers at address 0x%4lX [0x%4lX]\n",
+ board_info->me4000_regbase, board_info->me4000_regbase_size);
+
+ /*--------------------------- timer regbase ------------------------------*/
+
+ board_info->timer_regbase = pci_resource_start(dev, 3);
+ if (board_info->timer_regbase == 0) {
+ printk(KERN_ERR
+ "ME4000:get_registers():PCI base address 3 is not available\n");
+ return -ENODEV;
+ }
+ board_info->timer_regbase_size = pci_resource_len(dev, 3);
+
+ PDEBUG("get_registers():Timer registers at address 0x%4lX [0x%4lX]\n",
+ board_info->timer_regbase, board_info->timer_regbase_size);
+
+ /*--------------------------- program regbase ------------------------------*/
+
+ board_info->program_regbase = pci_resource_start(dev, 5);
+ if (board_info->program_regbase == 0) {
+ printk(KERN_ERR
+ "get_registers():ME4000:PCI base address 5 is not available\n");
+ return -ENODEV;
+ }
+ board_info->program_regbase_size = pci_resource_len(dev, 5);
+
+ PDEBUG("get_registers():Program registers at address 0x%4lX [0x%4lX]\n",
+ board_info->program_regbase, board_info->program_regbase_size);
+
+ return 0;
+}
+
+static int init_board_info(struct pci_dev *pci_dev_p,
+ me4000_info_t * board_info)
+{
+ int i;
+ int result;
+ struct list_head *board_p;
+ board_info->pci_dev_p = pci_dev_p;
+
+ for (i = 0; i < ME4000_BOARD_VERSIONS; i++) {
+ if (me4000_boards[i].device_id == pci_dev_p->device) {
+ board_info->board_p = &me4000_boards[i];
+ break;
+ }
+ }
+ if (i == ME4000_BOARD_VERSIONS) {
+ printk(KERN_ERR
+ "ME4000:init_board_info():Device ID not valid\n");
+ return -ENODEV;
+ }
+
+ /* Get the index of the board in the global list */
+ for (board_p = me4000_board_info_list.next, i = 0;
+ board_p != &me4000_board_info_list; board_p = board_p->next, i++) {
+ if (board_p == &board_info->list) {
+ board_info->board_count = i;
+ break;
+ }
+ }
+ if (board_p == &me4000_board_info_list) {
+ printk(KERN_ERR
+ "ME4000:init_board_info():Cannot get index of baord\n");
+ return -ENODEV;
+ }
+
+ /* Init list head for analog output contexts */
+ INIT_LIST_HEAD(&board_info->ao_context_list);
+
+ /* Init spin locks */
+ spin_lock_init(&board_info->preload_lock);
+ spin_lock_init(&board_info->ai_ctrl_lock);
+
+ /* Get the serial number */
+ result = pci_read_config_dword(pci_dev_p, 0x2C, &board_info->serial_no);
+ if (result != PCIBIOS_SUCCESSFUL) {
+ printk(KERN_WARNING
+ "ME4000:init_board_info: Can't get serial_no\n");
+ return result;
+ }
+ PDEBUG("init_board_info():serial_no = 0x%x\n", board_info->serial_no);
+
+ /* Get the hardware revision */
+ result =
+ pci_read_config_byte(pci_dev_p, 0x08, &board_info->hw_revision);
+ if (result != PCIBIOS_SUCCESSFUL) {
+ printk(KERN_WARNING
+ "ME4000:init_board_info():Can't get hw_revision\n");
+ return result;
+ }
+ PDEBUG("init_board_info():hw_revision = 0x%x\n",
+ board_info->hw_revision);
+
+ /* Get the vendor id */
+ board_info->vendor_id = pci_dev_p->vendor;
+ PDEBUG("init_board_info():vendor_id = 0x%x\n", board_info->vendor_id);
+
+ /* Get the device id */
+ board_info->device_id = pci_dev_p->device;
+ PDEBUG("init_board_info():device_id = 0x%x\n", board_info->device_id);
+
+ /* Get the pci device number */
+ board_info->pci_dev_no = PCI_FUNC(pci_dev_p->devfn);
+ PDEBUG("init_board_info():pci_func_no = 0x%x\n",
+ board_info->pci_func_no);
+
+ /* Get the pci slot number */
+ board_info->pci_dev_no = PCI_SLOT(pci_dev_p->devfn);
+ PDEBUG("init_board_info():pci_dev_no = 0x%x\n", board_info->pci_dev_no);
+
+ /* Get the pci bus number */
+ board_info->pci_bus_no = pci_dev_p->bus->number;
+ PDEBUG("init_board_info():pci_bus_no = 0x%x\n", board_info->pci_bus_no);
+
+ /* Get the irq assigned to the board */
+ board_info->irq = pci_dev_p->irq;
+ PDEBUG("init_board_info():irq = %d\n", board_info->irq);
+
+ return 0;
+}
+
+static int alloc_ao_contexts(me4000_info_t * info)
+{
+ int i;
+ int err;
+ me4000_ao_context_t *ao_context;
+
+ for (i = 0; i < info->board_p->ao.count; i++) {
+ ao_context = kmalloc(sizeof(me4000_ao_context_t), GFP_KERNEL);
+ if (!ao_context) {
+ printk(KERN_ERR
+ "alloc_ao_contexts():Can't get memory for ao context\n");
+ release_ao_contexts(info);
+ return -ENOMEM;
+ }
+ memset(ao_context, 0, sizeof(me4000_ao_context_t));
+
+ spin_lock_init(&ao_context->use_lock);
+ spin_lock_init(&ao_context->int_lock);
+ ao_context->irq = info->irq;
+ init_waitqueue_head(&ao_context->wait_queue);
+ ao_context->board_info = info;
+
+ if (info->board_p->ao.fifo_count) {
+ /* Allocate circular buffer */
+ ao_context->circ_buf.buf =
+ kmalloc(ME4000_AO_BUFFER_SIZE, GFP_KERNEL);
+ if (!ao_context->circ_buf.buf) {
+ printk(KERN_ERR
+ "alloc_ao_contexts():Can't get circular buffer\n");
+ release_ao_contexts(info);
+ return -ENOMEM;
+ }
+ memset(ao_context->circ_buf.buf, 0,
+ ME4000_AO_BUFFER_SIZE);
+
+ /* Clear the circular buffer */
+ ao_context->circ_buf.head = 0;
+ ao_context->circ_buf.tail = 0;
+ }
+
+ switch (i) {
+ case 0:
+ ao_context->ctrl_reg =
+ info->me4000_regbase + ME4000_AO_00_CTRL_REG;
+ ao_context->status_reg =
+ info->me4000_regbase + ME4000_AO_00_STATUS_REG;
+ ao_context->fifo_reg =
+ info->me4000_regbase + ME4000_AO_00_FIFO_REG;
+ ao_context->single_reg =
+ info->me4000_regbase + ME4000_AO_00_SINGLE_REG;
+ ao_context->timer_reg =
+ info->me4000_regbase + ME4000_AO_00_TIMER_REG;
+ ao_context->irq_status_reg =
+ info->me4000_regbase + ME4000_IRQ_STATUS_REG;
+ ao_context->preload_reg =
+ info->me4000_regbase + ME4000_AO_LOADSETREG_XX;
+ break;
+ case 1:
+ ao_context->ctrl_reg =
+ info->me4000_regbase + ME4000_AO_01_CTRL_REG;
+ ao_context->status_reg =
+ info->me4000_regbase + ME4000_AO_01_STATUS_REG;
+ ao_context->fifo_reg =
+ info->me4000_regbase + ME4000_AO_01_FIFO_REG;
+ ao_context->single_reg =
+ info->me4000_regbase + ME4000_AO_01_SINGLE_REG;
+ ao_context->timer_reg =
+ info->me4000_regbase + ME4000_AO_01_TIMER_REG;
+ ao_context->irq_status_reg =
+ info->me4000_regbase + ME4000_IRQ_STATUS_REG;
+ ao_context->preload_reg =
+ info->me4000_regbase + ME4000_AO_LOADSETREG_XX;
+ break;
+ case 2:
+ ao_context->ctrl_reg =
+ info->me4000_regbase + ME4000_AO_02_CTRL_REG;
+ ao_context->status_reg =
+ info->me4000_regbase + ME4000_AO_02_STATUS_REG;
+ ao_context->fifo_reg =
+ info->me4000_regbase + ME4000_AO_02_FIFO_REG;
+ ao_context->single_reg =
+ info->me4000_regbase + ME4000_AO_02_SINGLE_REG;
+ ao_context->timer_reg =
+ info->me4000_regbase + ME4000_AO_02_TIMER_REG;
+ ao_context->irq_status_reg =
+ info->me4000_regbase + ME4000_IRQ_STATUS_REG;
+ ao_context->preload_reg =
+ info->me4000_regbase + ME4000_AO_LOADSETREG_XX;
+ break;
+ case 3:
+ ao_context->ctrl_reg =
+ info->me4000_regbase + ME4000_AO_03_CTRL_REG;
+ ao_context->status_reg =
+ info->me4000_regbase + ME4000_AO_03_STATUS_REG;
+ ao_context->fifo_reg =
+ info->me4000_regbase + ME4000_AO_03_FIFO_REG;
+ ao_context->single_reg =
+ info->me4000_regbase + ME4000_AO_03_SINGLE_REG;
+ ao_context->timer_reg =
+ info->me4000_regbase + ME4000_AO_03_TIMER_REG;
+ ao_context->irq_status_reg =
+ info->me4000_regbase + ME4000_IRQ_STATUS_REG;
+ ao_context->preload_reg =
+ info->me4000_regbase + ME4000_AO_LOADSETREG_XX;
+ break;
+ default:
+ break;
+ }
+
+ if (info->board_p->ao.fifo_count) {
+ /* Request the interrupt line */
+ err =
+ request_irq(ao_context->irq, me4000_ao_isr,
+ IRQF_DISABLED | IRQF_SHARED,
+ ME4000_NAME, ao_context);
+ if (err) {
+ printk(KERN_ERR
+ "alloc_ao_contexts():Can't get interrupt line");
+ if (ao_context->circ_buf.buf)
+ kfree(ao_context->circ_buf.buf);
+ kfree(ao_context);
+ release_ao_contexts(info);
+ return -ENODEV;
+ }
+ }
+
+ list_add_tail(&ao_context->list, &info->ao_context_list);
+ ao_context->index = i;
+ }
+
+ return 0;
+}
+
+static void release_ao_contexts(me4000_info_t * board_info)
+{
+ struct list_head *dac_p;
+ me4000_ao_context_t *ao_context;
+
+ /* Clear analog output context list */
+ while (!list_empty(&board_info->ao_context_list)) {
+ dac_p = board_info->ao_context_list.next;
+ ao_context = list_entry(dac_p, me4000_ao_context_t, list);
+ free_irq(ao_context->irq, ao_context);
+ if (ao_context->circ_buf.buf)
+ kfree(ao_context->circ_buf.buf);
+ list_del(dac_p);
+ kfree(ao_context);
+ }
+}
+
+static int alloc_ai_context(me4000_info_t * info)
+{
+ me4000_ai_context_t *ai_context;
+
+ if (info->board_p->ai.count) {
+ ai_context = kmalloc(sizeof(me4000_ai_context_t), GFP_KERNEL);
+ if (!ai_context) {
+ printk(KERN_ERR
+ "ME4000:alloc_ai_context():Can't get memory for ai context\n");
+ return -ENOMEM;
+ }
+ memset(ai_context, 0, sizeof(me4000_ai_context_t));
+
+ info->ai_context = ai_context;
+
+ spin_lock_init(&ai_context->use_lock);
+ spin_lock_init(&ai_context->int_lock);
+ ai_context->number = 0;
+ ai_context->irq = info->irq;
+ init_waitqueue_head(&ai_context->wait_queue);
+ ai_context->board_info = info;
+
+ ai_context->ctrl_reg =
+ info->me4000_regbase + ME4000_AI_CTRL_REG;
+ ai_context->status_reg =
+ info->me4000_regbase + ME4000_AI_STATUS_REG;
+ ai_context->channel_list_reg =
+ info->me4000_regbase + ME4000_AI_CHANNEL_LIST_REG;
+ ai_context->data_reg =
+ info->me4000_regbase + ME4000_AI_DATA_REG;
+ ai_context->chan_timer_reg =
+ info->me4000_regbase + ME4000_AI_CHAN_TIMER_REG;
+ ai_context->chan_pre_timer_reg =
+ info->me4000_regbase + ME4000_AI_CHAN_PRE_TIMER_REG;
+ ai_context->scan_timer_low_reg =
+ info->me4000_regbase + ME4000_AI_SCAN_TIMER_LOW_REG;
+ ai_context->scan_timer_high_reg =
+ info->me4000_regbase + ME4000_AI_SCAN_TIMER_HIGH_REG;
+ ai_context->scan_pre_timer_low_reg =
+ info->me4000_regbase + ME4000_AI_SCAN_PRE_TIMER_LOW_REG;
+ ai_context->scan_pre_timer_high_reg =
+ info->me4000_regbase + ME4000_AI_SCAN_PRE_TIMER_HIGH_REG;
+ ai_context->start_reg =
+ info->me4000_regbase + ME4000_AI_START_REG;
+ ai_context->irq_status_reg =
+ info->me4000_regbase + ME4000_IRQ_STATUS_REG;
+ ai_context->sample_counter_reg =
+ info->me4000_regbase + ME4000_AI_SAMPLE_COUNTER_REG;
+ }
+
+ return 0;
+}
+
+static int alloc_dio_context(me4000_info_t * info)
+{
+ me4000_dio_context_t *dio_context;
+
+ if (info->board_p->dio.count) {
+ dio_context = kmalloc(sizeof(me4000_dio_context_t), GFP_KERNEL);
+ if (!dio_context) {
+ printk(KERN_ERR
+ "ME4000:alloc_dio_context():Can't get memory for dio context\n");
+ return -ENOMEM;
+ }
+ memset(dio_context, 0, sizeof(me4000_dio_context_t));
+
+ info->dio_context = dio_context;
+
+ spin_lock_init(&dio_context->use_lock);
+ dio_context->board_info = info;
+
+ dio_context->dio_count = info->board_p->dio.count;
+
+ dio_context->dir_reg =
+ info->me4000_regbase + ME4000_DIO_DIR_REG;
+ dio_context->ctrl_reg =
+ info->me4000_regbase + ME4000_DIO_CTRL_REG;
+ dio_context->port_0_reg =
+ info->me4000_regbase + ME4000_DIO_PORT_0_REG;
+ dio_context->port_1_reg =
+ info->me4000_regbase + ME4000_DIO_PORT_1_REG;
+ dio_context->port_2_reg =
+ info->me4000_regbase + ME4000_DIO_PORT_2_REG;
+ dio_context->port_3_reg =
+ info->me4000_regbase + ME4000_DIO_PORT_3_REG;
+ }
+
+ return 0;
+}
+
+static int alloc_cnt_context(me4000_info_t * info)
+{
+ me4000_cnt_context_t *cnt_context;
+
+ if (info->board_p->cnt.count) {
+ cnt_context = kmalloc(sizeof(me4000_cnt_context_t), GFP_KERNEL);
+ if (!cnt_context) {
+ printk(KERN_ERR
+ "ME4000:alloc_cnt_context():Can't get memory for cnt context\n");
+ return -ENOMEM;
+ }
+ memset(cnt_context, 0, sizeof(me4000_cnt_context_t));
+
+ info->cnt_context = cnt_context;
+
+ spin_lock_init(&cnt_context->use_lock);
+ cnt_context->board_info = info;
+
+ cnt_context->ctrl_reg =
+ info->timer_regbase + ME4000_CNT_CTRL_REG;
+ cnt_context->counter_0_reg =
+ info->timer_regbase + ME4000_CNT_COUNTER_0_REG;
+ cnt_context->counter_1_reg =
+ info->timer_regbase + ME4000_CNT_COUNTER_1_REG;
+ cnt_context->counter_2_reg =
+ info->timer_regbase + ME4000_CNT_COUNTER_2_REG;
+ }
+
+ return 0;
+}
+
+static int alloc_ext_int_context(me4000_info_t * info)
+{
+ me4000_ext_int_context_t *ext_int_context;
+
+ if (info->board_p->cnt.count) {
+ ext_int_context =
+ kmalloc(sizeof(me4000_ext_int_context_t), GFP_KERNEL);
+ if (!ext_int_context) {
+ printk(KERN_ERR
+ "ME4000:alloc_ext_int_context():Can't get memory for cnt context\n");
+ return -ENOMEM;
+ }
+ memset(ext_int_context, 0, sizeof(me4000_ext_int_context_t));
+
+ info->ext_int_context = ext_int_context;
+
+ spin_lock_init(&ext_int_context->use_lock);
+ ext_int_context->board_info = info;
+
+ ext_int_context->fasync_ptr = NULL;
+ ext_int_context->irq = info->irq;
+
+ ext_int_context->ctrl_reg =
+ info->me4000_regbase + ME4000_AI_CTRL_REG;
+ ext_int_context->irq_status_reg =
+ info->me4000_regbase + ME4000_IRQ_STATUS_REG;
+ }
+
+ return 0;
+}
+
+static int me4000_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ int result = 0;
+ me4000_info_t *board_info;
+
+ CALL_PDEBUG("me4000_probe() is executed\n");
+
+ /* Allocate structure for board context */
+ board_info = kmalloc(sizeof(me4000_info_t), GFP_KERNEL);
+ if (!board_info) {
+ printk(KERN_ERR
+ "ME4000:Can't get memory for board info structure\n");
+ result = -ENOMEM;
+ goto PROBE_ERROR_1;
+ }
+ memset(board_info, 0, sizeof(me4000_info_t));
+
+ /* Add to global linked list */
+ list_add_tail(&board_info->list, &me4000_board_info_list);
+
+ /* Get the PCI base registers */
+ result = get_registers(dev, board_info);
+ if (result) {
+ printk(KERN_ERR "me4000_probe():Cannot get registers\n");
+ goto PROBE_ERROR_2;
+ }
+
+ /* Enable the device */
+ result = pci_enable_device(dev);
+ if (result < 0) {
+ printk(KERN_ERR "me4000_probe():Cannot enable PCI device\n");
+ goto PROBE_ERROR_2;
+ }
+
+ /* Request the PCI register regions */
+ result = pci_request_regions(dev, ME4000_NAME);
+ if (result < 0) {
+ printk(KERN_ERR "me4000_probe():Cannot request I/O regions\n");
+ goto PROBE_ERROR_2;
+ }
+
+ /* Initialize board info */
+ result = init_board_info(dev, board_info);
+ if (result) {
+ printk(KERN_ERR "me4000_probe():Cannot init baord info\n");
+ goto PROBE_ERROR_3;
+ }
+
+ /* Download the xilinx firmware */
+ result = me4000_xilinx_download(board_info);
+ if (result) {
+ printk(KERN_ERR "me4000_probe:Can't download firmware\n");
+ goto PROBE_ERROR_3;
+ }
+
+ /* Make a hardware reset */
+ result = me4000_reset_board(board_info);
+ if (result) {
+ printk(KERN_ERR "me4000_probe:Can't reset board\n");
+ goto PROBE_ERROR_3;
+ }
+
+ /* Allocate analog output context structures */
+ result = alloc_ao_contexts(board_info);
+ if (result) {
+ printk(KERN_ERR "me4000_probe():Cannot allocate ao contexts\n");
+ goto PROBE_ERROR_3;
+ }
+
+ /* Allocate analog input context */
+ result = alloc_ai_context(board_info);
+ if (result) {
+ printk(KERN_ERR "me4000_probe():Cannot allocate ai context\n");
+ goto PROBE_ERROR_4;
+ }
+
+ /* Allocate digital I/O context */
+ result = alloc_dio_context(board_info);
+ if (result) {
+ printk(KERN_ERR "me4000_probe():Cannot allocate dio context\n");
+ goto PROBE_ERROR_5;
+ }
+
+ /* Allocate counter context */
+ result = alloc_cnt_context(board_info);
+ if (result) {
+ printk(KERN_ERR "me4000_probe():Cannot allocate cnt context\n");
+ goto PROBE_ERROR_6;
+ }
+
+ /* Allocate external interrupt context */
+ result = alloc_ext_int_context(board_info);
+ if (result) {
+ printk(KERN_ERR
+ "me4000_probe():Cannot allocate ext_int context\n");
+ goto PROBE_ERROR_7;
+ }
+
+ return 0;
+
+ PROBE_ERROR_7:
+ kfree(board_info->cnt_context);
+
+ PROBE_ERROR_6:
+ kfree(board_info->dio_context);
+
+ PROBE_ERROR_5:
+ kfree(board_info->ai_context);
+
+ PROBE_ERROR_4:
+ release_ao_contexts(board_info);
+
+ PROBE_ERROR_3:
+ pci_release_regions(dev);
+
+ PROBE_ERROR_2:
+ list_del(&board_info->list);
+ kfree(board_info);
+
+ PROBE_ERROR_1:
+ return result;
+}
+
+static int me4000_xilinx_download(me4000_info_t * info)
+{
+ int size = 0;
+ u32 value = 0;
+ int idx = 0;
+ unsigned char *firm;
+ wait_queue_head_t queue;
+
+ CALL_PDEBUG("me4000_xilinx_download() is executed\n");
+
+ init_waitqueue_head(&queue);
+
+ firm = (info->device_id == 0x4610) ? xilinx_firm_4610 : xilinx_firm;
+
+ /*
+ * Set PLX local interrupt 2 polarity to high.
+ * Interrupt is thrown by init pin of xilinx.
+ */
+ outl(0x10, info->plx_regbase + PLX_INTCSR);
+
+ /* Set /CS and /WRITE of the Xilinx */
+ value = inl(info->plx_regbase + PLX_ICR);
+ value |= 0x100;
+ outl(value, info->plx_regbase + PLX_ICR);
+
+ /* Init Xilinx with CS1 */
+ inb(info->program_regbase + 0xC8);
+
+ /* Wait until /INIT pin is set */
+ udelay(20);
+ if (!inl(info->plx_regbase + PLX_INTCSR) & 0x20) {
+ printk(KERN_ERR "me4000_xilinx_download():Can't init Xilinx\n");
+ return -EIO;
+ }
+
+ /* Reset /CS and /WRITE of the Xilinx */
+ value = inl(info->plx_regbase + PLX_ICR);
+ value &= ~0x100;
+ outl(value, info->plx_regbase + PLX_ICR);
+
+ /* Download Xilinx firmware */
+ size = (firm[0] << 24) + (firm[1] << 16) + (firm[2] << 8) + firm[3];
+ udelay(10);
+
+ for (idx = 0; idx < size; idx++) {
+ outb(firm[16 + idx], info->program_regbase);
+
+ udelay(10);
+
+ /* Check if BUSY flag is low */
+ if (inl(info->plx_regbase + PLX_ICR) & 0x20) {
+ printk(KERN_ERR
+ "me4000_xilinx_download():Xilinx is still busy (idx = %d)\n",
+ idx);
+ return -EIO;
+ }
+ }
+
+ PDEBUG("me4000_xilinx_download():%d bytes written\n", idx);
+
+ /* If done flag is high download was successful */
+ if (inl(info->plx_regbase + PLX_ICR) & 0x4) {
+ PDEBUG("me4000_xilinx_download():Done flag is set\n");
+ PDEBUG("me4000_xilinx_download():Download was successful\n");
+ } else {
+ printk(KERN_ERR
+ "ME4000:me4000_xilinx_download():DONE flag is not set\n");
+ printk(KERN_ERR
+ "ME4000:me4000_xilinx_download():Download not succesful\n");
+ return -EIO;
+ }
+
+ /* Set /CS and /WRITE */
+ value = inl(info->plx_regbase + PLX_ICR);
+ value |= 0x100;
+ outl(value, info->plx_regbase + PLX_ICR);
+
+ return 0;
+}
+
+static int me4000_reset_board(me4000_info_t * info)
+{
+ unsigned long icr;
+
+ CALL_PDEBUG("me4000_reset_board() is executed\n");
+
+ /* Make a hardware reset */
+ icr = me4000_inl(info->plx_regbase + PLX_ICR);
+ icr |= 0x40000000;
+ me4000_outl(icr, info->plx_regbase + PLX_ICR);
+ icr &= ~0x40000000;
+ me4000_outl(icr, info->plx_regbase + PLX_ICR);
+
+ /* Set both stop bits in the analog input control register */
+ me4000_outl(ME4000_AI_CTRL_BIT_IMMEDIATE_STOP | ME4000_AI_CTRL_BIT_STOP,
+ info->me4000_regbase + ME4000_AI_CTRL_REG);
+
+ /* Set both stop bits in the analog output control register */
+ me4000_outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP,
+ info->me4000_regbase + ME4000_AO_00_CTRL_REG);
+ me4000_outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP,
+ info->me4000_regbase + ME4000_AO_01_CTRL_REG);
+ me4000_outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP,
+ info->me4000_regbase + ME4000_AO_02_CTRL_REG);
+ me4000_outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP,
+ info->me4000_regbase + ME4000_AO_03_CTRL_REG);
+
+ /* 0x8000 to the DACs means an output voltage of 0V */
+ me4000_outl(0x8000, info->me4000_regbase + ME4000_AO_00_SINGLE_REG);
+ me4000_outl(0x8000, info->me4000_regbase + ME4000_AO_01_SINGLE_REG);
+ me4000_outl(0x8000, info->me4000_regbase + ME4000_AO_02_SINGLE_REG);
+ me4000_outl(0x8000, info->me4000_regbase + ME4000_AO_03_SINGLE_REG);
+
+ /* Enable interrupts on the PLX */
+ me4000_outl(0x43, info->plx_regbase + PLX_INTCSR);
+
+ /* Set the adustment register for AO demux */
+ me4000_outl(ME4000_AO_DEMUX_ADJUST_VALUE,
+ info->me4000_regbase + ME4000_AO_DEMUX_ADJUST_REG);
+
+ /* Set digital I/O direction for port 0 to output on isolated versions */
+ if (!(me4000_inl(info->me4000_regbase + ME4000_DIO_DIR_REG) & 0x1)) {
+ me4000_outl(0x1, info->me4000_regbase + ME4000_DIO_CTRL_REG);
+ }
+
+ return 0;
+}
+
+static int me4000_open(struct inode *inode_p, struct file *file_p)
+{
+ int board, dev, mode;
+ int err = 0;
+ int i;
+ struct list_head *ptr;
+ me4000_info_t *board_info = NULL;
+ me4000_ao_context_t *ao_context = NULL;
+ me4000_ai_context_t *ai_context = NULL;
+ me4000_dio_context_t *dio_context = NULL;
+ me4000_cnt_context_t *cnt_context = NULL;
+ me4000_ext_int_context_t *ext_int_context = NULL;
+
+ CALL_PDEBUG("me4000_open() is executed\n");
+
+ /* Analog output */
+ if (MAJOR(inode_p->i_rdev) == me4000_ao_major_driver_no) {
+ board = AO_BOARD(inode_p->i_rdev);
+ dev = AO_PORT(inode_p->i_rdev);
+ mode = AO_MODE(inode_p->i_rdev);
+
+ PDEBUG("me4000_open():board = %d ao = %d mode = %d\n", board,
+ dev, mode);
+
+ /* Search for the board context */
+ for (ptr = me4000_board_info_list.next, i = 0;
+ ptr != &me4000_board_info_list; ptr = ptr->next, i++) {
+ board_info = list_entry(ptr, me4000_info_t, list);
+ if (i == board)
+ break;
+ }
+
+ if (ptr == &me4000_board_info_list) {
+ printk(KERN_ERR
+ "ME4000:me4000_open():Board %d not in device list\n",
+ board);
+ return -ENODEV;
+ }
+
+ /* Search for the dac context */
+ for (ptr = board_info->ao_context_list.next, i = 0;
+ ptr != &board_info->ao_context_list;
+ ptr = ptr->next, i++) {
+ ao_context = list_entry(ptr, me4000_ao_context_t, list);
+ if (i == dev)
+ break;
+ }
+
+ if (ptr == &board_info->ao_context_list) {
+ printk(KERN_ERR
+ "ME4000:me4000_open():Device %d not in device list\n",
+ dev);
+ return -ENODEV;
+ }
+
+ /* Check if mode is valid */
+ if (mode > 2) {
+ printk(KERN_ERR
+ "ME4000:me4000_open():Mode is not valid\n");
+ return -ENODEV;
+ }
+
+ /* Check if mode is valid for this AO */
+ if ((mode != ME4000_AO_CONV_MODE_SINGLE)
+ && (dev >= board_info->board_p->ao.fifo_count)) {
+ printk(KERN_ERR
+ "ME4000:me4000_open():AO %d only in single mode available\n",
+ dev);
+ return -ENODEV;
+ }
+
+ /* Check if already opened */
+ spin_lock(&ao_context->use_lock);
+ if (ao_context->dac_in_use) {
+ printk(KERN_ERR
+ "ME4000:me4000_open():AO %d already in use\n",
+ dev);
+ spin_unlock(&ao_context->use_lock);
+ return -EBUSY;
+ }
+ ao_context->dac_in_use = 1;
+ spin_unlock(&ao_context->use_lock);
+
+ ao_context->mode = mode;
+
+ /* Hold the context in private data */
+ file_p->private_data = ao_context;
+
+ /* Set file operations pointer */
+ file_p->f_op = me4000_ao_fops_array[mode];
+
+ err = me4000_ao_prepare(ao_context);
+ if (err) {
+ ao_context->dac_in_use = 0;
+ return 1;
+ }
+ }
+ /* Analog input */
+ else if (MAJOR(inode_p->i_rdev) == me4000_ai_major_driver_no) {
+ board = AI_BOARD(inode_p->i_rdev);
+ mode = AI_MODE(inode_p->i_rdev);
+
+ PDEBUG("me4000_open():ai board = %d mode = %d\n", board, mode);
+
+ /* Search for the board context */
+ for (ptr = me4000_board_info_list.next, i = 0;
+ ptr != &me4000_board_info_list; ptr = ptr->next, i++) {
+ board_info = list_entry(ptr, me4000_info_t, list);
+ if (i == board)
+ break;
+ }
+
+ if (ptr == &me4000_board_info_list) {
+ printk(KERN_ERR
+ "ME4000:me4000_open():Board %d not in device list\n",
+ board);
+ return -ENODEV;
+ }
+
+ ai_context = board_info->ai_context;
+
+ /* Check if mode is valid */
+ if (mode > 5) {
+ printk(KERN_ERR
+ "ME4000:me4000_open():Mode is not valid\n");
+ return -EINVAL;
+ }
+
+ /* Check if already opened */
+ spin_lock(&ai_context->use_lock);
+ if (ai_context->in_use) {
+ printk(KERN_ERR
+ "ME4000:me4000_open():AI already in use\n");
+ spin_unlock(&ai_context->use_lock);
+ return -EBUSY;
+ }
+ ai_context->in_use = 1;
+ spin_unlock(&ai_context->use_lock);
+
+ ai_context->mode = mode;
+
+ /* Hold the context in private data */
+ file_p->private_data = ai_context;
+
+ /* Set file operations pointer */
+ file_p->f_op = me4000_ai_fops_array[mode];
+
+ /* Prepare analog input */
+ me4000_ai_prepare(ai_context);
+ }
+ /* Digital I/O */
+ else if (MAJOR(inode_p->i_rdev) == me4000_dio_major_driver_no) {
+ board = DIO_BOARD(inode_p->i_rdev);
+ dev = 0;
+ mode = 0;
+
+ PDEBUG("me4000_open():board = %d\n", board);
+
+ /* Search for the board context */
+ for (ptr = me4000_board_info_list.next;
+ ptr != &me4000_board_info_list; ptr = ptr->next) {
+ board_info = list_entry(ptr, me4000_info_t, list);
+ if (board_info->board_count == board)
+ break;
+ }
+
+ if (ptr == &me4000_board_info_list) {
+ printk(KERN_ERR
+ "ME4000:me4000_open():Board %d not in device list\n",
+ board);
+ return -ENODEV;
+ }
+
+ /* Search for the dio context */
+ dio_context = board_info->dio_context;
+
+ /* Check if already opened */
+ spin_lock(&dio_context->use_lock);
+ if (dio_context->in_use) {
+ printk(KERN_ERR
+ "ME4000:me4000_open():DIO already in use\n");
+ spin_unlock(&dio_context->use_lock);
+ return -EBUSY;
+ }
+ dio_context->in_use = 1;
+ spin_unlock(&dio_context->use_lock);
+
+ /* Hold the context in private data */
+ file_p->private_data = dio_context;
+
+ /* Set file operations pointer to single functions */
+ file_p->f_op = &me4000_dio_fops;
+
+ //me4000_dio_reset(dio_context);
+ }
+ /* Counters */
+ else if (MAJOR(inode_p->i_rdev) == me4000_cnt_major_driver_no) {
+ board = CNT_BOARD(inode_p->i_rdev);
+ dev = 0;
+ mode = 0;
+
+ PDEBUG("me4000_open():board = %d\n", board);
+
+ /* Search for the board context */
+ for (ptr = me4000_board_info_list.next;
+ ptr != &me4000_board_info_list; ptr = ptr->next) {
+ board_info = list_entry(ptr, me4000_info_t, list);
+ if (board_info->board_count == board)
+ break;
+ }
+
+ if (ptr == &me4000_board_info_list) {
+ printk(KERN_ERR
+ "ME4000:me4000_open():Board %d not in device list\n",
+ board);
+ return -ENODEV;
+ }
+
+ /* Get the cnt context */
+ cnt_context = board_info->cnt_context;
+
+ /* Check if already opened */
+ spin_lock(&cnt_context->use_lock);
+ if (cnt_context->in_use) {
+ printk(KERN_ERR
+ "ME4000:me4000_open():CNT already in use\n");
+ spin_unlock(&cnt_context->use_lock);
+ return -EBUSY;
+ }
+ cnt_context->in_use = 1;
+ spin_unlock(&cnt_context->use_lock);
+
+ /* Hold the context in private data */
+ file_p->private_data = cnt_context;
+
+ /* Set file operations pointer to single functions */
+ file_p->f_op = &me4000_cnt_fops;
+ }
+ /* External Interrupt */
+ else if (MAJOR(inode_p->i_rdev) == me4000_ext_int_major_driver_no) {
+ board = EXT_INT_BOARD(inode_p->i_rdev);
+ dev = 0;
+ mode = 0;
+
+ PDEBUG("me4000_open():board = %d\n", board);
+
+ /* Search for the board context */
+ for (ptr = me4000_board_info_list.next;
+ ptr != &me4000_board_info_list; ptr = ptr->next) {
+ board_info = list_entry(ptr, me4000_info_t, list);
+ if (board_info->board_count == board)
+ break;
+ }
+
+ if (ptr == &me4000_board_info_list) {
+ printk(KERN_ERR
+ "ME4000:me4000_open():Board %d not in device list\n",
+ board);
+ return -ENODEV;
+ }
+
+ /* Get the external interrupt context */
+ ext_int_context = board_info->ext_int_context;
+
+ /* Check if already opened */
+ spin_lock(&cnt_context->use_lock);
+ if (ext_int_context->in_use) {
+ printk(KERN_ERR
+ "ME4000:me4000_open():External interrupt already in use\n");
+ spin_unlock(&ext_int_context->use_lock);
+ return -EBUSY;
+ }
+ ext_int_context->in_use = 1;
+ spin_unlock(&ext_int_context->use_lock);
+
+ /* Hold the context in private data */
+ file_p->private_data = ext_int_context;
+
+ /* Set file operations pointer to single functions */
+ file_p->f_op = &me4000_ext_int_fops;
+
+ /* Request the interrupt line */
+ err =
+ request_irq(ext_int_context->irq, me4000_ext_int_isr,
+ IRQF_DISABLED | IRQF_SHARED, ME4000_NAME,
+ ext_int_context);
+ if (err) {
+ printk(KERN_ERR
+ "ME4000:me4000_open():Can't get interrupt line");
+ ext_int_context->in_use = 0;
+ return -ENODEV;
+ }
+
+ /* Reset the counter */
+ me4000_ext_int_disable(ext_int_context);
+ } else {
+ printk(KERN_ERR "ME4000:me4000_open():Major number unknown\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int me4000_release(struct inode *inode_p, struct file *file_p)
+{
+ me4000_ao_context_t *ao_context;
+ me4000_ai_context_t *ai_context;
+ me4000_dio_context_t *dio_context;
+ me4000_cnt_context_t *cnt_context;
+ me4000_ext_int_context_t *ext_int_context;
+
+ CALL_PDEBUG("me4000_release() is executed\n");
+
+ if (MAJOR(inode_p->i_rdev) == me4000_ao_major_driver_no) {
+ ao_context = file_p->private_data;
+
+ /* Mark DAC as unused */
+ ao_context->dac_in_use = 0;
+ } else if (MAJOR(inode_p->i_rdev) == me4000_ai_major_driver_no) {
+ ai_context = file_p->private_data;
+
+ /* Reset the analog input */
+ me4000_ai_reset(ai_context);
+
+ /* Free the interrupt and the circular buffer */
+ if (ai_context->mode) {
+ free_irq(ai_context->irq, ai_context);
+ kfree(ai_context->circ_buf.buf);
+ ai_context->circ_buf.buf = NULL;
+ ai_context->circ_buf.head = 0;
+ ai_context->circ_buf.tail = 0;
+ }
+
+ /* Mark AI as unused */
+ ai_context->in_use = 0;
+ } else if (MAJOR(inode_p->i_rdev) == me4000_dio_major_driver_no) {
+ dio_context = file_p->private_data;
+
+ /* Mark digital I/O as unused */
+ dio_context->in_use = 0;
+ } else if (MAJOR(inode_p->i_rdev) == me4000_cnt_major_driver_no) {
+ cnt_context = file_p->private_data;
+
+ /* Mark counters as unused */
+ cnt_context->in_use = 0;
+ } else if (MAJOR(inode_p->i_rdev) == me4000_ext_int_major_driver_no) {
+ ext_int_context = file_p->private_data;
+
+ /* Disable the externel interrupt */
+ me4000_ext_int_disable(ext_int_context);
+
+ free_irq(ext_int_context->irq, ext_int_context);
+
+ /* Delete the fasync structure and free memory */
+ me4000_ext_int_fasync(0, file_p, 0);
+
+ /* Mark as unused */
+ ext_int_context->in_use = 0;
+ } else {
+ printk(KERN_ERR
+ "ME4000:me4000_release():Major number unknown\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*------------------------------- Analog output stuff --------------------------------------*/
+
+static int me4000_ao_prepare(me4000_ao_context_t * ao_context)
+{
+ unsigned long flags;
+
+ CALL_PDEBUG("me4000_ao_prepare() is executed\n");
+
+ if (ao_context->mode == ME4000_AO_CONV_MODE_CONTINUOUS) {
+ /* Only do anything if not already in the correct mode */
+ unsigned long mode = me4000_inl(ao_context->ctrl_reg);
+ if ((mode & ME4000_AO_CONV_MODE_CONTINUOUS)
+ && (mode & ME4000_AO_CTRL_BIT_ENABLE_FIFO)) {
+ return 0;
+ }
+
+ /* Stop any conversion */
+ me4000_ao_immediate_stop(ao_context);
+
+ /* Set the control register to default state */
+ spin_lock_irqsave(&ao_context->int_lock, flags);
+ me4000_outl(ME4000_AO_CONV_MODE_CONTINUOUS |
+ ME4000_AO_CTRL_BIT_ENABLE_FIFO |
+ ME4000_AO_CTRL_BIT_STOP |
+ ME4000_AO_CTRL_BIT_IMMEDIATE_STOP,
+ ao_context->ctrl_reg);
+ spin_unlock_irqrestore(&ao_context->int_lock, flags);
+
+ /* Set to fastest sample rate */
+ me4000_outl(65, ao_context->timer_reg);
+ } else if (ao_context->mode == ME4000_AO_CONV_MODE_WRAPAROUND) {
+ /* Only do anything if not already in the correct mode */
+ unsigned long mode = me4000_inl(ao_context->ctrl_reg);
+ if ((mode & ME4000_AO_CONV_MODE_WRAPAROUND)
+ && (mode & ME4000_AO_CTRL_BIT_ENABLE_FIFO)) {
+ return 0;
+ }
+
+ /* Stop any conversion */
+ me4000_ao_immediate_stop(ao_context);
+
+ /* Set the control register to default state */
+ spin_lock_irqsave(&ao_context->int_lock, flags);
+ me4000_outl(ME4000_AO_CONV_MODE_WRAPAROUND |
+ ME4000_AO_CTRL_BIT_ENABLE_FIFO |
+ ME4000_AO_CTRL_BIT_STOP |
+ ME4000_AO_CTRL_BIT_IMMEDIATE_STOP,
+ ao_context->ctrl_reg);
+ spin_unlock_irqrestore(&ao_context->int_lock, flags);
+
+ /* Set to fastest sample rate */
+ me4000_outl(65, ao_context->timer_reg);
+ } else if (ao_context->mode == ME4000_AO_CONV_MODE_SINGLE) {
+ /* Only do anything if not already in the correct mode */
+ unsigned long mode = me4000_inl(ao_context->ctrl_reg);
+ if (!
+ (mode &
+ (ME4000_AO_CONV_MODE_WRAPAROUND |
+ ME4000_AO_CONV_MODE_CONTINUOUS))) {
+ return 0;
+ }
+
+ /* Stop any conversion */
+ me4000_ao_immediate_stop(ao_context);
+
+ /* Clear the control register */
+ spin_lock_irqsave(&ao_context->int_lock, flags);
+ me4000_outl(0x0, ao_context->ctrl_reg);
+ spin_unlock_irqrestore(&ao_context->int_lock, flags);
+
+ /* Set voltage to 0V */
+ me4000_outl(0x8000, ao_context->single_reg);
+ } else {
+ printk(KERN_ERR
+ "ME4000:me4000_ao_prepare():Invalid mode specified\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int me4000_ao_reset(me4000_ao_context_t * ao_context)
+{
+ u32 tmp;
+ wait_queue_head_t queue;
+ unsigned long flags;
+
+ CALL_PDEBUG("me4000_ao_reset() is executed\n");
+
+ init_waitqueue_head(&queue);
+
+ if (ao_context->mode == ME4000_AO_CONV_MODE_WRAPAROUND) {
+ /*
+ * First stop conversion of the DAC before reconfigure.
+ * This is essantial, cause of the state machine.
+ * If not stopped before configuring mode, it could
+ * walk in a undefined state.
+ */
+ tmp = me4000_inl(ao_context->ctrl_reg);
+ tmp |= ME4000_AO_CTRL_BIT_IMMEDIATE_STOP;
+ me4000_outl(tmp, ao_context->ctrl_reg);
+
+ while (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) {
+ sleep_on_timeout(&queue, 1);
+ }
+
+ /* Set to transparent mode */
+ me4000_ao_simultaneous_disable(ao_context);
+
+ /* Set to single mode in order to set default voltage */
+ me4000_outl(0x0, ao_context->ctrl_reg);
+
+ /* Set voltage to 0V */
+ me4000_outl(0x8000, ao_context->single_reg);
+
+ /* Set to fastest sample rate */
+ me4000_outl(65, ao_context->timer_reg);
+
+ /* Set the original mode and enable FIFO */
+ me4000_outl(ME4000_AO_CONV_MODE_WRAPAROUND |
+ ME4000_AO_CTRL_BIT_ENABLE_FIFO |
+ ME4000_AO_CTRL_BIT_STOP |
+ ME4000_AO_CTRL_BIT_IMMEDIATE_STOP,
+ ao_context->ctrl_reg);
+ } else if (ao_context->mode == ME4000_AO_CONV_MODE_CONTINUOUS) {
+ /*
+ * First stop conversion of the DAC before reconfigure.
+ * This is essantial, cause of the state machine.
+ * If not stopped before configuring mode, it could
+ * walk in a undefined state.
+ */
+ spin_lock_irqsave(&ao_context->int_lock, flags);
+ tmp = me4000_inl(ao_context->ctrl_reg);
+ tmp |= ME4000_AO_CTRL_BIT_STOP;
+ me4000_outl(tmp, ao_context->ctrl_reg);
+ spin_unlock_irqrestore(&ao_context->int_lock, flags);
+
+ while (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) {
+ sleep_on_timeout(&queue, 1);
+ }
+
+ /* Clear the circular buffer */
+ ao_context->circ_buf.head = 0;
+ ao_context->circ_buf.tail = 0;
+
+ /* Set to transparent mode */
+ me4000_ao_simultaneous_disable(ao_context);
+
+ /* Set to single mode in order to set default voltage */
+ spin_lock_irqsave(&ao_context->int_lock, flags);
+ tmp = me4000_inl(ao_context->ctrl_reg);
+ me4000_outl(0x0, ao_context->ctrl_reg);
+
+ /* Set voltage to 0V */
+ me4000_outl(0x8000, ao_context->single_reg);
+
+ /* Set to fastest sample rate */
+ me4000_outl(65, ao_context->timer_reg);
+
+ /* Set the original mode and enable FIFO */
+ me4000_outl(ME4000_AO_CONV_MODE_CONTINUOUS |
+ ME4000_AO_CTRL_BIT_ENABLE_FIFO |
+ ME4000_AO_CTRL_BIT_STOP |
+ ME4000_AO_CTRL_BIT_IMMEDIATE_STOP,
+ ao_context->ctrl_reg);
+ spin_unlock_irqrestore(&ao_context->int_lock, flags);
+ } else {
+ /* Set to transparent mode */
+ me4000_ao_simultaneous_disable(ao_context);
+
+ /* Set voltage to 0V */
+ me4000_outl(0x8000, ao_context->single_reg);
+ }
+
+ return 0;
+}
+
+static ssize_t me4000_ao_write_sing(struct file *filep, const char *buff,
+ size_t cnt, loff_t * offp)
+{
+ me4000_ao_context_t *ao_context = filep->private_data;
+ u32 value;
+ const u16 *buffer = (const u16 *)buff;
+
+ CALL_PDEBUG("me4000_ao_write_sing() is executed\n");
+
+ if (cnt != 2) {
+ printk(KERN_ERR
+ "me4000_ao_write_sing():Write count is not 2\n");
+ return -EINVAL;
+ }
+
+ if (get_user(value, buffer)) {
+ printk(KERN_ERR
+ "me4000_ao_write_sing():Cannot copy data from user\n");
+ return -EFAULT;
+ }
+
+ me4000_outl(value, ao_context->single_reg);
+
+ return 2;
+}
+
+static ssize_t me4000_ao_write_wrap(struct file *filep, const char *buff,
+ size_t cnt, loff_t * offp)
+{
+ me4000_ao_context_t *ao_context = filep->private_data;
+ size_t i;
+ u32 value;
+ u32 tmp;
+ const u16 *buffer = (const u16 *)buff;
+ size_t count = cnt / 2;
+
+ CALL_PDEBUG("me4000_ao_write_wrap() is executed\n");
+
+ /* Check if a conversion is already running */
+ if (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) {
+ printk(KERN_ERR
+ "ME4000:me4000_ao_write_wrap():There is already a conversion running\n");
+ return -EBUSY;
+ }
+
+ if (count > ME4000_AO_FIFO_COUNT) {
+ printk(KERN_ERR
+ "me4000_ao_write_wrap():Can't load more than %d values\n",
+ ME4000_AO_FIFO_COUNT);
+ return -ENOSPC;
+ }
+
+ /* Reset the FIFO */
+ tmp = inl(ao_context->ctrl_reg);
+ tmp &= ~ME4000_AO_CTRL_BIT_ENABLE_FIFO;
+ outl(tmp, ao_context->ctrl_reg);
+ tmp |= ME4000_AO_CTRL_BIT_ENABLE_FIFO;
+ outl(tmp, ao_context->ctrl_reg);
+
+ for (i = 0; i < count; i++) {
+ if (get_user(value, buffer + i)) {
+ printk(KERN_ERR
+ "me4000_ao_write_single():Cannot copy data from user\n");
+ return -EFAULT;
+ }
+ if (((ao_context->fifo_reg & 0xFF) == ME4000_AO_01_FIFO_REG)
+ || ((ao_context->fifo_reg & 0xFF) == ME4000_AO_03_FIFO_REG))
+ value = value << 16;
+ outl(value, ao_context->fifo_reg);
+ }
+ CALL_PDEBUG("me4000_ao_write_wrap() is leaved with %d\n", i * 2);
+
+ return i * 2;
+}
+
+static ssize_t me4000_ao_write_cont(struct file *filep, const char *buff,
+ size_t cnt, loff_t * offp)
+{
+ me4000_ao_context_t *ao_context = filep->private_data;
+ const u16 *buffer = (const u16 *)buff;
+ size_t count = cnt / 2;
+ unsigned long flags;
+ u32 tmp;
+ int c = 0;
+ int k = 0;
+ int ret = 0;
+ u16 svalue;
+ u32 lvalue;
+ int i;
+ wait_queue_head_t queue;
+
+ CALL_PDEBUG("me4000_ao_write_cont() is executed\n");
+
+ init_waitqueue_head(&queue);
+
+ /* Check count */
+ if (count <= 0) {
+ PDEBUG("me4000_ao_write_cont():Count is 0\n");
+ return 0;
+ }
+
+ if (filep->f_flags & O_APPEND) {
+ PDEBUG("me4000_ao_write_cont():Append data to data stream\n");
+ while (count > 0) {
+ if (filep->f_flags & O_NONBLOCK) {
+ if (ao_context->pipe_flag) {
+ printk(KERN_ERR
+ "ME4000:me4000_ao_write_cont():Broken pipe in nonblocking write\n");
+ return -EPIPE;
+ }
+ c = me4000_space_to_end(ao_context->circ_buf,
+ ME4000_AO_BUFFER_COUNT);
+ if (!c) {
+ PDEBUG
+ ("me4000_ao_write_cont():Returning from nonblocking write\n");
+ break;
+ }
+ } else {
+ wait_event_interruptible(ao_context->wait_queue,
+ (c =
+ me4000_space_to_end
+ (ao_context->circ_buf,
+ ME4000_AO_BUFFER_COUNT)));
+ if (ao_context->pipe_flag) {
+ printk(KERN_ERR
+ "me4000_ao_write_cont():Broken pipe in blocking write\n");
+ return -EPIPE;
+ }
+ if (signal_pending(current)) {
+ printk(KERN_ERR
+ "me4000_ao_write_cont():Wait for free buffer interrupted from signal\n");
+ return -EINTR;
+ }
+ }
+
+ PDEBUG("me4000_ao_write_cont():Space to end = %d\n", c);
+
+ /* Only able to write size of free buffer or size of count */
+ if (count < c)
+ c = count;
+
+ k = 2 * c;
+ k -= copy_from_user(ao_context->circ_buf.buf +
+ ao_context->circ_buf.head, buffer,
+ k);
+ c = k / 2;
+ PDEBUG
+ ("me4000_ao_write_cont():Copy %d values from user space\n",
+ c);
+
+ if (!c)
+ return -EFAULT;
+
+ ao_context->circ_buf.head =
+ (ao_context->circ_buf.head +
+ c) & (ME4000_AO_BUFFER_COUNT - 1);
+ buffer += c;
+ count -= c;
+ ret += c;
+
+ /* Values are now available so enable interrupts */
+ spin_lock_irqsave(&ao_context->int_lock, flags);
+ if (me4000_buf_count
+ (ao_context->circ_buf, ME4000_AO_BUFFER_COUNT)) {
+ tmp = me4000_inl(ao_context->ctrl_reg);
+ tmp |= ME4000_AO_CTRL_BIT_ENABLE_IRQ;
+ me4000_outl(tmp, ao_context->ctrl_reg);
+ }
+ spin_unlock_irqrestore(&ao_context->int_lock, flags);
+ }
+
+ /* Wait until the state machine is stopped if O_SYNC is set */
+ if (filep->f_flags & O_SYNC) {
+ while (inl(ao_context->status_reg) &
+ ME4000_AO_STATUS_BIT_FSM) {
+ interruptible_sleep_on_timeout(&queue, 1);
+ if (ao_context->pipe_flag) {
+ PDEBUG
+ ("me4000_ao_write_cont():Broken pipe detected after sync\n");
+ return -EPIPE;
+ }
+ if (signal_pending(current)) {
+ printk(KERN_ERR
+ "me4000_ao_write_cont():Wait on state machine after sync interrupted\n");
+ return -EINTR;
+ }
+ }
+ }
+ } else {
+ PDEBUG("me4000_ao_write_cont():Preload DAC FIFO\n");
+ if ((me4000_inl(ao_context->status_reg) &
+ ME4000_AO_STATUS_BIT_FSM)) {
+ printk(KERN_ERR
+ "me4000_ao_write_cont():Can't Preload DAC FIFO while conversion is running\n");
+ return -EBUSY;
+ }
+
+ /* Clear the FIFO */
+ spin_lock_irqsave(&ao_context->int_lock, flags);
+ tmp = me4000_inl(ao_context->ctrl_reg);
+ tmp &=
+ ~(ME4000_AO_CTRL_BIT_ENABLE_FIFO |
+ ME4000_AO_CTRL_BIT_ENABLE_IRQ);
+ me4000_outl(tmp, ao_context->ctrl_reg);
+ tmp |= ME4000_AO_CTRL_BIT_ENABLE_FIFO;
+ me4000_outl(tmp, ao_context->ctrl_reg);
+ spin_unlock_irqrestore(&ao_context->int_lock, flags);
+
+ /* Clear the circular buffer */
+ ao_context->circ_buf.head = 0;
+ ao_context->circ_buf.tail = 0;
+
+ /* Reset the broken pipe flag */
+ ao_context->pipe_flag = 0;
+
+ /* Only able to write size of fifo or count */
+ c = ME4000_AO_FIFO_COUNT;
+ if (count < c)
+ c = count;
+
+ PDEBUG
+ ("me4000_ao_write_cont():Write %d values to DAC on 0x%lX\n",
+ c, ao_context->fifo_reg);
+
+ /* Write values to the fifo */
+ for (i = 0; i < c; i++) {
+ if (get_user(svalue, buffer))
+ return -EFAULT;
+
+ if (((ao_context->fifo_reg & 0xFF) ==
+ ME4000_AO_01_FIFO_REG)
+ || ((ao_context->fifo_reg & 0xFF) ==
+ ME4000_AO_03_FIFO_REG)) {
+ lvalue = ((u32) svalue) << 16;
+ } else
+ lvalue = (u32) svalue;
+
+ outl(lvalue, ao_context->fifo_reg);
+ buffer++;
+ }
+ count -= c;
+ ret += c;
+
+ while (1) {
+ /* Get free buffer */
+ c = me4000_space_to_end(ao_context->circ_buf,
+ ME4000_AO_BUFFER_COUNT);
+
+ if (c == 0)
+ return (2 * ret);
+
+ /* Only able to write size of free buffer or size of count */
+ if (count < c)
+ c = count;
+
+ /* If count = 0 return to user */
+ if (c <= 0) {
+ PDEBUG
+ ("me4000_ao_write_cont():Count reached 0\n");
+ break;
+ }
+
+ k = 2 * c;
+ k -= copy_from_user(ao_context->circ_buf.buf +
+ ao_context->circ_buf.head, buffer,
+ k);
+ c = k / 2;
+ PDEBUG
+ ("me4000_ao_write_cont():Wrote %d values to buffer\n",
+ c);
+
+ if (!c)
+ return -EFAULT;
+
+ ao_context->circ_buf.head =
+ (ao_context->circ_buf.head +
+ c) & (ME4000_AO_BUFFER_COUNT - 1);
+ buffer += c;
+ count -= c;
+ ret += c;
+
+ /* If values in the buffer are available so enable interrupts */
+ spin_lock_irqsave(&ao_context->int_lock, flags);
+ if (me4000_buf_count
+ (ao_context->circ_buf, ME4000_AO_BUFFER_COUNT)) {
+ PDEBUG
+ ("me4000_ao_write_cont():Enable Interrupts\n");
+ tmp = me4000_inl(ao_context->ctrl_reg);
+ tmp |= ME4000_AO_CTRL_BIT_ENABLE_IRQ;
+ me4000_outl(tmp, ao_context->ctrl_reg);
+ }
+ spin_unlock_irqrestore(&ao_context->int_lock, flags);
+ }
+ }
+
+ if (filep->f_flags & O_NONBLOCK) {
+ return (ret == 0) ? -EAGAIN : 2 * ret;
+ }
+
+ return 2 * ret;
+}
+
+static unsigned int me4000_ao_poll_cont(struct file *file_p, poll_table * wait)
+{
+ me4000_ao_context_t *ao_context;
+ unsigned long mask = 0;
+
+ CALL_PDEBUG("me4000_ao_poll_cont() is executed\n");
+
+ ao_context = file_p->private_data;
+
+ poll_wait(file_p, &ao_context->wait_queue, wait);
+
+ /* Get free buffer */
+ if (me4000_space_to_end(ao_context->circ_buf, ME4000_AO_BUFFER_COUNT))
+ mask |= POLLOUT | POLLWRNORM;
+
+ CALL_PDEBUG("me4000_ao_poll_cont():Return mask %lX\n", mask);
+
+ return mask;
+}
+
+static int me4000_ao_fsync_cont(struct file *file_p, struct dentry *dentry_p,
+ int datasync)
+{
+ me4000_ao_context_t *ao_context;
+ wait_queue_head_t queue;
+
+ CALL_PDEBUG("me4000_ao_fsync_cont() is executed\n");
+
+ ao_context = file_p->private_data;
+ init_waitqueue_head(&queue);
+
+ while (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) {
+ interruptible_sleep_on_timeout(&queue, 1);
+ if (ao_context->pipe_flag) {
+ printk(KERN_ERR
+ "me4000_ao_fsync_cont():Broken pipe detected\n");
+ return -EPIPE;
+ }
+
+ if (signal_pending(current)) {
+ printk(KERN_ERR
+ "me4000_ao_fsync_cont():Wait on state machine interrupted\n");
+ return -EINTR;
+ }
+ }
+
+ return 0;
+}
+
+static int me4000_ao_ioctl_sing(struct inode *inode_p, struct file *file_p,
+ unsigned int service, unsigned long arg)
+{
+ me4000_ao_context_t *ao_context;
+
+ CALL_PDEBUG("me4000_ao_ioctl_sing() is executed\n");
+
+ ao_context = file_p->private_data;
+
+ if (_IOC_TYPE(service) != ME4000_MAGIC) {
+ return -ENOTTY;
+ PDEBUG("me4000_ao_ioctl_sing():Wrong magic number\n");
+ }
+
+ switch (service) {
+ case ME4000_AO_EX_TRIG_SETUP:
+ return me4000_ao_ex_trig_set_edge((int *)arg, ao_context);
+ case ME4000_AO_EX_TRIG_ENABLE:
+ return me4000_ao_ex_trig_enable(ao_context);
+ case ME4000_AO_EX_TRIG_DISABLE:
+ return me4000_ao_ex_trig_disable(ao_context);
+ case ME4000_AO_PRELOAD:
+ return me4000_ao_preload(ao_context);
+ case ME4000_AO_PRELOAD_UPDATE:
+ return me4000_ao_preload_update(ao_context);
+ case ME4000_GET_USER_INFO:
+ return me4000_get_user_info((me4000_user_info_t *) arg,
+ ao_context->board_info);
+ case ME4000_AO_SIMULTANEOUS_EX_TRIG:
+ return me4000_ao_simultaneous_ex_trig(ao_context);
+ case ME4000_AO_SIMULTANEOUS_SW:
+ return me4000_ao_simultaneous_sw(ao_context);
+ case ME4000_AO_SIMULTANEOUS_DISABLE:
+ return me4000_ao_simultaneous_disable(ao_context);
+ case ME4000_AO_SIMULTANEOUS_UPDATE:
+ return
+ me4000_ao_simultaneous_update((me4000_ao_channel_list_t *)
+ arg, ao_context);
+ case ME4000_AO_EX_TRIG_TIMEOUT:
+ return me4000_ao_ex_trig_timeout((unsigned long *)arg,
+ ao_context);
+ case ME4000_AO_DISABLE_DO:
+ return me4000_ao_disable_do(ao_context);
+ default:
+ printk(KERN_ERR
+ "me4000_ao_ioctl_sing():Service number invalid\n");
+ return -ENOTTY;
+ }
+
+ return 0;
+}
+
+static int me4000_ao_ioctl_wrap(struct inode *inode_p, struct file *file_p,
+ unsigned int service, unsigned long arg)
+{
+ me4000_ao_context_t *ao_context;
+
+ CALL_PDEBUG("me4000_ao_ioctl_wrap() is executed\n");
+
+ ao_context = file_p->private_data;
+
+ if (_IOC_TYPE(service) != ME4000_MAGIC) {
+ return -ENOTTY;
+ PDEBUG("me4000_ao_ioctl_wrap():Wrong magic number\n");
+ }
+
+ switch (service) {
+ case ME4000_AO_START:
+ return me4000_ao_start((unsigned long *)arg, ao_context);
+ case ME4000_AO_STOP:
+ return me4000_ao_stop(ao_context);
+ case ME4000_AO_IMMEDIATE_STOP:
+ return me4000_ao_immediate_stop(ao_context);
+ case ME4000_AO_RESET:
+ return me4000_ao_reset(ao_context);
+ case ME4000_AO_TIMER_SET_DIVISOR:
+ return me4000_ao_timer_set_divisor((u32 *) arg, ao_context);
+ case ME4000_AO_EX_TRIG_SETUP:
+ return me4000_ao_ex_trig_set_edge((int *)arg, ao_context);
+ case ME4000_AO_EX_TRIG_ENABLE:
+ return me4000_ao_ex_trig_enable(ao_context);
+ case ME4000_AO_EX_TRIG_DISABLE:
+ return me4000_ao_ex_trig_disable(ao_context);
+ case ME4000_GET_USER_INFO:
+ return me4000_get_user_info((me4000_user_info_t *) arg,
+ ao_context->board_info);
+ case ME4000_AO_FSM_STATE:
+ return me4000_ao_fsm_state((int *)arg, ao_context);
+ case ME4000_AO_ENABLE_DO:
+ return me4000_ao_enable_do(ao_context);
+ case ME4000_AO_DISABLE_DO:
+ return me4000_ao_disable_do(ao_context);
+ case ME4000_AO_SYNCHRONOUS_EX_TRIG:
+ return me4000_ao_synchronous_ex_trig(ao_context);
+ case ME4000_AO_SYNCHRONOUS_SW:
+ return me4000_ao_synchronous_sw(ao_context);
+ case ME4000_AO_SYNCHRONOUS_DISABLE:
+ return me4000_ao_synchronous_disable(ao_context);
+ default:
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+static int me4000_ao_ioctl_cont(struct inode *inode_p, struct file *file_p,
+ unsigned int service, unsigned long arg)
+{
+ me4000_ao_context_t *ao_context;
+
+ CALL_PDEBUG("me4000_ao_ioctl_cont() is executed\n");
+
+ ao_context = file_p->private_data;
+
+ if (_IOC_TYPE(service) != ME4000_MAGIC) {
+ return -ENOTTY;
+ PDEBUG("me4000_ao_ioctl_cont():Wrong magic number\n");
+ }
+
+ switch (service) {
+ case ME4000_AO_START:
+ return me4000_ao_start((unsigned long *)arg, ao_context);
+ case ME4000_AO_STOP:
+ return me4000_ao_stop(ao_context);
+ case ME4000_AO_IMMEDIATE_STOP:
+ return me4000_ao_immediate_stop(ao_context);
+ case ME4000_AO_RESET:
+ return me4000_ao_reset(ao_context);
+ case ME4000_AO_TIMER_SET_DIVISOR:
+ return me4000_ao_timer_set_divisor((u32 *) arg, ao_context);
+ case ME4000_AO_EX_TRIG_SETUP:
+ return me4000_ao_ex_trig_set_edge((int *)arg, ao_context);
+ case ME4000_AO_EX_TRIG_ENABLE:
+ return me4000_ao_ex_trig_enable(ao_context);
+ case ME4000_AO_EX_TRIG_DISABLE:
+ return me4000_ao_ex_trig_disable(ao_context);
+ case ME4000_AO_ENABLE_DO:
+ return me4000_ao_enable_do(ao_context);
+ case ME4000_AO_DISABLE_DO:
+ return me4000_ao_disable_do(ao_context);
+ case ME4000_AO_FSM_STATE:
+ return me4000_ao_fsm_state((int *)arg, ao_context);
+ case ME4000_GET_USER_INFO:
+ return me4000_get_user_info((me4000_user_info_t *) arg,
+ ao_context->board_info);
+ case ME4000_AO_SYNCHRONOUS_EX_TRIG:
+ return me4000_ao_synchronous_ex_trig(ao_context);
+ case ME4000_AO_SYNCHRONOUS_SW:
+ return me4000_ao_synchronous_sw(ao_context);
+ case ME4000_AO_SYNCHRONOUS_DISABLE:
+ return me4000_ao_synchronous_disable(ao_context);
+ case ME4000_AO_GET_FREE_BUFFER:
+ return me4000_ao_get_free_buffer((unsigned long *)arg,
+ ao_context);
+ default:
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+static int me4000_ao_start(unsigned long *arg, me4000_ao_context_t * ao_context)
+{
+ u32 tmp;
+ wait_queue_head_t queue;
+ unsigned long ref;
+ unsigned long timeout;
+ unsigned long flags;
+
+ CALL_PDEBUG("me4000_ao_start() is executed\n");
+
+ if (get_user(timeout, arg)) {
+ printk(KERN_ERR
+ "me4000_ao_start():Cannot copy data from user\n");
+ return -EFAULT;
+ }
+
+ init_waitqueue_head(&queue);
+
+ spin_lock_irqsave(&ao_context->int_lock, flags);
+ tmp = inl(ao_context->ctrl_reg);
+ tmp &= ~(ME4000_AO_CTRL_BIT_STOP | ME4000_AO_CTRL_BIT_IMMEDIATE_STOP);
+ me4000_outl(tmp, ao_context->ctrl_reg);
+ spin_unlock_irqrestore(&ao_context->int_lock, flags);
+
+ if ((tmp & ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG)) {
+ if (timeout) {
+ ref = jiffies;
+ while (!
+ (inl(ao_context->status_reg) &
+ ME4000_AO_STATUS_BIT_FSM)) {
+ interruptible_sleep_on_timeout(&queue, 1);
+ if (signal_pending(current)) {
+ printk(KERN_ERR
+ "ME4000:me4000_ao_start():Wait on start of state machine interrupted\n");
+ return -EINTR;
+ }
+ if (((jiffies - ref) > (timeout * HZ / USER_HZ))) { // 2.6 has diffrent definitions for HZ in user and kernel space
+ printk(KERN_ERR
+ "ME4000:me4000_ao_start():Timeout reached\n");
+ return -EIO;
+ }
+ }
+ }
+ } else {
+ me4000_outl(0x8000, ao_context->single_reg);
+ }
+
+ return 0;
+}
+
+static int me4000_ao_stop(me4000_ao_context_t * ao_context)
+{
+ u32 tmp;
+ wait_queue_head_t queue;
+ unsigned long flags;
+
+ init_waitqueue_head(&queue);
+
+ CALL_PDEBUG("me4000_ao_stop() is executed\n");
+
+ /* Set the stop bit */
+ spin_lock_irqsave(&ao_context->int_lock, flags);
+ tmp = inl(ao_context->ctrl_reg);
+ tmp |= ME4000_AO_CTRL_BIT_STOP;
+ me4000_outl(tmp, ao_context->ctrl_reg);
+ spin_unlock_irqrestore(&ao_context->int_lock, flags);
+
+ while (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) {
+ interruptible_sleep_on_timeout(&queue, 1);
+ if (signal_pending(current)) {
+ printk(KERN_ERR
+ "me4000_ao_stop():Wait on state machine after stop interrupted\n");
+ return -EINTR;
+ }
+ }
+
+ /* Clear the stop bit */
+ //tmp &= ~ME4000_AO_CTRL_BIT_STOP;
+ //me4000_outl(tmp, ao_context->ctrl_reg);
+
+ return 0;
+}
+
+static int me4000_ao_immediate_stop(me4000_ao_context_t * ao_context)
+{
+ u32 tmp;
+ wait_queue_head_t queue;
+ unsigned long flags;
+
+ init_waitqueue_head(&queue);
+
+ CALL_PDEBUG("me4000_ao_immediate_stop() is executed\n");
+
+ spin_lock_irqsave(&ao_context->int_lock, flags);
+ tmp = inl(ao_context->ctrl_reg);
+ tmp |= ME4000_AO_CTRL_BIT_STOP | ME4000_AO_CTRL_BIT_IMMEDIATE_STOP;
+ me4000_outl(tmp, ao_context->ctrl_reg);
+ spin_unlock_irqrestore(&ao_context->int_lock, flags);
+
+ while (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) {
+ interruptible_sleep_on_timeout(&queue, 1);
+ if (signal_pending(current)) {
+ printk(KERN_ERR
+ "me4000_ao_immediate_stop():Wait on state machine after stop interrupted\n");
+ return -EINTR;
+ }
+ }
+
+ /* Clear the stop bits */
+ //tmp &= ~(ME4000_AO_CTRL_BIT_STOP | ME4000_AO_CTRL_BIT_IMMEDIATE_STOP);
+ //me4000_outl(tmp, ao_context->ctrl_reg);
+
+ return 0;
+}
+
+static int me4000_ao_timer_set_divisor(u32 * arg,
+ me4000_ao_context_t * ao_context)
+{
+ u32 divisor;
+ u32 tmp;
+
+ CALL_PDEBUG("me4000_ao_timer set_divisor() is executed\n");
+
+ if (get_user(divisor, arg))
+ return -EFAULT;
+
+ /* Check if the state machine is stopped */
+ tmp = me4000_inl(ao_context->status_reg);
+ if (tmp & ME4000_AO_STATUS_BIT_FSM) {
+ printk(KERN_ERR
+ "me4000_ao_timer_set_divisor():Can't set timer while DAC is running\n");
+ return -EBUSY;
+ }
+
+ PDEBUG("me4000_ao_timer set_divisor():Divisor from user = %d\n",
+ divisor);
+
+ /* Check if the divisor is right. ME4000_AO_MIN_TICKS is the lowest */
+ if (divisor < ME4000_AO_MIN_TICKS) {
+ printk(KERN_ERR
+ "ME4000:me4000_ao_timer set_divisor():Divisor to low\n");
+ return -EINVAL;
+ }
+
+ /* Fix bug in Firmware */
+ divisor -= 2;
+
+ PDEBUG("me4000_ao_timer set_divisor():Divisor to HW = %d\n", divisor);
+
+ /* Write the divisor */
+ me4000_outl(divisor, ao_context->timer_reg);
+
+ return 0;
+}
+
+static int me4000_ao_ex_trig_set_edge(int *arg,
+ me4000_ao_context_t * ao_context)
+{
+ int mode;
+ u32 tmp;
+ unsigned long flags;
+
+ CALL_PDEBUG("me4000_ao_ex_trig_set_edge() is executed\n");
+
+ if (get_user(mode, arg))
+ return -EFAULT;
+
+ /* Check if the state machine is stopped */
+ tmp = me4000_inl(ao_context->status_reg);
+ if (tmp & ME4000_AO_STATUS_BIT_FSM) {
+ printk(KERN_ERR
+ "me4000_ao_ex_trig_set_edge():Can't set trigger while DAC is running\n");
+ return -EBUSY;
+ }
+
+ if (mode == ME4000_AO_TRIGGER_EXT_EDGE_RISING) {
+ spin_lock_irqsave(&ao_context->int_lock, flags);
+ tmp = me4000_inl(ao_context->ctrl_reg);
+ tmp &=
+ ~(ME4000_AO_CTRL_BIT_EX_TRIG_EDGE |
+ ME4000_AO_CTRL_BIT_EX_TRIG_BOTH);
+ me4000_outl(tmp, ao_context->ctrl_reg);
+ spin_unlock_irqrestore(&ao_context->int_lock, flags);
+ } else if (mode == ME4000_AO_TRIGGER_EXT_EDGE_FALLING) {
+ spin_lock_irqsave(&ao_context->int_lock, flags);
+ tmp = me4000_inl(ao_context->ctrl_reg);
+ tmp &= ~ME4000_AO_CTRL_BIT_EX_TRIG_BOTH;
+ tmp |= ME4000_AO_CTRL_BIT_EX_TRIG_EDGE;
+ me4000_outl(tmp, ao_context->ctrl_reg);
+ spin_unlock_irqrestore(&ao_context->int_lock, flags);
+ } else if (mode == ME4000_AO_TRIGGER_EXT_EDGE_BOTH) {
+ spin_lock_irqsave(&ao_context->int_lock, flags);
+ tmp = me4000_inl(ao_context->ctrl_reg);
+ tmp |=
+ ME4000_AO_CTRL_BIT_EX_TRIG_EDGE |
+ ME4000_AO_CTRL_BIT_EX_TRIG_BOTH;
+ me4000_outl(tmp, ao_context->ctrl_reg);
+ spin_unlock_irqrestore(&ao_context->int_lock, flags);
+ } else {
+ printk(KERN_ERR
+ "me4000_ao_ex_trig_set_edge():Invalid trigger mode\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int me4000_ao_ex_trig_enable(me4000_ao_context_t * ao_context)
+{
+ u32 tmp;
+ unsigned long flags;
+
+ CALL_PDEBUG("me4000_ao_ex_trig_enable() is executed\n");
+
+ /* Check if the state machine is stopped */
+ tmp = me4000_inl(ao_context->status_reg);
+ if (tmp & ME4000_AO_STATUS_BIT_FSM) {
+ printk(KERN_ERR
+ "me4000_ao_ex_trig_enable():Can't enable trigger while DAC is running\n");
+ return -EBUSY;
+ }
+
+ spin_lock_irqsave(&ao_context->int_lock, flags);
+ tmp = me4000_inl(ao_context->ctrl_reg);
+ tmp |= ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG;
+ me4000_outl(tmp, ao_context->ctrl_reg);
+ spin_unlock_irqrestore(&ao_context->int_lock, flags);
+
+ return 0;
+}
+
+static int me4000_ao_ex_trig_disable(me4000_ao_context_t * ao_context)
+{
+ u32 tmp;
+ unsigned long flags;
+
+ CALL_PDEBUG("me4000_ao_ex_trig_disable() is executed\n");
+
+ /* Check if the state machine is stopped */
+ tmp = me4000_inl(ao_context->status_reg);
+ if (tmp & ME4000_AO_STATUS_BIT_FSM) {
+ printk(KERN_ERR
+ "me4000_ao_ex_trig_disable():Can't disable trigger while DAC is running\n");
+ return -EBUSY;
+ }
+
+ spin_lock_irqsave(&ao_context->int_lock, flags);
+ tmp = me4000_inl(ao_context->ctrl_reg);
+ tmp &= ~ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG;
+ me4000_outl(tmp, ao_context->ctrl_reg);
+ spin_unlock_irqrestore(&ao_context->int_lock, flags);
+
+ return 0;
+}
+
+static int me4000_ao_simultaneous_disable(me4000_ao_context_t * ao_context)
+{
+ u32 tmp;
+
+ CALL_PDEBUG("me4000_ao_simultaneous_disable() is executed\n");
+
+ /* Check if the state machine is stopped */
+ /* Be careful here because this function is called from
+ me4000_ao_synchronous disable */
+ tmp = me4000_inl(ao_context->status_reg);
+ if (tmp & ME4000_AO_STATUS_BIT_FSM) {
+ printk(KERN_ERR
+ "me4000_ao_simultaneous_disable():Can't disable while DAC is running\n");
+ return -EBUSY;
+ }
+
+ spin_lock(&ao_context->board_info->preload_lock);
+ tmp = me4000_inl(ao_context->preload_reg);
+ tmp &= ~(0x1 << ao_context->index); // Disable preload bit
+ tmp &= ~(0x1 << (ao_context->index + 16)); // Disable hw simultaneous bit
+ me4000_outl(tmp, ao_context->preload_reg);
+ spin_unlock(&ao_context->board_info->preload_lock);
+
+ return 0;
+}
+
+static int me4000_ao_simultaneous_ex_trig(me4000_ao_context_t * ao_context)
+{
+ u32 tmp;
+
+ CALL_PDEBUG("me4000_ao_simultaneous_ex_trig() is executed\n");
+
+ spin_lock(&ao_context->board_info->preload_lock);
+ tmp = me4000_inl(ao_context->preload_reg);
+ tmp |= (0x1 << ao_context->index); // Enable preload bit
+ tmp |= (0x1 << (ao_context->index + 16)); // Enable hw simultaneous bit
+ me4000_outl(tmp, ao_context->preload_reg);
+ spin_unlock(&ao_context->board_info->preload_lock);
+
+ return 0;
+}
+
+static int me4000_ao_simultaneous_sw(me4000_ao_context_t * ao_context)
+{
+ u32 tmp;
+
+ CALL_PDEBUG("me4000_ao_simultaneous_sw() is executed\n");
+
+ spin_lock(&ao_context->board_info->preload_lock);
+ tmp = me4000_inl(ao_context->preload_reg);
+ tmp |= (0x1 << ao_context->index); // Enable preload bit
+ tmp &= ~(0x1 << (ao_context->index + 16)); // Disable hw simultaneous bit
+ me4000_outl(tmp, ao_context->preload_reg);
+ spin_unlock(&ao_context->board_info->preload_lock);
+
+ return 0;
+}
+
+static int me4000_ao_preload(me4000_ao_context_t * ao_context)
+{
+ CALL_PDEBUG("me4000_ao_preload() is executed\n");
+ return me4000_ao_simultaneous_sw(ao_context);
+}
+
+static int me4000_ao_preload_update(me4000_ao_context_t * ao_context)
+{
+ u32 tmp;
+ u32 ctrl;
+ struct list_head *entry;
+
+ CALL_PDEBUG("me4000_ao_preload_update() is executed\n");
+
+ spin_lock(&ao_context->board_info->preload_lock);
+ tmp = me4000_inl(ao_context->preload_reg);
+ list_for_each(entry, &ao_context->board_info->ao_context_list) {
+ /* The channels we update must be in the following state :
+ - Mode A
+ - Hardware trigger is disabled
+ - Corresponding simultaneous bit is reset
+ */
+ ctrl = me4000_inl(ao_context->ctrl_reg);
+ if (!
+ (ctrl &
+ (ME4000_AO_CTRL_BIT_MODE_0 | ME4000_AO_CTRL_BIT_MODE_1 |
+ ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG))) {
+ if (!
+ (tmp &
+ (0x1 <<
+ (((me4000_ao_context_t *) entry)->index + 16)))) {
+ tmp &=
+ ~(0x1 <<
+ (((me4000_ao_context_t *) entry)->index));
+ }
+ }
+ }
+ me4000_outl(tmp, ao_context->preload_reg);
+ spin_unlock(&ao_context->board_info->preload_lock);
+
+ return 0;
+}
+
+static int me4000_ao_simultaneous_update(me4000_ao_channel_list_t * arg,
+ me4000_ao_context_t * ao_context)
+{
+ int err;
+ int i;
+ u32 tmp;
+ me4000_ao_channel_list_t channels;
+
+ CALL_PDEBUG("me4000_ao_simultaneous_update() is executed\n");
+
+ /* Copy data from user */
+ err = copy_from_user(&channels, arg, sizeof(me4000_ao_channel_list_t));
+ if (err) {
+ printk(KERN_ERR
+ "ME4000:me4000_ao_simultaneous_update():Can't copy command\n");
+ return -EFAULT;
+ }
+
+ channels.list =
+ kmalloc(sizeof(unsigned long) * channels.count, GFP_KERNEL);
+ if (!channels.list) {
+ printk(KERN_ERR
+ "ME4000:me4000_ao_simultaneous_update():Can't get buffer\n");
+ return -ENOMEM;
+ }
+ memset(channels.list, 0, sizeof(unsigned long) * channels.count);
+
+ /* Copy channel list from user */
+ err =
+ copy_from_user(channels.list, arg->list,
+ sizeof(unsigned long) * channels.count);
+ if (err) {
+ printk(KERN_ERR
+ "ME4000:me4000_ao_simultaneous_update():Can't copy list\n");
+ kfree(channels.list);
+ return -EFAULT;
+ }
+
+ spin_lock(&ao_context->board_info->preload_lock);
+ tmp = me4000_inl(ao_context->preload_reg);
+ for (i = 0; i < channels.count; i++) {
+ if (channels.list[i] >
+ ao_context->board_info->board_p->ao.count) {
+ spin_unlock(&ao_context->board_info->preload_lock);
+ kfree(channels.list);
+ printk(KERN_ERR
+ "ME4000:me4000_ao_simultaneous_update():Invalid board number specified\n");
+ return -EFAULT;
+ }
+ tmp &= ~(0x1 << channels.list[i]); // Clear the preload bit
+ tmp &= ~(0x1 << (channels.list[i] + 16)); // Clear the hw simultaneous bit
+ }
+ me4000_outl(tmp, ao_context->preload_reg);
+ spin_unlock(&ao_context->board_info->preload_lock);
+ kfree(channels.list);
+
+ return 0;
+}
+
+static int me4000_ao_synchronous_ex_trig(me4000_ao_context_t * ao_context)
+{
+ u32 tmp;
+ unsigned long flags;
+
+ CALL_PDEBUG("me4000_ao_synchronous_ex_trig() is executed\n");
+
+ /* Check if the state machine is stopped */
+ tmp = me4000_inl(ao_context->status_reg);
+ if (tmp & ME4000_AO_STATUS_BIT_FSM) {
+ printk(KERN_ERR
+ "me4000_ao_synchronous_ex_trig(): DAC is running\n");
+ return -EBUSY;
+ }
+
+ spin_lock(&ao_context->board_info->preload_lock);
+ tmp = me4000_inl(ao_context->preload_reg);
+ tmp &= ~(0x1 << ao_context->index); // Disable synchronous sw bit
+ tmp |= 0x1 << (ao_context->index + 16); // Enable synchronous hw bit
+ me4000_outl(tmp, ao_context->preload_reg);
+ spin_unlock(&ao_context->board_info->preload_lock);
+
+ /* Make runnable */
+ spin_lock_irqsave(&ao_context->int_lock, flags);
+ tmp = me4000_inl(ao_context->ctrl_reg);
+ if (tmp & (ME4000_AO_CTRL_BIT_MODE_0 | ME4000_AO_CTRL_BIT_MODE_1)) {
+ tmp &=
+ ~(ME4000_AO_CTRL_BIT_STOP |
+ ME4000_AO_CTRL_BIT_IMMEDIATE_STOP);
+ me4000_outl(tmp, ao_context->ctrl_reg);
+ }
+ spin_unlock_irqrestore(&ao_context->int_lock, flags);
+
+ return 0;
+}
+
+static int me4000_ao_synchronous_sw(me4000_ao_context_t * ao_context)
+{
+ u32 tmp;
+ unsigned long flags;
+
+ CALL_PDEBUG("me4000_ao_synchronous_sw() is executed\n");
+
+ /* Check if the state machine is stopped */
+ tmp = me4000_inl(ao_context->status_reg);
+ if (tmp & ME4000_AO_STATUS_BIT_FSM) {
+ printk(KERN_ERR "me4000_ao_synchronous_sw(): DAC is running\n");
+ return -EBUSY;
+ }
+
+ spin_lock(&ao_context->board_info->preload_lock);
+ tmp = me4000_inl(ao_context->preload_reg);
+ tmp |= 0x1 << ao_context->index; // Enable synchronous sw bit
+ tmp &= ~(0x1 << (ao_context->index + 16)); // Disable synchronous hw bit
+ me4000_outl(tmp, ao_context->preload_reg);
+ spin_unlock(&ao_context->board_info->preload_lock);
+
+ /* Make runnable */
+ spin_lock_irqsave(&ao_context->int_lock, flags);
+ tmp = me4000_inl(ao_context->ctrl_reg);
+ if (tmp & (ME4000_AO_CTRL_BIT_MODE_0 | ME4000_AO_CTRL_BIT_MODE_1)) {
+ tmp &=
+ ~(ME4000_AO_CTRL_BIT_STOP |
+ ME4000_AO_CTRL_BIT_IMMEDIATE_STOP);
+ me4000_outl(tmp, ao_context->ctrl_reg);
+ }
+ spin_unlock_irqrestore(&ao_context->int_lock, flags);
+
+ return 0;
+}
+
+static int me4000_ao_synchronous_disable(me4000_ao_context_t * ao_context)
+{
+ return me4000_ao_simultaneous_disable(ao_context);
+}
+
+static int me4000_ao_get_free_buffer(unsigned long *arg,
+ me4000_ao_context_t * ao_context)
+{
+ unsigned long c;
+ int err;
+
+ c = me4000_buf_space(ao_context->circ_buf, ME4000_AO_BUFFER_COUNT);
+
+ err = copy_to_user(arg, &c, sizeof(unsigned long));
+ if (err) {
+ printk(KERN_ERR
+ "ME4000:me4000_ao_get_free_buffer():Can't copy to user space\n");
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int me4000_ao_ex_trig_timeout(unsigned long *arg,
+ me4000_ao_context_t * ao_context)
+{
+ u32 tmp;
+ wait_queue_head_t queue;
+ unsigned long ref;
+ unsigned long timeout;
+
+ CALL_PDEBUG("me4000_ao_ex_trig_timeout() is executed\n");
+
+ if (get_user(timeout, arg)) {
+ printk(KERN_ERR
+ "me4000_ao_ex_trig_timeout():Cannot copy data from user\n");
+ return -EFAULT;
+ }
+
+ init_waitqueue_head(&queue);
+
+ tmp = inl(ao_context->ctrl_reg);
+
+ if ((tmp & ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG)) {
+ if (timeout) {
+ ref = jiffies;
+ while ((inl(ao_context->status_reg) &
+ ME4000_AO_STATUS_BIT_FSM)) {
+ interruptible_sleep_on_timeout(&queue, 1);
+ if (signal_pending(current)) {
+ printk(KERN_ERR
+ "ME4000:me4000_ao_ex_trig_timeout():Wait on start of state machine interrupted\n");
+ return -EINTR;
+ }
+ if (((jiffies - ref) > (timeout * HZ / USER_HZ))) { // 2.6 has diffrent definitions for HZ in user and kernel space
+ printk(KERN_ERR
+ "ME4000:me4000_ao_ex_trig_timeout():Timeout reached\n");
+ return -EIO;
+ }
+ }
+ } else {
+ while ((inl(ao_context->status_reg) &
+ ME4000_AO_STATUS_BIT_FSM)) {
+ interruptible_sleep_on_timeout(&queue, 1);
+ if (signal_pending(current)) {
+ printk(KERN_ERR
+ "ME4000:me4000_ao_ex_trig_timeout():Wait on start of state machine interrupted\n");
+ return -EINTR;
+ }
+ }
+ }
+ } else {
+ printk(KERN_ERR
+ "ME4000:me4000_ao_ex_trig_timeout():External Trigger is not enabled\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int me4000_ao_enable_do(me4000_ao_context_t * ao_context)
+{
+ u32 tmp;
+ unsigned long flags;
+
+ CALL_PDEBUG("me4000_ao_enable_do() is executed\n");
+
+ /* Only available for analog output 3 */
+ if (ao_context->index != 3) {
+ printk(KERN_ERR
+ "me4000_ao_enable_do():Only available for analog output 3\n");
+ return -ENOTTY;
+ }
+
+ /* Check if the state machine is stopped */
+ tmp = me4000_inl(ao_context->status_reg);
+ if (tmp & ME4000_AO_STATUS_BIT_FSM) {
+ printk(KERN_ERR "me4000_ao_enable_do(): DAC is running\n");
+ return -EBUSY;
+ }
+
+ /* Set the stop bit */
+ spin_lock_irqsave(&ao_context->int_lock, flags);
+ tmp = inl(ao_context->ctrl_reg);
+ tmp |= ME4000_AO_CTRL_BIT_ENABLE_DO;
+ me4000_outl(tmp, ao_context->ctrl_reg);
+ spin_unlock_irqrestore(&ao_context->int_lock, flags);
+
+ return 0;
+}
+
+static int me4000_ao_disable_do(me4000_ao_context_t * ao_context)
+{
+ u32 tmp;
+ unsigned long flags;
+
+ CALL_PDEBUG("me4000_ao_disable_do() is executed\n");
+
+ /* Only available for analog output 3 */
+ if (ao_context->index != 3) {
+ printk(KERN_ERR
+ "me4000_ao_disable():Only available for analog output 3\n");
+ return -ENOTTY;
+ }
+
+ /* Check if the state machine is stopped */
+ tmp = me4000_inl(ao_context->status_reg);
+ if (tmp & ME4000_AO_STATUS_BIT_FSM) {
+ printk(KERN_ERR "me4000_ao_disable_do(): DAC is running\n");
+ return -EBUSY;
+ }
+
+ spin_lock_irqsave(&ao_context->int_lock, flags);
+ tmp = inl(ao_context->ctrl_reg);
+ tmp &= ~(ME4000_AO_CTRL_BIT_ENABLE_DO);
+ me4000_outl(tmp, ao_context->ctrl_reg);
+ spin_unlock_irqrestore(&ao_context->int_lock, flags);
+
+ return 0;
+}
+
+static int me4000_ao_fsm_state(int *arg, me4000_ao_context_t * ao_context)
+{
+ unsigned long tmp;
+
+ CALL_PDEBUG("me4000_ao_fsm_state() is executed\n");
+
+ tmp =
+ (me4000_inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) ? 1
+ : 0;
+
+ if (ao_context->pipe_flag) {
+ printk(KERN_ERR "me4000_ao_fsm_state():Broken pipe detected\n");
+ return -EPIPE;
+ }
+
+ if (put_user(tmp, arg)) {
+ printk(KERN_ERR "me4000_ao_fsm_state():Cannot copy to user\n");
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+/*------------------------------- Analog input stuff --------------------------------------*/
+
+static int me4000_ai_prepare(me4000_ai_context_t * ai_context)
+{
+ wait_queue_head_t queue;
+ int err;
+
+ CALL_PDEBUG("me4000_ai_prepare() is executed\n");
+
+ init_waitqueue_head(&queue);
+
+ /* Set the new mode and stop bits */
+ me4000_outl(ai_context->
+ mode | ME4000_AI_CTRL_BIT_STOP |
+ ME4000_AI_CTRL_BIT_IMMEDIATE_STOP, ai_context->ctrl_reg);
+
+ /* Set the timer registers */
+ ai_context->chan_timer = 66;
+ ai_context->chan_pre_timer = 66;
+ ai_context->scan_timer_low = 0;
+ ai_context->scan_timer_high = 0;
+
+ me4000_outl(65, ai_context->chan_timer_reg);
+ me4000_outl(65, ai_context->chan_pre_timer_reg);
+ me4000_outl(0, ai_context->scan_timer_low_reg);
+ me4000_outl(0, ai_context->scan_timer_high_reg);
+ me4000_outl(0, ai_context->scan_pre_timer_low_reg);
+ me4000_outl(0, ai_context->scan_pre_timer_high_reg);
+
+ ai_context->channel_list_count = 0;
+
+ if (ai_context->mode) {
+ /* Request the interrupt line */
+ err =
+ request_irq(ai_context->irq, me4000_ai_isr,
+ IRQF_DISABLED | IRQF_SHARED, ME4000_NAME,
+ ai_context);
+ if (err) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_prepare():Can't get interrupt line");
+ return -ENODEV;
+ }
+
+ /* Allocate circular buffer */
+ ai_context->circ_buf.buf =
+ kmalloc(ME4000_AI_BUFFER_SIZE, GFP_KERNEL);
+ if (!ai_context->circ_buf.buf) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_prepare():Can't get circular buffer\n");
+ free_irq(ai_context->irq, ai_context);
+ return -ENOMEM;
+ }
+ memset(ai_context->circ_buf.buf, 0, ME4000_AI_BUFFER_SIZE);
+
+ /* Clear the circular buffer */
+ ai_context->circ_buf.head = 0;
+ ai_context->circ_buf.tail = 0;
+ }
+
+ return 0;
+}
+
+static int me4000_ai_reset(me4000_ai_context_t * ai_context)
+{
+ wait_queue_head_t queue;
+ u32 tmp;
+ unsigned long flags;
+
+ CALL_PDEBUG("me4000_ai_reset() is executed\n");
+
+ init_waitqueue_head(&queue);
+
+ /*
+ * First stop conversion of the state machine before reconfigure.
+ * If not stopped before configuring mode, it could
+ * walk in a undefined state.
+ */
+ spin_lock_irqsave(&ai_context->int_lock, flags);
+ tmp = me4000_inl(ai_context->ctrl_reg);
+ tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
+ me4000_outl(tmp, ai_context->ctrl_reg);
+ spin_unlock_irqrestore(&ai_context->int_lock, flags);
+
+ while (inl(ai_context->status_reg) & ME4000_AI_STATUS_BIT_FSM) {
+ interruptible_sleep_on_timeout(&queue, 1);
+ if (signal_pending(current)) {
+ printk(KERN_ERR
+ "me4000_ai_reset():Wait on state machine after stop interrupted\n");
+ return -EINTR;
+ }
+ }
+
+ /* Clear the control register and set the stop bits */
+ spin_lock_irqsave(&ai_context->int_lock, flags);
+ tmp = me4000_inl(ai_context->ctrl_reg);
+ me4000_outl(ME4000_AI_CTRL_BIT_IMMEDIATE_STOP | ME4000_AI_CTRL_BIT_STOP,
+ ai_context->ctrl_reg);
+ spin_unlock_irqrestore(&ai_context->int_lock, flags);
+
+ /* Reset timer registers */
+ ai_context->chan_timer = 66;
+ ai_context->chan_pre_timer = 66;
+ ai_context->scan_timer_low = 0;
+ ai_context->scan_timer_high = 0;
+ ai_context->sample_counter = 0;
+ ai_context->sample_counter_reload = 0;
+
+ me4000_outl(65, ai_context->chan_timer_reg);
+ me4000_outl(65, ai_context->chan_pre_timer_reg);
+ me4000_outl(0, ai_context->scan_timer_low_reg);
+ me4000_outl(0, ai_context->scan_timer_high_reg);
+ me4000_outl(0, ai_context->scan_pre_timer_low_reg);
+ me4000_outl(0, ai_context->scan_pre_timer_high_reg);
+ me4000_outl(0, ai_context->sample_counter_reg);
+
+ ai_context->channel_list_count = 0;
+
+ /* Clear the circular buffer */
+ ai_context->circ_buf.head = 0;
+ ai_context->circ_buf.tail = 0;
+
+ return 0;
+}
+
+static int me4000_ai_ioctl_sing(struct inode *inode_p, struct file *file_p,
+ unsigned int service, unsigned long arg)
+{
+ me4000_ai_context_t *ai_context;
+
+ CALL_PDEBUG("me4000_ai_ioctl_sing() is executed\n");
+
+ ai_context = file_p->private_data;
+
+ if (_IOC_TYPE(service) != ME4000_MAGIC) {
+ printk(KERN_ERR "me4000_ai_ioctl_sing():Wrong magic number\n");
+ return -ENOTTY;
+ }
+ if (_IOC_NR(service) > ME4000_IOCTL_MAXNR) {
+ printk(KERN_ERR
+ "me4000_ai_ioctl_sing():Service number to high\n");
+ return -ENOTTY;
+ }
+
+ switch (service) {
+ case ME4000_AI_SINGLE:
+ return me4000_ai_single((me4000_ai_single_t *) arg, ai_context);
+ case ME4000_AI_EX_TRIG_ENABLE:
+ return me4000_ai_ex_trig_enable(ai_context);
+ case ME4000_AI_EX_TRIG_DISABLE:
+ return me4000_ai_ex_trig_disable(ai_context);
+ case ME4000_AI_EX_TRIG_SETUP:
+ return me4000_ai_ex_trig_setup((me4000_ai_trigger_t *) arg,
+ ai_context);
+ case ME4000_GET_USER_INFO:
+ return me4000_get_user_info((me4000_user_info_t *) arg,
+ ai_context->board_info);
+ case ME4000_AI_OFFSET_ENABLE:
+ return me4000_ai_offset_enable(ai_context);
+ case ME4000_AI_OFFSET_DISABLE:
+ return me4000_ai_offset_disable(ai_context);
+ case ME4000_AI_FULLSCALE_ENABLE:
+ return me4000_ai_fullscale_enable(ai_context);
+ case ME4000_AI_FULLSCALE_DISABLE:
+ return me4000_ai_fullscale_disable(ai_context);
+ case ME4000_AI_EEPROM_READ:
+ return me4000_eeprom_read((me4000_eeprom_t *) arg, ai_context);
+ case ME4000_AI_EEPROM_WRITE:
+ return me4000_eeprom_write((me4000_eeprom_t *) arg, ai_context);
+ default:
+ printk(KERN_ERR
+ "me4000_ai_ioctl_sing():Invalid service number\n");
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+static int me4000_ai_single(me4000_ai_single_t * arg,
+ me4000_ai_context_t * ai_context)
+{
+ me4000_ai_single_t cmd;
+ int err;
+ u32 tmp;
+ wait_queue_head_t queue;
+ unsigned long jiffy;
+
+ CALL_PDEBUG("me4000_ai_single() is executed\n");
+
+ init_waitqueue_head(&queue);
+
+ /* Copy data from user */
+ err = copy_from_user(&cmd, arg, sizeof(me4000_ai_single_t));
+ if (err) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_single():Can't copy from user space\n");
+ return -EFAULT;
+ }
+
+ /* Check range parameter */
+ switch (cmd.range) {
+ case ME4000_AI_LIST_RANGE_BIPOLAR_10:
+ case ME4000_AI_LIST_RANGE_BIPOLAR_2_5:
+ case ME4000_AI_LIST_RANGE_UNIPOLAR_10:
+ case ME4000_AI_LIST_RANGE_UNIPOLAR_2_5:
+ break;
+ default:
+ printk(KERN_ERR
+ "ME4000:me4000_ai_single():Invalid range specified\n");
+ return -EINVAL;
+ }
+
+ /* Check mode and channel number */
+ switch (cmd.mode) {
+ case ME4000_AI_LIST_INPUT_SINGLE_ENDED:
+ if (cmd.channel >= ai_context->board_info->board_p->ai.count) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_single():Analog input is not available\n");
+ return -EINVAL;
+ }
+ break;
+ case ME4000_AI_LIST_INPUT_DIFFERENTIAL:
+ if (cmd.channel >=
+ ai_context->board_info->board_p->ai.diff_count) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_single():Analog input is not available in differential mode\n");
+ return -EINVAL;
+ }
+ break;
+ default:
+ printk(KERN_ERR
+ "ME4000:me4000_ai_single():Invalid mode specified\n");
+ return -EINVAL;
+ }
+
+ /* Clear channel list, data fifo and both stop bits */
+ tmp = me4000_inl(ai_context->ctrl_reg);
+ tmp &=
+ ~(ME4000_AI_CTRL_BIT_CHANNEL_FIFO | ME4000_AI_CTRL_BIT_DATA_FIFO |
+ ME4000_AI_CTRL_BIT_STOP | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP);
+ me4000_outl(tmp, ai_context->ctrl_reg);
+
+ /* Enable channel list and data fifo */
+ tmp |= ME4000_AI_CTRL_BIT_CHANNEL_FIFO | ME4000_AI_CTRL_BIT_DATA_FIFO;
+ me4000_outl(tmp, ai_context->ctrl_reg);
+
+ /* Generate channel list entry */
+ me4000_outl(cmd.channel | cmd.range | cmd.
+ mode | ME4000_AI_LIST_LAST_ENTRY,
+ ai_context->channel_list_reg);
+
+ /* Set the timer to maximum */
+ me4000_outl(66, ai_context->chan_timer_reg);
+ me4000_outl(66, ai_context->chan_pre_timer_reg);
+
+ if (tmp & ME4000_AI_CTRL_BIT_EX_TRIG) {
+ jiffy = jiffies;
+ while (!
+ (me4000_inl(ai_context->status_reg) &
+ ME4000_AI_STATUS_BIT_EF_DATA)) {
+ interruptible_sleep_on_timeout(&queue, 1);
+ if (signal_pending(current)) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_single():Wait on start of state machine interrupted\n");
+ return -EINTR;
+ }
+ if (((jiffies - jiffy) > (cmd.timeout * HZ / USER_HZ)) && cmd.timeout) { // 2.6 has diffrent definitions for HZ in user and kernel space
+ printk(KERN_ERR
+ "ME4000:me4000_ai_single():Timeout reached\n");
+ return -EIO;
+ }
+ }
+ } else {
+ /* Start conversion */
+ me4000_inl(ai_context->start_reg);
+
+ /* Wait until ready */
+ udelay(10);
+ if (!
+ (me4000_inl(ai_context->status_reg) &
+ ME4000_AI_STATUS_BIT_EF_DATA)) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_single():Value not available after wait\n");
+ return -EIO;
+ }
+ }
+
+ /* Read value from data fifo */
+ cmd.value = me4000_inl(ai_context->data_reg) & 0xFFFF;
+
+ /* Copy result back to user */
+ err = copy_to_user(arg, &cmd, sizeof(me4000_ai_single_t));
+ if (err) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_single():Can't copy to user space\n");
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int me4000_ai_ioctl_sw(struct inode *inode_p, struct file *file_p,
+ unsigned int service, unsigned long arg)
+{
+ me4000_ai_context_t *ai_context;
+
+ CALL_PDEBUG("me4000_ai_ioctl_sw() is executed\n");
+
+ ai_context = file_p->private_data;
+
+ if (_IOC_TYPE(service) != ME4000_MAGIC) {
+ printk(KERN_ERR "me4000_ai_ioctl_sw():Wrong magic number\n");
+ return -ENOTTY;
+ }
+ if (_IOC_NR(service) > ME4000_IOCTL_MAXNR) {
+ printk(KERN_ERR
+ "me4000_ai_ioctl_sw():Service number to high\n");
+ return -ENOTTY;
+ }
+
+ switch (service) {
+ case ME4000_AI_SC_SETUP:
+ return me4000_ai_sc_setup((me4000_ai_sc_t *) arg, ai_context);
+ case ME4000_AI_CONFIG:
+ return me4000_ai_config((me4000_ai_config_t *) arg, ai_context);
+ case ME4000_AI_START:
+ return me4000_ai_start(ai_context);
+ case ME4000_AI_STOP:
+ return me4000_ai_stop(ai_context);
+ case ME4000_AI_IMMEDIATE_STOP:
+ return me4000_ai_immediate_stop(ai_context);
+ case ME4000_AI_FSM_STATE:
+ return me4000_ai_fsm_state((int *)arg, ai_context);
+ case ME4000_GET_USER_INFO:
+ return me4000_get_user_info((me4000_user_info_t *) arg,
+ ai_context->board_info);
+ case ME4000_AI_EEPROM_READ:
+ return me4000_eeprom_read((me4000_eeprom_t *) arg, ai_context);
+ case ME4000_AI_EEPROM_WRITE:
+ return me4000_eeprom_write((me4000_eeprom_t *) arg, ai_context);
+ case ME4000_AI_GET_COUNT_BUFFER:
+ return me4000_ai_get_count_buffer((unsigned long *)arg,
+ ai_context);
+ default:
+ printk(KERN_ERR
+ "ME4000:me4000_ai_ioctl_sw():Invalid service number %d\n",
+ service);
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+static int me4000_ai_ioctl_ext(struct inode *inode_p, struct file *file_p,
+ unsigned int service, unsigned long arg)
+{
+ me4000_ai_context_t *ai_context;
+
+ CALL_PDEBUG("me4000_ai_ioctl_ext() is executed\n");
+
+ ai_context = file_p->private_data;
+
+ if (_IOC_TYPE(service) != ME4000_MAGIC) {
+ printk(KERN_ERR "me4000_ai_ioctl_ext():Wrong magic number\n");
+ return -ENOTTY;
+ }
+ if (_IOC_NR(service) > ME4000_IOCTL_MAXNR) {
+ printk(KERN_ERR
+ "me4000_ai_ioctl_ext():Service number to high\n");
+ return -ENOTTY;
+ }
+
+ switch (service) {
+ case ME4000_AI_SC_SETUP:
+ return me4000_ai_sc_setup((me4000_ai_sc_t *) arg, ai_context);
+ case ME4000_AI_CONFIG:
+ return me4000_ai_config((me4000_ai_config_t *) arg, ai_context);
+ case ME4000_AI_START:
+ return me4000_ai_start_ex((unsigned long *)arg, ai_context);
+ case ME4000_AI_STOP:
+ return me4000_ai_stop(ai_context);
+ case ME4000_AI_IMMEDIATE_STOP:
+ return me4000_ai_immediate_stop(ai_context);
+ case ME4000_AI_EX_TRIG_ENABLE:
+ return me4000_ai_ex_trig_enable(ai_context);
+ case ME4000_AI_EX_TRIG_DISABLE:
+ return me4000_ai_ex_trig_disable(ai_context);
+ case ME4000_AI_EX_TRIG_SETUP:
+ return me4000_ai_ex_trig_setup((me4000_ai_trigger_t *) arg,
+ ai_context);
+ case ME4000_AI_FSM_STATE:
+ return me4000_ai_fsm_state((int *)arg, ai_context);
+ case ME4000_GET_USER_INFO:
+ return me4000_get_user_info((me4000_user_info_t *) arg,
+ ai_context->board_info);
+ case ME4000_AI_GET_COUNT_BUFFER:
+ return me4000_ai_get_count_buffer((unsigned long *)arg,
+ ai_context);
+ default:
+ printk(KERN_ERR
+ "ME4000:me4000_ai_ioctl_ext():Invalid service number %d\n",
+ service);
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+static int me4000_ai_fasync(int fd, struct file *file_p, int mode)
+{
+ me4000_ai_context_t *ai_context;
+
+ CALL_PDEBUG("me4000_ao_fasync_cont() is executed\n");
+
+ ai_context = file_p->private_data;
+ return fasync_helper(fd, file_p, mode, &ai_context->fasync_p);
+}
+
+static int me4000_ai_config(me4000_ai_config_t * arg,
+ me4000_ai_context_t * ai_context)
+{
+ me4000_ai_config_t cmd;
+ u32 *list = NULL;
+ u32 mode;
+ int i;
+ int err;
+ wait_queue_head_t queue;
+ u64 scan;
+ u32 tmp;
+
+ CALL_PDEBUG("me4000_ai_config() is executed\n");
+
+ init_waitqueue_head(&queue);
+
+ /* Check if conversion is stopped */
+ if (inl(ai_context->ctrl_reg) & ME4000_AI_STATUS_BIT_FSM) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_config():Conversion is not stopped\n");
+ err = -EBUSY;
+ goto AI_CONFIG_ERR;
+ }
+
+ /* Copy data from user */
+ err = copy_from_user(&cmd, arg, sizeof(me4000_ai_config_t));
+ if (err) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_config():Can't copy from user space\n");
+ err = -EFAULT;
+ goto AI_CONFIG_ERR;
+ }
+
+ PDEBUG
+ ("me4000_ai_config():chan = %ld, pre_chan = %ld, scan_low = %ld, scan_high = %ld, count = %ld\n",
+ cmd.timer.chan, cmd.timer.pre_chan, cmd.timer.scan_low,
+ cmd.timer.scan_high, cmd.channel_list.count);
+
+ /* Check whether sample and hold is available for this board */
+ if (cmd.sh) {
+ if (!ai_context->board_info->board_p->ai.sh_count) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_config():Sample and Hold is not available for this board\n");
+ err = -ENODEV;
+ goto AI_CONFIG_ERR;
+ }
+ }
+
+ /* Check the channel list size */
+ if (cmd.channel_list.count > ME4000_AI_CHANNEL_LIST_COUNT) {
+ printk(KERN_ERR
+ "me4000_ai_config():Channel list is to large\n");
+ err = -EINVAL;
+ goto AI_CONFIG_ERR;
+ }
+
+ /* Copy channel list from user */
+ list = kmalloc(sizeof(u32) * cmd.channel_list.count, GFP_KERNEL);
+ if (!list) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_config():Can't get memory for channel list\n");
+ err = -ENOMEM;
+ goto AI_CONFIG_ERR;
+ }
+ err =
+ copy_from_user(list, cmd.channel_list.list,
+ sizeof(u32) * cmd.channel_list.count);
+ if (err) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_config():Can't copy from user space\n");
+ err = -EFAULT;
+ goto AI_CONFIG_ERR;
+ }
+
+ /* Check if last entry bit is set */
+ if (!(list[cmd.channel_list.count - 1] & ME4000_AI_LIST_LAST_ENTRY)) {
+ printk(KERN_WARNING
+ "me4000_ai_config():Last entry bit is not set\n");
+ list[cmd.channel_list.count - 1] |= ME4000_AI_LIST_LAST_ENTRY;
+ }
+
+ /* Check whether mode is equal for all entries */
+ mode = list[0] & 0x20;
+ for (i = 0; i < cmd.channel_list.count; i++) {
+ if ((list[i] & 0x20) != mode) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_config():Mode is not equal for all entries\n");
+ err = -EINVAL;
+ goto AI_CONFIG_ERR;
+ }
+ }
+
+ /* Check whether channels are available for this mode */
+ if (mode == ME4000_AI_LIST_INPUT_SINGLE_ENDED) {
+ for (i = 0; i < cmd.channel_list.count; i++) {
+ if ((list[i] & 0x1F) >=
+ ai_context->board_info->board_p->ai.count) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_config():Channel is not available for single ended\n");
+ err = -EINVAL;
+ goto AI_CONFIG_ERR;
+ }
+ }
+ } else if (mode == ME4000_AI_LIST_INPUT_DIFFERENTIAL) {
+ for (i = 0; i < cmd.channel_list.count; i++) {
+ if ((list[i] & 0x1F) >=
+ ai_context->board_info->board_p->ai.diff_count) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_config():Channel is not available for differential\n");
+ err = -EINVAL;
+ goto AI_CONFIG_ERR;
+ }
+ }
+ }
+
+ /* Check if bipolar is set for all entries when in differential mode */
+ if (mode == ME4000_AI_LIST_INPUT_DIFFERENTIAL) {
+ for (i = 0; i < cmd.channel_list.count; i++) {
+ if ((list[i] & 0xC0) != ME4000_AI_LIST_RANGE_BIPOLAR_10
+ && (list[i] & 0xC0) !=
+ ME4000_AI_LIST_RANGE_BIPOLAR_2_5) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_config():Bipolar is not selected in differential mode\n");
+ err = -EINVAL;
+ goto AI_CONFIG_ERR;
+ }
+ }
+ }
+
+ if (ai_context->mode != ME4000_AI_ACQ_MODE_EXT_SINGLE_VALUE) {
+ /* Check for minimum channel divisor */
+ if (cmd.timer.chan < ME4000_AI_MIN_TICKS) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_config():Channel timer divisor is to low\n");
+ err = -EINVAL;
+ goto AI_CONFIG_ERR;
+ }
+
+ /* Check if minimum channel divisor is adjusted when sample and hold is activated */
+ if ((cmd.sh) && (cmd.timer.chan != ME4000_AI_MIN_TICKS)) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_config():Channel timer divisor must be at minimum when sample and hold is activated\n");
+ err = -EINVAL;
+ goto AI_CONFIG_ERR;
+ }
+
+ /* Check for minimum channel pre divisor */
+ if (cmd.timer.pre_chan < ME4000_AI_MIN_TICKS) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_config():Channel pre timer divisor is to low\n");
+ err = -EINVAL;
+ goto AI_CONFIG_ERR;
+ }
+
+ /* Write the channel timers */
+ me4000_outl(cmd.timer.chan - 1, ai_context->chan_timer_reg);
+ me4000_outl(cmd.timer.pre_chan - 1,
+ ai_context->chan_pre_timer_reg);
+
+ /* Save the timer values in the board context */
+ ai_context->chan_timer = cmd.timer.chan;
+ ai_context->chan_pre_timer = cmd.timer.pre_chan;
+
+ if (ai_context->mode != ME4000_AI_ACQ_MODE_EXT_SINGLE_CHANLIST) {
+ /* Check for scan timer divisor */
+ scan =
+ (u64) cmd.timer.scan_low | ((u64) cmd.timer.
+ scan_high << 32);
+ if (scan != 0) {
+ if (scan <
+ cmd.channel_list.count * cmd.timer.chan +
+ 1) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_config():Scan timer divisor is to low\n");
+ err = -EINVAL;
+ goto AI_CONFIG_ERR;
+ }
+ }
+
+ /* Write the scan timers */
+ if (scan != 0) {
+ scan--;
+ tmp = (u32) (scan & 0xFFFFFFFF);
+ me4000_outl(tmp,
+ ai_context->scan_timer_low_reg);
+ tmp = (u32) ((scan >> 32) & 0xFFFFFFFF);
+ me4000_outl(tmp,
+ ai_context->scan_timer_high_reg);
+
+ scan =
+ scan - (cmd.timer.chan - 1) +
+ (cmd.timer.pre_chan - 1);
+ tmp = (u32) (scan & 0xFFFFFFFF);
+ me4000_outl(tmp,
+ ai_context->scan_pre_timer_low_reg);
+ tmp = (u32) ((scan >> 32) & 0xFFFFFFFF);
+ me4000_outl(tmp,
+ ai_context->
+ scan_pre_timer_high_reg);
+ } else {
+ me4000_outl(0x0,
+ ai_context->scan_timer_low_reg);
+ me4000_outl(0x0,
+ ai_context->scan_timer_high_reg);
+
+ me4000_outl(0x0,
+ ai_context->scan_pre_timer_low_reg);
+ me4000_outl(0x0,
+ ai_context->
+ scan_pre_timer_high_reg);
+ }
+
+ ai_context->scan_timer_low = cmd.timer.scan_low;
+ ai_context->scan_timer_high = cmd.timer.scan_high;
+ }
+ }
+
+ /* Clear the channel list */
+ tmp = me4000_inl(ai_context->ctrl_reg);
+ tmp &= ~ME4000_AI_CTRL_BIT_CHANNEL_FIFO;
+ me4000_outl(tmp, ai_context->ctrl_reg);
+ tmp |= ME4000_AI_CTRL_BIT_CHANNEL_FIFO;
+ me4000_outl(tmp, ai_context->ctrl_reg);
+
+ /* Write the channel list */
+ for (i = 0; i < cmd.channel_list.count; i++) {
+ me4000_outl(list[i], ai_context->channel_list_reg);
+ }
+
+ /* Setup sample and hold */
+ if (cmd.sh) {
+ tmp |= ME4000_AI_CTRL_BIT_SAMPLE_HOLD;
+ me4000_outl(tmp, ai_context->ctrl_reg);
+ } else {
+ tmp &= ~ME4000_AI_CTRL_BIT_SAMPLE_HOLD;
+ me4000_outl(tmp, ai_context->ctrl_reg);
+ }
+
+ /* Save the channel list size in the board context */
+ ai_context->channel_list_count = cmd.channel_list.count;
+
+ kfree(list);
+
+ return 0;
+
+ AI_CONFIG_ERR:
+
+ /* Reset the timers */
+ ai_context->chan_timer = 66;
+ ai_context->chan_pre_timer = 66;
+ ai_context->scan_timer_low = 0;
+ ai_context->scan_timer_high = 0;
+
+ me4000_outl(65, ai_context->chan_timer_reg);
+ me4000_outl(65, ai_context->chan_pre_timer_reg);
+ me4000_outl(0, ai_context->scan_timer_high_reg);
+ me4000_outl(0, ai_context->scan_timer_low_reg);
+ me4000_outl(0, ai_context->scan_pre_timer_high_reg);
+ me4000_outl(0, ai_context->scan_pre_timer_low_reg);
+
+ ai_context->channel_list_count = 0;
+
+ tmp = me4000_inl(ai_context->ctrl_reg);
+ tmp &=
+ ~(ME4000_AI_CTRL_BIT_CHANNEL_FIFO | ME4000_AI_CTRL_BIT_SAMPLE_HOLD);
+
+ if (list)
+ kfree(list);
+
+ return err;
+
+}
+
+static int ai_common_start(me4000_ai_context_t * ai_context)
+{
+ u32 tmp;
+ CALL_PDEBUG("ai_common_start() is executed\n");
+
+ tmp = me4000_inl(ai_context->ctrl_reg);
+
+ /* Check if conversion is stopped */
+ if (tmp & ME4000_AI_STATUS_BIT_FSM) {
+ printk(KERN_ERR
+ "ME4000:ai_common_start():Conversion is not stopped\n");
+ return -EBUSY;
+ }
+
+ /* Clear data fifo, disable all interrupts, clear sample counter reload */
+ tmp &= ~(ME4000_AI_CTRL_BIT_DATA_FIFO | ME4000_AI_CTRL_BIT_LE_IRQ |
+ ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ |
+ ME4000_AI_CTRL_BIT_SC_RELOAD);
+
+ me4000_outl(tmp, ai_context->ctrl_reg);
+
+ /* Clear circular buffer */
+ ai_context->circ_buf.head = 0;
+ ai_context->circ_buf.tail = 0;
+
+ /* Enable data fifo */
+ tmp |= ME4000_AI_CTRL_BIT_DATA_FIFO;
+
+ /* Determine interrupt setup */
+ if (ai_context->sample_counter && !ai_context->sample_counter_reload) {
+ /* Enable Half Full Interrupt and Sample Counter Interrupt */
+ tmp |= ME4000_AI_CTRL_BIT_SC_IRQ | ME4000_AI_CTRL_BIT_HF_IRQ;
+ } else if (ai_context->sample_counter
+ && ai_context->sample_counter_reload) {
+ if (ai_context->sample_counter <= ME4000_AI_FIFO_COUNT / 2) {
+ /* Enable only Sample Counter Interrupt */
+ tmp |=
+ ME4000_AI_CTRL_BIT_SC_IRQ |
+ ME4000_AI_CTRL_BIT_SC_RELOAD;
+ } else {
+ /* Enable Half Full Interrupt and Sample Counter Interrupt */
+ tmp |=
+ ME4000_AI_CTRL_BIT_SC_IRQ |
+ ME4000_AI_CTRL_BIT_HF_IRQ |
+ ME4000_AI_CTRL_BIT_SC_RELOAD;
+ }
+ } else {
+ /* Enable only Half Full Interrupt */
+ tmp |= ME4000_AI_CTRL_BIT_HF_IRQ;
+ }
+
+ /* Clear the stop bits */
+ tmp &= ~(ME4000_AI_CTRL_BIT_STOP | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP);
+
+ /* Write setup to hardware */
+ me4000_outl(tmp, ai_context->ctrl_reg);
+
+ /* Write sample counter */
+ me4000_outl(ai_context->sample_counter, ai_context->sample_counter_reg);
+
+ return 0;
+}
+
+static int me4000_ai_start(me4000_ai_context_t * ai_context)
+{
+ int err;
+ CALL_PDEBUG("me4000_ai_start() is executed\n");
+
+ /* Prepare Hardware */
+ err = ai_common_start(ai_context);
+ if (err)
+ return err;
+
+ /* Start conversion by dummy read */
+ me4000_inl(ai_context->start_reg);
+
+ return 0;
+}
+
+static int me4000_ai_start_ex(unsigned long *arg,
+ me4000_ai_context_t * ai_context)
+{
+ int err;
+ wait_queue_head_t queue;
+ unsigned long ref;
+ unsigned long timeout;
+
+ CALL_PDEBUG("me4000_ai_start_ex() is executed\n");
+
+ if (get_user(timeout, arg)) {
+ printk(KERN_ERR
+ "me4000_ai_start_ex():Cannot copy data from user\n");
+ return -EFAULT;
+ }
+
+ init_waitqueue_head(&queue);
+
+ /* Prepare Hardware */
+ err = ai_common_start(ai_context);
+ if (err)
+ return err;
+
+ if (timeout) {
+ ref = jiffies;
+ while (!
+ (inl(ai_context->status_reg) & ME4000_AI_STATUS_BIT_FSM))
+ {
+ interruptible_sleep_on_timeout(&queue, 1);
+ if (signal_pending(current)) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_start_ex():Wait on start of state machine interrupted\n");
+ return -EINTR;
+ }
+ if (((jiffies - ref) > (timeout * HZ / USER_HZ))) { // 2.6 has diffrent definitions for HZ in user and kernel space
+ printk(KERN_ERR
+ "ME4000:me4000_ai_start_ex():Timeout reached\n");
+ return -EIO;
+ }
+ }
+ } else {
+ while (!
+ (inl(ai_context->status_reg) & ME4000_AI_STATUS_BIT_FSM))
+ {
+ interruptible_sleep_on_timeout(&queue, 1);
+ if (signal_pending(current)) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_start_ex():Wait on start of state machine interrupted\n");
+ return -EINTR;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int me4000_ai_stop(me4000_ai_context_t * ai_context)
+{
+ wait_queue_head_t queue;
+ u32 tmp;
+ unsigned long flags;
+
+ CALL_PDEBUG("me4000_ai_stop() is executed\n");
+
+ init_waitqueue_head(&queue);
+
+ /* Disable irqs and clear data fifo */
+ spin_lock_irqsave(&ai_context->int_lock, flags);
+ tmp = me4000_inl(ai_context->ctrl_reg);
+ tmp &=
+ ~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ |
+ ME4000_AI_CTRL_BIT_DATA_FIFO);
+ /* Stop conversion of the state machine */
+ tmp |= ME4000_AI_CTRL_BIT_STOP;
+ me4000_outl(tmp, ai_context->ctrl_reg);
+ spin_unlock_irqrestore(&ai_context->int_lock, flags);
+
+ /* Clear circular buffer */
+ ai_context->circ_buf.head = 0;
+ ai_context->circ_buf.tail = 0;
+
+ while (inl(ai_context->status_reg) & ME4000_AI_STATUS_BIT_FSM) {
+ interruptible_sleep_on_timeout(&queue, 1);
+ if (signal_pending(current)) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_stop():Wait on state machine after stop interrupted\n");
+ return -EINTR;
+ }
+ }
+
+ return 0;
+}
+
+static int me4000_ai_immediate_stop(me4000_ai_context_t * ai_context)
+{
+ wait_queue_head_t queue;
+ u32 tmp;
+ unsigned long flags;
+
+ CALL_PDEBUG("me4000_ai_stop() is executed\n");
+
+ init_waitqueue_head(&queue);
+
+ /* Disable irqs and clear data fifo */
+ spin_lock_irqsave(&ai_context->int_lock, flags);
+ tmp = me4000_inl(ai_context->ctrl_reg);
+ tmp &=
+ ~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ |
+ ME4000_AI_CTRL_BIT_DATA_FIFO);
+ /* Stop conversion of the state machine */
+ tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
+ me4000_outl(tmp, ai_context->ctrl_reg);
+ spin_unlock_irqrestore(&ai_context->int_lock, flags);
+
+ /* Clear circular buffer */
+ ai_context->circ_buf.head = 0;
+ ai_context->circ_buf.tail = 0;
+
+ while (inl(ai_context->status_reg) & ME4000_AI_STATUS_BIT_FSM) {
+ interruptible_sleep_on_timeout(&queue, 1);
+ if (signal_pending(current)) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_stop():Wait on state machine after stop interrupted\n");
+ return -EINTR;
+ }
+ }
+
+ return 0;
+}
+
+static int me4000_ai_ex_trig_enable(me4000_ai_context_t * ai_context)
+{
+ u32 tmp;
+ unsigned long flags;
+
+ CALL_PDEBUG("me4000_ai_ex_trig_enable() is executed\n");
+
+ spin_lock_irqsave(&ai_context->int_lock, flags);
+ tmp = me4000_inl(ai_context->ctrl_reg);
+ tmp |= ME4000_AI_CTRL_BIT_EX_TRIG;
+ me4000_outl(tmp, ai_context->ctrl_reg);
+ spin_unlock_irqrestore(&ai_context->int_lock, flags);
+
+ return 0;
+}
+
+static int me4000_ai_ex_trig_disable(me4000_ai_context_t * ai_context)
+{
+ u32 tmp;
+ unsigned long flags;
+
+ CALL_PDEBUG("me4000_ai_ex_trig_disable() is executed\n");
+
+ spin_lock_irqsave(&ai_context->int_lock, flags);
+ tmp = me4000_inl(ai_context->ctrl_reg);
+ tmp &= ~ME4000_AI_CTRL_BIT_EX_TRIG;
+ me4000_outl(tmp, ai_context->ctrl_reg);
+ spin_unlock_irqrestore(&ai_context->int_lock, flags);
+
+ return 0;
+}
+
+static int me4000_ai_ex_trig_setup(me4000_ai_trigger_t * arg,
+ me4000_ai_context_t * ai_context)
+{
+ me4000_ai_trigger_t cmd;
+ int err;
+ u32 tmp;
+ unsigned long flags;
+
+ CALL_PDEBUG("me4000_ai_ex_trig_setup() is executed\n");
+
+ /* Copy data from user */
+ err = copy_from_user(&cmd, arg, sizeof(me4000_ai_trigger_t));
+ if (err) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_ex_trig_setup():Can't copy from user space\n");
+ return -EFAULT;
+ }
+
+ spin_lock_irqsave(&ai_context->int_lock, flags);
+ tmp = me4000_inl(ai_context->ctrl_reg);
+
+ if (cmd.mode == ME4000_AI_TRIGGER_EXT_DIGITAL) {
+ tmp &= ~ME4000_AI_CTRL_BIT_EX_TRIG_ANALOG;
+ } else if (cmd.mode == ME4000_AI_TRIGGER_EXT_ANALOG) {
+ if (!ai_context->board_info->board_p->ai.ex_trig_analog) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_ex_trig_setup():No analog trigger available\n");
+ return -EINVAL;
+ }
+ tmp |= ME4000_AI_CTRL_BIT_EX_TRIG_ANALOG;
+ } else {
+ spin_unlock_irqrestore(&ai_context->int_lock, flags);
+ printk(KERN_ERR
+ "ME4000:me4000_ai_ex_trig_setup():Invalid trigger mode specified\n");
+ return -EINVAL;
+ }
+
+ if (cmd.edge == ME4000_AI_TRIGGER_EXT_EDGE_RISING) {
+ tmp &=
+ ~(ME4000_AI_CTRL_BIT_EX_TRIG_BOTH |
+ ME4000_AI_CTRL_BIT_EX_TRIG_FALLING);
+ } else if (cmd.edge == ME4000_AI_TRIGGER_EXT_EDGE_FALLING) {
+ tmp |= ME4000_AI_CTRL_BIT_EX_TRIG_FALLING;
+ tmp &= ~ME4000_AI_CTRL_BIT_EX_TRIG_BOTH;
+ } else if (cmd.edge == ME4000_AI_TRIGGER_EXT_EDGE_BOTH) {
+ tmp |=
+ ME4000_AI_CTRL_BIT_EX_TRIG_BOTH |
+ ME4000_AI_CTRL_BIT_EX_TRIG_FALLING;
+ } else {
+ spin_unlock_irqrestore(&ai_context->int_lock, flags);
+ printk(KERN_ERR
+ "ME4000:me4000_ai_ex_trig_setup():Invalid trigger edge specified\n");
+ return -EINVAL;
+ }
+
+ me4000_outl(tmp, ai_context->ctrl_reg);
+ spin_unlock_irqrestore(&ai_context->int_lock, flags);
+ return 0;
+}
+
+static int me4000_ai_sc_setup(me4000_ai_sc_t * arg,
+ me4000_ai_context_t * ai_context)
+{
+ me4000_ai_sc_t cmd;
+ int err;
+
+ CALL_PDEBUG("me4000_ai_sc_setup() is executed\n");
+
+ /* Copy data from user */
+ err = copy_from_user(&cmd, arg, sizeof(me4000_ai_sc_t));
+ if (err) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_sc_setup():Can't copy from user space\n");
+ return -EFAULT;
+ }
+
+ ai_context->sample_counter = cmd.value;
+ ai_context->sample_counter_reload = cmd.reload;
+
+ return 0;
+}
+
+static ssize_t me4000_ai_read(struct file *filep, char *buff, size_t cnt,
+ loff_t * offp)
+{
+ me4000_ai_context_t *ai_context = filep->private_data;
+ s16 *buffer = (s16 *) buff;
+ size_t count = cnt / 2;
+ unsigned long flags;
+ int tmp;
+ int c = 0;
+ int k = 0;
+ int ret = 0;
+ wait_queue_t wait;
+
+ CALL_PDEBUG("me4000_ai_read() is executed\n");
+
+ init_waitqueue_entry(&wait, current);
+
+ /* Check count */
+ if (count <= 0) {
+ PDEBUG("me4000_ai_read():Count is 0\n");
+ return 0;
+ }
+
+ while (count > 0) {
+ if (filep->f_flags & O_NONBLOCK) {
+ c = me4000_values_to_end(ai_context->circ_buf,
+ ME4000_AI_BUFFER_COUNT);
+ if (!c) {
+ PDEBUG
+ ("me4000_ai_read():Returning from nonblocking read\n");
+ break;
+ }
+ } else {
+ /* Check if conversion is still running */
+ if (!
+ (me4000_inl(ai_context->status_reg) &
+ ME4000_AI_STATUS_BIT_FSM)) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_read():Conversion interrupted\n");
+ return -EPIPE;
+ }
+
+ wait_event_interruptible(ai_context->wait_queue,
+ (me4000_values_to_end
+ (ai_context->circ_buf,
+ ME4000_AI_BUFFER_COUNT)));
+ if (signal_pending(current)) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_read():Wait on values interrupted from signal\n");
+ return -EINTR;
+ }
+ }
+
+ /* Only read count values or as much as available */
+ c = me4000_values_to_end(ai_context->circ_buf,
+ ME4000_AI_BUFFER_COUNT);
+ PDEBUG("me4000_ai_read():%d values to end\n", c);
+ if (count < c)
+ c = count;
+
+ PDEBUG("me4000_ai_read():Copy %d values to user space\n", c);
+ k = 2 * c;
+ k -= copy_to_user(buffer,
+ ai_context->circ_buf.buf +
+ ai_context->circ_buf.tail, k);
+ c = k / 2;
+ if (!c) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_read():Cannot copy new values to user\n");
+ return -EFAULT;
+ }
+
+ ai_context->circ_buf.tail =
+ (ai_context->circ_buf.tail + c) & (ME4000_AI_BUFFER_COUNT -
+ 1);
+ buffer += c;
+ count -= c;
+ ret += c;
+
+ spin_lock_irqsave(&ai_context->int_lock, flags);
+ if (me4000_buf_space
+ (ai_context->circ_buf, ME4000_AI_BUFFER_COUNT)) {
+ tmp = me4000_inl(ai_context->ctrl_reg);
+
+ /* Determine interrupt setup */
+ if (ai_context->sample_counter
+ && !ai_context->sample_counter_reload) {
+ /* Enable Half Full Interrupt and Sample Counter Interrupt */
+ tmp |=
+ ME4000_AI_CTRL_BIT_SC_IRQ |
+ ME4000_AI_CTRL_BIT_HF_IRQ;
+ } else if (ai_context->sample_counter
+ && ai_context->sample_counter_reload) {
+ if (ai_context->sample_counter <
+ ME4000_AI_FIFO_COUNT / 2) {
+ /* Enable only Sample Counter Interrupt */
+ tmp |= ME4000_AI_CTRL_BIT_SC_IRQ;
+ } else {
+ /* Enable Half Full Interrupt and Sample Counter Interrupt */
+ tmp |=
+ ME4000_AI_CTRL_BIT_SC_IRQ |
+ ME4000_AI_CTRL_BIT_HF_IRQ;
+ }
+ } else {
+ /* Enable only Half Full Interrupt */
+ tmp |= ME4000_AI_CTRL_BIT_HF_IRQ;
+ }
+
+ me4000_outl(tmp, ai_context->ctrl_reg);
+ }
+ spin_unlock_irqrestore(&ai_context->int_lock, flags);
+ }
+
+ /* Check if conversion is still running */
+ if (!(me4000_inl(ai_context->status_reg) & ME4000_AI_STATUS_BIT_FSM)) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_read():Conversion not running after complete read\n");
+ return -EPIPE;
+ }
+
+ if (filep->f_flags & O_NONBLOCK) {
+ return (k == 0) ? -EAGAIN : 2 * ret;
+ }
+
+ CALL_PDEBUG("me4000_ai_read() is leaved\n");
+ return ret * 2;
+}
+
+static unsigned int me4000_ai_poll(struct file *file_p, poll_table * wait)
+{
+ me4000_ai_context_t *ai_context;
+ unsigned long mask = 0;
+
+ CALL_PDEBUG("me4000_ai_poll() is executed\n");
+
+ ai_context = file_p->private_data;
+
+ /* Register wait queue */
+ poll_wait(file_p, &ai_context->wait_queue, wait);
+
+ /* Get available values */
+ if (me4000_values_to_end(ai_context->circ_buf, ME4000_AI_BUFFER_COUNT))
+ mask |= POLLIN | POLLRDNORM;
+
+ PDEBUG("me4000_ai_poll():Return mask %lX\n", mask);
+
+ return mask;
+}
+
+static int me4000_ai_offset_enable(me4000_ai_context_t * ai_context)
+{
+ unsigned long tmp;
+
+ CALL_PDEBUG("me4000_ai_offset_enable() is executed\n");
+
+ tmp = me4000_inl(ai_context->ctrl_reg);
+ tmp |= ME4000_AI_CTRL_BIT_OFFSET;
+ me4000_outl(tmp, ai_context->ctrl_reg);
+
+ return 0;
+}
+
+static int me4000_ai_offset_disable(me4000_ai_context_t * ai_context)
+{
+ unsigned long tmp;
+
+ CALL_PDEBUG("me4000_ai_offset_disable() is executed\n");
+
+ tmp = me4000_inl(ai_context->ctrl_reg);
+ tmp &= ~ME4000_AI_CTRL_BIT_OFFSET;
+ me4000_outl(tmp, ai_context->ctrl_reg);
+
+ return 0;
+}
+
+static int me4000_ai_fullscale_enable(me4000_ai_context_t * ai_context)
+{
+ unsigned long tmp;
+
+ CALL_PDEBUG("me4000_ai_fullscale_enable() is executed\n");
+
+ tmp = me4000_inl(ai_context->ctrl_reg);
+ tmp |= ME4000_AI_CTRL_BIT_FULLSCALE;
+ me4000_outl(tmp, ai_context->ctrl_reg);
+
+ return 0;
+}
+
+static int me4000_ai_fullscale_disable(me4000_ai_context_t * ai_context)
+{
+ unsigned long tmp;
+
+ CALL_PDEBUG("me4000_ai_fullscale_disable() is executed\n");
+
+ tmp = me4000_inl(ai_context->ctrl_reg);
+ tmp &= ~ME4000_AI_CTRL_BIT_FULLSCALE;
+ me4000_outl(tmp, ai_context->ctrl_reg);
+
+ return 0;
+}
+
+static int me4000_ai_fsm_state(int *arg, me4000_ai_context_t * ai_context)
+{
+ unsigned long tmp;
+
+ CALL_PDEBUG("me4000_ai_fsm_state() is executed\n");
+
+ tmp =
+ (me4000_inl(ai_context->status_reg) & ME4000_AI_STATUS_BIT_FSM) ? 1
+ : 0;
+
+ if (put_user(tmp, arg)) {
+ printk(KERN_ERR "me4000_ai_fsm_state():Cannot copy to user\n");
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int me4000_ai_get_count_buffer(unsigned long *arg,
+ me4000_ai_context_t * ai_context)
+{
+ unsigned long c;
+ int err;
+
+ c = me4000_buf_count(ai_context->circ_buf, ME4000_AI_BUFFER_COUNT);
+
+ err = copy_to_user(arg, &c, sizeof(unsigned long));
+ if (err) {
+ printk(KERN_ERR
+ "ME4000:me4000_ai_get_count_buffer():Can't copy to user space\n");
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+/*---------------------------------- EEPROM stuff ---------------------------*/
+
+static int eeprom_write_cmd(me4000_ai_context_t * ai_context, unsigned long cmd,
+ int length)
+{
+ int i;
+ unsigned long value;
+
+ CALL_PDEBUG("eeprom_write_cmd() is executed\n");
+
+ PDEBUG("eeprom_write_cmd():Write command 0x%08lX with length = %d\n",
+ cmd, length);
+
+ /* Get the ICR register and clear the related bits */
+ value = me4000_inl(ai_context->board_info->plx_regbase + PLX_ICR);
+ value &= ~(PLX_ICR_MASK_EEPROM);
+ me4000_outl(value, ai_context->board_info->plx_regbase + PLX_ICR);
+
+ /* Raise the chip select */
+ value |= PLX_ICR_BIT_EEPROM_CHIP_SELECT;
+ me4000_outl(value, ai_context->board_info->plx_regbase + PLX_ICR);
+ udelay(EEPROM_DELAY);
+
+ for (i = 0; i < length; i++) {
+ if (cmd & ((0x1 << (length - 1)) >> i)) {
+ value |= PLX_ICR_BIT_EEPROM_WRITE;
+ } else {
+ value &= ~PLX_ICR_BIT_EEPROM_WRITE;
+ }
+
+ /* Write to EEPROM */
+ me4000_outl(value,
+ ai_context->board_info->plx_regbase + PLX_ICR);
+ udelay(EEPROM_DELAY);
+
+ /* Raising edge of the clock */
+ value |= PLX_ICR_BIT_EEPROM_CLOCK_SET;
+ me4000_outl(value,
+ ai_context->board_info->plx_regbase + PLX_ICR);
+ udelay(EEPROM_DELAY);
+
+ /* Falling edge of the clock */
+ value &= ~PLX_ICR_BIT_EEPROM_CLOCK_SET;
+ me4000_outl(value,
+ ai_context->board_info->plx_regbase + PLX_ICR);
+ udelay(EEPROM_DELAY);
+ }
+
+ /* Clear the chip select */
+ value &= ~PLX_ICR_BIT_EEPROM_CHIP_SELECT;
+ me4000_outl(value, ai_context->board_info->plx_regbase + PLX_ICR);
+ udelay(EEPROM_DELAY);
+
+ /* Wait until hardware is ready for sure */
+ mdelay(10);
+
+ return 0;
+}
+
+static unsigned short eeprom_read_cmd(me4000_ai_context_t * ai_context,
+ unsigned long cmd, int length)
+{
+ int i;
+ unsigned long value;
+ unsigned short id = 0;
+
+ CALL_PDEBUG("eeprom_read_cmd() is executed\n");
+
+ PDEBUG("eeprom_read_cmd():Read command 0x%08lX with length = %d\n", cmd,
+ length);
+
+ /* Get the ICR register and clear the related bits */
+ value = me4000_inl(ai_context->board_info->plx_regbase + PLX_ICR);
+ value &= ~(PLX_ICR_MASK_EEPROM);
+
+ me4000_outl(value, ai_context->board_info->plx_regbase + PLX_ICR);
+
+ /* Raise the chip select */
+ value |= PLX_ICR_BIT_EEPROM_CHIP_SELECT;
+ me4000_outl(value, ai_context->board_info->plx_regbase + PLX_ICR);
+ udelay(EEPROM_DELAY);
+
+ /* Write the read command to the eeprom */
+ for (i = 0; i < length; i++) {
+ if (cmd & ((0x1 << (length - 1)) >> i)) {
+ value |= PLX_ICR_BIT_EEPROM_WRITE;
+ } else {
+ value &= ~PLX_ICR_BIT_EEPROM_WRITE;
+ }
+ me4000_outl(value,
+ ai_context->board_info->plx_regbase + PLX_ICR);
+ udelay(EEPROM_DELAY);
+
+ /* Raising edge of the clock */
+ value |= PLX_ICR_BIT_EEPROM_CLOCK_SET;
+ me4000_outl(value,
+ ai_context->board_info->plx_regbase + PLX_ICR);
+ udelay(EEPROM_DELAY);
+
+ /* Falling edge of the clock */
+ value &= ~PLX_ICR_BIT_EEPROM_CLOCK_SET;
+ me4000_outl(value,
+ ai_context->board_info->plx_regbase + PLX_ICR);
+ udelay(EEPROM_DELAY);
+ }
+
+ /* Read the value from the eeprom */
+ for (i = 0; i < 16; i++) {
+ /* Raising edge of the clock */
+ value |= PLX_ICR_BIT_EEPROM_CLOCK_SET;
+ me4000_outl(value,
+ ai_context->board_info->plx_regbase + PLX_ICR);
+ udelay(EEPROM_DELAY);
+
+ if (me4000_inl(ai_context->board_info->plx_regbase + PLX_ICR) &
+ PLX_ICR_BIT_EEPROM_READ) {
+ id |= (0x8000 >> i);
+ PDEBUG("eeprom_read_cmd():OR with 0x%04X\n",
+ (0x8000 >> i));
+ } else {
+ PDEBUG("eeprom_read_cmd():Dont't OR\n");
+ }
+
+ /* Falling edge of the clock */
+ value &= ~PLX_ICR_BIT_EEPROM_CLOCK_SET;
+ me4000_outl(value,
+ ai_context->board_info->plx_regbase + PLX_ICR);
+ udelay(EEPROM_DELAY);
+ }
+
+ /* Clear the chip select */
+ value &= ~PLX_ICR_BIT_EEPROM_CHIP_SELECT;
+ me4000_outl(value, ai_context->board_info->plx_regbase + PLX_ICR);
+ udelay(EEPROM_DELAY);
+
+ return id;
+}
+
+static int me4000_eeprom_write(me4000_eeprom_t * arg,
+ me4000_ai_context_t * ai_context)
+{
+ int err;
+ me4000_eeprom_t setup;
+ unsigned long cmd;
+ unsigned long date_high;
+ unsigned long date_low;
+
+ CALL_PDEBUG("me4000_eeprom_write() is executed\n");
+
+ err = copy_from_user(&setup, arg, sizeof(setup));
+ if (err) {
+ printk(KERN_ERR
+ "ME4000:me4000_eeprom_write():Cannot copy from user\n");
+ return err;
+ }
+
+ /* Enable writing */
+ eeprom_write_cmd(ai_context, ME4000_EEPROM_CMD_WRITE_ENABLE,
+ ME4000_EEPROM_CMD_LENGTH_WRITE_ENABLE);
+
+ /* Command for date */
+ date_high = (setup.date & 0xFFFF0000) >> 16;
+ date_low = (setup.date & 0x0000FFFF);
+
+ cmd =
+ ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_DATE_HIGH <<
+ ME4000_EEPROM_DATA_LENGTH) | (0xFFFF &
+ (unsigned
+ long)
+ date_high);
+ err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE);
+ if (err)
+ return err;
+
+ cmd =
+ ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_DATE_LOW <<
+ ME4000_EEPROM_DATA_LENGTH) | (0xFFFF &
+ (unsigned
+ long)
+ date_low);
+ err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE);
+ if (err)
+ return err;
+
+ /* Command for unipolar 10V offset */
+ cmd =
+ ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_1_UNI_OFFSET <<
+ ME4000_EEPROM_DATA_LENGTH) | (0xFFFF &
+ (unsigned
+ long)
+ setup.
+ uni_10_offset);
+ err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE);
+ if (err)
+ return err;
+
+ /* Command for unipolar 10V fullscale */
+ cmd =
+ ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_1_UNI_FULLSCALE <<
+ ME4000_EEPROM_DATA_LENGTH) | (0xFFFF &
+ (unsigned
+ long)
+ setup.
+ uni_10_fullscale);
+ err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE);
+ if (err)
+ return err;
+
+ /* Command for unipolar 2,5V offset */
+ cmd =
+ ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_4_UNI_OFFSET <<
+ ME4000_EEPROM_DATA_LENGTH) | (0xFFFF &
+ (unsigned
+ long)
+ setup.
+ uni_2_5_offset);
+ err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE);
+ if (err)
+ return err;
+
+ /* Command for unipolar 2,5V fullscale */
+ cmd =
+ ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_4_UNI_FULLSCALE <<
+ ME4000_EEPROM_DATA_LENGTH) | (0xFFFF &
+ (unsigned
+ long)
+ setup.
+ uni_2_5_fullscale);
+ err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE);
+ if (err)
+ return err;
+
+ /* Command for bipolar 10V offset */
+ cmd =
+ ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_1_BI_OFFSET <<
+ ME4000_EEPROM_DATA_LENGTH) | (0xFFFF &
+ (unsigned
+ long)
+ setup.
+ bi_10_offset);
+ err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE);
+ if (err)
+ return err;
+
+ /* Command for bipolar 10V fullscale */
+ cmd =
+ ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_1_BI_FULLSCALE <<
+ ME4000_EEPROM_DATA_LENGTH) | (0xFFFF &
+ (unsigned
+ long)
+ setup.
+ bi_10_fullscale);
+ err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE);
+ if (err)
+ return err;
+
+ /* Command for bipolar 2,5V offset */
+ cmd =
+ ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_4_BI_OFFSET <<
+ ME4000_EEPROM_DATA_LENGTH) | (0xFFFF &
+ (unsigned
+ long)
+ setup.
+ bi_2_5_offset);
+ err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE);
+ if (err)
+ return err;
+
+ /* Command for bipolar 2,5V fullscale */
+ cmd =
+ ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_4_BI_FULLSCALE <<
+ ME4000_EEPROM_DATA_LENGTH) | (0xFFFF &
+ (unsigned
+ long)
+ setup.
+ bi_2_5_fullscale);
+ err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE);
+ if (err)
+ return err;
+
+ /* Command for differential 10V offset */
+ cmd =
+ ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_1_DIFF_OFFSET <<
+ ME4000_EEPROM_DATA_LENGTH) | (0xFFFF &
+ (unsigned
+ long)
+ setup.
+ diff_10_offset);
+ err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE);
+ if (err)
+ return err;
+
+ /* Command for differential 10V fullscale */
+ cmd =
+ ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_1_DIFF_FULLSCALE
+ << ME4000_EEPROM_DATA_LENGTH) | (0xFFFF &
+ (unsigned
+ long)
+ setup.
+ diff_10_fullscale);
+ err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE);
+ if (err)
+ return err;
+
+ /* Command for differential 2,5V offset */
+ cmd =
+ ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_4_DIFF_OFFSET <<
+ ME4000_EEPROM_DATA_LENGTH) | (0xFFFF &
+ (unsigned
+ long)
+ setup.
+ diff_2_5_offset);
+ err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE);
+ if (err)
+ return err;
+
+ /* Command for differential 2,5V fullscale */
+ cmd =
+ ME4000_EEPROM_CMD_WRITE | (ME4000_EEPROM_ADR_GAIN_4_DIFF_FULLSCALE
+ << ME4000_EEPROM_DATA_LENGTH) | (0xFFFF &
+ (unsigned
+ long)
+ setup.
+ diff_2_5_fullscale);
+ err = eeprom_write_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_WRITE);
+ if (err)
+ return err;
+
+ /* Disable writing */
+ eeprom_write_cmd(ai_context, ME4000_EEPROM_CMD_WRITE_DISABLE,
+ ME4000_EEPROM_CMD_LENGTH_WRITE_DISABLE);
+
+ return 0;
+}
+
+static int me4000_eeprom_read(me4000_eeprom_t * arg,
+ me4000_ai_context_t * ai_context)
+{
+ int err;
+ unsigned long cmd;
+ me4000_eeprom_t setup;
+
+ CALL_PDEBUG("me4000_eeprom_read() is executed\n");
+
+ /* Command for date */
+ cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_DATE_HIGH;
+ setup.date =
+ eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ);
+ setup.date <<= 16;
+ cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_DATE_LOW;
+ setup.date |=
+ eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ);
+
+ /* Command for unipolar 10V offset */
+ cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_1_UNI_OFFSET;
+ setup.uni_10_offset =
+ eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ);
+
+ /* Command for unipolar 10V fullscale */
+ cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_1_UNI_FULLSCALE;
+ setup.uni_10_fullscale =
+ eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ);
+
+ /* Command for unipolar 2,5V offset */
+ cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_4_UNI_OFFSET;
+ setup.uni_2_5_offset =
+ eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ);
+
+ /* Command for unipolar 2,5V fullscale */
+ cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_4_UNI_FULLSCALE;
+ setup.uni_2_5_fullscale =
+ eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ);
+
+ /* Command for bipolar 10V offset */
+ cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_1_BI_OFFSET;
+ setup.bi_10_offset =
+ eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ);
+
+ /* Command for bipolar 10V fullscale */
+ cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_1_BI_FULLSCALE;
+ setup.bi_10_fullscale =
+ eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ);
+
+ /* Command for bipolar 2,5V offset */
+ cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_4_BI_OFFSET;
+ setup.bi_2_5_offset =
+ eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ);
+
+ /* Command for bipolar 2,5V fullscale */
+ cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_4_BI_FULLSCALE;
+ setup.bi_2_5_fullscale =
+ eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ);
+
+ /* Command for differntial 10V offset */
+ cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_1_DIFF_OFFSET;
+ setup.diff_10_offset =
+ eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ);
+
+ /* Command for differential 10V fullscale */
+ cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_1_DIFF_FULLSCALE;
+ setup.diff_10_fullscale =
+ eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ);
+
+ /* Command for differntial 2,5V offset */
+ cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_4_DIFF_OFFSET;
+ setup.diff_2_5_offset =
+ eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ);
+
+ /* Command for differential 2,5V fullscale */
+ cmd = ME4000_EEPROM_CMD_READ | ME4000_EEPROM_ADR_GAIN_4_DIFF_FULLSCALE;
+ setup.diff_2_5_fullscale =
+ eeprom_read_cmd(ai_context, cmd, ME4000_EEPROM_CMD_LENGTH_READ);
+
+ err = copy_to_user(arg, &setup, sizeof(setup));
+ if (err) {
+ printk(KERN_ERR
+ "ME4000:me4000_eeprom_read():Cannot copy to user\n");
+ return err;
+ }
+
+ return 0;
+}
+
+/*------------------------------------ DIO stuff ----------------------------------------------*/
+
+static int me4000_dio_ioctl(struct inode *inode_p, struct file *file_p,
+ unsigned int service, unsigned long arg)
+{
+ me4000_dio_context_t *dio_context;
+
+ CALL_PDEBUG("me4000_dio_ioctl() is executed\n");
+
+ dio_context = file_p->private_data;
+
+ if (_IOC_TYPE(service) != ME4000_MAGIC) {
+ printk(KERN_ERR "me4000_dio_ioctl():Wrong magic number\n");
+ return -ENOTTY;
+ }
+ if (_IOC_NR(service) > ME4000_IOCTL_MAXNR) {
+ printk(KERN_ERR "me4000_dio_ioctl():Service number to high\n");
+ return -ENOTTY;
+ }
+
+ switch (service) {
+ case ME4000_DIO_CONFIG:
+ return me4000_dio_config((me4000_dio_config_t *) arg,
+ dio_context);
+ case ME4000_DIO_SET_BYTE:
+ return me4000_dio_set_byte((me4000_dio_byte_t *) arg,
+ dio_context);
+ case ME4000_DIO_GET_BYTE:
+ return me4000_dio_get_byte((me4000_dio_byte_t *) arg,
+ dio_context);
+ case ME4000_DIO_RESET:
+ return me4000_dio_reset(dio_context);
+ default:
+ printk(KERN_ERR
+ "ME4000:me4000_dio_ioctl():Invalid service number %d\n",
+ service);
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+static int me4000_dio_config(me4000_dio_config_t * arg,
+ me4000_dio_context_t * dio_context)
+{
+ me4000_dio_config_t cmd;
+ u32 tmp;
+ int err;
+
+ CALL_PDEBUG("me4000_dio_config() is executed\n");
+
+ /* Copy data from user */
+ err = copy_from_user(&cmd, arg, sizeof(me4000_dio_config_t));
+ if (err) {
+ printk(KERN_ERR
+ "ME4000:me4000_dio_config():Can't copy from user space\n");
+ return -EFAULT;
+ }
+
+ /* Check port parameter */
+ if (cmd.port >= dio_context->dio_count) {
+ printk(KERN_ERR
+ "ME4000:me4000_dio_config():Port %d is not available\n",
+ cmd.port);
+ return -EINVAL;
+ }
+
+ PDEBUG("me4000_dio_config(): port %d, mode %d, function %d\n", cmd.port,
+ cmd.mode, cmd.function);
+
+ if (cmd.port == ME4000_DIO_PORT_A) {
+ if (cmd.mode == ME4000_DIO_PORT_INPUT) {
+ /* Check if opto isolated version */
+ if (!(me4000_inl(dio_context->dir_reg) & 0x1)) {
+ printk(KERN_ERR
+ "ME4000:me4000_dio_config():Cannot set to input on opto isolated versions\n");
+ return -EIO;
+ }
+
+ tmp = me4000_inl(dio_context->ctrl_reg);
+ tmp &=
+ ~(ME4000_DIO_CTRL_BIT_MODE_0 |
+ ME4000_DIO_CTRL_BIT_MODE_1);
+ me4000_outl(tmp, dio_context->ctrl_reg);
+ } else if (cmd.mode == ME4000_DIO_PORT_OUTPUT) {
+ tmp = me4000_inl(dio_context->ctrl_reg);
+ tmp &=
+ ~(ME4000_DIO_CTRL_BIT_MODE_0 |
+ ME4000_DIO_CTRL_BIT_MODE_1);
+ tmp |= ME4000_DIO_CTRL_BIT_MODE_0;
+ me4000_outl(tmp, dio_context->ctrl_reg);
+ } else if (cmd.mode == ME4000_DIO_FIFO_LOW) {
+ tmp = me4000_inl(dio_context->ctrl_reg);
+ tmp &=
+ ~(ME4000_DIO_CTRL_BIT_MODE_0 |
+ ME4000_DIO_CTRL_BIT_MODE_1 |
+ ME4000_DIO_CTRL_BIT_FIFO_HIGH_0);
+ tmp |=
+ ME4000_DIO_CTRL_BIT_MODE_0 |
+ ME4000_DIO_CTRL_BIT_MODE_1;
+ me4000_outl(tmp, dio_context->ctrl_reg);
+ } else if (cmd.mode == ME4000_DIO_FIFO_HIGH) {
+ tmp = me4000_inl(dio_context->ctrl_reg);
+ tmp |=
+ ME4000_DIO_CTRL_BIT_MODE_0 |
+ ME4000_DIO_CTRL_BIT_MODE_1 |
+ ME4000_DIO_CTRL_BIT_FIFO_HIGH_0;
+ me4000_outl(tmp, dio_context->ctrl_reg);
+ } else {
+ printk(KERN_ERR
+ "ME4000:me4000_dio_config():Mode %d is not available\n",
+ cmd.mode);
+ return -EINVAL;
+ }
+ } else if (cmd.port == ME4000_DIO_PORT_B) {
+ if (cmd.mode == ME4000_DIO_PORT_INPUT) {
+ /* Only do anything when TTL version is installed */
+ if ((me4000_inl(dio_context->dir_reg) & 0x1)) {
+ tmp = me4000_inl(dio_context->ctrl_reg);
+ tmp &=
+ ~(ME4000_DIO_CTRL_BIT_MODE_2 |
+ ME4000_DIO_CTRL_BIT_MODE_3);
+ me4000_outl(tmp, dio_context->ctrl_reg);
+ }
+ } else if (cmd.mode == ME4000_DIO_PORT_OUTPUT) {
+ /* Check if opto isolated version */
+ if (!(me4000_inl(dio_context->dir_reg) & 0x1)) {
+ printk(KERN_ERR
+ "ME4000:me4000_dio_config():Cannot set to output on opto isolated versions\n");
+ return -EIO;
+ }
+
+ tmp = me4000_inl(dio_context->ctrl_reg);
+ tmp &=
+ ~(ME4000_DIO_CTRL_BIT_MODE_2 |
+ ME4000_DIO_CTRL_BIT_MODE_3);
+ tmp |= ME4000_DIO_CTRL_BIT_MODE_2;
+ me4000_outl(tmp, dio_context->ctrl_reg);
+ } else if (cmd.mode == ME4000_DIO_FIFO_LOW) {
+ /* Check if opto isolated version */
+ if (!(me4000_inl(dio_context->dir_reg) & 0x1)) {
+ printk(KERN_ERR
+ "ME4000:me4000_dio_config():Cannot set to FIFO low output on opto isolated versions\n");
+ return -EIO;
+ }
+
+ tmp = me4000_inl(dio_context->ctrl_reg);
+ tmp &=
+ ~(ME4000_DIO_CTRL_BIT_MODE_2 |
+ ME4000_DIO_CTRL_BIT_MODE_3 |
+ ME4000_DIO_CTRL_BIT_FIFO_HIGH_1);
+ tmp |=
+ ME4000_DIO_CTRL_BIT_MODE_2 |
+ ME4000_DIO_CTRL_BIT_MODE_3;
+ me4000_outl(tmp, dio_context->ctrl_reg);
+ } else if (cmd.mode == ME4000_DIO_FIFO_HIGH) {
+ /* Check if opto isolated version */
+ if (!(me4000_inl(dio_context->dir_reg) & 0x1)) {
+ printk(KERN_ERR
+ "ME4000:me4000_dio_config():Cannot set to FIFO high output on opto isolated versions\n");
+ return -EIO;
+ }
+
+ tmp = me4000_inl(dio_context->ctrl_reg);
+ tmp |=
+ ME4000_DIO_CTRL_BIT_MODE_2 |
+ ME4000_DIO_CTRL_BIT_MODE_3 |
+ ME4000_DIO_CTRL_BIT_FIFO_HIGH_1;
+ me4000_outl(tmp, dio_context->ctrl_reg);
+ } else {
+ printk(KERN_ERR
+ "ME4000:me4000_dio_config():Mode %d is not available\n",
+ cmd.mode);
+ return -EINVAL;
+ }
+ } else if (cmd.port == ME4000_DIO_PORT_C) {
+ if (cmd.mode == ME4000_DIO_PORT_INPUT) {
+ tmp = me4000_inl(dio_context->ctrl_reg);
+ tmp &=
+ ~(ME4000_DIO_CTRL_BIT_MODE_4 |
+ ME4000_DIO_CTRL_BIT_MODE_5);
+ me4000_outl(tmp, dio_context->ctrl_reg);
+ } else if (cmd.mode == ME4000_DIO_PORT_OUTPUT) {
+ tmp = me4000_inl(dio_context->ctrl_reg);
+ tmp &=
+ ~(ME4000_DIO_CTRL_BIT_MODE_4 |
+ ME4000_DIO_CTRL_BIT_MODE_5);
+ tmp |= ME4000_DIO_CTRL_BIT_MODE_4;
+ me4000_outl(tmp, dio_context->ctrl_reg);
+ } else if (cmd.mode == ME4000_DIO_FIFO_LOW) {
+ tmp = me4000_inl(dio_context->ctrl_reg);
+ tmp &=
+ ~(ME4000_DIO_CTRL_BIT_MODE_4 |
+ ME4000_DIO_CTRL_BIT_MODE_5 |
+ ME4000_DIO_CTRL_BIT_FIFO_HIGH_2);
+ tmp |=
+ ME4000_DIO_CTRL_BIT_MODE_4 |
+ ME4000_DIO_CTRL_BIT_MODE_5;
+ me4000_outl(tmp, dio_context->ctrl_reg);
+ } else if (cmd.mode == ME4000_DIO_FIFO_HIGH) {
+ tmp = me4000_inl(dio_context->ctrl_reg);
+ tmp |=
+ ME4000_DIO_CTRL_BIT_MODE_4 |
+ ME4000_DIO_CTRL_BIT_MODE_5 |
+ ME4000_DIO_CTRL_BIT_FIFO_HIGH_2;
+ me4000_outl(tmp, dio_context->ctrl_reg);
+ } else {
+ printk(KERN_ERR
+ "ME4000:me4000_dio_config():Mode %d is not available\n",
+ cmd.mode);
+ return -EINVAL;
+ }
+ } else if (cmd.port == ME4000_DIO_PORT_D) {
+ if (cmd.mode == ME4000_DIO_PORT_INPUT) {
+ tmp = me4000_inl(dio_context->ctrl_reg);
+ tmp &=
+ ~(ME4000_DIO_CTRL_BIT_MODE_6 |
+ ME4000_DIO_CTRL_BIT_MODE_7);
+ me4000_outl(tmp, dio_context->ctrl_reg);
+ } else if (cmd.mode == ME4000_DIO_PORT_OUTPUT) {
+ tmp = me4000_inl(dio_context->ctrl_reg);
+ tmp &=
+ ~(ME4000_DIO_CTRL_BIT_MODE_6 |
+ ME4000_DIO_CTRL_BIT_MODE_7);
+ tmp |= ME4000_DIO_CTRL_BIT_MODE_6;
+ me4000_outl(tmp, dio_context->ctrl_reg);
+ } else if (cmd.mode == ME4000_DIO_FIFO_LOW) {
+ tmp = me4000_inl(dio_context->ctrl_reg);
+ tmp &=
+ ~(ME4000_DIO_CTRL_BIT_MODE_6 |
+ ME4000_DIO_CTRL_BIT_MODE_7 |
+ ME4000_DIO_CTRL_BIT_FIFO_HIGH_3);
+ tmp |=
+ ME4000_DIO_CTRL_BIT_MODE_6 |
+ ME4000_DIO_CTRL_BIT_MODE_7;
+ me4000_outl(tmp, dio_context->ctrl_reg);
+ } else if (cmd.mode == ME4000_DIO_FIFO_HIGH) {
+ tmp = me4000_inl(dio_context->ctrl_reg);
+ tmp |=
+ ME4000_DIO_CTRL_BIT_MODE_6 |
+ ME4000_DIO_CTRL_BIT_MODE_7 |
+ ME4000_DIO_CTRL_BIT_FIFO_HIGH_3;
+ me4000_outl(tmp, dio_context->ctrl_reg);
+ } else {
+ printk(KERN_ERR
+ "ME4000:me4000_dio_config():Mode %d is not available\n",
+ cmd.mode);
+ return -EINVAL;
+ }
+ } else {
+ printk(KERN_ERR
+ "ME4000:me4000_dio_config():Port %d is not available\n",
+ cmd.port);
+ return -EINVAL;
+ }
+
+ PDEBUG("me4000_dio_config(): port %d, mode %d, function %d\n", cmd.port,
+ cmd.mode, cmd.function);
+
+ if ((cmd.mode == ME4000_DIO_FIFO_HIGH)
+ || (cmd.mode == ME4000_DIO_FIFO_LOW)) {
+ tmp = me4000_inl(dio_context->ctrl_reg);
+ tmp &=
+ ~(ME4000_DIO_CTRL_BIT_FUNCTION_0 |
+ ME4000_DIO_CTRL_BIT_FUNCTION_1);
+ if (cmd.function == ME4000_DIO_FUNCTION_PATTERN) {
+ me4000_outl(tmp, dio_context->ctrl_reg);
+ } else if (cmd.function == ME4000_DIO_FUNCTION_DEMUX) {
+ tmp |= ME4000_DIO_CTRL_BIT_FUNCTION_0;
+ me4000_outl(tmp, dio_context->ctrl_reg);
+ } else if (cmd.function == ME4000_DIO_FUNCTION_MUX) {
+ tmp |= ME4000_DIO_CTRL_BIT_FUNCTION_1;
+ me4000_outl(tmp, dio_context->ctrl_reg);
+ } else {
+ printk(KERN_ERR
+ "ME4000:me4000_dio_config():Invalid port function specified\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int me4000_dio_set_byte(me4000_dio_byte_t * arg,
+ me4000_dio_context_t * dio_context)
+{
+ me4000_dio_byte_t cmd;
+ int err;
+
+ CALL_PDEBUG("me4000_dio_set_byte() is executed\n");
+
+ /* Copy data from user */
+ err = copy_from_user(&cmd, arg, sizeof(me4000_dio_byte_t));
+ if (err) {
+ printk(KERN_ERR
+ "ME4000:me4000_dio_set_byte():Can't copy from user space\n");
+ return -EFAULT;
+ }
+
+ /* Check port parameter */
+ if (cmd.port >= dio_context->dio_count) {
+ printk(KERN_ERR
+ "ME4000:me4000_dio_set_byte():Port %d is not available\n",
+ cmd.port);
+ return -EINVAL;
+ }
+
+ if (cmd.port == ME4000_DIO_PORT_A) {
+ if ((me4000_inl(dio_context->ctrl_reg) & 0x3) != 0x1) {
+ printk(KERN_ERR
+ "ME4000:me4000_dio_set_byte():Port %d is not in output mode\n",
+ cmd.port);
+ return -EIO;
+ }
+ me4000_outl(cmd.byte, dio_context->port_0_reg);
+ } else if (cmd.port == ME4000_DIO_PORT_B) {
+ if ((me4000_inl(dio_context->ctrl_reg) & 0xC) != 0x4) {
+ printk(KERN_ERR
+ "ME4000:me4000_dio_set_byte():Port %d is not in output mode\n",
+ cmd.port);
+ return -EIO;
+ }
+ me4000_outl(cmd.byte, dio_context->port_1_reg);
+ } else if (cmd.port == ME4000_DIO_PORT_C) {
+ if ((me4000_inl(dio_context->ctrl_reg) & 0x30) != 0x10) {
+ printk(KERN_ERR
+ "ME4000:me4000_dio_set_byte():Port %d is not in output mode\n",
+ cmd.port);
+ return -EIO;
+ }
+ me4000_outl(cmd.byte, dio_context->port_2_reg);
+ } else if (cmd.port == ME4000_DIO_PORT_D) {
+ if ((me4000_inl(dio_context->ctrl_reg) & 0xC0) != 0x40) {
+ printk(KERN_ERR
+ "ME4000:me4000_dio_set_byte():Port %d is not in output mode\n",
+ cmd.port);
+ return -EIO;
+ }
+ me4000_outl(cmd.byte, dio_context->port_3_reg);
+ } else {
+ printk(KERN_ERR
+ "ME4000:me4000_dio_set_byte():Port %d is not available\n",
+ cmd.port);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int me4000_dio_get_byte(me4000_dio_byte_t * arg,
+ me4000_dio_context_t * dio_context)
+{
+ me4000_dio_byte_t cmd;
+ int err;
+
+ CALL_PDEBUG("me4000_dio_get_byte() is executed\n");
+
+ /* Copy data from user */
+ err = copy_from_user(&cmd, arg, sizeof(me4000_dio_byte_t));
+ if (err) {
+ printk(KERN_ERR
+ "ME4000:me4000_dio_get_byte():Can't copy from user space\n");
+ return -EFAULT;
+ }
+
+ /* Check port parameter */
+ if (cmd.port >= dio_context->dio_count) {
+ printk(KERN_ERR
+ "ME4000:me4000_dio_get_byte():Port %d is not available\n",
+ cmd.port);
+ return -EINVAL;
+ }
+
+ if (cmd.port == ME4000_DIO_PORT_A) {
+ cmd.byte = me4000_inl(dio_context->port_0_reg) & 0xFF;
+ } else if (cmd.port == ME4000_DIO_PORT_B) {
+ cmd.byte = me4000_inl(dio_context->port_1_reg) & 0xFF;
+ } else if (cmd.port == ME4000_DIO_PORT_C) {
+ cmd.byte = me4000_inl(dio_context->port_2_reg) & 0xFF;
+ } else if (cmd.port == ME4000_DIO_PORT_D) {
+ cmd.byte = me4000_inl(dio_context->port_3_reg) & 0xFF;
+ } else {
+ printk(KERN_ERR
+ "ME4000:me4000_dio_get_byte():Port %d is not available\n",
+ cmd.port);
+ return -EINVAL;
+ }
+
+ /* Copy result back to user */
+ err = copy_to_user(arg, &cmd, sizeof(me4000_dio_byte_t));
+ if (err) {
+ printk(KERN_ERR
+ "ME4000:me4000_dio_get_byte():Can't copy to user space\n");
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int me4000_dio_reset(me4000_dio_context_t * dio_context)
+{
+ CALL_PDEBUG("me4000_dio_reset() is executed\n");
+
+ /* Clear the control register */
+ me4000_outl(0, dio_context->ctrl_reg);
+
+ /* Check for opto isolated version */
+ if (!(me4000_inl(dio_context->dir_reg) & 0x1)) {
+ me4000_outl(0x1, dio_context->ctrl_reg);
+ me4000_outl(0x0, dio_context->port_0_reg);
+ }
+
+ return 0;
+}
+
+/*------------------------------------ COUNTER STUFF ------------------------------------*/
+
+static int me4000_cnt_ioctl(struct inode *inode_p, struct file *file_p,
+ unsigned int service, unsigned long arg)
+{
+ me4000_cnt_context_t *cnt_context;
+
+ CALL_PDEBUG("me4000_cnt_ioctl() is executed\n");
+
+ cnt_context = file_p->private_data;
+
+ if (_IOC_TYPE(service) != ME4000_MAGIC) {
+ printk(KERN_ERR "me4000_dio_ioctl():Wrong magic number\n");
+ return -ENOTTY;
+ }
+ if (_IOC_NR(service) > ME4000_IOCTL_MAXNR) {
+ printk(KERN_ERR "me4000_dio_ioctl():Service number to high\n");
+ return -ENOTTY;
+ }
+
+ switch (service) {
+ case ME4000_CNT_READ:
+ return me4000_cnt_read((me4000_cnt_t *) arg, cnt_context);
+ case ME4000_CNT_WRITE:
+ return me4000_cnt_write((me4000_cnt_t *) arg, cnt_context);
+ case ME4000_CNT_CONFIG:
+ return me4000_cnt_config((me4000_cnt_config_t *) arg,
+ cnt_context);
+ case ME4000_CNT_RESET:
+ return me4000_cnt_reset(cnt_context);
+ default:
+ printk(KERN_ERR
+ "ME4000:me4000_dio_ioctl():Invalid service number %d\n",
+ service);
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+static int me4000_cnt_config(me4000_cnt_config_t * arg,
+ me4000_cnt_context_t * cnt_context)
+{
+ me4000_cnt_config_t cmd;
+ u8 counter;
+ u8 mode;
+ int err;
+
+ CALL_PDEBUG("me4000_cnt_config() is executed\n");
+
+ /* Copy data from user */
+ err = copy_from_user(&cmd, arg, sizeof(me4000_cnt_config_t));
+ if (err) {
+ printk(KERN_ERR
+ "ME4000:me4000_cnt_config():Can't copy from user space\n");
+ return -EFAULT;
+ }
+
+ /* Check counter parameter */
+ switch (cmd.counter) {
+ case ME4000_CNT_COUNTER_0:
+ counter = ME4000_CNT_CTRL_BIT_COUNTER_0;
+ break;
+ case ME4000_CNT_COUNTER_1:
+ counter = ME4000_CNT_CTRL_BIT_COUNTER_1;
+ break;
+ case ME4000_CNT_COUNTER_2:
+ counter = ME4000_CNT_CTRL_BIT_COUNTER_2;
+ break;
+ default:
+ printk(KERN_ERR
+ "ME4000:me4000_cnt_config():Counter %d is not available\n",
+ cmd.counter);
+ return -EINVAL;
+ }
+
+ /* Check mode parameter */
+ switch (cmd.mode) {
+ case ME4000_CNT_MODE_0:
+ mode = ME4000_CNT_CTRL_BIT_MODE_0;
+ break;
+ case ME4000_CNT_MODE_1:
+ mode = ME4000_CNT_CTRL_BIT_MODE_1;
+ break;
+ case ME4000_CNT_MODE_2:
+ mode = ME4000_CNT_CTRL_BIT_MODE_2;
+ break;
+ case ME4000_CNT_MODE_3:
+ mode = ME4000_CNT_CTRL_BIT_MODE_3;
+ break;
+ case ME4000_CNT_MODE_4:
+ mode = ME4000_CNT_CTRL_BIT_MODE_4;
+ break;
+ case ME4000_CNT_MODE_5:
+ mode = ME4000_CNT_CTRL_BIT_MODE_5;
+ break;
+ default:
+ printk(KERN_ERR
+ "ME4000:me4000_cnt_config():Mode %d is not available\n",
+ cmd.mode);
+ return -EINVAL;
+ }
+
+ /* Write the control word */
+ me4000_outb((counter | mode | 0x30), cnt_context->ctrl_reg);
+
+ return 0;
+}
+
+static int me4000_cnt_read(me4000_cnt_t * arg,
+ me4000_cnt_context_t * cnt_context)
+{
+ me4000_cnt_t cmd;
+ u8 tmp;
+ int err;
+
+ CALL_PDEBUG("me4000_cnt_read() is executed\n");
+
+ /* Copy data from user */
+ err = copy_from_user(&cmd, arg, sizeof(me4000_cnt_t));
+ if (err) {
+ printk(KERN_ERR
+ "ME4000:me4000_cnt_read():Can't copy from user space\n");
+ return -EFAULT;
+ }
+
+ /* Read counter */
+ switch (cmd.counter) {
+ case ME4000_CNT_COUNTER_0:
+ tmp = me4000_inb(cnt_context->counter_0_reg);
+ cmd.value = tmp;
+ tmp = me4000_inb(cnt_context->counter_0_reg);
+ cmd.value |= ((u16) tmp) << 8;
+ break;
+ case ME4000_CNT_COUNTER_1:
+ tmp = me4000_inb(cnt_context->counter_1_reg);
+ cmd.value = tmp;
+ tmp = me4000_inb(cnt_context->counter_1_reg);
+ cmd.value |= ((u16) tmp) << 8;
+ break;
+ case ME4000_CNT_COUNTER_2:
+ tmp = me4000_inb(cnt_context->counter_2_reg);
+ cmd.value = tmp;
+ tmp = me4000_inb(cnt_context->counter_2_reg);
+ cmd.value |= ((u16) tmp) << 8;
+ break;
+ default:
+ printk(KERN_ERR
+ "ME4000:me4000_cnt_read():Counter %d is not available\n",
+ cmd.counter);
+ return -EINVAL;
+ }
+
+ /* Copy result back to user */
+ err = copy_to_user(arg, &cmd, sizeof(me4000_cnt_t));
+ if (err) {
+ printk(KERN_ERR
+ "ME4000:me4000_cnt_read():Can't copy to user space\n");
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int me4000_cnt_write(me4000_cnt_t * arg,
+ me4000_cnt_context_t * cnt_context)
+{
+ me4000_cnt_t cmd;
+ u8 tmp;
+ int err;
+
+ CALL_PDEBUG("me4000_cnt_write() is executed\n");
+
+ /* Copy data from user */
+ err = copy_from_user(&cmd, arg, sizeof(me4000_cnt_t));
+ if (err) {
+ printk(KERN_ERR
+ "ME4000:me4000_cnt_write():Can't copy from user space\n");
+ return -EFAULT;
+ }
+
+ /* Write counter */
+ switch (cmd.counter) {
+ case ME4000_CNT_COUNTER_0:
+ tmp = cmd.value & 0xFF;
+ me4000_outb(tmp, cnt_context->counter_0_reg);
+ tmp = (cmd.value >> 8) & 0xFF;
+ me4000_outb(tmp, cnt_context->counter_0_reg);
+ break;
+ case ME4000_CNT_COUNTER_1:
+ tmp = cmd.value & 0xFF;
+ me4000_outb(tmp, cnt_context->counter_1_reg);
+ tmp = (cmd.value >> 8) & 0xFF;
+ me4000_outb(tmp, cnt_context->counter_1_reg);
+ break;
+ case ME4000_CNT_COUNTER_2:
+ tmp = cmd.value & 0xFF;
+ me4000_outb(tmp, cnt_context->counter_2_reg);
+ tmp = (cmd.value >> 8) & 0xFF;
+ me4000_outb(tmp, cnt_context->counter_2_reg);
+ break;
+ default:
+ printk(KERN_ERR
+ "ME4000:me4000_cnt_write():Counter %d is not available\n",
+ cmd.counter);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int me4000_cnt_reset(me4000_cnt_context_t * cnt_context)
+{
+ CALL_PDEBUG("me4000_cnt_reset() is executed\n");
+
+ /* Set the mode and value for counter 0 */
+ me4000_outb(0x30, cnt_context->ctrl_reg);
+ me4000_outb(0x00, cnt_context->counter_0_reg);
+ me4000_outb(0x00, cnt_context->counter_0_reg);
+
+ /* Set the mode and value for counter 1 */
+ me4000_outb(0x70, cnt_context->ctrl_reg);
+ me4000_outb(0x00, cnt_context->counter_1_reg);
+ me4000_outb(0x00, cnt_context->counter_1_reg);
+
+ /* Set the mode and value for counter 2 */
+ me4000_outb(0xB0, cnt_context->ctrl_reg);
+ me4000_outb(0x00, cnt_context->counter_2_reg);
+ me4000_outb(0x00, cnt_context->counter_2_reg);
+
+ return 0;
+}
+
+/*------------------------------------ External Interrupt stuff ------------------------------------*/
+
+static int me4000_ext_int_ioctl(struct inode *inode_p, struct file *file_p,
+ unsigned int service, unsigned long arg)
+{
+ me4000_ext_int_context_t *ext_int_context;
+
+ CALL_PDEBUG("me4000_ext_int_ioctl() is executed\n");
+
+ ext_int_context = file_p->private_data;
+
+ if (_IOC_TYPE(service) != ME4000_MAGIC) {
+ printk(KERN_ERR "me4000_ext_int_ioctl():Wrong magic number\n");
+ return -ENOTTY;
+ }
+ if (_IOC_NR(service) > ME4000_IOCTL_MAXNR) {
+ printk(KERN_ERR
+ "me4000_ext_int_ioctl():Service number to high\n");
+ return -ENOTTY;
+ }
+
+ switch (service) {
+ case ME4000_EXT_INT_ENABLE:
+ return me4000_ext_int_enable(ext_int_context);
+ case ME4000_EXT_INT_DISABLE:
+ return me4000_ext_int_disable(ext_int_context);
+ case ME4000_EXT_INT_COUNT:
+ return me4000_ext_int_count((unsigned long *)arg,
+ ext_int_context);
+ default:
+ printk(KERN_ERR
+ "ME4000:me4000_ext_int_ioctl():Invalid service number %d\n",
+ service);
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+static int me4000_ext_int_enable(me4000_ext_int_context_t * ext_int_context)
+{
+ unsigned long tmp;
+
+ CALL_PDEBUG("me4000_ext_int_enable() is executed\n");
+
+ tmp = me4000_inl(ext_int_context->ctrl_reg);
+ tmp |= ME4000_AI_CTRL_BIT_EX_IRQ;
+ me4000_outl(tmp, ext_int_context->ctrl_reg);
+
+ return 0;
+}
+
+static int me4000_ext_int_disable(me4000_ext_int_context_t * ext_int_context)
+{
+ unsigned long tmp;
+
+ CALL_PDEBUG("me4000_ext_int_disable() is executed\n");
+
+ tmp = me4000_inl(ext_int_context->ctrl_reg);
+ tmp &= ~ME4000_AI_CTRL_BIT_EX_IRQ;
+ me4000_outl(tmp, ext_int_context->ctrl_reg);
+
+ return 0;
+}
+
+static int me4000_ext_int_count(unsigned long *arg,
+ me4000_ext_int_context_t * ext_int_context)
+{
+
+ CALL_PDEBUG("me4000_ext_int_count() is executed\n");
+
+ put_user(ext_int_context->int_count, arg);
+ return 0;
+}
+
+/*------------------------------------ General stuff ------------------------------------*/
+
+static int me4000_get_user_info(me4000_user_info_t * arg,
+ me4000_info_t * board_info)
+{
+ me4000_user_info_t user_info;
+
+ CALL_PDEBUG("me4000_get_user_info() is executed\n");
+
+ user_info.board_count = board_info->board_count;
+ user_info.plx_regbase = board_info->plx_regbase;
+ user_info.plx_regbase_size = board_info->plx_regbase_size;
+ user_info.me4000_regbase = board_info->me4000_regbase;
+ user_info.me4000_regbase_size = board_info->me4000_regbase_size;
+ user_info.serial_no = board_info->serial_no;
+ user_info.hw_revision = board_info->hw_revision;
+ user_info.vendor_id = board_info->vendor_id;
+ user_info.device_id = board_info->device_id;
+ user_info.pci_bus_no = board_info->pci_bus_no;
+ user_info.pci_dev_no = board_info->pci_dev_no;
+ user_info.pci_func_no = board_info->pci_func_no;
+ user_info.irq = board_info->irq;
+ user_info.irq_count = board_info->irq_count;
+ user_info.driver_version = ME4000_DRIVER_VERSION;
+ user_info.ao_count = board_info->board_p->ao.count;
+ user_info.ao_fifo_count = board_info->board_p->ao.fifo_count;
+
+ user_info.ai_count = board_info->board_p->ai.count;
+ user_info.ai_sh_count = board_info->board_p->ai.sh_count;
+ user_info.ai_ex_trig_analog = board_info->board_p->ai.ex_trig_analog;
+
+ user_info.dio_count = board_info->board_p->dio.count;
+
+ user_info.cnt_count = board_info->board_p->cnt.count;
+
+ if (copy_to_user(arg, &user_info, sizeof(me4000_user_info_t)))
+ return -EFAULT;
+
+ return 0;
+}
+
+/*------------------------------------ ISR STUFF ------------------------------------*/
+
+static int me4000_ext_int_fasync(int fd, struct file *file_ptr, int mode)
+{
+ int result = 0;
+ me4000_ext_int_context_t *ext_int_context;
+
+ CALL_PDEBUG("me4000_ext_int_fasync() is executed\n");
+
+ ext_int_context = file_ptr->private_data;
+
+ result =
+ fasync_helper(fd, file_ptr, mode, &ext_int_context->fasync_ptr);
+
+ CALL_PDEBUG("me4000_ext_int_fasync() is leaved\n");
+ return result;
+}
+
+static irqreturn_t me4000_ao_isr(int irq, void *dev_id)
+{
+ u32 tmp;
+ u32 value;
+ me4000_ao_context_t *ao_context;
+ int i;
+ int c = 0;
+ int c1 = 0;
+ //unsigned long before;
+ //unsigned long after;
+
+ ISR_PDEBUG("me4000_ao_isr() is executed\n");
+
+ ao_context = dev_id;
+
+ /* Check if irq number is right */
+ if (irq != ao_context->irq) {
+ ISR_PDEBUG("me4000_ao_isr():incorrect interrupt num: %d\n",
+ irq);
+ return IRQ_NONE;
+ }
+
+ /* Check if this DAC rised an interrupt */
+ if (!
+ ((0x1 << (ao_context->index + 3)) &
+ me4000_inl(ao_context->irq_status_reg))) {
+ ISR_PDEBUG("me4000_ao_isr():Not this DAC\n");
+ return IRQ_NONE;
+ }
+
+ /* Read status register to find out what happened */
+ tmp = me4000_inl(ao_context->status_reg);
+
+ if (!(tmp & ME4000_AO_STATUS_BIT_EF) && (tmp & ME4000_AO_STATUS_BIT_HF)
+ && (tmp & ME4000_AO_STATUS_BIT_HF)) {
+ c = ME4000_AO_FIFO_COUNT;
+ ISR_PDEBUG("me4000_ao_isr():Fifo empty\n");
+ } else if ((tmp & ME4000_AO_STATUS_BIT_EF)
+ && (tmp & ME4000_AO_STATUS_BIT_HF)
+ && (tmp & ME4000_AO_STATUS_BIT_HF)) {
+ c = ME4000_AO_FIFO_COUNT / 2;
+ ISR_PDEBUG("me4000_ao_isr():Fifo under half full\n");
+ } else {
+ c = 0;
+ ISR_PDEBUG("me4000_ao_isr():Fifo full\n");
+ }
+
+ ISR_PDEBUG("me4000_ao_isr():Try to write 0x%04X values\n", c);
+
+ while (1) {
+ c1 = me4000_values_to_end(ao_context->circ_buf,
+ ME4000_AO_BUFFER_COUNT);
+ ISR_PDEBUG("me4000_ao_isr():Values to end = %d\n", c1);
+ if (c1 > c)
+ c1 = c;
+
+ if (c1 <= 0) {
+ ISR_PDEBUG
+ ("me4000_ao_isr():Work done or buffer empty\n");
+ break;
+ }
+ //rdtscl(before);
+ if (((ao_context->fifo_reg & 0xFF) == ME4000_AO_01_FIFO_REG) ||
+ ((ao_context->fifo_reg & 0xFF) == ME4000_AO_03_FIFO_REG)) {
+ for (i = 0; i < c1; i++) {
+ value =
+ ((u32)
+ (*
+ (ao_context->circ_buf.buf +
+ ao_context->circ_buf.tail + i))) << 16;
+ outl(value, ao_context->fifo_reg);
+ }
+ } else
+ outsw(ao_context->fifo_reg,
+ ao_context->circ_buf.buf +
+ ao_context->circ_buf.tail, c1);
+
+ //rdtscl(after);
+ //printk(KERN_ERR"ME4000:me4000_ao_isr():Time lapse = %lu\n", after - before);
+
+ ao_context->circ_buf.tail =
+ (ao_context->circ_buf.tail + c1) & (ME4000_AO_BUFFER_COUNT -
+ 1);
+ ISR_PDEBUG("me4000_ao_isr():%d values wrote to port 0x%04X\n",
+ c1, ao_context->fifo_reg);
+ c -= c1;
+ }
+
+ /* If there are no values left in the buffer, disable interrupts */
+ spin_lock(&ao_context->int_lock);
+ if (!me4000_buf_count(ao_context->circ_buf, ME4000_AO_BUFFER_COUNT)) {
+ ISR_PDEBUG
+ ("me4000_ao_isr():Disable Interrupt because no values left in buffer\n");
+ tmp = me4000_inl(ao_context->ctrl_reg);
+ tmp &= ~ME4000_AO_CTRL_BIT_ENABLE_IRQ;
+ me4000_outl(tmp, ao_context->ctrl_reg);
+ }
+ spin_unlock(&ao_context->int_lock);
+
+ /* Reset the interrupt */
+ spin_lock(&ao_context->int_lock);
+ tmp = me4000_inl(ao_context->ctrl_reg);
+ tmp |= ME4000_AO_CTRL_BIT_RESET_IRQ;
+ me4000_outl(tmp, ao_context->ctrl_reg);
+ tmp &= ~ME4000_AO_CTRL_BIT_RESET_IRQ;
+ me4000_outl(tmp, ao_context->ctrl_reg);
+
+ /* If state machine is stopped, flow was interrupted */
+ if (!(me4000_inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM)) {
+ printk(KERN_ERR "ME4000:me4000_ao_isr():Broken pipe\n");
+ ao_context->pipe_flag = 1; // Set flag in order to inform write routine
+ tmp &= ~ME4000_AO_CTRL_BIT_ENABLE_IRQ; // Disable interrupt
+ }
+ me4000_outl(tmp, ao_context->ctrl_reg);
+ spin_unlock(&ao_context->int_lock);
+
+ /* Wake up waiting process */
+ wake_up_interruptible(&(ao_context->wait_queue));
+
+ /* Count the interrupt */
+ ao_context->board_info->irq_count++;
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
+{
+ u32 tmp;
+ me4000_ai_context_t *ai_context;
+ int i;
+ int c = 0;
+ int c1 = 0;
+#ifdef ME4000_ISR_DEBUG
+ unsigned long before;
+ unsigned long after;
+#endif
+
+ ISR_PDEBUG("me4000_ai_isr() is executed\n");
+
+#ifdef ME4000_ISR_DEBUG
+ rdtscl(before);
+#endif
+
+ ai_context = dev_id;
+
+ /* Check if irq number is right */
+ if (irq != ai_context->irq) {
+ ISR_PDEBUG("me4000_ai_isr():incorrect interrupt num: %d\n",
+ irq);
+ return IRQ_NONE;
+ }
+
+ if (me4000_inl(ai_context->irq_status_reg) &
+ ME4000_IRQ_STATUS_BIT_AI_HF) {
+ ISR_PDEBUG
+ ("me4000_ai_isr():Fifo half full interrupt occured\n");
+
+ /* Read status register to find out what happened */
+ tmp = me4000_inl(ai_context->ctrl_reg);
+
+ if (!(tmp & ME4000_AI_STATUS_BIT_FF_DATA) &&
+ !(tmp & ME4000_AI_STATUS_BIT_HF_DATA)
+ && (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) {
+ ISR_PDEBUG("me4000_ai_isr():Fifo full\n");
+ c = ME4000_AI_FIFO_COUNT;
+
+ /* FIFO overflow, so stop conversion and disable all interrupts */
+ spin_lock(&ai_context->int_lock);
+ tmp = me4000_inl(ai_context->ctrl_reg);
+ tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
+ tmp &=
+ ~(ME4000_AI_CTRL_BIT_HF_IRQ |
+ ME4000_AI_CTRL_BIT_SC_IRQ);
+ outl(tmp, ai_context->ctrl_reg);
+ spin_unlock(&ai_context->int_lock);
+ } else if ((tmp & ME4000_AI_STATUS_BIT_FF_DATA) &&
+ !(tmp & ME4000_AI_STATUS_BIT_HF_DATA)
+ && (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) {
+ ISR_PDEBUG("me4000_ai_isr():Fifo half full\n");
+ c = ME4000_AI_FIFO_COUNT / 2;
+ } else {
+ c = 0;
+ ISR_PDEBUG
+ ("me4000_ai_isr():Can't determine state of fifo\n");
+ }
+
+ ISR_PDEBUG("me4000_ai_isr():Try to read %d values\n", c);
+
+ while (1) {
+ c1 = me4000_space_to_end(ai_context->circ_buf,
+ ME4000_AI_BUFFER_COUNT);
+ ISR_PDEBUG("me4000_ai_isr():Space to end = %d\n", c1);
+ if (c1 > c)
+ c1 = c;
+
+ if (c1 <= 0) {
+ ISR_PDEBUG
+ ("me4000_ai_isr():Work done or buffer full\n");
+ break;
+ }
+
+ insw(ai_context->data_reg,
+ ai_context->circ_buf.buf +
+ ai_context->circ_buf.head, c1);
+ ai_context->circ_buf.head =
+ (ai_context->circ_buf.head +
+ c1) & (ME4000_AI_BUFFER_COUNT - 1);
+ c -= c1;
+ }
+
+ /* Work is done, so reset the interrupt */
+ ISR_PDEBUG
+ ("me4000_ai_isr():reset interrupt fifo half full interrupt\n");
+ spin_lock(&ai_context->int_lock);
+ tmp = me4000_inl(ai_context->ctrl_reg);
+ tmp |= ME4000_AI_CTRL_BIT_HF_IRQ_RESET;
+ me4000_outl(tmp, ai_context->ctrl_reg);
+ tmp &= ~ME4000_AI_CTRL_BIT_HF_IRQ_RESET;
+ me4000_outl(tmp, ai_context->ctrl_reg);
+ spin_unlock(&ai_context->int_lock);
+ }
+
+ if (me4000_inl(ai_context->irq_status_reg) & ME4000_IRQ_STATUS_BIT_SC) {
+ ISR_PDEBUG
+ ("me4000_ai_isr():Sample counter interrupt occured\n");
+
+ if (!ai_context->sample_counter_reload) {
+ ISR_PDEBUG
+ ("me4000_ai_isr():Single data block available\n");
+
+ /* Poll data until fifo empty */
+ for (i = 0;
+ (i < ME4000_AI_FIFO_COUNT / 2)
+ && (inl(ai_context->ctrl_reg) &
+ ME4000_AI_STATUS_BIT_EF_DATA); i++) {
+ if (me4000_space_to_end
+ (ai_context->circ_buf,
+ ME4000_AI_BUFFER_COUNT)) {
+ *(ai_context->circ_buf.buf +
+ ai_context->circ_buf.head) =
+ inw(ai_context->data_reg);
+ ai_context->circ_buf.head =
+ (ai_context->circ_buf.head +
+ 1) & (ME4000_AI_BUFFER_COUNT - 1);
+ } else
+ break;
+ }
+ ISR_PDEBUG("me4000_ai_isr():%d values read\n", i);
+ } else {
+ if (ai_context->sample_counter <=
+ ME4000_AI_FIFO_COUNT / 2) {
+ ISR_PDEBUG
+ ("me4000_ai_isr():Interrupt from adjustable half full threshold\n");
+
+ /* Read status register to find out what happened */
+ tmp = me4000_inl(ai_context->ctrl_reg);
+
+ if (!(tmp & ME4000_AI_STATUS_BIT_FF_DATA) &&
+ !(tmp & ME4000_AI_STATUS_BIT_HF_DATA)
+ && (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) {
+ ISR_PDEBUG
+ ("me4000_ai_isr():Fifo full\n");
+ c = ME4000_AI_FIFO_COUNT;
+
+ /* FIFO overflow, so stop conversion */
+ spin_lock(&ai_context->int_lock);
+ tmp = me4000_inl(ai_context->ctrl_reg);
+ tmp |=
+ ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
+ outl(tmp, ai_context->ctrl_reg);
+ spin_unlock(&ai_context->int_lock);
+ } else if ((tmp & ME4000_AI_STATUS_BIT_FF_DATA)
+ && !(tmp &
+ ME4000_AI_STATUS_BIT_HF_DATA)
+ && (tmp &
+ ME4000_AI_STATUS_BIT_EF_DATA)) {
+ ISR_PDEBUG
+ ("me4000_ai_isr():Fifo half full\n");
+ c = ME4000_AI_FIFO_COUNT / 2;
+ } else {
+ c = ai_context->sample_counter;
+ ISR_PDEBUG
+ ("me4000_ai_isr():Sample count values\n");
+ }
+
+ ISR_PDEBUG
+ ("me4000_ai_isr():Try to read %d values\n",
+ c);
+
+ while (1) {
+ c1 = me4000_space_to_end(ai_context->
+ circ_buf,
+ ME4000_AI_BUFFER_COUNT);
+ ISR_PDEBUG
+ ("me4000_ai_isr():Space to end = %d\n",
+ c1);
+ if (c1 > c)
+ c1 = c;
+
+ if (c1 <= 0) {
+ ISR_PDEBUG
+ ("me4000_ai_isr():Work done or buffer full\n");
+ break;
+ }
+
+ insw(ai_context->data_reg,
+ ai_context->circ_buf.buf +
+ ai_context->circ_buf.head, c1);
+ ai_context->circ_buf.head =
+ (ai_context->circ_buf.head +
+ c1) & (ME4000_AI_BUFFER_COUNT - 1);
+ c -= c1;
+ }
+ } else {
+ ISR_PDEBUG
+ ("me4000_ai_isr():Multiple data block available\n");
+
+ /* Read status register to find out what happened */
+ tmp = me4000_inl(ai_context->ctrl_reg);
+
+ if (!(tmp & ME4000_AI_STATUS_BIT_FF_DATA) &&
+ !(tmp & ME4000_AI_STATUS_BIT_HF_DATA)
+ && (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) {
+ ISR_PDEBUG
+ ("me4000_ai_isr():Fifo full\n");
+ c = ME4000_AI_FIFO_COUNT;
+
+ /* FIFO overflow, so stop conversion */
+ spin_lock(&ai_context->int_lock);
+ tmp = me4000_inl(ai_context->ctrl_reg);
+ tmp |=
+ ME4000_AI_CTRL_BIT_IMMEDIATE_STOP;
+ outl(tmp, ai_context->ctrl_reg);
+ spin_unlock(&ai_context->int_lock);
+
+ while (1) {
+ c1 = me4000_space_to_end
+ (ai_context->circ_buf,
+ ME4000_AI_BUFFER_COUNT);
+ ISR_PDEBUG
+ ("me4000_ai_isr():Space to end = %d\n",
+ c1);
+ if (c1 > c)
+ c1 = c;
+
+ if (c1 <= 0) {
+ ISR_PDEBUG
+ ("me4000_ai_isr():Work done or buffer full\n");
+ break;
+ }
+
+ insw(ai_context->data_reg,
+ ai_context->circ_buf.buf +
+ ai_context->circ_buf.head,
+ c1);
+ ai_context->circ_buf.head =
+ (ai_context->circ_buf.head +
+ c1) &
+ (ME4000_AI_BUFFER_COUNT -
+ 1);
+ c -= c1;
+ }
+ } else if ((tmp & ME4000_AI_STATUS_BIT_FF_DATA)
+ && !(tmp &
+ ME4000_AI_STATUS_BIT_HF_DATA)
+ && (tmp &
+ ME4000_AI_STATUS_BIT_EF_DATA)) {
+ ISR_PDEBUG
+ ("me4000_ai_isr():Fifo half full\n");
+ c = ME4000_AI_FIFO_COUNT / 2;
+
+ while (1) {
+ c1 = me4000_space_to_end
+ (ai_context->circ_buf,
+ ME4000_AI_BUFFER_COUNT);
+ ISR_PDEBUG
+ ("me4000_ai_isr():Space to end = %d\n",
+ c1);
+ if (c1 > c)
+ c1 = c;
+
+ if (c1 <= 0) {
+ ISR_PDEBUG
+ ("me4000_ai_isr():Work done or buffer full\n");
+ break;
+ }
+
+ insw(ai_context->data_reg,
+ ai_context->circ_buf.buf +
+ ai_context->circ_buf.head,
+ c1);
+ ai_context->circ_buf.head =
+ (ai_context->circ_buf.head +
+ c1) &
+ (ME4000_AI_BUFFER_COUNT -
+ 1);
+ c -= c1;
+ }
+ } else {
+ /* Poll data until fifo empty */
+ for (i = 0;
+ (i < ME4000_AI_FIFO_COUNT / 2)
+ && (inl(ai_context->ctrl_reg) &
+ ME4000_AI_STATUS_BIT_EF_DATA);
+ i++) {
+ if (me4000_space_to_end
+ (ai_context->circ_buf,
+ ME4000_AI_BUFFER_COUNT)) {
+ *(ai_context->circ_buf.
+ buf +
+ ai_context->circ_buf.
+ head) =
+ inw(ai_context->data_reg);
+ ai_context->circ_buf.
+ head =
+ (ai_context->
+ circ_buf.head +
+ 1) &
+ (ME4000_AI_BUFFER_COUNT
+ - 1);
+ } else
+ break;
+ }
+ ISR_PDEBUG
+ ("me4000_ai_isr():%d values read\n",
+ i);
+ }
+ }
+ }
+
+ /* Work is done, so reset the interrupt */
+ ISR_PDEBUG
+ ("me4000_ai_isr():reset interrupt from sample counter\n");
+ spin_lock(&ai_context->int_lock);
+ tmp = me4000_inl(ai_context->ctrl_reg);
+ tmp |= ME4000_AI_CTRL_BIT_SC_IRQ_RESET;
+ me4000_outl(tmp, ai_context->ctrl_reg);
+ tmp &= ~ME4000_AI_CTRL_BIT_SC_IRQ_RESET;
+ me4000_outl(tmp, ai_context->ctrl_reg);
+ spin_unlock(&ai_context->int_lock);
+ }
+
+ /* Values are now available, so wake up waiting process */
+ if (me4000_buf_count(ai_context->circ_buf, ME4000_AI_BUFFER_COUNT)) {
+ ISR_PDEBUG("me4000_ai_isr():Wake up waiting process\n");
+ wake_up_interruptible(&(ai_context->wait_queue));
+ }
+
+ /* If there is no space left in the buffer, disable interrupts */
+ spin_lock(&ai_context->int_lock);
+ if (!me4000_buf_space(ai_context->circ_buf, ME4000_AI_BUFFER_COUNT)) {
+ ISR_PDEBUG
+ ("me4000_ai_isr():Disable Interrupt because no space left in buffer\n");
+ tmp = me4000_inl(ai_context->ctrl_reg);
+ tmp &=
+ ~(ME4000_AI_CTRL_BIT_SC_IRQ | ME4000_AI_CTRL_BIT_HF_IRQ |
+ ME4000_AI_CTRL_BIT_LE_IRQ);
+ me4000_outl(tmp, ai_context->ctrl_reg);
+ }
+ spin_unlock(&ai_context->int_lock);
+
+#ifdef ME4000_ISR_DEBUG
+ rdtscl(after);
+ printk(KERN_ERR "ME4000:me4000_ai_isr():Time lapse = %lu\n",
+ after - before);
+#endif
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t me4000_ext_int_isr(int irq, void *dev_id)
+{
+ me4000_ext_int_context_t *ext_int_context;
+ unsigned long tmp;
+
+ ISR_PDEBUG("me4000_ext_int_isr() is executed\n");
+
+ ext_int_context = dev_id;
+
+ /* Check if irq number is right */
+ if (irq != ext_int_context->irq) {
+ ISR_PDEBUG("me4000_ext_int_isr():incorrect interrupt num: %d\n",
+ irq);
+ return IRQ_NONE;
+ }
+
+ if (me4000_inl(ext_int_context->irq_status_reg) &
+ ME4000_IRQ_STATUS_BIT_EX) {
+ ISR_PDEBUG("me4000_ext_int_isr():External interrupt occured\n");
+ tmp = me4000_inl(ext_int_context->ctrl_reg);
+ tmp |= ME4000_AI_CTRL_BIT_EX_IRQ_RESET;
+ me4000_outl(tmp, ext_int_context->ctrl_reg);
+ tmp &= ~ME4000_AI_CTRL_BIT_EX_IRQ_RESET;
+ me4000_outl(tmp, ext_int_context->ctrl_reg);
+
+ ext_int_context->int_count++;
+
+ if (ext_int_context->fasync_ptr) {
+ ISR_PDEBUG
+ ("me2600_ext_int_isr():Send signal to process\n");
+ kill_fasync(&ext_int_context->fasync_ptr, SIGIO,
+ POLL_IN);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+void __exit me4000_module_exit(void)
+{
+ struct list_head *board_p;
+ me4000_info_t *board_info;
+
+ CALL_PDEBUG("cleanup_module() is executed\n");
+
+ unregister_chrdev(me4000_ext_int_major_driver_no, ME4000_EXT_INT_NAME);
+
+ unregister_chrdev(me4000_cnt_major_driver_no, ME4000_CNT_NAME);
+
+ unregister_chrdev(me4000_dio_major_driver_no, ME4000_DIO_NAME);
+
+ unregister_chrdev(me4000_ai_major_driver_no, ME4000_AI_NAME);
+
+ unregister_chrdev(me4000_ao_major_driver_no, ME4000_AO_NAME);
+
+ remove_proc_entry("me4000", NULL);
+
+ pci_unregister_driver(&me4000_driver);
+
+ /* Reset the boards */
+ for (board_p = me4000_board_info_list.next;
+ board_p != &me4000_board_info_list; board_p = board_p->next) {
+ board_info = list_entry(board_p, me4000_info_t, list);
+ me4000_reset_board(board_info);
+ }
+
+ clear_board_info_list();
+}
+
+module_exit(me4000_module_exit);
+
+static int me4000_read_procmem(char *buf, char **start, off_t offset, int count,
+ int *eof, void *data)
+{
+ int len = 0;
+ int limit = count - 1000;
+ me4000_info_t *board_info;
+ struct list_head *ptr;
+
+ len += sprintf(buf + len, "\nME4000 DRIVER VERSION %X.%X.%X\n\n",
+ (ME4000_DRIVER_VERSION & 0xFF0000) >> 16,
+ (ME4000_DRIVER_VERSION & 0xFF00) >> 8,
+ (ME4000_DRIVER_VERSION & 0xFF));
+
+ /* Search for the board context */
+ for (ptr = me4000_board_info_list.next;
+ (ptr != &me4000_board_info_list) && (len < limit);
+ ptr = ptr->next) {
+ board_info = list_entry(ptr, me4000_info_t, list);
+
+ len +=
+ sprintf(buf + len, "Board number %d:\n",
+ board_info->board_count);
+ len += sprintf(buf + len, "---------------\n");
+ len +=
+ sprintf(buf + len, "PLX base register = 0x%lX\n",
+ board_info->plx_regbase);
+ len +=
+ sprintf(buf + len, "PLX base register size = 0x%lX\n",
+ board_info->plx_regbase_size);
+ len +=
+ sprintf(buf + len, "ME4000 base register = 0x%lX\n",
+ board_info->me4000_regbase);
+ len +=
+ sprintf(buf + len, "ME4000 base register size = 0x%lX\n",
+ board_info->me4000_regbase_size);
+ len +=
+ sprintf(buf + len, "Serial number = 0x%X\n",
+ board_info->serial_no);
+ len +=
+ sprintf(buf + len, "Hardware revision = 0x%X\n",
+ board_info->hw_revision);
+ len +=
+ sprintf(buf + len, "Vendor id = 0x%X\n",
+ board_info->vendor_id);
+ len +=
+ sprintf(buf + len, "Device id = 0x%X\n",
+ board_info->device_id);
+ len +=
+ sprintf(buf + len, "PCI bus number = %d\n",
+ board_info->pci_bus_no);
+ len +=
+ sprintf(buf + len, "PCI device number = %d\n",
+ board_info->pci_dev_no);
+ len +=
+ sprintf(buf + len, "PCI function number = %d\n",
+ board_info->pci_func_no);
+ len += sprintf(buf + len, "IRQ = %u\n", board_info->irq);
+ len +=
+ sprintf(buf + len,
+ "Count of interrupts since module was loaded = %d\n",
+ board_info->irq_count);
+
+ len +=
+ sprintf(buf + len, "Count of analog outputs = %d\n",
+ board_info->board_p->ao.count);
+ len +=
+ sprintf(buf + len, "Count of analog output fifos = %d\n",
+ board_info->board_p->ao.fifo_count);
+
+ len +=
+ sprintf(buf + len, "Count of analog inputs = %d\n",
+ board_info->board_p->ai.count);
+ len +=
+ sprintf(buf + len,
+ "Count of sample and hold devices for analog input = %d\n",
+ board_info->board_p->ai.sh_count);
+ len +=
+ sprintf(buf + len,
+ "Analog external trigger available for analog input = %d\n",
+ board_info->board_p->ai.ex_trig_analog);
+
+ len +=
+ sprintf(buf + len, "Count of digital ports = %d\n",
+ board_info->board_p->dio.count);
+
+ len +=
+ sprintf(buf + len, "Count of counter devices = %d\n",
+ board_info->board_p->cnt.count);
+ len +=
+ sprintf(buf + len, "AI control register = 0x%08X\n",
+ inl(board_info->me4000_regbase +
+ ME4000_AI_CTRL_REG));
+
+ len += sprintf(buf + len, "AO 0 control register = 0x%08X\n",
+ inl(board_info->me4000_regbase +
+ ME4000_AO_00_CTRL_REG));
+ len +=
+ sprintf(buf + len, "AO 0 status register = 0x%08X\n",
+ inl(board_info->me4000_regbase +
+ ME4000_AO_00_STATUS_REG));
+ len +=
+ sprintf(buf + len, "AO 1 control register = 0x%08X\n",
+ inl(board_info->me4000_regbase +
+ ME4000_AO_01_CTRL_REG));
+ len +=
+ sprintf(buf + len, "AO 1 status register = 0x%08X\n",
+ inl(board_info->me4000_regbase +
+ ME4000_AO_01_STATUS_REG));
+ len +=
+ sprintf(buf + len, "AO 2 control register = 0x%08X\n",
+ inl(board_info->me4000_regbase +
+ ME4000_AO_02_CTRL_REG));
+ len +=
+ sprintf(buf + len, "AO 2 status register = 0x%08X\n",
+ inl(board_info->me4000_regbase +
+ ME4000_AO_02_STATUS_REG));
+ len +=
+ sprintf(buf + len, "AO 3 control register = 0x%08X\n",
+ inl(board_info->me4000_regbase +
+ ME4000_AO_03_CTRL_REG));
+ len +=
+ sprintf(buf + len, "AO 3 status register = 0x%08X\n",
+ inl(board_info->me4000_regbase +
+ ME4000_AO_03_STATUS_REG));
+ }
+
+ *eof = 1;
+ return len;
+}
diff --git a/drivers/staging/me4000/me4000.h b/drivers/staging/me4000/me4000.h
new file mode 100644
index 0000000..c35e4b9
--- /dev/null
+++ b/drivers/staging/me4000/me4000.h
@@ -0,0 +1,954 @@
+/*
+ * Copyright (C) 2003 Meilhaus Electronic GmbH (support@meilhaus.de)
+ *
+ * Source File : me4000.h
+ * Author : GG (Guenter Gebhardt) <g.gebhardt@meilhaus.de>
+ */
+
+#ifndef _ME4000_H_
+#define _ME4000_H_
+
+#ifdef __KERNEL__
+
+/*=============================================================================
+ The version of the driver release
+ ===========================================================================*/
+
+#define ME4000_DRIVER_VERSION 0x10009 // Version 1.00.09
+
+/*=============================================================================
+ Debug section
+ ===========================================================================*/
+
+#undef ME4000_CALL_DEBUG // Debug function entry and exit
+#undef ME4000_ISR_DEBUG // Debug the interrupt service routine
+#undef ME4000_PORT_DEBUG // Debug port access
+#undef ME4000_DEBUG // General purpose debug masseges
+
+#ifdef ME4000_CALL_DEBUG
+#undef CALL_PDEBUG
+#define CALL_PDEBUG(fmt, args...) printk(KERN_DEBUG"ME4000:" fmt, ##args)
+#else
+# define CALL_PDEBUG(fmt, args...) // no debugging, do nothing
+#endif
+
+#ifdef ME4000_ISR_DEBUG
+#undef ISR_PDEBUG
+#define ISR_PDEBUG(fmt, args...) printk(KERN_DEBUG"ME4000:" fmt, ##args)
+#else
+#define ISR_PDEBUG(fmt, args...) // no debugging, do nothing
+#endif
+
+#ifdef ME4000_PORT_DEBUG
+#undef PORT_PDEBUG
+#define PORT_PDEBUG(fmt, args...) printk(KERN_DEBUG"ME4000:" fmt, ##args)
+#else
+#define PORT_PDEBUG(fmt, args...) // no debugging, do nothing
+#endif
+
+#ifdef ME4000_DEBUG
+#undef PDEBUG
+#define PDEBUG(fmt, args...) printk(KERN_DEBUG"ME4000:" fmt, ##args)
+#else
+#define PDEBUG(fmt, args...) // no debugging, do nothing
+#endif
+
+/*=============================================================================
+ PCI vendor and device IDs
+ ===========================================================================*/
+
+#define PCI_VENDOR_ID_MEILHAUS 0x1402
+
+#define PCI_DEVICE_ID_MEILHAUS_ME4650 0x4650 // Low Cost version
+
+#define PCI_DEVICE_ID_MEILHAUS_ME4660 0x4660 // Standard version
+#define PCI_DEVICE_ID_MEILHAUS_ME4660I 0x4661 // Isolated version
+#define PCI_DEVICE_ID_MEILHAUS_ME4660S 0x4662 // Standard version with Sample and Hold
+#define PCI_DEVICE_ID_MEILHAUS_ME4660IS 0x4663 // Isolated version with Sample and Hold
+
+#define PCI_DEVICE_ID_MEILHAUS_ME4670 0x4670 // Standard version
+#define PCI_DEVICE_ID_MEILHAUS_ME4670I 0x4671 // Isolated version
+#define PCI_DEVICE_ID_MEILHAUS_ME4670S 0x4672 // Standard version with Sample and Hold
+#define PCI_DEVICE_ID_MEILHAUS_ME4670IS 0x4673 // Isolated version with Sample and Hold
+
+#define PCI_DEVICE_ID_MEILHAUS_ME4680 0x4680 // Standard version
+#define PCI_DEVICE_ID_MEILHAUS_ME4680I 0x4681 // Isolated version
+#define PCI_DEVICE_ID_MEILHAUS_ME4680S 0x4682 // Standard version with Sample and Hold
+#define PCI_DEVICE_ID_MEILHAUS_ME4680IS 0x4683 // Isolated version with Sample and Hold
+
+/*=============================================================================
+ Device names, for entries in /proc/..
+ ===========================================================================*/
+
+#define ME4000_NAME "me4000"
+#define ME4000_AO_NAME "me4000_ao"
+#define ME4000_AI_NAME "me4000_ai"
+#define ME4000_DIO_NAME "me4000_dio"
+#define ME4000_CNT_NAME "me4000_cnt"
+#define ME4000_EXT_INT_NAME "me4000_ext_int"
+
+/*=============================================================================
+ ME-4000 base register offsets
+ ===========================================================================*/
+
+#define ME4000_AO_00_CTRL_REG 0x00 // R/W
+#define ME4000_AO_00_STATUS_REG 0x04 // R/_
+#define ME4000_AO_00_FIFO_REG 0x08 // _/W
+#define ME4000_AO_00_SINGLE_REG 0x0C // R/W
+#define ME4000_AO_00_TIMER_REG 0x10 // _/W
+
+#define ME4000_AO_01_CTRL_REG 0x18 // R/W
+#define ME4000_AO_01_STATUS_REG 0x1C // R/_
+#define ME4000_AO_01_FIFO_REG 0x20 // _/W
+#define ME4000_AO_01_SINGLE_REG 0x24 // R/W
+#define ME4000_AO_01_TIMER_REG 0x28 // _/W
+
+#define ME4000_AO_02_CTRL_REG 0x30 // R/W
+#define ME4000_AO_02_STATUS_REG 0x34 // R/_
+#define ME4000_AO_02_FIFO_REG 0x38 // _/W
+#define ME4000_AO_02_SINGLE_REG 0x3C // R/W
+#define ME4000_AO_02_TIMER_REG 0x40 // _/W
+
+#define ME4000_AO_03_CTRL_REG 0x48 // R/W
+#define ME4000_AO_03_STATUS_REG 0x4C // R/_
+#define ME4000_AO_03_FIFO_REG 0x50 // _/W
+#define ME4000_AO_03_SINGLE_REG 0x54 // R/W
+#define ME4000_AO_03_TIMER_REG 0x58 // _/W
+
+#define ME4000_AI_CTRL_REG 0x74 // _/W
+#define ME4000_AI_STATUS_REG 0x74 // R/_
+#define ME4000_AI_CHANNEL_LIST_REG 0x78 // _/W
+#define ME4000_AI_DATA_REG 0x7C // R/_
+#define ME4000_AI_CHAN_TIMER_REG 0x80 // _/W
+#define ME4000_AI_CHAN_PRE_TIMER_REG 0x84 // _/W
+#define ME4000_AI_SCAN_TIMER_LOW_REG 0x88 // _/W
+#define ME4000_AI_SCAN_TIMER_HIGH_REG 0x8C // _/W
+#define ME4000_AI_SCAN_PRE_TIMER_LOW_REG 0x90 // _/W
+#define ME4000_AI_SCAN_PRE_TIMER_HIGH_REG 0x94 // _/W
+#define ME4000_AI_START_REG 0x98 // R/_
+
+#define ME4000_IRQ_STATUS_REG 0x9C // R/_
+
+#define ME4000_DIO_PORT_0_REG 0xA0 // R/W
+#define ME4000_DIO_PORT_1_REG 0xA4 // R/W
+#define ME4000_DIO_PORT_2_REG 0xA8 // R/W
+#define ME4000_DIO_PORT_3_REG 0xAC // R/W
+#define ME4000_DIO_DIR_REG 0xB0 // R/W
+
+#define ME4000_AO_LOADSETREG_XX 0xB4 // R/W
+
+#define ME4000_DIO_CTRL_REG 0xB8 // R/W
+
+#define ME4000_AO_DEMUX_ADJUST_REG 0xBC // -/W
+
+#define ME4000_AI_SAMPLE_COUNTER_REG 0xC0 // _/W
+
+/*=============================================================================
+ Value to adjust Demux
+ ===========================================================================*/
+
+#define ME4000_AO_DEMUX_ADJUST_VALUE 0x4C
+
+/*=============================================================================
+ Counter base register offsets
+ ===========================================================================*/
+
+#define ME4000_CNT_COUNTER_0_REG 0x00
+#define ME4000_CNT_COUNTER_1_REG 0x01
+#define ME4000_CNT_COUNTER_2_REG 0x02
+#define ME4000_CNT_CTRL_REG 0x03
+
+/*=============================================================================
+ PLX base register offsets
+ ===========================================================================*/
+
+#define PLX_INTCSR 0x4C // Interrupt control and status register
+#define PLX_ICR 0x50 // Initialization control register
+
+/*=============================================================================
+ Bits for the PLX_ICSR register
+ ===========================================================================*/
+
+#define PLX_INTCSR_LOCAL_INT1_EN 0x01 // If set, local interrupt 1 is enabled (r/w)
+#define PLX_INTCSR_LOCAL_INT1_POL 0x02 // If set, local interrupt 1 polarity is active high (r/w)
+#define PLX_INTCSR_LOCAL_INT1_STATE 0x04 // If set, local interrupt 1 is active (r/_)
+#define PLX_INTCSR_LOCAL_INT2_EN 0x08 // If set, local interrupt 2 is enabled (r/w)
+#define PLX_INTCSR_LOCAL_INT2_POL 0x10 // If set, local interrupt 2 polarity is active high (r/w)
+#define PLX_INTCSR_LOCAL_INT2_STATE 0x20 // If set, local interrupt 2 is active (r/_)
+#define PLX_INTCSR_PCI_INT_EN 0x40 // If set, PCI interrupt is enabled (r/w)
+#define PLX_INTCSR_SOFT_INT 0x80 // If set, a software interrupt is generated (r/w)
+
+/*=============================================================================
+ Bits for the PLX_ICR register
+ ===========================================================================*/
+
+#define PLX_ICR_BIT_EEPROM_CLOCK_SET 0x01000000
+#define PLX_ICR_BIT_EEPROM_CHIP_SELECT 0x02000000
+#define PLX_ICR_BIT_EEPROM_WRITE 0x04000000
+#define PLX_ICR_BIT_EEPROM_READ 0x08000000
+#define PLX_ICR_BIT_EEPROM_VALID 0x10000000
+
+#define PLX_ICR_MASK_EEPROM 0x1F000000
+
+#define EEPROM_DELAY 1
+
+/*=============================================================================
+ Bits for the ME4000_AO_CTRL_REG register
+ ===========================================================================*/
+
+#define ME4000_AO_CTRL_BIT_MODE_0 0x001
+#define ME4000_AO_CTRL_BIT_MODE_1 0x002
+#define ME4000_AO_CTRL_MASK_MODE 0x003
+#define ME4000_AO_CTRL_BIT_STOP 0x004
+#define ME4000_AO_CTRL_BIT_ENABLE_FIFO 0x008
+#define ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG 0x010
+#define ME4000_AO_CTRL_BIT_EX_TRIG_EDGE 0x020
+#define ME4000_AO_CTRL_BIT_IMMEDIATE_STOP 0x080
+#define ME4000_AO_CTRL_BIT_ENABLE_DO 0x100
+#define ME4000_AO_CTRL_BIT_ENABLE_IRQ 0x200
+#define ME4000_AO_CTRL_BIT_RESET_IRQ 0x400
+#define ME4000_AO_CTRL_BIT_EX_TRIG_BOTH 0x800
+
+/*=============================================================================
+ Bits for the ME4000_AO_STATUS_REG register
+ ===========================================================================*/
+
+#define ME4000_AO_STATUS_BIT_FSM 0x01
+#define ME4000_AO_STATUS_BIT_FF 0x02
+#define ME4000_AO_STATUS_BIT_HF 0x04
+#define ME4000_AO_STATUS_BIT_EF 0x08
+
+/*=============================================================================
+ Bits for the ME4000_AI_CTRL_REG register
+ ===========================================================================*/
+
+#define ME4000_AI_CTRL_BIT_MODE_0 0x00000001
+#define ME4000_AI_CTRL_BIT_MODE_1 0x00000002
+#define ME4000_AI_CTRL_BIT_MODE_2 0x00000004
+#define ME4000_AI_CTRL_BIT_SAMPLE_HOLD 0x00000008
+#define ME4000_AI_CTRL_BIT_IMMEDIATE_STOP 0x00000010
+#define ME4000_AI_CTRL_BIT_STOP 0x00000020
+#define ME4000_AI_CTRL_BIT_CHANNEL_FIFO 0x00000040
+#define ME4000_AI_CTRL_BIT_DATA_FIFO 0x00000080
+#define ME4000_AI_CTRL_BIT_FULLSCALE 0x00000100
+#define ME4000_AI_CTRL_BIT_OFFSET 0x00000200
+#define ME4000_AI_CTRL_BIT_EX_TRIG_ANALOG 0x00000400
+#define ME4000_AI_CTRL_BIT_EX_TRIG 0x00000800
+#define ME4000_AI_CTRL_BIT_EX_TRIG_FALLING 0x00001000
+#define ME4000_AI_CTRL_BIT_EX_IRQ 0x00002000
+#define ME4000_AI_CTRL_BIT_EX_IRQ_RESET 0x00004000
+#define ME4000_AI_CTRL_BIT_LE_IRQ 0x00008000
+#define ME4000_AI_CTRL_BIT_LE_IRQ_RESET 0x00010000
+#define ME4000_AI_CTRL_BIT_HF_IRQ 0x00020000
+#define ME4000_AI_CTRL_BIT_HF_IRQ_RESET 0x00040000
+#define ME4000_AI_CTRL_BIT_SC_IRQ 0x00080000
+#define ME4000_AI_CTRL_BIT_SC_IRQ_RESET 0x00100000
+#define ME4000_AI_CTRL_BIT_SC_RELOAD 0x00200000
+#define ME4000_AI_CTRL_BIT_EX_TRIG_BOTH 0x80000000
+
+/*=============================================================================
+ Bits for the ME4000_AI_STATUS_REG register
+ ===========================================================================*/
+
+#define ME4000_AI_STATUS_BIT_EF_CHANNEL 0x00400000
+#define ME4000_AI_STATUS_BIT_HF_CHANNEL 0x00800000
+#define ME4000_AI_STATUS_BIT_FF_CHANNEL 0x01000000
+#define ME4000_AI_STATUS_BIT_EF_DATA 0x02000000
+#define ME4000_AI_STATUS_BIT_HF_DATA 0x04000000
+#define ME4000_AI_STATUS_BIT_FF_DATA 0x08000000
+#define ME4000_AI_STATUS_BIT_LE 0x10000000
+#define ME4000_AI_STATUS_BIT_FSM 0x20000000
+
+/*=============================================================================
+ Bits for the ME4000_IRQ_STATUS_REG register
+ ===========================================================================*/
+
+#define ME4000_IRQ_STATUS_BIT_EX 0x01
+#define ME4000_IRQ_STATUS_BIT_LE 0x02
+#define ME4000_IRQ_STATUS_BIT_AI_HF 0x04
+#define ME4000_IRQ_STATUS_BIT_AO_0_HF 0x08
+#define ME4000_IRQ_STATUS_BIT_AO_1_HF 0x10
+#define ME4000_IRQ_STATUS_BIT_AO_2_HF 0x20
+#define ME4000_IRQ_STATUS_BIT_AO_3_HF 0x40
+#define ME4000_IRQ_STATUS_BIT_SC 0x80
+
+/*=============================================================================
+ Bits for the ME4000_DIO_CTRL_REG register
+ ===========================================================================*/
+
+#define ME4000_DIO_CTRL_BIT_MODE_0 0X0001
+#define ME4000_DIO_CTRL_BIT_MODE_1 0X0002
+#define ME4000_DIO_CTRL_BIT_MODE_2 0X0004
+#define ME4000_DIO_CTRL_BIT_MODE_3 0X0008
+#define ME4000_DIO_CTRL_BIT_MODE_4 0X0010
+#define ME4000_DIO_CTRL_BIT_MODE_5 0X0020
+#define ME4000_DIO_CTRL_BIT_MODE_6 0X0040
+#define ME4000_DIO_CTRL_BIT_MODE_7 0X0080
+
+#define ME4000_DIO_CTRL_BIT_FUNCTION_0 0X0100
+#define ME4000_DIO_CTRL_BIT_FUNCTION_1 0X0200
+
+#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_0 0X0400
+#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_1 0X0800
+#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_2 0X1000
+#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_3 0X2000
+
+/*=============================================================================
+ Bits for the ME4000_CNT_CTRL_REG register
+ ===========================================================================*/
+
+#define ME4000_CNT_CTRL_BIT_COUNTER_0 0x00
+#define ME4000_CNT_CTRL_BIT_COUNTER_1 0x40
+#define ME4000_CNT_CTRL_BIT_COUNTER_2 0x80
+
+#define ME4000_CNT_CTRL_BIT_MODE_0 0x00 // Change state if zero crossing
+#define ME4000_CNT_CTRL_BIT_MODE_1 0x02 // Retriggerable One-Shot
+#define ME4000_CNT_CTRL_BIT_MODE_2 0x04 // Asymmetrical divider
+#define ME4000_CNT_CTRL_BIT_MODE_3 0x06 // Symmetrical divider
+#define ME4000_CNT_CTRL_BIT_MODE_4 0x08 // Counter start by software trigger
+#define ME4000_CNT_CTRL_BIT_MODE_5 0x0A // Counter start by hardware trigger
+
+/*=============================================================================
+ Extract information from minor device number
+ ===========================================================================*/
+
+#define AO_BOARD(dev) ((MINOR(dev) >> 6) & 0x3)
+#define AO_PORT(dev) ((MINOR(dev) >> 2) & 0xF)
+#define AO_MODE(dev) (MINOR(dev) & 0x3)
+
+#define AI_BOARD(dev) ((MINOR(dev) >> 3) & 0x1F)
+#define AI_MODE(dev) (MINOR(dev) & 0x7)
+
+#define DIO_BOARD(dev) (MINOR(dev))
+
+#define CNT_BOARD(dev) (MINOR(dev))
+
+#define EXT_INT_BOARD(dev) (MINOR(dev))
+
+/*=============================================================================
+ Circular buffer used for analog input/output reads/writes.
+ ===========================================================================*/
+
+typedef struct me4000_circ_buf {
+ s16 *buf;
+ int volatile head;
+ int volatile tail;
+} me4000_circ_buf_t;
+
+/*=============================================================================
+ Information about the hardware capabilities
+ ===========================================================================*/
+
+typedef struct me4000_ao_info {
+ int count;
+ int fifo_count;
+} me4000_ao_info_t;
+
+typedef struct me4000_ai_info {
+ int count;
+ int sh_count;
+ int diff_count;
+ int ex_trig_analog;
+} me4000_ai_info_t;
+
+typedef struct me4000_dio_info {
+ int count;
+} me4000_dio_info_t;
+
+typedef struct me4000_cnt_info {
+ int count;
+} me4000_cnt_info_t;
+
+typedef struct me4000_board {
+ u16 vendor_id;
+ u16 device_id;
+ me4000_ao_info_t ao;
+ me4000_ai_info_t ai;
+ me4000_dio_info_t dio;
+ me4000_cnt_info_t cnt;
+} me4000_board_t;
+
+static me4000_board_t me4000_boards[] = {
+ {PCI_VENDOR_ID_MEILHAUS, 0x4610, {0, 0}, {16, 0, 0, 0}, {4}, {3}},
+
+ {PCI_VENDOR_ID_MEILHAUS, 0x4650, {0, 0}, {16, 0, 0, 0}, {4}, {0}},
+
+ {PCI_VENDOR_ID_MEILHAUS, 0x4660, {2, 0}, {16, 0, 0, 0}, {4}, {3}},
+ {PCI_VENDOR_ID_MEILHAUS, 0x4661, {2, 0}, {16, 0, 0, 0}, {4}, {3}},
+ {PCI_VENDOR_ID_MEILHAUS, 0x4662, {2, 0}, {16, 8, 0, 0}, {4}, {3}},
+ {PCI_VENDOR_ID_MEILHAUS, 0x4663, {2, 0}, {16, 8, 0, 0}, {4}, {3}},
+
+ {PCI_VENDOR_ID_MEILHAUS, 0x4670, {4, 0}, {32, 0, 16, 1}, {4}, {3}},
+ {PCI_VENDOR_ID_MEILHAUS, 0x4671, {4, 0}, {32, 0, 16, 1}, {4}, {3}},
+ {PCI_VENDOR_ID_MEILHAUS, 0x4672, {4, 0}, {32, 8, 16, 1}, {4}, {3}},
+ {PCI_VENDOR_ID_MEILHAUS, 0x4673, {4, 0}, {32, 8, 16, 1}, {4}, {3}},
+
+ {PCI_VENDOR_ID_MEILHAUS, 0x4680, {4, 4}, {32, 0, 16, 1}, {4}, {3}},
+ {PCI_VENDOR_ID_MEILHAUS, 0x4681, {4, 4}, {32, 0, 16, 1}, {4}, {3}},
+ {PCI_VENDOR_ID_MEILHAUS, 0x4682, {4, 4}, {32, 8, 16, 1}, {4}, {3}},
+ {PCI_VENDOR_ID_MEILHAUS, 0x4683, {4, 4}, {32, 8, 16, 1}, {4}, {3}},
+
+ {0},
+};
+
+#define ME4000_BOARD_VERSIONS (sizeof(me4000_boards) / sizeof(me4000_board_t) - 1)
+
+/*=============================================================================
+ PCI device table.
+ This is used by modprobe to translate PCI IDs to drivers.
+ ===========================================================================*/
+
+static struct pci_device_id me4000_pci_table[] __devinitdata = {
+ {PCI_VENDOR_ID_MEILHAUS, 0x4610, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+
+ {PCI_VENDOR_ID_MEILHAUS, 0x4650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+
+ {PCI_VENDOR_ID_MEILHAUS, 0x4660, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_MEILHAUS, 0x4661, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_MEILHAUS, 0x4662, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_MEILHAUS, 0x4663, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+
+ {PCI_VENDOR_ID_MEILHAUS, 0x4670, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_MEILHAUS, 0x4671, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_MEILHAUS, 0x4672, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_MEILHAUS, 0x4673, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+
+ {PCI_VENDOR_ID_MEILHAUS, 0x4680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_MEILHAUS, 0x4681, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_MEILHAUS, 0x4682, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_MEILHAUS, 0x4683, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+
+ {0}
+};
+
+MODULE_DEVICE_TABLE(pci, me4000_pci_table);
+
+/*=============================================================================
+ Global board and subdevice information structures
+ ===========================================================================*/
+
+typedef struct me4000_info {
+ struct list_head list; // List of all detected boards
+ int board_count; // Index of the board after detection
+
+ unsigned long plx_regbase; // PLX configuration space base address
+ unsigned long me4000_regbase; // Base address of the ME4000
+ unsigned long timer_regbase; // Base address of the timer circuit
+ unsigned long program_regbase; // Base address to set the program pin for the xilinx
+
+ unsigned long plx_regbase_size; // PLX register set space
+ unsigned long me4000_regbase_size; // ME4000 register set space
+ unsigned long timer_regbase_size; // Timer circuit register set space
+ unsigned long program_regbase_size; // Size of program base address of the ME4000
+
+ unsigned int serial_no; // Serial number of the board
+ unsigned char hw_revision; // Hardware revision of the board
+ unsigned short vendor_id; // Meilhaus vendor id (0x1402)
+ unsigned short device_id; // Device ID
+
+ int pci_bus_no; // PCI bus number
+ int pci_dev_no; // PCI device number
+ int pci_func_no; // PCI function number
+ struct pci_dev *pci_dev_p; // General PCI information
+
+ me4000_board_t *board_p; // Holds the board capabilities
+
+ unsigned int irq; // IRQ assigned from the PCI BIOS
+ unsigned int irq_count; // Count of external interrupts
+
+ spinlock_t preload_lock; // Guards the analog output preload register
+ spinlock_t ai_ctrl_lock; // Guards the analog input control register
+
+ struct list_head ao_context_list; // List with analog output specific context
+ struct me4000_ai_context *ai_context; // Analog input specific context
+ struct me4000_dio_context *dio_context; // Digital I/O specific context
+ struct me4000_cnt_context *cnt_context; // Counter specific context
+ struct me4000_ext_int_context *ext_int_context; // External interrupt specific context
+} me4000_info_t;
+
+typedef struct me4000_ao_context {
+ struct list_head list; // linked list of me4000_ao_context_t
+ int index; // Index in the list
+ int mode; // Indicates mode (0 = single, 1 = wraparound, 2 = continous)
+ int dac_in_use; // Indicates if already opend
+ spinlock_t use_lock; // Guards in_use
+ spinlock_t int_lock; // Used when locking out interrupts
+ me4000_circ_buf_t circ_buf; // Circular buffer
+ wait_queue_head_t wait_queue; // Wait queue to sleep while blocking write
+ me4000_info_t *board_info;
+ unsigned int irq; // The irq associated with this ADC
+ int volatile pipe_flag; // Indicates broken pipe set from me4000_ao_isr()
+ unsigned long ctrl_reg;
+ unsigned long status_reg;
+ unsigned long fifo_reg;
+ unsigned long single_reg;
+ unsigned long timer_reg;
+ unsigned long irq_status_reg;
+ unsigned long preload_reg;
+ struct fasync_struct *fasync_p; // Queue for asynchronous notification
+} me4000_ao_context_t;
+
+typedef struct me4000_ai_context {
+ struct list_head list; // linked list of me4000_ai_info_t
+ int mode; // Indicates mode
+ int in_use; // Indicates if already opend
+ spinlock_t use_lock; // Guards in_use
+ spinlock_t int_lock; // Used when locking out interrupts
+ int number; // Number of the DAC
+ unsigned int irq; // The irq associated with this ADC
+ me4000_circ_buf_t circ_buf; // Circular buffer
+ wait_queue_head_t wait_queue; // Wait queue to sleep while blocking read
+ me4000_info_t *board_info;
+
+ struct fasync_struct *fasync_p; // Queue for asynchronous notification
+
+ unsigned long ctrl_reg;
+ unsigned long status_reg;
+ unsigned long channel_list_reg;
+ unsigned long data_reg;
+ unsigned long chan_timer_reg;
+ unsigned long chan_pre_timer_reg;
+ unsigned long scan_timer_low_reg;
+ unsigned long scan_timer_high_reg;
+ unsigned long scan_pre_timer_low_reg;
+ unsigned long scan_pre_timer_high_reg;
+ unsigned long start_reg;
+ unsigned long irq_status_reg;
+ unsigned long sample_counter_reg;
+
+ unsigned long chan_timer;
+ unsigned long chan_pre_timer;
+ unsigned long scan_timer_low;
+ unsigned long scan_timer_high;
+ unsigned long channel_list_count;
+ unsigned long sample_counter;
+ int sample_counter_reload;
+} me4000_ai_context_t;
+
+typedef struct me4000_dio_context {
+ struct list_head list; // linked list of me4000_dio_context_t
+ int in_use; // Indicates if already opend
+ spinlock_t use_lock; // Guards in_use
+ int number;
+ int dio_count;
+ me4000_info_t *board_info;
+ unsigned long dir_reg;
+ unsigned long ctrl_reg;
+ unsigned long port_0_reg;
+ unsigned long port_1_reg;
+ unsigned long port_2_reg;
+ unsigned long port_3_reg;
+} me4000_dio_context_t;
+
+typedef struct me4000_cnt_context {
+ struct list_head list; // linked list of me4000_dio_context_t
+ int in_use; // Indicates if already opend
+ spinlock_t use_lock; // Guards in_use
+ int number;
+ int cnt_count;
+ me4000_info_t *board_info;
+ unsigned long ctrl_reg;
+ unsigned long counter_0_reg;
+ unsigned long counter_1_reg;
+ unsigned long counter_2_reg;
+} me4000_cnt_context_t;
+
+typedef struct me4000_ext_int_context {
+ struct list_head list; // linked list of me4000_dio_context_t
+ int in_use; // Indicates if already opend
+ spinlock_t use_lock; // Guards in_use
+ int number;
+ me4000_info_t *board_info;
+ unsigned int irq;
+ unsigned long int_count;
+ struct fasync_struct *fasync_ptr;
+ unsigned long ctrl_reg;
+ unsigned long irq_status_reg;
+} me4000_ext_int_context_t;
+
+#endif
+
+/*=============================================================================
+ Application include section starts here
+ ===========================================================================*/
+
+/*-----------------------------------------------------------------------------
+ Defines for analog input
+ ----------------------------------------------------------------------------*/
+
+/* General stuff */
+#define ME4000_AI_FIFO_COUNT 2048
+
+#define ME4000_AI_MIN_TICKS 66
+#define ME4000_AI_MAX_SCAN_TICKS 0xFFFFFFFFFFLL
+
+#define ME4000_AI_BUFFER_SIZE (32 * 1024) // Size in bytes
+
+#define ME4000_AI_BUFFER_COUNT ((ME4000_AI_BUFFER_SIZE) / 2) // Size in values
+
+/* Channel list defines and masks */
+#define ME4000_AI_CHANNEL_LIST_COUNT 1024
+
+#define ME4000_AI_LIST_INPUT_SINGLE_ENDED 0x000
+#define ME4000_AI_LIST_INPUT_DIFFERENTIAL 0x020
+
+#define ME4000_AI_LIST_RANGE_BIPOLAR_10 0x000
+#define ME4000_AI_LIST_RANGE_BIPOLAR_2_5 0x040
+#define ME4000_AI_LIST_RANGE_UNIPOLAR_10 0x080
+#define ME4000_AI_LIST_RANGE_UNIPOLAR_2_5 0x0C0
+
+#define ME4000_AI_LIST_LAST_ENTRY 0x100
+
+/* External trigger defines */
+#define ME4000_AI_TRIGGER_SOFTWARE 0x0 // Use only with API
+#define ME4000_AI_TRIGGER_EXT_DIGITAL 0x1
+#define ME4000_AI_TRIGGER_EXT_ANALOG 0x2
+
+#define ME4000_AI_TRIGGER_EXT_EDGE_RISING 0x0
+#define ME4000_AI_TRIGGER_EXT_EDGE_FALLING 0x1
+#define ME4000_AI_TRIGGER_EXT_EDGE_BOTH 0x2
+
+/* Sample and Hold */
+#define ME4000_AI_SIMULTANEOUS_DISABLE 0x0
+#define ME4000_AI_SIMULTANEOUS_ENABLE 0x1
+
+/* Defines for the Sample Counter */
+#define ME4000_AI_SC_RELOAD 0x0
+#define ME4000_AI_SC_ONCE 0x1
+
+/* Modes for analog input */
+#define ME4000_AI_ACQ_MODE_SINGLE 0x00 // Catch one single value
+#define ME4000_AI_ACQ_MODE_SOFTWARE 0x01 // Continous sampling with software start
+#define ME4000_AI_ACQ_MODE_EXT 0x02 // Continous sampling with external trigger start
+#define ME4000_AI_ACQ_MODE_EXT_SINGLE_VALUE 0x03 // Sample one value by external trigger
+#define ME4000_AI_ACQ_MODE_EXT_SINGLE_CHANLIST 0x04 // Sample one channel list by external trigger
+
+/* Staus of AI FSM */
+#define ME4000_AI_STATUS_IDLE 0x0
+#define ME4000_AI_STATUS_BUSY 0x1
+
+/* Voltages for calibration */
+#define ME4000_AI_GAIN_1_UNI_OFFSET 10.0E-3
+#define ME4000_AI_GAIN_1_UNI_FULLSCALE 9950.0E-3
+#define ME4000_AI_GAIN_1_BI_OFFSET 0.0
+#define ME4000_AI_GAIN_1_BI_FULLSCALE 9950.0E-3
+#define ME4000_AI_GAIN_4_UNI_OFFSET 10.0E-3
+#define ME4000_AI_GAIN_4_UNI_FULLSCALE 2450.0E-3
+#define ME4000_AI_GAIN_4_BI_OFFSET 0.0
+#define ME4000_AI_GAIN_4_BI_FULLSCALE 2450.0E-3
+
+/* Ideal digits for calibration */
+#define ME4000_AI_GAIN_1_UNI_OFFSET_DIGITS (-32702)
+#define ME4000_AI_GAIN_1_UNI_FULLSCALE_DIGITS 32440
+#define ME4000_AI_GAIN_1_BI_OFFSET_DIGITS 0
+#define ME4000_AI_GAIN_1_BI_FULLSCALE_DIGITS 32604
+#define ME4000_AI_GAIN_4_UNI_OFFSET_DIGITS (-32505)
+#define ME4000_AI_GAIN_4_UNI_FULLSCALE_DIGITS 31457
+#define ME4000_AI_GAIN_4_BI_OFFSET_DIGITS 0
+#define ME4000_AI_GAIN_4_BI_FULLSCALE_DIGITS 32113
+
+/*-----------------------------------------------------------------------------
+ Defines for analog output
+ ----------------------------------------------------------------------------*/
+
+/* General stuff */
+#define ME4000_AO_FIFO_COUNT (4 * 1024)
+
+#define ME4000_AO_MIN_TICKS 66
+
+#define ME4000_AO_BUFFER_SIZE (32 * 1024) // Size in bytes
+
+#define ME4000_AO_BUFFER_COUNT ((ME4000_AO_BUFFER_SIZE) / 2) // Size in values
+
+/* Conversion modes for analog output */
+#define ME4000_AO_CONV_MODE_SINGLE 0x0
+#define ME4000_AO_CONV_MODE_WRAPAROUND 0x1
+#define ME4000_AO_CONV_MODE_CONTINUOUS 0x2
+
+/* Trigger setup */
+#define ME4000_AO_TRIGGER_EXT_EDGE_RISING 0x0
+#define ME4000_AO_TRIGGER_EXT_EDGE_FALLING 0x1
+#define ME4000_AO_TRIGGER_EXT_EDGE_BOTH 0x2
+
+/* Status of AO FSM */
+#define ME4000_AO_STATUS_IDLE 0x0
+#define ME4000_AO_STATUS_BUSY 0x1
+
+/*-----------------------------------------------------------------------------
+ Defines for eeprom
+ ----------------------------------------------------------------------------*/
+
+#define ME4000_EEPROM_CMD_READ 0x180
+#define ME4000_EEPROM_CMD_WRITE_ENABLE 0x130
+#define ME4000_EEPROM_CMD_WRITE_DISABLE 0x100
+#define ME4000_EEPROM_CMD_WRITE 0x1400000
+
+#define ME4000_EEPROM_CMD_LENGTH_READ 9
+#define ME4000_EEPROM_CMD_LENGTH_WRITE_ENABLE 9
+#define ME4000_EEPROM_CMD_LENGTH_WRITE_DISABLE 9
+#define ME4000_EEPROM_CMD_LENGTH_WRITE 25
+
+#define ME4000_EEPROM_ADR_DATE_HIGH 0x32
+#define ME4000_EEPROM_ADR_DATE_LOW 0x33
+
+#define ME4000_EEPROM_ADR_GAIN_1_UNI_OFFSET 0x34
+#define ME4000_EEPROM_ADR_GAIN_1_UNI_FULLSCALE 0x35
+#define ME4000_EEPROM_ADR_GAIN_1_BI_OFFSET 0x36
+#define ME4000_EEPROM_ADR_GAIN_1_BI_FULLSCALE 0x37
+#define ME4000_EEPROM_ADR_GAIN_1_DIFF_OFFSET 0x38
+#define ME4000_EEPROM_ADR_GAIN_1_DIFF_FULLSCALE 0x39
+
+#define ME4000_EEPROM_ADR_GAIN_4_UNI_OFFSET 0x3A
+#define ME4000_EEPROM_ADR_GAIN_4_UNI_FULLSCALE 0x3B
+#define ME4000_EEPROM_ADR_GAIN_4_BI_OFFSET 0x3C
+#define ME4000_EEPROM_ADR_GAIN_4_BI_FULLSCALE 0x3D
+#define ME4000_EEPROM_ADR_GAIN_4_DIFF_OFFSET 0x3E
+#define ME4000_EEPROM_ADR_GAIN_4_DIFF_FULLSCALE 0x3F
+
+#define ME4000_EEPROM_ADR_LENGTH 6
+#define ME4000_EEPROM_DATA_LENGTH 16
+
+/*-----------------------------------------------------------------------------
+ Defines for digital I/O
+ ----------------------------------------------------------------------------*/
+
+#define ME4000_DIO_PORT_A 0x0
+#define ME4000_DIO_PORT_B 0x1
+#define ME4000_DIO_PORT_C 0x2
+#define ME4000_DIO_PORT_D 0x3
+
+#define ME4000_DIO_PORT_INPUT 0x0
+#define ME4000_DIO_PORT_OUTPUT 0x1
+#define ME4000_DIO_FIFO_LOW 0x2
+#define ME4000_DIO_FIFO_HIGH 0x3
+
+#define ME4000_DIO_FUNCTION_PATTERN 0x0
+#define ME4000_DIO_FUNCTION_DEMUX 0x1
+#define ME4000_DIO_FUNCTION_MUX 0x2
+
+/*-----------------------------------------------------------------------------
+ Defines for counters
+ ----------------------------------------------------------------------------*/
+
+#define ME4000_CNT_COUNTER_0 0
+#define ME4000_CNT_COUNTER_1 1
+#define ME4000_CNT_COUNTER_2 2
+
+#define ME4000_CNT_MODE_0 0 // Change state if zero crossing
+#define ME4000_CNT_MODE_1 1 // Retriggerable One-Shot
+#define ME4000_CNT_MODE_2 2 // Asymmetrical divider
+#define ME4000_CNT_MODE_3 3 // Symmetrical divider
+#define ME4000_CNT_MODE_4 4 // Counter start by software trigger
+#define ME4000_CNT_MODE_5 5 // Counter start by hardware trigger
+
+/*-----------------------------------------------------------------------------
+ General type definitions
+ ----------------------------------------------------------------------------*/
+
+typedef struct me4000_user_info {
+ int board_count; // Index of the board after detection
+ unsigned long plx_regbase; // PLX configuration space base address
+ unsigned long me4000_regbase; // Base address of the ME4000
+ unsigned long plx_regbase_size; // PLX register set space
+ unsigned long me4000_regbase_size; // ME4000 register set space
+ unsigned long serial_no; // Serial number of the board
+ unsigned char hw_revision; // Hardware revision of the board
+ unsigned short vendor_id; // Meilhaus vendor id (0x1402)
+ unsigned short device_id; // Device ID
+ int pci_bus_no; // PCI bus number
+ int pci_dev_no; // PCI device number
+ int pci_func_no; // PCI function number
+ char irq; // IRQ assigned from the PCI BIOS
+ int irq_count; // Count of external interrupts
+
+ int driver_version; // Version of the driver release
+
+ int ao_count; // Count of analog output channels
+ int ao_fifo_count; // Count fo analog output fifos
+
+ int ai_count; // Count of analog input channels
+ int ai_sh_count; // Count of sample and hold devices
+ int ai_ex_trig_analog; // Flag to indicate if analogous external trigger is available
+
+ int dio_count; // Count of digital I/O ports
+
+ int cnt_count; // Count of counters
+} me4000_user_info_t;
+
+/*-----------------------------------------------------------------------------
+ Type definitions for analog output
+ ----------------------------------------------------------------------------*/
+
+typedef struct me4000_ao_channel_list {
+ unsigned long count;
+ unsigned long *list;
+} me4000_ao_channel_list_t;
+
+/*-----------------------------------------------------------------------------
+ Type definitions for analog input
+ ----------------------------------------------------------------------------*/
+
+typedef struct me4000_ai_channel_list {
+ unsigned long count;
+ unsigned long *list;
+} me4000_ai_channel_list_t;
+
+typedef struct me4000_ai_timer {
+ unsigned long pre_chan;
+ unsigned long chan;
+ unsigned long scan_low;
+ unsigned long scan_high;
+} me4000_ai_timer_t;
+
+typedef struct me4000_ai_config {
+ me4000_ai_timer_t timer;
+ me4000_ai_channel_list_t channel_list;
+ int sh;
+} me4000_ai_config_t;
+
+typedef struct me4000_ai_single {
+ int channel;
+ int range;
+ int mode;
+ short value;
+ unsigned long timeout;
+} me4000_ai_single_t;
+
+typedef struct me4000_ai_trigger {
+ int mode;
+ int edge;
+} me4000_ai_trigger_t;
+
+typedef struct me4000_ai_sc {
+ unsigned long value;
+ int reload;
+} me4000_ai_sc_t;
+
+/*-----------------------------------------------------------------------------
+ Type definitions for eeprom
+ ----------------------------------------------------------------------------*/
+
+typedef struct me4000_eeprom {
+ unsigned long date;
+ short uni_10_offset;
+ short uni_10_fullscale;
+ short uni_2_5_offset;
+ short uni_2_5_fullscale;
+ short bi_10_offset;
+ short bi_10_fullscale;
+ short bi_2_5_offset;
+ short bi_2_5_fullscale;
+ short diff_10_offset;
+ short diff_10_fullscale;
+ short diff_2_5_offset;
+ short diff_2_5_fullscale;
+} me4000_eeprom_t;
+
+/*-----------------------------------------------------------------------------
+ Type definitions for digital I/O
+ ----------------------------------------------------------------------------*/
+
+typedef struct me4000_dio_config {
+ int port;
+ int mode;
+ int function;
+} me4000_dio_config_t;
+
+typedef struct me4000_dio_byte {
+ int port;
+ unsigned char byte;
+} me4000_dio_byte_t;
+
+/*-----------------------------------------------------------------------------
+ Type definitions for counters
+ ----------------------------------------------------------------------------*/
+
+typedef struct me4000_cnt {
+ int counter;
+ unsigned short value;
+} me4000_cnt_t;
+
+typedef struct me4000_cnt_config {
+ int counter;
+ int mode;
+} me4000_cnt_config_t;
+
+/*-----------------------------------------------------------------------------
+ Type definitions for external interrupt
+ ----------------------------------------------------------------------------*/
+
+typedef struct {
+ int int1_count;
+ int int2_count;
+} me4000_int_type;
+
+/*-----------------------------------------------------------------------------
+ The ioctls of the board
+ ----------------------------------------------------------------------------*/
+
+#define ME4000_IOCTL_MAXNR 50
+#define ME4000_MAGIC 'y'
+#define ME4000_GET_USER_INFO _IOR (ME4000_MAGIC, 0, me4000_user_info_t)
+
+#define ME4000_AO_START _IOW (ME4000_MAGIC, 1, unsigned long)
+#define ME4000_AO_STOP _IO (ME4000_MAGIC, 2)
+#define ME4000_AO_IMMEDIATE_STOP _IO (ME4000_MAGIC, 3)
+#define ME4000_AO_RESET _IO (ME4000_MAGIC, 4)
+#define ME4000_AO_PRELOAD _IO (ME4000_MAGIC, 5)
+#define ME4000_AO_PRELOAD_UPDATE _IO (ME4000_MAGIC, 6)
+#define ME4000_AO_EX_TRIG_ENABLE _IO (ME4000_MAGIC, 7)
+#define ME4000_AO_EX_TRIG_DISABLE _IO (ME4000_MAGIC, 8)
+#define ME4000_AO_EX_TRIG_SETUP _IOW (ME4000_MAGIC, 9, int)
+#define ME4000_AO_TIMER_SET_DIVISOR _IOW (ME4000_MAGIC, 10, unsigned long)
+#define ME4000_AO_ENABLE_DO _IO (ME4000_MAGIC, 11)
+#define ME4000_AO_DISABLE_DO _IO (ME4000_MAGIC, 12)
+#define ME4000_AO_FSM_STATE _IOR (ME4000_MAGIC, 13, int)
+
+#define ME4000_AI_SINGLE _IOR (ME4000_MAGIC, 14, me4000_ai_single_t)
+#define ME4000_AI_START _IOW (ME4000_MAGIC, 15, unsigned long)
+#define ME4000_AI_STOP _IO (ME4000_MAGIC, 16)
+#define ME4000_AI_IMMEDIATE_STOP _IO (ME4000_MAGIC, 17)
+#define ME4000_AI_EX_TRIG_ENABLE _IO (ME4000_MAGIC, 18)
+#define ME4000_AI_EX_TRIG_DISABLE _IO (ME4000_MAGIC, 19)
+#define ME4000_AI_EX_TRIG_SETUP _IOW (ME4000_MAGIC, 20, me4000_ai_trigger_t)
+#define ME4000_AI_CONFIG _IOW (ME4000_MAGIC, 21, me4000_ai_config_t)
+#define ME4000_AI_SC_SETUP _IOW (ME4000_MAGIC, 22, me4000_ai_sc_t)
+#define ME4000_AI_FSM_STATE _IOR (ME4000_MAGIC, 23, int)
+
+#define ME4000_DIO_CONFIG _IOW (ME4000_MAGIC, 24, me4000_dio_config_t)
+#define ME4000_DIO_GET_BYTE _IOR (ME4000_MAGIC, 25, me4000_dio_byte_t)
+#define ME4000_DIO_SET_BYTE _IOW (ME4000_MAGIC, 26, me4000_dio_byte_t)
+#define ME4000_DIO_RESET _IO (ME4000_MAGIC, 27)
+
+#define ME4000_CNT_READ _IOR (ME4000_MAGIC, 28, me4000_cnt_t)
+#define ME4000_CNT_WRITE _IOW (ME4000_MAGIC, 29, me4000_cnt_t)
+#define ME4000_CNT_CONFIG _IOW (ME4000_MAGIC, 30, me4000_cnt_config_t)
+#define ME4000_CNT_RESET _IO (ME4000_MAGIC, 31)
+
+#define ME4000_EXT_INT_DISABLE _IO (ME4000_MAGIC, 32)
+#define ME4000_EXT_INT_ENABLE _IO (ME4000_MAGIC, 33)
+#define ME4000_EXT_INT_COUNT _IOR (ME4000_MAGIC, 34, int)
+
+#define ME4000_AI_OFFSET_ENABLE _IO (ME4000_MAGIC, 35)
+#define ME4000_AI_OFFSET_DISABLE _IO (ME4000_MAGIC, 36)
+#define ME4000_AI_FULLSCALE_ENABLE _IO (ME4000_MAGIC, 37)
+#define ME4000_AI_FULLSCALE_DISABLE _IO (ME4000_MAGIC, 38)
+
+#define ME4000_AI_EEPROM_READ _IOR (ME4000_MAGIC, 39, me4000_eeprom_t)
+#define ME4000_AI_EEPROM_WRITE _IOW (ME4000_MAGIC, 40, me4000_eeprom_t)
+
+#define ME4000_AO_SIMULTANEOUS_EX_TRIG _IO (ME4000_MAGIC, 41)
+#define ME4000_AO_SIMULTANEOUS_SW _IO (ME4000_MAGIC, 42)
+#define ME4000_AO_SIMULTANEOUS_DISABLE _IO (ME4000_MAGIC, 43)
+#define ME4000_AO_SIMULTANEOUS_UPDATE _IOW (ME4000_MAGIC, 44, me4000_ao_channel_list_t)
+
+#define ME4000_AO_SYNCHRONOUS_EX_TRIG _IO (ME4000_MAGIC, 45)
+#define ME4000_AO_SYNCHRONOUS_SW _IO (ME4000_MAGIC, 46)
+#define ME4000_AO_SYNCHRONOUS_DISABLE _IO (ME4000_MAGIC, 47)
+
+#define ME4000_AO_EX_TRIG_TIMEOUT _IOW (ME4000_MAGIC, 48, unsigned long)
+#define ME4000_AO_GET_FREE_BUFFER _IOR (ME4000_MAGIC, 49, unsigned long)
+
+#define ME4000_AI_GET_COUNT_BUFFER _IOR (ME4000_MAGIC, 50, unsigned long)
+
+#endif
--
1.6.0.2
^ permalink raw reply related [flat|nested] 37+ messages in thread* Re: [PATCH 09/23] Staging: add me4000 pci data collection driver
2008-10-10 22:42 ` [PATCH 09/23] Staging: add me4000 pci data collection driver Greg KH
@ 2008-10-15 8:41 ` Andrew Morton
0 siblings, 0 replies; 37+ messages in thread
From: Andrew Morton @ 2008-10-15 8:41 UTC (permalink / raw)
To: Greg KH; +Cc: linux-kernel, gregkh, w.beiter, g.gebhardt
> On Fri, 10 Oct 2008 15:42:33 -0700 Greg KH <greg@kroah.com> wrote:
> From: Greg Kroah-Hartman <gregkh@suse.de>
>
> Originally written by Guenter Gebhardt <g.gebhardt@meilhaus.de>
>
> TODO:
> - checkpatch.pl cleanups
> - sparse cleanups
> - possible /proc interaction cleanups
> - more info needed for Kconfig entry
> - real device id?
> - module parameter cleanup
- sort includes (include/linux before asm/)
- Make me4000_board_info_list static
> Cc: Wolfgang Beiter <w.beiter@aon.at>
> Cc: Guenter Gebhardt <g.gebhardt@meilhaus.de>
> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
> ---
> drivers/staging/Kconfig | 2 +
> drivers/staging/Makefile | 1 +
> drivers/staging/me4000/Kconfig | 10 +
> drivers/staging/me4000/Makefile | 1 +
> drivers/staging/me4000/README | 13 +
> drivers/staging/me4000/me4000.c | 6133 +++++++++++++++++++++++++++++++++++++++
> drivers/staging/me4000/me4000.h | 954 ++++++
> 7 files changed, 7114 insertions(+), 0 deletions(-)
> create mode 100644 drivers/staging/me4000/Kconfig
> create mode 100644 drivers/staging/me4000/Makefile
> create mode 100644 drivers/staging/me4000/README
> create mode 100644 drivers/staging/me4000/me4000.c
> create mode 100644 drivers/staging/me4000/me4000.h
>
> diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
> index 6da7662..56c73bc 100644
> --- a/drivers/staging/Kconfig
> +++ b/drivers/staging/Kconfig
> @@ -29,4 +29,6 @@ source "drivers/staging/slicoss/Kconfig"
>
> source "drivers/staging/sxg/Kconfig"
>
> +source "drivers/staging/me4000/Kconfig"
> +
> endif # STAGING
> diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
> index cd6d6a5..97df19b 100644
> --- a/drivers/staging/Makefile
> +++ b/drivers/staging/Makefile
> @@ -3,3 +3,4 @@
> obj-$(CONFIG_ET131X) += et131x/
> obj-$(CONFIG_SLICOSS) += slicoss/
> obj-$(CONFIG_SXG) += sxg/
> +obj-$(CONFIG_ME4000) += me4000/
> diff --git a/drivers/staging/me4000/Kconfig b/drivers/staging/me4000/Kconfig
> new file mode 100644
> index 0000000..5e6c9de
> --- /dev/null
> +++ b/drivers/staging/me4000/Kconfig
> @@ -0,0 +1,10 @@
> +config ME4000
> + tristate "Meilhaus ME-4000 support"
> + default n
> + depends on PCI
> + help
> + This driver supports the Meilhaus ME-4000 family of boards
> + that do data collection and multipurpose I/O.
> +
> + To compile this driver as a module, choose M here: the module
> + will be called me4000.
> diff --git a/drivers/staging/me4000/Makefile b/drivers/staging/me4000/Makefile
> new file mode 100644
> index 0000000..74487cd
> --- /dev/null
> +++ b/drivers/staging/me4000/Makefile
> @@ -0,0 +1 @@
> +obj-$(CONFIG_ME4000) += me4000.o
> diff --git a/drivers/staging/me4000/README b/drivers/staging/me4000/README
> new file mode 100644
> index 0000000..bbb8386
> --- /dev/null
> +++ b/drivers/staging/me4000/README
> @@ -0,0 +1,13 @@
> +
> +TODO:
> + - checkpatch.pl cleanups
> + - sparse cleanups
> + - possible /proc interaction cleanups
> + - more info needed for Kconfig entry
> + - real device id?
> + - module parameter cleanup
> +
> +Please send patches to Greg Kroah-Hartman <gregkh@suse.de>
> +and Cc: Wolfgang Beiter <w.beiter@aon.at> and
> +Guenter Gebhardt <g.gebhardt@meilhaus.de>
> +
> diff --git a/drivers/staging/me4000/me4000.c b/drivers/staging/me4000/me4000.c
> new file mode 100644
> index 0000000..862dd7f
> --- /dev/null
> +++ b/drivers/staging/me4000/me4000.c
> @@ -0,0 +1,6133 @@
> +/* Device driver for Meilhaus ME-4000 board family.
> + * ================================================
> + *
> + * Copyright (C) 2003 Meilhaus Electronic GmbH (support@meilhaus.de)
> + *
> + * This file 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., 675 Mass Ave, Cambridge, MA 02139, USA.
> + *
> + * Author: Guenter Gebhardt <g.gebhardt@meilhaus.de>
> + */
> +
> +#include <linux/module.h>
> +#include <linux/fs.h>
> +#include <linux/sched.h>
> +#include <linux/interrupt.h>
> +#include <linux/pci.h>
> +#include <asm/io.h>
> +#include <asm/system.h>
> +#include <asm/uaccess.h>
> +#include <linux/errno.h>
> +#include <linux/delay.h>
> +#include <linux/fs.h>
> +#include <linux/mm.h>
> +#include <linux/unistd.h>
> +#include <linux/list.h>
> +#include <linux/proc_fs.h>
> +
> +#include <linux/poll.h>
> +#include <linux/vmalloc.h>
> +#include <asm/pgtable.h>
> +#include <asm/uaccess.h>
> +#include <linux/types.h>
Reorder includes (inxlude/linux before include/asm)
> +#include <linux/slab.h>
> +
> +/* Include-File for the Meilhaus ME-4000 I/O board */
> +#include "me4000.h"
> +#include "me4000_firmware.h"
> +#include "me4610_firmware.h"
> +
> +/* Administrative stuff for modinfo */
> +MODULE_AUTHOR("Guenter Gebhardt <g.gebhardt@meilhaus.de>");
> +MODULE_DESCRIPTION
> + ("Device Driver Module for Meilhaus ME-4000 boards version 1.0.5");
> +MODULE_SUPPORTED_DEVICE("Meilhaus ME-4000 Multi I/O boards");
> +MODULE_LICENSE("GPL");
> +
> +/* Board specific data are kept in a global list */
> +LIST_HEAD(me4000_board_info_list);
static
> +/* Major Device Numbers. 0 means to get it automatically from the System */
> +static int me4000_ao_major_driver_no = 0;
> +static int me4000_ai_major_driver_no = 0;
> +static int me4000_dio_major_driver_no = 0;
> +static int me4000_cnt_major_driver_no = 0;
> +static int me4000_ext_int_major_driver_no = 0;
s/= 0//
> +/* Let the user specify a custom major driver number */
> +module_param(me4000_ao_major_driver_no, int, 0);
> +MODULE_PARM_DESC(me4000_ao_major_driver_no,
> + "Major driver number for analog output (default 0)");
> +
> +module_param(me4000_ai_major_driver_no, int, 0);
> +MODULE_PARM_DESC(me4000_ai_major_driver_no,
> + "Major driver number for analog input (default 0)");
> +
> +module_param(me4000_dio_major_driver_no, int, 0);
> +MODULE_PARM_DESC(me4000_dio_major_driver_no,
> + "Major driver number digital I/O (default 0)");
> +
> +module_param(me4000_cnt_major_driver_no, int, 0);
> +MODULE_PARM_DESC(me4000_cnt_major_driver_no,
> + "Major driver number for counter (default 0)");
> +
> +module_param(me4000_ext_int_major_driver_no, int, 0);
> +MODULE_PARM_DESC(me4000_ext_int_major_driver_no,
> + "Major driver number for external interrupt (default 0)");
> +
> +/*-----------------------------------------------------------------------------
> + Module stuff
> + ---------------------------------------------------------------------------*/
> +int init_module(void);
> +void cleanup_module(void);
kill
> +/*-----------------------------------------------------------------------------
> + Board detection and initialization
> + ---------------------------------------------------------------------------*/
> +static int me4000_probe(struct pci_dev *dev, const struct pci_device_id *id);
> +static int me4000_xilinx_download(me4000_info_t *);
> +static int me4000_reset_board(me4000_info_t *);
> +
> +static void clear_board_info_list(void);
> +static int get_registers(struct pci_dev *dev, me4000_info_t * info);
> +static int init_board_info(struct pci_dev *dev, me4000_info_t * board_info);
> +static int alloc_ao_contexts(me4000_info_t * info);
> +static void release_ao_contexts(me4000_info_t * board_info);
> +static int alloc_ai_context(me4000_info_t * info);
> +static int alloc_dio_context(me4000_info_t * info);
> +static int alloc_cnt_context(me4000_info_t * info);
> +static int alloc_ext_int_context(me4000_info_t * info);
lots of these are unneeded.
> +/*-----------------------------------------------------------------------------
> + Stuff used by all device parts
> + ---------------------------------------------------------------------------*/
> +static int me4000_open(struct inode *, struct file *);
> +static int me4000_release(struct inode *, struct file *);
> +
> +static int me4000_get_user_info(me4000_user_info_t *,
> + me4000_info_t * board_info);
> +static int me4000_read_procmem(char *, char **, off_t, int, int *, void *);
> +
> +/*-----------------------------------------------------------------------------
> + Analog output stuff
> + ---------------------------------------------------------------------------*/
> +static ssize_t me4000_ao_write_sing(struct file *, const char *, size_t,
> + loff_t *);
> +static ssize_t me4000_ao_write_wrap(struct file *, const char *, size_t,
> + loff_t *);
> +static ssize_t me4000_ao_write_cont(struct file *, const char *, size_t,
> + loff_t *);
> +
> +static int me4000_ao_ioctl_sing(struct inode *, struct file *, unsigned int,
> + unsigned long);
> +static int me4000_ao_ioctl_wrap(struct inode *, struct file *, unsigned int,
> + unsigned long);
> +static int me4000_ao_ioctl_cont(struct inode *, struct file *, unsigned int,
> + unsigned long);
> +
> +static unsigned int me4000_ao_poll_cont(struct file *, poll_table *);
> +static int me4000_ao_fsync_cont(struct file *, struct dentry *, int);
> +
> +static int me4000_ao_start(unsigned long *, me4000_ao_context_t *);
> +static int me4000_ao_stop(me4000_ao_context_t *);
> +static int me4000_ao_immediate_stop(me4000_ao_context_t *);
> +static int me4000_ao_timer_set_divisor(u32 *, me4000_ao_context_t *);
> +static int me4000_ao_preload(me4000_ao_context_t *);
> +static int me4000_ao_preload_update(me4000_ao_context_t *);
> +static int me4000_ao_ex_trig_set_edge(int *, me4000_ao_context_t *);
> +static int me4000_ao_ex_trig_enable(me4000_ao_context_t *);
> +static int me4000_ao_ex_trig_disable(me4000_ao_context_t *);
> +static int me4000_ao_prepare(me4000_ao_context_t * ao_info);
> +static int me4000_ao_reset(me4000_ao_context_t * ao_info);
> +static int me4000_ao_enable_do(me4000_ao_context_t *);
> +static int me4000_ao_disable_do(me4000_ao_context_t *);
> +static int me4000_ao_fsm_state(int *, me4000_ao_context_t *);
> +
> +static int me4000_ao_simultaneous_ex_trig(me4000_ao_context_t * ao_context);
> +static int me4000_ao_simultaneous_sw(me4000_ao_context_t * ao_context);
> +static int me4000_ao_simultaneous_disable(me4000_ao_context_t * ao_context);
> +static int me4000_ao_simultaneous_update(me4000_ao_channel_list_t * channels,
> + me4000_ao_context_t * ao_context);
> +
> +static int me4000_ao_synchronous_ex_trig(me4000_ao_context_t * ao_context);
> +static int me4000_ao_synchronous_sw(me4000_ao_context_t * ao_context);
> +static int me4000_ao_synchronous_disable(me4000_ao_context_t * ao_context);
> +
> +static int me4000_ao_ex_trig_timeout(unsigned long *arg,
> + me4000_ao_context_t * ao_context);
> +static int me4000_ao_get_free_buffer(unsigned long *arg,
> + me4000_ao_context_t * ao_context);
probably lots of those too.
> +/*-----------------------------------------------------------------------------
> + Analog input stuff
> + ---------------------------------------------------------------------------*/
> +static int me4000_ai_single(me4000_ai_single_t *, me4000_ai_context_t *);
> +static int me4000_ai_ioctl_sing(struct inode *, struct file *, unsigned int,
> + unsigned long);
> +
> +static ssize_t me4000_ai_read(struct file *, char *, size_t, loff_t *);
> +static int me4000_ai_ioctl_sw(struct inode *, struct file *, unsigned int,
> + unsigned long);
> +static unsigned int me4000_ai_poll(struct file *, poll_table *);
> +static int me4000_ai_fasync(int fd, struct file *file_p, int mode);
> +
> +static int me4000_ai_ioctl_ext(struct inode *, struct file *, unsigned int,
> + unsigned long);
> +
> +static int me4000_ai_prepare(me4000_ai_context_t * ai_context);
> +static int me4000_ai_reset(me4000_ai_context_t * ai_context);
> +static int me4000_ai_config(me4000_ai_config_t *, me4000_ai_context_t *);
> +static int me4000_ai_start(me4000_ai_context_t *);
> +static int me4000_ai_start_ex(unsigned long *, me4000_ai_context_t *);
> +static int me4000_ai_stop(me4000_ai_context_t *);
> +static int me4000_ai_immediate_stop(me4000_ai_context_t *);
> +static int me4000_ai_ex_trig_enable(me4000_ai_context_t *);
> +static int me4000_ai_ex_trig_disable(me4000_ai_context_t *);
> +static int me4000_ai_ex_trig_setup(me4000_ai_trigger_t *,
> + me4000_ai_context_t *);
> +static int me4000_ai_sc_setup(me4000_ai_sc_t * arg,
> + me4000_ai_context_t * ai_context);
> +static int me4000_ai_offset_enable(me4000_ai_context_t * ai_context);
> +static int me4000_ai_offset_disable(me4000_ai_context_t * ai_context);
> +static int me4000_ai_fullscale_enable(me4000_ai_context_t * ai_context);
> +static int me4000_ai_fullscale_disable(me4000_ai_context_t * ai_context);
> +static int me4000_ai_fsm_state(int *arg, me4000_ai_context_t * ai_context);
> +static int me4000_ai_get_count_buffer(unsigned long *arg,
> + me4000_ai_context_t * ai_context);
blah
> +/*-----------------------------------------------------------------------------
> + EEPROM stuff
> + ---------------------------------------------------------------------------*/
> +static int me4000_eeprom_read(me4000_eeprom_t * arg,
> + me4000_ai_context_t * ai_context);
> +static int me4000_eeprom_write(me4000_eeprom_t * arg,
> + me4000_ai_context_t * ai_context);
> +static unsigned short eeprom_read_cmd(me4000_ai_context_t * ai_context,
> + unsigned long cmd, int length);
> +static int eeprom_write_cmd(me4000_ai_context_t * ai_context, unsigned long cmd,
> + int length);
> +
> +/*-----------------------------------------------------------------------------
> + Digital I/O stuff
> + ---------------------------------------------------------------------------*/
> +static int me4000_dio_ioctl(struct inode *, struct file *, unsigned int,
> + unsigned long);
> +static int me4000_dio_config(me4000_dio_config_t *, me4000_dio_context_t *);
> +static int me4000_dio_get_byte(me4000_dio_byte_t *, me4000_dio_context_t *);
> +static int me4000_dio_set_byte(me4000_dio_byte_t *, me4000_dio_context_t *);
> +static int me4000_dio_reset(me4000_dio_context_t *);
> +
> +/*-----------------------------------------------------------------------------
> + Counter stuff
> + ---------------------------------------------------------------------------*/
> +static int me4000_cnt_ioctl(struct inode *, struct file *, unsigned int,
> + unsigned long);
> +static int me4000_cnt_config(me4000_cnt_config_t *, me4000_cnt_context_t *);
> +static int me4000_cnt_read(me4000_cnt_t *, me4000_cnt_context_t *);
> +static int me4000_cnt_write(me4000_cnt_t *, me4000_cnt_context_t *);
> +static int me4000_cnt_reset(me4000_cnt_context_t *);
> +
> +/*-----------------------------------------------------------------------------
> + External interrupt routines
> + ---------------------------------------------------------------------------*/
> +static int me4000_ext_int_ioctl(struct inode *, struct file *, unsigned int,
> + unsigned long);
> +static int me4000_ext_int_enable(me4000_ext_int_context_t *);
> +static int me4000_ext_int_disable(me4000_ext_int_context_t *);
> +static int me4000_ext_int_count(unsigned long *arg,
> + me4000_ext_int_context_t * ext_int_context);
> +static int me4000_ext_int_fasync(int fd, struct file *file_ptr, int mode);
> +
> +/*-----------------------------------------------------------------------------
> + The interrupt service routines
> + ---------------------------------------------------------------------------*/
> +static irqreturn_t me4000_ao_isr(int, void *);
> +static irqreturn_t me4000_ai_isr(int, void *);
> +static irqreturn_t me4000_ext_int_isr(int, void *);
> +
> +/*-----------------------------------------------------------------------------
> + Inline functions
> + ---------------------------------------------------------------------------*/
> +static int inline me4000_buf_count(me4000_circ_buf_t, int);
> +static int inline me4000_buf_space(me4000_circ_buf_t, int);
> +static int inline me4000_space_to_end(me4000_circ_buf_t, int);
> +static int inline me4000_values_to_end(me4000_circ_buf_t, int);
> +
> +static void inline me4000_outb(unsigned char value, unsigned long port);
> +static void inline me4000_outl(unsigned long value, unsigned long port);
> +static unsigned long inline me4000_inl(unsigned long port);
> +static unsigned char inline me4000_inb(unsigned long port);
wtf
> +static int me4000_buf_count(me4000_circ_buf_t buf, int size)
> +{
> + return ((buf.head - buf.tail) & (size - 1));
> +}
> +
> +static int me4000_buf_space(me4000_circ_buf_t buf, int size)
> +{
> + return ((buf.tail - (buf.head + 1)) & (size - 1));
> +}
>
> +static int me4000_values_to_end(me4000_circ_buf_t buf, int size)
> +{
> + int end;
> + int n;
> + end = size - buf.tail;
> + n = (buf.head + end) & (size - 1);
> + return (n < end) ? n : end;
> +}
> +
> +static int me4000_space_to_end(me4000_circ_buf_t buf, int size)
> +{
> + int end;
> + int n;
> +
> + end = size - 1 - buf.head;
> + n = (end + buf.tail) & (size - 1);
> + return (n <= end) ? n : (end + 1);
> +}
yet another home-made circular buffer implementation
rename all struct foo_t to struct foo
> +static void me4000_outb(unsigned char value, unsigned long port)
> +{
> + PORT_PDEBUG("--> 0x%02X port 0x%04lX\n", value, port);
> + outb(value, port);
> +}
> +
> +static void me4000_outl(unsigned long value, unsigned long port)
> +{
> + PORT_PDEBUG("--> 0x%08lX port 0x%04lX\n", value, port);
> + outl(value, port);
> +}
> +
> +static unsigned long me4000_inl(unsigned long port)
> +{
> + unsigned long value;
> + value = inl(port);
> + PORT_PDEBUG("<-- 0x%08lX port 0x%04lX\n", value, port);
> + return value;
> +}
> +
> +static unsigned char me4000_inb(unsigned long port)
> +{
> + unsigned char value;
> + value = inb(port);
> + PORT_PDEBUG("<-- 0x%08X port 0x%04lX\n", value, port);
> + return value;
> +}
> +
> +struct pci_driver me4000_driver = {
> + .name = ME4000_NAME,
> + .id_table = me4000_pci_table,
> + .probe = me4000_probe
> +};
> +
> +static struct file_operations me4000_ao_fops_sing = {
> + owner:THIS_MODULE,
> + write:me4000_ao_write_sing,
> + ioctl:me4000_ao_ioctl_sing,
> + open:me4000_open,
> + release:me4000_release,
> +};
.foo = bar,
> +static struct file_operations me4000_ao_fops_wrap = {
> + owner:THIS_MODULE,
> + write:me4000_ao_write_wrap,
> + ioctl:me4000_ao_ioctl_wrap,
> + open:me4000_open,
> + release:me4000_release,
> +};
> +
> +static struct file_operations me4000_ao_fops_cont = {
> + owner:THIS_MODULE,
> + write:me4000_ao_write_cont,
> + poll:me4000_ao_poll_cont,
> + ioctl:me4000_ao_ioctl_cont,
> + open:me4000_open,
> + release:me4000_release,
> + fsync:me4000_ao_fsync_cont,
> +};
> +
> +static struct file_operations me4000_ai_fops_sing = {
> + owner:THIS_MODULE,
> + ioctl:me4000_ai_ioctl_sing,
> + open:me4000_open,
> + release:me4000_release,
> +};
> +
> +static struct file_operations me4000_ai_fops_cont_sw = {
> + owner:THIS_MODULE,
> + read:me4000_ai_read,
> + poll:me4000_ai_poll,
> + ioctl:me4000_ai_ioctl_sw,
> + open:me4000_open,
> + release:me4000_release,
> + fasync:me4000_ai_fasync,
> +};
> +
> +static struct file_operations me4000_ai_fops_cont_et = {
> + owner:THIS_MODULE,
> + read:me4000_ai_read,
> + poll:me4000_ai_poll,
> + ioctl:me4000_ai_ioctl_ext,
> + open:me4000_open,
> + release:me4000_release,
> +};
> +
> +static struct file_operations me4000_ai_fops_cont_et_value = {
> + owner:THIS_MODULE,
> + read:me4000_ai_read,
> + poll:me4000_ai_poll,
> + ioctl:me4000_ai_ioctl_ext,
> + open:me4000_open,
> + release:me4000_release,
> +};
> +
> +static struct file_operations me4000_ai_fops_cont_et_chanlist = {
> + owner:THIS_MODULE,
> + read:me4000_ai_read,
> + poll:me4000_ai_poll,
> + ioctl:me4000_ai_ioctl_ext,
> + open:me4000_open,
> + release:me4000_release,
> +};
> +
> +static struct file_operations me4000_dio_fops = {
> + owner:THIS_MODULE,
> + ioctl:me4000_dio_ioctl,
> + open:me4000_open,
> + release:me4000_release,
> +};
> +
> +static struct file_operations me4000_cnt_fops = {
> + owner:THIS_MODULE,
> + ioctl:me4000_cnt_ioctl,
> + open:me4000_open,
> + release:me4000_release,
> +};
> +
> +static struct file_operations me4000_ext_int_fops = {
> + owner:THIS_MODULE,
> + ioctl:me4000_ext_int_ioctl,
> + open:me4000_open,
> + release:me4000_release,
> + fasync:me4000_ext_int_fasync,
> +};
dittoes
> +static struct file_operations *me4000_ao_fops_array[] = {
> + &me4000_ao_fops_sing, // single operations
> + &me4000_ao_fops_wrap, // wraparound operations
> + &me4000_ao_fops_cont, // continous operations
> +};
> +
> +static struct file_operations *me4000_ai_fops_array[] = {
> + &me4000_ai_fops_sing, // single operations
> + &me4000_ai_fops_cont_sw, // continuous operations with software start
> + &me4000_ai_fops_cont_et, // continous operations with external trigger
> + &me4000_ai_fops_cont_et_value, // sample values by external trigger
> + &me4000_ai_fops_cont_et_chanlist, // work through one channel list by external trigger
> +};
ditto
> +int __init me4000_init_module(void)
static
> +{
> + int result = 0;
unneeded initialisation
> + CALL_PDEBUG("init_module() is executed\n");
> +
> + /* Register driver capabilities */
> + result = pci_register_driver(&me4000_driver);
> + PDEBUG("init_module():%d devices detected\n", result);
> + if (result < 0) {
> + printk(KERN_ERR "ME4000:init_module():Can't register driver\n");
> + goto INIT_ERROR_1;
> + }
> +
> + /* Allocate major number for analog output */
> + result =
> + register_chrdev(me4000_ao_major_driver_no, ME4000_AO_NAME,
> + &me4000_ao_fops_sing);
> + if (result < 0) {
> + printk(KERN_ERR "ME4000:init_module():Can't get AO major no\n");
> + goto INIT_ERROR_2;
> + } else {
> + me4000_ao_major_driver_no = result;
> + }
> + PDEBUG("init_module():Major driver number for AO = %ld\n",
> + me4000_ao_major_driver_no);
> +
> + /* Allocate major number for analog input */
> + result =
> + register_chrdev(me4000_ai_major_driver_no, ME4000_AI_NAME,
> + &me4000_ai_fops_sing);
> + if (result < 0) {
> + printk(KERN_ERR "ME4000:init_module():Can't get AI major no\n");
> + goto INIT_ERROR_3;
> + } else {
> + me4000_ai_major_driver_no = result;
> + }
> + PDEBUG("init_module():Major driver number for AI = %ld\n",
> + me4000_ai_major_driver_no);
> +
> + /* Allocate major number for digital I/O */
> + result =
> + register_chrdev(me4000_dio_major_driver_no, ME4000_DIO_NAME,
> + &me4000_dio_fops);
> + if (result < 0) {
> + printk(KERN_ERR
> + "ME4000:init_module():Can't get DIO major no\n");
> + goto INIT_ERROR_4;
> + } else {
> + me4000_dio_major_driver_no = result;
> + }
> + PDEBUG("init_module():Major driver number for DIO = %ld\n",
> + me4000_dio_major_driver_no);
> +
> + /* Allocate major number for counter */
> + result =
> + register_chrdev(me4000_cnt_major_driver_no, ME4000_CNT_NAME,
> + &me4000_cnt_fops);
> + if (result < 0) {
> + printk(KERN_ERR
> + "ME4000:init_module():Can't get CNT major no\n");
> + goto INIT_ERROR_5;
> + } else {
> + me4000_cnt_major_driver_no = result;
> + }
> + PDEBUG("init_module():Major driver number for CNT = %ld\n",
> + me4000_cnt_major_driver_no);
> +
> + /* Allocate major number for external interrupt */
> + result =
> + register_chrdev(me4000_ext_int_major_driver_no, ME4000_EXT_INT_NAME,
> + &me4000_ext_int_fops);
> + if (result < 0) {
> + printk(KERN_ERR
> + "ME4000:init_module():Can't get major no for external interrupt\n");
> + goto INIT_ERROR_6;
> + } else {
> + me4000_ext_int_major_driver_no = result;
> + }
> + PDEBUG
Yet another home-made prdebug?
> + ("init_module():Major driver number for external interrupt = %ld\n",
> + me4000_ext_int_major_driver_no);
> +
> + /* Create the /proc/me4000 entry */
> + if (!create_proc_read_entry
> + ("me4000", 0, NULL, me4000_read_procmem, NULL)) {
> + result = -ENODEV;
> + printk(KERN_ERR
> + "ME4000:init_module():Can't create proc entry\n");
> + goto INIT_ERROR_7;
> + }
> +
> + return 0;
> +
> + INIT_ERROR_7:
crazy label indenting
> + unregister_chrdev(me4000_ext_int_major_driver_no, ME4000_EXT_INT_NAME);
> +
> + INIT_ERROR_6:
> + unregister_chrdev(me4000_cnt_major_driver_no, ME4000_CNT_NAME);
> +
> + INIT_ERROR_5:
> + unregister_chrdev(me4000_dio_major_driver_no, ME4000_DIO_NAME);
> +
> + INIT_ERROR_4:
> + unregister_chrdev(me4000_ai_major_driver_no, ME4000_AI_NAME);
> +
> + INIT_ERROR_3:
> + unregister_chrdev(me4000_ao_major_driver_no, ME4000_AO_NAME);
> +
> + INIT_ERROR_2:
> + pci_unregister_driver(&me4000_driver);
> + clear_board_info_list();
> +
> + INIT_ERROR_1:
> + return result;
> +}
> +
> +module_init(me4000_init_module);
> +
> +static void clear_board_info_list(void)
> +{
> + struct list_head *board_p;
> + struct list_head *dac_p;
> + me4000_info_t *board_info;
> + me4000_ao_context_t *ao_context;
> +
> + /* Clear context lists */
> + for (board_p = me4000_board_info_list.next;
> + board_p != &me4000_board_info_list; board_p = board_p->next) {
> + board_info = list_entry(board_p, me4000_info_t, list);
> + /* Clear analog output context list */
> + while (!list_empty(&board_info->ao_context_list)) {
> + dac_p = board_info->ao_context_list.next;
> + ao_context =
> + list_entry(dac_p, me4000_ao_context_t, list);
> + me4000_ao_reset(ao_context);
> + free_irq(ao_context->irq, ao_context);
> + if (ao_context->circ_buf.buf)
> + kfree(ao_context->circ_buf.buf);
> + list_del(dac_p);
> + kfree(ao_context);
> + }
> +
> + /* Clear analog input context */
> + if (board_info->ai_context->circ_buf.buf)
> + kfree(board_info->ai_context->circ_buf.buf);
> + kfree(board_info->ai_context);
> +
> + /* Clear digital I/O context */
> + kfree(board_info->dio_context);
> +
> + /* Clear counter context */
> + kfree(board_info->cnt_context);
> +
> + /* Clear external interrupt context */
> + kfree(board_info->ext_int_context);
> + }
> +
> + /* Clear the board info list */
> + while (!list_empty(&me4000_board_info_list)) {
> + board_p = me4000_board_info_list.next;
> + board_info = list_entry(board_p, me4000_info_t, list);
> + pci_release_regions(board_info->pci_dev_p);
> + list_del(board_p);
> + kfree(board_info);
> + }
> +}
locking for me4000_board_info_list
> +static int get_registers(struct pci_dev *dev, me4000_info_t * board_info)
> +{
> +
> + /*--------------------------- plx regbase ---------------------------------*/
> +
> + board_info->plx_regbase = pci_resource_start(dev, 1);
> + if (board_info->plx_regbase == 0) {
> + printk(KERN_ERR
> + "ME4000:get_registers():PCI base address 1 is not available\n");
> + return -ENODEV;
> + }
> + board_info->plx_regbase_size = pci_resource_len(dev, 1);
> +
> + PDEBUG
> + ("get_registers():PLX configuration registers at address 0x%4lX [0x%4lX]\n",
> + board_info->plx_regbase, board_info->plx_regbase_size);
> +
> + /*--------------------------- me4000 regbase ------------------------------*/
> +
> + board_info->me4000_regbase = pci_resource_start(dev, 2);
> + if (board_info->me4000_regbase == 0) {
> + printk(KERN_ERR
> + "ME4000:get_registers():PCI base address 2 is not available\n");
> + return -ENODEV;
> + }
> + board_info->me4000_regbase_size = pci_resource_len(dev, 2);
me4000_regbase and me4000_regbase_size should become resource_size_t.
> + PDEBUG("get_registers():ME4000 registers at address 0x%4lX [0x%4lX]\n",
> + board_info->me4000_regbase, board_info->me4000_regbase_size);
> + /*--------------------------- timer regbase ------------------------------*/
> +
> + board_info->timer_regbase = pci_resource_start(dev, 3);
> + if (board_info->timer_regbase == 0) {
> + printk(KERN_ERR
> + "ME4000:get_registers():PCI base address 3 is not available\n");
> + return -ENODEV;
> + }
> + board_info->timer_regbase_size = pci_resource_len(dev, 3);
> +
> + PDEBUG("get_registers():Timer registers at address 0x%4lX [0x%4lX]\n",
> + board_info->timer_regbase, board_info->timer_regbase_size);
> +
> + /*--------------------------- program regbase ------------------------------*/
> +
> + board_info->program_regbase = pci_resource_start(dev, 5);
> + if (board_info->program_regbase == 0) {
> + printk(KERN_ERR
> + "get_registers():ME4000:PCI base address 5 is not available\n");
> + return -ENODEV;
> + }
> + board_info->program_regbase_size = pci_resource_len(dev, 5);
> +
> + PDEBUG("get_registers():Program registers at address 0x%4lX [0x%4lX]\n",
> + board_info->program_regbase, board_info->program_regbase_size);
dittoes
> + return 0;
> +}
> +
> +static int init_board_info(struct pci_dev *pci_dev_p,
> + me4000_info_t * board_info)
> +{
> + int i;
> + int result;
> + struct list_head *board_p;
> + board_info->pci_dev_p = pci_dev_p;
> +
> + for (i = 0; i < ME4000_BOARD_VERSIONS; i++) {
> + if (me4000_boards[i].device_id == pci_dev_p->device) {
> + board_info->board_p = &me4000_boards[i];
> + break;
> + }
> + }
> + if (i == ME4000_BOARD_VERSIONS) {
> + printk(KERN_ERR
> + "ME4000:init_board_info():Device ID not valid\n");
> + return -ENODEV;
> + }
> +
> + /* Get the index of the board in the global list */
> + for (board_p = me4000_board_info_list.next, i = 0;
> + board_p != &me4000_board_info_list; board_p = board_p->next, i++) {
> + if (board_p == &board_info->list) {
> + board_info->board_count = i;
> + break;
> + }
> + }
> + if (board_p == &me4000_board_info_list) {
> + printk(KERN_ERR
> + "ME4000:init_board_info():Cannot get index of baord\n");
> + return -ENODEV;
> + }
> +
> + /* Init list head for analog output contexts */
> + INIT_LIST_HEAD(&board_info->ao_context_list);
> +
> + /* Init spin locks */
> + spin_lock_init(&board_info->preload_lock);
> + spin_lock_init(&board_info->ai_ctrl_lock);
> +
> + /* Get the serial number */
> + result = pci_read_config_dword(pci_dev_p, 0x2C, &board_info->serial_no);
> + if (result != PCIBIOS_SUCCESSFUL) {
> + printk(KERN_WARNING
> + "ME4000:init_board_info: Can't get serial_no\n");
> + return result;
> + }
> + PDEBUG("init_board_info():serial_no = 0x%x\n", board_info->serial_no);
> +
> + /* Get the hardware revision */
> + result =
> + pci_read_config_byte(pci_dev_p, 0x08, &board_info->hw_revision);
> + if (result != PCIBIOS_SUCCESSFUL) {
> + printk(KERN_WARNING
> + "ME4000:init_board_info():Can't get hw_revision\n");
> + return result;
> + }
> + PDEBUG("init_board_info():hw_revision = 0x%x\n",
> + board_info->hw_revision);
> +
> + /* Get the vendor id */
> + board_info->vendor_id = pci_dev_p->vendor;
> + PDEBUG("init_board_info():vendor_id = 0x%x\n", board_info->vendor_id);
> +
> + /* Get the device id */
> + board_info->device_id = pci_dev_p->device;
> + PDEBUG("init_board_info():device_id = 0x%x\n", board_info->device_id);
> +
> + /* Get the pci device number */
> + board_info->pci_dev_no = PCI_FUNC(pci_dev_p->devfn);
> + PDEBUG("init_board_info():pci_func_no = 0x%x\n",
> + board_info->pci_func_no);
> +
> + /* Get the pci slot number */
> + board_info->pci_dev_no = PCI_SLOT(pci_dev_p->devfn);
> + PDEBUG("init_board_info():pci_dev_no = 0x%x\n", board_info->pci_dev_no);
> +
> + /* Get the pci bus number */
> + board_info->pci_bus_no = pci_dev_p->bus->number;
> + PDEBUG("init_board_info():pci_bus_no = 0x%x\n", board_info->pci_bus_no);
> +
> + /* Get the irq assigned to the board */
> + board_info->irq = pci_dev_p->irq;
> + PDEBUG("init_board_info():irq = %d\n", board_info->irq);
> +
> + return 0;
> +}
> +
> +static int alloc_ao_contexts(me4000_info_t * info)
> +{
> + int i;
> + int err;
> + me4000_ao_context_t *ao_context;
> +
> + for (i = 0; i < info->board_p->ao.count; i++) {
> + ao_context = kmalloc(sizeof(me4000_ao_context_t), GFP_KERNEL);
> + if (!ao_context) {
> + printk(KERN_ERR
> + "alloc_ao_contexts():Can't get memory for ao context\n");
> + release_ao_contexts(info);
> + return -ENOMEM;
> + }
> + memset(ao_context, 0, sizeof(me4000_ao_context_t));
kzalloc
> + spin_lock_init(&ao_context->use_lock);
> + spin_lock_init(&ao_context->int_lock);
> + ao_context->irq = info->irq;
> + init_waitqueue_head(&ao_context->wait_queue);
> + ao_context->board_info = info;
> +
> + if (info->board_p->ao.fifo_count) {
> + /* Allocate circular buffer */
> + ao_context->circ_buf.buf =
> + kmalloc(ME4000_AO_BUFFER_SIZE, GFP_KERNEL);
> + if (!ao_context->circ_buf.buf) {
> + printk(KERN_ERR
> + "alloc_ao_contexts():Can't get circular buffer\n");
> + release_ao_contexts(info);
> + return -ENOMEM;
> + }
> + memset(ao_context->circ_buf.buf, 0,
> + ME4000_AO_BUFFER_SIZE);
kzalloc
> + /* Clear the circular buffer */
> + ao_context->circ_buf.head = 0;
> + ao_context->circ_buf.tail = 0;
> + }
> +
> + switch (i) {
> + case 0:
> + ao_context->ctrl_reg =
> + info->me4000_regbase + ME4000_AO_00_CTRL_REG;
> + ao_context->status_reg =
> + info->me4000_regbase + ME4000_AO_00_STATUS_REG;
> + ao_context->fifo_reg =
> + info->me4000_regbase + ME4000_AO_00_FIFO_REG;
> + ao_context->single_reg =
> + info->me4000_regbase + ME4000_AO_00_SINGLE_REG;
> + ao_context->timer_reg =
> + info->me4000_regbase + ME4000_AO_00_TIMER_REG;
> + ao_context->irq_status_reg =
> + info->me4000_regbase + ME4000_IRQ_STATUS_REG;
> + ao_context->preload_reg =
> + info->me4000_regbase + ME4000_AO_LOADSETREG_XX;
> + break;
> + case 1:
> + ao_context->ctrl_reg =
> + info->me4000_regbase + ME4000_AO_01_CTRL_REG;
> + ao_context->status_reg =
> + info->me4000_regbase + ME4000_AO_01_STATUS_REG;
> + ao_context->fifo_reg =
> + info->me4000_regbase + ME4000_AO_01_FIFO_REG;
> + ao_context->single_reg =
> + info->me4000_regbase + ME4000_AO_01_SINGLE_REG;
> + ao_context->timer_reg =
> + info->me4000_regbase + ME4000_AO_01_TIMER_REG;
> + ao_context->irq_status_reg =
> + info->me4000_regbase + ME4000_IRQ_STATUS_REG;
> + ao_context->preload_reg =
> + info->me4000_regbase + ME4000_AO_LOADSETREG_XX;
> + break;
> + case 2:
> + ao_context->ctrl_reg =
> + info->me4000_regbase + ME4000_AO_02_CTRL_REG;
> + ao_context->status_reg =
> + info->me4000_regbase + ME4000_AO_02_STATUS_REG;
> + ao_context->fifo_reg =
> + info->me4000_regbase + ME4000_AO_02_FIFO_REG;
> + ao_context->single_reg =
> + info->me4000_regbase + ME4000_AO_02_SINGLE_REG;
> + ao_context->timer_reg =
> + info->me4000_regbase + ME4000_AO_02_TIMER_REG;
> + ao_context->irq_status_reg =
> + info->me4000_regbase + ME4000_IRQ_STATUS_REG;
> + ao_context->preload_reg =
> + info->me4000_regbase + ME4000_AO_LOADSETREG_XX;
> + break;
> + case 3:
> + ao_context->ctrl_reg =
> + info->me4000_regbase + ME4000_AO_03_CTRL_REG;
> + ao_context->status_reg =
> + info->me4000_regbase + ME4000_AO_03_STATUS_REG;
> + ao_context->fifo_reg =
> + info->me4000_regbase + ME4000_AO_03_FIFO_REG;
> + ao_context->single_reg =
> + info->me4000_regbase + ME4000_AO_03_SINGLE_REG;
> + ao_context->timer_reg =
> + info->me4000_regbase + ME4000_AO_03_TIMER_REG;
> + ao_context->irq_status_reg =
> + info->me4000_regbase + ME4000_IRQ_STATUS_REG;
> + ao_context->preload_reg =
> + info->me4000_regbase + ME4000_AO_LOADSETREG_XX;
> + break;
> + default:
> + break;
> + }
> +
> + if (info->board_p->ao.fifo_count) {
> + /* Request the interrupt line */
> + err =
> + request_irq(ao_context->irq, me4000_ao_isr,
> + IRQF_DISABLED | IRQF_SHARED,
> + ME4000_NAME, ao_context);
> + if (err) {
> + printk(KERN_ERR
> + "alloc_ao_contexts():Can't get interrupt line");
__func__(?)
> + if (ao_context->circ_buf.buf)
> + kfree(ao_context->circ_buf.buf);
kfree(NULL) is legal
> + kfree(ao_context);
> + release_ao_contexts(info);
> + return -ENODEV;
> + }
> + }
> +
> + list_add_tail(&ao_context->list, &info->ao_context_list);
> + ao_context->index = i;
> + }
> +
> + return 0;
> +}
> +
> +static void release_ao_contexts(me4000_info_t * board_info)
> +{
> + struct list_head *dac_p;
> + me4000_ao_context_t *ao_context;
> +
> + /* Clear analog output context list */
> + while (!list_empty(&board_info->ao_context_list)) {
> + dac_p = board_info->ao_context_list.next;
> + ao_context = list_entry(dac_p, me4000_ao_context_t, list);
> + free_irq(ao_context->irq, ao_context);
> + if (ao_context->circ_buf.buf)
> + kfree(ao_context->circ_buf.buf);
etc
> + list_del(dac_p);
> + kfree(ao_context);
> + }
> +}
> +
> +static int alloc_ai_context(me4000_info_t * info)
> +{
> + me4000_ai_context_t *ai_context;
> +
> + if (info->board_p->ai.count) {
> + ai_context = kmalloc(sizeof(me4000_ai_context_t), GFP_KERNEL);
> + if (!ai_context) {
> + printk(KERN_ERR
> + "ME4000:alloc_ai_context():Can't get memory for ai context\n");
> + return -ENOMEM;
> + }
> + memset(ai_context, 0, sizeof(me4000_ai_context_t));
kzalloc()
> + info->ai_context = ai_context;
> +
> + spin_lock_init(&ai_context->use_lock);
> + spin_lock_init(&ai_context->int_lock);
> + ai_context->number = 0;
> + ai_context->irq = info->irq;
> + init_waitqueue_head(&ai_context->wait_queue);
> + ai_context->board_info = info;
> +
> + ai_context->ctrl_reg =
> + info->me4000_regbase + ME4000_AI_CTRL_REG;
> + ai_context->status_reg =
> + info->me4000_regbase + ME4000_AI_STATUS_REG;
> + ai_context->channel_list_reg =
> + info->me4000_regbase + ME4000_AI_CHANNEL_LIST_REG;
> + ai_context->data_reg =
> + info->me4000_regbase + ME4000_AI_DATA_REG;
> + ai_context->chan_timer_reg =
> + info->me4000_regbase + ME4000_AI_CHAN_TIMER_REG;
> + ai_context->chan_pre_timer_reg =
> + info->me4000_regbase + ME4000_AI_CHAN_PRE_TIMER_REG;
> + ai_context->scan_timer_low_reg =
> + info->me4000_regbase + ME4000_AI_SCAN_TIMER_LOW_REG;
> + ai_context->scan_timer_high_reg =
> + info->me4000_regbase + ME4000_AI_SCAN_TIMER_HIGH_REG;
> + ai_context->scan_pre_timer_low_reg =
> + info->me4000_regbase + ME4000_AI_SCAN_PRE_TIMER_LOW_REG;
> + ai_context->scan_pre_timer_high_reg =
> + info->me4000_regbase + ME4000_AI_SCAN_PRE_TIMER_HIGH_REG;
> + ai_context->start_reg =
> + info->me4000_regbase + ME4000_AI_START_REG;
> + ai_context->irq_status_reg =
> + info->me4000_regbase + ME4000_IRQ_STATUS_REG;
> + ai_context->sample_counter_reg =
> + info->me4000_regbase + ME4000_AI_SAMPLE_COUNTER_REG;
> + }
> +
> + return 0;
> +}
> +
> +static int alloc_dio_context(me4000_info_t * info)
> +{
> + me4000_dio_context_t *dio_context;
> +
> + if (info->board_p->dio.count) {
> + dio_context = kmalloc(sizeof(me4000_dio_context_t), GFP_KERNEL);
> + if (!dio_context) {
> + printk(KERN_ERR
> + "ME4000:alloc_dio_context():Can't get memory for dio context\n");
> + return -ENOMEM;
> + }
> + memset(dio_context, 0, sizeof(me4000_dio_context_t));
etc
> + info->dio_context = dio_context;
> +
> + spin_lock_init(&dio_context->use_lock);
> + dio_context->board_info = info;
> +
> + dio_context->dio_count = info->board_p->dio.count;
> +
> + dio_context->dir_reg =
> + info->me4000_regbase + ME4000_DIO_DIR_REG;
> + dio_context->ctrl_reg =
> + info->me4000_regbase + ME4000_DIO_CTRL_REG;
> + dio_context->port_0_reg =
> + info->me4000_regbase + ME4000_DIO_PORT_0_REG;
> + dio_context->port_1_reg =
> + info->me4000_regbase + ME4000_DIO_PORT_1_REG;
> + dio_context->port_2_reg =
> + info->me4000_regbase + ME4000_DIO_PORT_2_REG;
> + dio_context->port_3_reg =
> + info->me4000_regbase + ME4000_DIO_PORT_3_REG;
> + }
> +
> + return 0;
> +}
> +
> +static int alloc_cnt_context(me4000_info_t * info)
> +{
> + me4000_cnt_context_t *cnt_context;
> +
> + if (info->board_p->cnt.count) {
> + cnt_context = kmalloc(sizeof(me4000_cnt_context_t), GFP_KERNEL);
> + if (!cnt_context) {
> + printk(KERN_ERR
> + "ME4000:alloc_cnt_context():Can't get memory for cnt context\n");
> + return -ENOMEM;
> + }
> + memset(cnt_context, 0, sizeof(me4000_cnt_context_t));
etc
> + info->cnt_context = cnt_context;
> +
> + spin_lock_init(&cnt_context->use_lock);
> + cnt_context->board_info = info;
> +
> + cnt_context->ctrl_reg =
> + info->timer_regbase + ME4000_CNT_CTRL_REG;
> + cnt_context->counter_0_reg =
> + info->timer_regbase + ME4000_CNT_COUNTER_0_REG;
> + cnt_context->counter_1_reg =
> + info->timer_regbase + ME4000_CNT_COUNTER_1_REG;
> + cnt_context->counter_2_reg =
> + info->timer_regbase + ME4000_CNT_COUNTER_2_REG;
> + }
> +
> + return 0;
> +}
> +
> +static int alloc_ext_int_context(me4000_info_t * info)
> +{
> + me4000_ext_int_context_t *ext_int_context;
> +
> + if (info->board_p->cnt.count) {
> + ext_int_context =
> + kmalloc(sizeof(me4000_ext_int_context_t), GFP_KERNEL);
> + if (!ext_int_context) {
> + printk(KERN_ERR
> + "ME4000:alloc_ext_int_context():Can't get memory for cnt context\n");
> + return -ENOMEM;
> + }
> + memset(ext_int_context, 0, sizeof(me4000_ext_int_context_t));
ho hum
> + info->ext_int_context = ext_int_context;
> +
> + spin_lock_init(&ext_int_context->use_lock);
> + ext_int_context->board_info = info;
> +
> + ext_int_context->fasync_ptr = NULL;
> + ext_int_context->irq = info->irq;
> +
> + ext_int_context->ctrl_reg =
> + info->me4000_regbase + ME4000_AI_CTRL_REG;
> + ext_int_context->irq_status_reg =
> + info->me4000_regbase + ME4000_IRQ_STATUS_REG;
> + }
> +
> + return 0;
> +}
> +
> +static int me4000_probe(struct pci_dev *dev, const struct pci_device_id *id)
> +{
> + int result = 0;
> + me4000_info_t *board_info;
> +
> + CALL_PDEBUG("me4000_probe() is executed\n");
> +
> + /* Allocate structure for board context */
> + board_info = kmalloc(sizeof(me4000_info_t), GFP_KERNEL);
> + if (!board_info) {
> + printk(KERN_ERR
> + "ME4000:Can't get memory for board info structure\n");
> + result = -ENOMEM;
> + goto PROBE_ERROR_1;
> + }
> + memset(board_info, 0, sizeof(me4000_info_t));
> +
> + /* Add to global linked list */
> + list_add_tail(&board_info->list, &me4000_board_info_list);
> +
> + /* Get the PCI base registers */
> + result = get_registers(dev, board_info);
> + if (result) {
> + printk(KERN_ERR "me4000_probe():Cannot get registers\n");
> + goto PROBE_ERROR_2;
> + }
> +
> + /* Enable the device */
> + result = pci_enable_device(dev);
> + if (result < 0) {
> + printk(KERN_ERR "me4000_probe():Cannot enable PCI device\n");
> + goto PROBE_ERROR_2;
> + }
> +
> + /* Request the PCI register regions */
> + result = pci_request_regions(dev, ME4000_NAME);
> + if (result < 0) {
> + printk(KERN_ERR "me4000_probe():Cannot request I/O regions\n");
> + goto PROBE_ERROR_2;
> + }
> +
> + /* Initialize board info */
> + result = init_board_info(dev, board_info);
> + if (result) {
> + printk(KERN_ERR "me4000_probe():Cannot init baord info\n");
> + goto PROBE_ERROR_3;
> + }
> +
> + /* Download the xilinx firmware */
> + result = me4000_xilinx_download(board_info);
> + if (result) {
> + printk(KERN_ERR "me4000_probe:Can't download firmware\n");
> + goto PROBE_ERROR_3;
> + }
> +
> + /* Make a hardware reset */
> + result = me4000_reset_board(board_info);
> + if (result) {
> + printk(KERN_ERR "me4000_probe:Can't reset board\n");
> + goto PROBE_ERROR_3;
> + }
> +
> + /* Allocate analog output context structures */
> + result = alloc_ao_contexts(board_info);
> + if (result) {
> + printk(KERN_ERR "me4000_probe():Cannot allocate ao contexts\n");
> + goto PROBE_ERROR_3;
> + }
> +
> + /* Allocate analog input context */
> + result = alloc_ai_context(board_info);
> + if (result) {
> + printk(KERN_ERR "me4000_probe():Cannot allocate ai context\n");
> + goto PROBE_ERROR_4;
> + }
> +
> + /* Allocate digital I/O context */
> + result = alloc_dio_context(board_info);
> + if (result) {
> + printk(KERN_ERR "me4000_probe():Cannot allocate dio context\n");
> + goto PROBE_ERROR_5;
> + }
> +
> + /* Allocate counter context */
> + result = alloc_cnt_context(board_info);
> + if (result) {
> + printk(KERN_ERR "me4000_probe():Cannot allocate cnt context\n");
> + goto PROBE_ERROR_6;
> + }
> +
> + /* Allocate external interrupt context */
> + result = alloc_ext_int_context(board_info);
> + if (result) {
> + printk(KERN_ERR
> + "me4000_probe():Cannot allocate ext_int context\n");
> + goto PROBE_ERROR_7;
> + }
__func__
> + return 0;
> +
> + PROBE_ERROR_7:
indent
> + kfree(board_info->cnt_context);
> +
> + PROBE_ERROR_6:
> + kfree(board_info->dio_context);
> +
> + PROBE_ERROR_5:
> + kfree(board_info->ai_context);
> +
> + PROBE_ERROR_4:
> + release_ao_contexts(board_info);
> +
> + PROBE_ERROR_3:
> + pci_release_regions(dev);
> +
> + PROBE_ERROR_2:
> + list_del(&board_info->list);
> + kfree(board_info);
> +
> + PROBE_ERROR_1:
> + return result;
> +}
> +
> +static int me4000_xilinx_download(me4000_info_t * info)
> +{
> + int size = 0;
> + u32 value = 0;
> + int idx = 0;
> + unsigned char *firm;
> + wait_queue_head_t queue;
this doesn't do anything
> +
> + CALL_PDEBUG("me4000_xilinx_download() is executed\n");
> +
> + init_waitqueue_head(&queue);
> +
> + firm = (info->device_id == 0x4610) ? xilinx_firm_4610 : xilinx_firm;
> +
> + /*
> + * Set PLX local interrupt 2 polarity to high.
> + * Interrupt is thrown by init pin of xilinx.
> + */
> + outl(0x10, info->plx_regbase + PLX_INTCSR);
> +
> + /* Set /CS and /WRITE of the Xilinx */
> + value = inl(info->plx_regbase + PLX_ICR);
> + value |= 0x100;
> + outl(value, info->plx_regbase + PLX_ICR);
> +
> + /* Init Xilinx with CS1 */
> + inb(info->program_regbase + 0xC8);
> +
> + /* Wait until /INIT pin is set */
> + udelay(20);
> + if (!inl(info->plx_regbase + PLX_INTCSR) & 0x20) {
> + printk(KERN_ERR "me4000_xilinx_download():Can't init Xilinx\n");
> + return -EIO;
> + }
> +
> + /* Reset /CS and /WRITE of the Xilinx */
> + value = inl(info->plx_regbase + PLX_ICR);
> + value &= ~0x100;
> + outl(value, info->plx_regbase + PLX_ICR);
> +
> + /* Download Xilinx firmware */
> + size = (firm[0] << 24) + (firm[1] << 16) + (firm[2] << 8) + firm[3];
> + udelay(10);
> +
> + for (idx = 0; idx < size; idx++) {
> + outb(firm[16 + idx], info->program_regbase);
> +
> + udelay(10);
> +
> + /* Check if BUSY flag is low */
> + if (inl(info->plx_regbase + PLX_ICR) & 0x20) {
> + printk(KERN_ERR
> + "me4000_xilinx_download():Xilinx is still busy (idx = %d)\n",
> + idx);
> + return -EIO;
> + }
> + }
> +
> + PDEBUG("me4000_xilinx_download():%d bytes written\n", idx);
> +
> + /* If done flag is high download was successful */
> + if (inl(info->plx_regbase + PLX_ICR) & 0x4) {
> + PDEBUG("me4000_xilinx_download():Done flag is set\n");
> + PDEBUG("me4000_xilinx_download():Download was successful\n");
> + } else {
> + printk(KERN_ERR
> + "ME4000:me4000_xilinx_download():DONE flag is not set\n");
> + printk(KERN_ERR
> + "ME4000:me4000_xilinx_download():Download not succesful\n");
> + return -EIO;
> + }
> +
> + /* Set /CS and /WRITE */
> + value = inl(info->plx_regbase + PLX_ICR);
> + value |= 0x100;
> + outl(value, info->plx_regbase + PLX_ICR);
> +
> + return 0;
> +}
> +
> +static int me4000_reset_board(me4000_info_t * info)
> +{
> + unsigned long icr;
> +
> + CALL_PDEBUG("me4000_reset_board() is executed\n");
> +
> + /* Make a hardware reset */
> + icr = me4000_inl(info->plx_regbase + PLX_ICR);
> + icr |= 0x40000000;
> + me4000_outl(icr, info->plx_regbase + PLX_ICR);
> + icr &= ~0x40000000;
> + me4000_outl(icr, info->plx_regbase + PLX_ICR);
> +
> + /* Set both stop bits in the analog input control register */
> + me4000_outl(ME4000_AI_CTRL_BIT_IMMEDIATE_STOP | ME4000_AI_CTRL_BIT_STOP,
> + info->me4000_regbase + ME4000_AI_CTRL_REG);
> +
> + /* Set both stop bits in the analog output control register */
> + me4000_outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP,
> + info->me4000_regbase + ME4000_AO_00_CTRL_REG);
> + me4000_outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP,
> + info->me4000_regbase + ME4000_AO_01_CTRL_REG);
> + me4000_outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP,
> + info->me4000_regbase + ME4000_AO_02_CTRL_REG);
> + me4000_outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP,
> + info->me4000_regbase + ME4000_AO_03_CTRL_REG);
> +
> + /* 0x8000 to the DACs means an output voltage of 0V */
> + me4000_outl(0x8000, info->me4000_regbase + ME4000_AO_00_SINGLE_REG);
> + me4000_outl(0x8000, info->me4000_regbase + ME4000_AO_01_SINGLE_REG);
> + me4000_outl(0x8000, info->me4000_regbase + ME4000_AO_02_SINGLE_REG);
> + me4000_outl(0x8000, info->me4000_regbase + ME4000_AO_03_SINGLE_REG);
> +
> + /* Enable interrupts on the PLX */
> + me4000_outl(0x43, info->plx_regbase + PLX_INTCSR);
> +
> + /* Set the adustment register for AO demux */
> + me4000_outl(ME4000_AO_DEMUX_ADJUST_VALUE,
> + info->me4000_regbase + ME4000_AO_DEMUX_ADJUST_REG);
> +
> + /* Set digital I/O direction for port 0 to output on isolated versions */
> + if (!(me4000_inl(info->me4000_regbase + ME4000_DIO_DIR_REG) & 0x1)) {
> + me4000_outl(0x1, info->me4000_regbase + ME4000_DIO_CTRL_REG);
> + }
> +
> + return 0;
> +}
> +
> +static int me4000_open(struct inode *inode_p, struct file *file_p)
> +{
> + int board, dev, mode;
> + int err = 0;
> + int i;
> + struct list_head *ptr;
> + me4000_info_t *board_info = NULL;
> + me4000_ao_context_t *ao_context = NULL;
> + me4000_ai_context_t *ai_context = NULL;
> + me4000_dio_context_t *dio_context = NULL;
> + me4000_cnt_context_t *cnt_context = NULL;
> + me4000_ext_int_context_t *ext_int_context = NULL;
> +
> + CALL_PDEBUG("me4000_open() is executed\n");
> +
> + /* Analog output */
> + if (MAJOR(inode_p->i_rdev) == me4000_ao_major_driver_no) {
> + board = AO_BOARD(inode_p->i_rdev);
> + dev = AO_PORT(inode_p->i_rdev);
> + mode = AO_MODE(inode_p->i_rdev);
> +
> + PDEBUG("me4000_open():board = %d ao = %d mode = %d\n", board,
> + dev, mode);
> +
> + /* Search for the board context */
> + for (ptr = me4000_board_info_list.next, i = 0;
> + ptr != &me4000_board_info_list; ptr = ptr->next, i++) {
> + board_info = list_entry(ptr, me4000_info_t, list);
> + if (i == board)
> + break;
> + }
> +
> + if (ptr == &me4000_board_info_list) {
> + printk(KERN_ERR
> + "ME4000:me4000_open():Board %d not in device list\n",
> + board);
> + return -ENODEV;
> + }
> +
> + /* Search for the dac context */
> + for (ptr = board_info->ao_context_list.next, i = 0;
> + ptr != &board_info->ao_context_list;
> + ptr = ptr->next, i++) {
> + ao_context = list_entry(ptr, me4000_ao_context_t, list);
> + if (i == dev)
> + break;
> + }
> +
> + if (ptr == &board_info->ao_context_list) {
> + printk(KERN_ERR
> + "ME4000:me4000_open():Device %d not in device list\n",
> + dev);
> + return -ENODEV;
> + }
> +
> + /* Check if mode is valid */
> + if (mode > 2) {
> + printk(KERN_ERR
> + "ME4000:me4000_open():Mode is not valid\n");
> + return -ENODEV;
> + }
> +
> + /* Check if mode is valid for this AO */
> + if ((mode != ME4000_AO_CONV_MODE_SINGLE)
> + && (dev >= board_info->board_p->ao.fifo_count)) {
> + printk(KERN_ERR
> + "ME4000:me4000_open():AO %d only in single mode available\n",
> + dev);
> + return -ENODEV;
> + }
> +
> + /* Check if already opened */
> + spin_lock(&ao_context->use_lock);
> + if (ao_context->dac_in_use) {
> + printk(KERN_ERR
> + "ME4000:me4000_open():AO %d already in use\n",
> + dev);
> + spin_unlock(&ao_context->use_lock);
> + return -EBUSY;
> + }
> + ao_context->dac_in_use = 1;
> + spin_unlock(&ao_context->use_lock);
> +
> + ao_context->mode = mode;
> +
> + /* Hold the context in private data */
> + file_p->private_data = ao_context;
> +
> + /* Set file operations pointer */
> + file_p->f_op = me4000_ao_fops_array[mode];
> +
> + err = me4000_ao_prepare(ao_context);
> + if (err) {
> + ao_context->dac_in_use = 0;
> + return 1;
> + }
> + }
> + /* Analog input */
> + else if (MAJOR(inode_p->i_rdev) == me4000_ai_major_driver_no) {
> + board = AI_BOARD(inode_p->i_rdev);
> + mode = AI_MODE(inode_p->i_rdev);
> +
> + PDEBUG("me4000_open():ai board = %d mode = %d\n", board, mode);
> +
> + /* Search for the board context */
> + for (ptr = me4000_board_info_list.next, i = 0;
> + ptr != &me4000_board_info_list; ptr = ptr->next, i++) {
> + board_info = list_entry(ptr, me4000_info_t, list);
> + if (i == board)
> + break;
> + }
> +
> + if (ptr == &me4000_board_info_list) {
> + printk(KERN_ERR
> + "ME4000:me4000_open():Board %d not in device list\n",
> + board);
> + return -ENODEV;
> + }
> +
> + ai_context = board_info->ai_context;
> +
> + /* Check if mode is valid */
> + if (mode > 5) {
> + printk(KERN_ERR
> + "ME4000:me4000_open():Mode is not valid\n");
> + return -EINVAL;
> + }
> +
> + /* Check if already opened */
> + spin_lock(&ai_context->use_lock);
> + if (ai_context->in_use) {
> + printk(KERN_ERR
> + "ME4000:me4000_open():AI already in use\n");
> + spin_unlock(&ai_context->use_lock);
> + return -EBUSY;
> + }
> + ai_context->in_use = 1;
> + spin_unlock(&ai_context->use_lock);
> +
> + ai_context->mode = mode;
> +
> + /* Hold the context in private data */
> + file_p->private_data = ai_context;
> +
> + /* Set file operations pointer */
> + file_p->f_op = me4000_ai_fops_array[mode];
> +
> + /* Prepare analog input */
> + me4000_ai_prepare(ai_context);
> + }
> + /* Digital I/O */
> + else if (MAJOR(inode_p->i_rdev) == me4000_dio_major_driver_no) {
> + board = DIO_BOARD(inode_p->i_rdev);
> + dev = 0;
> + mode = 0;
> +
> + PDEBUG("me4000_open():board = %d\n", board);
> +
> + /* Search for the board context */
> + for (ptr = me4000_board_info_list.next;
> + ptr != &me4000_board_info_list; ptr = ptr->next) {
> + board_info = list_entry(ptr, me4000_info_t, list);
> + if (board_info->board_count == board)
> + break;
> + }
> +
> + if (ptr == &me4000_board_info_list) {
> + printk(KERN_ERR
> + "ME4000:me4000_open():Board %d not in device list\n",
> + board);
> + return -ENODEV;
> + }
> +
> + /* Search for the dio context */
> + dio_context = board_info->dio_context;
> +
> + /* Check if already opened */
> + spin_lock(&dio_context->use_lock);
> + if (dio_context->in_use) {
> + printk(KERN_ERR
> + "ME4000:me4000_open():DIO already in use\n");
> + spin_unlock(&dio_context->use_lock);
> + return -EBUSY;
> + }
> + dio_context->in_use = 1;
> + spin_unlock(&dio_context->use_lock);
> +
> + /* Hold the context in private data */
> + file_p->private_data = dio_context;
> +
> + /* Set file operations pointer to single functions */
> + file_p->f_op = &me4000_dio_fops;
> +
> + //me4000_dio_reset(dio_context);
> + }
> + /* Counters */
> + else if (MAJOR(inode_p->i_rdev) == me4000_cnt_major_driver_no) {
> + board = CNT_BOARD(inode_p->i_rdev);
> + dev = 0;
> + mode = 0;
> +
> + PDEBUG("me4000_open():board = %d\n", board);
> +
> + /* Search for the board context */
> + for (ptr = me4000_board_info_list.next;
> + ptr != &me4000_board_info_list; ptr = ptr->next) {
> + board_info = list_entry(ptr, me4000_info_t, list);
> + if (board_info->board_count == board)
> + break;
> + }
> +
> + if (ptr == &me4000_board_info_list) {
> + printk(KERN_ERR
> + "ME4000:me4000_open():Board %d not in device list\n",
> + board);
> + return -ENODEV;
> + }
> +
> + /* Get the cnt context */
> + cnt_context = board_info->cnt_context;
> +
> + /* Check if already opened */
> + spin_lock(&cnt_context->use_lock);
> + if (cnt_context->in_use) {
> + printk(KERN_ERR
> + "ME4000:me4000_open():CNT already in use\n");
> + spin_unlock(&cnt_context->use_lock);
> + return -EBUSY;
> + }
> + cnt_context->in_use = 1;
> + spin_unlock(&cnt_context->use_lock);
> +
> + /* Hold the context in private data */
> + file_p->private_data = cnt_context;
> +
> + /* Set file operations pointer to single functions */
> + file_p->f_op = &me4000_cnt_fops;
> + }
> + /* External Interrupt */
> + else if (MAJOR(inode_p->i_rdev) == me4000_ext_int_major_driver_no) {
> + board = EXT_INT_BOARD(inode_p->i_rdev);
> + dev = 0;
> + mode = 0;
> +
> + PDEBUG("me4000_open():board = %d\n", board);
> +
> + /* Search for the board context */
> + for (ptr = me4000_board_info_list.next;
> + ptr != &me4000_board_info_list; ptr = ptr->next) {
> + board_info = list_entry(ptr, me4000_info_t, list);
> + if (board_info->board_count == board)
> + break;
> + }
> +
> + if (ptr == &me4000_board_info_list) {
> + printk(KERN_ERR
> + "ME4000:me4000_open():Board %d not in device list\n",
> + board);
> + return -ENODEV;
> + }
> +
> + /* Get the external interrupt context */
> + ext_int_context = board_info->ext_int_context;
> +
> + /* Check if already opened */
> + spin_lock(&cnt_context->use_lock);
> + if (ext_int_context->in_use) {
> + printk(KERN_ERR
> + "ME4000:me4000_open():External interrupt already in use\n");
> + spin_unlock(&ext_int_context->use_lock);
> + return -EBUSY;
> + }
> + ext_int_context->in_use = 1;
> + spin_unlock(&ext_int_context->use_lock);
> +
> + /* Hold the context in private data */
> + file_p->private_data = ext_int_context;
> +
> + /* Set file operations pointer to single functions */
> + file_p->f_op = &me4000_ext_int_fops;
> +
> + /* Request the interrupt line */
> + err =
> + request_irq(ext_int_context->irq, me4000_ext_int_isr,
> + IRQF_DISABLED | IRQF_SHARED, ME4000_NAME,
> + ext_int_context);
> + if (err) {
> + printk(KERN_ERR
> + "ME4000:me4000_open():Can't get interrupt line");
> + ext_int_context->in_use = 0;
> + return -ENODEV;
> + }
> +
> + /* Reset the counter */
> + me4000_ext_int_disable(ext_int_context);
> + } else {
> + printk(KERN_ERR "ME4000:me4000_open():Major number unknown\n");
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static int me4000_release(struct inode *inode_p, struct file *file_p)
> +{
> + me4000_ao_context_t *ao_context;
> + me4000_ai_context_t *ai_context;
> + me4000_dio_context_t *dio_context;
> + me4000_cnt_context_t *cnt_context;
> + me4000_ext_int_context_t *ext_int_context;
> +
> + CALL_PDEBUG("me4000_release() is executed\n");
> +
> + if (MAJOR(inode_p->i_rdev) == me4000_ao_major_driver_no) {
> + ao_context = file_p->private_data;
> +
> + /* Mark DAC as unused */
> + ao_context->dac_in_use = 0;
> + } else if (MAJOR(inode_p->i_rdev) == me4000_ai_major_driver_no) {
> + ai_context = file_p->private_data;
> +
> + /* Reset the analog input */
> + me4000_ai_reset(ai_context);
> +
> + /* Free the interrupt and the circular buffer */
> + if (ai_context->mode) {
> + free_irq(ai_context->irq, ai_context);
> + kfree(ai_context->circ_buf.buf);
> + ai_context->circ_buf.buf = NULL;
> + ai_context->circ_buf.head = 0;
> + ai_context->circ_buf.tail = 0;
> + }
> +
> + /* Mark AI as unused */
> + ai_context->in_use = 0;
> + } else if (MAJOR(inode_p->i_rdev) == me4000_dio_major_driver_no) {
> + dio_context = file_p->private_data;
> +
> + /* Mark digital I/O as unused */
> + dio_context->in_use = 0;
> + } else if (MAJOR(inode_p->i_rdev) == me4000_cnt_major_driver_no) {
> + cnt_context = file_p->private_data;
> +
> + /* Mark counters as unused */
> + cnt_context->in_use = 0;
> + } else if (MAJOR(inode_p->i_rdev) == me4000_ext_int_major_driver_no) {
> + ext_int_context = file_p->private_data;
> +
> + /* Disable the externel interrupt */
> + me4000_ext_int_disable(ext_int_context);
> +
> + free_irq(ext_int_context->irq, ext_int_context);
> +
> + /* Delete the fasync structure and free memory */
> + me4000_ext_int_fasync(0, file_p, 0);
> +
> + /* Mark as unused */
> + ext_int_context->in_use = 0;
> + } else {
> + printk(KERN_ERR
> + "ME4000:me4000_release():Major number unknown\n");
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +/*------------------------------- Analog output stuff --------------------------------------*/
> +
> +static int me4000_ao_prepare(me4000_ao_context_t * ao_context)
> +{
> + unsigned long flags;
> +
> + CALL_PDEBUG("me4000_ao_prepare() is executed\n");
> +
> + if (ao_context->mode == ME4000_AO_CONV_MODE_CONTINUOUS) {
> + /* Only do anything if not already in the correct mode */
> + unsigned long mode = me4000_inl(ao_context->ctrl_reg);
> + if ((mode & ME4000_AO_CONV_MODE_CONTINUOUS)
> + && (mode & ME4000_AO_CTRL_BIT_ENABLE_FIFO)) {
> + return 0;
> + }
> +
> + /* Stop any conversion */
> + me4000_ao_immediate_stop(ao_context);
> +
> + /* Set the control register to default state */
> + spin_lock_irqsave(&ao_context->int_lock, flags);
> + me4000_outl(ME4000_AO_CONV_MODE_CONTINUOUS |
> + ME4000_AO_CTRL_BIT_ENABLE_FIFO |
> + ME4000_AO_CTRL_BIT_STOP |
> + ME4000_AO_CTRL_BIT_IMMEDIATE_STOP,
> + ao_context->ctrl_reg);
> + spin_unlock_irqrestore(&ao_context->int_lock, flags);
> +
> + /* Set to fastest sample rate */
> + me4000_outl(65, ao_context->timer_reg);
> + } else if (ao_context->mode == ME4000_AO_CONV_MODE_WRAPAROUND) {
> + /* Only do anything if not already in the correct mode */
> + unsigned long mode = me4000_inl(ao_context->ctrl_reg);
> + if ((mode & ME4000_AO_CONV_MODE_WRAPAROUND)
> + && (mode & ME4000_AO_CTRL_BIT_ENABLE_FIFO)) {
> + return 0;
> + }
> +
> + /* Stop any conversion */
> + me4000_ao_immediate_stop(ao_context);
> +
> + /* Set the control register to default state */
> + spin_lock_irqsave(&ao_context->int_lock, flags);
> + me4000_outl(ME4000_AO_CONV_MODE_WRAPAROUND |
> + ME4000_AO_CTRL_BIT_ENABLE_FIFO |
> + ME4000_AO_CTRL_BIT_STOP |
> + ME4000_AO_CTRL_BIT_IMMEDIATE_STOP,
> + ao_context->ctrl_reg);
> + spin_unlock_irqrestore(&ao_context->int_lock, flags);
> +
> + /* Set to fastest sample rate */
> + me4000_outl(65, ao_context->timer_reg);
> + } else if (ao_context->mode == ME4000_AO_CONV_MODE_SINGLE) {
> + /* Only do anything if not already in the correct mode */
> + unsigned long mode = me4000_inl(ao_context->ctrl_reg);
> + if (!
> + (mode &
> + (ME4000_AO_CONV_MODE_WRAPAROUND |
> + ME4000_AO_CONV_MODE_CONTINUOUS))) {
> + return 0;
> + }
> +
> + /* Stop any conversion */
> + me4000_ao_immediate_stop(ao_context);
> +
> + /* Clear the control register */
> + spin_lock_irqsave(&ao_context->int_lock, flags);
> + me4000_outl(0x0, ao_context->ctrl_reg);
> + spin_unlock_irqrestore(&ao_context->int_lock, flags);
> +
> + /* Set voltage to 0V */
> + me4000_outl(0x8000, ao_context->single_reg);
> + } else {
> + printk(KERN_ERR
> + "ME4000:me4000_ao_prepare():Invalid mode specified\n");
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static int me4000_ao_reset(me4000_ao_context_t * ao_context)
> +{
> + u32 tmp;
> + wait_queue_head_t queue;
> + unsigned long flags;
> +
> + CALL_PDEBUG("me4000_ao_reset() is executed\n");
> +
> + init_waitqueue_head(&queue);
> +
> + if (ao_context->mode == ME4000_AO_CONV_MODE_WRAPAROUND) {
> + /*
> + * First stop conversion of the DAC before reconfigure.
> + * This is essantial, cause of the state machine.
> + * If not stopped before configuring mode, it could
> + * walk in a undefined state.
> + */
> + tmp = me4000_inl(ao_context->ctrl_reg);
> + tmp |= ME4000_AO_CTRL_BIT_IMMEDIATE_STOP;
> + me4000_outl(tmp, ao_context->ctrl_reg);
> +
> + while (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) {
> + sleep_on_timeout(&queue, 1);
whee
> + }
> +
> + /* Set to transparent mode */
> + me4000_ao_simultaneous_disable(ao_context);
> +
> + /* Set to single mode in order to set default voltage */
> + me4000_outl(0x0, ao_context->ctrl_reg);
> +
> + /* Set voltage to 0V */
> + me4000_outl(0x8000, ao_context->single_reg);
> +
> + /* Set to fastest sample rate */
> + me4000_outl(65, ao_context->timer_reg);
> +
> + /* Set the original mode and enable FIFO */
> + me4000_outl(ME4000_AO_CONV_MODE_WRAPAROUND |
> + ME4000_AO_CTRL_BIT_ENABLE_FIFO |
> + ME4000_AO_CTRL_BIT_STOP |
> + ME4000_AO_CTRL_BIT_IMMEDIATE_STOP,
> + ao_context->ctrl_reg);
> + } else if (ao_context->mode == ME4000_AO_CONV_MODE_CONTINUOUS) {
> + /*
> + * First stop conversion of the DAC before reconfigure.
> + * This is essantial, cause of the state machine.
> + * If not stopped before configuring mode, it could
> + * walk in a undefined state.
> + */
> + spin_lock_irqsave(&ao_context->int_lock, flags);
> + tmp = me4000_inl(ao_context->ctrl_reg);
> + tmp |= ME4000_AO_CTRL_BIT_STOP;
> + me4000_outl(tmp, ao_context->ctrl_reg);
> + spin_unlock_irqrestore(&ao_context->int_lock, flags);
> +
> + while (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) {
> + sleep_on_timeout(&queue, 1);
> + }
> +
> + /* Clear the circular buffer */
> + ao_context->circ_buf.head = 0;
> + ao_context->circ_buf.tail = 0;
> +
> + /* Set to transparent mode */
> + me4000_ao_simultaneous_disable(ao_context);
> +
> + /* Set to single mode in order to set default voltage */
> + spin_lock_irqsave(&ao_context->int_lock, flags);
> + tmp = me4000_inl(ao_context->ctrl_reg);
> + me4000_outl(0x0, ao_context->ctrl_reg);
> +
> + /* Set voltage to 0V */
> + me4000_outl(0x8000, ao_context->single_reg);
> +
> + /* Set to fastest sample rate */
> + me4000_outl(65, ao_context->timer_reg);
> +
> + /* Set the original mode and enable FIFO */
> + me4000_outl(ME4000_AO_CONV_MODE_CONTINUOUS |
> + ME4000_AO_CTRL_BIT_ENABLE_FIFO |
> + ME4000_AO_CTRL_BIT_STOP |
> + ME4000_AO_CTRL_BIT_IMMEDIATE_STOP,
> + ao_context->ctrl_reg);
> + spin_unlock_irqrestore(&ao_context->int_lock, flags);
> + } else {
> + /* Set to transparent mode */
> + me4000_ao_simultaneous_disable(ao_context);
> +
> + /* Set voltage to 0V */
> + me4000_outl(0x8000, ao_context->single_reg);
> + }
> +
> + return 0;
> +}
> +
> +static ssize_t me4000_ao_write_sing(struct file *filep, const char *buff,
> + size_t cnt, loff_t * offp)
> +{
> + me4000_ao_context_t *ao_context = filep->private_data;
> + u32 value;
> + const u16 *buffer = (const u16 *)buff;
> +
> + CALL_PDEBUG("me4000_ao_write_sing() is executed\n");
> +
> + if (cnt != 2) {
> + printk(KERN_ERR
> + "me4000_ao_write_sing():Write count is not 2\n");
> + return -EINVAL;
> + }
> +
> + if (get_user(value, buffer)) {
eh?
> + printk(KERN_ERR
> + "me4000_ao_write_sing():Cannot copy data from user\n");
> + return -EFAULT;
> + }
> +
> + me4000_outl(value, ao_context->single_reg);
> +
> + return 2;
> +}
> +
> +static ssize_t me4000_ao_write_wrap(struct file *filep, const char *buff,
> + size_t cnt, loff_t * offp)
> +{
> + me4000_ao_context_t *ao_context = filep->private_data;
> + size_t i;
> + u32 value;
> + u32 tmp;
> + const u16 *buffer = (const u16 *)buff;
> + size_t count = cnt / 2;
> +
> + CALL_PDEBUG("me4000_ao_write_wrap() is executed\n");
> +
> + /* Check if a conversion is already running */
> + if (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) {
> + printk(KERN_ERR
> + "ME4000:me4000_ao_write_wrap():There is already a conversion running\n");
> + return -EBUSY;
> + }
> +
> + if (count > ME4000_AO_FIFO_COUNT) {
> + printk(KERN_ERR
> + "me4000_ao_write_wrap():Can't load more than %d values\n",
> + ME4000_AO_FIFO_COUNT);
> + return -ENOSPC;
> + }
> +
> + /* Reset the FIFO */
> + tmp = inl(ao_context->ctrl_reg);
> + tmp &= ~ME4000_AO_CTRL_BIT_ENABLE_FIFO;
> + outl(tmp, ao_context->ctrl_reg);
> + tmp |= ME4000_AO_CTRL_BIT_ENABLE_FIFO;
> + outl(tmp, ao_context->ctrl_reg);
> +
> + for (i = 0; i < count; i++) {
> + if (get_user(value, buffer + i)) {
> + printk(KERN_ERR
> + "me4000_ao_write_single():Cannot copy data from user\n");
> + return -EFAULT;
> + }
> + if (((ao_context->fifo_reg & 0xFF) == ME4000_AO_01_FIFO_REG)
> + || ((ao_context->fifo_reg & 0xFF) == ME4000_AO_03_FIFO_REG))
> + value = value << 16;
> + outl(value, ao_context->fifo_reg);
> + }
> + CALL_PDEBUG("me4000_ao_write_wrap() is leaved with %d\n", i * 2);
> +
> + return i * 2;
> +}
> +
> +static ssize_t me4000_ao_write_cont(struct file *filep, const char *buff,
> + size_t cnt, loff_t * offp)
> +{
> + me4000_ao_context_t *ao_context = filep->private_data;
> + const u16 *buffer = (const u16 *)buff;
> + size_t count = cnt / 2;
> + unsigned long flags;
> + u32 tmp;
> + int c = 0;
> + int k = 0;
> + int ret = 0;
> + u16 svalue;
> + u32 lvalue;
> + int i;
> + wait_queue_head_t queue;
> +
> + CALL_PDEBUG("me4000_ao_write_cont() is executed\n");
> +
> + init_waitqueue_head(&queue);
> +
> + /* Check count */
> + if (count <= 0) {
> + PDEBUG("me4000_ao_write_cont():Count is 0\n");
> + return 0;
> + }
> +
> + if (filep->f_flags & O_APPEND) {
> + PDEBUG("me4000_ao_write_cont():Append data to data stream\n");
> + while (count > 0) {
> + if (filep->f_flags & O_NONBLOCK) {
> + if (ao_context->pipe_flag) {
> + printk(KERN_ERR
> + "ME4000:me4000_ao_write_cont():Broken pipe in nonblocking write\n");
> + return -EPIPE;
> + }
> + c = me4000_space_to_end(ao_context->circ_buf,
> + ME4000_AO_BUFFER_COUNT);
> + if (!c) {
> + PDEBUG
> + ("me4000_ao_write_cont():Returning from nonblocking write\n");
> + break;
> + }
> + } else {
> + wait_event_interruptible(ao_context->wait_queue,
> + (c =
> + me4000_space_to_end
> + (ao_context->circ_buf,
> + ME4000_AO_BUFFER_COUNT)));
> + if (ao_context->pipe_flag) {
> + printk(KERN_ERR
> + "me4000_ao_write_cont():Broken pipe in blocking write\n");
> + return -EPIPE;
> + }
> + if (signal_pending(current)) {
> + printk(KERN_ERR
> + "me4000_ao_write_cont():Wait for free buffer interrupted from signal\n");
> + return -EINTR;
> + }
> + }
> +
> + PDEBUG("me4000_ao_write_cont():Space to end = %d\n", c);
> +
> + /* Only able to write size of free buffer or size of count */
> + if (count < c)
> + c = count;
> +
> + k = 2 * c;
> + k -= copy_from_user(ao_context->circ_buf.buf +
> + ao_context->circ_buf.head, buffer,
> + k);
> + c = k / 2;
> + PDEBUG
> + ("me4000_ao_write_cont():Copy %d values from user space\n",
> + c);
> +
> + if (!c)
> + return -EFAULT;
> +
> + ao_context->circ_buf.head =
> + (ao_context->circ_buf.head +
> + c) & (ME4000_AO_BUFFER_COUNT - 1);
> + buffer += c;
> + count -= c;
> + ret += c;
> +
> + /* Values are now available so enable interrupts */
> + spin_lock_irqsave(&ao_context->int_lock, flags);
> + if (me4000_buf_count
> + (ao_context->circ_buf, ME4000_AO_BUFFER_COUNT)) {
> + tmp = me4000_inl(ao_context->ctrl_reg);
> + tmp |= ME4000_AO_CTRL_BIT_ENABLE_IRQ;
> + me4000_outl(tmp, ao_context->ctrl_reg);
> + }
> + spin_unlock_irqrestore(&ao_context->int_lock, flags);
> + }
> +
> + /* Wait until the state machine is stopped if O_SYNC is set */
> + if (filep->f_flags & O_SYNC) {
> + while (inl(ao_context->status_reg) &
> + ME4000_AO_STATUS_BIT_FSM) {
> + interruptible_sleep_on_timeout(&queue, 1);
> + if (ao_context->pipe_flag) {
> + PDEBUG
> + ("me4000_ao_write_cont():Broken pipe detected after sync\n");
> + return -EPIPE;
> + }
> + if (signal_pending(current)) {
> + printk(KERN_ERR
> + "me4000_ao_write_cont():Wait on state machine after sync interrupted\n");
> + return -EINTR;
> + }
> + }
> + }
> + } else {
> + PDEBUG("me4000_ao_write_cont():Preload DAC FIFO\n");
> + if ((me4000_inl(ao_context->status_reg) &
> + ME4000_AO_STATUS_BIT_FSM)) {
> + printk(KERN_ERR
> + "me4000_ao_write_cont():Can't Preload DAC FIFO while conversion is running\n");
> + return -EBUSY;
> + }
> +
> + /* Clear the FIFO */
> + spin_lock_irqsave(&ao_context->int_lock, flags);
> + tmp = me4000_inl(ao_context->ctrl_reg);
> + tmp &=
> + ~(ME4000_AO_CTRL_BIT_ENABLE_FIFO |
> + ME4000_AO_CTRL_BIT_ENABLE_IRQ);
> + me4000_outl(tmp, ao_context->ctrl_reg);
> + tmp |= ME4000_AO_CTRL_BIT_ENABLE_FIFO;
> + me4000_outl(tmp, ao_context->ctrl_reg);
> + spin_unlock_irqrestore(&ao_context->int_lock, flags);
> +
> + /* Clear the circular buffer */
> + ao_context->circ_buf.head = 0;
> + ao_context->circ_buf.tail = 0;
> +
> + /* Reset the broken pipe flag */
> + ao_context->pipe_flag = 0;
> +
> + /* Only able to write size of fifo or count */
> + c = ME4000_AO_FIFO_COUNT;
> + if (count < c)
> + c = count;
> +
> + PDEBUG
> + ("me4000_ao_write_cont():Write %d values to DAC on 0x%lX\n",
> + c, ao_context->fifo_reg);
> +
> + /* Write values to the fifo */
> + for (i = 0; i < c; i++) {
> + if (get_user(svalue, buffer))
> + return -EFAULT;
> +
> + if (((ao_context->fifo_reg & 0xFF) ==
> + ME4000_AO_01_FIFO_REG)
> + || ((ao_context->fifo_reg & 0xFF) ==
> + ME4000_AO_03_FIFO_REG)) {
> + lvalue = ((u32) svalue) << 16;
> + } else
> + lvalue = (u32) svalue;
> +
> + outl(lvalue, ao_context->fifo_reg);
> + buffer++;
> + }
> + count -= c;
> + ret += c;
> +
> + while (1) {
> + /* Get free buffer */
> + c = me4000_space_to_end(ao_context->circ_buf,
> + ME4000_AO_BUFFER_COUNT);
> +
> + if (c == 0)
> + return (2 * ret);
> +
> + /* Only able to write size of free buffer or size of count */
> + if (count < c)
> + c = count;
> +
> + /* If count = 0 return to user */
> + if (c <= 0) {
> + PDEBUG
> + ("me4000_ao_write_cont():Count reached 0\n");
> + break;
> + }
> +
> + k = 2 * c;
> + k -= copy_from_user(ao_context->circ_buf.buf +
> + ao_context->circ_buf.head, buffer,
> + k);
> + c = k / 2;
> + PDEBUG
> + ("me4000_ao_write_cont():Wrote %d values to buffer\n",
> + c);
> +
> + if (!c)
> + return -EFAULT;
> +
> + ao_context->circ_buf.head =
> + (ao_context->circ_buf.head +
> + c) & (ME4000_AO_BUFFER_COUNT - 1);
> + buffer += c;
> + count -= c;
> + ret += c;
> +
> + /* If values in the buffer are available so enable interrupts */
> + spin_lock_irqsave(&ao_context->int_lock, flags);
> + if (me4000_buf_count
> + (ao_context->circ_buf, ME4000_AO_BUFFER_COUNT)) {
> + PDEBUG
> + ("me4000_ao_write_cont():Enable Interrupts\n");
> + tmp = me4000_inl(ao_context->ctrl_reg);
> + tmp |= ME4000_AO_CTRL_BIT_ENABLE_IRQ;
> + me4000_outl(tmp, ao_context->ctrl_reg);
> + }
> + spin_unlock_irqrestore(&ao_context->int_lock, flags);
> + }
> + }
> +
> + if (filep->f_flags & O_NONBLOCK) {
> + return (ret == 0) ? -EAGAIN : 2 * ret;
> + }
> +
> + return 2 * ret;
> +}
> +
> +static unsigned int me4000_ao_poll_cont(struct file *file_p, poll_table * wait)
> +{
> + me4000_ao_context_t *ao_context;
> + unsigned long mask = 0;
> +
> + CALL_PDEBUG("me4000_ao_poll_cont() is executed\n");
> +
> + ao_context = file_p->private_data;
> +
> + poll_wait(file_p, &ao_context->wait_queue, wait);
> +
> + /* Get free buffer */
> + if (me4000_space_to_end(ao_context->circ_buf, ME4000_AO_BUFFER_COUNT))
> + mask |= POLLOUT | POLLWRNORM;
> +
> + CALL_PDEBUG("me4000_ao_poll_cont():Return mask %lX\n", mask);
> +
> + return mask;
> +}
> +
> +static int me4000_ao_fsync_cont(struct file *file_p, struct dentry *dentry_p,
> + int datasync)
> +{
> + me4000_ao_context_t *ao_context;
> + wait_queue_head_t queue;
> +
> + CALL_PDEBUG("me4000_ao_fsync_cont() is executed\n");
> +
> + ao_context = file_p->private_data;
> + init_waitqueue_head(&queue);
> +
> + while (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) {
> + interruptible_sleep_on_timeout(&queue, 1);
remove all sleep_on()s
> + if (ao_context->pipe_flag) {
> + printk(KERN_ERR
> + "me4000_ao_fsync_cont():Broken pipe detected\n");
> + return -EPIPE;
> + }
> +
> + if (signal_pending(current)) {
> + printk(KERN_ERR
> + "me4000_ao_fsync_cont():Wait on state machine interrupted\n");
> + return -EINTR;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int me4000_ao_ioctl_sing(struct inode *inode_p, struct file *file_p,
> + unsigned int service, unsigned long arg)
> +{
> + me4000_ao_context_t *ao_context;
> +
> + CALL_PDEBUG("me4000_ao_ioctl_sing() is executed\n");
> +
> + ao_context = file_p->private_data;
> +
> + if (_IOC_TYPE(service) != ME4000_MAGIC) {
> + return -ENOTTY;
> + PDEBUG("me4000_ao_ioctl_sing():Wrong magic number\n");
> + }
> +
> + switch (service) {
> + case ME4000_AO_EX_TRIG_SETUP:
> + return me4000_ao_ex_trig_set_edge((int *)arg, ao_context);
> + case ME4000_AO_EX_TRIG_ENABLE:
> + return me4000_ao_ex_trig_enable(ao_context);
> + case ME4000_AO_EX_TRIG_DISABLE:
> + return me4000_ao_ex_trig_disable(ao_context);
> + case ME4000_AO_PRELOAD:
> + return me4000_ao_preload(ao_context);
> + case ME4000_AO_PRELOAD_UPDATE:
> + return me4000_ao_preload_update(ao_context);
> + case ME4000_GET_USER_INFO:
> + return me4000_get_user_info((me4000_user_info_t *) arg,
> + ao_context->board_info);
> + case ME4000_AO_SIMULTANEOUS_EX_TRIG:
> + return me4000_ao_simultaneous_ex_trig(ao_context);
> + case ME4000_AO_SIMULTANEOUS_SW:
> + return me4000_ao_simultaneous_sw(ao_context);
> + case ME4000_AO_SIMULTANEOUS_DISABLE:
> + return me4000_ao_simultaneous_disable(ao_context);
> + case ME4000_AO_SIMULTANEOUS_UPDATE:
> + return
> + me4000_ao_simultaneous_update((me4000_ao_channel_list_t *)
> + arg, ao_context);
> + case ME4000_AO_EX_TRIG_TIMEOUT:
> + return me4000_ao_ex_trig_timeout((unsigned long *)arg,
> + ao_context);
> + case ME4000_AO_DISABLE_DO:
> + return me4000_ao_disable_do(ao_context);
> + default:
> + printk(KERN_ERR
> + "me4000_ao_ioctl_sing():Service number invalid\n");
> + return -ENOTTY;
> + }
> +
> + return 0;
> +}
> +
> +static int me4000_ao_ioctl_wrap(struct inode *inode_p, struct file *file_p,
> + unsigned int service, unsigned long arg)
> +{
> + me4000_ao_context_t *ao_context;
> +
> + CALL_PDEBUG("me4000_ao_ioctl_wrap() is executed\n");
> +
> + ao_context = file_p->private_data;
> +
> + if (_IOC_TYPE(service) != ME4000_MAGIC) {
> + return -ENOTTY;
> + PDEBUG("me4000_ao_ioctl_wrap():Wrong magic number\n");
> + }
> +
> + switch (service) {
> + case ME4000_AO_START:
> + return me4000_ao_start((unsigned long *)arg, ao_context);
> + case ME4000_AO_STOP:
> + return me4000_ao_stop(ao_context);
> + case ME4000_AO_IMMEDIATE_STOP:
> + return me4000_ao_immediate_stop(ao_context);
> + case ME4000_AO_RESET:
> + return me4000_ao_reset(ao_context);
> + case ME4000_AO_TIMER_SET_DIVISOR:
> + return me4000_ao_timer_set_divisor((u32 *) arg, ao_context);
> + case ME4000_AO_EX_TRIG_SETUP:
> + return me4000_ao_ex_trig_set_edge((int *)arg, ao_context);
> + case ME4000_AO_EX_TRIG_ENABLE:
> + return me4000_ao_ex_trig_enable(ao_context);
> + case ME4000_AO_EX_TRIG_DISABLE:
> + return me4000_ao_ex_trig_disable(ao_context);
> + case ME4000_GET_USER_INFO:
> + return me4000_get_user_info((me4000_user_info_t *) arg,
> + ao_context->board_info);
> + case ME4000_AO_FSM_STATE:
> + return me4000_ao_fsm_state((int *)arg, ao_context);
> + case ME4000_AO_ENABLE_DO:
> + return me4000_ao_enable_do(ao_context);
> + case ME4000_AO_DISABLE_DO:
> + return me4000_ao_disable_do(ao_context);
> + case ME4000_AO_SYNCHRONOUS_EX_TRIG:
> + return me4000_ao_synchronous_ex_trig(ao_context);
> + case ME4000_AO_SYNCHRONOUS_SW:
> + return me4000_ao_synchronous_sw(ao_context);
> + case ME4000_AO_SYNCHRONOUS_DISABLE:
> + return me4000_ao_synchronous_disable(ao_context);
> + default:
> + return -ENOTTY;
> + }
> + return 0;
> +}
> +
> +static int me4000_ao_ioctl_cont(struct inode *inode_p, struct file *file_p,
> + unsigned int service, unsigned long arg)
> +{
> + me4000_ao_context_t *ao_context;
> +
> + CALL_PDEBUG("me4000_ao_ioctl_cont() is executed\n");
> +
> + ao_context = file_p->private_data;
> +
> + if (_IOC_TYPE(service) != ME4000_MAGIC) {
> + return -ENOTTY;
> + PDEBUG("me4000_ao_ioctl_cont():Wrong magic number\n");
> + }
> +
> + switch (service) {
> + case ME4000_AO_START:
> + return me4000_ao_start((unsigned long *)arg, ao_context);
> + case ME4000_AO_STOP:
> + return me4000_ao_stop(ao_context);
> + case ME4000_AO_IMMEDIATE_STOP:
> + return me4000_ao_immediate_stop(ao_context);
> + case ME4000_AO_RESET:
> + return me4000_ao_reset(ao_context);
> + case ME4000_AO_TIMER_SET_DIVISOR:
> + return me4000_ao_timer_set_divisor((u32 *) arg, ao_context);
> + case ME4000_AO_EX_TRIG_SETUP:
> + return me4000_ao_ex_trig_set_edge((int *)arg, ao_context);
> + case ME4000_AO_EX_TRIG_ENABLE:
> + return me4000_ao_ex_trig_enable(ao_context);
> + case ME4000_AO_EX_TRIG_DISABLE:
> + return me4000_ao_ex_trig_disable(ao_context);
> + case ME4000_AO_ENABLE_DO:
> + return me4000_ao_enable_do(ao_context);
> + case ME4000_AO_DISABLE_DO:
> + return me4000_ao_disable_do(ao_context);
> + case ME4000_AO_FSM_STATE:
> + return me4000_ao_fsm_state((int *)arg, ao_context);
> + case ME4000_GET_USER_INFO:
> + return me4000_get_user_info((me4000_user_info_t *) arg,
> + ao_context->board_info);
> + case ME4000_AO_SYNCHRONOUS_EX_TRIG:
> + return me4000_ao_synchronous_ex_trig(ao_context);
> + case ME4000_AO_SYNCHRONOUS_SW:
> + return me4000_ao_synchronous_sw(ao_context);
> + case ME4000_AO_SYNCHRONOUS_DISABLE:
> + return me4000_ao_synchronous_disable(ao_context);
> + case ME4000_AO_GET_FREE_BUFFER:
> + return me4000_ao_get_free_buffer((unsigned long *)arg,
> + ao_context);
> + default:
> + return -ENOTTY;
> + }
> + return 0;
> +}
> +
> +static int me4000_ao_start(unsigned long *arg, me4000_ao_context_t * ao_context)
> +{
> + u32 tmp;
> + wait_queue_head_t queue;
> + unsigned long ref;
> + unsigned long timeout;
> + unsigned long flags;
> +
> + CALL_PDEBUG("me4000_ao_start() is executed\n");
> +
> + if (get_user(timeout, arg)) {
?
> + printk(KERN_ERR
> + "me4000_ao_start():Cannot copy data from user\n");
> + return -EFAULT;
> + }
> +
> + init_waitqueue_head(&queue);
> +
> + spin_lock_irqsave(&ao_context->int_lock, flags);
> + tmp = inl(ao_context->ctrl_reg);
> + tmp &= ~(ME4000_AO_CTRL_BIT_STOP | ME4000_AO_CTRL_BIT_IMMEDIATE_STOP);
> + me4000_outl(tmp, ao_context->ctrl_reg);
> + spin_unlock_irqrestore(&ao_context->int_lock, flags);
> +
> + if ((tmp & ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG)) {
> + if (timeout) {
> + ref = jiffies;
> + while (!
> + (inl(ao_context->status_reg) &
> + ME4000_AO_STATUS_BIT_FSM)) {
> + interruptible_sleep_on_timeout(&queue, 1);
> + if (signal_pending(current)) {
> + printk(KERN_ERR
> + "ME4000:me4000_ao_start():Wait on start of state machine interrupted\n");
> + return -EINTR;
> + }
> + if (((jiffies - ref) > (timeout * HZ / USER_HZ))) { // 2.6 has diffrent definitions for HZ in user and kernel space
> + printk(KERN_ERR
> + "ME4000:me4000_ao_start():Timeout reached\n");
> + return -EIO;
> + }
> + }
> + }
> + } else {
> + me4000_outl(0x8000, ao_context->single_reg);
> + }
> +
> + return 0;
> +}
> +
> +static int me4000_ao_stop(me4000_ao_context_t * ao_context)
> +{
> + u32 tmp;
> + wait_queue_head_t queue;
> + unsigned long flags;
> +
> + init_waitqueue_head(&queue);
> +
> + CALL_PDEBUG("me4000_ao_stop() is executed\n");
> +
> + /* Set the stop bit */
> + spin_lock_irqsave(&ao_context->int_lock, flags);
> + tmp = inl(ao_context->ctrl_reg);
> + tmp |= ME4000_AO_CTRL_BIT_STOP;
> + me4000_outl(tmp, ao_context->ctrl_reg);
> + spin_unlock_irqrestore(&ao_context->int_lock, flags);
> +
> + while (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) {
> + interruptible_sleep_on_timeout(&queue, 1);
> + if (signal_pending(current)) {
> + printk(KERN_ERR
> + "me4000_ao_stop():Wait on state machine after stop interrupted\n");
> + return -EINTR;
> + }
> + }
> +
> + /* Clear the stop bit */
> + //tmp &= ~ME4000_AO_CTRL_BIT_STOP;
> + //me4000_outl(tmp, ao_context->ctrl_reg);
> +
> + return 0;
> +}
> +
> +static int me4000_ao_immediate_stop(me4000_ao_context_t * ao_context)
> +{
> + u32 tmp;
> + wait_queue_head_t queue;
> + unsigned long flags;
> +
> + init_waitqueue_head(&queue);
> +
> + CALL_PDEBUG("me4000_ao_immediate_stop() is executed\n");
> +
> + spin_lock_irqsave(&ao_context->int_lock, flags);
> + tmp = inl(ao_context->ctrl_reg);
> + tmp |= ME4000_AO_CTRL_BIT_STOP | ME4000_AO_CTRL_BIT_IMMEDIATE_STOP;
> + me4000_outl(tmp, ao_context->ctrl_reg);
> + spin_unlock_irqrestore(&ao_context->int_lock, flags);
> +
> + while (inl(ao_context->status_reg) & ME4000_AO_STATUS_BIT_FSM) {
> + interruptible_sleep_on_timeout(&queue, 1);
> + if (signal_pending(current)) {
> + printk(KERN_ERR
> + "me4000_ao_immediate_stop():Wait on state machine after stop interrupted\n");
> + return -EINTR;
> + }
> + }
> +
> + /* Clear the stop bits */
> + //tmp &= ~(ME4000_AO_CTRL_BIT_STOP | ME4000_AO_CTRL_BIT_IMMEDIATE_STOP);
> + //me4000_outl(tmp, ao_context->ctrl_reg);
> +
> + return 0;
> +}
> +
> +static int me4000_ao_timer_set_divisor(u32 * arg,
> + me4000_ao_context_t * ao_context)
> +{
> + u32 divisor;
> + u32 tmp;
> +
> + CALL_PDEBUG("me4000_ao_timer set_divisor() is executed\n");
> +
> + if (get_user(divisor, arg))
> + return -EFAULT;
> +
> + /* Check if the state machine is stopped */
> + tmp = me4000_inl(ao_context->status_reg);
> + if (tmp & ME4000_AO_STATUS_BIT_FSM) {
> + printk(KERN_ERR
> + "me4000_ao_timer_set_divisor():Can't set timer while DAC is running\n");
> + return -EBUSY;
> + }
> +
> + PDEBUG("me4000_ao_timer set_divisor():Divisor from user = %d\n",
> + divisor);
> +
> + /* Check if the divisor is right. ME4000_AO_MIN_TICKS is the lowest */
> + if (divisor < ME4000_AO_MIN_TICKS) {
> + printk(KERN_ERR
> + "ME4000:me4000_ao_timer set_divisor():Divisor to low\n");
> + return -EINVAL;
> + }
> +
> + /* Fix bug in Firmware */
> + divisor -= 2;
> +
> + PDEBUG("me4000_ao_timer set_divisor():Divisor to HW = %d\n", divisor);
> +
> + /* Write the divisor */
> + me4000_outl(divisor, ao_context->timer_reg);
> +
> + return 0;
> +}
> +
> +static int me4000_ao_ex_trig_set_edge(int *arg,
> + me4000_ao_context_t * ao_context)
> +{
> + int mode;
> + u32 tmp;
> + unsigned long flags;
> +
> + CALL_PDEBUG("me4000_ao_ex_trig_set_edge() is executed\n");
> +
> + if (get_user(mode, arg))
> + return -EFAULT;
?
> + /* Check if the state machine is stopped */
> + tmp = me4000_inl(ao_context->status_reg);
> + if (tmp & ME4000_AO_STATUS_BIT_FSM) {
> + printk(KERN_ERR
> + "me4000_ao_ex_trig_set_edge():Can't set trigger while DAC is running\n");
> + return -EBUSY;
> + }
> +
> + if (mode == ME4000_AO_TRIGGER_EXT_EDGE_RISING) {
> + spin_lock_irqsave(&ao_context->int_lock, flags);
> + tmp = me4000_inl(ao_context->ctrl_reg);
> + tmp &=
> + ~(ME4000_AO_CTRL_BIT_EX_TRIG_EDGE |
> + ME4000_AO_CTRL_BIT_EX_TRIG_BOTH);
> + me4000_outl(tmp, ao_context->ctrl_reg);
> + spin_unlock_irqrestore(&ao_context->int_lock, flags);
> + } else if (mode == ME4000_AO_TRIGGER_EXT_EDGE_FALLING) {
> + spin_lock_irqsave(&ao_context->int_lock, flags);
> + tmp = me4000_inl(ao_context->ctrl_reg);
> + tmp &= ~ME4000_AO_CTRL_BIT_EX_TRIG_BOTH;
> + tmp |= ME4000_AO_CTRL_BIT_EX_TRIG_EDGE;
> + me4000_outl(tmp, ao_context->ctrl_reg);
> + spin_unlock_irqrestore(&ao_context->int_lock, flags);
> + } else if (mode == ME4000_AO_TRIGGER_EXT_EDGE_BOTH) {
> + spin_lock_irqsave(&ao_context->int_lock, flags);
> + tmp = me4000_inl(ao_context->ctrl_reg);
> + tmp |=
> + ME4000_AO_CTRL_BIT_EX_TRIG_EDGE |
> + ME4000_AO_CTRL_BIT_EX_TRIG_BOTH;
> + me4000_outl(tmp, ao_context->ctrl_reg);
> + spin_unlock_irqrestore(&ao_context->int_lock, flags);
> + } else {
> + printk(KERN_ERR
> + "me4000_ao_ex_trig_set_edge():Invalid trigger mode\n");
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static int me4000_ao_ex_trig_enable(me4000_ao_context_t * ao_context)
> +{
> + u32 tmp;
> + unsigned long flags;
> +
> + CALL_PDEBUG("me4000_ao_ex_trig_enable() is executed\n");
> +
> + /* Check if the state machine is stopped */
> + tmp = me4000_inl(ao_context->status_reg);
> + if (tmp & ME4000_AO_STATUS_BIT_FSM) {
> + printk(KERN_ERR
> + "me4000_ao_ex_trig_enable():Can't enable trigger while DAC is running\n");
> + return -EBUSY;
> + }
> +
> + spin_lock_irqsave(&ao_context->int_lock, flags);
> + tmp = me4000_inl(ao_context->ctrl_reg);
> + tmp |= ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG;
> + me4000_outl(tmp, ao_context->ctrl_reg);
> + spin_unlock_irqrestore(&ao_context->int_lock, flags);
> +
> + return 0;
> +}
> +
> +static int me4000_ao_ex_trig_disable(me4000_ao_context_t * ao_context)
> +{
> + u32 tmp;
> + unsigned long flags;
> +
> + CALL_PDEBUG("me4000_ao_ex_trig_disable() is executed\n");
> +
> + /* Check if the state machine is stopped */
> + tmp = me4000_inl(ao_context->status_reg);
> + if (tmp & ME4000_AO_STATUS_BIT_FSM) {
> + printk(KERN_ERR
> + "me4000_ao_ex_trig_disable():Can't disable trigger while DAC is running\n");
> + return -EBUSY;
> + }
> +
> + spin_lock_irqsave(&ao_context->int_lock, flags);
> + tmp = me4000_inl(ao_context->ctrl_reg);
> + tmp &= ~ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG;
> + me4000_outl(tmp, ao_context->ctrl_reg);
> + spin_unlock_irqrestore(&ao_context->int_lock, flags);
> +
> + return 0;
> +}
> +
> +static int me4000_ao_simultaneous_disable(me4000_ao_context_t * ao_context)
> +{
> + u32 tmp;
> +
> + CALL_PDEBUG("me4000_ao_simultaneous_disable() is executed\n");
> +
> + /* Check if the state machine is stopped */
> + /* Be careful here because this function is called from
> + me4000_ao_synchronous disable */
> + tmp = me4000_inl(ao_context->status_reg);
> + if (tmp & ME4000_AO_STATUS_BIT_FSM) {
> + printk(KERN_ERR
> + "me4000_ao_simultaneous_disable():Can't disable while DAC is running\n");
> + return -EBUSY;
> + }
> +
> + spin_lock(&ao_context->board_info->preload_lock);
> + tmp = me4000_inl(ao_context->preload_reg);
> + tmp &= ~(0x1 << ao_context->index); // Disable preload bit
> + tmp &= ~(0x1 << (ao_context->index + 16)); // Disable hw simultaneous bit
> + me4000_outl(tmp, ao_context->preload_reg);
> + spin_unlock(&ao_context->board_info->preload_lock);
> +
> + return 0;
> +}
> +
> +static int me4000_ao_simultaneous_ex_trig(me4000_ao_context_t * ao_context)
> +{
> + u32 tmp;
> +
> + CALL_PDEBUG("me4000_ao_simultaneous_ex_trig() is executed\n");
> +
> + spin_lock(&ao_context->board_info->preload_lock);
> + tmp = me4000_inl(ao_context->preload_reg);
> + tmp |= (0x1 << ao_context->index); // Enable preload bit
> + tmp |= (0x1 << (ao_context->index + 16)); // Enable hw simultaneous bit
> + me4000_outl(tmp, ao_context->preload_reg);
> + spin_unlock(&ao_context->board_info->preload_lock);
> +
> + return 0;
> +}
> +
> +static int me4000_ao_simultaneous_sw(me4000_ao_context_t * ao_context)
> +{
> + u32 tmp;
> +
> + CALL_PDEBUG("me4000_ao_simultaneous_sw() is executed\n");
> +
> + spin_lock(&ao_context->board_info->preload_lock);
> + tmp = me4000_inl(ao_context->preload_reg);
> + tmp |= (0x1 << ao_context->index); // Enable preload bit
> + tmp &= ~(0x1 << (ao_context->index + 16)); // Disable hw simultaneous bit
> + me4000_outl(tmp, ao_context->preload_reg);
> + spin_unlock(&ao_context->board_info->preload_lock);
> +
> + return 0;
> +}
> +
> +static int me4000_ao_preload(me4000_ao_context_t * ao_context)
> +{
> + CALL_PDEBUG("me4000_ao_preload() is executed\n");
> + return me4000_ao_simultaneous_sw(ao_context);
> +}
> +
> +static int me4000_ao_preload_update(me4000_ao_context_t * ao_context)
> +{
> + u32 tmp;
> + u32 ctrl;
> + struct list_head *entry;
> +
> + CALL_PDEBUG("me4000_ao_preload_update() is executed\n");
> +
> + spin_lock(&ao_context->board_info->preload_lock);
> + tmp = me4000_inl(ao_context->preload_reg);
> + list_for_each(entry, &ao_context->board_info->ao_context_list) {
> + /* The channels we update must be in the following state :
> + - Mode A
> + - Hardware trigger is disabled
> + - Corresponding simultaneous bit is reset
> + */
> + ctrl = me4000_inl(ao_context->ctrl_reg);
> + if (!
> + (ctrl &
> + (ME4000_AO_CTRL_BIT_MODE_0 | ME4000_AO_CTRL_BIT_MODE_1 |
> + ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG))) {
> + if (!
> + (tmp &
> + (0x1 <<
> + (((me4000_ao_context_t *) entry)->index + 16)))) {
> + tmp &=
> + ~(0x1 <<
> + (((me4000_ao_context_t *) entry)->index));
> + }
> + }
> + }
> + me4000_outl(tmp, ao_context->preload_reg);
> + spin_unlock(&ao_context->board_info->preload_lock);
> +
> + return 0;
> +}
> +
> +static int me4000_ao_simultaneous_update(me4000_ao_channel_list_t * arg,
> + me4000_ao_context_t * ao_context)
> +{
> + int err;
> + int i;
> + u32 tmp;
> + me4000_ao_channel_list_t channels;
> +
> + CALL_PDEBUG("me4000_ao_simultaneous_update() is executed\n");
> +
> + /* Copy data from user */
> + err = copy_from_user(&channels, arg, sizeof(me4000_ao_channel_list_t));
> + if (err) {
> + printk(KERN_ERR
> + "ME4000:me4000_ao_simultaneous_update():Can't copy command\n");
> + return -EFAULT;
> + }
> +
> + channels.list =
> + kmalloc(sizeof(unsigned long) * channels.count, GFP_KERNEL);
> + if (!channels.list) {
> + printk(KERN_ERR
> + "ME4000:me4000_ao_simultaneous_update():Can't get buffer\n");
> + return -ENOMEM;
> + }
> + memset(channels.list, 0, sizeof(unsigned long) * channels.count);
kzalloc
> + /* Copy channel list from user */
> + err =
> + copy_from_user(channels.list, arg->list,
> + sizeof(unsigned long) * channels.count);
> + if (err) {
> + printk(KERN_ERR
> + "ME4000:me4000_ao_simultaneous_update():Can't copy list\n");
> + kfree(channels.list);
> + return -EFAULT;
> + }
> +
> + spin_lock(&ao_context->board_info->preload_lock);
> + tmp = me4000_inl(ao_context->preload_reg);
> + for (i = 0; i < channels.count; i++) {
> + if (channels.list[i] >
> + ao_context->board_info->board_p->ao.count) {
> + spin_unlock(&ao_context->board_info->preload_lock);
> + kfree(channels.list);
> + printk(KERN_ERR
> + "ME4000:me4000_ao_simultaneous_update():Invalid board number specified\n");
> + return -EFAULT;
> + }
> + tmp &= ~(0x1 << channels.list[i]); // Clear the preload bit
> + tmp &= ~(0x1 << (channels.list[i] + 16)); // Clear the hw simultaneous bit
> + }
> + me4000_outl(tmp, ao_context->preload_reg);
> + spin_unlock(&ao_context->board_info->preload_lock);
> + kfree(channels.list);
> +
> + return 0;
> +}
> +
> +static int me4000_ao_synchronous_ex_trig(me4000_ao_context_t * ao_context)
> +{
> + u32 tmp;
> + unsigned long flags;
> +
> + CALL_PDEBUG("me4000_ao_synchronous_ex_trig() is executed\n");
> +
> + /* Check if the state machine is stopped */
> + tmp = me4000_inl(ao_context->status_reg);
> + if (tmp & ME4000_AO_STATUS_BIT_FSM) {
> + printk(KERN_ERR
> + "me4000_ao_synchronous_ex_trig(): DAC is running\n");
> + return -EBUSY;
> + }
> +
> + spin_lock(&ao_context->board_info->preload_lock);
> + tmp = me4000_inl(ao_context->preload_reg);
> + tmp &= ~(0x1 << ao_context->index); // Disable synchronous sw bit
> + tmp |= 0x1 << (ao_context->index + 16); // Enable synchronous hw bit
> + me4000_outl(tmp, ao_context->preload_reg);
> + spin_unlock(&ao_context->board_info->preload_lock);
> +
> + /* Make runnable */
> + spin_lock_irqsave(&ao_context->int_lock, flags);
> + tmp = me4000_inl(ao_context->ctrl_reg);
> + if (tmp & (ME4000_AO_CTRL_BIT_MODE_0 | ME4000_AO_CTRL_BIT_MODE_1)) {
> + tmp &=
> + ~(ME4000_AO_CTRL_BIT_STOP |
> + ME4000_AO_CTRL_BIT_IMMEDIATE_STOP);
> + me4000_outl(tmp, ao_context->ctrl_reg);
> + }
> + spin_unlock_irqrestore(&ao_context->int_lock, flags);
> +
> + return 0;
> +}
> +
> +static int me4000_ao_synchronous_sw(me4000_ao_context_t * ao_context)
> +{
> + u32 tmp;
> + unsigned long flags;
> +
> + CALL_PDEBUG("me4000_ao_synchronous_sw() is executed\n");
> +
> + /* Check if the state machine is stopped */
> + tmp = me4000_inl(ao_context->status_reg);
> + if (tmp & ME4000_AO_STATUS_BIT_FSM) {
> + printk(KERN_ERR "me4000_ao_synchronous_sw(): DAC is running\n");
> + return -EBUSY;
> + }
> +
> + spin_lock(&ao_context->board_info->preload_lock);
> + tmp = me4000_inl(ao_context->preload_reg);
> + tmp |= 0x1 << ao_context->index; // Enable synchronous sw bit
> + tmp &= ~(0x1 << (ao_context->index + 16)); // Disable synchronous hw bit
> + me4000_outl(tmp, ao_context->preload_reg);
> + spin_unlock(&ao_context->board_info->preload_lock);
> +
> + /* Make runnable */
> + spin_lock_irqsave(&ao_context->int_lock, flags);
> + tmp = me4000_inl(ao_context->ctrl_reg);
> + if (tmp & (ME4000_AO_CTRL_BIT_MODE_0 | ME4000_AO_CTRL_BIT_MODE_1)) {
> + tmp &=
> + ~(ME4000_AO_CTRL_BIT_STOP |
> + ME4000_AO_CTRL_BIT_IMMEDIATE_STOP);
> + me4000_outl(tmp, ao_context->ctrl_reg);
> + }
> + spin_unlock_irqrestore(&ao_context->int_lock, flags);
> +
> + return 0;
> +}
> +
> +static int me4000_ao_synchronous_disable(me4000_ao_context_t * ao_context)
> +{
> + return me4000_ao_simultaneous_disable(ao_context);
> +}
> +
> +static int me4000_ao_get_free_buffer(unsigned long *arg,
> + me4000_ao_context_t * ao_context)
> +{
> + unsigned long c;
> + int err;
> +
> + c = me4000_buf_space(ao_context->circ_buf, ME4000_AO_BUFFER_COUNT);
> +
> + err = copy_to_user(arg, &c, sizeof(unsigned long));
> + if (err) {
> + printk(KERN_ERR
> + "ME4000:me4000_ao_get_free_buffer():Can't copy to user space\n");
> + return -EFAULT;
> + }
> +
> + return 0;
> +}
> +
> +static int me4000_ao_ex_trig_timeout(unsigned long *arg,
> + me4000_ao_context_t * ao_context)
> +{
> + u32 tmp;
> + wait_queue_head_t queue;
> + unsigned long ref;
> + unsigned long timeout;
> +
> + CALL_PDEBUG("me4000_ao_ex_trig_timeout() is executed\n");
> +
> + if (get_user(timeout, arg)) {
> + printk(KERN_ERR
> + "me4000_ao_ex_trig_timeout():Cannot copy data from user\n");
> + return -EFAULT;
> + }
erm. Exactly what is the userspace interface which this driver is
implementing?
> +#define ME4000_BOARD_VERSIONS (sizeof(me4000_boards) / sizeof(me4000_board_t) - 1)
Kill this altogether, use open-coded ARRAY_SIZE
<can't take any more, stops there>
^ permalink raw reply [flat|nested] 37+ messages in thread
* [PATCH 10/23] Staging: add the go7007 video driver
2008-10-10 22:41 [GIT PATCH] STAGING patches for 2.6.28 Greg KH
` (5 preceding siblings ...)
2008-10-10 22:42 ` [PATCH 09/23] Staging: add me4000 pci data collection driver Greg KH
@ 2008-10-10 22:42 ` Greg KH
2008-10-10 22:42 ` [PATCH 11/23] Staging: USB/IP: add common functions needed Greg KH
` (12 subsequent siblings)
19 siblings, 0 replies; 37+ messages in thread
From: Greg KH @ 2008-10-10 22:42 UTC (permalink / raw)
To: linux-kernel; +Cc: Greg Kroah-Hartman, Ross Cohen
From: Greg Kroah-Hartman <gregkh@suse.de>
Todo:
- checkpatch.pl cleanups
- sparse cleanups
- lots of little modules, should be merged together
and added to the build.
- testing?
- handle churn in v4l layer.
Many thanks to Ross Cohen <rcohen@snurgle.org> for cleanup patches on
this driver.
Cc: Ross Cohen <rcohen@snurgle.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/Kconfig | 2 +
drivers/staging/Makefile | 1 +
drivers/staging/go7007/Kconfig | 25 +
drivers/staging/go7007/Makefile | 18 +
drivers/staging/go7007/README | 11 +
drivers/staging/go7007/go7007-driver.c | 688 +++++++++++++
drivers/staging/go7007/go7007-fw.c | 1639 +++++++++++++++++++++++++++++++
drivers/staging/go7007/go7007-i2c.c | 309 ++++++
drivers/staging/go7007/go7007-priv.h | 279 ++++++
drivers/staging/go7007/go7007-usb.c | 1229 +++++++++++++++++++++++
drivers/staging/go7007/go7007-v4l2.c | 1503 ++++++++++++++++++++++++++++
drivers/staging/go7007/go7007.h | 114 +++
drivers/staging/go7007/saa7134-go7007.c | 484 +++++++++
drivers/staging/go7007/snd-go7007.c | 305 ++++++
drivers/staging/go7007/wis-i2c.h | 55 +
drivers/staging/go7007/wis-ov7640.c | 131 +++
drivers/staging/go7007/wis-saa7113.c | 363 +++++++
drivers/staging/go7007/wis-saa7115.c | 492 +++++++++
drivers/staging/go7007/wis-sony-tuner.c | 741 ++++++++++++++
drivers/staging/go7007/wis-tw2804.c | 381 +++++++
drivers/staging/go7007/wis-tw9903.c | 363 +++++++
drivers/staging/go7007/wis-uda1342.c | 136 +++
22 files changed, 9269 insertions(+), 0 deletions(-)
create mode 100644 drivers/staging/go7007/Kconfig
create mode 100644 drivers/staging/go7007/Makefile
create mode 100644 drivers/staging/go7007/README
create mode 100644 drivers/staging/go7007/go7007-driver.c
create mode 100644 drivers/staging/go7007/go7007-fw.c
create mode 100644 drivers/staging/go7007/go7007-i2c.c
create mode 100644 drivers/staging/go7007/go7007-priv.h
create mode 100644 drivers/staging/go7007/go7007-usb.c
create mode 100644 drivers/staging/go7007/go7007-v4l2.c
create mode 100644 drivers/staging/go7007/go7007.h
create mode 100644 drivers/staging/go7007/saa7134-go7007.c
create mode 100644 drivers/staging/go7007/snd-go7007.c
create mode 100644 drivers/staging/go7007/wis-i2c.h
create mode 100644 drivers/staging/go7007/wis-ov7640.c
create mode 100644 drivers/staging/go7007/wis-saa7113.c
create mode 100644 drivers/staging/go7007/wis-saa7115.c
create mode 100644 drivers/staging/go7007/wis-sony-tuner.c
create mode 100644 drivers/staging/go7007/wis-tw2804.c
create mode 100644 drivers/staging/go7007/wis-tw9903.c
create mode 100644 drivers/staging/go7007/wis-uda1342.c
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 56c73bc..f16bc9c 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -31,4 +31,6 @@ source "drivers/staging/sxg/Kconfig"
source "drivers/staging/me4000/Kconfig"
+source "drivers/staging/go7007/Kconfig"
+
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 97df19b..aa61662 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -4,3 +4,4 @@ obj-$(CONFIG_ET131X) += et131x/
obj-$(CONFIG_SLICOSS) += slicoss/
obj-$(CONFIG_SXG) += sxg/
obj-$(CONFIG_ME4000) += me4000/
+obj-$(CONFIG_VIDEO_GO7007) += go7007/
diff --git a/drivers/staging/go7007/Kconfig b/drivers/staging/go7007/Kconfig
new file mode 100644
index 0000000..57a121c
--- /dev/null
+++ b/drivers/staging/go7007/Kconfig
@@ -0,0 +1,25 @@
+config VIDEO_GO7007
+ tristate "Go 7007 support"
+ depends on VIDEO_DEV && PCI && I2C && INPUT
+ select VIDEOBUF_DMA_SG
+ select VIDEO_IR
+ select VIDEO_TUNER
+ select VIDEO_TVEEPROM
+ select CRC32
+ default N
+ ---help---
+ This is a video4linux driver for some wierd device...
+
+ To compile this driver as a module, choose M here: the
+ module will be called go7007
+
+config VIDEO_GO7007_USB
+ tristate "Go 7007 USB support"
+ depends on VIDEO_GO7007 && USB
+ default N
+ ---help---
+ This is a video4linux driver for some wierd device...
+
+ To compile this driver as a module, choose M here: the
+ module will be called go7007-usb
+
diff --git a/drivers/staging/go7007/Makefile b/drivers/staging/go7007/Makefile
new file mode 100644
index 0000000..9b9310c
--- /dev/null
+++ b/drivers/staging/go7007/Makefile
@@ -0,0 +1,18 @@
+#obj-m += go7007.o go7007-usb.o snd-go7007.o wis-saa7115.o wis-tw9903.o \
+ wis-uda1342.o wis-sony-tuner.o wis-saa7113.o wis-ov7640.o \
+ wis-tw2804.o
+
+
+obj-$(CONFIG_VIDEO_GO7007) += go7007.o
+obj-$(CONFIG_VIDEO_GO7007_USB) += go7007-usb.o
+
+go7007-objs += go7007-v4l2.o go7007-driver.o go7007-i2c.o go7007-fw.o snd-go7007.o
+
+
+#ifneq ($(SAA7134_BUILD),)
+#obj-m += saa7134-go7007.o
+#endif
+
+EXTRA_CFLAGS += -Idrivers/staging/saa7134
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
diff --git a/drivers/staging/go7007/README b/drivers/staging/go7007/README
new file mode 100644
index 0000000..48f4476
--- /dev/null
+++ b/drivers/staging/go7007/README
@@ -0,0 +1,11 @@
+Todo:
+ - checkpatch.pl cleanups
+ - sparse cleanups
+ - lots of little modules, should be merged together
+ and added to the build.
+ - testing?
+ - handle churn in v4l layer.
+
+Please send patchs to Greg Kroah-Hartman <greg@kroah.com> and Cc: Ross
+Cohen <rcohen@snurgle.org> as well.
+
diff --git a/drivers/staging/go7007/go7007-driver.c b/drivers/staging/go7007/go7007-driver.c
new file mode 100644
index 0000000..5a336ff
--- /dev/null
+++ b/drivers/staging/go7007/go7007-driver.c
@@ -0,0 +1,688 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/unistd.h>
+#include <linux/time.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/firmware.h>
+#include <linux/semaphore.h>
+#include <linux/uaccess.h>
+#include <asm/system.h>
+#include <linux/videodev.h>
+#include <media/tuner.h>
+#include <media/v4l2-common.h>
+
+#include "go7007-priv.h"
+#include "wis-i2c.h"
+
+/*
+ * Wait for an interrupt to be delivered from the GO7007SB and return
+ * the associated value and data.
+ *
+ * Must be called with the hw_lock held.
+ */
+int go7007_read_interrupt(struct go7007 *go, u16 *value, u16 *data)
+{
+ go->interrupt_available = 0;
+ go->hpi_ops->read_interrupt(go);
+ if (wait_event_timeout(go->interrupt_waitq,
+ go->interrupt_available, 5*HZ) < 0) {
+ printk(KERN_ERR "go7007: timeout waiting for read interrupt\n");
+ return -1;
+ }
+ if (!go->interrupt_available)
+ return -1;
+ go->interrupt_available = 0;
+ *value = go->interrupt_value & 0xfffe;
+ *data = go->interrupt_data;
+ return 0;
+}
+EXPORT_SYMBOL(go7007_read_interrupt);
+
+/*
+ * Read a register/address on the GO7007SB.
+ *
+ * Must be called with the hw_lock held.
+ */
+int go7007_read_addr(struct go7007 *go, u16 addr, u16 *data)
+{
+ int count = 100;
+ u16 value;
+
+ if (go7007_write_interrupt(go, 0x0010, addr) < 0)
+ return -EIO;
+ while (count-- > 0) {
+ if (go7007_read_interrupt(go, &value, data) == 0 &&
+ value == 0xa000)
+ return 0;
+ }
+ return -EIO;
+}
+EXPORT_SYMBOL(go7007_read_addr);
+
+/*
+ * Send the boot firmware to the encoder, which just wakes it up and lets
+ * us talk to the GPIO pins and on-board I2C adapter.
+ *
+ * Must be called with the hw_lock held.
+ */
+static int go7007_load_encoder(struct go7007 *go)
+{
+ const struct firmware *fw_entry;
+ char fw_name[] = "go7007fw.bin";
+ void *bounce;
+ int fw_len, rv = 0;
+ u16 intr_val, intr_data;
+
+ if (request_firmware(&fw_entry, fw_name, go->dev)) {
+ printk(KERN_ERR
+ "go7007: unable to load firmware from file \"%s\"\n",
+ fw_name);
+ return -1;
+ }
+ if (fw_entry->size < 16 || memcmp(fw_entry->data, "WISGO7007FW", 11)) {
+ printk(KERN_ERR "go7007: file \"%s\" does not appear to be "
+ "go7007 firmware\n", fw_name);
+ release_firmware(fw_entry);
+ return -1;
+ }
+ fw_len = fw_entry->size - 16;
+ bounce = kmalloc(fw_len, GFP_KERNEL);
+ if (bounce == NULL) {
+ printk(KERN_ERR "go7007: unable to allocate %d bytes for "
+ "firmware transfer\n", fw_len);
+ release_firmware(fw_entry);
+ return -1;
+ }
+ memcpy(bounce, fw_entry->data + 16, fw_len);
+ release_firmware(fw_entry);
+ if (go7007_interface_reset(go) < 0 ||
+ go7007_send_firmware(go, bounce, fw_len) < 0 ||
+ go7007_read_interrupt(go, &intr_val, &intr_data) < 0 ||
+ (intr_val & ~0x1) != 0x5a5a) {
+ printk(KERN_ERR "go7007: error transferring firmware\n");
+ rv = -1;
+ }
+ kfree(bounce);
+ return rv;
+}
+
+/*
+ * Boot the encoder and register the I2C adapter if requested. Do the
+ * minimum initialization necessary, since the board-specific code may
+ * still need to probe the board ID.
+ *
+ * Must NOT be called with the hw_lock held.
+ */
+int go7007_boot_encoder(struct go7007 *go, int init_i2c)
+{
+ int ret;
+
+ down(&go->hw_lock);
+ ret = go7007_load_encoder(go);
+ up(&go->hw_lock);
+ if (ret < 0)
+ return -1;
+ if (!init_i2c)
+ return 0;
+ if (go7007_i2c_init(go) < 0)
+ return -1;
+ go->i2c_adapter_online = 1;
+ return 0;
+}
+EXPORT_SYMBOL(go7007_boot_encoder);
+
+/*
+ * Configure any hardware-related registers in the GO7007, such as GPIO
+ * pins and bus parameters, which are board-specific. This assumes
+ * the boot firmware has already been downloaded.
+ *
+ * Must be called with the hw_lock held.
+ */
+static int go7007_init_encoder(struct go7007 *go)
+{
+ if (go->board_info->audio_flags & GO7007_AUDIO_I2S_MASTER) {
+ go7007_write_addr(go, 0x1000, 0x0811);
+ go7007_write_addr(go, 0x1000, 0x0c11);
+ }
+ if (go->board_id == GO7007_BOARDID_MATRIX_REV) {
+ /* Set GPIO pin 0 to be an output (audio clock control) */
+ go7007_write_addr(go, 0x3c82, 0x0001);
+ go7007_write_addr(go, 0x3c80, 0x00fe);
+ }
+ return 0;
+}
+
+/*
+ * Send the boot firmware to the GO7007 and configure the registers. This
+ * is the only way to stop the encoder once it has started streaming video.
+ *
+ * Must be called with the hw_lock held.
+ */
+int go7007_reset_encoder(struct go7007 *go)
+{
+ if (go7007_load_encoder(go) < 0)
+ return -1;
+ return go7007_init_encoder(go);
+}
+
+/*
+ * Attempt to instantiate an I2C client by ID, probably loading a module.
+ */
+static int init_i2c_module(struct i2c_adapter *adapter, int id, int addr)
+{
+ char *modname;
+
+ switch (id) {
+ case I2C_DRIVERID_WIS_SAA7115:
+ modname = "wis-saa7115";
+ break;
+ case I2C_DRIVERID_WIS_SAA7113:
+ modname = "wis-saa7113";
+ break;
+ case I2C_DRIVERID_WIS_UDA1342:
+ modname = "wis-uda1342";
+ break;
+ case I2C_DRIVERID_WIS_SONY_TUNER:
+ modname = "wis-sony-tuner";
+ break;
+ case I2C_DRIVERID_WIS_TW9903:
+ modname = "wis-tw9903";
+ break;
+ case I2C_DRIVERID_WIS_TW2804:
+ modname = "wis-tw2804";
+ break;
+ case I2C_DRIVERID_WIS_OV7640:
+ modname = "wis-ov7640";
+ break;
+ default:
+ modname = NULL;
+ break;
+ }
+ if (modname != NULL)
+ request_module(modname);
+ if (wis_i2c_probe_device(adapter, id, addr) == 1)
+ return 0;
+ if (modname != NULL)
+ printk(KERN_INFO
+ "go7007: probing for module %s failed", modname);
+ else
+ printk(KERN_INFO
+ "go7007: sensor %u seems to be unsupported!\n", id);
+ return -1;
+}
+
+/*
+ * Finalize the GO7007 hardware setup, register the on-board I2C adapter
+ * (if used on this board), load the I2C client driver for the sensor
+ * (SAA7115 or whatever) and other devices, and register the ALSA and V4L2
+ * interfaces.
+ *
+ * Must NOT be called with the hw_lock held.
+ */
+int go7007_register_encoder(struct go7007 *go)
+{
+ int i, ret;
+
+ printk(KERN_INFO "go7007: registering new %s\n", go->name);
+
+ down(&go->hw_lock);
+ ret = go7007_init_encoder(go);
+ up(&go->hw_lock);
+ if (ret < 0)
+ return -1;
+
+ if (!go->i2c_adapter_online &&
+ go->board_info->flags & GO7007_BOARD_USE_ONBOARD_I2C) {
+ if (go7007_i2c_init(go) < 0)
+ return -1;
+ go->i2c_adapter_online = 1;
+ }
+ if (go->i2c_adapter_online) {
+ for (i = 0; i < go->board_info->num_i2c_devs; ++i)
+ init_i2c_module(&go->i2c_adapter,
+ go->board_info->i2c_devs[i].id,
+ go->board_info->i2c_devs[i].addr);
+#ifdef TUNER_SET_TYPE_ADDR
+ if (go->tuner_type >= 0) {
+ struct tuner_setup tun_setup = {
+ .mode_mask = T_ANALOG_TV,
+ .addr = ADDR_UNSET,
+ .type = go->tuner_type
+ };
+ i2c_clients_command(&go->i2c_adapter,
+ TUNER_SET_TYPE_ADDR, &tun_setup);
+ }
+#else
+ if (go->tuner_type >= 0)
+ i2c_clients_command(&go->i2c_adapter,
+ TUNER_SET_TYPE, &go->tuner_type);
+#endif
+ if (go->board_id == GO7007_BOARDID_ADLINK_MPG24)
+ i2c_clients_command(&go->i2c_adapter,
+ DECODER_SET_CHANNEL, &go->channel_number);
+ }
+ if (go->board_info->flags & GO7007_BOARD_HAS_AUDIO) {
+ go->audio_enabled = 1;
+ go7007_snd_init(go);
+ }
+ return go7007_v4l2_init(go);
+}
+EXPORT_SYMBOL(go7007_register_encoder);
+
+/*
+ * Send the encode firmware to the encoder, which will cause it
+ * to immediately start delivering the video and audio streams.
+ *
+ * Must be called with the hw_lock held.
+ */
+int go7007_start_encoder(struct go7007 *go)
+{
+ u8 *fw;
+ int fw_len, rv = 0, i;
+ u16 intr_val, intr_data;
+
+ go->modet_enable = 0;
+ if (!go->dvd_mode)
+ for (i = 0; i < 4; ++i) {
+ if (go->modet[i].enable) {
+ go->modet_enable = 1;
+ continue;
+ }
+ go->modet[i].pixel_threshold = 32767;
+ go->modet[i].motion_threshold = 32767;
+ go->modet[i].mb_threshold = 32767;
+ }
+
+ if (go7007_construct_fw_image(go, &fw, &fw_len) < 0)
+ return -1;
+
+ if (go7007_send_firmware(go, fw, fw_len) < 0 ||
+ go7007_read_interrupt(go, &intr_val, &intr_data) < 0) {
+ printk(KERN_ERR "go7007: error transferring firmware\n");
+ rv = -1;
+ goto start_error;
+ }
+
+ go->state = STATE_DATA;
+ go->parse_length = 0;
+ go->seen_frame = 0;
+ if (go7007_stream_start(go) < 0) {
+ printk(KERN_ERR "go7007: error starting stream transfer\n");
+ rv = -1;
+ goto start_error;
+ }
+
+start_error:
+ kfree(fw);
+ return rv;
+}
+
+/*
+ * Store a byte in the current video buffer, if there is one.
+ */
+static inline void store_byte(struct go7007_buffer *gobuf, u8 byte)
+{
+ if (gobuf != NULL && gobuf->bytesused < GO7007_BUF_SIZE) {
+ unsigned int pgidx = gobuf->offset >> PAGE_SHIFT;
+ unsigned int pgoff = gobuf->offset & ~PAGE_MASK;
+
+ *((u8 *)page_address(gobuf->pages[pgidx]) + pgoff) = byte;
+ ++gobuf->offset;
+ ++gobuf->bytesused;
+ }
+}
+
+/*
+ * Deliver the last video buffer and get a new one to start writing to.
+ */
+static void frame_boundary(struct go7007 *go)
+{
+ struct go7007_buffer *gobuf;
+ int i;
+
+ if (go->active_buf) {
+ if (go->active_buf->modet_active) {
+ if (go->active_buf->bytesused + 216 < GO7007_BUF_SIZE) {
+ for (i = 0; i < 216; ++i)
+ store_byte(go->active_buf,
+ go->active_map[i]);
+ go->active_buf->bytesused -= 216;
+ } else
+ go->active_buf->modet_active = 0;
+ }
+ go->active_buf->state = BUF_STATE_DONE;
+ wake_up_interruptible(&go->frame_waitq);
+ go->active_buf = NULL;
+ }
+ list_for_each_entry(gobuf, &go->stream, stream)
+ if (gobuf->state == BUF_STATE_QUEUED) {
+ gobuf->seq = go->next_seq;
+ do_gettimeofday(&gobuf->timestamp);
+ go->active_buf = gobuf;
+ break;
+ }
+ ++go->next_seq;
+}
+
+static void write_bitmap_word(struct go7007 *go)
+{
+ int x, y, i, stride = ((go->width >> 4) + 7) >> 3;
+
+ for (i = 0; i < 16; ++i) {
+ y = (((go->parse_length - 1) << 3) + i) / (go->width >> 4);
+ x = (((go->parse_length - 1) << 3) + i) % (go->width >> 4);
+ go->active_map[stride * y + (x >> 3)] |=
+ (go->modet_word & 1) << (x & 0x7);
+ go->modet_word >>= 1;
+ }
+}
+
+/*
+ * Parse a chunk of the video stream into frames. The frames are not
+ * delimited by the hardware, so we have to parse the frame boundaries
+ * based on the type of video stream we're receiving.
+ */
+void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length)
+{
+ int i, seq_start_code = -1, frame_start_code = -1;
+
+ spin_lock(&go->spinlock);
+
+ switch (go->format) {
+ case GO7007_FORMAT_MPEG4:
+ seq_start_code = 0xB0;
+ frame_start_code = 0xB6;
+ break;
+ case GO7007_FORMAT_MPEG1:
+ case GO7007_FORMAT_MPEG2:
+ seq_start_code = 0xB3;
+ frame_start_code = 0x00;
+ break;
+ }
+
+ for (i = 0; i < length; ++i) {
+ if (go->active_buf != NULL &&
+ go->active_buf->bytesused >= GO7007_BUF_SIZE - 3) {
+ printk(KERN_DEBUG "go7007: dropping oversized frame\n");
+ go->active_buf->offset -= go->active_buf->bytesused;
+ go->active_buf->bytesused = 0;
+ go->active_buf->modet_active = 0;
+ go->active_buf = NULL;
+ }
+
+ switch (go->state) {
+ case STATE_DATA:
+ switch (buf[i]) {
+ case 0x00:
+ go->state = STATE_00;
+ break;
+ case 0xFF:
+ go->state = STATE_FF;
+ break;
+ default:
+ store_byte(go->active_buf, buf[i]);
+ break;
+ }
+ break;
+ case STATE_00:
+ switch (buf[i]) {
+ case 0x00:
+ go->state = STATE_00_00;
+ break;
+ case 0xFF:
+ store_byte(go->active_buf, 0x00);
+ go->state = STATE_FF;
+ break;
+ default:
+ store_byte(go->active_buf, 0x00);
+ store_byte(go->active_buf, buf[i]);
+ go->state = STATE_DATA;
+ break;
+ }
+ break;
+ case STATE_00_00:
+ switch (buf[i]) {
+ case 0x00:
+ store_byte(go->active_buf, 0x00);
+ /* go->state remains STATE_00_00 */
+ break;
+ case 0x01:
+ go->state = STATE_00_00_01;
+ break;
+ case 0xFF:
+ store_byte(go->active_buf, 0x00);
+ store_byte(go->active_buf, 0x00);
+ go->state = STATE_FF;
+ break;
+ default:
+ store_byte(go->active_buf, 0x00);
+ store_byte(go->active_buf, 0x00);
+ store_byte(go->active_buf, buf[i]);
+ go->state = STATE_DATA;
+ break;
+ }
+ break;
+ case STATE_00_00_01:
+ /* If this is the start of a new MPEG frame,
+ * get a new buffer */
+ if ((go->format == GO7007_FORMAT_MPEG1 ||
+ go->format == GO7007_FORMAT_MPEG2 ||
+ go->format == GO7007_FORMAT_MPEG4) &&
+ (buf[i] == seq_start_code ||
+ buf[i] == 0xB8 || /* GOP code */
+ buf[i] == frame_start_code)) {
+ if (go->active_buf == NULL || go->seen_frame)
+ frame_boundary(go);
+ if (buf[i] == frame_start_code) {
+ if (go->active_buf != NULL)
+ go->active_buf->frame_offset =
+ go->active_buf->offset;
+ go->seen_frame = 1;
+ } else {
+ go->seen_frame = 0;
+ }
+ }
+ /* Handle any special chunk types, or just write the
+ * start code to the (potentially new) buffer */
+ switch (buf[i]) {
+ case 0xF5: /* timestamp */
+ go->parse_length = 12;
+ go->state = STATE_UNPARSED;
+ break;
+ case 0xF6: /* vbi */
+ go->state = STATE_VBI_LEN_A;
+ break;
+ case 0xF8: /* MD map */
+ go->parse_length = 0;
+ memset(go->active_map, 0,
+ sizeof(go->active_map));
+ go->state = STATE_MODET_MAP;
+ break;
+ case 0xFF: /* Potential JPEG start code */
+ store_byte(go->active_buf, 0x00);
+ store_byte(go->active_buf, 0x00);
+ store_byte(go->active_buf, 0x01);
+ go->state = STATE_FF;
+ break;
+ default:
+ store_byte(go->active_buf, 0x00);
+ store_byte(go->active_buf, 0x00);
+ store_byte(go->active_buf, 0x01);
+ store_byte(go->active_buf, buf[i]);
+ go->state = STATE_DATA;
+ break;
+ }
+ break;
+ case STATE_FF:
+ switch (buf[i]) {
+ case 0x00:
+ store_byte(go->active_buf, 0xFF);
+ go->state = STATE_00;
+ break;
+ case 0xFF:
+ store_byte(go->active_buf, 0xFF);
+ /* go->state remains STATE_FF */
+ break;
+ case 0xD8:
+ if (go->format == GO7007_FORMAT_MJPEG)
+ frame_boundary(go);
+ /* fall through */
+ default:
+ store_byte(go->active_buf, 0xFF);
+ store_byte(go->active_buf, buf[i]);
+ go->state = STATE_DATA;
+ break;
+ }
+ break;
+ case STATE_VBI_LEN_A:
+ go->parse_length = buf[i] << 8;
+ go->state = STATE_VBI_LEN_B;
+ break;
+ case STATE_VBI_LEN_B:
+ go->parse_length |= buf[i];
+ if (go->parse_length > 0)
+ go->state = STATE_UNPARSED;
+ else
+ go->state = STATE_DATA;
+ break;
+ case STATE_MODET_MAP:
+ if (go->parse_length < 204) {
+ if (go->parse_length & 1) {
+ go->modet_word |= buf[i];
+ write_bitmap_word(go);
+ } else
+ go->modet_word = buf[i] << 8;
+ } else if (go->parse_length == 207 && go->active_buf) {
+ go->active_buf->modet_active = buf[i];
+ }
+ if (++go->parse_length == 208)
+ go->state = STATE_DATA;
+ break;
+ case STATE_UNPARSED:
+ if (--go->parse_length == 0)
+ go->state = STATE_DATA;
+ break;
+ }
+ }
+
+ spin_unlock(&go->spinlock);
+}
+EXPORT_SYMBOL(go7007_parse_video_stream);
+
+/*
+ * Allocate a new go7007 struct. Used by the hardware-specific probe.
+ */
+struct go7007 *go7007_alloc(struct go7007_board_info *board, struct device *dev)
+{
+ struct go7007 *go;
+ int i;
+
+ go = kmalloc(sizeof(struct go7007), GFP_KERNEL);
+ if (go == NULL)
+ return NULL;
+ go->dev = dev;
+ go->board_info = board;
+ go->board_id = 0;
+ go->tuner_type = -1;
+ go->channel_number = 0;
+ go->name[0] = 0;
+ init_MUTEX(&go->hw_lock);
+ init_waitqueue_head(&go->frame_waitq);
+ spin_lock_init(&go->spinlock);
+ go->video_dev = NULL;
+ go->ref_count = 0;
+ go->status = STATUS_INIT;
+ memset(&go->i2c_adapter, 0, sizeof(go->i2c_adapter));
+ go->i2c_adapter_online = 0;
+ go->interrupt_available = 0;
+ init_waitqueue_head(&go->interrupt_waitq);
+ go->in_use = 0;
+ go->input = 0;
+ if (board->sensor_flags & GO7007_SENSOR_TV) {
+ go->standard = GO7007_STD_NTSC;
+ go->width = 720;
+ go->height = 480;
+ go->sensor_framerate = 30000;
+ } else {
+ go->standard = GO7007_STD_OTHER;
+ go->width = board->sensor_width;
+ go->height = board->sensor_height;
+ go->sensor_framerate = board->sensor_framerate;
+ }
+ go->encoder_v_offset = board->sensor_v_offset;
+ go->encoder_h_offset = board->sensor_h_offset;
+ go->encoder_h_halve = 0;
+ go->encoder_v_halve = 0;
+ go->encoder_subsample = 0;
+ go->streaming = 0;
+ go->format = GO7007_FORMAT_MJPEG;
+ go->bitrate = 1500000;
+ go->fps_scale = 1;
+ go->pali = 0;
+ go->aspect_ratio = GO7007_RATIO_1_1;
+ go->gop_size = 0;
+ go->ipb = 0;
+ go->closed_gop = 0;
+ go->repeat_seqhead = 0;
+ go->seq_header_enable = 0;
+ go->gop_header_enable = 0;
+ go->dvd_mode = 0;
+ go->interlace_coding = 0;
+ for (i = 0; i < 4; ++i)
+ go->modet[i].enable = 0;;
+ for (i = 0; i < 1624; ++i)
+ go->modet_map[i] = 0;
+ go->audio_deliver = NULL;
+ go->audio_enabled = 0;
+ INIT_LIST_HEAD(&go->stream);
+
+ return go;
+}
+EXPORT_SYMBOL(go7007_alloc);
+
+/*
+ * Detach and unregister the encoder. The go7007 struct won't be freed
+ * until v4l2 finishes releasing its resources and all associated fds are
+ * closed by applications.
+ */
+void go7007_remove(struct go7007 *go)
+{
+ if (go->i2c_adapter_online) {
+ if (i2c_del_adapter(&go->i2c_adapter) == 0)
+ go->i2c_adapter_online = 0;
+ else
+ printk(KERN_ERR
+ "go7007: error removing I2C adapter!\n");
+ }
+
+ if (go->audio_enabled)
+ go7007_snd_remove(go);
+ go7007_v4l2_remove(go);
+}
+EXPORT_SYMBOL(go7007_remove);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/go7007/go7007-fw.c b/drivers/staging/go7007/go7007-fw.c
new file mode 100644
index 0000000..c2aea10
--- /dev/null
+++ b/drivers/staging/go7007/go7007-fw.c
@@ -0,0 +1,1639 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/*
+ * This file contains code to generate a firmware image for the GO7007SB
+ * encoder. Much of the firmware is read verbatim from a file, but some of
+ * it concerning bitrate control and other things that can be configured at
+ * run-time are generated dynamically. Note that the format headers
+ * generated here do not affect the functioning of the encoder; they are
+ * merely parroted back to the host at the start of each frame.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/time.h>
+#include <linux/mm.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/firmware.h>
+#include <asm/byteorder.h>
+
+#include "go7007-priv.h"
+
+/* Constants used in the source firmware image to describe code segments */
+
+#define FLAG_MODE_MJPEG (1)
+#define FLAG_MODE_MPEG1 (1<<1)
+#define FLAG_MODE_MPEG2 (1<<2)
+#define FLAG_MODE_MPEG4 (1<<3)
+#define FLAG_MODE_H263 (1<<4)
+#define FLAG_MODE_ALL (FLAG_MODE_MJPEG | FLAG_MODE_MPEG1 | \
+ FLAG_MODE_MPEG2 | FLAG_MODE_MPEG4 | \
+ FLAG_MODE_H263)
+#define FLAG_SPECIAL (1<<8)
+
+#define SPECIAL_FRM_HEAD 0
+#define SPECIAL_BRC_CTRL 1
+#define SPECIAL_CONFIG 2
+#define SPECIAL_SEQHEAD 3
+#define SPECIAL_AV_SYNC 4
+#define SPECIAL_FINAL 5
+#define SPECIAL_AUDIO 6
+#define SPECIAL_MODET 7
+
+/* Little data class for creating MPEG headers bit-by-bit */
+
+struct code_gen {
+ unsigned char *p; /* destination */
+ u32 a; /* collects bits at the top of the variable */
+ int b; /* bit position of most recently-written bit */
+ int len; /* written out so far */
+};
+
+#define CODE_GEN(name, dest) struct code_gen name = { dest, 0, 32, 0 }
+
+#define CODE_ADD(name, val, length) do { \
+ name.b -= (length); \
+ name.a |= (val) << name.b; \
+ while (name.b <= 24) { \
+ *name.p = name.a >> 24; \
+ ++name.p; \
+ name.a <<= 8; \
+ name.b += 8; \
+ name.len += 8; \
+ } \
+} while (0)
+
+#define CODE_LENGTH(name) (name.len + (32 - name.b))
+
+/* Tables for creating the bitrate control data */
+
+static const s16 converge_speed_ip[101] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 3,
+ 3, 3, 3, 3, 3, 4, 4, 4, 4, 4,
+ 5, 5, 5, 6, 6, 6, 7, 7, 8, 8,
+ 9, 10, 10, 11, 12, 13, 14, 15, 16, 17,
+ 19, 20, 22, 23, 25, 27, 30, 32, 35, 38,
+ 41, 45, 49, 53, 58, 63, 69, 76, 83, 91,
+ 100
+};
+
+static const s16 converge_speed_ipb[101] = {
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 5, 5, 5, 5, 5, 6,
+ 6, 6, 6, 7, 7, 7, 7, 8, 8, 9,
+ 9, 9, 10, 10, 11, 12, 12, 13, 14, 14,
+ 15, 16, 17, 18, 19, 20, 22, 23, 25, 26,
+ 28, 30, 32, 34, 37, 40, 42, 46, 49, 53,
+ 57, 61, 66, 71, 77, 83, 90, 97, 106, 115,
+ 125, 135, 147, 161, 175, 191, 209, 228, 249, 273,
+ 300
+};
+
+static const s16 LAMBDA_table[4][101] = {
+ { 16, 16, 16, 16, 17, 17, 17, 18, 18, 18,
+ 19, 19, 19, 20, 20, 20, 21, 21, 22, 22,
+ 22, 23, 23, 24, 24, 25, 25, 25, 26, 26,
+ 27, 27, 28, 28, 29, 29, 30, 31, 31, 32,
+ 32, 33, 33, 34, 35, 35, 36, 37, 37, 38,
+ 39, 39, 40, 41, 42, 42, 43, 44, 45, 46,
+ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63, 64, 65,
+ 67, 68, 69, 70, 72, 73, 74, 76, 77, 78,
+ 80, 81, 83, 84, 86, 87, 89, 90, 92, 94,
+ 96
+ },
+ {
+ 20, 20, 20, 21, 21, 21, 22, 22, 23, 23,
+ 23, 24, 24, 25, 25, 26, 26, 27, 27, 28,
+ 28, 29, 29, 30, 30, 31, 31, 32, 33, 33,
+ 34, 34, 35, 36, 36, 37, 38, 38, 39, 40,
+ 40, 41, 42, 43, 43, 44, 45, 46, 47, 48,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+ 58, 59, 60, 61, 62, 64, 65, 66, 67, 68,
+ 70, 71, 72, 73, 75, 76, 78, 79, 80, 82,
+ 83, 85, 86, 88, 90, 91, 93, 95, 96, 98,
+ 100, 102, 103, 105, 107, 109, 111, 113, 115, 117,
+ 120
+ },
+ {
+ 24, 24, 24, 25, 25, 26, 26, 27, 27, 28,
+ 28, 29, 29, 30, 30, 31, 31, 32, 33, 33,
+ 34, 34, 35, 36, 36, 37, 38, 38, 39, 40,
+ 41, 41, 42, 43, 44, 44, 45, 46, 47, 48,
+ 49, 50, 50, 51, 52, 53, 54, 55, 56, 57,
+ 58, 59, 60, 62, 63, 64, 65, 66, 67, 69,
+ 70, 71, 72, 74, 75, 76, 78, 79, 81, 82,
+ 84, 85, 87, 88, 90, 92, 93, 95, 97, 98,
+ 100, 102, 104, 106, 108, 110, 112, 114, 116, 118,
+ 120, 122, 124, 127, 129, 131, 134, 136, 138, 141,
+ 144
+ },
+ {
+ 32, 32, 33, 33, 34, 34, 35, 36, 36, 37,
+ 38, 38, 39, 40, 41, 41, 42, 43, 44, 44,
+ 45, 46, 47, 48, 49, 50, 50, 51, 52, 53,
+ 54, 55, 56, 57, 58, 59, 60, 62, 63, 64,
+ 65, 66, 67, 69, 70, 71, 72, 74, 75, 76,
+ 78, 79, 81, 82, 84, 85, 87, 88, 90, 92,
+ 93, 95, 97, 98, 100, 102, 104, 106, 108, 110,
+ 112, 114, 116, 118, 120, 122, 124, 127, 129, 131,
+ 134, 136, 139, 141, 144, 146, 149, 152, 154, 157,
+ 160, 163, 166, 169, 172, 175, 178, 181, 185, 188,
+ 192
+ }
+};
+
+/* MPEG blank frame generation tables */
+
+enum mpeg_frame_type {
+ PFRAME,
+ BFRAME_PRE,
+ BFRAME_POST,
+ BFRAME_BIDIR,
+ BFRAME_EMPTY
+};
+
+static const u32 addrinctab[33][2] = {
+ { 0x01, 1 }, { 0x03, 3 }, { 0x02, 3 }, { 0x03, 4 },
+ { 0x02, 4 }, { 0x03, 5 }, { 0x02, 5 }, { 0x07, 7 },
+ { 0x06, 7 }, { 0x0b, 8 }, { 0x0a, 8 }, { 0x09, 8 },
+ { 0x08, 8 }, { 0x07, 8 }, { 0x06, 8 }, { 0x17, 10 },
+ { 0x16, 10 }, { 0x15, 10 }, { 0x14, 10 }, { 0x13, 10 },
+ { 0x12, 10 }, { 0x23, 11 }, { 0x22, 11 }, { 0x21, 11 },
+ { 0x20, 11 }, { 0x1f, 11 }, { 0x1e, 11 }, { 0x1d, 11 },
+ { 0x1c, 11 }, { 0x1b, 11 }, { 0x1a, 11 }, { 0x19, 11 },
+ { 0x18, 11 }
+};
+
+/* Standard JPEG tables */
+
+static const u8 default_intra_quant_table[] = {
+ 8, 16, 19, 22, 26, 27, 29, 34,
+ 16, 16, 22, 24, 27, 29, 34, 37,
+ 19, 22, 26, 27, 29, 34, 34, 38,
+ 22, 22, 26, 27, 29, 34, 37, 40,
+ 22, 26, 27, 29, 32, 35, 40, 48,
+ 26, 27, 29, 32, 35, 40, 48, 58,
+ 26, 27, 29, 34, 38, 46, 56, 69,
+ 27, 29, 35, 38, 46, 56, 69, 83
+};
+
+static const u8 bits_dc_luminance[] = {
+ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
+};
+
+static const u8 val_dc_luminance[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+};
+
+static const u8 bits_dc_chrominance[] = {
+ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
+};
+
+static const u8 val_dc_chrominance[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+};
+
+static const u8 bits_ac_luminance[] = {
+ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
+};
+
+static const u8 val_ac_luminance[] = {
+ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+ 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+ 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+ 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa
+};
+
+static const u8 bits_ac_chrominance[] = {
+ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
+};
+
+static const u8 val_ac_chrominance[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+ 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+ 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+ 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+ 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
+ 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+ 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+ 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+ 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+ 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+ 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa
+};
+
+/* Zig-zag mapping for quant table
+ *
+ * OK, let's do this mapping on the actual table above so it doesn't have
+ * to be done on the fly.
+ */
+static const int zz[64] = {
+ 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28,
+ 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
+ 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63
+};
+
+static int copy_packages(u16 *dest, u16 *src, int pkg_cnt, int space)
+{
+ int i, cnt = pkg_cnt * 32;
+
+ if (space < cnt)
+ return -1;
+
+ for (i = 0; i < cnt; ++i)
+ dest[i] = __cpu_to_le16(src[i]);
+
+ return cnt;
+}
+
+static int mjpeg_frame_header(struct go7007 *go, unsigned char *buf, int q)
+{
+ int i, p = 0;
+
+ buf[p++] = 0xff;
+ buf[p++] = 0xd8;
+ buf[p++] = 0xff;
+ buf[p++] = 0xdb;
+ buf[p++] = 0;
+ buf[p++] = 2 + 65;
+ buf[p++] = 0;
+ buf[p++] = default_intra_quant_table[0];
+ for (i = 1; i < 64; ++i)
+ /* buf[p++] = (default_intra_quant_table[i] * q) >> 3; */
+ buf[p++] = (default_intra_quant_table[zz[i]] * q) >> 3;
+ buf[p++] = 0xff;
+ buf[p++] = 0xc0;
+ buf[p++] = 0;
+ buf[p++] = 17;
+ buf[p++] = 8;
+ buf[p++] = go->height >> 8;
+ buf[p++] = go->height & 0xff;
+ buf[p++] = go->width >> 8;
+ buf[p++] = go->width & 0xff;
+ buf[p++] = 3;
+ buf[p++] = 1;
+ buf[p++] = 0x22;
+ buf[p++] = 0;
+ buf[p++] = 2;
+ buf[p++] = 0x11;
+ buf[p++] = 0;
+ buf[p++] = 3;
+ buf[p++] = 0x11;
+ buf[p++] = 0;
+ buf[p++] = 0xff;
+ buf[p++] = 0xc4;
+ buf[p++] = 418 >> 8;
+ buf[p++] = 418 & 0xff;
+ buf[p++] = 0x00;
+ memcpy(buf + p, bits_dc_luminance + 1, 16);
+ p += 16;
+ memcpy(buf + p, val_dc_luminance, sizeof(val_dc_luminance));
+ p += sizeof(val_dc_luminance);
+ buf[p++] = 0x01;
+ memcpy(buf + p, bits_dc_chrominance + 1, 16);
+ p += 16;
+ memcpy(buf + p, val_dc_chrominance, sizeof(val_dc_chrominance));
+ p += sizeof(val_dc_chrominance);
+ buf[p++] = 0x10;
+ memcpy(buf + p, bits_ac_luminance + 1, 16);
+ p += 16;
+ memcpy(buf + p, val_ac_luminance, sizeof(val_ac_luminance));
+ p += sizeof(val_ac_luminance);
+ buf[p++] = 0x11;
+ memcpy(buf + p, bits_ac_chrominance + 1, 16);
+ p += 16;
+ memcpy(buf + p, val_ac_chrominance, sizeof(val_ac_chrominance));
+ p += sizeof(val_ac_chrominance);
+ buf[p++] = 0xff;
+ buf[p++] = 0xda;
+ buf[p++] = 0;
+ buf[p++] = 12;
+ buf[p++] = 3;
+ buf[p++] = 1;
+ buf[p++] = 0x00;
+ buf[p++] = 2;
+ buf[p++] = 0x11;
+ buf[p++] = 3;
+ buf[p++] = 0x11;
+ buf[p++] = 0;
+ buf[p++] = 63;
+ buf[p++] = 0;
+ return p;
+}
+
+static int gen_mjpeghdr_to_package(struct go7007 *go, u16 *code, int space)
+{
+ u8 *buf;
+ u16 mem = 0x3e00;
+ unsigned int addr = 0x19;
+ int size = 0, i, off = 0, chunk;
+
+ buf = kmalloc(4096, GFP_KERNEL);
+ if (buf == NULL) {
+ printk(KERN_ERR "go7007: unable to allocate 4096 bytes for "
+ "firmware construction\n");
+ return -1;
+ }
+ memset(buf, 0, 4096);
+
+ for (i = 1; i < 32; ++i) {
+ mjpeg_frame_header(go, buf + size, i);
+ size += 80;
+ }
+ chunk = mjpeg_frame_header(go, buf + size, 1);
+ memmove(buf + size, buf + size + 80, chunk - 80);
+ size += chunk - 80;
+
+ for (i = 0; i < size; i += chunk * 2) {
+ if (space - off < 32) {
+ off = -1;
+ goto done;
+ }
+
+ code[off + 1] = __cpu_to_le16(0x8000 | mem);
+
+ chunk = 28;
+ if (mem + chunk > 0x4000)
+ chunk = 0x4000 - mem;
+ if (i + 2 * chunk > size)
+ chunk = (size - i) / 2;
+
+ if (chunk < 28) {
+ code[off] = __cpu_to_le16(0x4000 | chunk);
+ code[off + 31] = __cpu_to_le16(addr++);
+ mem = 0x3e00;
+ } else {
+ code[off] = __cpu_to_le16(0x1000 | 28);
+ code[off + 31] = 0;
+ mem += 28;
+ }
+
+ memcpy(&code[off + 2], buf + i, chunk * 2);
+ off += 32;
+ }
+done:
+ kfree(buf);
+ return off;
+}
+
+static int mpeg1_frame_header(struct go7007 *go, unsigned char *buf,
+ int modulo, int pict_struct, enum mpeg_frame_type frame)
+{
+ int i, j, mb_code, mb_len;
+ int rows = go->interlace_coding ? go->height / 32 : go->height / 16;
+ CODE_GEN(c, buf + 6);
+
+ switch (frame) {
+ case PFRAME:
+ mb_code = 0x1;
+ mb_len = 3;
+ break;
+ case BFRAME_PRE:
+ mb_code = 0x2;
+ mb_len = 4;
+ break;
+ case BFRAME_POST:
+ mb_code = 0x2;
+ mb_len = 3;
+ break;
+ case BFRAME_BIDIR:
+ mb_code = 0x2;
+ mb_len = 2;
+ break;
+ default: /* keep the compiler happy */
+ mb_code = mb_len = 0;
+ break;
+ }
+
+ CODE_ADD(c, frame == PFRAME ? 0x2 : 0x3, 13);
+ CODE_ADD(c, 0xffff, 16);
+ CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 0x7 : 0x4, 4);
+ if (frame != PFRAME)
+ CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 0x7 : 0x4, 4);
+ else
+ CODE_ADD(c, 0, 4); /* Is this supposed to be here?? */
+ CODE_ADD(c, 0, 3); /* What is this?? */
+ /* Byte-align with zeros */
+ j = 8 - (CODE_LENGTH(c) % 8);
+ if (j != 8)
+ CODE_ADD(c, 0, j);
+
+ if (go->format == GO7007_FORMAT_MPEG2) {
+ CODE_ADD(c, 0x1, 24);
+ CODE_ADD(c, 0xb5, 8);
+ CODE_ADD(c, 0x844, 12);
+ CODE_ADD(c, frame == PFRAME ? 0xff : 0x44, 8);
+ if (go->interlace_coding) {
+ CODE_ADD(c, pict_struct, 4);
+ if (go->dvd_mode)
+ CODE_ADD(c, 0x000, 11);
+ else
+ CODE_ADD(c, 0x200, 11);
+ } else {
+ CODE_ADD(c, 0x3, 4);
+ CODE_ADD(c, 0x20c, 11);
+ }
+ /* Byte-align with zeros */
+ j = 8 - (CODE_LENGTH(c) % 8);
+ if (j != 8)
+ CODE_ADD(c, 0, j);
+ }
+
+ for (i = 0; i < rows; ++i) {
+ CODE_ADD(c, 1, 24);
+ CODE_ADD(c, i + 1, 8);
+ CODE_ADD(c, 0x2, 6);
+ CODE_ADD(c, 0x1, 1);
+ CODE_ADD(c, mb_code, mb_len);
+ if (go->interlace_coding) {
+ CODE_ADD(c, 0x1, 2);
+ CODE_ADD(c, pict_struct == 1 ? 0x0 : 0x1, 1);
+ }
+ if (frame == BFRAME_BIDIR) {
+ CODE_ADD(c, 0x3, 2);
+ if (go->interlace_coding)
+ CODE_ADD(c, pict_struct == 1 ? 0x0 : 0x1, 1);
+ }
+ CODE_ADD(c, 0x3, 2);
+ for (j = (go->width >> 4) - 2; j >= 33; j -= 33)
+ CODE_ADD(c, 0x8, 11);
+ CODE_ADD(c, addrinctab[j][0], addrinctab[j][1]);
+ CODE_ADD(c, mb_code, mb_len);
+ if (go->interlace_coding) {
+ CODE_ADD(c, 0x1, 2);
+ CODE_ADD(c, pict_struct == 1 ? 0x0 : 0x1, 1);
+ }
+ if (frame == BFRAME_BIDIR) {
+ CODE_ADD(c, 0x3, 2);
+ if (go->interlace_coding)
+ CODE_ADD(c, pict_struct == 1 ? 0x0 : 0x1, 1);
+ }
+ CODE_ADD(c, 0x3, 2);
+
+ /* Byte-align with zeros */
+ j = 8 - (CODE_LENGTH(c) % 8);
+ if (j != 8)
+ CODE_ADD(c, 0, j);
+ }
+
+ i = CODE_LENGTH(c) + 4 * 8;
+ buf[2] = 0x00;
+ buf[3] = 0x00;
+ buf[4] = 0x01;
+ buf[5] = 0x00;
+ return i;
+}
+
+static int mpeg1_sequence_header(struct go7007 *go, unsigned char *buf, int ext)
+{
+ int i, aspect_ratio, picture_rate;
+ CODE_GEN(c, buf + 6);
+
+ if (go->format == GO7007_FORMAT_MPEG1) {
+ switch (go->aspect_ratio) {
+ case GO7007_RATIO_4_3:
+ aspect_ratio = go->standard == GO7007_STD_NTSC ? 3 : 2;
+ break;
+ case GO7007_RATIO_16_9:
+ aspect_ratio = go->standard == GO7007_STD_NTSC ? 5 : 4;
+ break;
+ default:
+ aspect_ratio = 1;
+ break;
+ }
+ } else {
+ switch (go->aspect_ratio) {
+ case GO7007_RATIO_4_3:
+ aspect_ratio = 2;
+ break;
+ case GO7007_RATIO_16_9:
+ aspect_ratio = 3;
+ break;
+ default:
+ aspect_ratio = 1;
+ break;
+ }
+ }
+ switch (go->sensor_framerate) {
+ case 24000:
+ picture_rate = 1;
+ break;
+ case 24024:
+ picture_rate = 2;
+ break;
+ case 25025:
+ picture_rate = go->interlace_coding ? 6 : 3;
+ break;
+ case 30000:
+ picture_rate = go->interlace_coding ? 7 : 4;
+ break;
+ case 30030:
+ picture_rate = go->interlace_coding ? 8 : 5;
+ break;
+ default:
+ picture_rate = 5; /* 30 fps seems like a reasonable default */
+ break;
+ }
+
+ CODE_ADD(c, go->width, 12);
+ CODE_ADD(c, go->height, 12);
+ CODE_ADD(c, aspect_ratio, 4);
+ CODE_ADD(c, picture_rate, 4);
+ CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 20000 : 0x3ffff, 18);
+ CODE_ADD(c, 1, 1);
+ CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 112 : 20, 10);
+ CODE_ADD(c, 0, 3);
+
+ /* Byte-align with zeros */
+ i = 8 - (CODE_LENGTH(c) % 8);
+ if (i != 8)
+ CODE_ADD(c, 0, i);
+
+ if (go->format == GO7007_FORMAT_MPEG2) {
+ CODE_ADD(c, 0x1, 24);
+ CODE_ADD(c, 0xb5, 8);
+ CODE_ADD(c, 0x148, 12);
+ if (go->interlace_coding)
+ CODE_ADD(c, 0x20001, 20);
+ else
+ CODE_ADD(c, 0xa0001, 20);
+ CODE_ADD(c, 0, 16);
+
+ /* Byte-align with zeros */
+ i = 8 - (CODE_LENGTH(c) % 8);
+ if (i != 8)
+ CODE_ADD(c, 0, i);
+
+ if (ext) {
+ CODE_ADD(c, 0x1, 24);
+ CODE_ADD(c, 0xb52, 12);
+ CODE_ADD(c, go->standard == GO7007_STD_NTSC ? 2 : 1, 3);
+ CODE_ADD(c, 0x105, 9);
+ CODE_ADD(c, 0x505, 16);
+ CODE_ADD(c, go->width, 14);
+ CODE_ADD(c, 1, 1);
+ CODE_ADD(c, go->height, 14);
+
+ /* Byte-align with zeros */
+ i = 8 - (CODE_LENGTH(c) % 8);
+ if (i != 8)
+ CODE_ADD(c, 0, i);
+ }
+ }
+
+ i = CODE_LENGTH(c) + 4 * 8;
+ buf[0] = i & 0xff;
+ buf[1] = i >> 8;
+ buf[2] = 0x00;
+ buf[3] = 0x00;
+ buf[4] = 0x01;
+ buf[5] = 0xb3;
+ return i;
+}
+
+static int gen_mpeg1hdr_to_package(struct go7007 *go,
+ u16 *code, int space, int *framelen)
+{
+ u8 *buf;
+ u16 mem = 0x3e00;
+ unsigned int addr = 0x19;
+ int i, off = 0, chunk;
+
+ buf = kmalloc(5120, GFP_KERNEL);
+ if (buf == NULL) {
+ printk(KERN_ERR "go7007: unable to allocate 5120 bytes for "
+ "firmware construction\n");
+ return -1;
+ }
+ memset(buf, 0, 5120);
+ framelen[0] = mpeg1_frame_header(go, buf, 0, 1, PFRAME);
+ if (go->interlace_coding)
+ framelen[0] += mpeg1_frame_header(go, buf + framelen[0] / 8,
+ 0, 2, PFRAME);
+ buf[0] = framelen[0] & 0xff;
+ buf[1] = framelen[0] >> 8;
+ i = 368;
+ framelen[1] = mpeg1_frame_header(go, buf + i, 0, 1, BFRAME_PRE);
+ if (go->interlace_coding)
+ framelen[1] += mpeg1_frame_header(go, buf + i + framelen[1] / 8,
+ 0, 2, BFRAME_PRE);
+ buf[i] = framelen[1] & 0xff;
+ buf[i + 1] = framelen[1] >> 8;
+ i += 1632;
+ framelen[2] = mpeg1_frame_header(go, buf + i, 0, 1, BFRAME_POST);
+ if (go->interlace_coding)
+ framelen[2] += mpeg1_frame_header(go, buf + i + framelen[2] / 8,
+ 0, 2, BFRAME_POST);
+ buf[i] = framelen[2] & 0xff;
+ buf[i + 1] = framelen[2] >> 8;
+ i += 1432;
+ framelen[3] = mpeg1_frame_header(go, buf + i, 0, 1, BFRAME_BIDIR);
+ if (go->interlace_coding)
+ framelen[3] += mpeg1_frame_header(go, buf + i + framelen[3] / 8,
+ 0, 2, BFRAME_BIDIR);
+ buf[i] = framelen[3] & 0xff;
+ buf[i + 1] = framelen[3] >> 8;
+ i += 1632 + 16;
+ mpeg1_sequence_header(go, buf + i, 0);
+ i += 40;
+ for (i = 0; i < 5120; i += chunk * 2) {
+ if (space - off < 32) {
+ off = -1;
+ goto done;
+ }
+
+ code[off + 1] = __cpu_to_le16(0x8000 | mem);
+
+ chunk = 28;
+ if (mem + chunk > 0x4000)
+ chunk = 0x4000 - mem;
+ if (i + 2 * chunk > 5120)
+ chunk = (5120 - i) / 2;
+
+ if (chunk < 28) {
+ code[off] = __cpu_to_le16(0x4000 | chunk);
+ code[off + 31] = __cpu_to_le16(addr);
+ if (mem + chunk == 0x4000) {
+ mem = 0x3e00;
+ ++addr;
+ }
+ } else {
+ code[off] = __cpu_to_le16(0x1000 | 28);
+ code[off + 31] = 0;
+ mem += 28;
+ }
+
+ memcpy(&code[off + 2], buf + i, chunk * 2);
+ off += 32;
+ }
+done:
+ kfree(buf);
+ return off;
+}
+
+static int vti_bitlen(struct go7007 *go)
+{
+ unsigned int i, max_time_incr = go->sensor_framerate / go->fps_scale;
+
+ for (i = 31; (max_time_incr & ((1 << i) - 1)) == max_time_incr; --i);
+ return i + 1;
+}
+
+static int mpeg4_frame_header(struct go7007 *go, unsigned char *buf,
+ int modulo, enum mpeg_frame_type frame)
+{
+ int i;
+ CODE_GEN(c, buf + 6);
+ int mb_count = (go->width >> 4) * (go->height >> 4);
+
+ CODE_ADD(c, frame == PFRAME ? 0x1 : 0x2, 2);
+ if (modulo)
+ CODE_ADD(c, 0x1, 1);
+ CODE_ADD(c, 0x1, 2);
+ CODE_ADD(c, 0, vti_bitlen(go));
+ CODE_ADD(c, 0x3, 2);
+ if (frame == PFRAME)
+ CODE_ADD(c, 0, 1);
+ CODE_ADD(c, 0xc, 11);
+ if (frame != PFRAME)
+ CODE_ADD(c, 0x4, 3);
+ if (frame != BFRAME_EMPTY) {
+ for (i = 0; i < mb_count; ++i) {
+ switch (frame) {
+ case PFRAME:
+ CODE_ADD(c, 0x1, 1);
+ break;
+ case BFRAME_PRE:
+ CODE_ADD(c, 0x47, 8);
+ break;
+ case BFRAME_POST:
+ CODE_ADD(c, 0x27, 7);
+ break;
+ case BFRAME_BIDIR:
+ CODE_ADD(c, 0x5f, 8);
+ break;
+ case BFRAME_EMPTY: /* keep compiler quiet */
+ break;
+ }
+ }
+ }
+
+ /* Byte-align with a zero followed by ones */
+ i = 8 - (CODE_LENGTH(c) % 8);
+ CODE_ADD(c, 0, 1);
+ CODE_ADD(c, (1 << (i - 1)) - 1, i - 1);
+
+ i = CODE_LENGTH(c) + 4 * 8;
+ buf[0] = i & 0xff;
+ buf[1] = i >> 8;
+ buf[2] = 0x00;
+ buf[3] = 0x00;
+ buf[4] = 0x01;
+ buf[5] = 0xb6;
+ return i;
+}
+
+static int mpeg4_sequence_header(struct go7007 *go, unsigned char *buf, int ext)
+{
+ const unsigned char head[] = { 0x00, 0x00, 0x01, 0xb0, go->pali,
+ 0x00, 0x00, 0x01, 0xb5, 0x09,
+ 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x01, 0x20, };
+ int i, aspect_ratio;
+ int fps = go->sensor_framerate / go->fps_scale;
+ CODE_GEN(c, buf + 2 + sizeof(head));
+
+ switch (go->aspect_ratio) {
+ case GO7007_RATIO_4_3:
+ aspect_ratio = go->standard == GO7007_STD_NTSC ? 3 : 2;
+ break;
+ case GO7007_RATIO_16_9:
+ aspect_ratio = go->standard == GO7007_STD_NTSC ? 5 : 4;
+ break;
+ default:
+ aspect_ratio = 1;
+ break;
+ }
+
+ memcpy(buf + 2, head, sizeof(head));
+ CODE_ADD(c, 0x191, 17);
+ CODE_ADD(c, aspect_ratio, 4);
+ CODE_ADD(c, 0x1, 4);
+ CODE_ADD(c, fps, 16);
+ CODE_ADD(c, 0x3, 2);
+ CODE_ADD(c, 1001, vti_bitlen(go));
+ CODE_ADD(c, 1, 1);
+ CODE_ADD(c, go->width, 13);
+ CODE_ADD(c, 1, 1);
+ CODE_ADD(c, go->height, 13);
+ CODE_ADD(c, 0x2830, 14);
+
+ /* Byte-align */
+ i = 8 - (CODE_LENGTH(c) % 8);
+ CODE_ADD(c, 0, 1);
+ CODE_ADD(c, (1 << (i - 1)) - 1, i - 1);
+
+ i = CODE_LENGTH(c) + sizeof(head) * 8;
+ buf[0] = i & 0xff;
+ buf[1] = i >> 8;
+ return i;
+}
+
+static int gen_mpeg4hdr_to_package(struct go7007 *go,
+ u16 *code, int space, int *framelen)
+{
+ u8 *buf;
+ u16 mem = 0x3e00;
+ unsigned int addr = 0x19;
+ int i, off = 0, chunk;
+
+ buf = kmalloc(5120, GFP_KERNEL);
+ if (buf == NULL) {
+ printk(KERN_ERR "go7007: unable to allocate 5120 bytes for "
+ "firmware construction\n");
+ return -1;
+ }
+ memset(buf, 0, 5120);
+ framelen[0] = mpeg4_frame_header(go, buf, 0, PFRAME);
+ i = 368;
+ framelen[1] = mpeg4_frame_header(go, buf + i, 0, BFRAME_PRE);
+ i += 1632;
+ framelen[2] = mpeg4_frame_header(go, buf + i, 0, BFRAME_POST);
+ i += 1432;
+ framelen[3] = mpeg4_frame_header(go, buf + i, 0, BFRAME_BIDIR);
+ i += 1632;
+ mpeg4_frame_header(go, buf + i, 0, BFRAME_EMPTY);
+ i += 16;
+ mpeg4_sequence_header(go, buf + i, 0);
+ i += 40;
+ for (i = 0; i < 5120; i += chunk * 2) {
+ if (space - off < 32) {
+ off = -1;
+ goto done;
+ }
+
+ code[off + 1] = __cpu_to_le16(0x8000 | mem);
+
+ chunk = 28;
+ if (mem + chunk > 0x4000)
+ chunk = 0x4000 - mem;
+ if (i + 2 * chunk > 5120)
+ chunk = (5120 - i) / 2;
+
+ if (chunk < 28) {
+ code[off] = __cpu_to_le16(0x4000 | chunk);
+ code[off + 31] = __cpu_to_le16(addr);
+ if (mem + chunk == 0x4000) {
+ mem = 0x3e00;
+ ++addr;
+ }
+ } else {
+ code[off] = __cpu_to_le16(0x1000 | 28);
+ code[off + 31] = 0;
+ mem += 28;
+ }
+
+ memcpy(&code[off + 2], buf + i, chunk * 2);
+ off += 32;
+ }
+ mem = 0x3e00;
+ addr = go->ipb ? 0x14f9 : 0x0af9;
+ memset(buf, 0, 5120);
+ framelen[4] = mpeg4_frame_header(go, buf, 1, PFRAME);
+ i = 368;
+ framelen[5] = mpeg4_frame_header(go, buf + i, 1, BFRAME_PRE);
+ i += 1632;
+ framelen[6] = mpeg4_frame_header(go, buf + i, 1, BFRAME_POST);
+ i += 1432;
+ framelen[7] = mpeg4_frame_header(go, buf + i, 1, BFRAME_BIDIR);
+ i += 1632;
+ mpeg4_frame_header(go, buf + i, 1, BFRAME_EMPTY);
+ i += 16;
+ for (i = 0; i < 5120; i += chunk * 2) {
+ if (space - off < 32) {
+ off = -1;
+ goto done;
+ }
+
+ code[off + 1] = __cpu_to_le16(0x8000 | mem);
+
+ chunk = 28;
+ if (mem + chunk > 0x4000)
+ chunk = 0x4000 - mem;
+ if (i + 2 * chunk > 5120)
+ chunk = (5120 - i) / 2;
+
+ if (chunk < 28) {
+ code[off] = __cpu_to_le16(0x4000 | chunk);
+ code[off + 31] = __cpu_to_le16(addr);
+ if (mem + chunk == 0x4000) {
+ mem = 0x3e00;
+ ++addr;
+ }
+ } else {
+ code[off] = __cpu_to_le16(0x1000 | 28);
+ code[off + 31] = 0;
+ mem += 28;
+ }
+
+ memcpy(&code[off + 2], buf + i, chunk * 2);
+ off += 32;
+ }
+done:
+ kfree(buf);
+ return off;
+}
+
+static int brctrl_to_package(struct go7007 *go,
+ u16 *code, int space, int *framelen)
+{
+ int converge_speed = 0;
+ int lambda = (go->format == GO7007_FORMAT_MJPEG || go->dvd_mode) ?
+ 100 : 0;
+ int peak_rate = 6 * go->bitrate / 5;
+ int vbv_buffer = go->format == GO7007_FORMAT_MJPEG ?
+ go->bitrate :
+ (go->dvd_mode ? 900000 : peak_rate);
+ int fps = go->sensor_framerate / go->fps_scale;
+ int q = 0;
+ /* Bizarre math below depends on rounding errors in division */
+ u32 sgop_expt_addr = go->bitrate / 32 * (go->ipb ? 3 : 1) * 1001 / fps;
+ u32 sgop_peak_addr = peak_rate / 32 * 1001 / fps;
+ u32 total_expt_addr = go->bitrate / 32 * 1000 / fps * (fps / 1000);
+ u32 vbv_alert_addr = vbv_buffer * 3 / (4 * 32);
+ u32 cplx[] = {
+ q > 0 ? sgop_expt_addr * q :
+ 2 * go->width * go->height * (go->ipb ? 6 : 4) / 32,
+ q > 0 ? sgop_expt_addr * q :
+ 2 * go->width * go->height * (go->ipb ? 6 : 4) / 32,
+ q > 0 ? sgop_expt_addr * q :
+ 2 * go->width * go->height * (go->ipb ? 6 : 4) / 32,
+ q > 0 ? sgop_expt_addr * q :
+ 2 * go->width * go->height * (go->ipb ? 6 : 4) / 32,
+ };
+ u32 calc_q = q > 0 ? q : cplx[0] / sgop_expt_addr;
+ u16 pack[] = {
+ 0x200e, 0x0000,
+ 0xBF20, go->ipb ? converge_speed_ipb[converge_speed]
+ : converge_speed_ip[converge_speed],
+ 0xBF21, go->ipb ? 2 : 0,
+ 0xBF22, go->ipb ? LAMBDA_table[0][lambda / 2 + 50]
+ : 32767,
+ 0xBF23, go->ipb ? LAMBDA_table[1][lambda] : 32767,
+ 0xBF24, 32767,
+ 0xBF25, lambda > 99 ? 32767 : LAMBDA_table[3][lambda],
+ 0xBF26, sgop_expt_addr & 0x0000FFFF,
+ 0xBF27, sgop_expt_addr >> 16,
+ 0xBF28, sgop_peak_addr & 0x0000FFFF,
+ 0xBF29, sgop_peak_addr >> 16,
+ 0xBF2A, vbv_alert_addr & 0x0000FFFF,
+ 0xBF2B, vbv_alert_addr >> 16,
+ 0xBF2C, 0,
+ 0xBF2D, 0,
+ 0, 0,
+
+ 0x200e, 0x0000,
+ 0xBF2E, vbv_alert_addr & 0x0000FFFF,
+ 0xBF2F, vbv_alert_addr >> 16,
+ 0xBF30, cplx[0] & 0x0000FFFF,
+ 0xBF31, cplx[0] >> 16,
+ 0xBF32, cplx[1] & 0x0000FFFF,
+ 0xBF33, cplx[1] >> 16,
+ 0xBF34, cplx[2] & 0x0000FFFF,
+ 0xBF35, cplx[2] >> 16,
+ 0xBF36, cplx[3] & 0x0000FFFF,
+ 0xBF37, cplx[3] >> 16,
+ 0xBF38, 0,
+ 0xBF39, 0,
+ 0xBF3A, total_expt_addr & 0x0000FFFF,
+ 0xBF3B, total_expt_addr >> 16,
+ 0, 0,
+
+ 0x200e, 0x0000,
+ 0xBF3C, total_expt_addr & 0x0000FFFF,
+ 0xBF3D, total_expt_addr >> 16,
+ 0xBF3E, 0,
+ 0xBF3F, 0,
+ 0xBF48, 0,
+ 0xBF49, 0,
+ 0xBF4A, calc_q < 4 ? 4 : (calc_q > 124 ? 124 : calc_q),
+ 0xBF4B, 4,
+ 0xBF4C, 0,
+ 0xBF4D, 0,
+ 0xBF4E, 0,
+ 0xBF4F, 0,
+ 0xBF50, 0,
+ 0xBF51, 0,
+ 0, 0,
+
+ 0x200e, 0x0000,
+ 0xBF40, sgop_expt_addr & 0x0000FFFF,
+ 0xBF41, sgop_expt_addr >> 16,
+ 0xBF42, 0,
+ 0xBF43, 0,
+ 0xBF44, 0,
+ 0xBF45, 0,
+ 0xBF46, (go->width >> 4) * (go->height >> 4),
+ 0xBF47, 0,
+ 0xBF64, 0,
+ 0xBF65, 0,
+ 0xBF18, framelen[4],
+ 0xBF19, framelen[5],
+ 0xBF1A, framelen[6],
+ 0xBF1B, framelen[7],
+ 0, 0,
+
+#if 0 /* Remove once we don't care about matching */
+ 0x200e, 0x0000,
+ 0xBF56, 4,
+ 0xBF57, 0,
+ 0xBF58, 5,
+ 0xBF59, 0,
+ 0xBF5A, 6,
+ 0xBF5B, 0,
+ 0xBF5C, 8,
+ 0xBF5D, 0,
+ 0xBF5E, 1,
+ 0xBF5F, 0,
+ 0xBF60, 1,
+ 0xBF61, 0,
+ 0xBF62, 0,
+ 0xBF63, 0,
+ 0, 0,
+#else
+ 0x2008, 0x0000,
+ 0xBF56, 4,
+ 0xBF57, 0,
+ 0xBF58, 5,
+ 0xBF59, 0,
+ 0xBF5A, 6,
+ 0xBF5B, 0,
+ 0xBF5C, 8,
+ 0xBF5D, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+#endif
+
+ 0x200e, 0x0000,
+ 0xBF10, 0,
+ 0xBF11, 0,
+ 0xBF12, 0,
+ 0xBF13, 0,
+ 0xBF14, 0,
+ 0xBF15, 0,
+ 0xBF16, 0,
+ 0xBF17, 0,
+ 0xBF7E, 0,
+ 0xBF7F, 1,
+ 0xBF52, framelen[0],
+ 0xBF53, framelen[1],
+ 0xBF54, framelen[2],
+ 0xBF55, framelen[3],
+ 0, 0,
+ };
+
+ return copy_packages(code, pack, 6, space);
+}
+
+static int config_package(struct go7007 *go, u16 *code, int space)
+{
+ int fps = go->sensor_framerate / go->fps_scale / 1000;
+ int rows = go->interlace_coding ? go->height / 32 : go->height / 16;
+ int brc_window_size = fps;
+ int q_min = 2, q_max = 31;
+ int THACCoeffSet0 = 0;
+ u16 pack[] = {
+ 0x200e, 0x0000,
+ 0xc002, 0x14b4,
+ 0xc003, 0x28b4,
+ 0xc004, 0x3c5a,
+ 0xdc05, 0x2a77,
+ 0xc6c3, go->format == GO7007_FORMAT_MPEG4 ? 0 :
+ (go->format == GO7007_FORMAT_H263 ? 0 : 1),
+ 0xc680, go->format == GO7007_FORMAT_MPEG4 ? 0xf1 :
+ (go->format == GO7007_FORMAT_H263 ? 0x61 :
+ 0xd3),
+ 0xc780, 0x0140,
+ 0xe009, 0x0001,
+ 0xc60f, 0x0008,
+ 0xd4ff, 0x0002,
+ 0xe403, 2340,
+ 0xe406, 75,
+ 0xd411, 0x0001,
+ 0xd410, 0xa1d6,
+ 0x0001, 0x2801,
+
+ 0x200d, 0x0000,
+ 0xe402, 0x018b,
+ 0xe401, 0x8b01,
+ 0xd472, (go->board_info->sensor_flags &
+ GO7007_SENSOR_TV) &&
+ (!go->interlace_coding) ?
+ 0x01b0 : 0x0170,
+ 0xd475, (go->board_info->sensor_flags &
+ GO7007_SENSOR_TV) &&
+ (!go->interlace_coding) ?
+ 0x0008 : 0x0009,
+ 0xc404, go->interlace_coding ? 0x44 :
+ (go->format == GO7007_FORMAT_MPEG4 ? 0x11 :
+ (go->format == GO7007_FORMAT_MPEG1 ? 0x02 :
+ (go->format == GO7007_FORMAT_MPEG2 ? 0x04 :
+ (go->format == GO7007_FORMAT_H263 ? 0x08 :
+ 0x20)))),
+ 0xbf0a, (go->format == GO7007_FORMAT_MPEG4 ? 8 :
+ (go->format == GO7007_FORMAT_MPEG1 ? 1 :
+ (go->format == GO7007_FORMAT_MPEG2 ? 2 :
+ (go->format == GO7007_FORMAT_H263 ? 4 : 16)))) |
+ ((go->repeat_seqhead ? 1 : 0) << 6) |
+ ((go->dvd_mode ? 1 : 0) << 9) |
+ ((go->gop_header_enable ? 1 : 0) << 10),
+ 0xbf0b, 0,
+ 0xdd5a, go->ipb ? 0x14 : 0x0a,
+ 0xbf0c, 0,
+ 0xbf0d, 0,
+ 0xc683, THACCoeffSet0,
+ 0xc40a, (go->width << 4) | rows,
+ 0xe01a, go->board_info->hpi_buffer_cap,
+ 0, 0,
+ 0, 0,
+
+ 0x2008, 0,
+ 0xe402, 0x88,
+ 0xe401, 0x8f01,
+ 0xbf6a, 0,
+ 0xbf6b, 0,
+ 0xbf6c, 0,
+ 0xbf6d, 0,
+ 0xbf6e, 0,
+ 0xbf6f, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+
+ 0x200e, 0,
+ 0xbf66, brc_window_size,
+ 0xbf67, 0,
+ 0xbf68, q_min,
+ 0xbf69, q_max,
+ 0xbfe0, 0,
+ 0xbfe1, 0,
+ 0xbfe2, 0,
+ 0xbfe3, go->ipb ? 3 : 1,
+ 0xc031, go->board_info->sensor_flags &
+ GO7007_SENSOR_VBI ? 1 : 0,
+ 0xc01c, 0x1f,
+ 0xdd8c, 0x15,
+ 0xdd94, 0x15,
+ 0xdd88, go->ipb ? 0x1401 : 0x0a01,
+ 0xdd90, go->ipb ? 0x1401 : 0x0a01,
+ 0, 0,
+
+ 0x200e, 0,
+ 0xbfe4, 0,
+ 0xbfe5, 0,
+ 0xbfe6, 0,
+ 0xbfe7, fps << 8,
+ 0xbfe8, 0x3a00,
+ 0xbfe9, 0,
+ 0xbfea, 0,
+ 0xbfeb, 0,
+ 0xbfec, (go->interlace_coding ? 1 << 15 : 0) |
+ (go->modet_enable ? 0xa : 0) |
+ (go->board_info->sensor_flags &
+ GO7007_SENSOR_VBI ? 1 : 0),
+ 0xbfed, 0,
+ 0xbfee, 0,
+ 0xbfef, 0,
+ 0xbff0, go->board_info->sensor_flags &
+ GO7007_SENSOR_TV ? 0xf060 : 0xb060,
+ 0xbff1, 0,
+ 0, 0,
+ };
+
+ return copy_packages(code, pack, 5, space);
+}
+
+static int seqhead_to_package(struct go7007 *go, u16 *code, int space,
+ int (*sequence_header_func)(struct go7007 *go,
+ unsigned char *buf, int ext))
+{
+ int vop_time_increment_bitlength = vti_bitlen(go);
+ int fps = go->sensor_framerate / go->fps_scale *
+ (go->interlace_coding ? 2 : 1);
+ unsigned char buf[40] = { };
+ int len = sequence_header_func(go, buf, 1);
+ u16 pack[] = {
+ 0x2006, 0,
+ 0xbf08, fps,
+ 0xbf09, 0,
+ 0xbff2, vop_time_increment_bitlength,
+ 0xbff3, (1 << vop_time_increment_bitlength) - 1,
+ 0xbfe6, 0,
+ 0xbfe7, (fps / 1000) << 8,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+
+ 0x2007, 0,
+ 0xc800, buf[2] << 8 | buf[3],
+ 0xc801, buf[4] << 8 | buf[5],
+ 0xc802, buf[6] << 8 | buf[7],
+ 0xc803, buf[8] << 8 | buf[9],
+ 0xc406, 64,
+ 0xc407, len - 64,
+ 0xc61b, 1,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+
+ 0x200e, 0,
+ 0xc808, buf[10] << 8 | buf[11],
+ 0xc809, buf[12] << 8 | buf[13],
+ 0xc80a, buf[14] << 8 | buf[15],
+ 0xc80b, buf[16] << 8 | buf[17],
+ 0xc80c, buf[18] << 8 | buf[19],
+ 0xc80d, buf[20] << 8 | buf[21],
+ 0xc80e, buf[22] << 8 | buf[23],
+ 0xc80f, buf[24] << 8 | buf[25],
+ 0xc810, buf[26] << 8 | buf[27],
+ 0xc811, buf[28] << 8 | buf[29],
+ 0xc812, buf[30] << 8 | buf[31],
+ 0xc813, buf[32] << 8 | buf[33],
+ 0xc814, buf[34] << 8 | buf[35],
+ 0xc815, buf[36] << 8 | buf[37],
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ };
+
+ return copy_packages(code, pack, 3, space);
+}
+
+static int relative_prime(int big, int little)
+{
+ int remainder;
+
+ while (little != 0) {
+ remainder = big % little;
+ big = little;
+ little = remainder;
+ }
+ return big;
+}
+
+static int avsync_to_package(struct go7007 *go, u16 *code, int space)
+{
+ int arate = go->board_info->audio_rate * 1001 * go->fps_scale;
+ int ratio = arate / go->sensor_framerate;
+ int adjratio = ratio * 215 / 100;
+ int rprime = relative_prime(go->sensor_framerate,
+ arate % go->sensor_framerate);
+ int f1 = (arate % go->sensor_framerate) / rprime;
+ int f2 = (go->sensor_framerate - arate % go->sensor_framerate) / rprime;
+ u16 pack[] = {
+ 0x200e, 0,
+ 0xbf98, (u16)((-adjratio) & 0xffff),
+ 0xbf99, (u16)((-adjratio) >> 16),
+ 0xbf92, 0,
+ 0xbf93, 0,
+ 0xbff4, f1 > f2 ? f1 : f2,
+ 0xbff5, f1 < f2 ? f1 : f2,
+ 0xbff6, f1 < f2 ? ratio : ratio + 1,
+ 0xbff7, f1 > f2 ? ratio : ratio + 1,
+ 0xbff8, 0,
+ 0xbff9, 0,
+ 0xbffa, adjratio & 0xffff,
+ 0xbffb, adjratio >> 16,
+ 0xbf94, 0,
+ 0xbf95, 0,
+ 0, 0,
+ };
+
+ return copy_packages(code, pack, 1, space);
+}
+
+static int final_package(struct go7007 *go, u16 *code, int space)
+{
+ int rows = go->interlace_coding ? go->height / 32 : go->height / 16;
+ u16 pack[] = {
+ 0x8000,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2,
+ ((go->board_info->sensor_flags & GO7007_SENSOR_TV) &&
+ (!go->interlace_coding) ?
+ (1 << 14) | (1 << 9) : 0) |
+ ((go->encoder_subsample ? 1 : 0) << 8) |
+ (go->board_info->sensor_flags &
+ GO7007_SENSOR_CONFIG_MASK),
+ ((go->encoder_v_halve ? 1 : 0) << 14) |
+ (go->encoder_v_halve ? rows << 9 : rows << 8) |
+ (go->encoder_h_halve ? 1 << 6 : 0) |
+ (go->encoder_h_halve ? go->width >> 3 : go->width >> 4),
+ (1 << 15) | (go->encoder_v_offset << 6) |
+ (1 << 7) | (go->encoder_h_offset >> 2),
+ (1 << 6),
+ 0,
+ 0,
+ ((go->fps_scale - 1) << 8) |
+ (go->board_info->sensor_flags & GO7007_SENSOR_TV ?
+ (1 << 7) : 0) |
+ 0x41,
+ go->ipb ? 0xd4c : 0x36b,
+ (rows << 8) | (go->width >> 4),
+ go->format == GO7007_FORMAT_MPEG4 ? 0x0404 : 0,
+ (1 << 15) | ((go->interlace_coding ? 1 : 0) << 13) |
+ ((go->closed_gop ? 1 : 0) << 12) |
+ ((go->format == GO7007_FORMAT_MPEG4 ? 1 : 0) << 11) |
+ /* (1 << 9) | */
+ ((go->ipb ? 3 : 0) << 7) |
+ ((go->modet_enable ? 1 : 0) << 2) |
+ ((go->dvd_mode ? 1 : 0) << 1) | 1,
+ (go->format == GO7007_FORMAT_MPEG1 ? 0x89a0 :
+ (go->format == GO7007_FORMAT_MPEG2 ? 0x89a0 :
+ (go->format == GO7007_FORMAT_MJPEG ? 0x89a0 :
+ (go->format == GO7007_FORMAT_MPEG4 ? 0x8920 :
+ (go->format == GO7007_FORMAT_H263 ? 0x8920 : 0))))),
+ go->ipb ? 0x1f15 : 0x1f0b,
+ go->ipb ? 0x0015 : 0x000b,
+ go->ipb ? 0xa800 : 0x5800,
+ 0xffff,
+ 0x0020 + 0x034b * 0,
+ 0x0020 + 0x034b * 1,
+ 0x0020 + 0x034b * 2,
+ 0x0020 + 0x034b * 3,
+ 0x0020 + 0x034b * 4,
+ 0x0020 + 0x034b * 5,
+ go->ipb ? (go->gop_size / 3) : go->gop_size,
+ (go->height >> 4) * (go->width >> 4) * 110 / 100,
+ };
+
+ return copy_packages(code, pack, 1, space);
+}
+
+static int audio_to_package(struct go7007 *go, u16 *code, int space)
+{
+ int clock_config = ((go->board_info->audio_flags &
+ GO7007_AUDIO_I2S_MASTER ? 1 : 0) << 11) |
+ ((go->board_info->audio_flags &
+ GO7007_AUDIO_OKI_MODE ? 1 : 0) << 8) |
+ (((go->board_info->audio_bclk_div / 4) - 1) << 4) |
+ (go->board_info->audio_main_div - 1);
+ u16 pack[] = {
+ 0x200d, 0,
+ 0x9002, 0,
+ 0x9002, 0,
+ 0x9031, 0,
+ 0x9032, 0,
+ 0x9033, 0,
+ 0x9034, 0,
+ 0x9035, 0,
+ 0x9036, 0,
+ 0x9037, 0,
+ 0x9040, 0,
+ 0x9000, clock_config,
+ 0x9001, (go->board_info->audio_flags & 0xffff) |
+ (1 << 9),
+ 0x9000, ((go->board_info->audio_flags &
+ GO7007_AUDIO_I2S_MASTER ?
+ 1 : 0) << 10) |
+ clock_config,
+ 0, 0,
+ 0, 0,
+ 0x2005, 0,
+ 0x9041, 0,
+ 0x9042, 256,
+ 0x9043, 0,
+ 0x9044, 16,
+ 0x9045, 16,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ };
+
+ return copy_packages(code, pack, 2, space);
+}
+
+static int modet_to_package(struct go7007 *go, u16 *code, int space)
+{
+ int ret, mb, i, addr, cnt = 0;
+ u16 pack[32];
+ u16 thresholds[] = {
+ 0x200e, 0,
+ 0xbf82, go->modet[0].pixel_threshold,
+ 0xbf83, go->modet[1].pixel_threshold,
+ 0xbf84, go->modet[2].pixel_threshold,
+ 0xbf85, go->modet[3].pixel_threshold,
+ 0xbf86, go->modet[0].motion_threshold,
+ 0xbf87, go->modet[1].motion_threshold,
+ 0xbf88, go->modet[2].motion_threshold,
+ 0xbf89, go->modet[3].motion_threshold,
+ 0xbf8a, go->modet[0].mb_threshold,
+ 0xbf8b, go->modet[1].mb_threshold,
+ 0xbf8c, go->modet[2].mb_threshold,
+ 0xbf8d, go->modet[3].mb_threshold,
+ 0xbf8e, 0,
+ 0xbf8f, 0,
+ 0, 0,
+ };
+
+ ret = copy_packages(code, thresholds, 1, space);
+ if (ret < 0)
+ return -1;
+ cnt += ret;
+
+ addr = 0xbac0;
+ memset(pack, 0, 64);
+ i = 0;
+ for (mb = 0; mb < 1624; ++mb) {
+ pack[i * 2 + 3] <<= 2;
+ pack[i * 2 + 3] |= go->modet_map[mb];
+ if (mb % 8 != 7)
+ continue;
+ pack[i * 2 + 2] = addr++;
+ ++i;
+ if (i == 10 || mb == 1623) {
+ pack[0] = 0x2000 | i;
+ ret = copy_packages(code + cnt, pack, 1, space - cnt);
+ if (ret < 0)
+ return -1;
+ cnt += ret;
+ i = 0;
+ memset(pack, 0, 64);
+ }
+ pack[i * 2 + 3] = 0;
+ }
+
+ memset(pack, 0, 64);
+ i = 0;
+ for (addr = 0xbb90; addr < 0xbbfa; ++addr) {
+ pack[i * 2 + 2] = addr;
+ pack[i * 2 + 3] = 0;
+ ++i;
+ if (i == 10 || addr == 0xbbf9) {
+ pack[0] = 0x2000 | i;
+ ret = copy_packages(code + cnt, pack, 1, space - cnt);
+ if (ret < 0)
+ return -1;
+ cnt += ret;
+ i = 0;
+ memset(pack, 0, 64);
+ }
+ }
+ return cnt;
+}
+
+static int do_special(struct go7007 *go, u16 type, u16 *code, int space,
+ int *framelen)
+{
+ switch (type) {
+ case SPECIAL_FRM_HEAD:
+ switch (go->format) {
+ case GO7007_FORMAT_MJPEG:
+ return gen_mjpeghdr_to_package(go, code, space);
+ case GO7007_FORMAT_MPEG1:
+ case GO7007_FORMAT_MPEG2:
+ return gen_mpeg1hdr_to_package(go, code, space,
+ framelen);
+ case GO7007_FORMAT_MPEG4:
+ return gen_mpeg4hdr_to_package(go, code, space,
+ framelen);
+ }
+ case SPECIAL_BRC_CTRL:
+ return brctrl_to_package(go, code, space, framelen);
+ case SPECIAL_CONFIG:
+ return config_package(go, code, space);
+ case SPECIAL_SEQHEAD:
+ switch (go->format) {
+ case GO7007_FORMAT_MPEG1:
+ case GO7007_FORMAT_MPEG2:
+ return seqhead_to_package(go, code, space,
+ mpeg1_sequence_header);
+ case GO7007_FORMAT_MPEG4:
+ return seqhead_to_package(go, code, space,
+ mpeg4_sequence_header);
+ default:
+ return 0;
+ }
+ case SPECIAL_AV_SYNC:
+ return avsync_to_package(go, code, space);
+ case SPECIAL_FINAL:
+ return final_package(go, code, space);
+ case SPECIAL_AUDIO:
+ return audio_to_package(go, code, space);
+ case SPECIAL_MODET:
+ return modet_to_package(go, code, space);
+ }
+ printk(KERN_ERR
+ "go7007: firmware file contains unsupported feature %04x\n",
+ type);
+ return -1;
+}
+
+int go7007_construct_fw_image(struct go7007 *go, u8 **fw, int *fwlen)
+{
+ const struct firmware *fw_entry;
+ u16 *code, *src;
+ int framelen[8] = { }; /* holds the lengths of empty frame templates */
+ int codespace = 64 * 1024, i = 0, srclen, chunk_len, chunk_flags;
+ int mode_flag;
+ int ret;
+
+ switch (go->format) {
+ case GO7007_FORMAT_MJPEG:
+ mode_flag = FLAG_MODE_MJPEG;
+ break;
+ case GO7007_FORMAT_MPEG1:
+ mode_flag = FLAG_MODE_MPEG1;
+ break;
+ case GO7007_FORMAT_MPEG2:
+ mode_flag = FLAG_MODE_MPEG2;
+ break;
+ case GO7007_FORMAT_MPEG4:
+ mode_flag = FLAG_MODE_MPEG4;
+ break;
+ default:
+ return -1;
+ }
+ if (request_firmware(&fw_entry, go->board_info->firmware, go->dev)) {
+ printk(KERN_ERR
+ "go7007: unable to load firmware from file \"%s\"\n",
+ go->board_info->firmware);
+ return -1;
+ }
+ code = kmalloc(codespace * 2, GFP_KERNEL);
+ if (code == NULL) {
+ printk(KERN_ERR "go7007: unable to allocate %d bytes for "
+ "firmware construction\n", codespace * 2);
+ goto fw_failed;
+ }
+ memset(code, 0, codespace * 2);
+ src = (u16 *)fw_entry->data;
+ srclen = fw_entry->size / 2;
+ while (srclen >= 2) {
+ chunk_flags = __le16_to_cpu(src[0]);
+ chunk_len = __le16_to_cpu(src[1]);
+ if (chunk_len + 2 > srclen) {
+ printk(KERN_ERR "go7007: firmware file \"%s\" "
+ "appears to be corrupted\n",
+ go->board_info->firmware);
+ goto fw_failed;
+ }
+ if (chunk_flags & mode_flag) {
+ if (chunk_flags & FLAG_SPECIAL) {
+ ret = do_special(go, __le16_to_cpu(src[2]),
+ &code[i], codespace - i, framelen);
+ if (ret < 0) {
+ printk(KERN_ERR "go7007: insufficient "
+ "memory for firmware "
+ "construction\n");
+ goto fw_failed;
+ }
+ i += ret;
+ } else {
+ if (codespace - i < chunk_len) {
+ printk(KERN_ERR "go7007: insufficient "
+ "memory for firmware "
+ "construction\n");
+ goto fw_failed;
+ }
+ memcpy(&code[i], &src[2], chunk_len * 2);
+ i += chunk_len;
+ }
+ }
+ srclen -= chunk_len + 2;
+ src += chunk_len + 2;
+ }
+ release_firmware(fw_entry);
+ *fw = (u8 *)code;
+ *fwlen = i * 2;
+ return 0;
+
+fw_failed:
+ kfree(code);
+ release_firmware(fw_entry);
+ return -1;
+}
diff --git a/drivers/staging/go7007/go7007-i2c.c b/drivers/staging/go7007/go7007-i2c.c
new file mode 100644
index 0000000..10baae3
--- /dev/null
+++ b/drivers/staging/go7007/go7007-i2c.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/unistd.h>
+#include <linux/time.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/semaphore.h>
+#include <linux/uaccess.h>
+#include <asm/system.h>
+
+#include "go7007-priv.h"
+#include "wis-i2c.h"
+
+/************** Registration interface for I2C client drivers **************/
+
+/* Since there's no way to auto-probe the I2C devices connected to the I2C
+ * bus on the go7007, we have this silly little registration system that
+ * client drivers can use to register their I2C driver ID and their
+ * detect_client function (the one that's normally passed to i2c_probe).
+ *
+ * When a new go7007 device is connected, we can look up in a board info
+ * table by the USB or PCI vendor/product/revision ID to determine
+ * which I2C client module to load. The client driver module will register
+ * itself here, and then we can call the registered detect_client function
+ * to force-load a new client at the address listed in the board info table.
+ *
+ * Really the I2C subsystem should have a way to force-load I2C client
+ * drivers when we have a priori knowledge of what's on the bus, especially
+ * since the existing I2C auto-probe mechanism is so hokey, but we'll use
+ * our own mechanism for the time being. */
+
+struct wis_i2c_client_driver {
+ unsigned int id;
+ found_proc found_proc;
+ struct list_head list;
+};
+
+static LIST_HEAD(i2c_client_drivers);
+static DECLARE_MUTEX(i2c_client_driver_list_lock);
+
+/* Client drivers register here by their I2C driver ID */
+int wis_i2c_add_driver(unsigned int id, found_proc found_proc)
+{
+ struct wis_i2c_client_driver *driver;
+
+ driver = kmalloc(sizeof(struct wis_i2c_client_driver), GFP_KERNEL);
+ if (driver == NULL)
+ return -ENOMEM;
+ driver->id = id;
+ driver->found_proc = found_proc;
+
+ down(&i2c_client_driver_list_lock);
+ list_add_tail(&driver->list, &i2c_client_drivers);
+ up(&i2c_client_driver_list_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(wis_i2c_add_driver);
+
+void wis_i2c_del_driver(found_proc found_proc)
+{
+ struct wis_i2c_client_driver *driver, *next;
+
+ down(&i2c_client_driver_list_lock);
+ list_for_each_entry_safe(driver, next, &i2c_client_drivers, list)
+ if (driver->found_proc == found_proc) {
+ list_del(&driver->list);
+ kfree(driver);
+ }
+ up(&i2c_client_driver_list_lock);
+}
+EXPORT_SYMBOL(wis_i2c_del_driver);
+
+/* The main go7007 driver calls this to instantiate a client by driver
+ * ID and bus address, which are both stored in the board info table */
+int wis_i2c_probe_device(struct i2c_adapter *adapter,
+ unsigned int id, int addr)
+{
+ struct wis_i2c_client_driver *driver;
+ int found = 0;
+
+ if (addr < 0 || addr > 0x7f)
+ return -1;
+ down(&i2c_client_driver_list_lock);
+ list_for_each_entry(driver, &i2c_client_drivers, list)
+ if (driver->id == id) {
+ if (driver->found_proc(adapter, addr, 0) == 0)
+ found = 1;
+ break;
+ }
+ up(&i2c_client_driver_list_lock);
+ return found;
+}
+
+/********************* Driver for on-board I2C adapter *********************/
+
+/* #define GO7007_I2C_DEBUG */
+
+#define SPI_I2C_ADDR_BASE 0x1400
+#define STATUS_REG_ADDR (SPI_I2C_ADDR_BASE + 0x2)
+#define I2C_CTRL_REG_ADDR (SPI_I2C_ADDR_BASE + 0x6)
+#define I2C_DEV_UP_ADDR_REG_ADDR (SPI_I2C_ADDR_BASE + 0x7)
+#define I2C_LO_ADDR_REG_ADDR (SPI_I2C_ADDR_BASE + 0x8)
+#define I2C_DATA_REG_ADDR (SPI_I2C_ADDR_BASE + 0x9)
+#define I2C_CLKFREQ_REG_ADDR (SPI_I2C_ADDR_BASE + 0xa)
+
+#define I2C_STATE_MASK 0x0007
+#define I2C_READ_READY_MASK 0x0008
+
+/* There is only one I2C port on the TW2804 that feeds all four GO7007 VIPs
+ * on the Adlink PCI-MPG24, so access is shared between all of them. */
+static DECLARE_MUTEX(adlink_mpg24_i2c_lock);
+
+static int go7007_i2c_xfer(struct go7007 *go, u16 addr, int read,
+ u16 command, int flags, u8 *data)
+{
+ int i, ret = -1;
+ u16 val;
+
+ if (go->status == STATUS_SHUTDOWN)
+ return -1;
+
+#ifdef GO7007_I2C_DEBUG
+ if (read)
+ printk(KERN_DEBUG "go7007-i2c: reading 0x%02x on 0x%02x\n",
+ command, addr);
+ else
+ printk(KERN_DEBUG
+ "go7007-i2c: writing 0x%02x to 0x%02x on 0x%02x\n",
+ *data, command, addr);
+#endif
+
+ down(&go->hw_lock);
+
+ if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) {
+ /* Bridge the I2C port on this GO7007 to the shared bus */
+ down(&adlink_mpg24_i2c_lock);
+ go7007_write_addr(go, 0x3c82, 0x0020);
+ }
+
+ /* Wait for I2C adapter to be ready */
+ for (i = 0; i < 10; ++i) {
+ if (go7007_read_addr(go, STATUS_REG_ADDR, &val) < 0)
+ goto i2c_done;
+ if (!(val & I2C_STATE_MASK))
+ break;
+ msleep(100);
+ }
+ if (i == 10) {
+ printk(KERN_ERR "go7007-i2c: I2C adapter is hung\n");
+ goto i2c_done;
+ }
+
+ /* Set target register (command) */
+ go7007_write_addr(go, I2C_CTRL_REG_ADDR, flags);
+ go7007_write_addr(go, I2C_LO_ADDR_REG_ADDR, command);
+
+ /* If we're writing, send the data and target address and we're done */
+ if (!read) {
+ go7007_write_addr(go, I2C_DATA_REG_ADDR, *data);
+ go7007_write_addr(go, I2C_DEV_UP_ADDR_REG_ADDR,
+ (addr << 9) | (command >> 8));
+ ret = 0;
+ goto i2c_done;
+ }
+
+ /* Otherwise, we're reading. First clear i2c_rx_data_rdy. */
+ if (go7007_read_addr(go, I2C_DATA_REG_ADDR, &val) < 0)
+ goto i2c_done;
+
+ /* Send the target address plus read flag */
+ go7007_write_addr(go, I2C_DEV_UP_ADDR_REG_ADDR,
+ (addr << 9) | 0x0100 | (command >> 8));
+
+ /* Wait for i2c_rx_data_rdy */
+ for (i = 0; i < 10; ++i) {
+ if (go7007_read_addr(go, STATUS_REG_ADDR, &val) < 0)
+ goto i2c_done;
+ if (val & I2C_READ_READY_MASK)
+ break;
+ msleep(100);
+ }
+ if (i == 10) {
+ printk(KERN_ERR "go7007-i2c: I2C adapter is hung\n");
+ goto i2c_done;
+ }
+
+ /* Retrieve the read byte */
+ if (go7007_read_addr(go, I2C_DATA_REG_ADDR, &val) < 0)
+ goto i2c_done;
+ *data = val;
+ ret = 0;
+
+i2c_done:
+ if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) {
+ /* Isolate the I2C port on this GO7007 from the shared bus */
+ go7007_write_addr(go, 0x3c82, 0x0000);
+ up(&adlink_mpg24_i2c_lock);
+ }
+ up(&go->hw_lock);
+ return ret;
+}
+
+static int go7007_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data *data)
+{
+ struct go7007 *go = i2c_get_adapdata(adapter);
+
+ if (size != I2C_SMBUS_BYTE_DATA)
+ return -1;
+ return go7007_i2c_xfer(go, addr, read_write == I2C_SMBUS_READ, command,
+ flags & I2C_CLIENT_SCCB ? 0x10 : 0x00, &data->byte);
+}
+
+/* VERY LIMITED I2C master xfer function -- only needed because the
+ * SMBus functions only support 8-bit commands and the SAA7135 uses
+ * 16-bit commands. The I2C interface on the GO7007, as limited as
+ * it is, does support this mode. */
+
+static int go7007_i2c_master_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg msgs[], int num)
+{
+ struct go7007 *go = i2c_get_adapdata(adapter);
+ int i;
+
+ for (i = 0; i < num; ++i) {
+ /* We can only do two things here -- write three bytes, or
+ * write two bytes and read one byte. */
+ if (msgs[i].len == 2) {
+ if (i + 1 == num || msgs[i].addr != msgs[i + 1].addr ||
+ (msgs[i].flags & I2C_M_RD) ||
+ !(msgs[i + 1].flags & I2C_M_RD) ||
+ msgs[i + 1].len != 1)
+ return -1;
+ if (go7007_i2c_xfer(go, msgs[i].addr, 1,
+ (msgs[i].buf[0] << 8) | msgs[i].buf[1],
+ 0x01, &msgs[i + 1].buf[0]) < 0)
+ return -1;
+ ++i;
+ } else if (msgs[i].len == 3) {
+ if (msgs[i].flags & I2C_M_RD)
+ return -1;
+ if (msgs[i].len != 3)
+ return -1;
+ if (go7007_i2c_xfer(go, msgs[i].addr, 0,
+ (msgs[i].buf[0] << 8) | msgs[i].buf[1],
+ 0x01, &msgs[i].buf[2]) < 0)
+ return -1;
+ } else
+ return -1;
+ }
+
+ return 0;
+}
+
+static u32 go7007_functionality(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_BYTE_DATA;
+}
+
+static struct i2c_algorithm go7007_algo = {
+ .smbus_xfer = go7007_smbus_xfer,
+ .master_xfer = go7007_i2c_master_xfer,
+ .functionality = go7007_functionality,
+};
+
+static struct i2c_adapter go7007_adap_templ = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_TV_ANALOG,
+ .name = "WIS GO7007SB",
+ .id = I2C_ALGO_GO7007,
+ .algo = &go7007_algo,
+};
+
+int go7007_i2c_init(struct go7007 *go)
+{
+ memcpy(&go->i2c_adapter, &go7007_adap_templ,
+ sizeof(go7007_adap_templ));
+ go->i2c_adapter.dev.parent = go->dev;
+ i2c_set_adapdata(&go->i2c_adapter, go);
+ if (i2c_add_adapter(&go->i2c_adapter) < 0) {
+ printk(KERN_ERR
+ "go7007-i2c: error: i2c_add_adapter failed\n");
+ return -1;
+ }
+ return 0;
+}
diff --git a/drivers/staging/go7007/go7007-priv.h b/drivers/staging/go7007/go7007-priv.h
new file mode 100644
index 0000000..005542d
--- /dev/null
+++ b/drivers/staging/go7007/go7007-priv.h
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/*
+ * This is the private include file for the go7007 driver. It should not
+ * be included by anybody but the driver itself, and especially not by
+ * user-space applications.
+ */
+
+struct go7007;
+
+/* IDs to activate board-specific support code */
+#define GO7007_BOARDID_MATRIX_II 0
+#define GO7007_BOARDID_MATRIX_RELOAD 1
+#define GO7007_BOARDID_STAR_TREK 2
+#define GO7007_BOARDID_PCI_VOYAGER 3
+#define GO7007_BOARDID_XMEN 4
+#define GO7007_BOARDID_XMEN_II 5
+#define GO7007_BOARDID_XMEN_III 6
+#define GO7007_BOARDID_MATRIX_REV 7
+#define GO7007_BOARDID_PX_M402U 16
+#define GO7007_BOARDID_PX_TV402U_ANY 17 /* need to check tuner model */
+#define GO7007_BOARDID_PX_TV402U_NA 18 /* detected NTSC tuner */
+#define GO7007_BOARDID_PX_TV402U_EU 19 /* detected PAL tuner */
+#define GO7007_BOARDID_PX_TV402U_JP 20 /* detected NTSC-J tuner */
+#define GO7007_BOARDID_LIFEVIEW_LR192 21 /* TV Walker Ultra */
+#define GO7007_BOARDID_ENDURA 22
+#define GO7007_BOARDID_ADLINK_MPG24 23
+
+/* Various characteristics of each board */
+#define GO7007_BOARD_HAS_AUDIO (1<<0)
+#define GO7007_BOARD_USE_ONBOARD_I2C (1<<1)
+#define GO7007_BOARD_HAS_TUNER (1<<2)
+
+/* Characteristics of sensor devices */
+#define GO7007_SENSOR_VALID_POLAR (1<<0)
+#define GO7007_SENSOR_HREF_POLAR (1<<1)
+#define GO7007_SENSOR_VREF_POLAR (1<<2)
+#define GO7007_SENSOR_FIELD_ID_POLAR (1<<3)
+#define GO7007_SENSOR_BIT_WIDTH (1<<4)
+#define GO7007_SENSOR_VALID_ENABLE (1<<5)
+#define GO7007_SENSOR_656 (1<<6)
+#define GO7007_SENSOR_CONFIG_MASK 0x7f
+#define GO7007_SENSOR_TV (1<<7)
+#define GO7007_SENSOR_VBI (1<<8)
+#define GO7007_SENSOR_SCALING (1<<9)
+
+/* Characteristics of audio sensor devices */
+#define GO7007_AUDIO_I2S_MODE_1 (1)
+#define GO7007_AUDIO_I2S_MODE_2 (2)
+#define GO7007_AUDIO_I2S_MODE_3 (3)
+#define GO7007_AUDIO_BCLK_POLAR (1<<2)
+#define GO7007_AUDIO_WORD_14 (14<<4)
+#define GO7007_AUDIO_WORD_16 (16<<4)
+#define GO7007_AUDIO_ONE_CHANNEL (1<<11)
+#define GO7007_AUDIO_I2S_MASTER (1<<16)
+#define GO7007_AUDIO_OKI_MODE (1<<17)
+
+struct go7007_board_info {
+ char *firmware;
+ unsigned int flags;
+ int hpi_buffer_cap;
+ unsigned int sensor_flags;
+ int sensor_width;
+ int sensor_height;
+ int sensor_framerate;
+ int sensor_h_offset;
+ int sensor_v_offset;
+ unsigned int audio_flags;
+ int audio_rate;
+ int audio_bclk_div;
+ int audio_main_div;
+ int num_i2c_devs;
+ struct {
+ int id;
+ int addr;
+ } i2c_devs[4];
+ int num_inputs;
+ struct {
+ int video_input;
+ int audio_input;
+ char *name;
+ } inputs[4];
+};
+
+struct go7007_hpi_ops {
+ int (*interface_reset)(struct go7007 *go);
+ int (*write_interrupt)(struct go7007 *go, int addr, int data);
+ int (*read_interrupt)(struct go7007 *go);
+ int (*stream_start)(struct go7007 *go);
+ int (*stream_stop)(struct go7007 *go);
+ int (*send_firmware)(struct go7007 *go, u8 *data, int len);
+};
+
+/* The video buffer size must be a multiple of PAGE_SIZE */
+#define GO7007_BUF_PAGES (128 * 1024 / PAGE_SIZE)
+#define GO7007_BUF_SIZE (GO7007_BUF_PAGES << PAGE_SHIFT)
+
+struct go7007_buffer {
+ struct go7007 *go; /* Reverse reference for VMA ops */
+ int index; /* Reverse reference for DQBUF */
+ enum { BUF_STATE_IDLE, BUF_STATE_QUEUED, BUF_STATE_DONE } state;
+ u32 seq;
+ struct timeval timestamp;
+ struct list_head stream;
+ struct page *pages[GO7007_BUF_PAGES + 1]; /* extra for straddling */
+ unsigned long user_addr;
+ unsigned int page_count;
+ unsigned int offset;
+ unsigned int bytesused;
+ unsigned int frame_offset;
+ u32 modet_active;
+ int mapped;
+};
+
+struct go7007_file {
+ struct go7007 *go;
+ struct semaphore lock;
+ int buf_count;
+ struct go7007_buffer *bufs;
+};
+
+#define GO7007_FORMAT_MJPEG 0
+#define GO7007_FORMAT_MPEG4 1
+#define GO7007_FORMAT_MPEG1 2
+#define GO7007_FORMAT_MPEG2 3
+#define GO7007_FORMAT_H263 4
+
+#define GO7007_RATIO_1_1 0
+#define GO7007_RATIO_4_3 1
+#define GO7007_RATIO_16_9 2
+
+enum go7007_parser_state {
+ STATE_DATA,
+ STATE_00,
+ STATE_00_00,
+ STATE_00_00_01,
+ STATE_FF,
+ STATE_VBI_LEN_A,
+ STATE_VBI_LEN_B,
+ STATE_MODET_MAP,
+ STATE_UNPARSED,
+};
+
+struct go7007 {
+ struct device *dev;
+ struct go7007_board_info *board_info;
+ unsigned int board_id;
+ int tuner_type;
+ int channel_number; /* for multi-channel boards like Adlink PCI-MPG24 */
+ char name[64];
+ struct video_device *video_dev;
+ int ref_count;
+ enum { STATUS_INIT, STATUS_ONLINE, STATUS_SHUTDOWN } status;
+ spinlock_t spinlock;
+ struct semaphore hw_lock;
+ int streaming;
+ int in_use;
+ int audio_enabled;
+
+ /* Video input */
+ int input;
+ enum { GO7007_STD_NTSC, GO7007_STD_PAL, GO7007_STD_OTHER } standard;
+ int sensor_framerate;
+ int width;
+ int height;
+ int encoder_h_offset;
+ int encoder_v_offset;
+ unsigned int encoder_h_halve:1;
+ unsigned int encoder_v_halve:1;
+ unsigned int encoder_subsample:1;
+
+ /* Encoder config */
+ int format;
+ int bitrate;
+ int fps_scale;
+ int pali;
+ int aspect_ratio;
+ int gop_size;
+ unsigned int ipb:1;
+ unsigned int closed_gop:1;
+ unsigned int repeat_seqhead:1;
+ unsigned int seq_header_enable:1;
+ unsigned int gop_header_enable:1;
+ unsigned int dvd_mode:1;
+ unsigned int interlace_coding:1;
+
+ /* Motion detection */
+ unsigned int modet_enable:1;
+ struct {
+ unsigned int enable:1;
+ int pixel_threshold;
+ int motion_threshold;
+ int mb_threshold;
+ } modet[4];
+ unsigned char modet_map[1624];
+ unsigned char active_map[216];
+
+ /* Video streaming */
+ struct go7007_buffer *active_buf;
+ enum go7007_parser_state state;
+ int parse_length;
+ u16 modet_word;
+ int seen_frame;
+ u32 next_seq;
+ struct list_head stream;
+ wait_queue_head_t frame_waitq;
+
+ /* Audio streaming */
+ void (*audio_deliver)(struct go7007 *go, u8 *buf, int length);
+ void *snd_context;
+
+ /* I2C */
+ int i2c_adapter_online;
+ struct i2c_adapter i2c_adapter;
+
+ /* HPI driver */
+ struct go7007_hpi_ops *hpi_ops;
+ void *hpi_context;
+ int interrupt_available;
+ wait_queue_head_t interrupt_waitq;
+ unsigned short interrupt_value;
+ unsigned short interrupt_data;
+};
+
+/* All of these must be called with the hpi_lock semaphore held! */
+#define go7007_interface_reset(go) \
+ ((go)->hpi_ops->interface_reset(go))
+#define go7007_write_interrupt(go, x, y) \
+ ((go)->hpi_ops->write_interrupt)((go), (x), (y))
+#define go7007_stream_start(go) \
+ ((go)->hpi_ops->stream_start(go))
+#define go7007_stream_stop(go) \
+ ((go)->hpi_ops->stream_stop(go))
+#define go7007_send_firmware(go, x, y) \
+ ((go)->hpi_ops->send_firmware)((go), (x), (y))
+#define go7007_write_addr(go, x, y) \
+ ((go)->hpi_ops->write_interrupt)((go), (x)|0x8000, (y))
+
+/* go7007-driver.c */
+int go7007_read_addr(struct go7007 *go, u16 addr, u16 *data);
+int go7007_read_interrupt(struct go7007 *go, u16 *value, u16 *data);
+int go7007_boot_encoder(struct go7007 *go, int init_i2c);
+int go7007_reset_encoder(struct go7007 *go);
+int go7007_register_encoder(struct go7007 *go);
+int go7007_start_encoder(struct go7007 *go);
+void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length);
+struct go7007 *go7007_alloc(struct go7007_board_info *board,
+ struct device *dev);
+void go7007_remove(struct go7007 *go);
+
+/* go7007-fw.c */
+int go7007_construct_fw_image(struct go7007 *go, u8 **fw, int *fwlen);
+
+/* go7007-i2c.c */
+int go7007_i2c_init(struct go7007 *go);
+int go7007_i2c_remove(struct go7007 *go);
+
+/* go7007-v4l2.c */
+int go7007_v4l2_init(struct go7007 *go);
+void go7007_v4l2_remove(struct go7007 *go);
+
+/* snd-go7007.c */
+int go7007_snd_init(struct go7007 *go);
+int go7007_snd_remove(struct go7007 *go);
diff --git a/drivers/staging/go7007/go7007-usb.c b/drivers/staging/go7007/go7007-usb.c
new file mode 100644
index 0000000..d4ed6d2
--- /dev/null
+++ b/drivers/staging/go7007/go7007-usb.c
@@ -0,0 +1,1229 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/mm.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <asm/byteorder.h>
+#include <media/tvaudio.h>
+
+#include "go7007-priv.h"
+#include "wis-i2c.h"
+
+static unsigned int assume_endura;
+module_param(assume_endura, int, 0644);
+MODULE_PARM_DESC(assume_endura, "when probing fails, hardware is a Pelco Endura");
+
+/* #define GO7007_USB_DEBUG */
+/* #define GO7007_I2C_DEBUG */ /* for debugging the EZ-USB I2C adapter */
+
+#define HPI_STATUS_ADDR 0xFFF4
+#define INT_PARAM_ADDR 0xFFF6
+#define INT_INDEX_ADDR 0xFFF8
+
+/*
+ * Pipes on EZ-USB interface:
+ * 0 snd - Control
+ * 0 rcv - Control
+ * 2 snd - Download firmware (control)
+ * 4 rcv - Read Interrupt (interrupt)
+ * 6 rcv - Read Video (bulk)
+ * 8 rcv - Read Audio (bulk)
+ */
+
+#define GO7007_USB_EZUSB (1<<0)
+#define GO7007_USB_EZUSB_I2C (1<<1)
+
+struct go7007_usb_board {
+ unsigned int flags;
+ struct go7007_board_info main_info;
+};
+
+struct go7007_usb {
+ struct go7007_usb_board *board;
+ struct semaphore i2c_lock;
+ struct usb_device *usbdev;
+ struct urb *video_urbs[8];
+ struct urb *audio_urbs[8];
+ struct urb *intr_urb;
+};
+
+/*********************** Product specification data ***********************/
+
+static struct go7007_usb_board board_matrix_ii = {
+ .flags = GO7007_USB_EZUSB,
+ .main_info = {
+ .firmware = "go7007tv.bin",
+ .flags = GO7007_BOARD_HAS_AUDIO |
+ GO7007_BOARD_USE_ONBOARD_I2C,
+ .audio_flags = GO7007_AUDIO_I2S_MODE_1 |
+ GO7007_AUDIO_WORD_16,
+ .audio_rate = 48000,
+ .audio_bclk_div = 8,
+ .audio_main_div = 2,
+ .hpi_buffer_cap = 7,
+ .sensor_flags = GO7007_SENSOR_656 |
+ GO7007_SENSOR_VALID_ENABLE |
+ GO7007_SENSOR_TV |
+ GO7007_SENSOR_VBI |
+ GO7007_SENSOR_SCALING,
+ .num_i2c_devs = 1,
+ .i2c_devs = {
+ {
+ .id = I2C_DRIVERID_WIS_SAA7115,
+ .addr = 0x20,
+ },
+ },
+ .num_inputs = 2,
+ .inputs = {
+ {
+ .video_input = 0,
+ .name = "Composite",
+ },
+ {
+ .video_input = 9,
+ .name = "S-Video",
+ },
+ },
+ },
+};
+
+static struct go7007_usb_board board_matrix_reload = {
+ .flags = GO7007_USB_EZUSB,
+ .main_info = {
+ .firmware = "go7007tv.bin",
+ .flags = GO7007_BOARD_HAS_AUDIO |
+ GO7007_BOARD_USE_ONBOARD_I2C,
+ .audio_flags = GO7007_AUDIO_I2S_MODE_1 |
+ GO7007_AUDIO_I2S_MASTER |
+ GO7007_AUDIO_WORD_16,
+ .audio_rate = 48000,
+ .audio_bclk_div = 8,
+ .audio_main_div = 2,
+ .hpi_buffer_cap = 7,
+ .sensor_flags = GO7007_SENSOR_656 |
+ GO7007_SENSOR_TV,
+ .num_i2c_devs = 1,
+ .i2c_devs = {
+ {
+ .id = I2C_DRIVERID_WIS_SAA7113,
+ .addr = 0x25,
+ },
+ },
+ .num_inputs = 2,
+ .inputs = {
+ {
+ .video_input = 0,
+ .name = "Composite",
+ },
+ {
+ .video_input = 9,
+ .name = "S-Video",
+ },
+ },
+ },
+};
+
+static struct go7007_usb_board board_star_trek = {
+ .flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C,
+ .main_info = {
+ .firmware = "go7007tv.bin",
+ .flags = GO7007_BOARD_HAS_AUDIO, /* |
+ GO7007_BOARD_HAS_TUNER, */
+ .sensor_flags = GO7007_SENSOR_656 |
+ GO7007_SENSOR_VALID_ENABLE |
+ GO7007_SENSOR_TV |
+ GO7007_SENSOR_VBI |
+ GO7007_SENSOR_SCALING,
+ .audio_flags = GO7007_AUDIO_I2S_MODE_1 |
+ GO7007_AUDIO_WORD_16,
+ .audio_bclk_div = 8,
+ .audio_main_div = 2,
+ .hpi_buffer_cap = 7,
+ .num_i2c_devs = 1,
+ .i2c_devs = {
+ {
+ .id = I2C_DRIVERID_WIS_SAA7115,
+ .addr = 0x20,
+ },
+ },
+ .num_inputs = 2,
+ .inputs = {
+ {
+ .video_input = 1,
+ /* .audio_input = AUDIO_EXTERN, */
+ .name = "Composite",
+ },
+ {
+ .video_input = 8,
+ /* .audio_input = AUDIO_EXTERN, */
+ .name = "S-Video",
+ },
+ /* {
+ * .video_input = 3,
+ * .audio_input = AUDIO_TUNER,
+ * .name = "Tuner",
+ * },
+ */
+ },
+ },
+};
+
+static struct go7007_usb_board board_px_tv402u = {
+ .flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C,
+ .main_info = {
+ .firmware = "go7007tv.bin",
+ .flags = GO7007_BOARD_HAS_AUDIO |
+ GO7007_BOARD_HAS_TUNER,
+ .sensor_flags = GO7007_SENSOR_656 |
+ GO7007_SENSOR_VALID_ENABLE |
+ GO7007_SENSOR_TV |
+ GO7007_SENSOR_VBI |
+ GO7007_SENSOR_SCALING,
+ .audio_flags = GO7007_AUDIO_I2S_MODE_1 |
+ GO7007_AUDIO_WORD_16,
+ .audio_bclk_div = 8,
+ .audio_main_div = 2,
+ .hpi_buffer_cap = 7,
+ .num_i2c_devs = 3,
+ .i2c_devs = {
+ {
+ .id = I2C_DRIVERID_WIS_SAA7115,
+ .addr = 0x20,
+ },
+ {
+ .id = I2C_DRIVERID_WIS_UDA1342,
+ .addr = 0x1a,
+ },
+ {
+ .id = I2C_DRIVERID_WIS_SONY_TUNER,
+ .addr = 0x60,
+ },
+ },
+ .num_inputs = 3,
+ .inputs = {
+ {
+ .video_input = 1,
+ .audio_input = TVAUDIO_INPUT_EXTERN,
+ .name = "Composite",
+ },
+ {
+ .video_input = 8,
+ .audio_input = TVAUDIO_INPUT_EXTERN,
+ .name = "S-Video",
+ },
+ {
+ .video_input = 3,
+ .audio_input = TVAUDIO_INPUT_TUNER,
+ .name = "Tuner",
+ },
+ },
+ },
+};
+
+static struct go7007_usb_board board_xmen = {
+ .flags = 0,
+ .main_info = {
+ .firmware = "go7007tv.bin",
+ .flags = GO7007_BOARD_USE_ONBOARD_I2C,
+ .hpi_buffer_cap = 0,
+ .sensor_flags = GO7007_SENSOR_VREF_POLAR,
+ .sensor_width = 320,
+ .sensor_height = 240,
+ .sensor_framerate = 30030,
+ .audio_flags = GO7007_AUDIO_ONE_CHANNEL |
+ GO7007_AUDIO_I2S_MODE_3 |
+ GO7007_AUDIO_WORD_14 |
+ GO7007_AUDIO_I2S_MASTER |
+ GO7007_AUDIO_BCLK_POLAR |
+ GO7007_AUDIO_OKI_MODE,
+ .audio_rate = 8000,
+ .audio_bclk_div = 48,
+ .audio_main_div = 1,
+ .num_i2c_devs = 1,
+ .i2c_devs = {
+ {
+ .id = I2C_DRIVERID_WIS_OV7640,
+ .addr = 0x21,
+ },
+ },
+ .num_inputs = 1,
+ .inputs = {
+ {
+ .name = "Camera",
+ },
+ },
+ },
+};
+
+static struct go7007_usb_board board_matrix_revolution = {
+ .flags = GO7007_USB_EZUSB,
+ .main_info = {
+ .firmware = "go7007tv.bin",
+ .flags = GO7007_BOARD_HAS_AUDIO |
+ GO7007_BOARD_USE_ONBOARD_I2C,
+ .audio_flags = GO7007_AUDIO_I2S_MODE_1 |
+ GO7007_AUDIO_I2S_MASTER |
+ GO7007_AUDIO_WORD_16,
+ .audio_rate = 48000,
+ .audio_bclk_div = 8,
+ .audio_main_div = 2,
+ .hpi_buffer_cap = 7,
+ .sensor_flags = GO7007_SENSOR_656 |
+ GO7007_SENSOR_TV |
+ GO7007_SENSOR_VBI,
+ .num_i2c_devs = 1,
+ .i2c_devs = {
+ {
+ .id = I2C_DRIVERID_WIS_TW9903,
+ .addr = 0x44,
+ },
+ },
+ .num_inputs = 2,
+ .inputs = {
+ {
+ .video_input = 2,
+ .name = "Composite",
+ },
+ {
+ .video_input = 8,
+ .name = "S-Video",
+ },
+ },
+ },
+};
+
+static struct go7007_usb_board board_lifeview_lr192 = {
+ .flags = GO7007_USB_EZUSB,
+ .main_info = {
+ .firmware = "go7007tv.bin",
+ .flags = GO7007_BOARD_HAS_AUDIO |
+ GO7007_BOARD_USE_ONBOARD_I2C,
+ .audio_flags = GO7007_AUDIO_I2S_MODE_1 |
+ GO7007_AUDIO_WORD_16,
+ .audio_rate = 48000,
+ .audio_bclk_div = 8,
+ .audio_main_div = 2,
+ .hpi_buffer_cap = 7,
+ .sensor_flags = GO7007_SENSOR_656 |
+ GO7007_SENSOR_VALID_ENABLE |
+ GO7007_SENSOR_TV |
+ GO7007_SENSOR_VBI |
+ GO7007_SENSOR_SCALING,
+ .num_i2c_devs = 0,
+ .num_inputs = 1,
+ .inputs = {
+ {
+ .video_input = 0,
+ .name = "Composite",
+ },
+ },
+ },
+};
+
+static struct go7007_usb_board board_endura = {
+ .flags = 0,
+ .main_info = {
+ .firmware = "go7007tv.bin",
+ .flags = 0,
+ .audio_flags = GO7007_AUDIO_I2S_MODE_1 |
+ GO7007_AUDIO_I2S_MASTER |
+ GO7007_AUDIO_WORD_16,
+ .audio_rate = 8000,
+ .audio_bclk_div = 48,
+ .audio_main_div = 8,
+ .hpi_buffer_cap = 0,
+ .sensor_flags = GO7007_SENSOR_656 |
+ GO7007_SENSOR_TV,
+ .sensor_h_offset = 8,
+ .num_i2c_devs = 0,
+ .num_inputs = 1,
+ .inputs = {
+ {
+ .name = "Camera",
+ },
+ },
+ },
+};
+
+static struct go7007_usb_board board_adlink_mpg24 = {
+ .flags = 0,
+ .main_info = {
+ .firmware = "go7007tv.bin",
+ .flags = GO7007_BOARD_USE_ONBOARD_I2C,
+ .audio_flags = GO7007_AUDIO_I2S_MODE_1 |
+ GO7007_AUDIO_I2S_MASTER |
+ GO7007_AUDIO_WORD_16,
+ .audio_rate = 48000,
+ .audio_bclk_div = 8,
+ .audio_main_div = 2,
+ .hpi_buffer_cap = 0,
+ .sensor_flags = GO7007_SENSOR_656 |
+ GO7007_SENSOR_TV |
+ GO7007_SENSOR_VBI,
+ .num_i2c_devs = 1,
+ .i2c_devs = {
+ {
+ .id = I2C_DRIVERID_WIS_TW2804,
+ .addr = 0x00, /* yes, really */
+ },
+ },
+ .num_inputs = 1,
+ .inputs = {
+ {
+ .name = "Composite",
+ },
+ },
+ },
+};
+
+static struct usb_device_id go7007_usb_id_table[] = {
+ {
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |
+ USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
+ .idProduct = 0x7007, /* Product ID of GO7007SB chip */
+ .bcdDevice_lo = 0x200, /* Revision number of XMen */
+ .bcdDevice_hi = 0x200,
+ .bInterfaceClass = 255,
+ .bInterfaceSubClass = 0,
+ .bInterfaceProtocol = 255,
+ .driver_info = (kernel_ulong_t)GO7007_BOARDID_XMEN,
+ },
+ {
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
+ .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
+ .idProduct = 0x7007, /* Product ID of GO7007SB chip */
+ .bcdDevice_lo = 0x202, /* Revision number of Matrix II */
+ .bcdDevice_hi = 0x202,
+ .driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_II,
+ },
+ {
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
+ .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
+ .idProduct = 0x7007, /* Product ID of GO7007SB chip */
+ .bcdDevice_lo = 0x204, /* Revision number of Matrix */
+ .bcdDevice_hi = 0x204, /* Reloaded */
+ .driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_RELOAD,
+ },
+ {
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |
+ USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
+ .idProduct = 0x7007, /* Product ID of GO7007SB chip */
+ .bcdDevice_lo = 0x205, /* Revision number of XMen-II */
+ .bcdDevice_hi = 0x205,
+ .bInterfaceClass = 255,
+ .bInterfaceSubClass = 0,
+ .bInterfaceProtocol = 255,
+ .driver_info = (kernel_ulong_t)GO7007_BOARDID_XMEN_II,
+ },
+ {
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
+ .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
+ .idProduct = 0x7007, /* Product ID of GO7007SB chip */
+ .bcdDevice_lo = 0x208, /* Revision number of Star Trek */
+ .bcdDevice_hi = 0x208,
+ .driver_info = (kernel_ulong_t)GO7007_BOARDID_STAR_TREK,
+ },
+ {
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION |
+ USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
+ .idProduct = 0x7007, /* Product ID of GO7007SB chip */
+ .bcdDevice_lo = 0x209, /* Revision number of XMen-III */
+ .bcdDevice_hi = 0x209,
+ .bInterfaceClass = 255,
+ .bInterfaceSubClass = 0,
+ .bInterfaceProtocol = 255,
+ .driver_info = (kernel_ulong_t)GO7007_BOARDID_XMEN_III,
+ },
+ {
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
+ .idVendor = 0x0eb1, /* Vendor ID of WIS Technologies */
+ .idProduct = 0x7007, /* Product ID of GO7007SB chip */
+ .bcdDevice_lo = 0x210, /* Revision number of Matrix */
+ .bcdDevice_hi = 0x210, /* Revolution */
+ .driver_info = (kernel_ulong_t)GO7007_BOARDID_MATRIX_REV,
+ },
+ {
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
+ .idVendor = 0x093b, /* Vendor ID of Plextor */
+ .idProduct = 0xa102, /* Product ID of M402U */
+ .bcdDevice_lo = 0x1, /* revision number of Blueberry */
+ .bcdDevice_hi = 0x1,
+ .driver_info = (kernel_ulong_t)GO7007_BOARDID_PX_M402U,
+ },
+ {
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
+ .idVendor = 0x093b, /* Vendor ID of Plextor */
+ .idProduct = 0xa104, /* Product ID of TV402U */
+ .bcdDevice_lo = 0x1,
+ .bcdDevice_hi = 0x1,
+ .driver_info = (kernel_ulong_t)GO7007_BOARDID_PX_TV402U_ANY,
+ },
+ {
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION,
+ .idVendor = 0x10fd, /* Vendor ID of Anubis Electronics */
+ .idProduct = 0xde00, /* Product ID of Lifeview LR192 */
+ .bcdDevice_lo = 0x1,
+ .bcdDevice_hi = 0x1,
+ .driver_info = (kernel_ulong_t)GO7007_BOARDID_LIFEVIEW_LR192,
+ },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, go7007_usb_id_table);
+
+/********************* Driver for EZ-USB HPI interface *********************/
+
+static int go7007_usb_vendor_request(struct go7007 *go, int request,
+ int value, int index, void *transfer_buffer, int length, int in)
+{
+ struct go7007_usb *usb = go->hpi_context;
+ int timeout = 5000;
+
+ if (in) {
+ return usb_control_msg(usb->usbdev,
+ usb_rcvctrlpipe(usb->usbdev, 0), request,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ value, index, transfer_buffer, length, timeout);
+ } else {
+ return usb_control_msg(usb->usbdev,
+ usb_sndctrlpipe(usb->usbdev, 0), request,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, transfer_buffer, length, timeout);
+ }
+}
+
+static int go7007_usb_interface_reset(struct go7007 *go)
+{
+ struct go7007_usb *usb = go->hpi_context;
+ u16 intr_val, intr_data;
+
+ /* Reset encoder */
+ if (go7007_write_interrupt(go, 0x0001, 0x0001) < 0)
+ return -1;
+ msleep(100);
+
+ if (usb->board->flags & GO7007_USB_EZUSB) {
+ /* Reset buffer in EZ-USB */
+#ifdef GO7007_USB_DEBUG
+ printk(KERN_DEBUG "go7007-usb: resetting EZ-USB buffers\n");
+#endif
+ if (go7007_usb_vendor_request(go, 0x10, 0, 0, NULL, 0, 0) < 0 ||
+ go7007_usb_vendor_request(go, 0x10, 0, 0, NULL, 0, 0) < 0)
+ return -1;
+
+ /* Reset encoder again */
+ if (go7007_write_interrupt(go, 0x0001, 0x0001) < 0)
+ return -1;
+ msleep(100);
+ }
+
+ /* Wait for an interrupt to indicate successful hardware reset */
+ if (go7007_read_interrupt(go, &intr_val, &intr_data) < 0 ||
+ (intr_val & ~0x1) != 0x55aa) {
+ printk(KERN_ERR
+ "go7007-usb: unable to reset the USB interface\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int go7007_usb_ezusb_write_interrupt(struct go7007 *go,
+ int addr, int data)
+{
+ struct go7007_usb *usb = go->hpi_context;
+ int i, r;
+ u16 status_reg;
+ int timeout = 500;
+
+#ifdef GO7007_USB_DEBUG
+ printk(KERN_DEBUG
+ "go7007-usb: WriteInterrupt: %04x %04x\n", addr, data);
+#endif
+
+ for (i = 0; i < 100; ++i) {
+ r = usb_control_msg(usb->usbdev,
+ usb_rcvctrlpipe(usb->usbdev, 0), 0x14,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0, HPI_STATUS_ADDR, &status_reg,
+ sizeof(status_reg), timeout);
+ if (r < 0)
+ goto write_int_error;
+ __le16_to_cpus(&status_reg);
+ if (!(status_reg & 0x0010))
+ break;
+ msleep(10);
+ }
+ if (i == 100) {
+ printk(KERN_ERR
+ "go7007-usb: device is hung, status reg = 0x%04x\n",
+ status_reg);
+ return -1;
+ }
+ r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 0), 0x12,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE, data,
+ INT_PARAM_ADDR, NULL, 0, timeout);
+ if (r < 0)
+ goto write_int_error;
+ r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 0),
+ 0x12, USB_TYPE_VENDOR | USB_RECIP_DEVICE, addr,
+ INT_INDEX_ADDR, NULL, 0, timeout);
+ if (r < 0)
+ goto write_int_error;
+ return 0;
+
+write_int_error:
+ printk(KERN_ERR "go7007-usb: error in WriteInterrupt: %d\n", r);
+ return r;
+}
+
+static int go7007_usb_onboard_write_interrupt(struct go7007 *go,
+ int addr, int data)
+{
+ struct go7007_usb *usb = go->hpi_context;
+ u8 *tbuf;
+ int r;
+ int timeout = 500;
+
+#ifdef GO7007_USB_DEBUG
+ printk(KERN_DEBUG
+ "go7007-usb: WriteInterrupt: %04x %04x\n", addr, data);
+#endif
+
+ tbuf = kmalloc(8, GFP_KERNEL);
+ if (tbuf == NULL)
+ return -ENOMEM;
+ memset(tbuf, 0, 8);
+ tbuf[0] = data & 0xff;
+ tbuf[1] = data >> 8;
+ tbuf[2] = addr & 0xff;
+ tbuf[3] = addr >> 8;
+ r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 2), 0x00,
+ USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0x55aa,
+ 0xf0f0, tbuf, 8, timeout);
+ kfree(tbuf);
+ if (r < 0) {
+ printk(KERN_ERR "go7007-usb: error in WriteInterrupt: %d\n", r);
+ return r;
+ }
+ return 0;
+}
+
+static void go7007_usb_readinterrupt_complete(struct urb *urb)
+{
+ struct go7007 *go = (struct go7007 *)urb->context;
+ u16 *regs = (u16 *)urb->transfer_buffer;
+
+ if (urb->status != 0) {
+ if (urb->status != -ESHUTDOWN &&
+ go->status != STATUS_SHUTDOWN) {
+ printk(KERN_ERR
+ "go7007-usb: error in read interrupt: %d\n",
+ urb->status);
+ } else {
+ wake_up(&go->interrupt_waitq);
+ return;
+ }
+ } else if (urb->actual_length != urb->transfer_buffer_length) {
+ printk(KERN_ERR "go7007-usb: short read in interrupt pipe!\n");
+ } else {
+ go->interrupt_available = 1;
+ go->interrupt_data = __le16_to_cpu(regs[0]);
+ go->interrupt_value = __le16_to_cpu(regs[1]);
+#ifdef GO7007_USB_DEBUG
+ printk(KERN_DEBUG "go7007-usb: ReadInterrupt: %04x %04x\n",
+ go->interrupt_value, go->interrupt_data);
+#endif
+ }
+
+ wake_up(&go->interrupt_waitq);
+}
+
+static int go7007_usb_read_interrupt(struct go7007 *go)
+{
+ struct go7007_usb *usb = go->hpi_context;
+ int r;
+
+ r = usb_submit_urb(usb->intr_urb, GFP_KERNEL);
+ if (r < 0) {
+ printk(KERN_ERR
+ "go7007-usb: unable to submit interrupt urb: %d\n", r);
+ return r;
+ }
+ return 0;
+}
+
+static void go7007_usb_read_video_pipe_complete(struct urb *urb)
+{
+ struct go7007 *go = (struct go7007 *)urb->context;
+ int r;
+
+ if (!go->streaming) {
+ wake_up_interruptible(&go->frame_waitq);
+ return;
+ }
+ if (urb->status != 0) {
+ printk(KERN_ERR "go7007-usb: error in video pipe: %d\n",
+ urb->status);
+ return;
+ }
+ if (urb->actual_length != urb->transfer_buffer_length) {
+ printk(KERN_ERR "go7007-usb: short read in video pipe!\n");
+ return;
+ }
+ go7007_parse_video_stream(go, urb->transfer_buffer, urb->actual_length);
+ r = usb_submit_urb(urb, GFP_ATOMIC);
+ if (r < 0)
+ printk(KERN_ERR "go7007-usb: error in video pipe: %d\n", r);
+}
+
+static void go7007_usb_read_audio_pipe_complete(struct urb *urb)
+{
+ struct go7007 *go = (struct go7007 *)urb->context;
+ int r;
+
+ if (!go->streaming)
+ return;
+ if (urb->status != 0) {
+ printk(KERN_ERR "go7007-usb: error in audio pipe: %d\n",
+ urb->status);
+ return;
+ }
+ if (urb->actual_length != urb->transfer_buffer_length) {
+ printk(KERN_ERR "go7007-usb: short read in audio pipe!\n");
+ return;
+ }
+ if (go->audio_deliver != NULL)
+ go->audio_deliver(go, urb->transfer_buffer, urb->actual_length);
+ r = usb_submit_urb(urb, GFP_ATOMIC);
+ if (r < 0)
+ printk(KERN_ERR "go7007-usb: error in audio pipe: %d\n", r);
+}
+
+static int go7007_usb_stream_start(struct go7007 *go)
+{
+ struct go7007_usb *usb = go->hpi_context;
+ int i, r;
+
+ for (i = 0; i < 8; ++i) {
+ r = usb_submit_urb(usb->video_urbs[i], GFP_KERNEL);
+ if (r < 0) {
+ printk(KERN_ERR "go7007-usb: error submitting video "
+ "urb %d: %d\n", i, r);
+ goto video_submit_failed;
+ }
+ }
+ if (!go->audio_enabled)
+ return 0;
+
+ for (i = 0; i < 8; ++i) {
+ r = usb_submit_urb(usb->audio_urbs[i], GFP_KERNEL);
+ if (r < 0) {
+ printk(KERN_ERR "go7007-usb: error submitting audio "
+ "urb %d: %d\n", i, r);
+ goto audio_submit_failed;
+ }
+ }
+ return 0;
+
+audio_submit_failed:
+ for (i = 0; i < 8; ++i)
+ usb_kill_urb(usb->audio_urbs[i]);
+video_submit_failed:
+ for (i = 0; i < 8; ++i)
+ usb_kill_urb(usb->video_urbs[i]);
+ return -1;
+}
+
+static int go7007_usb_stream_stop(struct go7007 *go)
+{
+ struct go7007_usb *usb = go->hpi_context;
+ int i;
+
+ if (go->status == STATUS_SHUTDOWN)
+ return 0;
+ for (i = 0; i < 8; ++i)
+ usb_kill_urb(usb->video_urbs[i]);
+ if (go->audio_enabled)
+ for (i = 0; i < 8; ++i)
+ usb_kill_urb(usb->audio_urbs[i]);
+ return 0;
+}
+
+static int go7007_usb_send_firmware(struct go7007 *go, u8 *data, int len)
+{
+ struct go7007_usb *usb = go->hpi_context;
+ int transferred, pipe;
+ int timeout = 500;
+
+#ifdef GO7007_USB_DEBUG
+ printk(KERN_DEBUG "go7007-usb: DownloadBuffer sending %d bytes\n", len);
+#endif
+
+ if (usb->board->flags & GO7007_USB_EZUSB)
+ pipe = usb_sndbulkpipe(usb->usbdev, 2);
+ else
+ pipe = usb_sndbulkpipe(usb->usbdev, 3);
+
+ return usb_bulk_msg(usb->usbdev, pipe, data, len,
+ &transferred, timeout);
+}
+
+static struct go7007_hpi_ops go7007_usb_ezusb_hpi_ops = {
+ .interface_reset = go7007_usb_interface_reset,
+ .write_interrupt = go7007_usb_ezusb_write_interrupt,
+ .read_interrupt = go7007_usb_read_interrupt,
+ .stream_start = go7007_usb_stream_start,
+ .stream_stop = go7007_usb_stream_stop,
+ .send_firmware = go7007_usb_send_firmware,
+};
+
+static struct go7007_hpi_ops go7007_usb_onboard_hpi_ops = {
+ .interface_reset = go7007_usb_interface_reset,
+ .write_interrupt = go7007_usb_onboard_write_interrupt,
+ .read_interrupt = go7007_usb_read_interrupt,
+ .stream_start = go7007_usb_stream_start,
+ .stream_stop = go7007_usb_stream_stop,
+ .send_firmware = go7007_usb_send_firmware,
+};
+
+/********************* Driver for EZ-USB I2C adapter *********************/
+
+static int go7007_usb_i2c_master_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg msgs[], int num)
+{
+ struct go7007 *go = i2c_get_adapdata(adapter);
+ struct go7007_usb *usb = go->hpi_context;
+ u8 buf[16];
+ int buf_len, i;
+ int ret = -1;
+
+ if (go->status == STATUS_SHUTDOWN)
+ return -1;
+
+ down(&usb->i2c_lock);
+
+ for (i = 0; i < num; ++i) {
+ /* The hardware command is "write some bytes then read some
+ * bytes", so we try to coalesce a write followed by a read
+ * into a single USB transaction */
+ if (i + 1 < num && msgs[i].addr == msgs[i + 1].addr &&
+ !(msgs[i].flags & I2C_M_RD) &&
+ (msgs[i + 1].flags & I2C_M_RD)) {
+#ifdef GO7007_I2C_DEBUG
+ printk(KERN_DEBUG "go7007-usb: i2c write/read %d/%d "
+ "bytes on %02x\n", msgs[i].len,
+ msgs[i + 1].len, msgs[i].addr);
+#endif
+ buf[0] = 0x01;
+ buf[1] = msgs[i].len + 1;
+ buf[2] = msgs[i].addr << 1;
+ memcpy(&buf[3], msgs[i].buf, msgs[i].len);
+ buf_len = msgs[i].len + 3;
+ buf[buf_len++] = msgs[++i].len;
+ } else if (msgs[i].flags & I2C_M_RD) {
+#ifdef GO7007_I2C_DEBUG
+ printk(KERN_DEBUG "go7007-usb: i2c read %d "
+ "bytes on %02x\n", msgs[i].len,
+ msgs[i].addr);
+#endif
+ buf[0] = 0x01;
+ buf[1] = 1;
+ buf[2] = msgs[i].addr << 1;
+ buf[3] = msgs[i].len;
+ buf_len = 4;
+ } else {
+#ifdef GO7007_I2C_DEBUG
+ printk(KERN_DEBUG "go7007-usb: i2c write %d "
+ "bytes on %02x\n", msgs[i].len,
+ msgs[i].addr);
+#endif
+ buf[0] = 0x00;
+ buf[1] = msgs[i].len + 1;
+ buf[2] = msgs[i].addr << 1;
+ memcpy(&buf[3], msgs[i].buf, msgs[i].len);
+ buf_len = msgs[i].len + 3;
+ buf[buf_len++] = 0;
+ }
+ if (go7007_usb_vendor_request(go, 0x24, 0, 0,
+ buf, buf_len, 0) < 0)
+ goto i2c_done;
+ if (msgs[i].flags & I2C_M_RD) {
+ memset(buf, 0, sizeof(buf));
+ if (go7007_usb_vendor_request(go, 0x25, 0, 0, buf,
+ msgs[i].len + 1, 1) < 0)
+ goto i2c_done;
+ memcpy(msgs[i].buf, buf + 1, msgs[i].len);
+ }
+ }
+ ret = 0;
+
+i2c_done:
+ up(&usb->i2c_lock);
+ return ret;
+}
+
+static u32 go7007_usb_functionality(struct i2c_adapter *adapter)
+{
+ /* No errors are reported by the hardware, so we don't bother
+ * supporting quick writes to avoid confusing probing */
+ return (I2C_FUNC_SMBUS_EMUL) & ~I2C_FUNC_SMBUS_QUICK;
+}
+
+static struct i2c_algorithm go7007_usb_algo = {
+ .master_xfer = go7007_usb_i2c_master_xfer,
+ .functionality = go7007_usb_functionality,
+};
+
+static struct i2c_adapter go7007_usb_adap_templ = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_TV_ANALOG,
+ .name = "WIS GO7007SB EZ-USB",
+ .id = I2C_ALGO_GO7007_USB,
+ .algo = &go7007_usb_algo,
+};
+
+/********************* USB add/remove functions *********************/
+
+static int go7007_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct go7007 *go;
+ struct go7007_usb *usb;
+ struct go7007_usb_board *board;
+ struct usb_device *usbdev = interface_to_usbdev(intf);
+ char *name;
+ int video_pipe, i, v_urb_len;
+
+ printk(KERN_DEBUG "go7007-usb: probing new GO7007 USB board\n");
+
+ switch (id->driver_info) {
+ case GO7007_BOARDID_MATRIX_II:
+ name = "WIS Matrix II or compatible";
+ board = &board_matrix_ii;
+ break;
+ case GO7007_BOARDID_MATRIX_RELOAD:
+ name = "WIS Matrix Reloaded or compatible";
+ board = &board_matrix_reload;
+ break;
+ case GO7007_BOARDID_MATRIX_REV:
+ name = "WIS Matrix Revolution or compatible";
+ board = &board_matrix_revolution;
+ break;
+ case GO7007_BOARDID_STAR_TREK:
+ name = "WIS Star Trek or compatible";
+ board = &board_star_trek;
+ break;
+ case GO7007_BOARDID_XMEN:
+ name = "WIS XMen or compatible";
+ board = &board_xmen;
+ break;
+ case GO7007_BOARDID_XMEN_II:
+ name = "WIS XMen II or compatible";
+ board = &board_xmen;
+ break;
+ case GO7007_BOARDID_XMEN_III:
+ name = "WIS XMen III or compatible";
+ board = &board_xmen;
+ break;
+ case GO7007_BOARDID_PX_M402U:
+ name = "Plextor PX-M402U";
+ board = &board_matrix_ii;
+ break;
+ case GO7007_BOARDID_PX_TV402U_ANY:
+ name = "Plextor PX-TV402U (unknown tuner)";
+ board = &board_px_tv402u;
+ break;
+ case GO7007_BOARDID_LIFEVIEW_LR192:
+ printk(KERN_ERR "go7007-usb: The Lifeview TV Walker Ultra "
+ "is not supported. Sorry!\n");
+ return 0;
+ name = "Lifeview TV Walker Ultra";
+ board = &board_lifeview_lr192;
+ break;
+ default:
+ printk(KERN_ERR "go7007-usb: unknown board ID %d!\n",
+ (unsigned int)id->driver_info);
+ return 0;
+ }
+
+ usb = kmalloc(sizeof(struct go7007_usb), GFP_KERNEL);
+ if (usb == NULL)
+ return -ENOMEM;
+ memset(usb, 0, sizeof(struct go7007_usb));
+
+ /* Allocate the URB and buffer for receiving incoming interrupts */
+ usb->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (usb->intr_urb == NULL)
+ goto allocfail;
+ usb->intr_urb->transfer_buffer = kmalloc(2*sizeof(u16), GFP_KERNEL);
+ if (usb->intr_urb->transfer_buffer == NULL)
+ goto allocfail;
+
+ go = go7007_alloc(&board->main_info, &intf->dev);
+ if (go == NULL)
+ goto allocfail;
+ usb->board = board;
+ usb->usbdev = usbdev;
+ go->board_id = id->driver_info;
+ strncpy(go->name, name, sizeof(go->name));
+ if (board->flags & GO7007_USB_EZUSB)
+ go->hpi_ops = &go7007_usb_ezusb_hpi_ops;
+ else
+ go->hpi_ops = &go7007_usb_onboard_hpi_ops;
+ go->hpi_context = usb;
+ usb_fill_int_urb(usb->intr_urb, usb->usbdev,
+ usb_rcvintpipe(usb->usbdev, 4),
+ usb->intr_urb->transfer_buffer, 2*sizeof(u16),
+ go7007_usb_readinterrupt_complete, go, 8);
+ usb_set_intfdata(intf, go);
+
+ /* Boot the GO7007 */
+ if (go7007_boot_encoder(go, go->board_info->flags &
+ GO7007_BOARD_USE_ONBOARD_I2C) < 0)
+ goto initfail;
+
+ /* Register the EZ-USB I2C adapter, if we're using it */
+ if (board->flags & GO7007_USB_EZUSB_I2C) {
+ memcpy(&go->i2c_adapter, &go7007_usb_adap_templ,
+ sizeof(go7007_usb_adap_templ));
+ init_MUTEX(&usb->i2c_lock);
+ go->i2c_adapter.dev.parent = go->dev;
+ i2c_set_adapdata(&go->i2c_adapter, go);
+ if (i2c_add_adapter(&go->i2c_adapter) < 0) {
+ printk(KERN_ERR
+ "go7007-usb: error: i2c_add_adapter failed\n");
+ goto initfail;
+ }
+ go->i2c_adapter_online = 1;
+ }
+
+ /* Pelco and Adlink reused the XMen and XMen-III vendor and product
+ * IDs for their own incompatible designs. We can detect XMen boards
+ * by probing the sensor, but there is no way to probe the sensors on
+ * the Pelco and Adlink designs so we default to the Adlink. If it
+ * is actually a Pelco, the user must set the assume_endura module
+ * parameter. */
+ if ((go->board_id == GO7007_BOARDID_XMEN ||
+ go->board_id == GO7007_BOARDID_XMEN_III) &&
+ go->i2c_adapter_online) {
+ union i2c_smbus_data data;
+
+ /* Check to see if register 0x0A is 0x76 */
+ i2c_smbus_xfer(&go->i2c_adapter, 0x21, I2C_CLIENT_SCCB,
+ I2C_SMBUS_READ, 0x0A, I2C_SMBUS_BYTE_DATA, &data);
+ if (data.byte != 0x76) {
+ if (assume_endura) {
+ go->board_id = GO7007_BOARDID_ENDURA;
+ usb->board = board = &board_endura;
+ go->board_info = &board->main_info;
+ strncpy(go->name, "Pelco Endura",
+ sizeof(go->name));
+ } else {
+ u16 channel;
+
+ /* set GPIO5 to be an output, currently low */
+ go7007_write_addr(go, 0x3c82, 0x0000);
+ go7007_write_addr(go, 0x3c80, 0x00df);
+ /* read channel number from GPIO[1:0] */
+ go7007_read_addr(go, 0x3c81, &channel);
+ channel &= 0x3;
+ go->board_id = GO7007_BOARDID_ADLINK_MPG24;
+ usb->board = board = &board_adlink_mpg24;
+ go->board_info = &board->main_info;
+ go->channel_number = channel;
+ snprintf(go->name, sizeof(go->name),
+ "Adlink PCI-MPG24, channel #%d",
+ channel);
+ }
+ }
+ }
+
+ /* Probe the tuner model on the TV402U */
+ if (go->board_id == GO7007_BOARDID_PX_TV402U_ANY) {
+ u8 data[3];
+
+ /* Board strapping indicates tuner model */
+ if (go7007_usb_vendor_request(go, 0x41, 0, 0, data, 3, 1) < 0) {
+ printk(KERN_ERR "go7007-usb: GPIO read failed!\n");
+ goto initfail;
+ }
+ switch (data[0] >> 6) {
+ case 1:
+ go->board_id = GO7007_BOARDID_PX_TV402U_EU;
+ go->tuner_type = TUNER_SONY_BTF_PG472Z;
+ strncpy(go->name, "Plextor PX-TV402U-EU",
+ sizeof(go->name));
+ break;
+ case 2:
+ go->board_id = GO7007_BOARDID_PX_TV402U_JP;
+ go->tuner_type = TUNER_SONY_BTF_PK467Z;
+ strncpy(go->name, "Plextor PX-TV402U-JP",
+ sizeof(go->name));
+ break;
+ case 3:
+ go->board_id = GO7007_BOARDID_PX_TV402U_NA;
+ go->tuner_type = TUNER_SONY_BTF_PB463Z;
+ strncpy(go->name, "Plextor PX-TV402U-NA",
+ sizeof(go->name));
+ break;
+ default:
+ printk(KERN_DEBUG "go7007-usb: unable to detect "
+ "tuner type!\n");
+ break;
+ }
+ /* Configure tuner mode selection inputs connected
+ * to the EZ-USB GPIO output pins */
+ if (go7007_usb_vendor_request(go, 0x40, 0x7f02, 0,
+ NULL, 0, 0) < 0) {
+ printk(KERN_ERR
+ "go7007-usb: GPIO write failed!\n");
+ goto initfail;
+ }
+ }
+
+ /* Print a nasty message if the user attempts to use a USB2.0 device in
+ * a USB1.1 port. There will be silent corruption of the stream. */
+ if ((board->flags & GO7007_USB_EZUSB) &&
+ usbdev->speed != USB_SPEED_HIGH)
+ printk(KERN_ERR "go7007-usb: *** WARNING *** This device "
+ "must be connected to a USB 2.0 port! "
+ "Attempting to capture video through a USB 1.1 "
+ "port will result in stream corruption, even "
+ "at low bitrates!\n");
+
+ /* Do any final GO7007 initialization, then register the
+ * V4L2 and ALSA interfaces */
+ if (go7007_register_encoder(go) < 0)
+ goto initfail;
+
+ /* Allocate the URBs and buffers for receiving the video stream */
+ if (board->flags & GO7007_USB_EZUSB) {
+ v_urb_len = 1024;
+ video_pipe = usb_rcvbulkpipe(usb->usbdev, 6);
+ } else {
+ v_urb_len = 512;
+ video_pipe = usb_rcvbulkpipe(usb->usbdev, 1);
+ }
+ for (i = 0; i < 8; ++i) {
+ usb->video_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
+ if (usb->video_urbs[i] == NULL)
+ goto initfail;
+ usb->video_urbs[i]->transfer_buffer =
+ kmalloc(v_urb_len, GFP_KERNEL);
+ if (usb->video_urbs[i]->transfer_buffer == NULL)
+ goto initfail;
+ usb_fill_bulk_urb(usb->video_urbs[i], usb->usbdev, video_pipe,
+ usb->video_urbs[i]->transfer_buffer, v_urb_len,
+ go7007_usb_read_video_pipe_complete, go);
+ }
+
+ /* Allocate the URBs and buffers for receiving the audio stream */
+ if ((board->flags & GO7007_USB_EZUSB) && go->audio_enabled)
+ for (i = 0; i < 8; ++i) {
+ usb->audio_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
+ if (usb->audio_urbs[i] == NULL)
+ goto initfail;
+ usb->audio_urbs[i]->transfer_buffer = kmalloc(4096,
+ GFP_KERNEL);
+ if (usb->audio_urbs[i]->transfer_buffer == NULL)
+ goto initfail;
+ usb_fill_bulk_urb(usb->audio_urbs[i], usb->usbdev,
+ usb_rcvbulkpipe(usb->usbdev, 8),
+ usb->audio_urbs[i]->transfer_buffer, 4096,
+ go7007_usb_read_audio_pipe_complete, go);
+ }
+
+
+ go->status = STATUS_ONLINE;
+ return 0;
+
+initfail:
+ go->status = STATUS_SHUTDOWN;
+ return 0;
+
+allocfail:
+ if (usb->intr_urb) {
+ kfree(usb->intr_urb->transfer_buffer);
+ usb_free_urb(usb->intr_urb);
+ }
+ kfree(usb);
+ return -ENOMEM;
+}
+
+static void go7007_usb_disconnect(struct usb_interface *intf)
+{
+ struct go7007 *go = usb_get_intfdata(intf);
+ struct go7007_usb *usb = go->hpi_context;
+ int i;
+
+ go->status = STATUS_SHUTDOWN;
+ usb_kill_urb(usb->intr_urb);
+
+ /* Free USB-related structs */
+ for (i = 0; i < 8; ++i) {
+ if (usb->video_urbs[i] != NULL) {
+ if (usb->video_urbs[i]->transfer_buffer != NULL)
+ kfree(usb->video_urbs[i]->transfer_buffer);
+ usb_free_urb(usb->video_urbs[i]);
+ }
+ if (usb->audio_urbs[i] != NULL) {
+ if (usb->audio_urbs[i]->transfer_buffer != NULL)
+ kfree(usb->audio_urbs[i]->transfer_buffer);
+ usb_free_urb(usb->audio_urbs[i]);
+ }
+ }
+ kfree(usb->intr_urb->transfer_buffer);
+ usb_free_urb(usb->intr_urb);
+
+ kfree(go->hpi_context);
+
+ go7007_remove(go);
+}
+
+static struct usb_driver go7007_usb_driver = {
+ .name = "go7007",
+ .probe = go7007_usb_probe,
+ .disconnect = go7007_usb_disconnect,
+ .id_table = go7007_usb_id_table,
+};
+
+static int __init go7007_usb_init(void)
+{
+ return usb_register(&go7007_usb_driver);
+}
+
+static void __exit go7007_usb_cleanup(void)
+{
+ usb_deregister(&go7007_usb_driver);
+}
+
+module_init(go7007_usb_init);
+module_exit(go7007_usb_cleanup);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/go7007/go7007-v4l2.c b/drivers/staging/go7007/go7007-v4l2.c
new file mode 100644
index 0000000..d54d019
--- /dev/null
+++ b/drivers/staging/go7007/go7007-v4l2.c
@@ -0,0 +1,1503 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/fs.h>
+#include <linux/unistd.h>
+#include <linux/time.h>
+#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
+#include <linux/videodev.h>
+#include <linux/video_decoder.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <linux/i2c.h>
+#include <linux/semaphore.h>
+#include <linux/uaccess.h>
+#include <asm/system.h>
+
+#include "go7007.h"
+#include "go7007-priv.h"
+#include "wis-i2c.h"
+
+static void deactivate_buffer(struct go7007_buffer *gobuf)
+{
+ int i;
+
+ if (gobuf->state != BUF_STATE_IDLE) {
+ list_del(&gobuf->stream);
+ gobuf->state = BUF_STATE_IDLE;
+ }
+ if (gobuf->page_count > 0) {
+ for (i = 0; i < gobuf->page_count; ++i)
+ page_cache_release(gobuf->pages[i]);
+ gobuf->page_count = 0;
+ }
+}
+
+static void abort_queued(struct go7007 *go)
+{
+ struct go7007_buffer *gobuf, *next;
+
+ list_for_each_entry_safe(gobuf, next, &go->stream, stream) {
+ deactivate_buffer(gobuf);
+ }
+}
+
+static int go7007_streamoff(struct go7007 *go)
+{
+ int retval = -EINVAL;
+ unsigned long flags;
+
+ down(&go->hw_lock);
+ if (go->streaming) {
+ go->streaming = 0;
+ go7007_stream_stop(go);
+ spin_lock_irqsave(&go->spinlock, flags);
+ abort_queued(go);
+ spin_unlock_irqrestore(&go->spinlock, flags);
+ go7007_reset_encoder(go);
+ retval = 0;
+ }
+ up(&go->hw_lock);
+ return 0;
+}
+
+static int go7007_open(struct inode *inode, struct file *file)
+{
+ struct go7007 *go = video_get_drvdata(video_devdata(file));
+ struct go7007_file *gofh;
+
+ if (go->status != STATUS_ONLINE)
+ return -EBUSY;
+ gofh = kmalloc(sizeof(struct go7007_file), GFP_KERNEL);
+ if (gofh == NULL)
+ return -ENOMEM;
+ ++go->ref_count;
+ gofh->go = go;
+ init_MUTEX(&gofh->lock);
+ gofh->buf_count = 0;
+ file->private_data = gofh;
+ return 0;
+}
+
+static int go7007_release(struct inode *inode, struct file *file)
+{
+ struct go7007_file *gofh = file->private_data;
+ struct go7007 *go = gofh->go;
+
+ if (gofh->buf_count > 0) {
+ go7007_streamoff(go);
+ go->in_use = 0;
+ kfree(gofh->bufs);
+ gofh->buf_count = 0;
+ }
+ kfree(gofh);
+ if (--go->ref_count == 0)
+ kfree(go);
+ file->private_data = NULL;
+ return 0;
+}
+
+static u32 get_frame_type_flag(struct go7007_buffer *gobuf, int format)
+{
+ u8 *f = page_address(gobuf->pages[0]);
+
+ switch (format) {
+ case GO7007_FORMAT_MJPEG:
+ return V4L2_BUF_FLAG_KEYFRAME;
+ case GO7007_FORMAT_MPEG4:
+ switch ((f[gobuf->frame_offset + 4] >> 6) & 0x3) {
+ case 0:
+ return V4L2_BUF_FLAG_KEYFRAME;
+ case 1:
+ return V4L2_BUF_FLAG_PFRAME;
+ case 2:
+ return V4L2_BUF_FLAG_BFRAME;
+ default:
+ return 0;
+ }
+ case GO7007_FORMAT_MPEG1:
+ case GO7007_FORMAT_MPEG2:
+ switch ((f[gobuf->frame_offset + 5] >> 3) & 0x7) {
+ case 1:
+ return V4L2_BUF_FLAG_KEYFRAME;
+ case 2:
+ return V4L2_BUF_FLAG_PFRAME;
+ case 3:
+ return V4L2_BUF_FLAG_BFRAME;
+ default:
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try)
+{
+ int sensor_height = 0, sensor_width = 0;
+ int width, height, i;
+
+ if (fmt != NULL && fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG &&
+ fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MPEG &&
+ fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MPEG4)
+ return -EINVAL;
+
+ switch (go->standard) {
+ case GO7007_STD_NTSC:
+ sensor_width = 720;
+ sensor_height = 480;
+ break;
+ case GO7007_STD_PAL:
+ sensor_width = 720;
+ sensor_height = 576;
+ break;
+ case GO7007_STD_OTHER:
+ sensor_width = go->board_info->sensor_width;
+ sensor_height = go->board_info->sensor_height;
+ break;
+ }
+
+ if (fmt == NULL) {
+ width = sensor_width;
+ height = sensor_height;
+ } else if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) {
+ if (fmt->fmt.pix.width > sensor_width)
+ width = sensor_width;
+ else if (fmt->fmt.pix.width < 144)
+ width = 144;
+ else
+ width = fmt->fmt.pix.width & ~0x0f;
+
+ if (fmt->fmt.pix.height > sensor_height)
+ height = sensor_height;
+ else if (fmt->fmt.pix.height < 96)
+ height = 96;
+ else
+ height = fmt->fmt.pix.height & ~0x0f;
+ } else {
+ int requested_size = fmt->fmt.pix.width * fmt->fmt.pix.height;
+ int sensor_size = sensor_width * sensor_height;
+
+ if (64 * requested_size < 9 * sensor_size) {
+ width = sensor_width / 4;
+ height = sensor_height / 4;
+ } else if (64 * requested_size < 36 * sensor_size) {
+ width = sensor_width / 2;
+ height = sensor_height / 2;
+ } else {
+ width = sensor_width;
+ height = sensor_height;
+ }
+ width &= ~0xf;
+ height &= ~0xf;
+ }
+
+ if (fmt != NULL) {
+ u32 pixelformat = fmt->fmt.pix.pixelformat;
+
+ memset(fmt, 0, sizeof(*fmt));
+ fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fmt->fmt.pix.width = width;
+ fmt->fmt.pix.height = height;
+ fmt->fmt.pix.pixelformat = pixelformat;
+ fmt->fmt.pix.field = V4L2_FIELD_NONE;
+ fmt->fmt.pix.bytesperline = 0;
+ fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE;
+ fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* ?? */
+ }
+
+ if (try)
+ return 0;
+
+ go->width = width;
+ go->height = height;
+ go->encoder_h_offset = go->board_info->sensor_h_offset;
+ go->encoder_v_offset = go->board_info->sensor_v_offset;
+ for (i = 0; i < 4; ++i)
+ go->modet[i].enable = 0;
+ for (i = 0; i < 1624; ++i)
+ go->modet_map[i] = 0;
+
+ if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) {
+ struct video_decoder_resolution res;
+
+ res.width = width;
+ if (height > sensor_height / 2) {
+ res.height = height / 2;
+ go->encoder_v_halve = 0;
+ } else {
+ res.height = height;
+ go->encoder_v_halve = 1;
+ }
+ if (go->i2c_adapter_online)
+ i2c_clients_command(&go->i2c_adapter,
+ DECODER_SET_RESOLUTION, &res);
+ } else {
+ if (width <= sensor_width / 4) {
+ go->encoder_h_halve = 1;
+ go->encoder_v_halve = 1;
+ go->encoder_subsample = 1;
+ } else if (width <= sensor_width / 2) {
+ go->encoder_h_halve = 1;
+ go->encoder_v_halve = 1;
+ go->encoder_subsample = 0;
+ } else {
+ go->encoder_h_halve = 0;
+ go->encoder_v_halve = 0;
+ go->encoder_subsample = 0;
+ }
+ }
+
+ if (fmt == NULL)
+ return 0;
+
+ switch (fmt->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_MPEG:
+ if (go->format == GO7007_FORMAT_MPEG1 ||
+ go->format == GO7007_FORMAT_MPEG2 ||
+ go->format == GO7007_FORMAT_MPEG4)
+ break;
+ go->format = GO7007_FORMAT_MPEG1;
+ go->pali = 0;
+ go->aspect_ratio = GO7007_RATIO_1_1;
+ go->gop_size = go->sensor_framerate / 1000;
+ go->ipb = 0;
+ go->closed_gop = 1;
+ go->repeat_seqhead = 1;
+ go->seq_header_enable = 1;
+ go->gop_header_enable = 1;
+ go->dvd_mode = 0;
+ break;
+ /* Backwards compatibility only! */
+ case V4L2_PIX_FMT_MPEG4:
+ if (go->format == GO7007_FORMAT_MPEG4)
+ break;
+ go->format = GO7007_FORMAT_MPEG4;
+ go->pali = 0xf5;
+ go->aspect_ratio = GO7007_RATIO_1_1;
+ go->gop_size = go->sensor_framerate / 1000;
+ go->ipb = 0;
+ go->closed_gop = 1;
+ go->repeat_seqhead = 1;
+ go->seq_header_enable = 1;
+ go->gop_header_enable = 1;
+ go->dvd_mode = 0;
+ break;
+ case V4L2_PIX_FMT_MJPEG:
+ go->format = GO7007_FORMAT_MJPEG;
+ go->pali = 0;
+ go->aspect_ratio = GO7007_RATIO_1_1;
+ go->gop_size = 0;
+ go->ipb = 0;
+ go->closed_gop = 0;
+ go->repeat_seqhead = 0;
+ go->seq_header_enable = 0;
+ go->gop_header_enable = 0;
+ go->dvd_mode = 0;
+ break;
+ }
+ return 0;
+}
+
+static int clip_to_modet_map(struct go7007 *go, int region,
+ struct v4l2_clip *clip_list)
+{
+ struct v4l2_clip clip, *clip_ptr;
+ int x, y, mbnum;
+
+ /* Check if coordinates are OK and if any macroblocks are already
+ * used by other regions (besides 0) */
+ clip_ptr = clip_list;
+ while (clip_ptr) {
+ if (copy_from_user(&clip, clip_ptr, sizeof(clip)))
+ return -EFAULT;
+ if (clip.c.left < 0 || (clip.c.left & 0xF) ||
+ clip.c.width <= 0 || (clip.c.width & 0xF))
+ return -EINVAL;
+ if (clip.c.left + clip.c.width > go->width)
+ return -EINVAL;
+ if (clip.c.top < 0 || (clip.c.top & 0xF) ||
+ clip.c.height <= 0 || (clip.c.height & 0xF))
+ return -EINVAL;
+ if (clip.c.top + clip.c.height > go->height)
+ return -EINVAL;
+ for (y = 0; y < clip.c.height; y += 16)
+ for (x = 0; x < clip.c.width; x += 16) {
+ mbnum = (go->width >> 4) *
+ ((clip.c.top + y) >> 4) +
+ ((clip.c.left + x) >> 4);
+ if (go->modet_map[mbnum] != 0 &&
+ go->modet_map[mbnum] != region)
+ return -EBUSY;
+ }
+ clip_ptr = clip.next;
+ }
+
+ /* Clear old region macroblocks */
+ for (mbnum = 0; mbnum < 1624; ++mbnum)
+ if (go->modet_map[mbnum] == region)
+ go->modet_map[mbnum] = 0;
+
+ /* Claim macroblocks in this list */
+ clip_ptr = clip_list;
+ while (clip_ptr) {
+ if (copy_from_user(&clip, clip_ptr, sizeof(clip)))
+ return -EFAULT;
+ for (y = 0; y < clip.c.height; y += 16)
+ for (x = 0; x < clip.c.width; x += 16) {
+ mbnum = (go->width >> 4) *
+ ((clip.c.top + y) >> 4) +
+ ((clip.c.left + x) >> 4);
+ go->modet_map[mbnum] = region;
+ }
+ clip_ptr = clip.next;
+ }
+ return 0;
+}
+
+static int go7007_do_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg)
+{
+ struct go7007_file *gofh = file->private_data;
+ struct go7007 *go = gofh->go;
+ unsigned long flags;
+ int retval = 0;
+
+ switch (cmd) {
+ case VIDIOC_QUERYCAP:
+ {
+ struct v4l2_capability *cap = arg;
+
+ memset(cap, 0, sizeof(*cap));
+ strcpy(cap->driver, "go7007");
+ strncpy(cap->card, go->name, sizeof(cap->card));
+ cap->version = KERNEL_VERSION(0, 9, 8);
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING; /* | V4L2_CAP_AUDIO; */
+ if (go->board_info->flags & GO7007_BOARD_HAS_TUNER)
+ cap->capabilities |= V4L2_CAP_TUNER;
+ return 0;
+ }
+ case VIDIOC_ENUM_FMT:
+ {
+ struct v4l2_fmtdesc *fmt = arg;
+ unsigned int index;
+ char *desc;
+ u32 pixelformat;
+
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ switch (fmt->index) {
+ case 0:
+ pixelformat = V4L2_PIX_FMT_MJPEG;
+ desc = "Motion-JPEG";
+ break;
+ case 1:
+ pixelformat = V4L2_PIX_FMT_MPEG;
+ desc = "MPEG1/MPEG2/MPEG4";
+ break;
+ default:
+ return -EINVAL;
+ }
+ index = fmt->index;
+ memset(fmt, 0, sizeof(*fmt));
+ fmt->index = index;
+ fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fmt->flags = V4L2_FMT_FLAG_COMPRESSED;
+ strncpy(fmt->description, desc, sizeof(fmt->description));
+ fmt->pixelformat = pixelformat;
+
+ return 0;
+ }
+ case VIDIOC_TRY_FMT:
+ {
+ struct v4l2_format *fmt = arg;
+
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ return set_capture_size(go, fmt, 1);
+ }
+ case VIDIOC_G_FMT:
+ {
+ struct v4l2_format *fmt = arg;
+
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ memset(fmt, 0, sizeof(*fmt));
+ fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fmt->fmt.pix.width = go->width;
+ fmt->fmt.pix.height = go->height;
+ fmt->fmt.pix.pixelformat = go->format == GO7007_FORMAT_MJPEG ?
+ V4L2_PIX_FMT_MJPEG : V4L2_PIX_FMT_MPEG;
+ fmt->fmt.pix.field = V4L2_FIELD_NONE;
+ fmt->fmt.pix.bytesperline = 0;
+ fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE;
+ fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* ?? */
+ return 0;
+ }
+ case VIDIOC_S_FMT:
+ {
+ struct v4l2_format *fmt = arg;
+
+ if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (go->streaming)
+ return -EBUSY;
+ return set_capture_size(go, fmt, 0);
+ }
+ case VIDIOC_G_FBUF:
+ case VIDIOC_S_FBUF:
+ return -EINVAL;
+ case VIDIOC_REQBUFS:
+ {
+ struct v4l2_requestbuffers *req = arg;
+ unsigned int count, i;
+
+ if (go->streaming)
+ return -EBUSY;
+ if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ req->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+
+ down(&gofh->lock);
+ retval = -EBUSY;
+ for (i = 0; i < gofh->buf_count; ++i)
+ if (gofh->bufs[i].mapped > 0)
+ goto unlock_and_return;
+ down(&go->hw_lock);
+ if (go->in_use > 0 && gofh->buf_count == 0) {
+ up(&go->hw_lock);
+ goto unlock_and_return;
+ }
+ if (gofh->buf_count > 0)
+ kfree(gofh->bufs);
+ retval = -ENOMEM;
+ count = req->count;
+ if (count > 0) {
+ if (count < 2)
+ count = 2;
+ if (count > 32)
+ count = 32;
+ gofh->bufs = kmalloc(count *
+ sizeof(struct go7007_buffer),
+ GFP_KERNEL);
+ if (gofh->bufs == NULL) {
+ up(&go->hw_lock);
+ goto unlock_and_return;
+ }
+ memset(gofh->bufs, 0,
+ count * sizeof(struct go7007_buffer));
+ for (i = 0; i < count; ++i) {
+ gofh->bufs[i].go = go;
+ gofh->bufs[i].index = i;
+ gofh->bufs[i].state = BUF_STATE_IDLE;
+ gofh->bufs[i].mapped = 0;
+ }
+ go->in_use = 1;
+ } else {
+ go->in_use = 0;
+ }
+ gofh->buf_count = count;
+ up(&go->hw_lock);
+ up(&gofh->lock);
+ memset(req, 0, sizeof(*req));
+ req->count = count;
+ req->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ req->memory = V4L2_MEMORY_MMAP;
+ return 0;
+ }
+ case VIDIOC_QUERYBUF:
+ {
+ struct v4l2_buffer *buf = arg;
+ unsigned int index;
+
+ retval = -EINVAL;
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ index = buf->index;
+ down(&gofh->lock);
+ if (index >= gofh->buf_count)
+ goto unlock_and_return;
+ memset(buf, 0, sizeof(*buf));
+ buf->index = index;
+ buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ switch (gofh->bufs[index].state) {
+ case BUF_STATE_QUEUED:
+ buf->flags = V4L2_BUF_FLAG_QUEUED;
+ break;
+ case BUF_STATE_DONE:
+ buf->flags = V4L2_BUF_FLAG_DONE;
+ break;
+ default:
+ buf->flags = 0;
+ }
+ if (gofh->bufs[index].mapped)
+ buf->flags |= V4L2_BUF_FLAG_MAPPED;
+ buf->memory = V4L2_MEMORY_MMAP;
+ buf->m.offset = index * GO7007_BUF_SIZE;
+ buf->length = GO7007_BUF_SIZE;
+ up(&gofh->lock);
+
+ return 0;
+ }
+ case VIDIOC_QBUF:
+ {
+ struct v4l2_buffer *buf = arg;
+ struct go7007_buffer *gobuf;
+ int ret;
+
+ retval = -EINVAL;
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ buf->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+ down(&gofh->lock);
+ if (buf->index < 0 || buf->index >= gofh->buf_count)
+ goto unlock_and_return;
+ gobuf = &gofh->bufs[buf->index];
+ if (gobuf->mapped == 0)
+ goto unlock_and_return;
+ retval = -EBUSY;
+ if (gobuf->state != BUF_STATE_IDLE)
+ goto unlock_and_return;
+ /* offset will be 0 until we really support USERPTR streaming */
+ gobuf->offset = gobuf->user_addr & ~PAGE_MASK;
+ gobuf->bytesused = 0;
+ gobuf->frame_offset = 0;
+ gobuf->modet_active = 0;
+ if (gobuf->offset > 0)
+ gobuf->page_count = GO7007_BUF_PAGES + 1;
+ else
+ gobuf->page_count = GO7007_BUF_PAGES;
+ retval = -ENOMEM;
+ down_read(¤t->mm->mmap_sem);
+ ret = get_user_pages(current, current->mm,
+ gobuf->user_addr & PAGE_MASK, gobuf->page_count,
+ 1, 1, gobuf->pages, NULL);
+ up_read(¤t->mm->mmap_sem);
+ if (ret != gobuf->page_count) {
+ int i;
+ for (i = 0; i < ret; ++i)
+ page_cache_release(gobuf->pages[i]);
+ gobuf->page_count = 0;
+ goto unlock_and_return;
+ }
+ gobuf->state = BUF_STATE_QUEUED;
+ spin_lock_irqsave(&go->spinlock, flags);
+ list_add_tail(&gobuf->stream, &go->stream);
+ spin_unlock_irqrestore(&go->spinlock, flags);
+ up(&gofh->lock);
+ return 0;
+ }
+ case VIDIOC_DQBUF:
+ {
+ struct v4l2_buffer *buf = arg;
+ struct go7007_buffer *gobuf;
+ u32 frame_type_flag;
+ DEFINE_WAIT(wait);
+
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (buf->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+ down(&gofh->lock);
+ retval = -EINVAL;
+ if (list_empty(&go->stream))
+ goto unlock_and_return;
+ gobuf = list_entry(go->stream.next,
+ struct go7007_buffer, stream);
+ retval = -EAGAIN;
+ if (gobuf->state != BUF_STATE_DONE &&
+ !(file->f_flags & O_NONBLOCK)) {
+ for (;;) {
+ prepare_to_wait(&go->frame_waitq, &wait,
+ TASK_INTERRUPTIBLE);
+ if (gobuf->state == BUF_STATE_DONE)
+ break;
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
+ finish_wait(&go->frame_waitq, &wait);
+ }
+ if (gobuf->state != BUF_STATE_DONE)
+ goto unlock_and_return;
+ spin_lock_irqsave(&go->spinlock, flags);
+ deactivate_buffer(gobuf);
+ spin_unlock_irqrestore(&go->spinlock, flags);
+ frame_type_flag = get_frame_type_flag(gobuf, go->format);
+ gobuf->state = BUF_STATE_IDLE;
+ memset(buf, 0, sizeof(*buf));
+ buf->index = gobuf->index;
+ buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf->bytesused = gobuf->bytesused;
+ buf->flags = V4L2_BUF_FLAG_MAPPED | frame_type_flag;
+ buf->field = V4L2_FIELD_NONE;
+ buf->timestamp = gobuf->timestamp;
+ buf->sequence = gobuf->seq;
+ buf->memory = V4L2_MEMORY_MMAP;
+ buf->m.offset = gobuf->index * GO7007_BUF_SIZE;
+ buf->length = GO7007_BUF_SIZE;
+ buf->reserved = gobuf->modet_active;
+ up(&gofh->lock);
+ return 0;
+ }
+ case VIDIOC_STREAMON:
+ {
+ unsigned int *type = arg;
+
+ if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ down(&gofh->lock);
+ down(&go->hw_lock);
+ if (!go->streaming) {
+ go->streaming = 1;
+ go->next_seq = 0;
+ go->active_buf = NULL;
+ if (go7007_start_encoder(go) < 0)
+ retval = -EIO;
+ else
+ retval = 0;
+ }
+ up(&go->hw_lock);
+ up(&gofh->lock);
+ return retval;
+ }
+ case VIDIOC_STREAMOFF:
+ {
+ unsigned int *type = arg;
+
+ if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ down(&gofh->lock);
+ go7007_streamoff(go);
+ up(&gofh->lock);
+ return 0;
+ }
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *ctrl = arg;
+ u32 id;
+
+ if (!go->i2c_adapter_online)
+ return -EIO;
+ id = ctrl->id;
+ memset(ctrl, 0, sizeof(*ctrl));
+ ctrl->id = id;
+ i2c_clients_command(&go->i2c_adapter, VIDIOC_QUERYCTRL, arg);
+ return ctrl->name[0] == 0 ? -EINVAL : 0;
+ }
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+ struct v4l2_queryctrl query;
+
+ if (!go->i2c_adapter_online)
+ return -EIO;
+ memset(&query, 0, sizeof(query));
+ query.id = ctrl->id;
+ i2c_clients_command(&go->i2c_adapter, VIDIOC_QUERYCTRL, &query);
+ if (query.name[0] == 0)
+ return -EINVAL;
+ i2c_clients_command(&go->i2c_adapter, VIDIOC_G_CTRL, arg);
+ return 0;
+ }
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+ struct v4l2_queryctrl query;
+
+ if (!go->i2c_adapter_online)
+ return -EIO;
+ memset(&query, 0, sizeof(query));
+ query.id = ctrl->id;
+ i2c_clients_command(&go->i2c_adapter, VIDIOC_QUERYCTRL, &query);
+ if (query.name[0] == 0)
+ return -EINVAL;
+ i2c_clients_command(&go->i2c_adapter, VIDIOC_S_CTRL, arg);
+ return 0;
+ }
+ case VIDIOC_G_PARM:
+ {
+ struct v4l2_streamparm *parm = arg;
+ struct v4l2_fract timeperframe = {
+ .numerator = 1001 * go->fps_scale,
+ .denominator = go->sensor_framerate,
+ };
+
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ memset(parm, 0, sizeof(*parm));
+ parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ parm->parm.capture.capability |= V4L2_CAP_TIMEPERFRAME;
+ parm->parm.capture.timeperframe = timeperframe;
+ return 0;
+ }
+ case VIDIOC_S_PARM:
+ {
+ struct v4l2_streamparm *parm = arg;
+ unsigned int n, d;
+
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (parm->parm.capture.capturemode != 0)
+ return -EINVAL;
+ n = go->sensor_framerate *
+ parm->parm.capture.timeperframe.numerator;
+ d = 1001 * parm->parm.capture.timeperframe.denominator;
+ if (n != 0 && d != 0 && n > d)
+ go->fps_scale = (n + d/2) / d;
+ else
+ go->fps_scale = 1;
+ return 0;
+ }
+ case VIDIOC_ENUMSTD:
+ {
+ struct v4l2_standard *std = arg;
+
+ if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) &&
+ go->input == go->board_info->num_inputs - 1) {
+ if (!go->i2c_adapter_online)
+ return -EIO;
+ i2c_clients_command(&go->i2c_adapter,
+ VIDIOC_ENUMSTD, arg);
+ if (!std->id) /* hack to indicate EINVAL from tuner */
+ return -EINVAL;
+ } else if (go->board_info->sensor_flags & GO7007_SENSOR_TV) {
+ switch (std->index) {
+ case 0:
+ v4l2_video_std_construct(std,
+ V4L2_STD_NTSC, "NTSC");
+ break;
+ case 1:
+ v4l2_video_std_construct(std,
+ V4L2_STD_PAL | V4L2_STD_SECAM,
+ "PAL/SECAM");
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ if (std->index != 0)
+ return -EINVAL;
+ memset(std, 0, sizeof(*std));
+ snprintf(std->name, sizeof(std->name), "%dx%d, %dfps",
+ go->board_info->sensor_width,
+ go->board_info->sensor_height,
+ go->board_info->sensor_framerate / 1000);
+ std->frameperiod.numerator = 1001;
+ std->frameperiod.denominator =
+ go->board_info->sensor_framerate;
+ }
+ return 0;
+ }
+ case VIDIOC_G_STD:
+ {
+ v4l2_std_id *std = arg;
+
+ if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) &&
+ go->input == go->board_info->num_inputs - 1) {
+ if (!go->i2c_adapter_online)
+ return -EIO;
+ i2c_clients_command(&go->i2c_adapter,
+ VIDIOC_G_STD, arg);
+ } else if (go->board_info->sensor_flags & GO7007_SENSOR_TV) {
+ if (go->standard == GO7007_STD_NTSC)
+ *std = V4L2_STD_NTSC;
+ else
+ *std = V4L2_STD_PAL | V4L2_STD_SECAM;
+ } else
+ *std = 0;
+ return 0;
+ }
+ case VIDIOC_S_STD:
+ {
+ v4l2_std_id *std = arg;
+ int norm;
+
+ if (go->streaming)
+ return -EBUSY;
+ if (!(go->board_info->sensor_flags & GO7007_SENSOR_TV) &&
+ *std != 0)
+ return -EINVAL;
+ if (*std == 0)
+ return -EINVAL;
+ if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) &&
+ go->input == go->board_info->num_inputs - 1) {
+ if (!go->i2c_adapter_online)
+ return -EIO;
+ i2c_clients_command(&go->i2c_adapter,
+ VIDIOC_S_STD, arg);
+ if (!*std) /* hack to indicate EINVAL from tuner */
+ return -EINVAL;
+ }
+ if (*std & V4L2_STD_NTSC) {
+ go->standard = GO7007_STD_NTSC;
+ go->sensor_framerate = 30000;
+ norm = VIDEO_MODE_NTSC;
+ } else if (*std & V4L2_STD_PAL) {
+ go->standard = GO7007_STD_PAL;
+ go->sensor_framerate = 25025;
+ norm = VIDEO_MODE_PAL;
+ } else if (*std & V4L2_STD_SECAM) {
+ go->standard = GO7007_STD_PAL;
+ go->sensor_framerate = 25025;
+ norm = VIDEO_MODE_SECAM;
+ } else
+ return -EINVAL;
+ if (go->i2c_adapter_online)
+ i2c_clients_command(&go->i2c_adapter,
+ DECODER_SET_NORM, &norm);
+ set_capture_size(go, NULL, 0);
+ return 0;
+ }
+ case VIDIOC_QUERYSTD:
+ {
+ v4l2_std_id *std = arg;
+
+ if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) &&
+ go->input == go->board_info->num_inputs - 1) {
+ if (!go->i2c_adapter_online)
+ return -EIO;
+ i2c_clients_command(&go->i2c_adapter,
+ VIDIOC_QUERYSTD, arg);
+ } else if (go->board_info->sensor_flags & GO7007_SENSOR_TV)
+ *std = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM;
+ else
+ *std = 0;
+ return 0;
+ }
+ case VIDIOC_ENUMINPUT:
+ {
+ struct v4l2_input *inp = arg;
+ int index;
+
+ if (inp->index >= go->board_info->num_inputs)
+ return -EINVAL;
+ index = inp->index;
+ memset(inp, 0, sizeof(*inp));
+ inp->index = index;
+ strncpy(inp->name, go->board_info->inputs[index].name,
+ sizeof(inp->name));
+ /* If this board has a tuner, it will be the last input */
+ if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) &&
+ index == go->board_info->num_inputs - 1)
+ inp->type = V4L2_INPUT_TYPE_TUNER;
+ else
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+ inp->audioset = 0;
+ inp->tuner = 0;
+ if (go->board_info->sensor_flags & GO7007_SENSOR_TV)
+ inp->std = V4L2_STD_NTSC | V4L2_STD_PAL |
+ V4L2_STD_SECAM;
+ else
+ inp->std = 0;
+ return 0;
+ }
+ case VIDIOC_G_INPUT:
+ {
+ int *input = arg;
+
+ *input = go->input;
+ return 0;
+ }
+ case VIDIOC_S_INPUT:
+ {
+ int *input = arg;
+
+ if (*input >= go->board_info->num_inputs)
+ return -EINVAL;
+ if (go->streaming)
+ return -EBUSY;
+ go->input = *input;
+ if (go->i2c_adapter_online) {
+ i2c_clients_command(&go->i2c_adapter, DECODER_SET_INPUT,
+ &go->board_info->inputs[*input].video_input);
+ i2c_clients_command(&go->i2c_adapter, VIDIOC_S_AUDIO,
+ &go->board_info->inputs[*input].audio_input);
+ }
+ return 0;
+ }
+ case VIDIOC_G_TUNER:
+ {
+ struct v4l2_tuner *t = arg;
+
+ if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
+ return -EINVAL;
+ if (t->index != 0)
+ return -EINVAL;
+ if (!go->i2c_adapter_online)
+ return -EIO;
+ i2c_clients_command(&go->i2c_adapter, VIDIOC_G_TUNER, arg);
+ t->index = 0;
+ return 0;
+ }
+ case VIDIOC_S_TUNER:
+ {
+ struct v4l2_tuner *t = arg;
+
+ if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
+ return -EINVAL;
+ if (t->index != 0)
+ return -EINVAL;
+ if (!go->i2c_adapter_online)
+ return -EIO;
+ switch (go->board_id) {
+ case GO7007_BOARDID_PX_TV402U_NA:
+ case GO7007_BOARDID_PX_TV402U_JP:
+ /* No selectable options currently */
+ if (t->audmode != V4L2_TUNER_MODE_STEREO)
+ return -EINVAL;
+ break;
+ }
+ i2c_clients_command(&go->i2c_adapter, VIDIOC_S_TUNER, arg);
+ return 0;
+ }
+ case VIDIOC_G_FREQUENCY:
+ {
+ struct v4l2_frequency *f = arg;
+
+ if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
+ return -EINVAL;
+ if (!go->i2c_adapter_online)
+ return -EIO;
+ memset(f, 0, sizeof(*f));
+ f->type = V4L2_TUNER_ANALOG_TV;
+ i2c_clients_command(&go->i2c_adapter, VIDIOC_G_FREQUENCY, arg);
+ return 0;
+ }
+ case VIDIOC_S_FREQUENCY:
+ {
+ if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
+ return -EINVAL;
+ if (!go->i2c_adapter_online)
+ return -EIO;
+ i2c_clients_command(&go->i2c_adapter, VIDIOC_S_FREQUENCY, arg);
+ return 0;
+ }
+ case VIDIOC_CROPCAP:
+ {
+ struct v4l2_cropcap *cropcap = arg;
+
+ if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ memset(cropcap, 0, sizeof(*cropcap));
+ cropcap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ /* These specify the raw input of the sensor */
+ switch (go->standard) {
+ case GO7007_STD_NTSC:
+ cropcap->bounds.top = 0;
+ cropcap->bounds.left = 0;
+ cropcap->bounds.width = 720;
+ cropcap->bounds.height = 480;
+ cropcap->defrect.top = 0;
+ cropcap->defrect.left = 0;
+ cropcap->defrect.width = 720;
+ cropcap->defrect.height = 480;
+ break;
+ case GO7007_STD_PAL:
+ cropcap->bounds.top = 0;
+ cropcap->bounds.left = 0;
+ cropcap->bounds.width = 720;
+ cropcap->bounds.height = 576;
+ cropcap->defrect.top = 0;
+ cropcap->defrect.left = 0;
+ cropcap->defrect.width = 720;
+ cropcap->defrect.height = 576;
+ break;
+ case GO7007_STD_OTHER:
+ cropcap->bounds.top = 0;
+ cropcap->bounds.left = 0;
+ cropcap->bounds.width = go->board_info->sensor_width;
+ cropcap->bounds.height = go->board_info->sensor_height;
+ cropcap->defrect.top = 0;
+ cropcap->defrect.left = 0;
+ cropcap->defrect.width = go->board_info->sensor_width;
+ cropcap->defrect.height = go->board_info->sensor_height;
+ break;
+ }
+
+ return 0;
+ }
+ case VIDIOC_G_CROP:
+ {
+ struct v4l2_crop *crop = arg;
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ memset(crop, 0, sizeof(*crop));
+ crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ /* These specify the raw input of the sensor */
+ switch (go->standard) {
+ case GO7007_STD_NTSC:
+ crop->c.top = 0;
+ crop->c.left = 0;
+ crop->c.width = 720;
+ crop->c.height = 480;
+ break;
+ case GO7007_STD_PAL:
+ crop->c.top = 0;
+ crop->c.left = 0;
+ crop->c.width = 720;
+ crop->c.height = 576;
+ break;
+ case GO7007_STD_OTHER:
+ crop->c.top = 0;
+ crop->c.left = 0;
+ crop->c.width = go->board_info->sensor_width;
+ crop->c.height = go->board_info->sensor_height;
+ break;
+ }
+
+ return 0;
+ }
+ case VIDIOC_S_CROP:
+ {
+ struct v4l2_crop *crop = arg;
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ return 0;
+ }
+ case VIDIOC_G_JPEGCOMP:
+ {
+ struct v4l2_jpegcompression *params = arg;
+
+ memset(params, 0, sizeof(*params));
+ params->quality = 50; /* ?? */
+ params->jpeg_markers = V4L2_JPEG_MARKER_DHT |
+ V4L2_JPEG_MARKER_DQT;
+
+ return 0;
+ }
+ case VIDIOC_S_JPEGCOMP:
+ {
+ struct v4l2_jpegcompression *params = arg;
+
+ if (params->quality != 50 ||
+ params->jpeg_markers != (V4L2_JPEG_MARKER_DHT |
+ V4L2_JPEG_MARKER_DQT))
+ return -EINVAL;
+ return 0;
+ }
+ /* Temporary ioctls for controlling compression characteristics */
+ case GO7007IOC_S_BITRATE:
+ {
+ int *bitrate = arg;
+
+ if (go->streaming)
+ return -EINVAL;
+ /* Upper bound is kind of arbitrary here */
+ if (*bitrate < 64000 || *bitrate > 10000000)
+ return -EINVAL;
+ go->bitrate = *bitrate;
+ return 0;
+ }
+ case GO7007IOC_G_BITRATE:
+ {
+ int *bitrate = arg;
+
+ *bitrate = go->bitrate;
+ return 0;
+ }
+ case GO7007IOC_S_COMP_PARAMS:
+ {
+ struct go7007_comp_params *comp = arg;
+
+ if (go->format == GO7007_FORMAT_MJPEG)
+ return -EINVAL;
+ if (comp->gop_size > 0)
+ go->gop_size = comp->gop_size;
+ else
+ go->gop_size = go->sensor_framerate / 1000;
+ if (go->gop_size != 15)
+ go->dvd_mode = 0;
+ /*go->ipb = comp->max_b_frames > 0;*/ /* completely untested */
+ if (go->board_info->sensor_flags & GO7007_SENSOR_TV) {
+ switch (comp->aspect_ratio) {
+ case GO7007_ASPECT_RATIO_4_3_NTSC:
+ case GO7007_ASPECT_RATIO_4_3_PAL:
+ go->aspect_ratio = GO7007_RATIO_4_3;
+ break;
+ case GO7007_ASPECT_RATIO_16_9_NTSC:
+ case GO7007_ASPECT_RATIO_16_9_PAL:
+ go->aspect_ratio = GO7007_RATIO_16_9;
+ break;
+ default:
+ go->aspect_ratio = GO7007_RATIO_1_1;
+ break;
+ }
+ }
+ if (comp->flags & GO7007_COMP_OMIT_SEQ_HEADER) {
+ go->dvd_mode = 0;
+ go->seq_header_enable = 0;
+ } else {
+ go->seq_header_enable = 1;
+ }
+ /* fall-through */
+ }
+ case GO7007IOC_G_COMP_PARAMS:
+ {
+ struct go7007_comp_params *comp = arg;
+
+ if (go->format == GO7007_FORMAT_MJPEG)
+ return -EINVAL;
+ memset(comp, 0, sizeof(*comp));
+ comp->gop_size = go->gop_size;
+ comp->max_b_frames = go->ipb ? 2 : 0;
+ switch (go->aspect_ratio) {
+ case GO7007_RATIO_4_3:
+ if (go->standard == GO7007_STD_NTSC)
+ comp->aspect_ratio =
+ GO7007_ASPECT_RATIO_4_3_NTSC;
+ else
+ comp->aspect_ratio =
+ GO7007_ASPECT_RATIO_4_3_PAL;
+ break;
+ case GO7007_RATIO_16_9:
+ if (go->standard == GO7007_STD_NTSC)
+ comp->aspect_ratio =
+ GO7007_ASPECT_RATIO_16_9_NTSC;
+ else
+ comp->aspect_ratio =
+ GO7007_ASPECT_RATIO_16_9_PAL;
+ break;
+ default:
+ comp->aspect_ratio = GO7007_ASPECT_RATIO_1_1;
+ break;
+ }
+ if (go->closed_gop)
+ comp->flags |= GO7007_COMP_CLOSED_GOP;
+ if (!go->seq_header_enable)
+ comp->flags |= GO7007_COMP_OMIT_SEQ_HEADER;
+ return 0;
+ }
+ case GO7007IOC_S_MPEG_PARAMS:
+ {
+ struct go7007_mpeg_params *mpeg = arg;
+
+ if (go->format != GO7007_FORMAT_MPEG1 &&
+ go->format != GO7007_FORMAT_MPEG2 &&
+ go->format != GO7007_FORMAT_MPEG4)
+ return -EINVAL;
+
+ if (mpeg->flags & GO7007_MPEG_FORCE_DVD_MODE) {
+ go->format = GO7007_FORMAT_MPEG2;
+ go->bitrate = 9800000;
+ go->gop_size = 15;
+ go->pali = 0x48;
+ go->closed_gop = 1;
+ go->repeat_seqhead = 0;
+ go->seq_header_enable = 1;
+ go->gop_header_enable = 1;
+ go->dvd_mode = 1;
+ } else {
+ switch (mpeg->mpeg_video_standard) {
+ case GO7007_MPEG_VIDEO_MPEG1:
+ go->format = GO7007_FORMAT_MPEG1;
+ go->pali = 0;
+ break;
+ case GO7007_MPEG_VIDEO_MPEG2:
+ go->format = GO7007_FORMAT_MPEG2;
+ if (mpeg->pali >> 24 == 2)
+ go->pali = mpeg->pali & 0xff;
+ else
+ go->pali = 0x48;
+ break;
+ case GO7007_MPEG_VIDEO_MPEG4:
+ go->format = GO7007_FORMAT_MPEG4;
+ if (mpeg->pali >> 24 == 4)
+ go->pali = mpeg->pali & 0xff;
+ else
+ go->pali = 0xf5;
+ break;
+ default:
+ return -EINVAL;
+ }
+ go->gop_header_enable =
+ mpeg->flags & GO7007_MPEG_OMIT_GOP_HEADER
+ ? 0 : 1;
+ if (mpeg->flags & GO7007_MPEG_REPEAT_SEQHEADER)
+ go->repeat_seqhead = 1;
+ else
+ go->repeat_seqhead = 0;
+ go->dvd_mode = 0;
+ }
+ /* fall-through */
+ }
+ case GO7007IOC_G_MPEG_PARAMS:
+ {
+ struct go7007_mpeg_params *mpeg = arg;
+
+ memset(mpeg, 0, sizeof(*mpeg));
+ switch (go->format) {
+ case GO7007_FORMAT_MPEG1:
+ mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG1;
+ mpeg->pali = 0;
+ break;
+ case GO7007_FORMAT_MPEG2:
+ mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG2;
+ mpeg->pali = GO7007_MPEG_PROFILE(2, go->pali);
+ break;
+ case GO7007_FORMAT_MPEG4:
+ mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG4;
+ mpeg->pali = GO7007_MPEG_PROFILE(4, go->pali);
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (!go->gop_header_enable)
+ mpeg->flags |= GO7007_MPEG_OMIT_GOP_HEADER;
+ if (go->repeat_seqhead)
+ mpeg->flags |= GO7007_MPEG_REPEAT_SEQHEADER;
+ if (go->dvd_mode)
+ mpeg->flags |= GO7007_MPEG_FORCE_DVD_MODE;
+ return 0;
+ }
+ case GO7007IOC_S_MD_PARAMS:
+ {
+ struct go7007_md_params *mdp = arg;
+
+ if (mdp->region > 3)
+ return -EINVAL;
+ if (mdp->trigger > 0) {
+ go->modet[mdp->region].pixel_threshold =
+ mdp->pixel_threshold >> 1;
+ go->modet[mdp->region].motion_threshold =
+ mdp->motion_threshold >> 1;
+ go->modet[mdp->region].mb_threshold =
+ mdp->trigger >> 1;
+ go->modet[mdp->region].enable = 1;
+ } else
+ go->modet[mdp->region].enable = 0;
+ /* fall-through */
+ }
+ case GO7007IOC_G_MD_PARAMS:
+ {
+ struct go7007_md_params *mdp = arg;
+ int region = mdp->region;
+
+ if (mdp->region > 3)
+ return -EINVAL;
+ memset(mdp, 0, sizeof(struct go7007_md_params));
+ mdp->region = region;
+ if (!go->modet[region].enable)
+ return 0;
+ mdp->pixel_threshold =
+ (go->modet[region].pixel_threshold << 1) + 1;
+ mdp->motion_threshold =
+ (go->modet[region].motion_threshold << 1) + 1;
+ mdp->trigger =
+ (go->modet[region].mb_threshold << 1) + 1;
+ return 0;
+ }
+ case GO7007IOC_S_MD_REGION:
+ {
+ struct go7007_md_region *region = arg;
+
+ if (region->region < 1 || region->region > 3)
+ return -EINVAL;
+ return clip_to_modet_map(go, region->region, region->clips);
+ }
+ default:
+ printk(KERN_DEBUG "go7007: unsupported ioctl %d\n", cmd);
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+
+unlock_and_return:
+ up(&gofh->lock);
+ return retval;
+}
+
+static int go7007_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct go7007_file *gofh = file->private_data;
+
+ if (gofh->go->status != STATUS_ONLINE)
+ return -EIO;
+
+ return video_usercopy(inode, file, cmd, arg, go7007_do_ioctl);
+}
+
+static ssize_t go7007_read(struct file *file, char __user *data,
+ size_t count, loff_t *ppos)
+{
+ return -EINVAL;
+}
+
+static void go7007_vm_open(struct vm_area_struct *vma)
+{
+ struct go7007_buffer *gobuf = vma->vm_private_data;
+
+ ++gobuf->mapped;
+}
+
+static void go7007_vm_close(struct vm_area_struct *vma)
+{
+ struct go7007_buffer *gobuf = vma->vm_private_data;
+ unsigned long flags;
+
+ if (--gobuf->mapped == 0) {
+ spin_lock_irqsave(&gobuf->go->spinlock, flags);
+ deactivate_buffer(gobuf);
+ spin_unlock_irqrestore(&gobuf->go->spinlock, flags);
+ }
+}
+
+/* Copied from videobuf-dma-sg.c */
+static int go7007_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+ struct page *page;
+
+ page = alloc_page(GFP_USER | __GFP_DMA32);
+ if (!page)
+ return VM_FAULT_OOM;
+ clear_user_page(page_address(page), (unsigned long)vmf->virtual_address,
+ page);
+ vmf->page = page;
+ return 0;
+}
+
+static struct vm_operations_struct go7007_vm_ops = {
+ .open = go7007_vm_open,
+ .close = go7007_vm_close,
+ .fault = go7007_vm_fault,
+};
+
+static int go7007_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct go7007_file *gofh = file->private_data;
+ unsigned int index;
+
+ if (gofh->go->status != STATUS_ONLINE)
+ return -EIO;
+ if (!(vma->vm_flags & VM_SHARED))
+ return -EINVAL; /* only support VM_SHARED mapping */
+ if (vma->vm_end - vma->vm_start != GO7007_BUF_SIZE)
+ return -EINVAL; /* must map exactly one full buffer */
+ down(&gofh->lock);
+ index = vma->vm_pgoff / GO7007_BUF_PAGES;
+ if (index >= gofh->buf_count) {
+ up(&gofh->lock);
+ return -EINVAL; /* trying to map beyond requested buffers */
+ }
+ if (index * GO7007_BUF_PAGES != vma->vm_pgoff) {
+ up(&gofh->lock);
+ return -EINVAL; /* offset is not aligned on buffer boundary */
+ }
+ if (gofh->bufs[index].mapped > 0) {
+ up(&gofh->lock);
+ return -EBUSY;
+ }
+ gofh->bufs[index].mapped = 1;
+ gofh->bufs[index].user_addr = vma->vm_start;
+ vma->vm_ops = &go7007_vm_ops;
+ vma->vm_flags |= VM_DONTEXPAND;
+ vma->vm_flags &= ~VM_IO;
+ vma->vm_private_data = &gofh->bufs[index];
+ up(&gofh->lock);
+ return 0;
+}
+
+static unsigned int go7007_poll(struct file *file, poll_table *wait)
+{
+ struct go7007_file *gofh = file->private_data;
+ struct go7007_buffer *gobuf;
+
+ if (list_empty(&gofh->go->stream))
+ return POLLERR;
+ gobuf = list_entry(gofh->go->stream.next, struct go7007_buffer, stream);
+ poll_wait(file, &gofh->go->frame_waitq, wait);
+ if (gobuf->state == BUF_STATE_DONE)
+ return POLLIN | POLLRDNORM;
+ return 0;
+}
+
+static void go7007_vfl_release(struct video_device *vfd)
+{
+ struct go7007 *go = video_get_drvdata(vfd);
+
+ video_device_release(vfd);
+ if (--go->ref_count == 0)
+ kfree(go);
+}
+
+static struct file_operations go7007_fops = {
+ .owner = THIS_MODULE,
+ .open = go7007_open,
+ .release = go7007_release,
+ .ioctl = go7007_ioctl,
+ .llseek = no_llseek,
+ .read = go7007_read,
+ .mmap = go7007_mmap,
+ .poll = go7007_poll,
+};
+
+static struct video_device go7007_template = {
+ .name = "go7007",
+ .fops = &go7007_fops,
+ .minor = -1,
+ .release = go7007_vfl_release,
+};
+
+int go7007_v4l2_init(struct go7007 *go)
+{
+ int rv;
+
+ go->video_dev = video_device_alloc();
+ if (go->video_dev == NULL)
+ return -ENOMEM;
+ memcpy(go->video_dev, &go7007_template, sizeof(go7007_template));
+ go->video_dev->parent = go->dev;
+ rv = video_register_device(go->video_dev, VFL_TYPE_GRABBER, -1);
+ if (rv < 0) {
+ video_device_release(go->video_dev);
+ go->video_dev = NULL;
+ return rv;
+ }
+ video_set_drvdata(go->video_dev, go);
+ ++go->ref_count;
+
+ return 0;
+}
+
+void go7007_v4l2_remove(struct go7007 *go)
+{
+ unsigned long flags;
+
+ down(&go->hw_lock);
+ if (go->streaming) {
+ go->streaming = 0;
+ go7007_stream_stop(go);
+ spin_lock_irqsave(&go->spinlock, flags);
+ abort_queued(go);
+ spin_unlock_irqrestore(&go->spinlock, flags);
+ }
+ up(&go->hw_lock);
+ if (go->video_dev)
+ video_unregister_device(go->video_dev);
+}
diff --git a/drivers/staging/go7007/go7007.h b/drivers/staging/go7007/go7007.h
new file mode 100644
index 0000000..7399c91
--- /dev/null
+++ b/drivers/staging/go7007/go7007.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and the associated README documentation file (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* DEPRECATED -- use V4L2_PIX_FMT_MPEG and then call GO7007IOC_S_MPEG_PARAMS
+ * to select between MPEG1, MPEG2, and MPEG4 */
+#define V4L2_PIX_FMT_MPEG4 v4l2_fourcc('M', 'P', 'G', '4') /* MPEG4 */
+
+/* These will be replaced with a better interface
+ * soon, so don't get too attached to them */
+#define GO7007IOC_S_BITRATE _IOW('V', BASE_VIDIOC_PRIVATE + 0, int)
+#define GO7007IOC_G_BITRATE _IOR('V', BASE_VIDIOC_PRIVATE + 1, int)
+
+enum go7007_aspect_ratio {
+ GO7007_ASPECT_RATIO_1_1 = 0,
+ GO7007_ASPECT_RATIO_4_3_NTSC = 1,
+ GO7007_ASPECT_RATIO_4_3_PAL = 2,
+ GO7007_ASPECT_RATIO_16_9_NTSC = 3,
+ GO7007_ASPECT_RATIO_16_9_PAL = 4,
+};
+
+/* Used to set generic compression parameters */
+struct go7007_comp_params {
+ __u32 gop_size;
+ __u32 max_b_frames;
+ enum go7007_aspect_ratio aspect_ratio;
+ __u32 flags;
+ __u32 reserved[8];
+};
+
+#define GO7007_COMP_CLOSED_GOP 0x00000001
+#define GO7007_COMP_OMIT_SEQ_HEADER 0x00000002
+
+enum go7007_mpeg_video_standard {
+ GO7007_MPEG_VIDEO_MPEG1 = 0,
+ GO7007_MPEG_VIDEO_MPEG2 = 1,
+ GO7007_MPEG_VIDEO_MPEG4 = 2,
+};
+
+/* Used to set parameters for V4L2_PIX_FMT_MPEG format */
+struct go7007_mpeg_params {
+ enum go7007_mpeg_video_standard mpeg_video_standard;
+ __u32 flags;
+ __u32 pali;
+ __u32 reserved[8];
+};
+
+#define GO7007_MPEG_FORCE_DVD_MODE 0x00000001
+#define GO7007_MPEG_OMIT_GOP_HEADER 0x00000002
+#define GO7007_MPEG_REPEAT_SEQHEADER 0x00000004
+
+#define GO7007_MPEG_PROFILE(format, pali) (((format)<<24)|(pali))
+
+#define GO7007_MPEG2_PROFILE_MAIN_MAIN GO7007_MPEG_PROFILE(2, 0x48)
+
+#define GO7007_MPEG4_PROFILE_S_L0 GO7007_MPEG_PROFILE(4, 0x08)
+#define GO7007_MPEG4_PROFILE_S_L1 GO7007_MPEG_PROFILE(4, 0x01)
+#define GO7007_MPEG4_PROFILE_S_L2 GO7007_MPEG_PROFILE(4, 0x02)
+#define GO7007_MPEG4_PROFILE_S_L3 GO7007_MPEG_PROFILE(4, 0x03)
+#define GO7007_MPEG4_PROFILE_ARTS_L1 GO7007_MPEG_PROFILE(4, 0x91)
+#define GO7007_MPEG4_PROFILE_ARTS_L2 GO7007_MPEG_PROFILE(4, 0x92)
+#define GO7007_MPEG4_PROFILE_ARTS_L3 GO7007_MPEG_PROFILE(4, 0x93)
+#define GO7007_MPEG4_PROFILE_ARTS_L4 GO7007_MPEG_PROFILE(4, 0x94)
+#define GO7007_MPEG4_PROFILE_AS_L0 GO7007_MPEG_PROFILE(4, 0xf0)
+#define GO7007_MPEG4_PROFILE_AS_L1 GO7007_MPEG_PROFILE(4, 0xf1)
+#define GO7007_MPEG4_PROFILE_AS_L2 GO7007_MPEG_PROFILE(4, 0xf2)
+#define GO7007_MPEG4_PROFILE_AS_L3 GO7007_MPEG_PROFILE(4, 0xf3)
+#define GO7007_MPEG4_PROFILE_AS_L4 GO7007_MPEG_PROFILE(4, 0xf4)
+#define GO7007_MPEG4_PROFILE_AS_L5 GO7007_MPEG_PROFILE(4, 0xf5)
+
+struct go7007_md_params {
+ __u16 region;
+ __u16 trigger;
+ __u16 pixel_threshold;
+ __u16 motion_threshold;
+ __u32 reserved[8];
+};
+
+struct go7007_md_region {
+ __u16 region;
+ __u16 flags;
+ struct v4l2_clip *clips;
+ __u32 reserved[8];
+};
+
+#define GO7007IOC_S_MPEG_PARAMS _IOWR('V', BASE_VIDIOC_PRIVATE + 2, \
+ struct go7007_mpeg_params)
+#define GO7007IOC_G_MPEG_PARAMS _IOR('V', BASE_VIDIOC_PRIVATE + 3, \
+ struct go7007_mpeg_params)
+#define GO7007IOC_S_COMP_PARAMS _IOWR('V', BASE_VIDIOC_PRIVATE + 4, \
+ struct go7007_comp_params)
+#define GO7007IOC_G_COMP_PARAMS _IOR('V', BASE_VIDIOC_PRIVATE + 5, \
+ struct go7007_comp_params)
+#define GO7007IOC_S_MD_PARAMS _IOWR('V', BASE_VIDIOC_PRIVATE + 6, \
+ struct go7007_md_params)
+#define GO7007IOC_G_MD_PARAMS _IOR('V', BASE_VIDIOC_PRIVATE + 7, \
+ struct go7007_md_params)
+#define GO7007IOC_S_MD_REGION _IOW('V', BASE_VIDIOC_PRIVATE + 8, \
+ struct go7007_md_region)
diff --git a/drivers/staging/go7007/saa7134-go7007.c b/drivers/staging/go7007/saa7134-go7007.c
new file mode 100644
index 0000000..c4a6d8e
--- /dev/null
+++ b/drivers/staging/go7007/saa7134-go7007.c
@@ -0,0 +1,484 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/mm.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <asm/byteorder.h>
+#include <media/audiochip.h>
+
+#include "saa7134-reg.h"
+#include "saa7134.h"
+#include "go7007-priv.h"
+
+#define GO7007_HPI_DEBUG
+
+enum hpi_address {
+ HPI_ADDR_VIDEO_BUFFER = 0xe4,
+ HPI_ADDR_INIT_BUFFER = 0xea,
+ HPI_ADDR_INTR_RET_VALUE = 0xee,
+ HPI_ADDR_INTR_RET_DATA = 0xec,
+ HPI_ADDR_INTR_STATUS = 0xf4,
+ HPI_ADDR_INTR_WR_PARAM = 0xf6,
+ HPI_ADDR_INTR_WR_INDEX = 0xf8,
+};
+
+enum gpio_command {
+ GPIO_COMMAND_RESET = 0x00, /* 000b */
+ GPIO_COMMAND_REQ1 = 0x04, /* 001b */
+ GPIO_COMMAND_WRITE = 0x20, /* 010b */
+ GPIO_COMMAND_REQ2 = 0x24, /* 011b */
+ GPIO_COMMAND_READ = 0x80, /* 100b */
+ GPIO_COMMAND_VIDEO = 0x84, /* 101b */
+ GPIO_COMMAND_IDLE = 0xA0, /* 110b */
+ GPIO_COMMAND_ADDR = 0xA4, /* 111b */
+};
+
+struct saa7134_go7007 {
+ struct saa7134_dev *dev;
+ u8 *top;
+ u8 *bottom;
+ dma_addr_t top_dma;
+ dma_addr_t bottom_dma;
+};
+
+static struct go7007_board_info board_voyager = {
+ .firmware = "go7007tv.bin",
+ .flags = 0,
+ .sensor_flags = GO7007_SENSOR_656 |
+ GO7007_SENSOR_VALID_ENABLE |
+ GO7007_SENSOR_TV |
+ GO7007_SENSOR_VBI,
+ .audio_flags = GO7007_AUDIO_I2S_MODE_1 |
+ GO7007_AUDIO_WORD_16,
+ .audio_rate = 48000,
+ .audio_bclk_div = 8,
+ .audio_main_div = 2,
+ .hpi_buffer_cap = 7,
+ .num_inputs = 1,
+ .inputs = {
+ {
+ .name = "SAA7134",
+ },
+ },
+};
+
+/********************* Driver for GPIO HPI interface *********************/
+
+static int gpio_write(struct saa7134_dev *dev, u8 addr, u16 data)
+{
+ saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+
+ /* Write HPI address */
+ saa_writeb(SAA7134_GPIO_GPSTATUS0, addr);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+ /* Write low byte */
+ saa_writeb(SAA7134_GPIO_GPSTATUS0, data & 0xff);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+ /* Write high byte */
+ saa_writeb(SAA7134_GPIO_GPSTATUS0, data >> 8);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+ return 0;
+}
+
+static int gpio_read(struct saa7134_dev *dev, u8 addr, u16 *data)
+{
+ saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+
+ /* Write HPI address */
+ saa_writeb(SAA7134_GPIO_GPSTATUS0, addr);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+ saa_writeb(SAA7134_GPIO_GPMODE0, 0x00);
+
+ /* Read low byte */
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_READ);
+ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ *data = saa_readb(SAA7134_GPIO_GPSTATUS0);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+ /* Read high byte */
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_READ);
+ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ *data |= saa_readb(SAA7134_GPIO_GPSTATUS0) << 8;
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+
+ return 0;
+}
+
+static int saa7134_go7007_interface_reset(struct go7007 *go)
+{
+ struct saa7134_go7007 *saa = go->hpi_context;
+ struct saa7134_dev *dev = saa->dev;
+ u32 status;
+ u16 intr_val, intr_data;
+ int count = 20;
+
+ saa_clearb(SAA7134_TS_PARALLEL, 0x80); /* Disable TS interface */
+ saa_writeb(SAA7134_GPIO_GPMODE2, 0xa4);
+ saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_RESET);
+ msleep(1);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ2);
+ msleep(10);
+
+ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+
+ status = saa_readb(SAA7134_GPIO_GPSTATUS2);
+ /*printk(KERN_DEBUG "status is %s\n", status & 0x40 ? "OK" : "not OK"); */
+
+ /* enter command mode...(?) */
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ1);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_REQ2);
+
+ do {
+ saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
+ status = saa_readb(SAA7134_GPIO_GPSTATUS2);
+ /*printk(KERN_INFO "gpio is %08x\n", saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2)); */
+ } while (--count > 0);
+
+ /* Wait for an interrupt to indicate successful hardware reset */
+ if (go7007_read_interrupt(go, &intr_val, &intr_data) < 0 ||
+ (intr_val & ~0x1) != 0x55aa) {
+ printk(KERN_ERR
+ "saa7134-go7007: unable to reset the GO7007\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int saa7134_go7007_write_interrupt(struct go7007 *go, int addr, int data)
+{
+ struct saa7134_go7007 *saa = go->hpi_context;
+ struct saa7134_dev *dev = saa->dev;
+ int i;
+ u16 status_reg;
+
+#ifdef GO7007_HPI_DEBUG
+ printk(KERN_DEBUG
+ "saa7134-go7007: WriteInterrupt: %04x %04x\n", addr, data);
+#endif
+
+ for (i = 0; i < 100; ++i) {
+ gpio_read(dev, HPI_ADDR_INTR_STATUS, &status_reg);
+ if (!(status_reg & 0x0010))
+ break;
+ msleep(10);
+ }
+ if (i == 100) {
+ printk(KERN_ERR
+ "saa7134-go7007: device is hung, status reg = 0x%04x\n",
+ status_reg);
+ return -1;
+ }
+ gpio_write(dev, HPI_ADDR_INTR_WR_PARAM, data);
+ gpio_write(dev, HPI_ADDR_INTR_WR_INDEX, addr);
+
+ return 0;
+}
+
+static int saa7134_go7007_read_interrupt(struct go7007 *go)
+{
+ struct saa7134_go7007 *saa = go->hpi_context;
+ struct saa7134_dev *dev = saa->dev;
+
+ /* XXX we need to wait if there is no interrupt available */
+ go->interrupt_available = 1;
+ gpio_read(dev, HPI_ADDR_INTR_RET_VALUE, &go->interrupt_value);
+ gpio_read(dev, HPI_ADDR_INTR_RET_DATA, &go->interrupt_data);
+#ifdef GO7007_HPI_DEBUG
+ printk(KERN_DEBUG "saa7134-go7007: ReadInterrupt: %04x %04x\n",
+ go->interrupt_value, go->interrupt_data);
+#endif
+ return 0;
+}
+
+static void saa7134_go7007_irq_ts_done(struct saa7134_dev *dev,
+ unsigned long status)
+{
+ struct go7007 *go = video_get_drvdata(dev->empress_dev);
+ struct saa7134_go7007 *saa = go->hpi_context;
+
+ if (!go->streaming)
+ return;
+ if (0 != (status & 0x000f0000))
+ printk(KERN_DEBUG "saa7134-go7007: irq: lost %ld\n",
+ (status >> 16) & 0x0f);
+ if (status & 0x100000) {
+ dma_sync_single(&dev->pci->dev,
+ saa->bottom_dma, PAGE_SIZE, DMA_FROM_DEVICE);
+ go7007_parse_video_stream(go, saa->bottom, PAGE_SIZE);
+ saa_writel(SAA7134_RS_BA2(5), cpu_to_le32(saa->bottom_dma));
+ } else {
+ dma_sync_single(&dev->pci->dev,
+ saa->top_dma, PAGE_SIZE, DMA_FROM_DEVICE);
+ go7007_parse_video_stream(go, saa->top, PAGE_SIZE);
+ saa_writel(SAA7134_RS_BA1(5), cpu_to_le32(saa->top_dma));
+ }
+}
+
+static int saa7134_go7007_stream_start(struct go7007 *go)
+{
+ struct saa7134_go7007 *saa = go->hpi_context;
+ struct saa7134_dev *dev = saa->dev;
+
+ saa->top_dma = dma_map_page(&dev->pci->dev, virt_to_page(saa->top),
+ 0, PAGE_SIZE, DMA_FROM_DEVICE);
+ if (!saa->top_dma)
+ return -ENOMEM;
+ saa->bottom_dma = dma_map_page(&dev->pci->dev,
+ virt_to_page(saa->bottom),
+ 0, PAGE_SIZE, DMA_FROM_DEVICE);
+ if (!saa->bottom_dma) {
+ dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE,
+ DMA_FROM_DEVICE);
+ return -ENOMEM;
+ }
+
+ saa_writel(SAA7134_VIDEO_PORT_CTRL0 >> 2, 0xA300B000);
+ saa_writel(SAA7134_VIDEO_PORT_CTRL4 >> 2, 0x40000200);
+
+ /* Set HPI interface for video */
+ saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+ saa_writeb(SAA7134_GPIO_GPSTATUS0, HPI_ADDR_VIDEO_BUFFER);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
+ saa_writeb(SAA7134_GPIO_GPMODE0, 0x00);
+
+ /* Enable TS interface */
+ saa_writeb(SAA7134_TS_PARALLEL, 0xe6);
+
+ /* Reset TS interface */
+ saa_setb(SAA7134_TS_SERIAL1, 0x01);
+ saa_clearb(SAA7134_TS_SERIAL1, 0x01);
+
+ /* Set up transfer block size */
+ saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 128 - 1);
+ saa_writeb(SAA7134_TS_DMA0, (PAGE_SIZE >> 7) - 1);
+ saa_writeb(SAA7134_TS_DMA1, 0);
+ saa_writeb(SAA7134_TS_DMA2, 0);
+
+ /* Enable video streaming mode */
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_VIDEO);
+
+ saa_writel(SAA7134_RS_BA1(5), cpu_to_le32(saa->top_dma));
+ saa_writel(SAA7134_RS_BA2(5), cpu_to_le32(saa->bottom_dma));
+ saa_writel(SAA7134_RS_PITCH(5), 128);
+ saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_MAX);
+
+ /* Enable TS FIFO */
+ saa_setl(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_TE5);
+
+ /* Enable DMA IRQ */
+ saa_setl(SAA7134_IRQ1,
+ SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0);
+
+ return 0;
+}
+
+static int saa7134_go7007_stream_stop(struct go7007 *go)
+{
+ struct saa7134_go7007 *saa = go->hpi_context;
+ struct saa7134_dev *dev = saa->dev;
+
+ /* Shut down TS FIFO */
+ saa_clearl(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_TE5);
+
+ /* Disable DMA IRQ */
+ saa_clearl(SAA7134_IRQ1,
+ SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0);
+
+ /* Disable TS interface */
+ saa_clearb(SAA7134_TS_PARALLEL, 0x80);
+
+ dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE,
+ DMA_FROM_DEVICE);
+ dma_unmap_page(&dev->pci->dev, saa->bottom_dma, PAGE_SIZE,
+ DMA_FROM_DEVICE);
+
+ return 0;
+}
+
+static int saa7134_go7007_send_firmware(struct go7007 *go, u8 *data, int len)
+{
+ struct saa7134_go7007 *saa = go->hpi_context;
+ struct saa7134_dev *dev = saa->dev;
+ u16 status_reg;
+ int i;
+
+#ifdef GO7007_HPI_DEBUG
+ printk(KERN_DEBUG "saa7134-go7007: DownloadBuffer "
+ "sending %d bytes\n", len);
+#endif
+
+ while (len > 0) {
+ i = len > 64 ? 64 : len;
+ saa_writeb(SAA7134_GPIO_GPMODE0, 0xff);
+ saa_writeb(SAA7134_GPIO_GPSTATUS0, HPI_ADDR_INIT_BUFFER);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_ADDR);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+ while (i-- > 0) {
+ saa_writeb(SAA7134_GPIO_GPSTATUS0, *data);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_WRITE);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_IDLE);
+ ++data;
+ --len;
+ }
+ for (i = 0; i < 100; ++i) {
+ gpio_read(dev, HPI_ADDR_INTR_STATUS, &status_reg);
+ if (!(status_reg & 0x0002))
+ break;
+ }
+ if (i == 100) {
+ printk(KERN_ERR "saa7134-go7007: device is hung, "
+ "status reg = 0x%04x\n", status_reg);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static struct go7007_hpi_ops saa7134_go7007_hpi_ops = {
+ .interface_reset = saa7134_go7007_interface_reset,
+ .write_interrupt = saa7134_go7007_write_interrupt,
+ .read_interrupt = saa7134_go7007_read_interrupt,
+ .stream_start = saa7134_go7007_stream_start,
+ .stream_stop = saa7134_go7007_stream_stop,
+ .send_firmware = saa7134_go7007_send_firmware,
+};
+
+/********************* Add/remove functions *********************/
+
+static int saa7134_go7007_init(struct saa7134_dev *dev)
+{
+ struct go7007 *go;
+ struct saa7134_go7007 *saa;
+
+ printk(KERN_DEBUG "saa7134-go7007: probing new SAA713X board\n");
+
+ saa = kmalloc(sizeof(struct saa7134_go7007), GFP_KERNEL);
+ if (saa == NULL)
+ return -ENOMEM;
+ memset(saa, 0, sizeof(struct saa7134_go7007));
+
+ /* Allocate a couple pages for receiving the compressed stream */
+ saa->top = (u8 *)get_zeroed_page(GFP_KERNEL);
+ if (!saa->top)
+ goto allocfail;
+ saa->bottom = (u8 *)get_zeroed_page(GFP_KERNEL);
+ if (!saa->bottom)
+ goto allocfail;
+
+ go = go7007_alloc(&board_voyager, &dev->pci->dev);
+ if (go == NULL)
+ goto allocfail;
+ go->board_id = GO7007_BOARDID_PCI_VOYAGER;
+ strncpy(go->name, saa7134_boards[dev->board].name, sizeof(go->name));
+ go->hpi_ops = &saa7134_go7007_hpi_ops;
+ go->hpi_context = saa;
+ saa->dev = dev;
+
+ /* Boot the GO7007 */
+ if (go7007_boot_encoder(go, go->board_info->flags &
+ GO7007_BOARD_USE_ONBOARD_I2C) < 0)
+ goto initfail;
+
+ /* Do any final GO7007 initialization, then register the
+ * V4L2 and ALSA interfaces */
+ if (go7007_register_encoder(go) < 0)
+ goto initfail;
+ dev->empress_dev = go->video_dev;
+ video_set_drvdata(dev->empress_dev, go);
+
+ go->status = STATUS_ONLINE;
+ return 0;
+
+initfail:
+ go->status = STATUS_SHUTDOWN;
+ return 0;
+
+allocfail:
+ if (saa->top)
+ free_page((unsigned long)saa->top);
+ if (saa->bottom)
+ free_page((unsigned long)saa->bottom);
+ kfree(saa);
+ return -ENOMEM;
+}
+
+static int saa7134_go7007_fini(struct saa7134_dev *dev)
+{
+ struct go7007 *go;
+ struct saa7134_go7007 *saa;
+
+ if (NULL == dev->empress_dev)
+ return 0;
+
+ go = video_get_drvdata(dev->empress_dev);
+ saa = go->hpi_context;
+ go->status = STATUS_SHUTDOWN;
+ free_page((unsigned long)saa->top);
+ free_page((unsigned long)saa->bottom);
+ kfree(saa);
+ go7007_remove(go);
+ dev->empress_dev = NULL;
+
+ return 0;
+}
+
+static struct saa7134_mpeg_ops saa7134_go7007_ops = {
+ .type = SAA7134_MPEG_GO7007,
+ .init = saa7134_go7007_init,
+ .fini = saa7134_go7007_fini,
+ .irq_ts_done = saa7134_go7007_irq_ts_done,
+};
+
+static int __init saa7134_go7007_mod_init(void)
+{
+ return saa7134_ts_register(&saa7134_go7007_ops);
+}
+
+static void __exit saa7134_go7007_mod_cleanup(void)
+{
+ saa7134_ts_unregister(&saa7134_go7007_ops);
+}
+
+module_init(saa7134_go7007_mod_init);
+module_exit(saa7134_go7007_mod_cleanup);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/go7007/snd-go7007.c b/drivers/staging/go7007/snd-go7007.c
new file mode 100644
index 0000000..f5cac08
--- /dev/null
+++ b/drivers/staging/go7007/snd-go7007.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+#include <linux/time.h>
+#include <linux/mm.h>
+#include <linux/i2c.h>
+#include <linux/semaphore.h>
+#include <linux/uaccess.h>
+#include <asm/system.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+
+#include "go7007-priv.h"
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+module_param_array(index, int, NULL, 0444);
+module_param_array(id, charp, NULL, 0444);
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for the go7007 audio driver");
+MODULE_PARM_DESC(index, "ID string for the go7007 audio driver");
+MODULE_PARM_DESC(index, "Enable for the go7007 audio driver");
+
+struct go7007_snd {
+ struct snd_card *card;
+ struct snd_pcm *pcm;
+ struct snd_pcm_substream *substream;
+ spinlock_t lock;
+ int w_idx;
+ int hw_ptr;
+ int avail;
+ int capturing;
+};
+
+static struct snd_pcm_hardware go7007_snd_capture_hw = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_48000,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = (128*1024),
+ .period_bytes_min = 4096,
+ .period_bytes_max = (128*1024),
+ .periods_min = 1,
+ .periods_max = 32,
+};
+
+static void parse_audio_stream_data(struct go7007 *go, u8 *buf, int length)
+{
+ struct go7007_snd *gosnd = go->snd_context;
+ struct snd_pcm_runtime *runtime = gosnd->substream->runtime;
+ int frames = bytes_to_frames(runtime, length);
+
+ spin_lock(&gosnd->lock);
+ gosnd->hw_ptr += frames;
+ if (gosnd->hw_ptr >= runtime->buffer_size)
+ gosnd->hw_ptr -= runtime->buffer_size;
+ gosnd->avail += frames;
+ spin_unlock(&gosnd->lock);
+ if (gosnd->w_idx + length > runtime->dma_bytes) {
+ int cpy = runtime->dma_bytes - gosnd->w_idx;
+
+ memcpy(runtime->dma_area + gosnd->w_idx, buf, cpy);
+ length -= cpy;
+ buf += cpy;
+ gosnd->w_idx = 0;
+ }
+ memcpy(runtime->dma_area + gosnd->w_idx, buf, length);
+ gosnd->w_idx += length;
+ spin_lock(&gosnd->lock);
+ if (gosnd->avail < runtime->period_size) {
+ spin_unlock(&gosnd->lock);
+ return;
+ }
+ gosnd->avail -= runtime->period_size;
+ spin_unlock(&gosnd->lock);
+ if (gosnd->capturing)
+ snd_pcm_period_elapsed(gosnd->substream);
+}
+
+static int go7007_snd_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct go7007 *go = snd_pcm_substream_chip(substream);
+ unsigned int bytes;
+
+ bytes = params_buffer_bytes(hw_params);
+ if (substream->runtime->dma_bytes > 0)
+ vfree(substream->runtime->dma_area);
+ substream->runtime->dma_bytes = 0;
+ substream->runtime->dma_area = vmalloc(bytes);
+ if (substream->runtime->dma_area == NULL)
+ return -ENOMEM;
+ substream->runtime->dma_bytes = bytes;
+ go->audio_deliver = parse_audio_stream_data;
+ return 0;
+}
+
+static int go7007_snd_hw_free(struct snd_pcm_substream *substream)
+{
+ struct go7007 *go = snd_pcm_substream_chip(substream);
+
+ go->audio_deliver = NULL;
+ if (substream->runtime->dma_bytes > 0)
+ vfree(substream->runtime->dma_area);
+ substream->runtime->dma_bytes = 0;
+ return 0;
+}
+
+static int go7007_snd_capture_open(struct snd_pcm_substream *substream)
+{
+ struct go7007 *go = snd_pcm_substream_chip(substream);
+ struct go7007_snd *gosnd = go->snd_context;
+ unsigned long flags;
+ int r;
+
+ spin_lock_irqsave(&gosnd->lock, flags);
+ if (gosnd->substream == NULL) {
+ gosnd->substream = substream;
+ substream->runtime->hw = go7007_snd_capture_hw;
+ r = 0;
+ } else
+ r = -EBUSY;
+ spin_unlock_irqrestore(&gosnd->lock, flags);
+ return r;
+}
+
+static int go7007_snd_capture_close(struct snd_pcm_substream *substream)
+{
+ struct go7007 *go = snd_pcm_substream_chip(substream);
+ struct go7007_snd *gosnd = go->snd_context;
+
+ gosnd->substream = NULL;
+ return 0;
+}
+
+static int go7007_snd_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ return 0;
+}
+
+static int go7007_snd_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct go7007 *go = snd_pcm_substream_chip(substream);
+ struct go7007_snd *gosnd = go->snd_context;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ /* Just set a flag to indicate we should signal ALSA when
+ * sound comes in */
+ gosnd->capturing = 1;
+ return 0;
+ case SNDRV_PCM_TRIGGER_STOP:
+ gosnd->hw_ptr = gosnd->w_idx = gosnd->avail = 0;
+ gosnd->capturing = 0;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static snd_pcm_uframes_t go7007_snd_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ struct go7007 *go = snd_pcm_substream_chip(substream);
+ struct go7007_snd *gosnd = go->snd_context;
+
+ return gosnd->hw_ptr;
+}
+
+static struct page *go7007_snd_pcm_page(struct snd_pcm_substream *substream,
+ unsigned long offset)
+{
+ return vmalloc_to_page(substream->runtime->dma_area + offset);
+}
+
+static struct snd_pcm_ops go7007_snd_capture_ops = {
+ .open = go7007_snd_capture_open,
+ .close = go7007_snd_capture_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = go7007_snd_hw_params,
+ .hw_free = go7007_snd_hw_free,
+ .prepare = go7007_snd_pcm_prepare,
+ .trigger = go7007_snd_pcm_trigger,
+ .pointer = go7007_snd_pcm_pointer,
+ .page = go7007_snd_pcm_page,
+};
+
+static int go7007_snd_free(struct snd_device *device)
+{
+ struct go7007 *go = device->device_data;
+
+ kfree(go->snd_context);
+ go->snd_context = NULL;
+ if (--go->ref_count == 0)
+ kfree(go);
+ return 0;
+}
+
+static struct snd_device_ops go7007_snd_device_ops = {
+ .dev_free = go7007_snd_free,
+};
+
+int go7007_snd_init(struct go7007 *go)
+{
+ static int dev;
+ struct go7007_snd *gosnd;
+ int ret = 0;
+
+ if (dev >= SNDRV_CARDS)
+ return -ENODEV;
+ if (!enable[dev]) {
+ dev++;
+ return -ENOENT;
+ }
+ gosnd = kmalloc(sizeof(struct go7007_snd), GFP_KERNEL);
+ if (gosnd == NULL)
+ return -ENOMEM;
+ spin_lock_init(&gosnd->lock);
+ gosnd->hw_ptr = gosnd->w_idx = gosnd->avail = 0;
+ gosnd->capturing = 0;
+ gosnd->card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+ if (gosnd->card == NULL) {
+ kfree(gosnd);
+ return -ENOMEM;
+ }
+ ret = snd_device_new(gosnd->card, SNDRV_DEV_LOWLEVEL, go,
+ &go7007_snd_device_ops);
+ if (ret < 0) {
+ kfree(gosnd);
+ return ret;
+ }
+ snd_card_set_dev(gosnd->card, go->dev);
+ ret = snd_pcm_new(gosnd->card, "go7007", 0, 0, 1, &gosnd->pcm);
+ if (ret < 0) {
+ snd_card_free(gosnd->card);
+ kfree(gosnd);
+ return ret;
+ }
+ strncpy(gosnd->card->driver, "go7007", sizeof(gosnd->card->driver));
+ strncpy(gosnd->card->shortname, go->name, sizeof(gosnd->card->driver));
+ strncpy(gosnd->card->longname, gosnd->card->shortname,
+ sizeof(gosnd->card->longname));
+
+ gosnd->pcm->private_data = go;
+ snd_pcm_set_ops(gosnd->pcm, SNDRV_PCM_STREAM_CAPTURE,
+ &go7007_snd_capture_ops);
+
+ ret = snd_card_register(gosnd->card);
+ if (ret < 0) {
+ snd_card_free(gosnd->card);
+ kfree(gosnd);
+ return ret;
+ }
+
+ gosnd->substream = NULL;
+ go->snd_context = gosnd;
+ ++dev;
+ ++go->ref_count;
+
+ return 0;
+}
+EXPORT_SYMBOL(go7007_snd_init);
+
+int go7007_snd_remove(struct go7007 *go)
+{
+ struct go7007_snd *gosnd = go->snd_context;
+
+ snd_card_disconnect(gosnd->card);
+ snd_card_free_when_closed(gosnd->card);
+ return 0;
+}
+EXPORT_SYMBOL(go7007_snd_remove);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/go7007/wis-i2c.h b/drivers/staging/go7007/wis-i2c.h
new file mode 100644
index 0000000..993f658
--- /dev/null
+++ b/drivers/staging/go7007/wis-i2c.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/* Temporary I2C IDs -- these need to be replaced with real registered IDs */
+#define I2C_DRIVERID_WIS_SAA7115 0xf0f0
+#define I2C_DRIVERID_WIS_UDA1342 0xf0f1
+#define I2C_DRIVERID_WIS_SONY_TUNER 0xf0f2
+#define I2C_DRIVERID_WIS_TW9903 0xf0f3
+#define I2C_DRIVERID_WIS_SAA7113 0xf0f4
+#define I2C_DRIVERID_WIS_OV7640 0xf0f5
+#define I2C_DRIVERID_WIS_TW2804 0xf0f6
+#define I2C_ALGO_GO7007 0xf00000
+#define I2C_ALGO_GO7007_USB 0xf10000
+
+/* Flag to indicate that the client needs to be accessed with SCCB semantics */
+/* We re-use the I2C_M_TEN value so the flag passes through the masks in the
+ * core I2C code. Major kludge, but the I2C layer ain't exactly flexible. */
+#define I2C_CLIENT_SCCB 0x10
+
+typedef int (*found_proc) (struct i2c_adapter *, int, int);
+int wis_i2c_add_driver(unsigned int id, found_proc found_proc);
+void wis_i2c_del_driver(found_proc found_proc);
+
+int wis_i2c_probe_device(struct i2c_adapter *adapter,
+ unsigned int id, int addr);
+
+/* Definitions for new video decoder commands */
+
+struct video_decoder_resolution {
+ unsigned int width;
+ unsigned int height;
+};
+
+#define DECODER_SET_RESOLUTION _IOW('d', 200, struct video_decoder_resolution)
+#define DECODER_SET_CHANNEL _IOW('d', 201, int)
+
+/* Sony tuner types */
+
+#define TUNER_SONY_BTF_PG472Z 200
+#define TUNER_SONY_BTF_PK467Z 201
+#define TUNER_SONY_BTF_PB463Z 202
diff --git a/drivers/staging/go7007/wis-ov7640.c b/drivers/staging/go7007/wis-ov7640.c
new file mode 100644
index 0000000..815615a
--- /dev/null
+++ b/drivers/staging/go7007/wis-ov7640.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <linux/video_decoder.h>
+
+#include "wis-i2c.h"
+
+struct wis_ov7640 {
+ int brightness;
+ int contrast;
+ int saturation;
+ int hue;
+};
+
+static u8 initial_registers[] =
+{
+ 0x12, 0x80,
+ 0x12, 0x54,
+ 0x14, 0x24,
+ 0x15, 0x01,
+ 0x28, 0x20,
+ 0x75, 0x82,
+ 0xFF, 0xFF, /* Terminator (reg 0xFF is unused) */
+};
+
+static int write_regs(struct i2c_client *client, u8 *regs)
+{
+ int i;
+
+ for (i = 0; regs[i] != 0xFF; i += 2)
+ if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0)
+ return -1;
+ return 0;
+}
+
+static struct i2c_driver wis_ov7640_driver;
+
+static struct i2c_client wis_ov7640_client_templ = {
+ .name = "OV7640 (WIS)",
+ .driver = &wis_ov7640_driver,
+};
+
+static int wis_ov7640_detect(struct i2c_adapter *adapter, int addr, int kind)
+{
+ struct i2c_client *client;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return 0;
+
+ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == NULL)
+ return -ENOMEM;
+ memcpy(client, &wis_ov7640_client_templ,
+ sizeof(wis_ov7640_client_templ));
+ client->adapter = adapter;
+ client->addr = addr;
+ client->flags = I2C_CLIENT_SCCB;
+
+ printk(KERN_DEBUG
+ "wis-ov7640: initializing OV7640 at address %d on %s\n",
+ addr, adapter->name);
+
+ if (write_regs(client, initial_registers) < 0) {
+ printk(KERN_ERR "wis-ov7640: error initializing OV7640\n");
+ kfree(client);
+ return 0;
+ }
+
+ i2c_attach_client(client);
+ return 0;
+}
+
+static int wis_ov7640_detach(struct i2c_client *client)
+{
+ int r;
+
+ r = i2c_detach_client(client);
+ if (r < 0)
+ return r;
+
+ kfree(client);
+ return 0;
+}
+
+static struct i2c_driver wis_ov7640_driver = {
+ .driver = {
+ .name = "WIS OV7640 I2C driver",
+ },
+ .id = I2C_DRIVERID_WIS_OV7640,
+ .detach_client = wis_ov7640_detach,
+};
+
+static int __init wis_ov7640_init(void)
+{
+ int r;
+
+ r = i2c_add_driver(&wis_ov7640_driver);
+ if (r < 0)
+ return r;
+ return wis_i2c_add_driver(wis_ov7640_driver.id, wis_ov7640_detect);
+}
+
+static void __exit wis_ov7640_cleanup(void)
+{
+ wis_i2c_del_driver(wis_ov7640_detect);
+ i2c_del_driver(&wis_ov7640_driver);
+}
+
+module_init(wis_ov7640_init);
+module_exit(wis_ov7640_cleanup);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/go7007/wis-saa7113.c b/drivers/staging/go7007/wis-saa7113.c
new file mode 100644
index 0000000..4b14ca8
--- /dev/null
+++ b/drivers/staging/go7007/wis-saa7113.c
@@ -0,0 +1,363 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <linux/video_decoder.h>
+#include <linux/ioctl.h>
+
+#include "wis-i2c.h"
+
+struct wis_saa7113 {
+ int norm;
+ int brightness;
+ int contrast;
+ int saturation;
+ int hue;
+};
+
+static u8 initial_registers[] =
+{
+ 0x01, 0x08,
+ 0x02, 0xc0,
+ 0x03, 0x33,
+ 0x04, 0x00,
+ 0x05, 0x00,
+ 0x06, 0xe9,
+ 0x07, 0x0d,
+ 0x08, 0xd8,
+ 0x09, 0x40,
+ 0x0a, 0x80,
+ 0x0b, 0x47,
+ 0x0c, 0x40,
+ 0x0d, 0x00,
+ 0x0e, 0x01,
+ 0x0f, 0x2a,
+ 0x10, 0x40,
+ 0x11, 0x0c,
+ 0x12, 0xfe,
+ 0x13, 0x00,
+ 0x14, 0x00,
+ 0x15, 0x04,
+ 0x16, 0x00,
+ 0x17, 0x00,
+ 0x18, 0x00,
+ 0x19, 0x00,
+ 0x1a, 0x00,
+ 0x1b, 0x00,
+ 0x1c, 0x00,
+ 0x1d, 0x00,
+ 0x1e, 0x00,
+ 0x1f, 0xc8,
+ 0x40, 0x00,
+ 0x41, 0xff,
+ 0x42, 0xff,
+ 0x43, 0xff,
+ 0x44, 0xff,
+ 0x45, 0xff,
+ 0x46, 0xff,
+ 0x47, 0xff,
+ 0x48, 0xff,
+ 0x49, 0xff,
+ 0x4a, 0xff,
+ 0x4b, 0xff,
+ 0x4c, 0xff,
+ 0x4d, 0xff,
+ 0x4e, 0xff,
+ 0x4f, 0xff,
+ 0x50, 0xff,
+ 0x51, 0xff,
+ 0x52, 0xff,
+ 0x53, 0xff,
+ 0x54, 0xff,
+ 0x55, 0xff,
+ 0x56, 0xff,
+ 0x57, 0xff,
+ 0x58, 0x00,
+ 0x59, 0x54,
+ 0x5a, 0x07,
+ 0x5b, 0x83,
+ 0x5c, 0x00,
+ 0x5d, 0x00,
+ 0x5e, 0x00,
+ 0x5f, 0x00,
+ 0x60, 0x00,
+ 0x61, 0x00,
+ 0x00, 0x00, /* Terminator (reg 0x00 is read-only) */
+};
+
+static int write_reg(struct i2c_client *client, u8 reg, u8 value)
+{
+ return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int write_regs(struct i2c_client *client, u8 *regs)
+{
+ int i;
+
+ for (i = 0; regs[i] != 0x00; i += 2)
+ if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0)
+ return -1;
+ return 0;
+}
+
+static int wis_saa7113_command(struct i2c_client *client,
+ unsigned int cmd, void *arg)
+{
+ struct wis_saa7113 *dec = i2c_get_clientdata(client);
+
+ switch (cmd) {
+ case DECODER_SET_INPUT:
+ {
+ int *input = arg;
+
+ i2c_smbus_write_byte_data(client, 0x02, 0xC0 | *input);
+ i2c_smbus_write_byte_data(client, 0x09,
+ *input < 6 ? 0x40 : 0x80);
+ break;
+ }
+ case DECODER_SET_NORM:
+ {
+ int *input = arg;
+ dec->norm = *input;
+ switch (dec->norm) {
+ case VIDEO_MODE_PAL:
+ write_reg(client, 0x0e, 0x01);
+ write_reg(client, 0x10, 0x48);
+ break;
+ case VIDEO_MODE_NTSC:
+ write_reg(client, 0x0e, 0x01);
+ write_reg(client, 0x10, 0x40);
+ break;
+ case VIDEO_MODE_SECAM:
+ write_reg(client, 0x0e, 0x50);
+ write_reg(client, 0x10, 0x48);
+ break;
+ }
+ break;
+ }
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *ctrl = arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ strncpy(ctrl->name, "Brightness", sizeof(ctrl->name));
+ ctrl->minimum = 0;
+ ctrl->maximum = 255;
+ ctrl->step = 1;
+ ctrl->default_value = 128;
+ ctrl->flags = 0;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ strncpy(ctrl->name, "Contrast", sizeof(ctrl->name));
+ ctrl->minimum = 0;
+ ctrl->maximum = 127;
+ ctrl->step = 1;
+ ctrl->default_value = 71;
+ ctrl->flags = 0;
+ break;
+ case V4L2_CID_SATURATION:
+ ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ strncpy(ctrl->name, "Saturation", sizeof(ctrl->name));
+ ctrl->minimum = 0;
+ ctrl->maximum = 127;
+ ctrl->step = 1;
+ ctrl->default_value = 64;
+ ctrl->flags = 0;
+ break;
+ case V4L2_CID_HUE:
+ ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ strncpy(ctrl->name, "Hue", sizeof(ctrl->name));
+ ctrl->minimum = -128;
+ ctrl->maximum = 127;
+ ctrl->step = 1;
+ ctrl->default_value = 0;
+ ctrl->flags = 0;
+ break;
+ }
+ break;
+ }
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ if (ctrl->value > 255)
+ dec->brightness = 255;
+ else if (ctrl->value < 0)
+ dec->brightness = 0;
+ else
+ dec->brightness = ctrl->value;
+ write_reg(client, 0x0a, dec->brightness);
+ break;
+ case V4L2_CID_CONTRAST:
+ if (ctrl->value > 127)
+ dec->contrast = 127;
+ else if (ctrl->value < 0)
+ dec->contrast = 0;
+ else
+ dec->contrast = ctrl->value;
+ write_reg(client, 0x0b, dec->contrast);
+ break;
+ case V4L2_CID_SATURATION:
+ if (ctrl->value > 127)
+ dec->saturation = 127;
+ else if (ctrl->value < 0)
+ dec->saturation = 0;
+ else
+ dec->saturation = ctrl->value;
+ write_reg(client, 0x0c, dec->saturation);
+ break;
+ case V4L2_CID_HUE:
+ if (ctrl->value > 127)
+ dec->hue = 127;
+ else if (ctrl->value < -128)
+ dec->hue = -128;
+ else
+ dec->hue = ctrl->value;
+ write_reg(client, 0x0d, dec->hue);
+ break;
+ }
+ break;
+ }
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->value = dec->brightness;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctrl->value = dec->contrast;
+ break;
+ case V4L2_CID_SATURATION:
+ ctrl->value = dec->saturation;
+ break;
+ case V4L2_CID_HUE:
+ ctrl->value = dec->hue;
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return 0;
+}
+
+static struct i2c_driver wis_saa7113_driver;
+
+static struct i2c_client wis_saa7113_client_templ = {
+ .name = "SAA7113 (WIS)",
+ .driver = &wis_saa7113_driver,
+};
+
+static int wis_saa7113_detect(struct i2c_adapter *adapter, int addr, int kind)
+{
+ struct i2c_client *client;
+ struct wis_saa7113 *dec;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return 0;
+
+ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == NULL)
+ return -ENOMEM;
+ memcpy(client, &wis_saa7113_client_templ,
+ sizeof(wis_saa7113_client_templ));
+ client->adapter = adapter;
+ client->addr = addr;
+
+ dec = kmalloc(sizeof(struct wis_saa7113), GFP_KERNEL);
+ if (dec == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+ dec->norm = VIDEO_MODE_NTSC;
+ dec->brightness = 128;
+ dec->contrast = 71;
+ dec->saturation = 64;
+ dec->hue = 0;
+ i2c_set_clientdata(client, dec);
+
+ printk(KERN_DEBUG
+ "wis-saa7113: initializing SAA7113 at address %d on %s\n",
+ addr, adapter->name);
+
+ if (write_regs(client, initial_registers) < 0) {
+ printk(KERN_ERR
+ "wis-saa7113: error initializing SAA7113\n");
+ kfree(client);
+ kfree(dec);
+ return 0;
+ }
+
+ i2c_attach_client(client);
+ return 0;
+}
+
+static int wis_saa7113_detach(struct i2c_client *client)
+{
+ struct wis_saa7113 *dec = i2c_get_clientdata(client);
+ int r;
+
+ r = i2c_detach_client(client);
+ if (r < 0)
+ return r;
+
+ kfree(client);
+ kfree(dec);
+ return 0;
+}
+
+static struct i2c_driver wis_saa7113_driver = {
+ .driver = {
+ .name = "WIS SAA7113 I2C driver",
+ },
+ .id = I2C_DRIVERID_WIS_SAA7113,
+ .detach_client = wis_saa7113_detach,
+ .command = wis_saa7113_command,
+};
+
+static int __init wis_saa7113_init(void)
+{
+ int r;
+
+ r = i2c_add_driver(&wis_saa7113_driver);
+ if (r < 0)
+ return r;
+ return wis_i2c_add_driver(wis_saa7113_driver.id, wis_saa7113_detect);
+}
+
+static void __exit wis_saa7113_cleanup(void)
+{
+ wis_i2c_del_driver(wis_saa7113_detect);
+ i2c_del_driver(&wis_saa7113_driver);
+}
+
+module_init(wis_saa7113_init);
+module_exit(wis_saa7113_cleanup);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/go7007/wis-saa7115.c b/drivers/staging/go7007/wis-saa7115.c
new file mode 100644
index 0000000..bd40bf4
--- /dev/null
+++ b/drivers/staging/go7007/wis-saa7115.c
@@ -0,0 +1,492 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <linux/video_decoder.h>
+#include <linux/ioctl.h>
+
+#include "wis-i2c.h"
+
+struct wis_saa7115 {
+ int norm;
+ int brightness;
+ int contrast;
+ int saturation;
+ int hue;
+};
+
+static u8 initial_registers[] =
+{
+ 0x01, 0x08,
+ 0x02, 0xc0,
+ 0x03, 0x20,
+ 0x04, 0x80,
+ 0x05, 0x80,
+ 0x06, 0xeb,
+ 0x07, 0xe0,
+ 0x08, 0xf0, /* always toggle FID */
+ 0x09, 0x40,
+ 0x0a, 0x80,
+ 0x0b, 0x40,
+ 0x0c, 0x40,
+ 0x0d, 0x00,
+ 0x0e, 0x03,
+ 0x0f, 0x2a,
+ 0x10, 0x0e,
+ 0x11, 0x00,
+ 0x12, 0x8d,
+ 0x13, 0x00,
+ 0x14, 0x00,
+ 0x15, 0x11,
+ 0x16, 0x01,
+ 0x17, 0xda,
+ 0x18, 0x40,
+ 0x19, 0x80,
+ 0x1a, 0x00,
+ 0x1b, 0x42,
+ 0x1c, 0xa9,
+ 0x30, 0x66,
+ 0x31, 0x90,
+ 0x32, 0x01,
+ 0x34, 0x00,
+ 0x35, 0x00,
+ 0x36, 0x20,
+ 0x38, 0x03,
+ 0x39, 0x20,
+ 0x3a, 0x88,
+ 0x40, 0x00,
+ 0x41, 0xff,
+ 0x42, 0xff,
+ 0x43, 0xff,
+ 0x44, 0xff,
+ 0x45, 0xff,
+ 0x46, 0xff,
+ 0x47, 0xff,
+ 0x48, 0xff,
+ 0x49, 0xff,
+ 0x4a, 0xff,
+ 0x4b, 0xff,
+ 0x4c, 0xff,
+ 0x4d, 0xff,
+ 0x4e, 0xff,
+ 0x4f, 0xff,
+ 0x50, 0xff,
+ 0x51, 0xff,
+ 0x52, 0xff,
+ 0x53, 0xff,
+ 0x54, 0xf4 /*0xff*/,
+ 0x55, 0xff,
+ 0x56, 0xff,
+ 0x57, 0xff,
+ 0x58, 0x40,
+ 0x59, 0x47,
+ 0x5a, 0x06 /*0x03*/,
+ 0x5b, 0x83,
+ 0x5d, 0x06,
+ 0x5e, 0x00,
+ 0x80, 0x30, /* window defined scaler operation, task A and B enabled */
+ 0x81, 0x03, /* use scaler datapath generated V */
+ 0x83, 0x00,
+ 0x84, 0x00,
+ 0x85, 0x00,
+ 0x86, 0x45,
+ 0x87, 0x31,
+ 0x88, 0xc0,
+ 0x90, 0x02, /* task A process top field */
+ 0x91, 0x08,
+ 0x92, 0x09,
+ 0x93, 0x80,
+ 0x94, 0x06,
+ 0x95, 0x00,
+ 0x96, 0xc0,
+ 0x97, 0x02,
+ 0x98, 0x12,
+ 0x99, 0x00,
+ 0x9a, 0xf2,
+ 0x9b, 0x00,
+ 0x9c, 0xd0,
+ 0x9d, 0x02,
+ 0x9e, 0xf2,
+ 0x9f, 0x00,
+ 0xa0, 0x01,
+ 0xa1, 0x01,
+ 0xa2, 0x01,
+ 0xa4, 0x80,
+ 0xa5, 0x40,
+ 0xa6, 0x40,
+ 0xa8, 0x00,
+ 0xa9, 0x04,
+ 0xaa, 0x00,
+ 0xac, 0x00,
+ 0xad, 0x02,
+ 0xae, 0x00,
+ 0xb0, 0x00,
+ 0xb1, 0x04,
+ 0xb2, 0x00,
+ 0xb3, 0x04,
+ 0xb4, 0x00,
+ 0xb8, 0x00,
+ 0xbc, 0x00,
+ 0xc0, 0x03, /* task B process bottom field */
+ 0xc1, 0x08,
+ 0xc2, 0x09,
+ 0xc3, 0x80,
+ 0xc4, 0x06,
+ 0xc5, 0x00,
+ 0xc6, 0xc0,
+ 0xc7, 0x02,
+ 0xc8, 0x12,
+ 0xc9, 0x00,
+ 0xca, 0xf2,
+ 0xcb, 0x00,
+ 0xcc, 0xd0,
+ 0xcd, 0x02,
+ 0xce, 0xf2,
+ 0xcf, 0x00,
+ 0xd0, 0x01,
+ 0xd1, 0x01,
+ 0xd2, 0x01,
+ 0xd4, 0x80,
+ 0xd5, 0x40,
+ 0xd6, 0x40,
+ 0xd8, 0x00,
+ 0xd9, 0x04,
+ 0xda, 0x00,
+ 0xdc, 0x00,
+ 0xdd, 0x02,
+ 0xde, 0x00,
+ 0xe0, 0x00,
+ 0xe1, 0x04,
+ 0xe2, 0x00,
+ 0xe3, 0x04,
+ 0xe4, 0x00,
+ 0xe8, 0x00,
+ 0x88, 0xf0, /* End of original static list */
+ 0x00, 0x00, /* Terminator (reg 0x00 is read-only) */
+};
+
+static int write_reg(struct i2c_client *client, u8 reg, u8 value)
+{
+ return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int write_regs(struct i2c_client *client, u8 *regs)
+{
+ int i;
+
+ for (i = 0; regs[i] != 0x00; i += 2)
+ if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0)
+ return -1;
+ return 0;
+}
+
+static int wis_saa7115_command(struct i2c_client *client,
+ unsigned int cmd, void *arg)
+{
+ struct wis_saa7115 *dec = i2c_get_clientdata(client);
+
+ switch (cmd) {
+ case DECODER_SET_INPUT:
+ {
+ int *input = arg;
+
+ i2c_smbus_write_byte_data(client, 0x02, 0xC0 | *input);
+ i2c_smbus_write_byte_data(client, 0x09,
+ *input < 6 ? 0x40 : 0xC0);
+ break;
+ }
+ case DECODER_SET_RESOLUTION:
+ {
+ struct video_decoder_resolution *res = arg;
+ /* Course-grained scaler */
+ int h_integer_scaler = res->width < 704 ? 704 / res->width : 1;
+ /* Fine-grained scaler to take care of remainder */
+ int h_scaling_increment = (704 / h_integer_scaler) *
+ 1024 / res->width;
+ /* Fine-grained scaler only */
+ int v_scaling_increment = (dec->norm == VIDEO_MODE_NTSC ?
+ 240 : 288) * 1024 / res->height;
+ u8 regs[] = {
+ 0x88, 0xc0,
+ 0x9c, res->width & 0xff,
+ 0x9d, res->width >> 8,
+ 0x9e, res->height & 0xff,
+ 0x9f, res->height >> 8,
+ 0xa0, h_integer_scaler,
+ 0xa1, 1,
+ 0xa2, 1,
+ 0xa8, h_scaling_increment & 0xff,
+ 0xa9, h_scaling_increment >> 8,
+ 0xac, (h_scaling_increment / 2) & 0xff,
+ 0xad, (h_scaling_increment / 2) >> 8,
+ 0xb0, v_scaling_increment & 0xff,
+ 0xb1, v_scaling_increment >> 8,
+ 0xb2, v_scaling_increment & 0xff,
+ 0xb3, v_scaling_increment >> 8,
+ 0xcc, res->width & 0xff,
+ 0xcd, res->width >> 8,
+ 0xce, res->height & 0xff,
+ 0xcf, res->height >> 8,
+ 0xd0, h_integer_scaler,
+ 0xd1, 1,
+ 0xd2, 1,
+ 0xd8, h_scaling_increment & 0xff,
+ 0xd9, h_scaling_increment >> 8,
+ 0xdc, (h_scaling_increment / 2) & 0xff,
+ 0xdd, (h_scaling_increment / 2) >> 8,
+ 0xe0, v_scaling_increment & 0xff,
+ 0xe1, v_scaling_increment >> 8,
+ 0xe2, v_scaling_increment & 0xff,
+ 0xe3, v_scaling_increment >> 8,
+ 0x88, 0xf0,
+ 0, 0,
+ };
+ write_regs(client, regs);
+ break;
+ }
+ case DECODER_SET_NORM:
+ {
+ int *input = arg;
+ u8 regs[] = {
+ 0x88, 0xc0,
+ 0x98, *input == VIDEO_MODE_NTSC ? 0x12 : 0x16,
+ 0x9a, *input == VIDEO_MODE_NTSC ? 0xf2 : 0x20,
+ 0x9b, *input == VIDEO_MODE_NTSC ? 0x00 : 0x01,
+ 0xc8, *input == VIDEO_MODE_NTSC ? 0x12 : 0x16,
+ 0xca, *input == VIDEO_MODE_NTSC ? 0xf2 : 0x20,
+ 0xcb, *input == VIDEO_MODE_NTSC ? 0x00 : 0x01,
+ 0x88, 0xf0,
+ 0x30, *input == VIDEO_MODE_NTSC ? 0x66 : 0x00,
+ 0x31, *input == VIDEO_MODE_NTSC ? 0x90 : 0xe0,
+ 0, 0,
+ };
+ write_regs(client, regs);
+ dec->norm = *input;
+ break;
+ }
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *ctrl = arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ strncpy(ctrl->name, "Brightness", sizeof(ctrl->name));
+ ctrl->minimum = 0;
+ ctrl->maximum = 255;
+ ctrl->step = 1;
+ ctrl->default_value = 128;
+ ctrl->flags = 0;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ strncpy(ctrl->name, "Contrast", sizeof(ctrl->name));
+ ctrl->minimum = 0;
+ ctrl->maximum = 127;
+ ctrl->step = 1;
+ ctrl->default_value = 64;
+ ctrl->flags = 0;
+ break;
+ case V4L2_CID_SATURATION:
+ ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ strncpy(ctrl->name, "Saturation", sizeof(ctrl->name));
+ ctrl->minimum = 0;
+ ctrl->maximum = 127;
+ ctrl->step = 1;
+ ctrl->default_value = 64;
+ ctrl->flags = 0;
+ break;
+ case V4L2_CID_HUE:
+ ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ strncpy(ctrl->name, "Hue", sizeof(ctrl->name));
+ ctrl->minimum = -128;
+ ctrl->maximum = 127;
+ ctrl->step = 1;
+ ctrl->default_value = 0;
+ ctrl->flags = 0;
+ break;
+ }
+ break;
+ }
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ if (ctrl->value > 255)
+ dec->brightness = 255;
+ else if (ctrl->value < 0)
+ dec->brightness = 0;
+ else
+ dec->brightness = ctrl->value;
+ write_reg(client, 0x0a, dec->brightness);
+ break;
+ case V4L2_CID_CONTRAST:
+ if (ctrl->value > 127)
+ dec->contrast = 127;
+ else if (ctrl->value < 0)
+ dec->contrast = 0;
+ else
+ dec->contrast = ctrl->value;
+ write_reg(client, 0x0b, dec->contrast);
+ break;
+ case V4L2_CID_SATURATION:
+ if (ctrl->value > 127)
+ dec->saturation = 127;
+ else if (ctrl->value < 0)
+ dec->saturation = 0;
+ else
+ dec->saturation = ctrl->value;
+ write_reg(client, 0x0c, dec->saturation);
+ break;
+ case V4L2_CID_HUE:
+ if (ctrl->value > 127)
+ dec->hue = 127;
+ else if (ctrl->value < -128)
+ dec->hue = -128;
+ else
+ dec->hue = ctrl->value;
+ write_reg(client, 0x0d, dec->hue);
+ break;
+ }
+ break;
+ }
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->value = dec->brightness;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctrl->value = dec->contrast;
+ break;
+ case V4L2_CID_SATURATION:
+ ctrl->value = dec->saturation;
+ break;
+ case V4L2_CID_HUE:
+ ctrl->value = dec->hue;
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return 0;
+}
+
+static struct i2c_driver wis_saa7115_driver;
+
+static struct i2c_client wis_saa7115_client_templ = {
+ .name = "SAA7115 (WIS)",
+ .driver = &wis_saa7115_driver,
+};
+
+static int wis_saa7115_detect(struct i2c_adapter *adapter, int addr, int kind)
+{
+ struct i2c_client *client;
+ struct wis_saa7115 *dec;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return 0;
+
+ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == NULL)
+ return -ENOMEM;
+ memcpy(client, &wis_saa7115_client_templ,
+ sizeof(wis_saa7115_client_templ));
+ client->adapter = adapter;
+ client->addr = addr;
+
+ dec = kmalloc(sizeof(struct wis_saa7115), GFP_KERNEL);
+ if (dec == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+ dec->norm = VIDEO_MODE_NTSC;
+ dec->brightness = 128;
+ dec->contrast = 64;
+ dec->saturation = 64;
+ dec->hue = 0;
+ i2c_set_clientdata(client, dec);
+
+ printk(KERN_DEBUG
+ "wis-saa7115: initializing SAA7115 at address %d on %s\n",
+ addr, adapter->name);
+
+ if (write_regs(client, initial_registers) < 0) {
+ printk(KERN_ERR
+ "wis-saa7115: error initializing SAA7115\n");
+ kfree(client);
+ kfree(dec);
+ return 0;
+ }
+
+ i2c_attach_client(client);
+ return 0;
+}
+
+static int wis_saa7115_detach(struct i2c_client *client)
+{
+ struct wis_saa7115 *dec = i2c_get_clientdata(client);
+ int r;
+
+ r = i2c_detach_client(client);
+ if (r < 0)
+ return r;
+
+ kfree(client);
+ kfree(dec);
+ return 0;
+}
+
+static struct i2c_driver wis_saa7115_driver = {
+ .driver = {
+ .name = "WIS SAA7115 I2C driver",
+ },
+ .id = I2C_DRIVERID_WIS_SAA7115,
+ .detach_client = wis_saa7115_detach,
+ .command = wis_saa7115_command,
+};
+
+static int __init wis_saa7115_init(void)
+{
+ int r;
+
+ r = i2c_add_driver(&wis_saa7115_driver);
+ if (r < 0)
+ return r;
+ return wis_i2c_add_driver(wis_saa7115_driver.id, wis_saa7115_detect);
+}
+
+static void __exit wis_saa7115_cleanup(void)
+{
+ wis_i2c_del_driver(wis_saa7115_detect);
+ i2c_del_driver(&wis_saa7115_driver);
+}
+
+module_init(wis_saa7115_init);
+module_exit(wis_saa7115_cleanup);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/go7007/wis-sony-tuner.c b/drivers/staging/go7007/wis-sony-tuner.c
new file mode 100644
index 0000000..82e66d6
--- /dev/null
+++ b/drivers/staging/go7007/wis-sony-tuner.c
@@ -0,0 +1,741 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <media/tuner.h>
+#include <media/v4l2-common.h>
+
+#include "wis-i2c.h"
+
+/* #define MPX_DEBUG */
+
+/* AS(IF/MPX) pin: LOW HIGH/OPEN
+ * IF/MPX address: 0x42/0x40 0x43/0x44
+ */
+#define IF_I2C_ADDR 0x43
+#define MPX_I2C_ADDR 0x44
+
+static v4l2_std_id force_band;
+static char force_band_str[] = "-";
+module_param_string(force_band, force_band_str, sizeof(force_band_str), 0644);
+static int force_mpx_mode = -1;
+module_param(force_mpx_mode, int, 0644);
+
+/* Store tuner info in the same format as tuner.c, so maybe we can put the
+ * Sony tuner support in there. */
+struct sony_tunertype {
+ char *name;
+ unsigned char Vendor; /* unused here */
+ unsigned char Type; /* unused here */
+
+ unsigned short thresh1; /* band switch VHF_LO <=> VHF_HI */
+ unsigned short thresh2; /* band switch VHF_HI <=> UHF */
+ unsigned char VHF_L;
+ unsigned char VHF_H;
+ unsigned char UHF;
+ unsigned char config;
+ unsigned short IFPCoff;
+};
+
+/* This array is indexed by (tuner_type - 200) */
+static struct sony_tunertype sony_tuners[] = {
+ { "Sony PAL+SECAM (BTF-PG472Z)", 0, 0,
+ 16*144.25, 16*427.25, 0x01, 0x02, 0x04, 0xc6, 623},
+ { "Sony NTSC_JP (BTF-PK467Z)", 0, 0,
+ 16*220.25, 16*467.25, 0x01, 0x02, 0x04, 0xc6, 940},
+ { "Sony NTSC (BTF-PB463Z)", 0, 0,
+ 16*130.25, 16*364.25, 0x01, 0x02, 0x04, 0xc6, 732},
+};
+
+struct wis_sony_tuner {
+ int type;
+ v4l2_std_id std;
+ unsigned int freq;
+ int mpxmode;
+ u32 audmode;
+};
+
+/* Basically the same as default_set_tv_freq() in tuner.c */
+static int set_freq(struct i2c_client *client, int freq)
+{
+ struct wis_sony_tuner *t = i2c_get_clientdata(client);
+ char *band_name;
+ int n;
+ int band_select;
+ struct sony_tunertype *tun;
+ u8 buffer[4];
+
+ tun = &sony_tuners[t->type - 200];
+ if (freq < tun->thresh1) {
+ band_name = "VHF_L";
+ band_select = tun->VHF_L;
+ } else if (freq < tun->thresh2) {
+ band_name = "VHF_H";
+ band_select = tun->VHF_H;
+ } else {
+ band_name = "UHF";
+ band_select = tun->UHF;
+ }
+ printk(KERN_DEBUG "wis-sony-tuner: tuning to frequency %d.%04d (%s)\n",
+ freq / 16, (freq % 16) * 625, band_name);
+ n = freq + tun->IFPCoff;
+
+ buffer[0] = n >> 8;
+ buffer[1] = n & 0xff;
+ buffer[2] = tun->config;
+ buffer[3] = band_select;
+ i2c_master_send(client, buffer, 4);
+
+ return 0;
+}
+
+static int mpx_write(struct i2c_client *client, int dev, int addr, int val)
+{
+ u8 buffer[5];
+ struct i2c_msg msg;
+
+ buffer[0] = dev;
+ buffer[1] = addr >> 8;
+ buffer[2] = addr & 0xff;
+ buffer[3] = val >> 8;
+ buffer[4] = val & 0xff;
+ msg.addr = MPX_I2C_ADDR;
+ msg.flags = 0;
+ msg.len = 5;
+ msg.buf = buffer;
+ i2c_transfer(client->adapter, &msg, 1);
+ return 0;
+}
+
+/*
+ * MPX register values for the BTF-PG472Z:
+ *
+ * FM_ NICAM_ SCART_
+ * MODUS SOURCE ACB PRESCAL PRESCAL PRESCAL SYSTEM VOLUME
+ * 10/0030 12/0008 12/0013 12/000E 12/0010 12/0000 10/0020 12/0000
+ * ---------------------------------------------------------------
+ * Auto 1003 0020 0100 2603 5000 XXXX 0001 7500
+ *
+ * B/G
+ * Mono 1003 0020 0100 2603 5000 XXXX 0003 7500
+ * A2 1003 0020 0100 2601 5000 XXXX 0003 7500
+ * NICAM 1003 0120 0100 2603 5000 XXXX 0008 7500
+ *
+ * I
+ * Mono 1003 0020 0100 2603 7900 XXXX 000A 7500
+ * NICAM 1003 0120 0100 2603 7900 XXXX 000A 7500
+ *
+ * D/K
+ * Mono 1003 0020 0100 2603 5000 XXXX 0004 7500
+ * A2-1 1003 0020 0100 2601 5000 XXXX 0004 7500
+ * A2-2 1003 0020 0100 2601 5000 XXXX 0005 7500
+ * A2-3 1003 0020 0100 2601 5000 XXXX 0007 7500
+ * NICAM 1003 0120 0100 2603 5000 XXXX 000B 7500
+ *
+ * L/L'
+ * Mono 0003 0200 0100 7C03 5000 2200 0009 7500
+ * NICAM 0003 0120 0100 7C03 5000 XXXX 0009 7500
+ *
+ * M
+ * Mono 1003 0200 0100 2B03 5000 2B00 0002 7500
+ *
+ * For Asia, replace the 0x26XX in FM_PRESCALE with 0x14XX.
+ *
+ * Bilingual selection in A2/NICAM:
+ *
+ * High byte of SOURCE Left chan Right chan
+ * 0x01 MAIN SUB
+ * 0x03 MAIN MAIN
+ * 0x04 SUB SUB
+ *
+ * Force mono in NICAM by setting the high byte of SOURCE to 0x02 (L/L') or
+ * 0x00 (all other bands). Force mono in A2 with FMONO_A2:
+ *
+ * FMONO_A2
+ * 10/0022
+ * --------
+ * Forced mono ON 07F0
+ * Forced mono OFF 0190
+ */
+
+static struct {
+ enum { AUD_MONO, AUD_A2, AUD_NICAM, AUD_NICAM_L } audio_mode;
+ u16 modus;
+ u16 source;
+ u16 acb;
+ u16 fm_prescale;
+ u16 nicam_prescale;
+ u16 scart_prescale;
+ u16 system;
+ u16 volume;
+} mpx_audio_modes[] = {
+ /* Auto */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
+ 0x5000, 0x0000, 0x0001, 0x7500 },
+ /* B/G Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
+ 0x5000, 0x0000, 0x0003, 0x7500 },
+ /* B/G A2 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601,
+ 0x5000, 0x0000, 0x0003, 0x7500 },
+ /* B/G NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603,
+ 0x5000, 0x0000, 0x0008, 0x7500 },
+ /* I Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
+ 0x7900, 0x0000, 0x000A, 0x7500 },
+ /* I NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603,
+ 0x7900, 0x0000, 0x000A, 0x7500 },
+ /* D/K Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603,
+ 0x5000, 0x0000, 0x0004, 0x7500 },
+ /* D/K A2-1 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601,
+ 0x5000, 0x0000, 0x0004, 0x7500 },
+ /* D/K A2-2 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601,
+ 0x5000, 0x0000, 0x0005, 0x7500 },
+ /* D/K A2-3 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601,
+ 0x5000, 0x0000, 0x0007, 0x7500 },
+ /* D/K NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603,
+ 0x5000, 0x0000, 0x000B, 0x7500 },
+ /* L/L' Mono */ { AUD_MONO, 0x0003, 0x0200, 0x0100, 0x7C03,
+ 0x5000, 0x2200, 0x0009, 0x7500 },
+ /* L/L' NICAM */{ AUD_NICAM_L, 0x0003, 0x0120, 0x0100, 0x7C03,
+ 0x5000, 0x0000, 0x0009, 0x7500 },
+};
+
+#define MPX_NUM_MODES ARRAY_SIZE(mpx_audio_modes)
+
+static int mpx_setup(struct i2c_client *client)
+{
+ struct wis_sony_tuner *t = i2c_get_clientdata(client);
+ u16 source = 0;
+ u8 buffer[3];
+ struct i2c_msg msg;
+
+ /* reset MPX */
+ buffer[0] = 0x00;
+ buffer[1] = 0x80;
+ buffer[2] = 0x00;
+ msg.addr = MPX_I2C_ADDR;
+ msg.flags = 0;
+ msg.len = 3;
+ msg.buf = buffer;
+ i2c_transfer(client->adapter, &msg, 1);
+ buffer[1] = 0x00;
+ i2c_transfer(client->adapter, &msg, 1);
+
+ if (mpx_audio_modes[t->mpxmode].audio_mode != AUD_MONO) {
+ switch (t->audmode) {
+ case V4L2_TUNER_MODE_MONO:
+ switch (mpx_audio_modes[t->mpxmode].audio_mode) {
+ case AUD_A2:
+ source = mpx_audio_modes[t->mpxmode].source;
+ break;
+ case AUD_NICAM:
+ source = 0x0000;
+ break;
+ case AUD_NICAM_L:
+ source = 0x0200;
+ break;
+ default:
+ break;
+ }
+ break;
+ case V4L2_TUNER_MODE_STEREO:
+ source = mpx_audio_modes[t->mpxmode].source;
+ break;
+ case V4L2_TUNER_MODE_LANG1:
+ source = 0x0300;
+ break;
+ case V4L2_TUNER_MODE_LANG2:
+ source = 0x0400;
+ break;
+ }
+ source |= mpx_audio_modes[t->mpxmode].source & 0x00ff;
+ } else
+ source = mpx_audio_modes[t->mpxmode].source;
+
+ mpx_write(client, 0x10, 0x0030, mpx_audio_modes[t->mpxmode].modus);
+ mpx_write(client, 0x12, 0x0008, source);
+ mpx_write(client, 0x12, 0x0013, mpx_audio_modes[t->mpxmode].acb);
+ mpx_write(client, 0x12, 0x000e,
+ mpx_audio_modes[t->mpxmode].fm_prescale);
+ mpx_write(client, 0x12, 0x0010,
+ mpx_audio_modes[t->mpxmode].nicam_prescale);
+ mpx_write(client, 0x12, 0x000d,
+ mpx_audio_modes[t->mpxmode].scart_prescale);
+ mpx_write(client, 0x10, 0x0020, mpx_audio_modes[t->mpxmode].system);
+ mpx_write(client, 0x12, 0x0000, mpx_audio_modes[t->mpxmode].volume);
+ if (mpx_audio_modes[t->mpxmode].audio_mode == AUD_A2)
+ mpx_write(client, 0x10, 0x0022,
+ t->audmode == V4L2_TUNER_MODE_MONO ? 0x07f0 : 0x0190);
+
+#ifdef MPX_DEBUG
+ {
+ u8 buf1[3], buf2[2];
+ struct i2c_msg msgs[2];
+
+ printk(KERN_DEBUG "wis-sony-tuner: MPX registers: %04x %04x "
+ "%04x %04x %04x %04x %04x %04x\n",
+ mpx_audio_modes[t->mpxmode].modus,
+ source,
+ mpx_audio_modes[t->mpxmode].acb,
+ mpx_audio_modes[t->mpxmode].fm_prescale,
+ mpx_audio_modes[t->mpxmode].nicam_prescale,
+ mpx_audio_modes[t->mpxmode].scart_prescale,
+ mpx_audio_modes[t->mpxmode].system,
+ mpx_audio_modes[t->mpxmode].volume);
+ buf1[0] = 0x11;
+ buf1[1] = 0x00;
+ buf1[2] = 0x7e;
+ msgs[0].addr = MPX_I2C_ADDR;
+ msgs[0].flags = 0;
+ msgs[0].len = 3;
+ msgs[0].buf = buf1;
+ msgs[1].addr = MPX_I2C_ADDR;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = 2;
+ msgs[1].buf = buf2;
+ i2c_transfer(client->adapter, msgs, 2);
+ printk(KERN_DEBUG "wis-sony-tuner: MPX system: %02x%02x\n",
+ buf2[0], buf2[1]);
+ buf1[0] = 0x11;
+ buf1[1] = 0x02;
+ buf1[2] = 0x00;
+ i2c_transfer(client->adapter, msgs, 2);
+ printk(KERN_DEBUG "wis-sony-tuner: MPX status: %02x%02x\n",
+ buf2[0], buf2[1]);
+ }
+#endif
+ return 0;
+}
+
+/*
+ * IF configuration values for the BTF-PG472Z:
+ *
+ * B/G: 0x94 0x70 0x49
+ * I: 0x14 0x70 0x4a
+ * D/K: 0x14 0x70 0x4b
+ * L: 0x04 0x70 0x4b
+ * L': 0x44 0x70 0x53
+ * M: 0x50 0x30 0x4c
+ */
+
+static int set_if(struct i2c_client *client)
+{
+ struct wis_sony_tuner *t = i2c_get_clientdata(client);
+ u8 buffer[4];
+ struct i2c_msg msg;
+ int default_mpx_mode = 0;
+
+ /* configure IF */
+ buffer[0] = 0;
+ if (t->std & V4L2_STD_PAL_BG) {
+ buffer[1] = 0x94;
+ buffer[2] = 0x70;
+ buffer[3] = 0x49;
+ default_mpx_mode = 1;
+ } else if (t->std & V4L2_STD_PAL_I) {
+ buffer[1] = 0x14;
+ buffer[2] = 0x70;
+ buffer[3] = 0x4a;
+ default_mpx_mode = 4;
+ } else if (t->std & V4L2_STD_PAL_DK) {
+ buffer[1] = 0x14;
+ buffer[2] = 0x70;
+ buffer[3] = 0x4b;
+ default_mpx_mode = 6;
+ } else if (t->std & V4L2_STD_SECAM_L) {
+ buffer[1] = 0x04;
+ buffer[2] = 0x70;
+ buffer[3] = 0x4b;
+ default_mpx_mode = 11;
+ }
+ msg.addr = IF_I2C_ADDR;
+ msg.flags = 0;
+ msg.len = 4;
+ msg.buf = buffer;
+ i2c_transfer(client->adapter, &msg, 1);
+
+ /* Select MPX mode if not forced by the user */
+ if (force_mpx_mode >= 0 || force_mpx_mode < MPX_NUM_MODES)
+ t->mpxmode = force_mpx_mode;
+ else
+ t->mpxmode = default_mpx_mode;
+ printk(KERN_DEBUG "wis-sony-tuner: setting MPX to mode %d\n",
+ t->mpxmode);
+ mpx_setup(client);
+
+ return 0;
+}
+
+static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+ struct wis_sony_tuner *t = i2c_get_clientdata(client);
+
+ switch (cmd) {
+#ifdef TUNER_SET_TYPE_ADDR
+ case TUNER_SET_TYPE_ADDR:
+ {
+ struct tuner_setup *tun_setup = arg;
+ int *type = &tun_setup->type;
+#else
+ case TUNER_SET_TYPE:
+ {
+ int *type = arg;
+#endif
+
+ if (t->type >= 0) {
+ if (t->type != *type)
+ printk(KERN_ERR "wis-sony-tuner: type already "
+ "set to %d, ignoring request for %d\n",
+ t->type, *type);
+ break;
+ }
+ t->type = *type;
+ switch (t->type) {
+ case TUNER_SONY_BTF_PG472Z:
+ switch (force_band_str[0]) {
+ case 'b':
+ case 'B':
+ case 'g':
+ case 'G':
+ printk(KERN_INFO "wis-sony-tuner: forcing "
+ "tuner to PAL-B/G bands\n");
+ force_band = V4L2_STD_PAL_BG;
+ break;
+ case 'i':
+ case 'I':
+ printk(KERN_INFO "wis-sony-tuner: forcing "
+ "tuner to PAL-I band\n");
+ force_band = V4L2_STD_PAL_I;
+ break;
+ case 'd':
+ case 'D':
+ case 'k':
+ case 'K':
+ printk(KERN_INFO "wis-sony-tuner: forcing "
+ "tuner to PAL-D/K bands\n");
+ force_band = V4L2_STD_PAL_I;
+ break;
+ case 'l':
+ case 'L':
+ printk(KERN_INFO "wis-sony-tuner: forcing "
+ "tuner to SECAM-L band\n");
+ force_band = V4L2_STD_SECAM_L;
+ break;
+ default:
+ force_band = 0;
+ break;
+ }
+ if (force_band)
+ t->std = force_band;
+ else
+ t->std = V4L2_STD_PAL_BG;
+ set_if(client);
+ break;
+ case TUNER_SONY_BTF_PK467Z:
+ t->std = V4L2_STD_NTSC_M_JP;
+ break;
+ case TUNER_SONY_BTF_PB463Z:
+ t->std = V4L2_STD_NTSC_M;
+ break;
+ default:
+ printk(KERN_ERR "wis-sony-tuner: tuner type %d is not "
+ "supported by this module\n", *type);
+ break;
+ }
+ if (type >= 0)
+ printk(KERN_INFO
+ "wis-sony-tuner: type set to %d (%s)\n",
+ t->type, sony_tuners[t->type - 200].name);
+ break;
+ }
+ case VIDIOC_G_FREQUENCY:
+ {
+ struct v4l2_frequency *f = arg;
+
+ f->frequency = t->freq;
+ break;
+ }
+ case VIDIOC_S_FREQUENCY:
+ {
+ struct v4l2_frequency *f = arg;
+
+ t->freq = f->frequency;
+ set_freq(client, t->freq);
+ break;
+ }
+ case VIDIOC_ENUMSTD:
+ {
+ struct v4l2_standard *std = arg;
+
+ switch (t->type) {
+ case TUNER_SONY_BTF_PG472Z:
+ switch (std->index) {
+ case 0:
+ v4l2_video_std_construct(std,
+ V4L2_STD_PAL_BG, "PAL-B/G");
+ break;
+ case 1:
+ v4l2_video_std_construct(std,
+ V4L2_STD_PAL_I, "PAL-I");
+ break;
+ case 2:
+ v4l2_video_std_construct(std,
+ V4L2_STD_PAL_DK, "PAL-D/K");
+ break;
+ case 3:
+ v4l2_video_std_construct(std,
+ V4L2_STD_SECAM_L, "SECAM-L");
+ break;
+ default:
+ std->id = 0; /* hack to indicate EINVAL */
+ break;
+ }
+ break;
+ case TUNER_SONY_BTF_PK467Z:
+ if (std->index != 0) {
+ std->id = 0; /* hack to indicate EINVAL */
+ break;
+ }
+ v4l2_video_std_construct(std,
+ V4L2_STD_NTSC_M_JP, "NTSC-J");
+ break;
+ case TUNER_SONY_BTF_PB463Z:
+ if (std->index != 0) {
+ std->id = 0; /* hack to indicate EINVAL */
+ break;
+ }
+ v4l2_video_std_construct(std, V4L2_STD_NTSC_M, "NTSC");
+ break;
+ }
+ break;
+ }
+ case VIDIOC_G_STD:
+ {
+ v4l2_std_id *std = arg;
+
+ *std = t->std;
+ break;
+ }
+ case VIDIOC_S_STD:
+ {
+ v4l2_std_id *std = arg;
+ v4l2_std_id old = t->std;
+
+ switch (t->type) {
+ case TUNER_SONY_BTF_PG472Z:
+ if (force_band && (*std & force_band) != *std &&
+ *std != V4L2_STD_PAL &&
+ *std != V4L2_STD_SECAM) {
+ printk(KERN_DEBUG "wis-sony-tuner: ignoring "
+ "requested TV standard in "
+ "favor of force_band value\n");
+ t->std = force_band;
+ } else if (*std & V4L2_STD_PAL_BG) { /* default */
+ t->std = V4L2_STD_PAL_BG;
+ } else if (*std & V4L2_STD_PAL_I) {
+ t->std = V4L2_STD_PAL_I;
+ } else if (*std & V4L2_STD_PAL_DK) {
+ t->std = V4L2_STD_PAL_DK;
+ } else if (*std & V4L2_STD_SECAM_L) {
+ t->std = V4L2_STD_SECAM_L;
+ } else {
+ printk(KERN_ERR "wis-sony-tuner: TV standard "
+ "not supported\n");
+ *std = 0; /* hack to indicate EINVAL */
+ break;
+ }
+ if (old != t->std)
+ set_if(client);
+ break;
+ case TUNER_SONY_BTF_PK467Z:
+ if (!(*std & V4L2_STD_NTSC_M_JP)) {
+ printk(KERN_ERR "wis-sony-tuner: TV standard "
+ "not supported\n");
+ *std = 0; /* hack to indicate EINVAL */
+ }
+ break;
+ case TUNER_SONY_BTF_PB463Z:
+ if (!(*std & V4L2_STD_NTSC_M)) {
+ printk(KERN_ERR "wis-sony-tuner: TV standard "
+ "not supported\n");
+ *std = 0; /* hack to indicate EINVAL */
+ }
+ break;
+ }
+ break;
+ }
+ case VIDIOC_QUERYSTD:
+ {
+ v4l2_std_id *std = arg;
+
+ switch (t->type) {
+ case TUNER_SONY_BTF_PG472Z:
+ if (force_band)
+ *std = force_band;
+ else
+ *std = V4L2_STD_PAL_BG | V4L2_STD_PAL_I |
+ V4L2_STD_PAL_DK | V4L2_STD_SECAM_L;
+ break;
+ case TUNER_SONY_BTF_PK467Z:
+ *std = V4L2_STD_NTSC_M_JP;
+ break;
+ case TUNER_SONY_BTF_PB463Z:
+ *std = V4L2_STD_NTSC_M;
+ break;
+ }
+ break;
+ }
+ case VIDIOC_G_TUNER:
+ {
+ struct v4l2_tuner *tun = arg;
+
+ memset(t, 0, sizeof(*tun));
+ strcpy(tun->name, "Television");
+ tun->type = V4L2_TUNER_ANALOG_TV;
+ tun->rangelow = 0UL; /* does anything use these? */
+ tun->rangehigh = 0xffffffffUL;
+ switch (t->type) {
+ case TUNER_SONY_BTF_PG472Z:
+ tun->capability = V4L2_TUNER_CAP_NORM |
+ V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
+ V4L2_TUNER_CAP_LANG2;
+ tun->rxsubchans = V4L2_TUNER_SUB_MONO |
+ V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_LANG1 |
+ V4L2_TUNER_SUB_LANG2;
+ break;
+ case TUNER_SONY_BTF_PK467Z:
+ case TUNER_SONY_BTF_PB463Z:
+ tun->capability = V4L2_TUNER_CAP_STEREO;
+ tun->rxsubchans = V4L2_TUNER_SUB_MONO |
+ V4L2_TUNER_SUB_STEREO;
+ break;
+ }
+ tun->audmode = t->audmode;
+ return 0;
+ }
+ case VIDIOC_S_TUNER:
+ {
+ struct v4l2_tuner *tun = arg;
+
+ switch (t->type) {
+ case TUNER_SONY_BTF_PG472Z:
+ if (tun->audmode != t->audmode) {
+ t->audmode = tun->audmode;
+ mpx_setup(client);
+ }
+ break;
+ case TUNER_SONY_BTF_PK467Z:
+ case TUNER_SONY_BTF_PB463Z:
+ break;
+ }
+ return 0;
+ }
+ default:
+ break;
+ }
+ return 0;
+}
+
+static struct i2c_driver wis_sony_tuner_driver;
+
+static struct i2c_client wis_sony_tuner_client_templ = {
+ .name = "Sony TV Tuner (WIS)",
+ .driver = &wis_sony_tuner_driver,
+};
+
+static int wis_sony_tuner_detect(struct i2c_adapter *adapter,
+ int addr, int kind)
+{
+ struct i2c_client *client;
+ struct wis_sony_tuner *t;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
+ return 0;
+
+ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == NULL)
+ return -ENOMEM;
+ memcpy(client, &wis_sony_tuner_client_templ,
+ sizeof(wis_sony_tuner_client_templ));
+ client->adapter = adapter;
+ client->addr = addr;
+
+ t = kmalloc(sizeof(struct wis_sony_tuner), GFP_KERNEL);
+ if (t == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+ t->type = -1;
+ t->freq = 0;
+ t->mpxmode = 0;
+ t->audmode = V4L2_TUNER_MODE_STEREO;
+ i2c_set_clientdata(client, t);
+
+ printk(KERN_DEBUG
+ "wis-sony-tuner: initializing tuner at address %d on %s\n",
+ addr, adapter->name);
+
+ i2c_attach_client(client);
+
+ return 0;
+}
+
+static int wis_sony_tuner_detach(struct i2c_client *client)
+{
+ struct wis_sony_tuner *t = i2c_get_clientdata(client);
+ int r;
+
+ r = i2c_detach_client(client);
+ if (r < 0)
+ return r;
+
+ kfree(t);
+ kfree(client);
+ return 0;
+}
+
+static struct i2c_driver wis_sony_tuner_driver = {
+ .driver = {
+ .name = "WIS Sony TV Tuner I2C driver",
+ },
+ .id = I2C_DRIVERID_WIS_SONY_TUNER,
+ .detach_client = wis_sony_tuner_detach,
+ .command = tuner_command,
+};
+
+static int __init wis_sony_tuner_init(void)
+{
+ int r;
+
+ r = i2c_add_driver(&wis_sony_tuner_driver);
+ if (r < 0)
+ return r;
+ return wis_i2c_add_driver(wis_sony_tuner_driver.id,
+ wis_sony_tuner_detect);
+}
+
+static void __exit wis_sony_tuner_cleanup(void)
+{
+ wis_i2c_del_driver(wis_sony_tuner_detect);
+ i2c_del_driver(&wis_sony_tuner_driver);
+}
+
+module_init(wis_sony_tuner_init);
+module_exit(wis_sony_tuner_cleanup);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/go7007/wis-tw2804.c b/drivers/staging/go7007/wis-tw2804.c
new file mode 100644
index 0000000..69ed7bf
--- /dev/null
+++ b/drivers/staging/go7007/wis-tw2804.c
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <linux/video_decoder.h>
+#include <linux/ioctl.h>
+
+#include "wis-i2c.h"
+
+struct wis_tw2804 {
+ int channel;
+ int norm;
+ int brightness;
+ int contrast;
+ int saturation;
+ int hue;
+};
+
+static u8 global_registers[] =
+{
+ 0x39, 0x00,
+ 0x3a, 0xff,
+ 0x3b, 0x84,
+ 0x3c, 0x80,
+ 0x3d, 0x80,
+ 0x3e, 0x82,
+ 0x3f, 0x82,
+ 0xff, 0xff, /* Terminator (reg 0xff does not exist) */
+};
+
+static u8 channel_registers[] =
+{
+ 0x01, 0xc4,
+ 0x02, 0xa5,
+ 0x03, 0x20,
+ 0x04, 0xd0,
+ 0x05, 0x20,
+ 0x06, 0xd0,
+ 0x07, 0x88,
+ 0x08, 0x20,
+ 0x09, 0x07,
+ 0x0a, 0xf0,
+ 0x0b, 0x07,
+ 0x0c, 0xf0,
+ 0x0d, 0x40,
+ 0x0e, 0xd2,
+ 0x0f, 0x80,
+ 0x10, 0x80,
+ 0x11, 0x80,
+ 0x12, 0x80,
+ 0x13, 0x1f,
+ 0x14, 0x00,
+ 0x15, 0x00,
+ 0x16, 0x00,
+ 0x17, 0x00,
+ 0x18, 0xff,
+ 0x19, 0xff,
+ 0x1a, 0xff,
+ 0x1b, 0xff,
+ 0x1c, 0xff,
+ 0x1d, 0xff,
+ 0x1e, 0xff,
+ 0x1f, 0xff,
+ 0x20, 0x07,
+ 0x21, 0x07,
+ 0x22, 0x00,
+ 0x23, 0x91,
+ 0x24, 0x51,
+ 0x25, 0x03,
+ 0x26, 0x00,
+ 0x27, 0x00,
+ 0x28, 0x00,
+ 0x29, 0x00,
+ 0x2a, 0x00,
+ 0x2b, 0x00,
+ 0x2c, 0x00,
+ 0x2d, 0x00,
+ 0x2e, 0x00,
+ 0x2f, 0x00,
+ 0x30, 0x00,
+ 0x31, 0x00,
+ 0x32, 0x00,
+ 0x33, 0x00,
+ 0x34, 0x00,
+ 0x35, 0x00,
+ 0x36, 0x00,
+ 0x37, 0x00,
+ 0xff, 0xff, /* Terminator (reg 0xff does not exist) */
+};
+
+static int write_reg(struct i2c_client *client, u8 reg, u8 value, int channel)
+{
+ return i2c_smbus_write_byte_data(client, reg | (channel << 6), value);
+}
+
+static int write_regs(struct i2c_client *client, u8 *regs, int channel)
+{
+ int i;
+
+ for (i = 0; regs[i] != 0xff; i += 2)
+ if (i2c_smbus_write_byte_data(client,
+ regs[i] | (channel << 6), regs[i + 1]) < 0)
+ return -1;
+ return 0;
+}
+
+static int wis_tw2804_command(struct i2c_client *client,
+ unsigned int cmd, void *arg)
+{
+ struct wis_tw2804 *dec = i2c_get_clientdata(client);
+
+ if (cmd == DECODER_SET_CHANNEL) {
+ int *input = arg;
+
+ if (*input < 0 || *input > 3) {
+ printk(KERN_ERR "wis-tw2804: channel %d is not "
+ "between 0 and 3!\n", *input);
+ return 0;
+ }
+ dec->channel = *input;
+ printk(KERN_DEBUG "wis-tw2804: initializing TW2804 "
+ "channel %d\n", dec->channel);
+ if (dec->channel == 0 &&
+ write_regs(client, global_registers, 0) < 0) {
+ printk(KERN_ERR "wis-tw2804: error initializing "
+ "TW2804 global registers\n");
+ return 0;
+ }
+ if (write_regs(client, channel_registers, dec->channel) < 0) {
+ printk(KERN_ERR "wis-tw2804: error initializing "
+ "TW2804 channel %d\n", dec->channel);
+ return 0;
+ }
+ return 0;
+ }
+
+ if (dec->channel < 0) {
+ printk(KERN_DEBUG "wis-tw2804: ignoring command %08x until "
+ "channel number is set\n", cmd);
+ return 0;
+ }
+
+ switch (cmd) {
+ case DECODER_SET_NORM:
+ {
+ int *input = arg;
+ u8 regs[] = {
+ 0x01, *input == VIDEO_MODE_NTSC ? 0xc4 : 0x84,
+ 0x09, *input == VIDEO_MODE_NTSC ? 0x07 : 0x04,
+ 0x0a, *input == VIDEO_MODE_NTSC ? 0xf0 : 0x20,
+ 0x0b, *input == VIDEO_MODE_NTSC ? 0x07 : 0x04,
+ 0x0c, *input == VIDEO_MODE_NTSC ? 0xf0 : 0x20,
+ 0x0d, *input == VIDEO_MODE_NTSC ? 0x40 : 0x4a,
+ 0x16, *input == VIDEO_MODE_NTSC ? 0x00 : 0x40,
+ 0x17, *input == VIDEO_MODE_NTSC ? 0x00 : 0x40,
+ 0x20, *input == VIDEO_MODE_NTSC ? 0x07 : 0x0f,
+ 0x21, *input == VIDEO_MODE_NTSC ? 0x07 : 0x0f,
+ 0xff, 0xff,
+ };
+ write_regs(client, regs, dec->channel);
+ dec->norm = *input;
+ break;
+ }
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *ctrl = arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ strncpy(ctrl->name, "Brightness", sizeof(ctrl->name));
+ ctrl->minimum = 0;
+ ctrl->maximum = 255;
+ ctrl->step = 1;
+ ctrl->default_value = 128;
+ ctrl->flags = 0;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ strncpy(ctrl->name, "Contrast", sizeof(ctrl->name));
+ ctrl->minimum = 0;
+ ctrl->maximum = 255;
+ ctrl->step = 1;
+ ctrl->default_value = 128;
+ ctrl->flags = 0;
+ break;
+ case V4L2_CID_SATURATION:
+ ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ strncpy(ctrl->name, "Saturation", sizeof(ctrl->name));
+ ctrl->minimum = 0;
+ ctrl->maximum = 255;
+ ctrl->step = 1;
+ ctrl->default_value = 128;
+ ctrl->flags = 0;
+ break;
+ case V4L2_CID_HUE:
+ ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ strncpy(ctrl->name, "Hue", sizeof(ctrl->name));
+ ctrl->minimum = 0;
+ ctrl->maximum = 255;
+ ctrl->step = 1;
+ ctrl->default_value = 128;
+ ctrl->flags = 0;
+ break;
+ }
+ break;
+ }
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ if (ctrl->value > 255)
+ dec->brightness = 255;
+ else if (ctrl->value < 0)
+ dec->brightness = 0;
+ else
+ dec->brightness = ctrl->value;
+ write_reg(client, 0x12, dec->brightness, dec->channel);
+ break;
+ case V4L2_CID_CONTRAST:
+ if (ctrl->value > 255)
+ dec->contrast = 255;
+ else if (ctrl->value < 0)
+ dec->contrast = 0;
+ else
+ dec->contrast = ctrl->value;
+ write_reg(client, 0x11, dec->contrast, dec->channel);
+ break;
+ case V4L2_CID_SATURATION:
+ if (ctrl->value > 255)
+ dec->saturation = 255;
+ else if (ctrl->value < 0)
+ dec->saturation = 0;
+ else
+ dec->saturation = ctrl->value;
+ write_reg(client, 0x10, dec->saturation, dec->channel);
+ break;
+ case V4L2_CID_HUE:
+ if (ctrl->value > 255)
+ dec->hue = 255;
+ else if (ctrl->value < 0)
+ dec->hue = 0;
+ else
+ dec->hue = ctrl->value;
+ write_reg(client, 0x0f, dec->hue, dec->channel);
+ break;
+ }
+ break;
+ }
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->value = dec->brightness;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctrl->value = dec->contrast;
+ break;
+ case V4L2_CID_SATURATION:
+ ctrl->value = dec->saturation;
+ break;
+ case V4L2_CID_HUE:
+ ctrl->value = dec->hue;
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return 0;
+}
+
+static struct i2c_driver wis_tw2804_driver;
+
+static struct i2c_client wis_tw2804_client_templ = {
+ .name = "TW2804 (WIS)",
+ .driver = &wis_tw2804_driver,
+};
+
+static int wis_tw2804_detect(struct i2c_adapter *adapter, int addr, int kind)
+{
+ struct i2c_client *client;
+ struct wis_tw2804 *dec;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return 0;
+
+ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == NULL)
+ return -ENOMEM;
+ memcpy(client, &wis_tw2804_client_templ,
+ sizeof(wis_tw2804_client_templ));
+ client->adapter = adapter;
+ client->addr = addr;
+
+ dec = kmalloc(sizeof(struct wis_tw2804), GFP_KERNEL);
+ if (dec == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+ dec->channel = -1;
+ dec->norm = VIDEO_MODE_NTSC;
+ dec->brightness = 128;
+ dec->contrast = 128;
+ dec->saturation = 128;
+ dec->hue = 128;
+ i2c_set_clientdata(client, dec);
+
+ printk(KERN_DEBUG "wis-tw2804: creating TW2804 at address %d on %s\n",
+ addr, adapter->name);
+
+ i2c_attach_client(client);
+ return 0;
+}
+
+static int wis_tw2804_detach(struct i2c_client *client)
+{
+ struct wis_tw2804 *dec = i2c_get_clientdata(client);
+ int r;
+
+ r = i2c_detach_client(client);
+ if (r < 0)
+ return r;
+
+ kfree(client);
+ kfree(dec);
+ return 0;
+}
+
+static struct i2c_driver wis_tw2804_driver = {
+ .driver = {
+ .name = "WIS TW2804 I2C driver",
+ },
+ .id = I2C_DRIVERID_WIS_TW2804,
+ .detach_client = wis_tw2804_detach,
+ .command = wis_tw2804_command,
+};
+
+static int __init wis_tw2804_init(void)
+{
+ int r;
+
+ r = i2c_add_driver(&wis_tw2804_driver);
+ if (r < 0)
+ return r;
+ return wis_i2c_add_driver(wis_tw2804_driver.id, wis_tw2804_detect);
+}
+
+static void __exit wis_tw2804_cleanup(void)
+{
+ wis_i2c_del_driver(wis_tw2804_detect);
+ i2c_del_driver(&wis_tw2804_driver);
+}
+
+module_init(wis_tw2804_init);
+module_exit(wis_tw2804_cleanup);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/go7007/wis-tw9903.c b/drivers/staging/go7007/wis-tw9903.c
new file mode 100644
index 0000000..1cdf01a
--- /dev/null
+++ b/drivers/staging/go7007/wis-tw9903.c
@@ -0,0 +1,363 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <linux/video_decoder.h>
+#include <linux/ioctl.h>
+
+#include "wis-i2c.h"
+
+struct wis_tw9903 {
+ int norm;
+ int brightness;
+ int contrast;
+ int hue;
+};
+
+static u8 initial_registers[] =
+{
+ 0x02, 0x44, /* input 1, composite */
+ 0x03, 0x92, /* correct digital format */
+ 0x04, 0x00,
+ 0x05, 0x80, /* or 0x00 for PAL */
+ 0x06, 0x40, /* second internal current reference */
+ 0x07, 0x02, /* window */
+ 0x08, 0x14, /* window */
+ 0x09, 0xf0, /* window */
+ 0x0a, 0x81, /* window */
+ 0x0b, 0xd0, /* window */
+ 0x0c, 0x8c,
+ 0x0d, 0x00, /* scaling */
+ 0x0e, 0x11, /* scaling */
+ 0x0f, 0x00, /* scaling */
+ 0x10, 0x00, /* brightness */
+ 0x11, 0x60, /* contrast */
+ 0x12, 0x01, /* sharpness */
+ 0x13, 0x7f, /* U gain */
+ 0x14, 0x5a, /* V gain */
+ 0x15, 0x00, /* hue */
+ 0x16, 0xc3, /* sharpness */
+ 0x18, 0x00,
+ 0x19, 0x58, /* vbi */
+ 0x1a, 0x80,
+ 0x1c, 0x0f, /* video norm */
+ 0x1d, 0x7f, /* video norm */
+ 0x20, 0xa0, /* clamping gain (working 0x50) */
+ 0x21, 0x22,
+ 0x22, 0xf0,
+ 0x23, 0xfe,
+ 0x24, 0x3c,
+ 0x25, 0x38,
+ 0x26, 0x44,
+ 0x27, 0x20,
+ 0x28, 0x00,
+ 0x29, 0x15,
+ 0x2a, 0xa0,
+ 0x2b, 0x44,
+ 0x2c, 0x37,
+ 0x2d, 0x00,
+ 0x2e, 0xa5, /* burst PLL control (working: a9) */
+ 0x2f, 0xe0, /* 0xea is blue test frame -- 0xe0 for normal */
+ 0x31, 0x00,
+ 0x33, 0x22,
+ 0x34, 0x11,
+ 0x35, 0x35,
+ 0x3b, 0x05,
+ 0x06, 0xc0, /* reset device */
+ 0x00, 0x00, /* Terminator (reg 0x00 is read-only) */
+};
+
+static int write_reg(struct i2c_client *client, u8 reg, u8 value)
+{
+ return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static int write_regs(struct i2c_client *client, u8 *regs)
+{
+ int i;
+
+ for (i = 0; regs[i] != 0x00; i += 2)
+ if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0)
+ return -1;
+ return 0;
+}
+
+static int wis_tw9903_command(struct i2c_client *client,
+ unsigned int cmd, void *arg)
+{
+ struct wis_tw9903 *dec = i2c_get_clientdata(client);
+
+ switch (cmd) {
+ case DECODER_SET_INPUT:
+ {
+ int *input = arg;
+
+ i2c_smbus_write_byte_data(client, 0x02, 0x40 | (*input << 1));
+ break;
+ }
+#if 0 /* The scaler on this thing seems to be horribly broken */
+ case DECODER_SET_RESOLUTION:
+ {
+ struct video_decoder_resolution *res = arg;
+ /*int hscale = 256 * 720 / res->width;*/
+ int hscale = 256 * 720 / (res->width - (res->width > 704 ? 0 : 8));
+ int vscale = 256 * (dec->norm == VIDEO_MODE_NTSC ? 240 : 288)
+ / res->height;
+ u8 regs[] = {
+ 0x0d, vscale & 0xff,
+ 0x0f, hscale & 0xff,
+ 0x0e, ((vscale & 0xf00) >> 4) | ((hscale & 0xf00) >> 8),
+ 0x06, 0xc0, /* reset device */
+ 0, 0,
+ };
+ printk(KERN_DEBUG "vscale is %04x, hscale is %04x\n",
+ vscale, hscale);
+ /*write_regs(client, regs);*/
+ break;
+ }
+#endif
+ case DECODER_SET_NORM:
+ {
+ int *input = arg;
+ u8 regs[] = {
+ 0x05, *input == VIDEO_MODE_NTSC ? 0x80 : 0x00,
+ 0x07, *input == VIDEO_MODE_NTSC ? 0x02 : 0x12,
+ 0x08, *input == VIDEO_MODE_NTSC ? 0x14 : 0x18,
+ 0x09, *input == VIDEO_MODE_NTSC ? 0xf0 : 0x20,
+ 0, 0,
+ };
+ write_regs(client, regs);
+ dec->norm = *input;
+ break;
+ }
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *ctrl = arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ strncpy(ctrl->name, "Brightness", sizeof(ctrl->name));
+ ctrl->minimum = -128;
+ ctrl->maximum = 127;
+ ctrl->step = 1;
+ ctrl->default_value = 0x00;
+ ctrl->flags = 0;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ strncpy(ctrl->name, "Contrast", sizeof(ctrl->name));
+ ctrl->minimum = 0;
+ ctrl->maximum = 255;
+ ctrl->step = 1;
+ ctrl->default_value = 0x60;
+ ctrl->flags = 0;
+ break;
+#if 0
+ /* I don't understand how the Chroma Gain registers work... */
+ case V4L2_CID_SATURATION:
+ ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ strncpy(ctrl->name, "Saturation", sizeof(ctrl->name));
+ ctrl->minimum = 0;
+ ctrl->maximum = 127;
+ ctrl->step = 1;
+ ctrl->default_value = 64;
+ ctrl->flags = 0;
+ break;
+#endif
+ case V4L2_CID_HUE:
+ ctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ strncpy(ctrl->name, "Hue", sizeof(ctrl->name));
+ ctrl->minimum = -128;
+ ctrl->maximum = 127;
+ ctrl->step = 1;
+ ctrl->default_value = 0;
+ ctrl->flags = 0;
+ break;
+ }
+ break;
+ }
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ if (ctrl->value > 127)
+ dec->brightness = 127;
+ else if (ctrl->value < -128)
+ dec->brightness = -128;
+ else
+ dec->brightness = ctrl->value;
+ write_reg(client, 0x10, dec->brightness);
+ break;
+ case V4L2_CID_CONTRAST:
+ if (ctrl->value > 255)
+ dec->contrast = 255;
+ else if (ctrl->value < 0)
+ dec->contrast = 0;
+ else
+ dec->contrast = ctrl->value;
+ write_reg(client, 0x11, dec->contrast);
+ break;
+#if 0
+ case V4L2_CID_SATURATION:
+ if (ctrl->value > 127)
+ dec->saturation = 127;
+ else if (ctrl->value < 0)
+ dec->saturation = 0;
+ else
+ dec->saturation = ctrl->value;
+ /*write_reg(client, 0x0c, dec->saturation);*/
+ break;
+#endif
+ case V4L2_CID_HUE:
+ if (ctrl->value > 127)
+ dec->hue = 127;
+ else if (ctrl->value < -128)
+ dec->hue = -128;
+ else
+ dec->hue = ctrl->value;
+ write_reg(client, 0x15, dec->hue);
+ break;
+ }
+ break;
+ }
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *ctrl = arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->value = dec->brightness;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctrl->value = dec->contrast;
+ break;
+#if 0
+ case V4L2_CID_SATURATION:
+ ctrl->value = dec->saturation;
+ break;
+#endif
+ case V4L2_CID_HUE:
+ ctrl->value = dec->hue;
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return 0;
+}
+
+static struct i2c_driver wis_tw9903_driver;
+
+static struct i2c_client wis_tw9903_client_templ = {
+ .name = "TW9903 (WIS)",
+ .driver = &wis_tw9903_driver,
+};
+
+static int wis_tw9903_detect(struct i2c_adapter *adapter, int addr, int kind)
+{
+ struct i2c_client *client;
+ struct wis_tw9903 *dec;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return 0;
+
+ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == NULL)
+ return -ENOMEM;
+ memcpy(client, &wis_tw9903_client_templ,
+ sizeof(wis_tw9903_client_templ));
+ client->adapter = adapter;
+ client->addr = addr;
+
+ dec = kmalloc(sizeof(struct wis_tw9903), GFP_KERNEL);
+ if (dec == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+ dec->norm = VIDEO_MODE_NTSC;
+ dec->brightness = 0;
+ dec->contrast = 0x60;
+ dec->hue = 0;
+ i2c_set_clientdata(client, dec);
+
+ printk(KERN_DEBUG
+ "wis-tw9903: initializing TW9903 at address %d on %s\n",
+ addr, adapter->name);
+
+ if (write_regs(client, initial_registers) < 0) {
+ printk(KERN_ERR "wis-tw9903: error initializing TW9903\n");
+ kfree(client);
+ kfree(dec);
+ return 0;
+ }
+
+ i2c_attach_client(client);
+ return 0;
+}
+
+static int wis_tw9903_detach(struct i2c_client *client)
+{
+ struct wis_tw9903 *dec = i2c_get_clientdata(client);
+ int r;
+
+ r = i2c_detach_client(client);
+ if (r < 0)
+ return r;
+
+ kfree(client);
+ kfree(dec);
+ return 0;
+}
+
+static struct i2c_driver wis_tw9903_driver = {
+ .driver = {
+ .name = "WIS TW9903 I2C driver",
+ },
+ .id = I2C_DRIVERID_WIS_TW9903,
+ .detach_client = wis_tw9903_detach,
+ .command = wis_tw9903_command,
+};
+
+static int __init wis_tw9903_init(void)
+{
+ int r;
+
+ r = i2c_add_driver(&wis_tw9903_driver);
+ if (r < 0)
+ return r;
+ return wis_i2c_add_driver(wis_tw9903_driver.id, wis_tw9903_detect);
+}
+
+static void __exit wis_tw9903_cleanup(void)
+{
+ wis_i2c_del_driver(wis_tw9903_detect);
+ i2c_del_driver(&wis_tw9903_driver);
+}
+
+module_init(wis_tw9903_init);
+module_exit(wis_tw9903_cleanup);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/go7007/wis-uda1342.c b/drivers/staging/go7007/wis-uda1342.c
new file mode 100644
index 0000000..28c10bf
--- /dev/null
+++ b/drivers/staging/go7007/wis-uda1342.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2005-2006 Micronas USA Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <media/tvaudio.h>
+#include <media/v4l2-common.h>
+
+#include "wis-i2c.h"
+
+static int write_reg(struct i2c_client *client, int reg, int value)
+{
+ /* UDA1342 wants MSB first, but SMBus sends LSB first */
+ i2c_smbus_write_word_data(client, reg, swab16(value));
+ return 0;
+}
+
+static int wis_uda1342_command(struct i2c_client *client,
+ unsigned int cmd, void *arg)
+{
+ switch (cmd) {
+ case VIDIOC_S_AUDIO:
+ {
+ int *inp = arg;
+
+ switch (*inp) {
+ case TVAUDIO_INPUT_TUNER:
+ write_reg(client, 0x00, 0x1441); /* select input 2 */
+ break;
+ case TVAUDIO_INPUT_EXTERN:
+ write_reg(client, 0x00, 0x1241); /* select input 1 */
+ break;
+ default:
+ printk(KERN_ERR "wis-uda1342: input %d not supported\n",
+ *inp);
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return 0;
+}
+
+static struct i2c_driver wis_uda1342_driver;
+
+static struct i2c_client wis_uda1342_client_templ = {
+ .name = "UDA1342 (WIS)",
+ .driver = &wis_uda1342_driver,
+};
+
+static int wis_uda1342_detect(struct i2c_adapter *adapter, int addr, int kind)
+{
+ struct i2c_client *client;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
+ return 0;
+
+ client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == NULL)
+ return -ENOMEM;
+ memcpy(client, &wis_uda1342_client_templ,
+ sizeof(wis_uda1342_client_templ));
+ client->adapter = adapter;
+ client->addr = addr;
+
+ printk(KERN_DEBUG
+ "wis-uda1342: initializing UDA1342 at address %d on %s\n",
+ addr, adapter->name);
+
+ write_reg(client, 0x00, 0x8000); /* reset registers */
+ write_reg(client, 0x00, 0x1241); /* select input 1 */
+
+ i2c_attach_client(client);
+ return 0;
+}
+
+static int wis_uda1342_detach(struct i2c_client *client)
+{
+ int r;
+
+ r = i2c_detach_client(client);
+ if (r < 0)
+ return r;
+
+ kfree(client);
+ return 0;
+}
+
+static struct i2c_driver wis_uda1342_driver = {
+ .driver = {
+ .name = "WIS UDA1342 I2C driver",
+ },
+ .id = I2C_DRIVERID_WIS_UDA1342,
+ .detach_client = wis_uda1342_detach,
+ .command = wis_uda1342_command,
+};
+
+static int __init wis_uda1342_init(void)
+{
+ int r;
+
+ r = i2c_add_driver(&wis_uda1342_driver);
+ if (r < 0)
+ return r;
+ return wis_i2c_add_driver(wis_uda1342_driver.id, wis_uda1342_detect);
+}
+
+static void __exit wis_uda1342_cleanup(void)
+{
+ wis_i2c_del_driver(wis_uda1342_detect);
+ i2c_del_driver(&wis_uda1342_driver);
+}
+
+module_init(wis_uda1342_init);
+module_exit(wis_uda1342_cleanup);
+
+MODULE_LICENSE("GPL v2");
--
1.6.0.2
^ permalink raw reply related [flat|nested] 37+ messages in thread* [PATCH 11/23] Staging: USB/IP: add common functions needed
2008-10-10 22:41 [GIT PATCH] STAGING patches for 2.6.28 Greg KH
` (6 preceding siblings ...)
2008-10-10 22:42 ` [PATCH 10/23] Staging: add the go7007 video driver Greg KH
@ 2008-10-10 22:42 ` Greg KH
2008-10-10 22:42 ` [PATCH 12/23] Staging: USB/IP: add client driver Greg KH
` (11 subsequent siblings)
19 siblings, 0 replies; 37+ messages in thread
From: Greg KH @ 2008-10-10 22:42 UTC (permalink / raw)
To: linux-kernel; +Cc: Takahiro Hirofuchi, Brian G. Merrell, Greg Kroah-Hartman
From: Takahiro Hirofuchi <hirofuchi@users.sourceforge.net>
This adds the common functions needed by both the host and client side
of the USB/IP code.
Brian Merrell cleaned up a lot of this code and submitted it for
inclusion. Greg also did a lot of cleanup.
Signed-off-by: Brian G. Merrell <bgmerrell@novell.com>
Cc: Takahiro Hirofuchi <hirofuchi@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/Kconfig | 2 +
drivers/staging/Makefile | 1 +
drivers/staging/usbip/Kconfig | 14 +
drivers/staging/usbip/Makefile | 6 +
drivers/staging/usbip/README | 6 +
drivers/staging/usbip/usbip_common.c | 997 ++++++++++++++++++++++++++++++++++
drivers/staging/usbip/usbip_common.h | 406 ++++++++++++++
drivers/staging/usbip/usbip_event.c | 141 +++++
8 files changed, 1573 insertions(+), 0 deletions(-)
create mode 100644 drivers/staging/usbip/Kconfig
create mode 100644 drivers/staging/usbip/Makefile
create mode 100644 drivers/staging/usbip/README
create mode 100644 drivers/staging/usbip/usbip_common.c
create mode 100644 drivers/staging/usbip/usbip_common.h
create mode 100644 drivers/staging/usbip/usbip_event.c
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index f16bc9c..4dbf795 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -33,4 +33,6 @@ source "drivers/staging/me4000/Kconfig"
source "drivers/staging/go7007/Kconfig"
+source "drivers/staging/usbip/Kconfig"
+
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index aa61662..be42c0d 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_SLICOSS) += slicoss/
obj-$(CONFIG_SXG) += sxg/
obj-$(CONFIG_ME4000) += me4000/
obj-$(CONFIG_VIDEO_GO7007) += go7007/
+obj-$(CONFIG_USB_IP_COMMON) += usbip/
diff --git a/drivers/staging/usbip/Kconfig b/drivers/staging/usbip/Kconfig
new file mode 100644
index 0000000..37efb5e
--- /dev/null
+++ b/drivers/staging/usbip/Kconfig
@@ -0,0 +1,14 @@
+config USB_IP_COMMON
+ tristate "USB IP support (EXPERIMENTAL)"
+ depends on USB && EXPERIMENTAL
+ default N
+ ---help---
+ This enables pushing USB packets over IP to allow remote
+ machines access to USB devices directly. For more details,
+ and links to the userspace utility programs to let this work
+ properly, see http://usbip.naist.jp/
+
+ To compile this driver as a module, choose M here: the
+ module will be called usbip_common_mod.
+
+ If unsure, say N.
diff --git a/drivers/staging/usbip/Makefile b/drivers/staging/usbip/Makefile
new file mode 100644
index 0000000..ce925ca
--- /dev/null
+++ b/drivers/staging/usbip/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_USB_IP_COMMON) += usbip_common_mod.o
+usbip_common_mod-objs := usbip_common.o usbip_event.o
+
+ifeq ($(CONFIG_USB_DEBUG),y)
+ EXTRA_CFLAGS += -DDEBUG
+endif
diff --git a/drivers/staging/usbip/README b/drivers/staging/usbip/README
new file mode 100644
index 0000000..c11be57
--- /dev/null
+++ b/drivers/staging/usbip/README
@@ -0,0 +1,6 @@
+TODO:
+ - more discussion about the protocol
+ - testing
+ - review of the userspace interface
+
+Please send patches for this code to Greg Kroah-Hartman <greg@kroah.com>
diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c
new file mode 100644
index 0000000..e64918f
--- /dev/null
+++ b/drivers/staging/usbip/usbip_common.c
@@ -0,0 +1,997 @@
+/*
+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
+ *
+ * This 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 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/file.h>
+#include <linux/tcp.h>
+#include <linux/in.h>
+#include "usbip_common.h"
+
+/* version information */
+#define DRIVER_VERSION "1.0"
+#define DRIVER_AUTHOR "Takahiro Hirofuchi <hirofuchi _at_ users.sourceforge.net>"
+#define DRIVER_DESC "usbip common driver"
+
+/*-------------------------------------------------------------------------*/
+/* debug routines */
+
+#ifdef CONFIG_USB_DEBUG
+unsigned long usbip_debug_flag = 0xffffffff;
+#else
+unsigned long usbip_debug_flag;
+#endif
+EXPORT_SYMBOL_GPL(usbip_debug_flag);
+
+
+/* FIXME */
+struct device_attribute dev_attr_usbip_debug;
+EXPORT_SYMBOL_GPL(dev_attr_usbip_debug);
+
+
+static ssize_t show_flag(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%lx\n", usbip_debug_flag);
+}
+
+static ssize_t store_flag(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long flag;
+
+ sscanf(buf, "%lx", &flag);
+ usbip_debug_flag = flag;
+
+ return count;
+}
+DEVICE_ATTR(usbip_debug, (S_IRUGO | S_IWUSR), show_flag, store_flag);
+
+static void usbip_dump_buffer(char *buff, int bufflen)
+{
+ int i;
+
+ if (bufflen > 128) {
+ for (i = 0; i < 128; i++) {
+ if (i%24 == 0)
+ printk(" ");
+ printk("%02x ", (unsigned char) buff[i]);
+ if (i%4 == 3)
+ printk("| ");
+ if (i%24 == 23)
+ printk("\n");
+ }
+ printk("... (%d byte)\n", bufflen);
+ return;
+ }
+
+ for (i = 0; i < bufflen; i++) {
+ if (i%24 == 0)
+ printk(" ");
+ printk("%02x ", (unsigned char) buff[i]);
+ if (i%4 == 3)
+ printk("| ");
+ if (i%24 == 23)
+ printk("\n");
+ }
+ printk("\n");
+
+}
+
+static void usbip_dump_pipe(unsigned int p)
+{
+ unsigned char type = usb_pipetype(p);
+ unsigned char ep = usb_pipeendpoint(p);
+ unsigned char dev = usb_pipedevice(p);
+ unsigned char dir = usb_pipein(p);
+
+ printk("dev(%d) ", dev);
+ printk("ep(%d) ", ep);
+ printk("%s ", dir ? "IN" : "OUT");
+
+ switch (type) {
+ case PIPE_ISOCHRONOUS:
+ printk("%s ", "ISO");
+ break;
+ case PIPE_INTERRUPT:
+ printk("%s ", "INT");
+ break;
+ case PIPE_CONTROL:
+ printk("%s ", "CTL");
+ break;
+ case PIPE_BULK:
+ printk("%s ", "BLK");
+ break;
+ default:
+ printk("ERR");
+ }
+
+ printk("\n");
+
+}
+
+static void usbip_dump_usb_device(struct usb_device *udev)
+{
+ struct device *dev = &udev->dev;
+ int i;
+
+ dev_dbg(dev, " devnum(%d) devpath(%s)",
+ udev->devnum, udev->devpath);
+
+ switch (udev->speed) {
+ case USB_SPEED_HIGH:
+ printk(" SPD_HIGH");
+ break;
+ case USB_SPEED_FULL:
+ printk(" SPD_FULL");
+ break;
+ case USB_SPEED_LOW:
+ printk(" SPD_LOW");
+ break;
+ case USB_SPEED_UNKNOWN:
+ printk(" SPD_UNKNOWN");
+ break;
+ default:
+ printk(" SPD_ERROR");
+ }
+
+ printk(" tt %p, ttport %d", udev->tt, udev->ttport);
+ printk("\n");
+
+ dev_dbg(dev, " ");
+ for (i = 0; i < 16; i++)
+ printk(" %2u", i);
+ printk("\n");
+
+ dev_dbg(dev, " toggle0(IN) :");
+ for (i = 0; i < 16; i++)
+ printk(" %2u", (udev->toggle[0] & (1 << i)) ? 1 : 0);
+ printk("\n");
+
+ dev_dbg(dev, " toggle1(OUT):");
+ for (i = 0; i < 16; i++)
+ printk(" %2u", (udev->toggle[1] & (1 << i)) ? 1 : 0);
+ printk("\n");
+
+
+ dev_dbg(dev, " epmaxp_in :");
+ for (i = 0; i < 16; i++) {
+ if (udev->ep_in[i])
+ printk(" %2u",
+ le16_to_cpu(udev->ep_in[i]->desc.wMaxPacketSize));
+ }
+ printk("\n");
+
+ dev_dbg(dev, " epmaxp_out :");
+ for (i = 0; i < 16; i++) {
+ if (udev->ep_out[i])
+ printk(" %2u",
+ le16_to_cpu(udev->ep_out[i]->desc.wMaxPacketSize));
+ }
+ printk("\n");
+
+ dev_dbg(dev, "parent %p, bus %p\n", udev->parent, udev->bus);
+
+ dev_dbg(dev, "descriptor %p, config %p, actconfig %p, "
+ "rawdescriptors %p\n", &udev->descriptor, udev->config,
+ udev->actconfig, udev->rawdescriptors);
+
+ dev_dbg(dev, "have_langid %d, string_langid %d\n",
+ udev->have_langid, udev->string_langid);
+
+ dev_dbg(dev, "maxchild %d, children %p\n",
+ udev->maxchild, udev->children);
+}
+
+static void usbip_dump_request_type(__u8 rt)
+{
+ switch (rt & USB_RECIP_MASK) {
+ case USB_RECIP_DEVICE:
+ printk("DEVICE");
+ break;
+ case USB_RECIP_INTERFACE:
+ printk("INTERF");
+ break;
+ case USB_RECIP_ENDPOINT:
+ printk("ENDPOI");
+ break;
+ case USB_RECIP_OTHER:
+ printk("OTHER ");
+ break;
+ default:
+ printk("------");
+ }
+}
+
+static void usbip_dump_usb_ctrlrequest(struct usb_ctrlrequest *cmd)
+{
+ if (!cmd) {
+ printk(" %s : null pointer\n", __FUNCTION__);
+ return;
+ }
+
+ printk(" ");
+ printk("bRequestType(%02X) ", cmd->bRequestType);
+ printk("bRequest(%02X) " , cmd->bRequest);
+ printk("wValue(%04X) ", cmd->wValue);
+ printk("wIndex(%04X) ", cmd->wIndex);
+ printk("wLength(%04X) ", cmd->wLength);
+
+ printk("\n ");
+
+ if ((cmd->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+ printk("STANDARD ");
+ switch (cmd->bRequest) {
+ case USB_REQ_GET_STATUS:
+ printk("GET_STATUS");
+ break;
+ case USB_REQ_CLEAR_FEATURE:
+ printk("CLEAR_FEAT");
+ break;
+ case USB_REQ_SET_FEATURE:
+ printk("SET_FEAT ");
+ break;
+ case USB_REQ_SET_ADDRESS:
+ printk("SET_ADDRRS");
+ break;
+ case USB_REQ_GET_DESCRIPTOR:
+ printk("GET_DESCRI");
+ break;
+ case USB_REQ_SET_DESCRIPTOR:
+ printk("SET_DESCRI");
+ break;
+ case USB_REQ_GET_CONFIGURATION:
+ printk("GET_CONFIG");
+ break;
+ case USB_REQ_SET_CONFIGURATION:
+ printk("SET_CONFIG");
+ break;
+ case USB_REQ_GET_INTERFACE:
+ printk("GET_INTERF");
+ break;
+ case USB_REQ_SET_INTERFACE:
+ printk("SET_INTERF");
+ break;
+ case USB_REQ_SYNCH_FRAME:
+ printk("SYNC_FRAME");
+ break;
+ default:
+ printk("REQ(%02X) ", cmd->bRequest);
+ }
+
+ printk(" ");
+ usbip_dump_request_type(cmd->bRequestType);
+
+ } else if ((cmd->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS)
+ printk("CLASS ");
+
+ else if ((cmd->bRequestType & USB_TYPE_MASK) == USB_TYPE_VENDOR)
+ printk("VENDOR ");
+
+ else if ((cmd->bRequestType & USB_TYPE_MASK) == USB_TYPE_RESERVED)
+ printk("RESERVED");
+
+ printk("\n");
+}
+
+void usbip_dump_urb(struct urb *urb)
+{
+ struct device *dev;
+
+ if (!urb) {
+ printk(KERN_DEBUG KBUILD_MODNAME
+ ":%s: urb: null pointer!!\n", __func__);
+ return;
+ }
+
+ if (!urb->dev) {
+ printk(KERN_DEBUG KBUILD_MODNAME
+ ":%s: urb->dev: null pointer!!\n", __func__);
+ return;
+ }
+ dev = &urb->dev->dev;
+
+ dev_dbg(dev, " urb :%p\n", urb);
+ dev_dbg(dev, " dev :%p\n", urb->dev);
+
+ usbip_dump_usb_device(urb->dev);
+
+ dev_dbg(dev, " pipe :%08x ", urb->pipe);
+
+ usbip_dump_pipe(urb->pipe);
+
+ dev_dbg(dev, " status :%d\n", urb->status);
+ dev_dbg(dev, " transfer_flags :%08X\n", urb->transfer_flags);
+ dev_dbg(dev, " transfer_buffer :%p\n", urb->transfer_buffer);
+ dev_dbg(dev, " transfer_buffer_length:%d\n", urb->transfer_buffer_length);
+ dev_dbg(dev, " actual_length :%d\n", urb->actual_length);
+ dev_dbg(dev, " setup_packet :%p\n", urb->setup_packet);
+
+ if (urb->setup_packet && usb_pipetype(urb->pipe) == PIPE_CONTROL)
+ usbip_dump_usb_ctrlrequest(
+ (struct usb_ctrlrequest *)urb->setup_packet);
+
+ dev_dbg(dev, " start_frame :%d\n", urb->start_frame);
+ dev_dbg(dev, " number_of_packets :%d\n", urb->number_of_packets);
+ dev_dbg(dev, " interval :%d\n", urb->interval);
+ dev_dbg(dev, " error_count :%d\n", urb->error_count);
+ dev_dbg(dev, " context :%p\n", urb->context);
+ dev_dbg(dev, " complete :%p\n", urb->complete);
+}
+EXPORT_SYMBOL_GPL(usbip_dump_urb);
+
+void usbip_dump_header(struct usbip_header *pdu)
+{
+ udbg("BASE: cmd %u seq %u devid %u dir %u ep %u\n",
+ pdu->base.command,
+ pdu->base.seqnum,
+ pdu->base.devid,
+ pdu->base.direction,
+ pdu->base.ep);
+
+ switch (pdu->base.command) {
+ case USBIP_CMD_SUBMIT:
+ udbg("CMD_SUBMIT: x_flags %u x_len %u sf %u #p %u iv %u\n",
+ pdu->u.cmd_submit.transfer_flags,
+ pdu->u.cmd_submit.transfer_buffer_length,
+ pdu->u.cmd_submit.start_frame,
+ pdu->u.cmd_submit.number_of_packets,
+ pdu->u.cmd_submit.interval);
+ break;
+ case USBIP_CMD_UNLINK:
+ udbg("CMD_UNLINK: seq %u\n", pdu->u.cmd_unlink.seqnum);
+ break;
+ case USBIP_RET_SUBMIT:
+ udbg("RET_SUBMIT: st %d al %u sf %d ec %d\n",
+ pdu->u.ret_submit.status,
+ pdu->u.ret_submit.actual_length,
+ pdu->u.ret_submit.start_frame,
+ pdu->u.ret_submit.error_count);
+ case USBIP_RET_UNLINK:
+ udbg("RET_UNLINK: status %d\n", pdu->u.ret_unlink.status);
+ break;
+ default:
+ /* NOT REACHED */
+ udbg("UNKNOWN\n");
+ }
+}
+EXPORT_SYMBOL_GPL(usbip_dump_header);
+
+
+/*-------------------------------------------------------------------------*/
+/* thread routines */
+
+int usbip_thread(void *param)
+{
+ struct usbip_task *ut = param;
+
+ if (!ut)
+ return -EINVAL;
+
+ lock_kernel();
+ daemonize(ut->name);
+ allow_signal(SIGKILL);
+ ut->thread = current;
+ unlock_kernel();
+
+ /* srv.rb must wait for rx_thread starting */
+ complete(&ut->thread_done);
+
+ /* start of while loop */
+ ut->loop_ops(ut);
+
+ /* end of loop */
+ ut->thread = NULL;
+
+ complete_and_exit(&ut->thread_done, 0);
+}
+
+void usbip_start_threads(struct usbip_device *ud)
+{
+ /*
+ * threads are invoked per one device (per one connection).
+ */
+ kernel_thread(usbip_thread, (void *)&ud->tcp_rx, 0);
+ kernel_thread(usbip_thread, (void *)&ud->tcp_tx, 0);
+
+ /* confirm threads are starting */
+ wait_for_completion(&ud->tcp_rx.thread_done);
+ wait_for_completion(&ud->tcp_tx.thread_done);
+}
+EXPORT_SYMBOL_GPL(usbip_start_threads);
+
+void usbip_stop_threads(struct usbip_device *ud)
+{
+ /* kill threads related to this sdev, if v.c. exists */
+ if (ud->tcp_rx.thread != NULL) {
+ send_sig(SIGKILL, ud->tcp_rx.thread, 1);
+ wait_for_completion(&ud->tcp_rx.thread_done);
+ udbg("rx_thread for ud %p has finished\n", ud);
+ }
+
+ if (ud->tcp_tx.thread != NULL) {
+ send_sig(SIGKILL, ud->tcp_tx.thread, 1);
+ wait_for_completion(&ud->tcp_tx.thread_done);
+ udbg("tx_thread for ud %p has finished\n", ud);
+ }
+}
+EXPORT_SYMBOL_GPL(usbip_stop_threads);
+
+void usbip_task_init(struct usbip_task *ut, char *name,
+ void (*loop_ops)(struct usbip_task *))
+{
+ ut->thread = NULL;
+ init_completion(&ut->thread_done);
+ ut->name = name;
+ ut->loop_ops = loop_ops;
+}
+EXPORT_SYMBOL_GPL(usbip_task_init);
+
+
+/*-------------------------------------------------------------------------*/
+/* socket routines */
+
+ /* Send/receive messages over TCP/IP. I refer drivers/block/nbd.c */
+int usbip_xmit(int send, struct socket *sock, char *buf,
+ int size, int msg_flags)
+{
+ int result;
+ struct msghdr msg;
+ struct kvec iov;
+ int total = 0;
+
+ /* for blocks of if (dbg_flag_xmit) */
+ char *bp = buf;
+ int osize = size;
+
+ dbg_xmit("enter\n");
+
+ if (!sock || !buf || !size) {
+ printk(KERN_ERR "%s: invalid arg, sock %p buff %p size %d\n",
+ __func__, sock, buf, size);
+ return -EINVAL;
+ }
+
+
+ if (dbg_flag_xmit) {
+ if (send) {
+ if (!in_interrupt())
+ printk(KERN_DEBUG "%-10s:", current->comm);
+ else
+ printk(KERN_DEBUG "interupt :");
+
+ printk("%s: sending... , sock %p, buf %p, "
+ "size %d, msg_flags %d\n", __func__,
+ sock, buf, size, msg_flags);
+ usbip_dump_buffer(buf, size);
+ }
+ }
+
+
+ do {
+ sock->sk->sk_allocation = GFP_NOIO;
+ iov.iov_base = buf;
+ iov.iov_len = size;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_namelen = 0;
+ msg.msg_flags = msg_flags | MSG_NOSIGNAL;
+
+ if (send)
+ result = kernel_sendmsg(sock, &msg, &iov, 1, size);
+ else
+ result = kernel_recvmsg(sock, &msg, &iov, 1, size,
+ MSG_WAITALL);
+
+ if (result <= 0) {
+ udbg("usbip_xmit: %s sock %p buf %p size %u ret %d"
+ " total %d\n",
+ send ? "send" : "receive", sock, buf,
+ size, result, total);
+ goto err;
+ }
+
+ size -= result;
+ buf += result;
+ total += result;
+
+ } while (size > 0);
+
+
+ if (dbg_flag_xmit) {
+ if (!send) {
+ if (!in_interrupt())
+ printk(KERN_DEBUG "%-10s:", current->comm);
+ else
+ printk(KERN_DEBUG "interupt :");
+
+ printk("usbip_xmit: receiving....\n");
+ usbip_dump_buffer(bp, osize);
+ printk("usbip_xmit: received, osize %d ret %d size %d "
+ "total %d\n", osize, result, size,
+ total);
+ }
+
+ if (send)
+ printk("usbip_xmit: send, total %d\n", total);
+ }
+
+ return total;
+
+err:
+ return result;
+}
+EXPORT_SYMBOL_GPL(usbip_xmit);
+
+
+/* now a usrland utility should set options. */
+#if 0
+int setquickack(struct socket *socket)
+{
+ mm_segment_t oldfs;
+ int val = 1;
+ int ret;
+
+ oldfs = get_fs();
+ set_fs(get_ds());
+ ret = socket->ops->setsockopt(socket, SOL_TCP, TCP_QUICKACK,
+ (char __user *) &val, sizeof(ret));
+ set_fs(oldfs);
+
+ return ret;
+}
+
+int setnodelay(struct socket *socket)
+{
+ mm_segment_t oldfs;
+ int val = 1;
+ int ret;
+
+ oldfs = get_fs();
+ set_fs(get_ds());
+ ret = socket->ops->setsockopt(socket, SOL_TCP, TCP_NODELAY,
+ (char __user *) &val, sizeof(ret));
+ set_fs(oldfs);
+
+ return ret;
+}
+
+int setkeepalive(struct socket *socket)
+{
+ mm_segment_t oldfs;
+ int val = 1;
+ int ret;
+
+ oldfs = get_fs();
+ set_fs(get_ds());
+ ret = socket->ops->setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE,
+ (char __user *) &val, sizeof(ret));
+ set_fs(oldfs);
+
+ return ret;
+}
+
+void setreuse(struct socket *socket)
+{
+ socket->sk->sk_reuse = 1;
+}
+#endif
+
+struct socket *sockfd_to_socket(unsigned int sockfd)
+{
+ struct socket *socket;
+ struct file *file;
+ struct inode *inode;
+
+ file = fget(sockfd);
+ if (!file) {
+ printk(KERN_ERR "%s: invalid sockfd\n", __func__);
+ return NULL;
+ }
+
+ inode = file->f_dentry->d_inode;
+
+ if (!inode || !S_ISSOCK(inode->i_mode))
+ return NULL;
+
+ socket = SOCKET_I(inode);
+
+ return socket;
+}
+EXPORT_SYMBOL_GPL(sockfd_to_socket);
+
+
+
+/*-------------------------------------------------------------------------*/
+/* pdu routines */
+
+/* there may be more cases to tweak the flags. */
+static unsigned int tweak_transfer_flags(unsigned int flags)
+{
+
+ if (flags & URB_NO_TRANSFER_DMA_MAP)
+ /*
+ * vhci_hcd does not provide DMA-mapped I/O. The upper
+ * driver does not need to set this flag. The remote
+ * usbip.ko does not still perform DMA-mapped I/O for
+ * DMA-caplable host controllers. So, clear this flag.
+ */
+ flags &= ~URB_NO_TRANSFER_DMA_MAP;
+
+ if (flags & URB_NO_SETUP_DMA_MAP)
+ flags &= ~URB_NO_SETUP_DMA_MAP;
+
+ return flags;
+}
+
+static void usbip_pack_cmd_submit(struct usbip_header *pdu, struct urb *urb,
+ int pack)
+{
+ struct usbip_header_cmd_submit *spdu = &pdu->u.cmd_submit;
+
+ /*
+ * Some members are not still implemented in usbip. I hope this issue
+ * will be discussed when usbip is ported to other operating systems.
+ */
+ if (pack) {
+ /* vhci_tx.c */
+ spdu->transfer_flags =
+ tweak_transfer_flags(urb->transfer_flags);
+ spdu->transfer_buffer_length = urb->transfer_buffer_length;
+ spdu->start_frame = urb->start_frame;
+ spdu->number_of_packets = urb->number_of_packets;
+ spdu->interval = urb->interval;
+ } else {
+ /* stub_rx.c */
+ urb->transfer_flags = spdu->transfer_flags;
+
+ urb->transfer_buffer_length = spdu->transfer_buffer_length;
+ urb->start_frame = spdu->start_frame;
+ urb->number_of_packets = spdu->number_of_packets;
+ urb->interval = spdu->interval;
+ }
+}
+
+static void usbip_pack_ret_submit(struct usbip_header *pdu, struct urb *urb,
+ int pack)
+{
+ struct usbip_header_ret_submit *rpdu = &pdu->u.ret_submit;
+
+ if (pack) {
+ /* stub_tx.c */
+
+ rpdu->status = urb->status;
+ rpdu->actual_length = urb->actual_length;
+ rpdu->start_frame = urb->start_frame;
+ rpdu->error_count = urb->error_count;
+ } else {
+ /* vhci_rx.c */
+
+ urb->status = rpdu->status;
+ urb->actual_length = rpdu->actual_length;
+ urb->start_frame = rpdu->start_frame;
+ urb->error_count = rpdu->error_count;
+ }
+}
+
+
+void usbip_pack_pdu(struct usbip_header *pdu, struct urb *urb, int cmd,
+ int pack)
+{
+ switch (cmd) {
+ case USBIP_CMD_SUBMIT:
+ usbip_pack_cmd_submit(pdu, urb, pack);
+ break;
+ case USBIP_RET_SUBMIT:
+ usbip_pack_ret_submit(pdu, urb, pack);
+ break;
+ default:
+ err("unknown command");
+ /* NOTREACHED */
+ /* BUG(); */
+ }
+}
+EXPORT_SYMBOL_GPL(usbip_pack_pdu);
+
+
+static void correct_endian_basic(struct usbip_header_basic *base, int send)
+{
+ if (send) {
+ base->command = cpu_to_be32(base->command);
+ base->seqnum = cpu_to_be32(base->seqnum);
+ base->devid = cpu_to_be32(base->devid);
+ base->direction = cpu_to_be32(base->direction);
+ base->ep = cpu_to_be32(base->ep);
+ } else {
+ base->command = be32_to_cpu(base->command);
+ base->seqnum = be32_to_cpu(base->seqnum);
+ base->devid = be32_to_cpu(base->devid);
+ base->direction = be32_to_cpu(base->direction);
+ base->ep = be32_to_cpu(base->ep);
+ }
+}
+
+static void correct_endian_cmd_submit(struct usbip_header_cmd_submit *pdu,
+ int send)
+{
+ if (send) {
+ pdu->transfer_flags = cpu_to_be32(pdu->transfer_flags);
+
+ cpu_to_be32s(&pdu->transfer_buffer_length);
+ cpu_to_be32s(&pdu->start_frame);
+ cpu_to_be32s(&pdu->number_of_packets);
+ cpu_to_be32s(&pdu->interval);
+ } else {
+ pdu->transfer_flags = be32_to_cpu(pdu->transfer_flags);
+
+ be32_to_cpus(&pdu->transfer_buffer_length);
+ be32_to_cpus(&pdu->start_frame);
+ be32_to_cpus(&pdu->number_of_packets);
+ be32_to_cpus(&pdu->interval);
+ }
+}
+
+static void correct_endian_ret_submit(struct usbip_header_ret_submit *pdu,
+ int send)
+{
+ if (send) {
+ cpu_to_be32s(&pdu->status);
+ cpu_to_be32s(&pdu->actual_length);
+ cpu_to_be32s(&pdu->start_frame);
+ cpu_to_be32s(&pdu->error_count);
+ } else {
+ be32_to_cpus(&pdu->status);
+ be32_to_cpus(&pdu->actual_length);
+ be32_to_cpus(&pdu->start_frame);
+ be32_to_cpus(&pdu->error_count);
+ }
+}
+
+static void correct_endian_cmd_unlink(struct usbip_header_cmd_unlink *pdu,
+ int send)
+{
+ if (send)
+ pdu->seqnum = cpu_to_be32(pdu->seqnum);
+ else
+ pdu->seqnum = be32_to_cpu(pdu->seqnum);
+}
+
+static void correct_endian_ret_unlink(struct usbip_header_ret_unlink *pdu,
+ int send)
+{
+ if (send)
+ cpu_to_be32s(&pdu->status);
+ else
+ be32_to_cpus(&pdu->status);
+}
+
+void usbip_header_correct_endian(struct usbip_header *pdu, int send)
+{
+ __u32 cmd = 0;
+
+ if (send)
+ cmd = pdu->base.command;
+
+ correct_endian_basic(&pdu->base, send);
+
+ if (!send)
+ cmd = pdu->base.command;
+
+ switch (cmd) {
+ case USBIP_CMD_SUBMIT:
+ correct_endian_cmd_submit(&pdu->u.cmd_submit, send);
+ break;
+ case USBIP_RET_SUBMIT:
+ correct_endian_ret_submit(&pdu->u.ret_submit, send);
+ break;
+ case USBIP_CMD_UNLINK:
+ correct_endian_cmd_unlink(&pdu->u.cmd_unlink, send);
+ break;
+ case USBIP_RET_UNLINK:
+ correct_endian_ret_unlink(&pdu->u.ret_unlink, send);
+ break;
+ default:
+ /* NOTREACHED */
+ err("unknown command in pdu header: %d", cmd);
+ /* BUG(); */
+ }
+}
+EXPORT_SYMBOL_GPL(usbip_header_correct_endian);
+
+static void usbip_iso_pakcet_correct_endian(
+ struct usbip_iso_packet_descriptor *iso,
+ int send)
+{
+ /* does not need all members. but copy all simply. */
+ if (send) {
+ iso->offset = cpu_to_be32(iso->offset);
+ iso->length = cpu_to_be32(iso->length);
+ iso->status = cpu_to_be32(iso->status);
+ iso->actual_length = cpu_to_be32(iso->actual_length);
+ } else {
+ iso->offset = be32_to_cpu(iso->offset);
+ iso->length = be32_to_cpu(iso->length);
+ iso->status = be32_to_cpu(iso->status);
+ iso->actual_length = be32_to_cpu(iso->actual_length);
+ }
+}
+
+static void usbip_pack_iso(struct usbip_iso_packet_descriptor *iso,
+ struct usb_iso_packet_descriptor *uiso, int pack)
+{
+ if (pack) {
+ iso->offset = uiso->offset;
+ iso->length = uiso->length;
+ iso->status = uiso->status;
+ iso->actual_length = uiso->actual_length;
+ } else {
+ uiso->offset = iso->offset;
+ uiso->length = iso->length;
+ uiso->status = iso->status;
+ uiso->actual_length = iso->actual_length;
+ }
+}
+
+
+/* must free buffer */
+void *usbip_alloc_iso_desc_pdu(struct urb *urb, ssize_t *bufflen)
+{
+ void *buff;
+ struct usbip_iso_packet_descriptor *iso;
+ int np = urb->number_of_packets;
+ ssize_t size = np * sizeof(*iso);
+ int i;
+
+ buff = kzalloc(size, GFP_KERNEL);
+ if (!buff)
+ return NULL;
+
+ for (i = 0; i < np; i++) {
+ iso = buff + (i * sizeof(*iso));
+
+ usbip_pack_iso(iso, &urb->iso_frame_desc[i], 1);
+ usbip_iso_pakcet_correct_endian(iso, 1);
+ }
+
+ *bufflen = size;
+
+ return buff;
+}
+EXPORT_SYMBOL_GPL(usbip_alloc_iso_desc_pdu);
+
+/* some members of urb must be substituted before. */
+int usbip_recv_iso(struct usbip_device *ud, struct urb *urb)
+{
+ void *buff;
+ struct usbip_iso_packet_descriptor *iso;
+ int np = urb->number_of_packets;
+ int size = np * sizeof(*iso);
+ int i;
+ int ret;
+
+ if (!usb_pipeisoc(urb->pipe))
+ return 0;
+
+ /* my Bluetooth dongle gets ISO URBs which are np = 0 */
+ if (np == 0) {
+ /* uinfo("iso np == 0\n"); */
+ /* usbip_dump_urb(urb); */
+ return 0;
+ }
+
+ buff = kzalloc(size, GFP_KERNEL);
+ if (!buff)
+ return -ENOMEM;
+
+ ret = usbip_xmit(0, ud->tcp_socket, buff, size, 0);
+ if (ret != size) {
+ dev_err(&urb->dev->dev, "recv iso_frame_descriptor, %d\n",
+ ret);
+ kfree(buff);
+
+ if (ud->side == USBIP_STUB)
+ usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
+ else
+ usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
+
+ return -EPIPE;
+ }
+
+ for (i = 0; i < np; i++) {
+ iso = buff + (i * sizeof(*iso));
+
+ usbip_iso_pakcet_correct_endian(iso, 0);
+ usbip_pack_iso(iso, &urb->iso_frame_desc[i], 0);
+ }
+
+
+ kfree(buff);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(usbip_recv_iso);
+
+
+/* some members of urb must be substituted before. */
+int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb)
+{
+ int ret;
+ int size;
+
+ if (ud->side == USBIP_STUB) {
+ /* stub_rx.c */
+ /* the direction of urb must be OUT. */
+ if (usb_pipein(urb->pipe))
+ return 0;
+
+ size = urb->transfer_buffer_length;
+ } else {
+ /* vhci_rx.c */
+ /* the direction of urb must be IN. */
+ if (usb_pipeout(urb->pipe))
+ return 0;
+
+ size = urb->actual_length;
+ }
+
+ /* no need to recv xbuff */
+ if (!(size > 0))
+ return 0;
+
+ ret = usbip_xmit(0, ud->tcp_socket, (char *)urb->transfer_buffer,
+ size, 0);
+ if (ret != size) {
+ dev_err(&urb->dev->dev, "recv xbuf, %d\n", ret);
+ if (ud->side == USBIP_STUB) {
+ usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
+ } else {
+ usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
+ return -EPIPE;
+ }
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(usbip_recv_xbuff);
+
+
+/*-------------------------------------------------------------------------*/
+
+static int __init usbip_common_init(void)
+{
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "" DRIVER_VERSION);
+
+ return 0;
+}
+
+static void __exit usbip_common_exit(void)
+{
+ return;
+}
+
+
+
+
+module_init(usbip_common_init);
+module_exit(usbip_common_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/usbip/usbip_common.h b/drivers/staging/usbip/usbip_common.h
new file mode 100644
index 0000000..b0186b7
--- /dev/null
+++ b/drivers/staging/usbip/usbip_common.h
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
+ *
+ * This 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 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 __VHCI_COMMON_H
+#define __VHCI_COMMON_H
+
+
+#include <linux/version.h>
+#include <linux/usb.h>
+#include <asm/byteorder.h>
+#include <net/sock.h>
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * define macros to print messages
+ */
+
+/**
+ * udbg - print debug messages if CONFIG_USB_DEBUG is defined
+ * @fmt:
+ * @args:
+ */
+
+#ifdef CONFIG_USB_DEBUG
+
+#define udbg(fmt, args...) \
+ do { \
+ printk(KERN_DEBUG "%-10s:(%s,%d) %s: " fmt, \
+ (in_interrupt() ? "interrupt" : (current)->comm),\
+ __FILE__, __LINE__, __func__, ##args); \
+ } while (0)
+
+#else /* CONFIG_USB_DEBUG */
+
+#define udbg(fmt, args...) do { } while (0)
+
+#endif /* CONFIG_USB_DEBUG */
+
+
+enum {
+ usbip_debug_xmit = (1 << 0),
+ usbip_debug_sysfs = (1 << 1),
+ usbip_debug_urb = (1 << 2),
+ usbip_debug_eh = (1 << 3),
+
+ usbip_debug_stub_cmp = (1 << 8),
+ usbip_debug_stub_dev = (1 << 9),
+ usbip_debug_stub_rx = (1 << 10),
+ usbip_debug_stub_tx = (1 << 11),
+
+ usbip_debug_vhci_rh = (1 << 8),
+ usbip_debug_vhci_hc = (1 << 9),
+ usbip_debug_vhci_rx = (1 << 10),
+ usbip_debug_vhci_tx = (1 << 11),
+ usbip_debug_vhci_sysfs = (1 << 12)
+};
+
+#define dbg_flag_xmit (usbip_debug_flag & usbip_debug_xmit)
+#define dbg_flag_vhci_rh (usbip_debug_flag & usbip_debug_vhci_rh)
+#define dbg_flag_vhci_hc (usbip_debug_flag & usbip_debug_vhci_hc)
+#define dbg_flag_vhci_rx (usbip_debug_flag & usbip_debug_vhci_rx)
+#define dbg_flag_vhci_tx (usbip_debug_flag & usbip_debug_vhci_tx)
+#define dbg_flag_vhci_sysfs (usbip_debug_flag & usbip_debug_vhci_sysfs)
+#define dbg_flag_stub_rx (usbip_debug_flag & usbip_debug_stub_rx)
+#define dbg_flag_stub_tx (usbip_debug_flag & usbip_debug_stub_tx)
+
+extern unsigned long usbip_debug_flag;
+extern struct device_attribute dev_attr_usbip_debug;
+
+#define dbg_with_flag(flag, fmt, args...) \
+ do { \
+ if (flag & usbip_debug_flag) \
+ udbg(fmt , ##args); \
+ } while (0)
+
+#define dbg_sysfs(fmt, args...) \
+ dbg_with_flag(usbip_debug_sysfs, fmt , ##args)
+#define dbg_xmit(fmt, args...) \
+ dbg_with_flag(usbip_debug_xmit, fmt , ##args)
+#define dbg_urb(fmt, args...) \
+ dbg_with_flag(usbip_debug_urb, fmt , ##args)
+#define dbg_eh(fmt, args...) \
+ dbg_with_flag(usbip_debug_eh, fmt , ##args)
+
+#define dbg_vhci_rh(fmt, args...) \
+ dbg_with_flag(usbip_debug_vhci_rh, fmt , ##args)
+#define dbg_vhci_hc(fmt, args...) \
+ dbg_with_flag(usbip_debug_vhci_hc, fmt , ##args)
+#define dbg_vhci_rx(fmt, args...) \
+ dbg_with_flag(usbip_debug_vhci_rx, fmt , ##args)
+#define dbg_vhci_tx(fmt, args...) \
+ dbg_with_flag(usbip_debug_vhci_tx, fmt , ##args)
+#define dbg_vhci_sysfs(fmt, args...) \
+ dbg_with_flag(usbip_debug_vhci_sysfs, fmt , ##args)
+
+#define dbg_stub_cmp(fmt, args...) \
+ dbg_with_flag(usbip_debug_stub_cmp, fmt , ##args)
+#define dbg_stub_rx(fmt, args...) \
+ dbg_with_flag(usbip_debug_stub_rx, fmt , ##args)
+#define dbg_stub_tx(fmt, args...) \
+ dbg_with_flag(usbip_debug_stub_tx, fmt , ##args)
+
+
+/**
+ * uerr - print error messages
+ * @fmt:
+ * @args:
+ */
+#define uerr(fmt, args...) \
+ do { \
+ printk(KERN_ERR "%-10s: ***ERROR*** (%s,%d) %s: " fmt, \
+ (in_interrupt() ? "interrupt" : (current)->comm),\
+ __FILE__, __LINE__, __func__, ##args); \
+ } while (0)
+
+/**
+ * uinfo - print information messages
+ * @fmt:
+ * @args:
+ */
+#define uinfo(fmt, args...) \
+ do { \
+ printk(KERN_INFO "usbip: " fmt , ## args); \
+ } while (0)
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * USB/IP request headers.
+ * Currently, we define 4 request types:
+ *
+ * - CMD_SUBMIT transfers a USB request, corresponding to usb_submit_urb().
+ * (client to server)
+ * - RET_RETURN transfers the result of CMD_SUBMIT.
+ * (server to client)
+ * - CMD_UNLINK transfers an unlink request of a pending USB request.
+ * (client to server)
+ * - RET_UNLINK transfers the result of CMD_UNLINK.
+ * (server to client)
+ *
+ * Note: The below request formats are based on the USB subsystem of Linux. Its
+ * details will be defined when other implementations come.
+ *
+ *
+ */
+
+/*
+ * A basic header followed by other additional headers.
+ */
+struct usbip_header_basic {
+#define USBIP_CMD_SUBMIT 0x0001
+#define USBIP_CMD_UNLINK 0x0002
+#define USBIP_RET_SUBMIT 0x0003
+#define USBIP_RET_UNLINK 0x0004
+ __u32 command;
+
+ /* sequencial number which identifies requests.
+ * incremented per connections */
+ __u32 seqnum;
+
+ /* devid is used to specify a remote USB device uniquely instead
+ * of busnum and devnum in Linux. In the case of Linux stub_driver,
+ * this value is ((busnum << 16) | devnum) */
+ __u32 devid;
+
+#define USBIP_DIR_OUT 0
+#define USBIP_DIR_IN 1
+ __u32 direction;
+ __u32 ep; /* endpoint number */
+} __attribute__ ((packed));
+
+/*
+ * An additional header for a CMD_SUBMIT packet.
+ */
+struct usbip_header_cmd_submit {
+ /* these values are basically the same as in a URB. */
+
+ /* the same in a URB. */
+ __u32 transfer_flags;
+
+ /* set the following data size (out),
+ * or expected reading data size (in) */
+ __s32 transfer_buffer_length;
+
+ /* it is difficult for usbip to sync frames (reserved only?) */
+ __s32 start_frame;
+
+ /* the number of iso descriptors that follows this header */
+ __s32 number_of_packets;
+
+ /* the maximum time within which this request works in a host
+ * controller of a server side */
+ __s32 interval;
+
+ /* set setup packet data for a CTRL request */
+ unsigned char setup[8];
+} __attribute__ ((packed));
+
+/*
+ * An additional header for a RET_SUBMIT packet.
+ */
+struct usbip_header_ret_submit {
+ __s32 status;
+ __s32 actual_length; /* returned data length */
+ __s32 start_frame; /* ISO and INT */
+ __s32 number_of_packets; /* ISO only */
+ __s32 error_count; /* ISO only */
+} __attribute__ ((packed));
+
+/*
+ * An additional header for a CMD_UNLINK packet.
+ */
+struct usbip_header_cmd_unlink {
+ __u32 seqnum; /* URB's seqnum which will be unlinked */
+} __attribute__ ((packed));
+
+
+/*
+ * An additional header for a RET_UNLINK packet.
+ */
+struct usbip_header_ret_unlink {
+ __s32 status;
+} __attribute__ ((packed));
+
+
+/* the same as usb_iso_packet_descriptor but packed for pdu */
+struct usbip_iso_packet_descriptor {
+ __u32 offset;
+ __u32 length; /* expected length */
+ __u32 actual_length;
+ __u32 status;
+} __attribute__ ((packed));
+
+
+/*
+ * All usbip packets use a common header to keep code simple.
+ */
+struct usbip_header {
+ struct usbip_header_basic base;
+
+ union {
+ struct usbip_header_cmd_submit cmd_submit;
+ struct usbip_header_ret_submit ret_submit;
+ struct usbip_header_cmd_unlink cmd_unlink;
+ struct usbip_header_ret_unlink ret_unlink;
+ } u;
+} __attribute__ ((packed));
+
+
+
+
+/*-------------------------------------------------------------------------*/
+
+
+int usbip_xmit(int, struct socket *, char *, int, int);
+int usbip_sendmsg(struct socket *, struct msghdr *, int);
+
+
+static inline int interface_to_busnum(struct usb_interface *interface)
+{
+ struct usb_device *udev = interface_to_usbdev(interface);
+ return udev->bus->busnum;
+}
+
+static inline int interface_to_devnum(struct usb_interface *interface)
+{
+ struct usb_device *udev = interface_to_usbdev(interface);
+ return udev->devnum;
+}
+
+static inline int interface_to_infnum(struct usb_interface *interface)
+{
+ return interface->cur_altsetting->desc.bInterfaceNumber;
+}
+
+#if 0
+int setnodelay(struct socket *);
+int setquickack(struct socket *);
+int setkeepalive(struct socket *socket);
+void setreuse(struct socket *);
+#endif
+
+struct socket *sockfd_to_socket(unsigned int);
+int set_sockaddr(struct socket *socket, struct sockaddr_storage *ss);
+
+void usbip_dump_urb(struct urb *purb);
+void usbip_dump_header(struct usbip_header *pdu);
+
+
+struct usbip_device;
+
+struct usbip_task {
+ struct task_struct *thread;
+ struct completion thread_done;
+ char *name;
+ void (*loop_ops)(struct usbip_task *);
+};
+
+enum usbip_side {
+ USBIP_VHCI,
+ USBIP_STUB,
+};
+
+enum usbip_status {
+ /* sdev is available. */
+ SDEV_ST_AVAILABLE = 0x01,
+ /* sdev is now used. */
+ SDEV_ST_USED,
+ /* sdev is unusable because of a fatal error. */
+ SDEV_ST_ERROR,
+
+ /* vdev does not connect a remote device. */
+ VDEV_ST_NULL,
+ /* vdev is used, but the USB address is not assigned yet */
+ VDEV_ST_NOTASSIGNED,
+ VDEV_ST_USED,
+ VDEV_ST_ERROR
+};
+
+/* a common structure for stub_device and vhci_device */
+struct usbip_device {
+ enum usbip_side side;
+
+ enum usbip_status status;
+
+ /* lock for status */
+ spinlock_t lock;
+
+ struct socket *tcp_socket;
+
+ struct usbip_task tcp_rx;
+ struct usbip_task tcp_tx;
+
+ /* event handler */
+#define USBIP_EH_SHUTDOWN (1 << 0)
+#define USBIP_EH_BYE (1 << 1)
+#define USBIP_EH_RESET (1 << 2)
+#define USBIP_EH_UNUSABLE (1 << 3)
+
+#define SDEV_EVENT_REMOVED (USBIP_EH_SHUTDOWN | USBIP_EH_RESET | USBIP_EH_BYE)
+#define SDEV_EVENT_DOWN (USBIP_EH_SHUTDOWN | USBIP_EH_RESET)
+#define SDEV_EVENT_ERROR_TCP (USBIP_EH_SHUTDOWN | USBIP_EH_RESET)
+#define SDEV_EVENT_ERROR_SUBMIT (USBIP_EH_SHUTDOWN | USBIP_EH_RESET)
+#define SDEV_EVENT_ERROR_MALLOC (USBIP_EH_SHUTDOWN | USBIP_EH_UNUSABLE)
+
+#define VDEV_EVENT_REMOVED (USBIP_EH_SHUTDOWN | USBIP_EH_BYE)
+#define VDEV_EVENT_DOWN (USBIP_EH_SHUTDOWN | USBIP_EH_RESET)
+#define VDEV_EVENT_ERROR_TCP (USBIP_EH_SHUTDOWN | USBIP_EH_RESET)
+#define VDEV_EVENT_ERROR_MALLOC (USBIP_EH_SHUTDOWN | USBIP_EH_UNUSABLE)
+
+ unsigned long event;
+ struct usbip_task eh;
+ wait_queue_head_t eh_waitq;
+
+ struct eh_ops {
+ void (*shutdown)(struct usbip_device *);
+ void (*reset)(struct usbip_device *);
+ void (*unusable)(struct usbip_device *);
+ } eh_ops;
+};
+
+
+void usbip_task_init(struct usbip_task *ut, char *,
+ void (*loop_ops)(struct usbip_task *));
+
+void usbip_start_threads(struct usbip_device *ud);
+void usbip_stop_threads(struct usbip_device *ud);
+int usbip_thread(void *param);
+
+void usbip_pack_pdu(struct usbip_header *pdu, struct urb *urb, int cmd,
+ int pack);
+
+void usbip_header_correct_endian(struct usbip_header *pdu, int send);
+/* some members of urb must be substituted before. */
+int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb);
+/* some members of urb must be substituted before. */
+int usbip_recv_iso(struct usbip_device *ud, struct urb *urb);
+void *usbip_alloc_iso_desc_pdu(struct urb *urb, ssize_t *bufflen);
+
+
+/* usbip_event.c */
+void usbip_start_eh(struct usbip_device *ud);
+void usbip_stop_eh(struct usbip_device *ud);
+void usbip_event_add(struct usbip_device *ud, unsigned long event);
+int usbip_event_happend(struct usbip_device *ud);
+
+
+#endif
diff --git a/drivers/staging/usbip/usbip_event.c b/drivers/staging/usbip/usbip_event.c
new file mode 100644
index 0000000..4318553
--- /dev/null
+++ b/drivers/staging/usbip/usbip_event.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
+ *
+ * This 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 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include "usbip_common.h"
+
+static int event_handler(struct usbip_device *ud)
+{
+ dbg_eh("enter\n");
+
+ /*
+ * Events are handled by only this thread.
+ */
+ while (usbip_event_happend(ud)) {
+ dbg_eh("pending event %lx\n", ud->event);
+
+ /*
+ * NOTE: shutdown must come first.
+ * Shutdown the device.
+ */
+ if (ud->event & USBIP_EH_SHUTDOWN) {
+ ud->eh_ops.shutdown(ud);
+
+ ud->event &= ~USBIP_EH_SHUTDOWN;
+
+ break;
+ }
+
+ /* Stop the error handler. */
+ if (ud->event & USBIP_EH_BYE)
+ return -1;
+
+ /* Reset the device. */
+ if (ud->event & USBIP_EH_RESET) {
+ ud->eh_ops.reset(ud);
+
+ ud->event &= ~USBIP_EH_RESET;
+
+ break;
+ }
+
+ /* Mark the device as unusable. */
+ if (ud->event & USBIP_EH_UNUSABLE) {
+ ud->eh_ops.unusable(ud);
+
+ ud->event &= ~USBIP_EH_UNUSABLE;
+
+ break;
+ }
+
+ /* NOTREACHED */
+ printk(KERN_ERR "%s: unknown event\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void event_handler_loop(struct usbip_task *ut)
+{
+ struct usbip_device *ud = container_of(ut, struct usbip_device, eh);
+
+ while (1) {
+ if (signal_pending(current)) {
+ dbg_eh("signal catched!\n");
+ break;
+ }
+
+ if (event_handler(ud) < 0)
+ break;
+
+ wait_event_interruptible(ud->eh_waitq, usbip_event_happend(ud));
+ dbg_eh("wakeup\n");
+ }
+}
+
+void usbip_start_eh(struct usbip_device *ud)
+{
+ struct usbip_task *eh = &ud->eh;
+
+ init_waitqueue_head(&ud->eh_waitq);
+ ud->event = 0;
+
+ usbip_task_init(eh, "usbip_eh", event_handler_loop);
+
+ kernel_thread(usbip_thread, (void *)eh, 0);
+
+ wait_for_completion(&eh->thread_done);
+}
+EXPORT_SYMBOL_GPL(usbip_start_eh);
+
+void usbip_stop_eh(struct usbip_device *ud)
+{
+ struct usbip_task *eh = &ud->eh;
+
+ wait_for_completion(&eh->thread_done);
+ dbg_eh("usbip_eh has finished\n");
+}
+EXPORT_SYMBOL_GPL(usbip_stop_eh);
+
+void usbip_event_add(struct usbip_device *ud, unsigned long event)
+{
+ spin_lock(&ud->lock);
+
+ ud->event |= event;
+
+ wake_up(&ud->eh_waitq);
+
+ spin_unlock(&ud->lock);
+}
+EXPORT_SYMBOL_GPL(usbip_event_add);
+
+int usbip_event_happend(struct usbip_device *ud)
+{
+ int happend = 0;
+
+ spin_lock(&ud->lock);
+
+ if (ud->event != 0)
+ happend = 1;
+
+ spin_unlock(&ud->lock);
+
+ return happend;
+}
+EXPORT_SYMBOL_GPL(usbip_event_happend);
--
1.6.0.2
^ permalink raw reply related [flat|nested] 37+ messages in thread* [PATCH 12/23] Staging: USB/IP: add client driver
2008-10-10 22:41 [GIT PATCH] STAGING patches for 2.6.28 Greg KH
` (7 preceding siblings ...)
2008-10-10 22:42 ` [PATCH 11/23] Staging: USB/IP: add common functions needed Greg KH
@ 2008-10-10 22:42 ` Greg KH
2008-10-10 22:42 ` [PATCH 13/23] Staging: USB/IP: add host driver Greg KH
` (10 subsequent siblings)
19 siblings, 0 replies; 37+ messages in thread
From: Greg KH @ 2008-10-10 22:42 UTC (permalink / raw)
To: linux-kernel; +Cc: Takahiro Hirofuchi, Brian G. Merrell, Greg Kroah-Hartman
From: Takahiro Hirofuchi <hirofuchi@users.sourceforge.net>
This adds the USB IP client driver
Brian Merrell cleaned up a lot of this code and submitted it for
inclusion. Greg also did a lot of cleanup.
Signed-off-by: Brian G. Merrell <bgmerrell@novell.com>
Cc: Takahiro Hirofuchi <hirofuchi@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/usbip/Kconfig | 11 +
drivers/staging/usbip/Makefile | 3 +
drivers/staging/usbip/vhci.h | 142 ++++
drivers/staging/usbip/vhci_hcd.c | 1275 ++++++++++++++++++++++++++++++++++++
drivers/staging/usbip/vhci_rx.c | 251 +++++++
drivers/staging/usbip/vhci_sysfs.c | 250 +++++++
drivers/staging/usbip/vhci_tx.c | 239 +++++++
7 files changed, 2171 insertions(+), 0 deletions(-)
create mode 100644 drivers/staging/usbip/vhci.h
create mode 100644 drivers/staging/usbip/vhci_hcd.c
create mode 100644 drivers/staging/usbip/vhci_rx.c
create mode 100644 drivers/staging/usbip/vhci_sysfs.c
create mode 100644 drivers/staging/usbip/vhci_tx.c
diff --git a/drivers/staging/usbip/Kconfig b/drivers/staging/usbip/Kconfig
index 37efb5e..c4d68e1 100644
--- a/drivers/staging/usbip/Kconfig
+++ b/drivers/staging/usbip/Kconfig
@@ -12,3 +12,14 @@ config USB_IP_COMMON
module will be called usbip_common_mod.
If unsure, say N.
+
+config USB_IP_VHCI_HCD
+ tristate "USB IP client driver"
+ depends on USB_IP_COMMON
+ default N
+ ---help---
+ This enables the USB IP host controller driver which will
+ run on the client machine.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vhci_hcd.
diff --git a/drivers/staging/usbip/Makefile b/drivers/staging/usbip/Makefile
index ce925ca..6ef4c39 100644
--- a/drivers/staging/usbip/Makefile
+++ b/drivers/staging/usbip/Makefile
@@ -1,6 +1,9 @@
obj-$(CONFIG_USB_IP_COMMON) += usbip_common_mod.o
usbip_common_mod-objs := usbip_common.o usbip_event.o
+obj-$(CONFIG_USB_IP_VHCI_HCD) += vhci-hcd.o
+vhci-hcd-objs := vhci_sysfs.o vhci_tx.o vhci_rx.o vhci_hcd.o
+
ifeq ($(CONFIG_USB_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
endif
diff --git a/drivers/staging/usbip/vhci.h b/drivers/staging/usbip/vhci.h
new file mode 100644
index 0000000..5e37517
--- /dev/null
+++ b/drivers/staging/usbip/vhci.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
+ *
+ * This 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 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include <linux/platform_device.h>
+#include "../../usb/core/hcd.h"
+
+
+struct vhci_device {
+ struct usb_device *udev;
+
+ /*
+ * devid specifies a remote usb device uniquely instead
+ * of combination of busnum and devnum.
+ */
+ __u32 devid;
+
+ /* speed of a remote device */
+ enum usb_device_speed speed;
+
+ /* vhci root-hub port to which this device is attached */
+ __u32 rhport;
+
+ struct usbip_device ud;
+
+
+ /* lock for the below link lists */
+ spinlock_t priv_lock;
+
+ /* vhci_priv is linked to one of them. */
+ struct list_head priv_tx;
+ struct list_head priv_rx;
+
+ /* vhci_unlink is linked to one of them */
+ struct list_head unlink_tx;
+ struct list_head unlink_rx;
+
+ /* vhci_tx thread sleeps for this queue */
+ wait_queue_head_t waitq_tx;
+};
+
+
+/* urb->hcpriv, use container_of() */
+struct vhci_priv {
+ unsigned long seqnum;
+ struct list_head list;
+
+ struct vhci_device *vdev;
+ struct urb *urb;
+};
+
+
+struct vhci_unlink {
+ /* seqnum of this request */
+ unsigned long seqnum;
+
+ struct list_head list;
+
+ /* seqnum of the unlink target */
+ unsigned long unlink_seqnum;
+};
+
+/*
+ * The number of ports is less than 16 ?
+ * USB_MAXCHILDREN is statically defined to 16 in usb.h. Its maximum value
+ * would be 31 because the event_bits[1] of struct usb_hub is defined as
+ * unsigned long in hub.h
+ */
+#define VHCI_NPORTS 8
+
+/* for usb_bus.hcpriv */
+struct vhci_hcd {
+ spinlock_t lock;
+
+ u32 port_status[VHCI_NPORTS];
+
+ unsigned resuming:1;
+ unsigned long re_timeout;
+
+ atomic_t seqnum;
+
+ /*
+ * NOTE:
+ * wIndex shows the port number and begins from 1.
+ * But, the index of this array begins from 0.
+ */
+ struct vhci_device vdev[VHCI_NPORTS];
+
+ /* vhci_device which has not been assiged its address yet */
+ int pending_port;
+};
+
+
+extern struct vhci_hcd *the_controller;
+extern struct attribute_group dev_attr_group;
+
+
+/*-------------------------------------------------------------------------*/
+/* prototype declaration */
+
+/* vhci_hcd.c */
+void rh_port_connect(int rhport, enum usb_device_speed speed);
+void rh_port_disconnect(int rhport);
+void vhci_rx_loop(struct usbip_task *ut);
+void vhci_tx_loop(struct usbip_task *ut);
+
+#define hardware (&the_controller->pdev.dev)
+
+static inline struct vhci_device *port_to_vdev(__u32 port)
+{
+ return &the_controller->vdev[port];
+}
+
+static inline struct vhci_hcd *hcd_to_vhci(struct usb_hcd *hcd)
+{
+ return (struct vhci_hcd *) (hcd->hcd_priv);
+}
+
+static inline struct usb_hcd *vhci_to_hcd(struct vhci_hcd *vhci)
+{
+ return container_of((void *) vhci, struct usb_hcd, hcd_priv);
+}
+
+static inline struct device *vhci_dev(struct vhci_hcd *vhci)
+{
+ return vhci_to_hcd(vhci)->self.controller;
+}
diff --git a/drivers/staging/usbip/vhci_hcd.c b/drivers/staging/usbip/vhci_hcd.c
new file mode 100644
index 0000000..5b5a2e3
--- /dev/null
+++ b/drivers/staging/usbip/vhci_hcd.c
@@ -0,0 +1,1275 @@
+/*
+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
+ *
+ * This 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 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+
+#include "usbip_common.h"
+#include "vhci.h"
+
+#define DRIVER_VERSION "1.0"
+#define DRIVER_AUTHOR "Takahiro Hirofuchi"
+#define DRIVER_DESC "Virtual Host Controller Interface Driver for USB/IP"
+#define DRIVER_LICENCE "GPL"
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENCE);
+
+
+
+/*
+ * TODO
+ * - update root hub emulation
+ * - move the emulation code to userland ?
+ * porting to other operating systems
+ * minimize kernel code
+ * - add suspend/resume code
+ * - clean up everything
+ */
+
+
+/* See usb gadget dummy hcd */
+
+
+static int vhci_hub_status(struct usb_hcd *hcd, char *buff);
+static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+ u16 wIndex, char *buff, u16 wLength);
+static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+ gfp_t mem_flags);
+static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
+static int vhci_start(struct usb_hcd *vhci_hcd);
+static void vhci_stop(struct usb_hcd *hcd);
+static int vhci_get_frame_number(struct usb_hcd *hcd);
+
+static const char driver_name[] = "vhci_hcd";
+static const char driver_desc[] = "USB/IP Virtual Host Contoroller";
+
+struct vhci_hcd *the_controller;
+
+static const char *bit_desc[] = {
+ "CONNECTION", /*0*/
+ "ENABLE", /*1*/
+ "SUSPEND", /*2*/
+ "OVER_CURRENT", /*3*/
+ "RESET", /*4*/
+ "R5", /*5*/
+ "R6", /*6*/
+ "R7", /*7*/
+ "POWER", /*8*/
+ "LOWSPEED", /*9*/
+ "HIGHSPEED", /*10*/
+ "PORT_TEST", /*11*/
+ "INDICATOR", /*12*/
+ "R13", /*13*/
+ "R14", /*14*/
+ "R15", /*15*/
+ "C_CONNECTION", /*16*/
+ "C_ENABLE", /*17*/
+ "C_SUSPEND", /*18*/
+ "C_OVER_CURRENT", /*19*/
+ "C_RESET", /*20*/
+ "R21", /*21*/
+ "R22", /*22*/
+ "R23", /*23*/
+ "R24", /*24*/
+ "R25", /*25*/
+ "R26", /*26*/
+ "R27", /*27*/
+ "R28", /*28*/
+ "R29", /*29*/
+ "R30", /*30*/
+ "R31", /*31*/
+};
+
+
+static void dump_port_status(u32 status)
+{
+ int i = 0;
+
+ printk(KERN_DEBUG "status %08x:", status);
+ for (i = 0; i < 32; i++) {
+ if (status & (1 << i))
+ printk(" %s", bit_desc[i]);
+ }
+
+ printk("\n");
+}
+
+
+
+void rh_port_connect(int rhport, enum usb_device_speed speed)
+{
+ unsigned long flags;
+
+ dbg_vhci_rh("rh_port_connect %d\n", rhport);
+
+ spin_lock_irqsave(&the_controller->lock, flags);
+
+ the_controller->port_status[rhport] |= USB_PORT_STAT_CONNECTION
+ | (1 << USB_PORT_FEAT_C_CONNECTION);
+
+ switch (speed) {
+ case USB_SPEED_HIGH:
+ the_controller->port_status[rhport] |= USB_PORT_STAT_HIGH_SPEED;
+ break;
+ case USB_SPEED_LOW:
+ the_controller->port_status[rhport] |= USB_PORT_STAT_LOW_SPEED;
+ break;
+ default:
+ break;
+ }
+
+ /* spin_lock(&the_controller->vdev[rhport].ud.lock);
+ * the_controller->vdev[rhport].ud.status = VDEV_CONNECT;
+ * spin_unlock(&the_controller->vdev[rhport].ud.lock); */
+
+ the_controller->pending_port = rhport;
+
+ spin_unlock_irqrestore(&the_controller->lock, flags);
+
+ usb_hcd_poll_rh_status(vhci_to_hcd(the_controller));
+}
+
+void rh_port_disconnect(int rhport)
+{
+ unsigned long flags;
+
+ dbg_vhci_rh("rh_port_disconnect %d\n", rhport);
+
+ spin_lock_irqsave(&the_controller->lock, flags);
+ /* stop_activity(dum, driver); */
+ the_controller->port_status[rhport] &= ~USB_PORT_STAT_CONNECTION;
+ the_controller->port_status[rhport] |=
+ (1 << USB_PORT_FEAT_C_CONNECTION);
+
+
+ /* not yet complete the disconnection
+ * spin_lock(&vdev->ud.lock);
+ * vdev->ud.status = VHC_ST_DISCONNECT;
+ * spin_unlock(&vdev->ud.lock); */
+
+ spin_unlock_irqrestore(&the_controller->lock, flags);
+}
+
+
+
+/*----------------------------------------------------------------------*/
+
+#define PORT_C_MASK \
+ ((USB_PORT_STAT_C_CONNECTION \
+ | USB_PORT_STAT_C_ENABLE \
+ | USB_PORT_STAT_C_SUSPEND \
+ | USB_PORT_STAT_C_OVERCURRENT \
+ | USB_PORT_STAT_C_RESET) << 16)
+
+/*
+ * This function is almostly the same as dummy_hcd.c:dummy_hub_status() without
+ * suspend/resume support. But, it is modified to provide multiple ports.
+ *
+ * @buf: a bitmap to show which port status has been changed.
+ * bit 0: reserved or used for another purpose?
+ * bit 1: the status of port 0 has been changed.
+ * bit 2: the status of port 1 has been changed.
+ * ...
+ * bit 7: the status of port 6 has been changed.
+ * bit 8: the status of port 7 has been changed.
+ * ...
+ * bit 15: the status of port 14 has been changed.
+ *
+ * So, the maximum number of ports is 31 ( port 0 to port 30) ?
+ *
+ * The return value is the actual transfered length in byte. If nothing has
+ * been changed, return 0. In the case that the number of ports is less than or
+ * equal to 6 (VHCI_NPORTS==7), return 1.
+ *
+ */
+static int vhci_hub_status(struct usb_hcd *hcd, char *buf)
+{
+ struct vhci_hcd *vhci;
+ unsigned long flags;
+ int retval = 0;
+
+ /* the enough buffer is allocated according to USB_MAXCHILDREN */
+ unsigned long *event_bits = (unsigned long *) buf;
+ int rhport;
+ int changed = 0;
+
+
+ *event_bits = 0;
+
+ vhci = hcd_to_vhci(hcd);
+
+ spin_lock_irqsave(&vhci->lock, flags);
+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
+ dbg_vhci_rh("hw accessible flag in on?\n");
+ goto done;
+ }
+
+ /* check pseudo status register for each port */
+ for (rhport = 0; rhport < VHCI_NPORTS; rhport++) {
+ if ((vhci->port_status[rhport] & PORT_C_MASK)) {
+ /* The status of a port has been changed, */
+ dbg_vhci_rh("port %d is changed\n", rhport);
+
+ *event_bits |= 1 << (rhport + 1);
+ changed = 1;
+ }
+ }
+
+ uinfo("changed %d\n", changed);
+
+ if (hcd->state == HC_STATE_SUSPENDED)
+ usb_hcd_resume_root_hub(hcd);
+
+ if (changed)
+ retval = 1 + (VHCI_NPORTS / 8);
+ else
+ retval = 0;
+
+done:
+ spin_unlock_irqrestore(&vhci->lock, flags);
+ return retval;
+}
+
+/* See hub_configure in hub.c */
+static inline void hub_descriptor(struct usb_hub_descriptor *desc)
+{
+ memset(desc, 0, sizeof(*desc));
+ desc->bDescriptorType = 0x29;
+ desc->bDescLength = 9;
+ desc->wHubCharacteristics = (__force __u16)
+ (__constant_cpu_to_le16(0x0001));
+ desc->bNbrPorts = VHCI_NPORTS;
+ desc->bitmap[0] = 0xff;
+ desc->bitmap[1] = 0xff;
+}
+
+static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+ u16 wIndex, char *buf, u16 wLength)
+{
+ struct vhci_hcd *dum;
+ int retval = 0;
+ unsigned long flags;
+ int rhport;
+
+ u32 prev_port_status[VHCI_NPORTS];
+
+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
+ return -ETIMEDOUT;
+
+ /*
+ * NOTE:
+ * wIndex shows the port number and begins from 1.
+ */
+ dbg_vhci_rh("typeReq %x wValue %x wIndex %x\n", typeReq, wValue,
+ wIndex);
+ if (wIndex > VHCI_NPORTS)
+ printk(KERN_ERR "%s: invalid port number %d\n", __func__, wIndex);
+ rhport = ((__u8)(wIndex & 0x00ff)) - 1;
+
+ dum = hcd_to_vhci(hcd);
+
+ spin_lock_irqsave(&dum->lock, flags);
+
+ /* store old status and compare now and old later */
+ if (dbg_flag_vhci_rh) {
+ int i = 0;
+ for (i = 0; i < VHCI_NPORTS; i++)
+ prev_port_status[i] = dum->port_status[i];
+ }
+
+ switch (typeReq) {
+ case ClearHubFeature:
+ dbg_vhci_rh(" ClearHubFeature\n");
+ break;
+ case ClearPortFeature:
+ switch (wValue) {
+ case USB_PORT_FEAT_SUSPEND:
+ if (dum->port_status[rhport] & USB_PORT_STAT_SUSPEND) {
+ /* 20msec signaling */
+ dum->resuming = 1;
+ dum->re_timeout =
+ jiffies + msecs_to_jiffies(20);
+ }
+ break;
+ case USB_PORT_FEAT_POWER:
+ dbg_vhci_rh(" ClearPortFeature: USB_PORT_FEAT_POWER\n");
+ dum->port_status[rhport] = 0;
+ /* dum->address = 0; */
+ /* dum->hdev = 0; */
+ dum->resuming = 0;
+ break;
+ case USB_PORT_FEAT_C_RESET:
+ dbg_vhci_rh(" ClearPortFeature: "
+ "USB_PORT_FEAT_C_RESET\n");
+ switch (dum->vdev[rhport].speed) {
+ case USB_SPEED_HIGH:
+ dum->port_status[rhport] |=
+ USB_PORT_STAT_HIGH_SPEED;
+ break;
+ case USB_SPEED_LOW:
+ dum->port_status[rhport] |=
+ USB_PORT_STAT_LOW_SPEED;
+ break;
+ default:
+ break;
+ }
+ default:
+ dbg_vhci_rh(" ClearPortFeature: default %x\n", wValue);
+ dum->port_status[rhport] &= ~(1 << wValue);
+ }
+ break;
+ case GetHubDescriptor:
+ dbg_vhci_rh(" GetHubDescriptor\n");
+ hub_descriptor((struct usb_hub_descriptor *) buf);
+ break;
+ case GetHubStatus:
+ dbg_vhci_rh(" GetHubStatus\n");
+ *(__le32 *) buf = __constant_cpu_to_le32(0);
+ break;
+ case GetPortStatus:
+ dbg_vhci_rh(" GetPortStatus port %x\n", wIndex);
+ if (wIndex > VHCI_NPORTS || wIndex < 1) {
+ printk(KERN_ERR "%s: invalid port number %d\n",
+ __func__, wIndex);
+ retval = -EPIPE;
+ }
+
+ /* we do no care of resume. */
+
+ /* whoever resets or resumes must GetPortStatus to
+ * complete it!!
+ * */
+ if (dum->resuming && time_after(jiffies, dum->re_timeout)) {
+ printk(KERN_ERR "%s: not yet\n", __func__);
+ dum->port_status[rhport] |=
+ (1 << USB_PORT_FEAT_C_SUSPEND);
+ dum->port_status[rhport] &=
+ ~(1 << USB_PORT_FEAT_SUSPEND);
+ dum->resuming = 0;
+ dum->re_timeout = 0;
+ /* if (dum->driver && dum->driver->resume) {
+ * spin_unlock (&dum->lock);
+ * dum->driver->resume (&dum->gadget);
+ * spin_lock (&dum->lock);
+ * } */
+ }
+
+ if ((dum->port_status[rhport] & (1 << USB_PORT_FEAT_RESET)) !=
+ 0 && time_after(jiffies, dum->re_timeout)) {
+ dum->port_status[rhport] |=
+ (1 << USB_PORT_FEAT_C_RESET);
+ dum->port_status[rhport] &=
+ ~(1 << USB_PORT_FEAT_RESET);
+ dum->re_timeout = 0;
+
+ if (dum->vdev[rhport].ud.status ==
+ VDEV_ST_NOTASSIGNED) {
+ dbg_vhci_rh(" enable rhport %d (status %u)\n",
+ rhport,
+ dum->vdev[rhport].ud.status);
+ dum->port_status[rhport] |=
+ USB_PORT_STAT_ENABLE;
+ }
+#if 0
+ if (dum->driver) {
+
+ dum->port_status[rhport] |=
+ USB_PORT_STAT_ENABLE;
+ /* give it the best speed we agree on */
+ dum->gadget.speed = dum->driver->speed;
+ dum->gadget.ep0->maxpacket = 64;
+ switch (dum->gadget.speed) {
+ case USB_SPEED_HIGH:
+ dum->port_status[rhport] |=
+ USB_PORT_STAT_HIGH_SPEED;
+ break;
+ case USB_SPEED_LOW:
+ dum->gadget.ep0->maxpacket = 8;
+ dum->port_status[rhport] |=
+ USB_PORT_STAT_LOW_SPEED;
+ break;
+ default:
+ dum->gadget.speed = USB_SPEED_FULL;
+ break;
+ }
+ }
+#endif
+
+ }
+ ((u16 *) buf)[0] = cpu_to_le16(dum->port_status[rhport]);
+ ((u16 *) buf)[1] =
+ cpu_to_le16(dum->port_status[rhport] >> 16);
+
+ dbg_vhci_rh(" GetPortStatus bye %x %x\n", ((u16 *)buf)[0],
+ ((u16 *)buf)[1]);
+ break;
+ case SetHubFeature:
+ dbg_vhci_rh(" SetHubFeature\n");
+ retval = -EPIPE;
+ break;
+ case SetPortFeature:
+ switch (wValue) {
+ case USB_PORT_FEAT_SUSPEND:
+ dbg_vhci_rh(" SetPortFeature: "
+ "USB_PORT_FEAT_SUSPEND\n");
+ printk(KERN_ERR "%s: not yet\n", __func__);
+#if 0
+ dum->port_status[rhport] |=
+ (1 << USB_PORT_FEAT_SUSPEND);
+ if (dum->driver->suspend) {
+ spin_unlock(&dum->lock);
+ dum->driver->suspend(&dum->gadget);
+ spin_lock(&dum->lock);
+ }
+#endif
+ break;
+ case USB_PORT_FEAT_RESET:
+ dbg_vhci_rh(" SetPortFeature: USB_PORT_FEAT_RESET\n");
+ /* if it's already running, disconnect first */
+ if (dum->port_status[rhport] & USB_PORT_STAT_ENABLE) {
+ dum->port_status[rhport] &=
+ ~(USB_PORT_STAT_ENABLE |
+ USB_PORT_STAT_LOW_SPEED |
+ USB_PORT_STAT_HIGH_SPEED);
+#if 0
+ if (dum->driver) {
+ dev_dbg(hardware, "disconnect\n");
+ stop_activity(dum, dum->driver);
+ }
+#endif
+
+ /* FIXME test that code path! */
+ }
+ /* 50msec reset signaling */
+ dum->re_timeout = jiffies + msecs_to_jiffies(50);
+
+ /* FALLTHROUGH */
+ default:
+ dbg_vhci_rh(" SetPortFeature: default %d\n", wValue);
+ dum->port_status[rhport] |= (1 << wValue);
+ }
+ break;
+
+ default:
+ printk(KERN_ERR "%s: default: no such request\n", __func__);
+ /* dev_dbg (hardware,
+ * "hub control req%04x v%04x i%04x l%d\n",
+ * typeReq, wValue, wIndex, wLength); */
+
+ /* "protocol stall" on error */
+ retval = -EPIPE;
+ }
+
+ if (dbg_flag_vhci_rh) {
+ printk(KERN_DEBUG "port %d\n", rhport);
+ dump_port_status(prev_port_status[rhport]);
+ dump_port_status(dum->port_status[rhport]);
+ }
+ dbg_vhci_rh(" bye\n");
+
+ spin_unlock_irqrestore(&dum->lock, flags);
+
+ return retval;
+}
+
+
+
+/*----------------------------------------------------------------------*/
+
+static struct vhci_device *get_vdev(struct usb_device *udev)
+{
+ int i;
+
+ if (!udev)
+ return NULL;
+
+ for (i = 0; i < VHCI_NPORTS; i++)
+ if (the_controller->vdev[i].udev == udev)
+ return port_to_vdev(i);
+
+ return NULL;
+}
+
+static void vhci_tx_urb(struct urb *urb)
+{
+ struct vhci_device *vdev = get_vdev(urb->dev);
+ struct vhci_priv *priv;
+ unsigned long flag;
+
+ if (!vdev) {
+ err("could not get virtual device");
+ /* BUG(); */
+ return;
+ }
+
+ spin_lock_irqsave(&vdev->priv_lock, flag);
+
+ priv = kzalloc(sizeof(struct vhci_priv), GFP_ATOMIC);
+ if (!priv) {
+ dev_err(&urb->dev->dev, "malloc vhci_priv\n");
+ spin_unlock_irqrestore(&vdev->priv_lock, flag);
+ usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC);
+ return;
+ }
+
+ priv->seqnum = atomic_inc_return(&the_controller->seqnum);
+ if (priv->seqnum == 0xffff)
+ uinfo("seqnum max\n");
+
+ priv->vdev = vdev;
+ priv->urb = urb;
+
+ urb->hcpriv = (void *) priv;
+
+
+ list_add_tail(&priv->list, &vdev->priv_tx);
+
+ wake_up(&vdev->waitq_tx);
+ spin_unlock_irqrestore(&vdev->priv_lock, flag);
+}
+
+static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+ gfp_t mem_flags)
+{
+ struct device *dev = &urb->dev->dev;
+ int ret = 0;
+ unsigned long flags;
+
+ dbg_vhci_hc("enter, usb_hcd %p urb %p mem_flags %d\n",
+ hcd, urb, mem_flags);
+
+ /* patch to usb_sg_init() is in 2.5.60 */
+ BUG_ON(!urb->transfer_buffer && urb->transfer_buffer_length);
+
+ spin_lock_irqsave(&the_controller->lock, flags);
+
+ /* check HC is active or not */
+ if (!HC_IS_RUNNING(hcd->state)) {
+ dev_err(dev, "HC is not running\n");
+ spin_unlock_irqrestore(&the_controller->lock, flags);
+ return -ENODEV;
+ }
+
+ if (urb->status != -EINPROGRESS) {
+ dev_err(dev, "URB already unlinked!, status %d\n", urb->status);
+ spin_unlock_irqrestore(&the_controller->lock, flags);
+ return urb->status;
+ }
+
+ ret = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (ret)
+ goto no_need_unlink;
+
+ /*
+ * The enumelation process is as follows;
+ *
+ * 1. Get_Descriptor request to DevAddrs(0) EndPoint(0)
+ * to get max packet length of default pipe
+ *
+ * 2. Set_Address request to DevAddr(0) EndPoint(0)
+ *
+ */
+
+ if (usb_pipedevice(urb->pipe) == 0) {
+ __u8 type = usb_pipetype(urb->pipe);
+ struct usb_ctrlrequest *ctrlreq =
+ (struct usb_ctrlrequest *) urb->setup_packet;
+ struct vhci_device *vdev =
+ port_to_vdev(the_controller->pending_port);
+
+ if (type != PIPE_CONTROL || !ctrlreq) {
+ dev_err(dev, "invalid request to devnum 0\n");
+ ret = EINVAL;
+ goto no_need_xmit;
+ }
+
+ switch (ctrlreq->bRequest) {
+ case USB_REQ_SET_ADDRESS:
+ /* set_address may come when a device is reset */
+ dev_info(dev, "SetAddress Request (%d) to port %d\n",
+ ctrlreq->wValue, vdev->rhport);
+
+ vdev->udev = urb->dev;
+
+ spin_lock(&vdev->ud.lock);
+ vdev->ud.status = VDEV_ST_USED;
+ spin_unlock(&vdev->ud.lock);
+
+ if (urb->status == -EINPROGRESS) {
+ /* This request is successfully completed. */
+ /* If not -EINPROGRESS, possibly unlinked. */
+ urb->status = 0;
+ }
+
+ goto no_need_xmit;
+
+ case USB_REQ_GET_DESCRIPTOR:
+ if (ctrlreq->wValue == (USB_DT_DEVICE << 8))
+ dbg_vhci_hc("Not yet?: "
+ "Get_Descriptor to device 0 "
+ "(get max pipe size)\n");
+
+ /* FIXME: reference count? (usb_get_dev()) */
+ vdev->udev = urb->dev;
+ goto out;
+
+ default:
+ /* NOT REACHED */
+ dev_err(dev, "invalid request to devnum 0 bRequest %u, "
+ "wValue %u\n", ctrlreq->bRequest,
+ ctrlreq->wValue);
+ ret = -EINVAL;
+ goto no_need_xmit;
+ }
+
+ }
+
+out:
+ vhci_tx_urb(urb);
+
+ spin_unlock_irqrestore(&the_controller->lock, flags);
+
+ return 0;
+
+no_need_xmit:
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+no_need_unlink:
+ spin_unlock_irqrestore(&the_controller->lock, flags);
+
+ usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status);
+
+ return 0;
+}
+
+/*
+ * vhci_rx gives back the urb after receiving the reply of the urb. If an
+ * unlink pdu is sent or not, vhci_rx receives a normal return pdu and gives
+ * back its urb. For the driver unlinking the urb, the content of the urb is
+ * not important, but the calling to its completion handler is important; the
+ * completion of unlinking is notified by the completion handler.
+ *
+ *
+ * CLIENT SIDE
+ *
+ * - When vhci_hcd receives RET_SUBMIT,
+ *
+ * - case 1a). the urb of the pdu is not unlinking.
+ * - normal case
+ * => just give back the urb
+ *
+ * - case 1b). the urb of the pdu is unlinking.
+ * - usbip.ko will return a reply of the unlinking request.
+ * => give back the urb now and go to case 2b).
+ *
+ * - When vhci_hcd receives RET_UNLINK,
+ *
+ * - case 2a). a submit request is still pending in vhci_hcd.
+ * - urb was really pending in usbip.ko and urb_unlink_urb() was
+ * completed there.
+ * => free a pending submit request
+ * => notify unlink completeness by giving back the urb
+ *
+ * - case 2b). a submit request is *not* pending in vhci_hcd.
+ * - urb was already given back to the core driver.
+ * => do not give back the urb
+ *
+ *
+ * SERVER SIDE
+ *
+ * - When usbip receives CMD_UNLINK,
+ *
+ * - case 3a). the urb of the unlink request is now in submission.
+ * => do usb_unlink_urb().
+ * => after the unlink is completed, send RET_UNLINK.
+ *
+ * - case 3b). the urb of the unlink request is not in submission.
+ * - may be already completed or never be received
+ * => send RET_UNLINK
+ *
+ */
+static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+ unsigned long flags;
+ struct vhci_priv *priv;
+ struct vhci_device *vdev;
+
+ uinfo("vhci_hcd: dequeue a urb %p\n", urb);
+
+
+ spin_lock_irqsave(&the_controller->lock, flags);
+
+ priv = urb->hcpriv;
+ if (!priv) {
+ /* URB was never linked! or will be soon given back by
+ * vhci_rx. */
+ spin_unlock_irqrestore(&the_controller->lock, flags);
+ return 0;
+ }
+
+ {
+ int ret = 0;
+ ret = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (ret) {
+ spin_unlock_irqrestore(&the_controller->lock, flags);
+ return 0;
+ }
+ }
+
+ /* send unlink request here? */
+ vdev = priv->vdev;
+
+ if (!vdev->ud.tcp_socket) {
+ /* tcp connection is closed */
+ unsigned long flags2;
+
+ spin_lock_irqsave(&vdev->priv_lock, flags2);
+
+ uinfo("vhci_hcd: device %p seems to be disconnected\n", vdev);
+ list_del(&priv->list);
+ kfree(priv);
+ urb->hcpriv = NULL;
+
+ spin_unlock_irqrestore(&vdev->priv_lock, flags2);
+
+ } else {
+ /* tcp connection is alive */
+ unsigned long flags2;
+ struct vhci_unlink *unlink;
+
+ spin_lock_irqsave(&vdev->priv_lock, flags2);
+
+ /* setup CMD_UNLINK pdu */
+ unlink = kzalloc(sizeof(struct vhci_unlink), GFP_ATOMIC);
+ if (!unlink) {
+ uerr("malloc vhci_unlink\n");
+ spin_unlock_irqrestore(&vdev->priv_lock, flags2);
+ spin_unlock_irqrestore(&the_controller->lock, flags);
+ usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC);
+ return -ENOMEM;
+ }
+
+ unlink->seqnum = atomic_inc_return(&the_controller->seqnum);
+ if (unlink->seqnum == 0xffff)
+ uinfo("seqnum max\n");
+
+ unlink->unlink_seqnum = priv->seqnum;
+
+ uinfo("vhci_hcd: device %p seems to be still connected\n",
+ vdev);
+
+ /* send cmd_unlink and try to cancel the pending URB in the
+ * peer */
+ list_add_tail(&unlink->list, &vdev->unlink_tx);
+ wake_up(&vdev->waitq_tx);
+
+ spin_unlock_irqrestore(&vdev->priv_lock, flags2);
+ }
+
+
+ /*
+ * If tcp connection is alive, we have sent CMD_UNLINK.
+ * vhci_rx will receive RET_UNLINK and give back the URB.
+ * Otherwise, we give back it here.
+ */
+ if (!vdev->ud.tcp_socket) {
+ /* tcp connection is closed */
+ uinfo("vhci_hcd: vhci_urb_dequeue() gives back urb %p\n", urb);
+
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+
+ spin_unlock_irqrestore(&the_controller->lock, flags);
+ usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
+ urb->status);
+ spin_lock_irqsave(&the_controller->lock, flags);
+ }
+
+ spin_unlock_irqrestore(&the_controller->lock, flags);
+
+ dbg_vhci_hc("leave\n");
+ return 0;
+}
+
+
+static void vhci_device_unlink_cleanup(struct vhci_device *vdev)
+{
+ struct vhci_unlink *unlink, *tmp;
+
+ spin_lock(&vdev->priv_lock);
+
+ list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {
+ list_del(&unlink->list);
+ kfree(unlink);
+ }
+
+ list_for_each_entry_safe(unlink, tmp, &vdev->unlink_rx, list) {
+ list_del(&unlink->list);
+ kfree(unlink);
+ }
+
+ spin_unlock(&vdev->priv_lock);
+}
+
+/*
+ * The important thing is that only one context begins cleanup.
+ * This is why error handling and cleanup become simple.
+ * We do not want to consider race condition as possible.
+ */
+static void vhci_shutdown_connection(struct usbip_device *ud)
+{
+ struct vhci_device *vdev = container_of(ud, struct vhci_device, ud);
+
+ /* need this? see stub_dev.c */
+ if (ud->tcp_socket) {
+ udbg("shutdown tcp_socket %p\n", ud->tcp_socket);
+ kernel_sock_shutdown(ud->tcp_socket, SHUT_RDWR);
+ }
+
+ usbip_stop_threads(&vdev->ud);
+ uinfo("stop threads\n");
+
+ /* active connection is closed */
+ if (vdev->ud.tcp_socket != NULL) {
+ sock_release(vdev->ud.tcp_socket);
+ vdev->ud.tcp_socket = NULL;
+ }
+ uinfo("release socket\n");
+
+ vhci_device_unlink_cleanup(vdev);
+
+ /*
+ * rh_port_disconnect() is a trigger of ...
+ * usb_disable_device():
+ * disable all the endpoints for a USB device.
+ * usb_disable_endpoint():
+ * disable endpoints. pending urbs are unlinked(dequeued).
+ *
+ * NOTE: After calling rh_port_disconnect(), the USB device drivers of a
+ * deteched device should release used urbs in a cleanup function(i.e.
+ * xxx_disconnect()). Therefore, vhci_hcd does not need to release
+ * pushed urbs and their private data in this function.
+ *
+ * NOTE: vhci_dequeue() must be considered carefully. When shutdowning
+ * a connection, vhci_shutdown_connection() expects vhci_dequeue()
+ * gives back pushed urbs and frees their private data by request of
+ * the cleanup function of a USB driver. When unlinking a urb with an
+ * active connection, vhci_dequeue() does not give back the urb which
+ * is actually given back by vhci_rx after receiving its return pdu.
+ *
+ */
+ rh_port_disconnect(vdev->rhport);
+
+ uinfo("disconnect device\n");
+}
+
+
+static void vhci_device_reset(struct usbip_device *ud)
+{
+ struct vhci_device *vdev = container_of(ud, struct vhci_device, ud);
+
+ spin_lock(&ud->lock);
+
+ vdev->speed = 0;
+ vdev->devid = 0;
+
+ ud->tcp_socket = NULL;
+
+ ud->status = VDEV_ST_NULL;
+
+ spin_unlock(&ud->lock);
+}
+
+static void vhci_device_unusable(struct usbip_device *ud)
+{
+ spin_lock(&ud->lock);
+
+ ud->status = VDEV_ST_ERROR;
+
+ spin_unlock(&ud->lock);
+}
+
+static void vhci_device_init(struct vhci_device *vdev)
+{
+ memset(vdev, 0, sizeof(*vdev));
+
+ usbip_task_init(&vdev->ud.tcp_rx, "vhci_rx", vhci_rx_loop);
+ usbip_task_init(&vdev->ud.tcp_tx, "vhci_tx", vhci_tx_loop);
+
+ vdev->ud.side = USBIP_VHCI;
+ vdev->ud.status = VDEV_ST_NULL;
+ /* vdev->ud.lock = SPIN_LOCK_UNLOCKED; */
+ spin_lock_init(&vdev->ud.lock);
+
+ INIT_LIST_HEAD(&vdev->priv_rx);
+ INIT_LIST_HEAD(&vdev->priv_tx);
+ INIT_LIST_HEAD(&vdev->unlink_tx);
+ INIT_LIST_HEAD(&vdev->unlink_rx);
+ /* vdev->priv_lock = SPIN_LOCK_UNLOCKED; */
+ spin_lock_init(&vdev->priv_lock);
+
+ init_waitqueue_head(&vdev->waitq_tx);
+
+ vdev->ud.eh_ops.shutdown = vhci_shutdown_connection;
+ vdev->ud.eh_ops.reset = vhci_device_reset;
+ vdev->ud.eh_ops.unusable = vhci_device_unusable;
+
+ usbip_start_eh(&vdev->ud);
+}
+
+
+/*----------------------------------------------------------------------*/
+
+static int vhci_start(struct usb_hcd *hcd)
+{
+ struct vhci_hcd *vhci = hcd_to_vhci(hcd);
+ int rhport;
+ int err = 0;
+
+ dbg_vhci_hc("enter vhci_start\n");
+
+
+ /* initialize private data of usb_hcd */
+
+ for (rhport = 0; rhport < VHCI_NPORTS; rhport++) {
+ struct vhci_device *vdev = &vhci->vdev[rhport];
+ vhci_device_init(vdev);
+ vdev->rhport = rhport;
+ }
+
+ atomic_set(&vhci->seqnum, 0);
+ spin_lock_init(&vhci->lock);
+
+
+
+ hcd->power_budget = 0; /* no limit */
+ hcd->state = HC_STATE_RUNNING;
+ hcd->uses_new_polling = 1;
+
+
+ /* vhci_hcd is now ready to be controlled through sysfs */
+ err = sysfs_create_group(&vhci_dev(vhci)->kobj, &dev_attr_group);
+ if (err) {
+ uerr("create sysfs files\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static void vhci_stop(struct usb_hcd *hcd)
+{
+ struct vhci_hcd *vhci = hcd_to_vhci(hcd);
+ int rhport = 0;
+
+ dbg_vhci_hc("stop VHCI controller\n");
+
+
+ /* 1. remove the userland interface of vhci_hcd */
+ sysfs_remove_group(&vhci_dev(vhci)->kobj, &dev_attr_group);
+
+ /* 2. shutdown all the ports of vhci_hcd */
+ for (rhport = 0 ; rhport < VHCI_NPORTS; rhport++) {
+ struct vhci_device *vdev = &vhci->vdev[rhport];
+
+ usbip_event_add(&vdev->ud, VDEV_EVENT_REMOVED);
+ usbip_stop_eh(&vdev->ud);
+ }
+
+
+ uinfo("vhci_stop done\n");
+}
+
+/*----------------------------------------------------------------------*/
+
+static int vhci_get_frame_number(struct usb_hcd *hcd)
+{
+ uerr("Not yet implemented\n");
+ return 0;
+}
+
+
+#ifdef CONFIG_PM
+
+/* FIXME: suspend/resume */
+static int vhci_bus_suspend(struct usb_hcd *hcd)
+{
+ struct vhci_hcd *vhci = hcd_to_vhci(hcd);
+
+ dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__);
+
+ spin_lock_irq(&vhci->lock);
+ /* vhci->rh_state = DUMMY_RH_SUSPENDED;
+ * set_link_state(vhci); */
+ hcd->state = HC_STATE_SUSPENDED;
+ spin_unlock_irq(&vhci->lock);
+
+ return 0;
+}
+
+static int vhci_bus_resume(struct usb_hcd *hcd)
+{
+ struct vhci_hcd *vhci = hcd_to_vhci(hcd);
+ int rc = 0;
+
+ dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__);
+
+ spin_lock_irq(&vhci->lock);
+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
+ rc = -ESHUTDOWN;
+ } else {
+ /* vhci->rh_state = DUMMY_RH_RUNNING;
+ * set_link_state(vhci);
+ * if (!list_empty(&vhci->urbp_list))
+ * mod_timer(&vhci->timer, jiffies); */
+ hcd->state = HC_STATE_RUNNING;
+ }
+ spin_unlock_irq(&vhci->lock);
+ return rc;
+
+ return 0;
+}
+
+#else
+
+#define vhci_bus_suspend NULL
+#define vhci_bus_resume NULL
+#endif
+
+
+
+static struct hc_driver vhci_hc_driver = {
+ .description = driver_name,
+ .product_desc = driver_desc,
+ .hcd_priv_size = sizeof(struct vhci_hcd),
+
+ .flags = HCD_USB2,
+
+ .start = vhci_start,
+ .stop = vhci_stop,
+
+ .urb_enqueue = vhci_urb_enqueue,
+ .urb_dequeue = vhci_urb_dequeue,
+
+ .get_frame_number = vhci_get_frame_number,
+
+ .hub_status_data = vhci_hub_status,
+ .hub_control = vhci_hub_control,
+ .bus_suspend = vhci_bus_suspend,
+ .bus_resume = vhci_bus_resume,
+};
+
+static int vhci_hcd_probe(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd;
+ int ret;
+
+ uinfo("proving...\n");
+
+ dbg_vhci_hc("name %s id %d\n", pdev->name, pdev->id);
+
+ /* will be removed */
+ if (pdev->dev.dma_mask) {
+ dev_info(&pdev->dev, "vhci_hcd DMA not supported\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Allocate and initialize hcd.
+ * Our private data is also allocated automatically.
+ */
+ hcd = usb_create_hcd(&vhci_hc_driver, &pdev->dev, pdev->dev.bus_id);
+ if (!hcd) {
+ uerr("create hcd failed\n");
+ return -ENOMEM;
+ }
+
+
+ /* this is private data for vhci_hcd */
+ the_controller = hcd_to_vhci(hcd);
+
+ /*
+ * Finish generic HCD structure initialization and register.
+ * Call the driver's reset() and start() routines.
+ */
+ ret = usb_add_hcd(hcd, 0, 0);
+ if (ret != 0) {
+ uerr("usb_add_hcd failed %d\n", ret);
+ usb_put_hcd(hcd);
+ the_controller = NULL;
+ return ret;
+ }
+
+
+ dbg_vhci_hc("bye\n");
+ return 0;
+}
+
+
+static int vhci_hcd_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd;
+
+ hcd = platform_get_drvdata(pdev);
+ if (!hcd)
+ return 0;
+
+ /*
+ * Disconnects the root hub,
+ * then reverses the effects of usb_add_hcd(),
+ * invoking the HCD's stop() methods.
+ */
+ usb_remove_hcd(hcd);
+ usb_put_hcd(hcd);
+ the_controller = NULL;
+
+
+ return 0;
+}
+
+
+
+#ifdef CONFIG_PM
+
+/* what should happen for USB/IP under suspend/resume? */
+static int vhci_hcd_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct usb_hcd *hcd;
+ int rhport = 0;
+ int connected = 0;
+ int ret = 0;
+
+ dev_dbg(&pdev->dev, "%s\n", __func__);
+
+ hcd = platform_get_drvdata(pdev);
+
+ spin_lock(&the_controller->lock);
+
+ for (rhport = 0; rhport < VHCI_NPORTS; rhport++)
+ if (the_controller->port_status[rhport] &
+ USB_PORT_STAT_CONNECTION)
+ connected += 1;
+
+ spin_unlock(&the_controller->lock);
+
+ if (connected > 0) {
+ uinfo("We have %d active connection%s. Do not suspend.\n",
+ connected, (connected == 1 ? "" : "s"));
+ ret = -EBUSY;
+ } else {
+ uinfo("suspend vhci_hcd");
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ }
+
+ return ret;
+}
+
+static int vhci_hcd_resume(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd;
+
+ dev_dbg(&pdev->dev, "%s\n", __func__);
+
+ hcd = platform_get_drvdata(pdev);
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ usb_hcd_poll_rh_status(hcd);
+
+ return 0;
+}
+
+#else
+
+#define vhci_hcd_suspend NULL
+#define vhci_hcd_resume NULL
+
+#endif
+
+
+static struct platform_driver vhci_driver = {
+ .probe = vhci_hcd_probe,
+ .remove = __devexit_p(vhci_hcd_remove),
+ .suspend = vhci_hcd_suspend,
+ .resume = vhci_hcd_resume,
+ .driver = {
+ .name = (char *) driver_name,
+ .owner = THIS_MODULE,
+ },
+};
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * The VHCI 'device' is 'virtual'; not a real plug&play hardware.
+ * We need to add this virtual device as a platform device arbitrarily:
+ * 1. platform_device_register()
+ */
+static void the_pdev_release(struct device *dev)
+{
+ return;
+}
+
+static struct platform_device the_pdev = {
+ /* should be the same name as driver_name */
+ .name = (char *) driver_name,
+ .id = -1,
+ .dev = {
+ /* .driver = &vhci_driver, */
+ .release = the_pdev_release,
+ },
+};
+
+static int __init vhci_init(void)
+{
+ int ret;
+
+ dbg_vhci_hc("enter\n");
+ if (usb_disabled())
+ return -ENODEV;
+
+ printk(KERN_INFO KBUILD_MODNAME ": %s, %s\n", driver_name,
+ DRIVER_VERSION);
+
+ ret = platform_driver_register(&vhci_driver);
+ if (ret < 0)
+ goto err_driver_register;
+
+ ret = platform_device_register(&the_pdev);
+ if (ret < 0)
+ goto err_platform_device_register;
+
+ dbg_vhci_hc("bye\n");
+ return ret;
+
+ /* error occurred */
+err_platform_device_register:
+ platform_driver_unregister(&vhci_driver);
+
+err_driver_register:
+ dbg_vhci_hc("bye\n");
+ return ret;
+}
+module_init(vhci_init);
+
+static void __exit vhci_cleanup(void)
+{
+ dbg_vhci_hc("enter\n");
+
+ platform_device_unregister(&the_pdev);
+ platform_driver_unregister(&vhci_driver);
+
+ dbg_vhci_hc("bye\n");
+}
+module_exit(vhci_cleanup);
diff --git a/drivers/staging/usbip/vhci_rx.c b/drivers/staging/usbip/vhci_rx.c
new file mode 100644
index 0000000..933ccaf
--- /dev/null
+++ b/drivers/staging/usbip/vhci_rx.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
+ *
+ * This 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 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include "usbip_common.h"
+#include "vhci.h"
+
+
+/* get URB from transmitted urb queue */
+static struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev,
+ __u32 seqnum)
+{
+ struct vhci_priv *priv, *tmp;
+ struct urb *urb = NULL;
+ int status;
+
+ spin_lock(&vdev->priv_lock);
+
+ list_for_each_entry_safe(priv, tmp, &vdev->priv_rx, list) {
+ if (priv->seqnum == seqnum) {
+ urb = priv->urb;
+ status = urb->status;
+
+ dbg_vhci_rx("find urb %p vurb %p seqnum %u\n",
+ urb, priv, seqnum);
+
+ /* TODO: fix logic here to improve indent situtation */
+ if (status != -EINPROGRESS) {
+ if (status == -ENOENT ||
+ status == -ECONNRESET)
+ dev_info(&urb->dev->dev,
+ "urb %p was unlinked "
+ "%ssynchronuously.\n", urb,
+ status == -ENOENT ? "" : "a");
+ else
+ dev_info(&urb->dev->dev,
+ "urb %p may be in a error, "
+ "status %d\n", urb, status);
+ }
+
+ list_del(&priv->list);
+ kfree(priv);
+ urb->hcpriv = NULL;
+
+ break;
+ }
+ }
+
+ spin_unlock(&vdev->priv_lock);
+
+ return urb;
+}
+
+static void vhci_recv_ret_submit(struct vhci_device *vdev,
+ struct usbip_header *pdu)
+{
+ struct usbip_device *ud = &vdev->ud;
+ struct urb *urb;
+
+
+ urb = pickup_urb_and_free_priv(vdev, pdu->base.seqnum);
+
+
+ if (!urb) {
+ uerr("cannot find a urb of seqnum %u\n", pdu->base.seqnum);
+ uinfo("max seqnum %d\n", atomic_read(&the_controller->seqnum));
+ usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
+ return;
+ }
+
+
+ /* unpack the pdu to a urb */
+ usbip_pack_pdu(pdu, urb, USBIP_RET_SUBMIT, 0);
+
+
+ /* recv transfer buffer */
+ if (usbip_recv_xbuff(ud, urb) < 0)
+ return;
+
+
+ /* recv iso_packet_descriptor */
+ if (usbip_recv_iso(ud, urb) < 0)
+ return;
+
+
+ if (dbg_flag_vhci_rx)
+ usbip_dump_urb(urb);
+
+
+ dbg_vhci_rx("now giveback urb %p\n", urb);
+
+ spin_lock(&the_controller->lock);
+ usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb);
+ spin_unlock(&the_controller->lock);
+
+ usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status);
+
+
+ dbg_vhci_rx("Leave\n");
+
+ return;
+}
+
+
+static struct vhci_unlink *dequeue_pending_unlink(struct vhci_device *vdev,
+ struct usbip_header *pdu)
+{
+ struct vhci_unlink *unlink, *tmp;
+
+ spin_lock(&vdev->priv_lock);
+
+ list_for_each_entry_safe(unlink, tmp, &vdev->unlink_rx, list) {
+ uinfo("unlink->seqnum %lu\n", unlink->seqnum);
+ if (unlink->seqnum == pdu->base.seqnum) {
+ dbg_vhci_rx("found pending unlink, %lu\n",
+ unlink->seqnum);
+ list_del(&unlink->list);
+
+ spin_unlock(&vdev->priv_lock);
+ return unlink;
+ }
+ }
+
+ spin_unlock(&vdev->priv_lock);
+
+ return NULL;
+}
+
+
+static void vhci_recv_ret_unlink(struct vhci_device *vdev,
+ struct usbip_header *pdu)
+{
+ struct vhci_unlink *unlink;
+ struct urb *urb;
+
+ usbip_dump_header(pdu);
+
+ unlink = dequeue_pending_unlink(vdev, pdu);
+ if (!unlink) {
+ uinfo("cannot find the pending unlink %u\n", pdu->base.seqnum);
+ return;
+ }
+
+ urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum);
+ if (!urb) {
+ /*
+ * I get the result of a unlink request. But, it seems that I
+ * already received the result of its submit result and gave
+ * back the URB.
+ */
+ uinfo("the urb (seqnum %d) was already given backed\n",
+ pdu->base.seqnum);
+ } else {
+ dbg_vhci_rx("now giveback urb %p\n", urb);
+
+ /* If unlink is succeed, status is -ECONNRESET */
+ urb->status = pdu->u.ret_unlink.status;
+ uinfo("%d\n", urb->status);
+
+ spin_lock(&the_controller->lock);
+ usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb);
+ spin_unlock(&the_controller->lock);
+
+ usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb,
+ urb->status);
+ }
+
+ kfree(unlink);
+
+ return;
+}
+
+/* recv a pdu */
+static void vhci_rx_pdu(struct usbip_device *ud)
+{
+ int ret;
+ struct usbip_header pdu;
+ struct vhci_device *vdev = container_of(ud, struct vhci_device, ud);
+
+
+ dbg_vhci_rx("Enter\n");
+
+ memset(&pdu, 0, sizeof(pdu));
+
+
+ /* 1. receive a pdu header */
+ ret = usbip_xmit(0, ud->tcp_socket, (char *) &pdu, sizeof(pdu), 0);
+ if (ret != sizeof(pdu)) {
+ uerr("receiving pdu failed! size is %d, should be %d\n",
+ ret, sizeof(pdu));
+ usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
+ return;
+ }
+
+ usbip_header_correct_endian(&pdu, 0);
+
+ if (dbg_flag_vhci_rx)
+ usbip_dump_header(&pdu);
+
+ switch (pdu.base.command) {
+ case USBIP_RET_SUBMIT:
+ vhci_recv_ret_submit(vdev, &pdu);
+ break;
+ case USBIP_RET_UNLINK:
+ vhci_recv_ret_unlink(vdev, &pdu);
+ break;
+ default:
+ /* NOTREACHED */
+ uerr("unknown pdu %u\n", pdu.base.command);
+ usbip_dump_header(&pdu);
+ usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
+ }
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+void vhci_rx_loop(struct usbip_task *ut)
+{
+ struct usbip_device *ud = container_of(ut, struct usbip_device, tcp_rx);
+
+
+ while (1) {
+ if (signal_pending(current)) {
+ dbg_vhci_rx("signal catched!\n");
+ break;
+ }
+
+
+ if (usbip_event_happend(ud))
+ break;
+
+ vhci_rx_pdu(ud);
+ }
+}
+
diff --git a/drivers/staging/usbip/vhci_sysfs.c b/drivers/staging/usbip/vhci_sysfs.c
new file mode 100644
index 0000000..24c2851
--- /dev/null
+++ b/drivers/staging/usbip/vhci_sysfs.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
+ *
+ * This 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 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include "usbip_common.h"
+#include "vhci.h"
+
+#include <linux/in.h>
+
+/* TODO: refine locking ?*/
+
+/* Sysfs entry to show port status */
+static ssize_t show_status(struct device *dev, struct device_attribute *attr,
+ char *out)
+{
+ char *s = out;
+ int i = 0;
+
+ if (!the_controller || !out)
+ BUG();
+
+ spin_lock(&the_controller->lock);
+
+ /*
+ * output example:
+ * prt sta spd dev socket local_busid
+ * 000 004 000 000 c5a7bb80 1-2.3
+ * 001 004 000 000 d8cee980 2-3.4
+ *
+ * IP address can be retrieved from a socket pointer address by looking
+ * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a
+ * port number and its peer IP address.
+ */
+ out += sprintf(out, "prt sta spd bus dev socket "
+ "local_busid\n");
+
+ for (i = 0; i < VHCI_NPORTS; i++) {
+ struct vhci_device *vdev = port_to_vdev(i);
+
+ spin_lock(&vdev->ud.lock);
+
+ out += sprintf(out, "%03u %03u ", i, vdev->ud.status);
+
+ if (vdev->ud.status == VDEV_ST_USED) {
+ out += sprintf(out, "%03u %08x ",
+ vdev->speed, vdev->devid);
+ out += sprintf(out, "%16p ", vdev->ud.tcp_socket);
+ out += sprintf(out, "%s", vdev->udev->dev.bus_id);
+
+ } else
+ out += sprintf(out, "000 000 000 0000000000000000 0-0");
+
+ out += sprintf(out, "\n");
+
+ spin_unlock(&vdev->ud.lock);
+ }
+
+ spin_unlock(&the_controller->lock);
+
+ return out - s;
+}
+static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
+
+/* Sysfs entry to shutdown a virtual connection */
+static int vhci_port_disconnect(__u32 rhport)
+{
+ struct vhci_device *vdev;
+
+ dbg_vhci_sysfs("enter\n");
+
+ /* lock */
+ spin_lock(&the_controller->lock);
+
+ vdev = port_to_vdev(rhport);
+
+ spin_lock(&vdev->ud.lock);
+ if (vdev->ud.status == VDEV_ST_NULL) {
+ uerr("not connected %d\n", vdev->ud.status);
+
+ /* unlock */
+ spin_unlock(&vdev->ud.lock);
+ spin_unlock(&the_controller->lock);
+
+ return -EINVAL;
+ }
+
+ /* unlock */
+ spin_unlock(&vdev->ud.lock);
+ spin_unlock(&the_controller->lock);
+
+ usbip_event_add(&vdev->ud, VDEV_EVENT_DOWN);
+
+ return 0;
+}
+
+static ssize_t store_detach(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int err;
+ __u32 rhport = 0;
+
+ sscanf(buf, "%u", &rhport);
+
+ /* check rhport */
+ if (rhport >= VHCI_NPORTS) {
+ uerr("invalid port %u\n", rhport);
+ return -EINVAL;
+ }
+
+ err = vhci_port_disconnect(rhport);
+ if (err < 0)
+ return -EINVAL;
+
+ dbg_vhci_sysfs("Leave\n");
+ return count;
+}
+static DEVICE_ATTR(detach, S_IWUSR, NULL, store_detach);
+
+/* Sysfs entry to establish a virtual connection */
+static int valid_args(__u32 rhport, enum usb_device_speed speed)
+{
+ /* check rhport */
+ if ((rhport < 0) || (rhport >= VHCI_NPORTS)) {
+ uerr("port %u\n", rhport);
+ return -EINVAL;
+ }
+
+ /* check speed */
+ switch (speed) {
+ case USB_SPEED_LOW:
+ case USB_SPEED_FULL:
+ case USB_SPEED_HIGH:
+ case USB_SPEED_VARIABLE:
+ break;
+ default:
+ uerr("speed %d\n", speed);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * To start a new USB/IP attachment, a userland program needs to setup a TCP
+ * connection and then write its socket descriptor with remote device
+ * information into this sysfs file.
+ *
+ * A remote device is virtually attached to the root-hub port of @rhport with
+ * @speed. @devid is embedded into a request to specify the remote device in a
+ * server host.
+ *
+ * write() returns 0 on success, else negative errno.
+ */
+static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct vhci_device *vdev;
+ struct socket *socket;
+ int sockfd = 0;
+ __u32 rhport = 0, devid = 0, speed = 0;
+
+ /*
+ * @rhport: port number of vhci_hcd
+ * @sockfd: socket descriptor of an established TCP connection
+ * @devid: unique device identifier in a remote host
+ * @speed: usb device speed in a remote host
+ */
+ sscanf(buf, "%u %u %u %u", &rhport, &sockfd, &devid, &speed);
+
+ dbg_vhci_sysfs("rhport(%u) sockfd(%u) devid(%u) speed(%u)\n",
+ rhport, sockfd, devid, speed);
+
+
+ /* check received parameters */
+ if (valid_args(rhport, speed) < 0)
+ return -EINVAL;
+
+ /* check sockfd */
+ socket = sockfd_to_socket(sockfd);
+ if (!socket)
+ return -EINVAL;
+
+ /* now need lock until setting vdev status as used */
+
+ /* begin a lock */
+ spin_lock(&the_controller->lock);
+
+ vdev = port_to_vdev(rhport);
+
+ spin_lock(&vdev->ud.lock);
+
+ if (vdev->ud.status != VDEV_ST_NULL) {
+ /* end of the lock */
+ spin_unlock(&vdev->ud.lock);
+ spin_unlock(&the_controller->lock);
+
+ uerr("port %d already used\n", rhport);
+ return -EINVAL;
+ }
+
+ uinfo("rhport(%u) sockfd(%d) devid(%u) speed(%u)\n",
+ rhport, sockfd, devid, speed);
+
+ vdev->devid = devid;
+ vdev->speed = speed;
+ vdev->ud.tcp_socket = socket;
+ vdev->ud.status = VDEV_ST_NOTASSIGNED;
+
+ spin_unlock(&vdev->ud.lock);
+ spin_unlock(&the_controller->lock);
+ /* end the lock */
+
+ /*
+ * this function will sleep, so should be out of the lock. but, it's ok
+ * because we already marked vdev as being used. really?
+ */
+ usbip_start_threads(&vdev->ud);
+
+ rh_port_connect(rhport, speed);
+
+ return count;
+}
+static DEVICE_ATTR(attach, S_IWUSR, NULL, store_attach);
+
+static struct attribute *dev_attrs[] = {
+ &dev_attr_status.attr,
+ &dev_attr_detach.attr,
+ &dev_attr_attach.attr,
+ &dev_attr_usbip_debug.attr,
+ NULL,
+};
+
+struct attribute_group dev_attr_group = {
+ .attrs = dev_attrs,
+};
diff --git a/drivers/staging/usbip/vhci_tx.c b/drivers/staging/usbip/vhci_tx.c
new file mode 100644
index 0000000..1f552a9
--- /dev/null
+++ b/drivers/staging/usbip/vhci_tx.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
+ *
+ * This 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 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include "usbip_common.h"
+#include "vhci.h"
+
+
+static void setup_cmd_submit_pdu(struct usbip_header *pdup, struct urb *urb)
+{
+ struct vhci_priv *priv = ((struct vhci_priv *)urb->hcpriv);
+ struct vhci_device *vdev = priv->vdev;
+
+ dbg_vhci_tx("URB, local devnum %u, remote devid %u\n",
+ usb_pipedevice(urb->pipe), vdev->devid);
+
+ pdup->base.command = USBIP_CMD_SUBMIT;
+ pdup->base.seqnum = priv->seqnum;
+ pdup->base.devid = vdev->devid;
+ if (usb_pipein(urb->pipe))
+ pdup->base.direction = USBIP_DIR_IN;
+ else
+ pdup->base.direction = USBIP_DIR_OUT;
+ pdup->base.ep = usb_pipeendpoint(urb->pipe);
+
+ usbip_pack_pdu(pdup, urb, USBIP_CMD_SUBMIT, 1);
+
+ if (urb->setup_packet)
+ memcpy(pdup->u.cmd_submit.setup, urb->setup_packet, 8);
+}
+
+static struct vhci_priv *dequeue_from_priv_tx(struct vhci_device *vdev)
+{
+ unsigned long flags;
+ struct vhci_priv *priv, *tmp;
+
+ spin_lock_irqsave(&vdev->priv_lock, flags);
+
+ list_for_each_entry_safe(priv, tmp, &vdev->priv_tx, list) {
+ list_move_tail(&priv->list, &vdev->priv_rx);
+ spin_unlock_irqrestore(&vdev->priv_lock, flags);
+ return priv;
+ }
+
+ spin_unlock_irqrestore(&vdev->priv_lock, flags);
+
+ return NULL;
+}
+
+
+
+static int vhci_send_cmd_submit(struct vhci_device *vdev)
+{
+ struct vhci_priv *priv = NULL;
+
+ struct msghdr msg;
+ struct kvec iov[3];
+ size_t txsize;
+
+ size_t total_size = 0;
+
+ while ((priv = dequeue_from_priv_tx(vdev)) != NULL) {
+ int ret;
+ struct urb *urb = priv->urb;
+ struct usbip_header pdu_header;
+ void *iso_buffer = NULL;
+
+ txsize = 0;
+ memset(&pdu_header, 0, sizeof(pdu_header));
+ memset(&msg, 0, sizeof(msg));
+ memset(&iov, 0, sizeof(iov));
+
+ dbg_vhci_tx("setup txdata urb %p\n", urb);
+
+
+ /* 1. setup usbip_header */
+ setup_cmd_submit_pdu(&pdu_header, urb);
+ usbip_header_correct_endian(&pdu_header, 1);
+
+ iov[0].iov_base = &pdu_header;
+ iov[0].iov_len = sizeof(pdu_header);
+ txsize += sizeof(pdu_header);
+
+ /* 2. setup transfer buffer */
+ if (!usb_pipein(urb->pipe) && urb->transfer_buffer_length > 0) {
+ iov[1].iov_base = urb->transfer_buffer;
+ iov[1].iov_len = urb->transfer_buffer_length;
+ txsize += urb->transfer_buffer_length;
+ }
+
+ /* 3. setup iso_packet_descriptor */
+ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+ ssize_t len = 0;
+
+ iso_buffer = usbip_alloc_iso_desc_pdu(urb, &len);
+ if (!iso_buffer) {
+ usbip_event_add(&vdev->ud,
+ SDEV_EVENT_ERROR_MALLOC);
+ return -1;
+ }
+
+ iov[2].iov_base = iso_buffer;
+ iov[2].iov_len = len;
+ txsize += len;
+ }
+
+ ret = kernel_sendmsg(vdev->ud.tcp_socket, &msg, iov, 3, txsize);
+ if (ret != txsize) {
+ uerr("sendmsg failed!, retval %d for %zd\n", ret,
+ txsize);
+ kfree(iso_buffer);
+ usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_TCP);
+ return -1;
+ }
+
+ kfree(iso_buffer);
+ dbg_vhci_tx("send txdata\n");
+
+ total_size += txsize;
+ }
+
+ return total_size;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static struct vhci_unlink *dequeue_from_unlink_tx(struct vhci_device *vdev)
+{
+ unsigned long flags;
+ struct vhci_unlink *unlink, *tmp;
+
+ spin_lock_irqsave(&vdev->priv_lock, flags);
+
+ list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {
+ list_move_tail(&unlink->list, &vdev->unlink_rx);
+ spin_unlock_irqrestore(&vdev->priv_lock, flags);
+ return unlink;
+ }
+
+ spin_unlock_irqrestore(&vdev->priv_lock, flags);
+
+ return NULL;
+}
+
+static int vhci_send_cmd_unlink(struct vhci_device *vdev)
+{
+ struct vhci_unlink *unlink = NULL;
+
+ struct msghdr msg;
+ struct kvec iov[3];
+ size_t txsize;
+
+ size_t total_size = 0;
+
+ while ((unlink = dequeue_from_unlink_tx(vdev)) != NULL) {
+ int ret;
+ struct usbip_header pdu_header;
+
+ txsize = 0;
+ memset(&pdu_header, 0, sizeof(pdu_header));
+ memset(&msg, 0, sizeof(msg));
+ memset(&iov, 0, sizeof(iov));
+
+ dbg_vhci_tx("setup cmd unlink, %lu \n", unlink->seqnum);
+
+
+ /* 1. setup usbip_header */
+ pdu_header.base.command = USBIP_CMD_UNLINK;
+ pdu_header.base.seqnum = unlink->seqnum;
+ pdu_header.base.devid = vdev->devid;
+ pdu_header.base.ep = 0;
+ pdu_header.u.cmd_unlink.seqnum = unlink->unlink_seqnum;
+
+ usbip_header_correct_endian(&pdu_header, 1);
+
+ iov[0].iov_base = &pdu_header;
+ iov[0].iov_len = sizeof(pdu_header);
+ txsize += sizeof(pdu_header);
+
+ ret = kernel_sendmsg(vdev->ud.tcp_socket, &msg, iov, 1, txsize);
+ if (ret != txsize) {
+ uerr("sendmsg failed!, retval %d for %zd\n", ret,
+ txsize);
+ usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_TCP);
+ return -1;
+ }
+
+
+ dbg_vhci_tx("send txdata\n");
+
+ total_size += txsize;
+ }
+
+ return total_size;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+void vhci_tx_loop(struct usbip_task *ut)
+{
+ struct usbip_device *ud = container_of(ut, struct usbip_device, tcp_tx);
+ struct vhci_device *vdev = container_of(ud, struct vhci_device, ud);
+
+ while (1) {
+ if (signal_pending(current)) {
+ uinfo("vhci_tx signal catched\n");
+ break;
+ }
+
+ if (vhci_send_cmd_submit(vdev) < 0)
+ break;
+
+ if (vhci_send_cmd_unlink(vdev) < 0)
+ break;
+
+ wait_event_interruptible(vdev->waitq_tx,
+ (!list_empty(&vdev->priv_tx) ||
+ !list_empty(&vdev->unlink_tx)));
+
+ dbg_vhci_tx("pending urbs ?, now wake up\n");
+ }
+}
--
1.6.0.2
^ permalink raw reply related [flat|nested] 37+ messages in thread* [PATCH 13/23] Staging: USB/IP: add host driver
2008-10-10 22:41 [GIT PATCH] STAGING patches for 2.6.28 Greg KH
` (8 preceding siblings ...)
2008-10-10 22:42 ` [PATCH 12/23] Staging: USB/IP: add client driver Greg KH
@ 2008-10-10 22:42 ` Greg KH
2008-10-10 22:42 ` [PATCH 14/23] Staging: add w35und wifi driver Greg KH
` (9 subsequent siblings)
19 siblings, 0 replies; 37+ messages in thread
From: Greg KH @ 2008-10-10 22:42 UTC (permalink / raw)
To: linux-kernel; +Cc: Takahiro Hirofuchi, Brian G. Merrell, Greg Kroah-Hartman
From: Takahiro Hirofuchi <hirofuchi@users.sourceforge.net>
This adds the USB IP client driver
Brian Merrell cleaned up a lot of this code and submitted it for
inclusion. Greg also did a lot of cleanup.
Signed-off-by: Brian G. Merrell <bgmerrell@novell.com>
Cc: Takahiro Hirofuchi <hirofuchi@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/usbip/Kconfig | 11 +
drivers/staging/usbip/Makefile | 3 +
drivers/staging/usbip/stub.h | 95 ++++++
drivers/staging/usbip/stub_dev.c | 483 +++++++++++++++++++++++++++++
drivers/staging/usbip/stub_main.c | 300 ++++++++++++++++++
drivers/staging/usbip/stub_rx.c | 615 +++++++++++++++++++++++++++++++++++++
drivers/staging/usbip/stub_tx.c | 371 ++++++++++++++++++++++
7 files changed, 1878 insertions(+), 0 deletions(-)
create mode 100644 drivers/staging/usbip/stub.h
create mode 100644 drivers/staging/usbip/stub_dev.c
create mode 100644 drivers/staging/usbip/stub_main.c
create mode 100644 drivers/staging/usbip/stub_rx.c
create mode 100644 drivers/staging/usbip/stub_tx.c
diff --git a/drivers/staging/usbip/Kconfig b/drivers/staging/usbip/Kconfig
index c4d68e1..7426235 100644
--- a/drivers/staging/usbip/Kconfig
+++ b/drivers/staging/usbip/Kconfig
@@ -23,3 +23,14 @@ config USB_IP_VHCI_HCD
To compile this driver as a module, choose M here: the
module will be called vhci_hcd.
+
+config USB_IP_HOST
+ tristate "USB IP host driver"
+ depends on USB_IP_COMMON
+ default N
+ ---help---
+ This enables the USB IP device driver which will run on the
+ host machine.
+
+ To compile this driver as a module, choose M here: the
+ module will be called usbip.
diff --git a/drivers/staging/usbip/Makefile b/drivers/staging/usbip/Makefile
index 6ef4c39..179f421 100644
--- a/drivers/staging/usbip/Makefile
+++ b/drivers/staging/usbip/Makefile
@@ -4,6 +4,9 @@ usbip_common_mod-objs := usbip_common.o usbip_event.o
obj-$(CONFIG_USB_IP_VHCI_HCD) += vhci-hcd.o
vhci-hcd-objs := vhci_sysfs.o vhci_tx.o vhci_rx.o vhci_hcd.o
+obj-$(CONFIG_USB_IP_HOST) += usbip.o
+usbip-objs := stub_dev.o stub_main.o stub_rx.o stub_tx.o
+
ifeq ($(CONFIG_USB_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
endif
diff --git a/drivers/staging/usbip/stub.h b/drivers/staging/usbip/stub.h
new file mode 100644
index 0000000..f541a3a
--- /dev/null
+++ b/drivers/staging/usbip/stub.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
+ *
+ * This 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 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/net.h>
+
+struct stub_device {
+ struct usb_interface *interface;
+ struct list_head list;
+
+ struct usbip_device ud;
+ __u32 devid;
+
+ /*
+ * stub_priv preserves private data of each urb.
+ * It is allocated as stub_priv_cache and assigned to urb->context.
+ *
+ * stub_priv is always linked to any one of 3 lists;
+ * priv_init: linked to this until the comletion of a urb.
+ * priv_tx : linked to this after the completion of a urb.
+ * priv_free: linked to this after the sending of the result.
+ *
+ * Any of these list operations should be locked by priv_lock.
+ */
+ spinlock_t priv_lock;
+ struct list_head priv_init;
+ struct list_head priv_tx;
+ struct list_head priv_free;
+
+ /* see comments for unlinking in stub_rx.c */
+ struct list_head unlink_tx;
+ struct list_head unlink_free;
+
+
+ wait_queue_head_t tx_waitq;
+};
+
+/* private data into urb->priv */
+struct stub_priv {
+ unsigned long seqnum;
+ struct list_head list;
+ struct stub_device *sdev;
+ struct urb *urb;
+
+ int unlinking;
+};
+
+struct stub_unlink {
+ unsigned long seqnum;
+ struct list_head list;
+ __u32 status;
+};
+
+
+extern struct kmem_cache *stub_priv_cache;
+
+
+/*-------------------------------------------------------------------------*/
+/* prototype declarations */
+
+/* stub_tx.c */
+void stub_complete(struct urb *);
+void stub_tx_loop(struct usbip_task *);
+
+/* stub_dev.c */
+extern struct usb_driver stub_driver;
+
+/* stub_rx.c */
+void stub_rx_loop(struct usbip_task *);
+void stub_enqueue_ret_unlink(struct stub_device *, __u32, __u32);
+
+/* stub_main.c */
+int match_busid(char *busid);
+void stub_device_cleanup_urbs(struct stub_device *sdev);
diff --git a/drivers/staging/usbip/stub_dev.c b/drivers/staging/usbip/stub_dev.c
new file mode 100644
index 0000000..ee455a0
--- /dev/null
+++ b/drivers/staging/usbip/stub_dev.c
@@ -0,0 +1,483 @@
+/*
+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
+ *
+ * This 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 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include "usbip_common.h"
+#include "stub.h"
+
+
+
+static int stub_probe(struct usb_interface *interface,
+ const struct usb_device_id *id);
+static void stub_disconnect(struct usb_interface *interface);
+
+
+/*
+ * Define device IDs here if you want to explicitly limit exportable devices.
+ * In the most cases, wild card matching will be ok because driver binding can
+ * be changed dynamically by a userland program.
+ */
+static struct usb_device_id stub_table[] = {
+#if 0
+ /* just an example */
+ { USB_DEVICE(0x05ac, 0x0301) }, /* Mac 1 button mouse */
+ { USB_DEVICE(0x0430, 0x0009) }, /* Plat Home Keyboard */
+ { USB_DEVICE(0x059b, 0x0001) }, /* Iomega USB Zip 100 */
+ { USB_DEVICE(0x04b3, 0x4427) }, /* IBM USB CD-ROM */
+ { USB_DEVICE(0x05a9, 0xa511) }, /* LifeView USB cam */
+ { USB_DEVICE(0x55aa, 0x0201) }, /* Imation card reader */
+ { USB_DEVICE(0x046d, 0x0870) }, /* Qcam Express(QV-30) */
+ { USB_DEVICE(0x04bb, 0x0101) }, /* IO-DATA HD 120GB */
+ { USB_DEVICE(0x04bb, 0x0904) }, /* IO-DATA USB-ET/TX */
+ { USB_DEVICE(0x04bb, 0x0201) }, /* IO-DATA USB-ET/TX */
+ { USB_DEVICE(0x08bb, 0x2702) }, /* ONKYO USB Speaker */
+ { USB_DEVICE(0x046d, 0x08b2) }, /* Logicool Qcam 4000 Pro */
+#endif
+ /* magic for wild card */
+ { .driver_info = 1 },
+ { 0, } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, stub_table);
+
+struct usb_driver stub_driver = {
+ .name = "usbip",
+ .probe = stub_probe,
+ .disconnect = stub_disconnect,
+ .id_table = stub_table,
+};
+
+
+/*-------------------------------------------------------------------------*/
+
+/* Define sysfs entries for a usbip-bound device */
+
+
+/*
+ * usbip_status shows status of usbip as long as this driver is bound to the
+ * target device.
+ */
+static ssize_t show_status(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct stub_device *sdev = dev_get_drvdata(dev);
+ int status;
+
+ if (!sdev) {
+ dev_err(dev, "sdev is null\n");
+ return -ENODEV;
+ }
+
+ spin_lock(&sdev->ud.lock);
+ status = sdev->ud.status;
+ spin_unlock(&sdev->ud.lock);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", status);
+}
+static DEVICE_ATTR(usbip_status, S_IRUGO, show_status, NULL);
+
+/*
+ * usbip_sockfd gets a socket descriptor of an established TCP connection that
+ * is used to transfer usbip requests by kernel threads. -1 is a magic number
+ * by which usbip connection is finished.
+ */
+static ssize_t store_sockfd(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct stub_device *sdev = dev_get_drvdata(dev);
+ int sockfd = 0;
+ struct socket *socket;
+
+ if (!sdev) {
+ dev_err(dev, "sdev is null\n");
+ return -ENODEV;
+ }
+
+ sscanf(buf, "%d", &sockfd);
+
+ if (sockfd != -1) {
+ dev_info(dev, "stub up\n");
+
+ spin_lock(&sdev->ud.lock);
+
+ if (sdev->ud.status != SDEV_ST_AVAILABLE) {
+ dev_err(dev, "not ready\n");
+ spin_unlock(&sdev->ud.lock);
+ return -EINVAL;
+ }
+
+ socket = sockfd_to_socket(sockfd);
+ if (!socket) {
+ spin_unlock(&sdev->ud.lock);
+ return -EINVAL;
+ }
+
+#if 0
+ setnodelay(socket);
+ setkeepalive(socket);
+ setreuse(socket);
+#endif
+
+ sdev->ud.tcp_socket = socket;
+
+ spin_unlock(&sdev->ud.lock);
+
+ usbip_start_threads(&sdev->ud);
+
+ spin_lock(&sdev->ud.lock);
+ sdev->ud.status = SDEV_ST_USED;
+ spin_unlock(&sdev->ud.lock);
+
+ } else {
+ dev_info(dev, "stub down\n");
+
+ spin_lock(&sdev->ud.lock);
+ if (sdev->ud.status != SDEV_ST_USED) {
+ spin_unlock(&sdev->ud.lock);
+ return -EINVAL;
+ }
+ spin_unlock(&sdev->ud.lock);
+
+ usbip_event_add(&sdev->ud, SDEV_EVENT_DOWN);
+ }
+
+ return count;
+}
+static DEVICE_ATTR(usbip_sockfd, S_IWUSR, NULL, store_sockfd);
+
+static int stub_add_files(struct device *dev)
+{
+ int err = 0;
+
+ err = device_create_file(dev, &dev_attr_usbip_status);
+ if (err)
+ goto err_status;
+
+ err = device_create_file(dev, &dev_attr_usbip_sockfd);
+ if (err)
+ goto err_sockfd;
+
+ err = device_create_file(dev, &dev_attr_usbip_debug);
+ if (err)
+ goto err_debug;
+
+ return 0;
+
+err_debug:
+ device_remove_file(dev, &dev_attr_usbip_sockfd);
+
+err_sockfd:
+ device_remove_file(dev, &dev_attr_usbip_status);
+
+err_status:
+ return err;
+}
+
+static void stub_remove_files(struct device *dev)
+{
+ device_remove_file(dev, &dev_attr_usbip_status);
+ device_remove_file(dev, &dev_attr_usbip_sockfd);
+ device_remove_file(dev, &dev_attr_usbip_debug);
+}
+
+
+
+/*-------------------------------------------------------------------------*/
+
+/* Event handler functions called by an event handler thread */
+
+static void stub_shutdown_connection(struct usbip_device *ud)
+{
+ struct stub_device *sdev = container_of(ud, struct stub_device, ud);
+
+ /*
+ * When removing an exported device, kernel panic sometimes occurred
+ * and then EIP was sk_wait_data of stub_rx thread. Is this because
+ * sk_wait_data returned though stub_rx thread was already finished by
+ * step 1?
+ */
+ if (ud->tcp_socket) {
+ udbg("shutdown tcp_socket %p\n", ud->tcp_socket);
+ kernel_sock_shutdown(ud->tcp_socket, SHUT_RDWR);
+ }
+
+ /* 1. stop threads */
+ usbip_stop_threads(ud);
+
+ /* 2. close the socket */
+ /*
+ * tcp_socket is freed after threads are killed.
+ * So usbip_xmit do not touch NULL socket.
+ */
+ if (ud->tcp_socket) {
+ sock_release(ud->tcp_socket);
+ ud->tcp_socket = NULL;
+ }
+
+ /* 3. free used data */
+ stub_device_cleanup_urbs(sdev);
+
+ /* 4. free stub_unlink */
+ {
+ unsigned long flags;
+ struct stub_unlink *unlink, *tmp;
+
+ spin_lock_irqsave(&sdev->priv_lock, flags);
+
+ list_for_each_entry_safe(unlink, tmp, &sdev->unlink_tx, list) {
+ list_del(&unlink->list);
+ kfree(unlink);
+ }
+
+ list_for_each_entry_safe(unlink, tmp,
+ &sdev->unlink_free, list) {
+ list_del(&unlink->list);
+ kfree(unlink);
+ }
+
+ spin_unlock_irqrestore(&sdev->priv_lock, flags);
+ }
+}
+
+static void stub_device_reset(struct usbip_device *ud)
+{
+ struct stub_device *sdev = container_of(ud, struct stub_device, ud);
+ struct usb_device *udev = interface_to_usbdev(sdev->interface);
+ int ret;
+
+ udbg("device reset");
+ ret = usb_lock_device_for_reset(udev, sdev->interface);
+ if (ret < 0) {
+ dev_err(&udev->dev, "lock for reset\n");
+
+ spin_lock(&ud->lock);
+ ud->status = SDEV_ST_ERROR;
+ spin_unlock(&ud->lock);
+
+ return;
+ }
+
+ /* try to reset the device */
+ ret = usb_reset_device(udev);
+
+ usb_unlock_device(udev);
+
+ spin_lock(&ud->lock);
+ if (ret) {
+ dev_err(&udev->dev, "device reset\n");
+ ud->status = SDEV_ST_ERROR;
+
+ } else {
+ dev_info(&udev->dev, "device reset\n");
+ ud->status = SDEV_ST_AVAILABLE;
+
+ }
+ spin_unlock(&ud->lock);
+
+ return;
+}
+
+static void stub_device_unusable(struct usbip_device *ud)
+{
+ spin_lock(&ud->lock);
+ ud->status = SDEV_ST_ERROR;
+ spin_unlock(&ud->lock);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * stub_device_alloc - allocate a new stub_device struct
+ * @interface: usb_interface of a new device
+ *
+ * Allocates and initializes a new stub_device struct.
+ */
+static struct stub_device *stub_device_alloc(struct usb_interface *interface)
+{
+ struct stub_device *sdev;
+ int busnum = interface_to_busnum(interface);
+ int devnum = interface_to_devnum(interface);
+
+ dev_dbg(&interface->dev, "allocating stub device");
+
+ /* yes, it's a new device */
+ sdev = kzalloc(sizeof(struct stub_device), GFP_KERNEL);
+ if (!sdev) {
+ dev_err(&interface->dev, "no memory for stub_device\n");
+ return NULL;
+ }
+
+ sdev->interface = interface;
+
+ /*
+ * devid is defined with devnum when this driver is first allocated.
+ * devnum may change later if a device is reset. However, devid never
+ * changes during a usbip connection.
+ */
+ sdev->devid = (busnum << 16) | devnum;
+
+ usbip_task_init(&sdev->ud.tcp_rx, "stub_rx", stub_rx_loop);
+ usbip_task_init(&sdev->ud.tcp_tx, "stub_tx", stub_tx_loop);
+
+ sdev->ud.side = USBIP_STUB;
+ sdev->ud.status = SDEV_ST_AVAILABLE;
+ /* sdev->ud.lock = SPIN_LOCK_UNLOCKED; */
+ spin_lock_init(&sdev->ud.lock);
+ sdev->ud.tcp_socket = NULL;
+
+ INIT_LIST_HEAD(&sdev->priv_init);
+ INIT_LIST_HEAD(&sdev->priv_tx);
+ INIT_LIST_HEAD(&sdev->priv_free);
+ INIT_LIST_HEAD(&sdev->unlink_free);
+ INIT_LIST_HEAD(&sdev->unlink_tx);
+ /* sdev->priv_lock = SPIN_LOCK_UNLOCKED; */
+ spin_lock_init(&sdev->priv_lock);
+
+ init_waitqueue_head(&sdev->tx_waitq);
+
+ sdev->ud.eh_ops.shutdown = stub_shutdown_connection;
+ sdev->ud.eh_ops.reset = stub_device_reset;
+ sdev->ud.eh_ops.unusable = stub_device_unusable;
+
+ usbip_start_eh(&sdev->ud);
+
+ udbg("register new interface\n");
+ return sdev;
+}
+
+static int stub_device_free(struct stub_device *sdev)
+{
+ if (!sdev)
+ return -EINVAL;
+
+ kfree(sdev);
+ udbg("kfree udev ok\n");
+
+ return 0;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * If a usb device has multiple active interfaces, this driver is bound to all
+ * the active interfaces. However, usbip exports *a* usb device (i.e., not *an*
+ * active interface). Currently, a userland program must ensure that it
+ * looks at the usbip's sysfs entries of only the first active interface.
+ *
+ * TODO: use "struct usb_device_driver" to bind a usb device.
+ * However, it seems it is not fully supported in mainline kernel yet
+ * (2.6.19.2).
+ */
+static int stub_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(interface);
+ struct stub_device *sdev = NULL;
+ char *udev_busid = interface->dev.parent->bus_id;
+ int err = 0;
+
+ dev_dbg(&interface->dev, "Enter\n");
+
+ /* check we should claim or not by busid_table */
+ if (match_busid(udev_busid)) {
+ dev_info(&interface->dev,
+ "this device %s is not in match_busid table. skip!\n",
+ udev_busid);
+
+ /*
+ * Return value should be ENODEV or ENOXIO to continue trying
+ * other matched drivers by the driver core.
+ * See driver_probe_device() in driver/base/dd.c
+ */
+ return -ENODEV;
+ }
+
+ if (udev->descriptor.bDeviceClass == USB_CLASS_HUB) {
+ udbg("this device %s is a usb hub device. skip!\n",
+ udev_busid);
+ return -ENODEV;
+ }
+
+ if (!strcmp(udev->bus->bus_name, "vhci_hcd")) {
+ udbg("this device %s is attached on vhci_hcd. skip!\n",
+ udev_busid);
+ return -ENODEV;
+ }
+
+ /* ok. this is my device. */
+ sdev = stub_device_alloc(interface);
+ if (!sdev)
+ return -ENOMEM;
+
+ dev_info(&interface->dev, "USB/IP Stub: register a new interface "
+ "(bus %u dev %u ifn %u)\n", udev->bus->busnum, udev->devnum,
+ interface->cur_altsetting->desc.bInterfaceNumber);
+
+ /* set private data to usb_interface */
+ usb_set_intfdata(interface, sdev);
+
+ err = stub_add_files(&interface->dev);
+ if (err) {
+ dev_err(&interface->dev, "create sysfs files for %s\n",
+ udev_busid);
+ return err;
+ }
+
+ return 0;
+}
+
+
+/*
+ * called in usb_disconnect() or usb_deregister()
+ * but only if actconfig(active configuration) exists
+ */
+static void stub_disconnect(struct usb_interface *interface)
+{
+ struct stub_device *sdev = usb_get_intfdata(interface);
+
+ udbg("Enter\n");
+
+ /* get stub_device */
+ if (!sdev) {
+ err(" could not get device from inteface data");
+ /* BUG(); */
+ return;
+ }
+
+ usb_set_intfdata(interface, NULL);
+
+
+ /*
+ * NOTE:
+ * rx/tx threads are invoked for each usb_device.
+ */
+ stub_remove_files(&interface->dev);
+
+ /* 1. shutdown the current connection */
+ usbip_event_add(&sdev->ud, SDEV_EVENT_REMOVED);
+
+ /* 2. wait for the stop of the event handler */
+ usbip_stop_eh(&sdev->ud);
+
+ /* 3. free sdev */
+ stub_device_free(sdev);
+
+
+ udbg("bye\n");
+}
diff --git a/drivers/staging/usbip/stub_main.c b/drivers/staging/usbip/stub_main.c
new file mode 100644
index 0000000..c665d7f
--- /dev/null
+++ b/drivers/staging/usbip/stub_main.c
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
+ *
+ * This 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 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+
+#include "usbip_common.h"
+#include "stub.h"
+
+/* Version Information */
+#define DRIVER_VERSION "1.0"
+#define DRIVER_AUTHOR "Takahiro Hirofuchi"
+#define DRIVER_DESC "Stub Driver for USB/IP"
+
+/* stub_priv is allocated from stub_priv_cache */
+struct kmem_cache *stub_priv_cache;
+
+/*-------------------------------------------------------------------------*/
+
+/* Define sysfs entries for the usbip driver */
+
+
+/*
+ * busid_tables defines matching busids that usbip can grab. A user can change
+ * dynamically what device is locally used and what device is exported to a
+ * remote host.
+ */
+#define MAX_BUSID 16
+static char busid_table[MAX_BUSID][BUS_ID_SIZE];
+static spinlock_t busid_table_lock;
+
+
+int match_busid(char *busid)
+{
+ int i;
+
+ spin_lock(&busid_table_lock);
+
+ for (i = 0; i < MAX_BUSID; i++)
+ if (busid_table[i][0])
+ if (!strncmp(busid_table[i], busid, BUS_ID_SIZE)) {
+ /* already registerd */
+ spin_unlock(&busid_table_lock);
+ return 0;
+ }
+
+ spin_unlock(&busid_table_lock);
+
+ return 1;
+}
+
+static ssize_t show_match_busid(struct device_driver *drv, char *buf)
+{
+ int i;
+ char *out = buf;
+
+ spin_lock(&busid_table_lock);
+
+ for (i = 0; i < MAX_BUSID; i++)
+ if (busid_table[i][0])
+ out += sprintf(out, "%s ", busid_table[i]);
+
+ spin_unlock(&busid_table_lock);
+
+ out += sprintf(out, "\n");
+
+ return out - buf;
+}
+
+static int add_match_busid(char *busid)
+{
+ int i;
+
+ if (!match_busid(busid))
+ return 0;
+
+ spin_lock(&busid_table_lock);
+
+ for (i = 0; i < MAX_BUSID; i++)
+ if (!busid_table[i][0]) {
+ strncpy(busid_table[i], busid, BUS_ID_SIZE);
+ spin_unlock(&busid_table_lock);
+ return 0;
+ }
+
+ spin_unlock(&busid_table_lock);
+
+ return -1;
+}
+
+static int del_match_busid(char *busid)
+{
+ int i;
+
+ spin_lock(&busid_table_lock);
+
+ for (i = 0; i < MAX_BUSID; i++)
+ if (!strncmp(busid_table[i], busid, BUS_ID_SIZE)) {
+ /* found */
+ memset(busid_table[i], 0, BUS_ID_SIZE);
+ spin_unlock(&busid_table_lock);
+ return 0;
+ }
+
+ spin_unlock(&busid_table_lock);
+
+ return -1;
+}
+
+static ssize_t store_match_busid(struct device_driver *dev, const char *buf,
+ size_t count)
+{
+ int len;
+ char busid[BUS_ID_SIZE];
+
+ if (count < 5)
+ return -EINVAL;
+
+ /* strnlen() does not include \0 */
+ len = strnlen(buf + 4, BUS_ID_SIZE);
+
+ /* busid needs to include \0 termination */
+ if (!(len < BUS_ID_SIZE))
+ return -EINVAL;
+
+ strncpy(busid, buf + 4, BUS_ID_SIZE);
+
+
+ if (!strncmp(buf, "add ", 4)) {
+ if (add_match_busid(busid) < 0)
+ return -ENOMEM;
+ else {
+ udbg("add busid %s\n", busid);
+ return count;
+ }
+ } else if (!strncmp(buf, "del ", 4)) {
+ if (del_match_busid(busid) < 0)
+ return -ENODEV;
+ else {
+ udbg("del busid %s\n", busid);
+ return count;
+ }
+ } else
+ return -EINVAL;
+}
+
+static DRIVER_ATTR(match_busid, S_IRUSR|S_IWUSR, show_match_busid,
+ store_match_busid);
+
+
+
+/*-------------------------------------------------------------------------*/
+
+/* Cleanup functions used to free private data */
+
+static struct stub_priv *stub_priv_pop_from_listhead(struct list_head *listhead)
+{
+ struct stub_priv *priv, *tmp;
+
+ list_for_each_entry_safe(priv, tmp, listhead, list) {
+ list_del(&priv->list);
+ return priv;
+ }
+
+ return NULL;
+}
+
+static struct stub_priv *stub_priv_pop(struct stub_device *sdev)
+{
+ unsigned long flags;
+ struct stub_priv *priv;
+
+ spin_lock_irqsave(&sdev->priv_lock, flags);
+
+ priv = stub_priv_pop_from_listhead(&sdev->priv_init);
+ if (priv) {
+ spin_unlock_irqrestore(&sdev->priv_lock, flags);
+ return priv;
+ }
+
+ priv = stub_priv_pop_from_listhead(&sdev->priv_tx);
+ if (priv) {
+ spin_unlock_irqrestore(&sdev->priv_lock, flags);
+ return priv;
+ }
+
+ priv = stub_priv_pop_from_listhead(&sdev->priv_free);
+ if (priv) {
+ spin_unlock_irqrestore(&sdev->priv_lock, flags);
+ return priv;
+ }
+
+ spin_unlock_irqrestore(&sdev->priv_lock, flags);
+ return NULL;
+}
+
+void stub_device_cleanup_urbs(struct stub_device *sdev)
+{
+ struct stub_priv *priv;
+
+ udbg("free sdev %p\n", sdev);
+
+ while ((priv = stub_priv_pop(sdev))) {
+ struct urb *urb = priv->urb;
+
+ udbg(" free urb %p\n", urb);
+ usb_kill_urb(urb);
+
+ kmem_cache_free(stub_priv_cache, priv);
+
+ if (urb->transfer_buffer != NULL)
+ kfree(urb->transfer_buffer);
+
+ if (urb->setup_packet != NULL)
+ kfree(urb->setup_packet);
+
+ usb_free_urb(urb);
+ }
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int __init usb_stub_init(void)
+{
+ int ret;
+
+ stub_priv_cache = kmem_cache_create("stub_priv",
+ sizeof(struct stub_priv), 0,
+ SLAB_HWCACHE_ALIGN, NULL);
+
+ if (!stub_priv_cache) {
+ printk(KERN_ERR KBUILD_MODNAME
+ ": create stub_priv_cache error\n");
+ return -ENOMEM;
+ }
+
+ ret = usb_register(&stub_driver);
+ if (ret) {
+ printk(KERN_ERR KBUILD_MODNAME ": usb_register failed %d\n",
+ ret);
+ goto error_usb_register;
+ }
+
+ printk(KERN_INFO KBUILD_MODNAME ":"
+ DRIVER_DESC ":" DRIVER_VERSION "\n");
+
+ memset(busid_table, 0, sizeof(busid_table));
+ spin_lock_init(&busid_table_lock);
+
+ ret = driver_create_file(&stub_driver.drvwrap.driver,
+ &driver_attr_match_busid);
+
+ if (ret) {
+ printk(KERN_ERR KBUILD_MODNAME ": create driver sysfs\n");
+ goto error_create_file;
+ }
+
+ return ret;
+error_create_file:
+ usb_deregister(&stub_driver);
+error_usb_register:
+ kmem_cache_destroy(stub_priv_cache);
+ return ret;
+}
+
+static void __exit usb_stub_exit(void)
+{
+ driver_remove_file(&stub_driver.drvwrap.driver,
+ &driver_attr_match_busid);
+
+ /*
+ * deregister() calls stub_disconnect() for all devices. Device
+ * specific data is cleared in stub_disconnect().
+ */
+ usb_deregister(&stub_driver);
+
+ kmem_cache_destroy(stub_priv_cache);
+}
+
+module_init(usb_stub_init);
+module_exit(usb_stub_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/usbip/stub_rx.c b/drivers/staging/usbip/stub_rx.c
new file mode 100644
index 0000000..36ce898
--- /dev/null
+++ b/drivers/staging/usbip/stub_rx.c
@@ -0,0 +1,615 @@
+/*
+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
+ *
+ * This 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 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include "usbip_common.h"
+#include "stub.h"
+#include "../../usb/core/hcd.h"
+
+
+static int is_clear_halt_cmd(struct urb *urb)
+{
+ struct usb_ctrlrequest *req;
+
+ req = (struct usb_ctrlrequest *) urb->setup_packet;
+
+ return (req->bRequest == USB_REQ_CLEAR_FEATURE) &&
+ (req->bRequestType == USB_RECIP_ENDPOINT) &&
+ (req->wValue == USB_ENDPOINT_HALT);
+}
+
+static int is_set_interface_cmd(struct urb *urb)
+{
+ struct usb_ctrlrequest *req;
+
+ req = (struct usb_ctrlrequest *) urb->setup_packet;
+
+ return (req->bRequest == USB_REQ_SET_INTERFACE) &&
+ (req->bRequestType == USB_RECIP_INTERFACE);
+}
+
+static int is_set_configuration_cmd(struct urb *urb)
+{
+ struct usb_ctrlrequest *req;
+
+ req = (struct usb_ctrlrequest *) urb->setup_packet;
+
+ return (req->bRequest == USB_REQ_SET_CONFIGURATION) &&
+ (req->bRequestType == USB_RECIP_DEVICE);
+}
+
+static int is_reset_device_cmd(struct urb *urb)
+{
+ struct usb_ctrlrequest *req;
+ __u16 value;
+ __u16 index;
+
+ req = (struct usb_ctrlrequest *) urb->setup_packet;
+ value = le16_to_cpu(req->wValue);
+ index = le16_to_cpu(req->wIndex);
+
+ if ((req->bRequest == USB_REQ_SET_FEATURE) &&
+ (req->bRequestType == USB_RT_PORT) &&
+ (value = USB_PORT_FEAT_RESET)) {
+ dbg_stub_rx("reset_device_cmd, port %u\n", index);
+ return 1;
+ } else
+ return 0;
+}
+
+static int tweak_clear_halt_cmd(struct urb *urb)
+{
+ struct usb_ctrlrequest *req;
+ int target_endp;
+ int target_dir;
+ int target_pipe;
+ int ret;
+
+ req = (struct usb_ctrlrequest *) urb->setup_packet;
+
+ /*
+ * The stalled endpoint is specified in the wIndex value. The endpoint
+ * of the urb is the target of this clear_halt request (i.e., control
+ * endpoint).
+ */
+ target_endp = le16_to_cpu(req->wIndex) & 0x000f;
+
+ /* the stalled endpoint direction is IN or OUT?. USB_DIR_IN is 0x80. */
+ target_dir = le16_to_cpu(req->wIndex) & 0x0080;
+
+ if (target_dir)
+ target_pipe = usb_rcvctrlpipe(urb->dev, target_endp);
+ else
+ target_pipe = usb_sndctrlpipe(urb->dev, target_endp);
+
+ ret = usb_clear_halt(urb->dev, target_pipe);
+ if (ret < 0)
+ uinfo("clear_halt error: devnum %d endp %d, %d\n",
+ urb->dev->devnum, target_endp, ret);
+ else
+ uinfo("clear_halt done: devnum %d endp %d\n",
+ urb->dev->devnum, target_endp);
+
+ return ret;
+}
+
+static int tweak_set_interface_cmd(struct urb *urb)
+{
+ struct usb_ctrlrequest *req;
+ __u16 alternate;
+ __u16 interface;
+ int ret;
+
+ req = (struct usb_ctrlrequest *) urb->setup_packet;
+ alternate = le16_to_cpu(req->wValue);
+ interface = le16_to_cpu(req->wIndex);
+
+ dbg_stub_rx("set_interface: inf %u alt %u\n", interface, alternate);
+
+ ret = usb_set_interface(urb->dev, interface, alternate);
+ if (ret < 0)
+ uinfo("set_interface error: inf %u alt %u, %d\n",
+ interface, alternate, ret);
+ else
+ uinfo("set_interface done: inf %u alt %u\n",
+ interface,
+ alternate);
+
+ return ret;
+}
+
+static int tweak_set_configuration_cmd(struct urb *urb)
+{
+ struct usb_ctrlrequest *req;
+ __u16 config;
+
+ req = (struct usb_ctrlrequest *) urb->setup_packet;
+ config = le16_to_cpu(req->wValue);
+
+ /*
+ * I have never seen a multi-config device. Very rare.
+ * For most devices, this will be called to choose a default
+ * configuration only once in an initialization phase.
+ *
+ * set_configuration may change a device configuration and its device
+ * drivers will be unbound and assigned for a new device configuration.
+ * This means this usbip driver will be also unbound when called, then
+ * eventually reassigned to the device as far as driver matching
+ * condition is kept.
+ *
+ * Unfortunatelly, an existing usbip connection will be dropped
+ * due to this driver unbinding. So, skip here.
+ * A user may need to set a special configuration value before
+ * exporting the device.
+ */
+ uinfo("set_configuration (%d) to %s\n", config, urb->dev->dev.bus_id);
+ uinfo("but, skip!\n");
+
+ return 0;
+ /* return usb_driver_set_configuration(urb->dev, config); */
+}
+
+static int tweak_reset_device_cmd(struct urb *urb)
+{
+ struct usb_ctrlrequest *req;
+ __u16 value;
+ __u16 index;
+ int ret;
+
+ req = (struct usb_ctrlrequest *) urb->setup_packet;
+ value = le16_to_cpu(req->wValue);
+ index = le16_to_cpu(req->wIndex);
+
+ uinfo("reset_device (port %d) to %s\n", index, urb->dev->dev.bus_id);
+
+ /* all interfaces should be owned by usbip driver, so just reset it. */
+ ret = usb_lock_device_for_reset(urb->dev, NULL);
+ if (ret < 0) {
+ dev_err(&urb->dev->dev, "lock for reset\n");
+ return ret;
+ }
+
+ /* try to reset the device */
+ ret = usb_reset_device(urb->dev);
+ if (ret < 0)
+ dev_err(&urb->dev->dev, "device reset\n");
+
+ usb_unlock_device(urb->dev);
+
+ return ret;
+}
+
+/*
+ * clear_halt, set_interface, and set_configuration require special tricks.
+ */
+static void tweak_special_requests(struct urb *urb)
+{
+ if (!urb || !urb->setup_packet)
+ return;
+
+ if (usb_pipetype(urb->pipe) != PIPE_CONTROL)
+ return;
+
+ if (is_clear_halt_cmd(urb))
+ /* tweak clear_halt */
+ tweak_clear_halt_cmd(urb);
+
+ else if (is_set_interface_cmd(urb))
+ /* tweak set_interface */
+ tweak_set_interface_cmd(urb);
+
+ else if (is_set_configuration_cmd(urb))
+ /* tweak set_configuration */
+ tweak_set_configuration_cmd(urb);
+
+ else if (is_reset_device_cmd(urb))
+ tweak_reset_device_cmd(urb);
+ else
+ dbg_stub_rx("no need to tweak\n");
+}
+
+/*
+ * stub_recv_unlink() unlinks the URB by a call to usb_unlink_urb().
+ * By unlinking the urb asynchronously, stub_rx can continuously
+ * process coming urbs. Even if the urb is unlinked, its completion
+ * handler will be called and stub_tx will send a return pdu.
+ *
+ * See also comments about unlinking strategy in vhci_hcd.c.
+ */
+static int stub_recv_cmd_unlink(struct stub_device *sdev,
+ struct usbip_header *pdu)
+{
+ struct list_head *listhead = &sdev->priv_init;
+ struct list_head *ptr;
+ unsigned long flags;
+
+ struct stub_priv *priv;
+
+
+ spin_lock_irqsave(&sdev->priv_lock, flags);
+
+ for (ptr = listhead->next; ptr != listhead; ptr = ptr->next) {
+ priv = list_entry(ptr, struct stub_priv, list);
+ if (priv->seqnum == pdu->u.cmd_unlink.seqnum) {
+ int ret;
+
+ dev_info(&priv->urb->dev->dev, "unlink urb %p\n",
+ priv->urb);
+
+ /*
+ * This matched urb is not completed yet (i.e., be in
+ * flight in usb hcd hardware/driver). Now we are
+ * cancelling it. The unlinking flag means that we are
+ * now not going to return the normal result pdu of a
+ * submission request, but going to return a result pdu
+ * of the unlink request.
+ */
+ priv->unlinking = 1;
+
+ /*
+ * In the case that unlinking flag is on, prev->seqnum
+ * is changed from the seqnum of the cancelling urb to
+ * the seqnum of the unlink request. This will be used
+ * to make the result pdu of the unlink request.
+ */
+ priv->seqnum = pdu->base.seqnum;
+
+ spin_unlock_irqrestore(&sdev->priv_lock, flags);
+
+ /*
+ * usb_unlink_urb() is now out of spinlocking to avoid
+ * spinlock recursion since stub_complete() is
+ * sometimes called in this context but not in the
+ * interrupt context. If stub_complete() is executed
+ * before we call usb_unlink_urb(), usb_unlink_urb()
+ * will return an error value. In this case, stub_tx
+ * will return the result pdu of this unlink request
+ * though submission is completed and actual unlinking
+ * is not executed. OK?
+ */
+ /* In the above case, urb->status is not -ECONNRESET,
+ * so a driver in a client host will know the failure
+ * of the unlink request ?
+ */
+ ret = usb_unlink_urb(priv->urb);
+ if (ret != -EINPROGRESS)
+ dev_err(&priv->urb->dev->dev,
+ "failed to unlink a urb %p, ret %d\n",
+ priv->urb, ret);
+ return 0;
+ }
+ }
+
+ dbg_stub_rx("seqnum %d is not pending\n", pdu->u.cmd_unlink.seqnum);
+
+ /*
+ * The urb of the unlink target is not found in priv_init queue. It was
+ * already completed and its results is/was going to be sent by a
+ * CMD_RET pdu. In this case, usb_unlink_urb() is not needed. We only
+ * return the completeness of this unlink request to vhci_hcd.
+ */
+ stub_enqueue_ret_unlink(sdev, pdu->base.seqnum, 0);
+
+ spin_unlock_irqrestore(&sdev->priv_lock, flags);
+
+
+ return 0;
+}
+
+static int valid_request(struct stub_device *sdev, struct usbip_header *pdu)
+{
+ struct usbip_device *ud = &sdev->ud;
+
+ if (pdu->base.devid == sdev->devid) {
+ spin_lock(&ud->lock);
+ if (ud->status == SDEV_ST_USED) {
+ /* A request is valid. */
+ spin_unlock(&ud->lock);
+ return 1;
+ }
+ spin_unlock(&ud->lock);
+ }
+
+ return 0;
+}
+
+static struct stub_priv *stub_priv_alloc(struct stub_device *sdev,
+ struct usbip_header *pdu)
+{
+ struct stub_priv *priv;
+ struct usbip_device *ud = &sdev->ud;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sdev->priv_lock, flags);
+
+ priv = kmem_cache_alloc(stub_priv_cache, GFP_ATOMIC);
+ if (!priv) {
+ dev_err(&sdev->interface->dev, "alloc stub_priv\n");
+ spin_unlock_irqrestore(&sdev->priv_lock, flags);
+ usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC);
+ return NULL;
+ }
+
+ memset(priv, 0, sizeof(struct stub_priv));
+
+ priv->seqnum = pdu->base.seqnum;
+ priv->sdev = sdev;
+
+ /*
+ * After a stub_priv is linked to a list_head,
+ * our error handler can free allocated data.
+ */
+ list_add_tail(&priv->list, &sdev->priv_init);
+
+ spin_unlock_irqrestore(&sdev->priv_lock, flags);
+
+ return priv;
+}
+
+
+static struct usb_host_endpoint *get_ep_from_epnum(struct usb_device *udev,
+ int epnum0)
+{
+ struct usb_host_config *config;
+ int i = 0, j = 0;
+ struct usb_host_endpoint *ep = NULL;
+ int epnum;
+ int found = 0;
+
+ if (epnum0 == 0)
+ return &udev->ep0;
+
+ config = udev->actconfig;
+ if (!config)
+ return NULL;
+
+ for (i = 0; i < config->desc.bNumInterfaces; i++) {
+ struct usb_host_interface *setting;
+
+ setting = config->interface[i]->cur_altsetting;
+
+ for (j = 0; j < setting->desc.bNumEndpoints; j++) {
+ ep = &setting->endpoint[j];
+ epnum = (ep->desc.bEndpointAddress & 0x7f);
+
+ if (epnum == epnum0) {
+ /* uinfo("found epnum %d\n", epnum0); */
+ found = 1;
+ break;
+ }
+ }
+ }
+
+ if (found)
+ return ep;
+ else
+ return NULL;
+}
+
+
+static int get_pipe(struct stub_device *sdev, int epnum, int dir)
+{
+ struct usb_device *udev = interface_to_usbdev(sdev->interface);
+ struct usb_host_endpoint *ep;
+ struct usb_endpoint_descriptor *epd = NULL;
+
+ ep = get_ep_from_epnum(udev, epnum);
+ if (!ep) {
+ dev_err(&sdev->interface->dev, "no such endpoint?, %d\n",
+ epnum);
+ BUG();
+ }
+
+ epd = &ep->desc;
+
+
+#if 0
+ /* epnum 0 is always control */
+ if (epnum == 0) {
+ if (dir == USBIP_DIR_OUT)
+ return usb_sndctrlpipe(udev, 0);
+ else
+ return usb_rcvctrlpipe(udev, 0);
+ }
+#endif
+
+ if (usb_endpoint_xfer_control(epd)) {
+ if (dir == USBIP_DIR_OUT)
+ return usb_sndctrlpipe(udev, epnum);
+ else
+ return usb_rcvctrlpipe(udev, epnum);
+ }
+
+ if (usb_endpoint_xfer_bulk(epd)) {
+ if (dir == USBIP_DIR_OUT)
+ return usb_sndbulkpipe(udev, epnum);
+ else
+ return usb_rcvbulkpipe(udev, epnum);
+ }
+
+ if (usb_endpoint_xfer_int(epd)) {
+ if (dir == USBIP_DIR_OUT)
+ return usb_sndintpipe(udev, epnum);
+ else
+ return usb_rcvintpipe(udev, epnum);
+ }
+
+ if (usb_endpoint_xfer_isoc(epd)) {
+ if (dir == USBIP_DIR_OUT)
+ return usb_sndisocpipe(udev, epnum);
+ else
+ return usb_rcvisocpipe(udev, epnum);
+ }
+
+ /* NOT REACHED */
+ dev_err(&sdev->interface->dev, "get pipe, epnum %d\n", epnum);
+ return 0;
+}
+
+static void stub_recv_cmd_submit(struct stub_device *sdev,
+ struct usbip_header *pdu)
+{
+ int ret;
+ struct stub_priv *priv;
+ struct usbip_device *ud = &sdev->ud;
+ struct usb_device *udev = interface_to_usbdev(sdev->interface);
+ int pipe = get_pipe(sdev, pdu->base.ep, pdu->base.direction);
+
+
+ priv = stub_priv_alloc(sdev, pdu);
+ if (!priv)
+ return;
+
+ /* setup a urb */
+ if (usb_pipeisoc(pipe))
+ priv->urb = usb_alloc_urb(pdu->u.cmd_submit.number_of_packets,
+ GFP_KERNEL);
+ else
+ priv->urb = usb_alloc_urb(0, GFP_KERNEL);
+
+ if (!priv->urb) {
+ dev_err(&sdev->interface->dev, "malloc urb\n");
+ usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC);
+ return;
+ }
+
+ /* set priv->urb->transfer_buffer */
+ if (pdu->u.cmd_submit.transfer_buffer_length > 0) {
+ priv->urb->transfer_buffer =
+ kzalloc(pdu->u.cmd_submit.transfer_buffer_length,
+ GFP_KERNEL);
+ if (!priv->urb->transfer_buffer) {
+ dev_err(&sdev->interface->dev, "malloc x_buff\n");
+ usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC);
+ return;
+ }
+ }
+
+ /* set priv->urb->setup_packet */
+ priv->urb->setup_packet = kzalloc(8, GFP_KERNEL);
+ if (!priv->urb->setup_packet) {
+ dev_err(&sdev->interface->dev, "allocate setup_packet\n");
+ usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC);
+ return;
+ }
+ memcpy(priv->urb->setup_packet, &pdu->u.cmd_submit.setup, 8);
+
+ /* set other members from the base header of pdu */
+ priv->urb->context = (void *) priv;
+ priv->urb->dev = udev;
+ priv->urb->pipe = pipe;
+ priv->urb->complete = stub_complete;
+
+ usbip_pack_pdu(pdu, priv->urb, USBIP_CMD_SUBMIT, 0);
+
+
+ if (usbip_recv_xbuff(ud, priv->urb) < 0)
+ return;
+
+ if (usbip_recv_iso(ud, priv->urb) < 0)
+ return;
+
+ /* no need to submit an intercepted request, but harmless? */
+ tweak_special_requests(priv->urb);
+
+ /* urb is now ready to submit */
+ ret = usb_submit_urb(priv->urb, GFP_KERNEL);
+
+ if (ret == 0)
+ dbg_stub_rx("submit urb ok, seqnum %u\n", pdu->base.seqnum);
+ else {
+ dev_err(&sdev->interface->dev, "submit_urb error, %d\n", ret);
+ usbip_dump_header(pdu);
+ usbip_dump_urb(priv->urb);
+
+ /*
+ * Pessimistic.
+ * This connection will be discarded.
+ */
+ usbip_event_add(ud, SDEV_EVENT_ERROR_SUBMIT);
+ }
+
+ dbg_stub_rx("Leave\n");
+ return;
+}
+
+/* recv a pdu */
+static void stub_rx_pdu(struct usbip_device *ud)
+{
+ int ret;
+ struct usbip_header pdu;
+ struct stub_device *sdev = container_of(ud, struct stub_device, ud);
+ struct device *dev = &sdev->interface->dev;
+
+ dbg_stub_rx("Enter\n");
+
+ memset(&pdu, 0, sizeof(pdu));
+
+ /* 1. receive a pdu header */
+ ret = usbip_xmit(0, ud->tcp_socket, (char *) &pdu, sizeof(pdu), 0);
+ if (ret != sizeof(pdu)) {
+ dev_err(dev, "recv a header, %d\n", ret);
+ usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
+ return;
+ }
+
+ usbip_header_correct_endian(&pdu, 0);
+
+ if (dbg_flag_stub_rx)
+ usbip_dump_header(&pdu);
+
+ if (!valid_request(sdev, &pdu)) {
+ dev_err(dev, "recv invalid request\n");
+ usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
+ return;
+ }
+
+ switch (pdu.base.command) {
+ case USBIP_CMD_UNLINK:
+ stub_recv_cmd_unlink(sdev, &pdu);
+ break;
+
+ case USBIP_CMD_SUBMIT:
+ stub_recv_cmd_submit(sdev, &pdu);
+ break;
+
+ default:
+ /* NOTREACHED */
+ dev_err(dev, "unknown pdu\n");
+ usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
+ return;
+ }
+
+}
+
+void stub_rx_loop(struct usbip_task *ut)
+{
+ struct usbip_device *ud = container_of(ut, struct usbip_device, tcp_rx);
+
+ while (1) {
+ if (signal_pending(current)) {
+ dbg_stub_rx("signal caught!\n");
+ break;
+ }
+
+ if (usbip_event_happend(ud))
+ break;
+
+ stub_rx_pdu(ud);
+ }
+}
diff --git a/drivers/staging/usbip/stub_tx.c b/drivers/staging/usbip/stub_tx.c
new file mode 100644
index 0000000..d5563cd
--- /dev/null
+++ b/drivers/staging/usbip/stub_tx.c
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2003-2008 Takahiro Hirofuchi
+ *
+ * This 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 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+#include "usbip_common.h"
+#include "stub.h"
+
+
+static void stub_free_priv_and_urb(struct stub_priv *priv)
+{
+ struct urb *urb = priv->urb;
+
+ kfree(urb->setup_packet);
+ kfree(urb->transfer_buffer);
+ list_del(&priv->list);
+ kmem_cache_free(stub_priv_cache, priv);
+ usb_free_urb(urb);
+}
+
+/* be in spin_lock_irqsave(&sdev->priv_lock, flags) */
+void stub_enqueue_ret_unlink(struct stub_device *sdev, __u32 seqnum,
+ __u32 status)
+{
+ struct stub_unlink *unlink;
+
+ unlink = kzalloc(sizeof(struct stub_unlink), GFP_ATOMIC);
+ if (!unlink) {
+ dev_err(&sdev->interface->dev, "alloc stub_unlink\n");
+ usbip_event_add(&sdev->ud, VDEV_EVENT_ERROR_MALLOC);
+ return;
+ }
+
+ unlink->seqnum = seqnum;
+ unlink->status = status;
+
+ list_add_tail(&unlink->list, &sdev->unlink_tx);
+}
+
+/**
+ * stub_complete - completion handler of a usbip urb
+ * @urb: pointer to the urb completed
+ * @regs:
+ *
+ * When a urb has completed, the USB core driver calls this function mostly in
+ * the interrupt context. To return the result of a urb, the completed urb is
+ * linked to the pending list of returning.
+ *
+ */
+void stub_complete(struct urb *urb)
+{
+ struct stub_priv *priv = (struct stub_priv *) urb->context;
+ struct stub_device *sdev = priv->sdev;
+ unsigned long flags;
+
+ dbg_stub_tx("complete! status %d\n", urb->status);
+
+
+ switch (urb->status) {
+ case 0:
+ /* OK */
+ break;
+ case -ENOENT:
+ uinfo("stopped by a call of usb_kill_urb() because of"
+ "cleaning up a virtual connection\n");
+ return;
+ case -ECONNRESET:
+ uinfo("unlinked by a call of usb_unlink_urb()\n");
+ break;
+ case -EPIPE:
+ uinfo("endpoint %d is stalled\n", usb_pipeendpoint(urb->pipe));
+ break;
+ case -ESHUTDOWN:
+ uinfo("device removed?\n");
+ break;
+ default:
+ uinfo("urb completion with non-zero status %d\n", urb->status);
+ }
+
+ /* link a urb to the queue of tx. */
+ spin_lock_irqsave(&sdev->priv_lock, flags);
+
+ if (priv->unlinking) {
+ stub_enqueue_ret_unlink(sdev, priv->seqnum, urb->status);
+ stub_free_priv_and_urb(priv);
+ } else
+ list_move_tail(&priv->list, &sdev->priv_tx);
+
+
+ spin_unlock_irqrestore(&sdev->priv_lock, flags);
+
+ /* wake up tx_thread */
+ wake_up(&sdev->tx_waitq);
+}
+
+
+/*-------------------------------------------------------------------------*/
+/* fill PDU */
+
+static inline void setup_base_pdu(struct usbip_header_basic *base,
+ __u32 command, __u32 seqnum)
+{
+ base->command = command;
+ base->seqnum = seqnum;
+ base->devid = 0;
+ base->ep = 0;
+ base->direction = 0;
+}
+
+static void setup_ret_submit_pdu(struct usbip_header *rpdu, struct urb *urb)
+{
+ struct stub_priv *priv = (struct stub_priv *) urb->context;
+
+ setup_base_pdu(&rpdu->base, USBIP_RET_SUBMIT, priv->seqnum);
+
+ usbip_pack_pdu(rpdu, urb, USBIP_RET_SUBMIT, 1);
+}
+
+static void setup_ret_unlink_pdu(struct usbip_header *rpdu,
+ struct stub_unlink *unlink)
+{
+ setup_base_pdu(&rpdu->base, USBIP_RET_UNLINK, unlink->seqnum);
+
+ rpdu->u.ret_unlink.status = unlink->status;
+}
+
+
+/*-------------------------------------------------------------------------*/
+/* send RET_SUBMIT */
+
+static struct stub_priv *dequeue_from_priv_tx(struct stub_device *sdev)
+{
+ unsigned long flags;
+ struct stub_priv *priv, *tmp;
+
+ spin_lock_irqsave(&sdev->priv_lock, flags);
+
+ list_for_each_entry_safe(priv, tmp, &sdev->priv_tx, list) {
+ list_move_tail(&priv->list, &sdev->priv_free);
+ spin_unlock_irqrestore(&sdev->priv_lock, flags);
+ return priv;
+ }
+
+ spin_unlock_irqrestore(&sdev->priv_lock, flags);
+
+ return NULL;
+}
+
+static int stub_send_ret_submit(struct stub_device *sdev)
+{
+ unsigned long flags;
+ struct stub_priv *priv, *tmp;
+
+ struct msghdr msg;
+ struct kvec iov[3];
+ size_t txsize;
+
+ size_t total_size = 0;
+
+ while ((priv = dequeue_from_priv_tx(sdev)) != NULL) {
+ int ret;
+ struct urb *urb = priv->urb;
+ struct usbip_header pdu_header;
+ void *iso_buffer = NULL;
+
+ txsize = 0;
+ memset(&pdu_header, 0, sizeof(pdu_header));
+ memset(&msg, 0, sizeof(msg));
+ memset(&iov, 0, sizeof(iov));
+
+ dbg_stub_tx("setup txdata urb %p\n", urb);
+
+
+ /* 1. setup usbip_header */
+ setup_ret_submit_pdu(&pdu_header, urb);
+ usbip_header_correct_endian(&pdu_header, 1);
+
+ iov[0].iov_base = &pdu_header;
+ iov[0].iov_len = sizeof(pdu_header);
+ txsize += sizeof(pdu_header);
+
+ /* 2. setup transfer buffer */
+ if (usb_pipein(urb->pipe) && urb->actual_length > 0) {
+ iov[1].iov_base = urb->transfer_buffer;
+ iov[1].iov_len = urb->actual_length;
+ txsize += urb->actual_length;
+ }
+
+ /* 3. setup iso_packet_descriptor */
+ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+ ssize_t len = 0;
+
+ iso_buffer = usbip_alloc_iso_desc_pdu(urb, &len);
+ if (!iso_buffer) {
+ usbip_event_add(&sdev->ud,
+ SDEV_EVENT_ERROR_MALLOC);
+ return -1;
+ }
+
+ iov[2].iov_base = iso_buffer;
+ iov[2].iov_len = len;
+ txsize += len;
+ }
+
+ ret = kernel_sendmsg(sdev->ud.tcp_socket, &msg, iov,
+ 3, txsize);
+ if (ret != txsize) {
+ dev_err(&sdev->interface->dev,
+ "sendmsg failed!, retval %d for %zd\n",
+ ret, txsize);
+ kfree(iso_buffer);
+ usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP);
+ return -1;
+ }
+
+ kfree(iso_buffer);
+ dbg_stub_tx("send txdata\n");
+
+ total_size += txsize;
+ }
+
+
+ spin_lock_irqsave(&sdev->priv_lock, flags);
+
+ list_for_each_entry_safe(priv, tmp, &sdev->priv_free, list) {
+ stub_free_priv_and_urb(priv);
+ }
+
+ spin_unlock_irqrestore(&sdev->priv_lock, flags);
+
+ return total_size;
+}
+
+
+/*-------------------------------------------------------------------------*/
+/* send RET_UNLINK */
+
+static struct stub_unlink *dequeue_from_unlink_tx(struct stub_device *sdev)
+{
+ unsigned long flags;
+ struct stub_unlink *unlink, *tmp;
+
+ spin_lock_irqsave(&sdev->priv_lock, flags);
+
+ list_for_each_entry_safe(unlink, tmp, &sdev->unlink_tx, list) {
+ list_move_tail(&unlink->list, &sdev->unlink_free);
+ spin_unlock_irqrestore(&sdev->priv_lock, flags);
+ return unlink;
+ }
+
+ spin_unlock_irqrestore(&sdev->priv_lock, flags);
+
+ return NULL;
+}
+
+
+static int stub_send_ret_unlink(struct stub_device *sdev)
+{
+ unsigned long flags;
+ struct stub_unlink *unlink, *tmp;
+
+ struct msghdr msg;
+ struct kvec iov[1];
+ size_t txsize;
+
+ size_t total_size = 0;
+
+ while ((unlink = dequeue_from_unlink_tx(sdev)) != NULL) {
+ int ret;
+ struct usbip_header pdu_header;
+
+ txsize = 0;
+ memset(&pdu_header, 0, sizeof(pdu_header));
+ memset(&msg, 0, sizeof(msg));
+ memset(&iov, 0, sizeof(iov));
+
+ dbg_stub_tx("setup ret unlink %lu\n", unlink->seqnum);
+
+ /* 1. setup usbip_header */
+ setup_ret_unlink_pdu(&pdu_header, unlink);
+ usbip_header_correct_endian(&pdu_header, 1);
+
+ iov[0].iov_base = &pdu_header;
+ iov[0].iov_len = sizeof(pdu_header);
+ txsize += sizeof(pdu_header);
+
+ ret = kernel_sendmsg(sdev->ud.tcp_socket, &msg, iov,
+ 1, txsize);
+ if (ret != txsize) {
+ dev_err(&sdev->interface->dev,
+ "sendmsg failed!, retval %d for %zd\n",
+ ret, txsize);
+ usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP);
+ return -1;
+ }
+
+
+ dbg_stub_tx("send txdata\n");
+
+ total_size += txsize;
+ }
+
+
+ spin_lock_irqsave(&sdev->priv_lock, flags);
+
+ list_for_each_entry_safe(unlink, tmp, &sdev->unlink_free, list) {
+ list_del(&unlink->list);
+ kfree(unlink);
+ }
+
+ spin_unlock_irqrestore(&sdev->priv_lock, flags);
+
+ return total_size;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+void stub_tx_loop(struct usbip_task *ut)
+{
+ struct usbip_device *ud = container_of(ut, struct usbip_device, tcp_tx);
+ struct stub_device *sdev = container_of(ud, struct stub_device, ud);
+
+ while (1) {
+ if (signal_pending(current)) {
+ dbg_stub_tx("signal catched\n");
+ break;
+ }
+
+ if (usbip_event_happend(ud))
+ break;
+
+ /*
+ * send_ret_submit comes earlier than send_ret_unlink. stub_rx
+ * looks at only priv_init queue. If the completion of a URB is
+ * earlier than the receive of CMD_UNLINK, priv is moved to
+ * priv_tx queue and stub_rx does not find the target priv. In
+ * this case, vhci_rx receives the result of the submit request
+ * and then receives the result of the unlink request. The
+ * result of the submit is given back to the usbcore as the
+ * completion of the unlink request. The request of the
+ * unlink is ignored. This is ok because a driver who calls
+ * usb_unlink_urb() understands the unlink was too late by
+ * getting the status of the given-backed URB which has the
+ * status of usb_submit_urb().
+ */
+ if (stub_send_ret_submit(sdev) < 0)
+ break;
+
+ if (stub_send_ret_unlink(sdev) < 0)
+ break;
+
+ wait_event_interruptible(sdev->tx_waitq,
+ (!list_empty(&sdev->priv_tx) ||
+ !list_empty(&sdev->unlink_tx)));
+ }
+}
--
1.6.0.2
^ permalink raw reply related [flat|nested] 37+ messages in thread* [PATCH 14/23] Staging: add w35und wifi driver
2008-10-10 22:41 [GIT PATCH] STAGING patches for 2.6.28 Greg KH
` (9 preceding siblings ...)
2008-10-10 22:42 ` [PATCH 13/23] Staging: USB/IP: add host driver Greg KH
@ 2008-10-10 22:42 ` Greg KH
2008-10-18 20:55 ` Geert Uytterhoeven
2008-10-10 22:42 ` [PATCH 16/23] Staging: add echo cancelation module Greg KH
` (8 subsequent siblings)
19 siblings, 1 reply; 37+ messages in thread
From: Greg KH @ 2008-10-10 22:42 UTC (permalink / raw)
To: linux-kernel; +Cc: Pavel Machek, Greg Kroah-Hartman
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 489774 bytes --]
From: Pavel Machek <pavel@suse.cz>
This is driver for w35und usb wifi -- also in kohjinsha
subnotebook. It should work well enough to associate and ping, but it
obviously needs to be rewritten two more times...
OTOH worst horrors (like embedded wifi stack) should have been fixed
already...
Signed-off-by: Pavel Machek <pavel@suse.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/Kconfig | 2 +
drivers/staging/Makefile | 1 +
drivers/staging/winbond/Kconfig | 7 +
drivers/staging/winbond/Makefile | 18 +
drivers/staging/winbond/README | 10 +
drivers/staging/winbond/adapter.h | 23 +
drivers/staging/winbond/bss_f.h | 59 +
drivers/staging/winbond/bssdscpt.h | 156 ++
drivers/staging/winbond/ds_tkip.h | 33 +
drivers/staging/winbond/gl_80211.h | 125 ++
drivers/staging/winbond/ioctls.h | 678 ++++++++
drivers/staging/winbond/linux/common.h | 143 ++
drivers/staging/winbond/linux/sysdef.h | 73 +
drivers/staging/winbond/linux/wb35reg.c | 747 ++++++++
drivers/staging/winbond/linux/wb35reg_f.h | 56 +
drivers/staging/winbond/linux/wb35reg_s.h | 170 ++
drivers/staging/winbond/linux/wb35rx.c | 337 ++++
drivers/staging/winbond/linux/wb35rx_f.h | 17 +
drivers/staging/winbond/linux/wb35rx_s.h | 48 +
drivers/staging/winbond/linux/wb35tx.c | 313 ++++
drivers/staging/winbond/linux/wb35tx_f.h | 20 +
drivers/staging/winbond/linux/wb35tx_s.h | 47 +
drivers/staging/winbond/linux/wbusb.c | 404 +++++
drivers/staging/winbond/linux/wbusb_f.h | 34 +
drivers/staging/winbond/linux/wbusb_s.h | 42 +
drivers/staging/winbond/localpara.h | 275 +++
drivers/staging/winbond/mac_structures.h | 670 +++++++
drivers/staging/winbond/mds.c | 630 +++++++
drivers/staging/winbond/mds_f.h | 33 +
drivers/staging/winbond/mds_s.h | 183 ++
drivers/staging/winbond/mlme_mib.h | 84 +
drivers/staging/winbond/mlme_s.h | 195 +++
drivers/staging/winbond/mlmetxrx.c | 150 ++
drivers/staging/winbond/mlmetxrx_f.h | 52 +
drivers/staging/winbond/mto.c | 1229 +++++++++++++
drivers/staging/winbond/mto.h | 265 +++
drivers/staging/winbond/mto_f.h | 7 +
drivers/staging/winbond/os_common.h | 2 +
drivers/staging/winbond/phy_calibration.c | 1759 +++++++++++++++++++
drivers/staging/winbond/phy_calibration.h | 101 ++
drivers/staging/winbond/reg.c | 2683 +++++++++++++++++++++++++++++
drivers/staging/winbond/rxisr.c | 30 +
drivers/staging/winbond/scan_s.h | 115 ++
drivers/staging/winbond/sme_api.c | 13 +
drivers/staging/winbond/sme_api.h | 265 +++
drivers/staging/winbond/sme_s.h | 228 +++
drivers/staging/winbond/wb35_ver.h | 30 +
drivers/staging/winbond/wbhal.c | 878 ++++++++++
drivers/staging/winbond/wbhal_f.h | 122 ++
drivers/staging/winbond/wbhal_s.h | 615 +++++++
drivers/staging/winbond/wblinux.c | 277 +++
drivers/staging/winbond/wblinux_f.h | 23 +
drivers/staging/winbond/wblinux_s.h | 45 +
53 files changed, 14522 insertions(+), 0 deletions(-)
create mode 100644 drivers/staging/winbond/Kconfig
create mode 100644 drivers/staging/winbond/Makefile
create mode 100644 drivers/staging/winbond/README
create mode 100644 drivers/staging/winbond/adapter.h
create mode 100644 drivers/staging/winbond/bss_f.h
create mode 100644 drivers/staging/winbond/bssdscpt.h
create mode 100644 drivers/staging/winbond/ds_tkip.h
create mode 100644 drivers/staging/winbond/gl_80211.h
create mode 100644 drivers/staging/winbond/ioctls.h
create mode 100644 drivers/staging/winbond/linux/common.h
create mode 100644 drivers/staging/winbond/linux/sysdef.h
create mode 100644 drivers/staging/winbond/linux/wb35reg.c
create mode 100644 drivers/staging/winbond/linux/wb35reg_f.h
create mode 100644 drivers/staging/winbond/linux/wb35reg_s.h
create mode 100644 drivers/staging/winbond/linux/wb35rx.c
create mode 100644 drivers/staging/winbond/linux/wb35rx_f.h
create mode 100644 drivers/staging/winbond/linux/wb35rx_s.h
create mode 100644 drivers/staging/winbond/linux/wb35tx.c
create mode 100644 drivers/staging/winbond/linux/wb35tx_f.h
create mode 100644 drivers/staging/winbond/linux/wb35tx_s.h
create mode 100644 drivers/staging/winbond/linux/wbusb.c
create mode 100644 drivers/staging/winbond/linux/wbusb_f.h
create mode 100644 drivers/staging/winbond/linux/wbusb_s.h
create mode 100644 drivers/staging/winbond/localpara.h
create mode 100644 drivers/staging/winbond/mac_structures.h
create mode 100644 drivers/staging/winbond/mds.c
create mode 100644 drivers/staging/winbond/mds_f.h
create mode 100644 drivers/staging/winbond/mds_s.h
create mode 100644 drivers/staging/winbond/mlme_mib.h
create mode 100644 drivers/staging/winbond/mlme_s.h
create mode 100644 drivers/staging/winbond/mlmetxrx.c
create mode 100644 drivers/staging/winbond/mlmetxrx_f.h
create mode 100644 drivers/staging/winbond/mto.c
create mode 100644 drivers/staging/winbond/mto.h
create mode 100644 drivers/staging/winbond/mto_f.h
create mode 100644 drivers/staging/winbond/os_common.h
create mode 100644 drivers/staging/winbond/phy_calibration.c
create mode 100644 drivers/staging/winbond/phy_calibration.h
create mode 100644 drivers/staging/winbond/reg.c
create mode 100644 drivers/staging/winbond/rxisr.c
create mode 100644 drivers/staging/winbond/scan_s.h
create mode 100644 drivers/staging/winbond/sme_api.c
create mode 100644 drivers/staging/winbond/sme_api.h
create mode 100644 drivers/staging/winbond/sme_s.h
create mode 100644 drivers/staging/winbond/wb35_ver.h
create mode 100644 drivers/staging/winbond/wbhal.c
create mode 100644 drivers/staging/winbond/wbhal_f.h
create mode 100644 drivers/staging/winbond/wbhal_s.h
create mode 100644 drivers/staging/winbond/wblinux.c
create mode 100644 drivers/staging/winbond/wblinux_f.h
create mode 100644 drivers/staging/winbond/wblinux_s.h
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 4dbf795..fdbdf84 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -35,4 +35,6 @@ source "drivers/staging/go7007/Kconfig"
source "drivers/staging/usbip/Kconfig"
+source "drivers/staging/winbond/Kconfig"
+
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index be42c0d..9b576c9 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_SXG) += sxg/
obj-$(CONFIG_ME4000) += me4000/
obj-$(CONFIG_VIDEO_GO7007) += go7007/
obj-$(CONFIG_USB_IP_COMMON) += usbip/
+obj-$(CONFIG_W35UND) += winbond/
diff --git a/drivers/staging/winbond/Kconfig b/drivers/staging/winbond/Kconfig
new file mode 100644
index 0000000..10d72be
--- /dev/null
+++ b/drivers/staging/winbond/Kconfig
@@ -0,0 +1,7 @@
+config W35UND
+ tristate "Winbond driver"
+ depends on MAC80211 && WLAN_80211 && EXPERIMENTAL && !4KSTACKS
+ default n
+ ---help---
+ This is highly experimental driver for winbond wifi card on some Kohjinsha notebooks
+ Check http://code.google.com/p/winbondport/ for new version
diff --git a/drivers/staging/winbond/Makefile b/drivers/staging/winbond/Makefile
new file mode 100644
index 0000000..29c98bf
--- /dev/null
+++ b/drivers/staging/winbond/Makefile
@@ -0,0 +1,18 @@
+ DRIVER_DIR=./linux
+
+w35und-objs := $(DRIVER_DIR)/wbusb.o $(DRIVER_DIR)/wb35reg.o $(DRIVER_DIR)/wb35rx.o $(DRIVER_DIR)/wb35tx.o \
+ mds.o \
+ mlmetxrx.o \
+ mto.o \
+ phy_calibration.o \
+ reg.o \
+ rxisr.o \
+ sme_api.o \
+ wbhal.o \
+ wblinux.o \
+
+
+obj-$(CONFIG_W35UND) += w35und.o
+
+
+
diff --git a/drivers/staging/winbond/README b/drivers/staging/winbond/README
new file mode 100644
index 0000000..707b6b3
--- /dev/null
+++ b/drivers/staging/winbond/README
@@ -0,0 +1,10 @@
+TODO:
+ - sparse cleanups
+ - checkpatch cleanups
+ - kerneldoc cleanups
+ - remove typedefs
+ - remove unused ioctls
+ - use cfg80211 for regulatory stuff
+
+Please send patches to Greg Kroah-Hartman <greg@kroah.com> and
+Pavel Machek <pavel@suse.cz>
diff --git a/drivers/staging/winbond/adapter.h b/drivers/staging/winbond/adapter.h
new file mode 100644
index 0000000..609701d
--- /dev/null
+++ b/drivers/staging/winbond/adapter.h
@@ -0,0 +1,23 @@
+//
+// ADAPTER.H -
+// Windows NDIS global variable 'Adapter' typedef
+//
+#define MAX_ANSI_STRING 40
+typedef struct WB32_ADAPTER
+{
+ u32 AdapterIndex; // 20060703.4 Add for using pAdapterContext global Adapter point
+
+ WB_LOCALDESCRIPT sLocalPara; // Myself connected parameters
+ PWB_BSSDESCRIPTION asBSSDescriptElement;
+
+ MLME_FRAME sMlmeFrame; // connect to peerSTA parameters
+
+ MTO_PARAMETERS sMtoPara; // MTO_struct ...
+ hw_data_t sHwData; //For HAL
+ MDS Mds;
+
+ WBLINUX WbLinux;
+ struct iw_statistics iw_stats;
+
+ u8 LinkName[MAX_ANSI_STRING];
+} WB32_ADAPTER, ADAPTER, *PWB32_ADAPTER, *PADAPTER;
diff --git a/drivers/staging/winbond/bss_f.h b/drivers/staging/winbond/bss_f.h
new file mode 100644
index 0000000..c957bc9
--- /dev/null
+++ b/drivers/staging/winbond/bss_f.h
@@ -0,0 +1,59 @@
+//
+// BSS descriptor DataBase management global function
+//
+
+void vBSSdescriptionInit(PWB32_ADAPTER Adapter);
+void vBSSfoundList(PWB32_ADAPTER Adapter);
+u8 boChanFilter(PWB32_ADAPTER Adapter, u8 ChanNo);
+u16 wBSSallocateEntry(PWB32_ADAPTER Adapter);
+u16 wBSSGetEntry(PWB32_ADAPTER Adapter);
+void vSimpleHouseKeeping(PWB32_ADAPTER Adapter);
+u16 wBSShouseKeeping(PWB32_ADAPTER Adapter);
+void ClearBSSdescpt(PWB32_ADAPTER Adapter, u16 i);
+u16 wBSSfindBssID(PWB32_ADAPTER Adapter, u8 *pbBssid);
+u16 wBSSfindDedicateCandidate(PWB32_ADAPTER Adapter, struct SSID_Element *psSsid, u8 *pbBssid);
+u16 wBSSfindMACaddr(PWB32_ADAPTER Adapter, u8 *pbMacAddr);
+u16 wBSSsearchMACaddr(PWB32_ADAPTER Adapter, u8 *pbMacAddr, u8 band);
+u16 wBSSaddScanData(PWB32_ADAPTER, u16, psRXDATA);
+u16 wBSSUpdateScanData(PWB32_ADAPTER Adapter, u16 wBssIdx, psRXDATA psRcvData);
+u16 wBSScreateIBSSdata(PWB32_ADAPTER Adapter, PWB_BSSDESCRIPTION psDesData);
+void DesiredRate2BSSdescriptor(PWB32_ADAPTER Adapter, PWB_BSSDESCRIPTION psDesData,
+ u8 *pBasicRateSet, u8 BasicRateCount,
+ u8 *pOperationRateSet, u8 OperationRateCount);
+void DesiredRate2InfoElement(PWB32_ADAPTER Adapter, u8 *addr, u16 *iFildOffset,
+ u8 *pBasicRateSet, u8 BasicRateCount,
+ u8 *pOperationRateSet, u8 OperationRateCount);
+void BSSAddIBSSdata(PWB32_ADAPTER Adapter, PWB_BSSDESCRIPTION psDesData);
+unsigned char boCmpMacAddr( PUCHAR, PUCHAR );
+unsigned char boCmpSSID(struct SSID_Element *psSSID1, struct SSID_Element *psSSID2);
+u16 wBSSfindSSID(PWB32_ADAPTER Adapter, struct SSID_Element *psSsid);
+u16 wRoamingQuery(PWB32_ADAPTER Adapter);
+void vRateToBitmap(PWB32_ADAPTER Adapter, u16 index);
+u8 bRateToBitmapIndex(PWB32_ADAPTER Adapter, u8 bRate);
+u8 bBitmapToRate(u8 i);
+unsigned char boIsERPsta(PWB32_ADAPTER Adapter, u16 i);
+unsigned char boCheckConnect(PWB32_ADAPTER Adapter);
+unsigned char boCheckSignal(PWB32_ADAPTER Adapter);
+void AddIBSSIe(PWB32_ADAPTER Adapter,PWB_BSSDESCRIPTION psDesData );//added by ws for WPA_None06/01/04
+void BssScanUpToDate(PWB32_ADAPTER Adapter);
+void BssUpToDate(PWB32_ADAPTER Adapter);
+void RateSort(u8 *RateArray, u8 num, u8 mode);
+void RateReSortForSRate(PWB32_ADAPTER Adapter, u8 *RateArray, u8 num);
+void Assemble_IE(PWB32_ADAPTER Adapter, u16 wBssIdx);
+void SetMaxTxRate(PWB32_ADAPTER Adapter);
+
+void CreateWpaIE(PWB32_ADAPTER Adapter, u16* iFildOffset, PUCHAR msg, struct Management_Frame* msgHeader,
+ struct Association_Request_Frame_Body* msgBody, u16 iMSindex); //added by WS 05/14/05
+
+#ifdef _WPA2_
+void CreateRsnIE(PWB32_ADAPTER Adapter, u16* iFildOffset, PUCHAR msg, struct Management_Frame* msgHeader,
+ struct Association_Request_Frame_Body* msgBody, u16 iMSindex);//added by WS 05/14/05
+
+u16 SearchPmkid(PWB32_ADAPTER Adapter, struct Management_Frame* msgHeader,
+ struct PMKID_Information_Element * AssoReq_PMKID );
+#endif
+
+
+
+
+
diff --git a/drivers/staging/winbond/bssdscpt.h b/drivers/staging/winbond/bssdscpt.h
new file mode 100644
index 0000000..97150a2
--- /dev/null
+++ b/drivers/staging/winbond/bssdscpt.h
@@ -0,0 +1,156 @@
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+// bssdscpt.c
+// BSS descriptor data base
+// history :
+//
+// Description:
+// BSS descriptor data base will store the information of the stations at the
+// surrounding environment. The first entry( psBSS(0) ) will not be used and the
+// second one( psBSS(1) ) will be used for the broadcast address.
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+//#define MAX_ACC_RSSI_COUNT 10
+#define MAX_ACC_RSSI_COUNT 6
+
+///////////////////////////////////////////////////////////////////////////
+//
+// BSS Description set Element , to store scan received Beacon information
+//
+// Our's differs slightly from the specs. The specify a PHY_Parameter_Set.
+// Since we're only doing a DS design right now, we just have a DS structure.
+//////////////////////////////////////////////////////////////////////////////
+typedef struct BSSDescriptionElement
+{
+ u32 SlotValid;
+ u32 PowerSaveMode;
+ RXLAYER1 RxLayer1;
+
+ u8 abPeerAddress[ MAC_ADDR_LENGTH + 2 ]; // peer MAC Address associated with this session. 6-OCTET value
+ u32 dwBgScanStamp; // BgScan Sequence Counter stamp, record psROAM->dwScanCounter.
+
+ u16 Beacon_Period;
+ u16 wATIM_Window;
+
+ u8 abBssID[ MAC_ADDR_LENGTH + 2 ]; // 6B
+
+ u8 bBssType;
+ u8 DTIM_Period; // 1 octet usually from TIM element, if present
+ u8 boInTimerHandler;
+ u8 boERP; // analysis ERP or (extended) supported rate element
+
+ u8 Timestamp[8];
+ u8 BasicRate[32];
+ u8 OperationalRate[32];
+ u32 dwBasicRateBitmap; //bit map, retrieve from SupportedRateSet
+ u32 dwOperationalRateBitmap; //bit map, retrieve from SupportedRateSet and
+ // ExtendedSupportedRateSet
+ // For RSSI calculating
+ u32 HalRssi[MAX_ACC_RSSI_COUNT]; // Encode. It must use MACRO of HAL to get the LNA and AGC data
+ u32 HalRssiIndex;
+
+ ////From beacon/probe response
+ struct SSID_Element SSID; // 34B
+ u8 reserved_1[ 2 ];
+
+ struct Capability_Information_Element CapabilityInformation; // 2B
+ u8 reserved_2[ 2 ];
+
+ struct CF_Parameter_Set_Element CF_Parameter_Set; // 8B
+ struct IBSS_Parameter_Set_Element IBSS_Parameter_Set; // 4B
+ struct TIM_Element TIM_Element_Set; // 256B
+
+ struct DS_Parameter_Set_Element DS_Parameter_Set; // 3B
+ u8 reserved_3;
+
+ struct ERP_Information_Element ERP_Information_Set; // 3B
+ u8 reserved_4;
+
+ struct Supported_Rates_Element SupportedRateSet; // 10B
+ u8 reserved_5[2];
+
+ struct Extended_Supported_Rates_Element ExtendedSupportedRateSet; // 257B
+ u8 reserved_6[3];
+
+ u8 band;
+ u8 reserved_7[3];
+
+ // for MLME module
+ u16 wState; // the current state of the system
+ u16 wIndex; // THIS BSS element entry index
+
+ void* psAdapter; // pointer to THIS Adapter
+ OS_TIMER nTimer; // MLME timer
+
+ // Authentication
+ u16 wAuthAlgo; // peer MAC MLME use Auth algorithm, default OPEN_AUTH
+ u16 wAuthSeqNum; // current local MAC sendout AuthReq sequence number
+
+ u8 auth_challengeText[128];
+
+ ////For XP:
+ u32 ies_len; // information element length
+ u8 ies[256]; // information element
+
+ ////For WPA
+ u8 RsnIe_Type[2]; //added by ws for distinguish WPA and WPA2 05/14/04
+ u8 RsnIe_len;
+ u8 Rsn_Num;
+
+ // to record the rsn cipher suites,addded by ws 09/05/04
+ SUITE_SELECTOR group_cipher; // 4B
+ SUITE_SELECTOR pairwise_key_cipher_suites[WLAN_MAX_PAIRWISE_CIPHER_SUITE_COUNT];
+ SUITE_SELECTOR auth_key_mgt_suites[WLAN_MAX_AUTH_KEY_MGT_SUITE_LIST_COUNT];
+
+ u16 pairwise_key_cipher_suite_count;
+ u16 auth_key_mgt_suite_count;
+
+ u8 pairwise_key_cipher_suite_selected;
+ u8 auth_key_mgt_suite_selected;
+ u8 reserved_8[2];
+
+ struct RSN_Capability_Element rsn_capabilities; // 2B
+ u8 reserved_9[2];
+
+ //to record the rsn cipher suites for WPA2
+ #ifdef _WPA2_
+ u32 pre_auth; //added by WS for distinguish for 05/04/04
+ SUITE_SELECTOR wpa2_group_cipher; // 4B
+ SUITE_SELECTOR wpa2_pairwise_key_cipher_suites[WLAN_MAX_PAIRWISE_CIPHER_SUITE_COUNT];
+ SUITE_SELECTOR wpa2_auth_key_mgt_suites[WLAN_MAX_AUTH_KEY_MGT_SUITE_LIST_COUNT];
+
+ u16 wpa2_pairwise_key_cipher_suite_count;
+ u16 wpa2_auth_key_mgt_suite_count;
+
+ u8 wpa2_pairwise_key_cipher_suite_selected;
+ u8 wpa2_auth_key_mgt_suite_selected;
+ u8 reserved_10[2];
+
+ struct RSN_Capability_Element wpa2_rsn_capabilities; // 2B
+ u8 reserved_11[2];
+ #endif //endif _WPA2_
+
+ //For Replay protection
+// u8 PairwiseTSC[6];
+// u8 GroupTSC[6];
+
+ ////For up-to-date
+ u32 ScanTimeStamp; //for the decision whether the station/AP(may exist at
+ //different channels) has left. It must be detected by
+ //scanning. Local device may connected or disconnected.
+ u32 BssTimeStamp; //Only for the decision whether the station/AP(exist in
+ //the same channel, and no scanning) if local device has
+ //connected successfully.
+
+ // 20061108 Add for storing WPS_IE. [E id][Length][OUI][Data]
+ u8 WPS_IE_Data[MAX_IE_APPEND_SIZE];
+ u16 WPS_IE_length;
+ u16 WPS_IE_length_tmp; // For verify there is an WPS_IE in Beacon or probe response
+
+} WB_BSSDESCRIPTION, *PWB_BSSDESCRIPTION;
+
+#define wBSSConnectedSTA(Adapter) \
+ ((u16)(Adapter)->sLocalPara.wConnectedSTAindex)
+
+#define psBSS(i) (&(Adapter->asBSSDescriptElement[(i)]))
+
+
diff --git a/drivers/staging/winbond/ds_tkip.h b/drivers/staging/winbond/ds_tkip.h
new file mode 100644
index 0000000..29e5055
--- /dev/null
+++ b/drivers/staging/winbond/ds_tkip.h
@@ -0,0 +1,33 @@
+// Rotation functions on 32 bit values
+#define ROL32( A, n ) \
+ ( ((A) << (n)) | ( ((A)>>(32-(n))) & ( (1UL << (n)) - 1 ) ) )
+
+#define ROR32( A, n ) ROL32( (A), 32-(n) )
+
+
+typedef struct tkip
+{
+ u32 K0, K1; // Key
+ union
+ {
+ struct // Current state
+ {
+ u32 L;
+ u32 R;
+ };
+ u8 LR[8];
+ };
+ union
+ {
+ u32 M; // Message accumulator (single word)
+ u8 Mb[4];
+ };
+ s32 bytes_in_M; // # bytes in M
+} tkip_t;
+
+//void _append_data( PUCHAR pData, u16 size, tkip_t *p );
+void Mds_MicGet( void* Adapter, void* pRxLayer1, PUCHAR pKey, PUCHAR pMic );
+void Mds_MicFill( void* Adapter, void* pDes, PUCHAR XmitBufAddress );
+
+
+
diff --git a/drivers/staging/winbond/gl_80211.h b/drivers/staging/winbond/gl_80211.h
new file mode 100644
index 0000000..1806d81
--- /dev/null
+++ b/drivers/staging/winbond/gl_80211.h
@@ -0,0 +1,125 @@
+
+#ifndef __GL_80211_H__
+#define __GL_80211_H__
+
+/****************** CONSTANT AND MACRO SECTION ******************************/
+
+/* BSS Type */
+enum {
+ WLAN_BSSTYPE_INFRASTRUCTURE = 0,
+ WLAN_BSSTYPE_INDEPENDENT,
+ WLAN_BSSTYPE_ANY_BSS,
+};
+
+
+
+/* Preamble_Type, see <SFS-802.11G-MIB-203> */
+typedef enum preamble_type {
+ WLAN_PREAMBLE_TYPE_SHORT,
+ WLAN_PREAMBLE_TYPE_LONG,
+} preamble_type_e;
+
+
+/* Slot_Time_Type, see <SFS-802.11G-MIB-208> */
+typedef enum slot_time_type {
+ WLAN_SLOT_TIME_TYPE_LONG,
+ WLAN_SLOT_TIME_TYPE_SHORT,
+} slot_time_type_e;
+
+/*--------------------------------------------------------------------------*/
+/* Encryption Mode */
+typedef enum {
+ WEP_DISABLE = 0,
+ WEP_64,
+ WEP_128,
+
+ ENCRYPT_DISABLE,
+ ENCRYPT_WEP,
+ ENCRYPT_WEP_NOKEY,
+ ENCRYPT_TKIP,
+ ENCRYPT_TKIP_NOKEY,
+ ENCRYPT_CCMP,
+ ENCRYPT_CCMP_NOKEY,
+} encryption_mode_e;
+
+typedef enum _WLAN_RADIO {
+ WLAN_RADIO_ON,
+ WLAN_RADIO_OFF,
+ WLAN_RADIO_MAX, // not a real type, defined as an upper bound
+} WLAN_RADIO;
+
+typedef struct _WLAN_RADIO_STATUS {
+ WLAN_RADIO HWStatus;
+ WLAN_RADIO SWStatus;
+} WLAN_RADIO_STATUS;
+
+//----------------------------------------------------------------------------
+// 20041021 1.1.81.1000 ybjiang
+// add for radio notification
+typedef
+void (*RADIO_NOTIFICATION_HANDLER)(
+ void *Data,
+ void *RadioStatusBuffer,
+ u32 RadioStatusBufferLen
+ );
+
+typedef struct _WLAN_RADIO_NOTIFICATION
+{
+ RADIO_NOTIFICATION_HANDLER RadioChangeHandler;
+ void *Data;
+} WLAN_RADIO_NOTIFICATION;
+
+//----------------------------------------------------------------------------
+// 20041102 1.1.91.1000 ybjiang
+// add for OID_802_11_CUST_REGION_CAPABILITIES and OID_802_11_OID_REGION
+typedef enum _WLAN_REGION_CODE
+{
+ WLAN_REGION_UNKNOWN,
+ WLAN_REGION_EUROPE,
+ WLAN_REGION_JAPAN,
+ WLAN_REGION_USA,
+ WLAN_REGION_FRANCE,
+ WLAN_REGION_SPAIN,
+ WLAN_REGION_ISRAEL,
+ WLAN_REGION_MAX, // not a real type, defined as an upper bound
+} WLAN_REGION_CODE;
+
+#define REGION_NAME_MAX_LENGTH 256
+
+typedef struct _WLAN_REGION_CHANNELS
+{
+ u32 Length;
+ u32 NameLength;
+ u8 Name[REGION_NAME_MAX_LENGTH];
+ WLAN_REGION_CODE Code;
+ u32 Frequency[1];
+} WLAN_REGION_CHANNELS;
+
+typedef struct _WLAN_REGION_CAPABILITIES
+{
+ u32 NumberOfItems;
+ WLAN_REGION_CHANNELS Region[1];
+} WLAN_REGION_CAPABILITIES;
+
+typedef struct _region_name_map {
+ WLAN_REGION_CODE region;
+ u8 *name;
+ u32 *channels;
+} region_name_map;
+
+/*--------------------------------------------------------------------------*/
+#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
+#define MACSTR "%02X:%02X:%02X:%02X:%02X:%02X"
+
+// TODO: 0627 kevin
+#define MIC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5], (a)[6], (a)[7]
+#define MICSTR "%02X %02X %02X %02X %02X %02X %02X %02X"
+
+#define MICKEY2STR(a) MIC2STR(a)
+#define MICKEYSTR MICSTR
+
+
+#endif /* __GL_80211_H__ */
+/*** end of file ***/
+
+
diff --git a/drivers/staging/winbond/ioctls.h b/drivers/staging/winbond/ioctls.h
new file mode 100644
index 0000000..e8b35dc
--- /dev/null
+++ b/drivers/staging/winbond/ioctls.h
@@ -0,0 +1,678 @@
+//============================================================================
+// IOCTLS.H -
+//
+// Description:
+// Define the IOCTL codes.
+//
+// Revision history:
+// --------------------------------------------------------------------------
+//
+// Copyright (c) 2002-2004 Winbond Electronics Corp. All rights reserved.
+//=============================================================================
+
+#ifndef _IOCTLS_H
+#define _IOCTLS_H
+
+// PD43 Keep it - Used with the Win33 application
+// #include <winioctl.h>
+
+//========================================================
+// 20040108 ADD the follow for test
+//========================================================
+#define INFORMATION_LENGTH sizeof(unsigned int)
+
+#define WB32_IOCTL_INDEX 0x0900 //×§ďĽHŤKŹŰŽe//
+
+#define Wb32_RegisterRead CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB32_IOCTL_INDEX + 0, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define Wb32_RegisterWrite CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB32_IOCTL_INDEX + 1, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define Wb32_SendPacket CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB32_IOCTL_INDEX + 2, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define Wb32_QuerySendResult CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB32_IOCTL_INDEX + 3, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define Wb32_SetFragmentThreshold CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB32_IOCTL_INDEX + 4, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define Wb32_SetLinkStatus CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB32_IOCTL_INDEX + 5, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define Wb32_SetBulkIn CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB32_IOCTL_INDEX + 6, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define Wb32_LoopbackTest CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB32_IOCTL_INDEX + 7, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define Wb35_EEPromRead CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB32_IOCTL_INDEX + 8, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define Wb35_EEPromWrite CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB32_IOCTL_INDEX + 9, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define Wb35_FlashReadData CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB32_IOCTL_INDEX + 10, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define Wb35_FlashWrite CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB32_IOCTL_INDEX + 11, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define Wb35_FlashWriteBurst CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB32_IOCTL_INDEX + 12, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define Wb35_TxBurstStart CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB32_IOCTL_INDEX + 13, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define Wb35_TxBurstStop CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB32_IOCTL_INDEX + 14, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define Wb35_TxBurstStatus CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB32_IOCTL_INDEX + 15, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// For IOCTL interface
+//================================================
+#define LINKNAME_STRING "\\DosDevices\\W35UND"
+#define NTDEVICE_STRING "\\Device\\W35UND"
+#define APPLICATION_LINK "\\\\.\\W35UND"
+
+#define WB_IOCTL_INDEX 0x0800
+#define WB_IOCTL_TS_INDEX WB_IOCTL_INDEX + 60
+#define WB_IOCTL_DUT_INDEX WB_IOCTL_TS_INDEX + 40
+
+//=============================================================================
+// IOCTLS defined for DUT (Device Under Test)
+
+// IOCTL_WB_802_11_DUT_MAC_ADDRESS
+// Query: Return the dot11StationID
+// Set : Set the dot11StationID. Demo only.
+//
+#define IOCTL_WB_802_11_DUT_MAC_ADDRESS CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 1, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_BSS_DESCRIPTION
+// Query: Return the info. of the current connected BSS.
+// Set : None.
+//
+#define IOCTL_WB_802_11_DUT_BSS_DESCRIPTION CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 2, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_TX_RATE
+// Query: Return the current transmission rate.
+// Set : Set the transmission rate of the Tx packets.
+//
+#define IOCTL_WB_802_11_DUT_TX_RATE CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 3, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_CURRENT_STA_STATE
+// Query: Return the current STA state. (WB_STASTATE type)
+// Set : None.
+//
+#define IOCTL_WB_802_11_DUT_CURRENT_STA_STATE CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 4, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+/////////// 10/31/02' Added /////////////////////
+
+// IOCTL_WB_802_11_DUT_START_IBSS_REQUEST
+// Query: None.
+// Set : Start a new IBSS
+//
+#define IOCTL_WB_802_11_DUT_START_IBSS_REQUEST CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 5, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_JOIN_REQUEST
+// Query: None.
+// Set : Synchronize with the selected BSS
+//
+#define IOCTL_WB_802_11_DUT_JOIN_REQUEST CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 6, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_AUTHEN_REQUEST
+// Query: None.
+// Set : Authenticate with the BSS
+//
+#define IOCTL_WB_802_11_DUT_AUTHEN_REQUEST CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 7, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_DEAUTHEN_REQUEST
+// Query: None.
+// Set : DeAuthenticate withe the BSS
+//
+#define IOCTL_WB_802_11_DUT_DEAUTHEN_REQUEST CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 8, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_ASSOC_REQUEST
+// Query: None.
+// Set : Associate withe the BSS
+//
+#define IOCTL_WB_802_11_DUT_ASSOC_REQUEST CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 9, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_REASSOC_REQUEST
+// Query: None.
+// Set : ReAssociate withe the BSS
+//
+#define IOCTL_WB_802_11_DUT_REASSOC_REQUEST CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 10, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+
+// IOCTL_WB_802_11_DUT_DISASSOC_REQUEST
+// Query: None.
+// Set : DisAssociate withe the BSS
+//
+#define IOCTL_WB_802_11_DUT_DISASSOC_REQUEST CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 11, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_FRAG_THRESHOLD
+// Query: Return the dot11FragmentThreshold
+// Set : Set the dot11FragmentThreshold
+//
+#define IOCTL_WB_802_11_DUT_FRAG_THRESHOLD CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 12, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_RTS_THRESHOLD
+// Query: Return the dot11RTSThreshold
+// Set : Set the dot11RTSThresold
+//
+#define IOCTL_WB_802_11_DUT_RTS_THRESHOLD CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 13, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_WEP_KEYMODE
+// Query: Get the WEP key mode.
+// Set : Set the WEP key mode: disable/64 bits/128 bits
+//
+#define IOCTL_WB_802_11_DUT_WEP_KEYMODE CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 14, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_WEP_KEYVALUE
+// Query: None.
+// Set : fill in the WEP key value
+//
+#define IOCTL_WB_802_11_DUT_WEP_KEYVALUE CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 15, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_RESET
+// Query: None.
+// Set : Reset S/W and H/W
+//
+#define IOCTL_WB_802_11_DUT_RESET CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 16, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_POWER_SAVE
+// Query: None.
+// Set : Set Power Save Mode
+//
+#define IOCTL_WB_802_11_DUT_POWER_SAVE CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 17, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_BSSID_LIST_SCAN
+// Query: None.
+// Set :
+//
+#define IOCTL_WB_802_11_DUT_BSSID_LIST_SCAN CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 18, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_BSSID_LIST
+// Query: Return the BSS info of BSSs in the last scanning process
+// Set : None.
+//
+#define IOCTL_WB_802_11_DUT_BSSID_LIST CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 19, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_STATISTICS
+// Query: Return the statistics of Tx/Rx.
+// Set : None.
+//
+#define IOCTL_WB_802_11_DUT_STATISTICS CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 20, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_ACCEPT_BEACON
+// Query: Return the current mode to accept beacon or not.
+// Set : Enable or disable allowing the HW-MAC to pass the beacon to the SW-MAC
+// Arguments: unsigned char
+//
+#define IOCTL_WB_802_11_DUT_ACCEPT_BEACON CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 21, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_ROAMING
+// Query: Return the roaming function status
+// Set : Enable/Disable the roaming function.
+#define IOCTL_WB_802_11_DUT_ROAMING CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 22, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_DTO
+// Query: Return the DTO(Data Throughput Optimization)
+// function status (TRUE or FALSE)
+// Set : Enable/Disable the DTO function.
+//
+#define IOCTL_WB_802_11_DUT_DTO CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 23, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_ANTENNA_DIVERSITY
+// Query: Return the antenna diversity status. (TRUE/ON or FALSE/OFF)
+// Set : Enable/Disable the antenna diversity.
+//
+#define IOCTL_WB_802_11_DUT_ANTENNA_DIVERSITY CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 24, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+//-------------- new added for a+b+g ---------------------
+// IOCTL_WB_802_11_DUT_MAC_OPERATION_MODE
+// Query: Return the MAC operation mode. (MODE_802_11_BG, MODE_802_11_A,
+// MODE_802_11_ABG, MODE_802_11_BG_IBSS)
+// Set : Set the MAC operation mode.
+//
+#define IOCTL_WB_802_11_DUT_MAC_OPERATION_MODE CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 25, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_TX_RATE_REDEFINED
+// Query: Return the current tx rate which follows the definition in spec. (for
+// example, 5.5M => 0x0b)
+// Set : None
+//
+#define IOCTL_WB_802_11_DUT_TX_RATE_REDEFINED CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 26, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_PREAMBLE_MODE
+// Query: Return the preamble mode. (auto or long)
+// Set : Set the preamble mode.
+//
+#define IOCTL_WB_802_11_DUT_PREAMBLE_MODE CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 27, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_SLOT_TIME_MODE
+// Query: Return the slot time mode. (auto or long)
+// Set : Set the slot time mode.
+//
+#define IOCTL_WB_802_11_DUT_SLOT_TIME_MODE CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 28, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+//------------------------------------------------------------------
+
+// IOCTL_WB_802_11_DUT_ADVANCE_STATUS
+// Query:
+// Set : NONE
+//
+#define IOCTL_WB_802_11_DUT_ADVANCE_STATUS CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 29, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_TX_RATE_MODE
+// Query: Return the tx rate mode. (RATE_AUTO, RATE_1M, .., RATE_54M, RATE_MAX)
+// Set : Set the tx rate mode. (RATE_AUTO, RATE_1M, .., RATE_54M, RATE_MAX)
+//
+#define IOCTL_WB_802_11_DUT_TX_RATE_MODE CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 30, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_DTO_PARA
+// Query: Return the DTO parameters
+// Set : Set the DTO parameters
+//
+#define IOCTL_WB_802_11_DUT_DTO_PARA CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 31, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_EVENT_LOG
+// Query: Return event log
+// Set : Reset event log
+//
+#define IOCTL_WB_802_11_DUT_EVENT_LOG CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 32, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_CWMIN
+// Query: NONE(It will be obtained by IOCTL_WB_802_11_DUT_ADVANCE_STATUS)
+// Set : Set CWMin value
+//
+#define IOCTL_WB_802_11_DUT_CWMIN CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 33, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_DUT_CWMAX
+// Query: NONE(It will be obtained by IOCTL_WB_802_11_DUT_ADVANCE_STATUS)
+// Set : Set CWMax value
+//
+#define IOCTL_WB_802_11_DUT_CWMAX CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_DUT_INDEX + 34, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+
+//==========================================================
+// IOCTLs for Testing
+
+// IOCTL_WB_802_11_TS_SET_CXX_REG
+// Query: None
+// Set : Write the value to one of Cxx register.
+//
+#define IOCTL_WB_802_11_TS_SET_CXX_REG CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_TS_INDEX + 0, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_TS_GET_CXX_REG
+// Query: Return the value of the Cxx register.
+// Set : Write the reg no. (0x00, 0x04, 0x08 etc)
+//
+#define IOCTL_WB_802_11_TS_GET_CXX_REG CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_TS_INDEX + 1, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_TS_SET_DXX_REG
+// Query: None
+// Set : Write the value to one of Dxx register.
+//
+#define IOCTL_WB_802_11_TS_SET_DXX_REG CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_TS_INDEX + 2, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// IOCTL_WB_802_11_TS_GET_DXX_REG
+// Query: Return the value of the Dxx register.
+// Set : Write the reg no. (0x00, 0x04, 0x08 etc)
+//
+#define IOCTL_WB_802_11_TS_GET_DXX_REG CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_TS_INDEX + 3, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+//============================================================
+// [TS]
+
+#define IOCTL_WB_802_11_TS_TX_RATE CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_TS_INDEX + 4, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_WB_802_11_TS_CURRENT_CHANNEL CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_TS_INDEX + 5, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_WB_802_11_TS_ENABLE_SEQNO CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_TS_INDEX + 6, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_WB_802_11_TS_ENALBE_ACKEDPACKET CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_TS_INDEX + 7, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_WB_802_11_TS_INHIBIT_CRC CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_TS_INDEX + 8, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_WB_802_11_TS_RESET_RCV_COUNTER CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_TS_INDEX + 9, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_WB_802_11_TS_SET_TX_TRIGGER CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_TS_INDEX + 10, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_WB_802_11_TS_FAILED_TX_COUNT CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_TS_INDEX + 11, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// [TS1]
+#define IOCTL_WB_802_11_TS_TX_POWER CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_TS_INDEX + 12, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_WB_802_11_TS_MODE_ENABLE CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_TS_INDEX + 13, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_WB_802_11_TS_MODE_DISABLE CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_TS_INDEX + 14, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_WB_802_11_TS_ANTENNA CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_TS_INDEX + 15, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_WB_802_11_TS_ADAPTER_INFO CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_TS_INDEX + 16, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_WB_802_11_TS_MAC_ADDRESS CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_TS_INDEX + 17, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_WB_802_11_TS_BSSID CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_TS_INDEX + 18, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_WB_802_11_TS_RF_PARAMETER CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_TS_INDEX + 19, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_WB_802_11_TS_FILTER CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_TS_INDEX + 20, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_WB_802_11_TS_CALIBRATION CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_TS_INDEX + 21, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_WB_802_11_TS_BSS_MODE CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_TS_INDEX + 22, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_WB_802_11_TS_SET_SSID CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_TS_INDEX + 23, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_WB_802_11_TS_IBSS_CHANNEL CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_TS_INDEX + 24, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+// set/query the slot time value(short or long slot time)
+#define IOCTL_WB_802_11_TS_SLOT_TIME CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_TS_INDEX + 25, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_WB_802_11_TS_SLOT_TIME CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_TS_INDEX + 25, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#define IOCTL_WB_802_11_TS_RX_STATISTICS CTL_CODE( \
+ FILE_DEVICE_UNKNOWN, \
+ WB_IOCTL_TS_INDEX + 26, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+
+#endif // #ifndef _IOCTLS_H
+
+
diff --git a/drivers/staging/winbond/linux/common.h b/drivers/staging/winbond/linux/common.h
new file mode 100644
index 0000000..6b00bad
--- /dev/null
+++ b/drivers/staging/winbond/linux/common.h
@@ -0,0 +1,143 @@
+//
+// common.h
+//
+// This file contains the OS dependant definition and function.
+// Every OS has this file individual.
+//
+
+#define DebugUsbdStatusInformation( _A )
+
+#ifndef COMMON_DEF
+#define COMMON_DEF
+
+#include <linux/version.h>
+#include <linux/usb.h>
+#include <linux/kernel.h> //need for kernel alert
+#include <linux/autoconf.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/slab.h> //memory allocate
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>//need for init and exit modules marco
+#include <linux/ctype.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/wireless.h>
+#include <linux/if_arp.h>
+#include <asm/uaccess.h>
+#include <net/iw_handler.h>
+#include <linux/skbuff.h>
+
+
+//#define DEBUG_ENABLED 1
+
+
+
+//===============================================================
+// Common type definition
+//===============================================================
+
+typedef u8* PUCHAR;
+typedef s8* PCHAR;
+typedef u8* PBOOLEAN;
+typedef u16* PUSHORT;
+typedef u32* PULONG;
+typedef s16* PSHORT;
+
+
+//===========================================
+#define IGNORE 2
+#define SUCCESS 1
+#define FAILURE 0
+
+
+#ifndef true
+#define true 1
+#endif
+
+#ifndef false
+#define false 0
+#endif
+
+// PD43 20021108
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define STATUS_MEDIA_CONNECT 1
+#define STATUS_MEDIA_DISCONNECT 0
+
+#ifndef BIT
+#define BIT(x) (1 << (x))
+#endif
+
+typedef struct urb * PURB;
+
+
+
+//==================================================================================================
+// Common function definition
+//==================================================================================================
+#ifndef abs
+#define abs(_T) ((_T) < 0 ? -_T : _T)
+#endif
+#define DEBUG_ENABLED
+#define ETH_LENGTH_OF_ADDRESS 6
+#ifdef DEBUG_ENABLED
+#define WBDEBUG( _M ) printk _M
+#else
+#define WBDEBUG( _M ) 0
+#endif
+
+#define OS_DISCONNECTED 0
+#define OS_CONNECTED 1
+
+
+#define OS_EVENT_INDICATE( _A, _B, _F )
+#define OS_PMKID_STATUS_EVENT( _A )
+
+
+/* Uff, no, longs are not atomic on all architectures Linux
+ * supports. This should really use atomic_t */
+
+#define OS_ATOMIC u32
+#define OS_ATOMIC_READ( _A, _V ) _V
+#define OS_ATOMIC_INC( _A, _V ) EncapAtomicInc( _A, (void*)_V )
+#define OS_ATOMIC_DEC( _A, _V ) EncapAtomicDec( _A, (void*)_V )
+#define OS_MEMORY_CLEAR( _A, _S ) memset( (PUCHAR)_A,0,_S)
+#define OS_MEMORY_COMPARE( _A, _B, _S ) (memcmp(_A,_B,_S)? 0 : 1) // Definition is reverse with Ndis 1: the same 0: different
+
+
+#define OS_SPIN_LOCK spinlock_t
+#define OS_SPIN_LOCK_ALLOCATE( _S ) spin_lock_init( _S );
+#define OS_SPIN_LOCK_FREE( _S )
+#define OS_SPIN_LOCK_ACQUIRED( _S ) spin_lock_irq( _S )
+#define OS_SPIN_LOCK_RELEASED( _S ) spin_unlock_irq( _S );
+
+#define OS_TIMER struct timer_list
+#define OS_TIMER_INITIAL( _T, _F, _P ) \
+{ \
+ init_timer( _T ); \
+ (_T)->function = (void *)_F##_1a; \
+ (_T)->data = (unsigned long)_P; \
+}
+
+// _S : Millisecond
+// 20060420 At least 1 large than jiffies
+#define OS_TIMER_SET( _T, _S ) \
+{ \
+ (_T)->expires = jiffies + ((_S*HZ+999)/1000);\
+ add_timer( _T ); \
+}
+#define OS_TIMER_CANCEL( _T, _B ) del_timer_sync( _T )
+#define OS_TIMER_GET_SYS_TIME( _T ) (*_T=jiffies)
+
+
+#endif // COMMON_DEF
+
diff --git a/drivers/staging/winbond/linux/sysdef.h b/drivers/staging/winbond/linux/sysdef.h
new file mode 100644
index 0000000..d46d63e
--- /dev/null
+++ b/drivers/staging/winbond/linux/sysdef.h
@@ -0,0 +1,73 @@
+
+
+//
+// Winbond WLAN System Configuration defines
+//
+
+//=====================================================================
+// Current directory is Linux
+// The definition WB_LINUX is a keyword for this OS
+//=====================================================================
+#ifndef SYS_DEF_H
+#define SYS_DEF_H
+#define WB_LINUX
+#define WB_LINUX_WPA_PSK
+
+
+//#define _IBSS_BEACON_SEQ_STICK_
+#define _USE_FALLBACK_RATE_
+//#define ANTDIV_DEFAULT_ON
+
+#define _WPA2_ // 20061122 It's needed for current Linux driver
+
+
+#ifndef _WPA_PSK_DEBUG
+#undef _WPA_PSK_DEBUG
+#endif
+
+// debug print options, mark what debug you don't need
+
+#ifdef FULL_DEBUG
+#define _PE_STATE_DUMP_
+#define _PE_TX_DUMP_
+#define _PE_RX_DUMP_
+#define _PE_OID_DUMP_
+#define _PE_DTO_DUMP_
+#define _PE_REG_DUMP_
+#define _PE_USB_INI_DUMP_
+#endif
+
+
+
+#include "common.h" // Individual file depends on OS
+
+#include "../wb35_ver.h"
+#include "../mac_structures.h"
+#include "../ds_tkip.h"
+#include "../localpara.h"
+#include "../sme_s.h"
+#include "../scan_s.h"
+#include "../mds_s.h"
+#include "../mlme_s.h"
+#include "../bssdscpt.h"
+#include "../sme_api.h"
+#include "../gl_80211.h"
+#include "../mto.h"
+#include "../wblinux_s.h"
+#include "../wbhal_s.h"
+
+
+#include "../adapter.h"
+
+#include "../mlme_mib.h"
+#include "../mds_f.h"
+#include "../bss_f.h"
+#include "../mlmetxrx_f.h"
+#include "../mto_f.h"
+#include "../wbhal_f.h"
+#include "../wblinux_f.h"
+// Kernel Timer resolution, NDIS is 10ms, 10000us
+#define MIN_TIMEOUT_VAL (10) //ms
+
+
+#endif
diff --git a/drivers/staging/winbond/linux/wb35reg.c b/drivers/staging/winbond/linux/wb35reg.c
new file mode 100644
index 0000000..2c0b454
--- /dev/null
+++ b/drivers/staging/winbond/linux/wb35reg.c
@@ -0,0 +1,747 @@
+#include "sysdef.h"
+
+extern void phy_calibration_winbond(hw_data_t *phw_data, u32 frequency);
+
+// TRUE : read command process successfully
+// FALSE : register not support
+// RegisterNo : start base
+// pRegisterData : data point
+// NumberOfData : number of register data
+// Flag : AUTO_INCREMENT - RegisterNo will auto increment 4
+// NO_INCREMENT - Function will write data into the same register
+unsigned char
+Wb35Reg_BurstWrite(phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterData, u8 NumberOfData, u8 Flag)
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ PURB pUrb = NULL;
+ PREG_QUEUE pRegQueue = NULL;
+ u16 UrbSize;
+ struct usb_ctrlrequest *dr;
+ u16 i, DataSize = NumberOfData*4;
+
+ // Module shutdown
+ if (pHwData->SurpriseRemove)
+ return FALSE;
+
+ // Trying to use burst write function if use new hardware
+ UrbSize = sizeof(REG_QUEUE) + DataSize + sizeof(struct usb_ctrlrequest);
+ OS_MEMORY_ALLOC( (void* *)&pRegQueue, UrbSize );
+ pUrb = wb_usb_alloc_urb(0);
+ if( pUrb && pRegQueue ) {
+ pRegQueue->DIRECT = 2;// burst write register
+ pRegQueue->INDEX = RegisterNo;
+ pRegQueue->pBuffer = (PULONG)((PUCHAR)pRegQueue + sizeof(REG_QUEUE));
+ memcpy( pRegQueue->pBuffer, pRegisterData, DataSize );
+ //the function for reversing register data from little endian to big endian
+ for( i=0; i<NumberOfData ; i++ )
+ pRegQueue->pBuffer[i] = cpu_to_le32( pRegQueue->pBuffer[i] );
+
+ dr = (struct usb_ctrlrequest *)((PUCHAR)pRegQueue + sizeof(REG_QUEUE) + DataSize);
+ dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE;
+ dr->bRequest = 0x04; // USB or vendor-defined request code, burst mode
+ dr->wValue = cpu_to_le16( Flag ); // 0: Register number auto-increment, 1: No auto increment
+ dr->wIndex = cpu_to_le16( RegisterNo );
+ dr->wLength = cpu_to_le16( DataSize );
+ pRegQueue->Next = NULL;
+ pRegQueue->pUsbReq = dr;
+ pRegQueue->pUrb = pUrb;
+
+ OS_SPIN_LOCK_ACQUIRED( &pWb35Reg->EP0VM_spin_lock );
+ if (pWb35Reg->pRegFirst == NULL)
+ pWb35Reg->pRegFirst = pRegQueue;
+ else
+ pWb35Reg->pRegLast->Next = pRegQueue;
+ pWb35Reg->pRegLast = pRegQueue;
+
+ OS_SPIN_LOCK_RELEASED( &pWb35Reg->EP0VM_spin_lock );
+
+ // Start EP0VM
+ Wb35Reg_EP0VM_start(pHwData);
+
+ return TRUE;
+ } else {
+ if (pUrb)
+ usb_free_urb(pUrb);
+ if (pRegQueue)
+ kfree(pRegQueue);
+ return FALSE;
+ }
+ return FALSE;
+}
+
+void
+Wb35Reg_Update(phw_data_t pHwData, u16 RegisterNo, u32 RegisterValue)
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ switch (RegisterNo) {
+ case 0x3b0: pWb35Reg->U1B0 = RegisterValue; break;
+ case 0x3bc: pWb35Reg->U1BC_LEDConfigure = RegisterValue; break;
+ case 0x400: pWb35Reg->D00_DmaControl = RegisterValue; break;
+ case 0x800: pWb35Reg->M00_MacControl = RegisterValue; break;
+ case 0x804: pWb35Reg->M04_MulticastAddress1 = RegisterValue; break;
+ case 0x808: pWb35Reg->M08_MulticastAddress2 = RegisterValue; break;
+ case 0x824: pWb35Reg->M24_MacControl = RegisterValue; break;
+ case 0x828: pWb35Reg->M28_MacControl = RegisterValue; break;
+ case 0x82c: pWb35Reg->M2C_MacControl = RegisterValue; break;
+ case 0x838: pWb35Reg->M38_MacControl = RegisterValue; break;
+ case 0x840: pWb35Reg->M40_MacControl = RegisterValue; break;
+ case 0x844: pWb35Reg->M44_MacControl = RegisterValue; break;
+ case 0x848: pWb35Reg->M48_MacControl = RegisterValue; break;
+ case 0x84c: pWb35Reg->M4C_MacStatus = RegisterValue; break;
+ case 0x860: pWb35Reg->M60_MacControl = RegisterValue; break;
+ case 0x868: pWb35Reg->M68_MacControl = RegisterValue; break;
+ case 0x870: pWb35Reg->M70_MacControl = RegisterValue; break;
+ case 0x874: pWb35Reg->M74_MacControl = RegisterValue; break;
+ case 0x878: pWb35Reg->M78_ERPInformation = RegisterValue; break;
+ case 0x87C: pWb35Reg->M7C_MacControl = RegisterValue; break;
+ case 0x880: pWb35Reg->M80_MacControl = RegisterValue; break;
+ case 0x884: pWb35Reg->M84_MacControl = RegisterValue; break;
+ case 0x888: pWb35Reg->M88_MacControl = RegisterValue; break;
+ case 0x898: pWb35Reg->M98_MacControl = RegisterValue; break;
+ case 0x100c: pWb35Reg->BB0C = RegisterValue; break;
+ case 0x102c: pWb35Reg->BB2C = RegisterValue; break;
+ case 0x1030: pWb35Reg->BB30 = RegisterValue; break;
+ case 0x103c: pWb35Reg->BB3C = RegisterValue; break;
+ case 0x1048: pWb35Reg->BB48 = RegisterValue; break;
+ case 0x104c: pWb35Reg->BB4C = RegisterValue; break;
+ case 0x1050: pWb35Reg->BB50 = RegisterValue; break;
+ case 0x1054: pWb35Reg->BB54 = RegisterValue; break;
+ case 0x1058: pWb35Reg->BB58 = RegisterValue; break;
+ case 0x105c: pWb35Reg->BB5C = RegisterValue; break;
+ case 0x1060: pWb35Reg->BB60 = RegisterValue; break;
+ }
+}
+
+// TRUE : read command process successfully
+// FALSE : register not support
+unsigned char
+Wb35Reg_WriteSync( phw_data_t pHwData, u16 RegisterNo, u32 RegisterValue )
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ int ret = -1;
+
+ // Module shutdown
+ if (pHwData->SurpriseRemove)
+ return FALSE;
+
+ RegisterValue = cpu_to_le32(RegisterValue);
+
+ // update the register by send usb message------------------------------------
+ pWb35Reg->SyncIoPause = 1;
+
+ // 20060717.5 Wait until EP0VM stop
+ while (pWb35Reg->EP0vm_state != VM_STOP)
+ OS_SLEEP(10000);
+
+ // Sync IoCallDriver
+ pWb35Reg->EP0vm_state = VM_RUNNING;
+ ret = usb_control_msg( pHwData->WbUsb.udev,
+ usb_sndctrlpipe( pHwData->WbUsb.udev, 0 ),
+ 0x03, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ 0x0,RegisterNo, &RegisterValue, 4, HZ*100 );
+ pWb35Reg->EP0vm_state = VM_STOP;
+ pWb35Reg->SyncIoPause = 0;
+
+ Wb35Reg_EP0VM_start(pHwData);
+
+ if (ret < 0) {
+ #ifdef _PE_REG_DUMP_
+ WBDEBUG(("EP0 Write register usb message sending error\n"));
+ #endif
+
+ pHwData->SurpriseRemove = 1; // 20060704.2
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// TRUE : read command process successfully
+// FALSE : register not support
+unsigned char
+Wb35Reg_Write( phw_data_t pHwData, u16 RegisterNo, u32 RegisterValue )
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ struct usb_ctrlrequest *dr;
+ PURB pUrb = NULL;
+ PREG_QUEUE pRegQueue = NULL;
+ u16 UrbSize;
+
+
+ // Module shutdown
+ if (pHwData->SurpriseRemove)
+ return FALSE;
+
+ // update the register by send urb request------------------------------------
+ UrbSize = sizeof(REG_QUEUE) + sizeof(struct usb_ctrlrequest);
+ OS_MEMORY_ALLOC( (void* *)&pRegQueue, UrbSize );
+ pUrb = wb_usb_alloc_urb(0);
+ if (pUrb && pRegQueue) {
+ pRegQueue->DIRECT = 1;// burst write register
+ pRegQueue->INDEX = RegisterNo;
+ pRegQueue->VALUE = cpu_to_le32(RegisterValue);
+ pRegQueue->RESERVED_VALID = FALSE;
+ dr = (struct usb_ctrlrequest *)((PUCHAR)pRegQueue + sizeof(REG_QUEUE));
+ dr->bRequestType = USB_TYPE_VENDOR|USB_DIR_OUT |USB_RECIP_DEVICE;
+ dr->bRequest = 0x03; // USB or vendor-defined request code, burst mode
+ dr->wValue = cpu_to_le16(0x0);
+ dr->wIndex = cpu_to_le16(RegisterNo);
+ dr->wLength = cpu_to_le16(4);
+
+ // Enter the sending queue
+ pRegQueue->Next = NULL;
+ pRegQueue->pUsbReq = dr;
+ pRegQueue->pUrb = pUrb;
+
+ OS_SPIN_LOCK_ACQUIRED(&pWb35Reg->EP0VM_spin_lock );
+ if (pWb35Reg->pRegFirst == NULL)
+ pWb35Reg->pRegFirst = pRegQueue;
+ else
+ pWb35Reg->pRegLast->Next = pRegQueue;
+ pWb35Reg->pRegLast = pRegQueue;
+
+ OS_SPIN_LOCK_RELEASED( &pWb35Reg->EP0VM_spin_lock );
+
+ // Start EP0VM
+ Wb35Reg_EP0VM_start(pHwData);
+
+ return TRUE;
+ } else {
+ if (pUrb)
+ usb_free_urb(pUrb);
+ kfree(pRegQueue);
+ return FALSE;
+ }
+}
+
+//This command will be executed with a user defined value. When it completes,
+//this value is useful. For example, hal_set_current_channel will use it.
+// TRUE : read command process successfully
+// FALSE : register not support
+unsigned char
+Wb35Reg_WriteWithCallbackValue( phw_data_t pHwData, u16 RegisterNo, u32 RegisterValue,
+ PCHAR pValue, s8 Len)
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ struct usb_ctrlrequest *dr;
+ PURB pUrb = NULL;
+ PREG_QUEUE pRegQueue = NULL;
+ u16 UrbSize;
+
+ // Module shutdown
+ if (pHwData->SurpriseRemove)
+ return FALSE;
+
+ // update the register by send urb request------------------------------------
+ UrbSize = sizeof(REG_QUEUE) + sizeof(struct usb_ctrlrequest);
+ OS_MEMORY_ALLOC((void* *) &pRegQueue, UrbSize );
+ pUrb = wb_usb_alloc_urb(0);
+ if (pUrb && pRegQueue) {
+ pRegQueue->DIRECT = 1;// burst write register
+ pRegQueue->INDEX = RegisterNo;
+ pRegQueue->VALUE = cpu_to_le32(RegisterValue);
+ //NOTE : Users must guarantee the size of value will not exceed the buffer size.
+ memcpy(pRegQueue->RESERVED, pValue, Len);
+ pRegQueue->RESERVED_VALID = TRUE;
+ dr = (struct usb_ctrlrequest *)((PUCHAR)pRegQueue + sizeof(REG_QUEUE));
+ dr->bRequestType = USB_TYPE_VENDOR|USB_DIR_OUT |USB_RECIP_DEVICE;
+ dr->bRequest = 0x03; // USB or vendor-defined request code, burst mode
+ dr->wValue = cpu_to_le16(0x0);
+ dr->wIndex = cpu_to_le16(RegisterNo);
+ dr->wLength = cpu_to_le16(4);
+
+ // Enter the sending queue
+ pRegQueue->Next = NULL;
+ pRegQueue->pUsbReq = dr;
+ pRegQueue->pUrb = pUrb;
+ OS_SPIN_LOCK_ACQUIRED (&pWb35Reg->EP0VM_spin_lock );
+ if( pWb35Reg->pRegFirst == NULL )
+ pWb35Reg->pRegFirst = pRegQueue;
+ else
+ pWb35Reg->pRegLast->Next = pRegQueue;
+ pWb35Reg->pRegLast = pRegQueue;
+
+ OS_SPIN_LOCK_RELEASED ( &pWb35Reg->EP0VM_spin_lock );
+
+ // Start EP0VM
+ Wb35Reg_EP0VM_start(pHwData);
+ return TRUE;
+ } else {
+ if (pUrb)
+ usb_free_urb(pUrb);
+ kfree(pRegQueue);
+ return FALSE;
+ }
+}
+
+// TRUE : read command process successfully
+// FALSE : register not support
+// pRegisterValue : It must be a resident buffer due to asynchronous read register.
+unsigned char
+Wb35Reg_ReadSync( phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterValue )
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ PULONG pltmp = pRegisterValue;
+ int ret = -1;
+
+ // Module shutdown
+ if (pHwData->SurpriseRemove)
+ return FALSE;
+
+ // Read the register by send usb message------------------------------------
+
+ pWb35Reg->SyncIoPause = 1;
+
+ // 20060717.5 Wait until EP0VM stop
+ while (pWb35Reg->EP0vm_state != VM_STOP)
+ OS_SLEEP(10000);
+
+ pWb35Reg->EP0vm_state = VM_RUNNING;
+ ret = usb_control_msg( pHwData->WbUsb.udev,
+ usb_rcvctrlpipe(pHwData->WbUsb.udev, 0),
+ 0x01, USB_TYPE_VENDOR|USB_RECIP_DEVICE|USB_DIR_IN,
+ 0x0, RegisterNo, pltmp, 4, HZ*100 );
+
+ *pRegisterValue = cpu_to_le32(*pltmp);
+
+ pWb35Reg->EP0vm_state = VM_STOP;
+
+ Wb35Reg_Update( pHwData, RegisterNo, *pRegisterValue );
+ pWb35Reg->SyncIoPause = 0;
+
+ Wb35Reg_EP0VM_start( pHwData );
+
+ if (ret < 0) {
+ #ifdef _PE_REG_DUMP_
+ WBDEBUG(("EP0 Read register usb message sending error\n"));
+ #endif
+
+ pHwData->SurpriseRemove = 1; // 20060704.2
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// TRUE : read command process successfully
+// FALSE : register not support
+// pRegisterValue : It must be a resident buffer due to asynchronous read register.
+unsigned char
+Wb35Reg_Read(phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterValue )
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ struct usb_ctrlrequest * dr;
+ PURB pUrb;
+ PREG_QUEUE pRegQueue;
+ u16 UrbSize;
+
+ // Module shutdown
+ if (pHwData->SurpriseRemove)
+ return FALSE;
+
+ // update the variable by send Urb to read register ------------------------------------
+ UrbSize = sizeof(REG_QUEUE) + sizeof(struct usb_ctrlrequest);
+ OS_MEMORY_ALLOC( (void* *)&pRegQueue, UrbSize );
+ pUrb = wb_usb_alloc_urb(0);
+ if( pUrb && pRegQueue )
+ {
+ pRegQueue->DIRECT = 0;// read register
+ pRegQueue->INDEX = RegisterNo;
+ pRegQueue->pBuffer = pRegisterValue;
+ dr = (struct usb_ctrlrequest *)((PUCHAR)pRegQueue + sizeof(REG_QUEUE));
+ dr->bRequestType = USB_TYPE_VENDOR|USB_RECIP_DEVICE|USB_DIR_IN;
+ dr->bRequest = 0x01; // USB or vendor-defined request code, burst mode
+ dr->wValue = cpu_to_le16(0x0);
+ dr->wIndex = cpu_to_le16 (RegisterNo);
+ dr->wLength = cpu_to_le16 (4);
+
+ // Enter the sending queue
+ pRegQueue->Next = NULL;
+ pRegQueue->pUsbReq = dr;
+ pRegQueue->pUrb = pUrb;
+ OS_SPIN_LOCK_ACQUIRED ( &pWb35Reg->EP0VM_spin_lock );
+ if( pWb35Reg->pRegFirst == NULL )
+ pWb35Reg->pRegFirst = pRegQueue;
+ else
+ pWb35Reg->pRegLast->Next = pRegQueue;
+ pWb35Reg->pRegLast = pRegQueue;
+
+ OS_SPIN_LOCK_RELEASED( &pWb35Reg->EP0VM_spin_lock );
+
+ // Start EP0VM
+ Wb35Reg_EP0VM_start( pHwData );
+
+ return TRUE;
+ } else {
+ if (pUrb)
+ usb_free_urb( pUrb );
+ kfree(pRegQueue);
+ return FALSE;
+ }
+}
+
+
+void
+Wb35Reg_EP0VM_start( phw_data_t pHwData )
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+
+ if (OS_ATOMIC_INC( pHwData->Adapter, &pWb35Reg->RegFireCount) == 1) {
+ pWb35Reg->EP0vm_state = VM_RUNNING;
+ Wb35Reg_EP0VM(pHwData);
+ } else
+ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Reg->RegFireCount );
+}
+
+void
+Wb35Reg_EP0VM(phw_data_t pHwData )
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ PURB pUrb;
+ struct usb_ctrlrequest *dr;
+ PULONG pBuffer;
+ int ret = -1;
+ PREG_QUEUE pRegQueue;
+
+
+ if (pWb35Reg->SyncIoPause)
+ goto cleanup;
+
+ if (pHwData->SurpriseRemove)
+ goto cleanup;
+
+ // Get the register data and send to USB through Irp
+ OS_SPIN_LOCK_ACQUIRED( &pWb35Reg->EP0VM_spin_lock );
+ pRegQueue = pWb35Reg->pRegFirst;
+ OS_SPIN_LOCK_RELEASED( &pWb35Reg->EP0VM_spin_lock );
+
+ if (!pRegQueue)
+ goto cleanup;
+
+ // Get an Urb, send it
+ pUrb = (PURB)pRegQueue->pUrb;
+
+ dr = pRegQueue->pUsbReq;
+ pUrb = pRegQueue->pUrb;
+ pBuffer = pRegQueue->pBuffer;
+ if (pRegQueue->DIRECT == 1) // output
+ pBuffer = &pRegQueue->VALUE;
+
+ usb_fill_control_urb( pUrb, pHwData->WbUsb.udev,
+ REG_DIRECTION(pHwData->WbUsb.udev,pRegQueue),
+ (PUCHAR)dr,pBuffer,cpu_to_le16(dr->wLength),
+ Wb35Reg_EP0VM_complete, (void*)pHwData);
+
+ pWb35Reg->EP0vm_state = VM_RUNNING;
+
+ ret = wb_usb_submit_urb( pUrb );
+
+ if (ret < 0) {
+#ifdef _PE_REG_DUMP_
+ WBDEBUG(("EP0 Irp sending error\n"));
+#endif
+ goto cleanup;
+ }
+
+ return;
+
+ cleanup:
+ pWb35Reg->EP0vm_state = VM_STOP;
+ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Reg->RegFireCount );
+}
+
+
+void
+Wb35Reg_EP0VM_complete(PURB pUrb)
+{
+ phw_data_t pHwData = (phw_data_t)pUrb->context;
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ PREG_QUEUE pRegQueue;
+
+
+ // Variable setting
+ pWb35Reg->EP0vm_state = VM_COMPLETED;
+ pWb35Reg->EP0VM_status = pUrb->status;
+
+ if (pHwData->SurpriseRemove) { // Let WbWlanHalt to handle surprise remove
+ pWb35Reg->EP0vm_state = VM_STOP;
+ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Reg->RegFireCount );
+ } else {
+ // Complete to send, remove the URB from the first
+ OS_SPIN_LOCK_ACQUIRED( &pWb35Reg->EP0VM_spin_lock );
+ pRegQueue = pWb35Reg->pRegFirst;
+ if (pRegQueue == pWb35Reg->pRegLast)
+ pWb35Reg->pRegLast = NULL;
+ pWb35Reg->pRegFirst = pWb35Reg->pRegFirst->Next;
+ OS_SPIN_LOCK_RELEASED( &pWb35Reg->EP0VM_spin_lock );
+
+ if (pWb35Reg->EP0VM_status) {
+#ifdef _PE_REG_DUMP_
+ WBDEBUG(("EP0 IoCompleteRoutine return error\n"));
+ DebugUsbdStatusInformation( pWb35Reg->EP0VM_status );
+#endif
+ pWb35Reg->EP0vm_state = VM_STOP;
+ pHwData->SurpriseRemove = 1;
+ } else {
+ // Success. Update the result
+
+ // Start the next send
+ Wb35Reg_EP0VM(pHwData);
+ }
+
+ kfree(pRegQueue);
+ }
+
+ usb_free_urb(pUrb);
+}
+
+
+void
+Wb35Reg_destroy(phw_data_t pHwData)
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ PURB pUrb;
+ PREG_QUEUE pRegQueue;
+
+
+ Uxx_power_off_procedure(pHwData);
+
+ // Wait for Reg operation completed
+ do {
+ OS_SLEEP(10000); // Delay for waiting function enter 940623.1.a
+ } while (pWb35Reg->EP0vm_state != VM_STOP);
+ OS_SLEEP(10000); // Delay for waiting function enter 940623.1.b
+
+ // Release all the data in RegQueue
+ OS_SPIN_LOCK_ACQUIRED( &pWb35Reg->EP0VM_spin_lock );
+ pRegQueue = pWb35Reg->pRegFirst;
+ while (pRegQueue) {
+ if (pRegQueue == pWb35Reg->pRegLast)
+ pWb35Reg->pRegLast = NULL;
+ pWb35Reg->pRegFirst = pWb35Reg->pRegFirst->Next;
+
+ pUrb = pRegQueue->pUrb;
+ OS_SPIN_LOCK_RELEASED( &pWb35Reg->EP0VM_spin_lock );
+ if (pUrb) {
+ usb_free_urb(pUrb);
+ kfree(pRegQueue);
+ } else {
+ #ifdef _PE_REG_DUMP_
+ WBDEBUG(("EP0 queue release error\n"));
+ #endif
+ }
+ OS_SPIN_LOCK_ACQUIRED( &pWb35Reg->EP0VM_spin_lock );
+
+ pRegQueue = pWb35Reg->pRegFirst;
+ }
+ OS_SPIN_LOCK_RELEASED( &pWb35Reg->EP0VM_spin_lock );
+
+ // Free resource
+ OS_SPIN_LOCK_FREE( &pWb35Reg->EP0VM_spin_lock );
+}
+
+//====================================================================================
+// The function can be run in passive-level only.
+//====================================================================================
+unsigned char Wb35Reg_initial(phw_data_t pHwData)
+{
+ PWB35REG pWb35Reg=&pHwData->Wb35Reg;
+ u32 ltmp;
+ u32 SoftwareSet, VCO_trim, TxVga, Region_ScanInterval;
+
+ // Spin lock is acquired for read and write IRP command
+ OS_SPIN_LOCK_ALLOCATE( &pWb35Reg->EP0VM_spin_lock );
+
+ // Getting RF module type from EEPROM ------------------------------------
+ Wb35Reg_WriteSync( pHwData, 0x03b4, 0x080d0000 ); // Start EEPROM access + Read + address(0x0d)
+ Wb35Reg_ReadSync( pHwData, 0x03b4, <mp );
+
+ //Update RF module type and determine the PHY type by inf or EEPROM
+ pWb35Reg->EEPROMPhyType = (u8)( ltmp & 0xff );
+ // 0 V MAX2825, 1 V MAX2827, 2 V MAX2828, 3 V MAX2829
+ // 16V AL2230, 17 - AL7230, 18 - AL2230S
+ // 32 Reserved
+ // 33 - W89RF242(TxVGA 0~19), 34 - W89RF242(TxVGA 0~34)
+ if (pWb35Reg->EEPROMPhyType != RF_DECIDE_BY_INF) {
+ if( (pWb35Reg->EEPROMPhyType == RF_MAXIM_2825) ||
+ (pWb35Reg->EEPROMPhyType == RF_MAXIM_2827) ||
+ (pWb35Reg->EEPROMPhyType == RF_MAXIM_2828) ||
+ (pWb35Reg->EEPROMPhyType == RF_MAXIM_2829) ||
+ (pWb35Reg->EEPROMPhyType == RF_MAXIM_V1) ||
+ (pWb35Reg->EEPROMPhyType == RF_AIROHA_2230) ||
+ (pWb35Reg->EEPROMPhyType == RF_AIROHA_2230S) ||
+ (pWb35Reg->EEPROMPhyType == RF_AIROHA_7230) ||
+ (pWb35Reg->EEPROMPhyType == RF_WB_242) ||
+ (pWb35Reg->EEPROMPhyType == RF_WB_242_1))
+ pHwData->phy_type = pWb35Reg->EEPROMPhyType;
+ }
+
+ // Power On procedure running. The relative parameter will be set according to phy_type
+ Uxx_power_on_procedure( pHwData );
+
+ // Reading MAC address
+ Uxx_ReadEthernetAddress( pHwData );
+
+ // Read VCO trim for RF parameter
+ Wb35Reg_WriteSync( pHwData, 0x03b4, 0x08200000 );
+ Wb35Reg_ReadSync( pHwData, 0x03b4, &VCO_trim );
+
+ // Read Antenna On/Off of software flag
+ Wb35Reg_WriteSync( pHwData, 0x03b4, 0x08210000 );
+ Wb35Reg_ReadSync( pHwData, 0x03b4, &SoftwareSet );
+
+ // Read TXVGA
+ Wb35Reg_WriteSync( pHwData, 0x03b4, 0x08100000 );
+ Wb35Reg_ReadSync( pHwData, 0x03b4, &TxVga );
+
+ // Get Scan interval setting from EEPROM offset 0x1c
+ Wb35Reg_WriteSync( pHwData, 0x03b4, 0x081d0000 );
+ Wb35Reg_ReadSync( pHwData, 0x03b4, &Region_ScanInterval );
+
+ // Update Ethernet address
+ memcpy( pHwData->CurrentMacAddress, pHwData->PermanentMacAddress, ETH_LENGTH_OF_ADDRESS );
+
+ // Update software variable
+ pHwData->SoftwareSet = (u16)(SoftwareSet & 0xffff);
+ TxVga &= 0x000000ff;
+ pHwData->PowerIndexFromEEPROM = (u8)TxVga;
+ pHwData->VCO_trim = (u8)VCO_trim & 0xff;
+ if (pHwData->VCO_trim == 0xff)
+ pHwData->VCO_trim = 0x28;
+
+ pWb35Reg->EEPROMRegion = (u8)(Region_ScanInterval>>8); // 20060720
+ if( pWb35Reg->EEPROMRegion<1 || pWb35Reg->EEPROMRegion>6 )
+ pWb35Reg->EEPROMRegion = REGION_AUTO;
+
+ //For Get Tx VGA from EEPROM 20060315.5 move here
+ GetTxVgaFromEEPROM( pHwData );
+
+ // Set Scan Interval
+ pHwData->Scan_Interval = (u8)(Region_ScanInterval & 0xff) * 10;
+ if ((pHwData->Scan_Interval == 2550) || (pHwData->Scan_Interval < 10)) // Is default setting 0xff * 10
+ pHwData->Scan_Interval = SCAN_MAX_CHNL_TIME;
+
+ // Initial register
+ RFSynthesizer_initial(pHwData);
+
+ BBProcessor_initial(pHwData); // Async write, must wait until complete
+
+ Wb35Reg_phy_calibration(pHwData);
+
+ Mxx_initial(pHwData);
+ Dxx_initial(pHwData);
+
+ if (pHwData->SurpriseRemove)
+ return FALSE;
+ else
+ return TRUE; // Initial fail
+}
+
+//===================================================================================
+// CardComputeCrc --
+//
+// Description:
+// Runs the AUTODIN II CRC algorithm on buffer Buffer of length, Length.
+//
+// Arguments:
+// Buffer - the input buffer
+// Length - the length of Buffer
+//
+// Return Value:
+// The 32-bit CRC value.
+//
+// Note:
+// This is adapted from the comments in the assembly language
+// version in _GENREQ.ASM of the DWB NE1000/2000 driver.
+//==================================================================================
+u32
+CardComputeCrc(PUCHAR Buffer, u32 Length)
+{
+ u32 Crc, Carry;
+ u32 i, j;
+ u8 CurByte;
+
+ Crc = 0xffffffff;
+
+ for (i = 0; i < Length; i++) {
+
+ CurByte = Buffer[i];
+
+ for (j = 0; j < 8; j++) {
+
+ Carry = ((Crc & 0x80000000) ? 1 : 0) ^ (CurByte & 0x01);
+ Crc <<= 1;
+ CurByte >>= 1;
+
+ if (Carry) {
+ Crc =(Crc ^ 0x04c11db6) | Carry;
+ }
+ }
+ }
+
+ return Crc;
+}
+
+
+//==================================================================
+// BitReverse --
+// Reverse the bits in the input argument, dwData, which is
+// regarded as a string of bits with the length, DataLength.
+//
+// Arguments:
+// dwData :
+// DataLength :
+//
+// Return:
+// The converted value.
+//==================================================================
+u32 BitReverse( u32 dwData, u32 DataLength)
+{
+ u32 HalfLength, i, j;
+ u32 BitA, BitB;
+
+ if ( DataLength <= 0) return 0; // No conversion is done.
+ dwData = dwData & (0xffffffff >> (32 - DataLength));
+
+ HalfLength = DataLength / 2;
+ for ( i = 0, j = DataLength-1 ; i < HalfLength; i++, j--)
+ {
+ BitA = GetBit( dwData, i);
+ BitB = GetBit( dwData, j);
+ if (BitA && !BitB) {
+ dwData = ClearBit( dwData, i);
+ dwData = SetBit( dwData, j);
+ } else if (!BitA && BitB) {
+ dwData = SetBit( dwData, i);
+ dwData = ClearBit( dwData, j);
+ } else
+ {
+ // Do nothing since these two bits are of the save values.
+ }
+ }
+
+ return dwData;
+}
+
+void Wb35Reg_phy_calibration( phw_data_t pHwData )
+{
+ u32 BB3c, BB54;
+
+ if ((pHwData->phy_type == RF_WB_242) ||
+ (pHwData->phy_type == RF_WB_242_1)) {
+ phy_calibration_winbond ( pHwData, 2412 ); // Sync operation
+ Wb35Reg_ReadSync( pHwData, 0x103c, &BB3c );
+ Wb35Reg_ReadSync( pHwData, 0x1054, &BB54 );
+
+ pHwData->BB3c_cal = BB3c;
+ pHwData->BB54_cal = BB54;
+
+ RFSynthesizer_initial(pHwData);
+ BBProcessor_initial(pHwData); // Async operation
+
+ Wb35Reg_WriteSync( pHwData, 0x103c, BB3c );
+ Wb35Reg_WriteSync( pHwData, 0x1054, BB54 );
+ }
+}
+
+
diff --git a/drivers/staging/winbond/linux/wb35reg_f.h b/drivers/staging/winbond/linux/wb35reg_f.h
new file mode 100644
index 0000000..38e2906
--- /dev/null
+++ b/drivers/staging/winbond/linux/wb35reg_f.h
@@ -0,0 +1,56 @@
+//====================================
+// Interface function declare
+//====================================
+unsigned char Wb35Reg_initial( phw_data_t pHwData );
+void Uxx_power_on_procedure( phw_data_t pHwData );
+void Uxx_power_off_procedure( phw_data_t pHwData );
+void Uxx_ReadEthernetAddress( phw_data_t pHwData );
+void Dxx_initial( phw_data_t pHwData );
+void Mxx_initial( phw_data_t pHwData );
+void RFSynthesizer_initial( phw_data_t pHwData );
+//void RFSynthesizer_SwitchingChannel( phw_data_t pHwData, s8 Channel );
+void RFSynthesizer_SwitchingChannel( phw_data_t pHwData, ChanInfo Channel );
+void BBProcessor_initial( phw_data_t pHwData );
+void BBProcessor_RateChanging( phw_data_t pHwData, u8 rate ); // 20060613.1
+//void RF_RateChanging( phw_data_t pHwData, u8 rate ); // 20060626.5.c Add
+u8 RFSynthesizer_SetPowerIndex( phw_data_t pHwData, u8 PowerIndex );
+u8 RFSynthesizer_SetMaxim2828_24Power( phw_data_t, u8 index );
+u8 RFSynthesizer_SetMaxim2828_50Power( phw_data_t, u8 index );
+u8 RFSynthesizer_SetMaxim2827_24Power( phw_data_t, u8 index );
+u8 RFSynthesizer_SetMaxim2827_50Power( phw_data_t, u8 index );
+u8 RFSynthesizer_SetMaxim2825Power( phw_data_t, u8 index );
+u8 RFSynthesizer_SetAiroha2230Power( phw_data_t, u8 index );
+u8 RFSynthesizer_SetAiroha7230Power( phw_data_t, u8 index );
+u8 RFSynthesizer_SetWinbond242Power( phw_data_t, u8 index );
+void GetTxVgaFromEEPROM( phw_data_t pHwData );
+void EEPROMTxVgaAdjust( phw_data_t pHwData ); // 20060619.5 Add
+
+#define RFWriteControlData( _A, _V ) Wb35Reg_Write( _A, 0x0864, _V )
+
+void Wb35Reg_destroy( phw_data_t pHwData );
+
+unsigned char Wb35Reg_Read( phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterValue );
+unsigned char Wb35Reg_ReadSync( phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterValue );
+unsigned char Wb35Reg_Write( phw_data_t pHwData, u16 RegisterNo, u32 RegisterValue );
+unsigned char Wb35Reg_WriteSync( phw_data_t pHwData, u16 RegisterNo, u32 RegisterValue );
+unsigned char Wb35Reg_WriteWithCallbackValue( phw_data_t pHwData,
+ u16 RegisterNo,
+ u32 RegisterValue,
+ PCHAR pValue,
+ s8 Len);
+unsigned char Wb35Reg_BurstWrite( phw_data_t pHwData, u16 RegisterNo, PULONG pRegisterData, u8 NumberOfData, u8 Flag );
+
+void Wb35Reg_EP0VM( phw_data_t pHwData );
+void Wb35Reg_EP0VM_start( phw_data_t pHwData );
+void Wb35Reg_EP0VM_complete( PURB pUrb );
+
+u32 BitReverse( u32 dwData, u32 DataLength);
+
+void CardGetMulticastBit( u8 Address[MAC_ADDR_LENGTH], u8 *Byte, u8 *Value );
+u32 CardComputeCrc( PUCHAR Buffer, u32 Length );
+
+void Wb35Reg_phy_calibration( phw_data_t pHwData );
+void Wb35Reg_Update( phw_data_t pHwData, u16 RegisterNo, u32 RegisterValue );
+unsigned char adjust_TXVGA_for_iq_mag( phw_data_t pHwData );
+
+
diff --git a/drivers/staging/winbond/linux/wb35reg_s.h b/drivers/staging/winbond/linux/wb35reg_s.h
new file mode 100644
index 0000000..a7595b1
--- /dev/null
+++ b/drivers/staging/winbond/linux/wb35reg_s.h
@@ -0,0 +1,170 @@
+//=======================================================================================
+/*
+ HAL setting function
+
+ ========================================
+ |Uxx| |Dxx| |Mxx| |BB| |RF|
+ ========================================
+ | |
+ Wb35Reg_Read Wb35Reg_Write
+
+ ----------------------------------------
+ WbUsb_CallUSBDASync supplied By WbUsb module
+*/
+//=======================================================================================
+
+#define GetBit( dwData, i) ( dwData & (0x00000001 << i))
+#define SetBit( dwData, i) ( dwData | (0x00000001 << i))
+#define ClearBit( dwData, i) ( dwData & ~(0x00000001 << i))
+
+#define IGNORE_INCREMENT 0
+#define AUTO_INCREMENT 0
+#define NO_INCREMENT 1
+#define REG_DIRECTION(_x,_y) ((_y)->DIRECT ==0 ? usb_rcvctrlpipe(_x,0) : usb_sndctrlpipe(_x,0))
+#define REG_BUF_SIZE(_x) ((_x)->bRequest== 0x04 ? cpu_to_le16((_x)->wLength) : 4)
+
+// 20060613.2 Add the follow definition
+#define BB48_DEFAULT_AL2230_11B 0x0033447c
+#define BB4C_DEFAULT_AL2230_11B 0x0A00FEFF
+#define BB48_DEFAULT_AL2230_11G 0x00332C1B
+#define BB4C_DEFAULT_AL2230_11G 0x0A00FEFF
+
+
+#define BB48_DEFAULT_WB242_11B 0x00292315 //backoff 2dB
+#define BB4C_DEFAULT_WB242_11B 0x0800FEFF //backoff 2dB
+//#define BB48_DEFAULT_WB242_11B 0x00201B11 //backoff 4dB
+//#define BB4C_DEFAULT_WB242_11B 0x0600FF00 //backoff 4dB
+#define BB48_DEFAULT_WB242_11G 0x00453B24
+#define BB4C_DEFAULT_WB242_11G 0x0E00FEFF
+
+//====================================
+// Default setting for Mxx
+//====================================
+#define DEFAULT_CWMIN 31 //(M2C) CWmin. Its value is in the range 0-31.
+#define DEFAULT_CWMAX 1023 //(M2C) CWmax. Its value is in the range 0-1023.
+#define DEFAULT_AID 1 //(M34) AID. Its value is in the range 1-2007.
+
+#ifdef _USE_FALLBACK_RATE_
+#define DEFAULT_RATE_RETRY_LIMIT 2 //(M38) as named
+#else
+#define DEFAULT_RATE_RETRY_LIMIT 7 //(M38) as named
+#endif
+
+#define DEFAULT_LONG_RETRY_LIMIT 7 //(M38) LongRetryLimit. Its value is in the range 0-15.
+#define DEFAULT_SHORT_RETRY_LIMIT 7 //(M38) ShortRetryLimit. Its value is in the range 0-15.
+#define DEFAULT_PIFST 25 //(M3C) PIFS Time. Its value is in the range 0-65535.
+#define DEFAULT_EIFST 354 //(M3C) EIFS Time. Its value is in the range 0-1048575.
+#define DEFAULT_DIFST 45 //(M3C) DIFS Time. Its value is in the range 0-65535.
+#define DEFAULT_SIFST 5 //(M3C) SIFS Time. Its value is in the range 0-65535.
+#define DEFAULT_OSIFST 10 //(M3C) Original SIFS Time. Its value is in the range 0-15.
+#define DEFAULT_ATIMWD 0 //(M40) ATIM Window. Its value is in the range 0-65535.
+#define DEFAULT_SLOT_TIME 20 //(M40) ($) SlotTime. Its value is in the range 0-255.
+#define DEFAULT_MAX_TX_MSDU_LIFE_TIME 512 //(M44) MaxTxMSDULifeTime. Its value is in the range 0-4294967295.
+#define DEFAULT_BEACON_INTERVAL 500 //(M48) Beacon Interval. Its value is in the range 0-65535.
+#define DEFAULT_PROBE_DELAY_TIME 200 //(M48) Probe Delay Time. Its value is in the range 0-65535.
+#define DEFAULT_PROTOCOL_VERSION 0 //(M4C)
+#define DEFAULT_MAC_POWER_STATE 2 //(M4C) 2: MAC at power active
+#define DEFAULT_DTIM_ALERT_TIME 0
+
+
+typedef struct _REG_QUEUE
+{
+ struct urb *pUrb;
+ void* pUsbReq;
+ void* Next;
+ union
+ {
+ u32 VALUE;
+ PULONG pBuffer;
+ };
+ u8 RESERVED[4];// space reserved for communication
+
+ u16 INDEX; // For storing the register index
+ u8 RESERVED_VALID; //Indicate whether the RESERVED space is valid at this command.
+ u8 DIRECT; // 0:In 1:Out
+
+} REG_QUEUE, *PREG_QUEUE;
+
+//====================================
+// Internal variable for module
+//====================================
+#define MAX_SQ3_FILTER_SIZE 5
+typedef struct _WB35REG
+{
+ //============================
+ // Register Bank backup
+ //============================
+ u32 U1B0; //bit16 record the h/w radio on/off status
+ u32 U1BC_LEDConfigure;
+ u32 D00_DmaControl;
+ u32 M00_MacControl;
+ union {
+ struct {
+ u32 M04_MulticastAddress1;
+ u32 M08_MulticastAddress2;
+ };
+ u8 Multicast[8]; // contents of card multicast registers
+ };
+
+ u32 M24_MacControl;
+ u32 M28_MacControl;
+ u32 M2C_MacControl;
+ u32 M38_MacControl;
+ u32 M3C_MacControl; // 20060214 backup only
+ u32 M40_MacControl;
+ u32 M44_MacControl; // 20060214 backup only
+ u32 M48_MacControl; // 20060214 backup only
+ u32 M4C_MacStatus;
+ u32 M60_MacControl; // 20060214 backup only
+ u32 M68_MacControl; // 20060214 backup only
+ u32 M70_MacControl; // 20060214 backup only
+ u32 M74_MacControl; // 20060214 backup only
+ u32 M78_ERPInformation;//930206.2.b
+ u32 M7C_MacControl; // 20060214 backup only
+ u32 M80_MacControl; // 20060214 backup only
+ u32 M84_MacControl; // 20060214 backup only
+ u32 M88_MacControl; // 20060214 backup only
+ u32 M98_MacControl; // 20060214 backup only
+
+ //[20040722 WK]
+ //Baseband register
+ u32 BB0C; // Used for LNA calculation
+ u32 BB2C; //
+ u32 BB30; //11b acquisition control register
+ u32 BB3C;
+ u32 BB48; // 20051221.1.a 20060613.1 Fix OBW issue of 11b/11g rate
+ u32 BB4C; // 20060613.1 Fix OBW issue of 11b/11g rate
+ u32 BB50; //mode control register
+ u32 BB54;
+ u32 BB58; //IQ_ALPHA
+ u32 BB5C; // For test
+ u32 BB60; // for WTO read value
+
+ //-------------------
+ // VM
+ //-------------------
+ OS_SPIN_LOCK EP0VM_spin_lock; // 4B
+ u32 EP0VM_status;//$$
+ PREG_QUEUE pRegFirst;
+ PREG_QUEUE pRegLast;
+ OS_ATOMIC RegFireCount;
+
+ // Hardware status
+ u8 EP0vm_state;
+ u8 mac_power_save;
+ u8 EEPROMPhyType; // 0 ~ 15 for Maxim (0 ĄV MAX2825, 1 ĄV MAX2827, 2 ĄV MAX2828, 3 ĄV MAX2829),
+ // 16 ~ 31 for Airoha (16 ĄV AL2230, 11 - AL7230)
+ // 32 ~ Reserved
+ // 33 ~ 47 For WB242 ( 33 - WB242, 34 - WB242 with new Txvga 0.5 db step)
+ // 48 ~ 255 ARE RESERVED.
+ u8 EEPROMRegion; //Region setting in EEPROM
+
+ u32 SyncIoPause; // If user use the Sync Io to access Hw, then pause the async access
+
+ u8 LNAValue[4]; //Table for speed up running
+ u32 SQ3_filter[MAX_SQ3_FILTER_SIZE];
+ u32 SQ3_index;
+
+} WB35REG, *PWB35REG;
+
+
diff --git a/drivers/staging/winbond/linux/wb35rx.c b/drivers/staging/winbond/linux/wb35rx.c
new file mode 100644
index 0000000..26157eb
--- /dev/null
+++ b/drivers/staging/winbond/linux/wb35rx.c
@@ -0,0 +1,337 @@
+//============================================================================
+// Copyright (c) 1996-2002 Winbond Electronic Corporation
+//
+// Module Name:
+// Wb35Rx.c
+//
+// Abstract:
+// Processing the Rx message from down layer
+//
+//============================================================================
+#include "sysdef.h"
+
+
+void Wb35Rx_start(phw_data_t pHwData)
+{
+ PWB35RX pWb35Rx = &pHwData->Wb35Rx;
+
+ // Allow only one thread to run into the Wb35Rx() function
+ if (OS_ATOMIC_INC(pHwData->Adapter, &pWb35Rx->RxFireCounter) == 1) {
+ pWb35Rx->EP3vm_state = VM_RUNNING;
+ Wb35Rx(pHwData);
+ } else
+ OS_ATOMIC_DEC(pHwData->Adapter, &pWb35Rx->RxFireCounter);
+}
+
+// This function cannot reentrain
+void Wb35Rx( phw_data_t pHwData )
+{
+ PWB35RX pWb35Rx = &pHwData->Wb35Rx;
+ PUCHAR pRxBufferAddress;
+ PURB pUrb = (PURB)pWb35Rx->RxUrb;
+ int retv;
+ u32 RxBufferId;
+
+ //
+ // Issuing URB
+ //
+ do {
+ if (pHwData->SurpriseRemove || pHwData->HwStop)
+ break;
+
+ if (pWb35Rx->rx_halt)
+ break;
+
+ // Get RxBuffer's ID
+ RxBufferId = pWb35Rx->RxBufferId;
+ if (!pWb35Rx->RxOwner[RxBufferId]) {
+ // It's impossible to run here.
+ #ifdef _PE_RX_DUMP_
+ WBDEBUG(("Rx driver fifo unavailable\n"));
+ #endif
+ break;
+ }
+
+ // Update buffer point, then start to bulkin the data from USB
+ pWb35Rx->RxBufferId++;
+ pWb35Rx->RxBufferId %= MAX_USB_RX_BUFFER_NUMBER;
+
+ pWb35Rx->CurrentRxBufferId = RxBufferId;
+
+ if (1 != OS_MEMORY_ALLOC((void* *)&pWb35Rx->pDRx, MAX_USB_RX_BUFFER)) {
+ printk("w35und: Rx memory alloc failed\n");
+ break;
+ }
+ pRxBufferAddress = pWb35Rx->pDRx;
+
+ usb_fill_bulk_urb(pUrb, pHwData->WbUsb.udev,
+ usb_rcvbulkpipe(pHwData->WbUsb.udev, 3),
+ pRxBufferAddress, MAX_USB_RX_BUFFER,
+ Wb35Rx_Complete, pHwData);
+
+ pWb35Rx->EP3vm_state = VM_RUNNING;
+
+ retv = wb_usb_submit_urb(pUrb);
+
+ if (retv != 0) {
+ printk("Rx URB sending error\n");
+ break;
+ }
+ return;
+ } while(FALSE);
+
+ // VM stop
+ pWb35Rx->EP3vm_state = VM_STOP;
+ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Rx->RxFireCounter );
+}
+
+void Wb35Rx_Complete(PURB pUrb)
+{
+ phw_data_t pHwData = pUrb->context;
+ PWB35RX pWb35Rx = &pHwData->Wb35Rx;
+ PUCHAR pRxBufferAddress;
+ u32 SizeCheck;
+ u16 BulkLength;
+ u32 RxBufferId;
+ R00_DESCRIPTOR R00;
+
+ // Variable setting
+ pWb35Rx->EP3vm_state = VM_COMPLETED;
+ pWb35Rx->EP3VM_status = pUrb->status;//Store the last result of Irp
+
+ do {
+ RxBufferId = pWb35Rx->CurrentRxBufferId;
+
+ pRxBufferAddress = pWb35Rx->pDRx;
+ BulkLength = (u16)pUrb->actual_length;
+
+ // The IRP is completed
+ pWb35Rx->EP3vm_state = VM_COMPLETED;
+
+ if (pHwData->SurpriseRemove || pHwData->HwStop) // Must be here, or RxBufferId is invalid
+ break;
+
+ if (pWb35Rx->rx_halt)
+ break;
+
+ // Start to process the data only in successful condition
+ pWb35Rx->RxOwner[ RxBufferId ] = 0; // Set the owner to driver
+ R00.value = le32_to_cpu(*(PULONG)pRxBufferAddress);
+
+ // The URB is completed, check the result
+ if (pWb35Rx->EP3VM_status != 0) {
+ #ifdef _PE_USB_STATE_DUMP_
+ WBDEBUG(("EP3 IoCompleteRoutine return error\n"));
+ DebugUsbdStatusInformation( pWb35Rx->EP3VM_status );
+ #endif
+ pWb35Rx->EP3vm_state = VM_STOP;
+ break;
+ }
+
+ // 20060220 For recovering. check if operating in single USB mode
+ if (!HAL_USB_MODE_BURST(pHwData)) {
+ SizeCheck = R00.R00_receive_byte_count; //20060926 anson's endian
+ if ((SizeCheck & 0x03) > 0)
+ SizeCheck -= 4;
+ SizeCheck = (SizeCheck + 3) & ~0x03;
+ SizeCheck += 12; // 8 + 4 badbeef
+ if ((BulkLength > 1600) ||
+ (SizeCheck > 1600) ||
+ (BulkLength != SizeCheck) ||
+ (BulkLength == 0)) { // Add for fail Urb
+ pWb35Rx->EP3vm_state = VM_STOP;
+ pWb35Rx->Ep3ErrorCount2++;
+ }
+ }
+
+ // Indicating the receiving data
+ pWb35Rx->ByteReceived += BulkLength;
+ pWb35Rx->RxBufferSize[ RxBufferId ] = BulkLength;
+
+ if (!pWb35Rx->RxOwner[ RxBufferId ])
+ Wb35Rx_indicate(pHwData);
+
+ kfree(pWb35Rx->pDRx);
+ // Do the next receive
+ Wb35Rx(pHwData);
+ return;
+
+ } while(FALSE);
+
+ pWb35Rx->RxOwner[ RxBufferId ] = 1; // Set the owner to hardware
+ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Rx->RxFireCounter );
+ pWb35Rx->EP3vm_state = VM_STOP;
+}
+
+//=====================================================================================
+unsigned char Wb35Rx_initial(phw_data_t pHwData)
+{
+ PWB35RX pWb35Rx = &pHwData->Wb35Rx;
+
+ // Initial the Buffer Queue
+ Wb35Rx_reset_descriptor( pHwData );
+
+ pWb35Rx->RxUrb = wb_usb_alloc_urb(0);
+ return (!!pWb35Rx->RxUrb);
+}
+
+void Wb35Rx_stop(phw_data_t pHwData)
+{
+ PWB35RX pWb35Rx = &pHwData->Wb35Rx;
+
+ // Canceling the Irp if already sends it out.
+ if (pWb35Rx->EP3vm_state == VM_RUNNING) {
+ usb_unlink_urb( pWb35Rx->RxUrb ); // Only use unlink, let Wb35Rx_destroy to free them
+ #ifdef _PE_RX_DUMP_
+ WBDEBUG(("EP3 Rx stop\n"));
+ #endif
+ }
+}
+
+// Needs process context
+void Wb35Rx_destroy(phw_data_t pHwData)
+{
+ PWB35RX pWb35Rx = &pHwData->Wb35Rx;
+
+ do {
+ OS_SLEEP(10000); // Delay for waiting function enter 940623.1.a
+ } while (pWb35Rx->EP3vm_state != VM_STOP);
+ OS_SLEEP(10000); // Delay for waiting function exit 940623.1.b
+
+ if (pWb35Rx->RxUrb)
+ usb_free_urb( pWb35Rx->RxUrb );
+ #ifdef _PE_RX_DUMP_
+ WBDEBUG(("Wb35Rx_destroy OK\n"));
+ #endif
+}
+
+void Wb35Rx_reset_descriptor( phw_data_t pHwData )
+{
+ PWB35RX pWb35Rx = &pHwData->Wb35Rx;
+ u32 i;
+
+ pWb35Rx->ByteReceived = 0;
+ pWb35Rx->RxProcessIndex = 0;
+ pWb35Rx->RxBufferId = 0;
+ pWb35Rx->EP3vm_state = VM_STOP;
+ pWb35Rx->rx_halt = 0;
+
+ // Initial the Queue. The last buffer is reserved for used if the Rx resource is unavailable.
+ for( i=0; i<MAX_USB_RX_BUFFER_NUMBER; i++ )
+ pWb35Rx->RxOwner[i] = 1;
+}
+
+void Wb35Rx_adjust(PDESCRIPTOR pRxDes)
+{
+ PULONG pRxBufferAddress;
+ u32 DecryptionMethod;
+ u32 i;
+ u16 BufferSize;
+
+ DecryptionMethod = pRxDes->R01.R01_decryption_method;
+ pRxBufferAddress = pRxDes->buffer_address[0];
+ BufferSize = pRxDes->buffer_size[0];
+
+ // Adjust the last part of data. Only data left
+ BufferSize -= 4; // For CRC-32
+ if (DecryptionMethod)
+ BufferSize -= 4;
+ if (DecryptionMethod == 3) // For CCMP
+ BufferSize -= 4;
+
+ // Adjust the IV field which after 802.11 header and ICV field.
+ if (DecryptionMethod == 1) // For WEP
+ {
+ for( i=6; i>0; i-- )
+ pRxBufferAddress[i] = pRxBufferAddress[i-1];
+ pRxDes->buffer_address[0] = pRxBufferAddress + 1;
+ BufferSize -= 4; // 4 byte for IV
+ }
+ else if( DecryptionMethod ) // For TKIP and CCMP
+ {
+ for (i=7; i>1; i--)
+ pRxBufferAddress[i] = pRxBufferAddress[i-2];
+ pRxDes->buffer_address[0] = pRxBufferAddress + 2;//Update the descriptor, shift 8 byte
+ BufferSize -= 8; // 8 byte for IV + ICV
+ }
+ pRxDes->buffer_size[0] = BufferSize;
+}
+
+extern void packet_came(char *pRxBufferAddress, int PacketSize);
+
+
+u16 Wb35Rx_indicate(phw_data_t pHwData)
+{
+ DESCRIPTOR RxDes;
+ PWB35RX pWb35Rx = &pHwData->Wb35Rx;
+ PUCHAR pRxBufferAddress;
+ u16 PacketSize;
+ u16 stmp, BufferSize, stmp2 = 0;
+ u32 RxBufferId;
+
+ // Only one thread be allowed to run into the following
+ do {
+ RxBufferId = pWb35Rx->RxProcessIndex;
+ if (pWb35Rx->RxOwner[ RxBufferId ]) //Owner by VM
+ break;
+
+ pWb35Rx->RxProcessIndex++;
+ pWb35Rx->RxProcessIndex %= MAX_USB_RX_BUFFER_NUMBER;
+
+ pRxBufferAddress = pWb35Rx->pDRx;
+ BufferSize = pWb35Rx->RxBufferSize[ RxBufferId ];
+
+ // Parse the bulkin buffer
+ while (BufferSize >= 4) {
+ if ((cpu_to_le32(*(PULONG)pRxBufferAddress) & 0x0fffffff) == RX_END_TAG) //Is ending? 921002.9.a
+ break;
+
+ // Get the R00 R01 first
+ RxDes.R00.value = le32_to_cpu(*(PULONG)pRxBufferAddress);
+ PacketSize = (u16)RxDes.R00.R00_receive_byte_count;
+ RxDes.R01.value = le32_to_cpu(*((PULONG)(pRxBufferAddress+4)));
+ // For new DMA 4k
+ if ((PacketSize & 0x03) > 0)
+ PacketSize -= 4;
+
+ // Basic check for Rx length. Is length valid?
+ if (PacketSize > MAX_PACKET_SIZE) {
+ #ifdef _PE_RX_DUMP_
+ WBDEBUG(("Serious ERROR : Rx data size too long, size =%d\n", PacketSize));
+ #endif
+
+ pWb35Rx->EP3vm_state = VM_STOP;
+ pWb35Rx->Ep3ErrorCount2++;
+ break;
+ }
+
+ // Start to process Rx buffer
+// RxDes.Descriptor_ID = RxBufferId; // Due to synchronous indicate, the field doesn't necessary to use.
+ BufferSize -= 8; //subtract 8 byte for 35's USB header length
+ pRxBufferAddress += 8;
+
+ RxDes.buffer_address[0] = pRxBufferAddress;
+ RxDes.buffer_size[0] = PacketSize;
+ RxDes.buffer_number = 1;
+ RxDes.buffer_start_index = 0;
+ RxDes.buffer_total_size = RxDes.buffer_size[0];
+ Wb35Rx_adjust(&RxDes);
+
+ packet_came(pRxBufferAddress, PacketSize);
+
+ // Move RxBuffer point to the next
+ stmp = PacketSize + 3;
+ stmp &= ~0x03; // 4n alignment
+ pRxBufferAddress += stmp;
+ BufferSize -= stmp;
+ stmp2 += stmp;
+ }
+
+ // Reclaim resource
+ pWb35Rx->RxOwner[ RxBufferId ] = 1;
+ } while(TRUE);
+
+ return stmp2;
+}
+
+
diff --git a/drivers/staging/winbond/linux/wb35rx_f.h b/drivers/staging/winbond/linux/wb35rx_f.h
new file mode 100644
index 0000000..daa3e73
--- /dev/null
+++ b/drivers/staging/winbond/linux/wb35rx_f.h
@@ -0,0 +1,17 @@
+//====================================
+// Interface function declare
+//====================================
+void Wb35Rx_reset_descriptor( phw_data_t pHwData );
+unsigned char Wb35Rx_initial( phw_data_t pHwData );
+void Wb35Rx_destroy( phw_data_t pHwData );
+void Wb35Rx_stop( phw_data_t pHwData );
+u16 Wb35Rx_indicate( phw_data_t pHwData );
+void Wb35Rx_adjust( PDESCRIPTOR pRxDes );
+void Wb35Rx_start( phw_data_t pHwData );
+
+void Wb35Rx( phw_data_t pHwData );
+void Wb35Rx_Complete( PURB pUrb );
+
+
+
+
diff --git a/drivers/staging/winbond/linux/wb35rx_s.h b/drivers/staging/winbond/linux/wb35rx_s.h
new file mode 100644
index 0000000..53b831f
--- /dev/null
+++ b/drivers/staging/winbond/linux/wb35rx_s.h
@@ -0,0 +1,48 @@
+//============================================================================
+// wb35rx.h --
+//============================================================================
+
+// Definition for this module used
+#define MAX_USB_RX_BUFFER 4096 // This parameter must be 4096 931130.4.f
+
+#define MAX_USB_RX_BUFFER_NUMBER ETHERNET_RX_DESCRIPTORS // Maximum 254, 255 is RESERVED ID
+#define RX_INTERFACE 0 // Interface 1
+#define RX_PIPE 2 // Pipe 3
+#define MAX_PACKET_SIZE 1600 //1568 // 8 + 1532 + 4 + 24(IV EIV MIC ICV CRC) for check DMA data 931130.4.g
+#define RX_END_TAG 0x0badbeef
+
+
+//====================================
+// Internal variable for module
+//====================================
+typedef struct _WB35RX
+{
+ u32 ByteReceived;// For calculating throughput of BulkIn
+ OS_ATOMIC RxFireCounter;// Does Wb35Rx module fire?
+
+ u8 RxBuffer[ MAX_USB_RX_BUFFER_NUMBER ][ ((MAX_USB_RX_BUFFER+3) & ~0x03 ) ];
+ u16 RxBufferSize[ ((MAX_USB_RX_BUFFER_NUMBER+1) & ~0x01) ];
+ u8 RxOwner[ ((MAX_USB_RX_BUFFER_NUMBER+3) & ~0x03 ) ];//Ownership of buffer 0: SW 1:HW
+
+ u32 RxProcessIndex;//The next index to process
+ u32 RxBufferId;
+ u32 EP3vm_state;
+
+ u32 rx_halt; // For VM stopping
+
+ u16 MoreDataSize;
+ u16 PacketSize;
+
+ u32 CurrentRxBufferId; // For complete routine usage
+ u32 Rx3UrbCancel;
+
+ u32 LastR1; // For RSSI reporting
+ struct urb * RxUrb;
+ u32 Ep3ErrorCount2; // 20060625.1 Usbd for Rx DMA error count
+
+ int EP3VM_status;
+ PUCHAR pDRx;
+
+} WB35RX, *PWB35RX;
+
+
diff --git a/drivers/staging/winbond/linux/wb35tx.c b/drivers/staging/winbond/linux/wb35tx.c
new file mode 100644
index 0000000..cf19c3b
--- /dev/null
+++ b/drivers/staging/winbond/linux/wb35tx.c
@@ -0,0 +1,313 @@
+//============================================================================
+// Copyright (c) 1996-2002 Winbond Electronic Corporation
+//
+// Module Name:
+// Wb35Tx.c
+//
+// Abstract:
+// Processing the Tx message and put into down layer
+//
+//============================================================================
+#include "sysdef.h"
+
+
+unsigned char
+Wb35Tx_get_tx_buffer(phw_data_t pHwData, PUCHAR *pBuffer )
+{
+ PWB35TX pWb35Tx = &pHwData->Wb35Tx;
+
+ *pBuffer = pWb35Tx->TxBuffer[0];
+ return TRUE;
+}
+
+void Wb35Tx_start(phw_data_t pHwData)
+{
+ PWB35TX pWb35Tx = &pHwData->Wb35Tx;
+
+ // Allow only one thread to run into function
+ if (OS_ATOMIC_INC(pHwData->Adapter, &pWb35Tx->TxFireCounter) == 1) {
+ pWb35Tx->EP4vm_state = VM_RUNNING;
+ Wb35Tx(pHwData);
+ } else
+ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxFireCounter );
+}
+
+
+void Wb35Tx(phw_data_t pHwData)
+{
+ PWB35TX pWb35Tx = &pHwData->Wb35Tx;
+ PADAPTER Adapter = pHwData->Adapter;
+ PUCHAR pTxBufferAddress;
+ PMDS pMds = &Adapter->Mds;
+ struct urb * pUrb = (struct urb *)pWb35Tx->Tx4Urb;
+ int retv;
+ u32 SendIndex;
+
+
+ if (pHwData->SurpriseRemove || pHwData->HwStop)
+ goto cleanup;
+
+ if (pWb35Tx->tx_halt)
+ goto cleanup;
+
+ // Ownership checking
+ SendIndex = pWb35Tx->TxSendIndex;
+ if (!pMds->TxOwner[SendIndex]) //No more data need to be sent, return immediately
+ goto cleanup;
+
+ pTxBufferAddress = pWb35Tx->TxBuffer[SendIndex];
+ //
+ // Issuing URB
+ //
+ usb_fill_bulk_urb(pUrb, pHwData->WbUsb.udev,
+ usb_sndbulkpipe(pHwData->WbUsb.udev, 4),
+ pTxBufferAddress, pMds->TxBufferSize[ SendIndex ],
+ Wb35Tx_complete, pHwData);
+
+ pWb35Tx->EP4vm_state = VM_RUNNING;
+ retv = wb_usb_submit_urb( pUrb );
+ if (retv<0) {
+ printk("EP4 Tx Irp sending error\n");
+ goto cleanup;
+ }
+
+ // Check if driver needs issue Irp for EP2
+ pWb35Tx->TxFillCount += pMds->TxCountInBuffer[SendIndex];
+ if (pWb35Tx->TxFillCount > 12)
+ Wb35Tx_EP2VM_start( pHwData );
+
+ pWb35Tx->ByteTransfer += pMds->TxBufferSize[SendIndex];
+ return;
+
+ cleanup:
+ pWb35Tx->EP4vm_state = VM_STOP;
+ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxFireCounter );
+}
+
+
+void Wb35Tx_complete(struct urb * pUrb)
+{
+ phw_data_t pHwData = pUrb->context;
+ PADAPTER Adapter = (PADAPTER)pHwData->Adapter;
+ PWB35TX pWb35Tx = &pHwData->Wb35Tx;
+ PMDS pMds = &Adapter->Mds;
+
+ printk("wb35: tx complete\n");
+ // Variable setting
+ pWb35Tx->EP4vm_state = VM_COMPLETED;
+ pWb35Tx->EP4VM_status = pUrb->status; //Store the last result of Irp
+ pMds->TxOwner[ pWb35Tx->TxSendIndex ] = 0;// Set the owner. Free the owner bit always.
+ pWb35Tx->TxSendIndex++;
+ pWb35Tx->TxSendIndex %= MAX_USB_TX_BUFFER_NUMBER;
+
+ do {
+ if (pHwData->SurpriseRemove || pHwData->HwStop) // Let WbWlanHalt to handle surprise remove
+ break;
+
+ if (pWb35Tx->tx_halt)
+ break;
+
+ // The URB is completed, check the result
+ if (pWb35Tx->EP4VM_status != 0) {
+ printk("URB submission failed\n");
+ pWb35Tx->EP4vm_state = VM_STOP;
+ break; // Exit while(FALSE);
+ }
+
+ Mds_Tx(Adapter);
+ Wb35Tx(pHwData);
+ return;
+ } while(FALSE);
+
+ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxFireCounter );
+ pWb35Tx->EP4vm_state = VM_STOP;
+}
+
+void Wb35Tx_reset_descriptor( phw_data_t pHwData )
+{
+ PWB35TX pWb35Tx = &pHwData->Wb35Tx;
+
+ pWb35Tx->TxSendIndex = 0;
+ pWb35Tx->tx_halt = 0;
+}
+
+unsigned char Wb35Tx_initial(phw_data_t pHwData)
+{
+ PWB35TX pWb35Tx = &pHwData->Wb35Tx;
+
+ pWb35Tx->Tx4Urb = wb_usb_alloc_urb(0);
+ if (!pWb35Tx->Tx4Urb)
+ return FALSE;
+
+ pWb35Tx->Tx2Urb = wb_usb_alloc_urb(0);
+ if (!pWb35Tx->Tx2Urb)
+ {
+ usb_free_urb( pWb35Tx->Tx4Urb );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+//======================================================
+void Wb35Tx_stop(phw_data_t pHwData)
+{
+ PWB35TX pWb35Tx = &pHwData->Wb35Tx;
+
+ // Trying to canceling the Trp of EP2
+ if (pWb35Tx->EP2vm_state == VM_RUNNING)
+ usb_unlink_urb( pWb35Tx->Tx2Urb ); // Only use unlink, let Wb35Tx_destrot to free them
+ #ifdef _PE_TX_DUMP_
+ WBDEBUG(("EP2 Tx stop\n"));
+ #endif
+
+ // Trying to canceling the Irp of EP4
+ if (pWb35Tx->EP4vm_state == VM_RUNNING)
+ usb_unlink_urb( pWb35Tx->Tx4Urb ); // Only use unlink, let Wb35Tx_destrot to free them
+ #ifdef _PE_TX_DUMP_
+ WBDEBUG(("EP4 Tx stop\n"));
+ #endif
+}
+
+//======================================================
+void Wb35Tx_destroy(phw_data_t pHwData)
+{
+ PWB35TX pWb35Tx = &pHwData->Wb35Tx;
+
+ // Wait for VM stop
+ do {
+ OS_SLEEP(10000); // Delay for waiting function enter 940623.1.a
+ } while( (pWb35Tx->EP2vm_state != VM_STOP) && (pWb35Tx->EP4vm_state != VM_STOP) );
+ OS_SLEEP(10000); // Delay for waiting function enter 940623.1.b
+
+ if (pWb35Tx->Tx4Urb)
+ usb_free_urb( pWb35Tx->Tx4Urb );
+
+ if (pWb35Tx->Tx2Urb)
+ usb_free_urb( pWb35Tx->Tx2Urb );
+
+ #ifdef _PE_TX_DUMP_
+ WBDEBUG(("Wb35Tx_destroy OK\n"));
+ #endif
+}
+
+void Wb35Tx_CurrentTime(phw_data_t pHwData, u32 TimeCount)
+{
+ PWB35TX pWb35Tx = &pHwData->Wb35Tx;
+ unsigned char Trigger = FALSE;
+
+ if (pWb35Tx->TxTimer > TimeCount)
+ Trigger = TRUE;
+ else if (TimeCount > (pWb35Tx->TxTimer+500))
+ Trigger = TRUE;
+
+ if (Trigger) {
+ pWb35Tx->TxTimer = TimeCount;
+ Wb35Tx_EP2VM_start( pHwData );
+ }
+}
+
+void Wb35Tx_EP2VM_start(phw_data_t pHwData)
+{
+ PWB35TX pWb35Tx = &pHwData->Wb35Tx;
+
+ // Allow only one thread to run into function
+ if (OS_ATOMIC_INC( pHwData->Adapter, &pWb35Tx->TxResultCount ) == 1) {
+ pWb35Tx->EP2vm_state = VM_RUNNING;
+ Wb35Tx_EP2VM( pHwData );
+ }
+ else
+ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxResultCount );
+}
+
+
+void Wb35Tx_EP2VM(phw_data_t pHwData)
+{
+ PWB35TX pWb35Tx = &pHwData->Wb35Tx;
+ struct urb * pUrb = (struct urb *)pWb35Tx->Tx2Urb;
+ PULONG pltmp = (PULONG)pWb35Tx->EP2_buf;
+ int retv;
+
+ do {
+ if (pHwData->SurpriseRemove || pHwData->HwStop)
+ break;
+
+ if (pWb35Tx->tx_halt)
+ break;
+
+ //
+ // Issuing URB
+ //
+ usb_fill_int_urb( pUrb, pHwData->WbUsb.udev, usb_rcvintpipe(pHwData->WbUsb.udev,2),
+ pltmp, MAX_INTERRUPT_LENGTH, Wb35Tx_EP2VM_complete, pHwData, 32);
+
+ pWb35Tx->EP2vm_state = VM_RUNNING;
+ retv = wb_usb_submit_urb( pUrb );
+
+ if(retv < 0) {
+ #ifdef _PE_TX_DUMP_
+ WBDEBUG(("EP2 Tx Irp sending error\n"));
+ #endif
+ break;
+ }
+
+ return;
+
+ } while(FALSE);
+
+ pWb35Tx->EP2vm_state = VM_STOP;
+ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxResultCount );
+}
+
+
+void Wb35Tx_EP2VM_complete(struct urb * pUrb)
+{
+ phw_data_t pHwData = pUrb->context;
+ T02_DESCRIPTOR T02, TSTATUS;
+ PADAPTER Adapter = (PADAPTER)pHwData->Adapter;
+ PWB35TX pWb35Tx = &pHwData->Wb35Tx;
+ PULONG pltmp = (PULONG)pWb35Tx->EP2_buf;
+ u32 i;
+ u16 InterruptInLength;
+
+
+ // Variable setting
+ pWb35Tx->EP2vm_state = VM_COMPLETED;
+ pWb35Tx->EP2VM_status = pUrb->status;
+
+ do {
+ // For Linux 2.4. Interrupt will always trigger
+ if( pHwData->SurpriseRemove || pHwData->HwStop ) // Let WbWlanHalt to handle surprise remove
+ break;
+
+ if( pWb35Tx->tx_halt )
+ break;
+
+ //The Urb is completed, check the result
+ if (pWb35Tx->EP2VM_status != 0) {
+ WBDEBUG(("EP2 IoCompleteRoutine return error\n"));
+ pWb35Tx->EP2vm_state= VM_STOP;
+ break; // Exit while(FALSE);
+ }
+
+ // Update the Tx result
+ InterruptInLength = pUrb->actual_length;
+ // Modify for minimum memory access and DWORD alignment.
+ T02.value = cpu_to_le32(pltmp[0]) >> 8; // [31:8] -> [24:0]
+ InterruptInLength -= 1;// 20051221.1.c Modify the follow for more stable
+ InterruptInLength >>= 2; // InterruptInLength/4
+ for (i=1; i<=InterruptInLength; i++) {
+ T02.value |= ((cpu_to_le32(pltmp[i]) & 0xff) << 24);
+
+ TSTATUS.value = T02.value; //20061009 anson's endian
+ Mds_SendComplete( Adapter, &TSTATUS );
+ T02.value = cpu_to_le32(pltmp[i]) >> 8;
+ }
+
+ return;
+ } while(FALSE);
+
+ OS_ATOMIC_DEC( pHwData->Adapter, &pWb35Tx->TxResultCount );
+ pWb35Tx->EP2vm_state = VM_STOP;
+}
+
diff --git a/drivers/staging/winbond/linux/wb35tx_f.h b/drivers/staging/winbond/linux/wb35tx_f.h
new file mode 100644
index 0000000..7705a84
--- /dev/null
+++ b/drivers/staging/winbond/linux/wb35tx_f.h
@@ -0,0 +1,20 @@
+//====================================
+// Interface function declare
+//====================================
+unsigned char Wb35Tx_initial( phw_data_t pHwData );
+void Wb35Tx_destroy( phw_data_t pHwData );
+unsigned char Wb35Tx_get_tx_buffer( phw_data_t pHwData, PUCHAR *pBuffer );
+
+void Wb35Tx_EP2VM( phw_data_t pHwData );
+void Wb35Tx_EP2VM_start( phw_data_t pHwData );
+void Wb35Tx_EP2VM_complete( PURB purb );
+
+void Wb35Tx_start( phw_data_t pHwData );
+void Wb35Tx_stop( phw_data_t pHwData );
+void Wb35Tx( phw_data_t pHwData );
+void Wb35Tx_complete( PURB purb );
+void Wb35Tx_reset_descriptor( phw_data_t pHwData );
+
+void Wb35Tx_CurrentTime( phw_data_t pHwData, u32 TimeCount );
+
+
diff --git a/drivers/staging/winbond/linux/wb35tx_s.h b/drivers/staging/winbond/linux/wb35tx_s.h
new file mode 100644
index 0000000..ac43257
--- /dev/null
+++ b/drivers/staging/winbond/linux/wb35tx_s.h
@@ -0,0 +1,47 @@
+//====================================
+// IS89C35 Tx related definition
+//====================================
+#define TX_INTERFACE 0 // Interface 1
+#define TX_PIPE 3 // endpoint 4
+#define TX_INTERRUPT 1 // endpoint 2
+#define MAX_INTERRUPT_LENGTH 64 // It must be 64 for EP2 hardware
+
+
+
+//====================================
+// Internal variable for module
+//====================================
+
+
+typedef struct _WB35TX
+{
+ // For Tx buffer
+ u8 TxBuffer[ MAX_USB_TX_BUFFER_NUMBER ][ MAX_USB_TX_BUFFER ];
+
+ // For Interrupt pipe
+ u8 EP2_buf[MAX_INTERRUPT_LENGTH];
+
+ OS_ATOMIC TxResultCount;// For thread control of EP2 931130.4.m
+ OS_ATOMIC TxFireCounter;// For thread control of EP4 931130.4.n
+ u32 ByteTransfer;
+
+ u32 TxSendIndex;// The next index of Mds array to be sent
+ u32 EP2vm_state; // for EP2vm state
+ u32 EP4vm_state; // for EP4vm state
+ u32 tx_halt; // Stopping VM
+
+ struct urb * Tx4Urb;
+ struct urb * Tx2Urb;
+
+ int EP2VM_status;
+ int EP4VM_status;
+
+ u32 TxFillCount; // 20060928
+ u32 TxTimer; // 20060928 Add if sending packet not great than 13
+
+} WB35TX, *PWB35TX;
+
+
+
+
+
diff --git a/drivers/staging/winbond/linux/wbusb.c b/drivers/staging/winbond/linux/wbusb.c
new file mode 100644
index 0000000..cbad5fb
--- /dev/null
+++ b/drivers/staging/winbond/linux/wbusb.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright 2008 Pavel Machek <pavel@suse.cz>
+ *
+ * Distribute under GPLv2.
+ */
+#include "sysdef.h"
+#include <net/mac80211.h>
+
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.1");
+
+
+//============================================================
+// vendor ID and product ID can into here for others
+//============================================================
+static struct usb_device_id Id_Table[] =
+{
+ {USB_DEVICE( 0x0416, 0x0035 )},
+ {USB_DEVICE( 0x18E8, 0x6201 )},
+ {USB_DEVICE( 0x18E8, 0x6206 )},
+ {USB_DEVICE( 0x18E8, 0x6217 )},
+ {USB_DEVICE( 0x18E8, 0x6230 )},
+ {USB_DEVICE( 0x18E8, 0x6233 )},
+ {USB_DEVICE( 0x1131, 0x2035 )},
+ { }
+};
+
+MODULE_DEVICE_TABLE(usb, Id_Table);
+
+static struct usb_driver wb35_driver = {
+ .name = "w35und",
+ .probe = wb35_probe,
+ .disconnect = wb35_disconnect,
+ .id_table = Id_Table,
+};
+
+static const struct ieee80211_rate wbsoft_rates[] = {
+ { .bitrate = 10, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+};
+
+static const struct ieee80211_channel wbsoft_channels[] = {
+ { .center_freq = 2412},
+};
+
+int wbsoft_enabled;
+struct ieee80211_hw *my_dev;
+PADAPTER my_adapter;
+
+static int wbsoft_add_interface(struct ieee80211_hw *dev,
+ struct ieee80211_if_init_conf *conf)
+{
+ printk("wbsoft_add interface called\n");
+ return 0;
+}
+
+static void wbsoft_remove_interface(struct ieee80211_hw *dev,
+ struct ieee80211_if_init_conf *conf)
+{
+ printk("wbsoft_remove interface called\n");
+}
+
+static int wbsoft_nop(void)
+{
+ printk("wbsoft_nop called\n");
+ return 0;
+}
+
+static void wbsoft_configure_filter(struct ieee80211_hw *dev,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count, struct dev_mc_list *mclist)
+{
+ unsigned int bit_nr, new_flags;
+ u32 mc_filter[2];
+ int i;
+
+ new_flags = 0;
+
+ if (*total_flags & FIF_PROMISC_IN_BSS) {
+ new_flags |= FIF_PROMISC_IN_BSS;
+ mc_filter[1] = mc_filter[0] = ~0;
+ } else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) {
+ new_flags |= FIF_ALLMULTI;
+ mc_filter[1] = mc_filter[0] = ~0;
+ } else {
+ mc_filter[1] = mc_filter[0] = 0;
+ for (i = 0; i < mc_count; i++) {
+ if (!mclist)
+ break;
+ printk("Should call ether_crc here\n");
+ //bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+ bit_nr = 0;
+
+ bit_nr &= 0x3F;
+ mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
+ mclist = mclist->next;
+ }
+ }
+
+ dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;
+
+ *total_flags = new_flags;
+}
+
+static int wbsoft_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
+{
+ char *buffer = kmalloc(skb->len, GFP_ATOMIC);
+ printk("Sending frame %d bytes\n", skb->len);
+ memcpy(buffer, skb->data, skb->len);
+ if (1 == MLMESendFrame(my_adapter, buffer, skb->len, FRAME_TYPE_802_11_MANAGEMENT))
+ printk("frame sent ok (%d bytes)?\n", skb->len);
+ return NETDEV_TX_OK;
+}
+
+
+static int wbsoft_start(struct ieee80211_hw *dev)
+{
+ wbsoft_enabled = 1;
+ printk("wbsoft_start called\n");
+ return 0;
+}
+
+static int wbsoft_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
+{
+ ChanInfo ch;
+ printk("wbsoft_config called\n");
+
+ ch.band = 1;
+ ch.ChanNo = 1; /* Should use channel_num, or something, as that is already pre-translated */
+
+
+ hal_set_current_channel(&my_adapter->sHwData, ch);
+ hal_set_beacon_period(&my_adapter->sHwData, conf->beacon_int);
+// hal_set_cap_info(&my_adapter->sHwData, ?? );
+// hal_set_ssid(phw_data_t pHwData, PUCHAR pssid, u8 ssid_len); ??
+ hal_set_accept_broadcast(&my_adapter->sHwData, 1);
+ hal_set_accept_promiscuous(&my_adapter->sHwData, 1);
+ hal_set_accept_multicast(&my_adapter->sHwData, 1);
+ hal_set_accept_beacon(&my_adapter->sHwData, 1);
+ hal_set_radio_mode(&my_adapter->sHwData, 0);
+ //hal_set_antenna_number( phw_data_t pHwData, u8 number )
+ //hal_set_rf_power(phw_data_t pHwData, u8 PowerIndex)
+
+
+// hal_start_bss(&my_adapter->sHwData, WLAN_BSSTYPE_INFRASTRUCTURE); ??
+
+//void hal_set_rates(phw_data_t pHwData, PUCHAR pbss_rates,
+// u8 length, unsigned char basic_rate_set)
+
+ return 0;
+}
+
+static int wbsoft_config_interface(struct ieee80211_hw *dev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_if_conf *conf)
+{
+ printk("wbsoft_config_interface called\n");
+ return 0;
+}
+
+static u64 wbsoft_get_tsf(struct ieee80211_hw *dev)
+{
+ printk("wbsoft_get_tsf called\n");
+ return 0;
+}
+
+static const struct ieee80211_ops wbsoft_ops = {
+ .tx = wbsoft_tx,
+ .start = wbsoft_start, /* Start can be pretty much empty as we do WbWLanInitialize() during probe? */
+ .stop = wbsoft_nop,
+ .add_interface = wbsoft_add_interface,
+ .remove_interface = wbsoft_remove_interface,
+ .config = wbsoft_config,
+ .config_interface = wbsoft_config_interface,
+ .configure_filter = wbsoft_configure_filter,
+ .get_stats = wbsoft_nop,
+ .get_tx_stats = wbsoft_nop,
+ .get_tsf = wbsoft_get_tsf,
+// conf_tx: hal_set_cwmin()/hal_set_cwmax;
+};
+
+struct wbsoft_priv {
+};
+
+
+int __init wb35_init(void)
+{
+ printk("[w35und]driver init\n");
+ return usb_register(&wb35_driver);
+}
+
+void __exit wb35_exit(void)
+{
+ printk("[w35und]driver exit\n");
+ usb_deregister( &wb35_driver );
+}
+
+module_init(wb35_init);
+module_exit(wb35_exit);
+
+// Usb kernel subsystem will call this function when a new device is plugged into.
+int wb35_probe(struct usb_interface *intf, const struct usb_device_id *id_table)
+{
+ PADAPTER Adapter;
+ PWBLINUX pWbLinux;
+ PWBUSB pWbUsb;
+ struct usb_host_interface *interface;
+ struct usb_endpoint_descriptor *endpoint;
+ int i, ret = -1;
+ u32 ltmp;
+ struct usb_device *udev = interface_to_usbdev(intf);
+
+ usb_get_dev(udev);
+
+ printk("[w35und]wb35_probe ->\n");
+
+ do {
+ for (i=0; i<(sizeof(Id_Table)/sizeof(struct usb_device_id)); i++ ) {
+ if ((udev->descriptor.idVendor == Id_Table[i].idVendor) &&
+ (udev->descriptor.idProduct == Id_Table[i].idProduct)) {
+ printk("[w35und]Found supported hardware\n");
+ break;
+ }
+ }
+ if ((i == (sizeof(Id_Table)/sizeof(struct usb_device_id)))) {
+ #ifdef _PE_USB_INI_DUMP_
+ WBDEBUG(("[w35und] This is not the one we are interested about\n"));
+ #endif
+ return -ENODEV;
+ }
+
+ // 20060630.2 Check the device if it already be opened
+ ret = usb_control_msg(udev, usb_rcvctrlpipe( udev, 0 ),
+ 0x01, USB_TYPE_VENDOR|USB_RECIP_DEVICE|USB_DIR_IN,
+ 0x0, 0x400, <mp, 4, HZ*100 );
+ if( ret < 0 )
+ break;
+
+ ltmp = cpu_to_le32(ltmp);
+ if (ltmp) // Is already initialized?
+ break;
+
+
+ Adapter = kzalloc(sizeof(ADAPTER), GFP_KERNEL);
+
+ my_adapter = Adapter;
+ pWbLinux = &Adapter->WbLinux;
+ pWbUsb = &Adapter->sHwData.WbUsb;
+ pWbUsb->udev = udev;
+
+ interface = intf->cur_altsetting;
+ endpoint = &interface->endpoint[0].desc;
+
+ if (endpoint[2].wMaxPacketSize == 512) {
+ printk("[w35und] Working on USB 2.0\n");
+ pWbUsb->IsUsb20 = 1;
+ }
+
+ if (!WbWLanInitialize(Adapter)) {
+ printk("[w35und]WbWLanInitialize fail\n");
+ break;
+ }
+
+ {
+ struct wbsoft_priv *priv;
+ struct ieee80211_hw *dev;
+ int res;
+
+ dev = ieee80211_alloc_hw(sizeof(*priv), &wbsoft_ops);
+
+ if (!dev) {
+ printk("w35und: ieee80211 alloc failed\n" );
+ BUG();
+ }
+
+ my_dev = dev;
+
+ SET_IEEE80211_DEV(dev, &udev->dev);
+ {
+ phw_data_t pHwData = &Adapter->sHwData;
+ unsigned char dev_addr[MAX_ADDR_LEN];
+ hal_get_permanent_address(pHwData, dev_addr);
+ SET_IEEE80211_PERM_ADDR(dev, dev_addr);
+ }
+
+
+ dev->extra_tx_headroom = 12; /* FIXME */
+ dev->flags = 0;
+
+ dev->channel_change_time = 1000;
+// dev->max_rssi = 100;
+
+ dev->queues = 1;
+
+ static struct ieee80211_supported_band band;
+
+ band.channels = wbsoft_channels;
+ band.n_channels = ARRAY_SIZE(wbsoft_channels);
+ band.bitrates = wbsoft_rates;
+ band.n_bitrates = ARRAY_SIZE(wbsoft_rates);
+
+ dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band;
+#if 0
+ wbsoft_modes[0].num_channels = 1;
+ wbsoft_modes[0].channels = wbsoft_channels;
+ wbsoft_modes[0].mode = MODE_IEEE80211B;
+ wbsoft_modes[0].num_rates = ARRAY_SIZE(wbsoft_rates);
+ wbsoft_modes[0].rates = wbsoft_rates;
+
+ res = ieee80211_register_hwmode(dev, &wbsoft_modes[0]);
+ BUG_ON(res);
+#endif
+
+ res = ieee80211_register_hw(dev);
+ BUG_ON(res);
+ }
+
+ usb_set_intfdata( intf, Adapter );
+
+ printk("[w35und] _probe OK\n");
+ return 0;
+
+ } while(FALSE);
+
+ return -ENOMEM;
+}
+
+void packet_came(char *pRxBufferAddress, int PacketSize)
+{
+ struct sk_buff *skb;
+ struct ieee80211_rx_status rx_status = {0};
+
+ if (!wbsoft_enabled)
+ return;
+
+ skb = dev_alloc_skb(PacketSize);
+ if (!skb) {
+ printk("Not enough memory for packet, FIXME\n");
+ return;
+ }
+
+ memcpy(skb_put(skb, PacketSize),
+ pRxBufferAddress,
+ PacketSize);
+
+/*
+ rx_status.rate = 10;
+ rx_status.channel = 1;
+ rx_status.freq = 12345;
+ rx_status.phymode = MODE_IEEE80211B;
+*/
+
+ ieee80211_rx_irqsafe(my_dev, skb, &rx_status);
+}
+
+unsigned char
+WbUsb_initial(phw_data_t pHwData)
+{
+ return 1;
+}
+
+
+void
+WbUsb_destroy(phw_data_t pHwData)
+{
+}
+
+int wb35_open(struct net_device *netdev)
+{
+ PADAPTER Adapter = (PADAPTER)netdev->priv;
+ phw_data_t pHwData = &Adapter->sHwData;
+
+ netif_start_queue(netdev);
+
+ //TODO : put here temporarily
+ hal_set_accept_broadcast(pHwData, 1); // open accept broadcast
+
+ return 0;
+}
+
+int wb35_close(struct net_device *netdev)
+{
+ netif_stop_queue(netdev);
+ return 0;
+}
+
+void wb35_disconnect(struct usb_interface *intf)
+{
+ PWBLINUX pWbLinux;
+ PADAPTER Adapter = usb_get_intfdata(intf);
+ usb_set_intfdata(intf, NULL);
+
+ pWbLinux = &Adapter->WbLinux;
+
+ // Card remove
+ WbWlanHalt(Adapter);
+
+}
+
+
diff --git a/drivers/staging/winbond/linux/wbusb_f.h b/drivers/staging/winbond/linux/wbusb_f.h
new file mode 100644
index 0000000..cae29e1
--- /dev/null
+++ b/drivers/staging/winbond/linux/wbusb_f.h
@@ -0,0 +1,34 @@
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+// Copyright (c) 1996-2004 Winbond Electronic Corporation
+//
+// Module Name:
+// wbusb_f.h
+//
+// Abstract:
+// Linux driver.
+//
+// Author:
+//
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+int wb35_open(struct net_device *netdev);
+int wb35_close(struct net_device *netdev);
+unsigned char WbUsb_initial(phw_data_t pHwData);
+void WbUsb_destroy(phw_data_t pHwData);
+unsigned char WbWLanInitialize(PADAPTER Adapter);
+#define WbUsb_Stop( _A )
+
+int wb35_probe(struct usb_interface *intf,const struct usb_device_id *id_table);
+void wb35_disconnect(struct usb_interface *intf);
+
+
+#define wb_usb_submit_urb(_A) usb_submit_urb(_A, GFP_ATOMIC)
+#define wb_usb_alloc_urb(_A) usb_alloc_urb(_A, GFP_ATOMIC)
+
+#define WbUsb_CheckForHang( _P )
+#define WbUsb_DetectStart( _P, _I )
+
+
+
+
+
diff --git a/drivers/staging/winbond/linux/wbusb_s.h b/drivers/staging/winbond/linux/wbusb_s.h
new file mode 100644
index 0000000..d5c1d53
--- /dev/null
+++ b/drivers/staging/winbond/linux/wbusb_s.h
@@ -0,0 +1,42 @@
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+// Copyright (c) 1996-2004 Winbond Electronic Corporation
+//
+// Module Name:
+// wbusb_s.h
+//
+// Abstract:
+// Linux driver.
+//
+// Author:
+//
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+#define OS_SLEEP( _MT ) { set_current_state(TASK_INTERRUPTIBLE); \
+ schedule_timeout( _MT*HZ/1000000 ); }
+
+
+//---------------------------------------------------------------------------
+// RW_CONTEXT --
+//
+// Used to track driver-generated io irps
+//---------------------------------------------------------------------------
+typedef struct _RW_CONTEXT
+{
+ void* pHwData;
+ PURB pUrb;
+ void* pCallBackFunctionParameter;
+} RW_CONTEXT, *PRW_CONTEXT;
+
+
+
+
+#define DRIVER_AUTHOR "Original by: Jeff Lee<YY_Lee@issc.com.tw> Adapted to 2.6.x by Costantino Leandro (Rxart Desktop) <le_costantino@pixartargentina.com.ar>"
+#define DRIVER_DESC "IS89C35 802.11bg WLAN USB Driver"
+
+
+
+typedef struct _WBUSB {
+ u32 IsUsb20;
+ struct usb_device *udev;
+ u32 DetectCount;
+} WBUSB, *PWBUSB;
diff --git a/drivers/staging/winbond/localpara.h b/drivers/staging/winbond/localpara.h
new file mode 100644
index 0000000..268cf91
--- /dev/null
+++ b/drivers/staging/winbond/localpara.h
@@ -0,0 +1,275 @@
+//=============================================================
+// LocalPara.h -
+//=============================================================
+//Define the local ability
+
+#define LOCAL_DEFAULT_BEACON_PERIOD 100 //ms
+#define LOCAL_DEFAULT_ATIM_WINDOW 0
+#define LOCAL_DEFAULT_ERP_CAPABILITY 0x0431 //0x0001: ESS
+ //0x0010: Privacy
+ //0x0020: short preamble
+ //0x0400: short slot time
+#define LOCAL_DEFAULT_LISTEN_INTERVAL 5
+
+//#define LOCAL_DEFAULT_24_CHANNEL_NUM 11 // channel 1..11
+#define LOCAL_DEFAULT_24_CHANNEL_NUM 13 // channel 1..13
+#define LOCAL_DEFAULT_5_CHANNEL_NUM 8 // channel 36..64
+
+#define LOCAL_USA_24_CHANNEL_NUM 11
+#define LOCAL_USA_5_CHANNEL_NUM 12
+#define LOCAL_EUROPE_24_CHANNEL_NUM 13
+#define LOCAL_EUROPE_5_CHANNEL_NUM 19
+#define LOCAL_JAPAN_24_CHANNEL_NUM 14
+#define LOCAL_JAPAN_5_CHANNEL_NUM 11
+#define LOCAL_UNKNOWN_24_CHANNEL_NUM 14
+#define LOCAL_UNKNOWN_5_CHANNEL_NUM 34 //not include 165
+
+
+#define psLOCAL (&(Adapter->sLocalPara))
+
+#define MODE_802_11_BG 0
+#define MODE_802_11_A 1
+#define MODE_802_11_ABG 2
+#define MODE_802_11_BG_IBSS 3
+#define MODE_802_11_B 4
+#define MODE_AUTO 255
+
+#define BAND_TYPE_DSSS 0
+#define BAND_TYPE_OFDM_24 1
+#define BAND_TYPE_OFDM_5 2
+
+//refer Bitmap2RateValue table
+#define LOCAL_ALL_SUPPORTED_RATES_BITMAP 0x130c1a66 //the bitmap value of all the H/W supported rates
+ //1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54
+#define LOCAL_OFDM_SUPPORTED_RATES_BITMAP 0x130c1240 //the bitmap value of all the H/W supported rates
+ //except to non-OFDM rates
+ //6, 9, 12, 18, 24, 36, 48, 54
+
+#define LOCAL_11B_SUPPORTED_RATE_BITMAP 0x826
+#define LOCAL_11B_BASIC_RATE_BITMAP 0x826
+#define LOCAL_11B_OPERATION_RATE_BITMAP 0x826
+#define LOCAL_11G_BASIC_RATE_BITMAP 0x826 //1, 2, 5.5, 11
+#define LOCAL_11G_OPERATION_RATE_BITMAP 0x130c1240 //6, 9, 12, 18, 24, 36, 48, 54
+#define LOCAL_11A_BASIC_RATE_BITMAP 0x01001040 //6, 12, 24
+#define LOCAL_11A_OPERATION_RATE_BITMAP 0x120c0200 //9, 18, 36, 48, 54
+
+
+
+#define PWR_ACTIVE 0
+#define PWR_SAVE 1
+#define PWR_TX_IDLE_CYCLE 6
+
+//bPreambleMode and bSlotTimeMode
+#define AUTO_MODE 0
+#define LONG_MODE 1
+
+//Region definition
+#define REGION_AUTO 0xff
+#define REGION_UNKNOWN 0
+#define REGION_EUROPE 1 //ETSI
+#define REGION_JAPAN 2 //MKK
+#define REGION_USA 3 //FCC
+#define REGION_FRANCE 4 //FRANCE
+#define REGION_SPAIN 5 //SPAIN
+#define REGION_ISRAEL 6 //ISRAEL
+//#define REGION_CANADA 7 //IC
+
+#define MAX_BSS_DESCRIPT_ELEMENT 32
+#define MAX_PMKID_CandidateList 16
+
+//High byte : Event number, low byte : reason
+//Event definition
+//-- SME/MLME event
+#define EVENT_RCV_DEAUTH 0x0100
+#define EVENT_JOIN_FAIL 0x0200
+#define EVENT_AUTH_FAIL 0x0300
+#define EVENT_ASSOC_FAIL 0x0400
+#define EVENT_LOST_SIGNAL 0x0500
+#define EVENT_BSS_DESCRIPT_LACK 0x0600
+#define EVENT_COUNTERMEASURE 0x0700
+#define EVENT_JOIN_FILTER 0x0800
+//-- TX/RX event
+#define EVENT_RX_BUFF_UNAVAILABLE 0x4100
+
+#define EVENT_CONNECT 0x8100
+#define EVENT_DISCONNECT 0x8200
+#define EVENT_SCAN_REQ 0x8300
+
+//Reason of Event
+#define EVENT_REASON_FILTER_BASIC_RATE 0x0001
+#define EVENT_REASON_FILTER_PRIVACY 0x0002
+#define EVENT_REASON_FILTER_AUTH_MODE 0x0003
+#define EVENT_REASON_TIMEOUT 0x00ff
+
+// 20061108 WPS IE buffer
+#define MAX_IE_APPEND_SIZE 256 + 4 // Due to [E id][Length][OUI][Data] may 257 bytes
+
+typedef struct _EVENTLOG
+{
+ u16 Count; //Total count from start
+ u16 index; //Buffer index, 0 ~ 63
+ u32 EventValue[64]; //BYTE 3~2 : count, BYTE 1 : Event, BYTE 0 : reason
+} Event_Log, *pEvent_Log;
+
+typedef struct _ChanInfo
+{
+ u8 band;
+ u8 ChanNo;
+} ChanInfo, *pChanInfo;
+
+typedef struct _CHAN_LIST
+{
+ u16 Count;
+ ChanInfo Channel[50]; // 100B
+} CHAN_LIST, *psCHAN_LIST;
+
+typedef struct _RadioOff
+{
+ u8 boHwRadioOff;
+ u8 boSwRadioOff;
+} RadioOff, *psRadioOff;
+
+//===========================================================================
+typedef struct LOCAL_PARA
+{
+ u8 PermanentAddress[ MAC_ADDR_LENGTH + 2 ]; // read from EPROM, manufacture set for each NetCard
+ u8 ThisMacAddress[ MAC_ADDR_LENGTH + 2 ]; // the driver will use actually.
+
+ u32 MTUsize; // Ind to Uplayer, Max transmission unit size
+
+ u8 region_INF; //region setting from INF
+ u8 region; //real region setting of the device
+ u8 Reserved_1[2];
+
+ //// power-save variables
+ u8 iPowerSaveMode; // 0 indicates it is on, 1 indicates it is off
+ u8 ShutDowned;
+ u8 ATIMmode;
+ u8 ExcludeUnencrypted;
+
+ u16 CheckCountForPS; //Unit ime count for the decision to enter PS mode
+ u8 boHasTxActivity; //tx activity has occurred
+ u8 boMacPsValid; //Power save mode obtained from H/W is valid or not
+
+ //// Rate
+ u8 TxRateMode; // Initial, input from Registry, may be updated by GUI
+ //Tx Rate Mode: auto(DTO on), max, 1M, 2M, ..
+ u8 CurrentTxRate; // The current Tx rate
+ u8 CurrentTxRateForMng; // The current Tx rate for management frames
+ // It will be decided before connection succeeds.
+ u8 CurrentTxFallbackRate;
+
+ //for Rate handler
+ u8 BRateSet[32]; //basic rate set
+ u8 SRateSet[32]; //support rate set
+
+ u8 NumOfBRate;
+ u8 NumOfSRate;
+ u8 NumOfDsssRateInSRate; //number of DSSS rates in supported rate set
+ u8 reserved1;
+
+ u32 dwBasicRateBitmap; //bit map of basic rates
+ u32 dwSupportRateBitmap; //bit map of all support rates including
+ //basic and operational rates
+
+ ////For SME/MLME handler
+ u16 wOldSTAindex; // valid when boHandover=TRUE, store old connected STA index
+ u16 wConnectedSTAindex; // Index of peerly connected AP or IBSS in
+ // the descriptionset.
+ u16 Association_ID; // The Association ID in the (Re)Association
+ // Response frame.
+ u16 ListenInterval; // The listen interval when SME invoking MLME_
+ // (Re)Associate_Request().
+
+ RadioOff RadioOffStatus;
+ u8 Reserved0[2];
+
+ u8 boMsRadioOff; // Ndis demands to be true when set Disassoc. OID and be false when set SSID OID.
+ u8 boAntennaDiversity; //TRUE/ON or FALSE/OFF
+ u8 bAntennaNo; //which antenna
+ u8 bConnectFlag; //the connect status flag for roaming task
+
+ u8 RoamStatus;
+ u8 reserved7[3];
+
+ ChanInfo CurrentChan; //Current channel no. and channel band. It may be changed by scanning.
+ u8 boHandover; // Roaming, Hnadover to other AP.
+ u8 boCCAbusy;
+
+ u16 CWMax; // It may not be the real value that H/W used
+ u8 CWMin; // 255: set according to 802.11 spec.
+ u8 reserved2;
+
+ //11G:
+ u8 bMacOperationMode; // operation in 802.11b or 802.11g
+ u8 bSlotTimeMode; //AUTO, s32
+ u8 bPreambleMode; //AUTO, s32
+ u8 boNonERPpresent;
+
+ u8 boProtectMechanism; // H/W will take the necessary action based on this variable
+ u8 boShortPreamble; // H/W will take the necessary action based on this variable
+ u8 boShortSlotTime; // H/W will take the necessary action based on this variable
+ u8 reserved_3;
+
+ u32 RSN_IE_Bitmap; //added by WS
+ u32 RSN_OUI_Type; //added by WS
+
+ //For the BSSID
+ u8 HwBssid[MAC_ADDR_LENGTH + 2];
+ u32 HwBssidValid;
+
+ //For scan list
+ u8 BssListCount; //Total count of valid descriptor indexes
+ u8 boReceiveUncorrectInfo; //important settings in beacon/probe resp. have been changed
+ u8 NoOfJoinerInIbss;
+ u8 reserved_4;
+
+ u8 BssListIndex[ (MAX_BSS_DESCRIPT_ELEMENT+3) & ~0x03 ]; //Store the valid descriptor indexes obtained from scannings
+ u8 JoinerInIbss[ (MAX_BSS_DESCRIPT_ELEMENT+3) & ~0x03 ]; //save the BssDescriptor index in this
+ //IBSS. The index 0 is local descriptor
+ //(psLOCAL->wConnectedSTAindex).
+ //If CONNECTED : NoOfJoinerInIbss >=2
+ // else : NoOfJoinerInIbss <=1
+
+ //// General Statistics, count at Rx_handler or Tx_callback interrupt handler
+ u64 GS_XMIT_OK; // Good Frames Transmitted
+ u64 GS_RCV_OK; // Good Frames Received
+ u32 GS_RCV_ERROR; // Frames received with crc error
+ u32 GS_XMIT_ERROR; // Bad Frames Transmitted
+ u32 GS_RCV_NO_BUFFER; // Receive Buffer underrun
+ u32 GS_XMIT_ONE_COLLISION; // one collision
+ u32 GS_XMIT_MORE_COLLISIONS;// more collisions
+
+ //================================================================
+ // Statistics (no matter whether it had done successfully) -wkchen
+ //================================================================
+ u32 _NumRxMSDU;
+ u32 _NumTxMSDU;
+ u32 _dot11WEPExcludedCount;
+ u32 _dot11WEPUndecryptableCount;
+ u32 _dot11FrameDuplicateCount;
+
+ ChanInfo IbssChanSetting; // 2B. Start IBSS Channel setting by registry or WWU.
+ u8 reserved_5[2]; //It may not be used after considering RF type,
+ //region and modulation type.
+
+ CHAN_LIST sSupportChanList; // 86B. It will be obtained according to RF type and region
+ u8 reserved_6[2]; //two variables are for wep key error detection added by ws 02/02/04
+
+ u32 bWepKeyError;
+ u32 bToSelfPacketReceived;
+ u32 WepKeyDetectTimerCount;
+
+ Event_Log EventLog;
+
+ u16 SignalLostTh;
+ u16 SignalRoamTh;
+
+ // 20061108 WPS IE Append
+ u8 IE_Append_data[MAX_IE_APPEND_SIZE];
+ u16 IE_Append_size;
+ u16 reserved_7;
+
+} WB_LOCALDESCRIPT, *PWB_LOCALDESCRIPT;
+
+
diff --git a/drivers/staging/winbond/mac_structures.h b/drivers/staging/winbond/mac_structures.h
new file mode 100644
index 0000000..031d2cb
--- /dev/null
+++ b/drivers/staging/winbond/mac_structures.h
@@ -0,0 +1,670 @@
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+// MAC_Structures.h
+//
+// This file contains the definitions and data structures used by SW-MAC.
+//
+// Revision Histoy
+//=================
+// 0.1 2002 UN00
+// 0.2 20021004 PD43 CCLiu6
+// 20021018 PD43 CCLiu6
+// Add enum_TxRate type
+// Modify enum_STAState type
+// 0.3 20021023 PE23 CYLiu update MAC session struct
+// 20021108
+// 20021122 PD43 Austin
+// Deleted some unused.
+// 20021129 PD43 Austin
+// 20030617 increase the 802.11g definition
+//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+#ifndef _MAC_Structures_H_
+#define _MAC_Structures_H_
+
+
+//=========================================================
+// Some miscellaneous definitions
+//-----
+#define MAX_CHANNELS 30
+#define MAC_ADDR_LENGTH 6
+#define MAX_WEP_KEY_SIZE 16 // 128 bits
+#define MAX_802_11_FRAGMENT_NUMBER 10 // By spec
+
+//========================================================
+// 802.11 Frame define
+//-----
+#define MASK_PROTOCOL_VERSION_TYPE 0x0F
+#define MASK_FRAGMENT_NUMBER 0x000F
+#define SEQUENCE_NUMBER_SHIFT 4
+#define DIFFER_11_TO_3 18
+#define DOT_11_MAC_HEADER_SIZE 24
+#define DOT_11_SNAP_SIZE 6
+#define DOT_11_DURATION_OFFSET 2
+#define DOT_11_SEQUENCE_OFFSET 22 //Sequence control offset
+#define DOT_11_TYPE_OFFSET 30 //The start offset of 802.11 Frame//
+#define DOT_11_DATA_OFFSET 24
+#define DOT_11_DA_OFFSET 4
+#define DOT_3_TYPE_ARP 0x80F3
+#define DOT_3_TYPE_IPX 0x8137
+#define DOT_3_TYPE_OFFSET 12
+
+
+#define ETHERNET_HEADER_SIZE 14
+#define MAX_ETHERNET_PACKET_SIZE 1514
+
+
+//----- management : Type of Bits (2, 3) and Subtype of Bits (4, 5, 6, 7)
+#define MAC_SUBTYPE_MNGMNT_ASSOC_REQUEST 0x00
+#define MAC_SUBTYPE_MNGMNT_ASSOC_RESPONSE 0x10
+#define MAC_SUBTYPE_MNGMNT_REASSOC_REQUEST 0x20
+#define MAC_SUBTYPE_MNGMNT_REASSOC_RESPONSE 0x30
+#define MAC_SUBTYPE_MNGMNT_PROBE_REQUEST 0x40
+#define MAC_SUBTYPE_MNGMNT_PROBE_RESPONSE 0x50
+#define MAC_SUBTYPE_MNGMNT_BEACON 0x80
+#define MAC_SUBTYPE_MNGMNT_ATIM 0x90
+#define MAC_SUBTYPE_MNGMNT_DISASSOCIATION 0xA0
+#define MAC_SUBTYPE_MNGMNT_AUTHENTICATION 0xB0
+#define MAC_SUBTYPE_MNGMNT_DEAUTHENTICATION 0xC0
+
+//----- control : Type of Bits (2, 3) and Subtype of Bits (4, 5, 6, 7)
+#define MAC_SUBTYPE_CONTROL_PSPOLL 0xA4
+#define MAC_SUBTYPE_CONTROL_RTS 0xB4
+#define MAC_SUBTYPE_CONTROL_CTS 0xC4
+#define MAC_SUBTYPE_CONTROL_ACK 0xD4
+#define MAC_SUBTYPE_CONTROL_CFEND 0xE4
+#define MAC_SUBTYPE_CONTROL_CFEND_CFACK 0xF4
+
+//----- data : Type of Bits (2, 3) and Subtype of Bits (4, 5, 6, 7)
+#define MAC_SUBTYPE_DATA 0x08
+#define MAC_SUBTYPE_DATA_CFACK 0x18
+#define MAC_SUBTYPE_DATA_CFPOLL 0x28
+#define MAC_SUBTYPE_DATA_CFACK_CFPOLL 0x38
+#define MAC_SUBTYPE_DATA_NULL 0x48
+#define MAC_SUBTYPE_DATA_CFACK_NULL 0x58
+#define MAC_SUBTYPE_DATA_CFPOLL_NULL 0x68
+#define MAC_SUBTYPE_DATA_CFACK_CFPOLL_NULL 0x78
+
+//----- Frame Type of Bits (2, 3)
+#define MAC_TYPE_MANAGEMENT 0x00
+#define MAC_TYPE_CONTROL 0x04
+#define MAC_TYPE_DATA 0x08
+
+//----- definitions for Management Frame Element ID (1 BYTE)
+#define ELEMENT_ID_SSID 0
+#define ELEMENT_ID_SUPPORTED_RATES 1
+#define ELEMENT_ID_FH_PARAMETER_SET 2
+#define ELEMENT_ID_DS_PARAMETER_SET 3
+#define ELEMENT_ID_CF_PARAMETER_SET 4
+#define ELEMENT_ID_TIM 5
+#define ELEMENT_ID_IBSS_PARAMETER_SET 6
+// 7~15 reserverd
+#define ELEMENT_ID_CHALLENGE_TEXT 16
+// 17~31 reserved for challenge text extension
+// 32~255 reserved
+//-- 11G --
+#define ELEMENT_ID_ERP_INFORMATION 42
+#define ELEMENT_ID_EXTENDED_SUPPORTED_RATES 50
+
+//-- WPA --
+
+#define ELEMENT_ID_RSN_WPA 221
+#ifdef _WPA2_
+#define ELEMENT_ID_RSN_WPA2 48
+#endif //endif WPA2
+
+#define WLAN_MAX_PAIRWISE_CIPHER_SUITE_COUNT ((u16) 6)
+#define WLAN_MAX_AUTH_KEY_MGT_SUITE_LIST_COUNT ((u16) 2)
+
+#ifdef WB_LINUX
+#define UNALIGNED
+#endif
+
+//========================================================
+typedef enum enum_PowerManagementMode
+{
+ ACTIVE = 0,
+ POWER_SAVE
+} WB_PM_Mode, *PWB_PM_MODE;
+
+//===================================================================
+// Reason Code (Table 18): indicate the reason of DisAssoc, DeAuthen
+// length of ReasonCode is 2 Octs.
+//===================================================================
+#define REASON_REASERED 0
+#define REASON_UNSPECIDIED 1
+#define REASON_PREAUTH_INVALID 2
+#define DEAUTH_REASON_LEFT_BSS 3
+#define DISASS_REASON_AP_INACTIVE 4
+#define DISASS_REASON_AP_BUSY 5
+#define REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6
+#define REASON_CLASS3_FRAME_FROM_NONASSO_STA 7
+#define DISASS_REASON_LEFT_BSS 8
+#define REASON_NOT_AUTH_YET 9
+//802.11i define
+#define REASON_INVALID_IE 13
+#define REASON_MIC_ERROR 14
+#define REASON_4WAY_HANDSHAKE_TIMEOUT 15
+#define REASON_GROUPKEY_UPDATE_TIMEOUT 16
+#define REASON_IE_DIFF_4WAY_ASSOC 17
+#define REASON_INVALID_MULTICAST_CIPHER 18
+#define REASON_INVALID_UNICAST_CIPHER 19
+#define REASON_INVALID_AKMP 20
+#define REASON_UNSUPPORTED_RSNIE_VERSION 21
+#define REASON_INVALID_RSNIE_CAPABILITY 22
+#define REASON_802_1X_AUTH_FAIL 23
+#define REASON_CIPHER_REJECT_PER_SEC_POLICY 14
+
+/*
+//===========================================================
+// enum_MMPDUResultCode --
+// Status code (2 Octs) in the MMPDU's frame body. Table.19
+//
+//===========================================================
+enum enum_MMPDUResultCode
+{
+// SUCCESS = 0, // Redefined
+ UNSPECIFIED_FAILURE = 1,
+
+ // 2 - 9 Reserved
+
+ NOT_SUPPROT_CAPABILITIES = 10,
+
+ //REASSOCIATION_DENIED
+ //
+ REASSOC_DENIED_UNABLE_CFM_ASSOC_EXIST = 11,
+
+ //ASSOCIATION_DENIED_NOT_IN_STANDARD
+ //
+ ASSOC_DENIED_REASON_NOT_IN_STANDARD = 12,
+ PEER_NOT_SUPPORT_AUTH_ALGORITHM = 13,
+ AUTH_SEQNUM_OUT_OF_EXPECT = 14,
+ AUTH_REJECT_REASON_CHALLENGE_FAIL = 15,
+ AUTH_REJECT_REASON_WAIT_TIMEOUT = 16,
+ ASSOC_DENIED_REASON_AP_BUSY = 17,
+ ASSOC_DENIED_REASON_NOT_SUPPORT_BASIC_RATE = 18
+} WB_MMPDURESULTCODE, *PWB_MMPDURESULTCODE;
+*/
+
+//===========================================================
+// enum_TxRate --
+// Define the transmission constants based on W89C32 MAC
+// target specification.
+//===========================================================
+typedef enum enum_TxRate
+{
+ TXRATE_1M = 0,
+ TXRATE_2MLONG = 2,
+ TXRATE_2MSHORT = 3,
+ TXRATE_55MLONG = 4,
+ TXRATE_55MSHORT = 5,
+ TXRATE_11MLONG = 6,
+ TXRATE_11MSHORT = 7,
+ TXRATE_AUTO = 255 // PD43 20021108
+} WB_TXRATE, *PWB_TXRATE;
+
+
+#define RATE_BITMAP_1M 1
+#define RATE_BITMAP_2M 2
+#define RATE_BITMAP_5dot5M 5
+#define RATE_BITMAP_6M 6
+#define RATE_BITMAP_9M 9
+#define RATE_BITMAP_11M 11
+#define RATE_BITMAP_12M 12
+#define RATE_BITMAP_18M 18
+#define RATE_BITMAP_22M 22
+#define RATE_BITMAP_24M 24
+#define RATE_BITMAP_33M 17
+#define RATE_BITMAP_36M 19
+#define RATE_BITMAP_48M 25
+#define RATE_BITMAP_54M 28
+
+#define RATE_AUTO 0
+#define RATE_1M 2
+#define RATE_2M 4
+#define RATE_5dot5M 11
+#define RATE_6M 12
+#define RATE_9M 18
+#define RATE_11M 22
+#define RATE_12M 24
+#define RATE_18M 36
+#define RATE_22M 44
+#define RATE_24M 48
+#define RATE_33M 66
+#define RATE_36M 72
+#define RATE_48M 96
+#define RATE_54M 108
+#define RATE_MAX 255
+
+//CAPABILITY
+#define CAPABILITY_ESS_BIT 0x0001
+#define CAPABILITY_IBSS_BIT 0x0002
+#define CAPABILITY_CF_POLL_BIT 0x0004
+#define CAPABILITY_CF_POLL_REQ_BIT 0x0008
+#define CAPABILITY_PRIVACY_BIT 0x0010
+#define CAPABILITY_SHORT_PREAMBLE_BIT 0x0020
+#define CAPABILITY_PBCC_BIT 0x0040
+#define CAPABILITY_CHAN_AGILITY_BIT 0x0080
+#define CAPABILITY_SHORT_SLOT_TIME_BIT 0x0400
+#define CAPABILITY_DSSS_OFDM_BIT 0x2000
+
+
+struct Capability_Information_Element
+{
+ union
+ {
+ u16 __attribute__ ((packed)) wValue;
+ #ifdef _BIG_ENDIAN_ //20060926 add by anson's endian
+ struct _Capability
+ {
+ //-- 11G --
+ u8 Reserved3 : 2;
+ u8 DSSS_OFDM : 1;
+ u8 Reserved2 : 2;
+ u8 Short_Slot_Time : 1;
+ u8 Reserved1 : 2;
+ u8 Channel_Agility : 1;
+ u8 PBCC : 1;
+ u8 ShortPreamble : 1;
+ u8 CF_Privacy : 1;
+ u8 CF_Poll_Request : 1;
+ u8 CF_Pollable : 1;
+ u8 IBSS : 1;
+ u8 ESS : 1;
+ } __attribute__ ((packed)) Capability;
+ #else
+ struct _Capability
+ {
+ u8 ESS : 1;
+ u8 IBSS : 1;
+ u8 CF_Pollable : 1;
+ u8 CF_Poll_Request : 1;
+ u8 CF_Privacy : 1;
+ u8 ShortPreamble : 1;
+ u8 PBCC : 1;
+ u8 Channel_Agility : 1;
+ u8 Reserved1 : 2;
+ //-- 11G --
+ u8 Short_Slot_Time : 1;
+ u8 Reserved2 : 2;
+ u8 DSSS_OFDM : 1;
+ u8 Reserved3 : 2;
+ } __attribute__ ((packed)) Capability;
+ #endif
+ }__attribute__ ((packed)) ;
+}__attribute__ ((packed));
+
+struct FH_Parameter_Set_Element
+{
+ u8 Element_ID;
+ u8 Length;
+ u8 Dwell_Time[2];
+ u8 Hop_Set;
+ u8 Hop_Pattern;
+ u8 Hop_Index;
+};
+
+struct DS_Parameter_Set_Element
+{
+ u8 Element_ID;
+ u8 Length;
+ u8 Current_Channel;
+};
+
+struct Supported_Rates_Element
+{
+ u8 Element_ID;
+ u8 Length;
+ u8 SupportedRates[8];
+}__attribute__ ((packed));
+
+struct SSID_Element
+{
+ u8 Element_ID;
+ u8 Length;
+ u8 SSID[32];
+}__attribute__ ((packed)) ;
+
+struct CF_Parameter_Set_Element
+{
+ u8 Element_ID;
+ u8 Length;
+ u8 CFP_Count;
+ u8 CFP_Period;
+ u8 CFP_MaxDuration[2]; // in Time Units
+ u8 CFP_DurRemaining[2]; // in time units
+};
+
+struct TIM_Element
+{
+ u8 Element_ID;
+ u8 Length;
+ u8 DTIM_Count;
+ u8 DTIM_Period;
+ u8 Bitmap_Control;
+ u8 Partial_Virtual_Bitmap[251];
+};
+
+struct IBSS_Parameter_Set_Element
+{
+ u8 Element_ID;
+ u8 Length;
+ u8 ATIM_Window[2];
+};
+
+struct Challenge_Text_Element
+{
+ u8 Element_ID;
+ u8 Length;
+ u8 Challenge_Text[253];
+};
+
+struct PHY_Parameter_Set_Element
+{
+// int aSlotTime;
+// int aSifsTime;
+ s32 aCCATime;
+ s32 aRxTxTurnaroundTime;
+ s32 aTxPLCPDelay;
+ s32 RxPLCPDelay;
+ s32 aRxTxSwitchTime;
+ s32 aTxRampOntime;
+ s32 aTxRampOffTime;
+ s32 aTxRFDelay;
+ s32 aRxRFDelay;
+ s32 aAirPropagationTime;
+ s32 aMACProcessingDelay;
+ s32 aPreambleLength;
+ s32 aPLCPHeaderLength;
+ s32 aMPDUDurationFactor;
+ s32 aMPDUMaxLength;
+// int aCWmin;
+// int aCWmax;
+};
+
+//-- 11G --
+struct ERP_Information_Element
+{
+ u8 Element_ID;
+ u8 Length;
+ #ifdef _BIG_ENDIAN_ //20060926 add by anson's endian
+ u8 Reserved:5; //20060926 add by anson
+ u8 Barker_Preamble_Mode:1;
+ u8 Use_Protection:1;
+ u8 NonERP_Present:1;
+ #else
+ u8 NonERP_Present:1;
+ u8 Use_Protection:1;
+ u8 Barker_Preamble_Mode:1;
+ u8 Reserved:5;
+ #endif
+};
+
+struct Extended_Supported_Rates_Element
+{
+ u8 Element_ID;
+ u8 Length;
+ u8 ExtendedSupportedRates[255];
+}__attribute__ ((packed));
+
+//WPA(802.11i draft 3.0)
+#define VERSION_WPA 1
+#ifdef _WPA2_
+#define VERSION_WPA2 1
+#endif //end def _WPA2_
+#define OUI_WPA 0x00F25000 //WPA2.0 OUI=00:50:F2, the MSB is reserved for suite type
+#ifdef _WPA2_
+#define OUI_WPA2 0x00AC0F00 // for wpa2 change to 0x00ACOF04 by Ws 26/04/04
+#endif //end def _WPA2_
+
+#define OUI_WPA_ADDITIONAL 0x01
+#define WLAN_MIN_RSN_WPA_LENGTH 6 //added by ws 09/10/04
+#ifdef _WPA2_
+#define WLAN_MIN_RSN_WPA2_LENGTH 2 // Fix to 2 09/14/05
+#endif //end def _WPA2_
+
+#define oui_wpa (u32)(OUI_WPA|OUI_WPA_ADDITIONAL)
+
+#define WPA_OUI_BIG ((u32) 0x01F25000)//added by ws 09/23/04
+#define WPA_OUI_LITTLE ((u32) 0x01F25001)//added by ws 09/23/04
+
+#define WPA_WPS_OUI cpu_to_le32(0x04F25000) // 20061108 For WPS. It's little endian. Big endian is 0x0050F204
+
+//-----WPA2-----
+#ifdef _WPA2_
+#define WPA2_OUI_BIG ((u32)0x01AC0F00)
+#define WPA2_OUI_LITTLE ((u32)0x01AC0F01)
+#endif //end def _WPA2_
+
+//Authentication suite
+#define OUI_AUTH_WPA_NONE 0x00 //for WPA_NONE
+#define OUI_AUTH_8021X 0x01
+#define OUI_AUTH_PSK 0x02
+//Cipher suite
+#define OUI_CIPHER_GROUP_KEY 0x00 //added by ws 05/21/04
+#define OUI_CIPHER_WEP_40 0x01
+#define OUI_CIPHER_TKIP 0x02
+#define OUI_CIPHER_CCMP 0x04
+#define OUI_CIPHER_WEP_104 0x05
+
+typedef struct _SUITE_SELECTOR_
+{
+ union
+ {
+ u8 Value[4];
+ struct _SUIT_
+ {
+ u8 OUI[3];
+ u8 Type;
+ }SuitSelector;
+ };
+}SUITE_SELECTOR;
+
+//-- WPA --
+struct RSN_Information_Element
+{
+ u8 Element_ID;
+ u8 Length;
+ UNALIGNED SUITE_SELECTOR OuiWPAAdditional;//WPA version 2.0 additional field, and should be 00:50:F2:01
+ u16 Version;
+ SUITE_SELECTOR GroupKeySuite;
+ u16 PairwiseKeySuiteCount;
+ SUITE_SELECTOR PairwiseKeySuite[1];
+}__attribute__ ((packed));
+struct RSN_Auth_Sub_Information_Element
+{
+ u16 AuthKeyMngtSuiteCount;
+ SUITE_SELECTOR AuthKeyMngtSuite[1];
+}__attribute__ ((packed));
+
+//-- WPA2 --
+struct RSN_Capability_Element
+{
+ union
+ {
+ u16 __attribute__ ((packed)) wValue;
+ #ifdef _BIG_ENDIAN_ //20060927 add by anson's endian
+ struct _RSN_Capability
+ {
+ u16 __attribute__ ((packed)) Reserved2 : 8; // 20051201
+ u16 __attribute__ ((packed)) Reserved1 : 2;
+ u16 __attribute__ ((packed)) GTK_Replay_Counter : 2;
+ u16 __attribute__ ((packed)) PTK_Replay_Counter : 2;
+ u16 __attribute__ ((packed)) No_Pairwise : 1;
+ u16 __attribute__ ((packed)) Pre_Auth : 1;
+ }__attribute__ ((packed)) RSN_Capability;
+ #else
+ struct _RSN_Capability
+ {
+ u16 __attribute__ ((packed)) Pre_Auth : 1;
+ u16 __attribute__ ((packed)) No_Pairwise : 1;
+ u16 __attribute__ ((packed)) PTK_Replay_Counter : 2;
+ u16 __attribute__ ((packed)) GTK_Replay_Counter : 2;
+ u16 __attribute__ ((packed)) Reserved1 : 2;
+ u16 __attribute__ ((packed)) Reserved2 : 8; // 20051201
+ }__attribute__ ((packed)) RSN_Capability;
+ #endif
+
+ }__attribute__ ((packed)) ;
+}__attribute__ ((packed)) ;
+
+#ifdef _WPA2_
+typedef struct _PMKID
+{
+ u8 pValue[16];
+}PMKID;
+
+struct WPA2_RSN_Information_Element
+{
+ u8 Element_ID;
+ u8 Length;
+ u16 Version;
+ SUITE_SELECTOR GroupKeySuite;
+ u16 PairwiseKeySuiteCount;
+ SUITE_SELECTOR PairwiseKeySuite[1];
+
+}__attribute__ ((packed));
+
+struct WPA2_RSN_Auth_Sub_Information_Element
+{
+ u16 AuthKeyMngtSuiteCount;
+ SUITE_SELECTOR AuthKeyMngtSuite[1];
+}__attribute__ ((packed));
+
+
+struct PMKID_Information_Element
+{
+ u16 PMKID_Count;
+ PMKID pmkid [16] ;
+}__attribute__ ((packed));
+
+#endif //enddef _WPA2_
+//============================================================
+// MAC Frame structure (different type) and subfield structure
+//============================================================
+struct MAC_frame_control
+{
+ u8 mac_frame_info; // a combination of the [Protocol Version, Control Type, Control Subtype]
+ #ifdef _BIG_ENDIAN_ //20060927 add by anson's endian
+ u8 order:1;
+ u8 WEP:1;
+ u8 more_data:1;
+ u8 pwr_mgt:1;
+ u8 retry:1;
+ u8 more_frag:1;
+ u8 from_ds:1;
+ u8 to_ds:1;
+ #else
+ u8 to_ds:1;
+ u8 from_ds:1;
+ u8 more_frag:1;
+ u8 retry:1;
+ u8 pwr_mgt:1;
+ u8 more_data:1;
+ u8 WEP:1;
+ u8 order:1;
+ #endif
+} __attribute__ ((packed));
+
+struct Management_Frame {
+ struct MAC_frame_control frame_control; // 2B, ToDS,FromDS,MoreFrag,MoreData,Order=0
+ u16 duration;
+ u8 DA[MAC_ADDR_LENGTH]; // Addr1
+ u8 SA[MAC_ADDR_LENGTH]; // Addr2
+ u8 BSSID[MAC_ADDR_LENGTH]; // Addr3
+ u16 Sequence_Control;
+ // Management Frame Body <= 325 bytes
+ // FCS 4 bytes
+}__attribute__ ((packed));
+
+// SW-MAC don't Tx/Rx Control-Frame, HW-MAC do it.
+struct Control_Frame {
+ struct MAC_frame_control frame_control; // ToDS,FromDS,MoreFrag,Retry,MoreData,WEP,Order=0
+ u16 duration;
+ u8 RA[MAC_ADDR_LENGTH];
+ u8 TA[MAC_ADDR_LENGTH];
+ u16 FCS;
+}__attribute__ ((packed));
+
+struct Data_Frame {
+ struct MAC_frame_control frame_control;
+ u16 duration;
+ u8 Addr1[MAC_ADDR_LENGTH];
+ u8 Addr2[MAC_ADDR_LENGTH];
+ u8 Addr3[MAC_ADDR_LENGTH];
+ u16 Sequence_Control;
+ u8 Addr4[MAC_ADDR_LENGTH]; // only exist when ToDS=FromDS=1
+ // Data Frame Body <= 2312
+ // FCS
+}__attribute__ ((packed));
+
+struct Disassociation_Frame_Body
+{
+ u16 reasonCode;
+}__attribute__ ((packed));
+
+struct Association_Request_Frame_Body
+{
+ u16 capability_information;
+ u16 listenInterval;
+ u8 Current_AP_Address[MAC_ADDR_LENGTH];//for reassociation only
+ // SSID (2+32 bytes)
+ // Supported_Rates (2+8 bytes)
+}__attribute__ ((packed));
+
+struct Association_Response_Frame_Body
+{
+ u16 capability_information;
+ u16 statusCode;
+ u16 Association_ID;
+ struct Supported_Rates_Element supportedRates;
+}__attribute__ ((packed));
+
+/*struct Reassociation_Request_Frame_Body
+{
+ u16 capability_information;
+ u16 listenInterval;
+ u8 Current_AP_Address[MAC_ADDR_LENGTH];
+ // SSID (2+32 bytes)
+ // Supported_Rates (2+8 bytes)
+};*/
+// eliminated by WS 07/22/04 comboined with associateion request frame.
+
+struct Reassociation_Response_Frame_Body
+{
+ u16 capability_information;
+ u16 statusCode;
+ u16 Association_ID;
+ struct Supported_Rates_Element supportedRates;
+}__attribute__ ((packed));
+
+struct Deauthentication_Frame_Body
+{
+ u16 reasonCode;
+}__attribute__ ((packed));
+
+
+struct Probe_Response_Frame_Body
+{
+ u16 Timestamp;
+ u16 Beacon_Interval;
+ u16 Capability_Information;
+ // SSID
+ // Supported_Rates
+ // PHY parameter Set (DS Parameters)
+ // CF parameter Set
+ // IBSS parameter Set
+}__attribute__ ((packed));
+
+struct Authentication_Frame_Body
+{
+ u16 algorithmNumber;
+ u16 sequenceNumber;
+ u16 statusCode;
+ // NB: don't include ChallengeText in this structure
+ // struct Challenge_Text_Element sChallengeTextElement; // wkchen added
+}__attribute__ ((packed));
+
+
+#endif // _MAC_Structure_H_
+
+
diff --git a/drivers/staging/winbond/mds.c b/drivers/staging/winbond/mds.c
new file mode 100644
index 0000000..8ce6389
--- /dev/null
+++ b/drivers/staging/winbond/mds.c
@@ -0,0 +1,630 @@
+#include "os_common.h"
+
+void
+Mds_reset_descriptor(PADAPTER Adapter)
+{
+ PMDS pMds = &Adapter->Mds;
+
+ pMds->TxPause = 0;
+ pMds->TxThreadCount = 0;
+ pMds->TxFillIndex = 0;
+ pMds->TxDesIndex = 0;
+ pMds->ScanTxPause = 0;
+ memset(pMds->TxOwner, 0, ((MAX_USB_TX_BUFFER_NUMBER + 3) & ~0x03));
+}
+
+unsigned char
+Mds_initial(PADAPTER Adapter)
+{
+ PMDS pMds = &Adapter->Mds;
+
+ pMds->TxPause = FALSE;
+ pMds->TxRTSThreshold = DEFAULT_RTSThreshold;
+ pMds->TxFragmentThreshold = DEFAULT_FRAGMENT_THRESHOLD;
+
+ vRxTimerInit(Adapter);//for WPA countermeasure
+
+ return hal_get_tx_buffer( &Adapter->sHwData, &pMds->pTxBuffer );
+}
+
+void
+Mds_Destroy(PADAPTER Adapter)
+{
+ vRxTimerStop(Adapter);
+}
+
+void
+Mds_Tx(PADAPTER Adapter)
+{
+ phw_data_t pHwData = &Adapter->sHwData;
+ PMDS pMds = &Adapter->Mds;
+ DESCRIPTOR TxDes;
+ PDESCRIPTOR pTxDes = &TxDes;
+ PUCHAR XmitBufAddress;
+ u16 XmitBufSize, PacketSize, stmp, CurrentSize, FragmentThreshold;
+ u8 FillIndex, TxDesIndex, FragmentCount, FillCount;
+ unsigned char BufferFilled = FALSE, MICAdd = 0;
+
+
+ if (pMds->TxPause)
+ return;
+ if (!hal_driver_init_OK(pHwData))
+ return;
+
+ //Only one thread can be run here
+ if (!OS_ATOMIC_INC( Adapter, &pMds->TxThreadCount) == 1)
+ goto cleanup;
+
+ // Start to fill the data
+ do {
+ FillIndex = pMds->TxFillIndex;
+ if (pMds->TxOwner[FillIndex]) { // Is owned by software 0:Yes 1:No
+#ifdef _PE_TX_DUMP_
+ WBDEBUG(("[Mds_Tx] Tx Owner is H/W.\n"));
+#endif
+ break;
+ }
+
+ XmitBufAddress = pMds->pTxBuffer + (MAX_USB_TX_BUFFER * FillIndex); //Get buffer
+ XmitBufSize = 0;
+ FillCount = 0;
+ do {
+ PacketSize = Adapter->sMlmeFrame.len;
+ if (!PacketSize)
+ break;
+
+ //For Check the buffer resource
+ FragmentThreshold = CURRENT_FRAGMENT_THRESHOLD;
+ //931130.5.b
+ FragmentCount = PacketSize/FragmentThreshold + 1;
+ stmp = PacketSize + FragmentCount*32 + 8;//931130.5.c 8:MIC
+ if ((XmitBufSize + stmp) >= MAX_USB_TX_BUFFER) {
+ printk("[Mds_Tx] Excess max tx buffer.\n");
+ break; // buffer is not enough
+ }
+
+
+ //
+ // Start transmitting
+ //
+ BufferFilled = TRUE;
+
+ /* Leaves first u8 intact */
+ memset((PUCHAR)pTxDes + 1, 0, sizeof(DESCRIPTOR) - 1);
+
+ TxDesIndex = pMds->TxDesIndex;//Get the current ID
+ pTxDes->Descriptor_ID = TxDesIndex;
+ pMds->TxDesFrom[ TxDesIndex ] = 2;//Storing the information of source comming from
+ pMds->TxDesIndex++;
+ pMds->TxDesIndex %= MAX_USB_TX_DESCRIPTOR;
+
+ MLME_GetNextPacket( Adapter, pTxDes );
+
+ // Copy header. 8byte USB + 24byte 802.11Hdr. Set TxRate, Preamble type
+ Mds_HeaderCopy( Adapter, pTxDes, XmitBufAddress );
+
+ // For speed up Key setting
+ if (pTxDes->EapFix) {
+#ifdef _PE_TX_DUMP_
+ WBDEBUG(("35: EPA 4th frame detected. Size = %d\n", PacketSize));
+#endif
+ pHwData->IsKeyPreSet = 1;
+ }
+
+ // Copy (fragment) frame body, and set USB, 802.11 hdr flag
+ CurrentSize = Mds_BodyCopy(Adapter, pTxDes, XmitBufAddress);
+
+ // Set RTS/CTS and Normal duration field into buffer
+ Mds_DurationSet(Adapter, pTxDes, XmitBufAddress);
+
+ //
+ // Calculation MIC from buffer which maybe fragment, then fill into temporary address 8 byte
+ // 931130.5.e
+ if (MICAdd)
+ Mds_MicFill( Adapter, pTxDes, XmitBufAddress );
+
+ //Shift to the next address
+ XmitBufSize += CurrentSize;
+ XmitBufAddress += CurrentSize;
+
+#ifdef _IBSS_BEACON_SEQ_STICK_
+ if ((XmitBufAddress[ DOT_11_DA_OFFSET+8 ] & 0xfc) != MAC_SUBTYPE_MNGMNT_PROBE_REQUEST) // +8 for USB hdr
+#endif
+ pMds->TxToggle = TRUE;
+
+ // Get packet to transmit completed, 1:TESTSTA 2:MLME 3: Ndis data
+ MLME_SendComplete(Adapter, 0, TRUE);
+
+ // Software TSC count 20060214
+ pMds->TxTsc++;
+ if (pMds->TxTsc == 0)
+ pMds->TxTsc_2++;
+
+ FillCount++; // 20060928
+ } while (HAL_USB_MODE_BURST(pHwData)); // End of multiple MSDU copy loop. FALSE = single TRUE = multiple sending
+
+ // Move to the next one, if necessary
+ if (BufferFilled) {
+ // size setting
+ pMds->TxBufferSize[ FillIndex ] = XmitBufSize;
+
+ // 20060928 set Tx count
+ pMds->TxCountInBuffer[FillIndex] = FillCount;
+
+ // Set owner flag
+ pMds->TxOwner[FillIndex] = 1;
+
+ pMds->TxFillIndex++;
+ pMds->TxFillIndex %= MAX_USB_TX_BUFFER_NUMBER;
+ BufferFilled = FALSE;
+ } else
+ break;
+
+ if (!PacketSize) // No more pk for transmitting
+ break;
+
+ } while(TRUE);
+
+ //
+ // Start to send by lower module
+ //
+ if (!pHwData->IsKeyPreSet)
+ Wb35Tx_start(pHwData);
+
+ cleanup:
+ OS_ATOMIC_DEC( Adapter, &pMds->TxThreadCount );
+}
+
+void
+Mds_SendComplete(PADAPTER Adapter, PT02_DESCRIPTOR pT02)
+{
+ PMDS pMds = &Adapter->Mds;
+ phw_data_t pHwData = &Adapter->sHwData;
+ u8 PacketId = (u8)pT02->T02_Tx_PktID;
+ unsigned char SendOK = TRUE;
+ u8 RetryCount, TxRate;
+
+ if (pT02->T02_IgnoreResult) // Don't care the result
+ return;
+ if (pT02->T02_IsLastMpdu) {
+ //TODO: DTO -- get the retry count and fragment count
+ // Tx rate
+ TxRate = pMds->TxRate[ PacketId ][ 0 ];
+ RetryCount = (u8)pT02->T02_MPDU_Cnt;
+ if (pT02->value & FLAG_ERROR_TX_MASK) {
+ SendOK = FALSE;
+
+ if (pT02->T02_transmit_abort || pT02->T02_out_of_MaxTxMSDULiftTime) {
+ //retry error
+ pHwData->dto_tx_retry_count += (RetryCount+1);
+ //[for tx debug]
+ if (RetryCount<7)
+ pHwData->tx_retry_count[RetryCount] += RetryCount;
+ else
+ pHwData->tx_retry_count[7] += RetryCount;
+ #ifdef _PE_STATE_DUMP_
+ WBDEBUG(("dto_tx_retry_count =%d\n", pHwData->dto_tx_retry_count));
+ #endif
+ MTO_SetTxCount(Adapter, TxRate, RetryCount);
+ }
+ pHwData->dto_tx_frag_count += (RetryCount+1);
+
+ //[for tx debug]
+ if (pT02->T02_transmit_abort_due_to_TBTT)
+ pHwData->tx_TBTT_start_count++;
+ if (pT02->T02_transmit_without_encryption_due_to_wep_on_false)
+ pHwData->tx_WepOn_false_count++;
+ if (pT02->T02_discard_due_to_null_wep_key)
+ pHwData->tx_Null_key_count++;
+ } else {
+ if (pT02->T02_effective_transmission_rate)
+ pHwData->tx_ETR_count++;
+ MTO_SetTxCount(Adapter, TxRate, RetryCount);
+ }
+
+ // Clear send result buffer
+ pMds->TxResult[ PacketId ] = 0;
+ } else
+ pMds->TxResult[ PacketId ] |= ((u16)(pT02->value & 0x0ffff));
+}
+
+void
+Mds_HeaderCopy(PADAPTER Adapter, PDESCRIPTOR pDes, PUCHAR TargetBuffer)
+{
+ PMDS pMds = &Adapter->Mds;
+ PUCHAR src_buffer = pDes->buffer_address[0];//931130.5.g
+ PT00_DESCRIPTOR pT00;
+ PT01_DESCRIPTOR pT01;
+ u16 stmp;
+ u8 i, ctmp1, ctmp2, ctmpf;
+ u16 FragmentThreshold = CURRENT_FRAGMENT_THRESHOLD;
+
+
+ stmp = pDes->buffer_total_size;
+ //
+ // Set USB header 8 byte
+ //
+ pT00 = (PT00_DESCRIPTOR)TargetBuffer;
+ TargetBuffer += 4;
+ pT01 = (PT01_DESCRIPTOR)TargetBuffer;
+ TargetBuffer += 4;
+
+ pT00->value = 0;// Clear
+ pT01->value = 0;// Clear
+
+ pT00->T00_tx_packet_id = pDes->Descriptor_ID;// Set packet ID
+ pT00->T00_header_length = 24;// Set header length
+ pT01->T01_retry_abort_ebable = 1;//921013 931130.5.h
+
+ // Key ID setup
+ pT01->T01_wep_id = 0;
+
+ FragmentThreshold = DEFAULT_FRAGMENT_THRESHOLD; //Do not fragment
+ // Copy full data, the 1'st buffer contain all the data 931130.5.j
+ memcpy( TargetBuffer, src_buffer, DOT_11_MAC_HEADER_SIZE );// Copy header
+ pDes->buffer_address[0] = src_buffer + DOT_11_MAC_HEADER_SIZE;
+ pDes->buffer_total_size -= DOT_11_MAC_HEADER_SIZE;
+ pDes->buffer_size[0] = pDes->buffer_total_size;
+
+ // Set fragment threshold
+ FragmentThreshold -= (DOT_11_MAC_HEADER_SIZE + 4);
+ pDes->FragmentThreshold = FragmentThreshold;
+
+ // Set more frag bit
+ TargetBuffer[1] |= 0x04;// Set more frag bit
+
+ //
+ // Set tx rate
+ //
+ stmp = *(PUSHORT)(TargetBuffer+30); // 2n alignment address
+
+ //Use basic rate
+ ctmp1 = ctmpf = CURRENT_TX_RATE_FOR_MNG;
+
+ pDes->TxRate = ctmp1;
+ #ifdef _PE_TX_DUMP_
+ WBDEBUG(("Tx rate =%x\n", ctmp1));
+ #endif
+
+ pT01->T01_modulation_type = (ctmp1%3) ? 0 : 1;
+
+ for( i=0; i<2; i++ ) {
+ if( i == 1 )
+ ctmp1 = ctmpf;
+
+ pMds->TxRate[pDes->Descriptor_ID][i] = ctmp1; // backup the ta rate and fall back rate
+
+ if( ctmp1 == 108) ctmp2 = 7;
+ else if( ctmp1 == 96 ) ctmp2 = 6; // Rate convert for USB
+ else if( ctmp1 == 72 ) ctmp2 = 5;
+ else if( ctmp1 == 48 ) ctmp2 = 4;
+ else if( ctmp1 == 36 ) ctmp2 = 3;
+ else if( ctmp1 == 24 ) ctmp2 = 2;
+ else if( ctmp1 == 18 ) ctmp2 = 1;
+ else if( ctmp1 == 12 ) ctmp2 = 0;
+ else if( ctmp1 == 22 ) ctmp2 = 3;
+ else if( ctmp1 == 11 ) ctmp2 = 2;
+ else if( ctmp1 == 4 ) ctmp2 = 1;
+ else ctmp2 = 0; // if( ctmp1 == 2 ) or default
+
+ if( i == 0 )
+ pT01->T01_transmit_rate = ctmp2;
+ else
+ pT01->T01_fall_back_rate = ctmp2;
+ }
+
+ //
+ // Set preamble type
+ //
+ if ((pT01->T01_modulation_type == 0) && (pT01->T01_transmit_rate == 0)) // RATE_1M
+ pDes->PreambleMode = WLAN_PREAMBLE_TYPE_LONG;
+ else
+ pDes->PreambleMode = CURRENT_PREAMBLE_MODE;
+ pT01->T01_plcp_header_length = pDes->PreambleMode; // Set preamble
+
+}
+
+// The function return the 4n size of usb pk
+u16
+Mds_BodyCopy(PADAPTER Adapter, PDESCRIPTOR pDes, PUCHAR TargetBuffer)
+{
+ PT00_DESCRIPTOR pT00;
+ PMDS pMds = &Adapter->Mds;
+ PUCHAR buffer, src_buffer, pctmp;
+ u16 Size = 0;
+ u16 SizeLeft, CopySize, CopyLeft, stmp;
+ u8 buf_index, FragmentCount = 0;
+
+
+ // Copy fragment body
+ buffer = TargetBuffer; // shift 8B usb + 24B 802.11
+ SizeLeft = pDes->buffer_total_size;
+ buf_index = pDes->buffer_start_index;
+
+ pT00 = (PT00_DESCRIPTOR)buffer;
+ while (SizeLeft) {
+ pT00 = (PT00_DESCRIPTOR)buffer;
+ CopySize = SizeLeft;
+ if (SizeLeft > pDes->FragmentThreshold) {
+ CopySize = pDes->FragmentThreshold;
+ pT00->T00_frame_length = 24 + CopySize;//Set USB length
+ } else
+ pT00->T00_frame_length = 24 + SizeLeft;//Set USB length
+
+ SizeLeft -= CopySize;
+
+ // 1 Byte operation
+ pctmp = (PUCHAR)( buffer + 8 + DOT_11_SEQUENCE_OFFSET );
+ *pctmp &= 0xf0;
+ *pctmp |= FragmentCount;//931130.5.m
+ if( !FragmentCount )
+ pT00->T00_first_mpdu = 1;
+
+ buffer += 32; // 8B usb + 24B 802.11 header
+ Size += 32;
+
+ // Copy into buffer
+ stmp = CopySize + 3;
+ stmp &= ~0x03;//4n Alignment
+ Size += stmp;// Current 4n offset of mpdu
+
+ while (CopySize) {
+ // Copy body
+ src_buffer = pDes->buffer_address[buf_index];
+ CopyLeft = CopySize;
+ if (CopySize >= pDes->buffer_size[buf_index]) {
+ CopyLeft = pDes->buffer_size[buf_index];
+
+ // Get the next buffer of descriptor
+ buf_index++;
+ buf_index %= MAX_DESCRIPTOR_BUFFER_INDEX;
+ } else {
+ PUCHAR pctmp = pDes->buffer_address[buf_index];
+ pctmp += CopySize;
+ pDes->buffer_address[buf_index] = pctmp;
+ pDes->buffer_size[buf_index] -= CopySize;
+ }
+
+ memcpy(buffer, src_buffer, CopyLeft);
+ buffer += CopyLeft;
+ CopySize -= CopyLeft;
+ }
+
+ // 931130.5.n
+ if (pMds->MicAdd) {
+ if (!SizeLeft) {
+ pMds->MicWriteAddress[ pMds->MicWriteIndex ] = buffer - pMds->MicAdd;
+ pMds->MicWriteSize[ pMds->MicWriteIndex ] = pMds->MicAdd;
+ pMds->MicAdd = 0;
+ }
+ else if( SizeLeft < 8 ) //931130.5.p
+ {
+ pMds->MicAdd = SizeLeft;
+ pMds->MicWriteAddress[ pMds->MicWriteIndex ] = buffer - ( 8 - SizeLeft );
+ pMds->MicWriteSize[ pMds->MicWriteIndex ] = 8 - SizeLeft;
+ pMds->MicWriteIndex++;
+ }
+ }
+
+ // Does it need to generate the new header for next mpdu?
+ if (SizeLeft) {
+ buffer = TargetBuffer + Size; // Get the next 4n start address
+ memcpy( buffer, TargetBuffer, 32 );//Copy 8B USB +24B 802.11
+ pT00 = (PT00_DESCRIPTOR)buffer;
+ pT00->T00_first_mpdu = 0;
+ }
+
+ FragmentCount++;
+ }
+
+ pT00->T00_last_mpdu = 1;
+ pT00->T00_IsLastMpdu = 1;
+ buffer = (PUCHAR)pT00 + 8; // +8 for USB hdr
+ buffer[1] &= ~0x04; // Clear more frag bit of 802.11 frame control
+ pDes->FragmentCount = FragmentCount; // Update the correct fragment number
+ return Size;
+}
+
+
+void
+Mds_DurationSet( PADAPTER Adapter, PDESCRIPTOR pDes, PUCHAR buffer )
+{
+ PT00_DESCRIPTOR pT00;
+ PT01_DESCRIPTOR pT01;
+ u16 Duration, NextBodyLen, OffsetSize;
+ u8 Rate, i;
+ unsigned char CTS_on = FALSE, RTS_on = FALSE;
+ PT00_DESCRIPTOR pNextT00;
+ u16 BodyLen;
+ unsigned char boGroupAddr = FALSE;
+
+
+ OffsetSize = pDes->FragmentThreshold + 32 + 3;
+ OffsetSize &= ~0x03;
+ Rate = pDes->TxRate >> 1;
+ if (!Rate)
+ Rate = 1;
+
+ pT00 = (PT00_DESCRIPTOR)buffer;
+ pT01 = (PT01_DESCRIPTOR)(buffer+4);
+ pNextT00 = (PT00_DESCRIPTOR)(buffer+OffsetSize);
+
+ if( buffer[ DOT_11_DA_OFFSET+8 ] & 0x1 ) // +8 for USB hdr
+ boGroupAddr = TRUE;
+
+ //========================================
+ // Set RTS/CTS mechanism
+ //========================================
+ if (!boGroupAddr)
+ {
+ //NOTE : If the protection mode is enabled and the MSDU will be fragmented,
+ // the tx rates of MPDUs will all be DSSS rates. So it will not use
+ // CTS-to-self in this case. CTS-To-self will only be used when without
+ // fragmentation. -- 20050112
+ BodyLen = (u16)pT00->T00_frame_length; //include 802.11 header
+ BodyLen += 4; //CRC
+
+ if( BodyLen >= CURRENT_RTS_THRESHOLD )
+ RTS_on = TRUE; // Using RTS
+ else
+ {
+ if( pT01->T01_modulation_type ) // Is using OFDM
+ {
+ if( CURRENT_PROTECT_MECHANISM ) // Is using protect
+ CTS_on = TRUE; // Using CTS
+ }
+ }
+ }
+
+ if( RTS_on || CTS_on )
+ {
+ if( pT01->T01_modulation_type) // Is using OFDM
+ {
+ //CTS duration
+ // 2 SIFS + DATA transmit time + 1 ACK
+ // ACK Rate : 24 Mega bps
+ // ACK frame length = 14 bytes
+ Duration = 2*DEFAULT_SIFSTIME +
+ 2*PREAMBLE_PLUS_SIGNAL_PLUS_SIGNALEXTENSION +
+ ((BodyLen*8 + 22 + Rate*4 - 1)/(Rate*4))*Tsym +
+ ((112 + 22 + 95)/96)*Tsym;
+ }
+ else //DSSS
+ {
+ //CTS duration
+ // 2 SIFS + DATA transmit time + 1 ACK
+ // Rate : ?? Mega bps
+ // ACK frame length = 14 bytes
+ if( pT01->T01_plcp_header_length ) //long preamble
+ Duration = LONG_PREAMBLE_PLUS_PLCPHEADER_TIME*2;
+ else
+ Duration = SHORT_PREAMBLE_PLUS_PLCPHEADER_TIME*2;
+
+ Duration += ( ((BodyLen + 14)*8 + Rate-1) / Rate +
+ DEFAULT_SIFSTIME*2 );
+ }
+
+ if( RTS_on )
+ {
+ if( pT01->T01_modulation_type ) // Is using OFDM
+ {
+ //CTS + 1 SIFS + CTS duration
+ //CTS Rate : 24 Mega bps
+ //CTS frame length = 14 bytes
+ Duration += (DEFAULT_SIFSTIME +
+ PREAMBLE_PLUS_SIGNAL_PLUS_SIGNALEXTENSION +
+ ((112 + 22 + 95)/96)*Tsym);
+ }
+ else
+ {
+ //CTS + 1 SIFS + CTS duration
+ //CTS Rate : ?? Mega bps
+ //CTS frame length = 14 bytes
+ if( pT01->T01_plcp_header_length ) //long preamble
+ Duration += LONG_PREAMBLE_PLUS_PLCPHEADER_TIME;
+ else
+ Duration += SHORT_PREAMBLE_PLUS_PLCPHEADER_TIME;
+
+ Duration += ( ((112 + Rate-1) / Rate) + DEFAULT_SIFSTIME );
+ }
+ }
+
+ // Set the value into USB descriptor
+ pT01->T01_add_rts = RTS_on ? 1 : 0;
+ pT01->T01_add_cts = CTS_on ? 1 : 0;
+ pT01->T01_rts_cts_duration = Duration;
+ }
+
+ //=====================================
+ // Fill the more fragment descriptor
+ //=====================================
+ if( boGroupAddr )
+ Duration = 0;
+ else
+ {
+ for( i=pDes->FragmentCount-1; i>0; i-- )
+ {
+ NextBodyLen = (u16)pNextT00->T00_frame_length;
+ NextBodyLen += 4; //CRC
+
+ if( pT01->T01_modulation_type )
+ {
+ //OFDM
+ // data transmit time + 3 SIFS + 2 ACK
+ // Rate : ??Mega bps
+ // ACK frame length = 14 bytes, tx rate = 24M
+ Duration = PREAMBLE_PLUS_SIGNAL_PLUS_SIGNALEXTENSION * 3;
+ Duration += (((NextBodyLen*8 + 22 + Rate*4 - 1)/(Rate*4)) * Tsym +
+ (((2*14)*8 + 22 + 95)/96)*Tsym +
+ DEFAULT_SIFSTIME*3);
+ }
+ else
+ {
+ //DSSS
+ // data transmit time + 2 ACK + 3 SIFS
+ // Rate : ??Mega bps
+ // ACK frame length = 14 bytes
+ //TODO :
+ if( pT01->T01_plcp_header_length ) //long preamble
+ Duration = LONG_PREAMBLE_PLUS_PLCPHEADER_TIME*3;
+ else
+ Duration = SHORT_PREAMBLE_PLUS_PLCPHEADER_TIME*3;
+
+ Duration += ( ((NextBodyLen + (2*14))*8 + Rate-1) / Rate +
+ DEFAULT_SIFSTIME*3 );
+ }
+
+ ((PUSHORT)buffer)[5] = cpu_to_le16(Duration);// 4 USHOR for skip 8B USB, 2USHORT=FC + Duration
+
+ //----20061009 add by anson's endian
+ pNextT00->value = cpu_to_le32(pNextT00->value);
+ pT01->value = cpu_to_le32( pT01->value );
+ //----end 20061009 add by anson's endian
+
+ buffer += OffsetSize;
+ pT01 = (PT01_DESCRIPTOR)(buffer+4);
+ if (i != 1) //The last fragment will not have the next fragment
+ pNextT00 = (PT00_DESCRIPTOR)(buffer+OffsetSize);
+ }
+
+ //=====================================
+ // Fill the last fragment descriptor
+ //=====================================
+ if( pT01->T01_modulation_type )
+ {
+ //OFDM
+ // 1 SIFS + 1 ACK
+ // Rate : 24 Mega bps
+ // ACK frame length = 14 bytes
+ Duration = PREAMBLE_PLUS_SIGNAL_PLUS_SIGNALEXTENSION;
+ //The Tx rate of ACK use 24M
+ Duration += (((112 + 22 + 95)/96)*Tsym + DEFAULT_SIFSTIME );
+ }
+ else
+ {
+ // DSSS
+ // 1 ACK + 1 SIFS
+ // Rate : ?? Mega bps
+ // ACK frame length = 14 bytes(112 bits)
+ if( pT01->T01_plcp_header_length ) //long preamble
+ Duration = LONG_PREAMBLE_PLUS_PLCPHEADER_TIME;
+ else
+ Duration = SHORT_PREAMBLE_PLUS_PLCPHEADER_TIME;
+
+ Duration += ( (112 + Rate-1)/Rate + DEFAULT_SIFSTIME );
+ }
+ }
+
+ ((PUSHORT)buffer)[5] = cpu_to_le16(Duration);// 4 USHOR for skip 8B USB, 2USHORT=FC + Duration
+ pT00->value = cpu_to_le32(pT00->value);
+ pT01->value = cpu_to_le32(pT01->value);
+ //--end 20061009 add
+
+}
+
+void MDS_EthernetPacketReceive( PADAPTER Adapter, PRXLAYER1 pRxLayer1 )
+{
+ OS_RECEIVE_PACKET_INDICATE( Adapter, pRxLayer1 );
+}
+
+
diff --git a/drivers/staging/winbond/mds_f.h b/drivers/staging/winbond/mds_f.h
new file mode 100644
index 0000000..651188b
--- /dev/null
+++ b/drivers/staging/winbond/mds_f.h
@@ -0,0 +1,33 @@
+unsigned char Mds_initial( PADAPTER Adapter );
+void Mds_Destroy( PADAPTER Adapter );
+void Mds_Tx( PADAPTER Adapter );
+void Mds_HeaderCopy( PADAPTER Adapter, PDESCRIPTOR pDes, PUCHAR TargetBuffer );
+u16 Mds_BodyCopy( PADAPTER Adapter, PDESCRIPTOR pDes, PUCHAR TargetBuffer );
+void Mds_DurationSet( PADAPTER Adapter, PDESCRIPTOR pDes, PUCHAR TargetBuffer );
+void Mds_SendComplete( PADAPTER Adapter, PT02_DESCRIPTOR pT02 );
+void Mds_MpduProcess( PADAPTER Adapter, PDESCRIPTOR pRxDes );
+void Mds_reset_descriptor( PADAPTER Adapter );
+extern void DataDmp(u8 *pdata, u32 len, u32 offset);
+
+
+void vRxTimerInit(PWB32_ADAPTER Adapter);
+void vRxTimerStart(PWB32_ADAPTER Adapter, int timeout_value);
+void RxTimerHandler_1a( PADAPTER Adapter);
+void vRxTimerStop(PWB32_ADAPTER Adapter);
+void RxTimerHandler( void* SystemSpecific1,
+ PWB32_ADAPTER Adapter,
+ void* SystemSpecific2,
+ void* SystemSpecific3);
+
+
+// For Asynchronous indicating. The routine collocates with USB.
+void Mds_MsduProcess( PWB32_ADAPTER Adapter, PRXLAYER1 pRxLayer1, u8 SlotIndex);
+
+// For data frame sending 20060802
+u16 MDS_GetPacketSize( PADAPTER Adapter );
+void MDS_GetNextPacket( PADAPTER Adapter, PDESCRIPTOR pDes );
+void MDS_GetNextPacketComplete( PADAPTER Adapter, PDESCRIPTOR pDes );
+void MDS_SendResult( PADAPTER Adapter, u8 PacketId, unsigned char SendOK );
+void MDS_EthernetPacketReceive( PADAPTER Adapter, PRXLAYER1 pRxLayer1 );
+
+
diff --git a/drivers/staging/winbond/mds_s.h b/drivers/staging/winbond/mds_s.h
new file mode 100644
index 0000000..4738279
--- /dev/null
+++ b/drivers/staging/winbond/mds_s.h
@@ -0,0 +1,183 @@
+////////////////////////////////////////////////////////////////////////////////////////////////////////
+#define MAX_USB_TX_DESCRIPTOR 15 // IS89C35 ability
+#define MAX_USB_TX_BUFFER_NUMBER 4 // Virtual pre-buffer number of MAX_USB_TX_BUFFER
+#define MAX_USB_TX_BUFFER 4096 // IS89C35 ability 4n alignment is required for hardware
+
+#define MDS_EVENT_INDICATE( _A, _B, _F ) OS_EVENT_INDICATE( _A, _B, _F )
+#define AUTH_REQUEST_PAIRWISE_ERROR 0 // _F flag setting
+#define AUTH_REQUEST_GROUP_ERROR 1 // _F flag setting
+
+// For variable setting
+#define CURRENT_BSS_TYPE psBSS(psLOCAL->wConnectedSTAindex)->bBssType
+#define CURRENT_WEP_MODE psSME->_dot11PrivacyInvoked
+#define CURRENT_BSSID psBSS(psLOCAL->wConnectedSTAindex)->abBssID
+#define CURRENT_DESIRED_WPA_ENABLE ((psSME->bDesiredAuthMode==WPA_AUTH)||(psSME->bDesiredAuthMode==WPAPSK_AUTH))
+#ifdef _WPA2_
+#define CURRENT_DESIRED_WPA2_ENABLE ((psSME->bDesiredAuthMode==WPA2_AUTH)||(psSME->bDesiredAuthMode==WPA2PSK_AUTH))
+#endif //end def _WPA2_
+#define CURRENT_PAIRWISE_KEY_OK psSME->pairwise_key_ok
+//[20040712 WS]
+#define CURRENT_GROUP_KEY_OK psSME->group_key_ok
+#define CURRENT_PAIRWISE_KEY psSME->tx_mic_key
+#define CURRENT_GROUP_KEY psSME->group_tx_mic_key
+#define CURRENT_ENCRYPT_STATUS psSME->encrypt_status
+#define CURRENT_WEP_ID Adapter->sSmePara._dot11WEPDefaultKeyID
+#define CURRENT_CONTROL_PORT_BLOCK ( psSME->wpa_ok!=1 || (Adapter->Mds.boCounterMeasureBlock==1 && (CURRENT_ENCRYPT_STATUS==ENCRYPT_TKIP)) )
+#define CURRENT_FRAGMENT_THRESHOLD (Adapter->Mds.TxFragmentThreshold & ~0x1)
+#define CURRENT_PREAMBLE_MODE psLOCAL->boShortPreamble?WLAN_PREAMBLE_TYPE_SHORT:WLAN_PREAMBLE_TYPE_LONG
+#define CURRENT_LINK_ON OS_LINK_STATUS
+#define CURRENT_TX_RATE Adapter->sLocalPara.CurrentTxRate
+#define CURRENT_FALL_BACK_TX_RATE Adapter->sLocalPara.CurrentTxFallbackRate
+#define CURRENT_TX_RATE_FOR_MNG Adapter->sLocalPara.CurrentTxRateForMng
+#define CURRENT_PROTECT_MECHANISM psLOCAL->boProtectMechanism
+#define CURRENT_RTS_THRESHOLD Adapter->Mds.TxRTSThreshold
+
+#define MIB_GS_XMIT_OK_INC Adapter->sLocalPara.GS_XMIT_OK++
+#define MIB_GS_RCV_OK_INC Adapter->sLocalPara.GS_RCV_OK++
+#define MIB_GS_XMIT_ERROR_INC Adapter->sLocalPara.GS_XMIT_ERROR
+
+//---------- TX -----------------------------------
+#define ETHERNET_TX_DESCRIPTORS MAX_USB_TX_BUFFER_NUMBER
+
+//---------- RX ------------------------------------
+#define ETHERNET_RX_DESCRIPTORS 8 //It's not necessary to allocate more than 2 in sync indicate
+
+//================================================================
+// Configration default value
+//================================================================
+#define DEFAULT_MULTICASTLISTMAX 32 // standard
+#define DEFAULT_TX_BURSTLENGTH 3 // 32 Longwords
+#define DEFAULT_RX_BURSTLENGTH 3 // 32 Longwords
+#define DEFAULT_TX_THRESHOLD 0 // Full Packet
+#define DEFAULT_RX_THRESHOLD 0 // Full Packet
+#define DEFAULT_MAXTXRATE 6 // 11 Mbps (Long)
+#define DEFAULT_CHANNEL 3 // Chennel 3
+#define DEFAULT_RTSThreshold 2347 // Disable RTS
+//#define DEFAULT_PME 1 // Enable
+#define DEFAULT_PME 0 // Disable
+#define DEFAULT_SIFSTIME 10
+#define DEFAULT_ACKTIME_1ML 304 // 148+44+112 911220 by LCC
+#define DEFAULT_ACKTIME_2ML 248 // 148+44+56 911220 by LCC
+#define DEFAULT_FRAGMENT_THRESHOLD 2346 // No fragment
+#define DEFAULT_PREAMBLE_LENGTH 72
+#define DEFAULT_PLCPHEADERTIME_LENGTH 24
+
+/*------------------------------------------------------------------------
+ 0.96 sec since time unit of the R03 for the current, W89C32 is about 60ns
+ instead of 960 ns. This shall be fixed in the future W89C32
+ -------------------------------------------------------------------------*/
+#define DEFAULT_MAX_RECEIVE_TIME 16440000
+
+#define RX_BUF_SIZE 2352 // 600 // For 301 must be multiple of 8
+#define MAX_RX_DESCRIPTORS 18 // Rx Layer 2
+#define MAX_BUFFER_QUEUE 8 // The value is always equal 8 due to NDIS_PACKET's MiniportReserved field size
+
+
+// For brand-new rx system
+#define MDS_ID_IGNORE ETHERNET_RX_DESCRIPTORS
+
+// For Tx Packet status classify
+#define PACKET_FREE_TO_USE 0
+#define PACKET_COME_FROM_NDIS 0x08
+#define PACKET_COME_FROM_MLME 0x80
+#define PACKET_SEND_COMPLETE 0xff
+
+typedef struct _MDS
+{
+ // For Tx usage
+ u8 TxOwner[ ((MAX_USB_TX_BUFFER_NUMBER + 3) & ~0x03) ];
+ PUCHAR pTxBuffer;
+ u16 TxBufferSize[ ((MAX_USB_TX_BUFFER_NUMBER + 1) & ~0x01) ];
+ u8 TxDesFrom[ ((MAX_USB_TX_DESCRIPTOR + 3) & ~0x03) ];//931130.4.u // 1: MLME 2: NDIS control 3: NDIS data
+ u8 TxCountInBuffer[ ((MAX_USB_TX_DESCRIPTOR + 3) & ~0x03) ]; // 20060928
+
+ u8 TxFillIndex;//the next index of TxBuffer can be used
+ u8 TxDesIndex;//The next index of TxDes can be used
+ u8 ScanTxPause; //data Tx pause because the scanning is progressing, but probe request Tx won't.
+ u8 TxPause;//For pause the Mds_Tx modult
+
+ OS_ATOMIC TxThreadCount;//For thread counting 931130.4.v
+//950301 delete due to HW
+// OS_ATOMIC TxConcurrentCount;//931130.4.w
+
+ u16 TxResult[ ((MAX_USB_TX_DESCRIPTOR + 1) & ~0x01) ];//Collect the sending result of Mpdu
+
+ u8 MicRedundant[8]; // For tmp use
+ PUCHAR MicWriteAddress[2]; //The start address to fill the Mic, use 2 point due to Mic maybe fragment
+
+ u16 MicWriteSize[2]; //931130.4.x
+
+ u16 MicAdd; // If want to add the Mic, this variable equal to 8
+ u16 MicWriteIndex;//The number of MicWriteAddress 931130.4.y
+
+ u8 TxRate[ ((MAX_USB_TX_DESCRIPTOR+1)&~0x01) ][2]; // [0] current tx rate, [1] fall back rate
+ u8 TxInfo[ ((MAX_USB_TX_DESCRIPTOR+1)&~0x01) ]; //Store information for callback function
+
+ //WKCHEN added for scanning mechanism
+ u8 TxToggle; //It is TRUE if there are tx activities in some time interval
+ u8 Reserved_[3];
+
+ //---------- for Tx Parameter
+ u16 TxFragmentThreshold; // For frame body only
+ u16 TxRTSThreshold;
+
+ u32 MaxReceiveTime;//911220.3 Add
+
+ // depend on OS,
+ u32 MulticastListNo;
+ u32 PacketFilter; // Setting by NDIS, the current packet filter in use.
+ u8 MulticastAddressesArray[DEFAULT_MULTICASTLISTMAX][MAC_ADDR_LENGTH];
+
+ //COUNTERMEASURE
+ u8 bMICfailCount;
+ u8 boCounterMeasureBlock;
+ u8 reserved_4[2];
+
+ //NDIS_MINIPORT_TIMER nTimer;
+ OS_TIMER nTimer;
+
+ u32 TxTsc; // 20060214
+ u32 TxTsc_2; // 20060214
+
+} MDS, *PMDS;
+
+
+typedef struct _RxBuffer
+{
+ PUCHAR pBufferAddress; // Pointer the received data buffer.
+ u16 BufferSize;
+ u8 RESERVED;
+ u8 BufferIndex;// Only 1 byte
+} RXBUFFER, *PRXBUFFER;
+
+//
+// Reveive Layer 1 Format.
+//----------------------------
+typedef struct _RXLAYER1
+{
+ u16 SequenceNumber; // The sequence number of the last received packet.
+ u16 BufferTotalSize;
+
+ u32 InUsed;
+ u32 DecryptionMethod; // The desired defragment number of the next incoming packet.
+
+ u8 DeFragmentNumber;
+ u8 FrameType;
+ u8 TypeEncapsulated;
+ u8 BufferNumber;
+
+ u32 FirstFrameArrivedTime;
+
+ RXBUFFER BufferQueue[ MAX_BUFFER_QUEUE ];
+
+ u8 LastFrameType; // 20061004 for fix intel 3945 's bug
+ u8 RESERVED[3]; //@@ anson
+
+ /////////////////////////////////////////////////////////////////////////////////////////////
+ // For brand-new Rx system
+ u8 ReservedBuffer[ 2400 ];//If Buffer ID is reserved one, it must copy the data into this area
+ PUCHAR ReservedBufferPoint;// Point to the next availabe address of reserved buffer
+
+}RXLAYER1, * PRXLAYER1;
+
+
diff --git a/drivers/staging/winbond/mlme_mib.h b/drivers/staging/winbond/mlme_mib.h
new file mode 100644
index 0000000..8975973
--- /dev/null
+++ b/drivers/staging/winbond/mlme_mib.h
@@ -0,0 +1,84 @@
+//============================================================================
+// MLMEMIB.H -
+//
+// Description:
+// Get and Set some of MLME MIB attributes.
+//
+// Revision history:
+// --------------------------------------------------------------------------
+// 20030117 PD43 Austin Liu
+// Initial release
+//
+// Copyright (c) 2003 Winbond Electronics Corp. All rights reserved.
+//============================================================================
+
+#ifndef _MLME_MIB_H
+#define _MLME_MIB_H
+
+//============================================================================
+// MLMESetExcludeUnencrypted --
+//
+// Description:
+// Set the dot11ExcludeUnencrypted value.
+//
+// Arguments:
+// Adapter - The pointer to the miniport adapter context.
+// ExUnencrypted - unsigned char type. The value to be set.
+//
+// Return values:
+// None.
+//============================================================================
+#define MLMESetExcludeUnencrypted(Adapter, ExUnencrypted) \
+{ \
+ (Adapter)->sLocalPara.ExcludeUnencrypted = ExUnencrypted; \
+}
+
+//============================================================================
+// MLMEGetExcludeUnencrypted --
+//
+// Description:
+// Get the dot11ExcludeUnencrypted value.
+//
+// Arguments:
+// Adapter - The pointer to the miniport adapter context.
+//
+// Return values:
+// unsigned char type. The current dot11ExcludeUnencrypted value.
+//============================================================================
+#define MLMEGetExcludeUnencrypted(Adapter) ((unsigned char) (Adapter)->sLocalPara.ExcludeUnencrypted)
+
+//============================================================================
+// MLMESetMaxReceiveLifeTime --
+//
+// Description:
+// Set the dot11MaxReceiveLifeTime value.
+//
+// Arguments:
+// Adapter - The pointer to the miniport adapter context.
+// ReceiveLifeTime- u32 type. The value to be set.
+//
+// Return values:
+// None.
+//============================================================================
+#define MLMESetMaxReceiveLifeTime(Adapter, ReceiveLifeTime) \
+{ \
+ (Adapter)->Mds.MaxReceiveTime = ReceiveLifeTime; \
+}
+
+//============================================================================
+// MLMESetMaxReceiveLifeTime --
+//
+// Description:
+// Get the dot11MaxReceiveLifeTime value.
+//
+// Arguments:
+// Adapter - The pointer to the miniport adapter context.
+//
+// Return values:
+// u32 type. The current dot11MaxReceiveLifeTime value.
+//============================================================================
+#define MLMEGetMaxReceiveLifeTime(Adapter) ((u32) (Adapter)->Mds.MaxReceiveTime)
+
+#endif
+
+
diff --git a/drivers/staging/winbond/mlme_s.h b/drivers/staging/winbond/mlme_s.h
new file mode 100644
index 0000000..58094f6
--- /dev/null
+++ b/drivers/staging/winbond/mlme_s.h
@@ -0,0 +1,195 @@
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+// Mlme.h
+// Define the related definitions of MLME module
+// history -- 01/14/03' created
+//
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+#define AUTH_REJECT_REASON_CHALLENGE_FAIL 1
+
+//====== the state of MLME module
+#define INACTIVE 0x0
+#define IDLE_SCAN 0x1
+
+//====== the state of MLME/ESS module
+#define STATE_1 0x2
+#define AUTH_REQ 0x3
+#define AUTH_WEP 0x4
+#define STATE_2 0x5
+#define ASSOC_REQ 0x6
+#define STATE_3 0x7
+
+//====== the state of MLME/IBSS module
+#define IBSS_JOIN_SYNC 0x8
+#define IBSS_AUTH_REQ 0x9
+#define IBSS_AUTH_CHANLGE 0xa
+#define IBSS_AUTH_WEP 0xb
+#define IBSS_AUTH_IND 0xc
+#define IBSS_STATE_2 0xd
+
+
+
+//=========================================
+//depend on D5C(MAC timing control 03 register): MaxTxMSDULifeTime default 0x80000us
+#define AUTH_FAIL_TIMEOUT 550
+#define ASSOC_FAIL_TIMEOUT 550
+#define REASSOC_FAIL_TIMEOUT 550
+
+
+
+//
+// MLME task global CONSTANTS, STRUCTURE, variables
+//
+
+
+/////////////////////////////////////////////////////////////
+// enum_ResultCode --
+// Result code returned from MLME to SME.
+//
+/////////////////////////////////////////////////////////////
+// PD43 20030829 Modifiled
+//#define SUCCESS 0
+#define MLME_SUCCESS 0 //follow spec.
+#define INVALID_PARAMETERS 1 //Not following spec.
+#define NOT_SUPPPORTED 2
+#define TIMEOUT 3
+#define TOO_MANY_SIMULTANEOUS_REQUESTS 4
+#define REFUSED 5
+#define BSS_ALREADY_STARTED_OR_JOINED 6
+#define TRANSMIT_FRAME_FAIL 7
+#define NO_BSS_FOUND 8
+#define RETRY 9
+#define GIVE_UP 10
+
+
+#define OPEN_AUTH 0
+#define SHARE_AUTH 1
+#define ANY_AUTH 2
+#define WPA_AUTH 3 //for WPA
+#define WPAPSK_AUTH 4
+#define WPANONE_AUTH 5
+///////////////////////////////////////////// added by ws 04/19/04
+#ifdef _WPA2_
+#define WPA2_AUTH 6//for WPA2
+#define WPA2PSK_AUTH 7
+#endif //end def _WPA2_
+
+//////////////////////////////////////////////////////////////////
+//define the msg type of MLME module
+//////////////////////////////////////////////////////////////////
+//--------------------------------------------------------
+//from SME
+
+#define MLMEMSG_AUTH_REQ 0x0b
+#define MLMEMSG_DEAUTH_REQ 0x0c
+#define MLMEMSG_ASSOC_REQ 0x0d
+#define MLMEMSG_REASSOC_REQ 0x0e
+#define MLMEMSG_DISASSOC_REQ 0x0f
+#define MLMEMSG_START_IBSS_REQ 0x10
+#define MLMEMSG_IBSS_NET_CFM 0x11
+
+//from RX :
+#define MLMEMSG_RCV_MLMEFRAME 0x20
+#define MLMEMSG_RCV_ASSOCRSP 0x22
+#define MLMEMSG_RCV_REASSOCRSP 0x24
+#define MLMEMSG_RCV_DISASSOC 0x2b
+#define MLMEMSG_RCV_AUTH 0x2c
+#define MLMEMSG_RCV_DEAUTH 0x2d
+
+
+//from TX callback
+#define MLMEMSG_TX_CALLBACK 0x40
+#define MLMEMSG_ASSOCREQ_CALLBACK 0x41
+#define MLMEMSG_REASSOCREQ_CALLBACK 0x43
+#define MLMEMSG_DISASSOC_CALLBACK 0x4a
+#define MLMEMSG_AUTH_CALLBACK 0x4c
+#define MLMEMSG_DEAUTH_CALLBACK 0x4d
+
+//#define MLMEMSG_JOIN_FAIL 4
+//#define MLMEMSG_AUTHEN_FAIL 18
+#define MLMEMSG_TIMEOUT 0x50
+
+///////////////////////////////////////////////////////////////////////////
+//Global data structures
+#define MAX_NUM_TX_MMPDU 2
+#define MAX_MMPDU_SIZE 1512
+#define MAX_NUM_RX_MMPDU 6
+
+
+///////////////////////////////////////////////////////////////////////////
+//MACRO
+#define boMLME_InactiveState(_AA_) (_AA_->wState==INACTIVE)
+#define boMLME_IdleScanState(_BB_) (_BB_->wState==IDLE_SCAN)
+#define boMLME_FoundSTAinfo(_CC_) (_CC_->wState>=IDLE_SCAN)
+
+typedef struct _MLME_FRAME
+{
+ //NDIS_PACKET MLME_Packet;
+ PCHAR pMMPDU;
+ u16 len;
+ u8 DataType;
+ u8 IsInUsed;
+
+ OS_SPIN_LOCK MLMESpinLock;
+
+ u8 TxMMPDU[MAX_NUM_TX_MMPDU][MAX_MMPDU_SIZE];
+ u8 TxMMPDUInUse[ (MAX_NUM_TX_MMPDU+3) & ~0x03 ];
+
+ u16 wNumTxMMPDU;
+ u16 wNumTxMMPDUDiscarded;
+
+ u8 RxMMPDU[MAX_NUM_RX_MMPDU][MAX_MMPDU_SIZE];
+ u8 SaveRxBufSlotInUse[ (MAX_NUM_RX_MMPDU+3) & ~0x03 ];
+
+ u16 wNumRxMMPDU;
+ u16 wNumRxMMPDUDiscarded;
+
+ u16 wNumRxMMPDUInMLME; // Number of the Rx MMPDU
+ u16 reserved_1; // in MLME.
+ // excluding the discarded
+} MLME_FRAME, *psMLME_FRAME;
+
+typedef struct _AUTHREQ {
+
+ u8 peerMACaddr[MAC_ADDR_LENGTH];
+ u16 wAuthAlgorithm;
+
+} MLME_AUTHREQ_PARA, *psMLME_AUTHREQ_PARA;
+
+struct _Reason_Code {
+
+ u8 peerMACaddr[MAC_ADDR_LENGTH];
+ u16 wReasonCode;
+};
+typedef struct _Reason_Code MLME_DEAUTHREQ_PARA, *psMLME_DEAUTHREQ_PARA;
+typedef struct _Reason_Code MLME_DISASSOCREQ_PARA, *psMLME_DISASSOCREQ_PARA;
+
+typedef struct _ASSOCREQ {
+ u8 PeerSTAAddr[MAC_ADDR_LENGTH];
+ u16 CapabilityInfo;
+ u16 ListenInterval;
+
+}__attribute__ ((packed)) MLME_ASSOCREQ_PARA, *psMLME_ASSOCREQ_PARA;
+
+typedef struct _REASSOCREQ {
+ u8 NewAPAddr[MAC_ADDR_LENGTH];
+ u16 CapabilityInfo;
+ u16 ListenInterval;
+
+}__attribute__ ((packed)) MLME_REASSOCREQ_PARA, *psMLME_REASSOCREQ_PARA;
+
+typedef struct _MLMECALLBACK {
+
+ u8 *psFramePtr;
+ u8 bResult;
+
+} MLME_TXCALLBACK, *psMLME_TXCALLBACK;
+
+typedef struct _RXDATA
+{
+ s32 FrameLength;
+ u8 __attribute__ ((packed)) *pbFramePtr;
+
+}__attribute__ ((packed)) RXDATA, *psRXDATA;
+
+
diff --git a/drivers/staging/winbond/mlmetxrx.c b/drivers/staging/winbond/mlmetxrx.c
new file mode 100644
index 0000000..46b091e
--- /dev/null
+++ b/drivers/staging/winbond/mlmetxrx.c
@@ -0,0 +1,150 @@
+//============================================================================
+// Module Name:
+// MLMETxRx.C
+//
+// Description:
+// The interface between MDS (MAC Data Service) and MLME.
+//
+// Revision History:
+// --------------------------------------------------------------------------
+// 200209 UN20 Jennifer Xu
+// Initial Release
+// 20021108 PD43 Austin Liu
+// 20030117 PD43 Austin Liu
+// Deleted MLMEReturnPacket and MLMEProcThread()
+//
+// Copyright (c) 1996-2002 Winbond Electronics Corp. All Rights Reserved.
+//============================================================================
+#include "os_common.h"
+
+void MLMEResetTxRx(PWB32_ADAPTER Adapter)
+{
+ s32 i;
+
+ // Reset the interface between MDS and MLME
+ for (i = 0; i < MAX_NUM_TX_MMPDU; i++)
+ Adapter->sMlmeFrame.TxMMPDUInUse[i] = FALSE;
+ for (i = 0; i < MAX_NUM_RX_MMPDU; i++)
+ Adapter->sMlmeFrame.SaveRxBufSlotInUse[i] = FALSE;
+
+ Adapter->sMlmeFrame.wNumRxMMPDUInMLME = 0;
+ Adapter->sMlmeFrame.wNumRxMMPDUDiscarded = 0;
+ Adapter->sMlmeFrame.wNumRxMMPDU = 0;
+ Adapter->sMlmeFrame.wNumTxMMPDUDiscarded = 0;
+ Adapter->sMlmeFrame.wNumTxMMPDU = 0;
+ Adapter->sLocalPara.boCCAbusy = FALSE;
+ Adapter->sLocalPara.iPowerSaveMode = PWR_ACTIVE; // Power active
+}
+
+//=============================================================================
+// Function:
+// MLMEGetMMPDUBuffer()
+//
+// Description:
+// Return the pointer to an available data buffer with
+// the size MAX_MMPDU_SIZE for a MMPDU.
+//
+// Arguments:
+// Adapter - pointer to the miniport adapter context.
+//
+// Return value:
+// NULL : No available data buffer available
+// Otherwise: Pointer to the data buffer
+//=============================================================================
+
+/* FIXME: Should this just be replaced with kmalloc() and kfree()? */
+u8 *MLMEGetMMPDUBuffer(PWB32_ADAPTER Adapter)
+{
+ s32 i;
+ u8 *returnVal;
+
+ for (i = 0; i< MAX_NUM_TX_MMPDU; i++) {
+ if (Adapter->sMlmeFrame.TxMMPDUInUse[i] == FALSE)
+ break;
+ }
+ if (i >= MAX_NUM_TX_MMPDU) return NULL;
+
+ returnVal = (u8 *)&(Adapter->sMlmeFrame.TxMMPDU[i]);
+ Adapter->sMlmeFrame.TxMMPDUInUse[i] = TRUE;
+
+ return returnVal;
+}
+
+//=============================================================================
+u8 MLMESendFrame(PWB32_ADAPTER Adapter, u8 *pMMPDU, u16 len, u8 DataType)
+/* DataType : FRAME_TYPE_802_11_MANAGEMENT, FRAME_TYPE_802_11_MANAGEMENT_CHALLENGE,
+ FRAME_TYPE_802_11_DATA */
+{
+ if (Adapter->sMlmeFrame.IsInUsed != PACKET_FREE_TO_USE) {
+ Adapter->sMlmeFrame.wNumTxMMPDUDiscarded++;
+ return FALSE;
+ }
+ Adapter->sMlmeFrame.IsInUsed = PACKET_COME_FROM_MLME;
+
+ // Keep information for sending
+ Adapter->sMlmeFrame.pMMPDU = pMMPDU;
+ Adapter->sMlmeFrame.DataType = DataType;
+ // len must be the last setting due to QUERY_SIZE_SECOND of Mds
+ Adapter->sMlmeFrame.len = len;
+ Adapter->sMlmeFrame.wNumTxMMPDU++;
+
+ // H/W will enter power save by set the register. S/W don't send null frame
+ //with PWRMgt bit enbled to enter power save now.
+
+ // Transmit NDIS packet
+ Mds_Tx(Adapter);
+ return TRUE;
+}
+
+void
+MLME_GetNextPacket(PADAPTER Adapter, PDESCRIPTOR pDes)
+{
+#define DESCRIPTOR_ADD_BUFFER( _D, _A, _S ) \
+{\
+ _D->InternalUsed = _D->buffer_start_index + _D->buffer_number; \
+ _D->InternalUsed %= MAX_DESCRIPTOR_BUFFER_INDEX; \
+ _D->buffer_address[ _D->InternalUsed ] = _A; \
+ _D->buffer_size[ _D->InternalUsed ] = _S; \
+ _D->buffer_total_size += _S; \
+ _D->buffer_number++;\
+}
+
+ DESCRIPTOR_ADD_BUFFER( pDes, Adapter->sMlmeFrame.pMMPDU, Adapter->sMlmeFrame.len );
+ pDes->Type = Adapter->sMlmeFrame.DataType;
+}
+
+void MLMEfreeMMPDUBuffer(PWB32_ADAPTER Adapter, PCHAR pData)
+{
+ int i;
+
+ // Reclaim the data buffer
+ for (i = 0; i < MAX_NUM_TX_MMPDU; i++) {
+ if (pData == (PCHAR)&(Adapter->sMlmeFrame.TxMMPDU[i]))
+ break;
+ }
+ if (Adapter->sMlmeFrame.TxMMPDUInUse[i])
+ Adapter->sMlmeFrame.TxMMPDUInUse[i] = FALSE;
+ else {
+ // Something wrong
+ // PD43 Add debug code here???
+ }
+}
+
+void
+MLME_SendComplete(PADAPTER Adapter, u8 PacketID, unsigned char SendOK)
+{
+ MLME_TXCALLBACK TxCallback;
+
+ // Reclaim the data buffer
+ Adapter->sMlmeFrame.len = 0;
+ MLMEfreeMMPDUBuffer( Adapter, Adapter->sMlmeFrame.pMMPDU );
+
+
+ TxCallback.bResult = MLME_SUCCESS;
+
+ // Return resource
+ Adapter->sMlmeFrame.IsInUsed = PACKET_FREE_TO_USE;
+}
+
+
+
diff --git a/drivers/staging/winbond/mlmetxrx_f.h b/drivers/staging/winbond/mlmetxrx_f.h
new file mode 100644
index 0000000..d74e225
--- /dev/null
+++ b/drivers/staging/winbond/mlmetxrx_f.h
@@ -0,0 +1,52 @@
+//================================================================
+// MLMETxRx.H --
+//
+// Functions defined in MLMETxRx.c.
+//
+// Copyright (c) 2002 Winbond Electrics Corp. All Rights Reserved.
+//================================================================
+#ifndef _MLMETXRX_H
+#define _MLMETXRX_H
+
+void
+MLMEProcThread(
+ PWB32_ADAPTER Adapter
+ );
+
+void MLMEResetTxRx( PWB32_ADAPTER Adapter);
+
+u8 *
+MLMEGetMMPDUBuffer(
+ PWB32_ADAPTER Adapter
+ );
+
+void MLMEfreeMMPDUBuffer( PWB32_ADAPTER Adapter, PCHAR pData);
+
+void MLME_GetNextPacket( PADAPTER Adapter, PDESCRIPTOR pDes );
+u8 MLMESendFrame( PWB32_ADAPTER Adapter,
+ u8 *pMMPDU,
+ u16 len,
+ u8 DataType);
+
+void
+MLME_SendComplete( PWB32_ADAPTER Adapter, u8 PacketID, unsigned char SendOK );
+
+void
+MLMERcvFrame(
+ PWB32_ADAPTER Adapter,
+ PRXBUFFER pRxBufferArray,
+ u8 NumOfBuffer,
+ u8 ReturnSlotIndex
+ );
+
+void
+MLMEReturnPacket(
+ PWB32_ADAPTER Adapter,
+ PUCHAR pRxBufer
+ );
+#ifdef _IBSS_BEACON_SEQ_STICK_
+s8 SendBCNullData(PWB32_ADAPTER Adapter, u16 wIdx);
+#endif
+
+#endif
+
diff --git a/drivers/staging/winbond/mto.c b/drivers/staging/winbond/mto.c
new file mode 100644
index 0000000..2ef60e5
--- /dev/null
+++ b/drivers/staging/winbond/mto.c
@@ -0,0 +1,1229 @@
+//============================================================================
+// MTO.C -
+//
+// Description:
+// MAC Throughput Optimization for W89C33 802.11g WLAN STA.
+//
+// The following MIB attributes or internal variables will be affected
+// while the MTO is being executed:
+// dot11FragmentationThreshold,
+// dot11RTSThreshold,
+// transmission rate and PLCP preamble type,
+// CCA mode,
+// antenna diversity.
+//
+// Revision history:
+// --------------------------------------------------------------------------
+// 20031227 UN20 Pete Chao
+// First draft
+// 20031229 Turbo copy from PD43
+// 20040210 Kevin revised
+// Copyright (c) 2003 Winbond Electronics Corp. All rights reserved.
+//============================================================================
+
+// LA20040210_DTO kevin
+#include "os_common.h"
+
+// Declare SQ3 to rate and fragmentation threshold table
+// Declare fragmentation thresholds table
+#define MTO_MAX_SQ3_LEVELS 14
+#define MTO_MAX_FRAG_TH_LEVELS 5
+#define MTO_MAX_DATA_RATE_LEVELS 12
+
+u16 MTO_Frag_Th_Tbl[MTO_MAX_FRAG_TH_LEVELS] =
+{
+ 256, 384, 512, 768, 1536
+};
+
+u8 MTO_SQ3_Level[MTO_MAX_SQ3_LEVELS] =
+{
+ 0, 26, 30, 32, 34, 35, 37, 42, 44, 46, 54, 62, 78, 81
+};
+u8 MTO_SQ3toRate[MTO_MAX_SQ3_LEVELS] =
+{
+ 0, 1, 1, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+};
+u8 MTO_SQ3toFrag[MTO_MAX_SQ3_LEVELS] =
+{
+ 0, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4
+};
+
+// One Exchange Time table
+//
+u16 MTO_One_Exchange_Time_Tbl_l[MTO_MAX_FRAG_TH_LEVELS][MTO_MAX_DATA_RATE_LEVELS] =
+{
+ { 2554, 1474, 822, 0, 0, 636, 0, 0, 0, 0, 0, 0},
+ { 3578, 1986, 1009, 0, 0, 729, 0, 0, 0, 0, 0, 0},
+ { 4602, 2498, 1195, 0, 0, 822, 0, 0, 0, 0, 0, 0},
+ { 6650, 3522, 1567, 0, 0, 1009, 0, 0, 0, 0, 0, 0},
+ {12794, 6594, 2684, 0, 0, 1567, 0, 0, 0, 0, 0, 0}
+};
+
+u16 MTO_One_Exchange_Time_Tbl_s[MTO_MAX_FRAG_TH_LEVELS][MTO_MAX_DATA_RATE_LEVELS] =
+{
+ { 0, 1282, 630, 404, 288, 444, 232, 172, 144, 116, 100, 96},
+ { 0, 1794, 817, 572, 400, 537, 316, 228, 188, 144, 124, 116},
+ { 0, 2306, 1003, 744, 516, 630, 400, 288, 228, 172, 144, 136},
+ { 0, 3330, 1375, 1084, 744, 817, 572, 400, 316, 228, 188, 172},
+ { 0, 6402, 2492, 2108, 1424, 1375, 1084, 740, 572, 400, 316, 284}
+};
+
+#define MTO_ONE_EXCHANGE_TIME(preamble_type, frag_th_lvl, data_rate_lvl) \
+ (preamble_type) ? MTO_One_Exchange_Time_Tbl_s[frag_th_lvl][data_rate_lvl] : \
+ MTO_One_Exchange_Time_Tbl_l[frag_th_lvl][data_rate_lvl]
+
+// Declare data rate table
+//The following table will be changed at anytime if the opration rate supported by AP don't
+//match the table
+u8 MTO_Data_Rate_Tbl[MTO_MAX_DATA_RATE_LEVELS] =
+{
+ 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108
+};
+
+//The Stardard_Data_Rate_Tbl and Level2PerTbl table is used to indirectly retreive PER
+//information from Rate_PER_TBL
+//The default settings is AP can support full rate set.
+static u8 Stardard_Data_Rate_Tbl[MTO_MAX_DATA_RATE_LEVELS] =
+{
+ 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108
+};
+static u8 Level2PerTbl[MTO_MAX_DATA_RATE_LEVELS] =
+{
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
+};
+//How many kind of tx rate can be supported by AP
+//DTO will change Rate between MTO_Data_Rate_Tbl[0] and MTO_Data_Rate_Tbl[MTO_DataRateAvailableLevel-1]
+static u8 MTO_DataRateAvailableLevel = MTO_MAX_DATA_RATE_LEVELS;
+//Smoothed PER table for each different RATE based on packet length of 1514
+static int Rate_PER_TBL[91][MTO_MAX_DATA_RATE_LEVELS] = {
+// 1M 2M 5.5M 11M 6M 9M 12M 18M 24M 36M 48M 54M
+/* 0% */{ 93, 177, 420, 538, 690, 774, 1001, 1401, 1768, 2358, 2838, 3039},
+/* 1% */{ 92, 176, 416, 533, 683, 767, 992, 1389, 1752, 2336, 2811, 3010},
+/* 2% */{ 91, 174, 412, 528, 675, 760, 983, 1376, 1735, 2313, 2783, 2979},
+/* 3% */{ 90, 172, 407, 523, 667, 753, 973, 1363, 1719, 2290, 2755, 2948},
+/* 4% */{ 90, 170, 403, 518, 659, 746, 964, 1350, 1701, 2266, 2726, 2916},
+/* 5% */{ 89, 169, 398, 512, 651, 738, 954, 1336, 1684, 2242, 2696, 2884},
+/* 6% */{ 88, 167, 394, 507, 643, 731, 944, 1322, 1666, 2217, 2665, 2851},
+/* 7% */{ 87, 165, 389, 502, 635, 723, 935, 1308, 1648, 2192, 2634, 2817},
+/* 8% */{ 86, 163, 384, 497, 626, 716, 924, 1294, 1629, 2166, 2602, 2782},
+/* 9% */{ 85, 161, 380, 491, 618, 708, 914, 1279, 1611, 2140, 2570, 2747},
+/* 10% */{ 84, 160, 375, 486, 609, 700, 904, 1265, 1591, 2113, 2537, 2711},
+/* 11% */{ 83, 158, 370, 480, 600, 692, 894, 1250, 1572, 2086, 2503, 2675},
+/* 12% */{ 82, 156, 365, 475, 592, 684, 883, 1234, 1552, 2059, 2469, 2638},
+/* 13% */{ 81, 154, 360, 469, 583, 676, 872, 1219, 1532, 2031, 2435, 2600},
+/* 14% */{ 80, 152, 355, 464, 574, 668, 862, 1204, 1512, 2003, 2400, 2562},
+/* 15% */{ 79, 150, 350, 458, 565, 660, 851, 1188, 1492, 1974, 2365, 2524},
+/* 16% */{ 78, 148, 345, 453, 556, 652, 840, 1172, 1471, 1945, 2329, 2485},
+/* 17% */{ 77, 146, 340, 447, 547, 643, 829, 1156, 1450, 1916, 2293, 2446},
+/* 18% */{ 76, 144, 335, 441, 538, 635, 818, 1140, 1429, 1887, 2256, 2406},
+/* 19% */{ 75, 143, 330, 436, 529, 627, 807, 1124, 1408, 1857, 2219, 2366},
+/* 20% */{ 74, 141, 325, 430, 520, 618, 795, 1107, 1386, 1827, 2182, 2326},
+/* 21% */{ 73, 139, 320, 424, 510, 610, 784, 1091, 1365, 1797, 2145, 2285},
+/* 22% */{ 72, 137, 314, 418, 501, 601, 772, 1074, 1343, 1766, 2107, 2244},
+/* 23% */{ 71, 135, 309, 412, 492, 592, 761, 1057, 1321, 1736, 2069, 2203},
+/* 24% */{ 70, 133, 304, 407, 482, 584, 749, 1040, 1299, 1705, 2031, 2161},
+/* 25% */{ 69, 131, 299, 401, 473, 575, 738, 1023, 1277, 1674, 1992, 2120},
+/* 26% */{ 68, 129, 293, 395, 464, 566, 726, 1006, 1254, 1642, 1953, 2078},
+/* 27% */{ 67, 127, 288, 389, 454, 557, 714, 989, 1232, 1611, 1915, 2035},
+/* 28% */{ 66, 125, 283, 383, 445, 549, 703, 972, 1209, 1579, 1876, 1993},
+/* 29% */{ 65, 123, 278, 377, 436, 540, 691, 955, 1187, 1548, 1836, 1951},
+/* 30% */{ 64, 121, 272, 371, 426, 531, 679, 937, 1164, 1516, 1797, 1908},
+/* 31% */{ 63, 119, 267, 365, 417, 522, 667, 920, 1141, 1484, 1758, 1866},
+/* 32% */{ 62, 117, 262, 359, 407, 513, 655, 902, 1118, 1453, 1719, 1823},
+/* 33% */{ 61, 115, 256, 353, 398, 504, 643, 885, 1095, 1421, 1679, 1781},
+/* 34% */{ 60, 113, 251, 347, 389, 495, 631, 867, 1072, 1389, 1640, 1738},
+/* 35% */{ 59, 111, 246, 341, 379, 486, 619, 850, 1049, 1357, 1600, 1695},
+/* 36% */{ 58, 108, 240, 335, 370, 477, 607, 832, 1027, 1325, 1561, 1653},
+/* 37% */{ 57, 106, 235, 329, 361, 468, 595, 815, 1004, 1293, 1522, 1610},
+/* 38% */{ 56, 104, 230, 323, 351, 459, 584, 797, 981, 1261, 1483, 1568},
+/* 39% */{ 55, 102, 224, 317, 342, 450, 572, 780, 958, 1230, 1443, 1526},
+/* 40% */{ 54, 100, 219, 311, 333, 441, 560, 762, 935, 1198, 1404, 1484},
+/* 41% */{ 53, 98, 214, 305, 324, 432, 548, 744, 912, 1166, 1366, 1442},
+/* 42% */{ 52, 96, 209, 299, 315, 423, 536, 727, 889, 1135, 1327, 1400},
+/* 43% */{ 51, 94, 203, 293, 306, 414, 524, 709, 866, 1104, 1289, 1358},
+/* 44% */{ 50, 92, 198, 287, 297, 405, 512, 692, 844, 1072, 1250, 1317},
+/* 45% */{ 49, 90, 193, 281, 288, 396, 500, 675, 821, 1041, 1212, 1276},
+/* 46% */{ 48, 88, 188, 275, 279, 387, 488, 657, 799, 1011, 1174, 1236},
+/* 47% */{ 47, 86, 183, 269, 271, 378, 476, 640, 777, 980, 1137, 1195},
+/* 48% */{ 46, 84, 178, 262, 262, 369, 464, 623, 754, 949, 1100, 1155},
+/* 49% */{ 45, 82, 173, 256, 254, 360, 452, 606, 732, 919, 1063, 1116},
+/* 50% */{ 44, 80, 168, 251, 245, 351, 441, 589, 710, 889, 1026, 1076},
+/* 51% */{ 43, 78, 163, 245, 237, 342, 429, 572, 689, 860, 990, 1038},
+/* 52% */{ 42, 76, 158, 239, 228, 333, 417, 555, 667, 830, 955, 999},
+/* 53% */{ 41, 74, 153, 233, 220, 324, 406, 538, 645, 801, 919, 961},
+/* 54% */{ 40, 72, 148, 227, 212, 315, 394, 522, 624, 773, 884, 924},
+/* 55% */{ 39, 70, 143, 221, 204, 307, 383, 505, 603, 744, 850, 887},
+/* 56% */{ 38, 68, 138, 215, 196, 298, 371, 489, 582, 716, 816, 851},
+/* 57% */{ 37, 67, 134, 209, 189, 289, 360, 473, 562, 688, 783, 815},
+/* 58% */{ 36, 65, 129, 203, 181, 281, 349, 457, 541, 661, 750, 780},
+/* 59% */{ 35, 63, 124, 197, 174, 272, 338, 441, 521, 634, 717, 745},
+/* 60% */{ 34, 61, 120, 192, 166, 264, 327, 425, 501, 608, 686, 712},
+/* 61% */{ 33, 59, 115, 186, 159, 255, 316, 409, 482, 582, 655, 678},
+/* 62% */{ 32, 57, 111, 180, 152, 247, 305, 394, 462, 556, 624, 646},
+/* 63% */{ 31, 55, 107, 174, 145, 238, 294, 379, 443, 531, 594, 614},
+/* 64% */{ 30, 53, 102, 169, 138, 230, 283, 364, 425, 506, 565, 583},
+/* 65% */{ 29, 52, 98, 163, 132, 222, 273, 349, 406, 482, 536, 553},
+/* 66% */{ 28, 50, 94, 158, 125, 214, 262, 334, 388, 459, 508, 523},
+/* 67% */{ 27, 48, 90, 152, 119, 206, 252, 320, 370, 436, 481, 495},
+/* 68% */{ 26, 46, 86, 147, 113, 198, 242, 306, 353, 413, 455, 467},
+/* 69% */{ 26, 44, 82, 141, 107, 190, 231, 292, 336, 391, 429, 440},
+/* 70% */{ 25, 43, 78, 136, 101, 182, 221, 278, 319, 370, 405, 414},
+/* 71% */{ 24, 41, 74, 130, 95, 174, 212, 265, 303, 350, 381, 389},
+/* 72% */{ 23, 39, 71, 125, 90, 167, 202, 252, 287, 329, 358, 365},
+/* 73% */{ 22, 37, 67, 119, 85, 159, 192, 239, 271, 310, 335, 342},
+/* 74% */{ 21, 36, 63, 114, 80, 151, 183, 226, 256, 291, 314, 320},
+/* 75% */{ 20, 34, 60, 109, 75, 144, 174, 214, 241, 273, 294, 298},
+/* 76% */{ 19, 32, 57, 104, 70, 137, 164, 202, 227, 256, 274, 278},
+/* 77% */{ 18, 31, 53, 99, 66, 130, 155, 190, 213, 239, 256, 259},
+/* 78% */{ 17, 29, 50, 94, 62, 122, 146, 178, 200, 223, 238, 241},
+/* 79% */{ 16, 28, 47, 89, 58, 115, 138, 167, 187, 208, 222, 225},
+/* 80% */{ 16, 26, 44, 84, 54, 109, 129, 156, 175, 194, 206, 209},
+/* 81% */{ 15, 24, 41, 79, 50, 102, 121, 146, 163, 180, 192, 194},
+/* 82% */{ 14, 23, 39, 74, 47, 95, 113, 136, 151, 167, 178, 181},
+/* 83% */{ 13, 21, 36, 69, 44, 89, 105, 126, 140, 155, 166, 169},
+/* 84% */{ 12, 20, 33, 64, 41, 82, 97, 116, 130, 144, 155, 158},
+/* 85% */{ 11, 19, 31, 60, 39, 76, 89, 107, 120, 134, 145, 149},
+/* 86% */{ 11, 17, 29, 55, 36, 70, 82, 98, 110, 125, 136, 140},
+/* 87% */{ 10, 16, 26, 51, 34, 64, 75, 90, 102, 116, 128, 133},
+/* 88% */{ 9, 14, 24, 46, 32, 58, 68, 81, 93, 108, 121, 128},
+/* 89% */{ 8, 13, 22, 42, 31, 52, 61, 74, 86, 102, 116, 124},
+/* 90% */{ 7, 12, 21, 37, 29, 46, 54, 66, 79, 96, 112, 121}
+};
+
+#define RSSIBUF_NUM 10
+#define RSSI2RATE_SIZE 9
+
+static TXRETRY_REC TxRateRec={MTO_MAX_DATA_RATE_LEVELS - 1, 0}; //new record=>TxRateRec
+static int TxRetryRate;
+//static int SQ3, BSS_PK_CNT, NIDLESLOT, SLOT_CNT, INTERF_CNT, GAP_CNT, DS_EVM;
+static s32 RSSIBuf[RSSIBUF_NUM]={-70, -70, -70, -70, -70, -70, -70, -70, -70, -70};
+static s32 RSSISmoothed=-700;
+static int RSSIBufIndex=0;
+static u8 max_rssi_rate;
+static int rate_tbl[13] = {0,1,2,5,11,6,9,12,18,24,36,48,54};
+//[WKCHEN]static core_data_t *pMTOcore_data=NULL;
+
+static int TotalTxPkt = 0;
+static int TotalTxPktRetry = 0;
+static int TxPktPerAnt[3] = {0,0,0};
+static int RXRSSIANT[3] ={-70,-70,-70};
+static int TxPktRetryPerAnt[3] = {0,0,0};
+//static int TxDominateFlag=FALSE;
+static u8 old_antenna[4]={1 ,0 ,1 ,0};
+static int retryrate_rec[MTO_MAX_DATA_RATE_LEVELS];//this record the retry rate at different data rate
+
+static int PeriodTotalTxPkt = 0;
+static int PeriodTotalTxPktRetry = 0;
+
+typedef struct
+{
+ s32 RSSI;
+ u8 TxRate;
+}RSSI2RATE;
+
+static RSSI2RATE RSSI2RateTbl[RSSI2RATE_SIZE] =
+{
+ {-740, 108}, // 54M
+ {-760, 96}, // 48M
+ {-820, 72}, // 36M
+ {-850, 48}, // 24M
+ {-870, 36}, // 18M
+ {-890, 24}, // 12M
+ {-900, 12}, // 6M
+ {-920, 11}, // 5.5M
+ {-950, 4}, // 2M
+};
+static u8 untogglecount;
+static u8 last_rate_ant; //this is used for antenna backoff-hh
+
+u8 boSparseTxTraffic = FALSE;
+
+void MTO_Init(MTO_FUNC_INPUT);
+void AntennaToggleInitiator(MTO_FUNC_INPUT);
+void AntennaToggleState(MTO_FUNC_INPUT);
+void TxPwrControl(MTO_FUNC_INPUT);
+void GetFreshAntennaData(MTO_FUNC_INPUT);
+void TxRateReductionCtrl(MTO_FUNC_INPUT);
+/** 1.1.31.1000 Turbo modify */
+//void MTO_SetDTORateRange(int type);
+void MTO_SetDTORateRange(MTO_FUNC_INPUT, u8 *pRateArray, u8 ArraySize);
+void MTO_SetTxCount(MTO_FUNC_INPUT, u8 t0, u8 index);
+void MTO_TxFailed(MTO_FUNC_INPUT);
+void SmoothRSSI(s32 new_rssi);
+void hal_get_dto_para(MTO_FUNC_INPUT, char *buffer);
+u8 CalcNewRate(MTO_FUNC_INPUT, u8 old_rate, u32 retry_cnt, u32 tx_frag_cnt);
+u8 GetMaxRateLevelFromRSSI(void);
+u8 MTO_GetTxFallbackRate(MTO_FUNC_INPUT);
+int Divide(int a, int b);
+void multiagc(MTO_FUNC_INPUT, u8 high_gain_mode);
+
+//===========================================================================
+// MTO_Init --
+//
+// Description:
+// Set DTO Tx Rate Scope because different AP could have different Rate set.
+// After our staion join with AP, LM core will call this function to initialize
+// Tx Rate table.
+//
+// Arguments:
+// pRateArray - The pointer to the Tx Rate Array by the following order
+// - 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108
+// - DTO won't check whether rate order is invalid or not
+// ArraySize - The array size to indicate how many tx rate we can choose
+//
+// sample code:
+// {
+// u8 RateArray[4] = {2, 4, 11, 22};
+// MTO_SetDTORateRange(RateArray, 4);
+// }
+//
+// Return Value:
+// None
+//============================================================================
+void MTO_SetDTORateRange(MTO_FUNC_INPUT,u8 *pRateArray, u8 ArraySize)
+{
+ u8 i, j=0;
+
+ for(i=0;i<ArraySize;i++)
+ {
+ if(pRateArray[i] == 22)
+ break;
+ }
+ if(i < ArraySize) //we need adjust the order of rate list because 11Mbps rate exists
+ {
+ for(;i>0;i--)
+ {
+ if(pRateArray[i-1] <= 11)
+ break;
+ pRateArray[i] = pRateArray[i-1];
+ }
+ pRateArray[i] = 22;
+ MTO_OFDM_RATE_LEVEL() = i;
+ }
+ else
+ {
+ for(i=0; i<ArraySize; i++)
+ {
+ if (pRateArray[i] >= 12)
+ break;
+ }
+ MTO_OFDM_RATE_LEVEL() = i;
+ }
+
+ for(i=0;i<ArraySize;i++)
+ {
+ MTO_Data_Rate_Tbl[i] = pRateArray[i];
+ for(;j<MTO_MAX_DATA_RATE_LEVELS;j++)
+ {
+ if(Stardard_Data_Rate_Tbl[j] == pRateArray[i])
+ break;
+ }
+ Level2PerTbl[i] = j;
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("[MTO]:Op Rate[%d]: %d\n",i, MTO_Data_Rate_Tbl[i]));
+ #endif
+ }
+ MTO_DataRateAvailableLevel = ArraySize;
+ if( MTO_DATA().RatePolicy ) // 0 means that no registry setting
+ {
+ if( MTO_DATA().RatePolicy == 1 )
+ TxRateRec.tx_rate = 0; //ascent
+ else
+ TxRateRec.tx_rate = MTO_DataRateAvailableLevel -1 ; //descent
+ }
+ else
+ {
+ if( MTO_INITTXRATE_MODE )
+ TxRateRec.tx_rate = 0; //ascent
+ else
+ TxRateRec.tx_rate = MTO_DataRateAvailableLevel -1 ; //descent
+ }
+ TxRateRec.tx_retry_rate = 0;
+ //set default rate for initial use
+ MTO_RATE_LEVEL() = TxRateRec.tx_rate;
+ MTO_FALLBACK_RATE_LEVEL() = MTO_RATE_LEVEL();
+}
+
+//===========================================================================
+// MTO_Init --
+//
+// Description:
+// Initialize MTO parameters.
+//
+// This function should be invoked during system initialization.
+//
+// Arguments:
+// Adapter - The pointer to the Miniport Adapter Context
+//
+// Return Value:
+// None
+//============================================================================
+void MTO_Init(MTO_FUNC_INPUT)
+{
+ int i;
+ //WBDEBUG(("[MTO] -> MTO_Init()\n"));
+ //[WKCHEN]pMTOcore_data = pcore_data;
+// 20040510 Turbo add for global variable
+ MTO_TMR_CNT() = 0;
+ MTO_TOGGLE_STATE() = TOGGLE_STATE_IDLE;
+ MTO_TX_RATE_REDUCTION_STATE() = RATE_CHGSTATE_IDLE;
+ MTO_BACKOFF_TMR() = 0;
+ MTO_LAST_RATE() = 11;
+ MTO_CO_EFFICENT() = 0;
+
+ //MTO_TH_FIXANT() = MTO_DEFAULT_TH_FIXANT;
+ MTO_TH_CNT() = MTO_DEFAULT_TH_CNT;
+ MTO_TH_SQ3() = MTO_DEFAULT_TH_SQ3;
+ MTO_TH_IDLE_SLOT() = MTO_DEFAULT_TH_IDLE_SLOT;
+ MTO_TH_PR_INTERF() = MTO_DEFAULT_TH_PR_INTERF;
+
+ MTO_TMR_AGING() = MTO_DEFAULT_TMR_AGING;
+ MTO_TMR_PERIODIC() = MTO_DEFAULT_TMR_PERIODIC;
+
+ //[WKCHEN]MTO_CCA_MODE_SETUP()= (u8) hal_get_cca_mode(MTO_HAL());
+ //[WKCHEN]MTO_CCA_MODE() = MTO_CCA_MODE_SETUP();
+
+ //MTO_PREAMBLE_TYPE() = MTO_PREAMBLE_LONG;
+ MTO_PREAMBLE_TYPE() = MTO_PREAMBLE_SHORT; // for test
+
+ MTO_ANT_SEL() = hal_get_antenna_number(MTO_HAL());
+ MTO_ANT_MAC() = MTO_ANT_SEL();
+ MTO_CNT_ANT(0) = 0;
+ MTO_CNT_ANT(1) = 0;
+ MTO_SQ_ANT(0) = 0;
+ MTO_SQ_ANT(1) = 0;
+ MTO_ANT_DIVERSITY() = MTO_ANTENNA_DIVERSITY_ON;
+ //CardSet_AntennaDiversity(Adapter, MTO_ANT_DIVERSITY());
+ //PLMESetAntennaDiversity( Adapter, MTO_ANT_DIVERSITY());
+
+ MTO_AGING_TIMEOUT() = 0;//MTO_TMR_AGING() / MTO_TMR_PERIODIC();
+
+ // The following parameters should be initialized to the values set by user
+ //
+ //MTO_RATE_LEVEL() = 10;
+ MTO_RATE_LEVEL() = 0;
+ MTO_FALLBACK_RATE_LEVEL() = MTO_RATE_LEVEL();
+ MTO_FRAG_TH_LEVEL() = 4;
+ /** 1.1.23.1000 Turbo modify from -1 to +1
+ MTO_RTS_THRESHOLD() = MTO_FRAG_TH() - 1;
+ MTO_RTS_THRESHOLD_SETUP() = MTO_FRAG_TH() - 1;
+ */
+ MTO_RTS_THRESHOLD() = MTO_FRAG_TH() + 1;
+ MTO_RTS_THRESHOLD_SETUP() = MTO_FRAG_TH() + 1;
+ // 1.1.23.1000 Turbo add for mto change preamble from 0 to 1
+ MTO_RATE_CHANGE_ENABLE() = 1;
+ MTO_FRAG_CHANGE_ENABLE() = 0; // 1.1.29.1000 Turbo add don't support frag
+ //The default valud of ANTDIV_DEFAULT_ON will be decided by EEPROM
+ //#ifdef ANTDIV_DEFAULT_ON
+ //MTO_ANT_DIVERSITY_ENABLE() = 1;
+ //#else
+ //MTO_ANT_DIVERSITY_ENABLE() = 0;
+ //#endif
+ MTO_POWER_CHANGE_ENABLE() = 1;
+ MTO_PREAMBLE_CHANGE_ENABLE()= 1;
+ MTO_RTS_CHANGE_ENABLE() = 0; // 1.1.29.1000 Turbo add don't support frag
+ // 20040512 Turbo add
+ //old_antenna[0] = 1;
+ //old_antenna[1] = 0;
+ //old_antenna[2] = 1;
+ //old_antenna[3] = 0;
+ for (i=0;i<MTO_MAX_DATA_RATE_LEVELS;i++)
+ retryrate_rec[i]=5;
+
+ MTO_TXFLOWCOUNT() = 0;
+ //--------- DTO threshold parameters -------------
+ //MTOPARA_PERIODIC_CHECK_CYCLE() = 50;
+ MTOPARA_PERIODIC_CHECK_CYCLE() = 10;
+ MTOPARA_RSSI_TH_FOR_ANTDIV() = 10;
+ MTOPARA_TXCOUNT_TH_FOR_CALC_RATE() = 50;
+ MTOPARA_TXRATE_INC_TH() = 10;
+ MTOPARA_TXRATE_DEC_TH() = 30;
+ MTOPARA_TXRATE_EQ_TH() = 40;
+ MTOPARA_TXRATE_BACKOFF() = 12;
+ MTOPARA_TXRETRYRATE_REDUCE() = 6;
+ if ( MTO_TXPOWER_FROM_EEPROM == 0xff)
+ {
+ switch( MTO_HAL()->phy_type)
+ {
+ case RF_AIROHA_2230:
+ case RF_AIROHA_2230S: // 20060420 Add this
+ MTOPARA_TXPOWER_INDEX() = 46; // MAX-8 // @@ Only for AL 2230
+ break;
+ case RF_AIROHA_7230:
+ MTOPARA_TXPOWER_INDEX() = 49;
+ break;
+ case RF_WB_242:
+ MTOPARA_TXPOWER_INDEX() = 10;
+ break;
+ case RF_WB_242_1:
+ MTOPARA_TXPOWER_INDEX() = 24; // ->10 20060316.1 modify
+ break;
+ }
+ }
+ else //follow the setting from EEPROM
+ MTOPARA_TXPOWER_INDEX() = MTO_TXPOWER_FROM_EEPROM;
+ hal_set_rf_power(MTO_HAL(), (u8)MTOPARA_TXPOWER_INDEX());
+ //------------------------------------------------
+
+ // For RSSI turning 20060808.4 Cancel load from EEPROM
+ MTO_DATA().RSSI_high = -41;
+ MTO_DATA().RSSI_low = -60;
+}
+
+//---------------------------------------------------------------------------//
+static u32 DTO_Rx_Info[13][3];
+static u32 DTO_RxCRCFail_Info[13][3];
+static u32 AntennaToggleBkoffTimer=5;
+typedef struct{
+ int RxRate;
+ int RxRatePkts;
+ int index;
+}RXRATE_ANT;
+RXRATE_ANT RxRatePeakAnt[3];
+
+#define ANT0 0
+#define ANT1 1
+#define OLD_ANT 2
+
+void SearchPeakRxRate(int index)
+{
+ int i;
+ RxRatePeakAnt[index].RxRatePkts=0;
+ //Find out the best rx rate which is used on different antenna
+ for(i=1;i<13;i++)
+ {
+ if(DTO_Rx_Info[i][index] > (u32) RxRatePeakAnt[index].RxRatePkts)
+ {
+ RxRatePeakAnt[index].RxRatePkts = DTO_Rx_Info[i][index];
+ RxRatePeakAnt[index].RxRate = rate_tbl[i];
+ RxRatePeakAnt[index].index = i;
+ }
+ }
+}
+
+void ResetDTO_RxInfo(int index, MTO_FUNC_INPUT)
+{
+ int i;
+
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("ResetDTOrx\n"));
+ #endif
+
+ for(i=0;i<13;i++)
+ DTO_Rx_Info[i][index] = MTO_HAL()->rx_ok_count[i];
+
+ for(i=0;i<13;i++)
+ DTO_RxCRCFail_Info[i][index] = MTO_HAL()->rx_err_count[i];
+
+ TotalTxPkt = 0;
+ TotalTxPktRetry = 0;
+}
+
+void GetDTO_RxInfo(int index, MTO_FUNC_INPUT)
+{
+ int i;
+
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("GetDTOrx\n"));
+ #endif
+
+ //PDEBUG(("[MTO]:DTO_Rx_Info[%d]=%d, rx_ok_count=%d\n", index, DTO_Rx_Info[0][index], phw_data->rx_ok_count[0]));
+ for(i=0;i<13;i++)
+ DTO_Rx_Info[i][index] = abs(MTO_HAL()->rx_ok_count[i] - DTO_Rx_Info[i][index]);
+ if(DTO_Rx_Info[0][index]==0) DTO_Rx_Info[0][index] = 1;
+
+ for(i=0;i<13;i++)
+ DTO_RxCRCFail_Info[i][index] = MTO_HAL()->rx_err_count[i] - DTO_RxCRCFail_Info[i][index];
+
+ TxPktPerAnt[index] = TotalTxPkt;
+ TxPktRetryPerAnt[index] = TotalTxPktRetry;
+ TotalTxPkt = 0;
+ TotalTxPktRetry = 0;
+}
+
+void OutputDebugInfo(int index1, int index2)
+{
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("[HHDTO]:Total Rx (%d)\t\t(%d) \n ", DTO_Rx_Info[0][index1], DTO_Rx_Info[0][index2]));
+ WBDEBUG(("[HHDTO]:RECEIVE RSSI: (%d)\t\t(%d) \n ", RXRSSIANT[index1], RXRSSIANT[index2]));
+ WBDEBUG(("[HHDTO]:TX packet correct rate: (%d)%%\t\t(%d)%% \n ",Divide(TxPktPerAnt[index1]*100,TxPktRetryPerAnt[index1]), Divide(TxPktPerAnt[index2]*100,TxPktRetryPerAnt[index2])));
+ #endif
+ {
+ int tmp1, tmp2;
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("[HHDTO]:Total Tx (%d)\t\t(%d) \n ", TxPktPerAnt[index1], TxPktPerAnt[index2]));
+ WBDEBUG(("[HHDTO]:Total Tx retry (%d)\t\t(%d) \n ", TxPktRetryPerAnt[index1], TxPktRetryPerAnt[index2]));
+ #endif
+ tmp1 = TxPktPerAnt[index1] + DTO_Rx_Info[0][index1];
+ tmp2 = TxPktPerAnt[index2] + DTO_Rx_Info[0][index2];
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("[HHDTO]:Total Tx+RX (%d)\t\t(%d) \n ", tmp1, tmp2));
+ #endif
+ }
+}
+
+unsigned char TxDominate(int index)
+{
+ int tmp;
+
+ tmp = TxPktPerAnt[index] + DTO_Rx_Info[0][index];
+
+ if(Divide(TxPktPerAnt[index]*100, tmp) > 40)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+unsigned char CmpTxRetryRate(int index1, int index2)
+{
+ int tx_retry_rate1, tx_retry_rate2;
+ tx_retry_rate1 = Divide((TxPktRetryPerAnt[index1] - TxPktPerAnt[index1])*100, TxPktRetryPerAnt[index1]);
+ tx_retry_rate2 = Divide((TxPktRetryPerAnt[index2] - TxPktPerAnt[index2])*100, TxPktRetryPerAnt[index2]);
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("[MTO]:TxRetry Ant0: (%d%%) Ant1: (%d%%) \n ", tx_retry_rate1, tx_retry_rate2));
+ #endif
+
+ if(tx_retry_rate1 > tx_retry_rate2)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+void GetFreshAntennaData(MTO_FUNC_INPUT)
+{
+ u8 x;
+
+ x = hal_get_antenna_number(MTO_HAL());
+ //hal_get_bss_pk_cnt(MTO_HAL());
+ //hal_get_est_sq3(MTO_HAL(), 1);
+ old_antenna[0] = x;
+ //if this is the function for timer
+ ResetDTO_RxInfo(x, MTO_FUNC_INPUT_DATA);
+ if(AntennaToggleBkoffTimer)
+ AntennaToggleBkoffTimer--;
+ if (abs(last_rate_ant-MTO_RATE_LEVEL())>1) //backoff timer reset
+ AntennaToggleBkoffTimer=0;
+
+ if (MTO_ANT_DIVERSITY() != MTO_ANTENNA_DIVERSITY_ON ||
+ MTO_ANT_DIVERSITY_ENABLE() != 1)
+ AntennaToggleBkoffTimer=1;
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("[HHDTO]:**last data rate=%d,now data rate=%d**antenna toggle timer=%d",last_rate_ant,MTO_RATE_LEVEL(),AntennaToggleBkoffTimer));
+ #endif
+ last_rate_ant=MTO_RATE_LEVEL();
+ if(AntennaToggleBkoffTimer==0)
+ {
+ MTO_TOGGLE_STATE() = TOGGLE_STATE_WAIT0;
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("[HHDTO]:===state is starting==for antenna toggle==="));
+ #endif
+ }
+ else
+ MTO_TOGGLE_STATE() = TOGGLE_STATE_IDLE;
+
+ if ((MTO_BACKOFF_TMR()!=0)&&(MTO_RATE_LEVEL()>MTO_DataRateAvailableLevel - 3))
+ {
+ MTO_TOGGLE_STATE() = TOGGLE_STATE_IDLE;
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("[HHDTO]:===the data rate is %d (good)and will not toogle ===",MTO_DATA_RATE()>>1));
+ #endif
+ }
+
+
+}
+
+int WB_PCR[2]; //packet correct rate
+
+void AntennaToggleState(MTO_FUNC_INPUT)
+{
+ int decideantflag = 0;
+ u8 x;
+ s32 rssi;
+
+ if(MTO_ANT_DIVERSITY_ENABLE() != 1)
+ return;
+ x = hal_get_antenna_number(MTO_HAL());
+ switch(MTO_TOGGLE_STATE())
+ {
+
+ //Missing.....
+ case TOGGLE_STATE_IDLE:
+ case TOGGLE_STATE_BKOFF:
+ break;;
+
+ case TOGGLE_STATE_WAIT0://========
+ GetDTO_RxInfo(x, MTO_FUNC_INPUT_DATA);
+ sme_get_rssi(MTO_FUNC_INPUT_DATA, &rssi);
+ RXRSSIANT[x] = rssi;
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("[HHDTO] **wait0==== Collecting Ant%d--rssi=%d\n", x,RXRSSIANT[x]));
+ #endif
+
+ //change antenna and reset the data at changed antenna
+ x = (~x) & 0x01;
+ MTO_ANT_SEL() = x;
+ hal_set_antenna_number(MTO_HAL(), MTO_ANT_SEL());
+ LOCAL_ANTENNA_NO() = x;
+
+ MTO_TOGGLE_STATE() = TOGGLE_STATE_WAIT1;//go to wait1
+ ResetDTO_RxInfo(x, MTO_FUNC_INPUT_DATA);
+ break;
+ case TOGGLE_STATE_WAIT1://=====wait1
+ //MTO_CNT_ANT(x) = hal_get_bss_pk_cnt(MTO_HAL());
+ //RXRSSIANT[x] = hal_get_rssi(MTO_HAL());
+ sme_get_rssi(MTO_FUNC_INPUT_DATA, &rssi);
+ RXRSSIANT[x] = rssi;
+ GetDTO_RxInfo(x, MTO_FUNC_INPUT_DATA);
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("[HHDTO] **wait1==== Collecting Ant%d--rssi=%d\n", x,RXRSSIANT[x]));
+ #endif
+ MTO_TOGGLE_STATE() = TOGGLE_STATE_MAKEDESISION;
+ break;
+ case TOGGLE_STATE_MAKEDESISION:
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("[HHDTO]:Ant--0-----------------1---\n"));
+ OutputDebugInfo(ANT0,ANT1);
+ #endif
+ //PDEBUG(("[HHDTO] **decision====\n "));
+
+ //=====following is the decision produrce
+ //
+ // first: compare the rssi if difference >10
+ // select the larger one
+ // ,others go to second
+ // second: comapre the tx+rx packet count if difference >100
+ // use larger total packets antenna
+ // third::compare the tx PER if packets>20
+ // if difference >5% using the bigger one
+ //
+ // fourth:compare the RX PER if packets>20
+ // if PER difference <5%
+ // using old antenna
+ //
+ //
+ if (abs(RXRSSIANT[ANT0]-RXRSSIANT[ANT1]) > MTOPARA_RSSI_TH_FOR_ANTDIV())//====rssi_th
+ {
+ if (RXRSSIANT[ANT0]>RXRSSIANT[ANT1])
+ {
+ decideantflag=1;
+ MTO_ANT_MAC() = ANT0;
+ }
+ else
+ {
+ decideantflag=1;
+ MTO_ANT_MAC() = ANT1;
+ }
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("Select antenna by RSSI\n"));
+ #endif
+ }
+ else if (abs(TxPktPerAnt[ANT0] + DTO_Rx_Info[0][ANT0]-TxPktPerAnt[ANT1]-DTO_Rx_Info[0][ANT1])<50)//=====total packet_th
+ {
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("Total tx/rx is close\n"));
+ #endif
+ if (TxDominate(ANT0) && TxDominate(ANT1))
+ {
+ if ((TxPktPerAnt[ANT0]>10) && (TxPktPerAnt[ANT1]>10))//====tx packet_th
+ {
+ WB_PCR[ANT0]=Divide(TxPktPerAnt[ANT0]*100,TxPktRetryPerAnt[ANT0]);
+ WB_PCR[ANT1]=Divide(TxPktPerAnt[ANT1]*100,TxPktRetryPerAnt[ANT1]);
+ if (abs(WB_PCR[ANT0]-WB_PCR[ANT1])>5)// tx PER_th
+ {
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("Decide by Tx correct rate\n"));
+ #endif
+ if (WB_PCR[ANT0]>WB_PCR[ANT1])
+ {
+ decideantflag=1;
+ MTO_ANT_MAC() = ANT0;
+ }
+ else
+ {
+ decideantflag=1;
+ MTO_ANT_MAC() = ANT1;
+ }
+ }
+ else
+ {
+ decideantflag=0;
+ untogglecount++;
+ MTO_ANT_MAC() = old_antenna[0];
+ }
+ }
+ else
+ {
+ decideantflag=0;
+ MTO_ANT_MAC() = old_antenna[0];
+ }
+ }
+ else if ((DTO_Rx_Info[0][ANT0]>10)&&(DTO_Rx_Info[0][ANT1]>10))//rx packet th
+ {
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("Decide by Rx\n"));
+ #endif
+ if (abs(DTO_Rx_Info[0][ANT0] - DTO_Rx_Info[0][ANT1])>50)
+ {
+ if (DTO_Rx_Info[0][ANT0] > DTO_Rx_Info[0][ANT1])
+ {
+ decideantflag=1;
+ MTO_ANT_MAC() = ANT0;
+ }
+ else
+ {
+ decideantflag=1;
+ MTO_ANT_MAC() = ANT1;
+ }
+ }
+ else
+ {
+ decideantflag=0;
+ untogglecount++;
+ MTO_ANT_MAC() = old_antenna[0];
+ }
+ }
+ else
+ {
+ decideantflag=0;
+ MTO_ANT_MAC() = old_antenna[0];
+ }
+ }
+ else if ((TxPktPerAnt[ANT0]+DTO_Rx_Info[0][ANT0])>(TxPktPerAnt[ANT1]+DTO_Rx_Info[0][ANT1]))//use more packekts
+ {
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("decide by total tx/rx : ANT 0\n"));
+ #endif
+
+ decideantflag=1;
+ MTO_ANT_MAC() = ANT0;
+ }
+ else
+ {
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("decide by total tx/rx : ANT 1\n"));
+ #endif
+ decideantflag=1;
+ MTO_ANT_MAC() = ANT1;
+
+ }
+ //this is force ant toggle
+ if (decideantflag==1)
+ untogglecount=0;
+
+ untogglecount=untogglecount%4;
+ if (untogglecount==3) //change antenna
+ MTO_ANT_MAC() = ((~old_antenna[0]) & 0x1);
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("[HHDTO]:==================untoggle-count=%d",untogglecount));
+ #endif
+
+
+
+
+ //PDEBUG(("[HHDTO] **********************************DTO ENABLE=%d",MTO_ANT_DIVERSITY_ENABLE()));
+ if(MTO_ANT_DIVERSITY_ENABLE() == 1)
+ {
+ MTO_ANT_SEL() = MTO_ANT_MAC();
+ hal_set_antenna_number(MTO_HAL(), MTO_ANT_SEL());
+ LOCAL_ANTENNA_NO() = MTO_ANT_SEL();
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("[HHDTO] ==decision==*******antflag=%d******************selected antenna=%d\n",decideantflag,MTO_ANT_SEL()));
+ #endif
+ }
+ if (decideantflag)
+ {
+ old_antenna[3]=old_antenna[2];//store antenna info
+ old_antenna[2]=old_antenna[1];
+ old_antenna[1]=old_antenna[0];
+ old_antenna[0]= MTO_ANT_MAC();
+ }
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("[HHDTO]:**old antenna=[%d][%d][%d][%d]\n",old_antenna[0],old_antenna[1],old_antenna[2],old_antenna[3]));
+ #endif
+ if (old_antenna[0]!=old_antenna[1])
+ AntennaToggleBkoffTimer=0;
+ else if (old_antenna[1]!=old_antenna[2])
+ AntennaToggleBkoffTimer=1;
+ else if (old_antenna[2]!=old_antenna[3])
+ AntennaToggleBkoffTimer=2;
+ else
+ AntennaToggleBkoffTimer=4;
+
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("[HHDTO]:**back off timer=%d",AntennaToggleBkoffTimer));
+ #endif
+
+ ResetDTO_RxInfo(MTO_ANT_MAC(), MTO_FUNC_INPUT_DATA);
+ if (AntennaToggleBkoffTimer==0 && decideantflag)
+ MTO_TOGGLE_STATE() = TOGGLE_STATE_WAIT0;
+ else
+ MTO_TOGGLE_STATE() = TOGGLE_STATE_IDLE;
+ break;
+ }
+
+}
+
+void multiagc(MTO_FUNC_INPUT, u8 high_gain_mode )
+{
+ s32 rssi;
+ hw_data_t *pHwData = MTO_HAL();
+
+ sme_get_rssi(MTO_FUNC_INPUT_DATA, &rssi);
+
+ if( (RF_WB_242 == pHwData->phy_type) ||
+ (RF_WB_242_1 == pHwData->phy_type) ) // 20060619.5 Add
+ {
+ if (high_gain_mode==1)
+ {
+ //hw_set_dxx_reg(phw_data, 0x0C, 0xf8f52230);
+ //hw_set_dxx_reg(phw_data, 0x20, 0x06C43440);
+ Wb35Reg_Write( pHwData, 0x100C, 0xF2F32232 ); // 940916 0xf8f52230 );
+ Wb35Reg_Write( pHwData, 0x1020, 0x04cb3440 ); // 940915 0x06C43440
+ }
+ else if (high_gain_mode==0)
+ {
+ //hw_set_dxx_reg(phw_data, 0x0C, 0xEEEE000D);
+ //hw_set_dxx_reg(phw_data, 0x20, 0x06c41440);
+ Wb35Reg_Write( pHwData, 0x100C, 0xEEEE000D );
+ Wb35Reg_Write( pHwData, 0x1020, 0x04cb1440 ); // 940915 0x06c41440
+ }
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("[HHDTOAGC] **rssi=%d, high gain mode=%d", rssi, high_gain_mode));
+ #endif
+ }
+}
+
+void TxPwrControl(MTO_FUNC_INPUT)
+{
+ s32 rssi;
+ hw_data_t *pHwData = MTO_HAL();
+
+ sme_get_rssi(MTO_FUNC_INPUT_DATA, &rssi);
+ if( (RF_WB_242 == pHwData->phy_type) ||
+ (RF_WB_242_1 == pHwData->phy_type) ) // 20060619.5 Add
+ {
+ static u8 high_gain_mode; //this is for winbond RF switch LNA
+ //using different register setting
+
+ if (high_gain_mode==1)
+ {
+ if( rssi > MTO_DATA().RSSI_high )
+ {
+ //hw_set_dxx_reg(phw_data, 0x0C, 0xf8f52230);
+ //hw_set_dxx_reg(phw_data, 0x20, 0x05541640);
+ high_gain_mode=0;
+ }
+ else
+ {
+ //hw_set_dxx_reg(phw_data, 0x0C, 0xf8f51830);
+ //hw_set_dxx_reg(phw_data, 0x20, 0x05543E40);
+ high_gain_mode=1;
+ }
+ }
+ else //if (high_gain_mode==0)
+ {
+ if( rssi < MTO_DATA().RSSI_low )
+ {
+ //hw_set_dxx_reg(phw_data, 0x0C, 0xf8f51830);
+ //hw_set_dxx_reg(phw_data, 0x20, 0x05543E40);
+ high_gain_mode=1;
+ }
+ else
+ {
+ //hw_set_dxx_reg(phw_data, 0x0C, 0xf8f52230);
+ //hw_set_dxx_reg(phw_data, 0x20, 0x05541640);
+ high_gain_mode=0;
+ }
+ }
+
+ // Always high gain 20051014. Using the initial value only.
+ multiagc(MTO_FUNC_INPUT_DATA, high_gain_mode);
+ }
+}
+
+
+u8 CalcNewRate(MTO_FUNC_INPUT, u8 old_rate, u32 retry_cnt, u32 tx_frag_cnt)
+{
+ int i;
+ u8 new_rate;
+ u32 retry_rate;
+ int TxThrouput1, TxThrouput2, TxThrouput3, BestThroupht;
+
+ if(tx_frag_cnt < MTOPARA_TXCOUNT_TH_FOR_CALC_RATE()) //too few packets transmit
+ {
+ return 0xff;
+ }
+ retry_rate = Divide(retry_cnt * 100, tx_frag_cnt);
+
+ if(retry_rate > 90) retry_rate = 90; //always truncate to 90% due to lookup table size
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("##### Current level =%d, Retry count =%d, Frag count =%d\n",
+ old_rate, retry_cnt, tx_frag_cnt));
+ WBDEBUG(("*##* Retry rate =%d, throughput =%d\n",
+ retry_rate, Rate_PER_TBL[retry_rate][old_rate]));
+ WBDEBUG(("TxRateRec.tx_rate =%d, Retry rate = %d, throughput = %d\n",
+ TxRateRec.tx_rate, TxRateRec.tx_retry_rate,
+ Rate_PER_TBL[TxRateRec.tx_retry_rate][Level2PerTbl[TxRateRec.tx_rate]]));
+ WBDEBUG(("old_rate-1 =%d, Retry rate = %d, throughput = %d\n",
+ old_rate-1, retryrate_rec[old_rate-1],
+ Rate_PER_TBL[retryrate_rec[old_rate-1]][old_rate-1]));
+ WBDEBUG(("old_rate+1 =%d, Retry rate = %d, throughput = %d\n",
+ old_rate+1, retryrate_rec[old_rate+1],
+ Rate_PER_TBL[retryrate_rec[old_rate+1]][old_rate+1]));
+ #endif
+
+ //following is for record the retry rate at the different data rate
+ if (abs(retry_rate-retryrate_rec[old_rate])<50)//---the per TH
+ retryrate_rec[old_rate] = retry_rate; //update retry rate
+ else
+ {
+ for (i=0;i<MTO_DataRateAvailableLevel;i++) //reset all retry rate
+ retryrate_rec[i]=0;
+ retryrate_rec[old_rate] = retry_rate;
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("Reset retry rate table\n"));
+ #endif
+ }
+
+ if(TxRateRec.tx_rate > old_rate) //Decrease Tx Rate
+ {
+ TxThrouput1 = Rate_PER_TBL[TxRateRec.tx_retry_rate][Level2PerTbl[TxRateRec.tx_rate]];
+ TxThrouput2 = Rate_PER_TBL[retry_rate][Level2PerTbl[old_rate]];
+ if(TxThrouput1 > TxThrouput2)
+ {
+ new_rate = TxRateRec.tx_rate;
+ BestThroupht = TxThrouput1;
+ }
+ else
+ {
+ new_rate = old_rate;
+ BestThroupht = TxThrouput2;
+ }
+ if((old_rate > 0) &&(retry_rate>MTOPARA_TXRATE_DEC_TH())) //Min Rate
+ {
+ TxThrouput3 = Rate_PER_TBL[retryrate_rec[old_rate-1]][Level2PerTbl[old_rate-1]];
+ if(BestThroupht < TxThrouput3)
+ {
+ new_rate = old_rate - 1;
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("--------\n"));
+ #endif
+ BestThroupht = TxThrouput3;
+ }
+ }
+ }
+ else if(TxRateRec.tx_rate < old_rate) //Increase Tx Rate
+ {
+ TxThrouput1 = Rate_PER_TBL[TxRateRec.tx_retry_rate][Level2PerTbl[TxRateRec.tx_rate]];
+ TxThrouput2 = Rate_PER_TBL[retry_rate][Level2PerTbl[old_rate]];
+ if(TxThrouput1 > TxThrouput2)
+ {
+ new_rate = TxRateRec.tx_rate;
+ BestThroupht = TxThrouput1;
+ }
+ else
+ {
+ new_rate = old_rate;
+ BestThroupht = TxThrouput2;
+ }
+ if ((old_rate < MTO_DataRateAvailableLevel - 1)&&(retry_rate<MTOPARA_TXRATE_INC_TH()))
+ {
+ //TxThrouput3 = Rate_PER_TBL[retryrate_rec[old_rate+1]][Level2PerTbl[old_rate+1]];
+ if (retryrate_rec[old_rate+1] > MTOPARA_TXRETRYRATE_REDUCE())
+ TxThrouput3 = Rate_PER_TBL[retryrate_rec[old_rate+1]-MTOPARA_TXRETRYRATE_REDUCE()][Level2PerTbl[old_rate+1]];
+ else
+ TxThrouput3 = Rate_PER_TBL[retryrate_rec[old_rate+1]][Level2PerTbl[old_rate+1]];
+ if(BestThroupht < TxThrouput3)
+ {
+ new_rate = old_rate + 1;
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("++++++++++\n"));
+ #endif
+ BestThroupht = TxThrouput3;
+ }
+ }
+ }
+ else //Tx Rate no change
+ {
+ TxThrouput2 = Rate_PER_TBL[retry_rate][Level2PerTbl[old_rate]];
+ new_rate = old_rate;
+ BestThroupht = TxThrouput2;
+
+ if (retry_rate <MTOPARA_TXRATE_EQ_TH()) //th for change higher rate
+ {
+ if(old_rate < MTO_DataRateAvailableLevel - 1)
+ {
+ //TxThrouput3 = Rate_PER_TBL[retryrate_rec[old_rate+1]][Level2PerTbl[old_rate+1]];
+ if (retryrate_rec[old_rate+1] > MTOPARA_TXRETRYRATE_REDUCE())
+ TxThrouput3 = Rate_PER_TBL[retryrate_rec[old_rate+1]-MTOPARA_TXRETRYRATE_REDUCE()][Level2PerTbl[old_rate+1]];
+ else
+ TxThrouput3 = Rate_PER_TBL[retryrate_rec[old_rate+1]][Level2PerTbl[old_rate+1]];
+ if(BestThroupht < TxThrouput3)
+ {
+ new_rate = old_rate + 1;
+ BestThroupht = TxThrouput3;
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("=++++++++++\n"));
+ #endif
+ }
+ }
+ }
+ else
+ if(old_rate > 0) //Min Rate
+ {
+ TxThrouput3 = Rate_PER_TBL[retryrate_rec[old_rate-1]][Level2PerTbl[old_rate-1]];
+ if(BestThroupht < TxThrouput3)
+ {
+ new_rate = old_rate - 1;
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("=--------\n"));
+ #endif
+ BestThroupht = TxThrouput3;
+ }
+ }
+ }
+
+ if (!LOCAL_IS_IBSS_MODE())
+ {
+ max_rssi_rate = GetMaxRateLevelFromRSSI();
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("[MTO]:RSSI2Rate=%d\n", MTO_Data_Rate_Tbl[max_rssi_rate]));
+ #endif
+ if(new_rate > max_rssi_rate)
+ new_rate = max_rssi_rate;
+ }
+
+ //save new rate;
+ TxRateRec.tx_rate = old_rate;
+ TxRateRec.tx_retry_rate = (u8) retry_rate;
+ TxRetryRate = retry_rate;
+ return new_rate;
+}
+
+void SmoothRSSI(s32 new_rssi)
+{
+ RSSISmoothed = RSSISmoothed + new_rssi - RSSIBuf[RSSIBufIndex];
+ RSSIBuf[RSSIBufIndex] = new_rssi;
+ RSSIBufIndex = (RSSIBufIndex + 1) % 10;
+}
+
+u8 GetMaxRateLevelFromRSSI(void)
+{
+ u8 i;
+ u8 TxRate;
+
+ for(i=0;i<RSSI2RATE_SIZE;i++)
+ {
+ if(RSSISmoothed > RSSI2RateTbl[i].RSSI)
+ break;
+ }
+ #ifdef _PE_DTO_DUMP_
+ WBDEBUG(("[MTO]:RSSI=%d\n", Divide(RSSISmoothed, 10)));
+ #endif
+ if(i < RSSI2RATE_SIZE)
+ TxRate = RSSI2RateTbl[i].TxRate;
+ else
+ TxRate = 2; //divided by 2 = 1Mbps
+
+ for(i=MTO_DataRateAvailableLevel-1;i>0;i--)
+ {
+ if(TxRate >=MTO_Data_Rate_Tbl[i])
+ break;
+ }
+ return i;
+}
+
+//===========================================================================
+// Description:
+// If we enable DTO, we will ignore the tx count with different tx rate from
+// DTO rate. This is because when we adjust DTO tx rate, there could be some
+// packets in the tx queue with previous tx rate
+void MTO_SetTxCount(MTO_FUNC_INPUT, u8 tx_rate, u8 index)
+{
+ MTO_TXFLOWCOUNT()++;
+ if ((MTO_ENABLE==1) && (MTO_RATE_CHANGE_ENABLE()==1))
+ {
+ if(tx_rate == MTO_DATA_RATE())
+ {
+ if (index == 0)
+ {
+ if (boSparseTxTraffic)
+ MTO_HAL()->dto_tx_frag_count += MTOPARA_PERIODIC_CHECK_CYCLE();
+ else
+ MTO_HAL()->dto_tx_frag_count += 1;
+ }
+ else
+ {
+ if (index<8)
+ {
+ MTO_HAL()->dto_tx_retry_count += index;
+ MTO_HAL()->dto_tx_frag_count += (index+1);
+ }
+ else
+ {
+ MTO_HAL()->dto_tx_retry_count += 7;
+ MTO_HAL()->dto_tx_frag_count += 7;
+ }
+ }
+ }
+ else if(MTO_DATA_RATE()>48 && tx_rate ==48)
+ {//ALFRED
+ if (index<3) //for reduciing data rate scheme ,
+ //do not calcu different data rate
+ //3 is the reducing data rate at retry
+ {
+ MTO_HAL()->dto_tx_retry_count += index;
+ MTO_HAL()->dto_tx_frag_count += (index+1);
+ }
+ else
+ {
+ MTO_HAL()->dto_tx_retry_count += 3;
+ MTO_HAL()->dto_tx_frag_count += 3;
+ }
+
+ }
+ }
+ else
+ {
+ MTO_HAL()->dto_tx_retry_count += index;
+ MTO_HAL()->dto_tx_frag_count += (index+1);
+ }
+ TotalTxPkt ++;
+ TotalTxPktRetry += (index+1);
+
+ PeriodTotalTxPkt ++;
+ PeriodTotalTxPktRetry += (index+1);
+}
+
+u8 MTO_GetTxFallbackRate(MTO_FUNC_INPUT)
+{
+ return MTO_DATA_FALLBACK_RATE();
+}
+
+
+//===========================================================================
+// MTO_TxFailed --
+//
+// Description:
+// Failure of transmitting a packet indicates that certain MTO parmeters
+// may need to be adjusted. This function is called when NIC just failed
+// to transmit a packet or when MSDULifeTime expired.
+//
+// Arguments:
+// Adapter - The pointer to the Miniport Adapter Context
+//
+// Return Value:
+// None
+//============================================================================
+void MTO_TxFailed(MTO_FUNC_INPUT)
+{
+ return;
+}
+
+int Divide(int a, int b)
+{
+ if (b==0) b=1;
+ return a/b;
+}
+
+
diff --git a/drivers/staging/winbond/mto.h b/drivers/staging/winbond/mto.h
new file mode 100644
index 0000000..f47936f
--- /dev/null
+++ b/drivers/staging/winbond/mto.h
@@ -0,0 +1,265 @@
+//==================================================================
+// MTO.H
+//
+// Revision history
+//=================================
+// 20030110 UN20 Pete Chao
+// Initial Release
+//
+// Copyright (c) 2003 Winbond Electronics Corp. All rights reserved.
+//==================================================================
+#ifndef __MTO_H__
+#define __MTO_H__
+
+#define MTO_DEFAULT_TH_CNT 5
+#define MTO_DEFAULT_TH_SQ3 112 //OLD IS 13 reference JohnXu
+#define MTO_DEFAULT_TH_IDLE_SLOT 15
+#define MTO_DEFAULT_TH_PR_INTERF 30
+#define MTO_DEFAULT_TMR_AGING 25 // unit: slot time 10 reference JohnXu
+#define MTO_DEFAULT_TMR_PERIODIC 5 // unit: slot time
+
+#define MTO_ANTENNA_DIVERSITY_OFF 0
+#define MTO_ANTENNA_DIVERSITY_ON 1
+
+// LA20040210_DTO kevin
+//#define MTO_PREAMBLE_LONG 0
+//#define MTO_PREAMBLE_SHORT 1
+#define MTO_PREAMBLE_LONG WLAN_PREAMBLE_TYPE_LONG
+#define MTO_PREAMBLE_SHORT WLAN_PREAMBLE_TYPE_SHORT
+
+typedef enum {
+ TOGGLE_STATE_IDLE = 0,
+ TOGGLE_STATE_WAIT0 = 1,
+ TOGGLE_STATE_WAIT1 = 2,
+ TOGGLE_STATE_MAKEDESISION = 3,
+ TOGGLE_STATE_BKOFF = 4
+} TOGGLE_STATE;
+
+typedef enum {
+ RATE_CHGSTATE_IDLE = 0,
+ RATE_CHGSTATE_CALCULATE = 1,
+ RATE_CHGSTATE_BACKOFF = 2
+} TX_RATE_REDUCTION_STATE;
+
+//============================================================================
+// struct _MTOParameters --
+//
+// Defines the parameters used in the MAC Throughput Optimization algorithm
+//============================================================================
+typedef struct _MTO_PARAMETERS
+{
+ u8 Th_Fixant;
+ u8 Th_Cnt;
+ u8 Th_SQ3;
+ u8 Th_IdleSlot;
+
+ u16 Tmr_Aging;
+ u8 Th_PrInterf;
+ u8 Tmr_Periodic;
+
+ //--------- wkchen added -------------
+ u32 TxFlowCount; //to judge what kind the tx flow(sparse or busy) is
+ //------------------------------------------------
+
+ //--------- DTO threshold parameters -------------
+ u16 DTO_PeriodicCheckCycle;
+ u16 DTO_RssiThForAntDiv;
+
+ u16 DTO_TxCountThForCalcNewRate;
+ u16 DTO_TxRateIncTh;
+
+ u16 DTO_TxRateDecTh;
+ u16 DTO_TxRateEqTh;
+
+ u16 DTO_TxRateBackOff;
+ u16 DTO_TxRetryRateReduce;
+
+ u16 DTO_TxPowerIndex; //0 ~ 31
+ u16 reserved_1;
+ //------------------------------------------------
+
+ u8 PowerChangeEnable;
+ u8 AntDiversityEnable;
+ u8 Ant_mac;
+ u8 Ant_div;
+
+ u8 CCA_Mode;
+ u8 CCA_Mode_Setup;
+ u8 Preamble_Type;
+ u8 PreambleChangeEnable;
+
+ u8 DataRateLevel;
+ u8 DataRateChangeEnable;
+ u8 FragThresholdLevel;
+ u8 FragThresholdChangeEnable;
+
+ u16 RTSThreshold;
+ u16 RTSThreshold_Setup;
+
+ u32 AvgIdleSlot;
+ u32 Pr_Interf;
+ u32 AvgGapBtwnInterf;
+
+ u8 RTSChangeEnable;
+ u8 Ant_sel;
+ u8 aging_timeout;
+ u8 reserved_2;
+
+ u32 Cnt_Ant[2];
+ u32 SQ_Ant[2];
+
+// 20040510 remove from globe vairable
+ u32 TmrCnt;
+ u32 BackoffTmr;
+ TOGGLE_STATE ToggleState;
+ TX_RATE_REDUCTION_STATE TxRateReductionState;
+
+ u8 Last_Rate;
+ u8 Co_efficent;
+ u8 FallbackRateLevel;
+ u8 OfdmRateLevel;
+
+ u8 RatePolicy;
+ u8 reserved_3[3];
+
+ // For RSSI turning
+ s32 RSSI_high;
+ s32 RSSI_low;
+
+} MTO_PARAMETERS, *PMTO_PARAMETERS;
+
+
+#define MTO_FUNC_INPUT PWB32_ADAPTER Adapter
+#define MTO_FUNC_INPUT_DATA Adapter
+#define MTO_DATA() (Adapter->sMtoPara)
+#define MTO_HAL() (&Adapter->sHwData)
+#define MTO_SET_PREAMBLE_TYPE(x) // 20040511 Turbo mark LM_PREAMBLE_TYPE(&pcore_data->lm_data) = (x)
+#define MTO_ENABLE (Adapter->sLocalPara.TxRateMode == RATE_AUTO)
+#define MTO_TXPOWER_FROM_EEPROM (Adapter->sHwData.PowerIndexFromEEPROM)
+#define LOCAL_ANTENNA_NO() (Adapter->sLocalPara.bAntennaNo)
+#define LOCAL_IS_CONNECTED() (Adapter->sLocalPara.wConnectedSTAindex != 0)
+#define LOCAL_IS_IBSS_MODE() (Adapter->asBSSDescriptElement[Adapter->sLocalPara.wConnectedSTAindex].bBssType == IBSS_NET)
+#define MTO_INITTXRATE_MODE (Adapter->sHwData.SoftwareSet&0x2) //bit 1
+// 20040510 Turbo add
+#define MTO_TMR_CNT() MTO_DATA().TmrCnt
+#define MTO_TOGGLE_STATE() MTO_DATA().ToggleState
+#define MTO_TX_RATE_REDUCTION_STATE() MTO_DATA().TxRateReductionState
+#define MTO_BACKOFF_TMR() MTO_DATA().BackoffTmr
+#define MTO_LAST_RATE() MTO_DATA().Last_Rate
+#define MTO_CO_EFFICENT() MTO_DATA().Co_efficent
+
+#define MTO_TH_CNT() MTO_DATA().Th_Cnt
+#define MTO_TH_SQ3() MTO_DATA().Th_SQ3
+#define MTO_TH_IDLE_SLOT() MTO_DATA().Th_IdleSlot
+#define MTO_TH_PR_INTERF() MTO_DATA().Th_PrInterf
+
+#define MTO_TMR_AGING() MTO_DATA().Tmr_Aging
+#define MTO_TMR_PERIODIC() MTO_DATA().Tmr_Periodic
+
+#define MTO_POWER_CHANGE_ENABLE() MTO_DATA().PowerChangeEnable
+#define MTO_ANT_DIVERSITY_ENABLE() Adapter->sLocalPara.boAntennaDiversity
+#define MTO_ANT_MAC() MTO_DATA().Ant_mac
+#define MTO_ANT_DIVERSITY() MTO_DATA().Ant_div
+#define MTO_CCA_MODE() MTO_DATA().CCA_Mode
+#define MTO_CCA_MODE_SETUP() MTO_DATA().CCA_Mode_Setup
+#define MTO_PREAMBLE_TYPE() MTO_DATA().Preamble_Type
+#define MTO_PREAMBLE_CHANGE_ENABLE() MTO_DATA().PreambleChangeEnable
+
+#define MTO_RATE_LEVEL() MTO_DATA().DataRateLevel
+#define MTO_FALLBACK_RATE_LEVEL() MTO_DATA().FallbackRateLevel
+#define MTO_OFDM_RATE_LEVEL() MTO_DATA().OfdmRateLevel
+#define MTO_RATE_CHANGE_ENABLE() MTO_DATA().DataRateChangeEnable
+#define MTO_FRAG_TH_LEVEL() MTO_DATA().FragThresholdLevel
+#define MTO_FRAG_CHANGE_ENABLE() MTO_DATA().FragThresholdChangeEnable
+#define MTO_RTS_THRESHOLD() MTO_DATA().RTSThreshold
+#define MTO_RTS_CHANGE_ENABLE() MTO_DATA().RTSChangeEnable
+#define MTO_RTS_THRESHOLD_SETUP() MTO_DATA().RTSThreshold_Setup
+
+#define MTO_AVG_IDLE_SLOT() MTO_DATA().AvgIdleSlot
+#define MTO_PR_INTERF() MTO_DATA().Pr_Interf
+#define MTO_AVG_GAP_BTWN_INTERF() MTO_DATA().AvgGapBtwnInterf
+
+#define MTO_ANT_SEL() MTO_DATA().Ant_sel
+#define MTO_CNT_ANT(x) MTO_DATA().Cnt_Ant[(x)]
+#define MTO_SQ_ANT(x) MTO_DATA().SQ_Ant[(x)]
+#define MTO_AGING_TIMEOUT() MTO_DATA().aging_timeout
+
+
+#define MTO_TXFLOWCOUNT() MTO_DATA().TxFlowCount
+//--------- DTO threshold parameters -------------
+#define MTOPARA_PERIODIC_CHECK_CYCLE() MTO_DATA().DTO_PeriodicCheckCycle
+#define MTOPARA_RSSI_TH_FOR_ANTDIV() MTO_DATA().DTO_RssiThForAntDiv
+#define MTOPARA_TXCOUNT_TH_FOR_CALC_RATE() MTO_DATA().DTO_TxCountThForCalcNewRate
+#define MTOPARA_TXRATE_INC_TH() MTO_DATA().DTO_TxRateIncTh
+#define MTOPARA_TXRATE_DEC_TH() MTO_DATA().DTO_TxRateDecTh
+#define MTOPARA_TXRATE_EQ_TH() MTO_DATA().DTO_TxRateEqTh
+#define MTOPARA_TXRATE_BACKOFF() MTO_DATA().DTO_TxRateBackOff
+#define MTOPARA_TXRETRYRATE_REDUCE() MTO_DATA().DTO_TxRetryRateReduce
+#define MTOPARA_TXPOWER_INDEX() MTO_DATA().DTO_TxPowerIndex
+//------------------------------------------------
+
+
+extern u8 MTO_Data_Rate_Tbl[];
+extern u16 MTO_Frag_Th_Tbl[];
+
+#define MTO_DATA_RATE() MTO_Data_Rate_Tbl[MTO_RATE_LEVEL()]
+#define MTO_DATA_FALLBACK_RATE() MTO_Data_Rate_Tbl[MTO_FALLBACK_RATE_LEVEL()] //next level
+#define MTO_FRAG_TH() MTO_Frag_Th_Tbl[MTO_FRAG_TH_LEVEL()]
+
+typedef struct {
+ u8 tx_rate;
+ u8 tx_retry_rate;
+} TXRETRY_REC;
+
+typedef struct _STATISTICS_INFO {
+ u32 Rate54M;
+ u32 Rate48M;
+ u32 Rate36M;
+ u32 Rate24M;
+ u32 Rate18M;
+ u32 Rate12M;
+ u32 Rate9M;
+ u32 Rate6M;
+ u32 Rate11MS;
+ u32 Rate11ML;
+ u32 Rate55MS;
+ u32 Rate55ML;
+ u32 Rate2MS;
+ u32 Rate2ML;
+ u32 Rate1M;
+ u32 Rate54MOK;
+ u32 Rate48MOK;
+ u32 Rate36MOK;
+ u32 Rate24MOK;
+ u32 Rate18MOK;
+ u32 Rate12MOK;
+ u32 Rate9MOK;
+ u32 Rate6MOK;
+ u32 Rate11MSOK;
+ u32 Rate11MLOK;
+ u32 Rate55MSOK;
+ u32 Rate55MLOK;
+ u32 Rate2MSOK;
+ u32 Rate2MLOK;
+ u32 Rate1MOK;
+ u32 SQ3;
+ s32 RSSIAVG;
+ s32 RSSIMAX;
+ s32 TXRATE;
+ s32 TxRetryRate;
+ s32 BSS_PK_CNT;
+ s32 NIDLESLOT;
+ s32 SLOT_CNT;
+ s32 INTERF_CNT;
+ s32 GAP_CNT;
+ s32 DS_EVM;
+ s32 RcvBeaconNum;
+ s32 RXRATE;
+ s32 RxBytes;
+ s32 TxBytes;
+ s32 Antenna;
+} STATISTICS_INFO, *PSTATISTICS_INFO;
+
+#endif //__MTO_H__
+
+
diff --git a/drivers/staging/winbond/mto_f.h b/drivers/staging/winbond/mto_f.h
new file mode 100644
index 0000000..30b3df2
--- /dev/null
+++ b/drivers/staging/winbond/mto_f.h
@@ -0,0 +1,7 @@
+extern void MTO_Init(PWB32_ADAPTER);
+extern void MTO_PeriodicTimerExpired(PWB32_ADAPTER);
+extern void MTO_SetDTORateRange(PWB32_ADAPTER, u8 *, u8);
+extern u8 MTO_GetTxRate(MTO_FUNC_INPUT, u32 fpdu_len);
+extern u8 MTO_GetTxFallbackRate(MTO_FUNC_INPUT);
+extern void MTO_SetTxCount(MTO_FUNC_INPUT, u8 t0, u8 index);
+
diff --git a/drivers/staging/winbond/os_common.h b/drivers/staging/winbond/os_common.h
new file mode 100644
index 0000000..e24ff41
--- /dev/null
+++ b/drivers/staging/winbond/os_common.h
@@ -0,0 +1,2 @@
+#include "linux/sysdef.h"
+
diff --git a/drivers/staging/winbond/phy_calibration.c b/drivers/staging/winbond/phy_calibration.c
new file mode 100644
index 0000000..272a650
--- /dev/null
+++ b/drivers/staging/winbond/phy_calibration.c
@@ -0,0 +1,1759 @@
+/*
+ * phy_302_calibration.c
+ *
+ * Copyright (C) 2002, 2005 Winbond Electronics Corp.
+ *
+ * modification history
+ * ---------------------------------------------------------------------------
+ * 0.01.001, 2003-04-16, Kevin created
+ *
+ */
+
+/****************** INCLUDE FILES SECTION ***********************************/
+#include "os_common.h"
+#include "phy_calibration.h"
+
+
+/****************** DEBUG CONSTANT AND MACRO SECTION ************************/
+
+/****************** LOCAL CONSTANT AND MACRO SECTION ************************/
+#define LOOP_TIMES 20
+#define US 1000//MICROSECOND
+
+#define AG_CONST 0.6072529350
+#define FIXED(X) ((s32)((X) * 32768.0))
+#define DEG2RAD(X) 0.017453 * (X)
+
+/****************** LOCAL TYPE DEFINITION SECTION ***************************/
+typedef s32 fixed; /* 16.16 fixed-point */
+
+static const fixed Angles[]=
+{
+ FIXED(DEG2RAD(45.0)), FIXED(DEG2RAD(26.565)), FIXED(DEG2RAD(14.0362)),
+ FIXED(DEG2RAD(7.12502)), FIXED(DEG2RAD(3.57633)), FIXED(DEG2RAD(1.78991)),
+ FIXED(DEG2RAD(0.895174)),FIXED(DEG2RAD(0.447614)),FIXED(DEG2RAD(0.223811)),
+ FIXED(DEG2RAD(0.111906)),FIXED(DEG2RAD(0.055953)),FIXED(DEG2RAD(0.027977))
+};
+
+/****************** LOCAL FUNCTION DECLARATION SECTION **********************/
+//void _phy_rf_write_delay(hw_data_t *phw_data);
+//void phy_init_rf(hw_data_t *phw_data);
+
+/****************** FUNCTION DEFINITION SECTION *****************************/
+
+s32 _s13_to_s32(u32 data)
+{
+ u32 val;
+
+ val = (data & 0x0FFF);
+
+ if ((data & BIT(12)) != 0)
+ {
+ val |= 0xFFFFF000;
+ }
+
+ return ((s32) val);
+}
+
+u32 _s32_to_s13(s32 data)
+{
+ u32 val;
+
+ if (data > 4095)
+ {
+ data = 4095;
+ }
+ else if (data < -4096)
+ {
+ data = -4096;
+ }
+
+ val = data & 0x1FFF;
+
+ return val;
+}
+
+/****************************************************************************/
+s32 _s4_to_s32(u32 data)
+{
+ s32 val;
+
+ val = (data & 0x0007);
+
+ if ((data & BIT(3)) != 0)
+ {
+ val |= 0xFFFFFFF8;
+ }
+
+ return val;
+}
+
+u32 _s32_to_s4(s32 data)
+{
+ u32 val;
+
+ if (data > 7)
+ {
+ data = 7;
+ }
+ else if (data < -8)
+ {
+ data = -8;
+ }
+
+ val = data & 0x000F;
+
+ return val;
+}
+
+/****************************************************************************/
+s32 _s5_to_s32(u32 data)
+{
+ s32 val;
+
+ val = (data & 0x000F);
+
+ if ((data & BIT(4)) != 0)
+ {
+ val |= 0xFFFFFFF0;
+ }
+
+ return val;
+}
+
+u32 _s32_to_s5(s32 data)
+{
+ u32 val;
+
+ if (data > 15)
+ {
+ data = 15;
+ }
+ else if (data < -16)
+ {
+ data = -16;
+ }
+
+ val = data & 0x001F;
+
+ return val;
+}
+
+/****************************************************************************/
+s32 _s6_to_s32(u32 data)
+{
+ s32 val;
+
+ val = (data & 0x001F);
+
+ if ((data & BIT(5)) != 0)
+ {
+ val |= 0xFFFFFFE0;
+ }
+
+ return val;
+}
+
+u32 _s32_to_s6(s32 data)
+{
+ u32 val;
+
+ if (data > 31)
+ {
+ data = 31;
+ }
+ else if (data < -32)
+ {
+ data = -32;
+ }
+
+ val = data & 0x003F;
+
+ return val;
+}
+
+/****************************************************************************/
+s32 _s9_to_s32(u32 data)
+{
+ s32 val;
+
+ val = data & 0x00FF;
+
+ if ((data & BIT(8)) != 0)
+ {
+ val |= 0xFFFFFF00;
+ }
+
+ return val;
+}
+
+u32 _s32_to_s9(s32 data)
+{
+ u32 val;
+
+ if (data > 255)
+ {
+ data = 255;
+ }
+ else if (data < -256)
+ {
+ data = -256;
+ }
+
+ val = data & 0x01FF;
+
+ return val;
+}
+
+/****************************************************************************/
+s32 _floor(s32 n)
+{
+ if (n > 0)
+ {
+ n += 5;
+ }
+ else
+ {
+ n -= 5;
+ }
+
+ return (n/10);
+}
+
+/****************************************************************************/
+// The following code is sqare-root function.
+// sqsum is the input and the output is sq_rt;
+// The maximum of sqsum = 2^27 -1;
+u32 _sqrt(u32 sqsum)
+{
+ u32 sq_rt;
+
+ int g0, g1, g2, g3, g4;
+ int seed;
+ int next;
+ int step;
+
+ g4 = sqsum / 100000000;
+ g3 = (sqsum - g4*100000000) /1000000;
+ g2 = (sqsum - g4*100000000 - g3*1000000) /10000;
+ g1 = (sqsum - g4*100000000 - g3*1000000 - g2*10000) /100;
+ g0 = (sqsum - g4*100000000 - g3*1000000 - g2*10000 - g1*100);
+
+ next = g4;
+ step = 0;
+ seed = 0;
+ while (((seed+1)*(step+1)) <= next)
+ {
+ step++;
+ seed++;
+ }
+
+ sq_rt = seed * 10000;
+ next = (next-(seed*step))*100 + g3;
+
+ step = 0;
+ seed = 2 * seed * 10;
+ while (((seed+1)*(step+1)) <= next)
+ {
+ step++;
+ seed++;
+ }
+
+ sq_rt = sq_rt + step * 1000;
+ next = (next - seed * step) * 100 + g2;
+ seed = (seed + step) * 10;
+ step = 0;
+ while (((seed+1)*(step+1)) <= next)
+ {
+ step++;
+ seed++;
+ }
+
+ sq_rt = sq_rt + step * 100;
+ next = (next - seed * step) * 100 + g1;
+ seed = (seed + step) * 10;
+ step = 0;
+
+ while (((seed+1)*(step+1)) <= next)
+ {
+ step++;
+ seed++;
+ }
+
+ sq_rt = sq_rt + step * 10;
+ next = (next - seed* step) * 100 + g0;
+ seed = (seed + step) * 10;
+ step = 0;
+
+ while (((seed+1)*(step+1)) <= next)
+ {
+ step++;
+ seed++;
+ }
+
+ sq_rt = sq_rt + step;
+
+ return sq_rt;
+}
+
+/****************************************************************************/
+void _sin_cos(s32 angle, s32 *sin, s32 *cos)
+{
+ fixed X, Y, TargetAngle, CurrAngle;
+ unsigned Step;
+
+ X=FIXED(AG_CONST); // AG_CONST * cos(0)
+ Y=0; // AG_CONST * sin(0)
+ TargetAngle=abs(angle);
+ CurrAngle=0;
+
+ for (Step=0; Step < 12; Step++)
+ {
+ fixed NewX;
+
+ if(TargetAngle > CurrAngle)
+ {
+ NewX=X - (Y >> Step);
+ Y=(X >> Step) + Y;
+ X=NewX;
+ CurrAngle += Angles[Step];
+ }
+ else
+ {
+ NewX=X + (Y >> Step);
+ Y=-(X >> Step) + Y;
+ X=NewX;
+ CurrAngle -= Angles[Step];
+ }
+ }
+
+ if (angle > 0)
+ {
+ *cos = X;
+ *sin = Y;
+ }
+ else
+ {
+ *cos = X;
+ *sin = -Y;
+ }
+}
+
+
+void _reset_rx_cal(hw_data_t *phw_data)
+{
+ u32 val;
+
+ hw_get_dxx_reg(phw_data, 0x54, &val);
+
+ if (phw_data->revision == 0x2002) // 1st-cut
+ {
+ val &= 0xFFFF0000;
+ }
+ else // 2nd-cut
+ {
+ val &= 0x000003FF;
+ }
+
+ hw_set_dxx_reg(phw_data, 0x54, val);
+}
+
+
+// ************for winbond calibration*********
+//
+
+//
+//
+// *********************************************
+void _rxadc_dc_offset_cancellation_winbond(hw_data_t *phw_data, u32 frequency)
+{
+ u32 reg_agc_ctrl3;
+ u32 reg_a_acq_ctrl;
+ u32 reg_b_acq_ctrl;
+ u32 val;
+
+ PHY_DEBUG(("[CAL] -> [1]_rxadc_dc_offset_cancellation()\n"));
+ phy_init_rf(phw_data);
+
+ // set calibration channel
+ if( (RF_WB_242 == phw_data->phy_type) ||
+ (RF_WB_242_1 == phw_data->phy_type) ) // 20060619.5 Add
+ {
+ if ((frequency >= 2412) && (frequency <= 2484))
+ {
+ // w89rf242 change frequency to 2390Mhz
+ PHY_DEBUG(("[CAL] W89RF242/11G/Channel=2390Mhz\n"));
+ phy_set_rf_data(phw_data, 3, (3<<24)|0x025586);
+
+ }
+ }
+ else
+ {
+
+ }
+
+ // reset cancel_dc_i[9:5] and cancel_dc_q[4:0] in register DC_Cancel
+ hw_get_dxx_reg(phw_data, 0x5C, &val);
+ val &= ~(0x03FF);
+ hw_set_dxx_reg(phw_data, 0x5C, val);
+
+ // reset the TX and RX IQ calibration data
+ hw_set_dxx_reg(phw_data, 0x3C, 0);
+ hw_set_dxx_reg(phw_data, 0x54, 0);
+
+ hw_set_dxx_reg(phw_data, 0x58, 0x30303030); // IQ_Alpha Changed
+
+ // a. Disable AGC
+ hw_get_dxx_reg(phw_data, REG_AGC_CTRL3, ®_agc_ctrl3);
+ reg_agc_ctrl3 &= ~BIT(2);
+ reg_agc_ctrl3 |= (MASK_LNA_FIX_GAIN|MASK_AGC_FIX);
+ hw_set_dxx_reg(phw_data, REG_AGC_CTRL3, reg_agc_ctrl3);
+
+ hw_get_dxx_reg(phw_data, REG_AGC_CTRL5, &val);
+ val |= MASK_AGC_FIX_GAIN;
+ hw_set_dxx_reg(phw_data, REG_AGC_CTRL5, val);
+
+ // b. Turn off BB RX
+ hw_get_dxx_reg(phw_data, REG_A_ACQ_CTRL, ®_a_acq_ctrl);
+ reg_a_acq_ctrl |= MASK_AMER_OFF_REG;
+ hw_set_dxx_reg(phw_data, REG_A_ACQ_CTRL, reg_a_acq_ctrl);
+
+ hw_get_dxx_reg(phw_data, REG_B_ACQ_CTRL, ®_b_acq_ctrl);
+ reg_b_acq_ctrl |= MASK_BMER_OFF_REG;
+ hw_set_dxx_reg(phw_data, REG_B_ACQ_CTRL, reg_b_acq_ctrl);
+
+ // c. Make sure MAC is in receiving mode
+ // d. Turn ON ADC calibration
+ // - ADC calibrator is triggered by this signal rising from 0 to 1
+ hw_get_dxx_reg(phw_data, REG_MODE_CTRL, &val);
+ val &= ~MASK_ADC_DC_CAL_STR;
+ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, val);
+
+ val |= MASK_ADC_DC_CAL_STR;
+ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, val);
+ pa_stall_execution(US); // *MUST* wait for a while
+
+ // e. The result are shown in "adc_dc_cal_i[8:0] and adc_dc_cal_q[8:0]"
+#ifdef _DEBUG
+ hw_get_dxx_reg(phw_data, REG_OFFSET_READ, &val);
+ PHY_DEBUG(("[CAL] REG_OFFSET_READ = 0x%08X\n", val));
+
+ PHY_DEBUG(("[CAL] ** adc_dc_cal_i = %d (0x%04X)\n",
+ _s9_to_s32(val&0x000001FF), val&0x000001FF));
+ PHY_DEBUG(("[CAL] ** adc_dc_cal_q = %d (0x%04X)\n",
+ _s9_to_s32((val&0x0003FE00)>>9), (val&0x0003FE00)>>9));
+#endif
+
+ hw_get_dxx_reg(phw_data, REG_MODE_CTRL, &val);
+ val &= ~MASK_ADC_DC_CAL_STR;
+ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, val);
+
+ // f. Turn on BB RX
+ //hw_get_dxx_reg(phw_data, REG_A_ACQ_CTRL, ®_a_acq_ctrl);
+ reg_a_acq_ctrl &= ~MASK_AMER_OFF_REG;
+ hw_set_dxx_reg(phw_data, REG_A_ACQ_CTRL, reg_a_acq_ctrl);
+
+ //hw_get_dxx_reg(phw_data, REG_B_ACQ_CTRL, ®_b_acq_ctrl);
+ reg_b_acq_ctrl &= ~MASK_BMER_OFF_REG;
+ hw_set_dxx_reg(phw_data, REG_B_ACQ_CTRL, reg_b_acq_ctrl);
+
+ // g. Enable AGC
+ //hw_get_dxx_reg(phw_data, REG_AGC_CTRL3, &val);
+ reg_agc_ctrl3 |= BIT(2);
+ reg_agc_ctrl3 &= ~(MASK_LNA_FIX_GAIN|MASK_AGC_FIX);
+ hw_set_dxx_reg(phw_data, REG_AGC_CTRL3, reg_agc_ctrl3);
+}
+
+////////////////////////////////////////////////////////
+void _txidac_dc_offset_cancellation_winbond(hw_data_t *phw_data)
+{
+ u32 reg_agc_ctrl3;
+ u32 reg_mode_ctrl;
+ u32 reg_dc_cancel;
+ s32 iqcal_image_i;
+ s32 iqcal_image_q;
+ u32 sqsum;
+ s32 mag_0;
+ s32 mag_1;
+ s32 fix_cancel_dc_i = 0;
+ u32 val;
+ int loop;
+
+ PHY_DEBUG(("[CAL] -> [2]_txidac_dc_offset_cancellation()\n"));
+
+ // a. Set to "TX calibration mode"
+
+ //0x01 0xEE3FC2 ; 3B8FF ; Calibration (6a). enable TX IQ calibration loop circuits
+ phy_set_rf_data(phw_data, 1, (1<<24)|0xEE3FC2);
+ //0x0B 0x1905D6 ; 06417 ; Calibration (6b). enable TX I/Q cal loop squaring circuit
+ phy_set_rf_data(phw_data, 11, (11<<24)|0x1901D6);
+ //0x05 0x24C60A ; 09318 ; Calibration (6c). setting TX-VGA gain: TXGCH=2 & GPK=110 --> to be optimized
+ phy_set_rf_data(phw_data, 5, (5<<24)|0x24C48A);
+ //0x06 0x06880C ; 01A20 ; Calibration (6d). RXGCH=00; RXGCL=100 000 (RXVGA=32) --> to be optimized
+ phy_set_rf_data(phw_data, 6, (6<<24)|0x06890C);
+ //0x00 0xFDF1C0 ; 3F7C7 ; Calibration (6e). turn on IQ imbalance/Test mode
+ phy_set_rf_data(phw_data, 0, (0<<24)|0xFDF1C0);
+
+ hw_set_dxx_reg(phw_data, 0x58, 0x30303030); // IQ_Alpha Changed
+
+ // a. Disable AGC
+ hw_get_dxx_reg(phw_data, REG_AGC_CTRL3, ®_agc_ctrl3);
+ reg_agc_ctrl3 &= ~BIT(2);
+ reg_agc_ctrl3 |= (MASK_LNA_FIX_GAIN|MASK_AGC_FIX);
+ hw_set_dxx_reg(phw_data, REG_AGC_CTRL3, reg_agc_ctrl3);
+
+ hw_get_dxx_reg(phw_data, REG_AGC_CTRL5, &val);
+ val |= MASK_AGC_FIX_GAIN;
+ hw_set_dxx_reg(phw_data, REG_AGC_CTRL5, val);
+
+ // b. set iqcal_mode[1:0] to 0x2 and set iqcal_tone[3:2] to 0
+ hw_get_dxx_reg(phw_data, REG_MODE_CTRL, ®_mode_ctrl);
+
+ PHY_DEBUG(("[CAL] MODE_CTRL (read) = 0x%08X\n", reg_mode_ctrl));
+ reg_mode_ctrl &= ~(MASK_IQCAL_TONE_SEL|MASK_IQCAL_MODE);
+
+ // mode=2, tone=0
+ //reg_mode_ctrl |= (MASK_CALIB_START|2);
+
+ // mode=2, tone=1
+ //reg_mode_ctrl |= (MASK_CALIB_START|2|(1<<2));
+
+ // mode=2, tone=2
+ reg_mode_ctrl |= (MASK_CALIB_START|2|(2<<2));
+ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl);
+ PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl));
+ pa_stall_execution(US);
+
+ hw_get_dxx_reg(phw_data, 0x5C, ®_dc_cancel);
+ PHY_DEBUG(("[CAL] DC_CANCEL (read) = 0x%08X\n", reg_dc_cancel));
+
+ for (loop = 0; loop < LOOP_TIMES; loop++)
+ {
+ PHY_DEBUG(("[CAL] [%d.] ==================================\n", loop));
+
+ // c.
+ // reset cancel_dc_i[9:5] and cancel_dc_q[4:0] in register DC_Cancel
+ reg_dc_cancel &= ~(0x03FF);
+ PHY_DEBUG(("[CAL] DC_CANCEL (write) = 0x%08X\n", reg_dc_cancel));
+ hw_set_dxx_reg(phw_data, 0x5C, reg_dc_cancel);
+ pa_stall_execution(US);
+
+ hw_get_dxx_reg(phw_data, REG_CALIB_READ2, &val);
+ PHY_DEBUG(("[CAL] CALIB_READ2 = 0x%08X\n", val));
+
+ iqcal_image_i = _s13_to_s32(val & 0x00001FFF);
+ iqcal_image_q = _s13_to_s32((val & 0x03FFE000) >> 13);
+ sqsum = iqcal_image_i*iqcal_image_i + iqcal_image_q*iqcal_image_q;
+ mag_0 = (s32) _sqrt(sqsum);
+ PHY_DEBUG(("[CAL] mag_0=%d (iqcal_image_i=%d, iqcal_image_q=%d)\n",
+ mag_0, iqcal_image_i, iqcal_image_q));
+
+ // d.
+ reg_dc_cancel |= (1 << CANCEL_DC_I_SHIFT);
+ PHY_DEBUG(("[CAL] DC_CANCEL (write) = 0x%08X\n", reg_dc_cancel));
+ hw_set_dxx_reg(phw_data, 0x5C, reg_dc_cancel);
+ pa_stall_execution(US);
+
+ hw_get_dxx_reg(phw_data, REG_CALIB_READ2, &val);
+ PHY_DEBUG(("[CAL] CALIB_READ2 = 0x%08X\n", val));
+
+ iqcal_image_i = _s13_to_s32(val & 0x00001FFF);
+ iqcal_image_q = _s13_to_s32((val & 0x03FFE000) >> 13);
+ sqsum = iqcal_image_i*iqcal_image_i + iqcal_image_q*iqcal_image_q;
+ mag_1 = (s32) _sqrt(sqsum);
+ PHY_DEBUG(("[CAL] mag_1=%d (iqcal_image_i=%d, iqcal_image_q=%d)\n",
+ mag_1, iqcal_image_i, iqcal_image_q));
+
+ // e. Calculate the correct DC offset cancellation value for I
+ if (mag_0 != mag_1)
+ {
+ fix_cancel_dc_i = (mag_0*10000) / (mag_0*10000 - mag_1*10000);
+ }
+ else
+ {
+ if (mag_0 == mag_1)
+ {
+ PHY_DEBUG(("[CAL] ***** mag_0 = mag_1 !!\n"));
+ }
+
+ fix_cancel_dc_i = 0;
+ }
+
+ PHY_DEBUG(("[CAL] ** fix_cancel_dc_i = %d (0x%04X)\n",
+ fix_cancel_dc_i, _s32_to_s5(fix_cancel_dc_i)));
+
+ if ((abs(mag_1-mag_0)*6) > mag_0)
+ {
+ break;
+ }
+ }
+
+ if ( loop >= 19 )
+ fix_cancel_dc_i = 0;
+
+ reg_dc_cancel &= ~(0x03FF);
+ reg_dc_cancel |= (_s32_to_s5(fix_cancel_dc_i) << CANCEL_DC_I_SHIFT);
+ hw_set_dxx_reg(phw_data, 0x5C, reg_dc_cancel);
+ PHY_DEBUG(("[CAL] DC_CANCEL (write) = 0x%08X\n", reg_dc_cancel));
+
+ // g.
+ reg_mode_ctrl &= ~MASK_CALIB_START;
+ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl);
+ PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl));
+ pa_stall_execution(US);
+}
+
+///////////////////////////////////////////////////////
+void _txqdac_dc_offset_cacellation_winbond(hw_data_t *phw_data)
+{
+ u32 reg_agc_ctrl3;
+ u32 reg_mode_ctrl;
+ u32 reg_dc_cancel;
+ s32 iqcal_image_i;
+ s32 iqcal_image_q;
+ u32 sqsum;
+ s32 mag_0;
+ s32 mag_1;
+ s32 fix_cancel_dc_q = 0;
+ u32 val;
+ int loop;
+
+ PHY_DEBUG(("[CAL] -> [3]_txqdac_dc_offset_cacellation()\n"));
+ //0x01 0xEE3FC2 ; 3B8FF ; Calibration (6a). enable TX IQ calibration loop circuits
+ phy_set_rf_data(phw_data, 1, (1<<24)|0xEE3FC2);
+ //0x0B 0x1905D6 ; 06417 ; Calibration (6b). enable TX I/Q cal loop squaring circuit
+ phy_set_rf_data(phw_data, 11, (11<<24)|0x1901D6);
+ //0x05 0x24C60A ; 09318 ; Calibration (6c). setting TX-VGA gain: TXGCH=2 & GPK=110 --> to be optimized
+ phy_set_rf_data(phw_data, 5, (5<<24)|0x24C48A);
+ //0x06 0x06880C ; 01A20 ; Calibration (6d). RXGCH=00; RXGCL=100 000 (RXVGA=32) --> to be optimized
+ phy_set_rf_data(phw_data, 6, (6<<24)|0x06890C);
+ //0x00 0xFDF1C0 ; 3F7C7 ; Calibration (6e). turn on IQ imbalance/Test mode
+ phy_set_rf_data(phw_data, 0, (0<<24)|0xFDF1C0);
+
+ hw_set_dxx_reg(phw_data, 0x58, 0x30303030); // IQ_Alpha Changed
+
+ // a. Disable AGC
+ hw_get_dxx_reg(phw_data, REG_AGC_CTRL3, ®_agc_ctrl3);
+ reg_agc_ctrl3 &= ~BIT(2);
+ reg_agc_ctrl3 |= (MASK_LNA_FIX_GAIN|MASK_AGC_FIX);
+ hw_set_dxx_reg(phw_data, REG_AGC_CTRL3, reg_agc_ctrl3);
+
+ hw_get_dxx_reg(phw_data, REG_AGC_CTRL5, &val);
+ val |= MASK_AGC_FIX_GAIN;
+ hw_set_dxx_reg(phw_data, REG_AGC_CTRL5, val);
+
+ // a. set iqcal_mode[1:0] to 0x3 and set iqcal_tone[3:2] to 0
+ hw_get_dxx_reg(phw_data, REG_MODE_CTRL, ®_mode_ctrl);
+ PHY_DEBUG(("[CAL] MODE_CTRL (read) = 0x%08X\n", reg_mode_ctrl));
+
+ //reg_mode_ctrl &= ~(MASK_IQCAL_TONE_SEL|MASK_IQCAL_MODE);
+ reg_mode_ctrl &= ~(MASK_IQCAL_MODE);
+ reg_mode_ctrl |= (MASK_CALIB_START|3);
+ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl);
+ PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl));
+ pa_stall_execution(US);
+
+ hw_get_dxx_reg(phw_data, 0x5C, ®_dc_cancel);
+ PHY_DEBUG(("[CAL] DC_CANCEL (read) = 0x%08X\n", reg_dc_cancel));
+
+ for (loop = 0; loop < LOOP_TIMES; loop++)
+ {
+ PHY_DEBUG(("[CAL] [%d.] ==================================\n", loop));
+
+ // b.
+ // reset cancel_dc_q[4:0] in register DC_Cancel
+ reg_dc_cancel &= ~(0x001F);
+ PHY_DEBUG(("[CAL] DC_CANCEL (write) = 0x%08X\n", reg_dc_cancel));
+ hw_set_dxx_reg(phw_data, 0x5C, reg_dc_cancel);
+ pa_stall_execution(US);
+
+ hw_get_dxx_reg(phw_data, REG_CALIB_READ2, &val);
+ PHY_DEBUG(("[CAL] CALIB_READ2 = 0x%08X\n", val));
+ pa_stall_execution(US);
+
+ iqcal_image_i = _s13_to_s32(val & 0x00001FFF);
+ iqcal_image_q = _s13_to_s32((val & 0x03FFE000) >> 13);
+ sqsum = iqcal_image_i*iqcal_image_i + iqcal_image_q*iqcal_image_q;
+ mag_0 = _sqrt(sqsum);
+ PHY_DEBUG(("[CAL] mag_0=%d (iqcal_image_i=%d, iqcal_image_q=%d)\n",
+ mag_0, iqcal_image_i, iqcal_image_q));
+
+ // c.
+ reg_dc_cancel |= (1 << CANCEL_DC_Q_SHIFT);
+ PHY_DEBUG(("[CAL] DC_CANCEL (write) = 0x%08X\n", reg_dc_cancel));
+ hw_set_dxx_reg(phw_data, 0x5C, reg_dc_cancel);
+ pa_stall_execution(US);
+
+ hw_get_dxx_reg(phw_data, REG_CALIB_READ2, &val);
+ PHY_DEBUG(("[CAL] CALIB_READ2 = 0x%08X\n", val));
+ pa_stall_execution(US);
+
+ iqcal_image_i = _s13_to_s32(val & 0x00001FFF);
+ iqcal_image_q = _s13_to_s32((val & 0x03FFE000) >> 13);
+ sqsum = iqcal_image_i*iqcal_image_i + iqcal_image_q*iqcal_image_q;
+ mag_1 = _sqrt(sqsum);
+ PHY_DEBUG(("[CAL] mag_1=%d (iqcal_image_i=%d, iqcal_image_q=%d)\n",
+ mag_1, iqcal_image_i, iqcal_image_q));
+
+ // d. Calculate the correct DC offset cancellation value for I
+ if (mag_0 != mag_1)
+ {
+ fix_cancel_dc_q = (mag_0*10000) / (mag_0*10000 - mag_1*10000);
+ }
+ else
+ {
+ if (mag_0 == mag_1)
+ {
+ PHY_DEBUG(("[CAL] ***** mag_0 = mag_1 !!\n"));
+ }
+
+ fix_cancel_dc_q = 0;
+ }
+
+ PHY_DEBUG(("[CAL] ** fix_cancel_dc_q = %d (0x%04X)\n",
+ fix_cancel_dc_q, _s32_to_s5(fix_cancel_dc_q)));
+
+ if ((abs(mag_1-mag_0)*6) > mag_0)
+ {
+ break;
+ }
+ }
+
+ if ( loop >= 19 )
+ fix_cancel_dc_q = 0;
+
+ reg_dc_cancel &= ~(0x001F);
+ reg_dc_cancel |= (_s32_to_s5(fix_cancel_dc_q) << CANCEL_DC_Q_SHIFT);
+ hw_set_dxx_reg(phw_data, 0x5C, reg_dc_cancel);
+ PHY_DEBUG(("[CAL] DC_CANCEL (write) = 0x%08X\n", reg_dc_cancel));
+
+
+ // f.
+ reg_mode_ctrl &= ~MASK_CALIB_START;
+ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl);
+ PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl));
+ pa_stall_execution(US);
+}
+
+//20060612.1.a 20060718.1 Modify
+u8 _tx_iq_calibration_loop_winbond(hw_data_t *phw_data,
+ s32 a_2_threshold,
+ s32 b_2_threshold)
+{
+ u32 reg_mode_ctrl;
+ s32 iq_mag_0_tx;
+ s32 iqcal_tone_i0;
+ s32 iqcal_tone_q0;
+ s32 iqcal_tone_i;
+ s32 iqcal_tone_q;
+ u32 sqsum;
+ s32 rot_i_b;
+ s32 rot_q_b;
+ s32 tx_cal_flt_b[4];
+ s32 tx_cal[4];
+ s32 tx_cal_reg[4];
+ s32 a_2, b_2;
+ s32 sin_b, sin_2b;
+ s32 cos_b, cos_2b;
+ s32 divisor;
+ s32 temp1, temp2;
+ u32 val;
+ u16 loop;
+ s32 iqcal_tone_i_avg,iqcal_tone_q_avg;
+ u8 verify_count;
+ int capture_time;
+
+ PHY_DEBUG(("[CAL] -> _tx_iq_calibration_loop()\n"));
+ PHY_DEBUG(("[CAL] ** a_2_threshold = %d\n", a_2_threshold));
+ PHY_DEBUG(("[CAL] ** b_2_threshold = %d\n", b_2_threshold));
+
+ verify_count = 0;
+
+ hw_get_dxx_reg(phw_data, REG_MODE_CTRL, ®_mode_ctrl);
+ PHY_DEBUG(("[CAL] MODE_CTRL (read) = 0x%08X\n", reg_mode_ctrl));
+
+ loop = LOOP_TIMES;
+
+ while (loop > 0)
+ {
+ PHY_DEBUG(("[CAL] [%d.] <_tx_iq_calibration_loop>\n", (LOOP_TIMES-loop+1)));
+
+ iqcal_tone_i_avg=0;
+ iqcal_tone_q_avg=0;
+ if( !hw_set_dxx_reg(phw_data, 0x3C, 0x00) ) // 20060718.1 modify
+ return 0;
+ for(capture_time=0;capture_time<10;capture_time++)
+ {
+ // a. Set iqcal_mode[1:0] to 0x2 and set "calib_start" to 0x1 to
+ // enable "IQ alibration Mode II"
+ reg_mode_ctrl &= ~(MASK_IQCAL_TONE_SEL|MASK_IQCAL_MODE);
+ reg_mode_ctrl &= ~MASK_IQCAL_MODE;
+ reg_mode_ctrl |= (MASK_CALIB_START|0x02);
+ reg_mode_ctrl |= (MASK_CALIB_START|0x02|2<<2);
+ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl);
+ PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl));
+ pa_stall_execution(US);
+
+ // b.
+ hw_get_dxx_reg(phw_data, REG_CALIB_READ1, &val);
+ PHY_DEBUG(("[CAL] CALIB_READ1 = 0x%08X\n", val));
+ pa_stall_execution(US);
+
+ iqcal_tone_i0 = _s13_to_s32(val & 0x00001FFF);
+ iqcal_tone_q0 = _s13_to_s32((val & 0x03FFE000) >> 13);
+ PHY_DEBUG(("[CAL] ** iqcal_tone_i0=%d, iqcal_tone_q0=%d\n",
+ iqcal_tone_i0, iqcal_tone_q0));
+
+ sqsum = iqcal_tone_i0*iqcal_tone_i0 +
+ iqcal_tone_q0*iqcal_tone_q0;
+ iq_mag_0_tx = (s32) _sqrt(sqsum);
+ PHY_DEBUG(("[CAL] ** iq_mag_0_tx=%d\n", iq_mag_0_tx));
+
+ // c. Set "calib_start" to 0x0
+ reg_mode_ctrl &= ~MASK_CALIB_START;
+ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl);
+ PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl));
+ pa_stall_execution(US);
+
+ // d. Set iqcal_mode[1:0] to 0x3 and set "calib_start" to 0x1 to
+ // enable "IQ alibration Mode II"
+ //hw_get_dxx_reg(phw_data, REG_MODE_CTRL, &val);
+ hw_get_dxx_reg(phw_data, REG_MODE_CTRL, ®_mode_ctrl);
+ reg_mode_ctrl &= ~MASK_IQCAL_MODE;
+ reg_mode_ctrl |= (MASK_CALIB_START|0x03);
+ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl);
+ PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl));
+ pa_stall_execution(US);
+
+ // e.
+ hw_get_dxx_reg(phw_data, REG_CALIB_READ1, &val);
+ PHY_DEBUG(("[CAL] CALIB_READ1 = 0x%08X\n", val));
+ pa_stall_execution(US);
+
+ iqcal_tone_i = _s13_to_s32(val & 0x00001FFF);
+ iqcal_tone_q = _s13_to_s32((val & 0x03FFE000) >> 13);
+ PHY_DEBUG(("[CAL] ** iqcal_tone_i = %d, iqcal_tone_q = %d\n",
+ iqcal_tone_i, iqcal_tone_q));
+ if( capture_time == 0)
+ {
+ continue;
+ }
+ else
+ {
+ iqcal_tone_i_avg=( iqcal_tone_i_avg*(capture_time-1) +iqcal_tone_i)/capture_time;
+ iqcal_tone_q_avg=( iqcal_tone_q_avg*(capture_time-1) +iqcal_tone_q)/capture_time;
+ }
+ }
+
+ iqcal_tone_i = iqcal_tone_i_avg;
+ iqcal_tone_q = iqcal_tone_q_avg;
+
+
+ rot_i_b = (iqcal_tone_i * iqcal_tone_i0 +
+ iqcal_tone_q * iqcal_tone_q0) / 1024;
+ rot_q_b = (iqcal_tone_i * iqcal_tone_q0 * (-1) +
+ iqcal_tone_q * iqcal_tone_i0) / 1024;
+ PHY_DEBUG(("[CAL] ** rot_i_b = %d, rot_q_b = %d\n",
+ rot_i_b, rot_q_b));
+
+ // f.
+ divisor = ((iq_mag_0_tx * iq_mag_0_tx * 2)/1024 - rot_i_b) * 2;
+
+ if (divisor == 0)
+ {
+ PHY_DEBUG(("[CAL] ** <_tx_iq_calibration_loop> ERROR *******\n"));
+ PHY_DEBUG(("[CAL] ** divisor=0 to calculate EPS and THETA !!\n"));
+ PHY_DEBUG(("[CAL] ******************************************\n"));
+ break;
+ }
+
+ a_2 = (rot_i_b * 32768) / divisor;
+ b_2 = (rot_q_b * (-32768)) / divisor;
+ PHY_DEBUG(("[CAL] ***** EPSILON/2 = %d\n", a_2));
+ PHY_DEBUG(("[CAL] ***** THETA/2 = %d\n", b_2));
+
+ phw_data->iq_rsdl_gain_tx_d2 = a_2;
+ phw_data->iq_rsdl_phase_tx_d2 = b_2;
+
+ //if ((abs(a_2) < 150) && (abs(b_2) < 100))
+ //if ((abs(a_2) < 200) && (abs(b_2) < 200))
+ if ((abs(a_2) < a_2_threshold) && (abs(b_2) < b_2_threshold))
+ {
+ verify_count++;
+
+ PHY_DEBUG(("[CAL] ** <_tx_iq_calibration_loop> *************\n"));
+ PHY_DEBUG(("[CAL] ** VERIFY OK # %d !!\n", verify_count));
+ PHY_DEBUG(("[CAL] ******************************************\n"));
+
+ if (verify_count > 2)
+ {
+ PHY_DEBUG(("[CAL] ** <_tx_iq_calibration_loop> *********\n"));
+ PHY_DEBUG(("[CAL] ** TX_IQ_CALIBRATION (EPS,THETA) OK !!\n"));
+ PHY_DEBUG(("[CAL] **************************************\n"));
+ return 0;
+ }
+
+ continue;
+ }
+ else
+ {
+ verify_count = 0;
+ }
+
+ _sin_cos(b_2, &sin_b, &cos_b);
+ _sin_cos(b_2*2, &sin_2b, &cos_2b);
+ PHY_DEBUG(("[CAL] ** sin(b/2)=%d, cos(b/2)=%d\n", sin_b, cos_b));
+ PHY_DEBUG(("[CAL] ** sin(b)=%d, cos(b)=%d\n", sin_2b, cos_2b));
+
+ if (cos_2b == 0)
+ {
+ PHY_DEBUG(("[CAL] ** <_tx_iq_calibration_loop> ERROR *******\n"));
+ PHY_DEBUG(("[CAL] ** cos(b)=0 !!\n"));
+ PHY_DEBUG(("[CAL] ******************************************\n"));
+ break;
+ }
+
+ // 1280 * 32768 = 41943040
+ temp1 = (41943040/cos_2b)*cos_b;
+
+ //temp2 = (41943040/cos_2b)*sin_b*(-1);
+ if (phw_data->revision == 0x2002) // 1st-cut
+ {
+ temp2 = (41943040/cos_2b)*sin_b*(-1);
+ }
+ else // 2nd-cut
+ {
+ temp2 = (41943040*4/cos_2b)*sin_b*(-1);
+ }
+
+ tx_cal_flt_b[0] = _floor(temp1/(32768+a_2));
+ tx_cal_flt_b[1] = _floor(temp2/(32768+a_2));
+ tx_cal_flt_b[2] = _floor(temp2/(32768-a_2));
+ tx_cal_flt_b[3] = _floor(temp1/(32768-a_2));
+ PHY_DEBUG(("[CAL] ** tx_cal_flt_b[0] = %d\n", tx_cal_flt_b[0]));
+ PHY_DEBUG(("[CAL] tx_cal_flt_b[1] = %d\n", tx_cal_flt_b[1]));
+ PHY_DEBUG(("[CAL] tx_cal_flt_b[2] = %d\n", tx_cal_flt_b[2]));
+ PHY_DEBUG(("[CAL] tx_cal_flt_b[3] = %d\n", tx_cal_flt_b[3]));
+
+ tx_cal[2] = tx_cal_flt_b[2];
+ tx_cal[2] = tx_cal[2] +3;
+ tx_cal[1] = tx_cal[2];
+ tx_cal[3] = tx_cal_flt_b[3] - 128;
+ tx_cal[0] = -tx_cal[3]+1;
+
+ PHY_DEBUG(("[CAL] tx_cal[0] = %d\n", tx_cal[0]));
+ PHY_DEBUG(("[CAL] tx_cal[1] = %d\n", tx_cal[1]));
+ PHY_DEBUG(("[CAL] tx_cal[2] = %d\n", tx_cal[2]));
+ PHY_DEBUG(("[CAL] tx_cal[3] = %d\n", tx_cal[3]));
+
+ //if ((tx_cal[0] == 0) && (tx_cal[1] == 0) &&
+ // (tx_cal[2] == 0) && (tx_cal[3] == 0))
+ //{
+ // PHY_DEBUG(("[CAL] ** <_tx_iq_calibration_loop> *************\n"));
+ // PHY_DEBUG(("[CAL] ** TX_IQ_CALIBRATION COMPLETE !!\n"));
+ // PHY_DEBUG(("[CAL] ******************************************\n"));
+ // return 0;
+ //}
+
+ // g.
+ if (phw_data->revision == 0x2002) // 1st-cut
+ {
+ hw_get_dxx_reg(phw_data, 0x54, &val);
+ PHY_DEBUG(("[CAL] ** 0x54 = 0x%08X\n", val));
+ tx_cal_reg[0] = _s4_to_s32((val & 0xF0000000) >> 28);
+ tx_cal_reg[1] = _s4_to_s32((val & 0x0F000000) >> 24);
+ tx_cal_reg[2] = _s4_to_s32((val & 0x00F00000) >> 20);
+ tx_cal_reg[3] = _s4_to_s32((val & 0x000F0000) >> 16);
+ }
+ else // 2nd-cut
+ {
+ hw_get_dxx_reg(phw_data, 0x3C, &val);
+ PHY_DEBUG(("[CAL] ** 0x3C = 0x%08X\n", val));
+ tx_cal_reg[0] = _s5_to_s32((val & 0xF8000000) >> 27);
+ tx_cal_reg[1] = _s6_to_s32((val & 0x07E00000) >> 21);
+ tx_cal_reg[2] = _s6_to_s32((val & 0x001F8000) >> 15);
+ tx_cal_reg[3] = _s5_to_s32((val & 0x00007C00) >> 10);
+
+ }
+
+ PHY_DEBUG(("[CAL] ** tx_cal_reg[0] = %d\n", tx_cal_reg[0]));
+ PHY_DEBUG(("[CAL] tx_cal_reg[1] = %d\n", tx_cal_reg[1]));
+ PHY_DEBUG(("[CAL] tx_cal_reg[2] = %d\n", tx_cal_reg[2]));
+ PHY_DEBUG(("[CAL] tx_cal_reg[3] = %d\n", tx_cal_reg[3]));
+
+ if (phw_data->revision == 0x2002) // 1st-cut
+ {
+ if (((tx_cal_reg[0]==7) || (tx_cal_reg[0]==(-8))) &&
+ ((tx_cal_reg[3]==7) || (tx_cal_reg[3]==(-8))))
+ {
+ PHY_DEBUG(("[CAL] ** <_tx_iq_calibration_loop> *********\n"));
+ PHY_DEBUG(("[CAL] ** TX_IQ_CALIBRATION SATUATION !!\n"));
+ PHY_DEBUG(("[CAL] **************************************\n"));
+ break;
+ }
+ }
+ else // 2nd-cut
+ {
+ if (((tx_cal_reg[0]==31) || (tx_cal_reg[0]==(-32))) &&
+ ((tx_cal_reg[3]==31) || (tx_cal_reg[3]==(-32))))
+ {
+ PHY_DEBUG(("[CAL] ** <_tx_iq_calibration_loop> *********\n"));
+ PHY_DEBUG(("[CAL] ** TX_IQ_CALIBRATION SATUATION !!\n"));
+ PHY_DEBUG(("[CAL] **************************************\n"));
+ break;
+ }
+ }
+
+ tx_cal[0] = tx_cal[0] + tx_cal_reg[0];
+ tx_cal[1] = tx_cal[1] + tx_cal_reg[1];
+ tx_cal[2] = tx_cal[2] + tx_cal_reg[2];
+ tx_cal[3] = tx_cal[3] + tx_cal_reg[3];
+ PHY_DEBUG(("[CAL] ** apply tx_cal[0] = %d\n", tx_cal[0]));
+ PHY_DEBUG(("[CAL] apply tx_cal[1] = %d\n", tx_cal[1]));
+ PHY_DEBUG(("[CAL] apply tx_cal[2] = %d\n", tx_cal[2]));
+ PHY_DEBUG(("[CAL] apply tx_cal[3] = %d\n", tx_cal[3]));
+
+ if (phw_data->revision == 0x2002) // 1st-cut
+ {
+ val &= 0x0000FFFF;
+ val |= ((_s32_to_s4(tx_cal[0]) << 28)|
+ (_s32_to_s4(tx_cal[1]) << 24)|
+ (_s32_to_s4(tx_cal[2]) << 20)|
+ (_s32_to_s4(tx_cal[3]) << 16));
+ hw_set_dxx_reg(phw_data, 0x54, val);
+ PHY_DEBUG(("[CAL] ** CALIB_DATA = 0x%08X\n", val));
+ return 0;
+ }
+ else // 2nd-cut
+ {
+ val &= 0x000003FF;
+ val |= ((_s32_to_s5(tx_cal[0]) << 27)|
+ (_s32_to_s6(tx_cal[1]) << 21)|
+ (_s32_to_s6(tx_cal[2]) << 15)|
+ (_s32_to_s5(tx_cal[3]) << 10));
+ hw_set_dxx_reg(phw_data, 0x3C, val);
+ PHY_DEBUG(("[CAL] ** TX_IQ_CALIBRATION = 0x%08X\n", val));
+ return 0;
+ }
+
+ // i. Set "calib_start" to 0x0
+ reg_mode_ctrl &= ~MASK_CALIB_START;
+ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl);
+ PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl));
+
+ loop--;
+ }
+
+ return 1;
+}
+
+void _tx_iq_calibration_winbond(hw_data_t *phw_data)
+{
+ u32 reg_agc_ctrl3;
+#ifdef _DEBUG
+ s32 tx_cal_reg[4];
+
+#endif
+ u32 reg_mode_ctrl;
+ u32 val;
+ u8 result;
+
+ PHY_DEBUG(("[CAL] -> [4]_tx_iq_calibration()\n"));
+
+ //0x01 0xEE3FC2 ; 3B8FF ; Calibration (6a). enable TX IQ calibration loop circuits
+ phy_set_rf_data(phw_data, 1, (1<<24)|0xEE3FC2);
+ //0x0B 0x1905D6 ; 06417 ; Calibration (6b). enable TX I/Q cal loop squaring circuit
+ phy_set_rf_data(phw_data, 11, (11<<24)|0x19BDD6); // 20060612.1.a 0x1905D6);
+ //0x05 0x24C60A ; 09318 ; Calibration (6c). setting TX-VGA gain: TXGCH=2 & GPK=110 --> to be optimized
+ phy_set_rf_data(phw_data, 5, (5<<24)|0x24C60A); //0x24C60A (high temperature)
+ //0x06 0x06880C ; 01A20 ; Calibration (6d). RXGCH=00; RXGCL=100 000 (RXVGA=32) --> to be optimized
+ phy_set_rf_data(phw_data, 6, (6<<24)|0x34880C); // 20060612.1.a 0x06890C);
+ //0x00 0xFDF1C0 ; 3F7C7 ; Calibration (6e). turn on IQ imbalance/Test mode
+ phy_set_rf_data(phw_data, 0, (0<<24)|0xFDF1C0);
+ //; [BB-chip]: Calibration (6f).Send test pattern
+ //; [BB-chip]: Calibration (6g). Search RXGCL optimal value
+ //; [BB-chip]: Calibration (6h). Caculate TX-path IQ imbalance and setting TX path IQ compensation table
+ //phy_set_rf_data(phw_data, 3, (3<<24)|0x025586);
+
+ OS_SLEEP(30000); // 20060612.1.a 30ms delay. Add the follow 2 lines
+ //To adjust TXVGA to fit iq_mag_0 range from 1250 ~ 1750
+ adjust_TXVGA_for_iq_mag( phw_data );
+
+ // a. Disable AGC
+ hw_get_dxx_reg(phw_data, REG_AGC_CTRL3, ®_agc_ctrl3);
+ reg_agc_ctrl3 &= ~BIT(2);
+ reg_agc_ctrl3 |= (MASK_LNA_FIX_GAIN|MASK_AGC_FIX);
+ hw_set_dxx_reg(phw_data, REG_AGC_CTRL3, reg_agc_ctrl3);
+
+ hw_get_dxx_reg(phw_data, REG_AGC_CTRL5, &val);
+ val |= MASK_AGC_FIX_GAIN;
+ hw_set_dxx_reg(phw_data, REG_AGC_CTRL5, val);
+
+ result = _tx_iq_calibration_loop_winbond(phw_data, 150, 100);
+
+ if (result > 0)
+ {
+ if (phw_data->revision == 0x2002) // 1st-cut
+ {
+ hw_get_dxx_reg(phw_data, 0x54, &val);
+ val &= 0x0000FFFF;
+ hw_set_dxx_reg(phw_data, 0x54, val);
+ }
+ else // 2nd-cut
+ {
+ hw_get_dxx_reg(phw_data, 0x3C, &val);
+ val &= 0x000003FF;
+ hw_set_dxx_reg(phw_data, 0x3C, val);
+ }
+
+ result = _tx_iq_calibration_loop_winbond(phw_data, 300, 200);
+
+ if (result > 0)
+ {
+ if (phw_data->revision == 0x2002) // 1st-cut
+ {
+ hw_get_dxx_reg(phw_data, 0x54, &val);
+ val &= 0x0000FFFF;
+ hw_set_dxx_reg(phw_data, 0x54, val);
+ }
+ else // 2nd-cut
+ {
+ hw_get_dxx_reg(phw_data, 0x3C, &val);
+ val &= 0x000003FF;
+ hw_set_dxx_reg(phw_data, 0x3C, val);
+ }
+
+ result = _tx_iq_calibration_loop_winbond(phw_data, 500, 400);
+ if (result > 0)
+ {
+ if (phw_data->revision == 0x2002) // 1st-cut
+ {
+ hw_get_dxx_reg(phw_data, 0x54, &val);
+ val &= 0x0000FFFF;
+ hw_set_dxx_reg(phw_data, 0x54, val);
+ }
+ else // 2nd-cut
+ {
+ hw_get_dxx_reg(phw_data, 0x3C, &val);
+ val &= 0x000003FF;
+ hw_set_dxx_reg(phw_data, 0x3C, val);
+ }
+
+
+ result = _tx_iq_calibration_loop_winbond(phw_data, 700, 500);
+
+ if (result > 0)
+ {
+ PHY_DEBUG(("[CAL] ** <_tx_iq_calibration> **************\n"));
+ PHY_DEBUG(("[CAL] ** TX_IQ_CALIBRATION FAILURE !!\n"));
+ PHY_DEBUG(("[CAL] **************************************\n"));
+
+ if (phw_data->revision == 0x2002) // 1st-cut
+ {
+ hw_get_dxx_reg(phw_data, 0x54, &val);
+ val &= 0x0000FFFF;
+ hw_set_dxx_reg(phw_data, 0x54, val);
+ }
+ else // 2nd-cut
+ {
+ hw_get_dxx_reg(phw_data, 0x3C, &val);
+ val &= 0x000003FF;
+ hw_set_dxx_reg(phw_data, 0x3C, val);
+ }
+ }
+ }
+ }
+ }
+
+ // i. Set "calib_start" to 0x0
+ hw_get_dxx_reg(phw_data, REG_MODE_CTRL, ®_mode_ctrl);
+ reg_mode_ctrl &= ~MASK_CALIB_START;
+ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl);
+ PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl));
+
+ // g. Enable AGC
+ //hw_get_dxx_reg(phw_data, REG_AGC_CTRL3, &val);
+ reg_agc_ctrl3 |= BIT(2);
+ reg_agc_ctrl3 &= ~(MASK_LNA_FIX_GAIN|MASK_AGC_FIX);
+ hw_set_dxx_reg(phw_data, REG_AGC_CTRL3, reg_agc_ctrl3);
+
+#ifdef _DEBUG
+ if (phw_data->revision == 0x2002) // 1st-cut
+ {
+ hw_get_dxx_reg(phw_data, 0x54, &val);
+ PHY_DEBUG(("[CAL] ** 0x54 = 0x%08X\n", val));
+ tx_cal_reg[0] = _s4_to_s32((val & 0xF0000000) >> 28);
+ tx_cal_reg[1] = _s4_to_s32((val & 0x0F000000) >> 24);
+ tx_cal_reg[2] = _s4_to_s32((val & 0x00F00000) >> 20);
+ tx_cal_reg[3] = _s4_to_s32((val & 0x000F0000) >> 16);
+ }
+ else // 2nd-cut
+ {
+ hw_get_dxx_reg(phw_data, 0x3C, &val);
+ PHY_DEBUG(("[CAL] ** 0x3C = 0x%08X\n", val));
+ tx_cal_reg[0] = _s5_to_s32((val & 0xF8000000) >> 27);
+ tx_cal_reg[1] = _s6_to_s32((val & 0x07E00000) >> 21);
+ tx_cal_reg[2] = _s6_to_s32((val & 0x001F8000) >> 15);
+ tx_cal_reg[3] = _s5_to_s32((val & 0x00007C00) >> 10);
+
+ }
+
+ PHY_DEBUG(("[CAL] ** tx_cal_reg[0] = %d\n", tx_cal_reg[0]));
+ PHY_DEBUG(("[CAL] tx_cal_reg[1] = %d\n", tx_cal_reg[1]));
+ PHY_DEBUG(("[CAL] tx_cal_reg[2] = %d\n", tx_cal_reg[2]));
+ PHY_DEBUG(("[CAL] tx_cal_reg[3] = %d\n", tx_cal_reg[3]));
+#endif
+
+
+ // for test - BEN
+ // RF Control Override
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+u8 _rx_iq_calibration_loop_winbond(hw_data_t *phw_data, u16 factor, u32 frequency)
+{
+ u32 reg_mode_ctrl;
+ s32 iqcal_tone_i;
+ s32 iqcal_tone_q;
+ s32 iqcal_image_i;
+ s32 iqcal_image_q;
+ s32 rot_tone_i_b;
+ s32 rot_tone_q_b;
+ s32 rot_image_i_b;
+ s32 rot_image_q_b;
+ s32 rx_cal_flt_b[4];
+ s32 rx_cal[4];
+ s32 rx_cal_reg[4];
+ s32 a_2, b_2;
+ s32 sin_b, sin_2b;
+ s32 cos_b, cos_2b;
+ s32 temp1, temp2;
+ u32 val;
+ u16 loop;
+
+ u32 pwr_tone;
+ u32 pwr_image;
+ u8 verify_count;
+
+ s32 iqcal_tone_i_avg,iqcal_tone_q_avg;
+ s32 iqcal_image_i_avg,iqcal_image_q_avg;
+ u16 capture_time;
+
+ PHY_DEBUG(("[CAL] -> [5]_rx_iq_calibration_loop()\n"));
+ PHY_DEBUG(("[CAL] ** factor = %d\n", factor));
+
+
+// RF Control Override
+ hw_get_cxx_reg(phw_data, 0x80, &val);
+ val |= BIT(19);
+ hw_set_cxx_reg(phw_data, 0x80, val);
+
+// RF_Ctrl
+ hw_get_cxx_reg(phw_data, 0xE4, &val);
+ val |= BIT(0);
+ hw_set_cxx_reg(phw_data, 0xE4, val);
+ PHY_DEBUG(("[CAL] ** RF_CTRL(0xE4) = 0x%08X", val));
+
+ hw_set_dxx_reg(phw_data, 0x58, 0x44444444); // IQ_Alpha
+
+ // b.
+
+ hw_get_dxx_reg(phw_data, REG_MODE_CTRL, ®_mode_ctrl);
+ PHY_DEBUG(("[CAL] MODE_CTRL (read) = 0x%08X\n", reg_mode_ctrl));
+
+ verify_count = 0;
+
+ //for (loop = 0; loop < 1; loop++)
+ //for (loop = 0; loop < LOOP_TIMES; loop++)
+ loop = LOOP_TIMES;
+ while (loop > 0)
+ {
+ PHY_DEBUG(("[CAL] [%d.] <_rx_iq_calibration_loop>\n", (LOOP_TIMES-loop+1)));
+ iqcal_tone_i_avg=0;
+ iqcal_tone_q_avg=0;
+ iqcal_image_i_avg=0;
+ iqcal_image_q_avg=0;
+ capture_time=0;
+
+ for(capture_time=0; capture_time<10; capture_time++)
+ {
+ // i. Set "calib_start" to 0x0
+ reg_mode_ctrl &= ~MASK_CALIB_START;
+ if( !hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl) )//20060718.1 modify
+ return 0;
+ PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl));
+ pa_stall_execution(US);
+
+ reg_mode_ctrl &= ~MASK_IQCAL_MODE;
+ reg_mode_ctrl |= (MASK_CALIB_START|0x1);
+ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl);
+ PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl));
+ pa_stall_execution(US); //Should be read out after 450us
+
+ // c.
+ hw_get_dxx_reg(phw_data, REG_CALIB_READ1, &val);
+ PHY_DEBUG(("[CAL] CALIB_READ1 = 0x%08X\n", val));
+
+ iqcal_tone_i = _s13_to_s32(val & 0x00001FFF);
+ iqcal_tone_q = _s13_to_s32((val & 0x03FFE000) >> 13);
+ PHY_DEBUG(("[CAL] ** iqcal_tone_i = %d, iqcal_tone_q = %d\n",
+ iqcal_tone_i, iqcal_tone_q));
+
+ hw_get_dxx_reg(phw_data, REG_CALIB_READ2, &val);
+ PHY_DEBUG(("[CAL] CALIB_READ2 = 0x%08X\n", val));
+
+ iqcal_image_i = _s13_to_s32(val & 0x00001FFF);
+ iqcal_image_q = _s13_to_s32((val & 0x03FFE000) >> 13);
+ PHY_DEBUG(("[CAL] ** iqcal_image_i = %d, iqcal_image_q = %d\n",
+ iqcal_image_i, iqcal_image_q));
+ if( capture_time == 0)
+ {
+ continue;
+ }
+ else
+ {
+ iqcal_image_i_avg=( iqcal_image_i_avg*(capture_time-1) +iqcal_image_i)/capture_time;
+ iqcal_image_q_avg=( iqcal_image_q_avg*(capture_time-1) +iqcal_image_q)/capture_time;
+ iqcal_tone_i_avg=( iqcal_tone_i_avg*(capture_time-1) +iqcal_tone_i)/capture_time;
+ iqcal_tone_q_avg=( iqcal_tone_q_avg*(capture_time-1) +iqcal_tone_q)/capture_time;
+ }
+ }
+
+
+ iqcal_image_i = iqcal_image_i_avg;
+ iqcal_image_q = iqcal_image_q_avg;
+ iqcal_tone_i = iqcal_tone_i_avg;
+ iqcal_tone_q = iqcal_tone_q_avg;
+
+ // d.
+ rot_tone_i_b = (iqcal_tone_i * iqcal_tone_i +
+ iqcal_tone_q * iqcal_tone_q) / 1024;
+ rot_tone_q_b = (iqcal_tone_i * iqcal_tone_q * (-1) +
+ iqcal_tone_q * iqcal_tone_i) / 1024;
+ rot_image_i_b = (iqcal_image_i * iqcal_tone_i -
+ iqcal_image_q * iqcal_tone_q) / 1024;
+ rot_image_q_b = (iqcal_image_i * iqcal_tone_q +
+ iqcal_image_q * iqcal_tone_i) / 1024;
+
+ PHY_DEBUG(("[CAL] ** rot_tone_i_b = %d\n", rot_tone_i_b));
+ PHY_DEBUG(("[CAL] ** rot_tone_q_b = %d\n", rot_tone_q_b));
+ PHY_DEBUG(("[CAL] ** rot_image_i_b = %d\n", rot_image_i_b));
+ PHY_DEBUG(("[CAL] ** rot_image_q_b = %d\n", rot_image_q_b));
+
+ // f.
+ if (rot_tone_i_b == 0)
+ {
+ PHY_DEBUG(("[CAL] ** <_rx_iq_calibration_loop> ERROR *******\n"));
+ PHY_DEBUG(("[CAL] ** rot_tone_i_b=0 to calculate EPS and THETA !!\n"));
+ PHY_DEBUG(("[CAL] ******************************************\n"));
+ break;
+ }
+
+ a_2 = (rot_image_i_b * 32768) / rot_tone_i_b -
+ phw_data->iq_rsdl_gain_tx_d2;
+ b_2 = (rot_image_q_b * 32768) / rot_tone_i_b -
+ phw_data->iq_rsdl_phase_tx_d2;
+
+ PHY_DEBUG(("[CAL] ** iq_rsdl_gain_tx_d2 = %d\n", phw_data->iq_rsdl_gain_tx_d2));
+ PHY_DEBUG(("[CAL] ** iq_rsdl_phase_tx_d2= %d\n", phw_data->iq_rsdl_phase_tx_d2));
+ PHY_DEBUG(("[CAL] ***** EPSILON/2 = %d\n", a_2));
+ PHY_DEBUG(("[CAL] ***** THETA/2 = %d\n", b_2));
+
+ _sin_cos(b_2, &sin_b, &cos_b);
+ _sin_cos(b_2*2, &sin_2b, &cos_2b);
+ PHY_DEBUG(("[CAL] ** sin(b/2)=%d, cos(b/2)=%d\n", sin_b, cos_b));
+ PHY_DEBUG(("[CAL] ** sin(b)=%d, cos(b)=%d\n", sin_2b, cos_2b));
+
+ if (cos_2b == 0)
+ {
+ PHY_DEBUG(("[CAL] ** <_rx_iq_calibration_loop> ERROR *******\n"));
+ PHY_DEBUG(("[CAL] ** cos(b)=0 !!\n"));
+ PHY_DEBUG(("[CAL] ******************************************\n"));
+ break;
+ }
+
+ // 1280 * 32768 = 41943040
+ temp1 = (41943040/cos_2b)*cos_b;
+
+ //temp2 = (41943040/cos_2b)*sin_b*(-1);
+ if (phw_data->revision == 0x2002) // 1st-cut
+ {
+ temp2 = (41943040/cos_2b)*sin_b*(-1);
+ }
+ else // 2nd-cut
+ {
+ temp2 = (41943040*4/cos_2b)*sin_b*(-1);
+ }
+
+ rx_cal_flt_b[0] = _floor(temp1/(32768+a_2));
+ rx_cal_flt_b[1] = _floor(temp2/(32768-a_2));
+ rx_cal_flt_b[2] = _floor(temp2/(32768+a_2));
+ rx_cal_flt_b[3] = _floor(temp1/(32768-a_2));
+
+ PHY_DEBUG(("[CAL] ** rx_cal_flt_b[0] = %d\n", rx_cal_flt_b[0]));
+ PHY_DEBUG(("[CAL] rx_cal_flt_b[1] = %d\n", rx_cal_flt_b[1]));
+ PHY_DEBUG(("[CAL] rx_cal_flt_b[2] = %d\n", rx_cal_flt_b[2]));
+ PHY_DEBUG(("[CAL] rx_cal_flt_b[3] = %d\n", rx_cal_flt_b[3]));
+
+ rx_cal[0] = rx_cal_flt_b[0] - 128;
+ rx_cal[1] = rx_cal_flt_b[1];
+ rx_cal[2] = rx_cal_flt_b[2];
+ rx_cal[3] = rx_cal_flt_b[3] - 128;
+ PHY_DEBUG(("[CAL] ** rx_cal[0] = %d\n", rx_cal[0]));
+ PHY_DEBUG(("[CAL] rx_cal[1] = %d\n", rx_cal[1]));
+ PHY_DEBUG(("[CAL] rx_cal[2] = %d\n", rx_cal[2]));
+ PHY_DEBUG(("[CAL] rx_cal[3] = %d\n", rx_cal[3]));
+
+ // e.
+ pwr_tone = (iqcal_tone_i*iqcal_tone_i + iqcal_tone_q*iqcal_tone_q);
+ pwr_image = (iqcal_image_i*iqcal_image_i + iqcal_image_q*iqcal_image_q)*factor;
+
+ PHY_DEBUG(("[CAL] ** pwr_tone = %d\n", pwr_tone));
+ PHY_DEBUG(("[CAL] ** pwr_image = %d\n", pwr_image));
+
+ if (pwr_tone > pwr_image)
+ {
+ verify_count++;
+
+ PHY_DEBUG(("[CAL] ** <_rx_iq_calibration_loop> *************\n"));
+ PHY_DEBUG(("[CAL] ** VERIFY OK # %d !!\n", verify_count));
+ PHY_DEBUG(("[CAL] ******************************************\n"));
+
+ if (verify_count > 2)
+ {
+ PHY_DEBUG(("[CAL] ** <_rx_iq_calibration_loop> *********\n"));
+ PHY_DEBUG(("[CAL] ** RX_IQ_CALIBRATION OK !!\n"));
+ PHY_DEBUG(("[CAL] **************************************\n"));
+ return 0;
+ }
+
+ continue;
+ }
+ // g.
+ hw_get_dxx_reg(phw_data, 0x54, &val);
+ PHY_DEBUG(("[CAL] ** 0x54 = 0x%08X\n", val));
+
+ if (phw_data->revision == 0x2002) // 1st-cut
+ {
+ rx_cal_reg[0] = _s4_to_s32((val & 0x0000F000) >> 12);
+ rx_cal_reg[1] = _s4_to_s32((val & 0x00000F00) >> 8);
+ rx_cal_reg[2] = _s4_to_s32((val & 0x000000F0) >> 4);
+ rx_cal_reg[3] = _s4_to_s32((val & 0x0000000F));
+ }
+ else // 2nd-cut
+ {
+ rx_cal_reg[0] = _s5_to_s32((val & 0xF8000000) >> 27);
+ rx_cal_reg[1] = _s6_to_s32((val & 0x07E00000) >> 21);
+ rx_cal_reg[2] = _s6_to_s32((val & 0x001F8000) >> 15);
+ rx_cal_reg[3] = _s5_to_s32((val & 0x00007C00) >> 10);
+ }
+
+ PHY_DEBUG(("[CAL] ** rx_cal_reg[0] = %d\n", rx_cal_reg[0]));
+ PHY_DEBUG(("[CAL] rx_cal_reg[1] = %d\n", rx_cal_reg[1]));
+ PHY_DEBUG(("[CAL] rx_cal_reg[2] = %d\n", rx_cal_reg[2]));
+ PHY_DEBUG(("[CAL] rx_cal_reg[3] = %d\n", rx_cal_reg[3]));
+
+ if (phw_data->revision == 0x2002) // 1st-cut
+ {
+ if (((rx_cal_reg[0]==7) || (rx_cal_reg[0]==(-8))) &&
+ ((rx_cal_reg[3]==7) || (rx_cal_reg[3]==(-8))))
+ {
+ PHY_DEBUG(("[CAL] ** <_rx_iq_calibration_loop> *********\n"));
+ PHY_DEBUG(("[CAL] ** RX_IQ_CALIBRATION SATUATION !!\n"));
+ PHY_DEBUG(("[CAL] **************************************\n"));
+ break;
+ }
+ }
+ else // 2nd-cut
+ {
+ if (((rx_cal_reg[0]==31) || (rx_cal_reg[0]==(-32))) &&
+ ((rx_cal_reg[3]==31) || (rx_cal_reg[3]==(-32))))
+ {
+ PHY_DEBUG(("[CAL] ** <_rx_iq_calibration_loop> *********\n"));
+ PHY_DEBUG(("[CAL] ** RX_IQ_CALIBRATION SATUATION !!\n"));
+ PHY_DEBUG(("[CAL] **************************************\n"));
+ break;
+ }
+ }
+
+ rx_cal[0] = rx_cal[0] + rx_cal_reg[0];
+ rx_cal[1] = rx_cal[1] + rx_cal_reg[1];
+ rx_cal[2] = rx_cal[2] + rx_cal_reg[2];
+ rx_cal[3] = rx_cal[3] + rx_cal_reg[3];
+ PHY_DEBUG(("[CAL] ** apply rx_cal[0] = %d\n", rx_cal[0]));
+ PHY_DEBUG(("[CAL] apply rx_cal[1] = %d\n", rx_cal[1]));
+ PHY_DEBUG(("[CAL] apply rx_cal[2] = %d\n", rx_cal[2]));
+ PHY_DEBUG(("[CAL] apply rx_cal[3] = %d\n", rx_cal[3]));
+
+ hw_get_dxx_reg(phw_data, 0x54, &val);
+ if (phw_data->revision == 0x2002) // 1st-cut
+ {
+ val &= 0x0000FFFF;
+ val |= ((_s32_to_s4(rx_cal[0]) << 12)|
+ (_s32_to_s4(rx_cal[1]) << 8)|
+ (_s32_to_s4(rx_cal[2]) << 4)|
+ (_s32_to_s4(rx_cal[3])));
+ hw_set_dxx_reg(phw_data, 0x54, val);
+ }
+ else // 2nd-cut
+ {
+ val &= 0x000003FF;
+ val |= ((_s32_to_s5(rx_cal[0]) << 27)|
+ (_s32_to_s6(rx_cal[1]) << 21)|
+ (_s32_to_s6(rx_cal[2]) << 15)|
+ (_s32_to_s5(rx_cal[3]) << 10));
+ hw_set_dxx_reg(phw_data, 0x54, val);
+
+ if( loop == 3 )
+ return 0;
+ }
+ PHY_DEBUG(("[CAL] ** CALIB_DATA = 0x%08X\n", val));
+
+ loop--;
+ }
+
+ return 1;
+}
+
+//////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////////
+void _rx_iq_calibration_winbond(hw_data_t *phw_data, u32 frequency)
+{
+// figo 20050523 marked thsi flag for can't compile for relesase
+#ifdef _DEBUG
+ s32 rx_cal_reg[4];
+ u32 val;
+#endif
+
+ u8 result;
+
+ PHY_DEBUG(("[CAL] -> [5]_rx_iq_calibration()\n"));
+// a. Set RFIC to "RX calibration mode"
+ //; ----- Calibration (7). RX path IQ imbalance calibration loop
+ // 0x01 0xFFBFC2 ; 3FEFF ; Calibration (7a). enable RX IQ calibration loop circuits
+ phy_set_rf_data(phw_data, 1, (1<<24)|0xEFBFC2);
+ // 0x0B 0x1A01D6 ; 06817 ; Calibration (7b). enable RX I/Q cal loop SW1 circuit
+ phy_set_rf_data(phw_data, 11, (11<<24)|0x1A05D6);
+ //0x05 0x24848A ; 09212 ; Calibration (7c). setting TX-VGA gain (TXGCH) to 2 --> to be optimized
+ phy_set_rf_data(phw_data, 5, (5<<24)| phw_data->txvga_setting_for_cal);
+ //0x06 0x06840C ; 01A10 ; Calibration (7d). RXGCH=00; RXGCL=010 000 (RXVGA) --> to be optimized
+ phy_set_rf_data(phw_data, 6, (6<<24)|0x06834C);
+ //0x00 0xFFF1C0 ; 3F7C7 ; Calibration (7e). turn on IQ imbalance/Test mode
+ phy_set_rf_data(phw_data, 0, (0<<24)|0xFFF1C0);
+
+ // ; [BB-chip]: Calibration (7f). Send test pattern
+ // ; [BB-chip]: Calibration (7g). Search RXGCL optimal value
+ // ; [BB-chip]: Calibration (7h). Caculate RX-path IQ imbalance and setting RX path IQ compensation table
+
+ result = _rx_iq_calibration_loop_winbond(phw_data, 12589, frequency);
+
+ if (result > 0)
+ {
+ _reset_rx_cal(phw_data);
+ result = _rx_iq_calibration_loop_winbond(phw_data, 7943, frequency);
+
+ if (result > 0)
+ {
+ _reset_rx_cal(phw_data);
+ result = _rx_iq_calibration_loop_winbond(phw_data, 5011, frequency);
+
+ if (result > 0)
+ {
+ PHY_DEBUG(("[CAL] ** <_rx_iq_calibration> **************\n"));
+ PHY_DEBUG(("[CAL] ** RX_IQ_CALIBRATION FAILURE !!\n"));
+ PHY_DEBUG(("[CAL] **************************************\n"));
+ _reset_rx_cal(phw_data);
+ }
+ }
+ }
+
+#ifdef _DEBUG
+ hw_get_dxx_reg(phw_data, 0x54, &val);
+ PHY_DEBUG(("[CAL] ** 0x54 = 0x%08X\n", val));
+
+ if (phw_data->revision == 0x2002) // 1st-cut
+ {
+ rx_cal_reg[0] = _s4_to_s32((val & 0x0000F000) >> 12);
+ rx_cal_reg[1] = _s4_to_s32((val & 0x00000F00) >> 8);
+ rx_cal_reg[2] = _s4_to_s32((val & 0x000000F0) >> 4);
+ rx_cal_reg[3] = _s4_to_s32((val & 0x0000000F));
+ }
+ else // 2nd-cut
+ {
+ rx_cal_reg[0] = _s5_to_s32((val & 0xF8000000) >> 27);
+ rx_cal_reg[1] = _s6_to_s32((val & 0x07E00000) >> 21);
+ rx_cal_reg[2] = _s6_to_s32((val & 0x001F8000) >> 15);
+ rx_cal_reg[3] = _s5_to_s32((val & 0x00007C00) >> 10);
+ }
+
+ PHY_DEBUG(("[CAL] ** rx_cal_reg[0] = %d\n", rx_cal_reg[0]));
+ PHY_DEBUG(("[CAL] rx_cal_reg[1] = %d\n", rx_cal_reg[1]));
+ PHY_DEBUG(("[CAL] rx_cal_reg[2] = %d\n", rx_cal_reg[2]));
+ PHY_DEBUG(("[CAL] rx_cal_reg[3] = %d\n", rx_cal_reg[3]));
+#endif
+
+}
+
+////////////////////////////////////////////////////////////////////////
+void phy_calibration_winbond(hw_data_t *phw_data, u32 frequency)
+{
+ u32 reg_mode_ctrl;
+ u32 iq_alpha;
+
+ PHY_DEBUG(("[CAL] -> phy_calibration_winbond()\n"));
+
+ // 20040701 1.1.25.1000 kevin
+ hw_get_cxx_reg(phw_data, 0x80, &mac_ctrl);
+ hw_get_cxx_reg(phw_data, 0xE4, &rf_ctrl);
+ hw_get_dxx_reg(phw_data, 0x58, &iq_alpha);
+
+
+
+ _rxadc_dc_offset_cancellation_winbond(phw_data, frequency);
+ //_txidac_dc_offset_cancellation_winbond(phw_data);
+ //_txqdac_dc_offset_cacellation_winbond(phw_data);
+
+ _tx_iq_calibration_winbond(phw_data);
+ _rx_iq_calibration_winbond(phw_data, frequency);
+
+ //------------------------------------------------------------------------
+ hw_get_dxx_reg(phw_data, REG_MODE_CTRL, ®_mode_ctrl);
+ reg_mode_ctrl &= ~(MASK_IQCAL_TONE_SEL|MASK_IQCAL_MODE|MASK_CALIB_START); // set when finish
+ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl);
+ PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl));
+
+ // i. Set RFIC to "Normal mode"
+ hw_set_cxx_reg(phw_data, 0x80, mac_ctrl);
+ hw_set_cxx_reg(phw_data, 0xE4, rf_ctrl);
+ hw_set_dxx_reg(phw_data, 0x58, iq_alpha);
+
+
+ //------------------------------------------------------------------------
+ phy_init_rf(phw_data);
+
+}
+
+//===========================
+void phy_set_rf_data( phw_data_t pHwData, u32 index, u32 value )
+{
+ u32 ltmp=0;
+
+ switch( pHwData->phy_type )
+ {
+ case RF_MAXIM_2825:
+ case RF_MAXIM_V1: // 11g Winbond 2nd BB(with Phy board (v1) + Maxim 331)
+ ltmp = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( value, 18 );
+ break;
+
+ case RF_MAXIM_2827:
+ ltmp = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( value, 18 );
+ break;
+
+ case RF_MAXIM_2828:
+ ltmp = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( value, 18 );
+ break;
+
+ case RF_MAXIM_2829:
+ ltmp = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( value, 18 );
+ break;
+
+ case RF_AIROHA_2230:
+ case RF_AIROHA_2230S: // 20060420 Add this
+ ltmp = (1 << 31) | (0 << 30) | (20 << 24) | BitReverse( value, 20 );
+ break;
+
+ case RF_AIROHA_7230:
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | (value&0xffffff);
+ break;
+
+ case RF_WB_242:
+ case RF_WB_242_1: // 20060619.5 Add
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( value, 24 );
+ break;
+ }
+
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+}
+
+// 20060717 modify as Bruce's mail
+unsigned char adjust_TXVGA_for_iq_mag(hw_data_t *phw_data)
+{
+ int init_txvga = 0;
+ u32 reg_mode_ctrl;
+ u32 val;
+ s32 iqcal_tone_i0;
+ s32 iqcal_tone_q0;
+ u32 sqsum;
+ s32 iq_mag_0_tx;
+ u8 reg_state;
+ int current_txvga;
+
+
+ reg_state = 0;
+ for( init_txvga=0; init_txvga<10; init_txvga++)
+ {
+ current_txvga = ( 0x24C40A|(init_txvga<<6) );
+ phy_set_rf_data(phw_data, 5, ((5<<24)|current_txvga) );
+ phw_data->txvga_setting_for_cal = current_txvga;
+
+ //pa_stall_execution(30000);//Sleep(30);
+ OS_SLEEP(30000); // 20060612.1.a
+
+ if( !hw_get_dxx_reg(phw_data, REG_MODE_CTRL, ®_mode_ctrl) ) // 20060718.1 modify
+ return FALSE;
+
+ PHY_DEBUG(("[CAL] MODE_CTRL (read) = 0x%08X\n", reg_mode_ctrl));
+
+ // a. Set iqcal_mode[1:0] to 0x2 and set "calib_start" to 0x1 to
+ // enable "IQ alibration Mode II"
+ reg_mode_ctrl &= ~(MASK_IQCAL_TONE_SEL|MASK_IQCAL_MODE);
+ reg_mode_ctrl &= ~MASK_IQCAL_MODE;
+ reg_mode_ctrl |= (MASK_CALIB_START|0x02);
+ reg_mode_ctrl |= (MASK_CALIB_START|0x02|2<<2);
+ hw_set_dxx_reg(phw_data, REG_MODE_CTRL, reg_mode_ctrl);
+ PHY_DEBUG(("[CAL] MODE_CTRL (write) = 0x%08X\n", reg_mode_ctrl));
+
+ //pa_stall_execution(US);
+ OS_SLEEP(1); // 20060612.1.a
+
+ //pa_stall_execution(300);//Sleep(30);
+ OS_SLEEP(300); // 20060612.1.a
+
+ // b.
+ hw_get_dxx_reg(phw_data, REG_CALIB_READ1, &val);
+
+ PHY_DEBUG(("[CAL] CALIB_READ1 = 0x%08X\n", val));
+ //pa_stall_execution(US);
+ //pa_stall_execution(300);//Sleep(30);
+ OS_SLEEP(300); // 20060612.1.a
+
+ iqcal_tone_i0 = _s13_to_s32(val & 0x00001FFF);
+ iqcal_tone_q0 = _s13_to_s32((val & 0x03FFE000) >> 13);
+ PHY_DEBUG(("[CAL] ** iqcal_tone_i0=%d, iqcal_tone_q0=%d\n",
+ iqcal_tone_i0, iqcal_tone_q0));
+
+ sqsum = iqcal_tone_i0*iqcal_tone_i0 + iqcal_tone_q0*iqcal_tone_q0;
+ iq_mag_0_tx = (s32) _sqrt(sqsum);
+ PHY_DEBUG(("[CAL] ** auto_adjust_txvga_for_iq_mag_0_tx=%d\n", iq_mag_0_tx));
+
+ if( iq_mag_0_tx>=700 && iq_mag_0_tx<=1750 )
+ break;
+ else if(iq_mag_0_tx > 1750)
+ {
+ init_txvga=-2;
+ continue;
+ }
+ else
+ continue;
+
+ }
+
+ if( iq_mag_0_tx>=700 && iq_mag_0_tx<=1750 )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+
+
diff --git a/drivers/staging/winbond/phy_calibration.h b/drivers/staging/winbond/phy_calibration.h
new file mode 100644
index 0000000..b6a65d3
--- /dev/null
+++ b/drivers/staging/winbond/phy_calibration.h
@@ -0,0 +1,101 @@
+// 20031229 Turbo add
+#define REG_AGC_CTRL1 0x1000
+#define REG_AGC_CTRL2 0x1004
+#define REG_AGC_CTRL3 0x1008
+#define REG_AGC_CTRL4 0x100C
+#define REG_AGC_CTRL5 0x1010
+#define REG_AGC_CTRL6 0x1014
+#define REG_AGC_CTRL7 0x1018
+#define REG_AGC_CTRL8 0x101C
+#define REG_AGC_CTRL9 0x1020
+#define REG_AGC_CTRL10 0x1024
+#define REG_CCA_CTRL 0x1028
+#define REG_A_ACQ_CTRL 0x102C
+#define REG_B_ACQ_CTRL 0x1030
+#define REG_A_TXRX_CTRL 0x1034
+#define REG_B_TXRX_CTRL 0x1038
+#define REG_A_TX_COEF3 0x103C
+#define REG_A_TX_COEF2 0x1040
+#define REG_A_TX_COEF1 0x1044
+#define REG_B_TX_COEF2 0x1048
+#define REG_B_TX_COEF1 0x104C
+#define REG_MODE_CTRL 0x1050
+#define REG_CALIB_DATA 0x1054
+#define REG_IQ_ALPHA 0x1058
+#define REG_DC_CANCEL 0x105C
+#define REG_WTO_READ 0x1060
+#define REG_OFFSET_READ 0x1064
+#define REG_CALIB_READ1 0x1068
+#define REG_CALIB_READ2 0x106C
+#define REG_A_FREQ_EST 0x1070
+
+
+
+
+// 20031101 Turbo add
+#define MASK_AMER_OFF_REG BIT(31)
+
+#define MASK_BMER_OFF_REG BIT(31)
+
+#define MASK_LNA_FIX_GAIN (BIT(3)|BIT(4))
+#define MASK_AGC_FIX BIT(1)
+
+#define MASK_AGC_FIX_GAIN 0xFF00
+
+#define MASK_ADC_DC_CAL_STR BIT(10)
+#define MASK_CALIB_START BIT(4)
+#define MASK_IQCAL_TONE_SEL (BIT(3)|BIT(2))
+#define MASK_IQCAL_MODE (BIT(1)|BIT(0))
+
+#define MASK_TX_CAL_0 0xF0000000
+#define TX_CAL_0_SHIFT 28
+#define MASK_TX_CAL_1 0x0F000000
+#define TX_CAL_1_SHIFT 24
+#define MASK_TX_CAL_2 0x00F00000
+#define TX_CAL_2_SHIFT 20
+#define MASK_TX_CAL_3 0x000F0000
+#define TX_CAL_3_SHIFT 16
+#define MASK_RX_CAL_0 0x0000F000
+#define RX_CAL_0_SHIFT 12
+#define MASK_RX_CAL_1 0x00000F00
+#define RX_CAL_1_SHIFT 8
+#define MASK_RX_CAL_2 0x000000F0
+#define RX_CAL_2_SHIFT 4
+#define MASK_RX_CAL_3 0x0000000F
+#define RX_CAL_3_SHIFT 0
+
+#define MASK_CANCEL_DC_I 0x3E0
+#define CANCEL_DC_I_SHIFT 5
+#define MASK_CANCEL_DC_Q 0x01F
+#define CANCEL_DC_Q_SHIFT 0
+
+// LA20040210 kevin
+//#define MASK_ADC_DC_CAL_I(x) (((x)&0x1FE00)>>9)
+//#define MASK_ADC_DC_CAL_Q(x) ((x)&0x1FF)
+#define MASK_ADC_DC_CAL_I(x) (((x)&0x0003FE00)>>9)
+#define MASK_ADC_DC_CAL_Q(x) ((x)&0x000001FF)
+
+// LA20040210 kevin (Turbo has wrong definition)
+//#define MASK_IQCAL_TONE_I 0x7FFC000
+//#define SHIFT_IQCAL_TONE_I(x) ((x)>>13)
+//#define MASK_IQCAL_TONE_Q 0x1FFF
+//#define SHIFT_IQCAL_TONE_Q(x) ((x)>>0)
+#define MASK_IQCAL_TONE_I 0x00001FFF
+#define SHIFT_IQCAL_TONE_I(x) ((x)>>0)
+#define MASK_IQCAL_TONE_Q 0x03FFE000
+#define SHIFT_IQCAL_TONE_Q(x) ((x)>>13)
+
+// LA20040210 kevin (Turbo has wrong definition)
+//#define MASK_IQCAL_IMAGE_I 0x7FFC000
+//#define SHIFT_IQCAL_IMAGE_I(x) ((x)>>13)
+//#define MASK_IQCAL_IMAGE_Q 0x1FFF
+//#define SHIFT_IQCAL_IMAGE_Q(x) ((x)>>0)
+
+//#define MASK_IQCAL_IMAGE_I 0x00001FFF
+//#define SHIFT_IQCAL_IMAGE_I(x) ((x)>>0)
+//#define MASK_IQCAL_IMAGE_Q 0x03FFE000
+//#define SHIFT_IQCAL_IMAGE_Q(x) ((x)>>13)
+
+void phy_set_rf_data( phw_data_t pHwData, u32 index, u32 value );
+#define phy_init_rf( _A ) //RFSynthesizer_initial( _A )
+
diff --git a/drivers/staging/winbond/reg.c b/drivers/staging/winbond/reg.c
new file mode 100644
index 0000000..b475c7a
--- /dev/null
+++ b/drivers/staging/winbond/reg.c
@@ -0,0 +1,2683 @@
+#include "os_common.h"
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Original Phy.h
+//*****************************************************************************
+
+/*****************************************************************************
+; For MAXIM2825/6/7 Ver. 331 or more
+; Edited by Tiger, Sep-17-2003
+; revised by Ben, Sep-18-2003
+
+0x00 0x000a2
+0x01 0x21cc0
+;0x02 0x13802
+0x02 0x1383a
+
+;channe1 01 ; 0x03 0x30142 ; 0x04 0x0b333;
+;channe1 02 ;0x03 0x32141 ;0x04 0x08444;
+;channe1 03 ;0x03 0x32143 ;0x04 0x0aeee;
+;channe1 04 ;0x03 0x32142 ;0x04 0x0b333;
+;channe1 05 ;0x03 0x31141 ;0x04 0x08444;
+;channe1 06 ;
+0x03 0x31143;
+0x04 0x0aeee;
+;channe1 07 ;0x03 0x31142 ;0x04 0x0b333;
+;channe1 08 ;0x03 0x33141 ;0x04 0x08444;
+;channe1 09 ;0x03 0x33143 ;0x04 0x0aeee;
+;channe1 10 ;0x03 0x33142 ;0x04 0x0b333;
+;channe1 11 ;0x03 0x30941 ;0x04 0x08444;
+;channe1 12 ;0x03 0x30943 ;0x04 0x0aeee;
+;channe1 13 ;0x03 0x30942 ;0x04 0x0b333;
+
+0x05 0x28986
+0x06 0x18008
+0x07 0x38400
+0x08 0x05100; 100 Hz DC
+;0x08 0x05900; 30 KHz DC
+0x09 0x24f08
+0x0a 0x17e00, 0x17ea0
+0x0b 0x37d80
+0x0c 0x0c900 // 0x0ca00 (lager power 9db than 0x0c000), 0x0c000
+*****************************************************************************/
+// MAX2825 (pure b/g)
+u32 max2825_rf_data[] =
+{
+ (0x00<<18)|0x000a2,
+ (0x01<<18)|0x21cc0,
+ (0x02<<18)|0x13806,
+ (0x03<<18)|0x30142,
+ (0x04<<18)|0x0b333,
+ (0x05<<18)|0x289A6,
+ (0x06<<18)|0x18008,
+ (0x07<<18)|0x38000,
+ (0x08<<18)|0x05100,
+ (0x09<<18)|0x24f08,
+ (0x0A<<18)|0x14000,
+ (0x0B<<18)|0x37d80,
+ (0x0C<<18)|0x0c100 // 11a: 0x0c300, 11g: 0x0c100
+};
+
+u32 max2825_channel_data_24[][3] =
+{
+ {(0x03<<18)|0x30142, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 01
+ {(0x03<<18)|0x32141, (0x04<<18)|0x08444, (0x05<<18)|0x289A6}, // channe1 02
+ {(0x03<<18)|0x32143, (0x04<<18)|0x0aeee, (0x05<<18)|0x289A6}, // channe1 03
+ {(0x03<<18)|0x32142, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 04
+ {(0x03<<18)|0x31141, (0x04<<18)|0x08444, (0x05<<18)|0x289A6}, // channe1 05
+ {(0x03<<18)|0x31143, (0x04<<18)|0x0aeee, (0x05<<18)|0x289A6}, // channe1 06
+ {(0x03<<18)|0x31142, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 07
+ {(0x03<<18)|0x33141, (0x04<<18)|0x08444, (0x05<<18)|0x289A6}, // channe1 08
+ {(0x03<<18)|0x33143, (0x04<<18)|0x0aeee, (0x05<<18)|0x289A6}, // channe1 09
+ {(0x03<<18)|0x33142, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 10
+ {(0x03<<18)|0x30941, (0x04<<18)|0x08444, (0x05<<18)|0x289A6}, // channe1 11
+ {(0x03<<18)|0x30943, (0x04<<18)|0x0aeee, (0x05<<18)|0x289A6}, // channe1 12
+ {(0x03<<18)|0x30942, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 13
+ {(0x03<<18)|0x32941, (0x04<<18)|0x09999, (0x05<<18)|0x289A6} // 14 (2484MHz) hhmodify
+};
+
+u32 max2825_power_data_24[] = {(0x0C<<18)|0x0c000, (0x0C<<18)|0x0c100};
+
+/****************************************************************************/
+// MAX2827 (a/b/g)
+u32 max2827_rf_data[] =
+{
+ (0x00<<18)|0x000a2,
+ (0x01<<18)|0x21cc0,
+ (0x02<<18)|0x13806,
+ (0x03<<18)|0x30142,
+ (0x04<<18)|0x0b333,
+ (0x05<<18)|0x289A6,
+ (0x06<<18)|0x18008,
+ (0x07<<18)|0x38000,
+ (0x08<<18)|0x05100,
+ (0x09<<18)|0x24f08,
+ (0x0A<<18)|0x14000,
+ (0x0B<<18)|0x37d80,
+ (0x0C<<18)|0x0c100 // 11a: 0x0c300, 11g: 0x0c100
+};
+
+u32 max2827_channel_data_24[][3] =
+{
+ {(0x03<<18)|0x30142, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 01
+ {(0x03<<18)|0x32141, (0x04<<18)|0x08444, (0x05<<18)|0x289A6}, // channe1 02
+ {(0x03<<18)|0x32143, (0x04<<18)|0x0aeee, (0x05<<18)|0x289A6}, // channe1 03
+ {(0x03<<18)|0x32142, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 04
+ {(0x03<<18)|0x31141, (0x04<<18)|0x08444, (0x05<<18)|0x289A6}, // channe1 05
+ {(0x03<<18)|0x31143, (0x04<<18)|0x0aeee, (0x05<<18)|0x289A6}, // channe1 06
+ {(0x03<<18)|0x31142, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 07
+ {(0x03<<18)|0x33141, (0x04<<18)|0x08444, (0x05<<18)|0x289A6}, // channe1 08
+ {(0x03<<18)|0x33143, (0x04<<18)|0x0aeee, (0x05<<18)|0x289A6}, // channe1 09
+ {(0x03<<18)|0x33142, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 10
+ {(0x03<<18)|0x30941, (0x04<<18)|0x08444, (0x05<<18)|0x289A6}, // channe1 11
+ {(0x03<<18)|0x30943, (0x04<<18)|0x0aeee, (0x05<<18)|0x289A6}, // channe1 12
+ {(0x03<<18)|0x30942, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 13
+ {(0x03<<18)|0x32941, (0x04<<18)|0x09999, (0x05<<18)|0x289A6} // 14 (2484MHz) hhmodify
+};
+
+u32 max2827_channel_data_50[][3] =
+{
+ {(0x03<<18)|0x33cc3, (0x04<<18)|0x08ccc, (0x05<<18)|0x2A9A6}, // channel 36
+ {(0x03<<18)|0x302c0, (0x04<<18)|0x08000, (0x05<<18)|0x2A9A6}, // channel 40
+ {(0x03<<18)|0x302c2, (0x04<<18)|0x0b333, (0x05<<18)|0x2A9A6}, // channel 44
+ {(0x03<<18)|0x322c1, (0x04<<18)|0x09999, (0x05<<18)|0x2A9A6}, // channel 48
+ {(0x03<<18)|0x312c1, (0x04<<18)|0x0a666, (0x05<<18)|0x2A9A6}, // channel 52
+ {(0x03<<18)|0x332c3, (0x04<<18)|0x08ccc, (0x05<<18)|0x2A9A6}, // channel 56
+ {(0x03<<18)|0x30ac0, (0x04<<18)|0x08000, (0x05<<18)|0x2A9A6}, // channel 60
+ {(0x03<<18)|0x30ac2, (0x04<<18)|0x0b333, (0x05<<18)|0x2A9A6} // channel 64
+};
+
+u32 max2827_power_data_24[] = {(0x0C<<18)|0x0C000, (0x0C<<18)|0x0D600, (0x0C<<18)|0x0C100};
+u32 max2827_power_data_50[] = {(0x0C<<18)|0x0C400, (0x0C<<18)|0x0D500, (0x0C<<18)|0x0C300};
+
+/****************************************************************************/
+// MAX2828 (a/b/g)
+u32 max2828_rf_data[] =
+{
+ (0x00<<18)|0x000a2,
+ (0x01<<18)|0x21cc0,
+ (0x02<<18)|0x13806,
+ (0x03<<18)|0x30142,
+ (0x04<<18)|0x0b333,
+ (0x05<<18)|0x289A6,
+ (0x06<<18)|0x18008,
+ (0x07<<18)|0x38000,
+ (0x08<<18)|0x05100,
+ (0x09<<18)|0x24f08,
+ (0x0A<<18)|0x14000,
+ (0x0B<<18)|0x37d80,
+ (0x0C<<18)|0x0c100 // 11a: 0x0c300, 11g: 0x0c100
+};
+
+u32 max2828_channel_data_24[][3] =
+{
+ {(0x03<<18)|0x30142, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 01
+ {(0x03<<18)|0x32141, (0x04<<18)|0x08444, (0x05<<18)|0x289A6}, // channe1 02
+ {(0x03<<18)|0x32143, (0x04<<18)|0x0aeee, (0x05<<18)|0x289A6}, // channe1 03
+ {(0x03<<18)|0x32142, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 04
+ {(0x03<<18)|0x31141, (0x04<<18)|0x08444, (0x05<<18)|0x289A6}, // channe1 05
+ {(0x03<<18)|0x31143, (0x04<<18)|0x0aeee, (0x05<<18)|0x289A6}, // channe1 06
+ {(0x03<<18)|0x31142, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 07
+ {(0x03<<18)|0x33141, (0x04<<18)|0x08444, (0x05<<18)|0x289A6}, // channe1 08
+ {(0x03<<18)|0x33143, (0x04<<18)|0x0aeee, (0x05<<18)|0x289A6}, // channe1 09
+ {(0x03<<18)|0x33142, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 10
+ {(0x03<<18)|0x30941, (0x04<<18)|0x08444, (0x05<<18)|0x289A6}, // channe1 11
+ {(0x03<<18)|0x30943, (0x04<<18)|0x0aeee, (0x05<<18)|0x289A6}, // channe1 12
+ {(0x03<<18)|0x30942, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channe1 13
+ {(0x03<<18)|0x32941, (0x04<<18)|0x09999, (0x05<<18)|0x289A6} // 14 (2484MHz) hhmodify
+};
+
+u32 max2828_channel_data_50[][3] =
+{
+ {(0x03<<18)|0x33cc3, (0x04<<18)|0x08ccc, (0x05<<18)|0x289A6}, // channel 36
+ {(0x03<<18)|0x302c0, (0x04<<18)|0x08000, (0x05<<18)|0x289A6}, // channel 40
+ {(0x03<<18)|0x302c2, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6}, // channel 44
+ {(0x03<<18)|0x322c1, (0x04<<18)|0x09999, (0x05<<18)|0x289A6}, // channel 48
+ {(0x03<<18)|0x312c1, (0x04<<18)|0x0a666, (0x05<<18)|0x289A6}, // channel 52
+ {(0x03<<18)|0x332c3, (0x04<<18)|0x08ccc, (0x05<<18)|0x289A6}, // channel 56
+ {(0x03<<18)|0x30ac0, (0x04<<18)|0x08000, (0x05<<18)|0x289A6}, // channel 60
+ {(0x03<<18)|0x30ac2, (0x04<<18)|0x0b333, (0x05<<18)|0x289A6} // channel 64
+};
+
+u32 max2828_power_data_24[] = {(0x0C<<18)|0x0c000, (0x0C<<18)|0x0c100};
+u32 max2828_power_data_50[] = {(0x0C<<18)|0x0c000, (0x0C<<18)|0x0c100};
+
+/****************************************************************************/
+// LA20040728 kevin
+// MAX2829 (a/b/g)
+u32 max2829_rf_data[] =
+{
+ (0x00<<18)|0x000a2,
+ (0x01<<18)|0x23520,
+ (0x02<<18)|0x13802,
+ (0x03<<18)|0x30142,
+ (0x04<<18)|0x0b333,
+ (0x05<<18)|0x28906,
+ (0x06<<18)|0x18008,
+ (0x07<<18)|0x3B500,
+ (0x08<<18)|0x05100,
+ (0x09<<18)|0x24f08,
+ (0x0A<<18)|0x14000,
+ (0x0B<<18)|0x37d80,
+ (0x0C<<18)|0x0F300 //TXVGA=51, (MAX-6 dB)
+};
+
+u32 max2829_channel_data_24[][3] =
+{
+ {(3<<18)|0x30142, (4<<18)|0x0b333, (5<<18)|0x289C6}, // 01 (2412MHz)
+ {(3<<18)|0x32141, (4<<18)|0x08444, (5<<18)|0x289C6}, // 02 (2417MHz)
+ {(3<<18)|0x32143, (4<<18)|0x0aeee, (5<<18)|0x289C6}, // 03 (2422MHz)
+ {(3<<18)|0x32142, (4<<18)|0x0b333, (5<<18)|0x289C6}, // 04 (2427MHz)
+ {(3<<18)|0x31141, (4<<18)|0x08444, (5<<18)|0x289C6}, // 05 (2432MHz)
+ {(3<<18)|0x31143, (4<<18)|0x0aeee, (5<<18)|0x289C6}, // 06 (2437MHz)
+ {(3<<18)|0x31142, (4<<18)|0x0b333, (5<<18)|0x289C6}, // 07 (2442MHz)
+ {(3<<18)|0x33141, (4<<18)|0x08444, (5<<18)|0x289C6}, // 08 (2447MHz)
+ {(3<<18)|0x33143, (4<<18)|0x0aeee, (5<<18)|0x289C6}, // 09 (2452MHz)
+ {(3<<18)|0x33142, (4<<18)|0x0b333, (5<<18)|0x289C6}, // 10 (2457MHz)
+ {(3<<18)|0x30941, (4<<18)|0x08444, (5<<18)|0x289C6}, // 11 (2462MHz)
+ {(3<<18)|0x30943, (4<<18)|0x0aeee, (5<<18)|0x289C6}, // 12 (2467MHz)
+ {(3<<18)|0x30942, (4<<18)|0x0b333, (5<<18)|0x289C6}, // 13 (2472MHz)
+ {(3<<18)|0x32941, (4<<18)|0x09999, (5<<18)|0x289C6}, // 14 (2484MHz) hh-modify
+};
+
+u32 max2829_channel_data_50[][4] =
+{
+ {36, (3<<18)|0x33cc3, (4<<18)|0x08ccc, (5<<18)|0x2A946}, // 36 (5.180GHz)
+ {40, (3<<18)|0x302c0, (4<<18)|0x08000, (5<<18)|0x2A946}, // 40 (5.200GHz)
+ {44, (3<<18)|0x302c2, (4<<18)|0x0b333, (5<<18)|0x2A946}, // 44 (5.220GHz)
+ {48, (3<<18)|0x322c1, (4<<18)|0x09999, (5<<18)|0x2A946}, // 48 (5.240GHz)
+ {52, (3<<18)|0x312c1, (4<<18)|0x0a666, (5<<18)|0x2A946}, // 52 (5.260GHz)
+ {56, (3<<18)|0x332c3, (4<<18)|0x08ccc, (5<<18)|0x2A946}, // 56 (5.280GHz)
+ {60, (3<<18)|0x30ac0, (4<<18)|0x08000, (5<<18)|0x2A946}, // 60 (5.300GHz)
+ {64, (3<<18)|0x30ac2, (4<<18)|0x0b333, (5<<18)|0x2A946}, // 64 (5.320GHz)
+
+ {100, (3<<18)|0x30ec0, (4<<18)|0x08000, (5<<18)|0x2A9C6}, // 100 (5.500GHz)
+ {104, (3<<18)|0x30ec2, (4<<18)|0x0b333, (5<<18)|0x2A9C6}, // 104 (5.520GHz)
+ {108, (3<<18)|0x32ec1, (4<<18)|0x09999, (5<<18)|0x2A9C6}, // 108 (5.540GHz)
+ {112, (3<<18)|0x31ec1, (4<<18)|0x0a666, (5<<18)|0x2A9C6}, // 112 (5.560GHz)
+ {116, (3<<18)|0x33ec3, (4<<18)|0x08ccc, (5<<18)|0x2A9C6}, // 116 (5.580GHz)
+ {120, (3<<18)|0x301c0, (4<<18)|0x08000, (5<<18)|0x2A9C6}, // 120 (5.600GHz)
+ {124, (3<<18)|0x301c2, (4<<18)|0x0b333, (5<<18)|0x2A9C6}, // 124 (5.620GHz)
+ {128, (3<<18)|0x321c1, (4<<18)|0x09999, (5<<18)|0x2A9C6}, // 128 (5.640GHz)
+ {132, (3<<18)|0x311c1, (4<<18)|0x0a666, (5<<18)|0x2A9C6}, // 132 (5.660GHz)
+ {136, (3<<18)|0x331c3, (4<<18)|0x08ccc, (5<<18)|0x2A9C6}, // 136 (5.680GHz)
+ {140, (3<<18)|0x309c0, (4<<18)|0x08000, (5<<18)|0x2A9C6}, // 140 (5.700GHz)
+
+ {149, (3<<18)|0x329c2, (4<<18)|0x0b333, (5<<18)|0x2A9C6}, // 149 (5.745GHz)
+ {153, (3<<18)|0x319c1, (4<<18)|0x09999, (5<<18)|0x2A9C6}, // 153 (5.765GHz)
+ {157, (3<<18)|0x339c1, (4<<18)|0x0a666, (5<<18)|0x2A9C6}, // 157 (5.785GHz)
+ {161, (3<<18)|0x305c3, (4<<18)|0x08ccc, (5<<18)|0x2A9C6}, // 161 (5.805GHz)
+
+ // Japan
+ { 184, (3<<18)|0x308c2, (4<<18)|0x0b333, (5<<18)|0x2A946}, // 184 (4.920GHz)
+ { 188, (3<<18)|0x328c1, (4<<18)|0x09999, (5<<18)|0x2A946}, // 188 (4.940GHz)
+ { 192, (3<<18)|0x318c1, (4<<18)|0x0a666, (5<<18)|0x2A946}, // 192 (4.960GHz)
+ { 196, (3<<18)|0x338c3, (4<<18)|0x08ccc, (5<<18)|0x2A946}, // 196 (4.980GHz)
+ { 8, (3<<18)|0x324c1, (4<<18)|0x09999, (5<<18)|0x2A946}, // 8 (5.040GHz)
+ { 12, (3<<18)|0x314c1, (4<<18)|0x0a666, (5<<18)|0x2A946}, // 12 (5.060GHz)
+ { 16, (3<<18)|0x334c3, (4<<18)|0x08ccc, (5<<18)|0x2A946}, // 16 (5.080GHz)
+ { 34, (3<<18)|0x31cc2, (4<<18)|0x0b333, (5<<18)|0x2A946}, // 34 (5.170GHz)
+ { 38, (3<<18)|0x33cc1, (4<<18)|0x09999, (5<<18)|0x2A946}, // 38 (5.190GHz)
+ { 42, (3<<18)|0x302c1, (4<<18)|0x0a666, (5<<18)|0x2A946}, // 42 (5.210GHz)
+ { 46, (3<<18)|0x322c3, (4<<18)|0x08ccc, (5<<18)|0x2A946}, // 46 (5.230GHz)
+};
+
+/*****************************************************************************
+; For MAXIM2825/6/7 Ver. 317 or less
+; Edited by Tiger, Sep-17-2003 for 2.4Ghz channels
+; Updated by Tiger, Sep-22-2003 for 5.0Ghz channels
+; Corrected by Tiger, Sep-23-2003, for 0x03 and 0x04 of 5.0Ghz channels
+
+0x00 0x00080
+0x01 0x214c0
+0x02 0x13802
+
+;2.4GHz Channels
+;channe1 01 (2.412GHz); 0x03 0x30143 ;0x04 0x0accc
+;channe1 02 (2.417GHz); 0x03 0x32140 ;0x04 0x09111
+;channe1 03 (2.422GHz); 0x03 0x32142 ;0x04 0x0bbbb
+;channe1 04 (2.427GHz); 0x03 0x32143 ;0x04 0x0accc
+;channe1 05 (2.432GHz); 0x03 0x31140 ;0x04 0x09111
+;channe1 06 (2.437GHz); 0x03 0x31142 ;0x04 0x0bbbb
+;channe1 07 (2.442GHz); 0x03 0x31143 ;0x04 0x0accc
+;channe1 08 (2.447GHz); 0x03 0x33140 ;0x04 0x09111
+;channe1 09 (2.452GHz); 0x03 0x33142 ;0x04 0x0bbbb
+;channe1 10 (2.457GHz); 0x03 0x33143 ;0x04 0x0accc
+;channe1 11 (2.462GHz); 0x03 0x30940 ;0x04 0x09111
+;channe1 12 (2.467GHz); 0x03 0x30942 ;0x04 0x0bbbb
+;channe1 13 (2.472GHz); 0x03 0x30943 ;0x04 0x0accc
+
+;5.0Ghz Channels
+;channel 36 (5.180GHz); 0x03 0x33cc0 ;0x04 0x0b333
+;channel 40 (5.200GHz); 0x03 0x302c0 ;0x04 0x08000
+;channel 44 (5.220GHz); 0x03 0x302c2 ;0x04 0x0b333
+;channel 48 (5.240GHz); 0x03 0x322c1 ;0x04 0x09999
+;channel 52 (5.260GHz); 0x03 0x312c1 ;0x04 0x0a666
+;channel 56 (5.280GHz); 0x03 0x332c3 ;0x04 0x08ccc
+;channel 60 (5.300GHz); 0x03 0x30ac0 ;0x04 0x08000
+;channel 64 (5.320GHz); 0x03 0x30ac2 ;0x04 0x08333
+
+;2.4GHz band ;0x05 0x28986;
+;5.0GHz band
+0x05 0x2a986
+
+0x06 0x18008
+0x07 0x38400
+0x08 0x05108
+0x09 0x27ff8
+0x0a 0x14000
+0x0b 0x37f99
+0x0c 0x0c000
+*****************************************************************************/
+u32 maxim_317_rf_data[] =
+{
+ (0x00<<18)|0x000a2,
+ (0x01<<18)|0x214c0,
+ (0x02<<18)|0x13802,
+ (0x03<<18)|0x30143,
+ (0x04<<18)|0x0accc,
+ (0x05<<18)|0x28986,
+ (0x06<<18)|0x18008,
+ (0x07<<18)|0x38400,
+ (0x08<<18)|0x05108,
+ (0x09<<18)|0x27ff8,
+ (0x0A<<18)|0x14000,
+ (0x0B<<18)|0x37f99,
+ (0x0C<<18)|0x0c000
+};
+
+u32 maxim_317_channel_data_24[][3] =
+{
+ {(0x03<<18)|0x30143, (0x04<<18)|0x0accc, (0x05<<18)|0x28986}, // channe1 01
+ {(0x03<<18)|0x32140, (0x04<<18)|0x09111, (0x05<<18)|0x28986}, // channe1 02
+ {(0x03<<18)|0x32142, (0x04<<18)|0x0bbbb, (0x05<<18)|0x28986}, // channe1 03
+ {(0x03<<18)|0x32143, (0x04<<18)|0x0accc, (0x05<<18)|0x28986}, // channe1 04
+ {(0x03<<18)|0x31140, (0x04<<18)|0x09111, (0x05<<18)|0x28986}, // channe1 05
+ {(0x03<<18)|0x31142, (0x04<<18)|0x0bbbb, (0x05<<18)|0x28986}, // channe1 06
+ {(0x03<<18)|0x31143, (0x04<<18)|0x0accc, (0x05<<18)|0x28986}, // channe1 07
+ {(0x03<<18)|0x33140, (0x04<<18)|0x09111, (0x05<<18)|0x28986}, // channe1 08
+ {(0x03<<18)|0x33142, (0x04<<18)|0x0bbbb, (0x05<<18)|0x28986}, // channe1 09
+ {(0x03<<18)|0x33143, (0x04<<18)|0x0accc, (0x05<<18)|0x28986}, // channe1 10
+ {(0x03<<18)|0x30940, (0x04<<18)|0x09111, (0x05<<18)|0x28986}, // channe1 11
+ {(0x03<<18)|0x30942, (0x04<<18)|0x0bbbb, (0x05<<18)|0x28986}, // channe1 12
+ {(0x03<<18)|0x30943, (0x04<<18)|0x0accc, (0x05<<18)|0x28986} // channe1 13
+};
+
+u32 maxim_317_channel_data_50[][3] =
+{
+ {(0x03<<18)|0x33cc0, (0x04<<18)|0x0b333, (0x05<<18)|0x2a986}, // channel 36
+ {(0x03<<18)|0x302c0, (0x04<<18)|0x08000, (0x05<<18)|0x2a986}, // channel 40
+ {(0x03<<18)|0x302c3, (0x04<<18)|0x0accc, (0x05<<18)|0x2a986}, // channel 44
+ {(0x03<<18)|0x322c1, (0x04<<18)|0x09666, (0x05<<18)|0x2a986}, // channel 48
+ {(0x03<<18)|0x312c2, (0x04<<18)|0x09999, (0x05<<18)|0x2a986}, // channel 52
+ {(0x03<<18)|0x332c0, (0x04<<18)|0x0b333, (0x05<<18)|0x2a99e}, // channel 56
+ {(0x03<<18)|0x30ac0, (0x04<<18)|0x08000, (0x05<<18)|0x2a99e}, // channel 60
+ {(0x03<<18)|0x30ac3, (0x04<<18)|0x0accc, (0x05<<18)|0x2a99e} // channel 64
+};
+
+u32 maxim_317_power_data_24[] = {(0x0C<<18)|0x0c000, (0x0C<<18)|0x0c100};
+u32 maxim_317_power_data_50[] = {(0x0C<<18)|0x0c000, (0x0C<<18)|0x0c100};
+
+/*****************************************************************************
+;;AL2230 MP (Mass Production Version)
+;;RF Registers Setting for Airoha AL2230 silicon after June 1st, 2004
+;;Updated by Tiger Huang (June 1st, 2004)
+;;20-bit length and LSB first
+
+;;Ch01 (2412MHz) ;0x00 0x09EFC ;0x01 0x8CCCC;
+;;Ch02 (2417MHz) ;0x00 0x09EFC ;0x01 0x8CCCD;
+;;Ch03 (2422MHz) ;0x00 0x09E7C ;0x01 0x8CCCC;
+;;Ch04 (2427MHz) ;0x00 0x09E7C ;0x01 0x8CCCD;
+;;Ch05 (2432MHz) ;0x00 0x05EFC ;0x01 0x8CCCC;
+;;Ch06 (2437MHz) ;0x00 0x05EFC ;0x01 0x8CCCD;
+;;Ch07 (2442MHz) ;0x00 0x05E7C ;0x01 0x8CCCC;
+;;Ch08 (2447MHz) ;0x00 0x05E7C ;0x01 0x8CCCD;
+;;Ch09 (2452MHz) ;0x00 0x0DEFC ;0x01 0x8CCCC;
+;;Ch10 (2457MHz) ;0x00 0x0DEFC ;0x01 0x8CCCD;
+;;Ch11 (2462MHz) ;0x00 0x0DE7C ;0x01 0x8CCCC;
+;;Ch12 (2467MHz) ;0x00 0x0DE7C ;0x01 0x8CCCD;
+;;Ch13 (2472MHz) ;0x00 0x03EFC ;0x01 0x8CCCC;
+;;Ch14 (2484Mhz) ;0x00 0x03E7C ;0x01 0x86666;
+
+0x02 0x401D8; RXDCOC BW 100Hz for RXHP low
+;;0x02 0x481DC; RXDCOC BW 30Khz for RXHP low
+
+0x03 0xCFFF0
+0x04 0x23800
+0x05 0xA3B72
+0x06 0x6DA01
+0x07 0xE1688
+0x08 0x11600
+0x09 0x99E02
+0x0A 0x5DDB0
+0x0B 0xD9900
+0x0C 0x3FFBD
+0x0D 0xB0000
+0x0F 0xF00A0
+
+;RF Calibration for Airoha AL2230
+;Edit by Ben Chang (01/30/04)
+;Updated by Tiger Huang (03/03/04)
+0x0f 0xf00a0 ; Initial Setting
+0x0f 0xf00b0 ; Activate TX DCC
+0x0f 0xf02a0 ; Activate Phase Calibration
+0x0f 0xf00e0 ; Activate Filter RC Calibration
+0x0f 0xf00a0 ; Restore Initial Setting
+*****************************************************************************/
+
+u32 al2230_rf_data[] =
+{
+ (0x00<<20)|0x09EFC,
+ (0x01<<20)|0x8CCCC,
+ (0x02<<20)|0x40058,// 20060627 Anson 0x401D8,
+ (0x03<<20)|0xCFFF0,
+ (0x04<<20)|0x24100,// 20060627 Anson 0x23800,
+ (0x05<<20)|0xA3B2F,// 20060627 Anson 0xA3B72
+ (0x06<<20)|0x6DA01,
+ (0x07<<20)|0xE3628,// 20060627 Anson 0xE1688,
+ (0x08<<20)|0x11600,
+ (0x09<<20)|0x9DC02,// 20060627 Anosn 0x97602,//0x99E02, //0x9AE02
+ (0x0A<<20)|0x5ddb0, // 941206 For QCOM interference 0x588b0,//0x5DDB0, 940601 adj 0x5aa30 for bluetooth
+ (0x0B<<20)|0xD9900,
+ (0x0C<<20)|0x3FFBD,
+ (0x0D<<20)|0xB0000,
+ (0x0F<<20)|0xF01A0 // 20060627 Anson 0xF00A0
+};
+
+u32 al2230s_rf_data[] =
+{
+ (0x00<<20)|0x09EFC,
+ (0x01<<20)|0x8CCCC,
+ (0x02<<20)|0x40058,// 20060419 0x401D8,
+ (0x03<<20)|0xCFFF0,
+ (0x04<<20)|0x24100,// 20060419 0x23800,
+ (0x05<<20)|0xA3B2F,// 20060419 0xA3B72,
+ (0x06<<20)|0x6DA01,
+ (0x07<<20)|0xE3628,// 20060419 0xE1688,
+ (0x08<<20)|0x11600,
+ (0x09<<20)|0x9DC02,// 20060419 0x97602,//0x99E02, //0x9AE02
+ (0x0A<<20)|0x5DDB0,// 941206 For QCOM interference 0x588b0,//0x5DDB0, 940601 adj 0x5aa30 for bluetooth
+ (0x0B<<20)|0xD9900,
+ (0x0C<<20)|0x3FFBD,
+ (0x0D<<20)|0xB0000,
+ (0x0F<<20)|0xF01A0 // 20060419 0xF00A0
+};
+
+u32 al2230_channel_data_24[][2] =
+{
+ {(0x00<<20)|0x09EFC, (0x01<<20)|0x8CCCC}, // channe1 01
+ {(0x00<<20)|0x09EFC, (0x01<<20)|0x8CCCD}, // channe1 02
+ {(0x00<<20)|0x09E7C, (0x01<<20)|0x8CCCC}, // channe1 03
+ {(0x00<<20)|0x09E7C, (0x01<<20)|0x8CCCD}, // channe1 04
+ {(0x00<<20)|0x05EFC, (0x01<<20)|0x8CCCC}, // channe1 05
+ {(0x00<<20)|0x05EFC, (0x01<<20)|0x8CCCD}, // channe1 06
+ {(0x00<<20)|0x05E7C, (0x01<<20)|0x8CCCC}, // channe1 07
+ {(0x00<<20)|0x05E7C, (0x01<<20)|0x8CCCD}, // channe1 08
+ {(0x00<<20)|0x0DEFC, (0x01<<20)|0x8CCCC}, // channe1 09
+ {(0x00<<20)|0x0DEFC, (0x01<<20)|0x8CCCD}, // channe1 10
+ {(0x00<<20)|0x0DE7C, (0x01<<20)|0x8CCCC}, // channe1 11
+ {(0x00<<20)|0x0DE7C, (0x01<<20)|0x8CCCD}, // channe1 12
+ {(0x00<<20)|0x03EFC, (0x01<<20)|0x8CCCC}, // channe1 13
+ {(0x00<<20)|0x03E7C, (0x01<<20)|0x86666} // channe1 14
+};
+
+// Current setting. u32 airoha_power_data_24[] = {(0x09<<20)|0x90202, (0x09<<20)|0x96602, (0x09<<20)|0x97602};
+#define AIROHA_TXVGA_LOW_INDEX 31 // Index for 0x90202
+#define AIROHA_TXVGA_MIDDLE_INDEX 12 // Index for 0x96602
+#define AIROHA_TXVGA_HIGH_INDEX 8 // Index for 0x97602 1.0.24.0 1.0.28.0
+/*
+u32 airoha_power_data_24[] =
+{
+ 0x9FE02, // Max - 0 dB
+ 0x9BE02, // Max - 1 dB
+ 0x9DE02, // Max - 2 dB
+ 0x99E02, // Max - 3 dB
+ 0x9EE02, // Max - 4 dB
+ 0x9AE02, // Max - 5 dB
+ 0x9CE02, // Max - 6 dB
+ 0x98E02, // Max - 7 dB
+ 0x97602, // Max - 8 dB
+ 0x93602, // Max - 9 dB
+ 0x95602, // Max - 10 dB
+ 0x91602, // Max - 11 dB
+ 0x96602, // Max - 12 dB
+ 0x92602, // Max - 13 dB
+ 0x94602, // Max - 14 dB
+ 0x90602, // Max - 15 dB
+ 0x97A02, // Max - 16 dB
+ 0x93A02, // Max - 17 dB
+ 0x95A02, // Max - 18 dB
+ 0x91A02, // Max - 19 dB
+ 0x96A02, // Max - 20 dB
+ 0x92A02, // Max - 21 dB
+ 0x94A02, // Max - 22 dB
+ 0x90A02, // Max - 23 dB
+ 0x97202, // Max - 24 dB
+ 0x93202, // Max - 25 dB
+ 0x95202, // Max - 26 dB
+ 0x91202, // Max - 27 dB
+ 0x96202, // Max - 28 dB
+ 0x92202, // Max - 29 dB
+ 0x94202, // Max - 30 dB
+ 0x90202 // Max - 31 dB
+};
+*/
+
+// 20040927 1.1.69.1000 ybjiang
+// from John
+u32 al2230_txvga_data[][2] =
+{
+ //value , index
+ {0x090202, 0},
+ {0x094202, 2},
+ {0x092202, 4},
+ {0x096202, 6},
+ {0x091202, 8},
+ {0x095202, 10},
+ {0x093202, 12},
+ {0x097202, 14},
+ {0x090A02, 16},
+ {0x094A02, 18},
+ {0x092A02, 20},
+ {0x096A02, 22},
+ {0x091A02, 24},
+ {0x095A02, 26},
+ {0x093A02, 28},
+ {0x097A02, 30},
+ {0x090602, 32},
+ {0x094602, 34},
+ {0x092602, 36},
+ {0x096602, 38},
+ {0x091602, 40},
+ {0x095602, 42},
+ {0x093602, 44},
+ {0x097602, 46},
+ {0x090E02, 48},
+ {0x098E02, 49},
+ {0x094E02, 50},
+ {0x09CE02, 51},
+ {0x092E02, 52},
+ {0x09AE02, 53},
+ {0x096E02, 54},
+ {0x09EE02, 55},
+ {0x091E02, 56},
+ {0x099E02, 57},
+ {0x095E02, 58},
+ {0x09DE02, 59},
+ {0x093E02, 60},
+ {0x09BE02, 61},
+ {0x097E02, 62},
+ {0x09FE02, 63}
+};
+
+//--------------------------------
+// For Airoha AL7230, 2.4Ghz band
+// Edit by Tiger, (March, 9, 2005)
+// 24bit, MSB first
+
+//channel independent registers:
+u32 al7230_rf_data_24[] =
+{
+ (0x00<<24)|0x003790,
+ (0x01<<24)|0x133331,
+ (0x02<<24)|0x841FF2,
+ (0x03<<24)|0x3FDFA3,
+ (0x04<<24)|0x7FD784,
+ (0x05<<24)|0x802B55,
+ (0x06<<24)|0x56AF36,
+ (0x07<<24)|0xCE0207,
+ (0x08<<24)|0x6EBC08,
+ (0x09<<24)|0x221BB9,
+ (0x0A<<24)|0xE0000A,
+ (0x0B<<24)|0x08071B,
+ (0x0C<<24)|0x000A3C,
+ (0x0D<<24)|0xFFFFFD,
+ (0x0E<<24)|0x00000E,
+ (0x0F<<24)|0x1ABA8F
+};
+
+u32 al7230_channel_data_24[][2] =
+{
+ {(0x00<<24)|0x003790, (0x01<<24)|0x133331}, // channe1 01
+ {(0x00<<24)|0x003790, (0x01<<24)|0x1B3331}, // channe1 02
+ {(0x00<<24)|0x003790, (0x01<<24)|0x033331}, // channe1 03
+ {(0x00<<24)|0x003790, (0x01<<24)|0x0B3331}, // channe1 04
+ {(0x00<<24)|0x0037A0, (0x01<<24)|0x133331}, // channe1 05
+ {(0x00<<24)|0x0037A0, (0x01<<24)|0x1B3331}, // channe1 06
+ {(0x00<<24)|0x0037A0, (0x01<<24)|0x033331}, // channe1 07
+ {(0x00<<24)|0x0037A0, (0x01<<24)|0x0B3331}, // channe1 08
+ {(0x00<<24)|0x0037B0, (0x01<<24)|0x133331}, // channe1 09
+ {(0x00<<24)|0x0037B0, (0x01<<24)|0x1B3331}, // channe1 10
+ {(0x00<<24)|0x0037B0, (0x01<<24)|0x033331}, // channe1 11
+ {(0x00<<24)|0x0037B0, (0x01<<24)|0x0B3331}, // channe1 12
+ {(0x00<<24)|0x0037C0, (0x01<<24)|0x133331}, // channe1 13
+ {(0x00<<24)|0x0037C0, (0x01<<24)|0x066661} // channel 14
+};
+
+//channel independent registers:
+u32 al7230_rf_data_50[] =
+{
+ (0x00<<24)|0x0FF520,
+ (0x01<<24)|0x000001,
+ (0x02<<24)|0x451FE2,
+ (0x03<<24)|0x5FDFA3,
+ (0x04<<24)|0x6FD784,
+ (0x05<<24)|0x853F55,
+ (0x06<<24)|0x56AF36,
+ (0x07<<24)|0xCE0207,
+ (0x08<<24)|0x6EBC08,
+ (0x09<<24)|0x221BB9,
+ (0x0A<<24)|0xE0600A,
+ (0x0B<<24)|0x08044B,
+ (0x0C<<24)|0x00143C,
+ (0x0D<<24)|0xFFFFFD,
+ (0x0E<<24)|0x00000E,
+ (0x0F<<24)|0x12BACF //5Ghz default state
+};
+
+u32 al7230_channel_data_5[][4] =
+{
+ //channel dependent registers: 0x00, 0x01 and 0x04
+ //11J ===========
+ {184, (0x00<<24)|0x0FF520, (0x01<<24)|0x000001, (0x04<<24)|0x67F784}, // channel 184
+ {188, (0x00<<24)|0x0FF520, (0x01<<24)|0x0AAAA1, (0x04<<24)|0x77F784}, // channel 188
+ {192, (0x00<<24)|0x0FF530, (0x01<<24)|0x155551, (0x04<<24)|0x77F784}, // channel 192
+ {196, (0x00<<24)|0x0FF530, (0x01<<24)|0x000001, (0x04<<24)|0x67F784}, // channel 196
+ {8, (0x00<<24)|0x0FF540, (0x01<<24)|0x000001, (0x04<<24)|0x67F784}, // channel 008
+ {12, (0x00<<24)|0x0FF540, (0x01<<24)|0x0AAAA1, (0x04<<24)|0x77F784}, // channel 012
+ {16, (0x00<<24)|0x0FF550, (0x01<<24)|0x155551, (0x04<<24)|0x77F784}, // channel 016
+ {34, (0x00<<24)|0x0FF560, (0x01<<24)|0x055551, (0x04<<24)|0x77F784}, // channel 034
+ {38, (0x00<<24)|0x0FF570, (0x01<<24)|0x100001, (0x04<<24)|0x77F784}, // channel 038
+ {42, (0x00<<24)|0x0FF570, (0x01<<24)|0x1AAAA1, (0x04<<24)|0x77F784}, // channel 042
+ {46, (0x00<<24)|0x0FF570, (0x01<<24)|0x055551, (0x04<<24)|0x77F784}, // channel 046
+ //11 A/H =========
+ {36, (0x00<<24)|0x0FF560, (0x01<<24)|0x0AAAA1, (0x04<<24)|0x77F784}, // channel 036
+ {40, (0x00<<24)|0x0FF570, (0x01<<24)|0x155551, (0x04<<24)|0x77F784}, // channel 040
+ {44, (0x00<<24)|0x0FF570, (0x01<<24)|0x000001, (0x04<<24)|0x67F784}, // channel 044
+ {48, (0x00<<24)|0x0FF570, (0x01<<24)|0x0AAAA1, (0x04<<24)|0x77F784}, // channel 048
+ {52, (0x00<<24)|0x0FF580, (0x01<<24)|0x155551, (0x04<<24)|0x77F784}, // channel 052
+ {56, (0x00<<24)|0x0FF580, (0x01<<24)|0x000001, (0x04<<24)|0x67F784}, // channel 056
+ {60, (0x00<<24)|0x0FF580, (0x01<<24)|0x0AAAA1, (0x04<<24)|0x77F784}, // channel 060
+ {64, (0x00<<24)|0x0FF590, (0x01<<24)|0x155551, (0x04<<24)|0x77F784}, // channel 064
+ {100, (0x00<<24)|0x0FF5C0, (0x01<<24)|0x155551, (0x04<<24)|0x77F784}, // channel 100
+ {104, (0x00<<24)|0x0FF5C0, (0x01<<24)|0x000001, (0x04<<24)|0x67F784}, // channel 104
+ {108, (0x00<<24)|0x0FF5C0, (0x01<<24)|0x0AAAA1, (0x04<<24)|0x77F784}, // channel 108
+ {112, (0x00<<24)|0x0FF5D0, (0x01<<24)|0x155551, (0x04<<24)|0x77F784}, // channel 112
+ {116, (0x00<<24)|0x0FF5D0, (0x01<<24)|0x000001, (0x04<<24)|0x67F784}, // channel 116
+ {120, (0x00<<24)|0x0FF5D0, (0x01<<24)|0x0AAAA1, (0x04<<24)|0x77F784}, // channel 120
+ {124, (0x00<<24)|0x0FF5E0, (0x01<<24)|0x155551, (0x04<<24)|0x77F784}, // channel 124
+ {128, (0x00<<24)|0x0FF5E0, (0x01<<24)|0x000001, (0x04<<24)|0x67F784}, // channel 128
+ {132, (0x00<<24)|0x0FF5E0, (0x01<<24)|0x0AAAA1, (0x04<<24)|0x77F784}, // channel 132
+ {136, (0x00<<24)|0x0FF5F0, (0x01<<24)|0x155551, (0x04<<24)|0x77F784}, // channel 136
+ {140, (0x00<<24)|0x0FF5F0, (0x01<<24)|0x000001, (0x04<<24)|0x67F784}, // channel 140
+ {149, (0x00<<24)|0x0FF600, (0x01<<24)|0x180001, (0x04<<24)|0x77F784}, // channel 149
+ {153, (0x00<<24)|0x0FF600, (0x01<<24)|0x02AAA1, (0x04<<24)|0x77F784}, // channel 153
+ {157, (0x00<<24)|0x0FF600, (0x01<<24)|0x0D5551, (0x04<<24)|0x77F784}, // channel 157
+ {161, (0x00<<24)|0x0FF610, (0x01<<24)|0x180001, (0x04<<24)|0x77F784}, // channel 161
+ {165, (0x00<<24)|0x0FF610, (0x01<<24)|0x02AAA1, (0x04<<24)|0x77F784} // channel 165
+};
+
+//; RF Calibration <=== Register 0x0F
+//0x0F 0x1ABA8F; start from 2.4Ghz default state
+//0x0F 0x9ABA8F; TXDC compensation
+//0x0F 0x3ABA8F; RXFIL adjustment
+//0x0F 0x1ABA8F; restore 2.4Ghz default state
+
+//;TXVGA Mapping Table <=== Register 0x0B
+u32 al7230_txvga_data[][2] =
+{
+ {0x08040B, 0}, //TXVGA=0;
+ {0x08041B, 1}, //TXVGA=1;
+ {0x08042B, 2}, //TXVGA=2;
+ {0x08043B, 3}, //TXVGA=3;
+ {0x08044B, 4}, //TXVGA=4;
+ {0x08045B, 5}, //TXVGA=5;
+ {0x08046B, 6}, //TXVGA=6;
+ {0x08047B, 7}, //TXVGA=7;
+ {0x08048B, 8}, //TXVGA=8;
+ {0x08049B, 9}, //TXVGA=9;
+ {0x0804AB, 10}, //TXVGA=10;
+ {0x0804BB, 11}, //TXVGA=11;
+ {0x0804CB, 12}, //TXVGA=12;
+ {0x0804DB, 13}, //TXVGA=13;
+ {0x0804EB, 14}, //TXVGA=14;
+ {0x0804FB, 15}, //TXVGA=15;
+ {0x08050B, 16}, //TXVGA=16;
+ {0x08051B, 17}, //TXVGA=17;
+ {0x08052B, 18}, //TXVGA=18;
+ {0x08053B, 19}, //TXVGA=19;
+ {0x08054B, 20}, //TXVGA=20;
+ {0x08055B, 21}, //TXVGA=21;
+ {0x08056B, 22}, //TXVGA=22;
+ {0x08057B, 23}, //TXVGA=23;
+ {0x08058B, 24}, //TXVGA=24;
+ {0x08059B, 25}, //TXVGA=25;
+ {0x0805AB, 26}, //TXVGA=26;
+ {0x0805BB, 27}, //TXVGA=27;
+ {0x0805CB, 28}, //TXVGA=28;
+ {0x0805DB, 29}, //TXVGA=29;
+ {0x0805EB, 30}, //TXVGA=30;
+ {0x0805FB, 31}, //TXVGA=31;
+ {0x08060B, 32}, //TXVGA=32;
+ {0x08061B, 33}, //TXVGA=33;
+ {0x08062B, 34}, //TXVGA=34;
+ {0x08063B, 35}, //TXVGA=35;
+ {0x08064B, 36}, //TXVGA=36;
+ {0x08065B, 37}, //TXVGA=37;
+ {0x08066B, 38}, //TXVGA=38;
+ {0x08067B, 39}, //TXVGA=39;
+ {0x08068B, 40}, //TXVGA=40;
+ {0x08069B, 41}, //TXVGA=41;
+ {0x0806AB, 42}, //TXVGA=42;
+ {0x0806BB, 43}, //TXVGA=43;
+ {0x0806CB, 44}, //TXVGA=44;
+ {0x0806DB, 45}, //TXVGA=45;
+ {0x0806EB, 46}, //TXVGA=46;
+ {0x0806FB, 47}, //TXVGA=47;
+ {0x08070B, 48}, //TXVGA=48;
+ {0x08071B, 49}, //TXVGA=49;
+ {0x08072B, 50}, //TXVGA=50;
+ {0x08073B, 51}, //TXVGA=51;
+ {0x08074B, 52}, //TXVGA=52;
+ {0x08075B, 53}, //TXVGA=53;
+ {0x08076B, 54}, //TXVGA=54;
+ {0x08077B, 55}, //TXVGA=55;
+ {0x08078B, 56}, //TXVGA=56;
+ {0x08079B, 57}, //TXVGA=57;
+ {0x0807AB, 58}, //TXVGA=58;
+ {0x0807BB, 59}, //TXVGA=59;
+ {0x0807CB, 60}, //TXVGA=60;
+ {0x0807DB, 61}, //TXVGA=61;
+ {0x0807EB, 62}, //TXVGA=62;
+ {0x0807FB, 63}, //TXVGA=63;
+};
+//--------------------------------
+
+
+//; W89RF242 RFIC SPI programming initial data
+//; Winbond WLAN 11g RFIC BB-SPI register -- version FA5976A rev 1.3b
+//; Update Date: Ocotber 3, 2005 by PP10 Hsiang-Te Ho
+//;
+//; Version 1.3b revision items: (Oct. 1, 2005 by HTHo) for FA5976A
+u32 w89rf242_rf_data[] =
+{
+ (0x00<<24)|0xF86100, // 20060721 0xF86100, //; 3E184; MODA (0x00) -- Normal mode ; calibration off
+ (0x01<<24)|0xEFFFC2, //; 3BFFF; MODB (0x01) -- turn off RSSI, and other circuits are turned on
+ (0x02<<24)|0x102504, //; 04094; FSET (0x02) -- default 20MHz crystal ; Icmp=1.5mA
+ (0x03<<24)|0x026286, //; 0098A; FCHN (0x03) -- default CH7, 2442MHz
+ (0x04<<24)|0x000208, // 20060612.1.a 0x0002C8, // 20050818 // 20050816 0x000388
+ //; 02008; FCAL (0x04) -- XTAL Freq Trim=001000 (socket board#1); FA5976AYG_v1.3C
+ (0x05<<24)|0x24C60A, // 20060612.1.a 0x24C58A, // 941003 0x24C48A, // 20050818.2 0x24848A, // 20050818 // 20050816 0x24C48A
+ //; 09316; GANA (0x05) -- TX VGA default (TXVGA=0x18(12)) & TXGPK=110 ; FA5976A_1.3D
+ (0x06<<24)|0x3432CC, // 941003 0x26C34C, // 20050818 0x06B40C
+ //; 0D0CB; GANB (0x06) -- RXDC(DC offset) on; LNA=11; RXVGA=001011(11) ; RXFLSW=11(010001); RXGPK=00; RXGCF=00; -50dBm input
+ (0x07<<24)|0x0C68CE, // 20050818.2 0x0C66CE, // 20050818 // 20050816 0x0C68CE
+ //; 031A3; FILT (0x07) -- TX/RX filter with auto-tuning; TFLBW=011; RFLBW=100
+ (0x08<<24)|0x100010, //; 04000; TCAL (0x08) -- //for LO
+ (0x09<<24)|0x004012, // 20060612.1.a 0x6E4012, // 0x004012,
+ //; 1B900; RCALA (0x09) -- FASTS=11; HPDE=01 (100nsec); SEHP=1 (select B0 pin=RXHP); RXHP=1 (Turn on RXHP function)(FA5976A_1.3C)
+ (0x0A<<24)|0x704014, //; 1C100; RCALB (0x0A)
+ (0x0B<<24)|0x18BDD6, // 941003 0x1805D6, // 20050818.2 0x1801D6, // 20050818 // 20050816 0x1805D6
+ //; 062F7; IQCAL (0x0B) -- Turn on LO phase tuner=0111 & RX-LO phase = 0111; FA5976A_1.3B (2005/09/29)
+ (0x0C<<24)|0x575558, // 20050818.2 0x555558, // 20050818 // 20050816 0x575558
+ //; 15D55 ; IBSA (0x0C) -- IFPre =11 ; TC5376A_v1.3A for corner
+ (0x0D<<24)|0x55545A, // 20060612.1.a 0x55555A,
+ //; 15555 ; IBSB (0x0D)
+ (0x0E<<24)|0x5557DC, // 20060612.1.a 0x55555C, // 941003 0x5557DC,
+ //; 1555F ; IBSC (0x0E) -- IRLNA & IRLNB (PTAT & Const current)=01/01; FA5976B_1.3F (2005/11/25)
+ (0x10<<24)|0x000C20, // 941003 0x000020, // 20050818
+ //; 00030 ; TMODA (0x10) -- LNA_gain_step=0011 ; LNA=15/16dB
+ (0x11<<24)|0x0C0022, // 941003 0x030022 // 20050818.2 0x030022 // 20050818 // 20050816 0x0C0022
+ //; 03000 ; TMODB (0x11) -- Turn ON RX-Q path Test Switch; To improve IQ path group delay (FA5976A_1.3C)
+ (0x12<<24)|0x000024 // 20060612.1.a 0x001824 // 941003 add
+ //; TMODC (0x12) -- Turn OFF Tempearure sensor
+};
+
+u32 w89rf242_channel_data_24[][2] =
+{
+ {(0x03<<24)|0x025B06, (0x04<<24)|0x080408}, // channe1 01
+ {(0x03<<24)|0x025C46, (0x04<<24)|0x080408}, // channe1 02
+ {(0x03<<24)|0x025D86, (0x04<<24)|0x080408}, // channe1 03
+ {(0x03<<24)|0x025EC6, (0x04<<24)|0x080408}, // channe1 04
+ {(0x03<<24)|0x026006, (0x04<<24)|0x080408}, // channe1 05
+ {(0x03<<24)|0x026146, (0x04<<24)|0x080408}, // channe1 06
+ {(0x03<<24)|0x026286, (0x04<<24)|0x080408}, // channe1 07
+ {(0x03<<24)|0x0263C6, (0x04<<24)|0x080408}, // channe1 08
+ {(0x03<<24)|0x026506, (0x04<<24)|0x080408}, // channe1 09
+ {(0x03<<24)|0x026646, (0x04<<24)|0x080408}, // channe1 10
+ {(0x03<<24)|0x026786, (0x04<<24)|0x080408}, // channe1 11
+ {(0x03<<24)|0x0268C6, (0x04<<24)|0x080408}, // channe1 12
+ {(0x03<<24)|0x026A06, (0x04<<24)|0x080408}, // channe1 13
+ {(0x03<<24)|0x026D06, (0x04<<24)|0x080408} // channe1 14
+};
+
+u32 w89rf242_power_data_24[] = {(0x05<<24)|0x24C48A, (0x05<<24)|0x24C48A, (0x05<<24)|0x24C48A};
+
+// 20060315.6 Enlarge for new scale
+// 20060316.6 20060619.2.a add mapping array
+u32 w89rf242_txvga_old_mapping[][2] =
+{
+ {0, 0} , // New <-> Old
+ {1, 1} ,
+ {2, 2} ,
+ {3, 3} ,
+ {4, 4} ,
+ {6, 5} ,
+ {8, 6 },
+ {10, 7 },
+ {12, 8 },
+ {14, 9 },
+ {16, 10},
+ {18, 11},
+ {20, 12},
+ {22, 13},
+ {24, 14},
+ {26, 15},
+ {28, 16},
+ {30, 17},
+ {32, 18},
+ {34, 19},
+
+
+};
+
+// 20060619.3 modify from Bruce's mail
+u32 w89rf242_txvga_data[][5] =
+{
+ //low gain mode
+ { (0x05<<24)|0x24C00A, 0, 0x00292315, 0x0800FEFF, 0x52523131 },// ; min gain
+ { (0x05<<24)|0x24C80A, 1, 0x00292315, 0x0800FEFF, 0x52523131 },
+ { (0x05<<24)|0x24C04A, 2, 0x00292315, 0x0800FEFF, 0x52523131 },// (default) +14dBm (ANT)
+ { (0x05<<24)|0x24C84A, 3, 0x00292315, 0x0800FEFF, 0x52523131 },
+
+ //TXVGA=0x10
+ { (0x05<<24)|0x24C40A, 4, 0x00292315, 0x0800FEFF, 0x60603838 },
+ { (0x05<<24)|0x24C40A, 5, 0x00262114, 0x0700FEFF, 0x65653B3B },
+
+ //TXVGA=0x11
+ { (0x05<<24)|0x24C44A, 6, 0x00241F13, 0x0700FFFF, 0x58583333 },
+ { (0x05<<24)|0x24C44A, 7, 0x00292315, 0x0800FEFF, 0x5E5E3737 },
+
+ //TXVGA=0x12
+ { (0x05<<24)|0x24C48A, 8, 0x00262114, 0x0700FEFF, 0x53533030 },
+ { (0x05<<24)|0x24C48A, 9, 0x00241F13, 0x0700FFFF, 0x59593434 },
+
+ //TXVGA=0x13
+ { (0x05<<24)|0x24C4CA, 10, 0x00292315, 0x0800FEFF, 0x52523030 },
+ { (0x05<<24)|0x24C4CA, 11, 0x00262114, 0x0700FEFF, 0x56563232 },
+
+ //TXVGA=0x14
+ { (0x05<<24)|0x24C50A, 12, 0x00292315, 0x0800FEFF, 0x54543131 },
+ { (0x05<<24)|0x24C50A, 13, 0x00262114, 0x0700FEFF, 0x58583434 },
+
+ //TXVGA=0x15
+ { (0x05<<24)|0x24C54A, 14, 0x00292315, 0x0800FEFF, 0x54543131 },
+ { (0x05<<24)|0x24C54A, 15, 0x00262114, 0x0700FEFF, 0x59593434 },
+
+ //TXVGA=0x16
+ { (0x05<<24)|0x24C58A, 16, 0x00292315, 0x0800FEFF, 0x55553131 },
+ { (0x05<<24)|0x24C58A, 17, 0x00292315, 0x0800FEFF, 0x5B5B3535 },
+
+ //TXVGA=0x17
+ { (0x05<<24)|0x24C5CA, 18, 0x00262114, 0x0700FEFF, 0x51512F2F },
+ { (0x05<<24)|0x24C5CA, 19, 0x00241F13, 0x0700FFFF, 0x55553131 },
+
+ //TXVGA=0x18
+ { (0x05<<24)|0x24C60A, 20, 0x00292315, 0x0800FEFF, 0x4F4F2E2E },
+ { (0x05<<24)|0x24C60A, 21, 0x00262114, 0x0700FEFF, 0x53533030 },
+
+ //TXVGA=0x19
+ { (0x05<<24)|0x24C64A, 22, 0x00292315, 0x0800FEFF, 0x4E4E2D2D },
+ { (0x05<<24)|0x24C64A, 23, 0x00262114, 0x0700FEFF, 0x53533030 },
+
+ //TXVGA=0x1A
+ { (0x05<<24)|0x24C68A, 24, 0x00292315, 0x0800FEFF, 0x50502E2E },
+ { (0x05<<24)|0x24C68A, 25, 0x00262114, 0x0700FEFF, 0x55553131 },
+
+ //TXVGA=0x1B
+ { (0x05<<24)|0x24C6CA, 26, 0x00262114, 0x0700FEFF, 0x53533030 },
+ { (0x05<<24)|0x24C6CA, 27, 0x00292315, 0x0800FEFF, 0x5A5A3434 },
+
+ //TXVGA=0x1C
+ { (0x05<<24)|0x24C70A, 28, 0x00292315, 0x0800FEFF, 0x55553131 },
+ { (0x05<<24)|0x24C70A, 29, 0x00292315, 0x0800FEFF, 0x5D5D3636 },
+
+ //TXVGA=0x1D
+ { (0x05<<24)|0x24C74A, 30, 0x00292315, 0x0800FEFF, 0x5F5F3737 },
+ { (0x05<<24)|0x24C74A, 31, 0x00262114, 0x0700FEFF, 0x65653B3B },
+
+ //TXVGA=0x1E
+ { (0x05<<24)|0x24C78A, 32, 0x00292315, 0x0800FEFF, 0x66663B3B },
+ { (0x05<<24)|0x24C78A, 33, 0x00262114, 0x0700FEFF, 0x70704141 },
+
+ //TXVGA=0x1F
+ { (0x05<<24)|0x24C7CA, 34, 0x00292315, 0x0800FEFF, 0x72724242 }
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+
+//=============================================================================================================
+// Uxx_ReadEthernetAddress --
+//
+// Routine Description:
+// Reads in the Ethernet address from the IC.
+//
+// Arguments:
+// pHwData - The pHwData structure
+//
+// Return Value:
+//
+// The address is stored in EthernetIDAddr.
+//=============================================================================================================
+void
+Uxx_ReadEthernetAddress( phw_data_t pHwData )
+{
+ u32 ltmp;
+
+ // Reading Ethernet address from EEPROM and set into hardware due to MAC address maybe change.
+ // Only unplug and plug again can make hardware read EEPROM again. 20060727
+ Wb35Reg_WriteSync( pHwData, 0x03b4, 0x08000000 ); // Start EEPROM access + Read + address(0x0d)
+ Wb35Reg_ReadSync( pHwData, 0x03b4, <mp );
+ *(PUSHORT)pHwData->PermanentMacAddress = cpu_to_le16((u16)ltmp); //20060926 anson's endian
+ Wb35Reg_WriteSync( pHwData, 0x03b4, 0x08010000 ); // Start EEPROM access + Read + address(0x0d)
+ Wb35Reg_ReadSync( pHwData, 0x03b4, <mp );
+ *(PUSHORT)(pHwData->PermanentMacAddress + 2) = cpu_to_le16((u16)ltmp); //20060926 anson's endian
+ Wb35Reg_WriteSync( pHwData, 0x03b4, 0x08020000 ); // Start EEPROM access + Read + address(0x0d)
+ Wb35Reg_ReadSync( pHwData, 0x03b4, <mp );
+ *(PUSHORT)(pHwData->PermanentMacAddress + 4) = cpu_to_le16((u16)ltmp); //20060926 anson's endian
+ *(PUSHORT)(pHwData->PermanentMacAddress + 6) = 0;
+ Wb35Reg_WriteSync( pHwData, 0x03e8, cpu_to_le32(*(PULONG)pHwData->PermanentMacAddress) ); //20060926 anson's endian
+ Wb35Reg_WriteSync( pHwData, 0x03ec, cpu_to_le32(*(PULONG)(pHwData->PermanentMacAddress+4)) ); //20060926 anson's endian
+}
+
+
+//===============================================================================================================
+// CardGetMulticastBit --
+// Description:
+// For a given multicast address, returns the byte and bit in the card multicast registers that it hashes to.
+// Calls CardComputeCrc() to determine the CRC value.
+// Arguments:
+// Address - the address
+// Byte - the byte that it hashes to
+// Value - will have a 1 in the relevant bit
+// Return Value:
+// None.
+//==============================================================================================================
+void CardGetMulticastBit( u8 Address[ETH_LENGTH_OF_ADDRESS],
+ u8 *Byte, u8 *Value )
+{
+ u32 Crc;
+ u32 BitNumber;
+
+ // First compute the CRC.
+ Crc = CardComputeCrc(Address, ETH_LENGTH_OF_ADDRESS);
+
+ // The computed CRC is bit0~31 from left to right
+ //At first we should do right shift 25bits, and read 7bits by using '&', 2^7=128
+ BitNumber = (u32) ((Crc >> 26) & 0x3f);
+
+ *Byte = (u8) (BitNumber >> 3);// 900514 original (BitNumber / 8)
+ *Value = (u8) ((u8)1 << (BitNumber % 8));
+}
+
+void Uxx_power_on_procedure( phw_data_t pHwData )
+{
+ u32 ltmp, loop;
+
+ if( pHwData->phy_type <= RF_MAXIM_V1 )
+ Wb35Reg_WriteSync( pHwData, 0x03d4, 0xffffff38 );
+ else
+ {
+ Wb35Reg_WriteSync( pHwData, 0x03f4, 0xFF5807FF );// 20060721 For NEW IC 0xFF5807FF
+
+ // 20060511.1 Fix the following 4 steps for Rx of RF 2230 initial fail
+ Wb35Reg_WriteSync( pHwData, 0x03d4, 0x80 );// regulator on only
+ OS_SLEEP(10000); // Modify 20051221.1.b
+ Wb35Reg_WriteSync( pHwData, 0x03d4, 0xb8 );// REG_ON RF_RSTN on, and
+ OS_SLEEP(10000); // Modify 20051221.1.b
+
+ ltmp = 0x4968;
+ if( (pHwData->phy_type == RF_WB_242) ||
+ (RF_WB_242_1 == pHwData->phy_type) ) // 20060619.5 Add
+ ltmp = 0x4468;
+ Wb35Reg_WriteSync( pHwData, 0x03d0, ltmp );
+
+ Wb35Reg_WriteSync( pHwData, 0x03d4, 0xa0 );// PLL_PD REF_PD set to 0
+
+ OS_SLEEP(20000); // Modify 20051221.1.b
+ Wb35Reg_ReadSync( pHwData, 0x03d0, <mp );
+ loop = 500; // Wait for 5 second 20061101
+ while( !(ltmp & 0x20) && loop-- )
+ {
+ OS_SLEEP(10000); // Modify 20051221.1.b
+ if( !Wb35Reg_ReadSync( pHwData, 0x03d0, <mp ) )
+ break;
+ }
+
+ Wb35Reg_WriteSync( pHwData, 0x03d4, 0xe0 );// MLK_EN
+ }
+
+ Wb35Reg_WriteSync( pHwData, 0x03b0, 1 );// Reset hardware first
+ OS_SLEEP(10000); // Add this 20051221.1.b
+
+ // Set burst write delay
+ Wb35Reg_WriteSync( pHwData, 0x03f8, 0x7ff );
+}
+
+void Set_ChanIndep_RfData_al7230_24( phw_data_t pHwData, u32 *pltmp ,char number)
+{
+ u8 i;
+
+ for( i=0; i<number; i++ )
+ {
+ pHwData->phy_para[i] = al7230_rf_data_24[i];
+ pltmp[i] = (1 << 31) | (0 << 30) | (24 << 24) | (al7230_rf_data_24[i]&0xffffff);
+ }
+}
+
+void Set_ChanIndep_RfData_al7230_50( phw_data_t pHwData, u32 *pltmp, char number)
+{
+ u8 i;
+
+ for( i=0; i<number; i++ )
+ {
+ pHwData->phy_para[i] = al7230_rf_data_50[i];
+ pltmp[i] = (1 << 31) | (0 << 30) | (24 << 24) | (al7230_rf_data_50[i]&0xffffff);
+ }
+}
+
+
+//=============================================================================================================
+// RFSynthesizer_initial --
+//=============================================================================================================
+void
+RFSynthesizer_initial(phw_data_t pHwData)
+{
+ u32 altmp[32];
+ PULONG pltmp = altmp;
+ u32 ltmp;
+ u8 number=0x00; // The number of register vale
+ u8 i;
+
+ //
+ // bit[31] SPI Enable.
+ // 1=perform synthesizer program operation. This bit will
+ // cleared automatically after the operation is completed.
+ // bit[30] SPI R/W Control
+ // 0=write, 1=read
+ // bit[29:24] SPI Data Format Length
+ // bit[17:4 ] RF Data bits.
+ // bit[3 :0 ] RF address.
+ switch( pHwData->phy_type )
+ {
+ case RF_MAXIM_2825:
+ case RF_MAXIM_V1: // 11g Winbond 2nd BB(with Phy board (v1) + Maxim 331)
+ number = sizeof(max2825_rf_data)/sizeof(max2825_rf_data[0]);
+ for( i=0; i<number; i++ )
+ {
+ pHwData->phy_para[i] = max2825_rf_data[i];// Backup Rf parameter
+ pltmp[i] = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2825_rf_data[i], 18);
+ }
+ break;
+
+ case RF_MAXIM_2827:
+ number = sizeof(max2827_rf_data)/sizeof(max2827_rf_data[0]);
+ for( i=0; i<number; i++ )
+ {
+ pHwData->phy_para[i] = max2827_rf_data[i];
+ pltmp[i] = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2827_rf_data[i], 18);
+ }
+ break;
+
+ case RF_MAXIM_2828:
+ number = sizeof(max2828_rf_data)/sizeof(max2828_rf_data[0]);
+ for( i=0; i<number; i++ )
+ {
+ pHwData->phy_para[i] = max2828_rf_data[i];
+ pltmp[i] = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2828_rf_data[i], 18);
+ }
+ break;
+
+ case RF_MAXIM_2829:
+ number = sizeof(max2829_rf_data)/sizeof(max2829_rf_data[0]);
+ for( i=0; i<number; i++ )
+ {
+ pHwData->phy_para[i] = max2829_rf_data[i];
+ pltmp[i] = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2829_rf_data[i], 18);
+ }
+ break;
+
+ case RF_AIROHA_2230:
+ number = sizeof(al2230_rf_data)/sizeof(al2230_rf_data[0]);
+ for( i=0; i<number; i++ )
+ {
+ pHwData->phy_para[i] = al2230_rf_data[i];
+ pltmp[i] = (1 << 31) | (0 << 30) | (20 << 24) | BitReverse( al2230_rf_data[i], 20);
+ }
+ break;
+
+ case RF_AIROHA_2230S:
+ number = sizeof(al2230s_rf_data)/sizeof(al2230s_rf_data[0]);
+ for( i=0; i<number; i++ )
+ {
+ pHwData->phy_para[i] = al2230s_rf_data[i];
+ pltmp[i] = (1 << 31) | (0 << 30) | (20 << 24) | BitReverse( al2230s_rf_data[i], 20);
+ }
+ break;
+
+ case RF_AIROHA_7230:
+
+ //Start to fill RF parameters, PLL_ON should be pulled low.
+ Wb35Reg_WriteSync( pHwData, 0x03dc, 0x00000000 );
+#ifdef _PE_STATE_DUMP_
+ WBDEBUG(("* PLL_ON low\n"));
+#endif
+
+ number = sizeof(al7230_rf_data_24)/sizeof(al7230_rf_data_24[0]);
+ Set_ChanIndep_RfData_al7230_24(pHwData, pltmp, number);
+ break;
+
+ case RF_WB_242:
+ case RF_WB_242_1: // 20060619.5 Add
+ number = sizeof(w89rf242_rf_data)/sizeof(w89rf242_rf_data[0]);
+ for( i=0; i<number; i++ )
+ {
+ ltmp = w89rf242_rf_data[i];
+ if( i == 4 ) // Update the VCO trim from EEPROM
+ {
+ ltmp &= ~0xff0; // Mask bit4 ~bit11
+ ltmp |= pHwData->VCO_trim<<4;
+ }
+
+ pHwData->phy_para[i] = ltmp;
+ pltmp[i] = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( ltmp, 24);
+ }
+ break;
+ }
+
+ pHwData->phy_number = number;
+
+ // The 16 is the maximum capability of hardware. Here use 12
+ if( number > 12 ) {
+ //Wb35Reg_BurstWrite( pHwData, 0x0864, pltmp, 12, NO_INCREMENT );
+ for( i=0; i<12; i++ ) // For Al2230
+ Wb35Reg_WriteSync( pHwData, 0x0864, pltmp[i] );
+
+ pltmp += 12;
+ number -= 12;
+ }
+
+ // Write to register. number must less and equal than 16
+ for( i=0; i<number; i++ )
+ Wb35Reg_WriteSync( pHwData, 0x864, pltmp[i] );
+
+ // 20060630.1 Calibration only 1 time
+ if( pHwData->CalOneTime )
+ return;
+ pHwData->CalOneTime = 1;
+
+ switch( pHwData->phy_type )
+ {
+ case RF_AIROHA_2230:
+
+ // 20060511.1 --- Modifying the follow step for Rx issue-----------------
+ ltmp = (1 << 31) | (0 << 30) | (20 << 24) | BitReverse( (0x07<<20)|0xE168E, 20);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ OS_SLEEP(10000);
+ ltmp = (1 << 31) | (0 << 30) | (20 << 24) | BitReverse( al2230_rf_data[7], 20);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ OS_SLEEP(10000);
+
+ case RF_AIROHA_2230S: // 20060420 Add this
+
+ // 20060511.1 --- Modifying the follow step for Rx issue-----------------
+ Wb35Reg_WriteSync( pHwData, 0x03d4, 0x80 );// regulator on only
+ OS_SLEEP(10000); // Modify 20051221.1.b
+
+ Wb35Reg_WriteSync( pHwData, 0x03d4, 0xa0 );// PLL_PD REF_PD set to 0
+ OS_SLEEP(10000); // Modify 20051221.1.b
+
+ Wb35Reg_WriteSync( pHwData, 0x03d4, 0xe0 );// MLK_EN
+ Wb35Reg_WriteSync( pHwData, 0x03b0, 1 );// Reset hardware first
+ OS_SLEEP(10000); // Add this 20051221.1.b
+ //------------------------------------------------------------------------
+
+ // The follow code doesn't use the burst-write mode
+ //phy_set_rf_data(phw_data, 0x0F, (0x0F<<20) | 0xF01A0); //Raise Initial Setting
+ ltmp = (1 << 31) | (0 << 30) | (20 << 24) | BitReverse( (0x0F<<20) | 0xF01A0, 20);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+
+ ltmp = pHwData->Wb35Reg.BB5C & 0xfffff000;
+ Wb35Reg_WriteSync( pHwData, 0x105c, ltmp );
+ pHwData->Wb35Reg.BB50 |= 0x13;//(MASK_IQCAL_MODE|MASK_CALIB_START);//20060315.1 modify
+ Wb35Reg_WriteSync( pHwData, 0x1050, pHwData->Wb35Reg.BB50);
+ OS_SLEEP(5000);
+
+ //phy_set_rf_data(phw_data, 0x0F, (0x0F<<20) | 0xF01B0); //Activate Filter Cal.
+ ltmp = (1 << 31) | (0 << 30) | (20 << 24) | BitReverse( (0x0F<<20) | 0xF01B0, 20);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ OS_SLEEP(5000);
+
+ //phy_set_rf_data(phw_data, 0x0F, (0x0F<<20) | 0xF01e0); //Activate TX DCC
+ ltmp = (1 << 31) | (0 << 30) | (20 << 24) | BitReverse( (0x0F<<20) | 0xF01E0, 20);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ OS_SLEEP(5000);
+
+ //phy_set_rf_data(phw_data, 0x0F, (0x0F<<20) | 0xF01A0); //Resotre Initial Setting
+ ltmp = (1 << 31) | (0 << 30) | (20 << 24) | BitReverse( (0x0F<<20) | 0xF01A0, 20);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+
+// //Force TXI(Q)P(N) to normal control
+ Wb35Reg_WriteSync( pHwData, 0x105c, pHwData->Wb35Reg.BB5C );
+ pHwData->Wb35Reg.BB50 &= ~0x13;//(MASK_IQCAL_MODE|MASK_CALIB_START);
+ Wb35Reg_WriteSync( pHwData, 0x1050, pHwData->Wb35Reg.BB50);
+ break;
+
+ case RF_AIROHA_7230:
+
+ //RF parameters have filled completely, PLL_ON should be
+ //pulled high
+ Wb35Reg_WriteSync( pHwData, 0x03dc, 0x00000080 );
+ #ifdef _PE_STATE_DUMP_
+ WBDEBUG(("* PLL_ON high\n"));
+ #endif
+
+ //2.4GHz
+ //ltmp = (1 << 31) | (0 << 30) | (24 << 24) | 0x1ABA8F;
+ //Wb35Reg_WriteSync pHwData, 0x0864, ltmp );
+ //OS_SLEEP(1000); // Sleep 1 ms
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | 0x9ABA8F;
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ OS_SLEEP(5000);
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | 0x3ABA8F;
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ OS_SLEEP(5000);
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | 0x1ABA8F;
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ OS_SLEEP(5000);
+
+ //5GHz
+ Wb35Reg_WriteSync( pHwData, 0x03dc, 0x00000000 );
+ #ifdef _PE_STATE_DUMP_
+ WBDEBUG(("* PLL_ON low\n"));
+ #endif
+
+ number = sizeof(al7230_rf_data_50)/sizeof(al7230_rf_data_50[0]);
+ Set_ChanIndep_RfData_al7230_50(pHwData, pltmp, number);
+ // Write to register. number must less and equal than 16
+ for( i=0; i<number; i++ )
+ Wb35Reg_WriteSync( pHwData, 0x0864, pltmp[i] );
+ OS_SLEEP(5000);
+
+ Wb35Reg_WriteSync( pHwData, 0x03dc, 0x00000080 );
+ #ifdef _PE_STATE_DUMP_
+ WBDEBUG(("* PLL_ON high\n"));
+ #endif
+
+ //ltmp = (1 << 31) | (0 << 30) | (24 << 24) | 0x12BACF;
+ //Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | 0x9ABA8F;
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ OS_SLEEP(5000);
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | 0x3ABA8F;
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ OS_SLEEP(5000);
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | 0x12BACF;
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ OS_SLEEP(5000);
+
+ //Wb35Reg_WriteSync( pHwData, 0x03dc, 0x00000080 );
+ //WBDEBUG(("* PLL_ON high\n"));
+ break;
+
+ case RF_WB_242:
+ case RF_WB_242_1: // 20060619.5 Add
+
+ //
+ // ; Version 1.3B revision items: for FA5976A , October 3, 2005 by HTHo
+ //
+ ltmp = pHwData->Wb35Reg.BB5C & 0xfffff000;
+ Wb35Reg_WriteSync( pHwData, 0x105c, ltmp );
+ Wb35Reg_WriteSync( pHwData, 0x1058, 0 );
+ pHwData->Wb35Reg.BB50 |= 0x3;//(MASK_IQCAL_MODE|MASK_CALIB_START);//20060630
+ Wb35Reg_WriteSync( pHwData, 0x1050, pHwData->Wb35Reg.BB50);
+
+ //----- Calibration (1). VCO frequency calibration
+ //Calibration (1a.0). Synthesizer reset (HTHo corrected 2005/05/10)
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x0F<<24) | 0x00101E, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ OS_SLEEP( 5000 ); // Sleep 5ms
+ //Calibration (1a). VCO frequency calibration mode ; waiting 2msec VCO calibration time
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFE69c0, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ OS_SLEEP( 2000 ); // Sleep 2ms
+
+ //----- Calibration (2). TX baseband Gm-C filter auto-tuning
+ //Calibration (2a). turn off ENCAL signal
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xF8EBC0, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ //Calibration (2b.0). TX filter auto-tuning BW: TFLBW=101 (TC5376A default)
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x07<<24) | 0x0C68CE, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ //Calibration (2b). send TX reset signal (HTHo corrected May 10, 2005)
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x0F<<24) | 0x00201E, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ //Calibration (2c). turn-on TX Gm-C filter auto-tuning
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFCEBC0, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ OS_SLEEP( 150 ); // Sleep 150 us
+ //turn off ENCAL signal
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xF8EBC0, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+
+ //----- Calibration (3). RX baseband Gm-C filter auto-tuning
+ //Calibration (3a). turn off ENCAL signal
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFAEDC0, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ //Calibration (3b.0). RX filter auto-tuning BW: RFLBW=100 (TC5376A+corner default; July 26, 2005)
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x07<<24) | 0x0C68CE, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ //Calibration (3b). send RX reset signal (HTHo corrected May 10, 2005)
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x0F<<24) | 0x00401E, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ //Calibration (3c). turn-on RX Gm-C filter auto-tuning
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFEEDC0, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ OS_SLEEP( 150 ); // Sleep 150 us
+ //Calibration (3e). turn off ENCAL signal
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFAEDC0, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+
+ //----- Calibration (4). TX LO leakage calibration
+ //Calibration (4a). TX LO leakage calibration
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFD6BC0, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ OS_SLEEP( 150 ); // Sleep 150 us
+
+ //----- Calibration (5). RX DC offset calibration
+ //Calibration (5a). turn off ENCAL signal and set to RX SW DC caliration mode
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFAEDC0, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ //Calibration (5b). turn off AGC servo-loop & RSSI
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x01<<24) | 0xEBFFC2, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+
+ //; for LNA=11 --------
+ //Calibration (5c-h). RX DC offset current bias ON; & LNA=11; RXVGA=111111
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x06<<24) | 0x343FCC, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ //Calibration (5d). turn on RX DC offset cal function; and waiting 2 msec cal time
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFF6DC0, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ OS_SLEEP(2000); // Sleep 2ms
+ //Calibration (5f). turn off ENCAL signal
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFAEDC0, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+
+ //; for LNA=10 --------
+ //Calibration (5c-m). RX DC offset current bias ON; & LNA=10; RXVGA=111111
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x06<<24) | 0x342FCC, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ //Calibration (5d). turn on RX DC offset cal function; and waiting 2 msec cal time
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFF6DC0, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ OS_SLEEP(2000); // Sleep 2ms
+ //Calibration (5f). turn off ENCAL signal
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFAEDC0, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+
+ //; for LNA=01 --------
+ //Calibration (5c-m). RX DC offset current bias ON; & LNA=01; RXVGA=111111
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x06<<24) | 0x341FCC, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ //Calibration (5d). turn on RX DC offset cal function; and waiting 2 msec cal time
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFF6DC0, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ OS_SLEEP(2000); // Sleep 2ms
+ //Calibration (5f). turn off ENCAL signal
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFAEDC0, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+
+ //; for LNA=00 --------
+ //Calibration (5c-l). RX DC offset current bias ON; & LNA=00; RXVGA=111111
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x06<<24) | 0x340FCC, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ //Calibration (5d). turn on RX DC offset cal function; and waiting 2 msec cal time
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFF6DC0, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ OS_SLEEP(2000); // Sleep 2ms
+ //Calibration (5f). turn off ENCAL signal
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xFAEDC0, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ //Calibration (5g). turn on AGC servo-loop
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x01<<24) | 0xEFFFC2, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+
+ //; ----- Calibration (7). Switch RF chip to normal mode
+ //0x00 0xF86100 ; 3E184 ; Switch RF chip to normal mode
+// OS_SLEEP(10000); // @@ 20060721
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( (0x00<<24) | 0xF86100, 24);
+ Wb35Reg_WriteSync( pHwData, 0x0864, ltmp );
+ OS_SLEEP(5000); // Sleep 5 ms
+
+// //write back
+// Wb35Reg_WriteSync( pHwData, 0x105c, pHwData->Wb35Reg.BB5C );
+// pHwData->Wb35Reg.BB50 &= ~0x13;//(MASK_IQCAL_MODE|MASK_CALIB_START); // 20060315.1 fix
+// Wb35Reg_WriteSync( pHwData, 0x1050, pHwData->Wb35Reg.BB50);
+// OS_SLEEP(1000); // Sleep 1 ms
+ break;
+ }
+}
+
+void BBProcessor_AL7230_2400( phw_data_t pHwData)
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ u32 pltmp[12];
+
+ pltmp[0] = 0x16A8337A; // 0x16a5215f; // 0x1000 AGC_Ctrl1
+ pltmp[1] = 0x9AFF9AA6; // 0x9aff9ca6; // 0x1004 AGC_Ctrl2
+ pltmp[2] = 0x55D00A04; // 0x55d00a04; // 0x1008 AGC_Ctrl3
+ pltmp[3] = 0xFFF72031; // 0xFfFf2138; // 0x100c AGC_Ctrl4
+ pWb35Reg->BB0C = 0xFFF72031;
+ pltmp[4] = 0x0FacDCC5; // 0x1010 AGC_Ctrl5 // 20050927 0x0FacDCB7
+ pltmp[5] = 0x00CAA333; // 0x00eaa333; // 0x1014 AGC_Ctrl6
+ pltmp[6] = 0xF2211111; // 0x11111111; // 0x1018 AGC_Ctrl7
+ pltmp[7] = 0x0FA3F0ED; // 0x101c AGC_Ctrl8
+ pltmp[8] = 0x06443440; // 0x1020 AGC_Ctrl9
+ pltmp[9] = 0xA8002A79; // 0xa9002A79; // 0x1024 AGC_Ctrl10
+ pltmp[10] = 0x40000528; // 20050927 0x40000228
+ pltmp[11] = 0x232D7F30; // 0x23457f30;// 0x102c A_ACQ_Ctrl
+ pWb35Reg->BB2C = 0x232D7F30;
+ Wb35Reg_BurstWrite( pHwData, 0x1000, pltmp, 12, AUTO_INCREMENT );
+
+ pltmp[0] = 0x00002c54; // 0x1030 B_ACQ_Ctrl
+ pWb35Reg->BB30 = 0x00002c54;
+ pltmp[1] = 0x00C0D6C5; // 0x1034 A_TXRX_Ctrl
+ pltmp[2] = 0x5B2C8769; // 0x1038 B_TXRX_Ctrl
+ pltmp[3] = 0x00000000; // 0x103c 11a TX LS filter
+ pWb35Reg->BB3C = 0x00000000;
+ pltmp[4] = 0x00003F29; // 0x1040 11a TX LS filter
+ pltmp[5] = 0x0EFEFBFE; // 0x1044 11a TX LS filter
+ pltmp[6] = 0x00332C1B; // 0x00453B24; // 0x1048 11b TX RC filter
+ pltmp[7] = 0x0A00FEFF; // 0x0E00FEFF; // 0x104c 11b TX RC filter
+ pltmp[8] = 0x2B106208; // 0x1050 MODE_Ctrl
+ pWb35Reg->BB50 = 0x2B106208;
+ pltmp[9] = 0; // 0x1054
+ pWb35Reg->BB54 = 0x00000000;
+ pltmp[10] = 0x52524242; // 0x64645252; // 0x1058 IQ_Alpha
+ pWb35Reg->BB58 = 0x52524242;
+ pltmp[11] = 0xAA0AC000; // 0x105c DC_Cancel
+ Wb35Reg_BurstWrite( pHwData, 0x1030, pltmp, 12, AUTO_INCREMENT );
+
+}
+
+void BBProcessor_AL7230_5000( phw_data_t pHwData)
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ u32 pltmp[12];
+
+ pltmp[0] = 0x16AA6678; // 0x1000 AGC_Ctrl1
+ pltmp[1] = 0x9AFFA0B2; // 0x1004 AGC_Ctrl2
+ pltmp[2] = 0x55D00A04; // 0x1008 AGC_Ctrl3
+ pltmp[3] = 0xEFFF233E; // 0x100c AGC_Ctrl4
+ pWb35Reg->BB0C = 0xEFFF233E;
+ pltmp[4] = 0x0FacDCC5; // 0x1010 AGC_Ctrl5 // 20050927 0x0FacDCB7
+ pltmp[5] = 0x00CAA333; // 0x1014 AGC_Ctrl6
+ pltmp[6] = 0xF2432111; // 0x1018 AGC_Ctrl7
+ pltmp[7] = 0x0FA3F0ED; // 0x101c AGC_Ctrl8
+ pltmp[8] = 0x05C43440; // 0x1020 AGC_Ctrl9
+ pltmp[9] = 0x00002A79; // 0x1024 AGC_Ctrl10
+ pltmp[10] = 0x40000528; // 20050927 0x40000228
+ pltmp[11] = 0x232FDF30;// 0x102c A_ACQ_Ctrl
+ pWb35Reg->BB2C = 0x232FDF30;
+ Wb35Reg_BurstWrite( pHwData, 0x1000, pltmp, 12, AUTO_INCREMENT );
+
+ pltmp[0] = 0x80002C7C; // 0x1030 B_ACQ_Ctrl
+ pltmp[1] = 0x00C0D6C5; // 0x1034 A_TXRX_Ctrl
+ pltmp[2] = 0x5B2C8769; // 0x1038 B_TXRX_Ctrl
+ pltmp[3] = 0x00000000; // 0x103c 11a TX LS filter
+ pWb35Reg->BB3C = 0x00000000;
+ pltmp[4] = 0x00003F29; // 0x1040 11a TX LS filter
+ pltmp[5] = 0x0EFEFBFE; // 0x1044 11a TX LS filter
+ pltmp[6] = 0x00332C1B; // 0x1048 11b TX RC filter
+ pltmp[7] = 0x0A00FEFF; // 0x104c 11b TX RC filter
+ pltmp[8] = 0x2B107208; // 0x1050 MODE_Ctrl
+ pWb35Reg->BB50 = 0x2B107208;
+ pltmp[9] = 0; // 0x1054
+ pWb35Reg->BB54 = 0x00000000;
+ pltmp[10] = 0x52524242; // 0x1058 IQ_Alpha
+ pWb35Reg->BB58 = 0x52524242;
+ pltmp[11] = 0xAA0AC000; // 0x105c DC_Cancel
+ Wb35Reg_BurstWrite( pHwData, 0x1030, pltmp, 12, AUTO_INCREMENT );
+
+}
+
+//=============================================================================================================
+// BBProcessorPowerupInit --
+//
+// Description:
+// Initialize the Baseband processor.
+//
+// Arguments:
+// pHwData - Handle of the USB Device.
+//
+// Return values:
+// None.
+//=============================================================================================================
+void
+BBProcessor_initial( phw_data_t pHwData )
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ u32 i, pltmp[12];
+
+ switch( pHwData->phy_type )
+ {
+ case RF_MAXIM_V1: // Initializng the Winbond 2nd BB(with Phy board (v1) + Maxim 331)
+
+ pltmp[0] = 0x16F47E77; // 0x1000 AGC_Ctrl1
+ pltmp[1] = 0x9AFFAEA4; // 0x1004 AGC_Ctrl2
+ pltmp[2] = 0x55D00A04; // 0x1008 AGC_Ctrl3
+ pltmp[3] = 0xEFFF1A34; // 0x100c AGC_Ctrl4
+ pWb35Reg->BB0C = 0xEFFF1A34;
+ pltmp[4] = 0x0FABE0B7; // 0x1010 AGC_Ctrl5
+ pltmp[5] = 0x00CAA332; // 0x1014 AGC_Ctrl6
+ pltmp[6] = 0xF6632111; // 0x1018 AGC_Ctrl7
+ pltmp[7] = 0x0FA3F0ED; // 0x101c AGC_Ctrl8
+ pltmp[8] = 0x04CC3640; // 0x1020 AGC_Ctrl9
+ pltmp[9] = 0x00002A79; // 0x1024 AGC_Ctrl10
+ pltmp[10] = (pHwData->phy_type==3) ? 0x40000a28 : 0x40000228; // 0x1028 MAXIM_331(b31=0) + WBRF_V1(b11=1) : MAXIM_331(b31=0) + WBRF_V2(b11=0)
+ pltmp[11] = 0x232FDF30; // 0x102c A_ACQ_Ctrl
+ pWb35Reg->BB2C = 0x232FDF30; //Modify for 33's 1.0.95.xxx version, antenna 1
+ Wb35Reg_BurstWrite( pHwData, 0x1000, pltmp, 12, AUTO_INCREMENT );
+
+ pltmp[0] = 0x00002C54; // 0x1030 B_ACQ_Ctrl
+ pWb35Reg->BB30 = 0x00002C54;
+ pltmp[1] = 0x00C0D6C5; // 0x1034 A_TXRX_Ctrl
+ pltmp[2] = 0x5B6C8769; // 0x1038 B_TXRX_Ctrl
+ pltmp[3] = 0x00000000; // 0x103c 11a TX LS filter
+ pWb35Reg->BB3C = 0x00000000;
+ pltmp[4] = 0x00003F29; // 0x1040 11a TX LS filter
+ pltmp[5] = 0x0EFEFBFE; // 0x1044 11a TX LS filter
+ pltmp[6] = 0x00453B24; // 0x1048 11b TX RC filter
+ pltmp[7] = 0x0E00FEFF; // 0x104c 11b TX RC filter
+ pltmp[8] = 0x27106208; // 0x1050 MODE_Ctrl
+ pWb35Reg->BB50 = 0x27106208;
+ pltmp[9] = 0; // 0x1054
+ pWb35Reg->BB54 = 0x00000000;
+ pltmp[10] = 0x64646464; // 0x1058 IQ_Alpha
+ pWb35Reg->BB58 = 0x64646464;
+ pltmp[11] = 0xAA0AC000; // 0x105c DC_Cancel
+ Wb35Reg_BurstWrite( pHwData, 0x1030, pltmp, 12, AUTO_INCREMENT );
+
+ Wb35Reg_Write( pHwData, 0x1070, 0x00000045 );
+ break;
+
+ //------------------------------------------------------------------
+ //[20040722 WK]
+ //Only for baseband version 2
+// case RF_MAXIM_317:
+ case RF_MAXIM_2825:
+ case RF_MAXIM_2827:
+ case RF_MAXIM_2828:
+
+ pltmp[0] = 0x16b47e77; // 0x1000 AGC_Ctrl1
+ pltmp[1] = 0x9affaea4; // 0x1004 AGC_Ctrl2
+ pltmp[2] = 0x55d00a04; // 0x1008 AGC_Ctrl3
+ pltmp[3] = 0xefff1a34; // 0x100c AGC_Ctrl4
+ pWb35Reg->BB0C = 0xefff1a34;
+ pltmp[4] = 0x0fabe0b7; // 0x1010 AGC_Ctrl5
+ pltmp[5] = 0x00caa332; // 0x1014 AGC_Ctrl6
+ pltmp[6] = 0xf6632111; // 0x1018 AGC_Ctrl7
+ pltmp[7] = 0x0FA3F0ED; // 0x101c AGC_Ctrl8
+ pltmp[8] = 0x04CC3640; // 0x1020 AGC_Ctrl9
+ pltmp[9] = 0x00002A79; // 0x1024 AGC_Ctrl10
+ pltmp[10] = 0x40000528; // 0x40000128; Modify for 33's 1.0.95
+ pltmp[11] = 0x232fdf30; // 0x102c A_ACQ_Ctrl
+ pWb35Reg->BB2C = 0x232fdf30; //Modify for 33's 1.0.95.xxx version, antenna 1
+ Wb35Reg_BurstWrite( pHwData, 0x1000, pltmp, 12, AUTO_INCREMENT );
+
+ pltmp[0] = 0x00002C54; // 0x1030 B_ACQ_Ctrl
+ pWb35Reg->BB30 = 0x00002C54;
+ pltmp[1] = 0x00C0D6C5; // 0x1034 A_TXRX_Ctrl
+ pltmp[2] = 0x5B6C8769; // 0x1038 B_TXRX_Ctrl
+ pltmp[3] = 0x00000000; // 0x103c 11a TX LS filter
+ pWb35Reg->BB3C = 0x00000000;
+ pltmp[4] = 0x00003F29; // 0x1040 11a TX LS filter
+ pltmp[5] = 0x0EFEFBFE; // 0x1044 11a TX LS filter
+ pltmp[6] = 0x00453B24; // 0x1048 11b TX RC filter
+ pltmp[7] = 0x0D00FDFF; // 0x104c 11b TX RC filter
+ pltmp[8] = 0x27106208; // 0x1050 MODE_Ctrl
+ pWb35Reg->BB50 = 0x27106208;
+ pltmp[9] = 0; // 0x1054
+ pWb35Reg->BB54 = 0x00000000;
+ pltmp[10] = 0x64646464; // 0x1058 IQ_Alpha
+ pWb35Reg->BB58 = 0x64646464;
+ pltmp[11] = 0xAA28C000; // 0x105c DC_Cancel
+ Wb35Reg_BurstWrite( pHwData, 0x1030, pltmp, 12, AUTO_INCREMENT );
+
+ Wb35Reg_Write( pHwData, 0x1070, 0x00000045 );
+ break;
+
+ case RF_MAXIM_2829:
+
+ pltmp[0] = 0x16b47e77; // 0x1000 AGC_Ctrl1
+ pltmp[1] = 0x9affaea4; // 0x1004 AGC_Ctrl2
+ pltmp[2] = 0x55d00a04; // 0x1008 AGC_Ctrl3
+ pltmp[3] = 0xf4ff1632; // 0xefff1a34; // 0x100c AGC_Ctrl4 Modify for 33's 1.0.95
+ pWb35Reg->BB0C = 0xf4ff1632; // 0xefff1a34; Modify for 33's 1.0.95
+ pltmp[4] = 0x0fabe0b7; // 0x1010 AGC_Ctrl5
+ pltmp[5] = 0x00caa332; // 0x1014 AGC_Ctrl6
+ pltmp[6] = 0xf8632112; // 0xf6632111; // 0x1018 AGC_Ctrl7 Modify for 33's 1.0.95
+ pltmp[7] = 0x0FA3F0ED; // 0x101c AGC_Ctrl8
+ pltmp[8] = 0x04CC3640; // 0x1020 AGC_Ctrl9
+ pltmp[9] = 0x00002A79; // 0x1024 AGC_Ctrl10
+ pltmp[10] = 0x40000528; // 0x40000128; modify for 33's 1.0.95
+ pltmp[11] = 0x232fdf30; // 0x102c A_ACQ_Ctrl
+ pWb35Reg->BB2C = 0x232fdf30; //Modify for 33's 1.0.95.xxx version, antenna 1
+ Wb35Reg_BurstWrite( pHwData, 0x1000, pltmp, 12, AUTO_INCREMENT );
+
+ pltmp[0] = 0x00002C54; // 0x1030 B_ACQ_Ctrl
+ pWb35Reg->BB30 = 0x00002C54;
+ pltmp[1] = 0x00C0D6C5; // 0x1034 A_TXRX_Ctrl
+ pltmp[2] = 0x5b2c8769; // 0x5B6C8769; // 0x1038 B_TXRX_Ctrl Modify for 33's 1.0.95
+ pltmp[3] = 0x00000000; // 0x103c 11a TX LS filter
+ pWb35Reg->BB3C = 0x00000000;
+ pltmp[4] = 0x00003F29; // 0x1040 11a TX LS filter
+ pltmp[5] = 0x0EFEFBFE; // 0x1044 11a TX LS filter
+ pltmp[6] = 0x002c2617; // 0x00453B24; // 0x1048 11b TX RC filter Modify for 33's 1.0.95
+ pltmp[7] = 0x0800feff; // 0x0D00FDFF; // 0x104c 11b TX RC filter Modify for 33's 1.0.95
+ pltmp[8] = 0x27106208; // 0x1050 MODE_Ctrl
+ pWb35Reg->BB50 = 0x27106208;
+ pltmp[9] = 0; // 0x1054
+ pWb35Reg->BB54 = 0x00000000;
+ pltmp[10] = 0x64644a4a; // 0x64646464; // 0x1058 IQ_Alpha Modify for 33's 1.0.95
+ pWb35Reg->BB58 = 0x64646464;
+ pltmp[11] = 0xAA28C000; // 0x105c DC_Cancel
+ Wb35Reg_BurstWrite( pHwData, 0x1030, pltmp, 12, AUTO_INCREMENT );
+
+ Wb35Reg_Write( pHwData, 0x1070, 0x00000045 );
+ break;
+
+ case RF_AIROHA_2230:
+
+ pltmp[0] = 0X16764A77; // 0x1000 AGC_Ctrl1 //0x16765A77
+ pltmp[1] = 0x9affafb2; // 0x1004 AGC_Ctrl2
+ pltmp[2] = 0x55d00a04; // 0x1008 AGC_Ctrl3
+ pltmp[3] = 0xFFFd203c; // 0xFFFb203a; // 0x100c AGC_Ctrl4 Modify for 33's 1.0.95.xxx version
+ pWb35Reg->BB0C = 0xFFFd203c;
+ pltmp[4] = 0X0FBFDCc5; // 0X0FBFDCA0; // 0x1010 AGC_Ctrl5 //0x0FB2E0B7 Modify for 33's 1.0.95.xxx version
+ pltmp[5] = 0x00caa332; // 0x00caa333; // 0x1014 AGC_Ctrl6 Modify for 33's 1.0.95.xxx version
+ pltmp[6] = 0XF6632111; // 0XF1632112; // 0x1018 AGC_Ctrl7 //0xf6632112 Modify for 33's 1.0.95.xxx version
+ pltmp[7] = 0x0FA3F0ED; // 0x101c AGC_Ctrl8
+ pltmp[8] = 0x04C43640; // 0x1020 AGC_Ctrl9
+ pltmp[9] = 0x00002A79; // 0x1024 AGC_Ctrl10
+ pltmp[10] = 0X40000528; //0x40000228
+ pltmp[11] = 0x232dfF30; // 0x232A9F30; // 0x102c A_ACQ_Ctrl //0x232a9730
+ pWb35Reg->BB2C = 0x232dfF30; //Modify for 33's 1.0.95.xxx version, antenna 1
+ Wb35Reg_BurstWrite( pHwData, 0x1000, pltmp, 12, AUTO_INCREMENT );
+
+ pltmp[0] = 0x00002C54; // 0x1030 B_ACQ_Ctrl
+ pWb35Reg->BB30 = 0x00002C54;
+ pltmp[1] = 0x00C0D6C5; // 0x1034 A_TXRX_Ctrl
+ pltmp[2] = 0x5B2C8769; // 0x1038 B_TXRX_Ctrl //0x5B6C8769
+ pltmp[3] = 0x00000000; // 0x103c 11a TX LS filter
+ pWb35Reg->BB3C = 0x00000000;
+ pltmp[4] = 0x00003F29; // 0x1040 11a TX LS filter
+ pltmp[5] = 0x0EFEFBFE; // 0x1044 11a TX LS filter
+ pltmp[6] = BB48_DEFAULT_AL2230_11G; // 0x1048 11b TX RC filter 20060613.2
+ pWb35Reg->BB48 = BB48_DEFAULT_AL2230_11G; // 20051221 ch14 20060613.2
+ pltmp[7] = BB4C_DEFAULT_AL2230_11G; // 0x104c 11b TX RC filter 20060613.2
+ pWb35Reg->BB4C = BB4C_DEFAULT_AL2230_11G; // 20060613.1 20060613.2
+ pltmp[8] = 0x27106200; // 0x1050 MODE_Ctrl
+ pWb35Reg->BB50 = 0x27106200;
+ pltmp[9] = 0; // 0x1054
+ pWb35Reg->BB54 = 0x00000000;
+ pltmp[10] = 0x52524242; // 0x1058 IQ_Alpha
+ pWb35Reg->BB58 = 0x52524242;
+ pltmp[11] = 0xAA0AC000; // 0x105c DC_Cancel
+ Wb35Reg_BurstWrite( pHwData, 0x1030, pltmp, 12, AUTO_INCREMENT );
+
+ Wb35Reg_Write( pHwData, 0x1070, 0x00000045 );
+ break;
+
+ case RF_AIROHA_2230S: // 20060420 Add this
+
+ pltmp[0] = 0X16764A77; // 0x1000 AGC_Ctrl1 //0x16765A77
+ pltmp[1] = 0x9affafb2; // 0x1004 AGC_Ctrl2
+ pltmp[2] = 0x55d00a04; // 0x1008 AGC_Ctrl3
+ pltmp[3] = 0xFFFd203c; // 0xFFFb203a; // 0x100c AGC_Ctrl4 Modify for 33's 1.0.95.xxx version
+ pWb35Reg->BB0C = 0xFFFd203c;
+ pltmp[4] = 0X0FBFDCc5; // 0X0FBFDCA0; // 0x1010 AGC_Ctrl5 //0x0FB2E0B7 Modify for 33's 1.0.95.xxx version
+ pltmp[5] = 0x00caa332; // 0x00caa333; // 0x1014 AGC_Ctrl6 Modify for 33's 1.0.95.xxx version
+ pltmp[6] = 0XF6632111; // 0XF1632112; // 0x1018 AGC_Ctrl7 //0xf6632112 Modify for 33's 1.0.95.xxx version
+ pltmp[7] = 0x0FA3F0ED; // 0x101c AGC_Ctrl8
+ pltmp[8] = 0x04C43640; // 0x1020 AGC_Ctrl9
+ pltmp[9] = 0x00002A79; // 0x1024 AGC_Ctrl10
+ pltmp[10] = 0X40000528; //0x40000228
+ pltmp[11] = 0x232dfF30; // 0x232A9F30; // 0x102c A_ACQ_Ctrl //0x232a9730
+ pWb35Reg->BB2C = 0x232dfF30; //Modify for 33's 1.0.95.xxx version, antenna 1
+ Wb35Reg_BurstWrite( pHwData, 0x1000, pltmp, 12, AUTO_INCREMENT );
+
+ pltmp[0] = 0x00002C54; // 0x1030 B_ACQ_Ctrl
+ pWb35Reg->BB30 = 0x00002C54;
+ pltmp[1] = 0x00C0D6C5; // 0x1034 A_TXRX_Ctrl
+ pltmp[2] = 0x5B2C8769; // 0x1038 B_TXRX_Ctrl //0x5B6C8769
+ pltmp[3] = 0x00000000; // 0x103c 11a TX LS filter
+ pWb35Reg->BB3C = 0x00000000;
+ pltmp[4] = 0x00003F29; // 0x1040 11a TX LS filter
+ pltmp[5] = 0x0EFEFBFE; // 0x1044 11a TX LS filter
+ pltmp[6] = BB48_DEFAULT_AL2230_11G; // 0x1048 11b TX RC filter 20060613.2
+ pWb35Reg->BB48 = BB48_DEFAULT_AL2230_11G; // 20051221 ch14 20060613.2
+ pltmp[7] = BB4C_DEFAULT_AL2230_11G; // 0x104c 11b TX RC filter 20060613.2
+ pWb35Reg->BB4C = BB4C_DEFAULT_AL2230_11G; // 20060613.1
+ pltmp[8] = 0x27106200; // 0x1050 MODE_Ctrl
+ pWb35Reg->BB50 = 0x27106200;
+ pltmp[9] = 0; // 0x1054
+ pWb35Reg->BB54 = 0x00000000;
+ pltmp[10] = 0x52523232; // 20060419 0x52524242; // 0x1058 IQ_Alpha
+ pWb35Reg->BB58 = 0x52523232; // 20060419 0x52524242;
+ pltmp[11] = 0xAA0AC000; // 0x105c DC_Cancel
+ Wb35Reg_BurstWrite( pHwData, 0x1030, pltmp, 12, AUTO_INCREMENT );
+
+ Wb35Reg_Write( pHwData, 0x1070, 0x00000045 );
+ break;
+
+ case RF_AIROHA_7230:
+/*
+ pltmp[0] = 0x16a84a77; // 0x1000 AGC_Ctrl1
+ pltmp[1] = 0x9affafb2; // 0x1004 AGC_Ctrl2
+ pltmp[2] = 0x55d00a04; // 0x1008 AGC_Ctrl3
+ pltmp[3] = 0xFFFb203a; // 0x100c AGC_Ctrl4
+ pWb35Reg->BB0c = 0xFFFb203a;
+ pltmp[4] = 0x0FBFDCB7; // 0x1010 AGC_Ctrl5
+ pltmp[5] = 0x00caa333; // 0x1014 AGC_Ctrl6
+ pltmp[6] = 0xf6632112; // 0x1018 AGC_Ctrl7
+ pltmp[7] = 0x0FA3F0ED; // 0x101c AGC_Ctrl8
+ pltmp[8] = 0x04C43640; // 0x1020 AGC_Ctrl9
+ pltmp[9] = 0x00002A79; // 0x1024 AGC_Ctrl10
+ pltmp[10] = 0x40000228;
+ pltmp[11] = 0x232A9F30;// 0x102c A_ACQ_Ctrl
+ pWb35Reg->BB2c = 0x232A9F30;
+ Wb35Reg_BurstWrite( pHwData, 0x1000, pltmp, 12, AUTO_INCREMENT );
+
+ pltmp[0] = 0x00002C54; // 0x1030 B_ACQ_Ctrl
+ pWb35Reg->BB30 = 0x00002C54;
+ pltmp[1] = 0x00C0D6C5; // 0x1034 A_TXRX_Ctrl
+ pltmp[2] = 0x5B2C8769; // 0x1038 B_TXRX_Ctrl
+ pltmp[3] = 0x00000000; // 0x103c 11a TX LS filter
+ pWb35Reg->BB3c = 0x00000000;
+ pltmp[4] = 0x00003F29; // 0x1040 11a TX LS filter
+ pltmp[5] = 0x0EFEFBFE; // 0x1044 11a TX LS filter
+ pltmp[6] = 0x00453B24; // 0x1048 11b TX RC filter
+ pltmp[7] = 0x0E00FEFF; // 0x104c 11b TX RC filter
+ pltmp[8] = 0x27106200; // 0x1050 MODE_Ctrl
+ pWb35Reg->BB50 = 0x27106200;
+ pltmp[9] = 0; // 0x1054
+ pWb35Reg->BB54 = 0x00000000;
+ pltmp[10] = 0x64645252; // 0x1058 IQ_Alpha
+ pWb35Reg->BB58 = 0x64645252;
+ pltmp[11] = 0xAA0AC000; // 0x105c DC_Cancel
+ Wb35Reg_BurstWrite( pHwData, 0x1030, pltmp, 12, AUTO_INCREMENT );
+*/
+ BBProcessor_AL7230_2400( pHwData );
+
+ Wb35Reg_Write( pHwData, 0x1070, 0x00000045 );
+ break;
+
+ case RF_WB_242:
+ case RF_WB_242_1: // 20060619.5 Add
+
+ pltmp[0] = 0x16A8525D; // 0x1000 AGC_Ctrl1
+ pltmp[1] = 0x9AFF9ABA; // 0x1004 AGC_Ctrl2
+ pltmp[2] = 0x55D00A04; // 0x1008 AGC_Ctrl3
+ pltmp[3] = 0xEEE91C32; // 0x100c AGC_Ctrl4
+ pWb35Reg->BB0C = 0xEEE91C32;
+ pltmp[4] = 0x0FACDCC5; // 0x1010 AGC_Ctrl5
+ pltmp[5] = 0x000AA344; // 0x1014 AGC_Ctrl6
+ pltmp[6] = 0x22222221; // 0x1018 AGC_Ctrl7
+ pltmp[7] = 0x0FA3F0ED; // 0x101c AGC_Ctrl8
+ pltmp[8] = 0x04CC3440; // 20051018 0x03CB3440; // 0x1020 AGC_Ctrl9 20051014 0x03C33440
+ pltmp[9] = 0xA9002A79; // 0x1024 AGC_Ctrl10
+ pltmp[10] = 0x40000528; // 0x1028
+ pltmp[11] = 0x23457F30; // 0x102c A_ACQ_Ctrl
+ pWb35Reg->BB2C = 0x23457F30;
+ Wb35Reg_BurstWrite( pHwData, 0x1000, pltmp, 12, AUTO_INCREMENT );
+
+ pltmp[0] = 0x00002C54; // 0x1030 B_ACQ_Ctrl
+ pWb35Reg->BB30 = 0x00002C54;
+ pltmp[1] = 0x00C0D6C5; // 0x1034 A_TXRX_Ctrl
+ pltmp[2] = 0x5B2C8769; // 0x1038 B_TXRX_Ctrl
+ pltmp[3] = pHwData->BB3c_cal; // 0x103c 11a TX LS filter
+ pWb35Reg->BB3C = pHwData->BB3c_cal;
+ pltmp[4] = 0x00003F29; // 0x1040 11a TX LS filter
+ pltmp[5] = 0x0EFEFBFE; // 0x1044 11a TX LS filter
+ pltmp[6] = BB48_DEFAULT_WB242_11G; // 0x1048 11b TX RC filter 20060613.2
+ pWb35Reg->BB48 = BB48_DEFAULT_WB242_11G; // 20060613.1 20060613.2
+ pltmp[7] = BB4C_DEFAULT_WB242_11G; // 0x104c 11b TX RC filter 20060613.2
+ pWb35Reg->BB4C = BB4C_DEFAULT_WB242_11G; // 20060613.1 20060613.2
+ pltmp[8] = 0x27106208; // 0x1050 MODE_Ctrl
+ pWb35Reg->BB50 = 0x27106208;
+ pltmp[9] = pHwData->BB54_cal; // 0x1054
+ pWb35Reg->BB54 = pHwData->BB54_cal;
+ pltmp[10] = 0x52523131; // 0x1058 IQ_Alpha
+ pWb35Reg->BB58 = 0x52523131;
+ pltmp[11] = 0xAA0AC000; // 20060825 0xAA2AC000; // 0x105c DC_Cancel
+ Wb35Reg_BurstWrite( pHwData, 0x1030, pltmp, 12, AUTO_INCREMENT );
+
+ Wb35Reg_Write( pHwData, 0x1070, 0x00000045 );
+ break;
+ }
+
+ // Fill the LNA table
+ pWb35Reg->LNAValue[0] = (u8)(pWb35Reg->BB0C & 0xff);
+ pWb35Reg->LNAValue[1] = 0;
+ pWb35Reg->LNAValue[2] = (u8)((pWb35Reg->BB0C & 0xff00)>>8);
+ pWb35Reg->LNAValue[3] = 0;
+
+ // Fill SQ3 table
+ for( i=0; i<MAX_SQ3_FILTER_SIZE; i++ )
+ pWb35Reg->SQ3_filter[i] = 0x2f; // half of Bit 0 ~ 6
+}
+
+void set_tx_power_per_channel_max2829( phw_data_t pHwData, ChanInfo Channel)
+{
+ RFSynthesizer_SetPowerIndex( pHwData, 100 ); // 20060620.1 Modify
+}
+
+void set_tx_power_per_channel_al2230( phw_data_t pHwData, ChanInfo Channel )
+{
+ u8 index = 100;
+
+ if (pHwData->TxVgaFor24[Channel.ChanNo - 1] != 0xff) // 20060620.1 Add
+ index = pHwData->TxVgaFor24[Channel.ChanNo - 1];
+
+ RFSynthesizer_SetPowerIndex( pHwData, index );
+}
+
+void set_tx_power_per_channel_al7230( phw_data_t pHwData, ChanInfo Channel)
+{
+ u8 i, index = 100;
+
+ switch ( Channel.band )
+ {
+ case BAND_TYPE_DSSS:
+ case BAND_TYPE_OFDM_24:
+ {
+ if (pHwData->TxVgaFor24[Channel.ChanNo - 1] != 0xff)
+ index = pHwData->TxVgaFor24[Channel.ChanNo - 1];
+ }
+ break;
+ case BAND_TYPE_OFDM_5:
+ {
+ for (i =0; i<35; i++)
+ {
+ if (Channel.ChanNo == pHwData->TxVgaFor50[i].ChanNo)
+ {
+ if (pHwData->TxVgaFor50[i].TxVgaValue != 0xff)
+ index = pHwData->TxVgaFor50[i].TxVgaValue;
+ break;
+ }
+ }
+ }
+ break;
+ }
+ RFSynthesizer_SetPowerIndex( pHwData, index );
+}
+
+void set_tx_power_per_channel_wb242( phw_data_t pHwData, ChanInfo Channel)
+{
+ u8 index = 100;
+
+ switch ( Channel.band )
+ {
+ case BAND_TYPE_DSSS:
+ case BAND_TYPE_OFDM_24:
+ {
+ if (pHwData->TxVgaFor24[Channel.ChanNo - 1] != 0xff)
+ index = pHwData->TxVgaFor24[Channel.ChanNo - 1];
+ }
+ break;
+ case BAND_TYPE_OFDM_5:
+ break;
+ }
+ RFSynthesizer_SetPowerIndex( pHwData, index );
+}
+
+//=============================================================================================================
+// RFSynthesizer_SwitchingChannel --
+//
+// Description:
+// Swithch the RF channel.
+//
+// Arguments:
+// pHwData - Handle of the USB Device.
+// Channel - The channel no.
+//
+// Return values:
+// None.
+//=============================================================================================================
+void
+RFSynthesizer_SwitchingChannel( phw_data_t pHwData, ChanInfo Channel )
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ u32 pltmp[16]; // The 16 is the maximum capability of hardware
+ u32 count, ltmp;
+ u8 i, j, number;
+ u8 ChnlTmp;
+
+ switch( pHwData->phy_type )
+ {
+ case RF_MAXIM_2825:
+ case RF_MAXIM_V1: // 11g Winbond 2nd BB(with Phy board (v1) + Maxim 331)
+
+ if( Channel.band <= BAND_TYPE_OFDM_24 ) // channel 1 ~ 13
+ {
+ for( i=0; i<3; i++ )
+ pltmp[i] = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2825_channel_data_24[Channel.ChanNo-1][i], 18);
+ Wb35Reg_BurstWrite( pHwData, 0x0864, pltmp, 3, NO_INCREMENT );
+ }
+ RFSynthesizer_SetPowerIndex( pHwData, 100 );
+ break;
+
+ case RF_MAXIM_2827:
+
+ if( Channel.band <= BAND_TYPE_OFDM_24 ) // channel 1 ~ 13
+ {
+ for( i=0; i<3; i++ )
+ pltmp[i] = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2827_channel_data_24[Channel.ChanNo-1][i], 18);
+ Wb35Reg_BurstWrite( pHwData, 0x0864, pltmp, 3, NO_INCREMENT );
+ }
+ else if( Channel.band == BAND_TYPE_OFDM_5 ) // channel 36 ~ 64
+ {
+ ChnlTmp = (Channel.ChanNo - 36) / 4;
+ for( i=0; i<3; i++ )
+ pltmp[i] = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2827_channel_data_50[ChnlTmp][i], 18);
+ Wb35Reg_BurstWrite( pHwData, 0x0864, pltmp, 3, NO_INCREMENT );
+ }
+ RFSynthesizer_SetPowerIndex( pHwData, 100 );
+ break;
+
+ case RF_MAXIM_2828:
+
+ if( Channel.band <= BAND_TYPE_OFDM_24 ) // channel 1 ~ 13
+ {
+ for( i=0; i<3; i++ )
+ pltmp[i] = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2828_channel_data_24[Channel.ChanNo-1][i], 18);
+ Wb35Reg_BurstWrite( pHwData, 0x0864, pltmp, 3, NO_INCREMENT );
+ }
+ else if( Channel.band == BAND_TYPE_OFDM_5 ) // channel 36 ~ 64
+ {
+ ChnlTmp = (Channel.ChanNo - 36) / 4;
+ for ( i = 0; i < 3; i++)
+ pltmp[i] = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2828_channel_data_50[ChnlTmp][i], 18);
+ Wb35Reg_BurstWrite( pHwData, 0x0864, pltmp, 3, NO_INCREMENT );
+ }
+ RFSynthesizer_SetPowerIndex( pHwData, 100 );
+ break;
+
+ case RF_MAXIM_2829:
+
+ if( Channel.band <= BAND_TYPE_OFDM_24)
+ {
+ for( i=0; i<3; i++ )
+ pltmp[i] = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2829_channel_data_24[Channel.ChanNo-1][i], 18);
+ Wb35Reg_BurstWrite( pHwData, 0x0864, pltmp, 3, NO_INCREMENT );
+ }
+ else if( Channel.band == BAND_TYPE_OFDM_5 )
+ {
+ count = sizeof(max2829_channel_data_50) / sizeof(max2829_channel_data_50[0]);
+
+ for( i=0; i<count; i++ )
+ {
+ if( max2829_channel_data_50[i][0] == Channel.ChanNo )
+ {
+ for( j=0; j<3; j++ )
+ pltmp[j] = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2829_channel_data_50[i][j+1], 18);
+ Wb35Reg_BurstWrite( pHwData, 0x0864, pltmp, 3, NO_INCREMENT );
+
+ if( (max2829_channel_data_50[i][3] & 0x3FFFF) == 0x2A946 )
+ {
+ ltmp = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( (5<<18)|0x2A906, 18);
+ Wb35Reg_Write( pHwData, 0x0864, ltmp );
+ }
+ else // 0x2A9C6
+ {
+ ltmp = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( (5<<18)|0x2A986, 18);
+ Wb35Reg_Write( pHwData, 0x0864, ltmp );
+ }
+ }
+ }
+ }
+ set_tx_power_per_channel_max2829( pHwData, Channel );
+ break;
+
+ case RF_AIROHA_2230:
+ case RF_AIROHA_2230S: // 20060420 Add this
+
+ if( Channel.band <= BAND_TYPE_OFDM_24 ) // channel 1 ~ 14
+ {
+ for( i=0; i<2; i++ )
+ pltmp[i] = (1 << 31) | (0 << 30) | (20 << 24) | BitReverse( al2230_channel_data_24[Channel.ChanNo-1][i], 20);
+ Wb35Reg_BurstWrite( pHwData, 0x0864, pltmp, 2, NO_INCREMENT );
+ }
+ set_tx_power_per_channel_al2230( pHwData, Channel );
+ break;
+
+ case RF_AIROHA_7230:
+
+ //Start to fill RF parameters, PLL_ON should be pulled low.
+ //Wb35Reg_Write( pHwData, 0x03dc, 0x00000000 );
+ //WBDEBUG(("* PLL_ON low\n"));
+
+ //Channel independent registers
+ if( Channel.band != pHwData->band)
+ {
+ if (Channel.band <= BAND_TYPE_OFDM_24)
+ {
+ //Update BB register
+ BBProcessor_AL7230_2400(pHwData);
+
+ number = sizeof(al7230_rf_data_24)/sizeof(al7230_rf_data_24[0]);
+ Set_ChanIndep_RfData_al7230_24(pHwData, pltmp, number);
+ }
+ else
+ {
+ //Update BB register
+ BBProcessor_AL7230_5000(pHwData);
+
+ number = sizeof(al7230_rf_data_50)/sizeof(al7230_rf_data_50[0]);
+ Set_ChanIndep_RfData_al7230_50(pHwData, pltmp, number);
+ }
+
+ // Write to register. number must less and equal than 16
+ Wb35Reg_BurstWrite( pHwData, 0x0864, pltmp, number, NO_INCREMENT );
+ #ifdef _PE_STATE_DUMP_
+ WBDEBUG(("Band changed\n"));
+ #endif
+ }
+
+ if( Channel.band <= BAND_TYPE_OFDM_24 ) // channel 1 ~ 14
+ {
+ for( i=0; i<2; i++ )
+ pltmp[i] = (1 << 31) | (0 << 30) | (24 << 24) | (al7230_channel_data_24[Channel.ChanNo-1][i]&0xffffff);
+ Wb35Reg_BurstWrite( pHwData, 0x0864, pltmp, 2, NO_INCREMENT );
+ }
+ else if( Channel.band == BAND_TYPE_OFDM_5 )
+ {
+ //Update Reg12
+ if ((Channel.ChanNo > 64) && (Channel.ChanNo <= 165))
+ {
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | 0x00143c;
+ Wb35Reg_Write( pHwData, 0x0864, ltmp );
+ }
+ else //reg12 = 0x00147c at Channel 4920 ~ 5320
+ {
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | 0x00147c;
+ Wb35Reg_Write( pHwData, 0x0864, ltmp );
+ }
+
+ count = sizeof(al7230_channel_data_5) / sizeof(al7230_channel_data_5[0]);
+
+ for (i=0; i<count; i++)
+ {
+ if (al7230_channel_data_5[i][0] == Channel.ChanNo)
+ {
+ for( j=0; j<3; j++ )
+ pltmp[j] = (1 << 31) | (0 << 30) | (24 << 24) | ( al7230_channel_data_5[i][j+1]&0xffffff);
+ Wb35Reg_BurstWrite( pHwData, 0x0864, pltmp, 3, NO_INCREMENT );
+ }
+ }
+ }
+ set_tx_power_per_channel_al7230(pHwData, Channel);
+ break;
+
+ case RF_WB_242:
+ case RF_WB_242_1: // 20060619.5 Add
+
+ if( Channel.band <= BAND_TYPE_OFDM_24 ) // channel 1 ~ 14
+ {
+ ltmp = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( w89rf242_channel_data_24[Channel.ChanNo-1][0], 24);
+ Wb35Reg_Write( pHwData, 0x864, ltmp );
+ }
+ set_tx_power_per_channel_wb242(pHwData, Channel);
+ break;
+ }
+
+ if( Channel.band <= BAND_TYPE_OFDM_24 )
+ {
+ // BB: select 2.4 GHz, bit[12-11]=00
+ pWb35Reg->BB50 &= ~(BIT(11)|BIT(12));
+ Wb35Reg_Write( pHwData, 0x1050, pWb35Reg->BB50 ); // MODE_Ctrl
+ // MAC: select 2.4 GHz, bit[5]=0
+ pWb35Reg->M78_ERPInformation &= ~BIT(5);
+ Wb35Reg_Write( pHwData, 0x0878, pWb35Reg->M78_ERPInformation );
+ // enable 11b Baseband
+ pWb35Reg->BB30 &= ~BIT(31);
+ Wb35Reg_Write( pHwData, 0x1030, pWb35Reg->BB30 );
+ }
+ else if( (Channel.band == BAND_TYPE_OFDM_5) )
+ {
+ // BB: select 5 GHz
+ pWb35Reg->BB50 &= ~(BIT(11)|BIT(12));
+ if (Channel.ChanNo <=64 )
+ pWb35Reg->BB50 |= BIT(12); // 10-5.25GHz
+ else if ((Channel.ChanNo >= 100) && (Channel.ChanNo <= 124))
+ pWb35Reg->BB50 |= BIT(11); // 01-5.48GHz
+ else if ((Channel.ChanNo >=128) && (Channel.ChanNo <= 161))
+ pWb35Reg->BB50 |= (BIT(12)|BIT(11)); // 11-5.775GHz
+ else //Chan 184 ~ 196 will use bit[12-11] = 10 in version sh-src-1.2.25
+ pWb35Reg->BB50 |= BIT(12);
+ Wb35Reg_Write( pHwData, 0x1050, pWb35Reg->BB50 ); // MODE_Ctrl
+
+ //(1) M78 should alway use 2.4G setting when using RF_AIROHA_7230
+ //(2) BB30 has been updated previously.
+ if (pHwData->phy_type != RF_AIROHA_7230)
+ {
+ // MAC: select 5 GHz, bit[5]=1
+ pWb35Reg->M78_ERPInformation |= BIT(5);
+ Wb35Reg_Write( pHwData, 0x0878, pWb35Reg->M78_ERPInformation );
+
+ // disable 11b Baseband
+ pWb35Reg->BB30 |= BIT(31);
+ Wb35Reg_Write( pHwData, 0x1030, pWb35Reg->BB30 );
+ }
+ }
+}
+
+//Set the tx power directly from DUT GUI, not from the EEPROM. Return the current setting
+u8 RFSynthesizer_SetPowerIndex( phw_data_t pHwData, u8 PowerIndex )
+{
+ u32 Band = pHwData->band;
+ u8 index=0;
+
+ if( pHwData->power_index == PowerIndex ) // 20060620.1 Add
+ return PowerIndex;
+
+ if (RF_MAXIM_2825 == pHwData->phy_type)
+ {
+ // Channel 1 - 13
+ index = RFSynthesizer_SetMaxim2825Power( pHwData, PowerIndex );
+ }
+ else if (RF_MAXIM_2827 == pHwData->phy_type)
+ {
+ if( Band <= BAND_TYPE_OFDM_24 ) // Channel 1 - 13
+ index = RFSynthesizer_SetMaxim2827_24Power( pHwData, PowerIndex );
+ else// if( Band == BAND_TYPE_OFDM_5 ) // Channel 36 - 64
+ index = RFSynthesizer_SetMaxim2827_50Power( pHwData, PowerIndex );
+ }
+ else if (RF_MAXIM_2828 == pHwData->phy_type)
+ {
+ if( Band <= BAND_TYPE_OFDM_24 ) // Channel 1 - 13
+ index = RFSynthesizer_SetMaxim2828_24Power( pHwData, PowerIndex );
+ else// if( Band == BAND_TYPE_OFDM_5 ) // Channel 36 - 64
+ index = RFSynthesizer_SetMaxim2828_50Power( pHwData, PowerIndex );
+ }
+ else if( RF_AIROHA_2230 == pHwData->phy_type )
+ {
+ //Power index: 0 ~ 63 // Channel 1 - 14
+ index = RFSynthesizer_SetAiroha2230Power( pHwData, PowerIndex );
+ index = (u8)al2230_txvga_data[index][1];
+ }
+ else if( RF_AIROHA_2230S == pHwData->phy_type ) // 20060420 Add this
+ {
+ //Power index: 0 ~ 63 // Channel 1 - 14
+ index = RFSynthesizer_SetAiroha2230Power( pHwData, PowerIndex );
+ index = (u8)al2230_txvga_data[index][1];
+ }
+ else if( RF_AIROHA_7230 == pHwData->phy_type )
+ {
+ //Power index: 0 ~ 63
+ index = RFSynthesizer_SetAiroha7230Power( pHwData, PowerIndex );
+ index = (u8)al7230_txvga_data[index][1];
+ }
+ else if( (RF_WB_242 == pHwData->phy_type) ||
+ (RF_WB_242_1 == pHwData->phy_type) ) // 20060619.5 Add
+ {
+ //Power index: 0 ~ 19 for original. New range is 0 ~ 33
+ index = RFSynthesizer_SetWinbond242Power( pHwData, PowerIndex );
+ index = (u8)w89rf242_txvga_data[index][1];
+ }
+
+ pHwData->power_index = index; // Backup current
+ return index;
+}
+
+//-- Sub function
+u8 RFSynthesizer_SetMaxim2828_24Power( phw_data_t pHwData, u8 index )
+{
+ u32 PowerData;
+ if( index > 1 ) index = 1;
+ PowerData = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2828_power_data_24[index], 18);
+ Wb35Reg_Write( pHwData, 0x0864, PowerData );
+ return index;
+}
+//--
+u8 RFSynthesizer_SetMaxim2828_50Power( phw_data_t pHwData, u8 index )
+{
+ u32 PowerData;
+ if( index > 1 ) index = 1;
+ PowerData = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2828_power_data_50[index], 18);
+ Wb35Reg_Write( pHwData, 0x0864, PowerData );
+ return index;
+}
+//--
+u8 RFSynthesizer_SetMaxim2827_24Power( phw_data_t pHwData, u8 index )
+{
+ u32 PowerData;
+ if( index > 1 ) index = 1;
+ PowerData = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2827_power_data_24[index], 18);
+ Wb35Reg_Write( pHwData, 0x0864, PowerData );
+ return index;
+}
+//--
+u8 RFSynthesizer_SetMaxim2827_50Power( phw_data_t pHwData, u8 index )
+{
+ u32 PowerData;
+ if( index > 1 ) index = 1;
+ PowerData = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2827_power_data_50[index], 18);
+ Wb35Reg_Write( pHwData, 0x0864, PowerData );
+ return index;
+}
+//--
+u8 RFSynthesizer_SetMaxim2825Power( phw_data_t pHwData, u8 index )
+{
+ u32 PowerData;
+ if( index > 1 ) index = 1;
+ PowerData = (1 << 31) | (0 << 30) | (18 << 24) | BitReverse( max2825_power_data_24[index], 18);
+ Wb35Reg_Write( pHwData, 0x0864, PowerData );
+ return index;
+}
+//--
+u8 RFSynthesizer_SetAiroha2230Power( phw_data_t pHwData, u8 index )
+{
+ u32 PowerData;
+ u8 i,count;
+
+ count = sizeof(al2230_txvga_data) / sizeof(al2230_txvga_data[0]);
+ for (i=0; i<count; i++)
+ {
+ if (al2230_txvga_data[i][1] >= index)
+ break;
+ }
+ if (i == count)
+ i--;
+
+ PowerData = (1 << 31) | (0 << 30) | (20 << 24) | BitReverse( al2230_txvga_data[i][0], 20);
+ Wb35Reg_Write( pHwData, 0x0864, PowerData );
+ return i;
+}
+//--
+u8 RFSynthesizer_SetAiroha7230Power( phw_data_t pHwData, u8 index )
+{
+ u32 PowerData;
+ u8 i,count;
+
+ //PowerData = (1 << 31) | (0 << 30) | (20 << 24) | BitReverse( airoha_power_data_24[index], 20);
+ count = sizeof(al7230_txvga_data) / sizeof(al7230_txvga_data[0]);
+ for (i=0; i<count; i++)
+ {
+ if (al7230_txvga_data[i][1] >= index)
+ break;
+ }
+ if (i == count)
+ i--;
+ PowerData = (1 << 31) | (0 << 30) | (24 << 24) | (al7230_txvga_data[i][0]&0xffffff);
+ Wb35Reg_Write( pHwData, 0x0864, PowerData );
+ return i;
+}
+
+u8 RFSynthesizer_SetWinbond242Power( phw_data_t pHwData, u8 index )
+{
+ u32 PowerData;
+ u8 i,count;
+
+ count = sizeof(w89rf242_txvga_data) / sizeof(w89rf242_txvga_data[0]);
+ for (i=0; i<count; i++)
+ {
+ if (w89rf242_txvga_data[i][1] >= index)
+ break;
+ }
+ if (i == count)
+ i--;
+
+ // Set TxVga into RF
+ PowerData = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( w89rf242_txvga_data[i][0], 24);
+ Wb35Reg_Write( pHwData, 0x0864, PowerData );
+
+ // Update BB48 BB4C BB58 for high precision txvga
+ Wb35Reg_Write( pHwData, 0x1048, w89rf242_txvga_data[i][2] );
+ Wb35Reg_Write( pHwData, 0x104c, w89rf242_txvga_data[i][3] );
+ Wb35Reg_Write( pHwData, 0x1058, w89rf242_txvga_data[i][4] );
+
+// Rf vga 0 ~ 3 for temperature compensate. It will affect the scan Bss.
+// The i value equals to 8 or 7 usually. So It's not necessary to setup this RF register.
+// if( i <= 3 )
+// PowerData = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( 0x000024, 24 );
+// else
+// PowerData = (1 << 31) | (0 << 30) | (24 << 24) | BitReverse( 0x001824, 24 );
+// Wb35Reg_Write( pHwData, 0x0864, PowerData );
+ return i;
+}
+
+//===========================================================================================================
+// Dxx_initial --
+// Mxx_initial --
+ //
+// Routine Description:
+// Initial the hardware setting and module variable
+ //
+//===========================================================================================================
+void Dxx_initial( phw_data_t pHwData )
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+
+ // Old IC:Single mode only.
+ // New IC: operation decide by Software set bit[4]. 1:multiple 0: single
+ pWb35Reg->D00_DmaControl = 0xc0000004; //Txon, Rxon, multiple Rx for new 4k DMA
+ //Txon, Rxon, single Rx for old 8k ASIC
+ if( !HAL_USB_MODE_BURST( pHwData ) )
+ pWb35Reg->D00_DmaControl = 0xc0000000;//Txon, Rxon, single Rx for new 4k DMA
+
+ Wb35Reg_WriteSync( pHwData, 0x0400, pWb35Reg->D00_DmaControl );
+}
+
+void Mxx_initial( phw_data_t pHwData )
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ u32 tmp;
+ u32 pltmp[11];
+ u16 i;
+
+
+ //======================================================
+ // Initial Mxx register
+ //======================================================
+
+ // M00 bit set
+#ifdef _IBSS_BEACON_SEQ_STICK_
+ pWb35Reg->M00_MacControl = 0; // Solve beacon sequence number stop by software
+#else
+ pWb35Reg->M00_MacControl = 0x80000000; // Solve beacon sequence number stop by hardware
+#endif
+
+ // M24 disable enter power save, BB RxOn and enable NAV attack
+ pWb35Reg->M24_MacControl = 0x08040042;
+ pltmp[0] = pWb35Reg->M24_MacControl;
+
+ pltmp[1] = 0; // Skip M28, because no initialize value is required.
+
+ // M2C CWmin and CWmax setting
+ pHwData->cwmin = DEFAULT_CWMIN;
+ pHwData->cwmax = DEFAULT_CWMAX;
+ pWb35Reg->M2C_MacControl = DEFAULT_CWMIN << 10;
+ pWb35Reg->M2C_MacControl |= DEFAULT_CWMAX;
+ pltmp[2] = pWb35Reg->M2C_MacControl;
+
+ // M30 BSSID
+ pltmp[3] = *(PULONG)pHwData->bssid;
+
+ // M34
+ pHwData->AID = DEFAULT_AID;
+ tmp = *(PUSHORT)(pHwData->bssid+4);
+ tmp |= DEFAULT_AID << 16;
+ pltmp[4] = tmp;
+
+ // M38
+ pWb35Reg->M38_MacControl = (DEFAULT_RATE_RETRY_LIMIT<<8) | (DEFAULT_LONG_RETRY_LIMIT << 4) | DEFAULT_SHORT_RETRY_LIMIT;
+ pltmp[5] = pWb35Reg->M38_MacControl;
+
+ // M3C
+ tmp = (DEFAULT_PIFST << 26) | (DEFAULT_EIFST << 16) | (DEFAULT_DIFST << 8) | (DEFAULT_SIFST << 4) | DEFAULT_OSIFST ;
+ pWb35Reg->M3C_MacControl = tmp;
+ pltmp[6] = tmp;
+
+ // M40
+ pHwData->slot_time_select = DEFAULT_SLOT_TIME;
+ tmp = (DEFAULT_ATIMWD << 16) | DEFAULT_SLOT_TIME;
+ pWb35Reg->M40_MacControl = tmp;
+ pltmp[7] = tmp;
+
+ // M44
+ tmp = DEFAULT_MAX_TX_MSDU_LIFE_TIME << 10; // *1024
+ pWb35Reg->M44_MacControl = tmp;
+ pltmp[8] = tmp;
+
+ // M48
+ pHwData->BeaconPeriod = DEFAULT_BEACON_INTERVAL;
+ pHwData->ProbeDelay = DEFAULT_PROBE_DELAY_TIME;
+ tmp = (DEFAULT_BEACON_INTERVAL << 16) | DEFAULT_PROBE_DELAY_TIME;
+ pWb35Reg->M48_MacControl = tmp;
+ pltmp[9] = tmp;
+
+ //M4C
+ pWb35Reg->M4C_MacStatus = (DEFAULT_PROTOCOL_VERSION << 30) | (DEFAULT_MAC_POWER_STATE << 28) | (DEFAULT_DTIM_ALERT_TIME << 24);
+ pltmp[10] = pWb35Reg->M4C_MacStatus;
+
+ // Burst write
+ //Wb35Reg_BurstWrite( pHwData, 0x0824, pltmp, 11, AUTO_INCREMENT );
+ for( i=0; i<11; i++ )
+ Wb35Reg_WriteSync( pHwData, 0x0824 + i*4, pltmp[i] );
+
+ // M60
+ Wb35Reg_WriteSync( pHwData, 0x0860, 0x12481248 );
+ pWb35Reg->M60_MacControl = 0x12481248;
+
+ // M68
+ Wb35Reg_WriteSync( pHwData, 0x0868, 0x00050900 ); // 20051018 0x000F0F00 ); // 940930 0x00131300
+ pWb35Reg->M68_MacControl = 0x00050900;
+
+ // M98
+ Wb35Reg_WriteSync( pHwData, 0x0898, 0xffff8888 );
+ pWb35Reg->M98_MacControl = 0xffff8888;
+}
+
+
+void Uxx_power_off_procedure( phw_data_t pHwData )
+{
+ // SW, PMU reset and turn off clock
+ Wb35Reg_WriteSync( pHwData, 0x03b0, 3 );
+ Wb35Reg_WriteSync( pHwData, 0x03f0, 0xf9 );
+}
+
+//Decide the TxVga of every channel
+void GetTxVgaFromEEPROM( phw_data_t pHwData )
+{
+ u32 i, j, ltmp;
+ u16 Value[MAX_TXVGA_EEPROM];
+ PUCHAR pctmp;
+ u8 ctmp=0;
+
+ // Get the entire TxVga setting in EEPROM
+ for( i=0; i<MAX_TXVGA_EEPROM; i++ )
+ {
+ Wb35Reg_WriteSync( pHwData, 0x03b4, 0x08100000 + 0x00010000*i );
+ Wb35Reg_ReadSync( pHwData, 0x03b4, <mp );
+ Value[i] = (u16)( ltmp & 0xffff ); // Get 16 bit available
+ Value[i] = cpu_to_le16( Value[i] ); // [7:0]2412 [7:0]2417 ....
+ }
+
+ // Adjust the filed which fills with reserved value.
+ pctmp = (PUCHAR)Value;
+ for( i=0; i<(MAX_TXVGA_EEPROM*2); i++ )
+ {
+ if( pctmp[i] != 0xff )
+ ctmp = pctmp[i];
+ else
+ pctmp[i] = ctmp;
+ }
+
+ // Adjust WB_242 to WB_242_1 TxVga scale
+ if( pHwData->phy_type == RF_WB_242 )
+ {
+ for( i=0; i<4; i++ ) // Only 2412 2437 2462 2484 case must be modified
+ {
+ for( j=0; j<(sizeof(w89rf242_txvga_old_mapping)/sizeof(w89rf242_txvga_old_mapping[0])); j++ )
+ {
+ if( pctmp[i] < (u8)w89rf242_txvga_old_mapping[j][1] )
+ {
+ pctmp[i] = (u8)w89rf242_txvga_old_mapping[j][0];
+ break;
+ }
+ }
+
+ if( j == (sizeof(w89rf242_txvga_old_mapping)/sizeof(w89rf242_txvga_old_mapping[0])) )
+ pctmp[i] = (u8)w89rf242_txvga_old_mapping[j-1][0];
+ }
+ }
+
+ // 20060621 Add
+ memcpy( pHwData->TxVgaSettingInEEPROM, pctmp, MAX_TXVGA_EEPROM*2 ); //MAX_TXVGA_EEPROM is u16 count
+ EEPROMTxVgaAdjust( pHwData );
+}
+
+// This function will affect the TxVga parameter in HAL. If hal_set_current_channel
+// or RFSynthesizer_SetPowerIndex be called, new TxVga will take effect.
+// TxVgaSettingInEEPROM of sHwData is an u8 array point to EEPROM contain for IS89C35
+// This function will use default TxVgaSettingInEEPROM data to calculate new TxVga.
+void EEPROMTxVgaAdjust( phw_data_t pHwData ) // 20060619.5 Add
+{
+ PUCHAR pTxVga = pHwData->TxVgaSettingInEEPROM;
+ s16 i, stmp;
+
+ //-- 2.4G -- 20060704.2 Request from Tiger
+ //channel 1 ~ 5
+ stmp = pTxVga[1] - pTxVga[0];
+ for( i=0; i<5; i++ )
+ pHwData->TxVgaFor24[i] = pTxVga[0] + stmp*i/4;
+ //channel 6 ~ 10
+ stmp = pTxVga[2] - pTxVga[1];
+ for( i=5; i<10; i++ )
+ pHwData->TxVgaFor24[i] = pTxVga[1] + stmp*(i-5)/4;
+ //channel 11 ~ 13
+ stmp = pTxVga[3] - pTxVga[2];
+ for( i=10; i<13; i++ )
+ pHwData->TxVgaFor24[i] = pTxVga[2] + stmp*(i-10)/2;
+ //channel 14
+ pHwData->TxVgaFor24[13] = pTxVga[3];
+
+ //-- 5G --
+ if( pHwData->phy_type == RF_AIROHA_7230 )
+ {
+ //channel 184
+ pHwData->TxVgaFor50[0].ChanNo = 184;
+ pHwData->TxVgaFor50[0].TxVgaValue = pTxVga[4];
+ //channel 196
+ pHwData->TxVgaFor50[3].ChanNo = 196;
+ pHwData->TxVgaFor50[3].TxVgaValue = pTxVga[5];
+ //interpolate
+ pHwData->TxVgaFor50[1].ChanNo = 188;
+ pHwData->TxVgaFor50[2].ChanNo = 192;
+ stmp = pTxVga[5] - pTxVga[4];
+ pHwData->TxVgaFor50[2].TxVgaValue = pTxVga[5] - stmp/3;
+ pHwData->TxVgaFor50[1].TxVgaValue = pTxVga[5] - stmp*2/3;
+
+ //channel 16
+ pHwData->TxVgaFor50[6].ChanNo = 16;
+ pHwData->TxVgaFor50[6].TxVgaValue = pTxVga[6];
+ pHwData->TxVgaFor50[4].ChanNo = 8;
+ pHwData->TxVgaFor50[4].TxVgaValue = pTxVga[6];
+ pHwData->TxVgaFor50[5].ChanNo = 12;
+ pHwData->TxVgaFor50[5].TxVgaValue = pTxVga[6];
+
+ //channel 36
+ pHwData->TxVgaFor50[8].ChanNo = 36;
+ pHwData->TxVgaFor50[8].TxVgaValue = pTxVga[7];
+ pHwData->TxVgaFor50[7].ChanNo = 34;
+ pHwData->TxVgaFor50[7].TxVgaValue = pTxVga[7];
+ pHwData->TxVgaFor50[9].ChanNo = 38;
+ pHwData->TxVgaFor50[9].TxVgaValue = pTxVga[7];
+
+ //channel 40
+ pHwData->TxVgaFor50[10].ChanNo = 40;
+ pHwData->TxVgaFor50[10].TxVgaValue = pTxVga[8];
+ //channel 48
+ pHwData->TxVgaFor50[14].ChanNo = 48;
+ pHwData->TxVgaFor50[14].TxVgaValue = pTxVga[9];
+ //interpolate
+ pHwData->TxVgaFor50[11].ChanNo = 42;
+ pHwData->TxVgaFor50[12].ChanNo = 44;
+ pHwData->TxVgaFor50[13].ChanNo = 46;
+ stmp = pTxVga[9] - pTxVga[8];
+ pHwData->TxVgaFor50[13].TxVgaValue = pTxVga[9] - stmp/4;
+ pHwData->TxVgaFor50[12].TxVgaValue = pTxVga[9] - stmp*2/4;
+ pHwData->TxVgaFor50[11].TxVgaValue = pTxVga[9] - stmp*3/4;
+
+ //channel 52
+ pHwData->TxVgaFor50[15].ChanNo = 52;
+ pHwData->TxVgaFor50[15].TxVgaValue = pTxVga[10];
+ //channel 64
+ pHwData->TxVgaFor50[18].ChanNo = 64;
+ pHwData->TxVgaFor50[18].TxVgaValue = pTxVga[11];
+ //interpolate
+ pHwData->TxVgaFor50[16].ChanNo = 56;
+ pHwData->TxVgaFor50[17].ChanNo = 60;
+ stmp = pTxVga[11] - pTxVga[10];
+ pHwData->TxVgaFor50[17].TxVgaValue = pTxVga[11] - stmp/3;
+ pHwData->TxVgaFor50[16].TxVgaValue = pTxVga[11] - stmp*2/3;
+
+ //channel 100
+ pHwData->TxVgaFor50[19].ChanNo = 100;
+ pHwData->TxVgaFor50[19].TxVgaValue = pTxVga[12];
+ //channel 112
+ pHwData->TxVgaFor50[22].ChanNo = 112;
+ pHwData->TxVgaFor50[22].TxVgaValue = pTxVga[13];
+ //interpolate
+ pHwData->TxVgaFor50[20].ChanNo = 104;
+ pHwData->TxVgaFor50[21].ChanNo = 108;
+ stmp = pTxVga[13] - pTxVga[12];
+ pHwData->TxVgaFor50[21].TxVgaValue = pTxVga[13] - stmp/3;
+ pHwData->TxVgaFor50[20].TxVgaValue = pTxVga[13] - stmp*2/3;
+
+ //channel 128
+ pHwData->TxVgaFor50[26].ChanNo = 128;
+ pHwData->TxVgaFor50[26].TxVgaValue = pTxVga[14];
+ //interpolate
+ pHwData->TxVgaFor50[23].ChanNo = 116;
+ pHwData->TxVgaFor50[24].ChanNo = 120;
+ pHwData->TxVgaFor50[25].ChanNo = 124;
+ stmp = pTxVga[14] - pTxVga[13];
+ pHwData->TxVgaFor50[25].TxVgaValue = pTxVga[14] - stmp/4;
+ pHwData->TxVgaFor50[24].TxVgaValue = pTxVga[14] - stmp*2/4;
+ pHwData->TxVgaFor50[23].TxVgaValue = pTxVga[14] - stmp*3/4;
+
+ //channel 140
+ pHwData->TxVgaFor50[29].ChanNo = 140;
+ pHwData->TxVgaFor50[29].TxVgaValue = pTxVga[15];
+ //interpolate
+ pHwData->TxVgaFor50[27].ChanNo = 132;
+ pHwData->TxVgaFor50[28].ChanNo = 136;
+ stmp = pTxVga[15] - pTxVga[14];
+ pHwData->TxVgaFor50[28].TxVgaValue = pTxVga[15] - stmp/3;
+ pHwData->TxVgaFor50[27].TxVgaValue = pTxVga[15] - stmp*2/3;
+
+ //channel 149
+ pHwData->TxVgaFor50[30].ChanNo = 149;
+ pHwData->TxVgaFor50[30].TxVgaValue = pTxVga[16];
+ //channel 165
+ pHwData->TxVgaFor50[34].ChanNo = 165;
+ pHwData->TxVgaFor50[34].TxVgaValue = pTxVga[17];
+ //interpolate
+ pHwData->TxVgaFor50[31].ChanNo = 153;
+ pHwData->TxVgaFor50[32].ChanNo = 157;
+ pHwData->TxVgaFor50[33].ChanNo = 161;
+ stmp = pTxVga[17] - pTxVga[16];
+ pHwData->TxVgaFor50[33].TxVgaValue = pTxVga[17] - stmp/4;
+ pHwData->TxVgaFor50[32].TxVgaValue = pTxVga[17] - stmp*2/4;
+ pHwData->TxVgaFor50[31].TxVgaValue = pTxVga[17] - stmp*3/4;
+ }
+
+ #ifdef _PE_STATE_DUMP_
+ WBDEBUG((" TxVgaFor24 : \n"));
+ DataDmp((u8 *)pHwData->TxVgaFor24, 14 ,0);
+ WBDEBUG((" TxVgaFor50 : \n"));
+ DataDmp((u8 *)pHwData->TxVgaFor50, 70 ,0);
+ #endif
+}
+
+void BBProcessor_RateChanging( phw_data_t pHwData, u8 rate ) // 20060613.1
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ unsigned char Is11bRate;
+
+ Is11bRate = (rate % 6) ? 1 : 0;
+ switch( pHwData->phy_type )
+ {
+ case RF_AIROHA_2230:
+ case RF_AIROHA_2230S: // 20060420 Add this
+ if( Is11bRate )
+ {
+ if( (pWb35Reg->BB48 != BB48_DEFAULT_AL2230_11B) &&
+ (pWb35Reg->BB4C != BB4C_DEFAULT_AL2230_11B) )
+ {
+ Wb35Reg_Write( pHwData, 0x1048, BB48_DEFAULT_AL2230_11B );
+ Wb35Reg_Write( pHwData, 0x104c, BB4C_DEFAULT_AL2230_11B );
+ }
+ }
+ else
+ {
+ if( (pWb35Reg->BB48 != BB48_DEFAULT_AL2230_11G) &&
+ (pWb35Reg->BB4C != BB4C_DEFAULT_AL2230_11G) )
+ {
+ Wb35Reg_Write( pHwData, 0x1048, BB48_DEFAULT_AL2230_11G );
+ Wb35Reg_Write( pHwData, 0x104c, BB4C_DEFAULT_AL2230_11G );
+ }
+ }
+ break;
+
+ case RF_WB_242: // 20060623 The fix only for old TxVGA setting
+ if( Is11bRate )
+ {
+ if( (pWb35Reg->BB48 != BB48_DEFAULT_WB242_11B) &&
+ (pWb35Reg->BB4C != BB4C_DEFAULT_WB242_11B) )
+ {
+ pWb35Reg->BB48 = BB48_DEFAULT_WB242_11B;
+ pWb35Reg->BB4C = BB4C_DEFAULT_WB242_11B;
+ Wb35Reg_Write( pHwData, 0x1048, BB48_DEFAULT_WB242_11B );
+ Wb35Reg_Write( pHwData, 0x104c, BB4C_DEFAULT_WB242_11B );
+ }
+ }
+ else
+ {
+ if( (pWb35Reg->BB48 != BB48_DEFAULT_WB242_11G) &&
+ (pWb35Reg->BB4C != BB4C_DEFAULT_WB242_11G) )
+ {
+ pWb35Reg->BB48 = BB48_DEFAULT_WB242_11G;
+ pWb35Reg->BB4C = BB4C_DEFAULT_WB242_11G;
+ Wb35Reg_Write( pHwData, 0x1048, BB48_DEFAULT_WB242_11G );
+ Wb35Reg_Write( pHwData, 0x104c, BB4C_DEFAULT_WB242_11G );
+ }
+ }
+ break;
+ }
+}
+
+
+
+
+
+
+
diff --git a/drivers/staging/winbond/rxisr.c b/drivers/staging/winbond/rxisr.c
new file mode 100644
index 0000000..18e942c
--- /dev/null
+++ b/drivers/staging/winbond/rxisr.c
@@ -0,0 +1,30 @@
+#include "os_common.h"
+
+void vRxTimerInit(PWB32_ADAPTER Adapter)
+{
+ OS_TIMER_INITIAL(&(Adapter->Mds.nTimer), (void*) RxTimerHandler, (void*) Adapter);
+}
+
+void vRxTimerStart(PWB32_ADAPTER Adapter, int timeout_value)
+{
+ if (timeout_value<MIN_TIMEOUT_VAL)
+ timeout_value=MIN_TIMEOUT_VAL;
+
+ OS_TIMER_SET( &(Adapter->Mds.nTimer), timeout_value );
+}
+
+void vRxTimerStop(PWB32_ADAPTER Adapter)
+{
+ OS_TIMER_CANCEL( &(Adapter->Mds.nTimer), 0 );
+}
+
+void RxTimerHandler_1a( PADAPTER Adapter)
+{
+ RxTimerHandler(NULL, Adapter, NULL, NULL);
+}
+
+void RxTimerHandler(void* SystemSpecific1, PWB32_ADAPTER Adapter,
+ void* SystemSpecific2, void* SystemSpecific3)
+{
+ WARN_ON(1);
+}
diff --git a/drivers/staging/winbond/scan_s.h b/drivers/staging/winbond/scan_s.h
new file mode 100644
index 0000000..1d1b0c4
--- /dev/null
+++ b/drivers/staging/winbond/scan_s.h
@@ -0,0 +1,115 @@
+//
+// SCAN task global CONSTANTS, STRUCTURES, variables
+//
+
+//////////////////////////////////////////////////////////////////////////
+//define the msg type of SCAN module
+#define SCANMSG_SCAN_REQ 0x01
+#define SCANMSG_BEACON 0x02
+#define SCANMSG_PROBE_RESPONSE 0x03
+#define SCANMSG_TIMEOUT 0x04
+#define SCANMSG_TXPROBE_FAIL 0x05
+#define SCANMSG_ENABLE_BGSCAN 0x06
+#define SCANMSG_STOP_SCAN 0x07
+
+// BSS Type =>conform to
+// IBSS : ToDS/FromDS = 00
+// Infrastructure : ToDS/FromDS = 01
+#define IBSS_NET 0
+#define ESS_NET 1
+#define ANYBSS_NET 2
+
+// Scan Type
+#define ACTIVE_SCAN 0
+#define PASSIVE_SCAN 1
+
+///////////////////////////////////////////////////////////////////////////
+//Global data structures, Initial Scan & Background Scan
+typedef struct _SCAN_REQ_PARA //mandatory parameters for SCAN request
+{
+ u32 ScanType; //passive/active scan
+
+ CHAN_LIST sChannelList; // 86B
+ u8 reserved_1[2];
+
+ struct SSID_Element sSSID; // 34B. scan only for this SSID
+ u8 reserved_2[2];
+
+} SCAN_REQ_PARA, *psSCAN_REQ_PARA;
+
+typedef struct _SCAN_PARAMETERS
+{
+ u16 wState;
+ u16 iCurrentChannelIndex;
+
+ SCAN_REQ_PARA sScanReq;
+
+ u8 BSSID[MAC_ADDR_LENGTH + 2]; //scan only for this BSSID
+
+ u32 BssType; //scan only for this BSS type
+
+ //struct SSID_Element sSSID; //scan only for this SSID
+ u16 ProbeDelay;
+ u16 MinChannelTime;
+
+ u16 MaxChannelTime;
+ u16 reserved_1;
+
+ s32 iBgScanPeriod; // XP: 5 sec
+
+ u8 boBgScan; // Wb: enable BG scan, For XP, this value must be FALSE
+ u8 boFastScan; // Wb: reserved
+ u8 boCCAbusy; // Wb: HWMAC CCA busy status
+ u8 reserved_2;
+
+ //NDIS_MINIPORT_TIMER nTimer;
+ OS_TIMER nTimer;
+
+ u32 ScanTimeStamp; //Increase 1 per background scan(1 minute)
+ u32 BssTimeStamp; //Increase 1 per connect status check
+ u32 RxNumPerAntenna[2]; //
+
+ u8 AntennaToggle; //
+ u8 boInTimerHandler;
+ u8 boTimerActive; // Wb: reserved
+ u8 boSave;
+
+ u32 BScanEnable; // Background scan enable. Default is On
+
+} SCAN_PARAMETERS, *psSCAN_PARAMETERS;
+
+// Encapsulate 'Adapter' data structure
+#define psSCAN (&(Adapter->sScanPara))
+#define psSCANREQ (&(Adapter->sScanPara.sScanReq))
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+// scan.h
+// Define the related definitions of scan module
+// history -- 01/14/03' created
+//
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+//Define the state of scan module
+#define SCAN_INACTIVE 0
+#define WAIT_PROBE_DELAY 1
+#define WAIT_RESPONSE_MIN 2
+#define WAIT_RESPONSE_MAX_ACTIVE 3
+#define WAIT_BEACON_MAX_PASSIVE 4
+#define SCAN_COMPLETE 5
+#define BG_SCAN 6
+#define BG_SCANNING 7
+
+
+// The value will load from EEPROM
+// If 0xff is set in EEPOM, the driver will use SCAN_MAX_CHNL_TIME instead.
+// The definition is in WbHal.h
+// #define SCAN_MAX_CHNL_TIME (50)
+
+
+
+// static functions
+
+//static void ScanTimerHandler(PWB32_ADAPTER Adapter);
+//static void vScanTimerStart(PWB32_ADAPTER Adapter, int timeout_value);
+//static void vScanTimerStop(PWB32_ADAPTER Adapter);
+
diff --git a/drivers/staging/winbond/sme_api.c b/drivers/staging/winbond/sme_api.c
new file mode 100644
index 0000000..40e93b7
--- /dev/null
+++ b/drivers/staging/winbond/sme_api.c
@@ -0,0 +1,13 @@
+//------------------------------------------------------------------------------------
+// sme_api.c
+//
+// Copyright(C) 2002 Winbond Electronics Corp.
+//
+//
+//------------------------------------------------------------------------------------
+#include "os_common.h"
+
+s8 sme_get_rssi(void *pcore_data, s32 *prssi)
+{
+ BUG();
+}
diff --git a/drivers/staging/winbond/sme_api.h b/drivers/staging/winbond/sme_api.h
new file mode 100644
index 0000000..016b225
--- /dev/null
+++ b/drivers/staging/winbond/sme_api.h
@@ -0,0 +1,265 @@
+/*
+ * sme_api.h
+ *
+ * Copyright(C) 2002 Winbond Electronics Corp.
+ *
+ * modification history
+ * ---------------------------------------------------------------------------
+ * 1.00.001, 2003-04-21, Kevin created
+ * 1.00.002, 2003-05-14, PD43 & PE20 modified
+ *
+ */
+
+#ifndef __SME_API_H__
+#define __SME_API_H__
+
+/****************** INCLUDE FILES SECTION ***********************************/
+//#include "GL\gl_core.h"
+
+/****************** CONSTANT AND MACRO SECTION ******************************/
+#define _INLINE __inline
+
+#define MEDIA_STATE_DISCONNECTED 0
+#define MEDIA_STATE_CONNECTED 1
+
+//ARRAY CHECK
+#define MAX_POWER_TO_DB 32
+
+/****************** TYPE DEFINITION SECTION *********************************/
+
+/****************** EXPORTED FUNCTION DECLARATION SECTION *******************/
+
+// OID_802_11_BSSID
+s8 sme_get_bssid(void *pcore_data, u8 *pbssid);
+s8 sme_get_desired_bssid(void *pcore_data, u8 *pbssid);//Not use
+s8 sme_set_desired_bssid(void *pcore_data, u8 *pbssid);
+
+// OID_802_11_SSID
+s8 sme_get_ssid(void *pcore_data, u8 *pssid, u8 *pssid_len);
+s8 sme_get_desired_ssid(void *pcore_data, u8 *pssid, u8 *pssid_len);// Not use
+s8 sme_set_desired_ssid(void *pcore_data, u8 *pssid, u8 ssid_len);
+
+// OID_802_11_INFRASTRUCTURE_MODE
+s8 sme_get_bss_type(void *pcore_data, u8 *pbss_type);
+s8 sme_get_desired_bss_type(void *pcore_data, u8 *pbss_type);//Not use
+s8 sme_set_desired_bss_type(void *pcore_data, u8 bss_type);
+
+// OID_802_11_FRAGMENTATION_THRESHOLD
+s8 sme_get_fragment_threshold(void *pcore_data, u32 *pthreshold);
+s8 sme_set_fragment_threshold(void *pcore_data, u32 threshold);
+
+// OID_802_11_RTS_THRESHOLD
+s8 sme_get_rts_threshold(void *pcore_data, u32 *pthreshold);
+s8 sme_set_rts_threshold(void *pcore_data, u32 threshold);
+
+// OID_802_11_RSSI
+s8 sme_get_rssi(void *pcore_data, s32 *prssi);
+
+// OID_802_11_CONFIGURATION
+s8 sme_get_beacon_period(void *pcore_data, u16 *pbeacon_period);
+s8 sme_set_beacon_period(void *pcore_data, u16 beacon_period);
+
+s8 sme_get_atim_window(void *pcore_data, u16 *patim_window);
+s8 sme_set_atim_window(void *pcore_data, u16 atim_window);
+
+s8 sme_get_current_channel(void *pcore_data, u8 *pcurrent_channel);
+s8 sme_get_current_band(void *pcore_data, u8 *pcurrent_band);
+s8 sme_set_current_channel(void *pcore_data, u8 current_channel);
+
+// OID_802_11_BSSID_LIST
+s8 sme_get_scan_bss_count(void *pcore_data, u8 *pcount);
+s8 sme_get_scan_bss(void *pcore_data, u8 index, void **ppbss);
+
+s8 sme_get_connected_bss(void *pcore_data, void **ppbss_now);
+
+// OID_802_11_AUTHENTICATION_MODE
+s8 sme_get_auth_mode(void *pcore_data, u8 *pauth_mode);
+s8 sme_set_auth_mode(void *pcore_data, u8 auth_mode);
+
+// OID_802_11_WEP_STATUS / OID_802_11_ENCRYPTION_STATUS
+s8 sme_get_wep_mode(void *pcore_data, u8 *pwep_mode);
+s8 sme_set_wep_mode(void *pcore_data, u8 wep_mode);
+//s8 sme_get_encryption_status(void *pcore_data, u8 *pstatus);
+//s8 sme_set_encryption_status(void *pcore_data, u8 status);
+
+// ???????????????????????????????????????
+
+// OID_GEN_VENDOR_ID
+// OID_802_3_PERMANENT_ADDRESS
+s8 sme_get_permanent_mac_addr(void *pcore_data, u8 *pmac_addr);
+
+// OID_802_3_CURRENT_ADDRESS
+s8 sme_get_current_mac_addr(void *pcore_data, u8 *pmac_addr);
+
+// OID_802_11_NETWORK_TYPE_IN_USE
+s8 sme_get_network_type_in_use(void *pcore_data, u8 *ptype);
+s8 sme_set_network_type_in_use(void *pcore_data, u8 type);
+
+// OID_802_11_SUPPORTED_RATES
+s8 sme_get_supported_rate(void *pcore_data, u8 *prates);
+
+// OID_802_11_ADD_WEP
+//12/29/03' wkchen
+s8 sme_set_add_wep(void *pcore_data, u32 key_index, u32 key_len,
+ u8 *Address, u8 *key);
+
+// OID_802_11_REMOVE_WEP
+s8 sme_set_remove_wep(void *pcre_data, u32 key_index);
+
+// OID_802_11_DISASSOCIATE
+s8 sme_set_disassociate(void *pcore_data);
+
+// OID_802_11_POWER_MODE
+s8 sme_get_power_mode(void *pcore_data, u8 *pmode);
+s8 sme_set_power_mode(void *pcore_data, u8 mode);
+
+// OID_802_11_BSSID_LIST_SCAN
+s8 sme_set_bssid_list_scan(void *pcore_data, void *pscan_para);
+
+// OID_802_11_RELOAD_DEFAULTS
+s8 sme_set_reload_defaults(void *pcore_data, u8 reload_type);
+
+
+// The following SME API functions are used for WPA
+//
+// Mandatory OIDs for WPA
+//
+
+// OID_802_11_ADD_KEY
+//s8 sme_set_add_key(void *pcore_data, NDIS_802_11_KEY *pkey);
+
+// OID_802_11_REMOVE_KEY
+//s8 sme_set_remove_key(void *pcore_data, NDIS_802_11_REMOVE_KEY *pkey);
+
+// OID_802_11_ASSOCIATION_INFORMATION
+//s8 sme_set_association_information(void *pcore_data,
+// NDIS_802_11_ASSOCIATION_INFORMATION *pinfo);
+
+// OID_802_11_TEST
+//s8 sme_set_test(void *pcore_data, NDIS_802_11_TEST *ptest_data);
+
+//--------------------------------------------------------------------------//
+/*
+// The left OIDs
+
+// OID_802_11_NETWORK_TYPES_SUPPORTED
+// OID_802_11_TX_POWER_LEVEL
+// OID_802_11_RSSI_TRIGGER
+// OID_802_11_NUMBER_OF_ANTENNAS
+// OID_802_11_RX_ANTENNA_SELECTED
+// OID_802_11_TX_ANTENNA_SELECTED
+// OID_802_11_STATISTICS
+// OID_802_11_DESIRED_RATES
+// OID_802_11_PRIVACY_FILTER
+
+*/
+
+/*------------------------- none-standard ----------------------------------*/
+s8 sme_get_connect_status(void *pcore_data, u8 *pstatus);
+
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+//s8 sme_get_scan_type(void *pcore_data, u8 *pscan_type);
+//s8 sme_set_scan_type(void *pcore_data, u8 scan_type);
+
+//s8 sme_get_scan_channel_list(void *pcore_data, u8 *pscan_type);
+//s8 sme_set_scan_channel_list(void *pcore_data, u8 scan_type);
+
+
+void sme_get_encryption_status(void *pcore_data, u8 *EncryptStatus);
+void sme_set_encryption_status(void *pcore_data, u8 EncryptStatus);
+s8 sme_add_key(void *pcore_data,
+ u32 key_index,
+ u8 key_len,
+ u8 key_type,
+ u8 *key_bssid,
+ //u8 *key_rsc,
+ u8 *ptx_tsc,
+ u8 *prx_tsc,
+ u8 *key_material);
+void sme_remove_default_key(void *pcore_data, int index);
+void sme_remove_mapping_key(void *pcore_data, u8 *pmac_addr);
+void sme_clear_all_mapping_key(void *pcore_data);
+void sme_clear_all_default_key(void *pcore_data);
+
+
+
+s8 sme_set_preamble_mode(void *pcore_data, u8 mode);
+s8 sme_get_preamble_mode(void *pcore_data, u8 *mode);
+s8 sme_get_preamble_type(void *pcore_data, u8 *type);
+s8 sme_set_slottime_mode(void *pcore_data, u8 mode);
+s8 sme_get_slottime_mode(void *pcore_data, u8 *mode);
+s8 sme_get_slottime_type(void *pcore_data, u8 *type);
+s8 sme_set_txrate_policy(void *pcore_data, u8 policy);
+s8 sme_get_txrate_policy(void *pcore_data, u8 *policy);
+s8 sme_get_cwmin_value(void *pcore_data, u8 *cwmin);
+s8 sme_get_cwmax_value(void *pcore_data, u16 *cwmax);
+s8 sme_get_ms_radio_mode(void *pcore_data, u8 * pMsRadioOff);
+s8 sme_set_ms_radio_mode(void *pcore_data, u8 boMsRadioOff);
+s8 sme_get_radio_mode(void *pcore_data, psRadioOff pRadioOffData);
+s8 sme_set_radio_mode(void *pcore_data, RadioOff RadioOffData);
+
+void sme_get_tx_power_level(void *pcore_data, u32 *TxPower);
+u8 sme_set_tx_power_level(void *pcore_data, u32 TxPower);
+void sme_get_antenna_count(void *pcore_data, u32 *AntennaCount);
+void sme_get_rx_antenna(void *pcore_data, u32 *RxAntenna);
+u8 sme_set_rx_antenna(void *pcore_data, u32 RxAntenna);
+void sme_get_tx_antenna(void *pcore_data, u32 *TxAntenna);
+s8 sme_set_tx_antenna(void *pcore_data, u32 TxAntenna);
+s8 sme_set_IBSS_chan(void *pcore_data, ChanInfo chan);
+
+//20061108 WPS
+s8 sme_set_IE_append(void *pcore_data, PUCHAR buffer, u16 buf_len);
+
+
+
+
+//================== Local functions ======================
+//#ifdef _HSINCHU
+//void drv_translate_rssi(); // HW RSSI bit -> NDIS RSSI representation
+//void drv_translate_bss_description(); // Local bss desc -> NDIS bss desc
+//void drv_translate_channel(u8 NetworkType, u8 ChannelNumber, u32 *freq); // channel number -> channel /freq.
+//#endif _HSINCHU
+//
+static const u32 PowerDbToMw[] =
+{
+ 56, //mW, MAX - 0, 17.5 dbm
+ 40, //mW, MAX - 1, 16.0 dbm
+ 30, //mW, MAX - 2, 14.8 dbm
+ 20, //mW, MAX - 3, 13.0 dbm
+ 15, //mW, MAX - 4, 11.8 dbm
+ 12, //mW, MAX - 5, 10.6 dbm
+ 9, //mW, MAX - 6, 9.4 dbm
+ 7, //mW, MAX - 7, 8.3 dbm
+ 5, //mW, MAX - 8, 6.4 dbm
+ 4, //mW, MAX - 9, 5.3 dbm
+ 3, //mW, MAX - 10, 4.0 dbm
+ 2, //mW, MAX - 11, ? dbm
+ 2, //mW, MAX - 12, ? dbm
+ 2, //mW, MAX - 13, ? dbm
+ 2, //mW, MAX - 14, ? dbm
+ 2, //mW, MAX - 15, ? dbm
+ 2, //mW, MAX - 16, ? dbm
+ 2, //mW, MAX - 17, ? dbm
+ 2, //mW, MAX - 18, ? dbm
+ 1, //mW, MAX - 19, ? dbm
+ 1, //mW, MAX - 20, ? dbm
+ 1, //mW, MAX - 21, ? dbm
+ 1, //mW, MAX - 22, ? dbm
+ 1, //mW, MAX - 23, ? dbm
+ 1, //mW, MAX - 24, ? dbm
+ 1, //mW, MAX - 25, ? dbm
+ 1, //mW, MAX - 26, ? dbm
+ 1, //mW, MAX - 27, ? dbm
+ 1, //mW, MAX - 28, ? dbm
+ 1, //mW, MAX - 29, ? dbm
+ 1, //mW, MAX - 30, ? dbm
+ 1 //mW, MAX - 31, ? dbm
+};
+
+
+
+
+
+#endif /* __SME_API_H__ */
+
+
diff --git a/drivers/staging/winbond/sme_s.h b/drivers/staging/winbond/sme_s.h
new file mode 100644
index 0000000..dfd2fbc
--- /dev/null
+++ b/drivers/staging/winbond/sme_s.h
@@ -0,0 +1,228 @@
+//
+// SME_S.H -
+// SME task global CONSTANTS, STRUCTURES, variables
+//
+
+//////////////////////////////////////////////////////////////////////////
+//define the msg type of SME module
+// 0x00~0x1F : MSG from GUI dispatch
+// 0x20~0x3F : MSG from MLME
+// 0x40~0x5F : MSG from SCAN
+// 0x60~0x6F : MSG from TX/RX
+// 0x70~0x7F : MSG from ROAMING
+// 0x80~0x8F : MSG from ISR
+// 0x90 : MSG TimeOut
+
+// from GUI
+#define SMEMSG_SCAN_REQ 0x01
+//#define SMEMSG_PASSIVE_SCAN_REQ 0x02
+#define SMEMSG_JOIN_REQ 0x03
+#define SMEMSG_START_IBSS 0x04
+#define SMEMSG_DISCONNECT_REQ 0x05
+#define SMEMSG_AUTHEN_REQ 0x06
+#define SMEMSG_DEAUTHEN_REQ 0x07
+#define SMEMSG_ASSOC_REQ 0x08
+#define SMEMSG_REASSOC_REQ 0x09
+#define SMEMSG_DISASSOC_REQ 0x0a
+#define SMEMSG_POWERSAVE_REQ 0x0b
+
+
+// from MLME
+#define SMEMSG_AUTHEN_CFM 0x21
+#define SMEMSG_AUTHEN_IND 0x22
+#define SMEMSG_ASSOC_CFM 0x23
+#define SMEMSG_DEAUTHEN_IND 0x24
+#define SMEMSG_DISASSOC_IND 0x25
+// from SCAN
+#define SMEMSG_SCAN_CFM 0x41
+#define SMEMSG_START_IBSS_CFM 0x42
+// from MTO, function call to set SME parameters
+
+// 0x60~0x6F : MSG from TX/RX
+//#define SMEMSG_IBSS_JOIN_UPDATE_BSSID 0x61
+#define SMEMSG_COUNTERMEASURE_MICFAIL_TIMEOUT 0x62
+#define SMEMSG_COUNTERMEASURE_BLOCK_TIMEOUT 0x63
+// from ROAMING
+#define SMEMSG_HANDOVER_JOIN_REQ 0x71
+#define SMEMSG_END_ROAMING 0x72
+#define SMEMSG_SCAN_JOIN_REQ 0x73
+// from ISR
+#define SMEMSG_TSF_SYNC_IND 0x81
+// from TimeOut
+#define SMEMSG_TIMEOUT 0x91
+
+
+
+#define MAX_PMKID_Accunt 16
+//@added by ws 04/22/05
+#define Cipher_Disabled 0
+#define Cipher_Wep 1
+#define Cipher_Tkip 2
+#define Cipher_Ccmp 4
+
+
+///////////////////////////////////////////////////////////////////////////
+//Constants
+
+///////////////////////////////////////////////////////////////////////////
+//Global data structures
+
+#define NUMOFWEPENTRIES 64
+
+typedef enum _WEPKeyMode
+{
+ WEPKEY_DISABLED = 0,
+ WEPKEY_64 = 1,
+ WEPKEY_128 = 2
+
+} WEPKEYMODE, *pWEPKEYMODE;
+
+#ifdef _WPA2_
+
+typedef struct _BSSInfo
+{
+ u8 PreAuthBssID[6];
+ PMKID pmkid_value;
+}BSSID_Info;
+
+typedef struct _PMKID_Table //added by ws 05/05/04
+{
+ u32 Length;
+ u32 BSSIDInfoCount;
+ BSSID_Info BSSIDInfo[16];
+
+} PMKID_Table;
+
+#endif //end def _WPA2_
+
+#define MAX_BASIC_RATE_SET 15
+#define MAX_OPT_RATE_SET MAX_BASIC_RATE_SET
+
+
+typedef struct _SME_PARAMETERS
+{
+ u16 wState;
+ u8 boDUTmode;
+ u8 bDesiredPowerSave;
+
+ // SME timer and timeout value
+ //NDIS_MINIPORT_TIMER nTimer;
+ OS_TIMER nTimer;
+
+ u8 boInTimerHandler;
+ u8 boAuthRetryActive;
+ u8 reserved_0[2];
+
+ u32 AuthenRetryTimerVal; // NOTE: Assoc don't fail timeout
+ u32 JoinFailTimerVal; // 10*Beacon-Interval
+
+ //Rates
+ u8 BSSBasicRateSet[(MAX_BASIC_RATE_SET + 3) & ~0x03 ]; // BSS basic rate set
+ u8 OperationalRateSet[(MAX_OPT_RATE_SET + 3) & ~0x03 ]; // Operational rate set
+
+ u8 NumOfBSSBasicRate;
+ u8 NumOfOperationalRate;
+ u8 reserved_1[2];
+
+ u32 BasicRateBitmap;
+ u32 OpRateBitmap;
+
+ // System parameters Set by GUI
+ //-------------------- start IBSS parameter ---------------------------//
+ u32 boStartIBSS; //Start IBSS toggle
+
+ u16 wBeaconPeriod;
+ u16 wATIM_Window;
+
+ ChanInfo IbssChan; // 2B //channel setting when start IBSS
+ u8 reserved_2[2];
+
+ // Join related
+ u16 wDesiredJoinBSS; // BSS index which desire to join
+ u8 boJoinReq; //Join request toggle
+ u8 bDesiredBSSType; //for Join request
+
+ u16 wCapabilityInfo; // Used when invoking the MLME_Associate_request().
+ u16 wNonERPcapabilityInfo;
+
+ struct SSID_Element sDesiredSSID; // 34 B
+ u8 reserved_3[2];
+
+ u8 abDesiredBSSID[MAC_ADDR_LENGTH + 2];
+
+ u8 bJoinScanCount; // the time of scan-join action need to do
+ u8 bDesiredAuthMode; // AUTH_OPEN_SYSTEM or AUTH_SHARED_KEY
+ u8 reserved_4[2];
+
+ // Encryption parameters
+ u8 _dot11PrivacyInvoked;
+ u8 _dot11PrivacyOptionImplemented;
+ u8 reserved_5[2];
+
+ //@ ws added
+ u8 DesiredEncrypt;
+ u8 encrypt_status; //ENCRYPT_DISABLE, ENCRYPT_WEP, ENCRYPT_WEP_NOKEY, ENCRYPT_TKIP, ...
+ u8 key_length;
+ u8 pairwise_key_ok;
+
+ u8 group_key_ok;
+ u8 wpa_ok; // indicate the control port of 802.1x is open or close
+ u8 pairwise_key_type;
+ u8 group_key_type;
+
+ u32 _dot11WEPDefaultKeyID;
+
+ u8 tx_mic_key[8]; // TODO: 0627 kevin-TKIP
+ u8 rx_mic_key[8]; // TODO: 0627 kevin-TKIP
+ u8 group_tx_mic_key[8];
+ u8 group_rx_mic_key[8];
+
+// #ifdef _WPA_
+ u8 AssocReqVarIE[200];
+ u8 AssocRespVarIE[200];
+
+ u16 AssocReqVarLen;
+ u16 AssocRespVarLen;
+ u8 boReassoc; //use assoc. or reassoc.
+ u8 reserved_6[3];
+ u16 AssocRespCapability;
+ u16 AssocRespStatus;
+// #endif
+
+ #ifdef _WPA2_
+ u8 PmkIdTable[256];
+ u32 PmkidTableIndex;
+ #endif //end def _WPA2_
+
+} SME_PARAMETERS, *PSME_PARAMETERS;
+
+#define psSME (&(Adapter->sSmePara))
+
+#define wSMEGetCurrentSTAState(Adapter) ((u16)(Adapter)->sSmePara.wState)
+
+
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+// SmeModule.h
+// Define the related definitions of SME module
+// history -- 01/14/03' created
+//
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+//Define the state of SME module
+#define DISABLED 0
+#define INIT_SCAN 1
+#define SCAN_READY 2
+#define START_IBSS 3
+#define JOIN_PENDING 4
+#define JOIN_CFM 5
+#define AUTHENTICATE_PENDING 6
+#define AUTHENTICATED 7
+#define CONNECTED 8
+//#define EAP_STARTING 9
+//#define EAPOL_AUTHEN_PENDING 10
+//#define SECURE_CONNECTED 11
+
+
+// Static function
+
diff --git a/drivers/staging/winbond/wb35_ver.h b/drivers/staging/winbond/wb35_ver.h
new file mode 100644
index 0000000..2433bc0
--- /dev/null
+++ b/drivers/staging/winbond/wb35_ver.h
@@ -0,0 +1,30 @@
+//
+// Only define one of follow
+//
+
+#ifdef WB_WIN
+ #define VER_FILEVERSION 1,00,47,00
+ #define VER_FILEVERSION_STR "1.00.47.00"
+ #define WB32_DRIVER_MAJOR_VERSION 0x0100
+ #define WB32_DRIVER_MINOR_VERSION 0x4700
+#endif
+
+#ifdef WB_CE
+ #define VER_FILEVERSION 2,00,47,00
+ #define VER_FILEVERSION_STR "2.00.47.00"
+ #define WB32_DRIVER_MAJOR_VERSION 0x0200
+ #define WB32_DRIVER_MINOR_VERSION 0x4700
+#endif
+
+#ifdef WB_LINUX
+ #define VER_FILEVERSION 3,00,47,00
+ #define VER_FILEVERSION_STR "3.00.47.00"
+ #define WB32_DRIVER_MAJOR_VERSION 0x0300
+ #define WB32_DRIVER_MINOR_VERSION 0x4700
+#endif
+
+
+
+
+
+
diff --git a/drivers/staging/winbond/wbhal.c b/drivers/staging/winbond/wbhal.c
new file mode 100644
index 0000000..daf4422
--- /dev/null
+++ b/drivers/staging/winbond/wbhal.c
@@ -0,0 +1,878 @@
+#include "os_common.h"
+
+void hal_get_ethernet_address( phw_data_t pHwData, PUCHAR current_address )
+{
+ if( pHwData->SurpriseRemove ) return;
+
+ memcpy( current_address, pHwData->CurrentMacAddress, ETH_LENGTH_OF_ADDRESS );
+}
+
+void hal_set_ethernet_address( phw_data_t pHwData, PUCHAR current_address )
+{
+ u32 ltmp[2];
+
+ if( pHwData->SurpriseRemove ) return;
+
+ memcpy( pHwData->CurrentMacAddress, current_address, ETH_LENGTH_OF_ADDRESS );
+
+ ltmp[0]= cpu_to_le32( *(PULONG)pHwData->CurrentMacAddress );
+ ltmp[1]= cpu_to_le32( *(PULONG)(pHwData->CurrentMacAddress + 4) ) & 0xffff;
+
+ Wb35Reg_BurstWrite( pHwData, 0x03e8, ltmp, 2, AUTO_INCREMENT );
+}
+
+void hal_get_permanent_address( phw_data_t pHwData, PUCHAR pethernet_address )
+{
+ if( pHwData->SurpriseRemove ) return;
+
+ memcpy( pethernet_address, pHwData->PermanentMacAddress, 6 );
+}
+
+u8 hal_init_hardware(phw_data_t pHwData, PWB32_ADAPTER Adapter)
+{
+ u16 SoftwareSet;
+ pHwData->Adapter = Adapter;
+
+ // Initial the variable
+ pHwData->MaxReceiveLifeTime = DEFAULT_MSDU_LIFE_TIME; // Setting Rx maximum MSDU life time
+ pHwData->FragmentThreshold = DEFAULT_FRAGMENT_THRESHOLD; // Setting default fragment threshold
+
+ if (WbUsb_initial(pHwData)) {
+ pHwData->InitialResource = 1;
+ if( Wb35Reg_initial(pHwData)) {
+ pHwData->InitialResource = 2;
+ if (Wb35Tx_initial(pHwData)) {
+ pHwData->InitialResource = 3;
+ if (Wb35Rx_initial(pHwData)) {
+ pHwData->InitialResource = 4;
+ OS_TIMER_INITIAL( &pHwData->LEDTimer, hal_led_control, pHwData );
+ OS_TIMER_SET( &pHwData->LEDTimer, 1000 ); // 20060623
+
+ //
+ // For restrict to vendor's hardware
+ //
+ SoftwareSet = hal_software_set( pHwData );
+
+ #ifdef Vendor2
+ // Try to make sure the EEPROM contain
+ SoftwareSet >>= 8;
+ if( SoftwareSet != 0x82 )
+ return FALSE;
+ #endif
+
+ Wb35Rx_start( pHwData );
+ Wb35Tx_EP2VM_start( pHwData );
+
+ return TRUE;
+ }
+ }
+ }
+ }
+
+ pHwData->SurpriseRemove = 1;
+ return FALSE;
+}
+
+
+void hal_halt(phw_data_t pHwData, void *ppa_data)
+{
+ switch( pHwData->InitialResource )
+ {
+ case 4:
+ case 3: OS_TIMER_CANCEL( &pHwData->LEDTimer, &cancel );
+ OS_SLEEP(100000); // Wait for Timer DPC exit 940623.2
+ Wb35Rx_destroy( pHwData ); // Release the Rx
+ case 2: Wb35Tx_destroy( pHwData ); // Release the Tx
+ case 1: Wb35Reg_destroy( pHwData ); // Release the Wb35 Regisster resources
+ WbUsb_destroy( pHwData );// Release the WbUsb
+ }
+}
+
+//---------------------------------------------------------------------------------------------------
+void hal_set_rates(phw_data_t pHwData, PUCHAR pbss_rates,
+ u8 length, unsigned char basic_rate_set)
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ u32 tmp, tmp1;
+ u8 Rate[12]={ 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 };
+ u8 SupportedRate[16];
+ u8 i, j, k, Count1, Count2, Byte;
+
+ if( pHwData->SurpriseRemove ) return;
+
+ if (basic_rate_set) {
+ pWb35Reg->M28_MacControl &= ~0x000fff00;
+ tmp1 = 0x00000100;
+ } else {
+ pWb35Reg->M28_MacControl &= ~0xfff00000;
+ tmp1 = 0x00100000;
+ }
+
+ tmp = 0;
+ for (i=0; i<length; i++) {
+ Byte = pbss_rates[i] & 0x7f;
+ for (j=0; j<12; j++) {
+ if( Byte == Rate[j] )
+ break;
+ }
+
+ if (j < 12)
+ tmp |= (tmp1<<j);
+ }
+
+ pWb35Reg->M28_MacControl |= tmp;
+ Wb35Reg_Write( pHwData, 0x0828, pWb35Reg->M28_MacControl );
+
+ // 930206.2.c M78 setting
+ j = k = Count1 = Count2 = 0;
+ memset( SupportedRate, 0, 16 );
+ tmp = 0x00100000;
+ tmp1 = 0x00000100;
+ for (i=0; i<12; i++) { // Get the supported rate
+ if (tmp & pWb35Reg->M28_MacControl) {
+ SupportedRate[j] = Rate[i];
+
+ if (tmp1 & pWb35Reg->M28_MacControl)
+ SupportedRate[j] |= 0x80;
+
+ if (k)
+ Count2++;
+ else
+ Count1++;
+
+ j++;
+ }
+
+ if (i==4 && k==0) {
+ if( !(pWb35Reg->M28_MacControl & 0x000ff000) ) // if basic rate in 11g domain)
+ {
+ k = 1;
+ j = 8;
+ }
+ }
+
+ tmp <<= 1;
+ tmp1 <<= 1;
+ }
+
+ // Fill data into support rate until buffer full
+ //---20060926 add by anson's endian
+ for (i=0; i<4; i++)
+ *(PULONG)(SupportedRate+(i<<2)) = cpu_to_le32( *(PULONG)(SupportedRate+(i<<2)) );
+ //--- end 20060926 add by anson's endian
+ Wb35Reg_BurstWrite( pHwData,0x087c, (PULONG)SupportedRate, 4, AUTO_INCREMENT );
+ pWb35Reg->M7C_MacControl = ((PULONG)SupportedRate)[0];
+ pWb35Reg->M80_MacControl = ((PULONG)SupportedRate)[1];
+ pWb35Reg->M84_MacControl = ((PULONG)SupportedRate)[2];
+ pWb35Reg->M88_MacControl = ((PULONG)SupportedRate)[3];
+
+ // Fill length
+ tmp = Count1<<28 | Count2<<24;
+ pWb35Reg->M78_ERPInformation &= ~0xff000000;
+ pWb35Reg->M78_ERPInformation |= tmp;
+ Wb35Reg_Write( pHwData, 0x0878, pWb35Reg->M78_ERPInformation );
+}
+
+
+//---------------------------------------------------------------------------------------------------
+void hal_set_beacon_period( phw_data_t pHwData, u16 beacon_period )
+{
+ u32 tmp;
+
+ if( pHwData->SurpriseRemove ) return;
+
+ pHwData->BeaconPeriod = beacon_period;
+ tmp = pHwData->BeaconPeriod << 16;
+ tmp |= pHwData->ProbeDelay;
+ Wb35Reg_Write( pHwData, 0x0848, tmp );
+}
+
+
+void hal_set_current_channel_ex( phw_data_t pHwData, ChanInfo channel )
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+
+ if( pHwData->SurpriseRemove )
+ return;
+
+ printk("Going to channel: %d/%d\n", channel.band, channel.ChanNo);
+
+ RFSynthesizer_SwitchingChannel( pHwData, channel );// Switch channel
+ pHwData->Channel = channel.ChanNo;
+ pHwData->band = channel.band;
+ #ifdef _PE_STATE_DUMP_
+ WBDEBUG(("Set channel is %d, band =%d\n", pHwData->Channel, pHwData->band));
+ #endif
+ pWb35Reg->M28_MacControl &= ~0xff; // Clean channel information field
+ pWb35Reg->M28_MacControl |= channel.ChanNo;
+ Wb35Reg_WriteWithCallbackValue( pHwData, 0x0828, pWb35Reg->M28_MacControl,
+ (PCHAR)&channel, sizeof(ChanInfo));
+}
+//---------------------------------------------------------------------------------------------------
+void hal_set_current_channel( phw_data_t pHwData, ChanInfo channel )
+{
+ hal_set_current_channel_ex( pHwData, channel );
+}
+//---------------------------------------------------------------------------------------------------
+void hal_get_current_channel( phw_data_t pHwData, ChanInfo *channel )
+{
+ channel->ChanNo = pHwData->Channel;
+ channel->band = pHwData->band;
+}
+//---------------------------------------------------------------------------------------------------
+void hal_set_accept_broadcast( phw_data_t pHwData, u8 enable )
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+
+ if( pHwData->SurpriseRemove ) return;
+
+ pWb35Reg->M00_MacControl &= ~0x02000000;//The HW value
+
+ if (enable)
+ pWb35Reg->M00_MacControl |= 0x02000000;//The HW value
+
+ Wb35Reg_Write( pHwData, 0x0800, pWb35Reg->M00_MacControl );
+}
+
+//for wep key error detection, we need to accept broadcast packets to be received temporary.
+void hal_set_accept_promiscuous( phw_data_t pHwData, u8 enable)
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+
+ if (pHwData->SurpriseRemove) return;
+ if (enable) {
+ pWb35Reg->M00_MacControl |= 0x00400000;
+ Wb35Reg_Write( pHwData, 0x0800, pWb35Reg->M00_MacControl );
+ } else {
+ pWb35Reg->M00_MacControl&=~0x00400000;
+ Wb35Reg_Write( pHwData, 0x0800, pWb35Reg->M00_MacControl );
+ }
+}
+
+void hal_set_accept_multicast( phw_data_t pHwData, u8 enable )
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+
+ if( pHwData->SurpriseRemove ) return;
+
+ pWb35Reg->M00_MacControl &= ~0x01000000;//The HW value
+ if (enable) pWb35Reg->M00_MacControl |= 0x01000000;//The HW value
+ Wb35Reg_Write( pHwData, 0x0800, pWb35Reg->M00_MacControl );
+}
+
+void hal_set_accept_beacon( phw_data_t pHwData, u8 enable )
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+
+ if( pHwData->SurpriseRemove ) return;
+
+ // 20040108 debug
+ if( !enable )//Due to SME and MLME are not suitable for 35
+ return;
+
+ pWb35Reg->M00_MacControl &= ~0x04000000;//The HW value
+ if( enable )
+ pWb35Reg->M00_MacControl |= 0x04000000;//The HW value
+
+ Wb35Reg_Write( pHwData, 0x0800, pWb35Reg->M00_MacControl );
+}
+//---------------------------------------------------------------------------------------------------
+void hal_set_multicast_address( phw_data_t pHwData, PUCHAR address, u8 number )
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ u8 Byte, Bit;
+
+ if( pHwData->SurpriseRemove ) return;
+
+ //Erases and refills the card multicast registers. Used when an address
+ // has been deleted and all bits must be recomputed.
+ pWb35Reg->M04_MulticastAddress1 = 0;
+ pWb35Reg->M08_MulticastAddress2 = 0;
+
+ while( number )
+ {
+ number--;
+ CardGetMulticastBit( (address+(number*ETH_LENGTH_OF_ADDRESS)), &Byte, &Bit);
+ pWb35Reg->Multicast[Byte] |= Bit;
+ }
+
+ // Updating register
+ Wb35Reg_BurstWrite( pHwData, 0x0804, (PULONG)pWb35Reg->Multicast, 2, AUTO_INCREMENT );
+}
+//---------------------------------------------------------------------------------------------------
+u8 hal_get_accept_beacon( phw_data_t pHwData )
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+
+ if( pHwData->SurpriseRemove ) return 0;
+
+ if( pWb35Reg->M00_MacControl & 0x04000000 )
+ return 1;
+ else
+ return 0;
+}
+
+unsigned char hal_reset_hardware( phw_data_t pHwData, void* ppa )
+{
+ // Not implement yet
+ return TRUE;
+}
+
+void hal_stop( phw_data_t pHwData )
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+
+ pHwData->Wb35Rx.rx_halt = 1;
+ Wb35Rx_stop( pHwData );
+
+ pHwData->Wb35Tx.tx_halt = 1;
+ Wb35Tx_stop( pHwData );
+
+ pWb35Reg->D00_DmaControl &= ~0xc0000000;//Tx Off, Rx Off
+ Wb35Reg_Write( pHwData, 0x0400, pWb35Reg->D00_DmaControl );
+
+ WbUsb_Stop( pHwData ); // 20051230 Add.4
+}
+
+unsigned char hal_idle(phw_data_t pHwData)
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ PWBUSB pWbUsb = &pHwData->WbUsb;
+
+ if( !pHwData->SurpriseRemove && ( pWbUsb->DetectCount || pWb35Reg->EP0vm_state!=VM_STOP ) )
+ return FALSE;
+
+ return TRUE;
+}
+//---------------------------------------------------------------------------------------------------
+void hal_set_cwmin( phw_data_t pHwData, u8 cwin_min )
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+
+ if( pHwData->SurpriseRemove ) return;
+
+ pHwData->cwmin = cwin_min;
+ pWb35Reg->M2C_MacControl &= ~0x7c00; //bit 10 ~ 14
+ pWb35Reg->M2C_MacControl |= (pHwData->cwmin<<10);
+ Wb35Reg_Write( pHwData, 0x082c, pWb35Reg->M2C_MacControl );
+}
+
+s32 hal_get_rssi( phw_data_t pHwData, u32 *HalRssiArry, u8 Count )
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ R01_DESCRIPTOR r01;
+ s32 ltmp = 0, tmp;
+ u8 i;
+
+ if( pHwData->SurpriseRemove ) return -200;
+ if( Count > MAX_ACC_RSSI_COUNT ) // Because the TS may use this funtion
+ Count = MAX_ACC_RSSI_COUNT;
+
+ // RSSI = C1 + C2 * (agc_state[7:0] + offset_map(lna_state[1:0]))
+ // C1 = -195, C2 = 0.66 = 85/128
+ for (i=0; i<Count; i++)
+ {
+ r01.value = HalRssiArry[i];
+ tmp = ((( r01.R01_AGC_state + pWb35Reg->LNAValue[r01.R01_LNA_state]) * 85 ) >>7 ) - 195;
+ ltmp += tmp;
+ }
+ ltmp /= Count;
+ if( pHwData->phy_type == RF_AIROHA_2230 ) ltmp -= 5; // 10;
+ if( pHwData->phy_type == RF_AIROHA_2230S ) ltmp -= 5; // 10; 20060420 Add this
+
+ //if( ltmp < -200 ) ltmp = -200;
+ if( ltmp < -110 ) ltmp = -110;// 1.0.24.0 For NJRC
+
+ return ltmp;
+}
+//----------------------------------------------------------------------------------------------------
+s32 hal_get_rssi_bss( phw_data_t pHwData, u16 idx, u8 Count )
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ R01_DESCRIPTOR r01;
+ s32 ltmp = 0, tmp;
+ u8 i, j;
+ PADAPTER Adapter = pHwData->Adapter;
+// u32 *HalRssiArry = psBSS(idx)->HalRssi;
+
+ if( pHwData->SurpriseRemove ) return -200;
+ if( Count > MAX_ACC_RSSI_COUNT ) // Because the TS may use this funtion
+ Count = MAX_ACC_RSSI_COUNT;
+
+ // RSSI = C1 + C2 * (agc_state[7:0] + offset_map(lna_state[1:0]))
+ // C1 = -195, C2 = 0.66 = 85/128
+#if 0
+ for (i=0; i<Count; i++)
+ {
+ r01.value = HalRssiArry[i];
+ tmp = ((( r01.R01_AGC_state + pWb35Reg->LNAValue[r01.R01_LNA_state]) * 85 ) >>7 ) - 195;
+ ltmp += tmp;
+ }
+#else
+ if (psBSS(idx)->HalRssiIndex == 0)
+ psBSS(idx)->HalRssiIndex = MAX_ACC_RSSI_COUNT;
+ j = (u8)psBSS(idx)->HalRssiIndex-1;
+
+ for (i=0; i<Count; i++)
+ {
+ r01.value = psBSS(idx)->HalRssi[j];
+ tmp = ((( r01.R01_AGC_state + pWb35Reg->LNAValue[r01.R01_LNA_state]) * 85 ) >>7 ) - 195;
+ ltmp += tmp;
+ if (j == 0)
+ {
+ j = MAX_ACC_RSSI_COUNT;
+ }
+ j--;
+ }
+#endif
+ ltmp /= Count;
+ if( pHwData->phy_type == RF_AIROHA_2230 ) ltmp -= 5; // 10;
+ if( pHwData->phy_type == RF_AIROHA_2230S ) ltmp -= 5; // 10; 20060420 Add this
+
+ //if( ltmp < -200 ) ltmp = -200;
+ if( ltmp < -110 ) ltmp = -110;// 1.0.24.0 For NJRC
+
+ return ltmp;
+}
+
+//---------------------------------------------------------------------------
+void hal_led_control_1a( phw_data_t pHwData )
+{
+ hal_led_control( NULL, pHwData, NULL, NULL );
+}
+
+void hal_led_control( void* S1, phw_data_t pHwData, void* S3, void* S4 )
+{
+ PADAPTER Adapter = pHwData->Adapter;
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+ u32 LEDSet = (pHwData->SoftwareSet & HAL_LED_SET_MASK) >> HAL_LED_SET_SHIFT;
+ u8 LEDgray[20] = { 0,3,4,6,8,10,11,12,13,14,15,14,13,12,11,10,8,6,4,2 };
+ u8 LEDgray2[30] = { 7,8,9,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,0,0,0,0,15,14,13,12,11,10,9,8 };
+ u32 TimeInterval = 500, ltmp, ltmp2;
+ ltmp=0;
+
+ if( pHwData->SurpriseRemove ) return;
+
+ if( pHwData->LED_control ) {
+ ltmp2 = pHwData->LED_control & 0xff;
+ if( ltmp2 == 5 ) // 5 is WPS mode
+ {
+ TimeInterval = 100;
+ ltmp2 = (pHwData->LED_control>>8) & 0xff;
+ switch( ltmp2 )
+ {
+ case 1: // [0.2 On][0.1 Off]...
+ pHwData->LED_Blinking %= 3;
+ ltmp = 0x1010; // Led 1 & 0 Green and Red
+ if( pHwData->LED_Blinking == 2 ) // Turn off
+ ltmp = 0;
+ break;
+ case 2: // [0.1 On][0.1 Off]...
+ pHwData->LED_Blinking %= 2;
+ ltmp = 0x0010; // Led 0 red color
+ if( pHwData->LED_Blinking ) // Turn off
+ ltmp = 0;
+ break;
+ case 3: // [0.1 On][0.1 Off][0.1 On][0.1 Off][0.1 On][0.1 Off][0.1 On][0.1 Off][0.1 On][0.1 Off][0.5 Off]...
+ pHwData->LED_Blinking %= 15;
+ ltmp = 0x0010; // Led 0 red color
+ if( (pHwData->LED_Blinking >= 9) || (pHwData->LED_Blinking%2) ) // Turn off 0.6 sec
+ ltmp = 0;
+ break;
+ case 4: // [300 On][ off ]
+ ltmp = 0x1000; // Led 1 Green color
+ if( pHwData->LED_Blinking >= 3000 )
+ ltmp = 0; // led maybe on after 300sec * 32bit counter overlap.
+ break;
+ }
+ pHwData->LED_Blinking++;
+
+ pWb35Reg->U1BC_LEDConfigure = ltmp;
+ if( LEDSet != 7 ) // Only 111 mode has 2 LEDs on PCB.
+ {
+ pWb35Reg->U1BC_LEDConfigure |= (ltmp &0xff)<<8; // Copy LED result to each LED control register
+ pWb35Reg->U1BC_LEDConfigure |= (ltmp &0xff00)>>8;
+ }
+ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure );
+ }
+ }
+ else if( pHwData->CurrentRadioSw || pHwData->CurrentRadioHw ) // If radio off
+ {
+ if( pWb35Reg->U1BC_LEDConfigure & 0x1010 )
+ {
+ pWb35Reg->U1BC_LEDConfigure &= ~0x1010;
+ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure );
+ }
+ }
+ else
+ {
+ switch( LEDSet )
+ {
+ case 4: // [100] Only 1 Led be placed on PCB and use pin 21 of IC. Use LED_0 for showing
+ if( !pHwData->LED_LinkOn ) // Blink only if not Link On
+ {
+ // Blinking if scanning is on progress
+ if( pHwData->LED_Scanning )
+ {
+ if( pHwData->LED_Blinking == 0 )
+ {
+ pWb35Reg->U1BC_LEDConfigure |= 0x10;
+ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); // LED_0 On
+ pHwData->LED_Blinking = 1;
+ TimeInterval = 300;
+ }
+ else
+ {
+ pWb35Reg->U1BC_LEDConfigure &= ~0x10;
+ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); // LED_0 Off
+ pHwData->LED_Blinking = 0;
+ TimeInterval = 300;
+ }
+ }
+ else
+ {
+ //Turn Off LED_0
+ if( pWb35Reg->U1BC_LEDConfigure & 0x10 )
+ {
+ pWb35Reg->U1BC_LEDConfigure &= ~0x10;
+ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); // LED_0 Off
+ }
+ }
+ }
+ else
+ {
+ // Turn On LED_0
+ if( (pWb35Reg->U1BC_LEDConfigure & 0x10) == 0 )
+ {
+ pWb35Reg->U1BC_LEDConfigure |= 0x10;
+ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); // LED_0 Off
+ }
+ }
+ break;
+
+ case 6: // [110] Only 1 Led be placed on PCB and use pin 21 of IC. Use LED_0 for showing
+ if( !pHwData->LED_LinkOn ) // Blink only if not Link On
+ {
+ // Blinking if scanning is on progress
+ if( pHwData->LED_Scanning )
+ {
+ if( pHwData->LED_Blinking == 0 )
+ {
+ pWb35Reg->U1BC_LEDConfigure &= ~0xf;
+ pWb35Reg->U1BC_LEDConfigure |= 0x10;
+ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); // LED_0 On
+ pHwData->LED_Blinking = 1;
+ TimeInterval = 300;
+ }
+ else
+ {
+ pWb35Reg->U1BC_LEDConfigure &= ~0x1f;
+ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); // LED_0 Off
+ pHwData->LED_Blinking = 0;
+ TimeInterval = 300;
+ }
+ }
+ else
+ {
+ // 20060901 Gray blinking if in disconnect state and not scanning
+ ltmp = pWb35Reg->U1BC_LEDConfigure;
+ pWb35Reg->U1BC_LEDConfigure &= ~0x1f;
+ if( LEDgray2[(pHwData->LED_Blinking%30)] )
+ {
+ pWb35Reg->U1BC_LEDConfigure |= 0x10;
+ pWb35Reg->U1BC_LEDConfigure |= LEDgray2[ (pHwData->LED_Blinking%30) ];
+ }
+ pHwData->LED_Blinking++;
+ if( pWb35Reg->U1BC_LEDConfigure != ltmp )
+ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); // LED_0 Off
+ TimeInterval = 100;
+ }
+ }
+ else
+ {
+ // Turn On LED_0
+ if( (pWb35Reg->U1BC_LEDConfigure & 0x10) == 0 )
+ {
+ pWb35Reg->U1BC_LEDConfigure |= 0x10;
+ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); // LED_0 Off
+ }
+ }
+ break;
+
+ case 5: // [101] Only 1 Led be placed on PCB and use LED_1 for showing
+ if( !pHwData->LED_LinkOn ) // Blink only if not Link On
+ {
+ // Blinking if scanning is on progress
+ if( pHwData->LED_Scanning )
+ {
+ if( pHwData->LED_Blinking == 0 )
+ {
+ pWb35Reg->U1BC_LEDConfigure |= 0x1000;
+ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); // LED_1 On
+ pHwData->LED_Blinking = 1;
+ TimeInterval = 300;
+ }
+ else
+ {
+ pWb35Reg->U1BC_LEDConfigure &= ~0x1000;
+ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); // LED_1 Off
+ pHwData->LED_Blinking = 0;
+ TimeInterval = 300;
+ }
+ }
+ else
+ {
+ //Turn Off LED_1
+ if( pWb35Reg->U1BC_LEDConfigure & 0x1000 )
+ {
+ pWb35Reg->U1BC_LEDConfigure &= ~0x1000;
+ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); // LED_1 Off
+ }
+ }
+ }
+ else
+ {
+ // Is transmitting/receiving ??
+ if( (OS_CURRENT_RX_BYTE( Adapter ) != pHwData->RxByteCountLast ) ||
+ (OS_CURRENT_TX_BYTE( Adapter ) != pHwData->TxByteCountLast ) )
+ {
+ if( (pWb35Reg->U1BC_LEDConfigure & 0x3000) != 0x3000 )
+ {
+ pWb35Reg->U1BC_LEDConfigure |= 0x3000;
+ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); // LED_1 On
+ }
+
+ // Update variable
+ pHwData->RxByteCountLast = OS_CURRENT_RX_BYTE( Adapter );
+ pHwData->TxByteCountLast = OS_CURRENT_TX_BYTE( Adapter );
+ TimeInterval = 200;
+ }
+ else
+ {
+ // Turn On LED_1 and blinking if transmitting/receiving
+ if( (pWb35Reg->U1BC_LEDConfigure & 0x3000) != 0x1000 )
+ {
+ pWb35Reg->U1BC_LEDConfigure &= ~0x3000;
+ pWb35Reg->U1BC_LEDConfigure |= 0x1000;
+ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure ); // LED_1 On
+ }
+ }
+ }
+ break;
+
+ default: // Default setting. 2 LED be placed on PCB. LED_0: Link On LED_1 Active
+ if( (pWb35Reg->U1BC_LEDConfigure & 0x3000) != 0x3000 )
+ {
+ pWb35Reg->U1BC_LEDConfigure |= 0x3000;// LED_1 is always on and event enable
+ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure );
+ }
+
+ if( pHwData->LED_Blinking )
+ {
+ // Gray blinking
+ pWb35Reg->U1BC_LEDConfigure &= ~0x0f;
+ pWb35Reg->U1BC_LEDConfigure |= 0x10;
+ pWb35Reg->U1BC_LEDConfigure |= LEDgray[ (pHwData->LED_Blinking-1)%20 ];
+ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure );
+
+ pHwData->LED_Blinking += 2;
+ if( pHwData->LED_Blinking < 40 )
+ TimeInterval = 100;
+ else
+ {
+ pHwData->LED_Blinking = 0; // Stop blinking
+ pWb35Reg->U1BC_LEDConfigure &= ~0x0f;
+ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure );
+ }
+ break;
+ }
+
+ if( pHwData->LED_LinkOn )
+ {
+ if( !(pWb35Reg->U1BC_LEDConfigure & 0x10) ) // Check the LED_0
+ {
+ //Try to turn ON LED_0 after gray blinking
+ pWb35Reg->U1BC_LEDConfigure |= 0x10;
+ pHwData->LED_Blinking = 1; //Start blinking
+ TimeInterval = 50;
+ }
+ }
+ else
+ {
+ if( pWb35Reg->U1BC_LEDConfigure & 0x10 ) // Check the LED_0
+ {
+ pWb35Reg->U1BC_LEDConfigure &= ~0x10;
+ Wb35Reg_Write( pHwData, 0x03bc, pWb35Reg->U1BC_LEDConfigure );
+ }
+ }
+ break;
+ }
+
+ //20060828.1 Active send null packet to avoid AP disconnect
+ if( pHwData->LED_LinkOn )
+ {
+ pHwData->NullPacketCount += TimeInterval;
+ if( pHwData->NullPacketCount >= DEFAULT_NULL_PACKET_COUNT )
+ {
+ pHwData->NullPacketCount = 0;
+ }
+ }
+ }
+
+ pHwData->time_count += TimeInterval;
+ Wb35Tx_CurrentTime( pHwData, pHwData->time_count ); // 20060928 add
+ OS_TIMER_SET( &pHwData->LEDTimer, TimeInterval ); // 20060623.1
+}
+
+
+void hal_set_phy_type( phw_data_t pHwData, u8 PhyType )
+{
+ pHwData->phy_type = PhyType;
+}
+
+void hal_get_phy_type( phw_data_t pHwData, u8 *PhyType )
+{
+ *PhyType = pHwData->phy_type;
+}
+
+void hal_reset_counter( phw_data_t pHwData )
+{
+ pHwData->dto_tx_retry_count = 0;
+ pHwData->dto_tx_frag_count = 0;
+ memset( pHwData->tx_retry_count, 0, 8);
+}
+
+void hal_set_radio_mode( phw_data_t pHwData, unsigned char radio_off)
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+
+ if( pHwData->SurpriseRemove ) return;
+
+ if (radio_off) //disable Baseband receive off
+ {
+ pHwData->CurrentRadioSw = 1; // off
+ pWb35Reg->M24_MacControl &= 0xffffffbf;
+ }
+ else
+ {
+ pHwData->CurrentRadioSw = 0; // on
+ pWb35Reg->M24_MacControl |= 0x00000040;
+ }
+ Wb35Reg_Write( pHwData, 0x0824, pWb35Reg->M24_MacControl );
+}
+
+u8 hal_get_antenna_number( phw_data_t pHwData )
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+
+ if ((pWb35Reg->BB2C & BIT(11)) == 0)
+ return 0;
+ else
+ return 1;
+}
+
+void hal_set_antenna_number( phw_data_t pHwData, u8 number )
+{
+
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+
+ if (number == 1) {
+ pWb35Reg->BB2C |= BIT(11);
+ } else {
+ pWb35Reg->BB2C &= ~BIT(11);
+ }
+ Wb35Reg_Write( pHwData, 0x102c, pWb35Reg->BB2C );
+#ifdef _PE_STATE_DUMP_
+ WBDEBUG(("Current antenna number : %d\n", number));
+#endif
+}
+
+//----------------------------------------------------------------------------------------------------
+//0 : radio on; 1: radio off
+u8 hal_get_hw_radio_off( phw_data_t pHwData )
+{
+ PWB35REG pWb35Reg = &pHwData->Wb35Reg;
+
+ if( pHwData->SurpriseRemove ) return 1;
+
+ //read the bit16 of register U1B0
+ Wb35Reg_Read( pHwData, 0x3b0, &pWb35Reg->U1B0 );
+ if ((pWb35Reg->U1B0 & 0x00010000)) {
+ pHwData->CurrentRadioHw = 1;
+ return 1;
+ } else {
+ pHwData->CurrentRadioHw = 0;
+ return 0;
+ }
+}
+
+unsigned char hal_get_dxx_reg( phw_data_t pHwData, u16 number, PULONG pValue )
+{
+ if( number < 0x1000 )
+ number += 0x1000;
+ return Wb35Reg_ReadSync( pHwData, number, pValue );
+}
+
+unsigned char hal_set_dxx_reg( phw_data_t pHwData, u16 number, u32 value )
+{
+ unsigned char ret;
+
+ if( number < 0x1000 )
+ number += 0x1000;
+ ret = Wb35Reg_WriteSync( pHwData, number, value );
+ return ret;
+}
+
+void hal_scan_status_indicate(phw_data_t pHwData, unsigned char IsOnProgress)
+{
+ if( pHwData->SurpriseRemove ) return;
+ pHwData->LED_Scanning = IsOnProgress ? 1 : 0;
+}
+
+void hal_system_power_change(phw_data_t pHwData, u32 PowerState)
+{
+ if( PowerState != 0 )
+ {
+ pHwData->SurpriseRemove = 1;
+ if( pHwData->WbUsb.IsUsb20 )
+ hal_stop( pHwData );
+ }
+ else
+ {
+ if( !pHwData->WbUsb.IsUsb20 )
+ hal_stop( pHwData );
+ }
+}
+
+void hal_surprise_remove( phw_data_t pHwData )
+{
+ PADAPTER Adapter = pHwData->Adapter;
+ if (OS_ATOMIC_INC( Adapter, &pHwData->SurpriseRemoveCount ) == 1) {
+ #ifdef _PE_STATE_DUMP_
+ WBDEBUG(("Calling hal_surprise_remove\n"));
+ #endif
+ OS_STOP( Adapter );
+ }
+}
+
+void hal_rate_change( phw_data_t pHwData ) // Notify the HAL rate is changing 20060613.1
+{
+ PADAPTER Adapter = pHwData->Adapter;
+ u8 rate = CURRENT_TX_RATE;
+
+ BBProcessor_RateChanging( pHwData, rate );
+}
+
+void hal_set_rf_power(phw_data_t pHwData, u8 PowerIndex)
+{
+ RFSynthesizer_SetPowerIndex( pHwData, PowerIndex );
+}
+
+unsigned char hal_set_LED(phw_data_t pHwData, u32 Mode) // 20061108 for WPS led control
+{
+ pHwData->LED_Blinking = 0;
+ pHwData->LED_control = Mode;
+ OS_TIMER_SET( &pHwData->LEDTimer, 10 ); // 20060623
+ return TRUE;
+}
+
diff --git a/drivers/staging/winbond/wbhal_f.h b/drivers/staging/winbond/wbhal_f.h
new file mode 100644
index 0000000..fe25f97
--- /dev/null
+++ b/drivers/staging/winbond/wbhal_f.h
@@ -0,0 +1,122 @@
+//=====================================================================
+// Device related include
+//=====================================================================
+#ifdef WB_LINUX
+ #include "linux/wbusb_f.h"
+ #include "linux/wb35reg_f.h"
+ #include "linux/wb35tx_f.h"
+ #include "linux/wb35rx_f.h"
+#else
+ #include "wbusb_f.h"
+ #include "wb35reg_f.h"
+ #include "wb35tx_f.h"
+ #include "wb35rx_f.h"
+#endif
+
+//====================================================================================
+// Function declaration
+//====================================================================================
+void hal_remove_mapping_key( phw_data_t pHwData, PUCHAR pmac_addr );
+void hal_remove_default_key( phw_data_t pHwData, u32 index );
+unsigned char hal_set_mapping_key( phw_data_t Adapter, PUCHAR pmac_addr, u8 null_key, u8 wep_on, PUCHAR ptx_tsc, PUCHAR prx_tsc, u8 key_type, u8 key_len, PUCHAR pkey_data );
+unsigned char hal_set_default_key( phw_data_t Adapter, u8 index, u8 null_key, u8 wep_on, PUCHAR ptx_tsc, PUCHAR prx_tsc, u8 key_type, u8 key_len, PUCHAR pkey_data );
+void hal_clear_all_default_key( phw_data_t pHwData );
+void hal_clear_all_group_key( phw_data_t pHwData );
+void hal_clear_all_mapping_key( phw_data_t pHwData );
+void hal_clear_all_key( phw_data_t pHwData );
+void hal_get_ethernet_address( phw_data_t pHwData, PUCHAR current_address );
+void hal_set_ethernet_address( phw_data_t pHwData, PUCHAR current_address );
+void hal_get_permanent_address( phw_data_t pHwData, PUCHAR pethernet_address );
+unsigned char hal_init_hardware( phw_data_t pHwData, PADAPTER Adapter );
+void hal_set_power_save_mode( phw_data_t pHwData, unsigned char power_save, unsigned char wakeup, unsigned char dtim );
+void hal_get_power_save_mode( phw_data_t pHwData, PBOOLEAN pin_pwr_save );
+void hal_set_slot_time( phw_data_t pHwData, u8 type );
+#define hal_set_atim_window( _A, _ATM )
+void hal_set_rates( phw_data_t pHwData, PUCHAR pbss_rates, u8 length, unsigned char basic_rate_set );
+#define hal_set_basic_rates( _A, _R, _L ) hal_set_rates( _A, _R, _L, TRUE )
+#define hal_set_op_rates( _A, _R, _L ) hal_set_rates( _A, _R, _L, FALSE )
+void hal_start_bss( phw_data_t pHwData, u8 mac_op_mode );
+void hal_join_request( phw_data_t pHwData, u8 bss_type ); // 0:BSS STA 1:IBSS STA//
+void hal_stop_sync_bss( phw_data_t pHwData );
+void hal_resume_sync_bss( phw_data_t pHwData);
+void hal_set_aid( phw_data_t pHwData, u16 aid );
+void hal_set_bssid( phw_data_t pHwData, PUCHAR pbssid );
+void hal_get_bssid( phw_data_t pHwData, PUCHAR pbssid );
+void hal_set_beacon_period( phw_data_t pHwData, u16 beacon_period );
+void hal_set_listen_interval( phw_data_t pHwData, u16 listen_interval );
+void hal_set_cap_info( phw_data_t pHwData, u16 capability_info );
+void hal_set_ssid( phw_data_t pHwData, PUCHAR pssid, u8 ssid_len );
+void hal_set_current_channel( phw_data_t pHwData, ChanInfo channel );
+void hal_set_current_channel_ex( phw_data_t pHwData, ChanInfo channel );
+void hal_get_current_channel( phw_data_t pHwData, ChanInfo *channel );
+void hal_set_accept_broadcast( phw_data_t pHwData, u8 enable );
+void hal_set_accept_multicast( phw_data_t pHwData, u8 enable );
+void hal_set_accept_beacon( phw_data_t pHwData, u8 enable );
+void hal_set_multicast_address( phw_data_t pHwData, PUCHAR address, u8 number );
+u8 hal_get_accept_beacon( phw_data_t pHwData );
+void hal_stop( phw_data_t pHwData );
+void hal_halt( phw_data_t pHwData, void *ppa_data );
+void hal_start_tx0( phw_data_t pHwData );
+void hal_set_phy_type( phw_data_t pHwData, u8 PhyType );
+void hal_get_phy_type( phw_data_t pHwData, u8 *PhyType );
+unsigned char hal_reset_hardware( phw_data_t pHwData, void* ppa );
+void hal_set_cwmin( phw_data_t pHwData, u8 cwin_min );
+#define hal_get_cwmin( _A ) ( (_A)->cwmin )
+void hal_set_cwmax( phw_data_t pHwData, u16 cwin_max );
+#define hal_get_cwmax( _A ) ( (_A)->cwmax )
+void hal_set_rsn_wpa( phw_data_t pHwData, u32 * RSN_IE_Bitmap , u32 * RSN_OUI_type , unsigned char bDesiredAuthMode);
+//s32 hal_get_rssi( phw_data_t pHwData, u32 HalRssi );
+s32 hal_get_rssi( phw_data_t pHwData, u32 *HalRssiArry, u8 Count );
+s32 hal_get_rssi_bss( phw_data_t pHwData, u16 idx, u8 Count );
+void hal_set_connect_info( phw_data_t pHwData, unsigned char boConnect );
+u8 hal_get_est_sq3( phw_data_t pHwData, u8 Count );
+void hal_led_control_1a( phw_data_t pHwData );
+void hal_led_control( void* S1, phw_data_t pHwData, void* S3, void* S4 );
+void hal_set_rf_power( phw_data_t pHwData, u8 PowerIndex ); // 20060621 Modify
+void hal_reset_counter( phw_data_t pHwData );
+void hal_set_radio_mode( phw_data_t pHwData, unsigned char boValue);
+void hal_descriptor_indicate( phw_data_t pHwData, PDESCRIPTOR pDes );
+u8 hal_get_antenna_number( phw_data_t pHwData );
+void hal_set_antenna_number( phw_data_t pHwData, u8 number );
+u32 hal_get_bss_pk_cnt( phw_data_t pHwData );
+#define hal_get_region_from_EEPROM( _A ) ( (_A)->Wb35Reg.EEPROMRegion )
+void hal_set_accept_promiscuous ( phw_data_t pHwData, u8 enable);
+#define hal_get_tx_buffer( _A, _B ) Wb35Tx_get_tx_buffer( _A, _B )
+u8 hal_get_hw_radio_off ( phw_data_t pHwData );
+#define hal_software_set( _A ) (_A->SoftwareSet)
+#define hal_driver_init_OK( _A ) (_A->IsInitOK)
+#define hal_rssi_boundary_high( _A ) (_A->RSSI_high)
+#define hal_rssi_boundary_low( _A ) (_A->RSSI_low)
+#define hal_scan_interval( _A ) (_A->Scan_Interval)
+void hal_scan_status_indicate( phw_data_t pHwData, u8 status); // 0: complete, 1: in progress
+void hal_system_power_change( phw_data_t pHwData, u32 PowerState ); // 20051230 -=D0 1=D1 ..
+void hal_surprise_remove( phw_data_t pHwData );
+
+#define PHY_DEBUG( msg, args... )
+
+
+
+void hal_rate_change( phw_data_t pHwData ); // Notify the HAL rate is changing 20060613.1
+unsigned char hal_get_dxx_reg( phw_data_t pHwData, u16 number, PULONG pValue );
+unsigned char hal_set_dxx_reg( phw_data_t pHwData, u16 number, u32 value );
+#define hal_get_time_count( _P ) (_P->time_count/10) // return 100ms count
+#define hal_detect_error( _P ) (_P->WbUsb.DetectCount)
+unsigned char hal_set_LED( phw_data_t pHwData, u32 Mode ); // 20061108 for WPS led control
+
+//-------------------------------------------------------------------------
+// The follow function is unused for IS89C35
+//-------------------------------------------------------------------------
+#define hal_disable_interrupt(_A)
+#define hal_enable_interrupt(_A)
+#define hal_get_interrupt_type( _A)
+#define hal_get_clear_interrupt(_A)
+#define hal_ibss_disconnect(_A) hal_stop_sync_bss(_A)
+#define hal_join_request_stop(_A)
+unsigned char hal_idle( phw_data_t pHwData );
+#define pa_stall_execution( _A ) //OS_SLEEP( 1 )
+#define hw_get_cxx_reg( _A, _B, _C )
+#define hw_set_cxx_reg( _A, _B, _C )
+#define hw_get_dxx_reg( _A, _B, _C ) hal_get_dxx_reg( _A, _B, (PULONG)_C )
+#define hw_set_dxx_reg( _A, _B, _C ) hal_set_dxx_reg( _A, _B, (u32)_C )
+
+
diff --git a/drivers/staging/winbond/wbhal_s.h b/drivers/staging/winbond/wbhal_s.h
new file mode 100644
index 0000000..5b862ff
--- /dev/null
+++ b/drivers/staging/winbond/wbhal_s.h
@@ -0,0 +1,615 @@
+//[20040722 WK]
+#define HAL_LED_SET_MASK 0x001c //20060901 Extend
+#define HAL_LED_SET_SHIFT 2
+
+//supported RF type
+#define RF_MAXIM_2825 0
+#define RF_MAXIM_2827 1
+#define RF_MAXIM_2828 2
+#define RF_MAXIM_2829 3
+#define RF_MAXIM_V1 15
+#define RF_AIROHA_2230 16
+#define RF_AIROHA_7230 17
+#define RF_AIROHA_2230S 18 // 20060420 Add this
+// #define RF_RFMD_2959 32 // 20060626 Remove all about RFMD
+#define RF_WB_242 33
+#define RF_WB_242_1 34 // 20060619.5 Add
+#define RF_DECIDE_BY_INF 255
+
+//----------------------------------------------------------------
+// The follow define connect to upper layer
+// User must modify for connection between HAL and upper layer
+//----------------------------------------------------------------
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+//================================================================================================
+// Common define
+//================================================================================================
+#define HAL_USB_MODE_BURST( _H ) (_H->SoftwareSet & 0x20 ) // Bit 5 20060901 Modify
+
+// Scan interval
+#define SCAN_MAX_CHNL_TIME (50)
+
+// For TxL2 Frame typr recognise
+#define FRAME_TYPE_802_3_DATA 0
+#define FRAME_TYPE_802_11_MANAGEMENT 1
+#define FRAME_TYPE_802_11_MANAGEMENT_CHALLENGE 2
+#define FRAME_TYPE_802_11_CONTROL 3
+#define FRAME_TYPE_802_11_DATA 4
+#define FRAME_TYPE_PROMISCUOUS 5
+
+// The follow definition is used for convert the frame--------------------
+#define DOT_11_SEQUENCE_OFFSET 22 //Sequence control offset
+#define DOT_3_TYPE_OFFSET 12
+#define DOT_11_MAC_HEADER_SIZE 24
+#define DOT_11_SNAP_SIZE 6
+#define DOT_11_TYPE_OFFSET 30 //The start offset of 802.11 Frame. Type encapsulatuin.
+#define DEFAULT_SIFSTIME 10
+#define DEFAULT_FRAGMENT_THRESHOLD 2346 // No fragment
+#define DEFAULT_MSDU_LIFE_TIME 0xffff
+
+#define LONG_PREAMBLE_PLUS_PLCPHEADER_TIME (144+48)
+#define SHORT_PREAMBLE_PLUS_PLCPHEADER_TIME (72+24)
+#define PREAMBLE_PLUS_SIGNAL_PLUS_SIGNALEXTENSION (16+4+6)
+#define Tsym 4
+
+// Frame Type of Bits (2, 3)---------------------------------------------
+#define MAC_TYPE_MANAGEMENT 0x00
+#define MAC_TYPE_CONTROL 0x04
+#define MAC_TYPE_DATA 0x08
+#define MASK_FRAGMENT_NUMBER 0x000F
+#define SEQUENCE_NUMBER_SHIFT 4
+
+#define HAL_WOL_TYPE_WAKEUP_FRAME 0x01
+#define HAL_WOL_TYPE_MAGIC_PACKET 0x02
+
+// 20040106 ADDED
+#define HAL_KEYTYPE_WEP40 0
+#define HAL_KEYTYPE_WEP104 1
+#define HAL_KEYTYPE_TKIP 2 // 128 bit key
+#define HAL_KEYTYPE_AES_CCMP 3 // 128 bit key
+
+// For VM state
+enum {
+ VM_STOP = 0,
+ VM_RUNNING,
+ VM_COMPLETED
+};
+
+// Be used for 802.11 mac header
+typedef struct _MAC_FRAME_CONTROL {
+ u8 mac_frame_info; // this is a combination of the protovl version, type and subtype
+ u8 to_ds:1;
+ u8 from_ds:1;
+ u8 more_frag:1;
+ u8 retry:1;
+ u8 pwr_mgt:1;
+ u8 more_data:1;
+ u8 WEP:1;
+ u8 order:1;
+} MAC_FRAME_CONTROL, *PMAC_FRAME_CONTROL;
+
+//-----------------------------------------------------
+// Normal Key table format
+//-----------------------------------------------------
+// The order of KEY index is MAPPING_KEY_START_INDEX > GROUP_KEY_START_INDEX
+#define MAX_KEY_TABLE 24 // 24 entry for storing key data
+#define GROUP_KEY_START_INDEX 4
+#define MAPPING_KEY_START_INDEX 8
+typedef struct _KEY_TABLE
+{
+ u32 DW0_Valid:1;
+ u32 DW0_NullKey:1;
+ u32 DW0_Security_Mode:2;//0:WEP 40 bit 1:WEP 104 bit 2:TKIP 128 bit 3:CCMP 128 bit
+ u32 DW0_WEPON:1;
+ u32 DW0_RESERVED:11;
+ u32 DW0_Address1:16;
+
+ u32 DW1_Address2;
+
+ u32 DW2_RxSequenceCount1;
+
+ u32 DW3_RxSequenceCount2:16;
+ u32 DW3_RESERVED:16;
+
+ u32 DW4_TxSequenceCount1;
+
+ u32 DW5_TxSequenceCount2:16;
+ u32 DW5_RESERVED:16;
+
+} KEY_TABLE, *PKEY_TABLE;
+
+//--------------------------------------------------------
+// Descriptor
+//--------------------------------------------------------
+#define MAX_DESCRIPTOR_BUFFER_INDEX 8 // Have to multiple of 2
+//#define FLAG_ERROR_TX_MASK cpu_to_le32(0x000000bf) //20061009 marked by anson's endian
+#define FLAG_ERROR_TX_MASK 0x000000bf //20061009 anson's endian
+//#define FLAG_ERROR_RX_MASK 0x00000c3f
+//#define FLAG_ERROR_RX_MASK cpu_to_le32(0x0000083f) //20061009 marked by anson's endian
+ //Don't care replay error,
+ //it is handled by S/W
+#define FLAG_ERROR_RX_MASK 0x0000083f //20060926 anson's endian
+
+#define FLAG_BAND_RX_MASK 0x10000000 //Bit 28
+
+typedef struct _R00_DESCRIPTOR
+{
+ union
+ {
+ u32 value;
+ #ifdef _BIG_ENDIAN_ //20060926 anson's endian
+ struct
+ {
+ u32 R00_packet_or_buffer_status:1;
+ u32 R00_packet_in_fifo:1;
+ u32 R00_RESERVED:2;
+ u32 R00_receive_byte_count:12;
+ u32 R00_receive_time_index:16;
+ };
+ #else
+ struct
+ {
+ u32 R00_receive_time_index:16;
+ u32 R00_receive_byte_count:12;
+ u32 R00_RESERVED:2;
+ u32 R00_packet_in_fifo:1;
+ u32 R00_packet_or_buffer_status:1;
+ };
+ #endif
+ };
+} R00_DESCRIPTOR, *PR00_DESCRIPTOR;
+
+typedef struct _T00_DESCRIPTOR
+{
+ union
+ {
+ u32 value;
+ #ifdef _BIG_ENDIAN_ //20061009 anson's endian
+ struct
+ {
+ u32 T00_first_mpdu:1; // for hardware use
+ u32 T00_last_mpdu:1; // for hardware use
+ u32 T00_IsLastMpdu:1;// 0: not 1:Yes for software used
+ u32 T00_IgnoreResult:1;// The same mechanism with T00 setting. 050111 Modify for TS
+ u32 T00_RESERVED_ID:2;//3 bit ID reserved
+ u32 T00_tx_packet_id:4;//930519.4.e 930810.3.c
+ u32 T00_RESERVED:4;
+ u32 T00_header_length:6;
+ u32 T00_frame_length:12;
+ };
+ #else
+ struct
+ {
+ u32 T00_frame_length:12;
+ u32 T00_header_length:6;
+ u32 T00_RESERVED:4;
+ u32 T00_tx_packet_id:4;//930519.4.e 930810.3.c
+ u32 T00_RESERVED_ID:2;//3 bit ID reserved
+ u32 T00_IgnoreResult:1;// The same mechanism with T00 setting. 050111 Modify for TS
+ u32 T00_IsLastMpdu:1;// 0: not 1:Yes for software used
+ u32 T00_last_mpdu:1; // for hardware use
+ u32 T00_first_mpdu:1; // for hardware use
+ };
+ #endif
+ };
+} T00_DESCRIPTOR, *PT00_DESCRIPTOR;
+
+typedef struct _R01_DESCRIPTOR
+{
+ union
+ {
+ u32 value;
+ #ifdef _BIG_ENDIAN_ //20060926 add by anson's endian
+ struct
+ {
+ u32 R01_RESERVED:3;
+ u32 R01_mod_type:1;
+ u32 R01_pre_type:1;
+ u32 R01_data_rate:3;
+ u32 R01_AGC_state:8;
+ u32 R01_LNA_state:2;
+ u32 R01_decryption_method:2;
+ u32 R01_mic_error:1;
+ u32 R01_replay:1;
+ u32 R01_broadcast_frame:1;
+ u32 R01_multicast_frame:1;
+ u32 R01_directed_frame:1;
+ u32 R01_receive_frame_antenna_selection:1;
+ u32 R01_frame_receive_during_atim_window:1;
+ u32 R01_protocol_version_error:1;
+ u32 R01_authentication_frame_icv_error:1;
+ u32 R01_null_key_to_authentication_frame:1;
+ u32 R01_icv_error:1;
+ u32 R01_crc_error:1;
+ };
+ #else
+ struct
+ {
+ u32 R01_crc_error:1;
+ u32 R01_icv_error:1;
+ u32 R01_null_key_to_authentication_frame:1;
+ u32 R01_authentication_frame_icv_error:1;
+ u32 R01_protocol_version_error:1;
+ u32 R01_frame_receive_during_atim_window:1;
+ u32 R01_receive_frame_antenna_selection:1;
+ u32 R01_directed_frame:1;
+ u32 R01_multicast_frame:1;
+ u32 R01_broadcast_frame:1;
+ u32 R01_replay:1;
+ u32 R01_mic_error:1;
+ u32 R01_decryption_method:2;
+ u32 R01_LNA_state:2;
+ u32 R01_AGC_state:8;
+ u32 R01_data_rate:3;
+ u32 R01_pre_type:1;
+ u32 R01_mod_type:1;
+ u32 R01_RESERVED:3;
+ };
+ #endif
+ };
+} R01_DESCRIPTOR, *PR01_DESCRIPTOR;
+
+typedef struct _T01_DESCRIPTOR
+{
+ union
+ {
+ u32 value;
+ #ifdef _BIG_ENDIAN_ //20061009 anson's endian
+ struct
+ {
+ u32 T01_rts_cts_duration:16;
+ u32 T01_fall_back_rate:3;
+ u32 T01_add_rts:1;
+ u32 T01_add_cts:1;
+ u32 T01_modulation_type:1;
+ u32 T01_plcp_header_length:1;
+ u32 T01_transmit_rate:3;
+ u32 T01_wep_id:2;
+ u32 T01_add_challenge_text:1;
+ u32 T01_inhibit_crc:1;
+ u32 T01_loop_back_wep_mode:1;
+ u32 T01_retry_abort_ebable:1;
+ };
+ #else
+ struct
+ {
+ u32 T01_retry_abort_ebable:1;
+ u32 T01_loop_back_wep_mode:1;
+ u32 T01_inhibit_crc:1;
+ u32 T01_add_challenge_text:1;
+ u32 T01_wep_id:2;
+ u32 T01_transmit_rate:3;
+ u32 T01_plcp_header_length:1;
+ u32 T01_modulation_type:1;
+ u32 T01_add_cts:1;
+ u32 T01_add_rts:1;
+ u32 T01_fall_back_rate:3;
+ u32 T01_rts_cts_duration:16;
+ };
+ #endif
+ };
+} T01_DESCRIPTOR, *PT01_DESCRIPTOR;
+
+typedef struct _T02_DESCRIPTOR
+{
+ union
+ {
+ u32 value;
+ #ifdef _BIG_ENDIAN_ //20061009 add by anson's endian
+ struct
+ {
+ u32 T02_IsLastMpdu:1;// The same mechanism with T00 setting
+ u32 T02_IgnoreResult:1;// The same mechanism with T00 setting. 050111 Modify for TS
+ u32 T02_RESERVED_ID:2;// The same mechanism with T00 setting
+ u32 T02_Tx_PktID:4;
+ u32 T02_MPDU_Cnt:4;
+ u32 T02_RTS_Cnt:4;
+ u32 T02_RESERVED:7;
+ u32 T02_transmit_complete:1;
+ u32 T02_transmit_abort_due_to_TBTT:1;
+ u32 T02_effective_transmission_rate:1;
+ u32 T02_transmit_without_encryption_due_to_wep_on_false:1;
+ u32 T02_discard_due_to_null_wep_key:1;
+ u32 T02_RESERVED_1:1;
+ u32 T02_out_of_MaxTxMSDULiftTime:1;
+ u32 T02_transmit_abort:1;
+ u32 T02_transmit_fail:1;
+ };
+ #else
+ struct
+ {
+ u32 T02_transmit_fail:1;
+ u32 T02_transmit_abort:1;
+ u32 T02_out_of_MaxTxMSDULiftTime:1;
+ u32 T02_RESERVED_1:1;
+ u32 T02_discard_due_to_null_wep_key:1;
+ u32 T02_transmit_without_encryption_due_to_wep_on_false:1;
+ u32 T02_effective_transmission_rate:1;
+ u32 T02_transmit_abort_due_to_TBTT:1;
+ u32 T02_transmit_complete:1;
+ u32 T02_RESERVED:7;
+ u32 T02_RTS_Cnt:4;
+ u32 T02_MPDU_Cnt:4;
+ u32 T02_Tx_PktID:4;
+ u32 T02_RESERVED_ID:2;// The same mechanism with T00 setting
+ u32 T02_IgnoreResult:1;// The same mechanism with T00 setting. 050111 Modify for TS
+ u32 T02_IsLastMpdu:1;// The same mechanism with T00 setting
+ };
+ #endif
+ };
+} T02_DESCRIPTOR, *PT02_DESCRIPTOR;
+
+typedef struct _DESCRIPTOR { // Skip length = 8 DWORD
+ // ID for descriptor ---, The field doesn't be cleard in the operation of Descriptor definition
+ u8 Descriptor_ID;
+ //----------------------The above region doesn't be cleared by DESCRIPTOR_RESET------
+ u8 RESERVED[3];
+
+ u16 FragmentThreshold;
+ u8 InternalUsed;//Only can be used by operation of descriptor definition
+ u8 Type;// 0: 802.3 1:802.11 data frame 2:802.11 management frame
+
+ u8 PreambleMode;// 0: short 1:long
+ u8 TxRate;
+ u8 FragmentCount;
+ u8 EapFix; // For speed up key install
+
+ // For R00 and T00 ----------------------------------------------
+ union
+ {
+ R00_DESCRIPTOR R00;
+ T00_DESCRIPTOR T00;
+ };
+
+ // For R01 and T01 ----------------------------------------------
+ union
+ {
+ R01_DESCRIPTOR R01;
+ T01_DESCRIPTOR T01;
+ };
+
+ // For R02 and T02 ----------------------------------------------
+ union
+ {
+ u32 R02;
+ T02_DESCRIPTOR T02;
+ };
+
+ // For R03 and T03 ----------------------------------------------
+ // For software used
+ union
+ {
+ u32 R03;
+ u32 T03;
+ struct
+ {
+ u8 buffer_number;
+ u8 buffer_start_index;
+ u16 buffer_total_size;
+ };
+ };
+
+ // For storing the buffer
+ u16 buffer_size[ MAX_DESCRIPTOR_BUFFER_INDEX ];
+ void* buffer_address[ MAX_DESCRIPTOR_BUFFER_INDEX ];//931130.4.q
+
+} DESCRIPTOR, *PDESCRIPTOR;
+
+
+#define DEFAULT_NULL_PACKET_COUNT 180000 //20060828.1 Add. 180 seconds
+
+#define MAX_TXVGA_EEPROM 9 //How many word(u16) of EEPROM will be used for TxVGA
+#define MAX_RF_PARAMETER 32
+
+typedef struct _TXVGA_FOR_50 {
+ u8 ChanNo;
+ u8 TxVgaValue;
+} TXVGA_FOR_50;
+
+
+//=====================================================================
+// Device related include
+//=====================================================================
+
+#include "linux/wbusb_s.h"
+#include "linux/wb35reg_s.h"
+#include "linux/wb35tx_s.h"
+#include "linux/wb35rx_s.h"
+
+
+// For Hal using ==================================================================
+typedef struct _HW_DATA_T
+{
+ // For compatible with 33
+ u32 revision;
+ u32 BB3c_cal; // The value for Tx calibration comes from EEPROM
+ u32 BB54_cal; // The value for Rx calibration comes from EEPROM
+
+
+ // For surprise remove
+ u32 SurpriseRemove; // 0: Normal 1: Surprise remove
+ u8 InitialResource;
+ u8 IsKeyPreSet;
+ u8 CalOneTime; // 20060630.1
+
+ u8 VCO_trim;
+
+ // For Fix 1'st DMA bug
+ u32 FragCount;
+ u32 DMAFix; //V1_DMA_FIX The variable can be removed if driver want to save mem space for V2.
+
+ //=======================================================================================
+ // For USB driver, hal need more variables. Due to
+ // 1. NDIS-WDM operation
+ // 2. The SME, MLME and OLD MDS need Adapter structure, but the driver under HAL doesn't
+ // have that parameter when receiving and indicating packet.
+ // The MDS must input the Adapter pointer as the second parameter of hal_init_hardware.
+ // The function usage is different than PCI driver.
+ //=======================================================================================
+ void* Adapter;
+
+ //===============================================
+ // Definition for MAC address
+ //===============================================
+ u8 PermanentMacAddress[ETH_LENGTH_OF_ADDRESS + 2]; // The Enthernet addr that are stored in EEPROM. + 2 to 8-byte alignment
+ u8 CurrentMacAddress[ETH_LENGTH_OF_ADDRESS + 2]; // The Enthernet addr that are in used. + 2 to 8-byte alignment
+
+ //=====================================================================
+ // Definition for 802.11
+ //=====================================================================
+ PUCHAR bssid_pointer; // Used by hal_get_bssid for return value
+ u8 bssid[8];// Only 6 byte will be used. 8 byte is required for read buffer
+ u8 ssid[32];// maximum ssid length is 32 byte
+
+ u16 AID;
+ u8 ssid_length;
+ u8 Channel;
+
+ u16 ListenInterval;
+ u16 CapabilityInformation;
+
+ u16 BeaconPeriod;
+ u16 ProbeDelay;
+
+ u8 bss_type;// 0: IBSS_NET or 1:ESS_NET
+ u8 preamble;// 0: short preamble, 1: long preamble
+ u8 slot_time_select;// 9 or 20 value
+ u8 phy_type;// Phy select
+
+ u32 phy_para[MAX_RF_PARAMETER];
+ u32 phy_number;
+
+ u32 CurrentRadioSw; // 20060320.2 0:On 1:Off
+ u32 CurrentRadioHw; // 20060825 0:On 1:Off
+
+ PUCHAR power_save_point; // Used by hal_get_power_save_mode for return value
+ u8 cwmin;
+ u8 desired_power_save;
+ u8 dtim;// Is running dtim
+ u8 mapping_key_replace_index;//In Key table, the next index be replaced 931130.4.r
+
+ u16 MaxReceiveLifeTime;
+ u16 FragmentThreshold;
+ u16 FragmentThreshold_tmp;
+ u16 cwmax;
+
+ u8 Key_slot[MAX_KEY_TABLE][8]; //Ownership record for key slot. For Alignment
+ u32 Key_content[MAX_KEY_TABLE][12]; // 10DW for each entry + 2 for burst command( Off and On valid bit)
+ u8 CurrentDefaultKeyIndex;
+ u32 CurrentDefaultKeyLength;
+
+ //========================================================================
+ // Variable for each module
+ //========================================================================
+ WBUSB WbUsb; // Need WbUsb.h
+ WB35REG Wb35Reg; // Need Wb35Reg.h
+ WB35TX Wb35Tx; // Need Wb35Tx.h
+ WB35RX Wb35Rx; // Need Wb35Rx.h
+
+ OS_TIMER LEDTimer;// For LED
+
+ u32 LEDpoint;// For LED
+
+ u32 dto_tx_retry_count; // LA20040210_DTO kevin
+ u32 dto_tx_frag_count; // LA20040210_DTO kevin
+ u32 rx_ok_count[13]; // index=0: total rx ok
+ //u32 rx_ok_bytes[13]; // index=0, total rx ok bytes
+ u32 rx_err_count[13]; // index=0: total rx err
+
+ //for Tx debug
+ u32 tx_TBTT_start_count;
+ u32 tx_ETR_count;
+ u32 tx_WepOn_false_count;
+ u32 tx_Null_key_count;
+ u32 tx_retry_count[8];
+
+ u8 PowerIndexFromEEPROM; // For 2412MHz
+ u8 power_index;
+ u8 IsWaitJoinComplete; // TRUE: set join request
+ u8 band;
+
+ u16 SoftwareSet;
+ u16 Reserved_s;
+
+ u32 IsInitOK; // 0: Driver starting 1: Driver init OK
+
+ // For Phy calibration
+ s32 iq_rsdl_gain_tx_d2;
+ s32 iq_rsdl_phase_tx_d2;
+ u32 txvga_setting_for_cal; // 20060703.1 Add
+
+ u8 TxVgaSettingInEEPROM[ (((MAX_TXVGA_EEPROM*2)+3) & ~0x03) ]; // 20060621 For backup EEPROM value
+ u8 TxVgaFor24[16]; // Max is 14, 2 for alignment
+ TXVGA_FOR_50 TxVgaFor50[36]; // 35 channels in 5G. 35x2 = 70 byte. 2 for alignments
+
+ u16 Scan_Interval;
+ u16 RESERVED6;
+
+ // LED control
+ u32 LED_control;
+ // LED_control 4 byte: Gray_Led_1[3] Gray_Led_0[2] Led[1] Led[0]
+ // Gray_Led
+ // For Led gray setting
+ // Led
+ // 0: normal control, LED behavior will decide by EEPROM setting
+ // 1: Turn off specific LED
+ // 2: Always on specific LED
+ // 3: slow blinking specific LED
+ // 4: fast blinking specific LED
+ // 5: WPS led control is set. Led0 is Red, Led1 id Green
+ // Led[1] is parameter for WPS LED mode
+ // // 1:InProgress 2: Error 3: Session overlap 4: Success 20061108 control
+
+ u32 LED_LinkOn; //Turn LED on control
+ u32 LED_Scanning; // Let LED in scan process control
+ u32 LED_Blinking; // Temp variable for shining
+ u32 RxByteCountLast;
+ u32 TxByteCountLast;
+
+ s32 SurpriseRemoveCount;
+
+ // For global timer
+ u32 time_count;//TICK_TIME_100ms 1 = 100ms
+
+ // For error recover
+ u32 HwStop;
+
+ // 20060828.1 for avoid AP disconnect
+ u32 NullPacketCount;
+
+} hw_data_t, *phw_data_t;
+
+// The mapping of Rx and Tx descriptor field
+typedef struct _HAL_RATE
+{
+ // DSSS
+ u32 RESERVED_0;
+ u32 NumRate2MS;
+ u32 NumRate55MS;
+ u32 NumRate11MS;
+
+ u32 RESERVED_1[4];
+
+ u32 NumRate1M;
+ u32 NumRate2ML;
+ u32 NumRate55ML;
+ u32 NumRate11ML;
+
+ u32 RESERVED_2[4];
+
+ // OFDM
+ u32 NumRate6M;
+ u32 NumRate9M;
+ u32 NumRate12M;
+ u32 NumRate18M;
+ u32 NumRate24M;
+ u32 NumRate36M;
+ u32 NumRate48M;
+ u32 NumRate54M;
+} HAL_RATE, *PHAL_RATE;
+
+
diff --git a/drivers/staging/winbond/wblinux.c b/drivers/staging/winbond/wblinux.c
new file mode 100644
index 0000000..2eade5a
--- /dev/null
+++ b/drivers/staging/winbond/wblinux.c
@@ -0,0 +1,277 @@
+//============================================================================
+// Copyright (c) 1996-2005 Winbond Electronic Corporation
+//
+// Module Name:
+// wblinux.c
+//
+// Abstract:
+// Linux releated routines
+//
+//============================================================================
+#include "os_common.h"
+
+u32
+WBLINUX_MemoryAlloc(void* *VirtualAddress, u32 Length)
+{
+ *VirtualAddress = kzalloc( Length, GFP_ATOMIC ); //GFP_KERNEL is not suitable
+
+ if (*VirtualAddress == NULL)
+ return 0;
+ return 1;
+}
+
+s32
+EncapAtomicInc(PADAPTER Adapter, void* pAtomic)
+{
+ PWBLINUX pWbLinux = &Adapter->WbLinux;
+ u32 ltmp;
+ PULONG pltmp = (PULONG)pAtomic;
+ OS_SPIN_LOCK_ACQUIRED( &pWbLinux->AtomicSpinLock );
+ (*pltmp)++;
+ ltmp = (*pltmp);
+ OS_SPIN_LOCK_RELEASED( &pWbLinux->AtomicSpinLock );
+ return ltmp;
+}
+
+s32
+EncapAtomicDec(PADAPTER Adapter, void* pAtomic)
+{
+ PWBLINUX pWbLinux = &Adapter->WbLinux;
+ u32 ltmp;
+ PULONG pltmp = (PULONG)pAtomic;
+ OS_SPIN_LOCK_ACQUIRED( &pWbLinux->AtomicSpinLock );
+ (*pltmp)--;
+ ltmp = (*pltmp);
+ OS_SPIN_LOCK_RELEASED( &pWbLinux->AtomicSpinLock );
+ return ltmp;
+}
+
+unsigned char
+WBLINUX_Initial(PADAPTER Adapter)
+{
+ PWBLINUX pWbLinux = &Adapter->WbLinux;
+
+ OS_SPIN_LOCK_ALLOCATE( &pWbLinux->SpinLock );
+ OS_SPIN_LOCK_ALLOCATE( &pWbLinux->AtomicSpinLock );
+ return TRUE;
+}
+
+void
+WBLinux_ReceivePacket(PADAPTER Adapter, PRXLAYER1 pRxLayer1)
+{
+ BUG();
+}
+
+
+void
+WBLINUX_GetNextPacket(PADAPTER Adapter, PDESCRIPTOR pDes)
+{
+ BUG();
+}
+
+void
+WBLINUX_GetNextPacketCompleted(PADAPTER Adapter, PDESCRIPTOR pDes)
+{
+ BUG();
+}
+
+void
+WBLINUX_Destroy(PADAPTER Adapter)
+{
+ WBLINUX_stop( Adapter );
+ OS_SPIN_LOCK_FREE( &pWbNdis->SpinLock );
+#ifdef _PE_USB_INI_DUMP_
+ WBDEBUG(("[w35und] unregister_netdev!\n"));
+#endif
+}
+
+void
+WBLINUX_stop( PADAPTER Adapter )
+{
+ PWBLINUX pWbLinux = &Adapter->WbLinux;
+ struct sk_buff *pSkb;
+
+ if (OS_ATOMIC_INC( Adapter, &pWbLinux->ThreadCount ) == 1) {
+ // Shutdown module immediately
+ pWbLinux->shutdown = 1;
+
+ while (pWbLinux->skb_array[ pWbLinux->skb_GetIndex ]) {
+ // Trying to free the un-sending packet
+ pSkb = pWbLinux->skb_array[ pWbLinux->skb_GetIndex ];
+ pWbLinux->skb_array[ pWbLinux->skb_GetIndex ] = NULL;
+ if( in_irq() )
+ dev_kfree_skb_irq( pSkb );
+ else
+ dev_kfree_skb( pSkb );
+
+ pWbLinux->skb_GetIndex++;
+ pWbLinux->skb_GetIndex %= WBLINUX_PACKET_ARRAY_SIZE;
+ }
+
+#ifdef _PE_STATE_DUMP_
+ WBDEBUG(( "[w35und] SKB_RELEASE OK\n" ));
+#endif
+ }
+
+ OS_ATOMIC_DEC( Adapter, &pWbLinux->ThreadCount );
+}
+
+void
+WbWlanHalt( PADAPTER Adapter )
+{
+ //---------------------
+ Adapter->sLocalPara.ShutDowned = TRUE;
+
+ Mds_Destroy( Adapter );
+
+ // Turn off Rx and Tx hardware ability
+ hal_stop( &Adapter->sHwData );
+#ifdef _PE_USB_INI_DUMP_
+ WBDEBUG(("[w35und] Hal_stop O.K.\n"));
+#endif
+ OS_SLEEP(100000);// Waiting Irp completed
+
+ // Destroy the NDIS module
+ WBLINUX_Destroy( Adapter );
+
+ // Halt the HAL
+ hal_halt(&Adapter->sHwData, NULL);
+}
+
+unsigned char
+WbWLanInitialize(PADAPTER Adapter)
+{
+ phw_data_t pHwData;
+ PUCHAR pMacAddr, pMacAddr2;
+ u32 InitStep = 0;
+ u8 EEPROM_region;
+ u8 HwRadioOff;
+
+ do {
+ //
+ // Setting default value for Linux
+ //
+ Adapter->sLocalPara.region_INF = REGION_AUTO;
+ Adapter->sLocalPara.TxRateMode = RATE_AUTO;
+ psLOCAL->bMacOperationMode = MODE_802_11_BG; // B/G mode
+ Adapter->Mds.TxRTSThreshold = DEFAULT_RTSThreshold;
+ Adapter->Mds.TxFragmentThreshold = DEFAULT_FRAGMENT_THRESHOLD;
+ hal_set_phy_type( &Adapter->sHwData, RF_WB_242_1 );
+ Adapter->sLocalPara.MTUsize = MAX_ETHERNET_PACKET_SIZE;
+ psLOCAL->bPreambleMode = AUTO_MODE;
+ Adapter->sLocalPara.RadioOffStatus.boSwRadioOff = FALSE;
+ pHwData = &Adapter->sHwData;
+ hal_set_phy_type( pHwData, RF_DECIDE_BY_INF );
+
+ //
+ // Initial each module and variable
+ //
+ if (!WBLINUX_Initial(Adapter)) {
+#ifdef _PE_USB_INI_DUMP_
+ WBDEBUG(("[w35und]WBNDIS initialization failed\n"));
+#endif
+ break;
+ }
+
+ // Initial Software variable
+ Adapter->sLocalPara.ShutDowned = FALSE;
+
+ //added by ws for wep key error detection
+ Adapter->sLocalPara.bWepKeyError= FALSE;
+ Adapter->sLocalPara.bToSelfPacketReceived = FALSE;
+ Adapter->sLocalPara.WepKeyDetectTimerCount= 2 * 100; /// 2 seconds
+
+ // Initial USB hal
+ InitStep = 1;
+ pHwData = &Adapter->sHwData;
+ if (!hal_init_hardware(pHwData, Adapter))
+ break;
+
+ EEPROM_region = hal_get_region_from_EEPROM( pHwData );
+ if (EEPROM_region != REGION_AUTO)
+ psLOCAL->region = EEPROM_region;
+ else {
+ if (psLOCAL->region_INF != REGION_AUTO)
+ psLOCAL->region = psLOCAL->region_INF;
+ else
+ psLOCAL->region = REGION_USA; //default setting
+ }
+
+ // Get Software setting flag from hal
+ Adapter->sLocalPara.boAntennaDiversity = FALSE;
+ if (hal_software_set(pHwData) & 0x00000001)
+ Adapter->sLocalPara.boAntennaDiversity = TRUE;
+
+ //
+ // For TS module
+ //
+ InitStep = 2;
+
+ // For MDS module
+ InitStep = 3;
+ Mds_initial(Adapter);
+
+ //=======================================
+ // Initialize the SME, SCAN, MLME, ROAM
+ //=======================================
+ InitStep = 4;
+ InitStep = 5;
+ InitStep = 6;
+
+ // If no user-defined address in the registry, use the addresss "burned" on the NIC instead.
+ pMacAddr = Adapter->sLocalPara.ThisMacAddress;
+ pMacAddr2 = Adapter->sLocalPara.PermanentAddress;
+ hal_get_permanent_address( pHwData, Adapter->sLocalPara.PermanentAddress );// Reading ethernet address from EEPROM
+ if (OS_MEMORY_COMPARE(pMacAddr, "\x00\x00\x00\x00\x00\x00", MAC_ADDR_LENGTH )) // Is equal
+ {
+ memcpy( pMacAddr, pMacAddr2, MAC_ADDR_LENGTH );
+ } else {
+ // Set the user define MAC address
+ hal_set_ethernet_address( pHwData, Adapter->sLocalPara.ThisMacAddress );
+ }
+
+ //get current antenna
+ psLOCAL->bAntennaNo = hal_get_antenna_number(pHwData);
+#ifdef _PE_STATE_DUMP_
+ WBDEBUG(("Driver init, antenna no = %d\n", psLOCAL->bAntennaNo));
+#endif
+ hal_get_hw_radio_off( pHwData );
+
+ // Waiting for HAL setting OK
+ while (!hal_idle(pHwData))
+ OS_SLEEP(10000);
+
+ MTO_Init(Adapter);
+
+ HwRadioOff = hal_get_hw_radio_off( pHwData );
+ psLOCAL->RadioOffStatus.boHwRadioOff = !!HwRadioOff;
+
+ hal_set_radio_mode( pHwData, (unsigned char)(psLOCAL->RadioOffStatus.boSwRadioOff || psLOCAL->RadioOffStatus.boHwRadioOff) );
+
+ hal_driver_init_OK(pHwData) = 1; // Notify hal that the driver is ready now.
+ //set a tx power for reference.....
+// sme_set_tx_power_level(Adapter, 12); FIXME?
+ return TRUE;
+ }
+ while(FALSE);
+
+ switch (InitStep) {
+ case 5:
+ case 4:
+ case 3: Mds_Destroy( Adapter );
+ case 2:
+ case 1: WBLINUX_Destroy( Adapter );
+ hal_halt( pHwData, NULL );
+ case 0: break;
+ }
+
+ return FALSE;
+}
+
+void WBLINUX_ConnectStatus(PADAPTER Adapter, u32 flag)
+{
+ PWBLINUX pWbLinux = &Adapter->WbLinux;
+
+ pWbLinux->LinkStatus = flag; // OS_DISCONNECTED or OS_CONNECTED
+}
+
diff --git a/drivers/staging/winbond/wblinux_f.h b/drivers/staging/winbond/wblinux_f.h
new file mode 100644
index 0000000..68240c5
--- /dev/null
+++ b/drivers/staging/winbond/wblinux_f.h
@@ -0,0 +1,23 @@
+//=========================================================================
+// Copyright (c) 1996-2004 Winbond Electronic Corporation
+//
+// wblinux_f.h
+//
+u32 WBLINUX_MemoryAlloc( void* *VirtualAddress, u32 Length );
+s32 EncapAtomicInc( PADAPTER Adapter, void* pAtomic );
+s32 EncapAtomicDec( PADAPTER Adapter, void* pAtomic );
+void WBLinux_ReceivePacket( PADAPTER Adapter, PRXLAYER1 pRxLayer1 );
+unsigned char WBLINUX_Initial( PADAPTER Adapter );
+int wb35_start_xmit(struct sk_buff *skb, struct net_device *netdev );
+void WBLINUX_GetNextPacket( PADAPTER Adapter, PDESCRIPTOR pDes );
+void WBLINUX_GetNextPacketCompleted( PADAPTER Adapter, PDESCRIPTOR pDes );
+void WBLINUX_stop( PADAPTER Adapter );
+void WBLINUX_Destroy( PADAPTER Adapter );
+void wb35_set_multicast( struct net_device *netdev );
+struct net_device_stats * wb35_netdev_stats( struct net_device *netdev );
+void WBLINUX_stop( PADAPTER Adapter );
+void WbWlanHalt( PADAPTER Adapter );
+void WBLINUX_ConnectStatus( PADAPTER Adapter, u32 flag );
+
+
+
diff --git a/drivers/staging/winbond/wblinux_s.h b/drivers/staging/winbond/wblinux_s.h
new file mode 100644
index 0000000..97e9167
--- /dev/null
+++ b/drivers/staging/winbond/wblinux_s.h
@@ -0,0 +1,45 @@
+//============================================================
+// wblinux_s.h
+//
+#define OS_MEMORY_ALLOC( _V, _S ) WBLINUX_MemoryAlloc( _V, _S )
+#define OS_LINK_STATUS (Adapter->WbLinux.LinkStatus == OS_CONNECTED)
+#define OS_SET_SHUTDOWN( _A ) _A->WbLinux.shutdown=1
+#define OS_SET_RESUME( _A ) _A->WbLinux.shutdown=0
+#define OS_CONNECT_STATUS_INDICATE( _A, _F ) WBLINUX_ConnectStatus( _A, _F )
+#define OS_DISCONNECTED 0
+#define OS_CONNECTED 1
+#define OS_STOP( _A ) WBLINUX_stop( _A )
+
+#define OS_CURRENT_RX_BYTE( _A ) _A->WbLinux.RxByteCount
+#define OS_CURRENT_TX_BYTE( _A ) _A->WbLinux.TxByteCount
+#define OS_EVENT_INDICATE( _A, _B, _F )
+#define OS_PMKID_STATUS_EVENT( _A )
+#define OS_RECEIVE_PACKET_INDICATE( _A, _D ) WBLinux_ReceivePacket( _A, _D )
+#define OS_RECEIVE_802_1X_PACKET_INDICATE( _A, _D ) EAP_ReceivePacket( _A, _D )
+#define OS_GET_PACKET( _A, _D ) WBLINUX_GetNextPacket( _A, _D )
+#define OS_GET_PACKET_COMPLETE( _A, _D ) WBLINUX_GetNextPacketCompleted( _A, _D )
+#define OS_SEND_RESULT( _A, _ID, _R )
+
+#define WBLINUX_PACKET_ARRAY_SIZE (ETHERNET_TX_DESCRIPTORS*4)
+
+typedef struct _WBLINUX
+{
+ OS_SPIN_LOCK AtomicSpinLock;
+ OS_SPIN_LOCK SpinLock;
+ u32 shutdown;
+
+ OS_ATOMIC ThreadCount;
+
+ u32 LinkStatus; // OS_DISCONNECTED or OS_CONNECTED
+
+ u32 RxByteCount;
+ u32 TxByteCount;
+
+ struct sk_buff *skb_array[ WBLINUX_PACKET_ARRAY_SIZE ];
+ struct sk_buff *packet_return;
+ s32 skb_SetIndex;
+ s32 skb_GetIndex;
+ s32 netif_state_stop; // 1: stop 0: normal
+} WBLINUX, *PWBLINUX;
+
+
--
1.6.0.2
^ permalink raw reply related [flat|nested] 37+ messages in thread* Re: [PATCH 14/23] Staging: add w35und wifi driver
2008-10-10 22:42 ` [PATCH 14/23] Staging: add w35und wifi driver Greg KH
@ 2008-10-18 20:55 ` Geert Uytterhoeven
0 siblings, 0 replies; 37+ messages in thread
From: Geert Uytterhoeven @ 2008-10-18 20:55 UTC (permalink / raw)
To: Greg KH; +Cc: linux-kernel, Pavel Machek, Greg Kroah-Hartman
On Fri, 10 Oct 2008, Greg KH wrote:
> From: Pavel Machek <pavel@suse.cz>
>
> This is driver for w35und usb wifi -- also in kohjinsha
> --- /dev/null
> +++ b/drivers/staging/winbond/Kconfig
> @@ -0,0 +1,7 @@
> +config W35UND
> + tristate "Winbond driver"
> + depends on MAC80211 && WLAN_80211 && EXPERIMENTAL && !4KSTACKS
> + default n
> + ---help---
> + This is highly experimental driver for winbond wifi card on some Kohjinsha notebooks
> + Check http://code.google.com/p/winbondport/ for new version
W35UND should depend on USB
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
---
drivers/staging/winbond/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/staging/winbond/Kconfig
+++ b/drivers/staging/winbond/Kconfig
@@ -1,6 +1,6 @@
config W35UND
tristate "Winbond driver"
- depends on MAC80211 && WLAN_80211 && EXPERIMENTAL && !4KSTACKS
+ depends on MAC80211 && WLAN_80211 && USB && EXPERIMENTAL && !4KSTACKS
default n
---help---
This is highly experimental driver for winbond wifi card on some Kohjinsha notebooks
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply [flat|nested] 37+ messages in thread
* [PATCH 16/23] Staging: add echo cancelation module
2008-10-10 22:41 [GIT PATCH] STAGING patches for 2.6.28 Greg KH
` (10 preceding siblings ...)
2008-10-10 22:42 ` [PATCH 14/23] Staging: add w35und wifi driver Greg KH
@ 2008-10-10 22:42 ` Greg KH
2008-10-10 23:08 ` Mike Frysinger
2008-10-11 6:33 ` Tzafrir Cohen
2008-10-10 22:42 ` [PATCH 17/23] Staging: Fix gcc warnings in sxg Greg KH
` (7 subsequent siblings)
19 siblings, 2 replies; 37+ messages in thread
From: Greg KH @ 2008-10-10 22:42 UTC (permalink / raw)
To: linux-kernel; +Cc: David Rowe, Tzafrir Cohen, Greg Kroah-Hartman
From: David Rowe <david@rowetel.com>
This is used by mISDN and Zaptel drivers.
From: Steve Underwood <steveu@coppice.org>
From: David Rowe <david@rowetel.com>
Cc: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/Kconfig | 2 +
drivers/staging/Makefile | 1 +
drivers/staging/echo/Kconfig | 9 +
drivers/staging/echo/Makefile | 1 +
drivers/staging/echo/TODO | 10 +
drivers/staging/echo/bit_operations.h | 253 +++++++++++++
drivers/staging/echo/echo.c | 632 +++++++++++++++++++++++++++++++++
drivers/staging/echo/echo.h | 220 ++++++++++++
drivers/staging/echo/fir.h | 369 +++++++++++++++++++
drivers/staging/echo/mmx.h | 288 +++++++++++++++
10 files changed, 1785 insertions(+), 0 deletions(-)
create mode 100644 drivers/staging/echo/Kconfig
create mode 100644 drivers/staging/echo/Makefile
create mode 100644 drivers/staging/echo/TODO
create mode 100644 drivers/staging/echo/bit_operations.h
create mode 100644 drivers/staging/echo/echo.c
create mode 100644 drivers/staging/echo/echo.h
create mode 100644 drivers/staging/echo/fir.h
create mode 100644 drivers/staging/echo/mmx.h
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 762b471..25338b7 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -39,4 +39,6 @@ source "drivers/staging/winbond/Kconfig"
source "drivers/staging/wlan-ng/Kconfig"
+source "drivers/staging/echo/Kconfig"
+
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 5741984..93decb8 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_VIDEO_GO7007) += go7007/
obj-$(CONFIG_USB_IP_COMMON) += usbip/
obj-$(CONFIG_W35UND) += winbond/
obj-$(CONFIG_PRISM2_USB) += wlan-ng/
+obj-$(CONFIG_ECHO) += echo/
diff --git a/drivers/staging/echo/Kconfig b/drivers/staging/echo/Kconfig
new file mode 100644
index 0000000..f1d41ea
--- /dev/null
+++ b/drivers/staging/echo/Kconfig
@@ -0,0 +1,9 @@
+config ECHO
+ tristate "Line Echo Canceller support"
+ default n
+ ---help---
+ This driver provides line echo cancelling support for mISDN and
+ Zaptel drivers.
+
+ To compile this driver as a module, choose M here. The module
+ will be called echo.
diff --git a/drivers/staging/echo/Makefile b/drivers/staging/echo/Makefile
new file mode 100644
index 0000000..7d4caac
--- /dev/null
+++ b/drivers/staging/echo/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_ECHO) += echo.o
diff --git a/drivers/staging/echo/TODO b/drivers/staging/echo/TODO
new file mode 100644
index 0000000..1ca09af
--- /dev/null
+++ b/drivers/staging/echo/TODO
@@ -0,0 +1,10 @@
+TODO:
+ - checkpatch.pl cleanups
+ - Lindent
+ - typedef removals
+ - handle bit_operations.h (merge in or make part of common code?)
+ - remove proc interface, only use echo.h interface (proc interface is
+ racy and not correct.)
+
+Please send patches to Greg Kroah-Hartman <greg@kroah.com> and Cc: Steve
+Underwood <steveu@coppice.org> and David Rowe <david@rowetel.com>
diff --git a/drivers/staging/echo/bit_operations.h b/drivers/staging/echo/bit_operations.h
new file mode 100644
index 0000000..b32f4bf
--- /dev/null
+++ b/drivers/staging/echo/bit_operations.h
@@ -0,0 +1,253 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * bit_operations.h - Various bit level operations, such as bit reversal
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2006 Steve Underwood
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: bit_operations.h,v 1.11 2006/11/28 15:37:03 steveu Exp $
+ */
+
+/*! \file */
+
+#if !defined(_BIT_OPERATIONS_H_)
+#define _BIT_OPERATIONS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(__i386__) || defined(__x86_64__)
+/*! \brief Find the bit position of the highest set bit in a word
+ \param bits The word to be searched
+ \return The bit number of the highest set bit, or -1 if the word is zero. */
+static __inline__ int top_bit(unsigned int bits)
+{
+ int res;
+
+ __asm__ (" xorl %[res],%[res];\n"
+ " decl %[res];\n"
+ " bsrl %[bits],%[res]\n"
+ : [res] "=&r" (res)
+ : [bits] "rm" (bits));
+ return res;
+}
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Find the bit position of the lowest set bit in a word
+ \param bits The word to be searched
+ \return The bit number of the lowest set bit, or -1 if the word is zero. */
+static __inline__ int bottom_bit(unsigned int bits)
+{
+ int res;
+
+ __asm__ (" xorl %[res],%[res];\n"
+ " decl %[res];\n"
+ " bsfl %[bits],%[res]\n"
+ : [res] "=&r" (res)
+ : [bits] "rm" (bits));
+ return res;
+}
+/*- End of function --------------------------------------------------------*/
+#else
+static __inline__ int top_bit(unsigned int bits)
+{
+ int i;
+
+ if (bits == 0)
+ return -1;
+ i = 0;
+ if (bits & 0xFFFF0000)
+ {
+ bits &= 0xFFFF0000;
+ i += 16;
+ }
+ if (bits & 0xFF00FF00)
+ {
+ bits &= 0xFF00FF00;
+ i += 8;
+ }
+ if (bits & 0xF0F0F0F0)
+ {
+ bits &= 0xF0F0F0F0;
+ i += 4;
+ }
+ if (bits & 0xCCCCCCCC)
+ {
+ bits &= 0xCCCCCCCC;
+ i += 2;
+ }
+ if (bits & 0xAAAAAAAA)
+ {
+ bits &= 0xAAAAAAAA;
+ i += 1;
+ }
+ return i;
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ int bottom_bit(unsigned int bits)
+{
+ int i;
+
+ if (bits == 0)
+ return -1;
+ i = 32;
+ if (bits & 0x0000FFFF)
+ {
+ bits &= 0x0000FFFF;
+ i -= 16;
+ }
+ if (bits & 0x00FF00FF)
+ {
+ bits &= 0x00FF00FF;
+ i -= 8;
+ }
+ if (bits & 0x0F0F0F0F)
+ {
+ bits &= 0x0F0F0F0F;
+ i -= 4;
+ }
+ if (bits & 0x33333333)
+ {
+ bits &= 0x33333333;
+ i -= 2;
+ }
+ if (bits & 0x55555555)
+ {
+ bits &= 0x55555555;
+ i -= 1;
+ }
+ return i;
+}
+/*- End of function --------------------------------------------------------*/
+#endif
+
+/*! \brief Bit reverse a byte.
+ \param data The byte to be reversed.
+ \return The bit reversed version of data. */
+static __inline__ uint8_t bit_reverse8(uint8_t x)
+{
+#if defined(__i386__) || defined(__x86_64__)
+ /* If multiply is fast */
+ return ((x*0x0802U & 0x22110U) | (x*0x8020U & 0x88440U))*0x10101U >> 16;
+#else
+ /* If multiply is slow, but we have a barrel shifter */
+ x = (x >> 4) | (x << 4);
+ x = ((x & 0xCC) >> 2) | ((x & 0x33) << 2);
+ return ((x & 0xAA) >> 1) | ((x & 0x55) << 1);
+#endif
+}
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Bit reverse a 16 bit word.
+ \param data The word to be reversed.
+ \return The bit reversed version of data. */
+uint16_t bit_reverse16(uint16_t data);
+
+/*! \brief Bit reverse a 32 bit word.
+ \param data The word to be reversed.
+ \return The bit reversed version of data. */
+uint32_t bit_reverse32(uint32_t data);
+
+/*! \brief Bit reverse each of the four bytes in a 32 bit word.
+ \param data The word to be reversed.
+ \return The bit reversed version of data. */
+uint32_t bit_reverse_4bytes(uint32_t data);
+
+/*! \brief Find the number of set bits in a 32 bit word.
+ \param x The word to be searched.
+ \return The number of set bits. */
+int one_bits32(uint32_t x);
+
+/*! \brief Create a mask as wide as the number in a 32 bit word.
+ \param x The word to be searched.
+ \return The mask. */
+uint32_t make_mask32(uint32_t x);
+
+/*! \brief Create a mask as wide as the number in a 16 bit word.
+ \param x The word to be searched.
+ \return The mask. */
+uint16_t make_mask16(uint16_t x);
+
+/*! \brief Find the least significant one in a word, and return a word
+ with just that bit set.
+ \param x The word to be searched.
+ \return The word with the single set bit. */
+static __inline__ uint32_t least_significant_one32(uint32_t x)
+{
+ return (x & (-(int32_t) x));
+}
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Find the most significant one in a word, and return a word
+ with just that bit set.
+ \param x The word to be searched.
+ \return The word with the single set bit. */
+static __inline__ uint32_t most_significant_one32(uint32_t x)
+{
+#if defined(__i386__) || defined(__x86_64__)
+ return 1 << top_bit(x);
+#else
+ x = make_mask32(x);
+ return (x ^ (x >> 1));
+#endif
+}
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Find the parity of a byte.
+ \param x The byte to be checked.
+ \return 1 for odd, or 0 for even. */
+static __inline__ int parity8(uint8_t x)
+{
+ x = (x ^ (x >> 4)) & 0x0F;
+ return (0x6996 >> x) & 1;
+}
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Find the parity of a 16 bit word.
+ \param x The word to be checked.
+ \return 1 for odd, or 0 for even. */
+static __inline__ int parity16(uint16_t x)
+{
+ x ^= (x >> 8);
+ x = (x ^ (x >> 4)) & 0x0F;
+ return (0x6996 >> x) & 1;
+}
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Find the parity of a 32 bit word.
+ \param x The word to be checked.
+ \return 1 for odd, or 0 for even. */
+static __inline__ int parity32(uint32_t x)
+{
+ x ^= (x >> 16);
+ x ^= (x >> 8);
+ x = (x ^ (x >> 4)) & 0x0F;
+ return (0x6996 >> x) & 1;
+}
+/*- End of function --------------------------------------------------------*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/*- End of file ------------------------------------------------------------*/
diff --git a/drivers/staging/echo/echo.c b/drivers/staging/echo/echo.c
new file mode 100644
index 0000000..4a281b1
--- /dev/null
+++ b/drivers/staging/echo/echo.c
@@ -0,0 +1,632 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * echo.c - A line echo canceller. This code is being developed
+ * against and partially complies with G168.
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ * and David Rowe <david_at_rowetel_dot_com>
+ *
+ * Copyright (C) 2001, 2003 Steve Underwood, 2007 David Rowe
+ *
+ * Based on a bit from here, a bit from there, eye of toad, ear of
+ * bat, 15 years of failed attempts by David and a few fried brain
+ * cells.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: echo.c,v 1.20 2006/12/01 18:00:48 steveu Exp $
+ */
+
+/*! \file */
+
+/* Implementation Notes
+ David Rowe
+ April 2007
+
+ This code started life as Steve's NLMS algorithm with a tap
+ rotation algorithm to handle divergence during double talk. I
+ added a Geigel Double Talk Detector (DTD) [2] and performed some
+ G168 tests. However I had trouble meeting the G168 requirements,
+ especially for double talk - there were always cases where my DTD
+ failed, for example where near end speech was under the 6dB
+ threshold required for declaring double talk.
+
+ So I tried a two path algorithm [1], which has so far given better
+ results. The original tap rotation/Geigel algorithm is available
+ in SVN http://svn.rowetel.com/software/oslec/tags/before_16bit.
+ It's probably possible to make it work if some one wants to put some
+ serious work into it.
+
+ At present no special treatment is provided for tones, which
+ generally cause NLMS algorithms to diverge. Initial runs of a
+ subset of the G168 tests for tones (e.g ./echo_test 6) show the
+ current algorithm is passing OK, which is kind of surprising. The
+ full set of tests needs to be performed to confirm this result.
+
+ One other interesting change is that I have managed to get the NLMS
+ code to work with 16 bit coefficients, rather than the original 32
+ bit coefficents. This reduces the MIPs and storage required.
+ I evaulated the 16 bit port using g168_tests.sh and listening tests
+ on 4 real-world samples.
+
+ I also attempted the implementation of a block based NLMS update
+ [2] but although this passes g168_tests.sh it didn't converge well
+ on the real-world samples. I have no idea why, perhaps a scaling
+ problem. The block based code is also available in SVN
+ http://svn.rowetel.com/software/oslec/tags/before_16bit. If this
+ code can be debugged, it will lead to further reduction in MIPS, as
+ the block update code maps nicely onto DSP instruction sets (it's a
+ dot product) compared to the current sample-by-sample update.
+
+ Steve also has some nice notes on echo cancellers in echo.h
+
+
+ References:
+
+ [1] Ochiai, Areseki, and Ogihara, "Echo Canceller with Two Echo
+ Path Models", IEEE Transactions on communications, COM-25,
+ No. 6, June
+ 1977.
+ http://www.rowetel.com/images/echo/dual_path_paper.pdf
+
+ [2] The classic, very useful paper that tells you how to
+ actually build a real world echo canceller:
+ Messerschmitt, Hedberg, Cole, Haoui, Winship, "Digital Voice
+ Echo Canceller with a TMS320020,
+ http://www.rowetel.com/images/echo/spra129.pdf
+
+ [3] I have written a series of blog posts on this work, here is
+ Part 1: http://www.rowetel.com/blog/?p=18
+
+ [4] The source code http://svn.rowetel.com/software/oslec/
+
+ [5] A nice reference on LMS filters:
+ http://en.wikipedia.org/wiki/Least_mean_squares_filter
+
+ Credits:
+
+ Thanks to Steve Underwood, Jean-Marc Valin, and Ramakrishnan
+ Muthukrishnan for their suggestions and email discussions. Thanks
+ also to those people who collected echo samples for me such as
+ Mark, Pawel, and Pavel.
+*/
+
+#include <linux/kernel.h> /* We're doing kernel work */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#define malloc(a) kmalloc((a), GFP_KERNEL)
+#define free(a) kfree(a)
+
+#include "bit_operations.h"
+#include "echo.h"
+
+#define MIN_TX_POWER_FOR_ADAPTION 64
+#define MIN_RX_POWER_FOR_ADAPTION 64
+#define DTD_HANGOVER 600 /* 600 samples, or 75ms */
+#define DC_LOG2BETA 3 /* log2() of DC filter Beta */
+
+/*-----------------------------------------------------------------------*\
+ FUNCTIONS
+\*-----------------------------------------------------------------------*/
+
+/* adapting coeffs using the traditional stochastic descent (N)LMS algorithm */
+
+
+#ifdef __BLACKFIN_ASM__
+static void __inline__ lms_adapt_bg(echo_can_state_t *ec, int clean, int shift)
+{
+ int i, j;
+ int offset1;
+ int offset2;
+ int factor;
+ int exp;
+ int16_t *phist;
+ int n;
+
+ if (shift > 0)
+ factor = clean << shift;
+ else
+ factor = clean >> -shift;
+
+ /* Update the FIR taps */
+
+ offset2 = ec->curr_pos;
+ offset1 = ec->taps - offset2;
+ phist = &ec->fir_state_bg.history[offset2];
+
+ /* st: and en: help us locate the assembler in echo.s */
+
+ //asm("st:");
+ n = ec->taps;
+ for (i = 0, j = offset2; i < n; i++, j++)
+ {
+ exp = *phist++ * factor;
+ ec->fir_taps16[1][i] += (int16_t) ((exp+(1<<14)) >> 15);
+ }
+ //asm("en:");
+
+ /* Note the asm for the inner loop above generated by Blackfin gcc
+ 4.1.1 is pretty good (note even parallel instructions used):
+
+ R0 = W [P0++] (X);
+ R0 *= R2;
+ R0 = R0 + R3 (NS) ||
+ R1 = W [P1] (X) ||
+ nop;
+ R0 >>>= 15;
+ R0 = R0 + R1;
+ W [P1++] = R0;
+
+ A block based update algorithm would be much faster but the
+ above can't be improved on much. Every instruction saved in
+ the loop above is 2 MIPs/ch! The for loop above is where the
+ Blackfin spends most of it's time - about 17 MIPs/ch measured
+ with speedtest.c with 256 taps (32ms). Write-back and
+ Write-through cache gave about the same performance.
+ */
+}
+
+/*
+ IDEAS for further optimisation of lms_adapt_bg():
+
+ 1/ The rounding is quite costly. Could we keep as 32 bit coeffs
+ then make filter pluck the MS 16-bits of the coeffs when filtering?
+ However this would lower potential optimisation of filter, as I
+ think the dual-MAC architecture requires packed 16 bit coeffs.
+
+ 2/ Block based update would be more efficient, as per comments above,
+ could use dual MAC architecture.
+
+ 3/ Look for same sample Blackfin LMS code, see if we can get dual-MAC
+ packing.
+
+ 4/ Execute the whole e/c in a block of say 20ms rather than sample
+ by sample. Processing a few samples every ms is inefficient.
+*/
+
+#else
+static __inline__ void lms_adapt_bg(echo_can_state_t *ec, int clean, int shift)
+{
+ int i;
+
+ int offset1;
+ int offset2;
+ int factor;
+ int exp;
+
+ if (shift > 0)
+ factor = clean << shift;
+ else
+ factor = clean >> -shift;
+
+ /* Update the FIR taps */
+
+ offset2 = ec->curr_pos;
+ offset1 = ec->taps - offset2;
+
+ for (i = ec->taps - 1; i >= offset1; i--)
+ {
+ exp = (ec->fir_state_bg.history[i - offset1]*factor);
+ ec->fir_taps16[1][i] += (int16_t) ((exp+(1<<14)) >> 15);
+ }
+ for ( ; i >= 0; i--)
+ {
+ exp = (ec->fir_state_bg.history[i + offset2]*factor);
+ ec->fir_taps16[1][i] += (int16_t) ((exp+(1<<14)) >> 15);
+ }
+}
+#endif
+
+/*- End of function --------------------------------------------------------*/
+
+echo_can_state_t *echo_can_create(int len, int adaption_mode)
+{
+ echo_can_state_t *ec;
+ int i;
+ int j;
+
+ ec = kmalloc(sizeof(*ec), GFP_KERNEL);
+ if (ec == NULL)
+ return NULL;
+ memset(ec, 0, sizeof(*ec));
+
+ ec->taps = len;
+ ec->log2taps = top_bit(len);
+ ec->curr_pos = ec->taps - 1;
+
+ for (i = 0; i < 2; i++)
+ {
+ if ((ec->fir_taps16[i] = (int16_t *) malloc((ec->taps)*sizeof(int16_t))) == NULL)
+ {
+ for (j = 0; j < i; j++)
+ kfree(ec->fir_taps16[j]);
+ kfree(ec);
+ return NULL;
+ }
+ memset(ec->fir_taps16[i], 0, (ec->taps)*sizeof(int16_t));
+ }
+
+ fir16_create(&ec->fir_state,
+ ec->fir_taps16[0],
+ ec->taps);
+ fir16_create(&ec->fir_state_bg,
+ ec->fir_taps16[1],
+ ec->taps);
+
+ for(i=0; i<5; i++) {
+ ec->xvtx[i] = ec->yvtx[i] = ec->xvrx[i] = ec->yvrx[i] = 0;
+ }
+
+ ec->cng_level = 1000;
+ echo_can_adaption_mode(ec, adaption_mode);
+
+ ec->snapshot = (int16_t*)malloc(ec->taps*sizeof(int16_t));
+ memset(ec->snapshot, 0, sizeof(int16_t)*ec->taps);
+
+ ec->cond_met = 0;
+ ec->Pstates = 0;
+ ec->Ltxacc = ec->Lrxacc = ec->Lcleanacc = ec->Lclean_bgacc = 0;
+ ec->Ltx = ec->Lrx = ec->Lclean = ec->Lclean_bg = 0;
+ ec->tx_1 = ec->tx_2 = ec->rx_1 = ec->rx_2 = 0;
+ ec->Lbgn = ec->Lbgn_acc = 0;
+ ec->Lbgn_upper = 200;
+ ec->Lbgn_upper_acc = ec->Lbgn_upper << 13;
+
+ return ec;
+}
+/*- End of function --------------------------------------------------------*/
+
+void echo_can_free(echo_can_state_t *ec)
+{
+ int i;
+
+ fir16_free(&ec->fir_state);
+ fir16_free(&ec->fir_state_bg);
+ for (i = 0; i < 2; i++)
+ kfree(ec->fir_taps16[i]);
+ kfree(ec->snapshot);
+ kfree(ec);
+}
+/*- End of function --------------------------------------------------------*/
+
+void echo_can_adaption_mode(echo_can_state_t *ec, int adaption_mode)
+{
+ ec->adaption_mode = adaption_mode;
+}
+/*- End of function --------------------------------------------------------*/
+
+void echo_can_flush(echo_can_state_t *ec)
+{
+ int i;
+
+ ec->Ltxacc = ec->Lrxacc = ec->Lcleanacc = ec->Lclean_bgacc = 0;
+ ec->Ltx = ec->Lrx = ec->Lclean = ec->Lclean_bg = 0;
+ ec->tx_1 = ec->tx_2 = ec->rx_1 = ec->rx_2 = 0;
+
+ ec->Lbgn = ec->Lbgn_acc = 0;
+ ec->Lbgn_upper = 200;
+ ec->Lbgn_upper_acc = ec->Lbgn_upper << 13;
+
+ ec->nonupdate_dwell = 0;
+
+ fir16_flush(&ec->fir_state);
+ fir16_flush(&ec->fir_state_bg);
+ ec->fir_state.curr_pos = ec->taps - 1;
+ ec->fir_state_bg.curr_pos = ec->taps - 1;
+ for (i = 0; i < 2; i++)
+ memset(ec->fir_taps16[i], 0, ec->taps*sizeof(int16_t));
+
+ ec->curr_pos = ec->taps - 1;
+ ec->Pstates = 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+void echo_can_snapshot(echo_can_state_t *ec) {
+ memcpy(ec->snapshot, ec->fir_taps16[0], ec->taps*sizeof(int16_t));
+}
+/*- End of function --------------------------------------------------------*/
+
+/* Dual Path Echo Canceller ------------------------------------------------*/
+
+int16_t echo_can_update(echo_can_state_t *ec, int16_t tx, int16_t rx)
+{
+ int32_t echo_value;
+ int clean_bg;
+ int tmp, tmp1;
+
+ /* Input scaling was found be required to prevent problems when tx
+ starts clipping. Another possible way to handle this would be the
+ filter coefficent scaling. */
+
+ ec->tx = tx; ec->rx = rx;
+ tx >>=1;
+ rx >>=1;
+
+ /*
+ Filter DC, 3dB point is 160Hz (I think), note 32 bit precision required
+ otherwise values do not track down to 0. Zero at DC, Pole at (1-Beta)
+ only real axis. Some chip sets (like Si labs) don't need
+ this, but something like a $10 X100P card does. Any DC really slows
+ down convergence.
+
+ Note: removes some low frequency from the signal, this reduces
+ the speech quality when listening to samples through headphones
+ but may not be obvious through a telephone handset.
+
+ Note that the 3dB frequency in radians is approx Beta, e.g. for
+ Beta = 2^(-3) = 0.125, 3dB freq is 0.125 rads = 159Hz.
+ */
+
+ if (ec->adaption_mode & ECHO_CAN_USE_RX_HPF) {
+ tmp = rx << 15;
+#if 1
+ /* Make sure the gain of the HPF is 1.0. This can still saturate a little under
+ impulse conditions, and it might roll to 32768 and need clipping on sustained peak
+ level signals. However, the scale of such clipping is small, and the error due to
+ any saturation should not markedly affect the downstream processing. */
+ tmp -= (tmp >> 4);
+#endif
+ ec->rx_1 += -(ec->rx_1>>DC_LOG2BETA) + tmp - ec->rx_2;
+
+ /* hard limit filter to prevent clipping. Note that at this stage
+ rx should be limited to +/- 16383 due to right shift above */
+ tmp1 = ec->rx_1 >> 15;
+ if (tmp1 > 16383) tmp1 = 16383;
+ if (tmp1 < -16383) tmp1 = -16383;
+ rx = tmp1;
+ ec->rx_2 = tmp;
+ }
+
+ /* Block average of power in the filter states. Used for
+ adaption power calculation. */
+
+ {
+ int new, old;
+
+ /* efficient "out with the old and in with the new" algorithm so
+ we don't have to recalculate over the whole block of
+ samples. */
+ new = (int)tx * (int)tx;
+ old = (int)ec->fir_state.history[ec->fir_state.curr_pos] *
+ (int)ec->fir_state.history[ec->fir_state.curr_pos];
+ ec->Pstates += ((new - old) + (1<<ec->log2taps)) >> ec->log2taps;
+ if (ec->Pstates < 0) ec->Pstates = 0;
+ }
+
+ /* Calculate short term average levels using simple single pole IIRs */
+
+ ec->Ltxacc += abs(tx) - ec->Ltx;
+ ec->Ltx = (ec->Ltxacc + (1<<4)) >> 5;
+ ec->Lrxacc += abs(rx) - ec->Lrx;
+ ec->Lrx = (ec->Lrxacc + (1<<4)) >> 5;
+
+ /* Foreground filter ---------------------------------------------------*/
+
+ ec->fir_state.coeffs = ec->fir_taps16[0];
+ echo_value = fir16(&ec->fir_state, tx);
+ ec->clean = rx - echo_value;
+ ec->Lcleanacc += abs(ec->clean) - ec->Lclean;
+ ec->Lclean = (ec->Lcleanacc + (1<<4)) >> 5;
+
+ /* Background filter ---------------------------------------------------*/
+
+ echo_value = fir16(&ec->fir_state_bg, tx);
+ clean_bg = rx - echo_value;
+ ec->Lclean_bgacc += abs(clean_bg) - ec->Lclean_bg;
+ ec->Lclean_bg = (ec->Lclean_bgacc + (1<<4)) >> 5;
+
+ /* Background Filter adaption -----------------------------------------*/
+
+ /* Almost always adap bg filter, just simple DT and energy
+ detection to minimise adaption in cases of strong double talk.
+ However this is not critical for the dual path algorithm.
+ */
+ ec->factor = 0;
+ ec->shift = 0;
+ if ((ec->nonupdate_dwell == 0)) {
+ int P, logP, shift;
+
+ /* Determine:
+
+ f = Beta * clean_bg_rx/P ------ (1)
+
+ where P is the total power in the filter states.
+
+ The Boffins have shown that if we obey (1) we converge
+ quickly and avoid instability.
+
+ The correct factor f must be in Q30, as this is the fixed
+ point format required by the lms_adapt_bg() function,
+ therefore the scaled version of (1) is:
+
+ (2^30) * f = (2^30) * Beta * clean_bg_rx/P
+ factor = (2^30) * Beta * clean_bg_rx/P ----- (2)
+
+ We have chosen Beta = 0.25 by experiment, so:
+
+ factor = (2^30) * (2^-2) * clean_bg_rx/P
+
+ (30 - 2 - log2(P))
+ factor = clean_bg_rx 2 ----- (3)
+
+ To avoid a divide we approximate log2(P) as top_bit(P),
+ which returns the position of the highest non-zero bit in
+ P. This approximation introduces an error as large as a
+ factor of 2, but the algorithm seems to handle it OK.
+
+ Come to think of it a divide may not be a big deal on a
+ modern DSP, so its probably worth checking out the cycles
+ for a divide versus a top_bit() implementation.
+ */
+
+ P = MIN_TX_POWER_FOR_ADAPTION + ec->Pstates;
+ logP = top_bit(P) + ec->log2taps;
+ shift = 30 - 2 - logP;
+ ec->shift = shift;
+
+ lms_adapt_bg(ec, clean_bg, shift);
+ }
+
+ /* very simple DTD to make sure we dont try and adapt with strong
+ near end speech */
+
+ ec->adapt = 0;
+ if ((ec->Lrx > MIN_RX_POWER_FOR_ADAPTION) && (ec->Lrx > ec->Ltx))
+ ec->nonupdate_dwell = DTD_HANGOVER;
+ if (ec->nonupdate_dwell)
+ ec->nonupdate_dwell--;
+
+ /* Transfer logic ------------------------------------------------------*/
+
+ /* These conditions are from the dual path paper [1], I messed with
+ them a bit to improve performance. */
+
+ if ((ec->adaption_mode & ECHO_CAN_USE_ADAPTION) &&
+ (ec->nonupdate_dwell == 0) &&
+ (8*ec->Lclean_bg < 7*ec->Lclean) /* (ec->Lclean_bg < 0.875*ec->Lclean) */ &&
+ (8*ec->Lclean_bg < ec->Ltx) /* (ec->Lclean_bg < 0.125*ec->Ltx) */ )
+ {
+ if (ec->cond_met == 6) {
+ /* BG filter has had better results for 6 consecutive samples */
+ ec->adapt = 1;
+ memcpy(ec->fir_taps16[0], ec->fir_taps16[1], ec->taps*sizeof(int16_t));
+ }
+ else
+ ec->cond_met++;
+ }
+ else
+ ec->cond_met = 0;
+
+ /* Non-Linear Processing ---------------------------------------------------*/
+
+ ec->clean_nlp = ec->clean;
+ if (ec->adaption_mode & ECHO_CAN_USE_NLP)
+ {
+ /* Non-linear processor - a fancy way to say "zap small signals, to avoid
+ residual echo due to (uLaw/ALaw) non-linearity in the channel.". */
+
+ if ((16*ec->Lclean < ec->Ltx))
+ {
+ /* Our e/c has improved echo by at least 24 dB (each factor of 2 is 6dB,
+ so 2*2*2*2=16 is the same as 6+6+6+6=24dB) */
+ if (ec->adaption_mode & ECHO_CAN_USE_CNG)
+ {
+ ec->cng_level = ec->Lbgn;
+
+ /* Very elementary comfort noise generation. Just random
+ numbers rolled off very vaguely Hoth-like. DR: This
+ noise doesn't sound quite right to me - I suspect there
+ are some overlfow issues in the filtering as it's too
+ "crackly". TODO: debug this, maybe just play noise at
+ high level or look at spectrum.
+ */
+
+ ec->cng_rndnum = 1664525U*ec->cng_rndnum + 1013904223U;
+ ec->cng_filter = ((ec->cng_rndnum & 0xFFFF) - 32768 + 5*ec->cng_filter) >> 3;
+ ec->clean_nlp = (ec->cng_filter*ec->cng_level*8) >> 14;
+
+ }
+ else if (ec->adaption_mode & ECHO_CAN_USE_CLIP)
+ {
+ /* This sounds much better than CNG */
+ if (ec->clean_nlp > ec->Lbgn)
+ ec->clean_nlp = ec->Lbgn;
+ if (ec->clean_nlp < -ec->Lbgn)
+ ec->clean_nlp = -ec->Lbgn;
+ }
+ else
+ {
+ /* just mute the residual, doesn't sound very good, used mainly
+ in G168 tests */
+ ec->clean_nlp = 0;
+ }
+ }
+ else {
+ /* Background noise estimator. I tried a few algorithms
+ here without much luck. This very simple one seems to
+ work best, we just average the level using a slow (1 sec
+ time const) filter if the current level is less than a
+ (experimentally derived) constant. This means we dont
+ include high level signals like near end speech. When
+ combined with CNG or especially CLIP seems to work OK.
+ */
+ if (ec->Lclean < 40) {
+ ec->Lbgn_acc += abs(ec->clean) - ec->Lbgn;
+ ec->Lbgn = (ec->Lbgn_acc + (1<<11)) >> 12;
+ }
+ }
+ }
+
+ /* Roll around the taps buffer */
+ if (ec->curr_pos <= 0)
+ ec->curr_pos = ec->taps;
+ ec->curr_pos--;
+
+ if (ec->adaption_mode & ECHO_CAN_DISABLE)
+ ec->clean_nlp = rx;
+
+ /* Output scaled back up again to match input scaling */
+
+ return (int16_t) ec->clean_nlp << 1;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+/* This function is seperated from the echo canceller is it is usually called
+ as part of the tx process. See rx HP (DC blocking) filter above, it's
+ the same design.
+
+ Some soft phones send speech signals with a lot of low frequency
+ energy, e.g. down to 20Hz. This can make the hybrid non-linear
+ which causes the echo canceller to fall over. This filter can help
+ by removing any low frequency before it gets to the tx port of the
+ hybrid.
+
+ It can also help by removing and DC in the tx signal. DC is bad
+ for LMS algorithms.
+
+ This is one of the classic DC removal filters, adjusted to provide sufficient
+ bass rolloff to meet the above requirement to protect hybrids from things that
+ upset them. The difference between successive samples produces a lousy HPF, and
+ then a suitably placed pole flattens things out. The final result is a nicely
+ rolled off bass end. The filtering is implemented with extended fractional
+ precision, which noise shapes things, giving very clean DC removal.
+*/
+
+int16_t echo_can_hpf_tx(echo_can_state_t *ec, int16_t tx) {
+ int tmp, tmp1;
+
+ if (ec->adaption_mode & ECHO_CAN_USE_TX_HPF) {
+ tmp = tx << 15;
+#if 1
+ /* Make sure the gain of the HPF is 1.0. The first can still saturate a little under
+ impulse conditions, and it might roll to 32768 and need clipping on sustained peak
+ level signals. However, the scale of such clipping is small, and the error due to
+ any saturation should not markedly affect the downstream processing. */
+ tmp -= (tmp >> 4);
+#endif
+ ec->tx_1 += -(ec->tx_1>>DC_LOG2BETA) + tmp - ec->tx_2;
+ tmp1 = ec->tx_1 >> 15;
+ if (tmp1 > 32767) tmp1 = 32767;
+ if (tmp1 < -32767) tmp1 = -32767;
+ tx = tmp1;
+ ec->tx_2 = tmp;
+ }
+
+ return tx;
+}
diff --git a/drivers/staging/echo/echo.h b/drivers/staging/echo/echo.h
new file mode 100644
index 0000000..7a91b43
--- /dev/null
+++ b/drivers/staging/echo/echo.h
@@ -0,0 +1,220 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * echo.c - A line echo canceller. This code is being developed
+ * against and partially complies with G168.
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ * and David Rowe <david_at_rowetel_dot_com>
+ *
+ * Copyright (C) 2001 Steve Underwood and 2007 David Rowe
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: echo.h,v 1.9 2006/10/24 13:45:28 steveu Exp $
+ */
+
+#ifndef __ECHO_H
+#define __ECHO_H
+
+/*! \page echo_can_page Line echo cancellation for voice
+
+\section echo_can_page_sec_1 What does it do?
+This module aims to provide G.168-2002 compliant echo cancellation, to remove
+electrical echoes (e.g. from 2-4 wire hybrids) from voice calls.
+
+\section echo_can_page_sec_2 How does it work?
+The heart of the echo cancellor is FIR filter. This is adapted to match the
+echo impulse response of the telephone line. It must be long enough to
+adequately cover the duration of that impulse response. The signal transmitted
+to the telephone line is passed through the FIR filter. Once the FIR is
+properly adapted, the resulting output is an estimate of the echo signal
+received from the line. This is subtracted from the received signal. The result
+is an estimate of the signal which originated at the far end of the line, free
+from echos of our own transmitted signal.
+
+The least mean squares (LMS) algorithm is attributed to Widrow and Hoff, and
+was introduced in 1960. It is the commonest form of filter adaption used in
+things like modem line equalisers and line echo cancellers. There it works very
+well. However, it only works well for signals of constant amplitude. It works
+very poorly for things like speech echo cancellation, where the signal level
+varies widely. This is quite easy to fix. If the signal level is normalised -
+similar to applying AGC - LMS can work as well for a signal of varying
+amplitude as it does for a modem signal. This normalised least mean squares
+(NLMS) algorithm is the commonest one used for speech echo cancellation. Many
+other algorithms exist - e.g. RLS (essentially the same as Kalman filtering),
+FAP, etc. Some perform significantly better than NLMS. However, factors such
+as computational complexity and patents favour the use of NLMS.
+
+A simple refinement to NLMS can improve its performance with speech. NLMS tends
+to adapt best to the strongest parts of a signal. If the signal is white noise,
+the NLMS algorithm works very well. However, speech has more low frequency than
+high frequency content. Pre-whitening (i.e. filtering the signal to flatten its
+spectrum) the echo signal improves the adapt rate for speech, and ensures the
+final residual signal is not heavily biased towards high frequencies. A very
+low complexity filter is adequate for this, so pre-whitening adds little to the
+compute requirements of the echo canceller.
+
+An FIR filter adapted using pre-whitened NLMS performs well, provided certain
+conditions are met:
+
+ - The transmitted signal has poor self-correlation.
+ - There is no signal being generated within the environment being
+ cancelled.
+
+The difficulty is that neither of these can be guaranteed.
+
+If the adaption is performed while transmitting noise (or something fairly
+noise like, such as voice) the adaption works very well. If the adaption is
+performed while transmitting something highly correlative (typically narrow
+band energy such as signalling tones or DTMF), the adaption can go seriously
+wrong. The reason is there is only one solution for the adaption on a near
+random signal - the impulse response of the line. For a repetitive signal,
+there are any number of solutions which converge the adaption, and nothing
+guides the adaption to choose the generalised one. Allowing an untrained
+canceller to converge on this kind of narrowband energy probably a good thing,
+since at least it cancels the tones. Allowing a well converged canceller to
+continue converging on such energy is just a way to ruin its generalised
+adaption. A narrowband detector is needed, so adapation can be suspended at
+appropriate times.
+
+The adaption process is based on trying to eliminate the received signal. When
+there is any signal from within the environment being cancelled it may upset
+the adaption process. Similarly, if the signal we are transmitting is small,
+noise may dominate and disturb the adaption process. If we can ensure that the
+adaption is only performed when we are transmitting a significant signal level,
+and the environment is not, things will be OK. Clearly, it is easy to tell when
+we are sending a significant signal. Telling, if the environment is generating
+a significant signal, and doing it with sufficient speed that the adaption will
+not have diverged too much more we stop it, is a little harder.
+
+The key problem in detecting when the environment is sourcing significant
+energy is that we must do this very quickly. Given a reasonably long sample of
+the received signal, there are a number of strategies which may be used to
+assess whether that signal contains a strong far end component. However, by the
+time that assessment is complete the far end signal will have already caused
+major mis-convergence in the adaption process. An assessment algorithm is
+needed which produces a fairly accurate result from a very short burst of far
+end energy.
+
+\section echo_can_page_sec_3 How do I use it?
+The echo cancellor processes both the transmit and receive streams sample by
+sample. The processing function is not declared inline. Unfortunately,
+cancellation requires many operations per sample, so the call overhead is only
+a minor burden.
+*/
+
+#include "fir.h"
+
+/* Mask bits for the adaption mode */
+#define ECHO_CAN_USE_ADAPTION 0x01
+#define ECHO_CAN_USE_NLP 0x02
+#define ECHO_CAN_USE_CNG 0x04
+#define ECHO_CAN_USE_CLIP 0x08
+#define ECHO_CAN_USE_TX_HPF 0x10
+#define ECHO_CAN_USE_RX_HPF 0x20
+#define ECHO_CAN_DISABLE 0x40
+
+/*!
+ G.168 echo canceller descriptor. This defines the working state for a line
+ echo canceller.
+*/
+typedef struct
+{
+ int16_t tx,rx;
+ int16_t clean;
+ int16_t clean_nlp;
+
+ int nonupdate_dwell;
+ int curr_pos;
+ int taps;
+ int log2taps;
+ int adaption_mode;
+
+ int cond_met;
+ int32_t Pstates;
+ int16_t adapt;
+ int32_t factor;
+ int16_t shift;
+
+ /* Average levels and averaging filter states */
+ int Ltxacc, Lrxacc, Lcleanacc, Lclean_bgacc;
+ int Ltx, Lrx;
+ int Lclean;
+ int Lclean_bg;
+ int Lbgn, Lbgn_acc, Lbgn_upper, Lbgn_upper_acc;
+
+ /* foreground and background filter states */
+ fir16_state_t fir_state;
+ fir16_state_t fir_state_bg;
+ int16_t *fir_taps16[2];
+
+ /* DC blocking filter states */
+ int tx_1, tx_2, rx_1, rx_2;
+
+ /* optional High Pass Filter states */
+ int32_t xvtx[5], yvtx[5];
+ int32_t xvrx[5], yvrx[5];
+
+ /* Parameters for the optional Hoth noise generator */
+ int cng_level;
+ int cng_rndnum;
+ int cng_filter;
+
+ /* snapshot sample of coeffs used for development */
+ int16_t *snapshot;
+} echo_can_state_t;
+
+/*! Create a voice echo canceller context.
+ \param len The length of the canceller, in samples.
+ \return The new canceller context, or NULL if the canceller could not be created.
+*/
+echo_can_state_t *echo_can_create(int len, int adaption_mode);
+
+/*! Free a voice echo canceller context.
+ \param ec The echo canceller context.
+*/
+void echo_can_free(echo_can_state_t *ec);
+
+/*! Flush (reinitialise) a voice echo canceller context.
+ \param ec The echo canceller context.
+*/
+void echo_can_flush(echo_can_state_t *ec);
+
+/*! Set the adaption mode of a voice echo canceller context.
+ \param ec The echo canceller context.
+ \param adapt The mode.
+*/
+void echo_can_adaption_mode(echo_can_state_t *ec, int adaption_mode);
+
+void echo_can_snapshot(echo_can_state_t *ec);
+
+/*! Process a sample through a voice echo canceller.
+ \param ec The echo canceller context.
+ \param tx The transmitted audio sample.
+ \param rx The received audio sample.
+ \return The clean (echo cancelled) received sample.
+*/
+int16_t echo_can_update(echo_can_state_t *ec, int16_t tx, int16_t rx);
+
+/*! Process to high pass filter the tx signal.
+ \param ec The echo canceller context.
+ \param tx The transmitted auio sample.
+ \return The HP filtered transmit sample, send this to your D/A.
+*/
+int16_t echo_can_hpf_tx(echo_can_state_t *ec, int16_t tx);
+
+#endif /* __ECHO_H */
diff --git a/drivers/staging/echo/fir.h b/drivers/staging/echo/fir.h
new file mode 100644
index 0000000..e1bfc49
--- /dev/null
+++ b/drivers/staging/echo/fir.h
@@ -0,0 +1,369 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * fir.h - General telephony FIR routines
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2002 Steve Underwood
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: fir.h,v 1.8 2006/10/24 13:45:28 steveu Exp $
+ */
+
+/*! \page fir_page FIR filtering
+\section fir_page_sec_1 What does it do?
+???.
+
+\section fir_page_sec_2 How does it work?
+???.
+*/
+
+#if !defined(_FIR_H_)
+#define _FIR_H_
+
+/*
+ Blackfin NOTES & IDEAS:
+
+ A simple dot product function is used to implement the filter. This performs
+ just one MAC/cycle which is inefficient but was easy to implement as a first
+ pass. The current Blackfin code also uses an unrolled form of the filter
+ history to avoid 0 length hardware loop issues. This is wasteful of
+ memory.
+
+ Ideas for improvement:
+
+ 1/ Rewrite filter for dual MAC inner loop. The issue here is handling
+ history sample offsets that are 16 bit aligned - the dual MAC needs
+ 32 bit aligmnent. There are some good examples in libbfdsp.
+
+ 2/ Use the hardware circular buffer facility tohalve memory usage.
+
+ 3/ Consider using internal memory.
+
+ Using less memory might also improve speed as cache misses will be
+ reduced. A drop in MIPs and memory approaching 50% should be
+ possible.
+
+ The foreground and background filters currenlty use a total of
+ about 10 MIPs/ch as measured with speedtest.c on a 256 TAP echo
+ can.
+*/
+
+#if defined(USE_MMX) || defined(USE_SSE2)
+#include "mmx.h"
+#endif
+
+/*!
+ 16 bit integer FIR descriptor. This defines the working state for a single
+ instance of an FIR filter using 16 bit integer coefficients.
+*/
+typedef struct
+{
+ int taps;
+ int curr_pos;
+ const int16_t *coeffs;
+ int16_t *history;
+} fir16_state_t;
+
+/*!
+ 32 bit integer FIR descriptor. This defines the working state for a single
+ instance of an FIR filter using 32 bit integer coefficients, and filtering
+ 16 bit integer data.
+*/
+typedef struct
+{
+ int taps;
+ int curr_pos;
+ const int32_t *coeffs;
+ int16_t *history;
+} fir32_state_t;
+
+/*!
+ Floating point FIR descriptor. This defines the working state for a single
+ instance of an FIR filter using floating point coefficients and data.
+*/
+typedef struct
+{
+ int taps;
+ int curr_pos;
+ const float *coeffs;
+ float *history;
+} fir_float_state_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static __inline__ const int16_t *fir16_create(fir16_state_t *fir,
+ const int16_t *coeffs,
+ int taps)
+{
+ fir->taps = taps;
+ fir->curr_pos = taps - 1;
+ fir->coeffs = coeffs;
+#if defined(USE_MMX) || defined(USE_SSE2) || defined(__BLACKFIN_ASM__)
+ if ((fir->history = malloc(2*taps*sizeof(int16_t))))
+ memset(fir->history, 0, 2*taps*sizeof(int16_t));
+#else
+ if ((fir->history = (int16_t *) malloc(taps*sizeof(int16_t))))
+ memset(fir->history, 0, taps*sizeof(int16_t));
+#endif
+ return fir->history;
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ void fir16_flush(fir16_state_t *fir)
+{
+#if defined(USE_MMX) || defined(USE_SSE2) || defined(__BLACKFIN_ASM__)
+ memset(fir->history, 0, 2*fir->taps*sizeof(int16_t));
+#else
+ memset(fir->history, 0, fir->taps*sizeof(int16_t));
+#endif
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ void fir16_free(fir16_state_t *fir)
+{
+ free(fir->history);
+}
+/*- End of function --------------------------------------------------------*/
+
+#ifdef __BLACKFIN_ASM__
+static inline int32_t dot_asm(short *x, short *y, int len)
+{
+ int dot;
+
+ len--;
+
+ __asm__
+ (
+ "I0 = %1;\n\t"
+ "I1 = %2;\n\t"
+ "A0 = 0;\n\t"
+ "R0.L = W[I0++] || R1.L = W[I1++];\n\t"
+ "LOOP dot%= LC0 = %3;\n\t"
+ "LOOP_BEGIN dot%=;\n\t"
+ "A0 += R0.L * R1.L (IS) || R0.L = W[I0++] || R1.L = W[I1++];\n\t"
+ "LOOP_END dot%=;\n\t"
+ "A0 += R0.L*R1.L (IS);\n\t"
+ "R0 = A0;\n\t"
+ "%0 = R0;\n\t"
+ : "=&d" (dot)
+ : "a" (x), "a" (y), "a" (len)
+ : "I0", "I1", "A1", "A0", "R0", "R1"
+ );
+
+ return dot;
+}
+#endif
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ int16_t fir16(fir16_state_t *fir, int16_t sample)
+{
+ int32_t y;
+#if defined(USE_MMX)
+ int i;
+ mmx_t *mmx_coeffs;
+ mmx_t *mmx_hist;
+
+ fir->history[fir->curr_pos] = sample;
+ fir->history[fir->curr_pos + fir->taps] = sample;
+
+ mmx_coeffs = (mmx_t *) fir->coeffs;
+ mmx_hist = (mmx_t *) &fir->history[fir->curr_pos];
+ i = fir->taps;
+ pxor_r2r(mm4, mm4);
+ /* 8 samples per iteration, so the filter must be a multiple of 8 long. */
+ while (i > 0)
+ {
+ movq_m2r(mmx_coeffs[0], mm0);
+ movq_m2r(mmx_coeffs[1], mm2);
+ movq_m2r(mmx_hist[0], mm1);
+ movq_m2r(mmx_hist[1], mm3);
+ mmx_coeffs += 2;
+ mmx_hist += 2;
+ pmaddwd_r2r(mm1, mm0);
+ pmaddwd_r2r(mm3, mm2);
+ paddd_r2r(mm0, mm4);
+ paddd_r2r(mm2, mm4);
+ i -= 8;
+ }
+ movq_r2r(mm4, mm0);
+ psrlq_i2r(32, mm0);
+ paddd_r2r(mm0, mm4);
+ movd_r2m(mm4, y);
+ emms();
+#elif defined(USE_SSE2)
+ int i;
+ xmm_t *xmm_coeffs;
+ xmm_t *xmm_hist;
+
+ fir->history[fir->curr_pos] = sample;
+ fir->history[fir->curr_pos + fir->taps] = sample;
+
+ xmm_coeffs = (xmm_t *) fir->coeffs;
+ xmm_hist = (xmm_t *) &fir->history[fir->curr_pos];
+ i = fir->taps;
+ pxor_r2r(xmm4, xmm4);
+ /* 16 samples per iteration, so the filter must be a multiple of 16 long. */
+ while (i > 0)
+ {
+ movdqu_m2r(xmm_coeffs[0], xmm0);
+ movdqu_m2r(xmm_coeffs[1], xmm2);
+ movdqu_m2r(xmm_hist[0], xmm1);
+ movdqu_m2r(xmm_hist[1], xmm3);
+ xmm_coeffs += 2;
+ xmm_hist += 2;
+ pmaddwd_r2r(xmm1, xmm0);
+ pmaddwd_r2r(xmm3, xmm2);
+ paddd_r2r(xmm0, xmm4);
+ paddd_r2r(xmm2, xmm4);
+ i -= 16;
+ }
+ movdqa_r2r(xmm4, xmm0);
+ psrldq_i2r(8, xmm0);
+ paddd_r2r(xmm0, xmm4);
+ movdqa_r2r(xmm4, xmm0);
+ psrldq_i2r(4, xmm0);
+ paddd_r2r(xmm0, xmm4);
+ movd_r2m(xmm4, y);
+#elif defined(__BLACKFIN_ASM__)
+ fir->history[fir->curr_pos] = sample;
+ fir->history[fir->curr_pos + fir->taps] = sample;
+ y = dot_asm((int16_t*)fir->coeffs, &fir->history[fir->curr_pos], fir->taps);
+#else
+ int i;
+ int offset1;
+ int offset2;
+
+ fir->history[fir->curr_pos] = sample;
+
+ offset2 = fir->curr_pos;
+ offset1 = fir->taps - offset2;
+ y = 0;
+ for (i = fir->taps - 1; i >= offset1; i--)
+ y += fir->coeffs[i]*fir->history[i - offset1];
+ for ( ; i >= 0; i--)
+ y += fir->coeffs[i]*fir->history[i + offset2];
+#endif
+ if (fir->curr_pos <= 0)
+ fir->curr_pos = fir->taps;
+ fir->curr_pos--;
+ return (int16_t) (y >> 15);
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ const int16_t *fir32_create(fir32_state_t *fir,
+ const int32_t *coeffs,
+ int taps)
+{
+ fir->taps = taps;
+ fir->curr_pos = taps - 1;
+ fir->coeffs = coeffs;
+ fir->history = (int16_t *) malloc(taps*sizeof(int16_t));
+ if (fir->history)
+ memset(fir->history, '\0', taps*sizeof(int16_t));
+ return fir->history;
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ void fir32_flush(fir32_state_t *fir)
+{
+ memset(fir->history, 0, fir->taps*sizeof(int16_t));
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ void fir32_free(fir32_state_t *fir)
+{
+ free(fir->history);
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ int16_t fir32(fir32_state_t *fir, int16_t sample)
+{
+ int i;
+ int32_t y;
+ int offset1;
+ int offset2;
+
+ fir->history[fir->curr_pos] = sample;
+ offset2 = fir->curr_pos;
+ offset1 = fir->taps - offset2;
+ y = 0;
+ for (i = fir->taps - 1; i >= offset1; i--)
+ y += fir->coeffs[i]*fir->history[i - offset1];
+ for ( ; i >= 0; i--)
+ y += fir->coeffs[i]*fir->history[i + offset2];
+ if (fir->curr_pos <= 0)
+ fir->curr_pos = fir->taps;
+ fir->curr_pos--;
+ return (int16_t) (y >> 15);
+}
+/*- End of function --------------------------------------------------------*/
+
+#ifndef __KERNEL__
+static __inline__ const float *fir_float_create(fir_float_state_t *fir,
+ const float *coeffs,
+ int taps)
+{
+ fir->taps = taps;
+ fir->curr_pos = taps - 1;
+ fir->coeffs = coeffs;
+ fir->history = (float *) malloc(taps*sizeof(float));
+ if (fir->history)
+ memset(fir->history, '\0', taps*sizeof(float));
+ return fir->history;
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ void fir_float_free(fir_float_state_t *fir)
+{
+ free(fir->history);
+}
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ int16_t fir_float(fir_float_state_t *fir, int16_t sample)
+{
+ int i;
+ float y;
+ int offset1;
+ int offset2;
+
+ fir->history[fir->curr_pos] = sample;
+
+ offset2 = fir->curr_pos;
+ offset1 = fir->taps - offset2;
+ y = 0;
+ for (i = fir->taps - 1; i >= offset1; i--)
+ y += fir->coeffs[i]*fir->history[i - offset1];
+ for ( ; i >= 0; i--)
+ y += fir->coeffs[i]*fir->history[i + offset2];
+ if (fir->curr_pos <= 0)
+ fir->curr_pos = fir->taps;
+ fir->curr_pos--;
+ return (int16_t) y;
+}
+/*- End of function --------------------------------------------------------*/
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/*- End of file ------------------------------------------------------------*/
diff --git a/drivers/staging/echo/mmx.h b/drivers/staging/echo/mmx.h
new file mode 100644
index 0000000..b5a3964
--- /dev/null
+++ b/drivers/staging/echo/mmx.h
@@ -0,0 +1,288 @@
+/*
+ * mmx.h
+ * Copyright (C) 1997-2001 H. Dietz and R. Fisher
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef AVCODEC_I386MMX_H
+#define AVCODEC_I386MMX_H
+
+/*
+ * The type of an value that fits in an MMX register (note that long
+ * long constant values MUST be suffixed by LL and unsigned long long
+ * values by ULL, lest they be truncated by the compiler)
+ */
+
+typedef union {
+ long long q; /* Quadword (64-bit) value */
+ unsigned long long uq; /* Unsigned Quadword */
+ int d[2]; /* 2 Doubleword (32-bit) values */
+ unsigned int ud[2]; /* 2 Unsigned Doubleword */
+ short w[4]; /* 4 Word (16-bit) values */
+ unsigned short uw[4]; /* 4 Unsigned Word */
+ char b[8]; /* 8 Byte (8-bit) values */
+ unsigned char ub[8]; /* 8 Unsigned Byte */
+ float s[2]; /* Single-precision (32-bit) value */
+} mmx_t; /* On an 8-byte (64-bit) boundary */
+
+/* SSE registers */
+typedef union {
+ char b[16];
+} xmm_t;
+
+
+#define mmx_i2r(op,imm,reg) \
+ __asm__ __volatile__ (#op " %0, %%" #reg \
+ : /* nothing */ \
+ : "i" (imm) )
+
+#define mmx_m2r(op,mem,reg) \
+ __asm__ __volatile__ (#op " %0, %%" #reg \
+ : /* nothing */ \
+ : "m" (mem))
+
+#define mmx_r2m(op,reg,mem) \
+ __asm__ __volatile__ (#op " %%" #reg ", %0" \
+ : "=m" (mem) \
+ : /* nothing */ )
+
+#define mmx_r2r(op,regs,regd) \
+ __asm__ __volatile__ (#op " %" #regs ", %" #regd)
+
+
+#define emms() __asm__ __volatile__ ("emms")
+
+#define movd_m2r(var,reg) mmx_m2r (movd, var, reg)
+#define movd_r2m(reg,var) mmx_r2m (movd, reg, var)
+#define movd_r2r(regs,regd) mmx_r2r (movd, regs, regd)
+
+#define movq_m2r(var,reg) mmx_m2r (movq, var, reg)
+#define movq_r2m(reg,var) mmx_r2m (movq, reg, var)
+#define movq_r2r(regs,regd) mmx_r2r (movq, regs, regd)
+
+#define packssdw_m2r(var,reg) mmx_m2r (packssdw, var, reg)
+#define packssdw_r2r(regs,regd) mmx_r2r (packssdw, regs, regd)
+#define packsswb_m2r(var,reg) mmx_m2r (packsswb, var, reg)
+#define packsswb_r2r(regs,regd) mmx_r2r (packsswb, regs, regd)
+
+#define packuswb_m2r(var,reg) mmx_m2r (packuswb, var, reg)
+#define packuswb_r2r(regs,regd) mmx_r2r (packuswb, regs, regd)
+
+#define paddb_m2r(var,reg) mmx_m2r (paddb, var, reg)
+#define paddb_r2r(regs,regd) mmx_r2r (paddb, regs, regd)
+#define paddd_m2r(var,reg) mmx_m2r (paddd, var, reg)
+#define paddd_r2r(regs,regd) mmx_r2r (paddd, regs, regd)
+#define paddw_m2r(var,reg) mmx_m2r (paddw, var, reg)
+#define paddw_r2r(regs,regd) mmx_r2r (paddw, regs, regd)
+
+#define paddsb_m2r(var,reg) mmx_m2r (paddsb, var, reg)
+#define paddsb_r2r(regs,regd) mmx_r2r (paddsb, regs, regd)
+#define paddsw_m2r(var,reg) mmx_m2r (paddsw, var, reg)
+#define paddsw_r2r(regs,regd) mmx_r2r (paddsw, regs, regd)
+
+#define paddusb_m2r(var,reg) mmx_m2r (paddusb, var, reg)
+#define paddusb_r2r(regs,regd) mmx_r2r (paddusb, regs, regd)
+#define paddusw_m2r(var,reg) mmx_m2r (paddusw, var, reg)
+#define paddusw_r2r(regs,regd) mmx_r2r (paddusw, regs, regd)
+
+#define pand_m2r(var,reg) mmx_m2r (pand, var, reg)
+#define pand_r2r(regs,regd) mmx_r2r (pand, regs, regd)
+
+#define pandn_m2r(var,reg) mmx_m2r (pandn, var, reg)
+#define pandn_r2r(regs,regd) mmx_r2r (pandn, regs, regd)
+
+#define pcmpeqb_m2r(var,reg) mmx_m2r (pcmpeqb, var, reg)
+#define pcmpeqb_r2r(regs,regd) mmx_r2r (pcmpeqb, regs, regd)
+#define pcmpeqd_m2r(var,reg) mmx_m2r (pcmpeqd, var, reg)
+#define pcmpeqd_r2r(regs,regd) mmx_r2r (pcmpeqd, regs, regd)
+#define pcmpeqw_m2r(var,reg) mmx_m2r (pcmpeqw, var, reg)
+#define pcmpeqw_r2r(regs,regd) mmx_r2r (pcmpeqw, regs, regd)
+
+#define pcmpgtb_m2r(var,reg) mmx_m2r (pcmpgtb, var, reg)
+#define pcmpgtb_r2r(regs,regd) mmx_r2r (pcmpgtb, regs, regd)
+#define pcmpgtd_m2r(var,reg) mmx_m2r (pcmpgtd, var, reg)
+#define pcmpgtd_r2r(regs,regd) mmx_r2r (pcmpgtd, regs, regd)
+#define pcmpgtw_m2r(var,reg) mmx_m2r (pcmpgtw, var, reg)
+#define pcmpgtw_r2r(regs,regd) mmx_r2r (pcmpgtw, regs, regd)
+
+#define pmaddwd_m2r(var,reg) mmx_m2r (pmaddwd, var, reg)
+#define pmaddwd_r2r(regs,regd) mmx_r2r (pmaddwd, regs, regd)
+
+#define pmulhw_m2r(var,reg) mmx_m2r (pmulhw, var, reg)
+#define pmulhw_r2r(regs,regd) mmx_r2r (pmulhw, regs, regd)
+
+#define pmullw_m2r(var,reg) mmx_m2r (pmullw, var, reg)
+#define pmullw_r2r(regs,regd) mmx_r2r (pmullw, regs, regd)
+
+#define por_m2r(var,reg) mmx_m2r (por, var, reg)
+#define por_r2r(regs,regd) mmx_r2r (por, regs, regd)
+
+#define pslld_i2r(imm,reg) mmx_i2r (pslld, imm, reg)
+#define pslld_m2r(var,reg) mmx_m2r (pslld, var, reg)
+#define pslld_r2r(regs,regd) mmx_r2r (pslld, regs, regd)
+#define psllq_i2r(imm,reg) mmx_i2r (psllq, imm, reg)
+#define psllq_m2r(var,reg) mmx_m2r (psllq, var, reg)
+#define psllq_r2r(regs,regd) mmx_r2r (psllq, regs, regd)
+#define psllw_i2r(imm,reg) mmx_i2r (psllw, imm, reg)
+#define psllw_m2r(var,reg) mmx_m2r (psllw, var, reg)
+#define psllw_r2r(regs,regd) mmx_r2r (psllw, regs, regd)
+
+#define psrad_i2r(imm,reg) mmx_i2r (psrad, imm, reg)
+#define psrad_m2r(var,reg) mmx_m2r (psrad, var, reg)
+#define psrad_r2r(regs,regd) mmx_r2r (psrad, regs, regd)
+#define psraw_i2r(imm,reg) mmx_i2r (psraw, imm, reg)
+#define psraw_m2r(var,reg) mmx_m2r (psraw, var, reg)
+#define psraw_r2r(regs,regd) mmx_r2r (psraw, regs, regd)
+
+#define psrld_i2r(imm,reg) mmx_i2r (psrld, imm, reg)
+#define psrld_m2r(var,reg) mmx_m2r (psrld, var, reg)
+#define psrld_r2r(regs,regd) mmx_r2r (psrld, regs, regd)
+#define psrlq_i2r(imm,reg) mmx_i2r (psrlq, imm, reg)
+#define psrlq_m2r(var,reg) mmx_m2r (psrlq, var, reg)
+#define psrlq_r2r(regs,regd) mmx_r2r (psrlq, regs, regd)
+#define psrlw_i2r(imm,reg) mmx_i2r (psrlw, imm, reg)
+#define psrlw_m2r(var,reg) mmx_m2r (psrlw, var, reg)
+#define psrlw_r2r(regs,regd) mmx_r2r (psrlw, regs, regd)
+
+#define psubb_m2r(var,reg) mmx_m2r (psubb, var, reg)
+#define psubb_r2r(regs,regd) mmx_r2r (psubb, regs, regd)
+#define psubd_m2r(var,reg) mmx_m2r (psubd, var, reg)
+#define psubd_r2r(regs,regd) mmx_r2r (psubd, regs, regd)
+#define psubw_m2r(var,reg) mmx_m2r (psubw, var, reg)
+#define psubw_r2r(regs,regd) mmx_r2r (psubw, regs, regd)
+
+#define psubsb_m2r(var,reg) mmx_m2r (psubsb, var, reg)
+#define psubsb_r2r(regs,regd) mmx_r2r (psubsb, regs, regd)
+#define psubsw_m2r(var,reg) mmx_m2r (psubsw, var, reg)
+#define psubsw_r2r(regs,regd) mmx_r2r (psubsw, regs, regd)
+
+#define psubusb_m2r(var,reg) mmx_m2r (psubusb, var, reg)
+#define psubusb_r2r(regs,regd) mmx_r2r (psubusb, regs, regd)
+#define psubusw_m2r(var,reg) mmx_m2r (psubusw, var, reg)
+#define psubusw_r2r(regs,regd) mmx_r2r (psubusw, regs, regd)
+
+#define punpckhbw_m2r(var,reg) mmx_m2r (punpckhbw, var, reg)
+#define punpckhbw_r2r(regs,regd) mmx_r2r (punpckhbw, regs, regd)
+#define punpckhdq_m2r(var,reg) mmx_m2r (punpckhdq, var, reg)
+#define punpckhdq_r2r(regs,regd) mmx_r2r (punpckhdq, regs, regd)
+#define punpckhwd_m2r(var,reg) mmx_m2r (punpckhwd, var, reg)
+#define punpckhwd_r2r(regs,regd) mmx_r2r (punpckhwd, regs, regd)
+
+#define punpcklbw_m2r(var,reg) mmx_m2r (punpcklbw, var, reg)
+#define punpcklbw_r2r(regs,regd) mmx_r2r (punpcklbw, regs, regd)
+#define punpckldq_m2r(var,reg) mmx_m2r (punpckldq, var, reg)
+#define punpckldq_r2r(regs,regd) mmx_r2r (punpckldq, regs, regd)
+#define punpcklwd_m2r(var,reg) mmx_m2r (punpcklwd, var, reg)
+#define punpcklwd_r2r(regs,regd) mmx_r2r (punpcklwd, regs, regd)
+
+#define pxor_m2r(var,reg) mmx_m2r (pxor, var, reg)
+#define pxor_r2r(regs,regd) mmx_r2r (pxor, regs, regd)
+
+
+/* 3DNOW extensions */
+
+#define pavgusb_m2r(var,reg) mmx_m2r (pavgusb, var, reg)
+#define pavgusb_r2r(regs,regd) mmx_r2r (pavgusb, regs, regd)
+
+
+/* AMD MMX extensions - also available in intel SSE */
+
+
+#define mmx_m2ri(op,mem,reg,imm) \
+ __asm__ __volatile__ (#op " %1, %0, %%" #reg \
+ : /* nothing */ \
+ : "m" (mem), "i" (imm))
+#define mmx_r2ri(op,regs,regd,imm) \
+ __asm__ __volatile__ (#op " %0, %%" #regs ", %%" #regd \
+ : /* nothing */ \
+ : "i" (imm) )
+
+#define mmx_fetch(mem,hint) \
+ __asm__ __volatile__ ("prefetch" #hint " %0" \
+ : /* nothing */ \
+ : "m" (mem))
+
+
+#define maskmovq(regs,maskreg) mmx_r2ri (maskmovq, regs, maskreg)
+
+#define movntq_r2m(mmreg,var) mmx_r2m (movntq, mmreg, var)
+
+#define pavgb_m2r(var,reg) mmx_m2r (pavgb, var, reg)
+#define pavgb_r2r(regs,regd) mmx_r2r (pavgb, regs, regd)
+#define pavgw_m2r(var,reg) mmx_m2r (pavgw, var, reg)
+#define pavgw_r2r(regs,regd) mmx_r2r (pavgw, regs, regd)
+
+#define pextrw_r2r(mmreg,reg,imm) mmx_r2ri (pextrw, mmreg, reg, imm)
+
+#define pinsrw_r2r(reg,mmreg,imm) mmx_r2ri (pinsrw, reg, mmreg, imm)
+
+#define pmaxsw_m2r(var,reg) mmx_m2r (pmaxsw, var, reg)
+#define pmaxsw_r2r(regs,regd) mmx_r2r (pmaxsw, regs, regd)
+
+#define pmaxub_m2r(var,reg) mmx_m2r (pmaxub, var, reg)
+#define pmaxub_r2r(regs,regd) mmx_r2r (pmaxub, regs, regd)
+
+#define pminsw_m2r(var,reg) mmx_m2r (pminsw, var, reg)
+#define pminsw_r2r(regs,regd) mmx_r2r (pminsw, regs, regd)
+
+#define pminub_m2r(var,reg) mmx_m2r (pminub, var, reg)
+#define pminub_r2r(regs,regd) mmx_r2r (pminub, regs, regd)
+
+#define pmovmskb(mmreg,reg) \
+ __asm__ __volatile__ ("movmskps %" #mmreg ", %" #reg)
+
+#define pmulhuw_m2r(var,reg) mmx_m2r (pmulhuw, var, reg)
+#define pmulhuw_r2r(regs,regd) mmx_r2r (pmulhuw, regs, regd)
+
+#define prefetcht0(mem) mmx_fetch (mem, t0)
+#define prefetcht1(mem) mmx_fetch (mem, t1)
+#define prefetcht2(mem) mmx_fetch (mem, t2)
+#define prefetchnta(mem) mmx_fetch (mem, nta)
+
+#define psadbw_m2r(var,reg) mmx_m2r (psadbw, var, reg)
+#define psadbw_r2r(regs,regd) mmx_r2r (psadbw, regs, regd)
+
+#define pshufw_m2r(var,reg,imm) mmx_m2ri(pshufw, var, reg, imm)
+#define pshufw_r2r(regs,regd,imm) mmx_r2ri(pshufw, regs, regd, imm)
+
+#define sfence() __asm__ __volatile__ ("sfence\n\t")
+
+/* SSE2 */
+#define pshufhw_m2r(var,reg,imm) mmx_m2ri(pshufhw, var, reg, imm)
+#define pshufhw_r2r(regs,regd,imm) mmx_r2ri(pshufhw, regs, regd, imm)
+#define pshuflw_m2r(var,reg,imm) mmx_m2ri(pshuflw, var, reg, imm)
+#define pshuflw_r2r(regs,regd,imm) mmx_r2ri(pshuflw, regs, regd, imm)
+
+#define pshufd_r2r(regs,regd,imm) mmx_r2ri(pshufd, regs, regd, imm)
+
+#define movdqa_m2r(var,reg) mmx_m2r (movdqa, var, reg)
+#define movdqa_r2m(reg,var) mmx_r2m (movdqa, reg, var)
+#define movdqa_r2r(regs,regd) mmx_r2r (movdqa, regs, regd)
+#define movdqu_m2r(var,reg) mmx_m2r (movdqu, var, reg)
+#define movdqu_r2m(reg,var) mmx_r2m (movdqu, reg, var)
+#define movdqu_r2r(regs,regd) mmx_r2r (movdqu, regs, regd)
+
+#define pmullw_r2m(reg,var) mmx_r2m (pmullw, reg, var)
+
+#define pslldq_i2r(imm,reg) mmx_i2r (pslldq, imm, reg)
+#define psrldq_i2r(imm,reg) mmx_i2r (psrldq, imm, reg)
+
+#define punpcklqdq_r2r(regs,regd) mmx_r2r (punpcklqdq, regs, regd)
+#define punpckhqdq_r2r(regs,regd) mmx_r2r (punpckhqdq, regs, regd)
+
+
+#endif /* AVCODEC_I386MMX_H */
--
1.6.0.2
^ permalink raw reply related [flat|nested] 37+ messages in thread* Re: [PATCH 16/23] Staging: add echo cancelation module
2008-10-10 22:42 ` [PATCH 16/23] Staging: add echo cancelation module Greg KH
@ 2008-10-10 23:08 ` Mike Frysinger
2008-10-10 23:12 ` Greg KH
2008-10-11 6:33 ` Tzafrir Cohen
1 sibling, 1 reply; 37+ messages in thread
From: Mike Frysinger @ 2008-10-10 23:08 UTC (permalink / raw)
To: David Rowe; +Cc: Linux Kernel, Greg KH, Tzafrir Cohen, Greg Kroah-Hartman
On Fri, Oct 10, 2008 at 18:42, Greg KH wrote:
> +#ifdef __BLACKFIN_ASM__
shouldnt this be CONFIG_BLACKFIN or just __bfin__ ? unless i missed
some magic, that define doesnt get defined anywhere ...
-mike
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 16/23] Staging: add echo cancelation module
2008-10-10 23:08 ` Mike Frysinger
@ 2008-10-10 23:12 ` Greg KH
0 siblings, 0 replies; 37+ messages in thread
From: Greg KH @ 2008-10-10 23:12 UTC (permalink / raw)
To: Mike Frysinger
Cc: David Rowe, Linux Kernel, Tzafrir Cohen, Greg Kroah-Hartman
On Fri, Oct 10, 2008 at 07:08:27PM -0400, Mike Frysinger wrote:
> On Fri, Oct 10, 2008 at 18:42, Greg KH wrote:
> > +#ifdef __BLACKFIN_ASM__
>
> shouldnt this be CONFIG_BLACKFIN or just __bfin__ ? unless i missed
> some magic, that define doesnt get defined anywhere ...
Probably, this code still needs to be cleaned up, hence the placement in
the staging tree :)
Patches gladly accepted to fix stuff like this, and anything else people
want to help out with, are always greatly appreciated.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 16/23] Staging: add echo cancelation module
2008-10-10 22:42 ` [PATCH 16/23] Staging: add echo cancelation module Greg KH
2008-10-10 23:08 ` Mike Frysinger
@ 2008-10-11 6:33 ` Tzafrir Cohen
2008-10-11 15:39 ` Greg KH
2008-10-11 15:39 ` Greg KH
1 sibling, 2 replies; 37+ messages in thread
From: Tzafrir Cohen @ 2008-10-11 6:33 UTC (permalink / raw)
To: Greg KH; +Cc: linux-kernel, David Rowe, Greg Kroah-Hartman
While there are a number of small issues in this code, I personally
would like to first and foremost get a usable interface so I could get a
working echo canceller module into dahdi:
http://svn.digium.com/svn/dahdi/linux/trunk/
http://svn.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/
(Don't preach me that it should be included in mainline. Or if you do,
do it in a different thread, please)
1. echo.h (The interface) needlessly includes the definition of
definition of echo_can_state_t. Anywhere in the interface it is used as
a pointer, including a _create and _destory function.
2. Furthermore, anybody that includes fir.h must also define malloc
first. See echo.c . fir.h is included for the definition of
echo_can_state_t .
3. In that specific environment (dahdi/zaptel) echo_can is not a very
unique prefix. Thus in my provisional change I added oslec_ as a prefix.
I'm not sure how much (3) counts here.
My current working tree is in not in the best place: the debian
(non-existing) package dahdi-linux . See
http://svn.debian.org/viewsvn/pkg-voip?rev=6284&view=rev
I hope that once I get a clear enough interface I can kick out the oslec
subdirectory and move the EC module upstream.
Also:
On Fri, Oct 10, 2008 at 03:42:40PM -0700, Greg KH wrote:
> diff --git a/drivers/staging/echo/TODO b/drivers/staging/echo/TODO
> new file mode 100644
> index 0000000..1ca09af
> --- /dev/null
> +++ b/drivers/staging/echo/TODO
> @@ -0,0 +1,10 @@
> +TODO:
> + - remove proc interface, only use echo.h interface (proc interface is
> + racy and not correct.)
Already done, right? I don't see any _wrapper.c around.
--
Tzafrir Cohen
icq#16849755 jabber:tzafrir.cohen@xorcom.com
+972-50-7952406 mailto:tzafrir.cohen@xorcom.com
http://www.xorcom.com iax:guest@local.xorcom.com/tzafrir
^ permalink raw reply [flat|nested] 37+ messages in thread* Re: [PATCH 16/23] Staging: add echo cancelation module
2008-10-11 6:33 ` Tzafrir Cohen
@ 2008-10-11 15:39 ` Greg KH
2008-10-11 15:39 ` Greg KH
1 sibling, 0 replies; 37+ messages in thread
From: Greg KH @ 2008-10-11 15:39 UTC (permalink / raw)
To: Tzafrir Cohen; +Cc: linux-kernel, David Rowe, Greg Kroah-Hartman
On Sat, Oct 11, 2008 at 08:33:10AM +0200, Tzafrir Cohen wrote:
> While there are a number of small issues in this code, I personally
> would like to first and foremost get a usable interface so I could get a
> working echo canceller module into dahdi:
> http://svn.digium.com/svn/dahdi/linux/trunk/
> http://svn.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/
Ok, that's great. I'm not saying that the current interface for this
driver is correct, that is why it is in the staging tree :)
It will change, don't worry.
But, what should it change into?
> 1. echo.h (The interface) needlessly includes the definition of
> definition of echo_can_state_t. Anywhere in the interface it is used as
> a pointer, including a _create and _destory function.
Simple to fix up.
> 2. Furthermore, anybody that includes fir.h must also define malloc
> first. See echo.c . fir.h is included for the definition of
> echo_can_state_t .
That will be resolved as well.
> 3. In that specific environment (dahdi/zaptel) echo_can is not a very
> unique prefix. Thus in my provisional change I added oslec_ as a prefix.
Ok, that seems very reasonable. The whole module should probably have
that added as a prefix as well.
> I'm not sure how much (3) counts here.
Lots :)
> My current working tree is in not in the best place: the debian
> (non-existing) package dahdi-linux . See
>
> http://svn.debian.org/viewsvn/pkg-voip?rev=6284&view=rev
>
> I hope that once I get a clear enough interface I can kick out the oslec
> subdirectory and move the EC module upstream.
Care to send me patches to help resolve these issues to make it easier
for you?
> On Fri, Oct 10, 2008 at 03:42:40PM -0700, Greg KH wrote:
>
> > diff --git a/drivers/staging/echo/TODO b/drivers/staging/echo/TODO
> > new file mode 100644
> > index 0000000..1ca09af
> > --- /dev/null
> > +++ b/drivers/staging/echo/TODO
> > @@ -0,0 +1,10 @@
> > +TODO:
>
> > + - remove proc interface, only use echo.h interface (proc interface is
> > + racy and not correct.)
>
> Already done, right? I don't see any _wrapper.c around.
Ah, good point, forgot that was already removed.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 16/23] Staging: add echo cancelation module
2008-10-11 6:33 ` Tzafrir Cohen
2008-10-11 15:39 ` Greg KH
@ 2008-10-11 15:39 ` Greg KH
1 sibling, 0 replies; 37+ messages in thread
From: Greg KH @ 2008-10-11 15:39 UTC (permalink / raw)
To: Tzafrir Cohen; +Cc: linux-kernel, David Rowe, Greg Kroah-Hartman
On Sat, Oct 11, 2008 at 08:33:10AM +0200, Tzafrir Cohen wrote:
> While there are a number of small issues in this code, I personally
> would like to first and foremost get a usable interface so I could get a
> working echo canceller module into dahdi:
> http://svn.digium.com/svn/dahdi/linux/trunk/
> http://svn.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/
>
> (Don't preach me that it should be included in mainline. Or if you do,
> do it in a different thread, please)
Ok, different thread :)
What is needed in order for you to include this in mainline?
Can it be placed in drivers/staging for now?
thanks,
greg k-h
^ permalink raw reply [flat|nested] 37+ messages in thread
* [PATCH 17/23] Staging: Fix gcc warnings in sxg
2008-10-10 22:41 [GIT PATCH] STAGING patches for 2.6.28 Greg KH
` (11 preceding siblings ...)
2008-10-10 22:42 ` [PATCH 16/23] Staging: add echo cancelation module Greg KH
@ 2008-10-10 22:42 ` Greg KH
2008-10-10 22:42 ` [PATCH 18/23] Staging: go7007 v4l fixes Greg KH
` (6 subsequent siblings)
19 siblings, 0 replies; 37+ messages in thread
From: Greg KH @ 2008-10-10 22:42 UTC (permalink / raw)
To: linux-kernel; +Cc: J.R. Mauro, Greg Kroah-Hartman
From: J.R. Mauro <jrm8005@gmail.com>
Fix for compiler warning about format specifier in prints in
drivers/staging/sxg/sxg.c
Prints were using %x to print unsigned long data.
Signed-off-by: J.R. Mauro <jrm8005@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/sxg/sxg.c | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/staging/sxg/sxg.c b/drivers/staging/sxg/sxg.c
index a91c9f3..0117d51 100644
--- a/drivers/staging/sxg/sxg.c
+++ b/drivers/staging/sxg/sxg.c
@@ -453,7 +453,7 @@ static int sxg_allocate_resources(p_adapter_t adapter)
// fails. If we hit a minimum, fail.
for (;;) {
- DBG_ERROR("%s Allocate XmtRings size[%x]\n", __FUNCTION__,
+ DBG_ERROR("%s Allocate XmtRings size[%lx]\n", __FUNCTION__,
(sizeof(SXG_XMT_RING) * 1));
// Start with big items first - receive and transmit rings. At the moment
@@ -470,7 +470,7 @@ static int sxg_allocate_resources(p_adapter_t adapter)
}
memset(adapter->XmtRings, 0, sizeof(SXG_XMT_RING) * 1);
- DBG_ERROR("%s Allocate RcvRings size[%x]\n", __FUNCTION__,
+ DBG_ERROR("%s Allocate RcvRings size[%lx]\n", __FUNCTION__,
(sizeof(SXG_RCV_RING) * 1));
adapter->RcvRings =
pci_alloc_consistent(adapter->pcidev,
@@ -531,7 +531,7 @@ static int sxg_allocate_resources(p_adapter_t adapter)
return (STATUS_RESOURCES);
}
- DBG_ERROR("%s Allocate EventRings size[%x]\n", __FUNCTION__,
+ DBG_ERROR("%s Allocate EventRings size[%lx]\n", __FUNCTION__,
(sizeof(SXG_EVENT_RING) * RssIds));
// Allocate event queues.
@@ -562,7 +562,7 @@ static int sxg_allocate_resources(p_adapter_t adapter)
}
memset(adapter->Isr, 0, sizeof(u32) * IsrCount);
- DBG_ERROR("%s Allocate shared XMT ring zero index location size[%x]\n",
+ DBG_ERROR("%s Allocate shared XMT ring zero index location size[%lx]\n",
__FUNCTION__, sizeof(u32));
// Allocate shared XMT ring zero index location
--
1.6.0.2
^ permalink raw reply related [flat|nested] 37+ messages in thread* [PATCH 18/23] Staging: go7007 v4l fixes
2008-10-10 22:41 [GIT PATCH] STAGING patches for 2.6.28 Greg KH
` (12 preceding siblings ...)
2008-10-10 22:42 ` [PATCH 17/23] Staging: Fix gcc warnings in sxg Greg KH
@ 2008-10-10 22:42 ` Greg KH
2008-10-10 22:42 ` [PATCH 19/23] Staging: SLICOSS: lots of checkpatch fixes Greg KH
` (5 subsequent siblings)
19 siblings, 0 replies; 37+ messages in thread
From: Greg KH @ 2008-10-10 22:42 UTC (permalink / raw)
To: linux-kernel; +Cc: Ross Cohen, Greg Kroah-Hartman
From: Ross Cohen <rcohen@snurgle.org>
Fix up some of the v4l issues that were recently changed to make the
go7007 driver a bit cleaner.
From: Ross Cohen <rcohen@snurgle.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/go7007/go7007-driver.c | 2 +-
drivers/staging/go7007/go7007-v4l2.c | 12 ++++--------
drivers/staging/go7007/snd-go7007.c | 4 ++--
drivers/staging/go7007/wis-ov7640.c | 3 +--
drivers/staging/go7007/wis-saa7113.c | 25 ++++++++++---------------
drivers/staging/go7007/wis-saa7115.c | 29 ++++++++++++++---------------
drivers/staging/go7007/wis-sony-tuner.c | 3 ++-
drivers/staging/go7007/wis-tw2804.c | 29 ++++++++++++++---------------
drivers/staging/go7007/wis-tw9903.c | 21 ++++++++++-----------
drivers/staging/go7007/wis-uda1342.c | 2 +-
10 files changed, 59 insertions(+), 71 deletions(-)
diff --git a/drivers/staging/go7007/go7007-driver.c b/drivers/staging/go7007/go7007-driver.c
index 5a336ff..81ae4b0 100644
--- a/drivers/staging/go7007/go7007-driver.c
+++ b/drivers/staging/go7007/go7007-driver.c
@@ -31,7 +31,7 @@
#include <linux/semaphore.h>
#include <linux/uaccess.h>
#include <asm/system.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <media/tuner.h>
#include <media/v4l2-common.h>
diff --git a/drivers/staging/go7007/go7007-v4l2.c b/drivers/staging/go7007/go7007-v4l2.c
index d54d019..94e1141 100644
--- a/drivers/staging/go7007/go7007-v4l2.c
+++ b/drivers/staging/go7007/go7007-v4l2.c
@@ -26,8 +26,7 @@
#include <linux/time.h>
#include <linux/vmalloc.h>
#include <linux/pagemap.h>
-#include <linux/videodev.h>
-#include <linux/video_decoder.h>
+#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <linux/i2c.h>
@@ -835,7 +834,6 @@ static int go7007_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_S_STD:
{
v4l2_std_id *std = arg;
- int norm;
if (go->streaming)
return -EBUSY;
@@ -856,20 +854,17 @@ static int go7007_do_ioctl(struct inode *inode, struct file *file,
if (*std & V4L2_STD_NTSC) {
go->standard = GO7007_STD_NTSC;
go->sensor_framerate = 30000;
- norm = VIDEO_MODE_NTSC;
} else if (*std & V4L2_STD_PAL) {
go->standard = GO7007_STD_PAL;
go->sensor_framerate = 25025;
- norm = VIDEO_MODE_PAL;
} else if (*std & V4L2_STD_SECAM) {
go->standard = GO7007_STD_PAL;
go->sensor_framerate = 25025;
- norm = VIDEO_MODE_SECAM;
} else
return -EINVAL;
if (go->i2c_adapter_online)
i2c_clients_command(&go->i2c_adapter,
- DECODER_SET_NORM, &norm);
+ VIDIOC_S_STD, std);
set_capture_size(go, NULL, 0);
return 0;
}
@@ -933,7 +928,7 @@ static int go7007_do_ioctl(struct inode *inode, struct file *file,
return -EBUSY;
go->input = *input;
if (go->i2c_adapter_online) {
- i2c_clients_command(&go->i2c_adapter, DECODER_SET_INPUT,
+ i2c_clients_command(&go->i2c_adapter, VIDIOC_S_INPUT,
&go->board_info->inputs[*input].video_input);
i2c_clients_command(&go->i2c_adapter, VIDIOC_S_AUDIO,
&go->board_info->inputs[*input].audio_input);
@@ -1459,6 +1454,7 @@ static struct file_operations go7007_fops = {
static struct video_device go7007_template = {
.name = "go7007",
+ .vfl_type = VID_TYPE_CAPTURE,
.fops = &go7007_fops,
.minor = -1,
.release = go7007_vfl_release,
diff --git a/drivers/staging/go7007/snd-go7007.c b/drivers/staging/go7007/snd-go7007.c
index f5cac08..382740c 100644
--- a/drivers/staging/go7007/snd-go7007.c
+++ b/drivers/staging/go7007/snd-go7007.c
@@ -44,8 +44,8 @@ module_param_array(index, int, NULL, 0444);
module_param_array(id, charp, NULL, 0444);
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for the go7007 audio driver");
-MODULE_PARM_DESC(index, "ID string for the go7007 audio driver");
-MODULE_PARM_DESC(index, "Enable for the go7007 audio driver");
+MODULE_PARM_DESC(id, "ID string for the go7007 audio driver");
+MODULE_PARM_DESC(enable, "Enable for the go7007 audio driver");
struct go7007_snd {
struct snd_card *card;
diff --git a/drivers/staging/go7007/wis-ov7640.c b/drivers/staging/go7007/wis-ov7640.c
index 815615a..f5f11e9 100644
--- a/drivers/staging/go7007/wis-ov7640.c
+++ b/drivers/staging/go7007/wis-ov7640.c
@@ -19,8 +19,7 @@
#include <linux/init.h>
#include <linux/version.h>
#include <linux/i2c.h>
-#include <linux/videodev.h>
-#include <linux/video_decoder.h>
+#include <linux/videodev2.h>
#include "wis-i2c.h"
diff --git a/drivers/staging/go7007/wis-saa7113.c b/drivers/staging/go7007/wis-saa7113.c
index 4b14ca8..c1aff1b 100644
--- a/drivers/staging/go7007/wis-saa7113.c
+++ b/drivers/staging/go7007/wis-saa7113.c
@@ -19,8 +19,7 @@
#include <linux/init.h>
#include <linux/version.h>
#include <linux/i2c.h>
-#include <linux/videodev.h>
-#include <linux/video_decoder.h>
+#include <linux/videodev2.h>
#include <linux/ioctl.h>
#include "wis-i2c.h"
@@ -124,7 +123,7 @@ static int wis_saa7113_command(struct i2c_client *client,
struct wis_saa7113 *dec = i2c_get_clientdata(client);
switch (cmd) {
- case DECODER_SET_INPUT:
+ case VIDIOC_S_INPUT:
{
int *input = arg;
@@ -133,23 +132,19 @@ static int wis_saa7113_command(struct i2c_client *client,
*input < 6 ? 0x40 : 0x80);
break;
}
- case DECODER_SET_NORM:
+ case VIDIOC_S_STD:
{
- int *input = arg;
+ v4l2_std_id *input = arg;
dec->norm = *input;
- switch (dec->norm) {
- case VIDEO_MODE_PAL:
- write_reg(client, 0x0e, 0x01);
- write_reg(client, 0x10, 0x48);
- break;
- case VIDEO_MODE_NTSC:
+ if (dec->norm & V4L2_STD_NTSC) {
write_reg(client, 0x0e, 0x01);
write_reg(client, 0x10, 0x40);
- break;
- case VIDEO_MODE_SECAM:
+ } else if (dec->norm & V4L2_STD_PAL) {
+ write_reg(client, 0x0e, 0x01);
+ write_reg(client, 0x10, 0x48);
+ } else if (dec->norm * V4L2_STD_SECAM) {
write_reg(client, 0x0e, 0x50);
write_reg(client, 0x10, 0x48);
- break;
}
break;
}
@@ -295,7 +290,7 @@ static int wis_saa7113_detect(struct i2c_adapter *adapter, int addr, int kind)
kfree(client);
return -ENOMEM;
}
- dec->norm = VIDEO_MODE_NTSC;
+ dec->norm = V4L2_STD_NTSC;
dec->brightness = 128;
dec->contrast = 71;
dec->saturation = 64;
diff --git a/drivers/staging/go7007/wis-saa7115.c b/drivers/staging/go7007/wis-saa7115.c
index bd40bf4..5c94c88 100644
--- a/drivers/staging/go7007/wis-saa7115.c
+++ b/drivers/staging/go7007/wis-saa7115.c
@@ -19,8 +19,7 @@
#include <linux/init.h>
#include <linux/version.h>
#include <linux/i2c.h>
-#include <linux/videodev.h>
-#include <linux/video_decoder.h>
+#include <linux/videodev2.h>
#include <linux/ioctl.h>
#include "wis-i2c.h"
@@ -204,7 +203,7 @@ static int wis_saa7115_command(struct i2c_client *client,
struct wis_saa7115 *dec = i2c_get_clientdata(client);
switch (cmd) {
- case DECODER_SET_INPUT:
+ case VIDIOC_S_INPUT:
{
int *input = arg;
@@ -222,7 +221,7 @@ static int wis_saa7115_command(struct i2c_client *client,
int h_scaling_increment = (704 / h_integer_scaler) *
1024 / res->width;
/* Fine-grained scaler only */
- int v_scaling_increment = (dec->norm == VIDEO_MODE_NTSC ?
+ int v_scaling_increment = (dec->norm & V4L2_STD_NTSC ?
240 : 288) * 1024 / res->height;
u8 regs[] = {
0x88, 0xc0,
@@ -262,20 +261,20 @@ static int wis_saa7115_command(struct i2c_client *client,
write_regs(client, regs);
break;
}
- case DECODER_SET_NORM:
+ case VIDIOC_S_STD:
{
- int *input = arg;
+ v4l2_std_id *input = arg;
u8 regs[] = {
0x88, 0xc0,
- 0x98, *input == VIDEO_MODE_NTSC ? 0x12 : 0x16,
- 0x9a, *input == VIDEO_MODE_NTSC ? 0xf2 : 0x20,
- 0x9b, *input == VIDEO_MODE_NTSC ? 0x00 : 0x01,
- 0xc8, *input == VIDEO_MODE_NTSC ? 0x12 : 0x16,
- 0xca, *input == VIDEO_MODE_NTSC ? 0xf2 : 0x20,
- 0xcb, *input == VIDEO_MODE_NTSC ? 0x00 : 0x01,
+ 0x98, *input & V4L2_STD_NTSC ? 0x12 : 0x16,
+ 0x9a, *input & V4L2_STD_NTSC ? 0xf2 : 0x20,
+ 0x9b, *input & V4L2_STD_NTSC ? 0x00 : 0x01,
+ 0xc8, *input & V4L2_STD_NTSC ? 0x12 : 0x16,
+ 0xca, *input & V4L2_STD_NTSC ? 0xf2 : 0x20,
+ 0xcb, *input & V4L2_STD_NTSC ? 0x00 : 0x01,
0x88, 0xf0,
- 0x30, *input == VIDEO_MODE_NTSC ? 0x66 : 0x00,
- 0x31, *input == VIDEO_MODE_NTSC ? 0x90 : 0xe0,
+ 0x30, *input & V4L2_STD_NTSC ? 0x66 : 0x00,
+ 0x31, *input & V4L2_STD_NTSC ? 0x90 : 0xe0,
0, 0,
};
write_regs(client, regs);
@@ -424,7 +423,7 @@ static int wis_saa7115_detect(struct i2c_adapter *adapter, int addr, int kind)
kfree(client);
return -ENOMEM;
}
- dec->norm = VIDEO_MODE_NTSC;
+ dec->norm = V4L2_STD_NTSC;
dec->brightness = 128;
dec->contrast = 64;
dec->saturation = 64;
diff --git a/drivers/staging/go7007/wis-sony-tuner.c b/drivers/staging/go7007/wis-sony-tuner.c
index 82e66d6..5997fb4 100644
--- a/drivers/staging/go7007/wis-sony-tuner.c
+++ b/drivers/staging/go7007/wis-sony-tuner.c
@@ -19,9 +19,10 @@
#include <linux/init.h>
#include <linux/version.h>
#include <linux/i2c.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <media/tuner.h>
#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
#include "wis-i2c.h"
diff --git a/drivers/staging/go7007/wis-tw2804.c b/drivers/staging/go7007/wis-tw2804.c
index 69ed7bf..27fe4d0 100644
--- a/drivers/staging/go7007/wis-tw2804.c
+++ b/drivers/staging/go7007/wis-tw2804.c
@@ -19,8 +19,7 @@
#include <linux/init.h>
#include <linux/version.h>
#include <linux/i2c.h>
-#include <linux/videodev.h>
-#include <linux/video_decoder.h>
+#include <linux/videodev2.h>
#include <linux/ioctl.h>
#include "wis-i2c.h"
@@ -159,20 +158,20 @@ static int wis_tw2804_command(struct i2c_client *client,
}
switch (cmd) {
- case DECODER_SET_NORM:
+ case VIDIOC_S_STD:
{
- int *input = arg;
+ v4l2_std_id *input = arg;
u8 regs[] = {
- 0x01, *input == VIDEO_MODE_NTSC ? 0xc4 : 0x84,
- 0x09, *input == VIDEO_MODE_NTSC ? 0x07 : 0x04,
- 0x0a, *input == VIDEO_MODE_NTSC ? 0xf0 : 0x20,
- 0x0b, *input == VIDEO_MODE_NTSC ? 0x07 : 0x04,
- 0x0c, *input == VIDEO_MODE_NTSC ? 0xf0 : 0x20,
- 0x0d, *input == VIDEO_MODE_NTSC ? 0x40 : 0x4a,
- 0x16, *input == VIDEO_MODE_NTSC ? 0x00 : 0x40,
- 0x17, *input == VIDEO_MODE_NTSC ? 0x00 : 0x40,
- 0x20, *input == VIDEO_MODE_NTSC ? 0x07 : 0x0f,
- 0x21, *input == VIDEO_MODE_NTSC ? 0x07 : 0x0f,
+ 0x01, *input & V4L2_STD_NTSC ? 0xc4 : 0x84,
+ 0x09, *input & V4L2_STD_NTSC ? 0x07 : 0x04,
+ 0x0a, *input & V4L2_STD_NTSC ? 0xf0 : 0x20,
+ 0x0b, *input & V4L2_STD_NTSC ? 0x07 : 0x04,
+ 0x0c, *input & V4L2_STD_NTSC ? 0xf0 : 0x20,
+ 0x0d, *input & V4L2_STD_NTSC ? 0x40 : 0x4a,
+ 0x16, *input & V4L2_STD_NTSC ? 0x00 : 0x40,
+ 0x17, *input & V4L2_STD_NTSC ? 0x00 : 0x40,
+ 0x20, *input & V4L2_STD_NTSC ? 0x07 : 0x0f,
+ 0x21, *input & V4L2_STD_NTSC ? 0x07 : 0x0f,
0xff, 0xff,
};
write_regs(client, regs, dec->channel);
@@ -322,7 +321,7 @@ static int wis_tw2804_detect(struct i2c_adapter *adapter, int addr, int kind)
return -ENOMEM;
}
dec->channel = -1;
- dec->norm = VIDEO_MODE_NTSC;
+ dec->norm = V4L2_STD_NTSC;
dec->brightness = 128;
dec->contrast = 128;
dec->saturation = 128;
diff --git a/drivers/staging/go7007/wis-tw9903.c b/drivers/staging/go7007/wis-tw9903.c
index 1cdf01a..d8e4196 100644
--- a/drivers/staging/go7007/wis-tw9903.c
+++ b/drivers/staging/go7007/wis-tw9903.c
@@ -19,8 +19,7 @@
#include <linux/init.h>
#include <linux/version.h>
#include <linux/i2c.h>
-#include <linux/videodev.h>
-#include <linux/video_decoder.h>
+#include <linux/videodev2.h>
#include <linux/ioctl.h>
#include "wis-i2c.h"
@@ -106,7 +105,7 @@ static int wis_tw9903_command(struct i2c_client *client,
struct wis_tw9903 *dec = i2c_get_clientdata(client);
switch (cmd) {
- case DECODER_SET_INPUT:
+ case VIDIOC_S_INPUT:
{
int *input = arg;
@@ -119,7 +118,7 @@ static int wis_tw9903_command(struct i2c_client *client,
struct video_decoder_resolution *res = arg;
/*int hscale = 256 * 720 / res->width;*/
int hscale = 256 * 720 / (res->width - (res->width > 704 ? 0 : 8));
- int vscale = 256 * (dec->norm == VIDEO_MODE_NTSC ? 240 : 288)
+ int vscale = 256 * (dec->norm & V4L2_STD_NTSC ? 240 : 288)
/ res->height;
u8 regs[] = {
0x0d, vscale & 0xff,
@@ -134,14 +133,14 @@ static int wis_tw9903_command(struct i2c_client *client,
break;
}
#endif
- case DECODER_SET_NORM:
+ case VIDIOC_S_STD:
{
- int *input = arg;
+ v4l2_std_id *input = arg;
u8 regs[] = {
- 0x05, *input == VIDEO_MODE_NTSC ? 0x80 : 0x00,
- 0x07, *input == VIDEO_MODE_NTSC ? 0x02 : 0x12,
- 0x08, *input == VIDEO_MODE_NTSC ? 0x14 : 0x18,
- 0x09, *input == VIDEO_MODE_NTSC ? 0xf0 : 0x20,
+ 0x05, *input & V4L2_STD_NTSC ? 0x80 : 0x00,
+ 0x07, *input & V4L2_STD_NTSC ? 0x02 : 0x12,
+ 0x08, *input & V4L2_STD_NTSC ? 0x14 : 0x18,
+ 0x09, *input & V4L2_STD_NTSC ? 0xf0 : 0x20,
0, 0,
};
write_regs(client, regs);
@@ -297,7 +296,7 @@ static int wis_tw9903_detect(struct i2c_adapter *adapter, int addr, int kind)
kfree(client);
return -ENOMEM;
}
- dec->norm = VIDEO_MODE_NTSC;
+ dec->norm = V4L2_STD_NTSC;
dec->brightness = 0;
dec->contrast = 0x60;
dec->hue = 0;
diff --git a/drivers/staging/go7007/wis-uda1342.c b/drivers/staging/go7007/wis-uda1342.c
index 28c10bf..a0894e3 100644
--- a/drivers/staging/go7007/wis-uda1342.c
+++ b/drivers/staging/go7007/wis-uda1342.c
@@ -19,7 +19,7 @@
#include <linux/init.h>
#include <linux/version.h>
#include <linux/i2c.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <media/tvaudio.h>
#include <media/v4l2-common.h>
--
1.6.0.2
^ permalink raw reply related [flat|nested] 37+ messages in thread* [PATCH 19/23] Staging: SLICOSS: lots of checkpatch fixes
2008-10-10 22:41 [GIT PATCH] STAGING patches for 2.6.28 Greg KH
` (13 preceding siblings ...)
2008-10-10 22:42 ` [PATCH 18/23] Staging: go7007 v4l fixes Greg KH
@ 2008-10-10 22:42 ` Greg KH
2008-10-10 22:42 ` [PATCH 20/23] Staging: SLICOSS: Fix warnings due to static usage Greg KH
` (4 subsequent siblings)
19 siblings, 0 replies; 37+ messages in thread
From: Greg KH @ 2008-10-10 22:42 UTC (permalink / raw)
To: linux-kernel; +Cc: Lior Dotan, Greg Kroah-Hartman
From: Lior Dotan <liodot@gmail.com>
Major cleanups of checkpatch warnings from the slicoss driver.
From: Lior Dotan <liodot@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/slicoss/gbdownload.h | 10 +-
drivers/staging/slicoss/gbrcvucode.h | 7 +-
drivers/staging/slicoss/oasisdbgdownload.h | 10 +-
drivers/staging/slicoss/oasisdownload.h | 10 +-
drivers/staging/slicoss/oasisrcvucode.h | 6 +-
drivers/staging/slicoss/slic.h | 485 +++++-----
drivers/staging/slicoss/slic_os.h | 85 +--
drivers/staging/slicoss/slicbuild.h | 1 -
drivers/staging/slicoss/slicdbg.h | 3 +-
drivers/staging/slicoss/slicdump.h | 89 +-
drivers/staging/slicoss/slichw.h | 653 +++++++-------
drivers/staging/slicoss/slicinc.h | 262 +++---
drivers/staging/slicoss/slicoss.c | 1351 +++++++++++++---------------
13 files changed, 1353 insertions(+), 1619 deletions(-)
diff --git a/drivers/staging/slicoss/gbdownload.h b/drivers/staging/slicoss/gbdownload.h
index 0350fb9..794432b 100644
--- a/drivers/staging/slicoss/gbdownload.h
+++ b/drivers/staging/slicoss/gbdownload.h
@@ -1,14 +1,14 @@
-#define MOJAVE_UCODE_VERS_STRING "$Revision: 1.2 $"
-#define MOJAVE_UCODE_VERS_DATE "$Date: 2006/03/27 15:12:22 $"
+#define MOJAVE_UCODE_VERS_STRING "1.2"
+#define MOJAVE_UCODE_VERS_DATE "2006/03/27 15:12:22"
#define MOJAVE_UCODE_HOSTIF_ID 3
-static LONG MNumSections = 0x2;
-static ULONG MSectionSize[] =
+static s32 MNumSections = 0x2;
+static u32 MSectionSize[] =
{
0x00008000, 0x00010000,
};
-static ULONG MSectionStart[] =
+static u32 MSectionStart[] =
{
0x00000000, 0x00008000,
};
diff --git a/drivers/staging/slicoss/gbrcvucode.h b/drivers/staging/slicoss/gbrcvucode.h
index dc00834..4fa5a4c 100644
--- a/drivers/staging/slicoss/gbrcvucode.h
+++ b/drivers/staging/slicoss/gbrcvucode.h
@@ -1,7 +1,6 @@
/*
* Copyright (c) 1997-2002 Alacritech, Inc. All rights reserved
*
- * $Id: gbrcvucode.h,v 1.2 2006/03/27 15:12:15 mook Exp $
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -32,10 +31,10 @@
* official policies, either expressed or implied, of Alacritech, Inc.
*
**************************************************************************/
-#define GB_RCVUCODE_VERS_STRING "$Revision: 1.2 $"
-#define GB_RCVUCODE_VERS_DATE "$Date: 2006/03/27 15:12:15 $"
+#define GB_RCVUCODE_VERS_STRING "1.2"
+#define GB_RCVUCODE_VERS_DATE "2006/03/27 15:12:15"
-static ULONG GBRcvUCodeLen = 512;
+static u32 GBRcvUCodeLen = 512;
static u8 GBRcvUCode[2560] =
{
diff --git a/drivers/staging/slicoss/oasisdbgdownload.h b/drivers/staging/slicoss/oasisdbgdownload.h
index cae5d55..519e007 100644
--- a/drivers/staging/slicoss/oasisdbgdownload.h
+++ b/drivers/staging/slicoss/oasisdbgdownload.h
@@ -1,14 +1,14 @@
-#define OASIS_UCODE_VERS_STRING "$Revision: 1.2 $"
-#define OASIS_UCODE_VERS_DATE "$Date: 2006/03/27 15:11:22 $"
+#define OASIS_UCODE_VERS_STRING "1.2"
+#define OASIS_UCODE_VERS_DATE "2006/03/27 15:11:22"
#define OASIS_UCODE_HOSTIF_ID 3
-static LONG ONumSections = 0x2;
-static ULONG OSectionSize[] =
+static s32 ONumSections = 0x2;
+static u32 OSectionSize[] =
{
0x00004000, 0x00010000,
};
-static ULONG OSectionStart[] =
+static u32 OSectionStart[] =
{
0x00000000, 0x00008000,
};
diff --git a/drivers/staging/slicoss/oasisdownload.h b/drivers/staging/slicoss/oasisdownload.h
index 89a440c..6438c23 100644
--- a/drivers/staging/slicoss/oasisdownload.h
+++ b/drivers/staging/slicoss/oasisdownload.h
@@ -1,13 +1,13 @@
-#define OASIS_UCODE_VERS_STRING "$Revision: 1.2 $"
-#define OASIS_UCODE_VERS_DATE "$Date: 2006/03/27 15:10:37 $"
+#define OASIS_UCODE_VERS_STRING "1.2"
+#define OASIS_UCODE_VERS_DATE "2006/03/27 15:10:37"
#define OASIS_UCODE_HOSTIF_ID 3
-static LONG ONumSections = 0x2;
-static ULONG OSectionSize[] = {
+static s32 ONumSections = 0x2;
+static u32 OSectionSize[] = {
0x00004000, 0x00010000,
};
-static ULONG OSectionStart[] = {
+static u32 OSectionStart[] = {
0x00000000, 0x00008000,
};
diff --git a/drivers/staging/slicoss/oasisrcvucode.h b/drivers/staging/slicoss/oasisrcvucode.h
index ef91632..5b3531f 100644
--- a/drivers/staging/slicoss/oasisrcvucode.h
+++ b/drivers/staging/slicoss/oasisrcvucode.h
@@ -1,7 +1,7 @@
-#define OASIS_RCVUCODE_VERS_STRING "$Revision: 1.2 $"
-#define OASIS_RCVUCODE_VERS_DATE "$Date: 2006/03/27 15:10:28 $"
+#define OASIS_RCVUCODE_VERS_STRING "1.2"
+#define OASIS_RCVUCODE_VERS_DATE "2006/03/27 15:10:28"
-static ULONG OasisRcvUCodeLen = 512;
+static u32 OasisRcvUCodeLen = 512;
static u8 OasisRcvUCode[2560] =
{
diff --git a/drivers/staging/slicoss/slic.h b/drivers/staging/slicoss/slic.h
index 9707e5a..0d5dc24 100644
--- a/drivers/staging/slicoss/slic.h
+++ b/drivers/staging/slicoss/slic.h
@@ -2,7 +2,6 @@
*
* Copyright (c) 2000-2002 Alacritech, Inc. All rights reserved.
*
- * $Id: slic.h,v 1.3 2006/07/14 16:43:02 mook Exp $
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -51,14 +50,14 @@ struct slic_spinlock {
#define SLIC_RSPQ_PAGES_GB 10
#define SLIC_RSPQ_BUFSINPAGE (PAGE_SIZE / SLIC_RSPBUF_SIZE)
-typedef struct _slic_rspqueue_t {
- ulong32 offset;
- ulong32 pageindex;
- ulong32 num_pages;
- p_slic_rspbuf_t rspbuf;
- pulong32 vaddr[SLIC_RSPQ_PAGES_GB];
+struct slic_rspqueue {
+ u32 offset;
+ u32 pageindex;
+ u32 num_pages;
+ struct slic_rspbuf *rspbuf;
+ u32 *vaddr[SLIC_RSPQ_PAGES_GB];
dma_addr_t paddr[SLIC_RSPQ_PAGES_GB];
-} slic_rspqueue_t, *p_slic_rspqueue_t;
+};
#define SLIC_RCVQ_EXPANSION 1
#define SLIC_RCVQ_ENTRIES (256 * SLIC_RCVQ_EXPANSION)
@@ -68,45 +67,45 @@ typedef struct _slic_rspqueue_t {
#define SLIC_RCVQ_FILLENTRIES (16 * SLIC_RCVQ_EXPANSION)
#define SLIC_RCVQ_FILLTHRESH (SLIC_RCVQ_ENTRIES - SLIC_RCVQ_FILLENTRIES)
-typedef struct _slic_rcvqueue_t {
+struct slic_rcvqueue {
struct sk_buff *head;
struct sk_buff *tail;
- ulong32 count;
- ulong32 size;
- ulong32 errors;
-} slic_rcvqueue_t, *p_slic_rcvqueue_t;
-
-typedef struct _slic_rcvbuf_info_t {
- ulong32 id;
- ulong32 starttime;
- ulong32 stoptime;
- ulong32 slicworld;
- ulong32 lasttime;
- ulong32 lastid;
-} slic_rcvbuf_info_t, *pslic_rcvbuf_info_t;
+ u32 count;
+ u32 size;
+ u32 errors;
+};
+
+struct slic_rcvbuf_info {
+ u32 id;
+ u32 starttime;
+ u32 stoptime;
+ u32 slicworld;
+ u32 lasttime;
+ u32 lastid;
+};
/*
SLIC Handle structure. Used to restrict handle values to
32 bits by using an index rather than an address.
Simplifies ucode in 64-bit systems
*/
-typedef struct _slic_handle_word_t {
+struct slic_handle_word {
union {
struct {
ushort index;
ushort bottombits; /* to denote num bufs to card */
} parts;
- ulong32 whole;
+ u32 whole;
} handle;
-} slic_handle_word_t, *pslic_handle_word_t;
+};
-typedef struct _slic_handle_t {
- slic_handle_word_t token; /* token passed between host and card*/
+struct slic_handle {
+ struct slic_handle_word token; /* token passed between host and card*/
ushort type;
- pvoid address; /* actual address of the object*/
+ void *address; /* actual address of the object*/
ushort offset;
- struct _slic_handle_t *other_handle;
- struct _slic_handle_t *next;
-} slic_handle_t, *pslic_handle_t;
+ struct slic_handle *other_handle;
+ struct slic_handle *next;
+};
#define SLIC_HANDLE_FREE 0x0000
#define SLIC_HANDLE_DATA 0x0001
@@ -120,19 +119,19 @@ typedef struct _slic_handle_t {
#define SLIC_HOSTCMD_SIZE 512
-typedef struct _slic_hostcmd_t {
- slic_host64_cmd_t cmd64;
- ulong32 type;
+struct slic_hostcmd {
+ struct slic_host64_cmd cmd64;
+ u32 type;
struct sk_buff *skb;
- ulong32 paddrl;
- ulong32 paddrh;
- ulong32 busy;
- ulong32 cmdsize;
+ u32 paddrl;
+ u32 paddrh;
+ u32 busy;
+ u32 cmdsize;
ushort numbufs;
- pslic_handle_t pslic_handle;/* handle associated with command */
- struct _slic_hostcmd_t *next;
- struct _slic_hostcmd_t *next_all;
-} slic_hostcmd_t, *p_slic_hostcmd_t;
+ struct slic_handle *pslic_handle;/* handle associated with command */
+ struct slic_hostcmd *next;
+ struct slic_hostcmd *next_all;
+};
#define SLIC_CMDQ_CMDSINPAGE (PAGE_SIZE / SLIC_HOSTCMD_SIZE)
#define SLIC_CMD_DUMB 3
@@ -142,18 +141,18 @@ typedef struct _slic_hostcmd_t {
#define SLIC_CMDQ_MAXPAGES (SLIC_CMDQ_MAXCMDS / SLIC_CMDQ_CMDSINPAGE)
#define SLIC_CMDQ_INITPAGES (SLIC_CMDQ_INITCMDS / SLIC_CMDQ_CMDSINPAGE)
-typedef struct _slic_cmdqmem_t {
- int pagecnt;
- pulong32 pages[SLIC_CMDQ_MAXPAGES];
- dma_addr_t dma_pages[SLIC_CMDQ_MAXPAGES];
-} slic_cmdqmem_t, *p_slic_cmdqmem_t;
+struct slic_cmdqmem {
+ int pagecnt;
+ u32 *pages[SLIC_CMDQ_MAXPAGES];
+ dma_addr_t dma_pages[SLIC_CMDQ_MAXPAGES];
+};
-typedef struct _slic_cmdqueue_t {
- p_slic_hostcmd_t head;
- p_slic_hostcmd_t tail;
- int count;
- struct slic_spinlock lock;
-} slic_cmdqueue_t, *p_slic_cmdqueue_t;
+struct slic_cmdqueue {
+ struct slic_hostcmd *head;
+ struct slic_hostcmd *tail;
+ int count;
+ struct slic_spinlock lock;
+};
#ifdef STATUS_SUCCESS
#undef STATUS_SUCCESS
@@ -181,10 +180,10 @@ just set this at 15K, shouldnt make that much of a diff.
#endif
-typedef struct _mcast_address_t {
- uchar address[6];
- struct _mcast_address_t *next;
-} mcast_address_t, *p_mcast_address_t;
+struct mcast_address {
+ unsigned char address[6];
+ struct mcast_address *next;
+};
#define CARD_DOWN 0x00000000
#define CARD_UP 0x00000001
@@ -236,38 +235,37 @@ typedef struct _mcast_address_t {
#define SLIC_ADAPTER_STATE(x) ((x == ADAPT_UP) ? "UP" : "Down")
#define SLIC_CARD_STATE(x) ((x == CARD_UP) ? "UP" : "Down")
-typedef struct _slic_iface_stats {
+struct slic_iface_stats {
/*
* Stats
*/
- ulong64 xmt_bytes;
- ulong64 xmt_ucast;
- ulong64 xmt_mcast;
- ulong64 xmt_bcast;
- ulong64 xmt_errors;
- ulong64 xmt_discards;
- ulong64 xmit_collisions;
- ulong64 xmit_excess_xmit_collisions;
- ulong64 rcv_bytes;
- ulong64 rcv_ucast;
- ulong64 rcv_mcast;
- ulong64 rcv_bcast;
- ulong64 rcv_errors;
- ulong64 rcv_discards;
-} slic_iface_stats_t, *p_slic_iface_stats_t;
-
-typedef struct _slic_tcp_stats {
- ulong64 xmit_tcp_segs;
- ulong64 xmit_tcp_bytes;
- ulong64 rcv_tcp_segs;
- ulong64 rcv_tcp_bytes;
-} slic_tcp_stats_t, *p_slic_tcp_stats_t;
-
-typedef struct _slicnet_stats {
- slic_tcp_stats_t tcp;
- slic_iface_stats_t iface;
-
-} slicnet_stats_t, *p_slicnet_stats_t;
+ u64 xmt_bytes;
+ u64 xmt_ucast;
+ u64 xmt_mcast;
+ u64 xmt_bcast;
+ u64 xmt_errors;
+ u64 xmt_discards;
+ u64 xmit_collisions;
+ u64 xmit_excess_xmit_collisions;
+ u64 rcv_bytes;
+ u64 rcv_ucast;
+ u64 rcv_mcast;
+ u64 rcv_bcast;
+ u64 rcv_errors;
+ u64 rcv_discards;
+};
+
+struct sliccp_stats {
+ u64 xmit_tcp_segs;
+ u64 xmit_tcp_bytes;
+ u64 rcv_tcp_segs;
+ u64 rcv_tcp_bytes;
+};
+
+struct slicnet_stats {
+ struct sliccp_stats tcp;
+ struct slic_iface_stats iface;
+};
#define SLIC_LOADTIMER_PERIOD 1
#define SLIC_INTAGG_DEFAULT 200
@@ -294,13 +292,13 @@ typedef struct _slicnet_stats {
#define SLIC_INTAGG_4GB 100
#define SLIC_INTAGG_5GB 100
-typedef struct _ether_header {
- uchar ether_dhost[6];
- uchar ether_shost[6];
+struct ether_header {
+ unsigned char ether_dhost[6];
+ unsigned char ether_shost[6];
ushort ether_type;
-} ether_header, *p_ether_header;
+};
-typedef struct _sliccard_t {
+struct sliccard {
uint busnumber;
uint slotnumber;
uint state;
@@ -310,114 +308,111 @@ typedef struct _sliccard_t {
uint adapters_allocated;
uint adapters_sleeping;
uint gennumber;
- ulong32 events;
- ulong32 loadlevel_current;
- ulong32 load;
+ u32 events;
+ u32 loadlevel_current;
+ u32 load;
uint reset_in_progress;
- ulong32 pingstatus;
- ulong32 bad_pingstatus;
+ u32 pingstatus;
+ u32 bad_pingstatus;
struct timer_list loadtimer;
- ulong32 loadtimerset;
+ u32 loadtimerset;
uint config_set;
- slic_config_t config;
+ struct slic_config config;
struct dentry *debugfs_dir;
struct dentry *debugfs_cardinfo;
- struct _adapter_t *master;
- struct _adapter_t *adapter[SLIC_MAX_PORTS];
- struct _sliccard_t *next;
- ulong32 error_interrupts;
- ulong32 error_rmiss_interrupts;
- ulong32 rcv_interrupts;
- ulong32 xmit_interrupts;
- ulong32 num_isrs;
- ulong32 false_interrupts;
- ulong32 max_isr_rcvs;
- ulong32 max_isr_xmits;
- ulong32 rcv_interrupt_yields;
- ulong32 tx_packets;
+ struct adapter *master;
+ struct adapter *adapter[SLIC_MAX_PORTS];
+ struct sliccard *next;
+ u32 error_interrupts;
+ u32 error_rmiss_interrupts;
+ u32 rcv_interrupts;
+ u32 xmit_interrupts;
+ u32 num_isrs;
+ u32 false_interrupts;
+ u32 max_isr_rcvs;
+ u32 max_isr_xmits;
+ u32 rcv_interrupt_yields;
+ u32 tx_packets;
#if SLIC_DUMP_ENABLED
- ulong32 dumpstatus; /* Result of dump UPR */
- pvoid cmdbuffer;
+ u32 dumpstatus; /* Result of dump UPR */
+ void *cmdbuffer;
ulong cmdbuffer_phys;
- ulong32 cmdbuffer_physl;
- ulong32 cmdbuffer_physh;
+ u32 cmdbuffer_physl;
+ u32 cmdbuffer_physh;
- ulong32 dump_count;
+ u32 dump_count;
struct task_struct *dump_task_id;
- ulong32 dump_wait_count;
+ u32 dump_wait_count;
uint dumpthread_running; /* has a dump thread been init'd */
uint dump_requested; /* 0 no, 1 = reqstd 2=curr 3=done */
- ulong32 dumptime_start;
- ulong32 dumptime_complete;
- ulong32 dumptime_delta;
- pvoid dumpbuffer;
+ u32 dumptime_start;
+ u32 dumptime_complete;
+ u32 dumptime_delta;
+ void *dumpbuffer;
ulong dumpbuffer_phys;
- ulong32 dumpbuffer_physl;
- ulong32 dumpbuffer_physh;
+ u32 dumpbuffer_physl;
+ u32 dumpbuffer_physh;
wait_queue_head_t dump_wq;
struct file *dumphandle;
mm_segment_t dumpfile_fs;
#endif
- ulong32 debug_ix;
+ u32 debug_ix;
ushort reg_type[32];
ushort reg_offset[32];
- ulong32 reg_value[32];
- ulong32 reg_valueh[32];
-} sliccard_t, *p_sliccard_t;
+ u32 reg_value[32];
+ u32 reg_valueh[32];
+};
#define NUM_CFG_SPACES 2
#define NUM_CFG_REGS 64
-#define NUM_CFG_REG_ULONGS (NUM_CFG_REGS / sizeof(ulong32))
+#define NUM_CFG_REG_ULONGS (NUM_CFG_REGS / sizeof(u32))
-typedef struct _physcard_t {
- struct _adapter_t *adapter[SLIC_MAX_PORTS];
- struct _physcard_t *next;
+struct physcard {
+ struct adapter *adapter[SLIC_MAX_PORTS];
+ struct physcard *next;
uint adapters_allocd;
/* the following is not currently needed
- ulong32 bridge_busnum;
- ulong32 bridge_cfg[NUM_CFG_SPACES][NUM_CFG_REG_ULONGS];
+ u32 bridge_busnum;
+ u32 bridge_cfg[NUM_CFG_SPACES][NUM_CFG_REG_ULONGS];
*/
-} physcard_t, *p_physcard_t;
+};
-typedef struct _base_driver {
+struct base_driver {
struct slic_spinlock driver_lock;
- ulong32 num_slic_cards;
- ulong32 num_slic_ports;
- ulong32 num_slic_ports_active;
- ulong32 dynamic_intagg;
- p_sliccard_t slic_card;
- p_physcard_t phys_card;
+ u32 num_slic_cards;
+ u32 num_slic_ports;
+ u32 num_slic_ports_active;
+ u32 dynamic_intagg;
+ struct sliccard *slic_card;
+ struct physcard *phys_card;
uint cardnuminuse[SLIC_MAX_CARDS];
-} base_driver_t, *p_base_driver_t;
-
-extern base_driver_t slic_global;
-
-typedef struct _slic_shmem_t {
- volatile ulong32 isr;
- volatile ulong32 linkstatus;
- volatile slic_stats_t inicstats;
-} slic_shmem_t, *p_slic_shmem_t;
-
-typedef struct _slic_reg_params_t {
- ulong32 linkspeed;
- ulong32 linkduplex;
- ulong32 fail_on_bad_eeprom;
-} slic_reg_params_t, *p_reg_params_t;
-
-typedef struct _slic_upr_t {
- uint adapter;
- ulong32 upr_request;
- ulong32 upr_data;
- ulong32 upr_data_h;
- ulong32 upr_buffer;
- ulong32 upr_buffer_h;
- struct _slic_upr_t *next;
-
-} slic_upr_t, *p_slic_upr_t;
-
-typedef struct _slic_ifevents_ti {
+};
+
+struct slic_shmem {
+ volatile u32 isr;
+ volatile u32 linkstatus;
+ volatile struct slic_stats inicstats;
+};
+
+struct slic_reg_params {
+ u32 linkspeed;
+ u32 linkduplex;
+ u32 fail_on_bad_eeprom;
+};
+
+struct slic_upr {
+ uint adapter;
+ u32 upr_request;
+ u32 upr_data;
+ u32 upr_data_h;
+ u32 upr_buffer;
+ u32 upr_buffer_h;
+ struct slic_upr *next;
+};
+
+struct slic_ifevents {
uint oflow802;
uint uflow802;
uint Tprtoflow;
@@ -434,19 +429,19 @@ typedef struct _slic_ifevents_ti {
uint IpCsum;
uint TpCsum;
uint TpHlen;
-} slic_ifevents_t;
+};
-typedef struct _adapter_t {
- pvoid ifp;
- p_sliccard_t card;
+struct adapter {
+ void *ifp;
+ struct sliccard *card;
uint port;
- p_physcard_t physcard;
+ struct physcard *physcard;
uint physport;
uint cardindex;
uint card_size;
uint chipid;
- struct net_device *netdev;
- struct net_device *next_netdevice;
+ struct net_device *netdev;
+ struct net_device *next_netdevice;
struct slic_spinlock adapter_lock;
struct slic_spinlock reset_lock;
struct pci_dev *pcidev;
@@ -456,90 +451,90 @@ typedef struct _adapter_t {
ushort vendid;
ushort devid;
ushort subsysid;
- ulong32 irq;
+ u32 irq;
void __iomem *memorybase;
- ulong32 memorylength;
- ulong32 drambase;
- ulong32 dramlength;
+ u32 memorylength;
+ u32 drambase;
+ u32 dramlength;
uint queues_initialized;
uint allocated;
uint activated;
- ulong32 intrregistered;
+ u32 intrregistered;
uint isp_initialized;
uint gennumber;
- ulong32 curaddrupper;
- p_slic_shmem_t pshmem;
+ u32 curaddrupper;
+ struct slic_shmem *pshmem;
dma_addr_t phys_shmem;
- ulong32 isrcopy;
- p_slic_regs_t slic_regs;
- uchar state;
- uchar linkstate;
- uchar linkspeed;
- uchar linkduplex;
+ u32 isrcopy;
+ __iomem struct slic_regs *slic_regs;
+ unsigned char state;
+ unsigned char linkstate;
+ unsigned char linkspeed;
+ unsigned char linkduplex;
uint flags;
- uchar macaddr[6];
- uchar currmacaddr[6];
- ulong32 macopts;
+ unsigned char macaddr[6];
+ unsigned char currmacaddr[6];
+ u32 macopts;
ushort devflags_prev;
- ulong64 mcastmask;
- p_mcast_address_t mcastaddrs;
- p_slic_upr_t upr_list;
+ u64 mcastmask;
+ struct mcast_address *mcastaddrs;
+ struct slic_upr *upr_list;
uint upr_busy;
struct timer_list pingtimer;
- ulong32 pingtimerset;
+ u32 pingtimerset;
struct timer_list statstimer;
- ulong32 statstimerset;
+ u32 statstimerset;
struct timer_list loadtimer;
- ulong32 loadtimerset;
+ u32 loadtimerset;
struct dentry *debugfs_entry;
struct slic_spinlock upr_lock;
struct slic_spinlock bit64reglock;
- slic_rspqueue_t rspqueue;
- slic_rcvqueue_t rcvqueue;
- slic_cmdqueue_t cmdq_free;
- slic_cmdqueue_t cmdq_done;
- slic_cmdqueue_t cmdq_all;
- slic_cmdqmem_t cmdqmem;
+ struct slic_rspqueue rspqueue;
+ struct slic_rcvqueue rcvqueue;
+ struct slic_cmdqueue cmdq_free;
+ struct slic_cmdqueue cmdq_done;
+ struct slic_cmdqueue cmdq_all;
+ struct slic_cmdqmem cmdqmem;
/*
* SLIC Handles
*/
- slic_handle_t slic_handles[SLIC_CMDQ_MAXCMDS+1]; /* Object handles*/
- pslic_handle_t pfree_slic_handles; /* Free object handles*/
+ struct slic_handle slic_handles[SLIC_CMDQ_MAXCMDS+1]; /* Object handles*/
+ struct slic_handle *pfree_slic_handles; /* Free object handles*/
struct slic_spinlock handle_lock; /* Object handle list lock*/
ushort slic_handle_ix;
- ulong32 xmitq_full;
- ulong32 all_reg_writes;
- ulong32 icr_reg_writes;
- ulong32 isr_reg_writes;
- ulong32 error_interrupts;
- ulong32 error_rmiss_interrupts;
- ulong32 rx_errors;
- ulong32 rcv_drops;
- ulong32 rcv_interrupts;
- ulong32 xmit_interrupts;
- ulong32 linkevent_interrupts;
- ulong32 upr_interrupts;
- ulong32 num_isrs;
- ulong32 false_interrupts;
- ulong32 tx_packets;
- ulong32 xmit_completes;
- ulong32 tx_drops;
- ulong32 rcv_broadcasts;
- ulong32 rcv_multicasts;
- ulong32 rcv_unicasts;
- ulong32 max_isr_rcvs;
- ulong32 max_isr_xmits;
- ulong32 rcv_interrupt_yields;
- ulong32 intagg_period;
- p_inicpm_state_t inicpm_info;
- pvoid pinicpm_info;
- slic_reg_params_t reg_params;
- slic_ifevents_t if_events;
- slic_stats_t inicstats_prev;
- slicnet_stats_t slic_stats;
+ u32 xmitq_full;
+ u32 all_reg_writes;
+ u32 icr_reg_writes;
+ u32 isr_reg_writes;
+ u32 error_interrupts;
+ u32 error_rmiss_interrupts;
+ u32 rx_errors;
+ u32 rcv_drops;
+ u32 rcv_interrupts;
+ u32 xmit_interrupts;
+ u32 linkevent_interrupts;
+ u32 upr_interrupts;
+ u32 num_isrs;
+ u32 false_interrupts;
+ u32 tx_packets;
+ u32 xmit_completes;
+ u32 tx_drops;
+ u32 rcv_broadcasts;
+ u32 rcv_multicasts;
+ u32 rcv_unicasts;
+ u32 max_isr_rcvs;
+ u32 max_isr_xmits;
+ u32 rcv_interrupt_yields;
+ u32 intagg_period;
+ struct inicpm_state *inicpm_info;
+ void *pinicpm_info;
+ struct slic_reg_params reg_params;
+ struct slic_ifevents if_events;
+ struct slic_stats inicstats_prev;
+ struct slicnet_stats slic_stats;
struct net_device_stats stats;
-} adapter_t, *p_adapter_t;
+};
#if SLIC_DUMP_ENABLED
#define SLIC_DUMP_REQUESTED 1
@@ -552,10 +547,10 @@ typedef struct _adapter_t {
* structure is written out to the card's SRAM when the microcode panic's.
*
****************************************************************************/
-typedef struct _slic_crash_info {
+struct slic_crash_info {
ushort cpu_id;
ushort crash_pc;
-} slic_crash_info, *p_slic_crash_info;
+};
#define CRASH_INFO_OFFSET 0x155C
@@ -577,20 +572,20 @@ typedef struct _slic_crash_info {
#define ETHER_EQ_ADDR(_AddrA, _AddrB, _Result) \
{ \
_Result = TRUE; \
- if (*(pulong32)(_AddrA) != *(pulong32)(_AddrB)) \
+ if (*(u32 *)(_AddrA) != *(u32 *)(_AddrB)) \
_Result = FALSE; \
- if (*(pushort)(&((_AddrA)[4])) != *(pushort)(&((_AddrB)[4]))) \
+ if (*(u16 *)(&((_AddrA)[4])) != *(u16 *)(&((_AddrB)[4]))) \
_Result = FALSE; \
}
#if defined(CONFIG_X86_64) || defined(CONFIG_IA64)
-#define SLIC_GET_ADDR_LOW(_addr) (ulong32)((ulong64)(_addr) & \
+#define SLIC_GET_ADDR_LOW(_addr) (u32)((u64)(_addr) & \
0x00000000FFFFFFFF)
-#define SLIC_GET_ADDR_HIGH(_addr) (ulong32)(((ulong64)(_addr) >> 32) & \
+#define SLIC_GET_ADDR_HIGH(_addr) (u32)(((u64)(_addr) >> 32) & \
0x00000000FFFFFFFF)
#else
-#define SLIC_GET_ADDR_LOW(_addr) (ulong32)_addr
-#define SLIC_GET_ADDR_HIGH(_addr) (ulong32)0
+#define SLIC_GET_ADDR_LOW(_addr) (u32)_addr
+#define SLIC_GET_ADDR_HIGH(_addr) (u32)0
#endif
#define FLUSH TRUE
diff --git a/drivers/staging/slicoss/slic_os.h b/drivers/staging/slicoss/slic_os.h
index 2064673..b0d2883 100644
--- a/drivers/staging/slicoss/slic_os.h
+++ b/drivers/staging/slicoss/slic_os.h
@@ -2,7 +2,6 @@
*
* Copyright (c)2000-2002 Alacritech, Inc. All rights reserved.
*
- * $Id: slic_os.h,v 1.2 2006/03/27 15:10:15 mook Exp $
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -43,87 +42,9 @@
#ifndef _SLIC_OS_SPECIFIC_H_
#define _SLIC_OS_SPECIFIC_H_
-typedef unsigned char uchar;
-typedef u64 ulong64;
-typedef char *pchar;
-typedef unsigned char *puchar;
-typedef u16 *pushort;
-typedef u32 ulong32;
-typedef u32 *pulong32;
-typedef int *plong32;
-typedef unsigned int *puint;
-typedef void *pvoid;
-typedef unsigned long *pulong;
-typedef unsigned int boolean;
-typedef unsigned int wchar;
-typedef unsigned int *pwchar;
-typedef unsigned char UCHAR;
-typedef u32 ULONG;
-typedef s32 LONG;
#define FALSE (0)
#define TRUE (1)
-#define SLIC_INIT_SPINLOCK(x) \
- { \
- spin_lock_init(&((x).lock)); \
- }
-#define SLIC_ACQUIRE_SPINLOCK(x) \
- { \
- spin_lock(&((x).lock)); \
- }
-
-#define SLIC_RELEASE_SPINLOCK(x) \
- { \
- spin_unlock(&((x).lock)); \
- }
-
-#define SLIC_ACQUIRE_IRQ_SPINLOCK(x) \
- { \
- spin_lock_irqsave(&((x).lock), (x).flags); \
- }
-
-#define SLIC_RELEASE_IRQ_SPINLOCK(x) \
- { \
- spin_unlock_irqrestore(&((x).lock), (x).flags); \
- }
-
-#define ATK_DEBUG 1
-
-#if ATK_DEBUG
-#define SLIC_TIMESTAMP(value) { \
- struct timeval timev; \
- do_gettimeofday(&timev); \
- value = timev.tv_sec*1000000 + timev.tv_usec; \
-}
-#else
-#define SLIC_TIMESTAMP(value)
-#endif
-
-#define SLIC_ALLOCATE_MEM(len, flag) kmalloc(len, flag)
-#define SLIC_DEALLOCATE_MEM(mem) kfree(mem)
-#define SLIC_DEALLOCATE_IRQ_MEM(mem) free(mem)
-#define SLIC_ALLOCATE_PAGE(x) (pulong32)get_free_page(GFP_KERNEL)
-#define SLIC_DEALLOCATE_PAGE(addr) free_page((ulong32)addr)
-#define SLIC_ALLOCATE_PCIMEM(a, sz, physp) \
- pci_alloc_consistent((a)->pcidev, (sz), &(physp))
-#define SLIC_DEALLOCATE_PCIMEM(a, sz, vp, pp) \
- pci_free_consistent((a)->pcidev, (sz), (vp), (pp))
-#define SLIC_GET_PHYSICAL_ADDRESS(addr) virt_to_bus((addr))
-#define SLIC_GET_PHYSICAL_ADDRESS_HIGH(addr) 0
-
-#define SLIC_GET_DMA_ADDRESS_WRITE(a, ptr, sz) \
- pci_map_single((a)->pcidev, (ptr), (sz), PCI_DMA_TODEVICE)
-#define SLIC_GET_DMA_ADDRESS_READ(a, ptr, sz) \
- pci_map_single((a)->pcidev, (ptr), (sz), PCI_DMA_FROMDEVICE)
-#define SLIC_UNGET_DMA_ADDRESS_WRITE(a, pa, sz) \
- pci_unmap_single((a)->pcidev, (pa), (sz), PCI_DMA_TODEVICE)
-#define SLIC_UNGET_DMA_ADDRESS_READ(a, pa, sz) \
- pci_unmap_single((a)->pcidev, (pa), (sz), PCI_DMA_FROMDEVICE)
-
-#define SLIC_ZERO_MEMORY(p, sz) memset((p), 0, (sz))
-#define SLIC_EQUAL_MEMORY(src1, src2, len) (!memcmp(src1, src2, len))
-#define SLIC_MOVE_MEMORY(dst, src, len) memcpy((dst), (src), (len))
-
#define SLIC_SECS_TO_JIFFS(x) ((x) * HZ)
#define SLIC_MS_TO_JIFFIES(x) (SLIC_SECS_TO_JIFFS((x)) / 1000)
@@ -132,7 +53,7 @@ typedef s32 LONG;
{ \
adapter->card->reg_type[adapter->card->debug_ix] = 0; \
adapter->card->reg_offset[adapter->card->debug_ix] = \
- ((puchar)(®)) - ((puchar)adapter->slic_regs); \
+ ((unsigned char *)(®)) - ((unsigned char *)adapter->slic_regs); \
adapter->card->reg_value[adapter->card->debug_ix++] = value; \
if (adapter->card->debug_ix == 32) \
adapter->card->debug_ix = 0; \
@@ -142,7 +63,7 @@ typedef s32 LONG;
{ \
adapter->card->reg_type[adapter->card->debug_ix] = 1; \
adapter->card->reg_offset[adapter->card->debug_ix] = \
- ((puchar)(®)) - ((puchar)adapter->slic_regs); \
+ ((unsigned char *)(®)) - ((unsigned char *)adapter->slic_regs); \
adapter->card->reg_value[adapter->card->debug_ix] = value; \
adapter->card->reg_valueh[adapter->card->debug_ix++] = valh; \
if (adapter->card->debug_ix == 32) \
@@ -156,8 +77,6 @@ typedef s32 LONG;
#define WRITE_REG64(a, reg, value, regh, valh, flush) \
slic_reg64_write((a), (®), (value), (®h), (valh), (flush))
#endif
-#define READ_REG(reg, flush) slic_reg32_read((®), (flush))
-#define READ_REGP16(reg, flush) slic_reg16_read((®), (flush))
#endif /* _SLIC_OS_SPECIFIC_H_ */
diff --git a/drivers/staging/slicoss/slicbuild.h b/drivers/staging/slicoss/slicbuild.h
index ddf1665..ae05e04 100644
--- a/drivers/staging/slicoss/slicbuild.h
+++ b/drivers/staging/slicoss/slicbuild.h
@@ -2,7 +2,6 @@
*
* Copyright (c) 2000-2002 Alacritech, Inc. All rights reserved.
*
- * $Id: slicbuild.h,v 1.2 2006/03/27 15:10:10 mook Exp $
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/drivers/staging/slicoss/slicdbg.h b/drivers/staging/slicoss/slicdbg.h
index c1be56f..c54e44f 100644
--- a/drivers/staging/slicoss/slicdbg.h
+++ b/drivers/staging/slicoss/slicdbg.h
@@ -2,7 +2,6 @@
*
* Copyright (c) 2000-2002 Alacritech, Inc. All rights reserved.
*
- * $Id: slicdbg.h,v 1.2 2006/03/27 15:10:04 mook Exp $
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -66,7 +65,7 @@
#ifdef CONFIG_X86_64
#define VALID_ADDRESS(p) (1)
#else
-#define VALID_ADDRESS(p) (((ulong32)(p) & 0x80000000) || ((ulong32)(p) == 0))
+#define VALID_ADDRESS(p) (((u32)(p) & 0x80000000) || ((u32)(p) == 0))
#endif
#ifndef ASSERT
#define ASSERT(a) \
diff --git a/drivers/staging/slicoss/slicdump.h b/drivers/staging/slicoss/slicdump.h
index 3c46094..ca0a221 100644
--- a/drivers/staging/slicoss/slicdump.h
+++ b/drivers/staging/slicoss/slicdump.h
@@ -1,5 +1,4 @@
/*
- * $Id: slicdump.h,v 1.2 2006/03/27 15:09:57 mook Exp $
*
* Copyright (c) 2000-2002 Alacritech, Inc. All rights reserved.
*
@@ -148,32 +147,32 @@
/*
* Break and Reset Break command structure
*/
-typedef struct _BREAK {
- uchar command; /* Command word defined above */
- uchar resvd;
+struct BREAK {
+ unsigned char command; /* Command word defined above */
+ unsigned char resvd;
ushort count; /* Number of executions before break */
- ulong32 addr; /* Address of break point */
-} BREAK, *PBREAK;
+ u32 addr; /* Address of break point */
+};
/*
* Dump and Load command structure
*/
-typedef struct _dump_cmd {
- uchar cmd; /* Command word defined above */
- uchar desc; /* Descriptor values - defined below */
+struct dump_cmd {
+ unsigned char cmd; /* Command word defined above */
+ unsigned char desc; /* Descriptor values - defined below */
ushort count; /* number of 4 byte words to be transferred */
- ulong32 addr; /* start address of dump or load */
-} dump_cmd_t, *pdump_cmd_t;
+ u32 addr; /* start address of dump or load */
+};
/*
* Receive or Transmit a frame.
*/
-typedef struct _RCV_OR_XMT_FRAME {
- uchar command; /* Command word defined above */
- uchar MacId; /* Mac ID of interface - transmit only */
+struct RCV_OR_XMT_FRAME {
+ unsigned char command; /* Command word defined above */
+ unsigned char MacId; /* Mac ID of interface - transmit only */
ushort count; /* Length of frame in bytes */
- ulong32 pad; /* not used */
-} RCV_OR_XMT_FRAME, *PRCV_OR_XMT_FRAME;
+ u32 pad; /* not used */
+};
/*
* Values of desc field in DUMP_OR_LOAD structure
@@ -196,12 +195,12 @@ typedef struct _RCV_OR_XMT_FRAME {
/*
* Map command to replace a command in ROM with a command in WCS
*/
-typedef struct _MAP {
- uchar command; /* Command word defined above */
- uchar not_used[3];
+struct MAP {
+ unsigned char command; /* Command word defined above */
+ unsigned char not_used[3];
ushort map_to; /* Instruction address in WCS */
ushort map_out; /* Instruction address in ROM */
-} MAP, *PMAP;
+};
/*
* Misc definitions
@@ -221,35 +220,35 @@ typedef struct _MAP {
/*
* Coredump header structure
*/
-typedef struct _CORE_Q {
- ulong32 queueOff; /* Offset of queue */
- ulong32 queuesize; /* size of queue */
-} CORE_Q;
+struct CORE_Q {
+ u32 queueOff; /* Offset of queue */
+ u32 queuesize; /* size of queue */
+};
#define DRIVER_NAME_SIZE 32
-typedef struct _sliccore_hdr_t {
- uchar driver_version[DRIVER_NAME_SIZE]; /* Driver version string */
- ulong32 RcvRegOff; /* Offset of receive registers */
- ulong32 RcvRegsize; /* size of receive registers */
- ulong32 XmtRegOff; /* Offset of transmit registers */
- ulong32 XmtRegsize; /* size of transmit registers */
- ulong32 FileRegOff; /* Offset of register file */
- ulong32 FileRegsize; /* size of register file */
- ulong32 SramOff; /* Offset of Sram */
- ulong32 Sramsize; /* size of Sram */
- ulong32 DramOff; /* Offset of Dram */
- ulong32 Dramsize; /* size of Dram */
+struct sliccore_hdr {
+ unsigned char driver_version[DRIVER_NAME_SIZE]; /* Driver version string */
+ u32 RcvRegOff; /* Offset of receive registers */
+ u32 RcvRegsize; /* size of receive registers */
+ u32 XmtRegOff; /* Offset of transmit registers */
+ u32 XmtRegsize; /* size of transmit registers */
+ u32 FileRegOff; /* Offset of register file */
+ u32 FileRegsize; /* size of register file */
+ u32 SramOff; /* Offset of Sram */
+ u32 Sramsize; /* size of Sram */
+ u32 DramOff; /* Offset of Dram */
+ u32 Dramsize; /* size of Dram */
CORE_Q queues[SLIC_MAX_QUEUE]; /* size and offsets of queues */
- ulong32 CamAMOff; /* Offset of CAM A contents */
- ulong32 CamASize; /* Size of Cam A */
- ulong32 CamBMOff; /* Offset of CAM B contents */
- ulong32 CamBSize; /* Size of Cam B */
- ulong32 CamCMOff; /* Offset of CAM C contents */
- ulong32 CamCSize; /* Size of Cam C */
- ulong32 CamDMOff; /* Offset of CAM D contents */
- ulong32 CamDSize; /* Size of Cam D */
-} sliccore_hdr_t, *p_sliccore_hdr_t;
+ u32 CamAMOff; /* Offset of CAM A contents */
+ u32 CamASize; /* Size of Cam A */
+ u32 CamBMOff; /* Offset of CAM B contents */
+ u32 CamBSize; /* Size of Cam B */
+ u32 CamCMOff; /* Offset of CAM C contents */
+ u32 CamCSize; /* Size of Cam C */
+ u32 CamDMOff; /* Offset of CAM D contents */
+ u32 CamDSize; /* Size of Cam D */
+};
/*
* definitions needed for our kernel-mode gdb stub.
diff --git a/drivers/staging/slicoss/slichw.h b/drivers/staging/slicoss/slichw.h
index d5765c4..4c5c15d 100644
--- a/drivers/staging/slicoss/slichw.h
+++ b/drivers/staging/slicoss/slichw.h
@@ -2,7 +2,6 @@
*
* Copyright (c) 2000-2002 Alacritech, Inc. All rights reserved.
*
- * $Id: slichw.h,v 1.3 2008/03/17 19:27:26 chris Exp $
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -236,110 +235,106 @@
#define TRUE 1
#endif
-typedef struct _slic_rcvbuf_t {
- uchar pad1[6];
+struct slic_rcvbuf {
+ unsigned char pad1[6];
ushort pad2;
- ulong32 pad3;
- ulong32 pad4;
- ulong32 buffer;
- ulong32 length;
- ulong32 status;
- ulong32 pad5;
+ u32 pad3;
+ u32 pad4;
+ u32 buffer;
+ u32 length;
+ u32 status;
+ u32 pad5;
ushort pad6;
- uchar data[SLIC_RCVBUF_DATASIZE];
-} slic_rcvbuf_t, *p_slic_rcvbuf_t;
+ unsigned char data[SLIC_RCVBUF_DATASIZE];
+};
-typedef struct _slic_hddr_wds {
+ struct slic_hddr_wds {
union {
struct {
- ulong32 frame_status;
- ulong32 frame_status_b;
- ulong32 time_stamp;
- ulong32 checksum;
+ u32 frame_status;
+ u32 frame_status_b;
+ u32 time_stamp;
+ u32 checksum;
} hdrs_14port;
struct {
- ulong32 frame_status;
+ u32 frame_status;
ushort ByteCnt;
ushort TpChksum;
ushort CtxHash;
ushort MacHash;
- ulong32 BufLnk;
+ u32 BufLnk;
} hdrs_gbit;
} u0;
-} slic_hddr_wds_t, *p_slic_hddr_wds;
+};
#define frame_status14 u0.hdrs_14port.frame_status
#define frame_status_b14 u0.hdrs_14port.frame_status_b
#define frame_statusGB u0.hdrs_gbit.frame_status
-typedef struct _slic_host64sg_t {
- ulong32 paddrl;
- ulong32 paddrh;
- ulong32 length;
-} slic_host64sg_t, *p_slic_host64sg_t;
-
-typedef struct _slic_host64_cmd_t {
- ulong32 hosthandle;
- ulong32 RSVD;
- uchar command;
- uchar flags;
+struct slic_host64sg {
+ u32 paddrl;
+ u32 paddrh;
+ u32 length;
+};
+
+struct slic_host64_cmd {
+ u32 hosthandle;
+ u32 RSVD;
+ unsigned char command;
+ unsigned char flags;
union {
ushort rsv1;
ushort rsv2;
} u0;
union {
struct {
- ulong32 totlen;
- slic_host64sg_t bufs[SLIC_MAX64_BCNT];
+ u32 totlen;
+ struct slic_host64sg bufs[SLIC_MAX64_BCNT];
} slic_buffers;
} u;
+};
-} slic_host64_cmd_t, *p_slic_host64_cmd_t;
+struct slic_rspbuf {
+ u32 hosthandle;
+ u32 pad0;
+ u32 pad1;
+ u32 status;
+ u32 pad2[4];
-typedef struct _slic_rspbuf_t {
- ulong32 hosthandle;
- ulong32 pad0;
- ulong32 pad1;
- ulong32 status;
- ulong32 pad2[4];
+};
-} slic_rspbuf_t, *p_slic_rspbuf_t;
+struct slic_regs {
+ u32 slic_reset; /* Reset Register */
+ u32 pad0;
-typedef ulong32 SLIC_REG;
-
-
-typedef struct _slic_regs_t {
- ULONG slic_reset; /* Reset Register */
- ULONG pad0;
-
- ULONG slic_icr; /* Interrupt Control Register */
- ULONG pad2;
+ u32 slic_icr; /* Interrupt Control Register */
+ u32 pad2;
#define SLIC_ICR 0x0008
- ULONG slic_isp; /* Interrupt status pointer */
- ULONG pad1;
+ u32 slic_isp; /* Interrupt status pointer */
+ u32 pad1;
#define SLIC_ISP 0x0010
- ULONG slic_isr; /* Interrupt status */
- ULONG pad3;
+ u32 slic_isr; /* Interrupt status */
+ u32 pad3;
#define SLIC_ISR 0x0018
- SLIC_REG slic_hbar; /* Header buffer address reg */
- ULONG pad4;
+ u32 slic_hbar; /* Header buffer address reg */
+ u32 pad4;
/* 31-8 - phy addr of set of contiguous hdr buffers
7-0 - number of buffers passed
Buffers are 256 bytes long on 256-byte boundaries. */
#define SLIC_HBAR 0x0020
#define SLIC_HBAR_CNT_MSK 0x000000FF
- SLIC_REG slic_dbar; /* Data buffer handle & address reg */
- ULONG pad5;
+ u32 slic_dbar; /* Data buffer handle & address reg */
+ u32 pad5;
/* 4 sets of registers; Buffers are 2K bytes long 2 per 4K page. */
#define SLIC_DBAR 0x0028
#define SLIC_DBAR_SIZE 2048
- SLIC_REG slic_cbar; /* Xmt Cmd buf addr regs.*/
+ u32 slic_cbar; /* Xmt Cmd buf addr regs.*/
/* 1 per XMT interface
31-5 - phy addr of host command buffer
4-0 - length of cmd in multiples of 32 bytes
@@ -348,13 +343,13 @@ typedef struct _slic_regs_t {
#define SLIC_CBAR_LEN_MSK 0x0000001F
#define SLIC_CBAR_ALIGN 0x00000020
- SLIC_REG slic_wcs; /* write control store*/
+ u32 slic_wcs; /* write control store*/
#define SLIC_WCS 0x0034
#define SLIC_WCS_START 0x80000000 /*Start the SLIC (Jump to WCS)*/
#define SLIC_WCS_COMPARE 0x40000000 /* Compare with value in WCS*/
- SLIC_REG slic_rbar; /* Response buffer address reg.*/
- ULONG pad7;
+ u32 slic_rbar; /* Response buffer address reg.*/
+ u32 pad7;
/*31-8 - phy addr of set of contiguous response buffers
7-0 - number of buffers passed
Buffers are 32 bytes long on 32-byte boundaries.*/
@@ -362,166 +357,166 @@ typedef struct _slic_regs_t {
#define SLIC_RBAR_CNT_MSK 0x000000FF
#define SLIC_RBAR_SIZE 32
- SLIC_REG slic_stats; /* read statistics (UPR) */
- ULONG pad8;
+ u32 slic_stats; /* read statistics (UPR) */
+ u32 pad8;
#define SLIC_RSTAT 0x0040
- SLIC_REG slic_rlsr; /* read link status */
- ULONG pad9;
+ u32 slic_rlsr; /* read link status */
+ u32 pad9;
#define SLIC_LSTAT 0x0048
- SLIC_REG slic_wmcfg; /* Write Mac Config */
- ULONG pad10;
+ u32 slic_wmcfg; /* Write Mac Config */
+ u32 pad10;
#define SLIC_WMCFG 0x0050
- SLIC_REG slic_wphy; /* Write phy register */
- ULONG pad11;
+ u32 slic_wphy; /* Write phy register */
+ u32 pad11;
#define SLIC_WPHY 0x0058
- SLIC_REG slic_rcbar; /*Rcv Cmd buf addr reg*/
- ULONG pad12;
+ u32 slic_rcbar; /*Rcv Cmd buf addr reg*/
+ u32 pad12;
#define SLIC_RCBAR 0x0060
- SLIC_REG slic_rconfig; /* Read SLIC Config*/
- ULONG pad13;
+ u32 slic_rconfig; /* Read SLIC Config*/
+ u32 pad13;
#define SLIC_RCONFIG 0x0068
- SLIC_REG slic_intagg; /* Interrupt aggregation time*/
- ULONG pad14;
+ u32 slic_intagg; /* Interrupt aggregation time*/
+ u32 pad14;
#define SLIC_INTAGG 0x0070
- SLIC_REG slic_wxcfg; /* Write XMIT config reg*/
- ULONG pad16;
+ u32 slic_wxcfg; /* Write XMIT config reg*/
+ u32 pad16;
#define SLIC_WXCFG 0x0078
- SLIC_REG slic_wrcfg; /* Write RCV config reg*/
- ULONG pad17;
+ u32 slic_wrcfg; /* Write RCV config reg*/
+ u32 pad17;
#define SLIC_WRCFG 0x0080
- SLIC_REG slic_wraddral; /* Write rcv addr a low*/
- ULONG pad18;
+ u32 slic_wraddral; /* Write rcv addr a low*/
+ u32 pad18;
#define SLIC_WRADDRAL 0x0088
- SLIC_REG slic_wraddrah; /* Write rcv addr a high*/
- ULONG pad19;
+ u32 slic_wraddrah; /* Write rcv addr a high*/
+ u32 pad19;
#define SLIC_WRADDRAH 0x0090
- SLIC_REG slic_wraddrbl; /* Write rcv addr b low*/
- ULONG pad20;
+ u32 slic_wraddrbl; /* Write rcv addr b low*/
+ u32 pad20;
#define SLIC_WRADDRBL 0x0098
- SLIC_REG slic_wraddrbh; /* Write rcv addr b high*/
- ULONG pad21;
+ u32 slic_wraddrbh; /* Write rcv addr b high*/
+ u32 pad21;
#define SLIC_WRADDRBH 0x00a0
- SLIC_REG slic_mcastlow; /* Low bits of mcast mask*/
- ULONG pad22;
+ u32 slic_mcastlow; /* Low bits of mcast mask*/
+ u32 pad22;
#define SLIC_MCASTLOW 0x00a8
- SLIC_REG slic_mcasthigh; /* High bits of mcast mask*/
- ULONG pad23;
+ u32 slic_mcasthigh; /* High bits of mcast mask*/
+ u32 pad23;
#define SLIC_MCASTHIGH 0x00b0
- SLIC_REG slic_ping; /* Ping the card*/
- ULONG pad24;
+ u32 slic_ping; /* Ping the card*/
+ u32 pad24;
#define SLIC_PING 0x00b8
- SLIC_REG slic_dump_cmd; /* Dump command */
- ULONG pad25;
+ u32 slic_dump_cmd; /* Dump command */
+ u32 pad25;
#define SLIC_DUMP_CMD 0x00c0
- SLIC_REG slic_dump_data; /* Dump data pointer */
- ULONG pad26;
+ u32 slic_dump_data; /* Dump data pointer */
+ u32 pad26;
#define SLIC_DUMP_DATA 0x00c8
- SLIC_REG slic_pcistatus; /* Read card's pci_status register */
- ULONG pad27;
+ u32 slic_pcistatus; /* Read card's pci_status register */
+ u32 pad27;
#define SLIC_PCISTATUS 0x00d0
- SLIC_REG slic_wrhostid; /* Write hostid field */
- ULONG pad28;
+ u32 slic_wrhostid; /* Write hostid field */
+ u32 pad28;
#define SLIC_WRHOSTID 0x00d8
#define SLIC_RDHOSTID_1GB 0x1554
#define SLIC_RDHOSTID_2GB 0x1554
- SLIC_REG slic_low_power; /* Put card in a low power state */
- ULONG pad29;
+ u32 slic_low_power; /* Put card in a low power state */
+ u32 pad29;
#define SLIC_LOW_POWER 0x00e0
- SLIC_REG slic_quiesce; /* force slic into quiescent state
+ u32 slic_quiesce; /* force slic into quiescent state
before soft reset */
- ULONG pad30;
+ u32 pad30;
#define SLIC_QUIESCE 0x00e8
- SLIC_REG slic_reset_iface; /* reset interface queues */
- ULONG pad31;
+ u32 slic_reset_iface; /* reset interface queues */
+ u32 pad31;
#define SLIC_RESET_IFACE 0x00f0
- SLIC_REG slic_addr_upper; /* Bits 63-32 for host i/f addrs */
- ULONG pad32;
+ u32 slic_addr_upper; /* Bits 63-32 for host i/f addrs */
+ u32 pad32;
#define SLIC_ADDR_UPPER 0x00f8 /*Register is only written when it has changed*/
- SLIC_REG slic_hbar64; /* 64 bit Header buffer address reg */
- ULONG pad33;
+ u32 slic_hbar64; /* 64 bit Header buffer address reg */
+ u32 pad33;
#define SLIC_HBAR64 0x0100
- SLIC_REG slic_dbar64; /* 64 bit Data buffer handle & address reg */
- ULONG pad34;
+ u32 slic_dbar64; /* 64 bit Data buffer handle & address reg */
+ u32 pad34;
#define SLIC_DBAR64 0x0108
- SLIC_REG slic_cbar64; /* 64 bit Xmt Cmd buf addr regs. */
- ULONG pad35;
+ u32 slic_cbar64; /* 64 bit Xmt Cmd buf addr regs. */
+ u32 pad35;
#define SLIC_CBAR64 0x0110
- SLIC_REG slic_rbar64; /* 64 bit Response buffer address reg.*/
- ULONG pad36;
+ u32 slic_rbar64; /* 64 bit Response buffer address reg.*/
+ u32 pad36;
#define SLIC_RBAR64 0x0118
- SLIC_REG slic_rcbar64; /* 64 bit Rcv Cmd buf addr reg*/
- ULONG pad37;
+ u32 slic_rcbar64; /* 64 bit Rcv Cmd buf addr reg*/
+ u32 pad37;
#define SLIC_RCBAR64 0x0120
- SLIC_REG slic_stats64; /*read statistics (64 bit UPR)*/
- ULONG pad38;
+ u32 slic_stats64; /*read statistics (64 bit UPR)*/
+ u32 pad38;
#define SLIC_RSTAT64 0x0128
- SLIC_REG slic_rcv_wcs; /*Download Gigabit RCV sequencer ucode*/
- ULONG pad39;
+ u32 slic_rcv_wcs; /*Download Gigabit RCV sequencer ucode*/
+ u32 pad39;
#define SLIC_RCV_WCS 0x0130
#define SLIC_RCVWCS_BEGIN 0x40000000
#define SLIC_RCVWCS_FINISH 0x80000000
- SLIC_REG slic_wrvlanid; /* Write VlanId field */
- ULONG pad40;
+ u32 slic_wrvlanid; /* Write VlanId field */
+ u32 pad40;
#define SLIC_WRVLANID 0x0138
- SLIC_REG slic_read_xf_info; /* Read Transformer info */
- ULONG pad41;
+ u32 slic_read_xf_info; /* Read Transformer info */
+ u32 pad41;
#define SLIC_READ_XF_INFO 0x0140
- SLIC_REG slic_write_xf_info; /* Write Transformer info */
- ULONG pad42;
+ u32 slic_write_xf_info; /* Write Transformer info */
+ u32 pad42;
#define SLIC_WRITE_XF_INFO 0x0148
- SLIC_REG RSVD1; /* TOE Only */
- ULONG pad43;
+ u32 RSVD1; /* TOE Only */
+ u32 pad43;
- SLIC_REG RSVD2; /* TOE Only */
- ULONG pad44;
+ u32 RSVD2; /* TOE Only */
+ u32 pad44;
- SLIC_REG RSVD3; /* TOE Only */
- ULONG pad45;
+ u32 RSVD3; /* TOE Only */
+ u32 pad45;
- SLIC_REG RSVD4; /* TOE Only */
- ULONG pad46;
+ u32 RSVD4; /* TOE Only */
+ u32 pad46;
- SLIC_REG slic_ticks_per_sec; /* Write card ticks per second */
- ULONG pad47;
+ u32 slic_ticks_per_sec; /* Write card ticks per second */
+ u32 pad47;
#define SLIC_TICKS_PER_SEC 0x0170
-} __iomem slic_regs_t, *p_slic_regs_t, SLIC_REGS, *PSLIC_REGS;
+};
-typedef enum _UPR_REQUEST {
+enum UPR_REQUEST {
SLIC_UPR_STATS,
SLIC_UPR_RLSR,
SLIC_UPR_WCFG,
@@ -532,103 +527,102 @@ typedef enum _UPR_REQUEST {
SLIC_UPR_PDWN,
SLIC_UPR_PING,
SLIC_UPR_DUMP,
-} UPR_REQUEST;
-
-typedef struct _inicpm_wakepattern {
- ulong32 patternlength;
- uchar pattern[SLIC_PM_PATTERNSIZE];
- uchar mask[SLIC_PM_PATTERNSIZE];
-} inicpm_wakepattern_t, *p_inicpm_wakepattern_t;
-
-typedef struct _inicpm_state {
- ulong32 powercaps;
- ulong32 powerstate;
- ulong32 wake_linkstatus;
- ulong32 wake_magicpacket;
- ulong32 wake_framepattern;
- inicpm_wakepattern_t wakepattern[SLIC_PM_MAXPATTERNS];
-} inicpm_state_t, *p_inicpm_state_t;
-
-typedef struct _slicpm_packet_pattern {
- ulong32 priority;
- ulong32 reserved;
- ulong32 masksize;
- ulong32 patternoffset;
- ulong32 patternsize;
- ulong32 patternflags;
-} slicpm_packet_pattern_t, *p_slicpm_packet_pattern_t;
-
-typedef enum _slicpm_power_state {
+};
+
+struct inicpm_wakepattern {
+ u32 patternlength;
+ unsigned char pattern[SLIC_PM_PATTERNSIZE];
+ unsigned char mask[SLIC_PM_PATTERNSIZE];
+};
+
+struct inicpm_state {
+ u32 powercaps;
+ u32 powerstate;
+ u32 wake_linkstatus;
+ u32 wake_magicpacket;
+ u32 wake_framepattern;
+ struct inicpm_wakepattern wakepattern[SLIC_PM_MAXPATTERNS];
+};
+
+struct slicpm_packet_pattern {
+ u32 priority;
+ u32 reserved;
+ u32 masksize;
+ u32 patternoffset;
+ u32 patternsize;
+ u32 patternflags;
+};
+
+enum slicpm_power_state {
slicpm_state_unspecified = 0,
slicpm_state_d0,
slicpm_state_d1,
slicpm_state_d2,
slicpm_state_d3,
slicpm_state_maximum
-} slicpm_state_t, *p_slicpm_state_t;
-
-typedef struct _slicpm_wakeup_capabilities {
- slicpm_state_t min_magic_packet_wakeup;
- slicpm_state_t min_pattern_wakeup;
- slicpm_state_t min_link_change_wakeup;
-} slicpm_wakeup_capabilities_t, *p_slicpm_wakeup_capabilities_t;
-
-
-typedef struct _slic_pnp_capabilities {
- ulong32 flags;
- slicpm_wakeup_capabilities_t wakeup_capabilities;
-} slic_pnp_capabilities_t, *p_slic_pnp_capabilities_t;
-
-typedef struct _xmt_stats_t {
- ulong32 xmit_tcp_bytes;
- ulong32 xmit_tcp_segs;
- ulong32 xmit_bytes;
- ulong32 xmit_collisions;
- ulong32 xmit_unicasts;
- ulong32 xmit_other_error;
- ulong32 xmit_excess_collisions;
-} xmt_stats100_t;
-
-typedef struct _rcv_stats_t {
- ulong32 rcv_tcp_bytes;
- ulong32 rcv_tcp_segs;
- ulong32 rcv_bytes;
- ulong32 rcv_unicasts;
- ulong32 rcv_other_error;
- ulong32 rcv_drops;
-} rcv_stats100_t;
-
-typedef struct _xmt_statsgb_t {
- ulong64 xmit_tcp_bytes;
- ulong64 xmit_tcp_segs;
- ulong64 xmit_bytes;
- ulong64 xmit_collisions;
- ulong64 xmit_unicasts;
- ulong64 xmit_other_error;
- ulong64 xmit_excess_collisions;
-} xmt_statsGB_t;
-
-typedef struct _rcv_statsgb_t {
- ulong64 rcv_tcp_bytes;
- ulong64 rcv_tcp_segs;
- ulong64 rcv_bytes;
- ulong64 rcv_unicasts;
- u64 rcv_other_error;
- ulong64 rcv_drops;
-} rcv_statsGB_t;
-
-typedef struct _slic_stats {
+};
+
+struct slicpm_wakeup_capabilities {
+ enum slicpm_power_state min_magic_packet_wakeup;
+ enum slicpm_power_state min_pattern_wakeup;
+ enum slicpm_power_state min_link_change_wakeup;
+};
+
+struct slic_pnp_capabilities {
+ u32 flags;
+ struct slicpm_wakeup_capabilities wakeup_capabilities;
+};
+
+struct xmt_stats {
+ u32 xmit_tcp_bytes;
+ u32 xmit_tcp_segs;
+ u32 xmit_bytes;
+ u32 xmit_collisions;
+ u32 xmit_unicasts;
+ u32 xmit_other_error;
+ u32 xmit_excess_collisions;
+};
+
+struct rcv_stats {
+ u32 rcv_tcp_bytes;
+ u32 rcv_tcp_segs;
+ u32 rcv_bytes;
+ u32 rcv_unicasts;
+ u32 rcv_other_error;
+ u32 rcv_drops;
+};
+
+struct xmt_statsgb {
+ u64 xmit_tcp_bytes;
+ u64 xmit_tcp_segs;
+ u64 xmit_bytes;
+ u64 xmit_collisions;
+ u64 xmit_unicasts;
+ u64 xmit_other_error;
+ u64 xmit_excess_collisions;
+};
+
+struct rcv_statsgb {
+ u64 rcv_tcp_bytes;
+ u64 rcv_tcp_segs;
+ u64 rcv_bytes;
+ u64 rcv_unicasts;
+ u64 rcv_other_error;
+ u64 rcv_drops;
+};
+
+struct slic_stats {
union {
struct {
- xmt_stats100_t xmt100;
- rcv_stats100_t rcv100;
+ struct xmt_stats xmt100;
+ struct rcv_stats rcv100;
} stats_100;
struct {
- xmt_statsGB_t xmtGB;
- rcv_statsGB_t rcvGB;
+ struct xmt_statsgb xmtGB;
+ struct rcv_statsgb rcvGB;
} stats_GB;
} u;
-} slic_stats_t, *p_slic_stats_t;
+};
#define xmit_tcp_segs100 u.stats_100.xmt100.xmit_tcp_segs
#define xmit_tcp_bytes100 u.stats_100.xmt100.xmit_tcp_bytes
@@ -658,10 +652,9 @@ typedef struct _slic_stats {
#define rcv_other_error_gb u.stats_GB.rcvGB.rcv_other_error
#define rcv_drops_gb u.stats_GB.rcvGB.rcv_drops
-typedef struct _slic_config_mac_t {
- uchar macaddrA[6];
-
-} slic_config_mac_t, *pslic_config_mac_t;
+struct slic_config_mac {
+ unsigned char macaddrA[6];
+};
#define ATK_FRU_FORMAT 0x00
#define VENDOR1_FRU_FORMAT 0x01
@@ -670,68 +663,68 @@ typedef struct _slic_config_mac_t {
#define VENDOR4_FRU_FORMAT 0x04
#define NO_FRU_FORMAT 0xFF
-typedef struct _atk_fru_t {
- uchar assembly[6];
- uchar revision[2];
- uchar serial[14];
- uchar pad[3];
-} atk_fru_t, *patk_fru_t;
-
-typedef struct _vendor1_fru_t {
- uchar commodity;
- uchar assembly[4];
- uchar revision[2];
- uchar supplier[2];
- uchar date[2];
- uchar sequence[3];
- uchar pad[13];
-} vendor1_fru_t, *pvendor1_fru_t;
-
-typedef struct _vendor2_fru_t {
- uchar part[8];
- uchar supplier[5];
- uchar date[3];
- uchar sequence[4];
- uchar pad[7];
-} vendor2_fru_t, *pvendor2_fru_t;
-
-typedef struct _vendor3_fru_t {
- uchar assembly[6];
- uchar revision[2];
- uchar serial[14];
- uchar pad[3];
-} vendor3_fru_t, *pvendor3_fru_t;
-
-typedef struct _vendor4_fru_t {
- uchar number[8];
- uchar part[8];
- uchar version[8];
- uchar pad[3];
-} vendor4_fru_t, *pvendor4_fru_t;
-
-typedef union _oemfru_t {
- vendor1_fru_t vendor1_fru;
- vendor2_fru_t vendor2_fru;
- vendor3_fru_t vendor3_fru;
- vendor4_fru_t vendor4_fru;
-} oemfru_t, *poemfru_t;
+struct atk_fru {
+ unsigned char assembly[6];
+ unsigned char revision[2];
+ unsigned char serial[14];
+ unsigned char pad[3];
+};
+
+struct vendor1_fru {
+ unsigned char commodity;
+ unsigned char assembly[4];
+ unsigned char revision[2];
+ unsigned char supplier[2];
+ unsigned char date[2];
+ unsigned char sequence[3];
+ unsigned char pad[13];
+};
+
+struct vendor2_fru {
+ unsigned char part[8];
+ unsigned char supplier[5];
+ unsigned char date[3];
+ unsigned char sequence[4];
+ unsigned char pad[7];
+};
+
+struct vendor3_fru {
+ unsigned char assembly[6];
+ unsigned char revision[2];
+ unsigned char serial[14];
+ unsigned char pad[3];
+};
+
+struct vendor4_fru {
+ unsigned char number[8];
+ unsigned char part[8];
+ unsigned char version[8];
+ unsigned char pad[3];
+};
+
+union oemfru_t {
+ struct vendor1_fru vendor1_fru;
+ struct vendor2_fru vendor2_fru;
+ struct vendor3_fru vendor3_fru;
+ struct vendor4_fru vendor4_fru;
+};
/*
SLIC EEPROM structure for Mojave
*/
-typedef struct _slic_eeprom {
+struct slic_eeprom {
ushort Id; /* 00 EEPROM/FLASH Magic code 'A5A5'*/
ushort EecodeSize; /* 01 Size of EEPROM Codes (bytes * 4)*/
ushort FlashSize; /* 02 Flash size */
ushort EepromSize; /* 03 EEPROM Size */
ushort VendorId; /* 04 Vendor ID */
ushort DeviceId; /* 05 Device ID */
- uchar RevisionId; /* 06 Revision ID */
- uchar ClassCode[3]; /* 07 Class Code */
- uchar DbgIntPin; /* 08 Debug Interrupt pin */
- uchar NetIntPin0; /* Network Interrupt Pin */
- uchar MinGrant; /* 09 Minimum grant */
- uchar MaxLat; /* Maximum Latency */
+ unsigned char RevisionId; /* 06 Revision ID */
+ unsigned char ClassCode[3]; /* 07 Class Code */
+ unsigned char DbgIntPin; /* 08 Debug Interrupt pin */
+ unsigned char NetIntPin0; /* Network Interrupt Pin */
+ unsigned char MinGrant; /* 09 Minimum grant */
+ unsigned char MaxLat; /* Maximum Latency */
ushort PciStatus; /* 10 PCI Status */
ushort SubSysVId; /* 11 Subsystem Vendor Id */
ushort SubSysId; /* 12 Subsystem ID */
@@ -739,58 +732,60 @@ typedef struct _slic_eeprom {
ushort DramRomFn; /* 14 Dram/Rom function */
ushort DSize2Pci; /* 15 DRAM size to PCI (bytes * 64K) */
ushort RSize2Pci; /* 16 ROM extension size to PCI (bytes * 4k) */
- uchar NetIntPin1; /* 17 Network Interface Pin 1 (simba/leone only) */
- uchar NetIntPin2; /* Network Interface Pin 2 (simba/leone only) */
+ unsigned char NetIntPin1;/* 17 Network Interface Pin 1
+ (simba/leone only) */
+ unsigned char NetIntPin2; /*Network Interface Pin 2 (simba/leone only)*/
union {
- uchar NetIntPin3;/* 18 Network Interface Pin 3 (simba only) */
- uchar FreeTime;/* FreeTime setting (leone/mojave only) */
+ unsigned char NetIntPin3;/*18 Network Interface Pin 3
+ (simba only)*/
+ unsigned char FreeTime;/*FreeTime setting (leone/mojave only) */
} u1;
- uchar TBIctl; /* 10-bit interface control (Mojave only) */
+ unsigned char TBIctl; /* 10-bit interface control (Mojave only) */
ushort DramSize; /* 19 DRAM size (bytes * 64k) */
union {
struct {
/* Mac Interface Specific portions */
- slic_config_mac_t MacInfo[SLIC_NBR_MACS];
+ struct slic_config_mac MacInfo[SLIC_NBR_MACS];
} mac; /* MAC access for all boards */
struct {
/* use above struct for MAC access */
- slic_config_mac_t pad[SLIC_NBR_MACS - 1];
+ struct slic_config_mac pad[SLIC_NBR_MACS - 1];
ushort DeviceId2; /* Device ID for 2nd
PCI function */
- uchar IntPin2; /* Interrupt pin for
+ unsigned char IntPin2; /* Interrupt pin for
2nd PCI function */
- uchar ClassCode2[3]; /* Class Code for 2nd
+ unsigned char ClassCode2[3]; /* Class Code for 2nd
PCI function */
} mojave; /* 2nd function access for gigabit board */
} u2;
ushort CfgByte6; /* Config Byte 6 */
ushort PMECapab; /* Power Mgment capabilities */
ushort NwClkCtrls; /* NetworkClockControls */
- uchar FruFormat; /* Alacritech FRU format type */
- atk_fru_t AtkFru; /* Alacritech FRU information */
- uchar OemFruFormat; /* optional OEM FRU format type */
- oemfru_t OemFru; /* optional OEM FRU information */
- uchar Pad[4]; /* Pad to 128 bytes - includes 2 cksum bytes
+ unsigned char FruFormat; /* Alacritech FRU format type */
+ struct atk_fru AtkFru; /* Alacritech FRU information */
+ unsigned char OemFruFormat; /* optional OEM FRU format type */
+ union oemfru_t OemFru; /* optional OEM FRU information */
+ unsigned char Pad[4]; /* Pad to 128 bytes - includes 2 cksum bytes
*(if OEM FRU info exists) and two unusable
* bytes at the end */
-} slic_eeprom_t, *pslic_eeprom_t;
+};
/* SLIC EEPROM structure for Oasis */
-typedef struct _oslic_eeprom_t {
+struct oslic_eeprom {
ushort Id; /* 00 EEPROM/FLASH Magic code 'A5A5' */
ushort EecodeSize; /* 01 Size of EEPROM Codes (bytes * 4)*/
ushort FlashConfig0; /* 02 Flash Config for SPI device 0 */
ushort FlashConfig1; /* 03 Flash Config for SPI device 1 */
ushort VendorId; /* 04 Vendor ID */
ushort DeviceId; /* 05 Device ID (function 0) */
- uchar RevisionId; /* 06 Revision ID */
- uchar ClassCode[3]; /* 07 Class Code for PCI function 0 */
- uchar IntPin1; /* 08 Interrupt pin for PCI function 1*/
- uchar ClassCode2[3]; /* 09 Class Code for PCI function 1 */
- uchar IntPin2; /* 10 Interrupt pin for PCI function 2*/
- uchar IntPin0; /* Interrupt pin for PCI function 0*/
- uchar MinGrant; /* 11 Minimum grant */
- uchar MaxLat; /* Maximum Latency */
+ unsigned char RevisionId; /* 06 Revision ID */
+ unsigned char ClassCode[3]; /* 07 Class Code for PCI function 0 */
+ unsigned char IntPin1; /* 08 Interrupt pin for PCI function 1*/
+ unsigned char ClassCode2[3]; /* 09 Class Code for PCI function 1 */
+ unsigned char IntPin2; /* 10 Interrupt pin for PCI function 2*/
+ unsigned char IntPin0; /* Interrupt pin for PCI function 0*/
+ unsigned char MinGrant; /* 11 Minimum grant */
+ unsigned char MaxLat; /* Maximum Latency */
ushort SubSysVId; /* 12 Subsystem Vendor Id */
ushort SubSysId; /* 13 Subsystem ID */
ushort FlashSize; /* 14 Flash size (bytes / 4K) */
@@ -801,8 +796,8 @@ typedef struct _oslic_eeprom_t {
ushort DeviceId2; /* 18 Device Id (function 2) */
ushort CfgByte6; /* 19 Device Status Config Bytes 6-7 */
ushort PMECapab; /* 20 Power Mgment capabilities */
- uchar MSICapab; /* 21 MSI capabilities */
- uchar ClockDivider; /* Clock divider */
+ unsigned char MSICapab; /* 21 MSI capabilities */
+ unsigned char ClockDivider; /* Clock divider */
ushort PciStatusLow; /* 22 PCI Status bits 15:0 */
ushort PciStatusHigh; /* 23 PCI Status bits 31:16 */
ushort DramConfigLow; /* 24 DRAM Configuration bits 15:0 */
@@ -810,18 +805,18 @@ typedef struct _oslic_eeprom_t {
ushort DramSize; /* 26 DRAM size (bytes / 64K) */
ushort GpioTbiCtl;/* 27 GPIO/TBI controls for functions 1/0 */
ushort EepromSize; /* 28 EEPROM Size */
- slic_config_mac_t MacInfo[2]; /* 29 MAC addresses (2 ports) */
- uchar FruFormat; /* 35 Alacritech FRU format type */
- atk_fru_t AtkFru; /* Alacritech FRU information */
- uchar OemFruFormat; /* optional OEM FRU format type */
- oemfru_t OemFru; /* optional OEM FRU information */
- uchar Pad[4]; /* Pad to 128 bytes - includes 2 checksum bytes
+ struct slic_config_mac MacInfo[2]; /* 29 MAC addresses (2 ports) */
+ unsigned char FruFormat; /* 35 Alacritech FRU format type */
+ struct atk_fru AtkFru; /* Alacritech FRU information */
+ unsigned char OemFruFormat; /* optional OEM FRU format type */
+ union oemfru_t OemFru; /* optional OEM FRU information */
+ unsigned char Pad[4]; /* Pad to 128 bytes - includes 2 checksum bytes
* (if OEM FRU info exists) and two unusable
* bytes at the end
*/
-} oslic_eeprom_t, *poslic_eeprom_t;
+};
-#define MAX_EECODE_SIZE sizeof(slic_eeprom_t)
+#define MAX_EECODE_SIZE sizeof(struct slic_eeprom)
#define MIN_EECODE_SIZE 0x62 /* code size without optional OEM FRU stuff */
/* SLIC CONFIG structure
@@ -830,20 +825,20 @@ typedef struct _oslic_eeprom_t {
board types. It is filled in from the appropriate EEPROM structure
by SlicGetConfigData().
*/
-typedef struct _slic_config_t {
- boolean EepromValid; /* Valid EEPROM flag (checksum good?) */
+struct slic_config {
+ bool EepromValid; /* Valid EEPROM flag (checksum good?) */
ushort DramSize; /* DRAM size (bytes / 64K) */
- slic_config_mac_t MacInfo[SLIC_NBR_MACS]; /* MAC addresses */
- uchar FruFormat; /* Alacritech FRU format type */
- atk_fru_t AtkFru; /* Alacritech FRU information */
- uchar OemFruFormat; /* optional OEM FRU format type */
- union {
- vendor1_fru_t vendor1_fru;
- vendor2_fru_t vendor2_fru;
- vendor3_fru_t vendor3_fru;
- vendor4_fru_t vendor4_fru;
- } OemFru;
-} slic_config_t, *pslic_config_t;
+ struct slic_config_mac MacInfo[SLIC_NBR_MACS]; /* MAC addresses */
+ unsigned char FruFormat; /* Alacritech FRU format type */
+ struct atk_fru AtkFru; /* Alacritech FRU information */
+ unsigned char OemFruFormat; /* optional OEM FRU format type */
+ union {
+ struct vendor1_fru vendor1_fru;
+ struct vendor2_fru vendor2_fru;
+ struct vendor3_fru vendor3_fru;
+ struct vendor4_fru vendor4_fru;
+ } OemFru;
+};
#pragma pack()
diff --git a/drivers/staging/slicoss/slicinc.h b/drivers/staging/slicoss/slicinc.h
index 9910306..610c1ab 100644
--- a/drivers/staging/slicoss/slicinc.h
+++ b/drivers/staging/slicoss/slicinc.h
@@ -2,7 +2,6 @@
*
* Copyright (c) 2000-2002 Alacritech, Inc. All rights reserved.
*
- * $Id: slicinc.h,v 1.4 2006/07/14 16:42:56 mook Exp $
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -48,164 +47,135 @@
#include "slichw.h"
#include "slic.h"
-int slic_entry_probe(struct pci_dev *pcidev,
+static int slic_entry_probe(struct pci_dev *pcidev,
const struct pci_device_id *ent);
-int slic_init(struct pci_dev *pcidev,
- const struct pci_device_id *pci_tbl_entry,
- long memaddr,
- int chip_idx,
- int acpi_idle_state);
-void slic_entry_remove(struct pci_dev *pcidev);
+static void slic_entry_remove(struct pci_dev *pcidev);
-void slic_init_driver(void);
-int slic_entry_open(struct net_device *dev);
-int slic_entry_halt(struct net_device *dev);
-int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-int slic_xmit_start(struct sk_buff *skb, struct net_device *dev);
-void slic_xmit_fail(p_adapter_t adapter,
+static void slic_init_driver(void);
+static int slic_entry_open(struct net_device *dev);
+static int slic_entry_halt(struct net_device *dev);
+static int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int slic_xmit_start(struct sk_buff *skb, struct net_device *dev);
+static void slic_xmit_fail(struct adapter *adapter,
struct sk_buff *skb,
- pvoid cmd,
- ulong32 skbtype,
- ulong32 status);
-void slic_xmit_timeout(struct net_device *dev);
-void slic_config_pci(struct pci_dev *pcidev);
-struct sk_buff *slic_rcvqueue_getnext(p_adapter_t adapter);
+ void *cmd,
+ u32 skbtype,
+ u32 status);
+static void slic_xmit_timeout(struct net_device *dev);
+static void slic_config_pci(struct pci_dev *pcidev);
+static struct sk_buff *slic_rcvqueue_getnext(struct adapter *adapter);
-inline void slic_reg32_write(void __iomem *reg, ulong32 value, uint flush);
-inline void slic_reg64_write(p_adapter_t adapter, void __iomem *reg,
- ulong32 value, void __iomem *regh, ulong32 paddrh, uint flush);
-inline ulong32 slic_reg32_read(pulong32 reg, uint flush);
-inline ulong32 slic_reg16_read(pulong32 reg, uint flush);
+static inline void slic_reg32_write(void __iomem *reg, u32 value, uint flush);
+static inline void slic_reg64_write(struct adapter *adapter, void __iomem *reg,
+ u32 value, void __iomem *regh, u32 paddrh, uint flush);
#if SLIC_GET_STATS_ENABLED
-struct net_device_stats *slic_get_stats(struct net_device *dev);
+static struct net_device_stats *slic_get_stats(struct net_device *dev);
#endif
-int slic_mac_set_address(struct net_device *dev, pvoid ptr);
+static int slic_mac_set_address(struct net_device *dev, void *ptr);
+static void slic_rcv_handler(struct adapter *adapter);
+static void slic_link_event_handler(struct adapter *adapter);
+static void slic_xmit_complete(struct adapter *adapter);
+static void slic_upr_request_complete(struct adapter *adapter, u32 isr);
+static int slic_rspqueue_init(struct adapter *adapter);
+static int slic_rspqueue_reset(struct adapter *adapter);
+static void slic_rspqueue_free(struct adapter *adapter);
+static struct slic_rspbuf *slic_rspqueue_getnext(struct adapter *adapter);
+static void slic_cmdqmem_init(struct adapter *adapter);
+static void slic_cmdqmem_free(struct adapter *adapter);
+static u32 *slic_cmdqmem_addpage(struct adapter *adapter);
+static int slic_cmdq_init(struct adapter *adapter);
+static void slic_cmdq_free(struct adapter *adapter);
+static void slic_cmdq_reset(struct adapter *adapter);
+static void slic_cmdq_addcmdpage(struct adapter *adapter, u32 *page);
+static void slic_cmdq_getdone(struct adapter *adapter);
+static void slic_cmdq_putdone(struct adapter *adapter,
+ struct slic_hostcmd *cmd);
+static void slic_cmdq_putdone_irq(struct adapter *adapter,
+ struct slic_hostcmd *cmd);
+static struct slic_hostcmd *slic_cmdq_getfree(struct adapter *adapter);
+static int slic_rcvqueue_init(struct adapter *adapter);
+static int slic_rcvqueue_reset(struct adapter *adapter);
+static int slic_rcvqueue_fill(struct adapter *adapter);
+static u32 slic_rcvqueue_reinsert(struct adapter *adapter, struct sk_buff *skb);
+static void slic_rcvqueue_free(struct adapter *adapter);
+static void slic_rcv_handle_error(struct adapter *adapter,
+ struct slic_rcvbuf *rcvbuf);
+static void slic_adapter_set_hwaddr(struct adapter *adapter);
+static void slic_card_halt(struct sliccard *card, struct adapter *adapter);
+static int slic_card_init(struct sliccard *card, struct adapter *adapter);
+static void slic_intagg_set(struct adapter *adapter, u32 value);
+static int slic_card_download(struct adapter *adapter);
+static u32 slic_card_locate(struct adapter *adapter);
-int slicproc_card_read(char *page, char **start, off_t off, int count,
- int *eof, void *data);
-int slicproc_card_write(struct file *file, const char __user *buffer,
- ulong count, void *data);
-void slicproc_card_create(p_sliccard_t card);
-void slicproc_card_destroy(p_sliccard_t card);
-int slicproc_adapter_read(char *page, char **start, off_t off, int count,
- int *eof, void *data);
-int slicproc_adapter_write(struct file *file, const char __user *buffer,
- ulong count, void *data);
-void slicproc_adapter_create(p_adapter_t adapter);
-void slicproc_adapter_destroy(p_adapter_t adapter);
-void slicproc_create(void);
-void slicproc_destroy(void);
-
-void slic_interrupt_process(p_adapter_t adapter, ulong32 isr);
-void slic_rcv_handler(p_adapter_t adapter);
-void slic_upr_handler(p_adapter_t adapter);
-void slic_link_event_handler(p_adapter_t adapter);
-void slic_xmit_complete(p_adapter_t adapter);
-void slic_upr_request_complete(p_adapter_t adapter, ulong32 isr);
-int slic_rspqueue_init(p_adapter_t adapter);
-int slic_rspqueue_reset(p_adapter_t adapter);
-void slic_rspqueue_free(p_adapter_t adapter);
-p_slic_rspbuf_t slic_rspqueue_getnext(p_adapter_t adapter);
-void slic_cmdqmem_init(p_adapter_t adapter);
-void slic_cmdqmem_free(p_adapter_t adapter);
-pulong32 slic_cmdqmem_addpage(p_adapter_t adapter);
-int slic_cmdq_init(p_adapter_t adapter);
-void slic_cmdq_free(p_adapter_t adapter);
-void slic_cmdq_reset(p_adapter_t adapter);
-void slic_cmdq_addcmdpage(p_adapter_t adapter, pulong32 page);
-void slic_cmdq_getdone(p_adapter_t adapter);
-void slic_cmdq_putdone(p_adapter_t adapter, p_slic_hostcmd_t cmd);
-void slic_cmdq_putdone_irq(p_adapter_t adapter, p_slic_hostcmd_t cmd);
-p_slic_hostcmd_t slic_cmdq_getfree(p_adapter_t adapter);
-int slic_rcvqueue_init(p_adapter_t adapter);
-int slic_rcvqueue_reset(p_adapter_t adapter);
-int slic_rcvqueue_fill(p_adapter_t adapter);
-ulong32 slic_rcvqueue_reinsert(p_adapter_t adapter, struct sk_buff *skb);
-void slic_rcvqueue_free(p_adapter_t adapter);
-void slic_rcv_handle_error(p_adapter_t adapter, p_slic_rcvbuf_t rcvbuf);
-void slic_adapter_set_hwaddr(p_adapter_t adapter);
-void slic_card_halt(p_sliccard_t card, p_adapter_t adapter);
-int slic_card_init(p_sliccard_t card, p_adapter_t adapter);
-void slic_intagg_set(p_adapter_t adapter, ulong32 value);
-int slic_card_download(p_adapter_t adapter);
-ulong32 slic_card_locate(p_adapter_t adapter);
-int slic_card_removeadapter(p_adapter_t adapter);
-void slic_card_remaster(p_adapter_t adapter);
-void slic_card_softreset(p_adapter_t adapter);
-void slic_card_up(p_adapter_t adapter);
-void slic_card_down(p_adapter_t adapter);
-
-void slic_if_stop_queue(p_adapter_t adapter);
-void slic_if_start_queue(p_adapter_t adapter);
-int slic_if_init(p_adapter_t adapter);
-void slic_adapter_close(p_adapter_t adapter);
-int slic_adapter_allocresources(p_adapter_t adapter);
-void slic_adapter_freeresources(p_adapter_t adapter);
-void slic_link_config(p_adapter_t adapter, ulong32 linkspeed,
- ulong32 linkduplex);
-void slic_unmap_mmio_space(p_adapter_t adapter);
-void slic_card_cleanup(p_sliccard_t card);
-void slic_init_cleanup(p_adapter_t adapter);
-void slic_card_reclaim_buffers(p_adapter_t adapter);
-void slic_soft_reset(p_adapter_t adapter);
-void slic_card_reset(p_adapter_t adapter);
-boolean slic_mac_filter(p_adapter_t adapter, p_ether_header ether_frame);
-void slic_mac_address_config(p_adapter_t adapter);
-void slic_mac_config(p_adapter_t adapter);
-void slic_mcast_set_mask(p_adapter_t adapter);
-void slic_mac_setmcastaddrs(p_adapter_t adapter);
-int slic_mcast_add_list(p_adapter_t adapter, pchar address);
-uchar slic_mcast_get_mac_hash(pchar macaddr);
-void slic_mcast_set_bit(p_adapter_t adapter, pchar address);
-void slic_config_set(p_adapter_t adapter, boolean linkchange);
-void slic_config_clear(p_adapter_t adapter);
-void slic_config_get(p_adapter_t adapter, ulong32 config, ulong32 configh);
-void slic_timer_get_stats(ulong device);
-void slic_timer_load_check(ulong context);
-void slic_timer_ping(ulong dev);
-void slic_stall_msec(int stall);
-void slic_stall_usec(int stall);
-void slic_assert_fail(void);
-ushort slic_eeprom_cksum(pchar m, int len);
+static void slic_if_stop_queue(struct adapter *adapter);
+static void slic_if_start_queue(struct adapter *adapter);
+static int slic_if_init(struct adapter *adapter);
+static int slic_adapter_allocresources(struct adapter *adapter);
+static void slic_adapter_freeresources(struct adapter *adapter);
+static void slic_link_config(struct adapter *adapter, u32 linkspeed,
+ u32 linkduplex);
+static void slic_unmap_mmio_space(struct adapter *adapter);
+static void slic_card_cleanup(struct sliccard *card);
+static void slic_init_cleanup(struct adapter *adapter);
+static void slic_soft_reset(struct adapter *adapter);
+static void slic_card_reset(struct adapter *adapter);
+static bool slic_mac_filter(struct adapter *adapter,
+ struct ether_header *ether_frame);
+static void slic_mac_address_config(struct adapter *adapter);
+static void slic_mac_config(struct adapter *adapter);
+static void slic_mcast_set_mask(struct adapter *adapter);
+static int slic_mcast_add_list(struct adapter *adapter, char *address);
+static unsigned char slic_mcast_get_mac_hash(char *macaddr);
+static void slic_mcast_set_bit(struct adapter *adapter, char *address);
+static void slic_config_set(struct adapter *adapter, bool linkchange);
+static void slic_config_clear(struct adapter *adapter);
+static void slic_config_get(struct adapter *adapter, u32 config,
+ u32 configh);
+static void slic_timer_get_stats(ulong device);
+static void slic_timer_load_check(ulong context);
+static void slic_timer_ping(ulong dev);
+static void slic_assert_fail(void);
+static ushort slic_eeprom_cksum(char *m, int len);
/* upr */
-void slic_upr_start(p_adapter_t adapter);
-void slic_link_upr_complete(p_adapter_t adapter, ulong32 Isr);
-int slic_upr_request(p_adapter_t adapter,
- ulong32 upr_request,
- ulong32 upr_data,
- ulong32 upr_data_h,
- ulong32 upr_buffer,
- ulong32 upr_buffer_h);
-int slic_upr_queue_request(p_adapter_t adapter,
- ulong32 upr_request,
- ulong32 upr_data,
- ulong32 upr_data_h,
- ulong32 upr_buffer,
- ulong32 upr_buffer_h);
-void slic_mcast_set_list(struct net_device *dev);
-void slic_mcast_init_crc32(void);
+static void slic_upr_start(struct adapter *adapter);
+static void slic_link_upr_complete(struct adapter *adapter, u32 Isr);
+static int slic_upr_request(struct adapter *adapter,
+ u32 upr_request,
+ u32 upr_data,
+ u32 upr_data_h,
+ u32 upr_buffer,
+ u32 upr_buffer_h);
+static int slic_upr_queue_request(struct adapter *adapter,
+ u32 upr_request,
+ u32 upr_data,
+ u32 upr_data_h,
+ u32 upr_buffer,
+ u32 upr_buffer_h);
+static void slic_mcast_set_list(struct net_device *dev);
+static void slic_mcast_init_crc32(void);
#if SLIC_DUMP_ENABLED
-int slic_dump_thread(void *context);
-uint slic_init_dump_thread(p_sliccard_t card);
-uchar slic_get_dump_index(pchar path);
-ulong32 slic_dump_card(p_sliccard_t card, boolean resume);
-ulong32 slic_dump_halt(p_sliccard_t card, uchar proc);
-ulong32 slic_dump_reg(p_sliccard_t card, uchar proc);
-ulong32 slic_dump_data(p_sliccard_t card, ulong32 addr,
- ushort count, uchar desc);
-ulong32 slic_dump_queue(p_sliccard_t card, ulong32 buf_phys,
- ulong32 buf_physh, ulong32 queue);
-ulong32 slic_dump_load_queue(p_sliccard_t card, ulong32 data, ulong32 queue);
-ulong32 slic_dump_cam(p_sliccard_t card, ulong32 addr,
- ulong32 count, uchar desc);
+static int slic_dump_thread(void *context);
+static uint slic_init_dump_thread(struct sliccard *card);
+static unsigned char slic_get_dump_index(char *path);
+static u32 slic_dump_card(struct sliccard *card, bool resume);
+static u32 slic_dump_halt(struct sliccard *card, unsigned char proc);
+static u32 slic_dump_reg(struct sliccard *card, unsigned char proc);
+static u32 slic_dump_data(struct sliccard *card, u32 addr,
+ ushort count, unsigned char desc);
+static u32 slic_dump_queue(struct sliccard *card, u32 buf_phys,
+ u32 buf_physh, u32 queue);
+static u32 slic_dump_load_queue(struct sliccard *card, u32 data,
+ u32 queue);
+static u32 slic_dump_cam(struct sliccard *card, u32 addr,
+ u32 count, unsigned char desc);
-ulong32 slic_dump_resume(p_sliccard_t card, uchar proc);
-ulong32 slic_dump_send_cmd(p_sliccard_t card, ulong32 cmd_phys,
- ulong32 cmd_physh, ulong32 buf_phys,
- ulong32 buf_physh);
+static u32 slic_dump_resume(struct sliccard *card, unsigned char proc);
+static u32 slic_dump_send_cmd(struct sliccard *card, u32 cmd_phys,
+ u32 cmd_physh, u32 buf_phys,
+ u32 buf_physh);
#define create_file(x) STATUS_SUCCESS
#define write_file(w, x, y, z) STATUS_SUCCESS
diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c
index a8c2648..eb61565 100644
--- a/drivers/staging/slicoss/slicoss.c
+++ b/drivers/staging/slicoss/slicoss.c
@@ -143,7 +143,7 @@ static int slic_debug = 1;
static int debug = -1;
static struct net_device *head_netdevice;
-base_driver_t slic_global = { {}, 0, 0, 0, 1, NULL, NULL };
+static struct base_driver slic_global = { {}, 0, 0, 0, 1, NULL, NULL };
static int intagg_delay = 100;
static u32 dynamic_intagg;
static int errormsg;
@@ -183,44 +183,49 @@ MODULE_DEVICE_TABLE(pci, slic_pci_tbl);
#define SLIC_GET_SLIC_HANDLE(_adapter, _pslic_handle) \
{ \
- SLIC_ACQUIRE_IRQ_SPINLOCK(_adapter->handle_lock); \
+ spin_lock_irqsave(&_adapter->handle_lock.lock, \
+ _adapter->handle_lock.flags); \
_pslic_handle = _adapter->pfree_slic_handles; \
if (_pslic_handle) { \
ASSERT(_pslic_handle->type == SLIC_HANDLE_FREE); \
_adapter->pfree_slic_handles = _pslic_handle->next; \
} \
- SLIC_RELEASE_IRQ_SPINLOCK(_adapter->handle_lock); \
+ spin_unlock_irqrestore(&_adapter->handle_lock.lock, \
+ _adapter->handle_lock.flags); \
}
#define SLIC_FREE_SLIC_HANDLE(_adapter, _pslic_handle) \
{ \
_pslic_handle->type = SLIC_HANDLE_FREE; \
- SLIC_ACQUIRE_IRQ_SPINLOCK(_adapter->handle_lock); \
+ spin_lock_irqsave(&_adapter->handle_lock.lock, \
+ _adapter->handle_lock.flags); \
_pslic_handle->next = _adapter->pfree_slic_handles; \
_adapter->pfree_slic_handles = _pslic_handle; \
- SLIC_RELEASE_IRQ_SPINLOCK(_adapter->handle_lock); \
+ spin_unlock_irqrestore(&_adapter->handle_lock.lock, \
+ _adapter->handle_lock.flags); \
}
static void slic_debug_init(void);
static void slic_debug_cleanup(void);
-static void slic_debug_adapter_create(p_adapter_t adapter);
-static void slic_debug_adapter_destroy(p_adapter_t adapter);
-static void slic_debug_card_create(p_sliccard_t card);
-static void slic_debug_card_destroy(p_sliccard_t card);
+static void slic_debug_adapter_create(struct adapter *adapter);
+static void slic_debug_adapter_destroy(struct adapter *adapter);
+static void slic_debug_card_create(struct sliccard *card);
+static void slic_debug_card_destroy(struct sliccard *card);
-inline void slic_reg32_write(void __iomem *reg, ulong32 value, uint flush)
+static inline void slic_reg32_write(void __iomem *reg, u32 value, uint flush)
{
writel(value, reg);
if (flush)
mb();
}
-inline void slic_reg64_write(p_adapter_t adapter,
+static inline void slic_reg64_write(struct adapter *adapter,
void __iomem *reg,
- ulong32 value,
- void __iomem *regh, ulong32 paddrh, uint flush)
+ u32 value,
+ void __iomem *regh, u32 paddrh, uint flush)
{
- SLIC_ACQUIRE_IRQ_SPINLOCK(adapter->bit64reglock);
+ spin_lock_irqsave(&adapter->bit64reglock.lock,
+ adapter->bit64reglock.flags);
if (paddrh != adapter->curaddrupper) {
adapter->curaddrupper = paddrh;
writel(paddrh, regh);
@@ -228,31 +233,22 @@ inline void slic_reg64_write(p_adapter_t adapter,
writel(value, reg);
if (flush)
mb();
- SLIC_RELEASE_IRQ_SPINLOCK(adapter->bit64reglock);
+ spin_unlock_irqrestore(&adapter->bit64reglock.lock,
+ adapter->bit64reglock.flags);
}
-inline ulong32 slic_reg32_read(u32 __iomem *reg, uint flush)
-{
- return readl(reg);
-}
-
-inline ulong32 slic_reg16_read(pulong32 reg, uint flush)
-{
- return (ushort) readw(reg);
-}
-
-void slic_init_driver(void)
+static void slic_init_driver(void)
{
if (slic_first_init) {
DBG_MSG("slicoss: %s slic_first_init set jiffies[%lx]\n",
__func__, jiffies);
slic_first_init = 0;
- SLIC_INIT_SPINLOCK(slic_global.driver_lock);
+ spin_lock_init(&slic_global.driver_lock.lock);
slic_debug_init();
}
}
-static void slic_dbg_macaddrs(p_adapter_t adapter)
+static void slic_dbg_macaddrs(struct adapter *adapter)
{
DBG_MSG(" (%s) curr %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
adapter->netdev->name, adapter->currmacaddr[0],
@@ -267,7 +263,8 @@ static void slic_dbg_macaddrs(p_adapter_t adapter)
}
#ifdef DEBUG_REGISTER_TRACE
-static void slic_dbg_register_trace(p_adapter_t adapter, p_sliccard_t card)
+static void slic_dbg_register_trace(struct adapter *adapter,
+ struct sliccard *card)
{
uint i;
@@ -287,9 +284,8 @@ static void slic_init_adapter(struct net_device *netdev,
void __iomem *memaddr, int chip_idx)
{
ushort index;
- pslic_handle_t pslic_handle;
- p_adapter_t adapter = (p_adapter_t) netdev_priv(netdev);
-
+ struct slic_handle *pslic_handle;
+ struct adapter *adapter = (struct adapter *)netdev_priv(netdev);
/*
DBG_MSG("slicoss: %s (%s)\n netdev [%p]\n adapter[%p]\n "
"pcidev [%p]\n", __func__, netdev->name, netdev, adapter, pcidev);*/
@@ -301,7 +297,7 @@ static void slic_init_adapter(struct net_device *netdev,
adapter->slotnumber = ((pcidev->devfn >> 3) & 0x1F);
adapter->functionnumber = (pcidev->devfn & 0x7);
adapter->memorylength = pci_resource_len(pcidev, 0);
- adapter->slic_regs = (p_slic_regs_t) memaddr;
+ adapter->slic_regs = (__iomem struct slic_regs *)memaddr;
adapter->irq = pcidev->irq;
/* adapter->netdev = netdev;*/
adapter->next_netdevice = head_netdevice;
@@ -310,11 +306,11 @@ static void slic_init_adapter(struct net_device *netdev,
adapter->port = 0; /*adapter->functionnumber;*/
adapter->cardindex = adapter->port;
adapter->memorybase = memaddr;
- SLIC_INIT_SPINLOCK(adapter->upr_lock);
- SLIC_INIT_SPINLOCK(adapter->bit64reglock);
- SLIC_INIT_SPINLOCK(adapter->adapter_lock);
- SLIC_INIT_SPINLOCK(adapter->reset_lock);
- SLIC_INIT_SPINLOCK(adapter->handle_lock);
+ spin_lock_init(&adapter->upr_lock.lock);
+ spin_lock_init(&adapter->bit64reglock.lock);
+ spin_lock_init(&adapter->adapter_lock.lock);
+ spin_lock_init(&adapter->reset_lock.lock);
+ spin_lock_init(&adapter->handle_lock.lock);
adapter->card_size = 1;
/*
@@ -335,36 +331,36 @@ static void slic_init_adapter(struct net_device *netdev,
/*
DBG_MSG(".........\nix[%d] phandle[%p] pfree[%p] next[%p]\n",
index, pslic_handle, adapter->pfree_slic_handles, pslic_handle->next);*/
- adapter->pshmem = (p_slic_shmem_t) pci_alloc_consistent(adapter->pcidev,
- sizeof
- (slic_shmem_t),
- &adapter->
- phys_shmem);
+ adapter->pshmem = (struct slic_shmem *)
+ pci_alloc_consistent(adapter->pcidev,
+ sizeof(struct slic_shmem *),
+ &adapter->
+ phys_shmem);
/*
DBG_MSG("slicoss: %s (%s)\n pshmem [%p]\n phys_shmem[%p]\n"\
"slic_regs [%p]\n", __func__, netdev->name, adapter->pshmem,
- (pvoid)adapter->phys_shmem, adapter->slic_regs);
+ (void *)adapter->phys_shmem, adapter->slic_regs);
*/
ASSERT(adapter->pshmem);
- SLIC_ZERO_MEMORY(adapter->pshmem, sizeof(slic_shmem_t));
+ memset(adapter->pshmem, 0, sizeof(struct slic_shmem));
return;
}
-int __devinit slic_entry_probe(struct pci_dev *pcidev,
+static int __devinit slic_entry_probe(struct pci_dev *pcidev,
const struct pci_device_id *pci_tbl_entry)
{
static int cards_found;
static int did_version;
int err;
struct net_device *netdev;
- p_adapter_t adapter;
+ struct adapter *adapter;
void __iomem *memmapped_ioaddr = NULL;
- ulong32 status = 0;
+ u32 status = 0;
ulong mmio_start = 0;
ulong mmio_len = 0;
- p_sliccard_t card = NULL;
+ struct sliccard *card = NULL;
DBG_MSG("slicoss: %s 2.6 VERSION ENTER jiffies[%lx] cpu %d\n",
__func__, jiffies, smp_processor_id());
@@ -408,7 +404,7 @@ int __devinit slic_entry_probe(struct pci_dev *pcidev,
pci_set_master(pcidev);
DBG_MSG("call alloc_etherdev\n");
- netdev = alloc_etherdev(sizeof(adapter_t));
+ netdev = alloc_etherdev(sizeof(struct adapter));
if (!netdev) {
err = -ENOMEM;
goto err_out_exit_slic_probe;
@@ -428,7 +424,7 @@ int __devinit slic_entry_probe(struct pci_dev *pcidev,
DBG_MSG("slicoss: call ioremap(mmio_start[%lx], mmio_len[%lx])\n",
mmio_start, mmio_len);
-/* memmapped_ioaddr = (ulong32)ioremap_nocache(mmio_start, mmio_len);*/
+/* memmapped_ioaddr = (u32)ioremap_nocache(mmio_start, mmio_len);*/
memmapped_ioaddr = ioremap(mmio_start, mmio_len);
DBG_MSG("slicoss: %s MEMMAPPED_IOADDR [%p]\n", __func__,
memmapped_ioaddr);
@@ -530,11 +526,11 @@ err_out_exit_slic_probe:
return -ENODEV;
}
-int slic_entry_open(struct net_device *dev)
+static int slic_entry_open(struct net_device *dev)
{
- p_adapter_t adapter = (p_adapter_t) netdev_priv(dev);
- p_sliccard_t card = adapter->card;
- ulong32 locked = 0;
+ struct adapter *adapter = (struct adapter *) netdev_priv(dev);
+ struct sliccard *card = adapter->card;
+ u32 locked = 0;
int status;
ASSERT(adapter);
@@ -552,7 +548,8 @@ int slic_entry_open(struct net_device *dev)
netif_stop_queue(adapter->netdev);
- SLIC_ACQUIRE_IRQ_SPINLOCK(slic_global.driver_lock);
+ spin_lock_irqsave(&slic_global.driver_lock.lock,
+ slic_global.driver_lock.flags);
locked = 1;
if (!adapter->activated) {
card->adapters_activated++;
@@ -568,7 +565,8 @@ int slic_entry_open(struct net_device *dev)
adapter->activated = 0;
}
if (locked) {
- SLIC_RELEASE_IRQ_SPINLOCK(slic_global.driver_lock);
+ spin_unlock_irqrestore(&slic_global.driver_lock.lock,
+ slic_global.driver_lock.flags);
locked = 0;
}
return status;
@@ -583,7 +581,8 @@ int slic_entry_open(struct net_device *dev)
#endif
if (locked) {
- SLIC_RELEASE_IRQ_SPINLOCK(slic_global.driver_lock);
+ spin_unlock_irqrestore(&slic_global.driver_lock.lock,
+ slic_global.driver_lock.flags);
locked = 0;
}
#if SLIC_DUMP_ENABLED
@@ -599,13 +598,13 @@ int slic_entry_open(struct net_device *dev)
return STATUS_SUCCESS;
}
-void __devexit slic_entry_remove(struct pci_dev *pcidev)
+static void __devexit slic_entry_remove(struct pci_dev *pcidev)
{
struct net_device *dev = pci_get_drvdata(pcidev);
- ulong32 mmio_start = 0;
+ u32 mmio_start = 0;
uint mmio_len = 0;
- p_adapter_t adapter = (p_adapter_t) netdev_priv(dev);
- p_sliccard_t card;
+ struct adapter *adapter = (struct adapter *) netdev_priv(dev);
+ struct sliccard *card;
ASSERT(adapter);
DBG_MSG("slicoss: %s ENTER dev[%p] adapter[%p]\n", __func__, dev,
@@ -635,7 +634,7 @@ void __devexit slic_entry_remove(struct pci_dev *pcidev)
__func__, card->adapters_activated, card->adapters_allocated,
card, adapter);
if (!card->adapters_allocated) {
- p_sliccard_t curr_card = slic_global.slic_card;
+ struct sliccard *curr_card = slic_global.slic_card;
if (curr_card == card) {
slic_global.slic_card = card->next;
} else {
@@ -649,17 +648,18 @@ void __devexit slic_entry_remove(struct pci_dev *pcidev)
slic_card_cleanup(card);
}
DBG_MSG("slicoss: %s deallocate device\n", __func__);
- SLIC_DEALLOCATE_MEM(dev);
+ kfree(dev);
DBG_MSG("slicoss: %s EXIT\n", __func__);
}
-int slic_entry_halt(struct net_device *dev)
+static int slic_entry_halt(struct net_device *dev)
{
- p_adapter_t adapter = (p_adapter_t) netdev_priv(dev);
- p_sliccard_t card = adapter->card;
- p_slic_regs_t slic_regs = adapter->slic_regs;
+ struct adapter *adapter = (struct adapter *)netdev_priv(dev);
+ struct sliccard *card = adapter->card;
+ __iomem struct slic_regs *slic_regs = adapter->slic_regs;
- SLIC_ACQUIRE_IRQ_SPINLOCK(slic_global.driver_lock);
+ spin_lock_irqsave(&slic_global.driver_lock.lock,
+ slic_global.driver_lock.flags);
ASSERT(card);
DBG_MSG("slicoss: %s (%s) ENTER\n", __func__, dev->name);
DBG_MSG("slicoss: %s (%s) actvtd[%d] alloc[%d] state[%x] adapt[%p]\n",
@@ -730,11 +730,12 @@ int slic_entry_halt(struct net_device *dev)
DBG_MSG("slicoss: %s (%s) EXIT\n", __func__, dev->name);
DBG_MSG("slicoss: %s EXIT\n", __func__);
- SLIC_RELEASE_IRQ_SPINLOCK(slic_global.driver_lock);
+ spin_unlock_irqrestore(&slic_global.driver_lock.lock,
+ slic_global.driver_lock.flags);
return STATUS_SUCCESS;
}
-int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
ASSERT(rq);
/*
@@ -743,9 +744,10 @@ int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
switch (cmd) {
case SIOCSLICSETINTAGG:
{
- p_adapter_t adapter = (p_adapter_t) netdev_priv(dev);
- ulong32 data[7];
- ulong32 intagg;
+ struct adapter *adapter = (struct adapter *)
+ netdev_priv(dev);
+ u32 data[7];
+ u32 intagg;
if (copy_from_user(data, rq->ifr_data, 28)) {
DBG_ERROR
@@ -763,8 +765,9 @@ int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
#ifdef SLIC_USER_REQUEST_DUMP_ENABLED
case SIOCSLICDUMPCARD:
{
- p_adapter_t adapter = (p_adapter_t) dev->priv;
- p_sliccard_t card;
+ struct adapter *adapter = (struct adapter *)
+ dev->priv;
+ struct sliccard *card;
ASSERT(adapter);
ASSERT(adapter->card)
@@ -833,7 +836,8 @@ int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
#if SLIC_ETHTOOL_SUPPORT
case SIOCETHTOOL:
{
- p_adapter_t adapter = (p_adapter_t) netdev_priv(dev);
+ struct adapter *adapter = (struct adapter *)
+ netdev_priv(dev);
struct ethtool_cmd data;
struct ethtool_cmd ecmd;
@@ -892,8 +896,8 @@ int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
data.maxrxpkt = 1;
if ((ecmd.speed != data.speed) ||
(ecmd.duplex != data.duplex)) {
- ulong32 speed;
- ulong32 duplex;
+ u32 speed;
+ u32 duplex;
if (ecmd.speed == SPEED_10) {
speed = 0;
@@ -935,10 +939,10 @@ int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
#define XMIT_FAIL_ZERO_LENGTH 2
#define XMIT_FAIL_HOSTCMD_FAIL 3
-static void slic_xmit_build_request(p_adapter_t adapter,
- p_slic_hostcmd_t hcmd, struct sk_buff *skb)
+static void slic_xmit_build_request(struct adapter *adapter,
+ struct slic_hostcmd *hcmd, struct sk_buff *skb)
{
- p_slic_host64_cmd_t ihcmd;
+ struct slic_host64_cmd *ihcmd;
ulong phys_addr;
ihcmd = &hcmd->cmd64;
@@ -946,16 +950,17 @@ static void slic_xmit_build_request(p_adapter_t adapter,
ihcmd->flags = (adapter->port << IHFLG_IFSHFT);
ihcmd->command = IHCMD_XMT_REQ;
ihcmd->u.slic_buffers.totlen = skb->len;
- phys_addr = SLIC_GET_DMA_ADDRESS_WRITE(adapter, skb->data, skb->len);
+ phys_addr = pci_map_single(adapter->pcidev, skb->data, skb->len,
+ PCI_DMA_TODEVICE);
ihcmd->u.slic_buffers.bufs[0].paddrl = SLIC_GET_ADDR_LOW(phys_addr);
ihcmd->u.slic_buffers.bufs[0].paddrh = SLIC_GET_ADDR_HIGH(phys_addr);
ihcmd->u.slic_buffers.bufs[0].length = skb->len;
#if defined(CONFIG_X86_64)
- hcmd->cmdsize = (ulong32) ((((ulong64)&ihcmd->u.slic_buffers.bufs[1] -
- (ulong64) hcmd) + 31) >> 5);
+ hcmd->cmdsize = (u32) ((((u64)&ihcmd->u.slic_buffers.bufs[1] -
+ (u64) hcmd) + 31) >> 5);
#elif defined(CONFIG_X86)
- hcmd->cmdsize = ((((ulong32) &ihcmd->u.slic_buffers.bufs[1] -
- (ulong32) hcmd) + 31) >> 5);
+ hcmd->cmdsize = ((((u32) &ihcmd->u.slic_buffers.bufs[1] -
+ (u32) hcmd) + 31) >> 5);
#else
Stop Compilation;
#endif
@@ -963,14 +968,14 @@ static void slic_xmit_build_request(p_adapter_t adapter,
#define NORMAL_ETHFRAME 0
-int slic_xmit_start(struct sk_buff *skb, struct net_device *dev)
+static int slic_xmit_start(struct sk_buff *skb, struct net_device *dev)
{
- p_sliccard_t card;
- p_adapter_t adapter = (p_adapter_t) netdev_priv(dev);
- p_slic_hostcmd_t hcmd = NULL;
- ulong32 status = 0;
- ulong32 skbtype = NORMAL_ETHFRAME;
- pvoid offloadcmd = NULL;
+ struct sliccard *card;
+ struct adapter *adapter = (struct adapter *)netdev_priv(dev);
+ struct slic_hostcmd *hcmd = NULL;
+ u32 status = 0;
+ u32 skbtype = NORMAL_ETHFRAME;
+ void *offloadcmd = NULL;
card = adapter->card;
ASSERT(card);
@@ -1035,9 +1040,9 @@ xmit_fail:
goto xmit_done;
}
-void slic_xmit_fail(p_adapter_t adapter,
+static void slic_xmit_fail(struct adapter *adapter,
struct sk_buff *skb,
- pvoid cmd, ulong32 skbtype, ulong32 status)
+ void *cmd, u32 skbtype, u32 status)
{
if (adapter->xmitq_full)
slic_if_stop_queue(adapter);
@@ -1072,31 +1077,10 @@ void slic_xmit_fail(p_adapter_t adapter,
adapter->stats.tx_dropped++;
}
-void slic_xmit_timeout(struct net_device *dev)
-{
- p_sliccard_t card;
- p_adapter_t adapter = (p_adapter_t) netdev_priv(dev);
- ulong32 i;
-
- ASSERT(adapter);
- card = adapter->card;
- ASSERT(card);
- for (i = 0; i < card->card_size; i++) {
- if (card->adapter[i])
- slic_if_stop_queue(card->adapter[i]);
- }
- if (!card->reset_in_progress) {
- DBG_ERROR
- ("%s card[%p] state[%x] adapter[%p] port[%d] state[%x]\n",
- __func__, card, card->state, adapter, adapter->port,
- adapter->state);
- slic_card_reset(adapter);
- }
-}
-
-void slic_rcv_handle_error(p_adapter_t adapter, p_slic_rcvbuf_t rcvbuf)
+static void slic_rcv_handle_error(struct adapter *adapter,
+ struct slic_rcvbuf *rcvbuf)
{
- p_slic_hddr_wds hdr = (p_slic_hddr_wds) rcvbuf->data;
+ struct slic_hddr_wds *hdr = (struct slic_hddr_wds *)rcvbuf->data;
if (adapter->devid != SLIC_1GB_DEVICE_ID) {
if (hdr->frame_status14 & VRHSTAT_802OE)
@@ -1141,7 +1125,7 @@ void slic_rcv_handle_error(p_adapter_t adapter, p_slic_rcvbuf_t rcvbuf)
adapter->if_events.IpHlen++;
} else {
if (hdr->frame_statusGB & VGBSTAT_XPERR) {
- ulong32 xerr = hdr->frame_statusGB >> VGBSTAT_XERRSHFT;
+ u32 xerr = hdr->frame_statusGB >> VGBSTAT_XERRSHFT;
if (xerr == VGBSTAT_XCSERR)
adapter->if_events.TpCsum++;
@@ -1151,7 +1135,7 @@ void slic_rcv_handle_error(p_adapter_t adapter, p_slic_rcvbuf_t rcvbuf)
adapter->if_events.TpHlen++;
}
if (hdr->frame_statusGB & VGBSTAT_NETERR) {
- ulong32 nerr =
+ u32 nerr =
(hdr->
frame_statusGB >> VGBSTAT_NERRSHFT) &
VGBSTAT_NERRMSK;
@@ -1163,7 +1147,7 @@ void slic_rcv_handle_error(p_adapter_t adapter, p_slic_rcvbuf_t rcvbuf)
adapter->if_events.IpHlen++;
}
if (hdr->frame_statusGB & VGBSTAT_LNKERR) {
- ulong32 lerr = hdr->frame_statusGB & VGBSTAT_LERRMSK;
+ u32 lerr = hdr->frame_statusGB & VGBSTAT_LERRMSK;
if (lerr == VGBSTAT_LDEARLY)
adapter->if_events.rcvearly++;
@@ -1187,17 +1171,17 @@ void slic_rcv_handle_error(p_adapter_t adapter, p_slic_rcvbuf_t rcvbuf)
#define TCP_OFFLOAD_FRAME_PUSHFLAG 0x10000000
#define M_FAST_PATH 0x0040
-void slic_rcv_handler(p_adapter_t adapter)
+static void slic_rcv_handler(struct adapter *adapter)
{
struct sk_buff *skb;
- p_slic_rcvbuf_t rcvbuf;
- ulong32 frames = 0;
+ struct slic_rcvbuf *rcvbuf;
+ u32 frames = 0;
while ((skb = slic_rcvqueue_getnext(adapter))) {
- ulong32 rx_bytes;
+ u32 rx_bytes;
ASSERT(skb->head);
- rcvbuf = (p_slic_rcvbuf_t) skb->head;
+ rcvbuf = (struct slic_rcvbuf *)skb->head;
adapter->card->events++;
if (rcvbuf->status & IRHDDR_ERR) {
adapter->rx_errors++;
@@ -1206,7 +1190,8 @@ void slic_rcv_handler(p_adapter_t adapter)
continue;
}
- if (!slic_mac_filter(adapter, (p_ether_header) rcvbuf->data)) {
+ if (!slic_mac_filter(adapter, (struct ether_header *)
+ rcvbuf->data)) {
#if 0
DBG_MSG
("slicoss: %s (%s) drop frame due to mac filter\n",
@@ -1239,12 +1224,12 @@ void slic_rcv_handler(p_adapter_t adapter)
adapter->max_isr_rcvs = max(adapter->max_isr_rcvs, frames);
}
-void slic_xmit_complete(p_adapter_t adapter)
+static void slic_xmit_complete(struct adapter *adapter)
{
- p_slic_hostcmd_t hcmd;
- p_slic_rspbuf_t rspbuf;
- ulong32 frames = 0;
- slic_handle_word_t slic_handle_word;
+ struct slic_hostcmd *hcmd;
+ struct slic_rspbuf *rspbuf;
+ u32 frames = 0;
+ struct slic_handle_word slic_handle_word;
do {
rspbuf = slic_rspqueue_getnext(adapter);
@@ -1259,10 +1244,10 @@ void slic_xmit_complete(p_adapter_t adapter)
ASSERT(slic_handle_word.handle_index);
ASSERT(slic_handle_word.handle_index <= SLIC_CMDQ_MAXCMDS);
hcmd =
- (p_slic_hostcmd_t) adapter->slic_handles[slic_handle_word.
- handle_index].
- address;
-/* hcmd = (p_slic_hostcmd_t) rspbuf->hosthandle; */
+ (struct slic_hostcmd *)
+ adapter->slic_handles[slic_handle_word.handle_index].
+ address;
+/* hcmd = (struct slic_hostcmd *) rspbuf->hosthandle; */
ASSERT(hcmd);
ASSERT(hcmd->pslic_handle ==
&adapter->slic_handles[slic_handle_word.handle_index]);
@@ -1286,9 +1271,9 @@ void slic_xmit_complete(p_adapter_t adapter)
static irqreturn_t slic_interrupt(int irq, void *dev_id)
{
- struct net_device *dev = (struct net_device *) dev_id;
- p_adapter_t adapter = (p_adapter_t) netdev_priv(dev);
- ulong32 isr;
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct adapter *adapter = (struct adapter *)netdev_priv(dev);
+ u32 isr;
if ((adapter->pshmem) && (adapter->pshmem->isr)) {
WRITE_REG(adapter->slic_regs->slic_icr, ICR_INT_MASK, FLUSH);
@@ -1305,7 +1290,7 @@ static irqreturn_t slic_interrupt(int irq, void *dev_id)
int pre_count;
int errors;
- p_slic_rcvqueue_t rcvq =
+ struct slic_rcvqueue *rcvq =
&adapter->rcvqueue;
adapter->
@@ -1400,17 +1385,17 @@ static irqreturn_t slic_interrupt(int irq, void *dev_id)
* will also complete asynchronously.
*
*/
-void slic_link_event_handler(p_adapter_t adapter)
+static void slic_link_event_handler(struct adapter *adapter)
{
int status;
- p_slic_shmem_t pshmem;
+ struct slic_shmem *pshmem;
if (adapter->state != ADAPT_UP) {
/* Adapter is not operational. Ignore. */
return;
}
- pshmem = (p_slic_shmem_t) adapter->phys_shmem;
+ pshmem = (struct slic_shmem *)adapter->phys_shmem;
#if defined(CONFIG_X86_64)
/*
@@ -1425,7 +1410,7 @@ void slic_link_event_handler(p_adapter_t adapter)
0, 0);
#elif defined(CONFIG_X86)
status = slic_upr_request(adapter, SLIC_UPR_RLSR,
- (ulong32) &pshmem->linkstatus, /* no 4GB wrap guaranteed */
+ (u32) &pshmem->linkstatus, /* no 4GB wrap guaranteed */
0, 0, 0);
#else
Stop compilation;
@@ -1433,7 +1418,7 @@ void slic_link_event_handler(p_adapter_t adapter)
ASSERT((status == STATUS_SUCCESS) || (status == STATUS_PENDING));
}
-void slic_init_cleanup(p_adapter_t adapter)
+static void slic_init_cleanup(struct adapter *adapter)
{
DBG_MSG("slicoss: %s ENTER adapter[%p] ", __func__, adapter);
if (adapter->intrregistered) {
@@ -1445,9 +1430,9 @@ void slic_init_cleanup(p_adapter_t adapter)
if (adapter->pshmem) {
DBG_MSG("FREE_SHMEM ");
DBG_MSG("adapter[%p] port %d pshmem[%p] FreeShmem ",
- adapter, adapter->port, (pvoid) adapter->pshmem);
+ adapter, adapter->port, (void *) adapter->pshmem);
pci_free_consistent(adapter->pcidev,
- sizeof(slic_shmem_t),
+ sizeof(struct slic_shmem *),
adapter->pshmem, adapter->phys_shmem);
adapter->pshmem = NULL;
adapter->phys_shmem = (dma_addr_t) NULL;
@@ -1475,9 +1460,9 @@ void slic_init_cleanup(p_adapter_t adapter)
}
#if SLIC_GET_STATS_ENABLED
-struct net_device_stats *slic_get_stats(struct net_device *dev)
+static struct net_device_stats *slic_get_stats(struct net_device *dev)
{
- p_adapter_t adapter = (p_adapter_t) netdev_priv(dev);
+ struct adapter *adapter = (struct adapter *)netdev_priv(dev);
struct net_device_stats *stats;
ASSERT(adapter);
@@ -1500,10 +1485,10 @@ struct net_device_stats *slic_get_stats(struct net_device *dev)
* Allocate a mcast_address structure to hold the multicast address.
* Link it in.
*/
-int slic_mcast_add_list(p_adapter_t adapter, pchar address)
+static int slic_mcast_add_list(struct adapter *adapter, char *address)
{
- p_mcast_address_t mcaddr, mlist;
- boolean equaladdr;
+ struct mcast_address *mcaddr, *mlist;
+ bool equaladdr;
/* Check to see if it already exists */
mlist = adapter->mcastaddrs;
@@ -1515,7 +1500,7 @@ int slic_mcast_add_list(p_adapter_t adapter, pchar address)
}
/* Doesn't already exist. Allocate a structure to hold it */
- mcaddr = SLIC_ALLOCATE_MEM(sizeof(mcast_address_t), GFP_ATOMIC);
+ mcaddr = kmalloc(sizeof(struct mcast_address), GFP_ATOMIC);
if (mcaddr == NULL)
return 1;
@@ -1545,10 +1530,10 @@ static u32 slic_crc_init; /* Is table initialized */
/*
* Contruct the CRC32 table
*/
-void slic_mcast_init_crc32(void)
+static void slic_mcast_init_crc32(void)
{
- ulong32 c; /* CRC shit reg */
- ulong32 e = 0; /* Poly X-or pattern */
+ u32 c; /* CRC shit reg */
+ u32 e = 0; /* Poly X-or pattern */
int i; /* counter */
int k; /* byte being shifted into crc */
@@ -1568,12 +1553,12 @@ void slic_mcast_init_crc32(void)
/*
* Return the MAC hast as described above.
*/
-uchar slic_mcast_get_mac_hash(pchar macaddr)
+static unsigned char slic_mcast_get_mac_hash(char *macaddr)
{
- ulong32 crc;
- pchar p;
+ u32 crc;
+ char *p;
int i;
- uchar machash = 0;
+ unsigned char machash = 0;
if (!slic_crc_init) {
slic_mcast_init_crc32();
@@ -1591,9 +1576,9 @@ uchar slic_mcast_get_mac_hash(pchar macaddr)
return machash;
}
-void slic_mcast_set_bit(p_adapter_t adapter, pchar address)
+static void slic_mcast_set_bit(struct adapter *adapter, char *address)
{
- uchar crcpoly;
+ unsigned char crcpoly;
/* Get the CRC polynomial for the mac address */
crcpoly = slic_mcast_get_mac_hash(address);
@@ -1604,22 +1589,22 @@ void slic_mcast_set_bit(p_adapter_t adapter, pchar address)
crcpoly &= 0x3F;
/* OR in the new bit into our 64 bit mask. */
- adapter->mcastmask |= (ulong64) 1 << crcpoly;
+ adapter->mcastmask |= (u64) 1 << crcpoly;
}
-void slic_mcast_set_list(struct net_device *dev)
+static void slic_mcast_set_list(struct net_device *dev)
{
- p_adapter_t adapter = (p_adapter_t) netdev_priv(dev);
+ struct adapter *adapter = (struct adapter *)netdev_priv(dev);
int status = STATUS_SUCCESS;
int i;
- pchar addresses;
+ char *addresses;
struct dev_mc_list *mc_list = dev->mc_list;
int mc_count = dev->mc_count;
ASSERT(adapter);
for (i = 1; i <= mc_count; i++) {
- addresses = (pchar) &mc_list->dmi_addr;
+ addresses = (char *) &mc_list->dmi_addr;
if (mc_list->dmi_addrlen == 6) {
status = slic_mcast_add_list(adapter, addresses);
if (status != STATUS_SUCCESS)
@@ -1657,9 +1642,9 @@ void slic_mcast_set_list(struct net_device *dev)
return;
}
-void slic_mcast_set_mask(p_adapter_t adapter)
+static void slic_mcast_set_mask(struct adapter *adapter)
{
- p_slic_regs_t slic_regs = adapter->slic_regs;
+ __iomem struct slic_regs *slic_regs = adapter->slic_regs;
DBG_MSG("%s ENTER (%s) macopts[%x] mask[%llx]\n", __func__,
adapter->netdev->name, (uint) adapter->macopts,
@@ -1687,20 +1672,20 @@ void slic_mcast_set_mask(p_adapter_t adapter)
((ulong) ((adapter->mcastmask >> 32) & 0xFFFFFFFF)));
WRITE_REG(slic_regs->slic_mcastlow,
- (ulong32) (adapter->mcastmask & 0xFFFFFFFF), FLUSH);
+ (u32) (adapter->mcastmask & 0xFFFFFFFF), FLUSH);
WRITE_REG(slic_regs->slic_mcasthigh,
- (ulong32) ((adapter->mcastmask >> 32) & 0xFFFFFFFF),
+ (u32) ((adapter->mcastmask >> 32) & 0xFFFFFFFF),
FLUSH);
}
}
-void slic_timer_ping(ulong dev)
+static void slic_timer_ping(ulong dev)
{
- p_adapter_t adapter;
- p_sliccard_t card;
+ struct adapter *adapter;
+ struct sliccard *card;
ASSERT(dev);
- adapter = (p_adapter_t) ((struct net_device *) dev)->priv;
+ adapter = (struct adapter *)((struct net_device *) dev)->priv;
ASSERT(adapter);
card = adapter->card;
ASSERT(card);
@@ -1741,12 +1726,12 @@ void slic_timer_ping(ulong dev)
add_timer(&adapter->pingtimer);
}
-void slic_if_stop_queue(p_adapter_t adapter)
+static void slic_if_stop_queue(struct adapter *adapter)
{
netif_stop_queue(adapter->netdev);
}
-void slic_if_start_queue(p_adapter_t adapter)
+static void slic_if_start_queue(struct adapter *adapter)
{
netif_start_queue(adapter->netdev);
}
@@ -1757,12 +1742,12 @@ void slic_if_start_queue(p_adapter_t adapter)
* Perform initialization of our slic interface.
*
*/
-int slic_if_init(p_adapter_t adapter)
+static int slic_if_init(struct adapter *adapter)
{
- p_sliccard_t card = adapter->card;
+ struct sliccard *card = adapter->card;
struct net_device *dev = adapter->netdev;
- p_slic_regs_t slic_regs = adapter->slic_regs;
- p_slic_shmem_t pshmem;
+ __iomem struct slic_regs *slic_regs = adapter->slic_regs;
+ struct slic_shmem *pshmem;
int status = 0;
ASSERT(card);
@@ -1829,12 +1814,13 @@ int slic_if_init(p_adapter_t adapter)
DBG_MSG("slicoss: %s disable interrupts(slic)\n", __func__);
WRITE_REG(slic_regs->slic_icr, ICR_INT_OFF, FLUSH);
- slic_stall_msec(1);
+ mdelay(1);
if (!adapter->isp_initialized) {
- pshmem = (p_slic_shmem_t) adapter->phys_shmem;
+ pshmem = (struct slic_shmem *)adapter->phys_shmem;
- SLIC_ACQUIRE_IRQ_SPINLOCK(adapter->bit64reglock);
+ spin_lock_irqsave(&adapter->bit64reglock.lock,
+ adapter->bit64reglock.flags);
#if defined(CONFIG_X86_64)
WRITE_REG(slic_regs->slic_addr_upper,
@@ -1842,12 +1828,13 @@ int slic_if_init(p_adapter_t adapter)
WRITE_REG(slic_regs->slic_isp,
SLIC_GET_ADDR_LOW(&pshmem->isr), FLUSH);
#elif defined(CONFIG_X86)
- WRITE_REG(slic_regs->slic_addr_upper, (ulong32) 0, DONT_FLUSH);
- WRITE_REG(slic_regs->slic_isp, (ulong32) &pshmem->isr, FLUSH);
+ WRITE_REG(slic_regs->slic_addr_upper, (u32) 0, DONT_FLUSH);
+ WRITE_REG(slic_regs->slic_isp, (u32) &pshmem->isr, FLUSH);
#else
Stop Compilations
#endif
- SLIC_RELEASE_IRQ_SPINLOCK(adapter->bit64reglock);
+ spin_unlock_irqrestore(&adapter->bit64reglock.lock,
+ adapter->bit64reglock.flags);
adapter->isp_initialized = 1;
}
@@ -1908,7 +1895,7 @@ int slic_if_init(p_adapter_t adapter)
return STATUS_SUCCESS;
}
-void slic_unmap_mmio_space(p_adapter_t adapter)
+static void slic_unmap_mmio_space(struct adapter *adapter)
{
#if LINUX_FREES_ADAPTER_RESOURCES
if (adapter->slic_regs)
@@ -1917,7 +1904,7 @@ void slic_unmap_mmio_space(p_adapter_t adapter)
#endif
}
-int slic_adapter_allocresources(p_adapter_t adapter)
+static int slic_adapter_allocresources(struct adapter *adapter)
{
if (!adapter->intrregistered) {
int retval;
@@ -1929,14 +1916,16 @@ int slic_adapter_allocresources(p_adapter_t adapter)
(void *)adapter->phys_shmem, adapter->netdev->irq,
NR_IRQS);
- SLIC_RELEASE_IRQ_SPINLOCK(slic_global.driver_lock);
+ spin_unlock_irqrestore(&slic_global.driver_lock.lock,
+ slic_global.driver_lock.flags);
retval = request_irq(adapter->netdev->irq,
&slic_interrupt,
IRQF_SHARED,
adapter->netdev->name, adapter->netdev);
- SLIC_ACQUIRE_IRQ_SPINLOCK(slic_global.driver_lock);
+ spin_lock_irqsave(&slic_global.driver_lock.lock,
+ slic_global.driver_lock.flags);
if (retval) {
DBG_ERROR("slicoss: request_irq (%s) FAILED [%x]\n",
@@ -1953,7 +1942,7 @@ int slic_adapter_allocresources(p_adapter_t adapter)
return STATUS_SUCCESS;
}
-void slic_config_pci(struct pci_dev *pcidev)
+static void slic_config_pci(struct pci_dev *pcidev)
{
u16 pci_command;
u16 new_command;
@@ -1972,11 +1961,11 @@ void slic_config_pci(struct pci_dev *pcidev)
}
}
-void slic_adapter_freeresources(p_adapter_t adapter)
+static void slic_adapter_freeresources(struct adapter *adapter)
{
DBG_MSG("slicoss: %s ENTER adapter[%p]\n", __func__, adapter);
slic_init_cleanup(adapter);
- SLIC_ZERO_MEMORY(&adapter->stats, sizeof(struct net_device_stats));
+ memset(&adapter->stats, 0, sizeof(struct net_device_stats));
adapter->error_interrupts = 0;
adapter->rcv_interrupts = 0;
adapter->xmit_interrupts = 0;
@@ -1996,14 +1985,14 @@ void slic_adapter_freeresources(p_adapter_t adapter)
* Write phy control to configure link duplex/speed
*
*/
-void slic_link_config(p_adapter_t adapter,
- ulong32 linkspeed, ulong32 linkduplex)
+static void slic_link_config(struct adapter *adapter,
+ u32 linkspeed, u32 linkduplex)
{
- ulong32 speed;
- ulong32 duplex;
- ulong32 phy_config;
- ulong32 phy_advreg;
- ulong32 phy_gctlreg;
+ u32 speed;
+ u32 duplex;
+ u32 phy_config;
+ u32 phy_advreg;
+ u32 phy_gctlreg;
if (adapter->state != ADAPT_UP) {
DBG_MSG
@@ -2052,7 +2041,7 @@ void slic_link_config(p_adapter_t adapter,
phy_config, FLUSH);
/* wait, Marvell says 1 sec,
try to get away with 10 ms */
- slic_stall_msec(10);
+ mdelay(10);
/* disable auto-neg, set speed/duplex,
soft reset phy, powerup */
@@ -2140,7 +2129,7 @@ void slic_link_config(p_adapter_t adapter,
WRITE_REG(adapter->slic_regs->slic_wphy, phy_config, FLUSH);
/* wait, Marvell says 1 sec, try to get away with 10 ms */
- slic_stall_msec(10);
+ mdelay(10);
if (adapter->subsysid != SLIC_1GB_CICADA_SUBSYS_ID) {
/* if a Marvell PHY
@@ -2164,24 +2153,24 @@ void slic_link_config(p_adapter_t adapter,
phy_config);
}
-void slic_card_cleanup(p_sliccard_t card)
+static void slic_card_cleanup(struct sliccard *card)
{
DBG_MSG("slicoss: %s ENTER\n", __func__);
#if SLIC_DUMP_ENABLED
if (card->dumpbuffer) {
- SLIC_DEALLOCATE_MEM(card->dumpbuffer);
- card->dumpbuffer = NULL;
card->dumpbuffer_phys = 0;
card->dumpbuffer_physl = 0;
card->dumpbuffer_physh = 0;
+ kfree(card->dumpbuffer);
+ card->dumpbuffer = NULL;
}
if (card->cmdbuffer) {
- SLIC_DEALLOCATE_MEM(card->cmdbuffer);
- card->cmdbuffer = NULL;
card->cmdbuffer_phys = 0;
card->cmdbuffer_physl = 0;
card->cmdbuffer_physh = 0;
+ kfree(card->cmdbuffer);
+ card->cmdbuffer = NULL;
}
#endif
@@ -2192,24 +2181,24 @@ void slic_card_cleanup(p_sliccard_t card)
slic_debug_card_destroy(card);
- SLIC_DEALLOCATE_MEM(card);
+ kfree(card);
DBG_MSG("slicoss: %s EXIT\n", __func__);
}
-static int slic_card_download_gbrcv(p_adapter_t adapter)
+static int slic_card_download_gbrcv(struct adapter *adapter)
{
- p_slic_regs_t slic_regs = adapter->slic_regs;
- ulong32 codeaddr;
- puchar instruction = NULL;
- ulong32 rcvucodelen = 0;
+ __iomem struct slic_regs *slic_regs = adapter->slic_regs;
+ u32 codeaddr;
+ unsigned char *instruction = NULL;
+ u32 rcvucodelen = 0;
switch (adapter->devid) {
case SLIC_2GB_DEVICE_ID:
- instruction = (puchar) &OasisRcvUCode[0];
+ instruction = (unsigned char *)&OasisRcvUCode[0];
rcvucodelen = OasisRcvUCodeLen;
break;
case SLIC_1GB_DEVICE_ID:
- instruction = (puchar) &GBRcvUCode[0];
+ instruction = (unsigned char *)&GBRcvUCode[0];
rcvucodelen = GBRcvUCodeLen;
break;
default:
@@ -2227,11 +2216,11 @@ static int slic_card_download_gbrcv(p_adapter_t adapter)
/* write out the instruction data low addr */
WRITE_REG(slic_regs->slic_rcv_wcs,
- (ulong32) *(pulong32) instruction, FLUSH);
+ (u32) *(u32 *) instruction, FLUSH);
instruction += 4;
/* write out the instruction data high addr */
- WRITE_REG(slic_regs->slic_rcv_wcs, (ulong32) *instruction,
+ WRITE_REG(slic_regs->slic_rcv_wcs, (u32) *instruction,
FLUSH);
instruction += 1;
}
@@ -2242,22 +2231,22 @@ static int slic_card_download_gbrcv(p_adapter_t adapter)
return 0;
}
-int slic_card_download(p_adapter_t adapter)
+static int slic_card_download(struct adapter *adapter)
{
- ulong32 section;
+ u32 section;
int thissectionsize;
int codeaddr;
- p_slic_regs_t slic_regs = adapter->slic_regs;
- ulong32 *instruction = NULL;
- ulong32 *lastinstruct = NULL;
- ulong32 *startinstruct = NULL;
- puchar nextinstruct;
- ulong32 baseaddress;
- ulong32 failure;
- ulong32 i;
- ulong32 numsects = 0;
- ulong32 sectsize[3];
- ulong32 sectstart[3];
+ __iomem struct slic_regs *slic_regs = adapter->slic_regs;
+ u32 *instruction = NULL;
+ u32 *lastinstruct = NULL;
+ u32 *startinstruct = NULL;
+ unsigned char *nextinstruct;
+ u32 baseaddress;
+ u32 failure;
+ u32 i;
+ u32 numsects = 0;
+ u32 sectsize[3];
+ u32 sectstart[3];
/* DBG_MSG ("slicoss: %s (%s) adapter[%p] card[%p] devid[%x] \
jiffies[%lx] cpu %d\n", __func__, adapter->netdev->name, adapter,
@@ -2292,19 +2281,19 @@ int slic_card_download(p_adapter_t adapter)
for (section = 0; section < numsects; section++) {
switch (adapter->devid) {
case SLIC_2GB_DEVICE_ID:
- instruction = (pulong32) &OasisUCode[section][0];
+ instruction = (u32 *) &OasisUCode[section][0];
baseaddress = sectstart[section];
thissectionsize = sectsize[section] >> 3;
lastinstruct =
- (pulong32) &OasisUCode[section][sectsize[section] -
+ (u32 *) &OasisUCode[section][sectsize[section] -
8];
break;
case SLIC_1GB_DEVICE_ID:
- instruction = (pulong32) &MojaveUCode[section][0];
+ instruction = (u32 *) &MojaveUCode[section][0];
baseaddress = sectstart[section];
thissectionsize = sectsize[section] >> 3;
lastinstruct =
- (pulong32) &MojaveUCode[section][sectsize[section]
+ (u32 *) &MojaveUCode[section][sectsize[section]
- 8];
break;
default:
@@ -2317,21 +2306,21 @@ int slic_card_download(p_adapter_t adapter)
for (codeaddr = 0; codeaddr < thissectionsize; codeaddr++) {
startinstruct = instruction;
- nextinstruct = ((puchar) instruction) + 8;
+ nextinstruct = ((unsigned char *)instruction) + 8;
/* Write out instruction address */
WRITE_REG(slic_regs->slic_wcs, baseaddress + codeaddr,
FLUSH);
/* Write out instruction to low addr */
WRITE_REG(slic_regs->slic_wcs, *instruction, FLUSH);
#ifdef CONFIG_X86_64
- instruction = (pulong32) ((puchar) instruction + 4);
+ instruction = (u32 *)((unsigned char *)instruction + 4);
#else
instruction++;
#endif
/* Write out instruction to high addr */
WRITE_REG(slic_regs->slic_wcs, *instruction, FLUSH);
#ifdef CONFIG_X86_64
- instruction = (pulong32) ((puchar) instruction + 4);
+ instruction = (u32 *)((unsigned char *)instruction + 4);
#else
instruction++;
#endif
@@ -2341,10 +2330,10 @@ int slic_card_download(p_adapter_t adapter)
for (section = 0; section < numsects; section++) {
switch (adapter->devid) {
case SLIC_2GB_DEVICE_ID:
- instruction = (pulong32) &OasisUCode[section][0];
+ instruction = (u32 *)&OasisUCode[section][0];
break;
case SLIC_1GB_DEVICE_ID:
- instruction = (pulong32) &MojaveUCode[section][0];
+ instruction = (u32 *)&MojaveUCode[section][0];
break;
default:
ASSERT(0);
@@ -2367,19 +2356,19 @@ int slic_card_download(p_adapter_t adapter)
/* Write out instruction to low addr */
WRITE_REG(slic_regs->slic_wcs, *instruction, FLUSH);
#ifdef CONFIG_X86_64
- instruction = (pulong32) ((puchar) instruction + 4);
+ instruction = (u32 *)((unsigned char *)instruction + 4);
#else
instruction++;
#endif
/* Write out instruction to high addr */
WRITE_REG(slic_regs->slic_wcs, *instruction, FLUSH);
#ifdef CONFIG_X86_64
- instruction = (pulong32) ((puchar) instruction + 4);
+ instruction = (u32 *)((unsigned char *)instruction + 4);
#else
instruction++;
#endif
/* Check SRAM location zero. If it is non-zero. Abort.*/
- failure = READ_REG(slic_regs->slic_reset, 0);
+ failure = readl((u32 __iomem *)&slic_regs->slic_reset);
if (failure) {
DBG_MSG
("slicoss: %s FAILURE EXIT codeaddr[%x] \
@@ -2394,12 +2383,12 @@ int slic_card_download(p_adapter_t adapter)
/* DBG_MSG ("slicoss: Compare done\n");*/
/* Everything OK, kick off the card */
- slic_stall_msec(10);
+ mdelay(10);
WRITE_REG(slic_regs->slic_wcs, SLIC_WCS_START, FLUSH);
/* stall for 20 ms, long enough for ucode to init card
and reach mainloop */
- slic_stall_msec(20);
+ mdelay(20);
DBG_MSG("slicoss: %s (%s) EXIT adapter[%p] card[%p]\n",
__func__, adapter->netdev->name, adapter, adapter->card);
@@ -2407,9 +2396,9 @@ int slic_card_download(p_adapter_t adapter)
return STATUS_SUCCESS;
}
-void slic_adapter_set_hwaddr(p_adapter_t adapter)
+static void slic_adapter_set_hwaddr(struct adapter *adapter)
{
- p_sliccard_t card = adapter->card;
+ struct sliccard *card = adapter->card;
/* DBG_MSG ("%s ENTER card->config_set[%x] port[%d] physport[%d] funct#[%d]\n",
__func__, card->config_set, adapter->port, adapter->physport,
@@ -2420,7 +2409,7 @@ void slic_adapter_set_hwaddr(p_adapter_t adapter)
if ((adapter->card) && (card->config_set)) {
memcpy(adapter->macaddr,
card->config.MacInfo[adapter->functionnumber].macaddrA,
- sizeof(slic_config_mac_t));
+ sizeof(struct slic_config_mac));
/* DBG_MSG ("%s AFTER copying from config.macinfo into currmacaddr\n",
__func__);
slic_dbg_macaddrs(adapter);*/
@@ -2438,53 +2427,35 @@ void slic_adapter_set_hwaddr(p_adapter_t adapter)
slic_dbg_macaddrs(adapter); */
}
-void slic_card_halt(p_sliccard_t card, p_adapter_t adapter)
+static void slic_intagg_set(struct adapter *adapter, u32 value)
{
- p_slic_regs_t slic_regs = adapter->slic_regs;
-
- DBG_MSG("slicoss: %s ENTER card[%p] adapter[%p] card->state[%x]\n",
- __func__, card, adapter, card->state);
- WRITE_REG(slic_regs->slic_icr, ICR_INT_OFF, FLUSH);
- adapter->all_reg_writes++;
- adapter->icr_reg_writes++;
- slic_config_clear(adapter);
- WRITE_REG(slic_regs->slic_reset_iface, 0, FLUSH);
- slic_soft_reset(adapter);
- DBG_MSG("slicoss: %s EXIT card[%p] adapter[%p] card->state[%x]\n",
- __func__, card, adapter, card->state);
- return;
-
-}
-
-void slic_intagg_set(p_adapter_t adapter, ulong32 value)
-{
- p_slic_regs_t slic_regs = adapter->slic_regs;
+ __iomem struct slic_regs *slic_regs = adapter->slic_regs;
WRITE_REG(slic_regs->slic_intagg, value, FLUSH);
adapter->card->loadlevel_current = value;
}
-int slic_card_init(p_sliccard_t card, p_adapter_t adapter)
+static int slic_card_init(struct sliccard *card, struct adapter *adapter)
{
- p_slic_regs_t slic_regs = adapter->slic_regs;
- pslic_eeprom_t peeprom;
- poslic_eeprom_t pOeeprom;
+ __iomem struct slic_regs *slic_regs = adapter->slic_regs;
+ struct slic_eeprom *peeprom;
+ struct oslic_eeprom *pOeeprom;
dma_addr_t phys_config;
- ulong32 phys_configh;
- ulong32 phys_configl;
- ulong32 i = 0;
- p_slic_shmem_t pshmem;
+ u32 phys_configh;
+ u32 phys_configl;
+ u32 i = 0;
+ struct slic_shmem *pshmem;
int status;
uint macaddrs = card->card_size;
ushort eecodesize;
ushort dramsize;
ushort ee_chksum;
ushort calc_chksum;
- pslic_config_mac_t pmac;
- uchar fruformat;
- uchar oemfruformat;
- patk_fru_t patkfru;
- poemfru_t poemfru;
+ struct slic_config_mac *pmac;
+ unsigned char fruformat;
+ unsigned char oemfruformat;
+ struct atk_fru *patkfru;
+ union oemfru_t *poemfru;
DBG_MSG
("slicoss: %s ENTER card[%p] adapter[%p] card->state[%x] \
@@ -2505,7 +2476,7 @@ int slic_card_init(p_sliccard_t card, p_adapter_t adapter)
if (!card->config_set) {
peeprom = pci_alloc_consistent(adapter->pcidev,
- sizeof(slic_eeprom_t),
+ sizeof(struct slic_eeprom),
&phys_config);
phys_configl = SLIC_GET_ADDR_LOW(phys_config);
@@ -2515,8 +2486,9 @@ int slic_card_init(p_sliccard_t card, p_adapter_t adapter)
"size [%x]\n peeprom [%p]\n "
"phys_config [%p]\n phys_configl[%x]\n "
"phys_configh[%x]\n",
- __func__, adapter, (ulong32) sizeof(slic_eeprom_t),
- peeprom, (pvoid) phys_config, phys_configl,
+ __func__, adapter,
+ (u32)sizeof(struct slic_eeprom),
+ peeprom, (void *) phys_config, phys_configl,
phys_configh);
if (!peeprom) {
DBG_ERROR
@@ -2526,17 +2498,19 @@ int slic_card_init(p_sliccard_t card, p_adapter_t adapter)
(uint) adapter->slotnumber);
return -ENOMEM;
} else {
- SLIC_ZERO_MEMORY(peeprom, sizeof(slic_eeprom_t));
+ memset(peeprom, 0, sizeof(struct slic_eeprom));
}
WRITE_REG(slic_regs->slic_icr, ICR_INT_OFF, FLUSH);
- slic_stall_msec(1);
- pshmem = (p_slic_shmem_t) adapter->phys_shmem;
+ mdelay(1);
+ pshmem = (struct slic_shmem *)adapter->phys_shmem;
- SLIC_ACQUIRE_IRQ_SPINLOCK(adapter->bit64reglock);
+ spin_lock_irqsave(&adapter->bit64reglock.lock,
+ adapter->bit64reglock.flags);
WRITE_REG(slic_regs->slic_addr_upper, 0, DONT_FLUSH);
WRITE_REG(slic_regs->slic_isp,
SLIC_GET_ADDR_LOW(&pshmem->isr), FLUSH);
- SLIC_RELEASE_IRQ_SPINLOCK(adapter->bit64reglock);
+ spin_unlock_irqrestore(&adapter->bit64reglock.lock,
+ adapter->bit64reglock.flags);
slic_config_get(adapter, phys_configl, phys_configh);
@@ -2564,7 +2538,7 @@ int slic_card_init(p_sliccard_t card, p_adapter_t adapter)
FLUSH);
}
} else {
- slic_stall_msec(1);
+ mdelay(1);
i++;
if (i > 5000) {
DBG_ERROR
@@ -2586,7 +2560,7 @@ int slic_card_init(p_sliccard_t card, p_adapter_t adapter)
/* Oasis card */
case SLIC_2GB_DEVICE_ID:
/* extract EEPROM data and pointers to EEPROM data */
- pOeeprom = (poslic_eeprom_t) peeprom;
+ pOeeprom = (struct oslic_eeprom *) peeprom;
eecodesize = pOeeprom->EecodeSize;
dramsize = pOeeprom->DramSize;
pmac = pOeeprom->MacInfo;
@@ -2619,12 +2593,12 @@ int slic_card_init(p_sliccard_t card, p_adapter_t adapter)
(eecodesize >= MIN_EECODE_SIZE)) {
ee_chksum =
- *(pushort) ((pchar) peeprom + (eecodesize - 2));
+ *(u16 *) ((char *) peeprom + (eecodesize - 2));
/*
calculate the EEPROM checksum
*/
calc_chksum =
- ~slic_eeprom_cksum((pchar) peeprom,
+ ~slic_eeprom_cksum((char *) peeprom,
(eecodesize - 2));
/*
if the ucdoe chksum flag bit worked,
@@ -2639,24 +2613,25 @@ int slic_card_init(p_sliccard_t card, p_adapter_t adapter)
/* copy in the MAC address(es) */
for (i = 0; i < macaddrs; i++) {
memcpy(&card->config.MacInfo[i],
- &pmac[i], sizeof(slic_config_mac_t));
+ &pmac[i], sizeof(struct slic_config_mac));
}
/* DBG_MSG ("%s EEPROM Checksum Good? %d MacAddress\n",__func__,
card->config.EepromValid); */
/* copy the Alacritech FRU information */
card->config.FruFormat = fruformat;
- memcpy(&card->config.AtkFru, patkfru, sizeof(atk_fru_t));
+ memcpy(&card->config.AtkFru, patkfru,
+ sizeof(struct atk_fru));
pci_free_consistent(adapter->pcidev,
- sizeof(slic_eeprom_t),
+ sizeof(struct slic_eeprom),
peeprom, phys_config);
DBG_MSG
("slicoss: %s adapter%d [%p] size[%x] FREE peeprom[%p] \
phys_config[%p]\n",
__func__, adapter->port, adapter,
- (ulong32) sizeof(slic_eeprom_t), peeprom,
- (pvoid) phys_config);
+ (u32) sizeof(struct slic_eeprom), peeprom,
+ (void *) phys_config);
if ((!card->config.EepromValid) &&
(adapter->reg_params.fail_on_bad_eeprom)) {
@@ -2698,8 +2673,7 @@ int slic_card_init(p_sliccard_t card, p_adapter_t adapter)
#if SLIC_DUMP_ENABLED
if (!card->dumpbuffer) {
- card->dumpbuffer =
- SLIC_ALLOCATE_MEM(DUMP_PAGE_SIZE, GFP_ATOMIC);
+ card->dumpbuffer = kmalloc(DUMP_PAGE_SIZE, GFP_ATOMIC);
ASSERT(card->dumpbuffer);
if (card->dumpbuffer == NULL)
@@ -2709,8 +2683,8 @@ int slic_card_init(p_sliccard_t card, p_adapter_t adapter)
* Smear the shared memory structure and then obtain
* the PHYSICAL address of this structure
*/
- SLIC_ZERO_MEMORY(card->dumpbuffer, DUMP_PAGE_SIZE);
- card->dumpbuffer_phys = SLIC_GET_PHYSICAL_ADDRESS(card->dumpbuffer);
+ memset(card->dumpbuffer, 0, DUMP_PAGE_SIZE);
+ card->dumpbuffer_phys = virt_to_bus(card->dumpbuffer);
card->dumpbuffer_physh = SLIC_GET_ADDR_HIGH(card->dumpbuffer_phys);
card->dumpbuffer_physl = SLIC_GET_ADDR_LOW(card->dumpbuffer_phys);
@@ -2718,8 +2692,7 @@ int slic_card_init(p_sliccard_t card, p_adapter_t adapter)
* Allocate COMMAND BUFFER
*/
if (!card->cmdbuffer) {
- card->cmdbuffer =
- SLIC_ALLOCATE_MEM(sizeof(dump_cmd_t), GFP_ATOMIC);
+ card->cmdbuffer = kmalloc(sizeof(dump_cmd_t), GFP_ATOMIC);
ASSERT(card->cmdbuffer);
if (card->cmdbuffer == NULL)
@@ -2729,8 +2702,8 @@ int slic_card_init(p_sliccard_t card, p_adapter_t adapter)
* Smear the shared memory structure and then obtain
* the PHYSICAL address of this structure
*/
- SLIC_ZERO_MEMORY(card->cmdbuffer, sizeof(dump_cmd_t));
- card->cmdbuffer_phys = SLIC_GET_PHYSICAL_ADDRESS(card->cmdbuffer);
+ memset(card->cmdbuffer, 0, sizeof(dump_cmd_t));
+ card->cmdbuffer_phys = virt_to_bus(card->cmdbuffer);
card->cmdbuffer_physh = SLIC_GET_ADDR_HIGH(card->cmdbuffer_phys);
card->cmdbuffer_physl = SLIC_GET_ADDR_LOW(card->cmdbuffer_phys);
#endif
@@ -2746,10 +2719,10 @@ int slic_card_init(p_sliccard_t card, p_adapter_t adapter)
return STATUS_SUCCESS;
}
-ulong32 slic_card_locate(p_adapter_t adapter)
+static u32 slic_card_locate(struct adapter *adapter)
{
- p_sliccard_t card = slic_global.slic_card;
- p_physcard_t physcard = slic_global.phys_card;
+ struct sliccard *card = slic_global.slic_card;
+ struct physcard *physcard = slic_global.phys_card;
ushort card_hostid;
u16 __iomem *hostid_reg;
uint i;
@@ -2777,13 +2750,12 @@ ulong32 slic_card_locate(p_adapter_t adapter)
DBG_MSG("slicoss: %s *hostid_reg[%p] == ", __func__, hostid_reg);
/* read the 16 bit hostid from SRAM */
-/* card_hostid = READ_REGP16(hostid_reg, 0);*/
card_hostid = (ushort) readw(hostid_reg);
DBG_MSG(" card_hostid[%x]\n", card_hostid);
/* Initialize a new card structure if need be */
if (card_hostid == SLIC_HOSTID_DEFAULT) {
- card = kzalloc(sizeof(sliccard_t), GFP_KERNEL);
+ card = kzalloc(sizeof(struct sliccard), GFP_KERNEL);
if (card == NULL)
return -ENOMEM;
@@ -2861,11 +2833,9 @@ ulong32 slic_card_locate(p_adapter_t adapter)
}
if (!physcard) {
/* no structure allocated for this physical card yet */
- physcard =
- (p_physcard_t) SLIC_ALLOCATE_MEM(sizeof(physcard_t),
- GFP_ATOMIC);
+ physcard = kmalloc(sizeof(struct physcard *), GFP_ATOMIC);
ASSERT(physcard);
- SLIC_ZERO_MEMORY(physcard, sizeof(physcard_t));
+ memset(physcard, 0, sizeof(struct physcard *));
DBG_MSG
("\n%s Allocate a PHYSICALcard:\n PHYSICAL_Card[%p]\n\
@@ -2890,130 +2860,27 @@ ulong32 slic_card_locate(p_adapter_t adapter)
return 0;
}
-void slic_card_remaster(p_adapter_t adapter)
-{
- p_sliccard_t card = adapter->card;
- int i;
-
- DBG_MSG("slicoss: %s card->master[%p] == adapter[%p]??\n",
- __func__, card->master, adapter);
- if (card->master != adapter)
- return;
- card->master = NULL;
- for (i = 0; i < SLIC_MAX_PORTS; i++) {
- if (card->adapter[i] && (card->adapter[i] != adapter)) {
- card->master = card->adapter[i];
- DBG_MSG("slicoss: %s NEW MASTER SET card->master[%p]"
- " == card->adapter[%d]\n", __func__,
- card->master, i);
- break;
- }
- }
-}
-
-void slic_soft_reset(p_adapter_t adapter)
+static void slic_soft_reset(struct adapter *adapter)
{
if (adapter->card->state == CARD_UP) {
DBG_MSG("slicoss: %s QUIESCE adapter[%p] card[%p] devid[%x]\n",
__func__, adapter, adapter->card, adapter->devid);
WRITE_REG(adapter->slic_regs->slic_quiesce, 0, FLUSH);
- slic_stall_msec(1);
+ mdelay(1);
}
/* DBG_MSG ("slicoss: %s (%s) adapter[%p] card[%p] devid[%x]\n",
__func__, adapter->netdev->name, adapter, adapter->card,
adapter->devid); */
WRITE_REG(adapter->slic_regs->slic_reset, SLIC_RESET_MAGIC, FLUSH);
- slic_stall_msec(1);
-}
-
-void slic_card_reset(p_adapter_t adapter)
-{
- p_sliccard_t card = adapter->card;
- p_slic_upr_t upr = adapter->upr_list;
- p_slic_upr_t upr_next = NULL;
- ulong32 i;
-#if SLIC_FAILURE_RESET
- ulong32 status = 0;
-#endif
- DBG_MSG
- ("slicoss: %s adapter[%p] port[%d] state[%x] card[%p] state[%x]\n",
- __func__, adapter, adapter->port, adapter->state, card,
- card->state);
- SLIC_ACQUIRE_IRQ_SPINLOCK(adapter->adapter_lock);
- SLIC_ACQUIRE_IRQ_SPINLOCK(adapter->reset_lock);
- if (card->state == CARD_DIAG) {
- SLIC_RELEASE_IRQ_SPINLOCK(adapter->reset_lock);
- SLIC_RELEASE_IRQ_SPINLOCK(adapter->adapter_lock);
- return;
- }
- SLIC_ACQUIRE_IRQ_SPINLOCK(slic_global.driver_lock);
- card->reset_in_progress = 1;
-#if SLIC_FAILURE_RESET
- if (adapter->state != ADAPT_RESET) {
- SLIC_RELEASE_IRQ_SPINLOCK(slic_global.driver_lock);
- SLIC_RELEASE_IRQ_SPINLOCK(adapter->reset_lock);
- SLIC_RELEASE_IRQ_SPINLOCK(adapter->adapter_lock);
- return;
- }
-
- adapter->state = ADAPT_DOWN;
- adapter->linkstate = LINK_DOWN;
-#endif
- if (adapter->gennumber == card->gennumber) {
- for (i = 0; i < card->card_size; i++) {
- if (card->adapter[i]) {
- if (card->adapter[i] == adapter)
- continue;
- if (card->adapter[i]->state == ADAPT_UP) {
- card->adapter[i]->state = ADAPT_RESET;
- adapter->linkstate = LINK_DOWN;
- }
- }
- }
-#if SLIC_FAILURE_RESET
- slic_soft_reset(adapter);
- card->state = CARD_DOWN;
- card->master = NULL;
- card->adapters_activated = 0;
-#endif
- card->gennumber++;
- }
- adapter->gennumber = card->gennumber;
- adapter->pshmem->isr = 0;
- adapter->isrcopy = 0;
- SLIC_RELEASE_IRQ_SPINLOCK(adapter->reset_lock);
- for (i = 0; i < card->card_size; i++) {
- if (card->adapter[i])
- slic_cmdq_reset(card->adapter[i]);
- }
- while (upr) {
- upr_next = upr->next;
- SLIC_DEALLOCATE_MEM(upr);
- upr = upr_next;
- }
- adapter->upr_list = NULL;
- adapter->upr_busy = 0;
-#if SLIC_FAILURE_RESET
- status = slic_if_init(adapter);
- if ((status == 0) && (!card->master))
- card->master = adapter;
- slic_mcast_set_mask(adapter);
-#endif
- SLIC_RELEASE_IRQ_SPINLOCK(slic_global.driver_lock);
- SLIC_RELEASE_IRQ_SPINLOCK(adapter->adapter_lock);
- DBG_MSG
- ("slicoss: %s EXIT adapter[%p] port[%d] state[%x] card[%p] \
- state[%x]\n", __func__, adapter, adapter->port, adapter->state,
- card, card->state);
- return;
+ mdelay(1);
}
-void slic_config_set(p_adapter_t adapter, boolean linkchange)
+static void slic_config_set(struct adapter *adapter, bool linkchange)
{
- ulong32 value;
- ulong32 RcrReset;
- p_slic_regs_t slic_regs = adapter->slic_regs;
+ u32 value;
+ u32 RcrReset;
+ __iomem struct slic_regs *slic_regs = adapter->slic_regs;
DBG_MSG("slicoss: %s (%s) slic_interface_enable[%p](%d)\n",
__func__, adapter->netdev->name, adapter,
@@ -3075,11 +2942,11 @@ void slic_config_set(p_adapter_t adapter, boolean linkchange)
/*
* Turn off RCV and XMT, power down PHY
*/
-void slic_config_clear(p_adapter_t adapter)
+static void slic_config_clear(struct adapter *adapter)
{
- ulong32 value;
- ulong32 phy_config;
- p_slic_regs_t slic_regs = adapter->slic_regs;
+ u32 value;
+ u32 phy_config;
+ __iomem struct slic_regs *slic_regs = adapter->slic_regs;
/* Setup xmtcfg */
value = (GXCR_RESET | /* Always reset */
@@ -3099,28 +2966,29 @@ void slic_config_clear(p_adapter_t adapter)
WRITE_REG(slic_regs->slic_wphy, phy_config, FLUSH);
}
-void slic_config_get(p_adapter_t adapter, ulong32 config, ulong32 config_h)
+static void slic_config_get(struct adapter *adapter, u32 config,
+ u32 config_h)
{
int status;
status = slic_upr_request(adapter,
SLIC_UPR_RCONFIG,
- (ulong32) config, (ulong32) config_h, 0, 0);
+ (u32) config, (u32) config_h, 0, 0);
ASSERT(status == 0);
}
-void slic_mac_address_config(p_adapter_t adapter)
+static void slic_mac_address_config(struct adapter *adapter)
{
- ulong32 value;
- ulong32 value2;
- p_slic_regs_t slic_regs = adapter->slic_regs;
+ u32 value;
+ u32 value2;
+ __iomem struct slic_regs *slic_regs = adapter->slic_regs;
- value = *(pulong32) &adapter->currmacaddr[2];
+ value = *(u32 *) &adapter->currmacaddr[2];
value = ntohl(value);
WRITE_REG(slic_regs->slic_wraddral, value, FLUSH);
WRITE_REG(slic_regs->slic_wraddrbl, value, FLUSH);
- value2 = (ulong32) ((adapter->currmacaddr[0] << 8 |
+ value2 = (u32) ((adapter->currmacaddr[0] << 8 |
adapter->currmacaddr[1]) & 0xFFFF);
WRITE_REG(slic_regs->slic_wraddrah, value2, FLUSH);
@@ -3136,10 +3004,10 @@ void slic_mac_address_config(p_adapter_t adapter)
slic_mcast_set_mask(adapter);
}
-void slic_mac_config(p_adapter_t adapter)
+static void slic_mac_config(struct adapter *adapter)
{
- ulong32 value;
- p_slic_regs_t slic_regs = adapter->slic_regs;
+ u32 value;
+ __iomem struct slic_regs *slic_regs = adapter->slic_regs;
/* Setup GMAC gaps */
if (adapter->linkspeed == LINK_1000MB) {
@@ -3169,12 +3037,13 @@ void slic_mac_config(p_adapter_t adapter)
slic_mac_address_config(adapter);
}
-boolean slic_mac_filter(p_adapter_t adapter, p_ether_header ether_frame)
+static bool slic_mac_filter(struct adapter *adapter,
+ struct ether_header *ether_frame)
{
- ulong32 opts = adapter->macopts;
- pulong32 dhost4 = (pulong32) ðer_frame->ether_dhost[0];
- pushort dhost2 = (pushort) ðer_frame->ether_dhost[4];
- boolean equaladdr;
+ u32 opts = adapter->macopts;
+ u32 *dhost4 = (u32 *)ðer_frame->ether_dhost[0];
+ u16 *dhost2 = (u16 *)ðer_frame->ether_dhost[4];
+ bool equaladdr;
if (opts & MAC_PROMISC) {
DBG_MSG("slicoss: %s (%s) PROMISCUOUS. Accept frame\n",
@@ -3198,7 +3067,7 @@ boolean slic_mac_filter(p_adapter_t adapter, p_ether_header ether_frame)
return TRUE;
}
if (opts & MAC_MCAST) {
- p_mcast_address_t mcaddr = adapter->mcastaddrs;
+ struct mcast_address *mcaddr = adapter->mcastaddrs;
while (mcaddr) {
ETHER_EQ_ADDR(mcaddr->address,
@@ -3224,9 +3093,9 @@ boolean slic_mac_filter(p_adapter_t adapter, p_ether_header ether_frame)
}
-int slic_mac_set_address(struct net_device *dev, pvoid ptr)
+static int slic_mac_set_address(struct net_device *dev, void *ptr)
{
- p_adapter_t adapter = (p_adapter_t) netdev_priv(dev);
+ struct adapter *adapter = (struct adapter *)netdev_priv(dev);
struct sockaddr *addr = ptr;
DBG_MSG("%s ENTER (%s)\n", __func__, adapter->netdev->name);
@@ -3259,21 +3128,21 @@ int slic_mac_set_address(struct net_device *dev, pvoid ptr)
* 50 seconds or whatever STATS_TIMER_INTERVAL is set to.
*
*/
-void slic_timer_get_stats(ulong dev)
+static void slic_timer_get_stats(ulong dev)
{
- p_adapter_t adapter;
- p_sliccard_t card;
- p_slic_shmem_t pshmem;
+ struct adapter *adapter;
+ struct sliccard *card;
+ struct slic_shmem *pshmem;
ASSERT(dev);
- adapter = (p_adapter_t) ((struct net_device *)dev)->priv;
+ adapter = (struct adapter *)((struct net_device *)dev)->priv;
ASSERT(adapter);
card = adapter->card;
ASSERT(card);
if ((card->state == CARD_UP) &&
(adapter->state == ADAPT_UP) && (adapter->linkstate == LINK_UP)) {
- pshmem = (p_slic_shmem_t) adapter->phys_shmem;
+ pshmem = (struct slic_shmem *)adapter->phys_shmem;
#ifdef CONFIG_X86_64
slic_upr_request(adapter,
SLIC_UPR_STATS,
@@ -3282,7 +3151,7 @@ void slic_timer_get_stats(ulong dev)
#elif defined(CONFIG_X86)
slic_upr_request(adapter,
SLIC_UPR_STATS,
- (ulong32) &pshmem->inicstats, 0, 0, 0);
+ (u32) &pshmem->inicstats, 0, 0, 0);
#else
Stop compilation;
#endif
@@ -3295,12 +3164,12 @@ void slic_timer_get_stats(ulong dev)
add_timer(&adapter->statstimer);
}
-void slic_timer_load_check(ulong cardaddr)
+static void slic_timer_load_check(ulong cardaddr)
{
- p_sliccard_t card = (p_sliccard_t) cardaddr;
- p_adapter_t adapter = card->master;
- ulong32 load = card->events;
- ulong32 level = 0;
+ struct sliccard *card = (struct sliccard *)cardaddr;
+ struct adapter *adapter = card->master;
+ u32 load = card->events;
+ u32 level = 0;
if ((adapter) && (adapter->state == ADAPT_UP) &&
(card->state == CARD_UP) && (slic_global.dynamic_intagg)) {
@@ -3352,36 +3221,26 @@ void slic_timer_load_check(ulong cardaddr)
add_timer(&card->loadtimer);
}
-void slic_stall_msec(int stall)
-{
- mdelay(stall);
-}
-
-void slic_stall_usec(int stall)
-{
- udelay(stall);
-}
-
-void slic_assert_fail(void)
+static void slic_assert_fail(void)
{
- ulong32 cpuid;
- ulong32 curr_pid;
+ u32 cpuid;
+ u32 curr_pid;
cpuid = smp_processor_id();
curr_pid = current->pid;
DBG_ERROR("%s CPU # %d ---- PID # %d\n", __func__, cpuid, curr_pid);
}
-int slic_upr_queue_request(p_adapter_t adapter,
- ulong32 upr_request,
- ulong32 upr_data,
- ulong32 upr_data_h,
- ulong32 upr_buffer, ulong32 upr_buffer_h)
+static int slic_upr_queue_request(struct adapter *adapter,
+ u32 upr_request,
+ u32 upr_data,
+ u32 upr_data_h,
+ u32 upr_buffer, u32 upr_buffer_h)
{
- p_slic_upr_t upr;
- p_slic_upr_t uprqueue;
+ struct slic_upr *upr;
+ struct slic_upr *uprqueue;
- upr = SLIC_ALLOCATE_MEM(sizeof(slic_upr_t), GFP_ATOMIC);
+ upr = kmalloc(sizeof(struct slic_upr), GFP_ATOMIC);
if (!upr) {
DBG_MSG("%s COULD NOT ALLOCATE UPR MEM\n", __func__);
@@ -3406,42 +3265,45 @@ int slic_upr_queue_request(p_adapter_t adapter,
return STATUS_SUCCESS;
}
-int slic_upr_request(p_adapter_t adapter,
- ulong32 upr_request,
- ulong32 upr_data,
- ulong32 upr_data_h,
- ulong32 upr_buffer, ulong32 upr_buffer_h)
+static int slic_upr_request(struct adapter *adapter,
+ u32 upr_request,
+ u32 upr_data,
+ u32 upr_data_h,
+ u32 upr_buffer, u32 upr_buffer_h)
{
int status;
- SLIC_ACQUIRE_IRQ_SPINLOCK(adapter->upr_lock);
+ spin_lock_irqsave(&adapter->upr_lock.lock, adapter->upr_lock.flags);
status = slic_upr_queue_request(adapter,
upr_request,
upr_data,
upr_data_h, upr_buffer, upr_buffer_h);
if (status != STATUS_SUCCESS) {
- SLIC_RELEASE_IRQ_SPINLOCK(adapter->upr_lock);
+ spin_unlock_irqrestore(&adapter->upr_lock.lock,
+ adapter->upr_lock.flags);
return status;
}
slic_upr_start(adapter);
- SLIC_RELEASE_IRQ_SPINLOCK(adapter->upr_lock);
+ spin_unlock_irqrestore(&adapter->upr_lock.lock,
+ adapter->upr_lock.flags);
return STATUS_PENDING;
}
-void slic_upr_request_complete(p_adapter_t adapter, ulong32 isr)
+static void slic_upr_request_complete(struct adapter *adapter, u32 isr)
{
- p_sliccard_t card = adapter->card;
- p_slic_upr_t upr;
+ struct sliccard *card = adapter->card;
+ struct slic_upr *upr;
/* if (card->dump_requested) {
DBG_MSG("ENTER slic_upr_request_complete Dump in progress ISR[%x]\n",
isr);
} */
- SLIC_ACQUIRE_IRQ_SPINLOCK(adapter->upr_lock);
+ spin_lock_irqsave(&adapter->upr_lock.lock, adapter->upr_lock.flags);
upr = adapter->upr_list;
if (!upr) {
ASSERT(0);
- SLIC_RELEASE_IRQ_SPINLOCK(adapter->upr_lock);
+ spin_unlock_irqrestore(&adapter->upr_lock.lock,
+ adapter->upr_lock.flags);
return;
}
adapter->upr_list = upr->next;
@@ -3452,11 +3314,11 @@ void slic_upr_request_complete(p_adapter_t adapter, ulong32 isr)
case SLIC_UPR_STATS:
{
#if SLIC_GET_STATS_ENABLED
- p_slic_stats_t slicstats =
- (p_slic_stats_t) &adapter->pshmem->inicstats;
- p_slic_stats_t newstats = slicstats;
- p_slic_stats_t old = &adapter->inicstats_prev;
- p_slicnet_stats_t stst = &adapter->slic_stats;
+ struct slic_stats *slicstats =
+ (struct slic_stats *) &adapter->pshmem->inicstats;
+ struct slic_stats *newstats = slicstats;
+ struct slic_stats *old = &adapter->inicstats_prev;
+ struct slicnet_stats *stst = &adapter->slic_stats;
#endif
if (isr & ISR_UPCERR) {
DBG_ERROR
@@ -3540,7 +3402,7 @@ void slic_upr_request_complete(p_adapter_t adapter, ulong32 isr)
(newstats->rcv_drops_gb -
old->rcv_drops_gb);
}
- memcpy(old, newstats, sizeof(slic_stats_t));
+ memcpy(old, newstats, sizeof(struct slic_stats));
#endif
break;
}
@@ -3572,15 +3434,16 @@ void slic_upr_request_complete(p_adapter_t adapter, ulong32 isr)
default:
ASSERT(0);
}
- SLIC_DEALLOCATE_MEM(upr);
+ kfree(upr);
slic_upr_start(adapter);
- SLIC_RELEASE_IRQ_SPINLOCK(adapter->upr_lock);
+ spin_unlock_irqrestore(&adapter->upr_lock.lock,
+ adapter->upr_lock.flags);
}
-void slic_upr_start(p_adapter_t adapter)
+static void slic_upr_start(struct adapter *adapter)
{
- p_slic_upr_t upr;
- p_slic_regs_t slic_regs = adapter->slic_regs;
+ struct slic_upr *upr;
+ __iomem struct slic_regs *slic_regs = adapter->slic_regs;
/*
char * ptr1;
char * ptr2;
@@ -3670,21 +3533,21 @@ void slic_upr_start(p_adapter_t adapter)
}
}
-void slic_link_upr_complete(p_adapter_t adapter, ulong32 isr)
+static void slic_link_upr_complete(struct adapter *adapter, u32 isr)
{
- ulong32 linkstatus = adapter->pshmem->linkstatus;
+ u32 linkstatus = adapter->pshmem->linkstatus;
uint linkup;
- uchar linkspeed;
- uchar linkduplex;
+ unsigned char linkspeed;
+ unsigned char linkduplex;
DBG_MSG("%s: %s ISR[%x] linkstatus[%x]\n adapter[%p](%d)\n",
__func__, adapter->netdev->name, isr, linkstatus, adapter,
adapter->cardindex);
if ((isr & ISR_UPCERR) || (isr & ISR_UPCBSY)) {
- p_slic_shmem_t pshmem;
+ struct slic_shmem *pshmem;
- pshmem = (p_slic_shmem_t) adapter->phys_shmem;
+ pshmem = (struct slic_shmem *)adapter->phys_shmem;
#if defined(CONFIG_X86_64)
slic_upr_queue_request(adapter,
SLIC_UPR_RLSR,
@@ -3694,7 +3557,7 @@ void slic_link_upr_complete(p_adapter_t adapter, ulong32 isr)
#elif defined(CONFIG_X86)
slic_upr_queue_request(adapter,
SLIC_UPR_RLSR,
- (ulong32) &pshmem->linkstatus,
+ (u32) &pshmem->linkstatus,
SLIC_GET_ADDR_HIGH(pshmem), 0, 0);
#else
Stop Compilation;
@@ -3792,16 +3655,16 @@ void slic_link_upr_complete(p_adapter_t adapter, ulong32 isr)
* which prevens us from using the ucode result.
* remove this once ucode is fixed.
*/
-ushort slic_eeprom_cksum(pchar m, int len)
+static ushort slic_eeprom_cksum(char *m, int len)
{
#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x)
#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);\
}
- pushort w;
- ulong32 sum = 0;
- ulong32 byte_swapped = 0;
- ulong32 w_int;
+ u16 *w;
+ u32 sum = 0;
+ u32 byte_swapped = 0;
+ u32 w_int;
union {
char c[2];
@@ -3816,17 +3679,17 @@ ushort slic_eeprom_cksum(pchar m, int len)
l_util.l = 0;
s_util.s = 0;
- w = (pushort) m;
+ w = (u16 *)m;
#ifdef CONFIG_X86_64
- w_int = (ulong32) ((ulong) w & 0x00000000FFFFFFFF);
+ w_int = (u32) ((ulong) w & 0x00000000FFFFFFFF);
#else
- w_int = (ulong32) (w);
+ w_int = (u32) (w);
#endif
if ((1 & w_int) && (len > 0)) {
REDUCE;
sum <<= 8;
- s_util.c[0] = *(puchar) w;
- w = (pushort) ((char *)w + 1);
+ s_util.c[0] = *(unsigned char *)w;
+ w = (u16 *)((char *)w + 1);
len--;
byte_swapped = 1;
}
@@ -3849,7 +3712,7 @@ ushort slic_eeprom_cksum(pchar m, int len)
sum += w[13];
sum += w[14];
sum += w[15];
- w = (pushort) ((ulong) w + 16); /* verify */
+ w = (u16 *)((ulong) w + 16); /* verify */
}
len += 32;
while ((len -= 8) >= 0) {
@@ -3857,7 +3720,7 @@ ushort slic_eeprom_cksum(pchar m, int len)
sum += w[1];
sum += w[2];
sum += w[3];
- w = (pushort) ((ulong) w + 4); /* verify */
+ w = (u16 *)((ulong) w + 4); /* verify */
}
len += 8;
if (len != 0 || byte_swapped != 0) {
@@ -3869,7 +3732,7 @@ ushort slic_eeprom_cksum(pchar m, int len)
sum <<= 8;
byte_swapped = 0;
if (len == -1) {
- s_util.c[1] = *(pchar) w;
+ s_util.c[1] = *(char *) w;
sum += s_util.s;
len = 0;
} else {
@@ -3877,7 +3740,7 @@ ushort slic_eeprom_cksum(pchar m, int len)
}
} else if (len == -1) {
- s_util.c[0] = *(pchar) w;
+ s_util.c[0] = *(char *) w;
}
if (len == -1) {
@@ -3889,17 +3752,17 @@ ushort slic_eeprom_cksum(pchar m, int len)
return (ushort) sum;
}
-int slic_rspqueue_init(p_adapter_t adapter)
+static int slic_rspqueue_init(struct adapter *adapter)
{
int i;
- p_slic_rspqueue_t rspq = &adapter->rspqueue;
- p_slic_regs_t slic_regs = adapter->slic_regs;
- ulong32 paddrh = 0;
+ struct slic_rspqueue *rspq = &adapter->rspqueue;
+ __iomem struct slic_regs *slic_regs = adapter->slic_regs;
+ u32 paddrh = 0;
DBG_MSG("slicoss: %s (%s) ENTER adapter[%p]\n", __func__,
adapter->netdev->name, adapter);
ASSERT(adapter->state == ADAPT_DOWN);
- SLIC_ZERO_MEMORY(rspq, sizeof(slic_rspqueue_t));
+ memset(rspq, 0, sizeof(struct slic_rspqueue));
rspq->num_pages = SLIC_RSPQ_PAGES_GB;
@@ -3914,12 +3777,12 @@ int slic_rspqueue_init(p_adapter_t adapter)
return STATUS_FAILURE;
}
#ifndef CONFIG_X86_64
- ASSERT(((ulong32) rspq->vaddr[i] & 0xFFFFF000) ==
- (ulong32) rspq->vaddr[i]);
- ASSERT(((ulong32) rspq->paddr[i] & 0xFFFFF000) ==
- (ulong32) rspq->paddr[i]);
+ ASSERT(((u32) rspq->vaddr[i] & 0xFFFFF000) ==
+ (u32) rspq->vaddr[i]);
+ ASSERT(((u32) rspq->paddr[i] & 0xFFFFF000) ==
+ (u32) rspq->paddr[i]);
#endif
- SLIC_ZERO_MEMORY(rspq->vaddr[i], PAGE_SIZE);
+ memset(rspq->vaddr[i], 0, PAGE_SIZE);
/* DBG_MSG("slicoss: %s UPLOAD RSPBUFF Page pageix[%x] paddr[%p] "
"vaddr[%p]\n",
__func__, i, (void *)rspq->paddr[i], rspq->vaddr[i]); */
@@ -3938,15 +3801,15 @@ int slic_rspqueue_init(p_adapter_t adapter)
}
rspq->offset = 0;
rspq->pageindex = 0;
- rspq->rspbuf = (p_slic_rspbuf_t) rspq->vaddr[0];
+ rspq->rspbuf = (struct slic_rspbuf *)rspq->vaddr[0];
DBG_MSG("slicoss: %s (%s) EXIT adapter[%p]\n", __func__,
adapter->netdev->name, adapter);
return STATUS_SUCCESS;
}
-int slic_rspqueue_reset(p_adapter_t adapter)
+static int slic_rspqueue_reset(struct adapter *adapter)
{
- p_slic_rspqueue_t rspq = &adapter->rspqueue;
+ struct slic_rspqueue *rspq = &adapter->rspqueue;
DBG_MSG("slicoss: %s (%s) ENTER adapter[%p]\n", __func__,
adapter->netdev->name, adapter);
@@ -3964,10 +3827,10 @@ int slic_rspqueue_reset(p_adapter_t adapter)
return STATUS_SUCCESS;
}
-void slic_rspqueue_free(p_adapter_t adapter)
+static void slic_rspqueue_free(struct adapter *adapter)
{
int i;
- slic_rspqueue_t *rspq = &adapter->rspqueue;
+ struct slic_rspqueue *rspq = &adapter->rspqueue;
DBG_MSG("slicoss: %s adapter[%p] port %d rspq[%p] FreeRSPQ\n",
__func__, adapter, adapter->physport, rspq);
@@ -3976,7 +3839,7 @@ void slic_rspqueue_free(p_adapter_t adapter)
DBG_MSG
("slicoss: pci_free_consistent rspq->vaddr[%p] \
paddr[%p]\n",
- rspq->vaddr[i], (pvoid) rspq->paddr[i]);
+ rspq->vaddr[i], (void *) rspq->paddr[i]);
pci_free_consistent(adapter->pcidev, PAGE_SIZE,
rspq->vaddr[i], rspq->paddr[i]);
}
@@ -3988,10 +3851,10 @@ void slic_rspqueue_free(p_adapter_t adapter)
rspq->rspbuf = NULL;
}
-p_slic_rspbuf_t slic_rspqueue_getnext(p_adapter_t adapter)
+static struct slic_rspbuf *slic_rspqueue_getnext(struct adapter *adapter)
{
- p_slic_rspqueue_t rspq = &adapter->rspqueue;
- p_slic_rspbuf_t buf;
+ struct slic_rspqueue *rspq = &adapter->rspqueue;
+ struct slic_rspbuf *buf;
if (!(rspq->rspbuf->status))
return NULL;
@@ -4004,8 +3867,8 @@ p_slic_rspbuf_t slic_rspqueue_getnext(p_adapter_t adapter)
if (++rspq->offset < SLIC_RSPQ_BUFSINPAGE) {
rspq->rspbuf++;
#ifndef CONFIG_X86_64
- ASSERT(((ulong32) rspq->rspbuf & 0xFFFFFFE0) ==
- (ulong32) rspq->rspbuf);
+ ASSERT(((u32) rspq->rspbuf & 0xFFFFFFE0) ==
+ (u32) rspq->rspbuf);
#endif
} else {
ASSERT(rspq->offset == SLIC_RSPQ_BUFSINPAGE);
@@ -4016,28 +3879,29 @@ p_slic_rspbuf_t slic_rspqueue_getnext(p_adapter_t adapter)
adapter->slic_regs->slic_addr_upper, 0, DONT_FLUSH);
rspq->pageindex = (++rspq->pageindex) % rspq->num_pages;
rspq->offset = 0;
- rspq->rspbuf = (p_slic_rspbuf_t) rspq->vaddr[rspq->pageindex];
+ rspq->rspbuf = (struct slic_rspbuf *)
+ rspq->vaddr[rspq->pageindex];
#ifndef CONFIG_X86_64
- ASSERT(((ulong32) rspq->rspbuf & 0xFFFFF000) ==
- (ulong32) rspq->rspbuf);
+ ASSERT(((u32) rspq->rspbuf & 0xFFFFF000) ==
+ (u32) rspq->rspbuf);
#endif
}
#ifndef CONFIG_X86_64
- ASSERT(((ulong32) buf & 0xFFFFFFE0) == (ulong32) buf);
+ ASSERT(((u32) buf & 0xFFFFFFE0) == (u32) buf);
#endif
return buf;
}
-void slic_cmdqmem_init(p_adapter_t adapter)
+static void slic_cmdqmem_init(struct adapter *adapter)
{
- slic_cmdqmem_t *cmdqmem = &adapter->cmdqmem;
+ struct slic_cmdqmem *cmdqmem = &adapter->cmdqmem;
- SLIC_ZERO_MEMORY(cmdqmem, sizeof(slic_cmdqmem_t));
+ memset(cmdqmem, 0, sizeof(struct slic_cmdqmem));
}
-void slic_cmdqmem_free(p_adapter_t adapter)
+static void slic_cmdqmem_free(struct adapter *adapter)
{
- slic_cmdqmem_t *cmdqmem = &adapter->cmdqmem;
+ struct slic_cmdqmem *cmdqmem = &adapter->cmdqmem;
int i;
DBG_MSG("slicoss: (%s) adapter[%p] port %d rspq[%p] Free CMDQ Memory\n",
@@ -4045,20 +3909,20 @@ void slic_cmdqmem_free(p_adapter_t adapter)
for (i = 0; i < SLIC_CMDQ_MAXPAGES; i++) {
if (cmdqmem->pages[i]) {
DBG_MSG("slicoss: %s Deallocate page CmdQPage[%p]\n",
- __func__, (pvoid) cmdqmem->pages[i]);
+ __func__, (void *) cmdqmem->pages[i]);
pci_free_consistent(adapter->pcidev,
PAGE_SIZE,
- (pvoid) cmdqmem->pages[i],
+ (void *) cmdqmem->pages[i],
cmdqmem->dma_pages[i]);
}
}
- SLIC_ZERO_MEMORY(cmdqmem, sizeof(slic_cmdqmem_t));
+ memset(cmdqmem, 0, sizeof(struct slic_cmdqmem));
}
-pulong32 slic_cmdqmem_addpage(p_adapter_t adapter)
+static u32 *slic_cmdqmem_addpage(struct adapter *adapter)
{
- p_slic_cmdqmem_t cmdqmem = &adapter->cmdqmem;
- pulong32 pageaddr;
+ struct slic_cmdqmem *cmdqmem = &adapter->cmdqmem;
+ u32 *pageaddr;
if (cmdqmem->pagecnt >= SLIC_CMDQ_MAXPAGES)
return NULL;
@@ -4068,32 +3932,32 @@ pulong32 slic_cmdqmem_addpage(p_adapter_t adapter)
if (!pageaddr)
return NULL;
#ifndef CONFIG_X86_64
- ASSERT(((ulong32) pageaddr & 0xFFFFF000) == (ulong32) pageaddr);
+ ASSERT(((u32) pageaddr & 0xFFFFF000) == (u32) pageaddr);
#endif
cmdqmem->pages[cmdqmem->pagecnt] = pageaddr;
cmdqmem->pagecnt++;
return pageaddr;
}
-int slic_cmdq_init(p_adapter_t adapter)
+static int slic_cmdq_init(struct adapter *adapter)
{
int i;
- pulong32 pageaddr;
+ u32 *pageaddr;
DBG_MSG("slicoss: %s ENTER adapter[%p]\n", __func__, adapter);
ASSERT(adapter->state == ADAPT_DOWN);
- SLIC_ZERO_MEMORY(&adapter->cmdq_all, sizeof(slic_cmdqueue_t));
- SLIC_ZERO_MEMORY(&adapter->cmdq_free, sizeof(slic_cmdqueue_t));
- SLIC_ZERO_MEMORY(&adapter->cmdq_done, sizeof(slic_cmdqueue_t));
- SLIC_INIT_SPINLOCK(adapter->cmdq_all.lock);
- SLIC_INIT_SPINLOCK(adapter->cmdq_free.lock);
- SLIC_INIT_SPINLOCK(adapter->cmdq_done.lock);
+ memset(&adapter->cmdq_all, 0, sizeof(struct slic_cmdqueue));
+ memset(&adapter->cmdq_free, 0, sizeof(struct slic_cmdqueue));
+ memset(&adapter->cmdq_done, 0, sizeof(struct slic_cmdqueue));
+ spin_lock_init(&adapter->cmdq_all.lock.lock);
+ spin_lock_init(&adapter->cmdq_free.lock.lock);
+ spin_lock_init(&adapter->cmdq_done.lock.lock);
slic_cmdqmem_init(adapter);
adapter->slic_handle_ix = 1;
for (i = 0; i < SLIC_CMDQ_INITPAGES; i++) {
pageaddr = slic_cmdqmem_addpage(adapter);
#ifndef CONFIG_X86_64
- ASSERT(((ulong32) pageaddr & 0xFFFFF000) == (ulong32) pageaddr);
+ ASSERT(((u32) pageaddr & 0xFFFFF000) == (u32) pageaddr);
#endif
if (!pageaddr) {
slic_cmdq_free(adapter);
@@ -4107,9 +3971,9 @@ int slic_cmdq_init(p_adapter_t adapter)
return STATUS_SUCCESS;
}
-void slic_cmdq_free(p_adapter_t adapter)
+static void slic_cmdq_free(struct adapter *adapter)
{
- p_slic_hostcmd_t cmd;
+ struct slic_hostcmd *cmd;
DBG_MSG("slicoss: %s adapter[%p] port %d FreeCommandsFrom CMDQ\n",
__func__, adapter, adapter->physport);
@@ -4126,21 +3990,23 @@ void slic_cmdq_free(p_adapter_t adapter)
}
cmd = cmd->next_all;
}
- SLIC_ZERO_MEMORY(&adapter->cmdq_all, sizeof(slic_cmdqueue_t));
- SLIC_ZERO_MEMORY(&adapter->cmdq_free, sizeof(slic_cmdqueue_t));
- SLIC_ZERO_MEMORY(&adapter->cmdq_done, sizeof(slic_cmdqueue_t));
+ memset(&adapter->cmdq_all, 0, sizeof(struct slic_cmdqueue));
+ memset(&adapter->cmdq_free, 0, sizeof(struct slic_cmdqueue));
+ memset(&adapter->cmdq_done, 0, sizeof(struct slic_cmdqueue));
slic_cmdqmem_free(adapter);
}
-void slic_cmdq_reset(p_adapter_t adapter)
+static void slic_cmdq_reset(struct adapter *adapter)
{
- p_slic_hostcmd_t hcmd;
+ struct slic_hostcmd *hcmd;
struct sk_buff *skb;
- ulong32 outstanding;
+ u32 outstanding;
DBG_MSG("%s ENTER adapter[%p]\n", __func__, adapter);
- SLIC_ACQUIRE_IRQ_SPINLOCK(adapter->cmdq_free.lock);
- SLIC_ACQUIRE_IRQ_SPINLOCK(adapter->cmdq_done.lock);
+ spin_lock_irqsave(&adapter->cmdq_free.lock.lock,
+ adapter->cmdq_free.lock.flags);
+ spin_lock_irqsave(&adapter->cmdq_done.lock.lock,
+ adapter->cmdq_done.lock.flags);
outstanding = adapter->cmdq_all.count - adapter->cmdq_done.count;
outstanding -= adapter->cmdq_free.count;
hcmd = adapter->cmdq_all.head;
@@ -4174,31 +4040,33 @@ void slic_cmdq_reset(p_adapter_t adapter)
DBG_ERROR("%s free_count %d != all count %d\n", __func__,
adapter->cmdq_free.count, adapter->cmdq_all.count);
}
- SLIC_RELEASE_IRQ_SPINLOCK(adapter->cmdq_done.lock);
- SLIC_RELEASE_IRQ_SPINLOCK(adapter->cmdq_free.lock);
+ spin_unlock_irqrestore(&adapter->cmdq_done.lock.lock,
+ adapter->cmdq_done.lock.flags);
+ spin_unlock_irqrestore(&adapter->cmdq_free.lock.lock,
+ adapter->cmdq_free.lock.flags);
DBG_MSG("%s EXIT adapter[%p]\n", __func__, adapter);
}
-void slic_cmdq_addcmdpage(p_adapter_t adapter, pulong32 page)
+static void slic_cmdq_addcmdpage(struct adapter *adapter, u32 *page)
{
- p_slic_hostcmd_t cmd;
- p_slic_hostcmd_t prev;
- p_slic_hostcmd_t tail;
- p_slic_cmdqueue_t cmdq;
+ struct slic_hostcmd *cmd;
+ struct slic_hostcmd *prev;
+ struct slic_hostcmd *tail;
+ struct slic_cmdqueue *cmdq;
int cmdcnt;
- pvoid cmdaddr;
+ void *cmdaddr;
ulong phys_addr;
- ulong32 phys_addrl;
- ulong32 phys_addrh;
- pslic_handle_t pslic_handle;
+ u32 phys_addrl;
+ u32 phys_addrh;
+ struct slic_handle *pslic_handle;
cmdaddr = page;
- cmd = (p_slic_hostcmd_t) cmdaddr;
+ cmd = (struct slic_hostcmd *)cmdaddr;
/* DBG_MSG("CMDQ Page addr[%p] ix[%d] pfree[%p]\n", cmdaddr, slic_handle_ix,
adapter->pfree_slic_handles); */
cmdcnt = 0;
- phys_addr = SLIC_GET_PHYSICAL_ADDRESS((void *)page);
+ phys_addr = virt_to_bus((void *)page);
phys_addrl = SLIC_GET_ADDR_LOW(phys_addr);
phys_addrh = SLIC_GET_ADDR_HIGH(phys_addr);
@@ -4214,7 +4082,7 @@ void slic_cmdq_addcmdpage(p_adapter_t adapter, pulong32 page)
&adapter->slic_handles[pslic_handle->token.
handle_index]);
pslic_handle->type = SLIC_HANDLE_CMD;
- pslic_handle->address = (pvoid) cmd;
+ pslic_handle->address = (void *) cmd;
pslic_handle->offset = (ushort) adapter->slic_handle_ix++;
pslic_handle->other_handle = NULL;
pslic_handle->next = NULL;
@@ -4230,7 +4098,7 @@ void slic_cmdq_addcmdpage(p_adapter_t adapter, pulong32 page)
phys_addrl += SLIC_HOSTCMD_SIZE;
cmdaddr += SLIC_HOSTCMD_SIZE;
- cmd = (p_slic_hostcmd_t) cmdaddr;
+ cmd = (struct slic_hostcmd *)cmdaddr;
cmdcnt++;
}
@@ -4240,36 +4108,37 @@ void slic_cmdq_addcmdpage(p_adapter_t adapter, pulong32 page)
ASSERT(VALID_ADDRESS(prev));
cmdq->head = prev;
cmdq = &adapter->cmdq_free;
- SLIC_ACQUIRE_IRQ_SPINLOCK(cmdq->lock);
+ spin_lock_irqsave(&cmdq->lock.lock, cmdq->lock.flags);
cmdq->count += cmdcnt; /* SLIC_CMDQ_CMDSINPAGE; mooktodo */
tail->next = cmdq->head;
ASSERT(VALID_ADDRESS(prev));
cmdq->head = prev;
- SLIC_RELEASE_IRQ_SPINLOCK(cmdq->lock);
+ spin_unlock_irqrestore(&cmdq->lock.lock, cmdq->lock.flags);
}
-p_slic_hostcmd_t slic_cmdq_getfree(p_adapter_t adapter)
+static struct slic_hostcmd *slic_cmdq_getfree(struct adapter *adapter)
{
- p_slic_cmdqueue_t cmdq = &adapter->cmdq_free;
- p_slic_hostcmd_t cmd = NULL;
+ struct slic_cmdqueue *cmdq = &adapter->cmdq_free;
+ struct slic_hostcmd *cmd = NULL;
lock_and_retry:
- SLIC_ACQUIRE_IRQ_SPINLOCK(cmdq->lock);
+ spin_lock_irqsave(&cmdq->lock.lock, cmdq->lock.flags);
retry:
cmd = cmdq->head;
if (cmd) {
cmdq->head = cmd->next;
cmdq->count--;
- SLIC_RELEASE_IRQ_SPINLOCK(cmdq->lock);
+ spin_unlock_irqrestore(&cmdq->lock.lock, cmdq->lock.flags);
} else {
slic_cmdq_getdone(adapter);
cmd = cmdq->head;
if (cmd) {
goto retry;
} else {
- pulong32 pageaddr;
+ u32 *pageaddr;
- SLIC_RELEASE_IRQ_SPINLOCK(cmdq->lock);
+ spin_unlock_irqrestore(&cmdq->lock.lock,
+ cmdq->lock.flags);
pageaddr = slic_cmdqmem_addpage(adapter);
if (pageaddr) {
slic_cmdq_addcmdpage(adapter, pageaddr);
@@ -4280,13 +4149,13 @@ retry:
return cmd;
}
-void slic_cmdq_getdone(p_adapter_t adapter)
+static void slic_cmdq_getdone(struct adapter *adapter)
{
- p_slic_cmdqueue_t done_cmdq = &adapter->cmdq_done;
- p_slic_cmdqueue_t free_cmdq = &adapter->cmdq_free;
+ struct slic_cmdqueue *done_cmdq = &adapter->cmdq_done;
+ struct slic_cmdqueue *free_cmdq = &adapter->cmdq_free;
ASSERT(free_cmdq->head == NULL);
- SLIC_ACQUIRE_IRQ_SPINLOCK(done_cmdq->lock);
+ spin_lock_irqsave(&done_cmdq->lock.lock, done_cmdq->lock.flags);
ASSERT(VALID_ADDRESS(done_cmdq->head));
free_cmdq->head = done_cmdq->head;
@@ -4294,28 +4163,15 @@ void slic_cmdq_getdone(p_adapter_t adapter)
done_cmdq->head = NULL;
done_cmdq->tail = NULL;
done_cmdq->count = 0;
- SLIC_RELEASE_IRQ_SPINLOCK(done_cmdq->lock);
+ spin_unlock_irqrestore(&done_cmdq->lock.lock, done_cmdq->lock.flags);
}
-void slic_cmdq_putdone(p_adapter_t adapter, p_slic_hostcmd_t cmd)
+static void slic_cmdq_putdone_irq(struct adapter *adapter,
+ struct slic_hostcmd *cmd)
{
- p_slic_cmdqueue_t cmdq = &adapter->cmdq_done;
+ struct slic_cmdqueue *cmdq = &adapter->cmdq_done;
- SLIC_ACQUIRE_IRQ_SPINLOCK(cmdq->lock);
- cmd->busy = 0;
- ASSERT(VALID_ADDRESS(cmdq->head));
- cmd->next = cmdq->head;
- ASSERT(VALID_ADDRESS(cmd));
- cmdq->head = cmd;
- cmdq->count++;
- SLIC_RELEASE_IRQ_SPINLOCK(cmdq->lock);
-}
-
-void slic_cmdq_putdone_irq(p_adapter_t adapter, p_slic_hostcmd_t cmd)
-{
- p_slic_cmdqueue_t cmdq = &adapter->cmdq_done;
-
- SLIC_ACQUIRE_SPINLOCK(cmdq->lock);
+ spin_lock(&cmdq->lock.lock);
cmd->busy = 0;
ASSERT(VALID_ADDRESS(cmdq->head));
cmd->next = cmdq->head;
@@ -4324,13 +4180,13 @@ void slic_cmdq_putdone_irq(p_adapter_t adapter, p_slic_hostcmd_t cmd)
cmdq->count++;
if ((adapter->xmitq_full) && (cmdq->count > 10))
netif_wake_queue(adapter->netdev);
- SLIC_RELEASE_SPINLOCK(cmdq->lock);
+ spin_unlock(&cmdq->lock.lock);
}
-int slic_rcvqueue_init(p_adapter_t adapter)
+static int slic_rcvqueue_init(struct adapter *adapter)
{
int i, count;
- p_slic_rcvqueue_t rcvq = &adapter->rcvqueue;
+ struct slic_rcvqueue *rcvq = &adapter->rcvqueue;
DBG_MSG("slicoss: %s ENTER adapter[%p]\n", __func__, adapter);
ASSERT(adapter->state == ADAPT_DOWN);
@@ -4353,9 +4209,9 @@ int slic_rcvqueue_init(p_adapter_t adapter)
return STATUS_SUCCESS;
}
-int slic_rcvqueue_reset(p_adapter_t adapter)
+static int slic_rcvqueue_reset(struct adapter *adapter)
{
- p_slic_rcvqueue_t rcvq = &adapter->rcvqueue;
+ struct slic_rcvqueue *rcvq = &adapter->rcvqueue;
DBG_MSG("slicoss: %s ENTER adapter[%p]\n", __func__, adapter);
ASSERT(adapter->state == ADAPT_DOWN);
@@ -4371,9 +4227,9 @@ int slic_rcvqueue_reset(p_adapter_t adapter)
return STATUS_SUCCESS;
}
-void slic_rcvqueue_free(p_adapter_t adapter)
+static void slic_rcvqueue_free(struct adapter *adapter)
{
- slic_rcvqueue_t *rcvq = &adapter->rcvqueue;
+ struct slic_rcvqueue *rcvq = &adapter->rcvqueue;
struct sk_buff *skb;
while (rcvq->head) {
@@ -4386,16 +4242,16 @@ void slic_rcvqueue_free(p_adapter_t adapter)
rcvq->count = 0;
}
-struct sk_buff *slic_rcvqueue_getnext(p_adapter_t adapter)
+static struct sk_buff *slic_rcvqueue_getnext(struct adapter *adapter)
{
- p_slic_rcvqueue_t rcvq = &adapter->rcvqueue;
+ struct slic_rcvqueue *rcvq = &adapter->rcvqueue;
struct sk_buff *skb;
- p_slic_rcvbuf_t rcvbuf;
+ struct slic_rcvbuf *rcvbuf;
int count;
if (rcvq->count) {
skb = rcvq->head;
- rcvbuf = (p_slic_rcvbuf_t) skb->head;
+ rcvbuf = (struct slic_rcvbuf *)skb->head;
ASSERT(rcvbuf);
if (rcvbuf->status & IRHDDR_SVALID) {
@@ -4420,30 +4276,31 @@ struct sk_buff *slic_rcvqueue_getnext(p_adapter_t adapter)
return skb;
}
-int slic_rcvqueue_fill(p_adapter_t adapter)
+static int slic_rcvqueue_fill(struct adapter *adapter)
{
- pvoid paddr;
- ulong32 paddrl;
- ulong32 paddrh;
- p_slic_rcvqueue_t rcvq = &adapter->rcvqueue;
+ void *paddr;
+ u32 paddrl;
+ u32 paddrh;
+ struct slic_rcvqueue *rcvq = &adapter->rcvqueue;
int i = 0;
while (i < SLIC_RCVQ_FILLENTRIES) {
- p_slic_rcvbuf_t rcvbuf;
+ struct slic_rcvbuf *rcvbuf;
struct sk_buff *skb;
#ifdef KLUDGE_FOR_4GB_BOUNDARY
retry_rcvqfill:
#endif
skb = alloc_skb(SLIC_RCVQ_RCVBUFSIZE, GFP_ATOMIC);
if (skb) {
- paddr = (void *)SLIC_GET_DMA_ADDRESS_READ(adapter,
+ paddr = (void *)pci_map_single(adapter->pcidev,
skb->data,
- SLIC_RCVQ_RCVBUFSIZE);
+ SLIC_RCVQ_RCVBUFSIZE,
+ PCI_DMA_FROMDEVICE);
paddrl = SLIC_GET_ADDR_LOW(paddr);
paddrh = SLIC_GET_ADDR_HIGH(paddr);
skb->len = SLIC_RCVBUF_HEADSIZE;
- rcvbuf = (p_slic_rcvbuf_t) skb->head;
+ rcvbuf = (struct slic_rcvbuf *)skb->head;
rcvbuf->status = 0;
skb->next = NULL;
#ifdef KLUDGE_FOR_4GB_BOUNDARY
@@ -4479,13 +4336,13 @@ retry_rcvqfill:
#endif
if (paddrh == 0) {
WRITE_REG(adapter->slic_regs->slic_hbar,
- (ulong32) paddrl, DONT_FLUSH);
+ (u32) paddrl, DONT_FLUSH);
} else {
WRITE_REG64(adapter,
adapter->slic_regs->slic_hbar64,
- (ulong32) paddrl,
+ (u32) paddrl,
adapter->slic_regs->slic_addr_upper,
- (ulong32) paddrh, DONT_FLUSH);
+ (u32) paddrh, DONT_FLUSH);
}
if (rcvq->head)
rcvq->tail->next = skb;
@@ -4505,18 +4362,18 @@ retry_rcvqfill:
return i;
}
-ulong32 slic_rcvqueue_reinsert(p_adapter_t adapter, struct sk_buff *skb)
+static u32 slic_rcvqueue_reinsert(struct adapter *adapter, struct sk_buff *skb)
{
- p_slic_rcvqueue_t rcvq = &adapter->rcvqueue;
- pvoid paddr;
- ulong32 paddrl;
- ulong32 paddrh;
- p_slic_rcvbuf_t rcvbuf = (p_slic_rcvbuf_t) skb->head;
+ struct slic_rcvqueue *rcvq = &adapter->rcvqueue;
+ void *paddr;
+ u32 paddrl;
+ u32 paddrh;
+ struct slic_rcvbuf *rcvbuf = (struct slic_rcvbuf *)skb->head;
ASSERT(skb->len == SLIC_RCVBUF_HEADSIZE);
- paddr = (void *)SLIC_GET_DMA_ADDRESS_READ(adapter,
- skb->head,
- SLIC_RCVQ_RCVBUFSIZE);
+
+ paddr = (void *)pci_map_single(adapter->pcidev, skb->head,
+ SLIC_RCVQ_RCVBUFSIZE, PCI_DMA_FROMDEVICE);
rcvbuf->status = 0;
skb->next = NULL;
@@ -4536,7 +4393,7 @@ ulong32 slic_rcvqueue_reinsert(p_adapter_t adapter, struct sk_buff *skb)
rcvq->count);
}
if (paddrh == 0) {
- WRITE_REG(adapter->slic_regs->slic_hbar, (ulong32) paddrl,
+ WRITE_REG(adapter->slic_regs->slic_hbar, (u32) paddrl,
DONT_FLUSH);
} else {
WRITE_REG64(adapter,
@@ -4558,10 +4415,10 @@ static int slic_debug_card_show(struct seq_file *seq, void *v)
{
#ifdef MOOKTODO
int i;
- p_sliccard_t card = seq->private;
+ struct sliccard *card = seq->private;
pslic_config_t config = &card->config;
- puchar fru = (puchar) (&card->config.atk_fru);
- puchar oemfru = (puchar) (&card->config.OemFru);
+ unsigned char *fru = (unsigned char *)(&card->config.atk_fru);
+ unsigned char *oemfru = (unsigned char *)(&card->config.OemFru);
#endif
seq_printf(seq, "driver_version : %s", slic_proc_version);
@@ -4600,7 +4457,7 @@ static int slic_debug_card_show(struct seq_file *seq, void *v)
seq_printf(seq, " IF Init State Duplex/Speed irq\n");
seq_printf(seq, " -------------------------------\n");
for (i = 0; i < card->adapters_allocated; i++) {
- p_adapter_t adapter;
+ struct adapter *adapter;
adapter = card->adapter[i];
if (adapter) {
@@ -4768,7 +4625,7 @@ static int slic_debug_card_show(struct seq_file *seq, void *v)
static int slic_debug_adapter_show(struct seq_file *seq, void *v)
{
- p_adapter_t adapter = seq->private;
+ struct adapter *adapter = seq->private;
if ((adapter->netdev) && (adapter->netdev->name)) {
seq_printf(seq, "info: interface : %s\n",
@@ -4801,21 +4658,21 @@ static int slic_debug_adapter_show(struct seq_file *seq, void *v)
seq_printf(seq, "rx stats: unicasts : %8.8X\n",
adapter->rcv_unicasts);
seq_printf(seq, "rx stats: errors : %8.8X\n",
- (ulong32) adapter->slic_stats.iface.rcv_errors);
+ (u32) adapter->slic_stats.iface.rcv_errors);
seq_printf(seq, "rx stats: Missed errors : %8.8X\n",
- (ulong32) adapter->slic_stats.iface.rcv_discards);
+ (u32) adapter->slic_stats.iface.rcv_discards);
seq_printf(seq, "rx stats: drops : %8.8X\n",
- (ulong32) adapter->rcv_drops);
+ (u32) adapter->rcv_drops);
seq_printf(seq, "tx stats: packets : %8.8lX\n",
adapter->stats.tx_packets);
seq_printf(seq, "tx stats: bytes : %8.8lX\n",
adapter->stats.tx_bytes);
seq_printf(seq, "tx stats: errors : %8.8X\n",
- (ulong32) adapter->slic_stats.iface.xmt_errors);
+ (u32) adapter->slic_stats.iface.xmt_errors);
seq_printf(seq, "rx stats: multicasts : %8.8lX\n",
adapter->stats.multicast);
seq_printf(seq, "tx stats: collision errors : %8.8X\n",
- (ulong32) adapter->slic_stats.iface.xmit_collisions);
+ (u32) adapter->slic_stats.iface.xmit_collisions);
seq_printf(seq, "perf: Max rcv frames/isr : %8.8X\n",
adapter->max_isr_rcvs);
seq_printf(seq, "perf: Rcv interrupt yields : %8.8X\n",
@@ -4905,11 +4762,11 @@ static const struct file_operations slic_debug_card_fops = {
.release = single_release,
};
-static void slic_debug_adapter_create(p_adapter_t adapter)
+static void slic_debug_adapter_create(struct adapter *adapter)
{
struct dentry *d;
char name[7];
- p_sliccard_t card = adapter->card;
+ struct sliccard *card = adapter->card;
if (!card->debugfs_dir)
return;
@@ -4924,7 +4781,7 @@ static void slic_debug_adapter_create(p_adapter_t adapter)
adapter->debugfs_entry = d;
}
-static void slic_debug_adapter_destroy(p_adapter_t adapter)
+static void slic_debug_adapter_destroy(struct adapter *adapter)
{
if (adapter->debugfs_entry) {
debugfs_remove(adapter->debugfs_entry);
@@ -4932,7 +4789,7 @@ static void slic_debug_adapter_destroy(p_adapter_t adapter)
}
}
-static void slic_debug_card_create(p_sliccard_t card)
+static void slic_debug_card_create(struct sliccard *card)
{
struct dentry *d;
char name[IFNAMSIZ];
@@ -4955,12 +4812,12 @@ static void slic_debug_card_create(p_sliccard_t card)
}
}
-static void slic_debug_card_destroy(p_sliccard_t card)
+static void slic_debug_card_destroy(struct sliccard *card)
{
int i;
for (i = 0; i < card->card_size; i++) {
- p_adapter_t adapter;
+ struct adapter *adapter;
adapter = card->adapter[i];
if (adapter)
@@ -5013,17 +4870,17 @@ static void slic_debug_cleanup(void)
#include <stdarg.h>
-pvoid slic_dump_handle; /* thread handle */
+void *slic_dump_handle; /* thread handle */
/*
* These are the only things you should do on a core-file: use only these
* functions to write out all the necessary info.
*/
-static int slic_dump_seek(struct file *SLIChandle, ulong32 file_offset)
+static int slic_dump_seek(struct file *SLIChandle, u32 file_offset)
{
if (SLIChandle->f_pos != file_offset) {
/*DBG_MSG("slic_dump_seek now needed [%x : %x]\n",
- (ulong32)SLIChandle->f_pos, (ulong32)file_offset); */
+ (u32)SLIChandle->f_pos, (u32)file_offset); */
if (SLIChandle->f_op->llseek) {
if (SLIChandle->f_op->
llseek(SLIChandle, file_offset, 0) != file_offset)
@@ -5035,11 +4892,11 @@ static int slic_dump_seek(struct file *SLIChandle, ulong32 file_offset)
return 1;
}
-static int slic_dump_write(p_sliccard_t card,
- const void *addr, int size, ulong32 file_offset)
+static int slic_dump_write(struct sliccard *card,
+ const void *addr, int size, u32 file_offset)
{
int r = 1;
- ulong32 result = 0;
+ u32 result = 0;
struct file *SLIChandle = card->dumphandle;
#ifdef HISTORICAL /* legacy */
@@ -5069,7 +4926,7 @@ static int slic_dump_write(p_sliccard_t card,
return r;
}
-uint slic_init_dump_thread(p_sliccard_t card)
+static uint slic_init_dump_thread(struct sliccard *card)
{
card->dump_task_id = kthread_run(slic_dump_thread, (void *)card, 0);
@@ -5082,17 +4939,17 @@ uint slic_init_dump_thread(p_sliccard_t card)
return STATUS_SUCCESS;
}
-int slic_dump_thread(void *context)
+static int slic_dump_thread(void *context)
{
- p_sliccard_t card = (p_sliccard_t) context;
- p_adapter_t adapter;
- p_adapter_t dump_adapter = NULL;
- ulong32 dump_complete = 0;
- ulong32 delay = SLIC_SECS_TO_JIFFS(PING_TIMER_INTERVAL);
- p_slic_regs_t pregs;
- ulong32 i;
- p_slic_upr_t upr, uprnext;
- ulong32 dump_card;
+ struct sliccard *card = (struct sliccard *)context;
+ struct adapter *adapter;
+ struct adapter *dump_adapter = NULL;
+ u32 dump_complete = 0;
+ u32 delay = SLIC_SECS_TO_JIFFS(PING_TIMER_INTERVAL);
+ struct slic_regs *pregs;
+ u32 i;
+ struct slic_upr *upr, *uprnext;
+ u32 dump_card;
ASSERT(card);
@@ -5248,19 +5105,20 @@ int slic_dump_thread(void *context)
* now.
*/
if (!card->pingstatus) {
- SLIC_ACQUIRE_IRQ_SPINLOCK
- (adapter->upr_lock);
+ spin_lock_irqsave(
+ &adapter->upr_lock.lock,
+ adapter->upr_lock.flags);
upr = adapter->upr_list;
while (upr) {
uprnext = upr->next;
- SLIC_DEALLOCATE_MEM
- (upr);
+ kfree(upr);
upr = uprnext;
}
adapter->upr_list = 0;
adapter->upr_busy = 0;
- SLIC_RELEASE_IRQ_SPINLOCK
- (adapter->upr_lock);
+ spin_unlock_irqrestore(
+ &adapter->upr_lock.lock,
+ adapter->upr_lock.flags);
}
slic_dump_card(card, FALSE);
@@ -5340,13 +5198,13 @@ end_thread:
* value is used as our suffix for our dump path. The
* value is incremented and written back to the file
*/
-uchar slic_get_dump_index(pchar path)
+static unsigned char slic_get_dump_index(char *path)
{
- uchar index = 0;
+ unsigned char index = 0;
#ifdef SLIC_DUMP_INDEX_SUPPORT
- ulong32 status;
- pvoid FileHandle;
- ulong32 offset;
+ u32 status;
+ void *FileHandle;
+ u32 offset;
offset = 0;
@@ -5356,7 +5214,7 @@ uchar slic_get_dump_index(pchar path)
status = create_file(&FileHandle);
if (status != STATUS_SUCCESS)
- return (uchar) 0;
+ return (unsigned char) 0;
status = read_file(FileHandle, &index, 1, &offset);
@@ -5371,7 +5229,7 @@ uchar slic_get_dump_index(pchar path)
return index;
}
-struct file *slic_dump_open_file(p_sliccard_t card)
+static struct file *slic_dump_open_file(struct sliccard *card)
{
struct file *SLIChandle = NULL;
struct dentry *dentry = NULL;
@@ -5434,7 +5292,7 @@ end_slicdump:
return NULL;
}
-void slic_dump_close_file(p_sliccard_t card)
+static void slic_dump_close_file(struct sliccard *card)
{
/* DBG_MSG("[slicmon] slic_dump_CLOSE_file close SLIChandle[%p]\n",
@@ -5445,19 +5303,19 @@ void slic_dump_close_file(p_sliccard_t card)
set_fs(card->dumpfile_fs);
}
-ulong32 slic_dump_card(p_sliccard_t card, boolean resume)
+static u32 slic_dump_card(struct sliccard *card, bool resume)
{
- p_adapter_t adapter = card->master;
- ulong32 status;
- ulong32 queue;
- ulong32 len, offset;
- ulong32 sram_size, dram_size, regs;
+ struct adapter *adapter = card->master;
+ u32 status;
+ u32 queue;
+ u32 len, offset;
+ u32 sram_size, dram_size, regs;
sliccore_hdr_t corehdr;
- ulong32 file_offset;
- pchar namestr;
- ulong32 i;
- ulong32 max_queues = 0;
- ulong32 result;
+ u32 file_offset;
+ char *namestr;
+ u32 i;
+ u32 max_queues = 0;
+ u32 result;
card->dumphandle = slic_dump_open_file(card);
@@ -5672,12 +5530,12 @@ ulong32 slic_dump_card(p_sliccard_t card, boolean resume)
max_queues = SLIC_MAX_QUEUE;
for (queue = 0; queue < max_queues; queue++) {
- pulong32 qarray = (pulong32) card->dumpbuffer;
- ulong32 qarray_physl = card->dumpbuffer_physl;
- ulong32 qarray_physh = card->dumpbuffer_physh;
- ulong32 qstart;
- ulong32 qdelta;
- ulong32 qtotal = 0;
+ u32 *qarray = (u32 *) card->dumpbuffer;
+ u32 qarray_physl = card->dumpbuffer_physl;
+ u32 qarray_physh = card->dumpbuffer_physh;
+ u32 qstart;
+ u32 qdelta;
+ u32 qtotal = 0;
DBG_MSG("[slicmon] Start Dump of QUEUE #0x%x\n", (uint) queue);
@@ -5823,9 +5681,9 @@ done:
return status;
}
-ulong32 slic_dump_halt(p_sliccard_t card, uchar proc)
+static u32 slic_dump_halt(struct sliccard *card, unsigned char proc)
{
- puchar cmd = card->cmdbuffer;
+ unsigned char *cmd = card->cmdbuffer;
*cmd = COMMAND_BYTE(CMD_HALT, 0, proc);
@@ -5834,9 +5692,9 @@ ulong32 slic_dump_halt(p_sliccard_t card, uchar proc)
card->cmdbuffer_physh, 0, 0);
}
-ulong32 slic_dump_resume(p_sliccard_t card, uchar proc)
+static u32 slic_dump_resume(struct sliccard *card, unsigned char proc)
{
- puchar cmd = card->cmdbuffer;
+ unsigned char *cmd = card->cmdbuffer;
*cmd = COMMAND_BYTE(CMD_RUN, 0, proc);
@@ -5845,7 +5703,7 @@ ulong32 slic_dump_resume(p_sliccard_t card, uchar proc)
card->cmdbuffer_physh, 0, 0);
}
-ulong32 slic_dump_reg(p_sliccard_t card, uchar proc)
+static u32 slic_dump_reg(struct sliccard *card, unsigned char proc)
{
pdump_cmd_t dump = (pdump_cmd_t) card->cmdbuffer;
@@ -5861,8 +5719,8 @@ ulong32 slic_dump_reg(p_sliccard_t card, uchar proc)
card->dumpbuffer_physh);
}
-ulong32 slic_dump_data(p_sliccard_t card,
- ulong32 addr, ushort count, uchar desc)
+static u32 slic_dump_data(struct sliccard *card,
+ u32 addr, ushort count, unsigned char desc)
{
pdump_cmd_t dump = (pdump_cmd_t) card->cmdbuffer;
@@ -5878,8 +5736,8 @@ ulong32 slic_dump_data(p_sliccard_t card,
card->dumpbuffer_physh);
}
-ulong32 slic_dump_queue(p_sliccard_t card,
- ulong32 addr, ulong32 buf_physh, ulong32 queue)
+static u32 slic_dump_queue(struct sliccard *card,
+ u32 addr, u32 buf_physh, u32 queue)
{
pdump_cmd_t dump = (pdump_cmd_t) card->cmdbuffer;
@@ -5894,7 +5752,8 @@ ulong32 slic_dump_queue(p_sliccard_t card,
addr, card->dumpbuffer_physh);
}
-ulong32 slic_dump_load_queue(p_sliccard_t card, ulong32 data, ulong32 queue)
+static u32 slic_dump_load_queue(struct sliccard *card, u32 data,
+ u32 queue)
{
pdump_cmd_t load = (pdump_cmd_t) card->cmdbuffer;
@@ -5908,8 +5767,8 @@ ulong32 slic_dump_load_queue(p_sliccard_t card, ulong32 data, ulong32 queue)
card->cmdbuffer_physh, 0, 0);
}
-ulong32 slic_dump_cam(p_sliccard_t card,
- ulong32 addr, ulong32 count, uchar desc)
+static u32 slic_dump_cam(struct sliccard *card,
+ u32 addr, u32 count, unsigned char desc)
{
pdump_cmd_t dump = (pdump_cmd_t) card->cmdbuffer;
@@ -5924,15 +5783,15 @@ ulong32 slic_dump_cam(p_sliccard_t card,
addr, card->dumpbuffer_physh);
}
-ulong32 slic_dump_send_cmd(p_sliccard_t card,
- ulong32 cmd_physl,
- ulong32 cmd_physh,
- ulong32 buf_physl, ulong32 buf_physh)
+static u32 slic_dump_send_cmd(struct sliccard *card,
+ u32 cmd_physl,
+ u32 cmd_physh,
+ u32 buf_physl, u32 buf_physh)
{
ulong timeout = SLIC_MS_TO_JIFFIES(500); /* 500 msec */
- ulong32 attempts = 5;
- ulong32 delay = SLIC_MS_TO_JIFFIES(10); /* 10 msec */
- p_adapter_t adapter = card->master;
+ u32 attempts = 5;
+ u32 delay = SLIC_MS_TO_JIFFIES(10); /* 10 msec */
+ struct adapter *adapter = card->master;
ASSERT(adapter);
do {
--
1.6.0.2
^ permalink raw reply related [flat|nested] 37+ messages in thread* [PATCH 20/23] Staging: SLICOSS: Fix warnings due to static usage
2008-10-10 22:41 [GIT PATCH] STAGING patches for 2.6.28 Greg KH
` (14 preceding siblings ...)
2008-10-10 22:42 ` [PATCH 19/23] Staging: SLICOSS: lots of checkpatch fixes Greg KH
@ 2008-10-10 22:42 ` Greg KH
2008-10-10 22:42 ` [PATCH 21/23] Staging: SLICOSS: Fix remaining type names Greg KH
` (3 subsequent siblings)
19 siblings, 0 replies; 37+ messages in thread
From: Greg KH @ 2008-10-10 22:42 UTC (permalink / raw)
To: linux-kernel; +Cc: Lior Dotan, Greg Kroah-Hartman
From: Lior Dotan <liodot@gmail.com>
Fix a few warning messages that crept in due to conversion of all the
functions to static
Signed-off-by: Lior Dotan <liodot@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/slicoss/slicinc.h | 6 ------
drivers/staging/slicoss/slicoss.c | 3 ++-
2 files changed, 2 insertions(+), 7 deletions(-)
diff --git a/drivers/staging/slicoss/slicinc.h b/drivers/staging/slicoss/slicinc.h
index 610c1ab..71288c4 100644
--- a/drivers/staging/slicoss/slicinc.h
+++ b/drivers/staging/slicoss/slicinc.h
@@ -61,7 +61,6 @@ static void slic_xmit_fail(struct adapter *adapter,
void *cmd,
u32 skbtype,
u32 status);
-static void slic_xmit_timeout(struct net_device *dev);
static void slic_config_pci(struct pci_dev *pcidev);
static struct sk_buff *slic_rcvqueue_getnext(struct adapter *adapter);
@@ -90,8 +89,6 @@ static void slic_cmdq_free(struct adapter *adapter);
static void slic_cmdq_reset(struct adapter *adapter);
static void slic_cmdq_addcmdpage(struct adapter *adapter, u32 *page);
static void slic_cmdq_getdone(struct adapter *adapter);
-static void slic_cmdq_putdone(struct adapter *adapter,
- struct slic_hostcmd *cmd);
static void slic_cmdq_putdone_irq(struct adapter *adapter,
struct slic_hostcmd *cmd);
static struct slic_hostcmd *slic_cmdq_getfree(struct adapter *adapter);
@@ -103,7 +100,6 @@ static void slic_rcvqueue_free(struct adapter *adapter);
static void slic_rcv_handle_error(struct adapter *adapter,
struct slic_rcvbuf *rcvbuf);
static void slic_adapter_set_hwaddr(struct adapter *adapter);
-static void slic_card_halt(struct sliccard *card, struct adapter *adapter);
static int slic_card_init(struct sliccard *card, struct adapter *adapter);
static void slic_intagg_set(struct adapter *adapter, u32 value);
static int slic_card_download(struct adapter *adapter);
@@ -120,7 +116,6 @@ static void slic_unmap_mmio_space(struct adapter *adapter);
static void slic_card_cleanup(struct sliccard *card);
static void slic_init_cleanup(struct adapter *adapter);
static void slic_soft_reset(struct adapter *adapter);
-static void slic_card_reset(struct adapter *adapter);
static bool slic_mac_filter(struct adapter *adapter,
struct ether_header *ether_frame);
static void slic_mac_address_config(struct adapter *adapter);
@@ -133,7 +128,6 @@ static void slic_config_set(struct adapter *adapter, bool linkchange);
static void slic_config_clear(struct adapter *adapter);
static void slic_config_get(struct adapter *adapter, u32 config,
u32 configh);
-static void slic_timer_get_stats(ulong device);
static void slic_timer_load_check(ulong context);
static void slic_timer_ping(ulong dev);
static void slic_assert_fail(void);
diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c
index eb61565..f242477 100644
--- a/drivers/staging/slicoss/slicoss.c
+++ b/drivers/staging/slicoss/slicoss.c
@@ -3128,6 +3128,7 @@ static int slic_mac_set_address(struct net_device *dev, void *ptr)
* 50 seconds or whatever STATS_TIMER_INTERVAL is set to.
*
*/
+#if SLIC_GET_STATS_TIMER_ENABLED
static void slic_timer_get_stats(ulong dev)
{
struct adapter *adapter;
@@ -3163,7 +3164,7 @@ static void slic_timer_get_stats(ulong dev)
SLIC_SECS_TO_JIFFS(STATS_TIMER_INTERVAL);
add_timer(&adapter->statstimer);
}
-
+#endif
static void slic_timer_load_check(ulong cardaddr)
{
struct sliccard *card = (struct sliccard *)cardaddr;
--
1.6.0.2
^ permalink raw reply related [flat|nested] 37+ messages in thread* [PATCH 21/23] Staging: SLICOSS: Fix remaining type names
2008-10-10 22:41 [GIT PATCH] STAGING patches for 2.6.28 Greg KH
` (15 preceding siblings ...)
2008-10-10 22:42 ` [PATCH 20/23] Staging: SLICOSS: Fix warnings due to static usage Greg KH
@ 2008-10-10 22:42 ` Greg KH
2008-10-10 22:42 ` [PATCH 22/23] Staging: SLICOSS: Call pci_release_regions at driver exit Greg KH
` (2 subsequent siblings)
19 siblings, 0 replies; 37+ messages in thread
From: Greg KH @ 2008-10-10 22:42 UTC (permalink / raw)
To: linux-kernel; +Cc: Lior Dotan, Greg Kroah-Hartman
From: Lior Dotan <liodot@gmail.com>
Fix the remaining variables that still had '_t' as a postfix and also
a couple of checkpatch warnings.
Signed-off-by: Lior Dotan <liodot@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/slicoss/slic_os.h | 6 ++++--
drivers/staging/slicoss/slicdump.h | 2 +-
drivers/staging/slicoss/slichw.h | 6 +++---
drivers/staging/slicoss/slicoss.c | 30 +++++++++++++++---------------
4 files changed, 23 insertions(+), 21 deletions(-)
diff --git a/drivers/staging/slicoss/slic_os.h b/drivers/staging/slicoss/slic_os.h
index b0d2883..46c6784 100644
--- a/drivers/staging/slicoss/slic_os.h
+++ b/drivers/staging/slicoss/slic_os.h
@@ -53,7 +53,8 @@
{ \
adapter->card->reg_type[adapter->card->debug_ix] = 0; \
adapter->card->reg_offset[adapter->card->debug_ix] = \
- ((unsigned char *)(®)) - ((unsigned char *)adapter->slic_regs); \
+ ((unsigned char *)(®)) - \
+ ((unsigned char *)adapter->slic_regs); \
adapter->card->reg_value[adapter->card->debug_ix++] = value; \
if (adapter->card->debug_ix == 32) \
adapter->card->debug_ix = 0; \
@@ -63,7 +64,8 @@
{ \
adapter->card->reg_type[adapter->card->debug_ix] = 1; \
adapter->card->reg_offset[adapter->card->debug_ix] = \
- ((unsigned char *)(®)) - ((unsigned char *)adapter->slic_regs); \
+ ((unsigned char *)(®)) - \
+ ((unsigned char *)adapter->slic_regs); \
adapter->card->reg_value[adapter->card->debug_ix] = value; \
adapter->card->reg_valueh[adapter->card->debug_ix++] = valh; \
if (adapter->card->debug_ix == 32) \
diff --git a/drivers/staging/slicoss/slicdump.h b/drivers/staging/slicoss/slicdump.h
index ca0a221..92a9b44 100644
--- a/drivers/staging/slicoss/slicdump.h
+++ b/drivers/staging/slicoss/slicdump.h
@@ -228,7 +228,7 @@ struct CORE_Q {
#define DRIVER_NAME_SIZE 32
struct sliccore_hdr {
- unsigned char driver_version[DRIVER_NAME_SIZE]; /* Driver version string */
+ unsigned char driver_version[DRIVER_NAME_SIZE]; /* Driver version string */
u32 RcvRegOff; /* Offset of receive registers */
u32 RcvRegsize; /* size of receive registers */
u32 XmtRegOff; /* Offset of transmit registers */
diff --git a/drivers/staging/slicoss/slichw.h b/drivers/staging/slicoss/slichw.h
index 4c5c15d..d03e90b 100644
--- a/drivers/staging/slicoss/slichw.h
+++ b/drivers/staging/slicoss/slichw.h
@@ -702,7 +702,7 @@ struct vendor4_fru {
unsigned char pad[3];
};
-union oemfru_t {
+union oemfru {
struct vendor1_fru vendor1_fru;
struct vendor2_fru vendor2_fru;
struct vendor3_fru vendor3_fru;
@@ -764,7 +764,7 @@ struct slic_eeprom {
unsigned char FruFormat; /* Alacritech FRU format type */
struct atk_fru AtkFru; /* Alacritech FRU information */
unsigned char OemFruFormat; /* optional OEM FRU format type */
- union oemfru_t OemFru; /* optional OEM FRU information */
+ union oemfru OemFru; /* optional OEM FRU information */
unsigned char Pad[4]; /* Pad to 128 bytes - includes 2 cksum bytes
*(if OEM FRU info exists) and two unusable
* bytes at the end */
@@ -809,7 +809,7 @@ struct oslic_eeprom {
unsigned char FruFormat; /* 35 Alacritech FRU format type */
struct atk_fru AtkFru; /* Alacritech FRU information */
unsigned char OemFruFormat; /* optional OEM FRU format type */
- union oemfru_t OemFru; /* optional OEM FRU information */
+ union oemfru OemFru; /* optional OEM FRU information */
unsigned char Pad[4]; /* Pad to 128 bytes - includes 2 checksum bytes
* (if OEM FRU info exists) and two unusable
* bytes at the end
diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c
index f242477..c129e83 100644
--- a/drivers/staging/slicoss/slicoss.c
+++ b/drivers/staging/slicoss/slicoss.c
@@ -1015,7 +1015,7 @@ static int slic_xmit_start(struct sk_buff *skb, struct net_device *dev)
#ifdef DEBUG_DUMP
if (adapter->kill_card) {
- p_slic_host64_cmd_t ihcmd;
+ struct slic_host64_cmd ihcmd;
ihcmd = &hcmd->cmd64;
@@ -2455,7 +2455,7 @@ static int slic_card_init(struct sliccard *card, struct adapter *adapter)
unsigned char fruformat;
unsigned char oemfruformat;
struct atk_fru *patkfru;
- union oemfru_t *poemfru;
+ union oemfru *poemfru;
DBG_MSG
("slicoss: %s ENTER card[%p] adapter[%p] card->state[%x] \
@@ -2692,7 +2692,7 @@ static int slic_card_init(struct sliccard *card, struct adapter *adapter)
* Allocate COMMAND BUFFER
*/
if (!card->cmdbuffer) {
- card->cmdbuffer = kmalloc(sizeof(dump_cmd_t), GFP_ATOMIC);
+ card->cmdbuffer = kmalloc(sizeof(struct dump_cmd), GFP_ATOMIC);
ASSERT(card->cmdbuffer);
if (card->cmdbuffer == NULL)
@@ -2702,7 +2702,7 @@ static int slic_card_init(struct sliccard *card, struct adapter *adapter)
* Smear the shared memory structure and then obtain
* the PHYSICAL address of this structure
*/
- memset(card->cmdbuffer, 0, sizeof(dump_cmd_t));
+ memset(card->cmdbuffer, 0, sizeof(struct dump_cmd));
card->cmdbuffer_phys = virt_to_bus(card->cmdbuffer);
card->cmdbuffer_physh = SLIC_GET_ADDR_HIGH(card->cmdbuffer_phys);
card->cmdbuffer_physl = SLIC_GET_ADDR_LOW(card->cmdbuffer_phys);
@@ -4417,7 +4417,7 @@ static int slic_debug_card_show(struct seq_file *seq, void *v)
#ifdef MOOKTODO
int i;
struct sliccard *card = seq->private;
- pslic_config_t config = &card->config;
+ struct slic_config *config = &card->config;
unsigned char *fru = (unsigned char *)(&card->config.atk_fru);
unsigned char *oemfru = (unsigned char *)(&card->config.OemFru);
#endif
@@ -5311,7 +5311,7 @@ static u32 slic_dump_card(struct sliccard *card, bool resume)
u32 queue;
u32 len, offset;
u32 sram_size, dram_size, regs;
- sliccore_hdr_t corehdr;
+ struct sliccore_hdr corehdr;
u32 file_offset;
char *namestr;
u32 i;
@@ -5344,7 +5344,7 @@ static u32 slic_dump_card(struct sliccard *card, bool resume)
}
corehdr.driver_version[i] = 0;
- file_offset = sizeof(sliccore_hdr_t);
+ file_offset = sizeof(struct sliccore_hdr);
/*
* Issue the following debug commands to the SLIC:
@@ -5651,10 +5651,10 @@ done:
*/
file_offset = 0;
DBG_MSG("[slicmon] Write CoreHeader len[%x] offset[%x]\n",
- (uint) sizeof(sliccore_hdr_t), file_offset);
+ (uint) sizeof(struct sliccore_hdr), file_offset);
result =
- slic_dump_write(card, &corehdr, sizeof(sliccore_hdr_t),
+ slic_dump_write(card, &corehdr, sizeof(struct sliccore_hdr),
file_offset);
DBG_MSG("[slicmon] corehdr xoff[%x] xsz[%x]\n"
" roff[%x] rsz[%x] fileoff[%x] filesz[%x]\n"
@@ -5663,7 +5663,7 @@ done:
corehdr.XmtRegsize, corehdr.RcvRegOff, corehdr.RcvRegsize,
corehdr.FileRegOff, corehdr.FileRegsize, corehdr.SramOff,
corehdr.Sramsize, corehdr.DramOff, corehdr.Dramsize,
- (uint) sizeof(sliccore_hdr_t));
+ (uint) sizeof(struct sliccore_hdr));
for (i = 0; i < max_queues; i++) {
DBG_MSG("[slicmon] QUEUE 0x%x offset[%x] size[%x]\n",
(uint) i, corehdr.queues[i].queueOff,
@@ -5706,7 +5706,7 @@ static u32 slic_dump_resume(struct sliccard *card, unsigned char proc)
static u32 slic_dump_reg(struct sliccard *card, unsigned char proc)
{
- pdump_cmd_t dump = (pdump_cmd_t) card->cmdbuffer;
+ struct dump_cmd *dump = (struct dump_cmd *)card->cmdbuffer;
dump->cmd = COMMAND_BYTE(CMD_DUMP, 0, proc);
dump->desc = DESC_REG;
@@ -5723,7 +5723,7 @@ static u32 slic_dump_reg(struct sliccard *card, unsigned char proc)
static u32 slic_dump_data(struct sliccard *card,
u32 addr, ushort count, unsigned char desc)
{
- pdump_cmd_t dump = (pdump_cmd_t) card->cmdbuffer;
+ struct dump_cmd *dump = (struct dump_cmd *)card->cmdbuffer;
dump->cmd = COMMAND_BYTE(CMD_DUMP, 0, PROC_RECEIVE);
dump->desc = desc;
@@ -5740,7 +5740,7 @@ static u32 slic_dump_data(struct sliccard *card,
static u32 slic_dump_queue(struct sliccard *card,
u32 addr, u32 buf_physh, u32 queue)
{
- pdump_cmd_t dump = (pdump_cmd_t) card->cmdbuffer;
+ struct dump_cmd *dump = (struct dump_cmd *)card->cmdbuffer;
dump->cmd = COMMAND_BYTE(CMD_DUMP, 0, PROC_RECEIVE);
dump->desc = DESC_QUEUE;
@@ -5756,7 +5756,7 @@ static u32 slic_dump_queue(struct sliccard *card,
static u32 slic_dump_load_queue(struct sliccard *card, u32 data,
u32 queue)
{
- pdump_cmd_t load = (pdump_cmd_t) card->cmdbuffer;
+ struct dump_cmd *load = (struct dump_cmd *) card->cmdbuffer;
load->cmd = COMMAND_BYTE(CMD_LOAD, 0, PROC_RECEIVE);
load->desc = DESC_QUEUE;
@@ -5771,7 +5771,7 @@ static u32 slic_dump_load_queue(struct sliccard *card, u32 data,
static u32 slic_dump_cam(struct sliccard *card,
u32 addr, u32 count, unsigned char desc)
{
- pdump_cmd_t dump = (pdump_cmd_t) card->cmdbuffer;
+ struct dump_cmd *dump = (struct dump_cmd *)card->cmdbuffer;
dump->cmd = COMMAND_BYTE(CMD_CAM_OPS, 0, PROC_NONE);
dump->desc = desc;
--
1.6.0.2
^ permalink raw reply related [flat|nested] 37+ messages in thread* [PATCH 22/23] Staging: SLICOSS: Call pci_release_regions at driver exit
2008-10-10 22:41 [GIT PATCH] STAGING patches for 2.6.28 Greg KH
` (16 preceding siblings ...)
2008-10-10 22:42 ` [PATCH 21/23] Staging: SLICOSS: Fix remaining type names Greg KH
@ 2008-10-10 22:42 ` Greg KH
2008-10-10 22:42 ` [PATCH 23/23] Staging: Lindent sxg.c Greg KH
2008-10-13 21:36 ` [GIT PATCH] STAGING patches for 2.6.28 Greg KH
19 siblings, 0 replies; 37+ messages in thread
From: Greg KH @ 2008-10-10 22:42 UTC (permalink / raw)
To: linux-kernel; +Cc: Lior Dotan, Greg Kroah-Hartman
From: Lior Dotan <liodot@gmail.com>
slic_entry_probe() calls pci_request_regions() but there's no matching
pci_release_regions() at driver's exit or if slic_entry_probe() fails.
Signed-off-by: Lior Dotan <liodot@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/slicoss/slicoss.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c
index c129e83..b61ac4b 100644
--- a/drivers/staging/slicoss/slicoss.c
+++ b/drivers/staging/slicoss/slicoss.c
@@ -520,6 +520,7 @@ err_out_free_mmio_region:
release_mem_region(mmio_start, mmio_len);
err_out_exit_slic_probe:
+ pci_release_regions(pcidev);
DBG_ERROR("%s EXIT jiffies[%lx] cpu %d\n", __func__, jiffies,
smp_processor_id());
@@ -649,6 +650,7 @@ static void __devexit slic_entry_remove(struct pci_dev *pcidev)
}
DBG_MSG("slicoss: %s deallocate device\n", __func__);
kfree(dev);
+ pci_release_regions(pcidev);
DBG_MSG("slicoss: %s EXIT\n", __func__);
}
--
1.6.0.2
^ permalink raw reply related [flat|nested] 37+ messages in thread* [PATCH 23/23] Staging: Lindent sxg.c
2008-10-10 22:41 [GIT PATCH] STAGING patches for 2.6.28 Greg KH
` (17 preceding siblings ...)
2008-10-10 22:42 ` [PATCH 22/23] Staging: SLICOSS: Call pci_release_regions at driver exit Greg KH
@ 2008-10-10 22:42 ` Greg KH
2008-10-13 21:36 ` [GIT PATCH] STAGING patches for 2.6.28 Greg KH
19 siblings, 0 replies; 37+ messages in thread
From: Greg KH @ 2008-10-10 22:42 UTC (permalink / raw)
To: linux-kernel; +Cc: J.R. Mauro, Greg Kroah-Hartman
From: J.R. Mauro <jrm8005@gmail.com>
Lindent drivers/staging/sxg/sxg.c
Signed-off by: J.R. Mauro <jrm8005@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/sxg/sxg.c | 146 +++++++++++++++++++++++++--------------------
1 files changed, 81 insertions(+), 65 deletions(-)
diff --git a/drivers/staging/sxg/sxg.c b/drivers/staging/sxg/sxg.c
index 0117d51..6ccbee8 100644
--- a/drivers/staging/sxg/sxg.c
+++ b/drivers/staging/sxg/sxg.c
@@ -80,9 +80,15 @@
#include "sxgphycode.h"
#include "saharadbgdownload.h"
-static int sxg_allocate_buffer_memory(p_adapter_t adapter, u32 Size, SXG_BUFFER_TYPE BufferType);
-static void sxg_allocate_rcvblock_complete(p_adapter_t adapter, void * RcvBlock, dma_addr_t PhysicalAddress, u32 Length);
-static void sxg_allocate_sgl_buffer_complete(p_adapter_t adapter, PSXG_SCATTER_GATHER SxgSgl, dma_addr_t PhysicalAddress, u32 Length);
+static int sxg_allocate_buffer_memory(p_adapter_t adapter, u32 Size,
+ SXG_BUFFER_TYPE BufferType);
+static void sxg_allocate_rcvblock_complete(p_adapter_t adapter, void *RcvBlock,
+ dma_addr_t PhysicalAddress,
+ u32 Length);
+static void sxg_allocate_sgl_buffer_complete(p_adapter_t adapter,
+ PSXG_SCATTER_GATHER SxgSgl,
+ dma_addr_t PhysicalAddress,
+ u32 Length);
static void sxg_mcast_init_crc32(void);
@@ -100,13 +106,13 @@ static void sxg_complete_slow_send(p_adapter_t adapter);
static struct sk_buff *sxg_slow_receive(p_adapter_t adapter, PSXG_EVENT Event);
static void sxg_process_rcv_error(p_adapter_t adapter, u32 ErrorStatus);
static bool sxg_mac_filter(p_adapter_t adapter,
- p_ether_header EtherHdr, ushort length);
+ p_ether_header EtherHdr, ushort length);
#if SLIC_GET_STATS_ENABLED
static struct net_device_stats *sxg_get_stats(p_net_device dev);
#endif
-static int sxg_mac_set_address(p_net_device dev, void * ptr);
+static int sxg_mac_set_address(p_net_device dev, void *ptr);
static void sxg_adapter_set_hwaddr(p_adapter_t adapter);
@@ -115,20 +121,19 @@ static void sxg_mcast_set_mask(p_adapter_t adapter);
static int sxg_initialize_adapter(p_adapter_t adapter);
static void sxg_stock_rcv_buffers(p_adapter_t adapter);
-static void sxg_complete_descriptor_blocks(p_adapter_t adapter, unsigned char Index);
+static void sxg_complete_descriptor_blocks(p_adapter_t adapter,
+ unsigned char Index);
static int sxg_initialize_link(p_adapter_t adapter);
static int sxg_phy_init(p_adapter_t adapter);
static void sxg_link_event(p_adapter_t adapter);
static SXG_LINK_STATE sxg_get_link_state(p_adapter_t adapter);
static void sxg_link_state(p_adapter_t adapter, SXG_LINK_STATE LinkState);
static int sxg_write_mdio_reg(p_adapter_t adapter,
- u32 DevAddr, u32 RegAddr, u32 Value);
+ u32 DevAddr, u32 RegAddr, u32 Value);
static int sxg_read_mdio_reg(p_adapter_t adapter,
- u32 DevAddr, u32 RegAddr, u32 * pValue);
+ u32 DevAddr, u32 RegAddr, u32 *pValue);
static void sxg_mcast_set_list(p_net_device dev);
-
-
#define XXXTODO 0
static unsigned int sxg_first_init = 1;
@@ -164,6 +169,7 @@ static struct pci_device_id sxg_pci_tbl[] __devinitdata = {
{PCI_DEVICE(SXG_VENDOR_ID, SXG_DEVICE_ID)},
{0,}
};
+
MODULE_DEVICE_TABLE(pci, sxg_pci_tbl);
/***********************************************************************
@@ -242,7 +248,7 @@ static bool sxg_download_microcode(p_adapter_t adapter, SXG_UCODE_SEL UcodeSel)
PSXG_HW_REGS HwRegs = adapter->HwRegs;
u32 Section;
u32 ThisSectionSize;
- u32 * Instruction = NULL;
+ u32 *Instruction = NULL;
u32 BaseAddress, AddressOffset, Address;
// u32 Failure;
u32 ValueRead;
@@ -606,7 +612,7 @@ static void sxg_config_pci(struct pci_dev *pcidev)
PCI_COMMAND_MASTER | // Bus master enable
PCI_COMMAND_INVALIDATE | // Memory write and invalidate
PCI_COMMAND_PARITY | // Parity error response
- PCI_COMMAND_SERR | // System ERR
+ PCI_COMMAND_SERR | // System ERR
PCI_COMMAND_FAST_BACK); // Fast back-to-back
if (pci_command != new_command) {
DBG_ERROR("%s -- Updating PCI COMMAND register %4.4x->%4.4x.\n",
@@ -695,17 +701,19 @@ static int sxg_entry_probe(struct pci_dev *pcidev,
mmio_start, mmio_len);
memmapped_ioaddr = ioremap(mmio_start, mmio_len);
- DBG_ERROR("sxg: %s MEMMAPPED_IOADDR [%p]\n", __FUNCTION__, memmapped_ioaddr);
+ DBG_ERROR("sxg: %s MEMMAPPED_IOADDR [%p]\n", __FUNCTION__,
+ memmapped_ioaddr);
if (!memmapped_ioaddr) {
DBG_ERROR("%s cannot remap MMIO region %lx @ %lx\n",
__FUNCTION__, mmio_len, mmio_start);
goto err_out_free_mmio_region;
}
- DBG_ERROR("sxg: %s found Alacritech SXG PCI, MMIO at %p, start[%lx] len[%lx], IRQ %d.\n",
+ DBG_ERROR
+ ("sxg: %s found Alacritech SXG PCI, MMIO at %p, start[%lx] len[%lx], IRQ %d.\n",
__func__, memmapped_ioaddr, mmio_start, mmio_len, pcidev->irq);
- adapter->HwRegs = (void *) memmapped_ioaddr;
+ adapter->HwRegs = (void *)memmapped_ioaddr;
adapter->base_addr = memmapped_ioaddr;
mmio_start = pci_resource_start(pcidev, 2);
@@ -715,7 +723,8 @@ static int sxg_entry_probe(struct pci_dev *pcidev,
mmio_start, mmio_len);
memmapped_ioaddr = ioremap(mmio_start, mmio_len);
- DBG_ERROR("sxg: %s MEMMAPPED_IOADDR [%p]\n", __func__, memmapped_ioaddr);
+ DBG_ERROR("sxg: %s MEMMAPPED_IOADDR [%p]\n", __func__,
+ memmapped_ioaddr);
if (!memmapped_ioaddr) {
DBG_ERROR("%s cannot remap MMIO region %lx @ %lx\n",
__FUNCTION__, mmio_len, mmio_start);
@@ -845,7 +854,6 @@ static int sxg_entry_probe(struct pci_dev *pcidev,
return -ENODEV;
}
-
/***********************************************************************
* LINE BASE Interrupt routines..
***********************************************************************/
@@ -957,7 +965,8 @@ static irqreturn_t sxg_isr(int irq, void *dev_id)
PSXG_EVENT_RING EventRing = &adapter->EventRings[i];
PSXG_EVENT Event =
&EventRing->Ring[adapter->NextEvent[i]];
- unsigned char Cpu = adapter->RssSystemInfo->RssIdToCpu[i];
+ unsigned char Cpu =
+ adapter->RssSystemInfo->RssIdToCpu[i];
if (Event->Status & EVENT_STATUS_VALID) {
adapter->IsrDpcsPending++;
CpuMask |= (1 << Cpu);
@@ -1078,7 +1087,8 @@ static int sxg_process_isr(p_adapter_t adapter, u32 MessageId)
if (Isr & SXG_ISR_DEAD) {
// Set aside the crash info and set the adapter state to RESET
adapter->CrashCpu =
- (unsigned char) ((Isr & SXG_ISR_CPU) >> SXG_ISR_CPU_SHIFT);
+ (unsigned char)((Isr & SXG_ISR_CPU) >>
+ SXG_ISR_CPU_SHIFT);
adapter->CrashLocation = (ushort) (Isr & SXG_ISR_CRASH);
adapter->Dead = TRUE;
DBG_ERROR("%s: ISR_DEAD %x, CPU: %d\n", __FUNCTION__,
@@ -1286,7 +1296,7 @@ static void sxg_complete_slow_send(p_adapter_t adapter)
{
PSXG_XMT_RING XmtRing = &adapter->XmtRings[0];
PSXG_RING_INFO XmtRingInfo = &adapter->XmtRingZeroInfo;
- u32 * ContextType;
+ u32 *ContextType;
PSXG_CMD XmtCmd;
// NOTE - This lock is dropped and regrabbed in this loop.
@@ -1380,11 +1390,9 @@ static struct sk_buff *sxg_slow_receive(p_adapter_t adapter, PSXG_EVENT Event)
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "RcvError",
Event, Event->Status, Event->HostHandle, 0);
// XXXTODO - Remove this print later
- DBG_ERROR("SXG: Receive error %x\n",
- *(u32 *)
+ DBG_ERROR("SXG: Receive error %x\n", *(u32 *)
SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr));
- sxg_process_rcv_error(adapter,
- *(u32 *)
+ sxg_process_rcv_error(adapter, *(u32 *)
SXG_RECEIVE_DATA_LOCATION
(RcvDataBufferHdr));
goto drop;
@@ -1406,8 +1414,7 @@ static struct sk_buff *sxg_slow_receive(p_adapter_t adapter, PSXG_EVENT Event)
//
// Dumb-nic frame. See if it passes our mac filter and update stats
//
- if (!sxg_mac_filter(adapter,
- (p_ether_header)
+ if (!sxg_mac_filter(adapter, (p_ether_header)
SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr),
Event->Length)) {
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "RcvFiltr",
@@ -1527,7 +1534,8 @@ static void sxg_process_rcv_error(p_adapter_t adapter, u32 ErrorStatus)
* Return Value:
* TRUE if the frame is to be allowed
*/
-static bool sxg_mac_filter(p_adapter_t adapter, p_ether_header EtherHdr, ushort length)
+static bool sxg_mac_filter(p_adapter_t adapter, p_ether_header EtherHdr,
+ ushort length)
{
bool EqualAddr;
@@ -1600,7 +1608,8 @@ static int sxg_register_interrupt(p_adapter_t adapter)
("sxg: %s AllocAdaptRsrcs adapter[%p] dev->irq[%x] %x\n",
__FUNCTION__, adapter, adapter->netdev->irq, NR_IRQS);
- spin_unlock_irqrestore(&sxg_global.driver_lock, sxg_global.flags);
+ spin_unlock_irqrestore(&sxg_global.driver_lock,
+ sxg_global.flags);
retval = request_irq(adapter->netdev->irq,
&sxg_isr,
@@ -1729,7 +1738,6 @@ static int sxg_entry_open(p_net_device dev)
sxg_global.num_sxg_ports_active++;
adapter->activated = 1;
}
-
// Initialize the adapter
DBG_ERROR("sxg: %s ENTER sxg_initialize_adapter\n", __FUNCTION__);
status = sxg_initialize_adapter(adapter);
@@ -1786,7 +1794,7 @@ static void __devexit sxg_entry_remove(struct pci_dev *pcidev)
release_mem_region(mmio_start, mmio_len);
DBG_ERROR("sxg: %s iounmap dev->base_addr[%x]\n", __FUNCTION__,
- (unsigned int) dev->base_addr);
+ (unsigned int)dev->base_addr);
iounmap((char *)dev->base_addr);
DBG_ERROR("sxg: %s deallocate device\n", __FUNCTION__);
@@ -1929,7 +1937,7 @@ static int sxg_transmit_packet(p_adapter_t adapter, struct sk_buff *skb)
{
PSCATTER_GATHER_LIST pSgl;
PSXG_SCATTER_GATHER SxgSgl;
- void * SglBuffer;
+ void *SglBuffer;
u32 SglBufferLength;
// The vast majority of work is done in the shared
@@ -2038,7 +2046,9 @@ static void sxg_dumb_sgl(PSCATTER_GATHER_LIST pSgl, PSXG_SCATTER_GATHER SxgSgl)
#endif
// Fill in the command
// Copy out the first SGE to the command and adjust for offset
- phys_addr = pci_map_single(adapter->pcidev, skb->data, skb->len, PCI_DMA_TODEVICE);
+ phys_addr =
+ pci_map_single(adapter->pcidev, skb->data, skb->len,
+ PCI_DMA_TODEVICE);
XmtCmd->Buffer.FirstSgeAddress = SXG_GET_ADDR_HIGH(phys_addr);
XmtCmd->Buffer.FirstSgeAddress = XmtCmd->Buffer.FirstSgeAddress << 32;
XmtCmd->Buffer.FirstSgeAddress =
@@ -2422,7 +2432,8 @@ static SXG_LINK_STATE sxg_get_link_state(p_adapter_t adapter)
return (SXG_LINK_DOWN);
}
-static void sxg_indicate_link_state(p_adapter_t adapter, SXG_LINK_STATE LinkState)
+static void sxg_indicate_link_state(p_adapter_t adapter,
+ SXG_LINK_STATE LinkState)
{
if (adapter->LinkState == SXG_LINK_UP) {
DBG_ERROR("%s: LINK now UP, call netif_start_queue\n",
@@ -2487,11 +2498,11 @@ static void sxg_link_state(p_adapter_t adapter, SXG_LINK_STATE LinkState)
* status
*/
static int sxg_write_mdio_reg(p_adapter_t adapter,
- u32 DevAddr, u32 RegAddr, u32 Value)
+ u32 DevAddr, u32 RegAddr, u32 Value)
{
PSXG_HW_REGS HwRegs = adapter->HwRegs;
u32 AddrOp; // Address operation (written to MIIM field reg)
- u32 WriteOp; // Write operation (written to MIIM field reg)
+ u32 WriteOp; // Write operation (written to MIIM field reg)
u32 Cmd; // Command (written to MIIM command reg)
u32 ValueRead;
u32 Timeout;
@@ -2577,7 +2588,7 @@ static int sxg_write_mdio_reg(p_adapter_t adapter,
* status
*/
static int sxg_read_mdio_reg(p_adapter_t adapter,
- u32 DevAddr, u32 RegAddr, u32 * pValue)
+ u32 DevAddr, u32 RegAddr, u32 *pValue)
{
PSXG_HW_REGS HwRegs = adapter->HwRegs;
u32 AddrOp; // Address operation (written to MIIM field reg)
@@ -2698,7 +2709,7 @@ static int sxg_mcast_add_list(p_adapter_t adapter, char *address)
* we must then transpose the value and return bits 30-23.
*
*/
-static u32 sxg_crc_table[256]; /* Table of CRC's for all possible byte values */
+static u32 sxg_crc_table[256]; /* Table of CRC's for all possible byte values */
static u32 sxg_crc_init; /* Is table initialized */
/*
@@ -2706,7 +2717,7 @@ static u32 sxg_crc_init; /* Is table initialized */
*/
static void sxg_mcast_init_crc32(void)
{
- u32 c; /* CRC shit reg */
+ u32 c; /* CRC shit reg */
u32 e = 0; /* Poly X-or pattern */
int i; /* counter */
int k; /* byte being shifted into crc */
@@ -2783,7 +2794,7 @@ static void sxg_mcast_set_list(p_net_device dev)
ASSERT(adapter);
for (i = 1; i <= mc_count; i++) {
- addresses = (char *) & mc_list->dmi_addr;
+ addresses = (char *)&mc_list->dmi_addr;
if (mc_list->dmi_addrlen == 6) {
status = sxg_mcast_add_list(adapter, addresses);
if (status != STATUS_SUCCESS) {
@@ -2833,7 +2844,7 @@ static void sxg_mcast_set_mask(p_adapter_t adapter)
PSXG_UCODE_REGS sxg_regs = adapter->UcodeRegs;
DBG_ERROR("%s ENTER (%s) macopts[%x] mask[%llx]\n", __FUNCTION__,
- adapter->netdev->name, (unsigned int) adapter->MacFilter,
+ adapter->netdev->name, (unsigned int)adapter->MacFilter,
adapter->MulticastMask);
if (adapter->MacFilter & (MAC_ALLMCAST | MAC_PROMISC)) {
@@ -2857,12 +2868,10 @@ static void sxg_mcast_set_mask(p_adapter_t adapter)
((adapter->MulticastMask >> 32) & 0xFFFFFFFF)));
WRITE_REG(sxg_regs->McastLow,
- (u32) (adapter->MulticastMask & 0xFFFFFFFF),
- FLUSH);
+ (u32) (adapter->MulticastMask & 0xFFFFFFFF), FLUSH);
WRITE_REG(sxg_regs->McastHigh,
(u32) ((adapter->
- MulticastMask >> 32) & 0xFFFFFFFF),
- FLUSH);
+ MulticastMask >> 32) & 0xFFFFFFFF), FLUSH);
}
}
@@ -2991,9 +3000,9 @@ void SxgFreeResources(p_adapter_t adapter)
* None.
*/
static void sxg_allocate_complete(p_adapter_t adapter,
- void *VirtualAddress,
- dma_addr_t PhysicalAddress,
- u32 Length, SXG_BUFFER_TYPE Context)
+ void *VirtualAddress,
+ dma_addr_t PhysicalAddress,
+ u32 Length, SXG_BUFFER_TYPE Context)
{
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "AllocCmp",
adapter, VirtualAddress, Length, Context);
@@ -3008,8 +3017,7 @@ static void sxg_allocate_complete(p_adapter_t adapter,
PhysicalAddress, Length);
break;
case SXG_BUFFER_TYPE_SGL:
- sxg_allocate_sgl_buffer_complete(adapter,
- (PSXG_SCATTER_GATHER)
+ sxg_allocate_sgl_buffer_complete(adapter, (PSXG_SCATTER_GATHER)
VirtualAddress,
PhysicalAddress, Length);
break;
@@ -3031,10 +3039,10 @@ static void sxg_allocate_complete(p_adapter_t adapter,
* int
*/
static int sxg_allocate_buffer_memory(p_adapter_t adapter,
- u32 Size, SXG_BUFFER_TYPE BufferType)
+ u32 Size, SXG_BUFFER_TYPE BufferType)
{
int status;
- void * Buffer;
+ void *Buffer;
dma_addr_t pBuffer;
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "AllocMem",
@@ -3083,8 +3091,9 @@ static int sxg_allocate_buffer_memory(p_adapter_t adapter,
*
*/
static void sxg_allocate_rcvblock_complete(p_adapter_t adapter,
- void * RcvBlock,
- dma_addr_t PhysicalAddress, u32 Length)
+ void *RcvBlock,
+ dma_addr_t PhysicalAddress,
+ u32 Length)
{
u32 i;
u32 BufferSize = adapter->ReceiveBufferSize;
@@ -3160,9 +3169,10 @@ static void sxg_allocate_rcvblock_complete(p_adapter_t adapter,
}
// Locate the descriptor block and put it on a separate free queue
- RcvDescriptorBlock = (PSXG_RCV_DESCRIPTOR_BLOCK) ((unsigned char *)RcvBlock +
- SXG_RCV_DESCRIPTOR_BLOCK_OFFSET
- (BufferSize));
+ RcvDescriptorBlock =
+ (PSXG_RCV_DESCRIPTOR_BLOCK) ((unsigned char *)RcvBlock +
+ SXG_RCV_DESCRIPTOR_BLOCK_OFFSET
+ (BufferSize));
RcvDescriptorBlockHdr =
(PSXG_RCV_DESCRIPTOR_BLOCK_HDR) ((unsigned char *)RcvBlock +
SXG_RCV_DESCRIPTOR_BLOCK_HDR_OFFSET
@@ -3210,8 +3220,9 @@ static void sxg_allocate_rcvblock_complete(p_adapter_t adapter,
*
*/
static void sxg_allocate_sgl_buffer_complete(p_adapter_t adapter,
- PSXG_SCATTER_GATHER SxgSgl,
- dma_addr_t PhysicalAddress, u32 Length)
+ PSXG_SCATTER_GATHER SxgSgl,
+ dma_addr_t PhysicalAddress,
+ u32 Length)
{
SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "AlSglCmp",
adapter, SxgSgl, Length, 0);
@@ -3228,7 +3239,8 @@ static void sxg_allocate_sgl_buffer_complete(p_adapter_t adapter,
adapter, SxgSgl, Length, 0);
}
-static unsigned char temp_mac_address[6] = { 0x00, 0xab, 0xcd, 0xef, 0x12, 0x69 };
+static unsigned char temp_mac_address[6] =
+ { 0x00, 0xab, 0xcd, 0xef, 0x12, 0x69 };
static void sxg_adapter_set_hwaddr(p_adapter_t adapter)
{
@@ -3255,7 +3267,7 @@ static void sxg_adapter_set_hwaddr(p_adapter_t adapter)
}
-static int sxg_mac_set_address(p_net_device dev, void * ptr)
+static int sxg_mac_set_address(p_net_device dev, void *ptr)
{
#if XXXTODO
p_adapter_t adapter = (p_adapter_t) netdev_priv(dev);
@@ -3400,7 +3412,8 @@ static int sxg_initialize_adapter(p_adapter_t adapter)
* status
*/
static int sxg_fill_descriptor_block(p_adapter_t adapter,
- PSXG_RCV_DESCRIPTOR_BLOCK_HDR RcvDescriptorBlockHdr)
+ PSXG_RCV_DESCRIPTOR_BLOCK_HDR
+ RcvDescriptorBlockHdr)
{
u32 i;
PSXG_RING_INFO RcvRingInfo = &adapter->RcvRingZeroInfo;
@@ -3436,7 +3449,8 @@ static int sxg_fill_descriptor_block(p_adapter_t adapter,
ASSERT(RcvDataBufferHdr);
SXG_REINIATIALIZE_PACKET(RcvDataBufferHdr->SxgDumbRcvPacket);
RcvDataBufferHdr->State = SXG_BUFFER_ONCARD;
- RcvDescriptorBlock->Descriptors[i].VirtualAddress = (void *)RcvDataBufferHdr;
+ RcvDescriptorBlock->Descriptors[i].VirtualAddress =
+ (void *)RcvDataBufferHdr;
RcvDescriptorBlock->Descriptors[i].PhysicalAddress =
RcvDataBufferHdr->PhysicalAddress;
}
@@ -3497,7 +3511,9 @@ static void sxg_stock_rcv_buffers(p_adapter_t adapter)
RcvDescriptorBlockHdr = NULL;
if (adapter->FreeRcvBlockCount) {
_ple = RemoveHeadList(&adapter->FreeRcvBlocks);
- RcvDescriptorBlockHdr = container_of(_ple, SXG_RCV_DESCRIPTOR_BLOCK_HDR, FreeList);
+ RcvDescriptorBlockHdr =
+ container_of(_ple, SXG_RCV_DESCRIPTOR_BLOCK_HDR,
+ FreeList);
adapter->FreeRcvBlockCount--;
RcvDescriptorBlockHdr->State = SXG_BUFFER_BUSY;
}
@@ -3533,7 +3549,8 @@ static void sxg_stock_rcv_buffers(p_adapter_t adapter)
* Return
* None
*/
-static void sxg_complete_descriptor_blocks(p_adapter_t adapter, unsigned char Index)
+static void sxg_complete_descriptor_blocks(p_adapter_t adapter,
+ unsigned char Index)
{
PSXG_RCV_RING RingZero = &adapter->RcvRings[0];
PSXG_RING_INFO RcvRingInfo = &adapter->RcvRingZeroInfo;
@@ -3576,7 +3593,6 @@ static void sxg_complete_descriptor_blocks(p_adapter_t adapter, unsigned char In
adapter, Index, RcvRingInfo->Head, RcvRingInfo->Tail);
}
-
static struct pci_driver sxg_driver = {
.name = DRV_NAME,
.id_table = sxg_pci_tbl,
--
1.6.0.2
^ permalink raw reply related [flat|nested] 37+ messages in thread* Re: [GIT PATCH] STAGING patches for 2.6.28
2008-10-10 22:41 [GIT PATCH] STAGING patches for 2.6.28 Greg KH
` (18 preceding siblings ...)
2008-10-10 22:42 ` [PATCH 23/23] Staging: Lindent sxg.c Greg KH
@ 2008-10-13 21:36 ` Greg KH
2008-10-13 21:38 ` [PATCH 24/25] Staging: workaround build system bug Greg KH
` (2 more replies)
19 siblings, 3 replies; 37+ messages in thread
From: Greg KH @ 2008-10-13 21:36 UTC (permalink / raw)
To: Linus Torvalds, Andrew Morton; +Cc: linux-kernel
On Fri, Oct 10, 2008 at 03:41:30PM -0700, Greg KH wrote:
> Here is a tree of patches against your 2.6 git tree that adds the
> drivers/staging/ directory and related infrastructure.
I've now added 2 more patches to this tree, fixing a build error if you
did not build any staging drivers into your tree (the normal mode of
building), and added an additional wireless driver that came from the
Fedora kernel trees.
The updated diffstat and shortlog are below.
Please pull from:
master.kernel.org:/pub/scm/linux/kernel/git/gregkh/staging-2.6.git/
I'll post the 2 additional patches to linux-kernel for those who wish to
see them.
thanks,
greg k-h
Documentation/sysctl/kernel.txt | 1 +
MAINTAINERS | 7 +
drivers/Kconfig | 2 +
drivers/Makefile | 1 +
drivers/staging/Kconfig | 46 +
drivers/staging/Makefile | 15 +
drivers/staging/at76_usb/Kconfig | 8 +
drivers/staging/at76_usb/Makefile | 1 +
drivers/staging/at76_usb/TODO | 2 +
drivers/staging/at76_usb/at76_usb.c | 5559 +++++++++++++++
drivers/staging/at76_usb/at76_usb.h | 619 ++
drivers/staging/echo/Kconfig | 9 +
drivers/staging/echo/Makefile | 1 +
drivers/staging/echo/TODO | 10 +
drivers/staging/echo/bit_operations.h | 253 +
drivers/staging/echo/echo.c | 632 ++
drivers/staging/echo/echo.h | 220 +
drivers/staging/echo/fir.h | 369 +
drivers/staging/echo/mmx.h | 288 +
drivers/staging/et131x/Kconfig | 18 +
drivers/staging/et131x/Makefile | 18 +
drivers/staging/et131x/README | 25 +
drivers/staging/et131x/et1310_address_map.h | 2399 +++++++
drivers/staging/et131x/et1310_eeprom.c | 480 ++
drivers/staging/et131x/et1310_eeprom.h | 89 +
drivers/staging/et131x/et1310_jagcore.c | 220 +
drivers/staging/et131x/et1310_jagcore.h | 112 +
drivers/staging/et131x/et1310_mac.c | 792 +++
drivers/staging/et131x/et1310_mac.h | 93 +
drivers/staging/et131x/et1310_phy.c | 1281 ++++
drivers/staging/et131x/et1310_phy.h | 910 +++
drivers/staging/et131x/et1310_pm.c | 207 +
drivers/staging/et131x/et1310_pm.h | 125 +
drivers/staging/et131x/et1310_rx.c | 1391 ++++
drivers/staging/et131x/et1310_rx.h | 373 +
drivers/staging/et131x/et1310_tx.c | 1525 ++++
drivers/staging/et131x/et1310_tx.h | 242 +
drivers/staging/et131x/et131x_adapter.h | 347 +
drivers/staging/et131x/et131x_config.c | 325 +
drivers/staging/et131x/et131x_config.h | 67 +
drivers/staging/et131x/et131x_debug.c | 218 +
drivers/staging/et131x/et131x_debug.h | 201 +
drivers/staging/et131x/et131x_defs.h | 128 +
drivers/staging/et131x/et131x_initpci.c | 1046 +++
drivers/staging/et131x/et131x_initpci.h | 73 +
drivers/staging/et131x/et131x_isr.c | 488 ++
drivers/staging/et131x/et131x_isr.h | 65 +
drivers/staging/et131x/et131x_netdev.c | 856 +++
drivers/staging/et131x/et131x_netdev.h | 64 +
drivers/staging/et131x/et131x_version.h | 81 +
drivers/staging/go7007/Kconfig | 25 +
drivers/staging/go7007/Makefile | 18 +
drivers/staging/go7007/README | 11 +
drivers/staging/go7007/go7007-driver.c | 688 ++
drivers/staging/go7007/go7007-fw.c | 1639 +++++
drivers/staging/go7007/go7007-i2c.c | 309 +
drivers/staging/go7007/go7007-priv.h | 279 +
drivers/staging/go7007/go7007-usb.c | 1229 ++++
drivers/staging/go7007/go7007-v4l2.c | 1499 ++++
drivers/staging/go7007/go7007.h | 114 +
drivers/staging/go7007/saa7134-go7007.c | 484 ++
drivers/staging/go7007/snd-go7007.c | 305 +
drivers/staging/go7007/wis-i2c.h | 55 +
drivers/staging/go7007/wis-ov7640.c | 130 +
drivers/staging/go7007/wis-saa7113.c | 358 +
drivers/staging/go7007/wis-saa7115.c | 491 ++
drivers/staging/go7007/wis-sony-tuner.c | 742 ++
drivers/staging/go7007/wis-tw2804.c | 380 +
drivers/staging/go7007/wis-tw9903.c | 362 +
drivers/staging/go7007/wis-uda1342.c | 136 +
drivers/staging/me4000/Kconfig | 10 +
drivers/staging/me4000/Makefile | 1 +
drivers/staging/me4000/README | 13 +
drivers/staging/me4000/me4000.c | 6133 ++++++++++++++++
drivers/staging/me4000/me4000.h | 954 +++
drivers/staging/me4000/me4000_firmware.h |10033 +++++++++++++++++++++++++++
drivers/staging/me4000/me4610_firmware.h | 5409 +++++++++++++++
drivers/staging/slicoss/Kconfig | 14 +
drivers/staging/slicoss/Makefile | 1 +
drivers/staging/slicoss/README | 19 +
drivers/staging/slicoss/gbdownload.h | 8215 ++++++++++++++++++++++
drivers/staging/slicoss/gbrcvucode.h | 238 +
drivers/staging/slicoss/oasisdbgdownload.h | 6850 ++++++++++++++++++
drivers/staging/slicoss/oasisdownload.h | 6848 ++++++++++++++++++
drivers/staging/slicoss/oasisrcvucode.h | 205 +
drivers/staging/slicoss/slic.h | 598 ++
drivers/staging/slicoss/slic_os.h | 84 +
drivers/staging/slicoss/slicbuild.h | 96 +
drivers/staging/slicoss/slicdbg.h | 100 +
drivers/staging/slicoss/slicdump.h | 278 +
drivers/staging/slicoss/slichw.h | 845 +++
drivers/staging/slicoss/slicinc.h | 185 +
drivers/staging/slicoss/slicoss.c | 5936 ++++++++++++++++
drivers/staging/staging.c | 19 +
drivers/staging/sxg/Kconfig | 10 +
drivers/staging/sxg/Makefile | 1 +
drivers/staging/sxg/README | 13 +
drivers/staging/sxg/saharadbgdownload.h | 4854 +++++++++++++
drivers/staging/sxg/sxg.c | 3624 ++++++++++
drivers/staging/sxg/sxg.h | 773 +++
drivers/staging/sxg/sxg_os.h | 154 +
drivers/staging/sxg/sxgdbg.h | 190 +
drivers/staging/sxg/sxghif.h | 861 +++
drivers/staging/sxg/sxghw.h | 734 ++
drivers/staging/sxg/sxgphycode.h | 349 +
drivers/staging/usbip/Kconfig | 36 +
drivers/staging/usbip/Makefile | 12 +
drivers/staging/usbip/README | 6 +
drivers/staging/usbip/stub.h | 95 +
drivers/staging/usbip/stub_dev.c | 483 ++
drivers/staging/usbip/stub_main.c | 300 +
drivers/staging/usbip/stub_rx.c | 615 ++
drivers/staging/usbip/stub_tx.c | 371 +
drivers/staging/usbip/usbip_common.c | 997 +++
drivers/staging/usbip/usbip_common.h | 406 ++
drivers/staging/usbip/usbip_event.c | 141 +
drivers/staging/usbip/vhci.h | 142 +
drivers/staging/usbip/vhci_hcd.c | 1275 ++++
drivers/staging/usbip/vhci_rx.c | 251 +
drivers/staging/usbip/vhci_sysfs.c | 250 +
drivers/staging/usbip/vhci_tx.c | 239 +
drivers/staging/winbond/Kconfig | 7 +
drivers/staging/winbond/Makefile | 18 +
drivers/staging/winbond/README | 10 +
drivers/staging/winbond/adapter.h | 23 +
drivers/staging/winbond/bss_f.h | 59 +
drivers/staging/winbond/bssdscpt.h | 156 +
drivers/staging/winbond/ds_tkip.h | 33 +
drivers/staging/winbond/gl_80211.h | 125 +
drivers/staging/winbond/ioctls.h | 678 ++
drivers/staging/winbond/linux/common.h | 143 +
drivers/staging/winbond/linux/sysdef.h | 73 +
drivers/staging/winbond/linux/wb35reg.c | 747 ++
drivers/staging/winbond/linux/wb35reg_f.h | 56 +
drivers/staging/winbond/linux/wb35reg_s.h | 170 +
drivers/staging/winbond/linux/wb35rx.c | 337 +
drivers/staging/winbond/linux/wb35rx_f.h | 17 +
drivers/staging/winbond/linux/wb35rx_s.h | 48 +
drivers/staging/winbond/linux/wb35tx.c | 313 +
drivers/staging/winbond/linux/wb35tx_f.h | 20 +
drivers/staging/winbond/linux/wb35tx_s.h | 47 +
drivers/staging/winbond/linux/wbusb.c | 404 ++
drivers/staging/winbond/linux/wbusb_f.h | 34 +
drivers/staging/winbond/linux/wbusb_s.h | 42 +
drivers/staging/winbond/localpara.h | 275 +
drivers/staging/winbond/mac_structures.h | 670 ++
drivers/staging/winbond/mds.c | 630 ++
drivers/staging/winbond/mds_f.h | 33 +
drivers/staging/winbond/mds_s.h | 183 +
drivers/staging/winbond/mlme_mib.h | 84 +
drivers/staging/winbond/mlme_s.h | 195 +
drivers/staging/winbond/mlmetxrx.c | 150 +
drivers/staging/winbond/mlmetxrx_f.h | 52 +
drivers/staging/winbond/mto.c | 1229 ++++
drivers/staging/winbond/mto.h | 265 +
drivers/staging/winbond/mto_f.h | 7 +
drivers/staging/winbond/os_common.h | 2 +
drivers/staging/winbond/phy_calibration.c | 1759 +++++
drivers/staging/winbond/phy_calibration.h | 101 +
drivers/staging/winbond/reg.c | 2683 +++++++
drivers/staging/winbond/rxisr.c | 30 +
drivers/staging/winbond/scan_s.h | 115 +
drivers/staging/winbond/sme_api.c | 13 +
drivers/staging/winbond/sme_api.h | 265 +
drivers/staging/winbond/sme_s.h | 228 +
drivers/staging/winbond/wb35_ver.h | 30 +
drivers/staging/winbond/wbhal.c | 878 +++
drivers/staging/winbond/wbhal_f.h | 122 +
drivers/staging/winbond/wbhal_s.h | 615 ++
drivers/staging/winbond/wblinux.c | 277 +
drivers/staging/winbond/wblinux_f.h | 23 +
drivers/staging/winbond/wblinux_s.h | 45 +
drivers/staging/wlan-ng/Kconfig | 10 +
drivers/staging/wlan-ng/Makefile | 9 +
drivers/staging/wlan-ng/README | 8 +
drivers/staging/wlan-ng/hfa384x.c | 4018 +++++++++++
drivers/staging/wlan-ng/hfa384x.h | 3067 ++++++++
drivers/staging/wlan-ng/hfa384x_usb.c | 5027 ++++++++++++++
drivers/staging/wlan-ng/p80211conv.c | 683 ++
drivers/staging/wlan-ng/p80211conv.h | 186 +
drivers/staging/wlan-ng/p80211hdr.h | 299 +
drivers/staging/wlan-ng/p80211ioctl.h | 123 +
drivers/staging/wlan-ng/p80211meta.h | 169 +
drivers/staging/wlan-ng/p80211metadef.h | 2524 +++++++
drivers/staging/wlan-ng/p80211metamib.h | 105 +
drivers/staging/wlan-ng/p80211metamsg.h | 105 +
drivers/staging/wlan-ng/p80211metastruct.h | 644 ++
drivers/staging/wlan-ng/p80211mgmt.h | 575 ++
drivers/staging/wlan-ng/p80211mod.c | 216 +
drivers/staging/wlan-ng/p80211msg.h | 102 +
drivers/staging/wlan-ng/p80211netdev.c | 1502 ++++
drivers/staging/wlan-ng/p80211netdev.h | 336 +
drivers/staging/wlan-ng/p80211req.c | 329 +
drivers/staging/wlan-ng/p80211req.h | 68 +
drivers/staging/wlan-ng/p80211types.h | 675 ++
drivers/staging/wlan-ng/p80211wep.c | 317 +
drivers/staging/wlan-ng/p80211wext.c | 2048 ++++++
drivers/staging/wlan-ng/prism2_cs.c | 1487 ++++
drivers/staging/wlan-ng/prism2_pci.c | 332 +
drivers/staging/wlan-ng/prism2_plx.c | 472 ++
drivers/staging/wlan-ng/prism2_usb.c | 361 +
drivers/staging/wlan-ng/prism2mgmt.c | 2956 ++++++++
drivers/staging/wlan-ng/prism2mgmt.h | 182 +
drivers/staging/wlan-ng/prism2mib.c | 3799 ++++++++++
drivers/staging/wlan-ng/prism2sta.c | 2502 +++++++
drivers/staging/wlan-ng/version.h | 64 +
drivers/staging/wlan-ng/wlan_compat.h | 757 ++
include/linux/kernel.h | 1 +
kernel/module.c | 11 +
kernel/panic.c | 6 +-
scripts/mod/modpost.c | 9 +
211 files changed, 152423 insertions(+), 2 deletions(-)
create mode 100644 drivers/staging/Kconfig
create mode 100644 drivers/staging/Makefile
create mode 100644 drivers/staging/at76_usb/Kconfig
create mode 100644 drivers/staging/at76_usb/Makefile
create mode 100644 drivers/staging/at76_usb/TODO
create mode 100644 drivers/staging/at76_usb/at76_usb.c
create mode 100644 drivers/staging/at76_usb/at76_usb.h
create mode 100644 drivers/staging/echo/Kconfig
create mode 100644 drivers/staging/echo/Makefile
create mode 100644 drivers/staging/echo/TODO
create mode 100644 drivers/staging/echo/bit_operations.h
create mode 100644 drivers/staging/echo/echo.c
create mode 100644 drivers/staging/echo/echo.h
create mode 100644 drivers/staging/echo/fir.h
create mode 100644 drivers/staging/echo/mmx.h
create mode 100644 drivers/staging/et131x/Kconfig
create mode 100644 drivers/staging/et131x/Makefile
create mode 100644 drivers/staging/et131x/README
create mode 100644 drivers/staging/et131x/et1310_address_map.h
create mode 100644 drivers/staging/et131x/et1310_eeprom.c
create mode 100644 drivers/staging/et131x/et1310_eeprom.h
create mode 100644 drivers/staging/et131x/et1310_jagcore.c
create mode 100644 drivers/staging/et131x/et1310_jagcore.h
create mode 100644 drivers/staging/et131x/et1310_mac.c
create mode 100644 drivers/staging/et131x/et1310_mac.h
create mode 100644 drivers/staging/et131x/et1310_phy.c
create mode 100644 drivers/staging/et131x/et1310_phy.h
create mode 100644 drivers/staging/et131x/et1310_pm.c
create mode 100644 drivers/staging/et131x/et1310_pm.h
create mode 100644 drivers/staging/et131x/et1310_rx.c
create mode 100644 drivers/staging/et131x/et1310_rx.h
create mode 100644 drivers/staging/et131x/et1310_tx.c
create mode 100644 drivers/staging/et131x/et1310_tx.h
create mode 100644 drivers/staging/et131x/et131x_adapter.h
create mode 100644 drivers/staging/et131x/et131x_config.c
create mode 100644 drivers/staging/et131x/et131x_config.h
create mode 100644 drivers/staging/et131x/et131x_debug.c
create mode 100644 drivers/staging/et131x/et131x_debug.h
create mode 100644 drivers/staging/et131x/et131x_defs.h
create mode 100644 drivers/staging/et131x/et131x_initpci.c
create mode 100644 drivers/staging/et131x/et131x_initpci.h
create mode 100644 drivers/staging/et131x/et131x_isr.c
create mode 100644 drivers/staging/et131x/et131x_isr.h
create mode 100644 drivers/staging/et131x/et131x_netdev.c
create mode 100644 drivers/staging/et131x/et131x_netdev.h
create mode 100644 drivers/staging/et131x/et131x_version.h
create mode 100644 drivers/staging/go7007/Kconfig
create mode 100644 drivers/staging/go7007/Makefile
create mode 100644 drivers/staging/go7007/README
create mode 100644 drivers/staging/go7007/go7007-driver.c
create mode 100644 drivers/staging/go7007/go7007-fw.c
create mode 100644 drivers/staging/go7007/go7007-i2c.c
create mode 100644 drivers/staging/go7007/go7007-priv.h
create mode 100644 drivers/staging/go7007/go7007-usb.c
create mode 100644 drivers/staging/go7007/go7007-v4l2.c
create mode 100644 drivers/staging/go7007/go7007.h
create mode 100644 drivers/staging/go7007/saa7134-go7007.c
create mode 100644 drivers/staging/go7007/snd-go7007.c
create mode 100644 drivers/staging/go7007/wis-i2c.h
create mode 100644 drivers/staging/go7007/wis-ov7640.c
create mode 100644 drivers/staging/go7007/wis-saa7113.c
create mode 100644 drivers/staging/go7007/wis-saa7115.c
create mode 100644 drivers/staging/go7007/wis-sony-tuner.c
create mode 100644 drivers/staging/go7007/wis-tw2804.c
create mode 100644 drivers/staging/go7007/wis-tw9903.c
create mode 100644 drivers/staging/go7007/wis-uda1342.c
create mode 100644 drivers/staging/me4000/Kconfig
create mode 100644 drivers/staging/me4000/Makefile
create mode 100644 drivers/staging/me4000/README
create mode 100644 drivers/staging/me4000/me4000.c
create mode 100644 drivers/staging/me4000/me4000.h
create mode 100644 drivers/staging/me4000/me4000_firmware.h
create mode 100644 drivers/staging/me4000/me4610_firmware.h
create mode 100644 drivers/staging/slicoss/Kconfig
create mode 100644 drivers/staging/slicoss/Makefile
create mode 100644 drivers/staging/slicoss/README
create mode 100644 drivers/staging/slicoss/gbdownload.h
create mode 100644 drivers/staging/slicoss/gbrcvucode.h
create mode 100644 drivers/staging/slicoss/oasisdbgdownload.h
create mode 100644 drivers/staging/slicoss/oasisdownload.h
create mode 100644 drivers/staging/slicoss/oasisrcvucode.h
create mode 100644 drivers/staging/slicoss/slic.h
create mode 100644 drivers/staging/slicoss/slic_os.h
create mode 100644 drivers/staging/slicoss/slicbuild.h
create mode 100644 drivers/staging/slicoss/slicdbg.h
create mode 100644 drivers/staging/slicoss/slicdump.h
create mode 100644 drivers/staging/slicoss/slichw.h
create mode 100644 drivers/staging/slicoss/slicinc.h
create mode 100644 drivers/staging/slicoss/slicoss.c
create mode 100644 drivers/staging/staging.c
create mode 100644 drivers/staging/sxg/Kconfig
create mode 100644 drivers/staging/sxg/Makefile
create mode 100644 drivers/staging/sxg/README
create mode 100644 drivers/staging/sxg/saharadbgdownload.h
create mode 100644 drivers/staging/sxg/sxg.c
create mode 100644 drivers/staging/sxg/sxg.h
create mode 100644 drivers/staging/sxg/sxg_os.h
create mode 100644 drivers/staging/sxg/sxgdbg.h
create mode 100644 drivers/staging/sxg/sxghif.h
create mode 100644 drivers/staging/sxg/sxghw.h
create mode 100644 drivers/staging/sxg/sxgphycode.h
create mode 100644 drivers/staging/usbip/Kconfig
create mode 100644 drivers/staging/usbip/Makefile
create mode 100644 drivers/staging/usbip/README
create mode 100644 drivers/staging/usbip/stub.h
create mode 100644 drivers/staging/usbip/stub_dev.c
create mode 100644 drivers/staging/usbip/stub_main.c
create mode 100644 drivers/staging/usbip/stub_rx.c
create mode 100644 drivers/staging/usbip/stub_tx.c
create mode 100644 drivers/staging/usbip/usbip_common.c
create mode 100644 drivers/staging/usbip/usbip_common.h
create mode 100644 drivers/staging/usbip/usbip_event.c
create mode 100644 drivers/staging/usbip/vhci.h
create mode 100644 drivers/staging/usbip/vhci_hcd.c
create mode 100644 drivers/staging/usbip/vhci_rx.c
create mode 100644 drivers/staging/usbip/vhci_sysfs.c
create mode 100644 drivers/staging/usbip/vhci_tx.c
create mode 100644 drivers/staging/winbond/Kconfig
create mode 100644 drivers/staging/winbond/Makefile
create mode 100644 drivers/staging/winbond/README
create mode 100644 drivers/staging/winbond/adapter.h
create mode 100644 drivers/staging/winbond/bss_f.h
create mode 100644 drivers/staging/winbond/bssdscpt.h
create mode 100644 drivers/staging/winbond/ds_tkip.h
create mode 100644 drivers/staging/winbond/gl_80211.h
create mode 100644 drivers/staging/winbond/ioctls.h
create mode 100644 drivers/staging/winbond/linux/common.h
create mode 100644 drivers/staging/winbond/linux/sysdef.h
create mode 100644 drivers/staging/winbond/linux/wb35reg.c
create mode 100644 drivers/staging/winbond/linux/wb35reg_f.h
create mode 100644 drivers/staging/winbond/linux/wb35reg_s.h
create mode 100644 drivers/staging/winbond/linux/wb35rx.c
create mode 100644 drivers/staging/winbond/linux/wb35rx_f.h
create mode 100644 drivers/staging/winbond/linux/wb35rx_s.h
create mode 100644 drivers/staging/winbond/linux/wb35tx.c
create mode 100644 drivers/staging/winbond/linux/wb35tx_f.h
create mode 100644 drivers/staging/winbond/linux/wb35tx_s.h
create mode 100644 drivers/staging/winbond/linux/wbusb.c
create mode 100644 drivers/staging/winbond/linux/wbusb_f.h
create mode 100644 drivers/staging/winbond/linux/wbusb_s.h
create mode 100644 drivers/staging/winbond/localpara.h
create mode 100644 drivers/staging/winbond/mac_structures.h
create mode 100644 drivers/staging/winbond/mds.c
create mode 100644 drivers/staging/winbond/mds_f.h
create mode 100644 drivers/staging/winbond/mds_s.h
create mode 100644 drivers/staging/winbond/mlme_mib.h
create mode 100644 drivers/staging/winbond/mlme_s.h
create mode 100644 drivers/staging/winbond/mlmetxrx.c
create mode 100644 drivers/staging/winbond/mlmetxrx_f.h
create mode 100644 drivers/staging/winbond/mto.c
create mode 100644 drivers/staging/winbond/mto.h
create mode 100644 drivers/staging/winbond/mto_f.h
create mode 100644 drivers/staging/winbond/os_common.h
create mode 100644 drivers/staging/winbond/phy_calibration.c
create mode 100644 drivers/staging/winbond/phy_calibration.h
create mode 100644 drivers/staging/winbond/reg.c
create mode 100644 drivers/staging/winbond/rxisr.c
create mode 100644 drivers/staging/winbond/scan_s.h
create mode 100644 drivers/staging/winbond/sme_api.c
create mode 100644 drivers/staging/winbond/sme_api.h
create mode 100644 drivers/staging/winbond/sme_s.h
create mode 100644 drivers/staging/winbond/wb35_ver.h
create mode 100644 drivers/staging/winbond/wbhal.c
create mode 100644 drivers/staging/winbond/wbhal_f.h
create mode 100644 drivers/staging/winbond/wbhal_s.h
create mode 100644 drivers/staging/winbond/wblinux.c
create mode 100644 drivers/staging/winbond/wblinux_f.h
create mode 100644 drivers/staging/winbond/wblinux_s.h
create mode 100644 drivers/staging/wlan-ng/Kconfig
create mode 100644 drivers/staging/wlan-ng/Makefile
create mode 100644 drivers/staging/wlan-ng/README
create mode 100644 drivers/staging/wlan-ng/hfa384x.c
create mode 100644 drivers/staging/wlan-ng/hfa384x.h
create mode 100644 drivers/staging/wlan-ng/hfa384x_usb.c
create mode 100644 drivers/staging/wlan-ng/p80211conv.c
create mode 100644 drivers/staging/wlan-ng/p80211conv.h
create mode 100644 drivers/staging/wlan-ng/p80211hdr.h
create mode 100644 drivers/staging/wlan-ng/p80211ioctl.h
create mode 100644 drivers/staging/wlan-ng/p80211meta.h
create mode 100644 drivers/staging/wlan-ng/p80211metadef.h
create mode 100644 drivers/staging/wlan-ng/p80211metamib.h
create mode 100644 drivers/staging/wlan-ng/p80211metamsg.h
create mode 100644 drivers/staging/wlan-ng/p80211metastruct.h
create mode 100644 drivers/staging/wlan-ng/p80211mgmt.h
create mode 100644 drivers/staging/wlan-ng/p80211mod.c
create mode 100644 drivers/staging/wlan-ng/p80211msg.h
create mode 100644 drivers/staging/wlan-ng/p80211netdev.c
create mode 100644 drivers/staging/wlan-ng/p80211netdev.h
create mode 100644 drivers/staging/wlan-ng/p80211req.c
create mode 100644 drivers/staging/wlan-ng/p80211req.h
create mode 100644 drivers/staging/wlan-ng/p80211types.h
create mode 100644 drivers/staging/wlan-ng/p80211wep.c
create mode 100644 drivers/staging/wlan-ng/p80211wext.c
create mode 100644 drivers/staging/wlan-ng/prism2_cs.c
create mode 100644 drivers/staging/wlan-ng/prism2_pci.c
create mode 100644 drivers/staging/wlan-ng/prism2_plx.c
create mode 100644 drivers/staging/wlan-ng/prism2_usb.c
create mode 100644 drivers/staging/wlan-ng/prism2mgmt.c
create mode 100644 drivers/staging/wlan-ng/prism2mgmt.h
create mode 100644 drivers/staging/wlan-ng/prism2mib.c
create mode 100644 drivers/staging/wlan-ng/prism2sta.c
create mode 100644 drivers/staging/wlan-ng/version.h
create mode 100644 drivers/staging/wlan-ng/wlan_compat.h
---------------
David Rowe (1):
Staging: add echo cancelation module
Greg Kroah-Hartman (12):
Staging: add TAINT_CRAP for all drivers/staging code
Staging: add TAINT_CRAP flag to drivers/staging modules
Staging: add Kconfig entries and Makefile infrastructure
Staging: add MAINTAINERS entry
Staging: add et131x network driver
Staging: add Alacritech slicoss network driver
Staging: add sxg network driver
Staging: add me4000 firmware files
Staging: add me4000 pci data collection driver
Staging: add the go7007 video driver
Staging: add wlan-ng prism2 usb driver
Staging: workaround build system bug
J.R. Mauro (2):
Staging: Fix gcc warnings in sxg
Staging: Lindent sxg.c
Lior Dotan (4):
Staging: SLICOSS: lots of checkpatch fixes
Staging: SLICOSS: Fix warnings due to static usage
Staging: SLICOSS: Fix remaining type names
Staging: SLICOSS: Call pci_release_regions at driver exit
Pavel Machek (1):
Staging: add w35und wifi driver
Pavel Roskin (1):
staging: at76_usb wireless driver
Ross Cohen (1):
Staging: go7007 v4l fixes
Takahiro Hirofuchi (3):
Staging: USB/IP: add common functions needed
Staging: USB/IP: add client driver
Staging: USB/IP: add host driver
^ permalink raw reply [flat|nested] 37+ messages in thread* [PATCH 24/25] Staging: workaround build system bug
2008-10-13 21:36 ` [GIT PATCH] STAGING patches for 2.6.28 Greg KH
@ 2008-10-13 21:38 ` Greg KH
2008-10-13 21:38 ` [PATCH 25/25] staging: at76_usb wireless driver Greg KH
2008-10-17 20:34 ` [GIT PATCH] STAGING patches for 2.6.28 Linus Torvalds
2 siblings, 0 replies; 37+ messages in thread
From: Greg KH @ 2008-10-13 21:38 UTC (permalink / raw)
To: linux-kernel; +Cc: Greg Kroah-Hartman, Sam Ravnborg
From: Greg Kroah-Hartman <gregkh@suse.de>
This is needed as CONFIG_STAGING is set to y, yet there is no code in
drivers/staging/ to build, so the build-in.o doesn't get created
properly. Create a "dummy" module in drivers/staging called staging.c
to work around this bug.
Cc: Sam Ravnborg <sam@ravnborg.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/Makefile | 3 +++
drivers/staging/staging.c | 19 +++++++++++++++++++
2 files changed, 22 insertions(+), 0 deletions(-)
create mode 100644 drivers/staging/staging.c
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 93decb8..7c466e9 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -1,5 +1,8 @@
# Makefile for staging directory
+# fix for build system bug...
+obj-$(CONFIG_STAGING) += staging.o
+
obj-$(CONFIG_ET131X) += et131x/
obj-$(CONFIG_SLICOSS) += slicoss/
obj-$(CONFIG_SXG) += sxg/
diff --git a/drivers/staging/staging.c b/drivers/staging/staging.c
new file mode 100644
index 0000000..233e589
--- /dev/null
+++ b/drivers/staging/staging.c
@@ -0,0 +1,19 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+static int __init staging_init(void)
+{
+ return 0;
+}
+
+static void __exit staging_exit(void)
+{
+}
+
+module_init(staging_init);
+module_exit(staging_exit);
+
+MODULE_AUTHOR("Greg Kroah-Hartman");
+MODULE_DESCRIPTION("Staging Core");
+MODULE_LICENSE("GPL");
--
1.6.0.2
^ permalink raw reply related [flat|nested] 37+ messages in thread* [PATCH 25/25] staging: at76_usb wireless driver
2008-10-13 21:36 ` [GIT PATCH] STAGING patches for 2.6.28 Greg KH
2008-10-13 21:38 ` [PATCH 24/25] Staging: workaround build system bug Greg KH
@ 2008-10-13 21:38 ` Greg KH
2008-10-13 21:49 ` Pavel Roskin
2008-10-17 20:34 ` [GIT PATCH] STAGING patches for 2.6.28 Linus Torvalds
2 siblings, 1 reply; 37+ messages in thread
From: Greg KH @ 2008-10-13 21:38 UTC (permalink / raw)
To: linux-kernel; +Cc: Pavel Roskin, John W. Linville, Greg Kroah-Hartman
From: Pavel Roskin <proski@gnu.org>
Add the at76_usb wireless driver to the staging tree while the
other kernel driver (out of tree) gets rewritten to use the internal
wireless stack.
This patch comes directly from the Fedora kernel tree, with only the
directory placement of the files changed.
Signed-off-by: Pavel Roskin <proski@gnu.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
drivers/staging/Kconfig | 2 +
drivers/staging/Makefile | 1 +
drivers/staging/at76_usb/Kconfig | 8 +
drivers/staging/at76_usb/Makefile | 1 +
drivers/staging/at76_usb/TODO | 2 +
drivers/staging/at76_usb/at76_usb.c | 5559 +++++++++++++++++++++++++++++++++++
drivers/staging/at76_usb/at76_usb.h | 619 ++++
7 files changed, 6192 insertions(+), 0 deletions(-)
create mode 100644 drivers/staging/at76_usb/Kconfig
create mode 100644 drivers/staging/at76_usb/Makefile
create mode 100644 drivers/staging/at76_usb/TODO
create mode 100644 drivers/staging/at76_usb/at76_usb.c
create mode 100644 drivers/staging/at76_usb/at76_usb.h
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 25338b7..2a79dec 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -41,4 +41,6 @@ source "drivers/staging/wlan-ng/Kconfig"
source "drivers/staging/echo/Kconfig"
+source "drivers/staging/at76_usb/Kconfig"
+
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 7c466e9..325bca4 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_USB_IP_COMMON) += usbip/
obj-$(CONFIG_W35UND) += winbond/
obj-$(CONFIG_PRISM2_USB) += wlan-ng/
obj-$(CONFIG_ECHO) += echo/
+obj-$(CONFIG_USB_ATMEL) += at76_usb/
diff --git a/drivers/staging/at76_usb/Kconfig b/drivers/staging/at76_usb/Kconfig
new file mode 100644
index 0000000..8606f96
--- /dev/null
+++ b/drivers/staging/at76_usb/Kconfig
@@ -0,0 +1,8 @@
+config USB_ATMEL
+ tristate "Atmel at76c503/at76c505/at76c505a USB cards"
+ depends on WLAN_80211 && USB
+ default N
+ select FW_LOADER
+ ---help---
+ Enable support for USB Wireless devices using Atmel at76c503,
+ at76c505 or at76c505a chips.
diff --git a/drivers/staging/at76_usb/Makefile b/drivers/staging/at76_usb/Makefile
new file mode 100644
index 0000000..6a47e88
--- /dev/null
+++ b/drivers/staging/at76_usb/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_USB_ATMEL) += at76_usb.o
diff --git a/drivers/staging/at76_usb/TODO b/drivers/staging/at76_usb/TODO
new file mode 100644
index 0000000..6911ca7
--- /dev/null
+++ b/drivers/staging/at76_usb/TODO
@@ -0,0 +1,2 @@
+rewrite the driver to use the proper in-kernel wireless stack
+instead of using its own.
diff --git a/drivers/staging/at76_usb/at76_usb.c b/drivers/staging/at76_usb/at76_usb.c
new file mode 100644
index 0000000..52df0c6
--- /dev/null
+++ b/drivers/staging/at76_usb/at76_usb.c
@@ -0,0 +1,5559 @@
+/*
+ * at76c503/at76c505 USB driver
+ *
+ * Copyright (c) 2002 - 2003 Oliver Kurth
+ * Copyright (c) 2004 Joerg Albert <joerg.albert@gmx.de>
+ * Copyright (c) 2004 Nick Jones
+ * Copyright (c) 2004 Balint Seeber <n0_5p4m_p13453@hotmail.com>
+ * Copyright (c) 2007 Guido Guenther <agx@sigxcpu.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This file is part of the Berlios driver for WLAN USB devices based on the
+ * Atmel AT76C503A/505/505A.
+ *
+ * Some iw_handler code was taken from airo.c, (C) 1999 Benjamin Reed
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/usb.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+#include <net/ieee80211_radiotap.h>
+#include <linux/firmware.h>
+#include <linux/leds.h>
+#include <net/ieee80211.h>
+
+#include "at76_usb.h"
+
+/* Version information */
+#define DRIVER_NAME "at76_usb"
+#define DRIVER_VERSION "0.17"
+#define DRIVER_DESC "Atmel at76x USB Wireless LAN Driver"
+
+/* at76_debug bits */
+#define DBG_PROGRESS 0x00000001 /* authentication/accociation */
+#define DBG_BSS_TABLE 0x00000002 /* show BSS table after scans */
+#define DBG_IOCTL 0x00000004 /* ioctl calls / settings */
+#define DBG_MAC_STATE 0x00000008 /* MAC state transitions */
+#define DBG_TX_DATA 0x00000010 /* tx header */
+#define DBG_TX_DATA_CONTENT 0x00000020 /* tx content */
+#define DBG_TX_MGMT 0x00000040 /* tx management */
+#define DBG_RX_DATA 0x00000080 /* rx data header */
+#define DBG_RX_DATA_CONTENT 0x00000100 /* rx data content */
+#define DBG_RX_MGMT 0x00000200 /* rx mgmt frame headers */
+#define DBG_RX_BEACON 0x00000400 /* rx beacon */
+#define DBG_RX_CTRL 0x00000800 /* rx control */
+#define DBG_RX_MGMT_CONTENT 0x00001000 /* rx mgmt content */
+#define DBG_RX_FRAGS 0x00002000 /* rx data fragment handling */
+#define DBG_DEVSTART 0x00004000 /* fw download, device start */
+#define DBG_URB 0x00008000 /* rx urb status, ... */
+#define DBG_RX_ATMEL_HDR 0x00010000 /* Atmel-specific Rx headers */
+#define DBG_PROC_ENTRY 0x00020000 /* procedure entries/exits */
+#define DBG_PM 0x00040000 /* power management settings */
+#define DBG_BSS_MATCH 0x00080000 /* BSS match failures */
+#define DBG_PARAMS 0x00100000 /* show configured parameters */
+#define DBG_WAIT_COMPLETE 0x00200000 /* command completion */
+#define DBG_RX_FRAGS_SKB 0x00400000 /* skb header of Rx fragments */
+#define DBG_BSS_TABLE_RM 0x00800000 /* purging bss table entries */
+#define DBG_MONITOR_MODE 0x01000000 /* monitor mode */
+#define DBG_MIB 0x02000000 /* dump all MIBs on startup */
+#define DBG_MGMT_TIMER 0x04000000 /* dump mgmt_timer ops */
+#define DBG_WE_EVENTS 0x08000000 /* dump wireless events */
+#define DBG_FW 0x10000000 /* firmware download */
+#define DBG_DFU 0x20000000 /* device firmware upgrade */
+
+#define DBG_DEFAULTS 0
+
+/* Use our own dbg macro */
+#define at76_dbg(bits, format, arg...) \
+ do { \
+ if (at76_debug & (bits)) \
+ printk(KERN_DEBUG DRIVER_NAME ": " format "\n" , ## arg); \
+ } while (0)
+
+static int at76_debug = DBG_DEFAULTS;
+
+/* Protect against concurrent firmware loading and parsing */
+static struct mutex fw_mutex;
+
+static struct fwentry firmwares[] = {
+ [0] = {""},
+ [BOARD_503_ISL3861] = {"atmel_at76c503-i3861.bin"},
+ [BOARD_503_ISL3863] = {"atmel_at76c503-i3863.bin"},
+ [BOARD_503] = {"atmel_at76c503-rfmd.bin"},
+ [BOARD_503_ACC] = {"atmel_at76c503-rfmd-acc.bin"},
+ [BOARD_505] = {"atmel_at76c505-rfmd.bin"},
+ [BOARD_505_2958] = {"atmel_at76c505-rfmd2958.bin"},
+ [BOARD_505A] = {"atmel_at76c505a-rfmd2958.bin"},
+ [BOARD_505AMX] = {"atmel_at76c505amx-rfmd.bin"},
+};
+
+#define USB_DEVICE_DATA(__ops) .driver_info = (kernel_ulong_t)(__ops)
+
+static struct usb_device_id dev_table[] = {
+ /*
+ * at76c503-i3861
+ */
+ /* Generic AT76C503/3861 device */
+ {USB_DEVICE(0x03eb, 0x7603), USB_DEVICE_DATA(BOARD_503_ISL3861)},
+ /* Linksys WUSB11 v2.1/v2.6 */
+ {USB_DEVICE(0x066b, 0x2211), USB_DEVICE_DATA(BOARD_503_ISL3861)},
+ /* Netgear MA101 rev. A */
+ {USB_DEVICE(0x0864, 0x4100), USB_DEVICE_DATA(BOARD_503_ISL3861)},
+ /* Tekram U300C / Allnet ALL0193 */
+ {USB_DEVICE(0x0b3b, 0x1612), USB_DEVICE_DATA(BOARD_503_ISL3861)},
+ /* HP HN210W J7801A */
+ {USB_DEVICE(0x03f0, 0x011c), USB_DEVICE_DATA(BOARD_503_ISL3861)},
+ /* Sitecom/Z-Com/Zyxel M4Y-750 */
+ {USB_DEVICE(0x0cde, 0x0001), USB_DEVICE_DATA(BOARD_503_ISL3861)},
+ /* Dynalink/Askey WLL013 (intersil) */
+ {USB_DEVICE(0x069a, 0x0320), USB_DEVICE_DATA(BOARD_503_ISL3861)},
+ /* EZ connect 11Mpbs Wireless USB Adapter SMC2662W v1 */
+ {USB_DEVICE(0x0d5c, 0xa001), USB_DEVICE_DATA(BOARD_503_ISL3861)},
+ /* BenQ AWL300 */
+ {USB_DEVICE(0x04a5, 0x9000), USB_DEVICE_DATA(BOARD_503_ISL3861)},
+ /* Addtron AWU-120, Compex WLU11 */
+ {USB_DEVICE(0x05dd, 0xff31), USB_DEVICE_DATA(BOARD_503_ISL3861)},
+ /* Intel AP310 AnyPoint II USB */
+ {USB_DEVICE(0x8086, 0x0200), USB_DEVICE_DATA(BOARD_503_ISL3861)},
+ /* Dynalink L11U */
+ {USB_DEVICE(0x0d8e, 0x7100), USB_DEVICE_DATA(BOARD_503_ISL3861)},
+ /* Arescom WL-210, FCC id 07J-GL2411USB */
+ {USB_DEVICE(0x0d8e, 0x7110), USB_DEVICE_DATA(BOARD_503_ISL3861)},
+ /* I-O DATA WN-B11/USB */
+ {USB_DEVICE(0x04bb, 0x0919), USB_DEVICE_DATA(BOARD_503_ISL3861)},
+ /* BT Voyager 1010 */
+ {USB_DEVICE(0x069a, 0x0821), USB_DEVICE_DATA(BOARD_503_ISL3861)},
+ /*
+ * at76c503-i3863
+ */
+ /* Generic AT76C503/3863 device */
+ {USB_DEVICE(0x03eb, 0x7604), USB_DEVICE_DATA(BOARD_503_ISL3863)},
+ /* Samsung SWL-2100U */
+ {USB_DEVICE(0x055d, 0xa000), USB_DEVICE_DATA(BOARD_503_ISL3863)},
+ /*
+ * at76c503-rfmd
+ */
+ /* Generic AT76C503/RFMD device */
+ {USB_DEVICE(0x03eb, 0x7605), USB_DEVICE_DATA(BOARD_503)},
+ /* Dynalink/Askey WLL013 (rfmd) */
+ {USB_DEVICE(0x069a, 0x0321), USB_DEVICE_DATA(BOARD_503)},
+ /* Linksys WUSB11 v2.6 */
+ {USB_DEVICE(0x077b, 0x2219), USB_DEVICE_DATA(BOARD_503)},
+ /* Network Everywhere NWU11B */
+ {USB_DEVICE(0x077b, 0x2227), USB_DEVICE_DATA(BOARD_503)},
+ /* Netgear MA101 rev. B */
+ {USB_DEVICE(0x0864, 0x4102), USB_DEVICE_DATA(BOARD_503)},
+ /* D-Link DWL-120 rev. E */
+ {USB_DEVICE(0x2001, 0x3200), USB_DEVICE_DATA(BOARD_503)},
+ /* Actiontec 802UAT1, HWU01150-01UK */
+ {USB_DEVICE(0x1668, 0x7605), USB_DEVICE_DATA(BOARD_503)},
+ /* AirVast W-Buddie WN210 */
+ {USB_DEVICE(0x03eb, 0x4102), USB_DEVICE_DATA(BOARD_503)},
+ /* Dick Smith Electronics XH1153 802.11b USB adapter */
+ {USB_DEVICE(0x1371, 0x5743), USB_DEVICE_DATA(BOARD_503)},
+ /* CNet CNUSB611 */
+ {USB_DEVICE(0x1371, 0x0001), USB_DEVICE_DATA(BOARD_503)},
+ /* FiberLine FL-WL200U */
+ {USB_DEVICE(0x1371, 0x0002), USB_DEVICE_DATA(BOARD_503)},
+ /* BenQ AWL400 USB stick */
+ {USB_DEVICE(0x04a5, 0x9001), USB_DEVICE_DATA(BOARD_503)},
+ /* 3Com 3CRSHEW696 */
+ {USB_DEVICE(0x0506, 0x0a01), USB_DEVICE_DATA(BOARD_503)},
+ /* Siemens Santis ADSL WLAN USB adapter WLL 013 */
+ {USB_DEVICE(0x0681, 0x001b), USB_DEVICE_DATA(BOARD_503)},
+ /* Belkin F5D6050, version 2 */
+ {USB_DEVICE(0x050d, 0x0050), USB_DEVICE_DATA(BOARD_503)},
+ /* iBlitzz, BWU613 (not *B or *SB) */
+ {USB_DEVICE(0x07b8, 0xb000), USB_DEVICE_DATA(BOARD_503)},
+ /* Gigabyte GN-WLBM101 */
+ {USB_DEVICE(0x1044, 0x8003), USB_DEVICE_DATA(BOARD_503)},
+ /* Planex GW-US11S */
+ {USB_DEVICE(0x2019, 0x3220), USB_DEVICE_DATA(BOARD_503)},
+ /* Internal WLAN adapter in h5[4,5]xx series iPAQs */
+ {USB_DEVICE(0x049f, 0x0032), USB_DEVICE_DATA(BOARD_503)},
+ /* Corega Wireless LAN USB-11 mini */
+ {USB_DEVICE(0x07aa, 0x0011), USB_DEVICE_DATA(BOARD_503)},
+ /* Corega Wireless LAN USB-11 mini2 */
+ {USB_DEVICE(0x07aa, 0x0018), USB_DEVICE_DATA(BOARD_503)},
+ /* Uniden PCW100 */
+ {USB_DEVICE(0x05dd, 0xff35), USB_DEVICE_DATA(BOARD_503)},
+ /*
+ * at76c503-rfmd-acc
+ */
+ /* SMC2664W */
+ {USB_DEVICE(0x083a, 0x3501), USB_DEVICE_DATA(BOARD_503_ACC)},
+ /* Belkin F5D6050, SMC2662W v2, SMC2662W-AR */
+ {USB_DEVICE(0x0d5c, 0xa002), USB_DEVICE_DATA(BOARD_503_ACC)},
+ /*
+ * at76c505-rfmd
+ */
+ /* Generic AT76C505/RFMD */
+ {USB_DEVICE(0x03eb, 0x7606), USB_DEVICE_DATA(BOARD_505)},
+ /*
+ * at76c505-rfmd2958
+ */
+ /* Generic AT76C505/RFMD, OvisLink WL-1130USB */
+ {USB_DEVICE(0x03eb, 0x7613), USB_DEVICE_DATA(BOARD_505_2958)},
+ /* Fiberline FL-WL240U */
+ {USB_DEVICE(0x1371, 0x0014), USB_DEVICE_DATA(BOARD_505_2958)},
+ /* CNet CNUSB-611G */
+ {USB_DEVICE(0x1371, 0x0013), USB_DEVICE_DATA(BOARD_505_2958)},
+ /* Linksys WUSB11 v2.8 */
+ {USB_DEVICE(0x1915, 0x2233), USB_DEVICE_DATA(BOARD_505_2958)},
+ /* Xterasys XN-2122B, IBlitzz BWU613B/BWU613SB */
+ {USB_DEVICE(0x12fd, 0x1001), USB_DEVICE_DATA(BOARD_505_2958)},
+ /* Corega WLAN USB Stick 11 */
+ {USB_DEVICE(0x07aa, 0x7613), USB_DEVICE_DATA(BOARD_505_2958)},
+ /* Microstar MSI Box MS6978 */
+ {USB_DEVICE(0x0db0, 0x1020), USB_DEVICE_DATA(BOARD_505_2958)},
+ /*
+ * at76c505a-rfmd2958
+ */
+ /* Generic AT76C505A device */
+ {USB_DEVICE(0x03eb, 0x7614), USB_DEVICE_DATA(BOARD_505A)},
+ /* Generic AT76C505AS device */
+ {USB_DEVICE(0x03eb, 0x7617), USB_DEVICE_DATA(BOARD_505A)},
+ /* Siemens Gigaset USB WLAN Adapter 11 */
+ {USB_DEVICE(0x1690, 0x0701), USB_DEVICE_DATA(BOARD_505A)},
+ /*
+ * at76c505amx-rfmd
+ */
+ /* Generic AT76C505AMX device */
+ {USB_DEVICE(0x03eb, 0x7615), USB_DEVICE_DATA(BOARD_505AMX)},
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, dev_table);
+
+/* Supported rates of this hardware, bit 7 marks basic rates */
+static const u8 hw_rates[] = { 0x82, 0x84, 0x0b, 0x16 };
+
+/* Frequency of each channel in MHz */
+static const long channel_frequency[] = {
+ 2412, 2417, 2422, 2427, 2432, 2437, 2442,
+ 2447, 2452, 2457, 2462, 2467, 2472, 2484
+};
+
+#define NUM_CHANNELS ARRAY_SIZE(channel_frequency)
+
+static const char *const preambles[] = { "long", "short", "auto" };
+
+static const char *const mac_states[] = {
+ [MAC_INIT] = "INIT",
+ [MAC_SCANNING] = "SCANNING",
+ [MAC_AUTH] = "AUTH",
+ [MAC_ASSOC] = "ASSOC",
+ [MAC_JOINING] = "JOINING",
+ [MAC_CONNECTED] = "CONNECTED",
+ [MAC_OWN_IBSS] = "OWN_IBSS"
+};
+
+/* Firmware download */
+/* DFU states */
+#define STATE_IDLE 0x00
+#define STATE_DETACH 0x01
+#define STATE_DFU_IDLE 0x02
+#define STATE_DFU_DOWNLOAD_SYNC 0x03
+#define STATE_DFU_DOWNLOAD_BUSY 0x04
+#define STATE_DFU_DOWNLOAD_IDLE 0x05
+#define STATE_DFU_MANIFEST_SYNC 0x06
+#define STATE_DFU_MANIFEST 0x07
+#define STATE_DFU_MANIFEST_WAIT_RESET 0x08
+#define STATE_DFU_UPLOAD_IDLE 0x09
+#define STATE_DFU_ERROR 0x0a
+
+/* DFU commands */
+#define DFU_DETACH 0
+#define DFU_DNLOAD 1
+#define DFU_UPLOAD 2
+#define DFU_GETSTATUS 3
+#define DFU_CLRSTATUS 4
+#define DFU_GETSTATE 5
+#define DFU_ABORT 6
+
+#define FW_BLOCK_SIZE 1024
+
+struct dfu_status {
+ unsigned char status;
+ unsigned char poll_timeout[3];
+ unsigned char state;
+ unsigned char string;
+} __attribute__((packed));
+
+static inline int at76_is_intersil(enum board_type board)
+{
+ return (board == BOARD_503_ISL3861 || board == BOARD_503_ISL3863);
+}
+
+static inline int at76_is_503rfmd(enum board_type board)
+{
+ return (board == BOARD_503 || board == BOARD_503_ACC);
+}
+
+static inline int at76_is_505a(enum board_type board)
+{
+ return (board == BOARD_505A || board == BOARD_505AMX);
+}
+
+/* Load a block of the first (internal) part of the firmware */
+static int at76_load_int_fw_block(struct usb_device *udev, int blockno,
+ void *block, int size)
+{
+ return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), DFU_DNLOAD,
+ USB_TYPE_CLASS | USB_DIR_OUT |
+ USB_RECIP_INTERFACE, blockno, 0, block, size,
+ USB_CTRL_GET_TIMEOUT);
+}
+
+static int at76_dfu_get_status(struct usb_device *udev,
+ struct dfu_status *status)
+{
+ int ret;
+
+ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), DFU_GETSTATUS,
+ USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE,
+ 0, 0, status, sizeof(struct dfu_status),
+ USB_CTRL_GET_TIMEOUT);
+ return ret;
+}
+
+static u8 at76_dfu_get_state(struct usb_device *udev, u8 *state)
+{
+ int ret;
+
+ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), DFU_GETSTATE,
+ USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE,
+ 0, 0, state, 1, USB_CTRL_GET_TIMEOUT);
+ return ret;
+}
+
+/* Convert timeout from the DFU status to jiffies */
+static inline unsigned long at76_get_timeout(struct dfu_status *s)
+{
+ return msecs_to_jiffies((s->poll_timeout[2] << 16)
+ | (s->poll_timeout[1] << 8)
+ | (s->poll_timeout[0]));
+}
+
+/* Load internal firmware from the buffer. If manifest_sync_timeout > 0, use
+ * its value in jiffies in the MANIFEST_SYNC state. */
+static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,
+ int manifest_sync_timeout)
+{
+ u8 *block;
+ struct dfu_status dfu_stat_buf;
+ int ret = 0;
+ int need_dfu_state = 1;
+ int is_done = 0;
+ u8 dfu_state = 0;
+ u32 dfu_timeout = 0;
+ int bsize = 0;
+ int blockno = 0;
+
+ at76_dbg(DBG_DFU, "%s( %p, %u, %d)", __func__, buf, size,
+ manifest_sync_timeout);
+
+ if (!size) {
+ dev_printk(KERN_ERR, &udev->dev, "FW buffer length invalid!\n");
+ return -EINVAL;
+ }
+
+ block = kmalloc(FW_BLOCK_SIZE, GFP_KERNEL);
+ if (!block)
+ return -ENOMEM;
+
+ do {
+ if (need_dfu_state) {
+ ret = at76_dfu_get_state(udev, &dfu_state);
+ if (ret < 0) {
+ dev_printk(KERN_ERR, &udev->dev,
+ "cannot get DFU state: %d\n", ret);
+ goto exit;
+ }
+ need_dfu_state = 0;
+ }
+
+ switch (dfu_state) {
+ case STATE_DFU_DOWNLOAD_SYNC:
+ at76_dbg(DBG_DFU, "STATE_DFU_DOWNLOAD_SYNC");
+ ret = at76_dfu_get_status(udev, &dfu_stat_buf);
+ if (ret >= 0) {
+ dfu_state = dfu_stat_buf.state;
+ dfu_timeout = at76_get_timeout(&dfu_stat_buf);
+ need_dfu_state = 0;
+ } else
+ dev_printk(KERN_ERR, &udev->dev,
+ "at76_dfu_get_status returned %d\n",
+ ret);
+ break;
+
+ case STATE_DFU_DOWNLOAD_BUSY:
+ at76_dbg(DBG_DFU, "STATE_DFU_DOWNLOAD_BUSY");
+ need_dfu_state = 1;
+
+ at76_dbg(DBG_DFU, "DFU: Resetting device");
+ schedule_timeout_interruptible(dfu_timeout);
+ break;
+
+ case STATE_DFU_DOWNLOAD_IDLE:
+ at76_dbg(DBG_DFU, "DOWNLOAD...");
+ /* fall through */
+ case STATE_DFU_IDLE:
+ at76_dbg(DBG_DFU, "DFU IDLE");
+
+ bsize = min_t(int, size, FW_BLOCK_SIZE);
+ memcpy(block, buf, bsize);
+ at76_dbg(DBG_DFU, "int fw, size left = %5d, "
+ "bsize = %4d, blockno = %2d", size, bsize,
+ blockno);
+ ret =
+ at76_load_int_fw_block(udev, blockno, block, bsize);
+ buf += bsize;
+ size -= bsize;
+ blockno++;
+
+ if (ret != bsize)
+ dev_printk(KERN_ERR, &udev->dev,
+ "at76_load_int_fw_block "
+ "returned %d\n", ret);
+ need_dfu_state = 1;
+ break;
+
+ case STATE_DFU_MANIFEST_SYNC:
+ at76_dbg(DBG_DFU, "STATE_DFU_MANIFEST_SYNC");
+
+ ret = at76_dfu_get_status(udev, &dfu_stat_buf);
+ if (ret < 0)
+ break;
+
+ dfu_state = dfu_stat_buf.state;
+ dfu_timeout = at76_get_timeout(&dfu_stat_buf);
+ need_dfu_state = 0;
+
+ /* override the timeout from the status response,
+ needed for AT76C505A */
+ if (manifest_sync_timeout > 0)
+ dfu_timeout = manifest_sync_timeout;
+
+ at76_dbg(DBG_DFU, "DFU: Waiting for manifest phase");
+ schedule_timeout_interruptible(dfu_timeout);
+ break;
+
+ case STATE_DFU_MANIFEST:
+ at76_dbg(DBG_DFU, "STATE_DFU_MANIFEST");
+ is_done = 1;
+ break;
+
+ case STATE_DFU_MANIFEST_WAIT_RESET:
+ at76_dbg(DBG_DFU, "STATE_DFU_MANIFEST_WAIT_RESET");
+ is_done = 1;
+ break;
+
+ case STATE_DFU_UPLOAD_IDLE:
+ at76_dbg(DBG_DFU, "STATE_DFU_UPLOAD_IDLE");
+ break;
+
+ case STATE_DFU_ERROR:
+ at76_dbg(DBG_DFU, "STATE_DFU_ERROR");
+ ret = -EPIPE;
+ break;
+
+ default:
+ at76_dbg(DBG_DFU, "DFU UNKNOWN STATE (%d)", dfu_state);
+ ret = -EINVAL;
+ break;
+ }
+ } while (!is_done && (ret >= 0));
+
+exit:
+ kfree(block);
+ if (ret >= 0)
+ ret = 0;
+
+ return ret;
+}
+
+/* Report that the scan results are ready */
+static inline void at76_iwevent_scan_complete(struct net_device *netdev)
+{
+ union iwreq_data wrqu;
+ wrqu.data.length = 0;
+ wrqu.data.flags = 0;
+ wireless_send_event(netdev, SIOCGIWSCAN, &wrqu, NULL);
+ at76_dbg(DBG_WE_EVENTS, "%s: SIOCGIWSCAN sent", netdev->name);
+}
+
+static inline void at76_iwevent_bss_connect(struct net_device *netdev,
+ u8 *bssid)
+{
+ union iwreq_data wrqu;
+ wrqu.data.length = 0;
+ wrqu.data.flags = 0;
+ memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(netdev, SIOCGIWAP, &wrqu, NULL);
+ at76_dbg(DBG_WE_EVENTS, "%s: %s: SIOCGIWAP sent", netdev->name,
+ __func__);
+}
+
+static inline void at76_iwevent_bss_disconnect(struct net_device *netdev)
+{
+ union iwreq_data wrqu;
+ wrqu.data.length = 0;
+ wrqu.data.flags = 0;
+ memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(netdev, SIOCGIWAP, &wrqu, NULL);
+ at76_dbg(DBG_WE_EVENTS, "%s: %s: SIOCGIWAP sent", netdev->name,
+ __func__);
+}
+
+#define HEX2STR_BUFFERS 4
+#define HEX2STR_MAX_LEN 64
+#define BIN2HEX(x) ((x) < 10 ? '0' + (x) : (x) + 'A' - 10)
+
+/* Convert binary data into hex string */
+static char *hex2str(void *buf, int len)
+{
+ static atomic_t a = ATOMIC_INIT(0);
+ static char bufs[HEX2STR_BUFFERS][3 * HEX2STR_MAX_LEN + 1];
+ char *ret = bufs[atomic_inc_return(&a) & (HEX2STR_BUFFERS - 1)];
+ char *obuf = ret;
+ u8 *ibuf = buf;
+
+ if (len > HEX2STR_MAX_LEN)
+ len = HEX2STR_MAX_LEN;
+
+ if (len <= 0) {
+ ret[0] = '\0';
+ return ret;
+ }
+
+ while (len--) {
+ *obuf++ = BIN2HEX(*ibuf >> 4);
+ *obuf++ = BIN2HEX(*ibuf & 0xf);
+ *obuf++ = '-';
+ ibuf++;
+ }
+ *(--obuf) = '\0';
+
+ return ret;
+}
+
+#define MAC2STR_BUFFERS 4
+
+static inline char *mac2str(u8 *mac)
+{
+ static atomic_t a = ATOMIC_INIT(0);
+ static char bufs[MAC2STR_BUFFERS][6 * 3];
+ char *str;
+
+ str = bufs[atomic_inc_return(&a) & (MAC2STR_BUFFERS - 1)];
+ sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ return str;
+}
+
+/* LED trigger */
+static int tx_activity;
+static void at76_ledtrig_tx_timerfunc(unsigned long data);
+static DEFINE_TIMER(ledtrig_tx_timer, at76_ledtrig_tx_timerfunc, 0, 0);
+DEFINE_LED_TRIGGER(ledtrig_tx);
+
+static void at76_ledtrig_tx_timerfunc(unsigned long data)
+{
+ static int tx_lastactivity;
+
+ if (tx_lastactivity != tx_activity) {
+ tx_lastactivity = tx_activity;
+ led_trigger_event(ledtrig_tx, LED_FULL);
+ mod_timer(&ledtrig_tx_timer, jiffies + HZ / 4);
+ } else
+ led_trigger_event(ledtrig_tx, LED_OFF);
+}
+
+static void at76_ledtrig_tx_activity(void)
+{
+ tx_activity++;
+ if (!timer_pending(&ledtrig_tx_timer))
+ mod_timer(&ledtrig_tx_timer, jiffies + HZ / 4);
+}
+
+/* Check if the given ssid is hidden */
+static inline int at76_is_hidden_ssid(u8 *ssid, int length)
+{
+ static const u8 zeros[32];
+
+ if (length == 0)
+ return 1;
+
+ if (length == 1 && ssid[0] == ' ')
+ return 1;
+
+ return (memcmp(ssid, zeros, length) == 0);
+}
+
+static inline void at76_free_bss_list(struct at76_priv *priv)
+{
+ struct list_head *next, *ptr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->bss_list_spinlock, flags);
+
+ priv->curr_bss = NULL;
+
+ list_for_each_safe(ptr, next, &priv->bss_list) {
+ list_del(ptr);
+ kfree(list_entry(ptr, struct bss_info, list));
+ }
+
+ spin_unlock_irqrestore(&priv->bss_list_spinlock, flags);
+}
+
+static int at76_remap(struct usb_device *udev)
+{
+ int ret;
+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x0a,
+ USB_TYPE_VENDOR | USB_DIR_OUT |
+ USB_RECIP_INTERFACE, 0, 0, NULL, 0,
+ USB_CTRL_GET_TIMEOUT);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static int at76_get_op_mode(struct usb_device *udev)
+{
+ int ret;
+ u8 op_mode;
+
+ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x33,
+ USB_TYPE_VENDOR | USB_DIR_IN |
+ USB_RECIP_INTERFACE, 0x01, 0, &op_mode, 1,
+ USB_CTRL_GET_TIMEOUT);
+ if (ret < 0)
+ return ret;
+ else if (ret < 1)
+ return -EIO;
+ else
+ return op_mode;
+}
+
+/* Load a block of the second ("external") part of the firmware */
+static inline int at76_load_ext_fw_block(struct usb_device *udev, int blockno,
+ void *block, int size)
+{
+ return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x0e,
+ USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+ 0x0802, blockno, block, size,
+ USB_CTRL_GET_TIMEOUT);
+}
+
+static inline int at76_get_hw_cfg(struct usb_device *udev,
+ union at76_hwcfg *buf, int buf_size)
+{
+ return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x33,
+ USB_TYPE_VENDOR | USB_DIR_IN |
+ USB_RECIP_INTERFACE, 0x0a02, 0,
+ buf, buf_size, USB_CTRL_GET_TIMEOUT);
+}
+
+/* Intersil boards use a different "value" for GetHWConfig requests */
+static inline int at76_get_hw_cfg_intersil(struct usb_device *udev,
+ union at76_hwcfg *buf, int buf_size)
+{
+ return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x33,
+ USB_TYPE_VENDOR | USB_DIR_IN |
+ USB_RECIP_INTERFACE, 0x0902, 0,
+ buf, buf_size, USB_CTRL_GET_TIMEOUT);
+}
+
+/* Get the hardware configuration for the adapter and put it to the appropriate
+ * fields of 'priv' (the GetHWConfig request and interpretation of the result
+ * depends on the board type) */
+static int at76_get_hw_config(struct at76_priv *priv)
+{
+ int ret;
+ union at76_hwcfg *hwcfg = kmalloc(sizeof(*hwcfg), GFP_KERNEL);
+
+ if (!hwcfg)
+ return -ENOMEM;
+
+ if (at76_is_intersil(priv->board_type)) {
+ ret = at76_get_hw_cfg_intersil(priv->udev, hwcfg,
+ sizeof(hwcfg->i));
+ if (ret < 0)
+ goto exit;
+ memcpy(priv->mac_addr, hwcfg->i.mac_addr, ETH_ALEN);
+ priv->regulatory_domain = hwcfg->i.regulatory_domain;
+ } else if (at76_is_503rfmd(priv->board_type)) {
+ ret = at76_get_hw_cfg(priv->udev, hwcfg, sizeof(hwcfg->r3));
+ if (ret < 0)
+ goto exit;
+ memcpy(priv->mac_addr, hwcfg->r3.mac_addr, ETH_ALEN);
+ priv->regulatory_domain = hwcfg->r3.regulatory_domain;
+ } else {
+ ret = at76_get_hw_cfg(priv->udev, hwcfg, sizeof(hwcfg->r5));
+ if (ret < 0)
+ goto exit;
+ memcpy(priv->mac_addr, hwcfg->r5.mac_addr, ETH_ALEN);
+ priv->regulatory_domain = hwcfg->r5.regulatory_domain;
+ }
+
+exit:
+ kfree(hwcfg);
+ if (ret < 0)
+ printk(KERN_ERR "%s: cannot get HW Config (error %d)\n",
+ priv->netdev->name, ret);
+
+ return ret;
+}
+
+static struct reg_domain const *at76_get_reg_domain(u16 code)
+{
+ int i;
+ static struct reg_domain const fd_tab[] = {
+ {0x10, "FCC (USA)", 0x7ff}, /* ch 1-11 */
+ {0x20, "IC (Canada)", 0x7ff}, /* ch 1-11 */
+ {0x30, "ETSI (most of Europe)", 0x1fff}, /* ch 1-13 */
+ {0x31, "Spain", 0x600}, /* ch 10-11 */
+ {0x32, "France", 0x1e00}, /* ch 10-13 */
+ {0x40, "MKK (Japan)", 0x2000}, /* ch 14 */
+ {0x41, "MKK1 (Japan)", 0x3fff}, /* ch 1-14 */
+ {0x50, "Israel", 0x3fc}, /* ch 3-9 */
+ {0x00, "<unknown>", 0xffffffff} /* ch 1-32 */
+ };
+
+ /* Last entry is fallback for unknown domain code */
+ for (i = 0; i < ARRAY_SIZE(fd_tab) - 1; i++)
+ if (code == fd_tab[i].code)
+ break;
+
+ return &fd_tab[i];
+}
+
+static inline int at76_get_mib(struct usb_device *udev, u16 mib, void *buf,
+ int buf_size)
+{
+ int ret;
+
+ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x33,
+ USB_TYPE_VENDOR | USB_DIR_IN |
+ USB_RECIP_INTERFACE, mib << 8, 0, buf, buf_size,
+ USB_CTRL_GET_TIMEOUT);
+ if (ret >= 0 && ret != buf_size)
+ return -EIO;
+ return ret;
+}
+
+/* Return positive number for status, negative for an error */
+static inline int at76_get_cmd_status(struct usb_device *udev, u8 cmd)
+{
+ u8 stat_buf[40];
+ int ret;
+
+ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x22,
+ USB_TYPE_VENDOR | USB_DIR_IN |
+ USB_RECIP_INTERFACE, cmd, 0, stat_buf,
+ sizeof(stat_buf), USB_CTRL_GET_TIMEOUT);
+ if (ret < 0)
+ return ret;
+
+ return stat_buf[5];
+}
+
+static int at76_set_card_command(struct usb_device *udev, int cmd, void *buf,
+ int buf_size)
+{
+ int ret;
+ struct at76_command *cmd_buf = kmalloc(sizeof(struct at76_command) +
+ buf_size, GFP_KERNEL);
+
+ if (!cmd_buf)
+ return -ENOMEM;
+
+ cmd_buf->cmd = cmd;
+ cmd_buf->reserved = 0;
+ cmd_buf->size = cpu_to_le16(buf_size);
+ memcpy(cmd_buf->data, buf, buf_size);
+
+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x0e,
+ USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+ 0, 0, cmd_buf,
+ sizeof(struct at76_command) + buf_size,
+ USB_CTRL_GET_TIMEOUT);
+ kfree(cmd_buf);
+ return ret;
+}
+
+#define MAKE_CMD_STATUS_CASE(c) case (c): return #c
+static const char *at76_get_cmd_status_string(u8 cmd_status)
+{
+ switch (cmd_status) {
+ MAKE_CMD_STATUS_CASE(CMD_STATUS_IDLE);
+ MAKE_CMD_STATUS_CASE(CMD_STATUS_COMPLETE);
+ MAKE_CMD_STATUS_CASE(CMD_STATUS_UNKNOWN);
+ MAKE_CMD_STATUS_CASE(CMD_STATUS_INVALID_PARAMETER);
+ MAKE_CMD_STATUS_CASE(CMD_STATUS_FUNCTION_NOT_SUPPORTED);
+ MAKE_CMD_STATUS_CASE(CMD_STATUS_TIME_OUT);
+ MAKE_CMD_STATUS_CASE(CMD_STATUS_IN_PROGRESS);
+ MAKE_CMD_STATUS_CASE(CMD_STATUS_HOST_FAILURE);
+ MAKE_CMD_STATUS_CASE(CMD_STATUS_SCAN_FAILED);
+ }
+
+ return "UNKNOWN";
+}
+
+/* Wait until the command is completed */
+static int at76_wait_completion(struct at76_priv *priv, int cmd)
+{
+ int status = 0;
+ unsigned long timeout = jiffies + CMD_COMPLETION_TIMEOUT;
+
+ do {
+ status = at76_get_cmd_status(priv->udev, cmd);
+ if (status < 0) {
+ printk(KERN_ERR "%s: at76_get_cmd_status failed: %d\n",
+ priv->netdev->name, status);
+ break;
+ }
+
+ at76_dbg(DBG_WAIT_COMPLETE,
+ "%s: Waiting on cmd %d, status = %d (%s)",
+ priv->netdev->name, cmd, status,
+ at76_get_cmd_status_string(status));
+
+ if (status != CMD_STATUS_IN_PROGRESS
+ && status != CMD_STATUS_IDLE)
+ break;
+
+ schedule_timeout_interruptible(HZ / 10); /* 100 ms */
+ if (time_after(jiffies, timeout)) {
+ printk(KERN_ERR
+ "%s: completion timeout for command %d\n",
+ priv->netdev->name, cmd);
+ status = -ETIMEDOUT;
+ break;
+ }
+ } while (1);
+
+ return status;
+}
+
+static int at76_set_mib(struct at76_priv *priv, struct set_mib_buffer *buf)
+{
+ int ret;
+
+ ret = at76_set_card_command(priv->udev, CMD_SET_MIB, buf,
+ offsetof(struct set_mib_buffer,
+ data) + buf->size);
+ if (ret < 0)
+ return ret;
+
+ ret = at76_wait_completion(priv, CMD_SET_MIB);
+ if (ret != CMD_STATUS_COMPLETE) {
+ printk(KERN_INFO
+ "%s: set_mib: at76_wait_completion failed "
+ "with %d\n", priv->netdev->name, ret);
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+/* Return < 0 on error, == 0 if no command sent, == 1 if cmd sent */
+static int at76_set_radio(struct at76_priv *priv, int enable)
+{
+ int ret;
+ int cmd;
+
+ if (priv->radio_on == enable)
+ return 0;
+
+ cmd = enable ? CMD_RADIO_ON : CMD_RADIO_OFF;
+
+ ret = at76_set_card_command(priv->udev, cmd, NULL, 0);
+ if (ret < 0)
+ printk(KERN_ERR "%s: at76_set_card_command(%d) failed: %d\n",
+ priv->netdev->name, cmd, ret);
+ else
+ ret = 1;
+
+ priv->radio_on = enable;
+ return ret;
+}
+
+/* Set current power save mode (AT76_PM_OFF/AT76_PM_ON/AT76_PM_SMART) */
+static int at76_set_pm_mode(struct at76_priv *priv)
+{
+ int ret = 0;
+
+ priv->mib_buf.type = MIB_MAC_MGMT;
+ priv->mib_buf.size = 1;
+ priv->mib_buf.index = offsetof(struct mib_mac_mgmt, power_mgmt_mode);
+ priv->mib_buf.data.byte = priv->pm_mode;
+
+ ret = at76_set_mib(priv, &priv->mib_buf);
+ if (ret < 0)
+ printk(KERN_ERR "%s: set_mib (pm_mode) failed: %d\n",
+ priv->netdev->name, ret);
+
+ return ret;
+}
+
+/* Set the association id for power save mode */
+static int at76_set_associd(struct at76_priv *priv, u16 id)
+{
+ int ret = 0;
+
+ priv->mib_buf.type = MIB_MAC_MGMT;
+ priv->mib_buf.size = 2;
+ priv->mib_buf.index = offsetof(struct mib_mac_mgmt, station_id);
+ priv->mib_buf.data.word = cpu_to_le16(id);
+
+ ret = at76_set_mib(priv, &priv->mib_buf);
+ if (ret < 0)
+ printk(KERN_ERR "%s: set_mib (associd) failed: %d\n",
+ priv->netdev->name, ret);
+
+ return ret;
+}
+
+/* Set the listen interval for power save mode */
+static int at76_set_listen_interval(struct at76_priv *priv, u16 interval)
+{
+ int ret = 0;
+
+ priv->mib_buf.type = MIB_MAC;
+ priv->mib_buf.size = 2;
+ priv->mib_buf.index = offsetof(struct mib_mac, listen_interval);
+ priv->mib_buf.data.word = cpu_to_le16(interval);
+
+ ret = at76_set_mib(priv, &priv->mib_buf);
+ if (ret < 0)
+ printk(KERN_ERR
+ "%s: set_mib (listen_interval) failed: %d\n",
+ priv->netdev->name, ret);
+
+ return ret;
+}
+
+static int at76_set_preamble(struct at76_priv *priv, u8 type)
+{
+ int ret = 0;
+
+ priv->mib_buf.type = MIB_LOCAL;
+ priv->mib_buf.size = 1;
+ priv->mib_buf.index = offsetof(struct mib_local, preamble_type);
+ priv->mib_buf.data.byte = type;
+
+ ret = at76_set_mib(priv, &priv->mib_buf);
+ if (ret < 0)
+ printk(KERN_ERR "%s: set_mib (preamble) failed: %d\n",
+ priv->netdev->name, ret);
+
+ return ret;
+}
+
+static int at76_set_frag(struct at76_priv *priv, u16 size)
+{
+ int ret = 0;
+
+ priv->mib_buf.type = MIB_MAC;
+ priv->mib_buf.size = 2;
+ priv->mib_buf.index = offsetof(struct mib_mac, frag_threshold);
+ priv->mib_buf.data.word = cpu_to_le16(size);
+
+ ret = at76_set_mib(priv, &priv->mib_buf);
+ if (ret < 0)
+ printk(KERN_ERR "%s: set_mib (frag threshold) failed: %d\n",
+ priv->netdev->name, ret);
+
+ return ret;
+}
+
+static int at76_set_rts(struct at76_priv *priv, u16 size)
+{
+ int ret = 0;
+
+ priv->mib_buf.type = MIB_MAC;
+ priv->mib_buf.size = 2;
+ priv->mib_buf.index = offsetof(struct mib_mac, rts_threshold);
+ priv->mib_buf.data.word = cpu_to_le16(size);
+
+ ret = at76_set_mib(priv, &priv->mib_buf);
+ if (ret < 0)
+ printk(KERN_ERR "%s: set_mib (rts) failed: %d\n",
+ priv->netdev->name, ret);
+
+ return ret;
+}
+
+static int at76_set_autorate_fallback(struct at76_priv *priv, int onoff)
+{
+ int ret = 0;
+
+ priv->mib_buf.type = MIB_LOCAL;
+ priv->mib_buf.size = 1;
+ priv->mib_buf.index = offsetof(struct mib_local, txautorate_fallback);
+ priv->mib_buf.data.byte = onoff;
+
+ ret = at76_set_mib(priv, &priv->mib_buf);
+ if (ret < 0)
+ printk(KERN_ERR "%s: set_mib (autorate fallback) failed: %d\n",
+ priv->netdev->name, ret);
+
+ return ret;
+}
+
+static int at76_add_mac_address(struct at76_priv *priv, void *addr)
+{
+ int ret = 0;
+
+ priv->mib_buf.type = MIB_MAC_ADDR;
+ priv->mib_buf.size = ETH_ALEN;
+ priv->mib_buf.index = offsetof(struct mib_mac_addr, mac_addr);
+ memcpy(priv->mib_buf.data.addr, addr, ETH_ALEN);
+
+ ret = at76_set_mib(priv, &priv->mib_buf);
+ if (ret < 0)
+ printk(KERN_ERR "%s: set_mib (MAC_ADDR, mac_addr) failed: %d\n",
+ priv->netdev->name, ret);
+
+ return ret;
+}
+
+static void at76_dump_mib_mac_addr(struct at76_priv *priv)
+{
+ int i;
+ int ret;
+ struct mib_mac_addr *m = kmalloc(sizeof(struct mib_mac_addr),
+ GFP_KERNEL);
+
+ if (!m)
+ return;
+
+ ret = at76_get_mib(priv->udev, MIB_MAC_ADDR, m,
+ sizeof(struct mib_mac_addr));
+ if (ret < 0) {
+ printk(KERN_ERR "%s: at76_get_mib (MAC_ADDR) failed: %d\n",
+ priv->netdev->name, ret);
+ goto exit;
+ }
+
+ at76_dbg(DBG_MIB, "%s: MIB MAC_ADDR: mac_addr %s res 0x%x 0x%x",
+ priv->netdev->name,
+ mac2str(m->mac_addr), m->res[0], m->res[1]);
+ for (i = 0; i < ARRAY_SIZE(m->group_addr); i++)
+ at76_dbg(DBG_MIB, "%s: MIB MAC_ADDR: group addr %d: %s, "
+ "status %d", priv->netdev->name, i,
+ mac2str(m->group_addr[i]), m->group_addr_status[i]);
+exit:
+ kfree(m);
+}
+
+static void at76_dump_mib_mac_wep(struct at76_priv *priv)
+{
+ int i;
+ int ret;
+ int key_len;
+ struct mib_mac_wep *m = kmalloc(sizeof(struct mib_mac_wep), GFP_KERNEL);
+
+ if (!m)
+ return;
+
+ ret = at76_get_mib(priv->udev, MIB_MAC_WEP, m,
+ sizeof(struct mib_mac_wep));
+ if (ret < 0) {
+ printk(KERN_ERR "%s: at76_get_mib (MAC_WEP) failed: %d\n",
+ priv->netdev->name, ret);
+ goto exit;
+ }
+
+ at76_dbg(DBG_MIB, "%s: MIB MAC_WEP: priv_invoked %u def_key_id %u "
+ "key_len %u excl_unencr %u wep_icv_err %u wep_excluded %u "
+ "encr_level %u key %d", priv->netdev->name,
+ m->privacy_invoked, m->wep_default_key_id,
+ m->wep_key_mapping_len, m->exclude_unencrypted,
+ le32_to_cpu(m->wep_icv_error_count),
+ le32_to_cpu(m->wep_excluded_count), m->encryption_level,
+ m->wep_default_key_id);
+
+ key_len = (m->encryption_level == 1) ?
+ WEP_SMALL_KEY_LEN : WEP_LARGE_KEY_LEN;
+
+ for (i = 0; i < WEP_KEYS; i++)
+ at76_dbg(DBG_MIB, "%s: MIB MAC_WEP: key %d: %s",
+ priv->netdev->name, i,
+ hex2str(m->wep_default_keyvalue[i], key_len));
+exit:
+ kfree(m);
+}
+
+static void at76_dump_mib_mac_mgmt(struct at76_priv *priv)
+{
+ int ret;
+ struct mib_mac_mgmt *m = kmalloc(sizeof(struct mib_mac_mgmt),
+ GFP_KERNEL);
+
+ if (!m)
+ return;
+
+ ret = at76_get_mib(priv->udev, MIB_MAC_MGMT, m,
+ sizeof(struct mib_mac_mgmt));
+ if (ret < 0) {
+ printk(KERN_ERR "%s: at76_get_mib (MAC_MGMT) failed: %d\n",
+ priv->netdev->name, ret);
+ goto exit;
+ }
+
+ at76_dbg(DBG_MIB, "%s: MIB MAC_MGMT: beacon_period %d CFP_max_duration "
+ "%d medium_occupancy_limit %d station_id 0x%x ATIM_window %d "
+ "CFP_mode %d privacy_opt_impl %d DTIM_period %d CFP_period %d "
+ "current_bssid %s current_essid %s current_bss_type %d "
+ "pm_mode %d ibss_change %d res %d "
+ "multi_domain_capability_implemented %d "
+ "international_roaming %d country_string %.3s",
+ priv->netdev->name, le16_to_cpu(m->beacon_period),
+ le16_to_cpu(m->CFP_max_duration),
+ le16_to_cpu(m->medium_occupancy_limit),
+ le16_to_cpu(m->station_id), le16_to_cpu(m->ATIM_window),
+ m->CFP_mode, m->privacy_option_implemented, m->DTIM_period,
+ m->CFP_period, mac2str(m->current_bssid),
+ hex2str(m->current_essid, IW_ESSID_MAX_SIZE),
+ m->current_bss_type, m->power_mgmt_mode, m->ibss_change,
+ m->res, m->multi_domain_capability_implemented,
+ m->multi_domain_capability_enabled, m->country_string);
+exit:
+ kfree(m);
+}
+
+static void at76_dump_mib_mac(struct at76_priv *priv)
+{
+ int ret;
+ struct mib_mac *m = kmalloc(sizeof(struct mib_mac), GFP_KERNEL);
+
+ if (!m)
+ return;
+
+ ret = at76_get_mib(priv->udev, MIB_MAC, m, sizeof(struct mib_mac));
+ if (ret < 0) {
+ printk(KERN_ERR "%s: at76_get_mib (MAC) failed: %d\n",
+ priv->netdev->name, ret);
+ goto exit;
+ }
+
+ at76_dbg(DBG_MIB, "%s: MIB MAC: max_tx_msdu_lifetime %d "
+ "max_rx_lifetime %d frag_threshold %d rts_threshold %d "
+ "cwmin %d cwmax %d short_retry_time %d long_retry_time %d "
+ "scan_type %d scan_channel %d probe_delay %u "
+ "min_channel_time %d max_channel_time %d listen_int %d "
+ "desired_ssid %s desired_bssid %s desired_bsstype %d",
+ priv->netdev->name, le32_to_cpu(m->max_tx_msdu_lifetime),
+ le32_to_cpu(m->max_rx_lifetime),
+ le16_to_cpu(m->frag_threshold), le16_to_cpu(m->rts_threshold),
+ le16_to_cpu(m->cwmin), le16_to_cpu(m->cwmax),
+ m->short_retry_time, m->long_retry_time, m->scan_type,
+ m->scan_channel, le16_to_cpu(m->probe_delay),
+ le16_to_cpu(m->min_channel_time),
+ le16_to_cpu(m->max_channel_time),
+ le16_to_cpu(m->listen_interval),
+ hex2str(m->desired_ssid, IW_ESSID_MAX_SIZE),
+ mac2str(m->desired_bssid), m->desired_bsstype);
+exit:
+ kfree(m);
+}
+
+static void at76_dump_mib_phy(struct at76_priv *priv)
+{
+ int ret;
+ struct mib_phy *m = kmalloc(sizeof(struct mib_phy), GFP_KERNEL);
+
+ if (!m)
+ return;
+
+ ret = at76_get_mib(priv->udev, MIB_PHY, m, sizeof(struct mib_phy));
+ if (ret < 0) {
+ printk(KERN_ERR "%s: at76_get_mib (PHY) failed: %d\n",
+ priv->netdev->name, ret);
+ goto exit;
+ }
+
+ at76_dbg(DBG_MIB, "%s: MIB PHY: ed_threshold %d slot_time %d "
+ "sifs_time %d preamble_length %d plcp_header_length %d "
+ "mpdu_max_length %d cca_mode_supported %d operation_rate_set "
+ "0x%x 0x%x 0x%x 0x%x channel_id %d current_cca_mode %d "
+ "phy_type %d current_reg_domain %d",
+ priv->netdev->name, le32_to_cpu(m->ed_threshold),
+ le16_to_cpu(m->slot_time), le16_to_cpu(m->sifs_time),
+ le16_to_cpu(m->preamble_length),
+ le16_to_cpu(m->plcp_header_length),
+ le16_to_cpu(m->mpdu_max_length),
+ le16_to_cpu(m->cca_mode_supported), m->operation_rate_set[0],
+ m->operation_rate_set[1], m->operation_rate_set[2],
+ m->operation_rate_set[3], m->channel_id, m->current_cca_mode,
+ m->phy_type, m->current_reg_domain);
+exit:
+ kfree(m);
+}
+
+static void at76_dump_mib_local(struct at76_priv *priv)
+{
+ int ret;
+ struct mib_local *m = kmalloc(sizeof(struct mib_phy), GFP_KERNEL);
+
+ if (!m)
+ return;
+
+ ret = at76_get_mib(priv->udev, MIB_LOCAL, m, sizeof(struct mib_local));
+ if (ret < 0) {
+ printk(KERN_ERR "%s: at76_get_mib (LOCAL) failed: %d\n",
+ priv->netdev->name, ret);
+ goto exit;
+ }
+
+ at76_dbg(DBG_MIB, "%s: MIB LOCAL: beacon_enable %d "
+ "txautorate_fallback %d ssid_size %d promiscuous_mode %d "
+ "preamble_type %d", priv->netdev->name, m->beacon_enable,
+ m->txautorate_fallback, m->ssid_size, m->promiscuous_mode,
+ m->preamble_type);
+exit:
+ kfree(m);
+}
+
+static void at76_dump_mib_mdomain(struct at76_priv *priv)
+{
+ int ret;
+ struct mib_mdomain *m = kmalloc(sizeof(struct mib_mdomain), GFP_KERNEL);
+
+ if (!m)
+ return;
+
+ ret = at76_get_mib(priv->udev, MIB_MDOMAIN, m,
+ sizeof(struct mib_mdomain));
+ if (ret < 0) {
+ printk(KERN_ERR "%s: at76_get_mib (MDOMAIN) failed: %d\n",
+ priv->netdev->name, ret);
+ goto exit;
+ }
+
+ at76_dbg(DBG_MIB, "%s: MIB MDOMAIN: channel_list %s",
+ priv->netdev->name,
+ hex2str(m->channel_list, sizeof(m->channel_list)));
+
+ at76_dbg(DBG_MIB, "%s: MIB MDOMAIN: tx_powerlevel %s",
+ priv->netdev->name,
+ hex2str(m->tx_powerlevel, sizeof(m->tx_powerlevel)));
+exit:
+ kfree(m);
+}
+
+static int at76_get_current_bssid(struct at76_priv *priv)
+{
+ int ret = 0;
+ struct mib_mac_mgmt *mac_mgmt =
+ kmalloc(sizeof(struct mib_mac_mgmt), GFP_KERNEL);
+
+ if (!mac_mgmt) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ ret = at76_get_mib(priv->udev, MIB_MAC_MGMT, mac_mgmt,
+ sizeof(struct mib_mac_mgmt));
+ if (ret < 0) {
+ printk(KERN_ERR "%s: at76_get_mib failed: %d\n",
+ priv->netdev->name, ret);
+ goto error;
+ }
+ memcpy(priv->bssid, mac_mgmt->current_bssid, ETH_ALEN);
+ printk(KERN_INFO "%s: using BSSID %s\n", priv->netdev->name,
+ mac2str(priv->bssid));
+error:
+ kfree(mac_mgmt);
+exit:
+ return ret;
+}
+
+static int at76_get_current_channel(struct at76_priv *priv)
+{
+ int ret = 0;
+ struct mib_phy *phy = kmalloc(sizeof(struct mib_phy), GFP_KERNEL);
+
+ if (!phy) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+ ret = at76_get_mib(priv->udev, MIB_PHY, phy, sizeof(struct mib_phy));
+ if (ret < 0) {
+ printk(KERN_ERR "%s: at76_get_mib(MIB_PHY) failed: %d\n",
+ priv->netdev->name, ret);
+ goto error;
+ }
+ priv->channel = phy->channel_id;
+error:
+ kfree(phy);
+exit:
+ return ret;
+}
+
+/**
+ * at76_start_scan - start a scan
+ *
+ * @use_essid - use the configured ESSID in non passive mode
+ */
+static int at76_start_scan(struct at76_priv *priv, int use_essid)
+{
+ struct at76_req_scan scan;
+
+ memset(&scan, 0, sizeof(struct at76_req_scan));
+ memset(scan.bssid, 0xff, ETH_ALEN);
+
+ if (use_essid) {
+ memcpy(scan.essid, priv->essid, IW_ESSID_MAX_SIZE);
+ scan.essid_size = priv->essid_size;
+ } else
+ scan.essid_size = 0;
+
+ /* jal: why should we start at a certain channel? we do scan the whole
+ range allowed by reg domain. */
+ scan.channel = priv->channel;
+
+ /* atmelwlandriver differs between scan type 0 and 1 (active/passive)
+ For ad-hoc mode, it uses type 0 only. */
+ scan.scan_type = priv->scan_mode;
+
+ /* INFO: For probe_delay, not multiplying by 1024 as this will be
+ slightly less than min_channel_time
+ (per spec: probe delay < min. channel time) */
+ scan.min_channel_time = cpu_to_le16(priv->scan_min_time);
+ scan.max_channel_time = cpu_to_le16(priv->scan_max_time);
+ scan.probe_delay = cpu_to_le16(priv->scan_min_time * 1000);
+ scan.international_scan = 0;
+
+ /* other values are set to 0 for type 0 */
+
+ at76_dbg(DBG_PROGRESS, "%s: start_scan (use_essid = %d, intl = %d, "
+ "channel = %d, probe_delay = %d, scan_min_time = %d, "
+ "scan_max_time = %d)",
+ priv->netdev->name, use_essid,
+ scan.international_scan, scan.channel,
+ le16_to_cpu(scan.probe_delay),
+ le16_to_cpu(scan.min_channel_time),
+ le16_to_cpu(scan.max_channel_time));
+
+ return at76_set_card_command(priv->udev, CMD_SCAN, &scan, sizeof(scan));
+}
+
+/* Enable monitor mode */
+static int at76_start_monitor(struct at76_priv *priv)
+{
+ struct at76_req_scan scan;
+ int ret;
+
+ memset(&scan, 0, sizeof(struct at76_req_scan));
+ memset(scan.bssid, 0xff, ETH_ALEN);
+
+ scan.channel = priv->channel;
+ scan.scan_type = SCAN_TYPE_PASSIVE;
+ scan.international_scan = 0;
+
+ ret = at76_set_card_command(priv->udev, CMD_SCAN, &scan, sizeof(scan));
+ if (ret >= 0)
+ ret = at76_get_cmd_status(priv->udev, CMD_SCAN);
+
+ return ret;
+}
+
+static int at76_start_ibss(struct at76_priv *priv)
+{
+ struct at76_req_ibss bss;
+ int ret;
+
+ WARN_ON(priv->mac_state != MAC_OWN_IBSS);
+ if (priv->mac_state != MAC_OWN_IBSS)
+ return -EBUSY;
+
+ memset(&bss, 0, sizeof(struct at76_req_ibss));
+ memset(bss.bssid, 0xff, ETH_ALEN);
+ memcpy(bss.essid, priv->essid, IW_ESSID_MAX_SIZE);
+ bss.essid_size = priv->essid_size;
+ bss.bss_type = ADHOC_MODE;
+ bss.channel = priv->channel;
+
+ ret = at76_set_card_command(priv->udev, CMD_START_IBSS, &bss,
+ sizeof(struct at76_req_ibss));
+ if (ret < 0) {
+ printk(KERN_ERR "%s: start_ibss failed: %d\n",
+ priv->netdev->name, ret);
+ return ret;
+ }
+
+ ret = at76_wait_completion(priv, CMD_START_IBSS);
+ if (ret != CMD_STATUS_COMPLETE) {
+ printk(KERN_ERR "%s: start_ibss failed to complete, %d\n",
+ priv->netdev->name, ret);
+ return ret;
+ }
+
+ ret = at76_get_current_bssid(priv);
+ if (ret < 0)
+ return ret;
+
+ ret = at76_get_current_channel(priv);
+ if (ret < 0)
+ return ret;
+
+ /* not sure what this is good for ??? */
+ priv->mib_buf.type = MIB_MAC_MGMT;
+ priv->mib_buf.size = 1;
+ priv->mib_buf.index = offsetof(struct mib_mac_mgmt, ibss_change);
+ priv->mib_buf.data.byte = 0;
+
+ ret = at76_set_mib(priv, &priv->mib_buf);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: set_mib (ibss change ok) failed: %d\n",
+ priv->netdev->name, ret);
+ return ret;
+ }
+
+ netif_carrier_on(priv->netdev);
+ netif_start_queue(priv->netdev);
+ return 0;
+}
+
+/* Request card to join BSS in managed or ad-hoc mode */
+static int at76_join_bss(struct at76_priv *priv, struct bss_info *ptr)
+{
+ struct at76_req_join join;
+
+ BUG_ON(!ptr);
+
+ memset(&join, 0, sizeof(struct at76_req_join));
+ memcpy(join.bssid, ptr->bssid, ETH_ALEN);
+ memcpy(join.essid, ptr->ssid, ptr->ssid_len);
+ join.essid_size = ptr->ssid_len;
+ join.bss_type = (priv->iw_mode == IW_MODE_ADHOC ? 1 : 2);
+ join.channel = ptr->channel;
+ join.timeout = cpu_to_le16(2000);
+
+ at76_dbg(DBG_PROGRESS,
+ "%s join addr %s ssid %s type %d ch %d timeout %d",
+ priv->netdev->name, mac2str(join.bssid), join.essid,
+ join.bss_type, join.channel, le16_to_cpu(join.timeout));
+ return at76_set_card_command(priv->udev, CMD_JOIN, &join,
+ sizeof(struct at76_req_join));
+}
+
+/* Calculate padding from txbuf->wlength (which excludes the USB TX header),
+ likely to compensate a flaw in the AT76C503A USB part ... */
+static inline int at76_calc_padding(int wlen)
+{
+ /* add the USB TX header */
+ wlen += AT76_TX_HDRLEN;
+
+ wlen = wlen % 64;
+
+ if (wlen < 50)
+ return 50 - wlen;
+
+ if (wlen >= 61)
+ return 64 + 50 - wlen;
+
+ return 0;
+}
+
+/* We are doing a lot of things here in an interrupt. Need
+ a bh handler (Watching TV with a TV card is probably
+ a good test: if you see flickers, we are doing too much.
+ Currently I do see flickers... even with our tasklet :-( )
+ Maybe because the bttv driver and usb-uhci use the same interrupt
+*/
+/* Or maybe because our BH handler is preempting bttv's BH handler.. BHs don't
+ * solve everything.. (alex) */
+static void at76_rx_callback(struct urb *urb)
+{
+ struct at76_priv *priv = urb->context;
+
+ priv->rx_tasklet.data = (unsigned long)urb;
+ tasklet_schedule(&priv->rx_tasklet);
+ return;
+}
+
+static void at76_tx_callback(struct urb *urb)
+{
+ struct at76_priv *priv = urb->context;
+ struct net_device_stats *stats = &priv->stats;
+ unsigned long flags;
+ struct at76_tx_buffer *mgmt_buf;
+ int ret;
+
+ switch (urb->status) {
+ case 0:
+ stats->tx_packets++;
+ break;
+ case -ENOENT:
+ case -ECONNRESET:
+ /* urb has been unlinked */
+ return;
+ default:
+ at76_dbg(DBG_URB, "%s - nonzero tx status received: %d",
+ __func__, urb->status);
+ stats->tx_errors++;
+ break;
+ }
+
+ spin_lock_irqsave(&priv->mgmt_spinlock, flags);
+ mgmt_buf = priv->next_mgmt_bulk;
+ priv->next_mgmt_bulk = NULL;
+ spin_unlock_irqrestore(&priv->mgmt_spinlock, flags);
+
+ if (!mgmt_buf) {
+ netif_wake_queue(priv->netdev);
+ return;
+ }
+
+ /* we don't copy the padding bytes, but add them
+ to the length */
+ memcpy(priv->bulk_out_buffer, mgmt_buf,
+ le16_to_cpu(mgmt_buf->wlength) + AT76_TX_HDRLEN);
+ usb_fill_bulk_urb(priv->tx_urb, priv->udev, priv->tx_pipe,
+ priv->bulk_out_buffer,
+ le16_to_cpu(mgmt_buf->wlength) + mgmt_buf->padding +
+ AT76_TX_HDRLEN, at76_tx_callback, priv);
+ ret = usb_submit_urb(priv->tx_urb, GFP_ATOMIC);
+ if (ret)
+ printk(KERN_ERR "%s: error in tx submit urb: %d\n",
+ priv->netdev->name, ret);
+
+ kfree(mgmt_buf);
+}
+
+/* Send a management frame on bulk-out. txbuf->wlength must be set */
+static int at76_tx_mgmt(struct at76_priv *priv, struct at76_tx_buffer *txbuf)
+{
+ unsigned long flags;
+ int ret;
+ int urb_status;
+ void *oldbuf = NULL;
+
+ netif_carrier_off(priv->netdev); /* stop netdev watchdog */
+ netif_stop_queue(priv->netdev); /* stop tx data packets */
+
+ spin_lock_irqsave(&priv->mgmt_spinlock, flags);
+
+ urb_status = priv->tx_urb->status;
+ if (urb_status == -EINPROGRESS) {
+ /* cannot transmit now, put in the queue */
+ oldbuf = priv->next_mgmt_bulk;
+ priv->next_mgmt_bulk = txbuf;
+ }
+ spin_unlock_irqrestore(&priv->mgmt_spinlock, flags);
+
+ if (oldbuf) {
+ /* a data/mgmt tx is already pending in the URB -
+ if this is no error in some situations we must
+ implement a queue or silently modify the old msg */
+ printk(KERN_ERR "%s: removed pending mgmt buffer %s\n",
+ priv->netdev->name, hex2str(oldbuf, 64));
+ kfree(oldbuf);
+ return 0;
+ }
+
+ txbuf->tx_rate = TX_RATE_1MBIT;
+ txbuf->padding = at76_calc_padding(le16_to_cpu(txbuf->wlength));
+ memset(txbuf->reserved, 0, sizeof(txbuf->reserved));
+
+ if (priv->next_mgmt_bulk)
+ printk(KERN_ERR "%s: URB status %d, but mgmt is pending\n",
+ priv->netdev->name, urb_status);
+
+ at76_dbg(DBG_TX_MGMT,
+ "%s: tx mgmt: wlen %d tx_rate %d pad %d %s",
+ priv->netdev->name, le16_to_cpu(txbuf->wlength),
+ txbuf->tx_rate, txbuf->padding,
+ hex2str(txbuf->packet, le16_to_cpu(txbuf->wlength)));
+
+ /* txbuf was not consumed above -> send mgmt msg immediately */
+ memcpy(priv->bulk_out_buffer, txbuf,
+ le16_to_cpu(txbuf->wlength) + AT76_TX_HDRLEN);
+ usb_fill_bulk_urb(priv->tx_urb, priv->udev, priv->tx_pipe,
+ priv->bulk_out_buffer,
+ le16_to_cpu(txbuf->wlength) + txbuf->padding +
+ AT76_TX_HDRLEN, at76_tx_callback, priv);
+ ret = usb_submit_urb(priv->tx_urb, GFP_ATOMIC);
+ if (ret)
+ printk(KERN_ERR "%s: error in tx submit urb: %d\n",
+ priv->netdev->name, ret);
+
+ kfree(txbuf);
+
+ return ret;
+}
+
+/* Go to the next information element */
+static inline void next_ie(struct ieee80211_info_element **ie)
+{
+ *ie = (struct ieee80211_info_element *)(&(*ie)->data[(*ie)->len]);
+}
+
+/* Challenge is the challenge string (in TLV format)
+ we got with seq_nr 2 for shared secret authentication only and
+ send in seq_nr 3 WEP encrypted to prove we have the correct WEP key;
+ otherwise it is NULL */
+static int at76_auth_req(struct at76_priv *priv, struct bss_info *bss,
+ int seq_nr, struct ieee80211_info_element *challenge)
+{
+ struct at76_tx_buffer *tx_buffer;
+ struct ieee80211_hdr_3addr *mgmt;
+ struct ieee80211_auth *req;
+ int buf_len = (seq_nr != 3 ? AUTH_FRAME_SIZE :
+ AUTH_FRAME_SIZE + 1 + 1 + challenge->len);
+
+ BUG_ON(!bss);
+ BUG_ON(seq_nr == 3 && !challenge);
+ tx_buffer = kmalloc(buf_len + MAX_PADDING_SIZE, GFP_ATOMIC);
+ if (!tx_buffer)
+ return -ENOMEM;
+
+ req = (struct ieee80211_auth *)tx_buffer->packet;
+ mgmt = &req->header;
+
+ /* make wireless header */
+ /* first auth msg is not encrypted, only the second (seq_nr == 3) */
+ mgmt->frame_ctl =
+ cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH |
+ (seq_nr == 3 ? IEEE80211_FCTL_PROTECTED : 0));
+
+ mgmt->duration_id = cpu_to_le16(0x8000);
+ memcpy(mgmt->addr1, bss->bssid, ETH_ALEN);
+ memcpy(mgmt->addr2, priv->netdev->dev_addr, ETH_ALEN);
+ memcpy(mgmt->addr3, bss->bssid, ETH_ALEN);
+ mgmt->seq_ctl = cpu_to_le16(0);
+
+ req->algorithm = cpu_to_le16(priv->auth_mode);
+ req->transaction = cpu_to_le16(seq_nr);
+ req->status = cpu_to_le16(0);
+
+ if (seq_nr == 3)
+ memcpy(req->info_element, challenge, 1 + 1 + challenge->len);
+
+ /* init. at76_priv tx header */
+ tx_buffer->wlength = cpu_to_le16(buf_len - AT76_TX_HDRLEN);
+ at76_dbg(DBG_TX_MGMT, "%s: AuthReq bssid %s alg %d seq_nr %d",
+ priv->netdev->name, mac2str(mgmt->addr3),
+ le16_to_cpu(req->algorithm), le16_to_cpu(req->transaction));
+ if (seq_nr == 3)
+ at76_dbg(DBG_TX_MGMT, "%s: AuthReq challenge: %s ...",
+ priv->netdev->name, hex2str(req->info_element, 18));
+
+ /* either send immediately (if no data tx is pending
+ or put it in pending list */
+ return at76_tx_mgmt(priv, tx_buffer);
+}
+
+static int at76_assoc_req(struct at76_priv *priv, struct bss_info *bss)
+{
+ struct at76_tx_buffer *tx_buffer;
+ struct ieee80211_hdr_3addr *mgmt;
+ struct ieee80211_assoc_request *req;
+ struct ieee80211_info_element *ie;
+ char *essid;
+ int essid_len;
+ u16 capa;
+
+ BUG_ON(!bss);
+
+ tx_buffer = kmalloc(ASSOCREQ_MAX_SIZE + MAX_PADDING_SIZE, GFP_ATOMIC);
+ if (!tx_buffer)
+ return -ENOMEM;
+
+ req = (struct ieee80211_assoc_request *)tx_buffer->packet;
+ mgmt = &req->header;
+ ie = req->info_element;
+
+ /* make wireless header */
+ mgmt->frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ASSOC_REQ);
+
+ mgmt->duration_id = cpu_to_le16(0x8000);
+ memcpy(mgmt->addr1, bss->bssid, ETH_ALEN);
+ memcpy(mgmt->addr2, priv->netdev->dev_addr, ETH_ALEN);
+ memcpy(mgmt->addr3, bss->bssid, ETH_ALEN);
+ mgmt->seq_ctl = cpu_to_le16(0);
+
+ /* we must set the Privacy bit in the capabilities to assure an
+ Agere-based AP with optional WEP transmits encrypted frames
+ to us. AP only set the Privacy bit in their capabilities
+ if WEP is mandatory in the BSS! */
+ capa = bss->capa;
+ if (priv->wep_enabled)
+ capa |= WLAN_CAPABILITY_PRIVACY;
+ if (priv->preamble_type != PREAMBLE_TYPE_LONG)
+ capa |= WLAN_CAPABILITY_SHORT_PREAMBLE;
+ req->capability = cpu_to_le16(capa);
+
+ req->listen_interval = cpu_to_le16(2 * bss->beacon_interval);
+
+ /* write TLV data elements */
+
+ ie->id = MFIE_TYPE_SSID;
+ ie->len = bss->ssid_len;
+ memcpy(ie->data, bss->ssid, bss->ssid_len);
+ next_ie(&ie);
+
+ ie->id = MFIE_TYPE_RATES;
+ ie->len = sizeof(hw_rates);
+ memcpy(ie->data, hw_rates, sizeof(hw_rates));
+ next_ie(&ie); /* ie points behind the supp_rates field */
+
+ /* init. at76_priv tx header */
+ tx_buffer->wlength = cpu_to_le16((u8 *)ie - (u8 *)mgmt);
+
+ ie = req->info_element;
+ essid = ie->data;
+ essid_len = min_t(int, IW_ESSID_MAX_SIZE, ie->len);
+
+ next_ie(&ie); /* points to IE of rates now */
+ at76_dbg(DBG_TX_MGMT,
+ "%s: AssocReq bssid %s capa 0x%04x ssid %.*s rates %s",
+ priv->netdev->name, mac2str(mgmt->addr3),
+ le16_to_cpu(req->capability), essid_len, essid,
+ hex2str(ie->data, ie->len));
+
+ /* either send immediately (if no data tx is pending
+ or put it in pending list */
+ return at76_tx_mgmt(priv, tx_buffer);
+}
+
+/* We got to check the bss_list for old entries */
+static void at76_bss_list_timeout(unsigned long par)
+{
+ struct at76_priv *priv = (struct at76_priv *)par;
+ unsigned long flags;
+ struct list_head *lptr, *nptr;
+ struct bss_info *ptr;
+
+ spin_lock_irqsave(&priv->bss_list_spinlock, flags);
+
+ list_for_each_safe(lptr, nptr, &priv->bss_list) {
+
+ ptr = list_entry(lptr, struct bss_info, list);
+
+ if (ptr != priv->curr_bss
+ && time_after(jiffies, ptr->last_rx + BSS_LIST_TIMEOUT)) {
+ at76_dbg(DBG_BSS_TABLE_RM,
+ "%s: bss_list: removing old BSS %s ch %d",
+ priv->netdev->name, mac2str(ptr->bssid),
+ ptr->channel);
+ list_del(&ptr->list);
+ kfree(ptr);
+ }
+ }
+ spin_unlock_irqrestore(&priv->bss_list_spinlock, flags);
+ /* restart the timer */
+ mod_timer(&priv->bss_list_timer, jiffies + BSS_LIST_TIMEOUT);
+}
+
+static inline void at76_set_mac_state(struct at76_priv *priv,
+ enum mac_state mac_state)
+{
+ at76_dbg(DBG_MAC_STATE, "%s state: %s", priv->netdev->name,
+ mac_states[mac_state]);
+ priv->mac_state = mac_state;
+}
+
+static void at76_dump_bss_table(struct at76_priv *priv)
+{
+ struct bss_info *ptr;
+ unsigned long flags;
+ struct list_head *lptr;
+
+ spin_lock_irqsave(&priv->bss_list_spinlock, flags);
+
+ at76_dbg(DBG_BSS_TABLE, "%s BSS table (curr=%p):", priv->netdev->name,
+ priv->curr_bss);
+
+ list_for_each(lptr, &priv->bss_list) {
+ ptr = list_entry(lptr, struct bss_info, list);
+ at76_dbg(DBG_BSS_TABLE, "0x%p: bssid %s channel %d ssid %.*s "
+ "(%s) capa 0x%04x rates %s rssi %d link %d noise %d",
+ ptr, mac2str(ptr->bssid), ptr->channel, ptr->ssid_len,
+ ptr->ssid, hex2str(ptr->ssid, ptr->ssid_len),
+ ptr->capa, hex2str(ptr->rates, ptr->rates_len),
+ ptr->rssi, ptr->link_qual, ptr->noise_level);
+ }
+ spin_unlock_irqrestore(&priv->bss_list_spinlock, flags);
+}
+
+/* Called upon successful association to mark interface as connected */
+static void at76_work_assoc_done(struct work_struct *work)
+{
+ struct at76_priv *priv = container_of(work, struct at76_priv,
+ work_assoc_done);
+
+ mutex_lock(&priv->mtx);
+
+ WARN_ON(priv->mac_state != MAC_ASSOC);
+ WARN_ON(!priv->curr_bss);
+ if (priv->mac_state != MAC_ASSOC || !priv->curr_bss)
+ goto exit;
+
+ if (priv->iw_mode == IW_MODE_INFRA) {
+ if (priv->pm_mode != AT76_PM_OFF) {
+ /* calculate the listen interval in units of
+ beacon intervals of the curr_bss */
+ u32 pm_period_beacon = (priv->pm_period >> 10) /
+ priv->curr_bss->beacon_interval;
+
+ pm_period_beacon = max(pm_period_beacon, 2u);
+ pm_period_beacon = min(pm_period_beacon, 0xffffu);
+
+ at76_dbg(DBG_PM,
+ "%s: pm_mode %d assoc id 0x%x listen int %d",
+ priv->netdev->name, priv->pm_mode,
+ priv->assoc_id, pm_period_beacon);
+
+ at76_set_associd(priv, priv->assoc_id);
+ at76_set_listen_interval(priv, (u16)pm_period_beacon);
+ }
+ schedule_delayed_work(&priv->dwork_beacon, BEACON_TIMEOUT);
+ }
+ at76_set_pm_mode(priv);
+
+ netif_carrier_on(priv->netdev);
+ netif_wake_queue(priv->netdev);
+ at76_set_mac_state(priv, MAC_CONNECTED);
+ at76_iwevent_bss_connect(priv->netdev, priv->curr_bss->bssid);
+ at76_dbg(DBG_PROGRESS, "%s: connected to BSSID %s",
+ priv->netdev->name, mac2str(priv->curr_bss->bssid));
+
+exit:
+ mutex_unlock(&priv->mtx);
+}
+
+/* We only store the new mac address in netdev struct,
+ it gets set when the netdev is opened. */
+static int at76_set_mac_address(struct net_device *netdev, void *addr)
+{
+ struct sockaddr *mac = addr;
+ memcpy(netdev->dev_addr, mac->sa_data, ETH_ALEN);
+ return 1;
+}
+
+static struct net_device_stats *at76_get_stats(struct net_device *netdev)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+ return &priv->stats;
+}
+
+static struct iw_statistics *at76_get_wireless_stats(struct net_device *netdev)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+
+ at76_dbg(DBG_IOCTL, "RETURN qual %d level %d noise %d updated %d",
+ priv->wstats.qual.qual, priv->wstats.qual.level,
+ priv->wstats.qual.noise, priv->wstats.qual.updated);
+
+ return &priv->wstats;
+}
+
+static void at76_set_multicast(struct net_device *netdev)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+ int promisc;
+
+ promisc = ((netdev->flags & IFF_PROMISC) != 0);
+ if (promisc != priv->promisc) {
+ /* This gets called in interrupt, must reschedule */
+ priv->promisc = promisc;
+ schedule_work(&priv->work_set_promisc);
+ }
+}
+
+/* Stop all network activity, flush all pending tasks */
+static void at76_quiesce(struct at76_priv *priv)
+{
+ unsigned long flags;
+
+ netif_stop_queue(priv->netdev);
+ netif_carrier_off(priv->netdev);
+
+ at76_set_mac_state(priv, MAC_INIT);
+
+ cancel_delayed_work(&priv->dwork_get_scan);
+ cancel_delayed_work(&priv->dwork_beacon);
+ cancel_delayed_work(&priv->dwork_auth);
+ cancel_delayed_work(&priv->dwork_assoc);
+ cancel_delayed_work(&priv->dwork_restart);
+
+ spin_lock_irqsave(&priv->mgmt_spinlock, flags);
+ kfree(priv->next_mgmt_bulk);
+ priv->next_mgmt_bulk = NULL;
+ spin_unlock_irqrestore(&priv->mgmt_spinlock, flags);
+}
+
+/*******************************************************************************
+ * at76_priv implementations of iw_handler functions:
+ */
+static int at76_iw_handler_commit(struct net_device *netdev,
+ struct iw_request_info *info,
+ void *null, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+
+ at76_dbg(DBG_IOCTL, "%s %s: restarting the device", netdev->name,
+ __func__);
+
+ if (priv->mac_state != MAC_INIT)
+ at76_quiesce(priv);
+
+ /* Wait half second before the restart to process subsequent
+ * requests from the same iwconfig in a single restart */
+ schedule_delayed_work(&priv->dwork_restart, HZ / 2);
+
+ return 0;
+}
+
+static int at76_iw_handler_get_name(struct net_device *netdev,
+ struct iw_request_info *info,
+ char *name, char *extra)
+{
+ strcpy(name, "IEEE 802.11b");
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWNAME - name %s", netdev->name, name);
+ return 0;
+}
+
+static int at76_iw_handler_set_freq(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_freq *freq, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+ int chan = -1;
+ int ret = -EIWCOMMIT;
+ at76_dbg(DBG_IOCTL, "%s: SIOCSIWFREQ - freq.m %d freq.e %d",
+ netdev->name, freq->m, freq->e);
+
+ if ((freq->e == 0) && (freq->m <= 1000))
+ /* Setting by channel number */
+ chan = freq->m;
+ else {
+ /* Setting by frequency - search the table */
+ int mult = 1;
+ int i;
+
+ for (i = 0; i < (6 - freq->e); i++)
+ mult *= 10;
+
+ for (i = 0; i < NUM_CHANNELS; i++) {
+ if (freq->m == (channel_frequency[i] * mult))
+ chan = i + 1;
+ }
+ }
+
+ if (chan < 1 || !priv->domain)
+ /* non-positive channels are invalid
+ * we need a domain info to set the channel
+ * either that or an invalid frequency was
+ * provided by the user */
+ ret = -EINVAL;
+ else if (!(priv->domain->channel_map & (1 << (chan - 1)))) {
+ printk(KERN_INFO "%s: channel %d not allowed for domain %s\n",
+ priv->netdev->name, chan, priv->domain->name);
+ ret = -EINVAL;
+ }
+
+ if (ret == -EIWCOMMIT) {
+ priv->channel = chan;
+ at76_dbg(DBG_IOCTL, "%s: SIOCSIWFREQ - ch %d", netdev->name,
+ chan);
+ }
+
+ return ret;
+}
+
+static int at76_iw_handler_get_freq(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_freq *freq, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+
+ freq->m = priv->channel;
+ freq->e = 0;
+
+ if (priv->channel)
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWFREQ - freq %ld x 10e%d",
+ netdev->name, channel_frequency[priv->channel - 1], 6);
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWFREQ - ch %d", netdev->name,
+ priv->channel);
+
+ return 0;
+}
+
+static int at76_iw_handler_set_mode(struct net_device *netdev,
+ struct iw_request_info *info,
+ __u32 *mode, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCSIWMODE - %d", netdev->name, *mode);
+
+ if ((*mode != IW_MODE_ADHOC) && (*mode != IW_MODE_INFRA) &&
+ (*mode != IW_MODE_MONITOR))
+ return -EINVAL;
+
+ priv->iw_mode = *mode;
+ if (priv->iw_mode != IW_MODE_INFRA)
+ priv->pm_mode = AT76_PM_OFF;
+
+ return -EIWCOMMIT;
+}
+
+static int at76_iw_handler_get_mode(struct net_device *netdev,
+ struct iw_request_info *info,
+ __u32 *mode, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+
+ *mode = priv->iw_mode;
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWMODE - %d", netdev->name, *mode);
+
+ return 0;
+}
+
+static int at76_iw_handler_get_range(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ /* inspired by atmel.c */
+ struct at76_priv *priv = netdev_priv(netdev);
+ struct iw_range *range = (struct iw_range *)extra;
+ int i;
+
+ data->length = sizeof(struct iw_range);
+ memset(range, 0, sizeof(struct iw_range));
+
+ /* TODO: range->throughput = xxxxxx; */
+
+ range->min_nwid = 0x0000;
+ range->max_nwid = 0x0000;
+
+ /* this driver doesn't maintain sensitivity information */
+ range->sensitivity = 0;
+
+ range->max_qual.qual = 100;
+ range->max_qual.level = 100;
+ range->max_qual.noise = 0;
+ range->max_qual.updated = IW_QUAL_NOISE_INVALID;
+
+ range->avg_qual.qual = 50;
+ range->avg_qual.level = 50;
+ range->avg_qual.noise = 0;
+ range->avg_qual.updated = IW_QUAL_NOISE_INVALID;
+
+ range->bitrate[0] = 1000000;
+ range->bitrate[1] = 2000000;
+ range->bitrate[2] = 5500000;
+ range->bitrate[3] = 11000000;
+ range->num_bitrates = 4;
+
+ range->min_rts = 0;
+ range->max_rts = MAX_RTS_THRESHOLD;
+
+ range->min_frag = MIN_FRAG_THRESHOLD;
+ range->max_frag = MAX_FRAG_THRESHOLD;
+
+ range->pmp_flags = IW_POWER_PERIOD;
+ range->pmt_flags = IW_POWER_ON;
+ range->pm_capa = IW_POWER_PERIOD | IW_POWER_ALL_R;
+
+ range->encoding_size[0] = WEP_SMALL_KEY_LEN;
+ range->encoding_size[1] = WEP_LARGE_KEY_LEN;
+ range->num_encoding_sizes = 2;
+ range->max_encoding_tokens = WEP_KEYS;
+
+ /* both WL-240U and Linksys WUSB11 v2.6 specify 15 dBm as output power
+ - take this for all (ignore antenna gains) */
+ range->txpower[0] = 15;
+ range->num_txpower = 1;
+ range->txpower_capa = IW_TXPOW_DBM;
+
+ range->we_version_source = WIRELESS_EXT;
+ range->we_version_compiled = WIRELESS_EXT;
+
+ /* same as the values used in atmel.c */
+ range->retry_capa = IW_RETRY_LIMIT;
+ range->retry_flags = IW_RETRY_LIMIT;
+ range->r_time_flags = 0;
+ range->min_retry = 1;
+ range->max_retry = 255;
+
+ range->num_channels = NUM_CHANNELS;
+ range->num_frequency = 0;
+
+ for (i = 0; i < NUM_CHANNELS; i++) {
+ /* test if channel map bit is raised */
+ if (priv->domain->channel_map & (0x1 << i)) {
+ range->num_frequency += 1;
+
+ range->freq[i].i = i + 1;
+ range->freq[i].m = channel_frequency[i] * 100000;
+ range->freq[i].e = 1; /* freq * 10^1 */
+ }
+ }
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWRANGE", netdev->name);
+
+ return 0;
+}
+
+static int at76_iw_handler_set_spy(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+ int ret = 0;
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCSIWSPY - number of addresses %d",
+ netdev->name, data->length);
+
+ spin_lock_bh(&priv->spy_spinlock);
+ ret = iw_handler_set_spy(priv->netdev, info, (union iwreq_data *)data,
+ extra);
+ spin_unlock_bh(&priv->spy_spinlock);
+
+ return ret;
+}
+
+static int at76_iw_handler_get_spy(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+
+ struct at76_priv *priv = netdev_priv(netdev);
+ int ret = 0;
+
+ spin_lock_bh(&priv->spy_spinlock);
+ ret = iw_handler_get_spy(priv->netdev, info,
+ (union iwreq_data *)data, extra);
+ spin_unlock_bh(&priv->spy_spinlock);
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWSPY - number of addresses %d",
+ netdev->name, data->length);
+
+ return ret;
+}
+
+static int at76_iw_handler_set_thrspy(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+ int ret;
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCSIWTHRSPY - number of addresses %d)",
+ netdev->name, data->length);
+
+ spin_lock_bh(&priv->spy_spinlock);
+ ret = iw_handler_set_thrspy(netdev, info, (union iwreq_data *)data,
+ extra);
+ spin_unlock_bh(&priv->spy_spinlock);
+
+ return ret;
+}
+
+static int at76_iw_handler_get_thrspy(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+ int ret;
+
+ spin_lock_bh(&priv->spy_spinlock);
+ ret = iw_handler_get_thrspy(netdev, info, (union iwreq_data *)data,
+ extra);
+ spin_unlock_bh(&priv->spy_spinlock);
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWTHRSPY - number of addresses %d)",
+ netdev->name, data->length);
+
+ return ret;
+}
+
+static int at76_iw_handler_set_wap(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCSIWAP - wap/bssid %s", netdev->name,
+ mac2str(ap_addr->sa_data));
+
+ /* if the incoming address == ff:ff:ff:ff:ff:ff, the user has
+ chosen any or auto AP preference */
+ if (is_broadcast_ether_addr(ap_addr->sa_data)
+ || is_zero_ether_addr(ap_addr->sa_data))
+ priv->wanted_bssid_valid = 0;
+ else {
+ /* user wants to set a preferred AP address */
+ priv->wanted_bssid_valid = 1;
+ memcpy(priv->wanted_bssid, ap_addr->sa_data, ETH_ALEN);
+ }
+
+ return -EIWCOMMIT;
+}
+
+static int at76_iw_handler_get_wap(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+
+ ap_addr->sa_family = ARPHRD_ETHER;
+ memcpy(ap_addr->sa_data, priv->bssid, ETH_ALEN);
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWAP - wap/bssid %s", netdev->name,
+ mac2str(ap_addr->sa_data));
+
+ return 0;
+}
+
+static int at76_iw_handler_set_scan(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+ int ret = 0;
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCSIWSCAN", netdev->name);
+
+ if (mutex_lock_interruptible(&priv->mtx))
+ return -EINTR;
+
+ if (!netif_running(netdev)) {
+ ret = -ENETDOWN;
+ goto exit;
+ }
+
+ /* jal: we don't allow "iwlist ethX scan" while we are
+ in monitor mode */
+ if (priv->iw_mode == IW_MODE_MONITOR) {
+ ret = -EBUSY;
+ goto exit;
+ }
+
+ /* Discard old scan results */
+ if ((jiffies - priv->last_scan) > (20 * HZ))
+ priv->scan_state = SCAN_IDLE;
+ priv->last_scan = jiffies;
+
+ /* Initiate a scan command */
+ if (priv->scan_state == SCAN_IN_PROGRESS) {
+ ret = -EBUSY;
+ goto exit;
+ }
+
+ priv->scan_state = SCAN_IN_PROGRESS;
+
+ at76_quiesce(priv);
+
+ /* Try to do passive or active scan if WE asks as. */
+ if (wrqu->data.length
+ && wrqu->data.length == sizeof(struct iw_scan_req)) {
+ struct iw_scan_req *req = (struct iw_scan_req *)extra;
+
+ if (req->scan_type == IW_SCAN_TYPE_PASSIVE)
+ priv->scan_mode = SCAN_TYPE_PASSIVE;
+ else if (req->scan_type == IW_SCAN_TYPE_ACTIVE)
+ priv->scan_mode = SCAN_TYPE_ACTIVE;
+
+ /* Sanity check values? */
+ if (req->min_channel_time > 0)
+ priv->scan_min_time = req->min_channel_time;
+
+ if (req->max_channel_time > 0)
+ priv->scan_max_time = req->max_channel_time;
+ }
+
+ /* change to scanning state */
+ at76_set_mac_state(priv, MAC_SCANNING);
+ schedule_work(&priv->work_start_scan);
+
+exit:
+ mutex_unlock(&priv->mtx);
+ return ret;
+}
+
+static int at76_iw_handler_get_scan(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+ unsigned long flags;
+ struct list_head *lptr, *nptr;
+ struct bss_info *curr_bss;
+ struct iw_event *iwe = kmalloc(sizeof(struct iw_event), GFP_KERNEL);
+ char *curr_val, *curr_pos = extra;
+ int i;
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWSCAN", netdev->name);
+
+ if (!iwe)
+ return -ENOMEM;
+
+ if (priv->scan_state != SCAN_COMPLETED)
+ /* scan not yet finished */
+ return -EAGAIN;
+
+ spin_lock_irqsave(&priv->bss_list_spinlock, flags);
+
+ list_for_each_safe(lptr, nptr, &priv->bss_list) {
+ curr_bss = list_entry(lptr, struct bss_info, list);
+
+ iwe->cmd = SIOCGIWAP;
+ iwe->u.ap_addr.sa_family = ARPHRD_ETHER;
+ memcpy(iwe->u.ap_addr.sa_data, curr_bss->bssid, 6);
+ curr_pos = iwe_stream_add_event(info, curr_pos,
+ extra + IW_SCAN_MAX_DATA, iwe,
+ IW_EV_ADDR_LEN);
+
+ iwe->u.data.length = curr_bss->ssid_len;
+ iwe->cmd = SIOCGIWESSID;
+ iwe->u.data.flags = 1;
+
+ curr_pos = iwe_stream_add_point(info, curr_pos,
+ extra + IW_SCAN_MAX_DATA, iwe,
+ curr_bss->ssid);
+
+ iwe->cmd = SIOCGIWMODE;
+ iwe->u.mode = (curr_bss->capa & WLAN_CAPABILITY_IBSS) ?
+ IW_MODE_ADHOC :
+ (curr_bss->capa & WLAN_CAPABILITY_ESS) ?
+ IW_MODE_MASTER : IW_MODE_AUTO;
+ /* IW_MODE_AUTO = 0 which I thought is
+ * the most logical value to return in this case */
+ curr_pos = iwe_stream_add_event(info, curr_pos,
+ extra + IW_SCAN_MAX_DATA, iwe,
+ IW_EV_UINT_LEN);
+
+ iwe->cmd = SIOCGIWFREQ;
+ iwe->u.freq.m = curr_bss->channel;
+ iwe->u.freq.e = 0;
+ curr_pos = iwe_stream_add_event(info, curr_pos,
+ extra + IW_SCAN_MAX_DATA, iwe,
+ IW_EV_FREQ_LEN);
+
+ iwe->cmd = SIOCGIWENCODE;
+ if (curr_bss->capa & WLAN_CAPABILITY_PRIVACY)
+ iwe->u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+ else
+ iwe->u.data.flags = IW_ENCODE_DISABLED;
+
+ iwe->u.data.length = 0;
+ curr_pos = iwe_stream_add_point(info, curr_pos,
+ extra + IW_SCAN_MAX_DATA, iwe,
+ NULL);
+
+ /* Add quality statistics */
+ iwe->cmd = IWEVQUAL;
+ iwe->u.qual.noise = 0;
+ iwe->u.qual.updated =
+ IW_QUAL_NOISE_INVALID | IW_QUAL_LEVEL_UPDATED;
+ iwe->u.qual.level = (curr_bss->rssi * 100 / 42);
+ if (iwe->u.qual.level > 100)
+ iwe->u.qual.level = 100;
+ if (at76_is_intersil(priv->board_type))
+ iwe->u.qual.qual = curr_bss->link_qual;
+ else {
+ iwe->u.qual.qual = 0;
+ iwe->u.qual.updated |= IW_QUAL_QUAL_INVALID;
+ }
+ /* Add new value to event */
+ curr_pos = iwe_stream_add_event(info, curr_pos,
+ extra + IW_SCAN_MAX_DATA, iwe,
+ IW_EV_QUAL_LEN);
+
+ /* Rate: stuffing multiple values in a single event requires
+ * a bit more of magic - Jean II */
+ curr_val = curr_pos + IW_EV_LCP_LEN;
+
+ iwe->cmd = SIOCGIWRATE;
+ /* Those two flags are ignored... */
+ iwe->u.bitrate.fixed = 0;
+ iwe->u.bitrate.disabled = 0;
+ /* Max 8 values */
+ for (i = 0; i < curr_bss->rates_len; i++) {
+ /* Bit rate given in 500 kb/s units (+ 0x80) */
+ iwe->u.bitrate.value =
+ ((curr_bss->rates[i] & 0x7f) * 500000);
+ /* Add new value to event */
+ curr_val = iwe_stream_add_value(info, curr_pos,
+ curr_val,
+ extra +
+ IW_SCAN_MAX_DATA, iwe,
+ IW_EV_PARAM_LEN);
+ }
+
+ /* Check if we added any event */
+ if ((curr_val - curr_pos) > IW_EV_LCP_LEN)
+ curr_pos = curr_val;
+
+ /* more information may be sent back using IWECUSTOM */
+
+ }
+
+ spin_unlock_irqrestore(&priv->bss_list_spinlock, flags);
+
+ data->length = (curr_pos - extra);
+ data->flags = 0;
+
+ kfree(iwe);
+ return 0;
+}
+
+static int at76_iw_handler_set_essid(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCSIWESSID - %s", netdev->name, extra);
+
+ if (data->flags) {
+ memcpy(priv->essid, extra, data->length);
+ priv->essid_size = data->length;
+ } else
+ priv->essid_size = 0; /* Use any SSID */
+
+ return -EIWCOMMIT;
+}
+
+static int at76_iw_handler_get_essid(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+
+ if (priv->essid_size) {
+ /* not the ANY ssid in priv->essid */
+ data->flags = 1;
+ data->length = priv->essid_size;
+ memcpy(extra, priv->essid, data->length);
+ } else {
+ /* the ANY ssid was specified */
+ if (priv->mac_state == MAC_CONNECTED && priv->curr_bss) {
+ /* report the SSID we have found */
+ data->flags = 1;
+ data->length = priv->curr_bss->ssid_len;
+ memcpy(extra, priv->curr_bss->ssid, data->length);
+ } else {
+ /* report ANY back */
+ data->flags = 0;
+ data->length = 0;
+ }
+ }
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWESSID - %.*s", netdev->name,
+ data->length, extra);
+
+ return 0;
+}
+
+static int at76_iw_handler_set_rate(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_param *bitrate, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+ int ret = -EIWCOMMIT;
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCSIWRATE - %d", netdev->name,
+ bitrate->value);
+
+ switch (bitrate->value) {
+ case -1:
+ priv->txrate = TX_RATE_AUTO;
+ break; /* auto rate */
+ case 1000000:
+ priv->txrate = TX_RATE_1MBIT;
+ break;
+ case 2000000:
+ priv->txrate = TX_RATE_2MBIT;
+ break;
+ case 5500000:
+ priv->txrate = TX_RATE_5_5MBIT;
+ break;
+ case 11000000:
+ priv->txrate = TX_RATE_11MBIT;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int at76_iw_handler_get_rate(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_param *bitrate, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+ int ret = 0;
+
+ switch (priv->txrate) {
+ /* return max rate if RATE_AUTO */
+ case TX_RATE_AUTO:
+ bitrate->value = 11000000;
+ break;
+ case TX_RATE_1MBIT:
+ bitrate->value = 1000000;
+ break;
+ case TX_RATE_2MBIT:
+ bitrate->value = 2000000;
+ break;
+ case TX_RATE_5_5MBIT:
+ bitrate->value = 5500000;
+ break;
+ case TX_RATE_11MBIT:
+ bitrate->value = 11000000;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ bitrate->fixed = (priv->txrate != TX_RATE_AUTO);
+ bitrate->disabled = 0;
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWRATE - %d", netdev->name,
+ bitrate->value);
+
+ return ret;
+}
+
+static int at76_iw_handler_set_rts(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_param *rts, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+ int ret = -EIWCOMMIT;
+ int rthr = rts->value;
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCSIWRTS - value %d disabled %s",
+ netdev->name, rts->value, (rts->disabled) ? "true" : "false");
+
+ if (rts->disabled)
+ rthr = MAX_RTS_THRESHOLD;
+
+ if ((rthr < 0) || (rthr > MAX_RTS_THRESHOLD))
+ ret = -EINVAL;
+ else
+ priv->rts_threshold = rthr;
+
+ return ret;
+}
+
+static int at76_iw_handler_get_rts(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_param *rts, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+
+ rts->value = priv->rts_threshold;
+ rts->disabled = (rts->value >= MAX_RTS_THRESHOLD);
+ rts->fixed = 1;
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWRTS - value %d disabled %s",
+ netdev->name, rts->value, (rts->disabled) ? "true" : "false");
+
+ return 0;
+}
+
+static int at76_iw_handler_set_frag(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_param *frag, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+ int ret = -EIWCOMMIT;
+ int fthr = frag->value;
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCSIWFRAG - value %d, disabled %s",
+ netdev->name, frag->value,
+ (frag->disabled) ? "true" : "false");
+
+ if (frag->disabled)
+ fthr = MAX_FRAG_THRESHOLD;
+
+ if ((fthr < MIN_FRAG_THRESHOLD) || (fthr > MAX_FRAG_THRESHOLD))
+ ret = -EINVAL;
+ else
+ priv->frag_threshold = fthr & ~0x1; /* get an even value */
+
+ return ret;
+}
+
+static int at76_iw_handler_get_frag(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_param *frag, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+
+ frag->value = priv->frag_threshold;
+ frag->disabled = (frag->value >= MAX_FRAG_THRESHOLD);
+ frag->fixed = 1;
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWFRAG - value %d, disabled %s",
+ netdev->name, frag->value,
+ (frag->disabled) ? "true" : "false");
+
+ return 0;
+}
+
+static int at76_iw_handler_get_txpow(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_param *power, char *extra)
+{
+ power->value = 15;
+ power->fixed = 1; /* No power control */
+ power->disabled = 0;
+ power->flags = IW_TXPOW_DBM;
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWTXPOW - txpow %d dBm", netdev->name,
+ power->value);
+
+ return 0;
+}
+
+/* jal: short retry is handled by the firmware (at least 0.90.x),
+ while long retry is not (?) */
+static int at76_iw_handler_set_retry(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_param *retry, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+ int ret = -EIWCOMMIT;
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCSIWRETRY disabled %d flags 0x%x val %d",
+ netdev->name, retry->disabled, retry->flags, retry->value);
+
+ if (!retry->disabled && (retry->flags & IW_RETRY_LIMIT)) {
+ if ((retry->flags & IW_RETRY_MIN) ||
+ !(retry->flags & IW_RETRY_MAX))
+ priv->short_retry_limit = retry->value;
+ else
+ ret = -EINVAL;
+ } else
+ ret = -EINVAL;
+
+ return ret;
+}
+
+/* Adapted (ripped) from atmel.c */
+static int at76_iw_handler_get_retry(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_param *retry, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWRETRY", netdev->name);
+
+ retry->disabled = 0; /* Can't be disabled */
+ retry->flags = IW_RETRY_LIMIT;
+ retry->value = priv->short_retry_limit;
+
+ return 0;
+}
+
+static int at76_iw_handler_set_encode(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_point *encoding, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+ int index = (encoding->flags & IW_ENCODE_INDEX) - 1;
+ int len = encoding->length;
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCSIWENCODE - enc.flags %08x "
+ "pointer %p len %d", netdev->name, encoding->flags,
+ encoding->pointer, encoding->length);
+ at76_dbg(DBG_IOCTL,
+ "%s: SIOCSIWENCODE - old wepstate: enabled %s key_id %d "
+ "auth_mode %s", netdev->name,
+ (priv->wep_enabled) ? "true" : "false", priv->wep_key_id,
+ (priv->auth_mode ==
+ WLAN_AUTH_SHARED_KEY) ? "restricted" : "open");
+
+ /* take the old default key if index is invalid */
+ if ((index < 0) || (index >= WEP_KEYS))
+ index = priv->wep_key_id;
+
+ if (len > 0) {
+ if (len > WEP_LARGE_KEY_LEN)
+ len = WEP_LARGE_KEY_LEN;
+
+ memset(priv->wep_keys[index], 0, WEP_KEY_LEN);
+ memcpy(priv->wep_keys[index], extra, len);
+ priv->wep_keys_len[index] = (len <= WEP_SMALL_KEY_LEN) ?
+ WEP_SMALL_KEY_LEN : WEP_LARGE_KEY_LEN;
+ priv->wep_enabled = 1;
+ }
+
+ priv->wep_key_id = index;
+ priv->wep_enabled = ((encoding->flags & IW_ENCODE_DISABLED) == 0);
+
+ if (encoding->flags & IW_ENCODE_RESTRICTED)
+ priv->auth_mode = WLAN_AUTH_SHARED_KEY;
+ if (encoding->flags & IW_ENCODE_OPEN)
+ priv->auth_mode = WLAN_AUTH_OPEN;
+
+ at76_dbg(DBG_IOCTL,
+ "%s: SIOCSIWENCODE - new wepstate: enabled %s key_id %d "
+ "key_len %d auth_mode %s", netdev->name,
+ (priv->wep_enabled) ? "true" : "false", priv->wep_key_id + 1,
+ priv->wep_keys_len[priv->wep_key_id],
+ (priv->auth_mode ==
+ WLAN_AUTH_SHARED_KEY) ? "restricted" : "open");
+
+ return -EIWCOMMIT;
+}
+
+static int at76_iw_handler_get_encode(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_point *encoding, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+ int index = (encoding->flags & IW_ENCODE_INDEX) - 1;
+
+ if ((index < 0) || (index >= WEP_KEYS))
+ index = priv->wep_key_id;
+
+ encoding->flags =
+ (priv->auth_mode == WLAN_AUTH_SHARED_KEY) ?
+ IW_ENCODE_RESTRICTED : IW_ENCODE_OPEN;
+
+ if (!priv->wep_enabled)
+ encoding->flags |= IW_ENCODE_DISABLED;
+
+ if (encoding->pointer) {
+ encoding->length = priv->wep_keys_len[index];
+
+ memcpy(extra, priv->wep_keys[index], priv->wep_keys_len[index]);
+
+ encoding->flags |= (index + 1);
+ }
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWENCODE - enc.flags %08x "
+ "pointer %p len %d", netdev->name, encoding->flags,
+ encoding->pointer, encoding->length);
+ at76_dbg(DBG_IOCTL,
+ "%s: SIOCGIWENCODE - wepstate: enabled %s key_id %d "
+ "key_len %d auth_mode %s", netdev->name,
+ (priv->wep_enabled) ? "true" : "false", priv->wep_key_id + 1,
+ priv->wep_keys_len[priv->wep_key_id],
+ (priv->auth_mode ==
+ WLAN_AUTH_SHARED_KEY) ? "restricted" : "open");
+
+ return 0;
+}
+
+static int at76_iw_handler_set_power(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_param *prq, char *extra)
+{
+ int err = -EIWCOMMIT;
+ struct at76_priv *priv = netdev_priv(netdev);
+
+ at76_dbg(DBG_IOCTL,
+ "%s: SIOCSIWPOWER - disabled %s flags 0x%x value 0x%x",
+ netdev->name, (prq->disabled) ? "true" : "false", prq->flags,
+ prq->value);
+
+ if (prq->disabled)
+ priv->pm_mode = AT76_PM_OFF;
+ else {
+ switch (prq->flags & IW_POWER_MODE) {
+ case IW_POWER_ALL_R:
+ case IW_POWER_ON:
+ break;
+ default:
+ err = -EINVAL;
+ goto exit;
+ }
+ if (prq->flags & IW_POWER_PERIOD)
+ priv->pm_period = prq->value;
+
+ if (prq->flags & IW_POWER_TIMEOUT) {
+ err = -EINVAL;
+ goto exit;
+ }
+ priv->pm_mode = AT76_PM_ON;
+ }
+exit:
+ return err;
+}
+
+static int at76_iw_handler_get_power(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_param *power, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+
+ power->disabled = (priv->pm_mode == AT76_PM_OFF);
+ if (!power->disabled) {
+ power->flags = IW_POWER_PERIOD | IW_POWER_ALL_R;
+ power->value = priv->pm_period;
+ }
+
+ at76_dbg(DBG_IOCTL, "%s: SIOCGIWPOWER - %s flags 0x%x value 0x%x",
+ netdev->name, power->disabled ? "disabled" : "enabled",
+ power->flags, power->value);
+
+ return 0;
+}
+
+/*******************************************************************************
+ * Private IOCTLS
+ */
+static int at76_iw_set_short_preamble(struct net_device *netdev,
+ struct iw_request_info *info, char *name,
+ char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+ int val = *((int *)name);
+ int ret = -EIWCOMMIT;
+
+ at76_dbg(DBG_IOCTL, "%s: AT76_SET_SHORT_PREAMBLE, %d",
+ netdev->name, val);
+
+ if (val < PREAMBLE_TYPE_LONG || val > PREAMBLE_TYPE_AUTO)
+ ret = -EINVAL;
+ else
+ priv->preamble_type = val;
+
+ return ret;
+}
+
+static int at76_iw_get_short_preamble(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+
+ snprintf(wrqu->name, sizeof(wrqu->name), "%s (%d)",
+ preambles[priv->preamble_type], priv->preamble_type);
+ return 0;
+}
+
+static int at76_iw_set_debug(struct net_device *netdev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ char *ptr;
+ u32 val;
+
+ if (data->length > 0) {
+ val = simple_strtol(extra, &ptr, 0);
+
+ if (ptr == extra)
+ val = DBG_DEFAULTS;
+
+ at76_dbg(DBG_IOCTL, "%s: AT76_SET_DEBUG input %d: %s -> 0x%x",
+ netdev->name, data->length, extra, val);
+ } else
+ val = DBG_DEFAULTS;
+
+ at76_dbg(DBG_IOCTL, "%s: AT76_SET_DEBUG, old 0x%x, new 0x%x",
+ netdev->name, at76_debug, val);
+
+ /* jal: some more output to pin down lockups */
+ at76_dbg(DBG_IOCTL, "%s: netif running %d queue_stopped %d "
+ "carrier_ok %d", netdev->name, netif_running(netdev),
+ netif_queue_stopped(netdev), netif_carrier_ok(netdev));
+
+ at76_debug = val;
+
+ return 0;
+}
+
+static int at76_iw_get_debug(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ snprintf(wrqu->name, sizeof(wrqu->name), "0x%08x", at76_debug);
+ return 0;
+}
+
+static int at76_iw_set_powersave_mode(struct net_device *netdev,
+ struct iw_request_info *info, char *name,
+ char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+ int val = *((int *)name);
+ int ret = -EIWCOMMIT;
+
+ at76_dbg(DBG_IOCTL, "%s: AT76_SET_POWERSAVE_MODE, %d (%s)",
+ netdev->name, val,
+ val == AT76_PM_OFF ? "active" : val == AT76_PM_ON ? "save" :
+ val == AT76_PM_SMART ? "smart save" : "<invalid>");
+ if (val < AT76_PM_OFF || val > AT76_PM_SMART)
+ ret = -EINVAL;
+ else
+ priv->pm_mode = val;
+
+ return ret;
+}
+
+static int at76_iw_get_powersave_mode(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+ int *param = (int *)extra;
+
+ param[0] = priv->pm_mode;
+ return 0;
+}
+
+static int at76_iw_set_scan_times(struct net_device *netdev,
+ struct iw_request_info *info, char *name,
+ char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+ int mint = *((int *)name);
+ int maxt = *((int *)name + 1);
+ int ret = -EIWCOMMIT;
+
+ at76_dbg(DBG_IOCTL, "%s: AT76_SET_SCAN_TIMES - min %d max %d",
+ netdev->name, mint, maxt);
+ if (mint <= 0 || maxt <= 0 || mint > maxt)
+ ret = -EINVAL;
+ else {
+ priv->scan_min_time = mint;
+ priv->scan_max_time = maxt;
+ }
+
+ return ret;
+}
+
+static int at76_iw_get_scan_times(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+ int *param = (int *)extra;
+
+ param[0] = priv->scan_min_time;
+ param[1] = priv->scan_max_time;
+ return 0;
+}
+
+static int at76_iw_set_scan_mode(struct net_device *netdev,
+ struct iw_request_info *info, char *name,
+ char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+ int val = *((int *)name);
+ int ret = -EIWCOMMIT;
+
+ at76_dbg(DBG_IOCTL, "%s: AT76_SET_SCAN_MODE - mode %s",
+ netdev->name, (val = SCAN_TYPE_ACTIVE) ? "active" :
+ (val = SCAN_TYPE_PASSIVE) ? "passive" : "<invalid>");
+
+ if (val != SCAN_TYPE_ACTIVE && val != SCAN_TYPE_PASSIVE)
+ ret = -EINVAL;
+ else
+ priv->scan_mode = val;
+
+ return ret;
+}
+
+static int at76_iw_get_scan_mode(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+ int *param = (int *)extra;
+
+ param[0] = priv->scan_mode;
+ return 0;
+}
+
+#define AT76_SET_HANDLER(h, f) [h - SIOCIWFIRST] = (iw_handler) f
+
+/* Standard wireless handlers */
+static const iw_handler at76_handlers[] = {
+ AT76_SET_HANDLER(SIOCSIWCOMMIT, at76_iw_handler_commit),
+ AT76_SET_HANDLER(SIOCGIWNAME, at76_iw_handler_get_name),
+ AT76_SET_HANDLER(SIOCSIWFREQ, at76_iw_handler_set_freq),
+ AT76_SET_HANDLER(SIOCGIWFREQ, at76_iw_handler_get_freq),
+ AT76_SET_HANDLER(SIOCSIWMODE, at76_iw_handler_set_mode),
+ AT76_SET_HANDLER(SIOCGIWMODE, at76_iw_handler_get_mode),
+ AT76_SET_HANDLER(SIOCGIWRANGE, at76_iw_handler_get_range),
+ AT76_SET_HANDLER(SIOCSIWSPY, at76_iw_handler_set_spy),
+ AT76_SET_HANDLER(SIOCGIWSPY, at76_iw_handler_get_spy),
+ AT76_SET_HANDLER(SIOCSIWTHRSPY, at76_iw_handler_set_thrspy),
+ AT76_SET_HANDLER(SIOCGIWTHRSPY, at76_iw_handler_get_thrspy),
+ AT76_SET_HANDLER(SIOCSIWAP, at76_iw_handler_set_wap),
+ AT76_SET_HANDLER(SIOCGIWAP, at76_iw_handler_get_wap),
+ AT76_SET_HANDLER(SIOCSIWSCAN, at76_iw_handler_set_scan),
+ AT76_SET_HANDLER(SIOCGIWSCAN, at76_iw_handler_get_scan),
+ AT76_SET_HANDLER(SIOCSIWESSID, at76_iw_handler_set_essid),
+ AT76_SET_HANDLER(SIOCGIWESSID, at76_iw_handler_get_essid),
+ AT76_SET_HANDLER(SIOCSIWRATE, at76_iw_handler_set_rate),
+ AT76_SET_HANDLER(SIOCGIWRATE, at76_iw_handler_get_rate),
+ AT76_SET_HANDLER(SIOCSIWRTS, at76_iw_handler_set_rts),
+ AT76_SET_HANDLER(SIOCGIWRTS, at76_iw_handler_get_rts),
+ AT76_SET_HANDLER(SIOCSIWFRAG, at76_iw_handler_set_frag),
+ AT76_SET_HANDLER(SIOCGIWFRAG, at76_iw_handler_get_frag),
+ AT76_SET_HANDLER(SIOCGIWTXPOW, at76_iw_handler_get_txpow),
+ AT76_SET_HANDLER(SIOCSIWRETRY, at76_iw_handler_set_retry),
+ AT76_SET_HANDLER(SIOCGIWRETRY, at76_iw_handler_get_retry),
+ AT76_SET_HANDLER(SIOCSIWENCODE, at76_iw_handler_set_encode),
+ AT76_SET_HANDLER(SIOCGIWENCODE, at76_iw_handler_get_encode),
+ AT76_SET_HANDLER(SIOCSIWPOWER, at76_iw_handler_set_power),
+ AT76_SET_HANDLER(SIOCGIWPOWER, at76_iw_handler_get_power)
+};
+
+#define AT76_SET_PRIV(h, f) [h - SIOCIWFIRSTPRIV] = (iw_handler) f
+
+/* Private wireless handlers */
+static const iw_handler at76_priv_handlers[] = {
+ AT76_SET_PRIV(AT76_SET_SHORT_PREAMBLE, at76_iw_set_short_preamble),
+ AT76_SET_PRIV(AT76_GET_SHORT_PREAMBLE, at76_iw_get_short_preamble),
+ AT76_SET_PRIV(AT76_SET_DEBUG, at76_iw_set_debug),
+ AT76_SET_PRIV(AT76_GET_DEBUG, at76_iw_get_debug),
+ AT76_SET_PRIV(AT76_SET_POWERSAVE_MODE, at76_iw_set_powersave_mode),
+ AT76_SET_PRIV(AT76_GET_POWERSAVE_MODE, at76_iw_get_powersave_mode),
+ AT76_SET_PRIV(AT76_SET_SCAN_TIMES, at76_iw_set_scan_times),
+ AT76_SET_PRIV(AT76_GET_SCAN_TIMES, at76_iw_get_scan_times),
+ AT76_SET_PRIV(AT76_SET_SCAN_MODE, at76_iw_set_scan_mode),
+ AT76_SET_PRIV(AT76_GET_SCAN_MODE, at76_iw_get_scan_mode),
+};
+
+/* Names and arguments of private wireless handlers */
+static const struct iw_priv_args at76_priv_args[] = {
+ /* 0 - long, 1 - short */
+ {AT76_SET_SHORT_PREAMBLE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_preamble"},
+
+ {AT76_GET_SHORT_PREAMBLE,
+ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 10, "get_preamble"},
+
+ /* we must pass the new debug mask as a string, because iwpriv cannot
+ * parse hex numbers starting with 0x :-( */
+ {AT76_SET_DEBUG,
+ IW_PRIV_TYPE_CHAR | 10, 0, "set_debug"},
+
+ {AT76_GET_DEBUG,
+ 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 10, "get_debug"},
+
+ /* 1 - active, 2 - power save, 3 - smart power save */
+ {AT76_SET_POWERSAVE_MODE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_powersave"},
+
+ {AT76_GET_POWERSAVE_MODE,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_powersave"},
+
+ /* min_channel_time, max_channel_time */
+ {AT76_SET_SCAN_TIMES,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_scan_times"},
+
+ {AT76_GET_SCAN_TIMES,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, "get_scan_times"},
+
+ /* 0 - active, 1 - passive scan */
+ {AT76_SET_SCAN_MODE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_scan_mode"},
+
+ {AT76_GET_SCAN_MODE,
+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_scan_mode"},
+};
+
+static const struct iw_handler_def at76_handler_def = {
+ .num_standard = ARRAY_SIZE(at76_handlers),
+ .num_private = ARRAY_SIZE(at76_priv_handlers),
+ .num_private_args = ARRAY_SIZE(at76_priv_args),
+ .standard = at76_handlers,
+ .private = at76_priv_handlers,
+ .private_args = at76_priv_args,
+ .get_wireless_stats = at76_get_wireless_stats,
+};
+
+static const u8 snapsig[] = { 0xaa, 0xaa, 0x03 };
+
+/* RFC 1042 encapsulates Ethernet frames in 802.2 SNAP (0xaa, 0xaa, 0x03) with
+ * a SNAP OID of 0 (0x00, 0x00, 0x00) */
+static const u8 rfc1042sig[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+static int at76_tx(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+ struct net_device_stats *stats = &priv->stats;
+ int ret = 0;
+ int wlen;
+ int submit_len;
+ struct at76_tx_buffer *tx_buffer = priv->bulk_out_buffer;
+ struct ieee80211_hdr_3addr *i802_11_hdr =
+ (struct ieee80211_hdr_3addr *)tx_buffer->packet;
+ u8 *payload = i802_11_hdr->payload;
+ struct ethhdr *eh = (struct ethhdr *)skb->data;
+
+ if (netif_queue_stopped(netdev)) {
+ printk(KERN_ERR "%s: %s called while netdev is stopped\n",
+ netdev->name, __func__);
+ /* skip this packet */
+ dev_kfree_skb(skb);
+ return 0;
+ }
+
+ if (priv->tx_urb->status == -EINPROGRESS) {
+ printk(KERN_ERR "%s: %s called while tx urb is pending\n",
+ netdev->name, __func__);
+ /* skip this packet */
+ dev_kfree_skb(skb);
+ return 0;
+ }
+
+ if (skb->len < ETH_HLEN) {
+ printk(KERN_ERR "%s: %s: skb too short (%d)\n",
+ netdev->name, __func__, skb->len);
+ dev_kfree_skb(skb);
+ return 0;
+ }
+
+ at76_ledtrig_tx_activity(); /* tell ledtrigger we send a packet */
+
+ /* we can get rid of memcpy if we set netdev->hard_header_len to
+ reserve enough space, but we would need to keep the skb around */
+
+ if (ntohs(eh->h_proto) <= ETH_DATA_LEN) {
+ /* this is a 802.3 packet */
+ if (skb->len >= ETH_HLEN + sizeof(rfc1042sig)
+ && skb->data[ETH_HLEN] == rfc1042sig[0]
+ && skb->data[ETH_HLEN + 1] == rfc1042sig[1]) {
+ /* higher layer delivered SNAP header - keep it */
+ memcpy(payload, skb->data + ETH_HLEN,
+ skb->len - ETH_HLEN);
+ wlen = IEEE80211_3ADDR_LEN + skb->len - ETH_HLEN;
+ } else {
+ printk(KERN_ERR "%s: dropping non-SNAP 802.2 packet "
+ "(DSAP 0x%02x SSAP 0x%02x cntrl 0x%02x)\n",
+ priv->netdev->name, skb->data[ETH_HLEN],
+ skb->data[ETH_HLEN + 1],
+ skb->data[ETH_HLEN + 2]);
+ dev_kfree_skb(skb);
+ return 0;
+ }
+ } else {
+ /* add RFC 1042 header in front */
+ memcpy(payload, rfc1042sig, sizeof(rfc1042sig));
+ memcpy(payload + sizeof(rfc1042sig), &eh->h_proto,
+ skb->len - offsetof(struct ethhdr, h_proto));
+ wlen = IEEE80211_3ADDR_LEN + sizeof(rfc1042sig) + skb->len -
+ offsetof(struct ethhdr, h_proto);
+ }
+
+ /* make wireless header */
+ i802_11_hdr->frame_ctl =
+ cpu_to_le16(IEEE80211_FTYPE_DATA |
+ (priv->wep_enabled ? IEEE80211_FCTL_PROTECTED : 0) |
+ (priv->iw_mode ==
+ IW_MODE_INFRA ? IEEE80211_FCTL_TODS : 0));
+
+ if (priv->iw_mode == IW_MODE_ADHOC) {
+ memcpy(i802_11_hdr->addr1, eh->h_dest, ETH_ALEN);
+ memcpy(i802_11_hdr->addr2, eh->h_source, ETH_ALEN);
+ memcpy(i802_11_hdr->addr3, priv->bssid, ETH_ALEN);
+ } else if (priv->iw_mode == IW_MODE_INFRA) {
+ memcpy(i802_11_hdr->addr1, priv->bssid, ETH_ALEN);
+ memcpy(i802_11_hdr->addr2, eh->h_source, ETH_ALEN);
+ memcpy(i802_11_hdr->addr3, eh->h_dest, ETH_ALEN);
+ }
+
+ i802_11_hdr->duration_id = cpu_to_le16(0);
+ i802_11_hdr->seq_ctl = cpu_to_le16(0);
+
+ /* setup 'Atmel' header */
+ tx_buffer->wlength = cpu_to_le16(wlen);
+ tx_buffer->tx_rate = priv->txrate;
+ /* for broadcast destination addresses, the firmware 0.100.x
+ seems to choose the highest rate set with CMD_STARTUP in
+ basic_rate_set replacing this value */
+
+ memset(tx_buffer->reserved, 0, sizeof(tx_buffer->reserved));
+
+ tx_buffer->padding = at76_calc_padding(wlen);
+ submit_len = wlen + AT76_TX_HDRLEN + tx_buffer->padding;
+
+ at76_dbg(DBG_TX_DATA_CONTENT, "%s skb->data %s", priv->netdev->name,
+ hex2str(skb->data, 32));
+ at76_dbg(DBG_TX_DATA, "%s tx: wlen 0x%x pad 0x%x rate %d hdr %s",
+ priv->netdev->name,
+ le16_to_cpu(tx_buffer->wlength),
+ tx_buffer->padding, tx_buffer->tx_rate,
+ hex2str(i802_11_hdr, sizeof(*i802_11_hdr)));
+ at76_dbg(DBG_TX_DATA_CONTENT, "%s payload %s", priv->netdev->name,
+ hex2str(payload, 48));
+
+ /* send stuff */
+ netif_stop_queue(netdev);
+ netdev->trans_start = jiffies;
+
+ usb_fill_bulk_urb(priv->tx_urb, priv->udev, priv->tx_pipe, tx_buffer,
+ submit_len, at76_tx_callback, priv);
+ ret = usb_submit_urb(priv->tx_urb, GFP_ATOMIC);
+ if (ret) {
+ stats->tx_errors++;
+ printk(KERN_ERR "%s: error in tx submit urb: %d\n",
+ netdev->name, ret);
+ if (ret == -EINVAL)
+ printk(KERN_ERR
+ "%s: -EINVAL: tx urb %p hcpriv %p complete %p\n",
+ priv->netdev->name, priv->tx_urb,
+ priv->tx_urb->hcpriv, priv->tx_urb->complete);
+ } else {
+ stats->tx_bytes += skb->len;
+ dev_kfree_skb(skb);
+ }
+
+ return ret;
+}
+
+static void at76_tx_timeout(struct net_device *netdev)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+
+ if (!priv)
+ return;
+ dev_warn(&netdev->dev, "tx timeout.");
+
+ usb_unlink_urb(priv->tx_urb);
+ priv->stats.tx_errors++;
+}
+
+static int at76_submit_rx_urb(struct at76_priv *priv)
+{
+ int ret;
+ int size;
+ struct sk_buff *skb = priv->rx_skb;
+
+ if (!priv->rx_urb) {
+ printk(KERN_ERR "%s: %s: priv->rx_urb is NULL\n",
+ priv->netdev->name, __func__);
+ return -EFAULT;
+ }
+
+ if (!skb) {
+ skb = dev_alloc_skb(sizeof(struct at76_rx_buffer));
+ if (!skb) {
+ printk(KERN_ERR "%s: cannot allocate rx skbuff\n",
+ priv->netdev->name);
+ ret = -ENOMEM;
+ goto exit;
+ }
+ priv->rx_skb = skb;
+ } else {
+ skb_push(skb, skb_headroom(skb));
+ skb_trim(skb, 0);
+ }
+
+ size = skb_tailroom(skb);
+ usb_fill_bulk_urb(priv->rx_urb, priv->udev, priv->rx_pipe,
+ skb_put(skb, size), size, at76_rx_callback, priv);
+ ret = usb_submit_urb(priv->rx_urb, GFP_ATOMIC);
+ if (ret < 0) {
+ if (ret == -ENODEV)
+ at76_dbg(DBG_DEVSTART,
+ "usb_submit_urb returned -ENODEV");
+ else
+ printk(KERN_ERR "%s: rx, usb_submit_urb failed: %d\n",
+ priv->netdev->name, ret);
+ }
+
+exit:
+ if (ret < 0 && ret != -ENODEV)
+ printk(KERN_ERR "%s: cannot submit rx urb - please unload the "
+ "driver and/or power cycle the device\n",
+ priv->netdev->name);
+
+ return ret;
+}
+
+static int at76_open(struct net_device *netdev)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+ int ret = 0;
+
+ at76_dbg(DBG_PROC_ENTRY, "%s(): entry", __func__);
+
+ if (mutex_lock_interruptible(&priv->mtx))
+ return -EINTR;
+
+ /* if netdev->dev_addr != priv->mac_addr we must
+ set the mac address in the device ! */
+ if (compare_ether_addr(netdev->dev_addr, priv->mac_addr)) {
+ if (at76_add_mac_address(priv, netdev->dev_addr) >= 0)
+ at76_dbg(DBG_PROGRESS, "%s: set new MAC addr %s",
+ netdev->name, mac2str(netdev->dev_addr));
+ }
+
+ priv->scan_state = SCAN_IDLE;
+ priv->last_scan = jiffies;
+
+ ret = at76_submit_rx_urb(priv);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: open: submit_rx_urb failed: %d\n",
+ netdev->name, ret);
+ goto error;
+ }
+
+ schedule_delayed_work(&priv->dwork_restart, 0);
+
+ at76_dbg(DBG_PROC_ENTRY, "%s(): end", __func__);
+error:
+ mutex_unlock(&priv->mtx);
+ return ret < 0 ? ret : 0;
+}
+
+static int at76_stop(struct net_device *netdev)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+
+ at76_dbg(DBG_DEVSTART, "%s: ENTER", __func__);
+
+ if (mutex_lock_interruptible(&priv->mtx))
+ return -EINTR;
+
+ at76_quiesce(priv);
+
+ if (!priv->device_unplugged) {
+ /* We are called by "ifconfig ethX down", not because the
+ * device is not available anymore. */
+ at76_set_radio(priv, 0);
+
+ /* We unlink rx_urb because at76_open() re-submits it.
+ * If unplugged, at76_delete_device() takes care of it. */
+ usb_kill_urb(priv->rx_urb);
+ }
+
+ /* free the bss_list */
+ at76_free_bss_list(priv);
+
+ mutex_unlock(&priv->mtx);
+ at76_dbg(DBG_DEVSTART, "%s: EXIT", __func__);
+
+ return 0;
+}
+
+static void at76_ethtool_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *info)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+
+ strncpy(info->driver, DRIVER_NAME, sizeof(info->driver));
+ strncpy(info->version, DRIVER_VERSION, sizeof(info->version));
+
+ usb_make_path(priv->udev, info->bus_info, sizeof(info->bus_info));
+
+ snprintf(info->fw_version, sizeof(info->fw_version), "%d.%d.%d-%d",
+ priv->fw_version.major, priv->fw_version.minor,
+ priv->fw_version.patch, priv->fw_version.build);
+}
+
+static u32 at76_ethtool_get_link(struct net_device *netdev)
+{
+ struct at76_priv *priv = netdev_priv(netdev);
+ return priv->mac_state == MAC_CONNECTED;
+}
+
+static struct ethtool_ops at76_ethtool_ops = {
+ .get_drvinfo = at76_ethtool_get_drvinfo,
+ .get_link = at76_ethtool_get_link,
+};
+
+/* Download external firmware */
+static int at76_load_external_fw(struct usb_device *udev, struct fwentry *fwe)
+{
+ int ret;
+ int op_mode;
+ int blockno = 0;
+ int bsize;
+ u8 *block;
+ u8 *buf = fwe->extfw;
+ int size = fwe->extfw_size;
+
+ if (!buf || !size)
+ return -ENOENT;
+
+ op_mode = at76_get_op_mode(udev);
+ at76_dbg(DBG_DEVSTART, "opmode %d", op_mode);
+
+ if (op_mode != OPMODE_NORMAL_NIC_WITHOUT_FLASH) {
+ dev_printk(KERN_ERR, &udev->dev, "unexpected opmode %d\n",
+ op_mode);
+ return -EINVAL;
+ }
+
+ block = kmalloc(FW_BLOCK_SIZE, GFP_KERNEL);
+ if (!block)
+ return -ENOMEM;
+
+ at76_dbg(DBG_DEVSTART, "downloading external firmware");
+
+ /* for fw >= 0.100, the device needs an extra empty block */
+ do {
+ bsize = min_t(int, size, FW_BLOCK_SIZE);
+ memcpy(block, buf, bsize);
+ at76_dbg(DBG_DEVSTART,
+ "ext fw, size left = %5d, bsize = %4d, blockno = %2d",
+ size, bsize, blockno);
+ ret = at76_load_ext_fw_block(udev, blockno, block, bsize);
+ if (ret != bsize) {
+ dev_printk(KERN_ERR, &udev->dev,
+ "loading %dth firmware block failed: %d\n",
+ blockno, ret);
+ goto exit;
+ }
+ buf += bsize;
+ size -= bsize;
+ blockno++;
+ } while (bsize > 0);
+
+ if (at76_is_505a(fwe->board_type)) {
+ at76_dbg(DBG_DEVSTART, "200 ms delay for 505a");
+ schedule_timeout_interruptible(HZ / 5 + 1);
+ }
+
+exit:
+ kfree(block);
+ if (ret < 0)
+ dev_printk(KERN_ERR, &udev->dev,
+ "downloading external firmware failed: %d\n", ret);
+ return ret;
+}
+
+/* Download internal firmware */
+static int at76_load_internal_fw(struct usb_device *udev, struct fwentry *fwe)
+{
+ int ret;
+ int need_remap = !at76_is_505a(fwe->board_type);
+
+ ret = at76_usbdfu_download(udev, fwe->intfw, fwe->intfw_size,
+ need_remap ? 0 : 2 * HZ);
+
+ if (ret < 0) {
+ dev_printk(KERN_ERR, &udev->dev,
+ "downloading internal fw failed with %d\n", ret);
+ goto exit;
+ }
+
+ at76_dbg(DBG_DEVSTART, "sending REMAP");
+
+ /* no REMAP for 505A (see SF driver) */
+ if (need_remap) {
+ ret = at76_remap(udev);
+ if (ret < 0) {
+ dev_printk(KERN_ERR, &udev->dev,
+ "sending REMAP failed with %d\n", ret);
+ goto exit;
+ }
+ }
+
+ at76_dbg(DBG_DEVSTART, "sleeping for 2 seconds");
+ schedule_timeout_interruptible(2 * HZ + 1);
+ usb_reset_device(udev);
+
+exit:
+ return ret;
+}
+
+static int at76_match_essid(struct at76_priv *priv, struct bss_info *ptr)
+{
+ /* common criteria for both modi */
+
+ int ret = (priv->essid_size == 0 /* ANY ssid */ ||
+ (priv->essid_size == ptr->ssid_len &&
+ !memcmp(priv->essid, ptr->ssid, ptr->ssid_len)));
+ if (!ret)
+ at76_dbg(DBG_BSS_MATCH,
+ "%s bss table entry %p: essid didn't match",
+ priv->netdev->name, ptr);
+ return ret;
+}
+
+static inline int at76_match_mode(struct at76_priv *priv, struct bss_info *ptr)
+{
+ int ret;
+
+ if (priv->iw_mode == IW_MODE_ADHOC)
+ ret = ptr->capa & WLAN_CAPABILITY_IBSS;
+ else
+ ret = ptr->capa & WLAN_CAPABILITY_ESS;
+ if (!ret)
+ at76_dbg(DBG_BSS_MATCH,
+ "%s bss table entry %p: mode didn't match",
+ priv->netdev->name, ptr);
+ return ret;
+}
+
+static int at76_match_rates(struct at76_priv *priv, struct bss_info *ptr)
+{
+ int i;
+
+ for (i = 0; i < ptr->rates_len; i++) {
+ u8 rate = ptr->rates[i];
+
+ if (!(rate & 0x80))
+ continue;
+
+ /* this is a basic rate we have to support
+ (see IEEE802.11, ch. 7.3.2.2) */
+ if (rate != (0x80 | hw_rates[0])
+ && rate != (0x80 | hw_rates[1])
+ && rate != (0x80 | hw_rates[2])
+ && rate != (0x80 | hw_rates[3])) {
+ at76_dbg(DBG_BSS_MATCH,
+ "%s: bss table entry %p: basic rate %02x not "
+ "supported", priv->netdev->name, ptr, rate);
+ return 0;
+ }
+ }
+
+ /* if we use short preamble, the bss must support it */
+ if (priv->preamble_type == PREAMBLE_TYPE_SHORT &&
+ !(ptr->capa & WLAN_CAPABILITY_SHORT_PREAMBLE)) {
+ at76_dbg(DBG_BSS_MATCH,
+ "%s: %p does not support short preamble",
+ priv->netdev->name, ptr);
+ return 0;
+ } else
+ return 1;
+}
+
+static inline int at76_match_wep(struct at76_priv *priv, struct bss_info *ptr)
+{
+ if (!priv->wep_enabled && ptr->capa & WLAN_CAPABILITY_PRIVACY) {
+ /* we have disabled WEP, but the BSS signals privacy */
+ at76_dbg(DBG_BSS_MATCH,
+ "%s: bss table entry %p: requires encryption",
+ priv->netdev->name, ptr);
+ return 0;
+ }
+ /* otherwise if the BSS does not signal privacy it may well
+ accept encrypted packets from us ... */
+ return 1;
+}
+
+static inline int at76_match_bssid(struct at76_priv *priv, struct bss_info *ptr)
+{
+ if (!priv->wanted_bssid_valid ||
+ !compare_ether_addr(ptr->bssid, priv->wanted_bssid))
+ return 1;
+
+ at76_dbg(DBG_BSS_MATCH,
+ "%s: requested bssid - %s does not match",
+ priv->netdev->name, mac2str(priv->wanted_bssid));
+ at76_dbg(DBG_BSS_MATCH,
+ " AP bssid - %s of bss table entry %p",
+ mac2str(ptr->bssid), ptr);
+ return 0;
+}
+
+/**
+ * at76_match_bss - try to find a matching bss in priv->bss
+ *
+ * last - last bss tried
+ *
+ * last == NULL signals a new round starting with priv->bss_list.next
+ * this function must be called inside an acquired priv->bss_list_spinlock
+ * otherwise the timeout on bss may remove the newly chosen entry
+ */
+static struct bss_info *at76_match_bss(struct at76_priv *priv,
+ struct bss_info *last)
+{
+ struct bss_info *ptr = NULL;
+ struct list_head *curr;
+
+ curr = last ? last->list.next : priv->bss_list.next;
+ while (curr != &priv->bss_list) {
+ ptr = list_entry(curr, struct bss_info, list);
+ if (at76_match_essid(priv, ptr) && at76_match_mode(priv, ptr)
+ && at76_match_wep(priv, ptr) && at76_match_rates(priv, ptr)
+ && at76_match_bssid(priv, ptr))
+ break;
+ curr = curr->next;
+ }
+
+ if (curr == &priv->bss_list)
+ ptr = NULL;
+ /* otherwise ptr points to the struct bss_info we have chosen */
+
+ at76_dbg(DBG_BSS_TABLE, "%s %s: returned %p", priv->netdev->name,
+ __func__, ptr);
+ return ptr;
+}
+
+/* Start joining a matching BSS, or create own IBSS */
+static void at76_work_join(struct work_struct *work)
+{
+ struct at76_priv *priv = container_of(work, struct at76_priv,
+ work_join);
+ int ret;
+ unsigned long flags;
+
+ mutex_lock(&priv->mtx);
+
+ WARN_ON(priv->mac_state != MAC_JOINING);
+ if (priv->mac_state != MAC_JOINING)
+ goto exit;
+
+ /* secure the access to priv->curr_bss ! */
+ spin_lock_irqsave(&priv->bss_list_spinlock, flags);
+ priv->curr_bss = at76_match_bss(priv, priv->curr_bss);
+ spin_unlock_irqrestore(&priv->bss_list_spinlock, flags);
+
+ if (!priv->curr_bss) {
+ /* here we haven't found a matching (i)bss ... */
+ if (priv->iw_mode == IW_MODE_ADHOC) {
+ at76_set_mac_state(priv, MAC_OWN_IBSS);
+ at76_start_ibss(priv);
+ goto exit;
+ }
+ /* haven't found a matching BSS in infra mode - try again */
+ at76_set_mac_state(priv, MAC_SCANNING);
+ schedule_work(&priv->work_start_scan);
+ goto exit;
+ }
+
+ ret = at76_join_bss(priv, priv->curr_bss);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: join_bss failed with %d\n",
+ priv->netdev->name, ret);
+ goto exit;
+ }
+
+ ret = at76_wait_completion(priv, CMD_JOIN);
+ if (ret != CMD_STATUS_COMPLETE) {
+ if (ret != CMD_STATUS_TIME_OUT)
+ printk(KERN_ERR "%s: join_bss completed with %d\n",
+ priv->netdev->name, ret);
+ else
+ printk(KERN_INFO "%s: join_bss ssid %s timed out\n",
+ priv->netdev->name,
+ mac2str(priv->curr_bss->bssid));
+
+ /* retry next BSS immediately */
+ schedule_work(&priv->work_join);
+ goto exit;
+ }
+
+ /* here we have joined the (I)BSS */
+ if (priv->iw_mode == IW_MODE_ADHOC) {
+ struct bss_info *bptr = priv->curr_bss;
+ at76_set_mac_state(priv, MAC_CONNECTED);
+ /* get ESSID, BSSID and channel for priv->curr_bss */
+ priv->essid_size = bptr->ssid_len;
+ memcpy(priv->essid, bptr->ssid, bptr->ssid_len);
+ memcpy(priv->bssid, bptr->bssid, ETH_ALEN);
+ priv->channel = bptr->channel;
+ at76_iwevent_bss_connect(priv->netdev, bptr->bssid);
+ netif_carrier_on(priv->netdev);
+ netif_start_queue(priv->netdev);
+ /* just to be sure */
+ cancel_delayed_work(&priv->dwork_get_scan);
+ cancel_delayed_work(&priv->dwork_auth);
+ cancel_delayed_work(&priv->dwork_assoc);
+ } else {
+ /* send auth req */
+ priv->retries = AUTH_RETRIES;
+ at76_set_mac_state(priv, MAC_AUTH);
+ at76_auth_req(priv, priv->curr_bss, 1, NULL);
+ at76_dbg(DBG_MGMT_TIMER,
+ "%s:%d: starting mgmt_timer + HZ", __func__, __LINE__);
+ schedule_delayed_work(&priv->dwork_auth, AUTH_TIMEOUT);
+ }
+
+exit:
+ mutex_unlock(&priv->mtx);
+}
+
+/* Reap scan results */
+static void at76_dwork_get_scan(struct work_struct *work)
+{
+ int status;
+ int ret;
+ struct at76_priv *priv = container_of(work, struct at76_priv,
+ dwork_get_scan.work);
+
+ mutex_lock(&priv->mtx);
+ WARN_ON(priv->mac_state != MAC_SCANNING);
+ if (priv->mac_state != MAC_SCANNING)
+ goto exit;
+
+ status = at76_get_cmd_status(priv->udev, CMD_SCAN);
+ if (status < 0) {
+ printk(KERN_ERR "%s: %s: at76_get_cmd_status failed with %d\n",
+ priv->netdev->name, __func__, status);
+ status = CMD_STATUS_IN_PROGRESS;
+ /* INFO: Hope it was a one off error - if not, scanning
+ further down the line and stop this cycle */
+ }
+ at76_dbg(DBG_PROGRESS,
+ "%s %s: got cmd_status %d (state %s, need_any %d)",
+ priv->netdev->name, __func__, status,
+ mac_states[priv->mac_state], priv->scan_need_any);
+
+ if (status != CMD_STATUS_COMPLETE) {
+ if ((status != CMD_STATUS_IN_PROGRESS) &&
+ (status != CMD_STATUS_IDLE))
+ printk(KERN_ERR "%s: %s: Bad scan status: %s\n",
+ priv->netdev->name, __func__,
+ at76_get_cmd_status_string(status));
+
+ /* the first cmd status after scan start is always a IDLE ->
+ start the timer to poll again until COMPLETED */
+ at76_dbg(DBG_MGMT_TIMER,
+ "%s:%d: starting mgmt_timer for %d ticks",
+ __func__, __LINE__, SCAN_POLL_INTERVAL);
+ schedule_delayed_work(&priv->dwork_get_scan,
+ SCAN_POLL_INTERVAL);
+ goto exit;
+ }
+
+ if (at76_debug & DBG_BSS_TABLE)
+ at76_dump_bss_table(priv);
+
+ if (priv->scan_need_any) {
+ ret = at76_start_scan(priv, 0);
+ if (ret < 0)
+ printk(KERN_ERR
+ "%s: %s: start_scan (ANY) failed with %d\n",
+ priv->netdev->name, __func__, ret);
+ at76_dbg(DBG_MGMT_TIMER,
+ "%s:%d: starting mgmt_timer for %d ticks", __func__,
+ __LINE__, SCAN_POLL_INTERVAL);
+ schedule_delayed_work(&priv->dwork_get_scan,
+ SCAN_POLL_INTERVAL);
+ priv->scan_need_any = 0;
+ } else {
+ priv->scan_state = SCAN_COMPLETED;
+ /* report the end of scan to user space */
+ at76_iwevent_scan_complete(priv->netdev);
+ at76_set_mac_state(priv, MAC_JOINING);
+ schedule_work(&priv->work_join);
+ }
+
+exit:
+ mutex_unlock(&priv->mtx);
+}
+
+/* Handle loss of beacons from the AP */
+static void at76_dwork_beacon(struct work_struct *work)
+{
+ struct at76_priv *priv = container_of(work, struct at76_priv,
+ dwork_beacon.work);
+
+ mutex_lock(&priv->mtx);
+ if (priv->mac_state != MAC_CONNECTED || priv->iw_mode != IW_MODE_INFRA)
+ goto exit;
+
+ /* We haven't received any beacons from out AP for BEACON_TIMEOUT */
+ printk(KERN_INFO "%s: lost beacon bssid %s\n",
+ priv->netdev->name, mac2str(priv->curr_bss->bssid));
+
+ netif_carrier_off(priv->netdev);
+ netif_stop_queue(priv->netdev);
+ at76_iwevent_bss_disconnect(priv->netdev);
+ at76_set_mac_state(priv, MAC_SCANNING);
+ schedule_work(&priv->work_start_scan);
+
+exit:
+ mutex_unlock(&priv->mtx);
+}
+
+/* Handle authentication response timeout */
+static void at76_dwork_auth(struct work_struct *work)
+{
+ struct at76_priv *priv = container_of(work, struct at76_priv,
+ dwork_auth.work);
+
+ mutex_lock(&priv->mtx);
+ WARN_ON(priv->mac_state != MAC_AUTH);
+ if (priv->mac_state != MAC_AUTH)
+ goto exit;
+
+ at76_dbg(DBG_PROGRESS, "%s: authentication response timeout",
+ priv->netdev->name);
+
+ if (priv->retries-- >= 0) {
+ at76_auth_req(priv, priv->curr_bss, 1, NULL);
+ at76_dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ",
+ __func__, __LINE__);
+ schedule_delayed_work(&priv->dwork_auth, AUTH_TIMEOUT);
+ } else {
+ /* try to get next matching BSS */
+ at76_set_mac_state(priv, MAC_JOINING);
+ schedule_work(&priv->work_join);
+ }
+
+exit:
+ mutex_unlock(&priv->mtx);
+}
+
+/* Handle association response timeout */
+static void at76_dwork_assoc(struct work_struct *work)
+{
+ struct at76_priv *priv = container_of(work, struct at76_priv,
+ dwork_assoc.work);
+
+ mutex_lock(&priv->mtx);
+ WARN_ON(priv->mac_state != MAC_ASSOC);
+ if (priv->mac_state != MAC_ASSOC)
+ goto exit;
+
+ at76_dbg(DBG_PROGRESS, "%s: association response timeout",
+ priv->netdev->name);
+
+ if (priv->retries-- >= 0) {
+ at76_assoc_req(priv, priv->curr_bss);
+ at76_dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ",
+ __func__, __LINE__);
+ schedule_delayed_work(&priv->dwork_assoc, ASSOC_TIMEOUT);
+ } else {
+ /* try to get next matching BSS */
+ at76_set_mac_state(priv, MAC_JOINING);
+ schedule_work(&priv->work_join);
+ }
+
+exit:
+ mutex_unlock(&priv->mtx);
+}
+
+/* Read new bssid in ad-hoc mode */
+static void at76_work_new_bss(struct work_struct *work)
+{
+ struct at76_priv *priv = container_of(work, struct at76_priv,
+ work_new_bss);
+ int ret;
+ struct mib_mac_mgmt mac_mgmt;
+
+ mutex_lock(&priv->mtx);
+
+ ret = at76_get_mib(priv->udev, MIB_MAC_MGMT, &mac_mgmt,
+ sizeof(struct mib_mac_mgmt));
+ if (ret < 0) {
+ printk(KERN_ERR "%s: at76_get_mib failed: %d\n",
+ priv->netdev->name, ret);
+ goto exit;
+ }
+
+ at76_dbg(DBG_PROGRESS, "ibss_change = 0x%2x", mac_mgmt.ibss_change);
+ memcpy(priv->bssid, mac_mgmt.current_bssid, ETH_ALEN);
+ at76_dbg(DBG_PROGRESS, "using BSSID %s", mac2str(priv->bssid));
+
+ at76_iwevent_bss_connect(priv->netdev, priv->bssid);
+
+ priv->mib_buf.type = MIB_MAC_MGMT;
+ priv->mib_buf.size = 1;
+ priv->mib_buf.index = offsetof(struct mib_mac_mgmt, ibss_change);
+ priv->mib_buf.data.byte = 0;
+
+ ret = at76_set_mib(priv, &priv->mib_buf);
+ if (ret < 0)
+ printk(KERN_ERR "%s: set_mib (ibss change ok) failed: %d\n",
+ priv->netdev->name, ret);
+
+exit:
+ mutex_unlock(&priv->mtx);
+}
+
+static int at76_startup_device(struct at76_priv *priv)
+{
+ struct at76_card_config *ccfg = &priv->card_config;
+ int ret;
+
+ at76_dbg(DBG_PARAMS,
+ "%s param: ssid %.*s (%s) mode %s ch %d wep %s key %d "
+ "keylen %d", priv->netdev->name, priv->essid_size, priv->essid,
+ hex2str(priv->essid, IW_ESSID_MAX_SIZE),
+ priv->iw_mode == IW_MODE_ADHOC ? "adhoc" : "infra",
+ priv->channel, priv->wep_enabled ? "enabled" : "disabled",
+ priv->wep_key_id, priv->wep_keys_len[priv->wep_key_id]);
+ at76_dbg(DBG_PARAMS,
+ "%s param: preamble %s rts %d retry %d frag %d "
+ "txrate %s auth_mode %d", priv->netdev->name,
+ preambles[priv->preamble_type], priv->rts_threshold,
+ priv->short_retry_limit, priv->frag_threshold,
+ priv->txrate == TX_RATE_1MBIT ? "1MBit" : priv->txrate ==
+ TX_RATE_2MBIT ? "2MBit" : priv->txrate ==
+ TX_RATE_5_5MBIT ? "5.5MBit" : priv->txrate ==
+ TX_RATE_11MBIT ? "11MBit" : priv->txrate ==
+ TX_RATE_AUTO ? "auto" : "<invalid>", priv->auth_mode);
+ at76_dbg(DBG_PARAMS,
+ "%s param: pm_mode %d pm_period %d auth_mode %s "
+ "scan_times %d %d scan_mode %s",
+ priv->netdev->name, priv->pm_mode, priv->pm_period,
+ priv->auth_mode == WLAN_AUTH_OPEN ? "open" : "shared_secret",
+ priv->scan_min_time, priv->scan_max_time,
+ priv->scan_mode == SCAN_TYPE_ACTIVE ? "active" : "passive");
+
+ memset(ccfg, 0, sizeof(struct at76_card_config));
+ ccfg->promiscuous_mode = 0;
+ ccfg->short_retry_limit = priv->short_retry_limit;
+
+ if (priv->wep_enabled) {
+ if (priv->wep_keys_len[priv->wep_key_id] > WEP_SMALL_KEY_LEN)
+ ccfg->encryption_type = 2;
+ else
+ ccfg->encryption_type = 1;
+
+ /* jal: always exclude unencrypted if WEP is active */
+ ccfg->exclude_unencrypted = 1;
+ } else {
+ ccfg->exclude_unencrypted = 0;
+ ccfg->encryption_type = 0;
+ }
+
+ ccfg->rts_threshold = cpu_to_le16(priv->rts_threshold);
+ ccfg->fragmentation_threshold = cpu_to_le16(priv->frag_threshold);
+
+ memcpy(ccfg->basic_rate_set, hw_rates, 4);
+ /* jal: really needed, we do a set_mib for autorate later ??? */
+ ccfg->auto_rate_fallback = (priv->txrate == TX_RATE_AUTO ? 1 : 0);
+ ccfg->channel = priv->channel;
+ ccfg->privacy_invoked = priv->wep_enabled;
+ memcpy(ccfg->current_ssid, priv->essid, IW_ESSID_MAX_SIZE);
+ ccfg->ssid_len = priv->essid_size;
+
+ ccfg->wep_default_key_id = priv->wep_key_id;
+ memcpy(ccfg->wep_default_key_value, priv->wep_keys, 4 * WEP_KEY_LEN);
+
+ ccfg->short_preamble = priv->preamble_type;
+ ccfg->beacon_period = cpu_to_le16(priv->beacon_period);
+
+ ret = at76_set_card_command(priv->udev, CMD_STARTUP, &priv->card_config,
+ sizeof(struct at76_card_config));
+ if (ret < 0) {
+ printk(KERN_ERR "%s: at76_set_card_command failed: %d\n",
+ priv->netdev->name, ret);
+ return ret;
+ }
+
+ at76_wait_completion(priv, CMD_STARTUP);
+
+ /* remove BSSID from previous run */
+ memset(priv->bssid, 0, ETH_ALEN);
+
+ if (at76_set_radio(priv, 1) == 1)
+ at76_wait_completion(priv, CMD_RADIO_ON);
+
+ ret = at76_set_preamble(priv, priv->preamble_type);
+ if (ret < 0)
+ return ret;
+
+ ret = at76_set_frag(priv, priv->frag_threshold);
+ if (ret < 0)
+ return ret;
+
+ ret = at76_set_rts(priv, priv->rts_threshold);
+ if (ret < 0)
+ return ret;
+
+ ret = at76_set_autorate_fallback(priv,
+ priv->txrate == TX_RATE_AUTO ? 1 : 0);
+ if (ret < 0)
+ return ret;
+
+ ret = at76_set_pm_mode(priv);
+ if (ret < 0)
+ return ret;
+
+ if (at76_debug & DBG_MIB) {
+ at76_dump_mib_mac(priv);
+ at76_dump_mib_mac_addr(priv);
+ at76_dump_mib_mac_mgmt(priv);
+ at76_dump_mib_mac_wep(priv);
+ at76_dump_mib_mdomain(priv);
+ at76_dump_mib_phy(priv);
+ at76_dump_mib_local(priv);
+ }
+
+ return 0;
+}
+
+/* Restart the interface */
+static void at76_dwork_restart(struct work_struct *work)
+{
+ struct at76_priv *priv = container_of(work, struct at76_priv,
+ dwork_restart.work);
+
+ mutex_lock(&priv->mtx);
+
+ netif_carrier_off(priv->netdev); /* stop netdev watchdog */
+ netif_stop_queue(priv->netdev); /* stop tx data packets */
+
+ at76_startup_device(priv);
+
+ if (priv->iw_mode != IW_MODE_MONITOR) {
+ priv->netdev->type = ARPHRD_ETHER;
+ at76_set_mac_state(priv, MAC_SCANNING);
+ schedule_work(&priv->work_start_scan);
+ } else {
+ priv->netdev->type = ARPHRD_IEEE80211_RADIOTAP;
+ at76_start_monitor(priv);
+ }
+
+ mutex_unlock(&priv->mtx);
+}
+
+/* Initiate scanning */
+static void at76_work_start_scan(struct work_struct *work)
+{
+ struct at76_priv *priv = container_of(work, struct at76_priv,
+ work_start_scan);
+ int ret;
+
+ mutex_lock(&priv->mtx);
+
+ WARN_ON(priv->mac_state != MAC_SCANNING);
+ if (priv->mac_state != MAC_SCANNING)
+ goto exit;
+
+ /* only clear the bss list when a scan is actively initiated,
+ * otherwise simply rely on at76_bss_list_timeout */
+ if (priv->scan_state == SCAN_IN_PROGRESS) {
+ at76_free_bss_list(priv);
+ priv->scan_need_any = 1;
+ } else
+ priv->scan_need_any = 0;
+
+ ret = at76_start_scan(priv, 1);
+
+ if (ret < 0)
+ printk(KERN_ERR "%s: %s: start_scan failed with %d\n",
+ priv->netdev->name, __func__, ret);
+ else {
+ at76_dbg(DBG_MGMT_TIMER,
+ "%s:%d: starting mgmt_timer for %d ticks",
+ __func__, __LINE__, SCAN_POLL_INTERVAL);
+ schedule_delayed_work(&priv->dwork_get_scan,
+ SCAN_POLL_INTERVAL);
+ }
+
+exit:
+ mutex_unlock(&priv->mtx);
+}
+
+/* Enable or disable promiscuous mode */
+static void at76_work_set_promisc(struct work_struct *work)
+{
+ struct at76_priv *priv = container_of(work, struct at76_priv,
+ work_set_promisc);
+ int ret = 0;
+
+ mutex_lock(&priv->mtx);
+
+ priv->mib_buf.type = MIB_LOCAL;
+ priv->mib_buf.size = 1;
+ priv->mib_buf.index = offsetof(struct mib_local, promiscuous_mode);
+ priv->mib_buf.data.byte = priv->promisc ? 1 : 0;
+
+ ret = at76_set_mib(priv, &priv->mib_buf);
+ if (ret < 0)
+ printk(KERN_ERR "%s: set_mib (promiscuous_mode) failed: %d\n",
+ priv->netdev->name, ret);
+
+ mutex_unlock(&priv->mtx);
+}
+
+/* Submit Rx urb back to the device */
+static void at76_work_submit_rx(struct work_struct *work)
+{
+ struct at76_priv *priv = container_of(work, struct at76_priv,
+ work_submit_rx);
+
+ mutex_lock(&priv->mtx);
+ at76_submit_rx_urb(priv);
+ mutex_unlock(&priv->mtx);
+}
+
+/* We got an association response */
+static void at76_rx_mgmt_assoc(struct at76_priv *priv,
+ struct at76_rx_buffer *buf)
+{
+ struct ieee80211_assoc_response *resp =
+ (struct ieee80211_assoc_response *)buf->packet;
+ u16 assoc_id = le16_to_cpu(resp->aid);
+ u16 status = le16_to_cpu(resp->status);
+
+ at76_dbg(DBG_RX_MGMT, "%s: rx AssocResp bssid %s capa 0x%04x status "
+ "0x%04x assoc_id 0x%04x rates %s", priv->netdev->name,
+ mac2str(resp->header.addr3), le16_to_cpu(resp->capability),
+ status, assoc_id, hex2str(resp->info_element->data,
+ resp->info_element->len));
+
+ if (priv->mac_state != MAC_ASSOC) {
+ printk(KERN_INFO "%s: AssocResp in state %s ignored\n",
+ priv->netdev->name, mac_states[priv->mac_state]);
+ return;
+ }
+
+ BUG_ON(!priv->curr_bss);
+
+ cancel_delayed_work(&priv->dwork_assoc);
+ if (status == WLAN_STATUS_SUCCESS) {
+ struct bss_info *ptr = priv->curr_bss;
+ priv->assoc_id = assoc_id & 0x3fff;
+ /* update iwconfig params */
+ memcpy(priv->bssid, ptr->bssid, ETH_ALEN);
+ memcpy(priv->essid, ptr->ssid, ptr->ssid_len);
+ priv->essid_size = ptr->ssid_len;
+ priv->channel = ptr->channel;
+ schedule_work(&priv->work_assoc_done);
+ } else {
+ at76_set_mac_state(priv, MAC_JOINING);
+ schedule_work(&priv->work_join);
+ }
+}
+
+/* Process disassociation request from the AP */
+static void at76_rx_mgmt_disassoc(struct at76_priv *priv,
+ struct at76_rx_buffer *buf)
+{
+ struct ieee80211_disassoc *resp =
+ (struct ieee80211_disassoc *)buf->packet;
+ struct ieee80211_hdr_3addr *mgmt = &resp->header;
+
+ at76_dbg(DBG_RX_MGMT,
+ "%s: rx DisAssoc bssid %s reason 0x%04x destination %s",
+ priv->netdev->name, mac2str(mgmt->addr3),
+ le16_to_cpu(resp->reason), mac2str(mgmt->addr1));
+
+ /* We are not connected, ignore */
+ if (priv->mac_state == MAC_SCANNING || priv->mac_state == MAC_INIT
+ || !priv->curr_bss)
+ return;
+
+ /* Not our BSSID, ignore */
+ if (compare_ether_addr(mgmt->addr3, priv->curr_bss->bssid))
+ return;
+
+ /* Not for our STA and not broadcast, ignore */
+ if (compare_ether_addr(priv->netdev->dev_addr, mgmt->addr1)
+ && !is_broadcast_ether_addr(mgmt->addr1))
+ return;
+
+ if (priv->mac_state != MAC_ASSOC && priv->mac_state != MAC_CONNECTED
+ && priv->mac_state != MAC_JOINING) {
+ printk(KERN_INFO "%s: DisAssoc in state %s ignored\n",
+ priv->netdev->name, mac_states[priv->mac_state]);
+ return;
+ }
+
+ if (priv->mac_state == MAC_CONNECTED) {
+ netif_carrier_off(priv->netdev);
+ netif_stop_queue(priv->netdev);
+ at76_iwevent_bss_disconnect(priv->netdev);
+ }
+ cancel_delayed_work(&priv->dwork_get_scan);
+ cancel_delayed_work(&priv->dwork_beacon);
+ cancel_delayed_work(&priv->dwork_auth);
+ cancel_delayed_work(&priv->dwork_assoc);
+ at76_set_mac_state(priv, MAC_JOINING);
+ schedule_work(&priv->work_join);
+}
+
+static void at76_rx_mgmt_auth(struct at76_priv *priv,
+ struct at76_rx_buffer *buf)
+{
+ struct ieee80211_auth *resp = (struct ieee80211_auth *)buf->packet;
+ struct ieee80211_hdr_3addr *mgmt = &resp->header;
+ int seq_nr = le16_to_cpu(resp->transaction);
+ int alg = le16_to_cpu(resp->algorithm);
+ int status = le16_to_cpu(resp->status);
+
+ at76_dbg(DBG_RX_MGMT,
+ "%s: rx AuthFrame bssid %s alg %d seq_nr %d status %d "
+ "destination %s", priv->netdev->name, mac2str(mgmt->addr3),
+ alg, seq_nr, status, mac2str(mgmt->addr1));
+
+ if (alg == WLAN_AUTH_SHARED_KEY && seq_nr == 2)
+ at76_dbg(DBG_RX_MGMT, "%s: AuthFrame challenge %s ...",
+ priv->netdev->name, hex2str(resp->info_element, 18));
+
+ if (priv->mac_state != MAC_AUTH) {
+ printk(KERN_INFO "%s: ignored AuthFrame in state %s\n",
+ priv->netdev->name, mac_states[priv->mac_state]);
+ return;
+ }
+ if (priv->auth_mode != alg) {
+ printk(KERN_INFO "%s: ignored AuthFrame for alg %d\n",
+ priv->netdev->name, alg);
+ return;
+ }
+
+ BUG_ON(!priv->curr_bss);
+
+ /* Not our BSSID or not for our STA, ignore */
+ if (compare_ether_addr(mgmt->addr3, priv->curr_bss->bssid)
+ || compare_ether_addr(priv->netdev->dev_addr, mgmt->addr1))
+ return;
+
+ cancel_delayed_work(&priv->dwork_auth);
+ if (status != WLAN_STATUS_SUCCESS) {
+ /* try to join next bss */
+ at76_set_mac_state(priv, MAC_JOINING);
+ schedule_work(&priv->work_join);
+ return;
+ }
+
+ if (priv->auth_mode == WLAN_AUTH_OPEN || seq_nr == 4) {
+ priv->retries = ASSOC_RETRIES;
+ at76_set_mac_state(priv, MAC_ASSOC);
+ at76_assoc_req(priv, priv->curr_bss);
+ at76_dbg(DBG_MGMT_TIMER,
+ "%s:%d: starting mgmt_timer + HZ", __func__, __LINE__);
+ schedule_delayed_work(&priv->dwork_assoc, ASSOC_TIMEOUT);
+ return;
+ }
+
+ WARN_ON(seq_nr != 2);
+ at76_auth_req(priv, priv->curr_bss, seq_nr + 1, resp->info_element);
+ at76_dbg(DBG_MGMT_TIMER, "%s:%d: starting mgmt_timer + HZ", __func__,
+ __LINE__);
+ schedule_delayed_work(&priv->dwork_auth, AUTH_TIMEOUT);
+}
+
+static void at76_rx_mgmt_deauth(struct at76_priv *priv,
+ struct at76_rx_buffer *buf)
+{
+ struct ieee80211_disassoc *resp =
+ (struct ieee80211_disassoc *)buf->packet;
+ struct ieee80211_hdr_3addr *mgmt = &resp->header;
+
+ at76_dbg(DBG_RX_MGMT | DBG_PROGRESS,
+ "%s: rx DeAuth bssid %s reason 0x%04x destination %s",
+ priv->netdev->name, mac2str(mgmt->addr3),
+ le16_to_cpu(resp->reason), mac2str(mgmt->addr1));
+
+ if (priv->mac_state != MAC_AUTH && priv->mac_state != MAC_ASSOC
+ && priv->mac_state != MAC_CONNECTED) {
+ printk(KERN_INFO "%s: DeAuth in state %s ignored\n",
+ priv->netdev->name, mac_states[priv->mac_state]);
+ return;
+ }
+
+ BUG_ON(!priv->curr_bss);
+
+ /* Not our BSSID, ignore */
+ if (compare_ether_addr(mgmt->addr3, priv->curr_bss->bssid))
+ return;
+
+ /* Not for our STA and not broadcast, ignore */
+ if (compare_ether_addr(priv->netdev->dev_addr, mgmt->addr1)
+ && !is_broadcast_ether_addr(mgmt->addr1))
+ return;
+
+ if (priv->mac_state == MAC_CONNECTED)
+ at76_iwevent_bss_disconnect(priv->netdev);
+
+ at76_set_mac_state(priv, MAC_JOINING);
+ schedule_work(&priv->work_join);
+ cancel_delayed_work(&priv->dwork_get_scan);
+ cancel_delayed_work(&priv->dwork_beacon);
+ cancel_delayed_work(&priv->dwork_auth);
+ cancel_delayed_work(&priv->dwork_assoc);
+}
+
+static void at76_rx_mgmt_beacon(struct at76_priv *priv,
+ struct at76_rx_buffer *buf)
+{
+ int varpar_len;
+ /* beacon content */
+ struct ieee80211_beacon *bdata = (struct ieee80211_beacon *)buf->packet;
+ struct ieee80211_hdr_3addr *mgmt = &bdata->header;
+
+ struct list_head *lptr;
+ struct bss_info *match; /* entry matching addr3 with its bssid */
+ int new_entry = 0;
+ int len;
+ struct ieee80211_info_element *ie;
+ int have_ssid = 0;
+ int have_rates = 0;
+ int have_channel = 0;
+ int keep_going = 1;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->bss_list_spinlock, flags);
+ if (priv->mac_state == MAC_CONNECTED) {
+ /* in state MAC_CONNECTED we use the mgmt_timer to control
+ the beacon of the BSS */
+ BUG_ON(!priv->curr_bss);
+
+ if (!compare_ether_addr(priv->curr_bss->bssid, mgmt->addr3)) {
+ /* We got our AP's beacon, defer the timeout handler.
+ Kill pending work first, as schedule_delayed_work()
+ won't do it. */
+ cancel_delayed_work(&priv->dwork_beacon);
+ schedule_delayed_work(&priv->dwork_beacon,
+ BEACON_TIMEOUT);
+ priv->curr_bss->rssi = buf->rssi;
+ priv->beacons_received++;
+ goto exit;
+ }
+ }
+
+ /* look if we have this BSS already in the list */
+ match = NULL;
+
+ if (!list_empty(&priv->bss_list)) {
+ list_for_each(lptr, &priv->bss_list) {
+ struct bss_info *bss_ptr =
+ list_entry(lptr, struct bss_info, list);
+ if (!compare_ether_addr(bss_ptr->bssid, mgmt->addr3)) {
+ match = bss_ptr;
+ break;
+ }
+ }
+ }
+
+ if (!match) {
+ /* BSS not in the list - append it */
+ match = kzalloc(sizeof(struct bss_info), GFP_ATOMIC);
+ if (!match) {
+ at76_dbg(DBG_BSS_TABLE,
+ "%s: cannot kmalloc new bss info (%zd byte)",
+ priv->netdev->name, sizeof(struct bss_info));
+ goto exit;
+ }
+ new_entry = 1;
+ list_add_tail(&match->list, &priv->bss_list);
+ }
+
+ match->capa = le16_to_cpu(bdata->capability);
+ match->beacon_interval = le16_to_cpu(bdata->beacon_interval);
+ match->rssi = buf->rssi;
+ match->link_qual = buf->link_quality;
+ match->noise_level = buf->noise_level;
+ memcpy(match->bssid, mgmt->addr3, ETH_ALEN);
+ at76_dbg(DBG_RX_BEACON, "%s: bssid %s", priv->netdev->name,
+ mac2str(match->bssid));
+
+ ie = bdata->info_element;
+
+ /* length of var length beacon parameters */
+ varpar_len = min_t(int, le16_to_cpu(buf->wlength) -
+ sizeof(struct ieee80211_beacon),
+ BEACON_MAX_DATA_LENGTH);
+
+ /* This routine steps through the bdata->data array to get
+ * some useful information about the access point.
+ * Currently, this implementation supports receipt of: SSID,
+ * supported transfer rates and channel, in any order, with some
+ * tolerance for intermittent unknown codes (although this
+ * functionality may not be necessary as the useful information will
+ * usually arrive in consecutively, but there have been some
+ * reports of some of the useful information fields arriving in a
+ * different order).
+ * It does not support any more IE types although MFIE_TYPE_TIM may
+ * be supported (on my AP at least).
+ * The bdata->data array is about 1500 bytes long but only ~36 of those
+ * bytes are useful, hence the have_ssid etc optimizations. */
+
+ while (keep_going &&
+ ((&ie->data[ie->len] - (u8 *)bdata->info_element) <=
+ varpar_len)) {
+
+ switch (ie->id) {
+
+ case MFIE_TYPE_SSID:
+ if (have_ssid)
+ break;
+
+ len = min_t(int, IW_ESSID_MAX_SIZE, ie->len);
+
+ /* we copy only if this is a new entry,
+ or the incoming SSID is not a hidden SSID. This
+ will protect us from overwriting a real SSID read
+ in a ProbeResponse with a hidden one from a
+ following beacon. */
+ if (!new_entry && at76_is_hidden_ssid(ie->data, len)) {
+ have_ssid = 1;
+ break;
+ }
+
+ match->ssid_len = len;
+ memcpy(match->ssid, ie->data, len);
+ at76_dbg(DBG_RX_BEACON, "%s: SSID - %.*s",
+ priv->netdev->name, len, match->ssid);
+ have_ssid = 1;
+ break;
+
+ case MFIE_TYPE_RATES:
+ if (have_rates)
+ break;
+
+ match->rates_len =
+ min_t(int, sizeof(match->rates), ie->len);
+ memcpy(match->rates, ie->data, match->rates_len);
+ have_rates = 1;
+ at76_dbg(DBG_RX_BEACON, "%s: SUPPORTED RATES %s",
+ priv->netdev->name,
+ hex2str(ie->data, ie->len));
+ break;
+
+ case MFIE_TYPE_DS_SET:
+ if (have_channel)
+ break;
+
+ match->channel = ie->data[0];
+ have_channel = 1;
+ at76_dbg(DBG_RX_BEACON, "%s: CHANNEL - %d",
+ priv->netdev->name, match->channel);
+ break;
+
+ case MFIE_TYPE_CF_SET:
+ case MFIE_TYPE_TIM:
+ case MFIE_TYPE_IBSS_SET:
+ default:
+ at76_dbg(DBG_RX_BEACON, "%s: beacon IE id %d len %d %s",
+ priv->netdev->name, ie->id, ie->len,
+ hex2str(ie->data, ie->len));
+ break;
+ }
+
+ /* advance to the next informational element */
+ next_ie(&ie);
+
+ /* Optimization: after all, the bdata->data array is
+ * varpar_len bytes long, whereas we get all of the useful
+ * information after only ~36 bytes, this saves us a lot of
+ * time (and trouble as the remaining portion of the array
+ * could be full of junk)
+ * Comment this out if you want to see what other information
+ * comes from the AP - although little of it may be useful */
+ }
+
+ at76_dbg(DBG_RX_BEACON, "%s: Finished processing beacon data",
+ priv->netdev->name);
+
+ match->last_rx = jiffies; /* record last rx of beacon */
+
+exit:
+ spin_unlock_irqrestore(&priv->bss_list_spinlock, flags);
+}
+
+/* Calculate the link level from a given rx_buffer */
+static void at76_calc_level(struct at76_priv *priv, struct at76_rx_buffer *buf,
+ struct iw_quality *qual)
+{
+ /* just a guess for now, might be different for other chips */
+ int max_rssi = 42;
+
+ qual->level = (buf->rssi * 100 / max_rssi);
+ if (qual->level > 100)
+ qual->level = 100;
+ qual->updated |= IW_QUAL_LEVEL_UPDATED;
+}
+
+/* Calculate the link quality from a given rx_buffer */
+static void at76_calc_qual(struct at76_priv *priv, struct at76_rx_buffer *buf,
+ struct iw_quality *qual)
+{
+ if (at76_is_intersil(priv->board_type))
+ qual->qual = buf->link_quality;
+ else {
+ unsigned long elapsed;
+
+ /* Update qual at most once a second */
+ elapsed = jiffies - priv->beacons_last_qual;
+ if (elapsed < 1 * HZ)
+ return;
+
+ qual->qual = qual->level * priv->beacons_received *
+ msecs_to_jiffies(priv->beacon_period) / elapsed;
+
+ priv->beacons_last_qual = jiffies;
+ priv->beacons_received = 0;
+ }
+ qual->qual = (qual->qual > 100) ? 100 : qual->qual;
+ qual->updated |= IW_QUAL_QUAL_UPDATED;
+}
+
+/* Calculate the noise quality from a given rx_buffer */
+static void at76_calc_noise(struct at76_priv *priv, struct at76_rx_buffer *buf,
+ struct iw_quality *qual)
+{
+ qual->noise = 0;
+ qual->updated |= IW_QUAL_NOISE_INVALID;
+}
+
+static void at76_update_wstats(struct at76_priv *priv,
+ struct at76_rx_buffer *buf)
+{
+ struct iw_quality *qual = &priv->wstats.qual;
+
+ if (buf->rssi && priv->mac_state == MAC_CONNECTED) {
+ qual->updated = 0;
+ at76_calc_level(priv, buf, qual);
+ at76_calc_qual(priv, buf, qual);
+ at76_calc_noise(priv, buf, qual);
+ } else {
+ qual->qual = 0;
+ qual->level = 0;
+ qual->noise = 0;
+ qual->updated = IW_QUAL_ALL_INVALID;
+ }
+}
+
+static void at76_rx_mgmt(struct at76_priv *priv, struct at76_rx_buffer *buf)
+{
+ struct ieee80211_hdr_3addr *mgmt =
+ (struct ieee80211_hdr_3addr *)buf->packet;
+ u16 framectl = le16_to_cpu(mgmt->frame_ctl);
+
+ /* update wstats */
+ if (priv->mac_state != MAC_INIT && priv->mac_state != MAC_SCANNING) {
+ /* jal: this is a dirty hack needed by Tim in ad-hoc mode */
+ /* Data packets always seem to have a 0 link level, so we
+ only read link quality info from management packets.
+ Atmel driver actually averages the present, and previous
+ values, we just present the raw value at the moment - TJS */
+ if (priv->iw_mode == IW_MODE_ADHOC
+ || (priv->curr_bss
+ && !compare_ether_addr(mgmt->addr3,
+ priv->curr_bss->bssid)))
+ at76_update_wstats(priv, buf);
+ }
+
+ at76_dbg(DBG_RX_MGMT_CONTENT, "%s rx mgmt framectl 0x%x %s",
+ priv->netdev->name, framectl,
+ hex2str(mgmt, le16_to_cpu(buf->wlength)));
+
+ switch (framectl & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_BEACON:
+ case IEEE80211_STYPE_PROBE_RESP:
+ at76_rx_mgmt_beacon(priv, buf);
+ break;
+
+ case IEEE80211_STYPE_ASSOC_RESP:
+ at76_rx_mgmt_assoc(priv, buf);
+ break;
+
+ case IEEE80211_STYPE_DISASSOC:
+ at76_rx_mgmt_disassoc(priv, buf);
+ break;
+
+ case IEEE80211_STYPE_AUTH:
+ at76_rx_mgmt_auth(priv, buf);
+ break;
+
+ case IEEE80211_STYPE_DEAUTH:
+ at76_rx_mgmt_deauth(priv, buf);
+ break;
+
+ default:
+ printk(KERN_DEBUG "%s: ignoring frame with framectl 0x%04x\n",
+ priv->netdev->name, framectl);
+ }
+
+ return;
+}
+
+/* Convert the 802.11 header into an ethernet-style header, make skb
+ * ready for consumption by netif_rx() */
+static void at76_ieee80211_to_eth(struct sk_buff *skb, int iw_mode)
+{
+ struct ieee80211_hdr_3addr *i802_11_hdr;
+ struct ethhdr *eth_hdr_p;
+ u8 *src_addr;
+ u8 *dest_addr;
+
+ i802_11_hdr = (struct ieee80211_hdr_3addr *)skb->data;
+
+ /* That would be the ethernet header if the hardware converted
+ * the frame for us. Make sure the source and the destination
+ * match the 802.11 header. Which hardware does it? */
+ eth_hdr_p = (struct ethhdr *)skb_pull(skb, IEEE80211_3ADDR_LEN);
+
+ dest_addr = i802_11_hdr->addr1;
+ if (iw_mode == IW_MODE_ADHOC)
+ src_addr = i802_11_hdr->addr2;
+ else
+ src_addr = i802_11_hdr->addr3;
+
+ if (!compare_ether_addr(eth_hdr_p->h_source, src_addr) &&
+ !compare_ether_addr(eth_hdr_p->h_dest, dest_addr))
+ /* Yes, we already have an ethernet header */
+ skb_reset_mac_header(skb);
+ else {
+ u16 len;
+
+ /* Need to build an ethernet header */
+ if (!memcmp(skb->data, snapsig, sizeof(snapsig))) {
+ /* SNAP frame - decapsulate, keep proto */
+ skb_push(skb, offsetof(struct ethhdr, h_proto) -
+ sizeof(rfc1042sig));
+ len = 0;
+ } else {
+ /* 802.3 frame, proto is length */
+ len = skb->len;
+ skb_push(skb, ETH_HLEN);
+ }
+
+ skb_reset_mac_header(skb);
+ eth_hdr_p = eth_hdr(skb);
+ /* This needs to be done in this order (eth_hdr_p->h_dest may
+ * overlap src_addr) */
+ memcpy(eth_hdr_p->h_source, src_addr, ETH_ALEN);
+ memcpy(eth_hdr_p->h_dest, dest_addr, ETH_ALEN);
+ if (len)
+ eth_hdr_p->h_proto = htons(len);
+ }
+
+ skb->protocol = eth_type_trans(skb, skb->dev);
+}
+
+/* Check for fragmented data in priv->rx_skb. If the packet was no fragment
+ or it was the last of a fragment set a skb containing the whole packet
+ is returned for further processing. Otherwise we get NULL and are
+ done and the packet is either stored inside the fragment buffer
+ or thrown away. Every returned skb starts with the ieee802_11 header
+ and contains _no_ FCS at the end */
+static struct sk_buff *at76_check_for_rx_frags(struct at76_priv *priv)
+{
+ struct sk_buff *skb = priv->rx_skb;
+ struct at76_rx_buffer *buf = (struct at76_rx_buffer *)skb->data;
+ struct ieee80211_hdr_3addr *i802_11_hdr =
+ (struct ieee80211_hdr_3addr *)buf->packet;
+ /* seq_ctrl, fragment_number, sequence number of new packet */
+ u16 sctl = le16_to_cpu(i802_11_hdr->seq_ctl);
+ u16 fragnr = sctl & 0xf;
+ u16 seqnr = sctl >> 4;
+ u16 frame_ctl = le16_to_cpu(i802_11_hdr->frame_ctl);
+
+ /* Length including the IEEE802.11 header, but without the trailing
+ * FCS and without the Atmel Rx header */
+ int length = le16_to_cpu(buf->wlength) - IEEE80211_FCS_LEN;
+
+ /* where does the data payload start in skb->data ? */
+ u8 *data = i802_11_hdr->payload;
+
+ /* length of payload, excl. the trailing FCS */
+ int data_len = length - IEEE80211_3ADDR_LEN;
+
+ int i;
+ struct rx_data_buf *bptr, *optr;
+ unsigned long oldest = ~0UL;
+
+ at76_dbg(DBG_RX_FRAGS,
+ "%s: rx data frame_ctl %04x addr2 %s seq/frag %d/%d "
+ "length %d data %d: %s ...", priv->netdev->name, frame_ctl,
+ mac2str(i802_11_hdr->addr2), seqnr, fragnr, length, data_len,
+ hex2str(data, 32));
+
+ at76_dbg(DBG_RX_FRAGS_SKB, "%s: incoming skb: head %p data %p "
+ "tail %p end %p len %d", priv->netdev->name, skb->head,
+ skb->data, skb_tail_pointer(skb), skb_end_pointer(skb),
+ skb->len);
+
+ if (data_len < 0) {
+ /* make sure data starts in the buffer */
+ printk(KERN_INFO "%s: data frame too short\n",
+ priv->netdev->name);
+ return NULL;
+ }
+
+ WARN_ON(length <= AT76_RX_HDRLEN);
+ if (length <= AT76_RX_HDRLEN)
+ return NULL;
+
+ /* remove the at76_rx_buffer header - we don't need it anymore */
+ /* we need the IEEE802.11 header (for the addresses) if this packet
+ is the first of a chain */
+ skb_pull(skb, AT76_RX_HDRLEN);
+
+ /* remove FCS at end */
+ skb_trim(skb, length);
+
+ at76_dbg(DBG_RX_FRAGS_SKB, "%s: trimmed skb: head %p data %p tail %p "
+ "end %p len %d data %p data_len %d", priv->netdev->name,
+ skb->head, skb->data, skb_tail_pointer(skb),
+ skb_end_pointer(skb), skb->len, data, data_len);
+
+ if (fragnr == 0 && !(frame_ctl & IEEE80211_FCTL_MOREFRAGS)) {
+ /* unfragmented packet received */
+ /* Use a new skb for the next receive */
+ priv->rx_skb = NULL;
+ at76_dbg(DBG_RX_FRAGS, "%s: unfragmented", priv->netdev->name);
+ return skb;
+ }
+
+ /* look if we've got a chain for the sender address.
+ afterwards optr points to first free or the oldest entry,
+ or, if i < NR_RX_DATA_BUF, bptr points to the entry for the
+ sender address */
+ /* determining the oldest entry doesn't cope with jiffies wrapping
+ but I don't care to delete a young entry at these rare moments ... */
+
+ bptr = priv->rx_data;
+ optr = NULL;
+ for (i = 0; i < NR_RX_DATA_BUF; i++, bptr++) {
+ if (!bptr->skb) {
+ optr = bptr;
+ oldest = 0UL;
+ continue;
+ }
+
+ if (!compare_ether_addr(i802_11_hdr->addr2, bptr->sender))
+ break;
+
+ if (!optr) {
+ optr = bptr;
+ oldest = bptr->last_rx;
+ } else if (bptr->last_rx < oldest)
+ optr = bptr;
+ }
+
+ if (i < NR_RX_DATA_BUF) {
+
+ at76_dbg(DBG_RX_FRAGS, "%s: %d. cacheentry (seq/frag = %d/%d) "
+ "matched sender addr",
+ priv->netdev->name, i, bptr->seqnr, bptr->fragnr);
+
+ /* bptr points to an entry for the sender address */
+ if (bptr->seqnr == seqnr) {
+ int left;
+ /* the fragment has the current sequence number */
+ if (((bptr->fragnr + 1) & 0xf) != fragnr) {
+ /* wrong fragment number -> ignore it */
+ /* is & 0xf necessary above ??? */
+ at76_dbg(DBG_RX_FRAGS,
+ "%s: frag nr mismatch: %d + 1 != %d",
+ priv->netdev->name, bptr->fragnr,
+ fragnr);
+ return NULL;
+ }
+ bptr->last_rx = jiffies;
+ /* the next following fragment number ->
+ add the data at the end */
+
+ /* for test only ??? */
+ left = skb_tailroom(bptr->skb);
+ if (left < data_len)
+ printk(KERN_INFO
+ "%s: only %d byte free (need %d)\n",
+ priv->netdev->name, left, data_len);
+ else
+ memcpy(skb_put(bptr->skb, data_len), data,
+ data_len);
+
+ bptr->fragnr = fragnr;
+ if (frame_ctl & IEEE80211_FCTL_MOREFRAGS)
+ return NULL;
+
+ /* this was the last fragment - send it */
+ skb = bptr->skb;
+ bptr->skb = NULL; /* free the entry */
+ at76_dbg(DBG_RX_FRAGS, "%s: last frag of seq %d",
+ priv->netdev->name, seqnr);
+ return skb;
+ }
+
+ /* got another sequence number */
+ if (fragnr == 0) {
+ /* it's the start of a new chain - replace the
+ old one by this */
+ /* bptr->sender has the correct value already */
+ at76_dbg(DBG_RX_FRAGS,
+ "%s: start of new seq %d, removing old seq %d",
+ priv->netdev->name, seqnr, bptr->seqnr);
+ bptr->seqnr = seqnr;
+ bptr->fragnr = 0;
+ bptr->last_rx = jiffies;
+ /* swap bptr->skb and priv->rx_skb */
+ skb = bptr->skb;
+ bptr->skb = priv->rx_skb;
+ priv->rx_skb = skb;
+ } else {
+ /* it from the middle of a new chain ->
+ delete the old entry and skip the new one */
+ at76_dbg(DBG_RX_FRAGS,
+ "%s: middle of new seq %d (%d) "
+ "removing old seq %d",
+ priv->netdev->name, seqnr, fragnr,
+ bptr->seqnr);
+ dev_kfree_skb(bptr->skb);
+ bptr->skb = NULL;
+ }
+ return NULL;
+ }
+
+ /* if we didn't find a chain for the sender address, optr
+ points either to the first free or the oldest entry */
+
+ if (fragnr != 0) {
+ /* this is not the begin of a fragment chain ... */
+ at76_dbg(DBG_RX_FRAGS,
+ "%s: no chain for non-first fragment (%d)",
+ priv->netdev->name, fragnr);
+ return NULL;
+ }
+
+ BUG_ON(!optr);
+ if (optr->skb) {
+ /* swap the skb's */
+ skb = optr->skb;
+ optr->skb = priv->rx_skb;
+ priv->rx_skb = skb;
+
+ at76_dbg(DBG_RX_FRAGS,
+ "%s: free old contents: sender %s seq/frag %d/%d",
+ priv->netdev->name, mac2str(optr->sender),
+ optr->seqnr, optr->fragnr);
+
+ } else {
+ /* take the skb from priv->rx_skb */
+ optr->skb = priv->rx_skb;
+ /* let at76_submit_rx_urb() allocate a new skb */
+ priv->rx_skb = NULL;
+
+ at76_dbg(DBG_RX_FRAGS, "%s: use a free entry",
+ priv->netdev->name);
+ }
+ memcpy(optr->sender, i802_11_hdr->addr2, ETH_ALEN);
+ optr->seqnr = seqnr;
+ optr->fragnr = 0;
+ optr->last_rx = jiffies;
+
+ return NULL;
+}
+
+/* Rx interrupt: we expect the complete data buffer in priv->rx_skb */
+static void at76_rx_data(struct at76_priv *priv)
+{
+ struct net_device *netdev = priv->netdev;
+ struct net_device_stats *stats = &priv->stats;
+ struct sk_buff *skb = priv->rx_skb;
+ struct at76_rx_buffer *buf = (struct at76_rx_buffer *)skb->data;
+ struct ieee80211_hdr_3addr *i802_11_hdr;
+ int length = le16_to_cpu(buf->wlength);
+
+ at76_dbg(DBG_RX_DATA, "%s received data packet: %s", netdev->name,
+ hex2str(skb->data, AT76_RX_HDRLEN));
+
+ at76_dbg(DBG_RX_DATA_CONTENT, "rx packet: %s",
+ hex2str(skb->data + AT76_RX_HDRLEN, length));
+
+ skb = at76_check_for_rx_frags(priv);
+ if (!skb)
+ return;
+
+ /* Atmel header and the FCS are already removed */
+ i802_11_hdr = (struct ieee80211_hdr_3addr *)skb->data;
+
+ skb->dev = netdev;
+ skb->ip_summed = CHECKSUM_NONE; /* TODO: should check CRC */
+
+ if (is_broadcast_ether_addr(i802_11_hdr->addr1)) {
+ if (!compare_ether_addr(i802_11_hdr->addr1, netdev->broadcast))
+ skb->pkt_type = PACKET_BROADCAST;
+ else
+ skb->pkt_type = PACKET_MULTICAST;
+ } else if (compare_ether_addr(i802_11_hdr->addr1, netdev->dev_addr))
+ skb->pkt_type = PACKET_OTHERHOST;
+
+ at76_ieee80211_to_eth(skb, priv->iw_mode);
+
+ netdev->last_rx = jiffies;
+ netif_rx(skb);
+ stats->rx_packets++;
+ stats->rx_bytes += length;
+
+ return;
+}
+
+static void at76_rx_monitor_mode(struct at76_priv *priv)
+{
+ struct at76_rx_radiotap *rt;
+ u8 *payload;
+ int skblen;
+ struct net_device *netdev = priv->netdev;
+ struct at76_rx_buffer *buf =
+ (struct at76_rx_buffer *)priv->rx_skb->data;
+ /* length including the IEEE802.11 header and the trailing FCS,
+ but not at76_rx_buffer */
+ int length = le16_to_cpu(buf->wlength);
+ struct sk_buff *skb = priv->rx_skb;
+ struct net_device_stats *stats = &priv->stats;
+
+ if (length < IEEE80211_FCS_LEN) {
+ /* buffer contains no data */
+ at76_dbg(DBG_MONITOR_MODE,
+ "%s: MONITOR MODE: rx skb without data",
+ priv->netdev->name);
+ return;
+ }
+
+ skblen = sizeof(struct at76_rx_radiotap) + length;
+
+ skb = dev_alloc_skb(skblen);
+ if (!skb) {
+ printk(KERN_ERR "%s: MONITOR MODE: dev_alloc_skb for radiotap "
+ "header returned NULL\n", priv->netdev->name);
+ return;
+ }
+
+ skb_put(skb, skblen);
+
+ rt = (struct at76_rx_radiotap *)skb->data;
+ payload = skb->data + sizeof(struct at76_rx_radiotap);
+
+ rt->rt_hdr.it_version = 0;
+ rt->rt_hdr.it_pad = 0;
+ rt->rt_hdr.it_len = cpu_to_le16(sizeof(struct at76_rx_radiotap));
+ rt->rt_hdr.it_present = cpu_to_le32(AT76_RX_RADIOTAP_PRESENT);
+
+ rt->rt_tsft = cpu_to_le64(le32_to_cpu(buf->rx_time));
+ rt->rt_rate = hw_rates[buf->rx_rate] & (~0x80);
+ rt->rt_signal = buf->rssi;
+ rt->rt_noise = buf->noise_level;
+ rt->rt_flags = IEEE80211_RADIOTAP_F_FCS;
+ if (buf->fragmentation)
+ rt->rt_flags |= IEEE80211_RADIOTAP_F_FRAG;
+
+ memcpy(payload, buf->packet, length);
+ skb->dev = netdev;
+ skb->ip_summed = CHECKSUM_NONE;
+ skb_reset_mac_header(skb);
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = htons(ETH_P_802_2);
+
+ netdev->last_rx = jiffies;
+ netif_rx(skb);
+ stats->rx_packets++;
+ stats->rx_bytes += length;
+}
+
+/* Check if we spy on the sender address in buf and update stats */
+static void at76_iwspy_update(struct at76_priv *priv,
+ struct at76_rx_buffer *buf)
+{
+ struct ieee80211_hdr_3addr *hdr =
+ (struct ieee80211_hdr_3addr *)buf->packet;
+ struct iw_quality qual;
+
+ /* We can only set the level here */
+ qual.updated = IW_QUAL_QUAL_INVALID | IW_QUAL_NOISE_INVALID;
+ qual.level = 0;
+ qual.noise = 0;
+ at76_calc_level(priv, buf, &qual);
+
+ spin_lock_bh(&priv->spy_spinlock);
+
+ if (priv->spy_data.spy_number > 0)
+ wireless_spy_update(priv->netdev, hdr->addr2, &qual);
+
+ spin_unlock_bh(&priv->spy_spinlock);
+}
+
+static void at76_rx_tasklet(unsigned long param)
+{
+ struct urb *urb = (struct urb *)param;
+ struct at76_priv *priv = urb->context;
+ struct net_device *netdev = priv->netdev;
+ struct at76_rx_buffer *buf;
+ struct ieee80211_hdr_3addr *i802_11_hdr;
+ u16 frame_ctl;
+
+ if (priv->device_unplugged) {
+ at76_dbg(DBG_DEVSTART, "device unplugged");
+ if (urb)
+ at76_dbg(DBG_DEVSTART, "urb status %d", urb->status);
+ return;
+ }
+
+ if (!priv->rx_skb || !netdev || !priv->rx_skb->data)
+ return;
+
+ buf = (struct at76_rx_buffer *)priv->rx_skb->data;
+
+ i802_11_hdr = (struct ieee80211_hdr_3addr *)buf->packet;
+
+ frame_ctl = le16_to_cpu(i802_11_hdr->frame_ctl);
+
+ if (urb->status != 0) {
+ if (urb->status != -ENOENT && urb->status != -ECONNRESET)
+ at76_dbg(DBG_URB,
+ "%s %s: - nonzero Rx bulk status received: %d",
+ __func__, netdev->name, urb->status);
+ return;
+ }
+
+ at76_dbg(DBG_RX_ATMEL_HDR,
+ "%s: rx frame: rate %d rssi %d noise %d link %d %s",
+ priv->netdev->name, buf->rx_rate, buf->rssi, buf->noise_level,
+ buf->link_quality, hex2str(i802_11_hdr, 48));
+ if (priv->iw_mode == IW_MODE_MONITOR) {
+ at76_rx_monitor_mode(priv);
+ goto exit;
+ }
+
+ /* there is a new bssid around, accept it: */
+ if (buf->newbss && priv->iw_mode == IW_MODE_ADHOC) {
+ at76_dbg(DBG_PROGRESS, "%s: rx newbss", netdev->name);
+ schedule_work(&priv->work_new_bss);
+ }
+
+ switch (frame_ctl & IEEE80211_FCTL_FTYPE) {
+ case IEEE80211_FTYPE_DATA:
+ at76_rx_data(priv);
+ break;
+
+ case IEEE80211_FTYPE_MGMT:
+ /* jal: TODO: find out if we can update iwspy also on
+ other frames than management (might depend on the
+ radio chip / firmware version !) */
+
+ at76_iwspy_update(priv, buf);
+
+ at76_rx_mgmt(priv, buf);
+ break;
+
+ case IEEE80211_FTYPE_CTL:
+ at76_dbg(DBG_RX_CTRL, "%s: ignored ctrl frame: %04x",
+ priv->netdev->name, frame_ctl);
+ break;
+
+ default:
+ printk(KERN_DEBUG "%s: ignoring frame with framectl 0x%04x\n",
+ priv->netdev->name, frame_ctl);
+ }
+exit:
+ at76_submit_rx_urb(priv);
+}
+
+/* Load firmware into kernel memory and parse it */
+static struct fwentry *at76_load_firmware(struct usb_device *udev,
+ enum board_type board_type)
+{
+ int ret;
+ char *str;
+ struct at76_fw_header *fwh;
+ struct fwentry *fwe = &firmwares[board_type];
+
+ mutex_lock(&fw_mutex);
+
+ if (fwe->loaded) {
+ at76_dbg(DBG_FW, "re-using previously loaded fw");
+ goto exit;
+ }
+
+ at76_dbg(DBG_FW, "downloading firmware %s", fwe->fwname);
+ ret = request_firmware(&fwe->fw, fwe->fwname, &udev->dev);
+ if (ret < 0) {
+ dev_printk(KERN_ERR, &udev->dev, "firmware %s not found!\n",
+ fwe->fwname);
+ dev_printk(KERN_ERR, &udev->dev,
+ "you may need to download the firmware from "
+ "http://developer.berlios.de/projects/at76c503a/");
+ goto exit;
+ }
+
+ at76_dbg(DBG_FW, "got it.");
+ fwh = (struct at76_fw_header *)(fwe->fw->data);
+
+ if (fwe->fw->size <= sizeof(*fwh)) {
+ dev_printk(KERN_ERR, &udev->dev,
+ "firmware is too short (0x%zx)\n", fwe->fw->size);
+ goto exit;
+ }
+
+ /* CRC currently not checked */
+ fwe->board_type = le32_to_cpu(fwh->board_type);
+ if (fwe->board_type != board_type) {
+ dev_printk(KERN_ERR, &udev->dev,
+ "board type mismatch, requested %u, got %u\n",
+ board_type, fwe->board_type);
+ goto exit;
+ }
+
+ fwe->fw_version.major = fwh->major;
+ fwe->fw_version.minor = fwh->minor;
+ fwe->fw_version.patch = fwh->patch;
+ fwe->fw_version.build = fwh->build;
+
+ str = (char *)fwh + le32_to_cpu(fwh->str_offset);
+ fwe->intfw = (u8 *)fwh + le32_to_cpu(fwh->int_fw_offset);
+ fwe->intfw_size = le32_to_cpu(fwh->int_fw_len);
+ fwe->extfw = (u8 *)fwh + le32_to_cpu(fwh->ext_fw_offset);
+ fwe->extfw_size = le32_to_cpu(fwh->ext_fw_len);
+
+ fwe->loaded = 1;
+
+ dev_printk(KERN_DEBUG, &udev->dev,
+ "using firmware %s (version %d.%d.%d-%d)\n",
+ fwe->fwname, fwh->major, fwh->minor, fwh->patch, fwh->build);
+
+ at76_dbg(DBG_DEVSTART, "board %u, int %d:%d, ext %d:%d", board_type,
+ le32_to_cpu(fwh->int_fw_offset), le32_to_cpu(fwh->int_fw_len),
+ le32_to_cpu(fwh->ext_fw_offset), le32_to_cpu(fwh->ext_fw_len));
+ at76_dbg(DBG_DEVSTART, "firmware id %s", str);
+
+exit:
+ mutex_unlock(&fw_mutex);
+
+ if (fwe->loaded)
+ return fwe;
+ else
+ return NULL;
+}
+
+/* Allocate network device and initialize private data */
+static struct at76_priv *at76_alloc_new_device(struct usb_device *udev)
+{
+ struct net_device *netdev;
+ struct at76_priv *priv;
+ int i;
+
+ /* allocate memory for our device state and initialize it */
+ netdev = alloc_etherdev(sizeof(struct at76_priv));
+ if (!netdev) {
+ dev_printk(KERN_ERR, &udev->dev, "out of memory\n");
+ return NULL;
+ }
+
+ priv = netdev_priv(netdev);
+
+ priv->udev = udev;
+ priv->netdev = netdev;
+
+ mutex_init(&priv->mtx);
+ INIT_WORK(&priv->work_assoc_done, at76_work_assoc_done);
+ INIT_WORK(&priv->work_join, at76_work_join);
+ INIT_WORK(&priv->work_new_bss, at76_work_new_bss);
+ INIT_WORK(&priv->work_start_scan, at76_work_start_scan);
+ INIT_WORK(&priv->work_set_promisc, at76_work_set_promisc);
+ INIT_WORK(&priv->work_submit_rx, at76_work_submit_rx);
+ INIT_DELAYED_WORK(&priv->dwork_restart, at76_dwork_restart);
+ INIT_DELAYED_WORK(&priv->dwork_get_scan, at76_dwork_get_scan);
+ INIT_DELAYED_WORK(&priv->dwork_beacon, at76_dwork_beacon);
+ INIT_DELAYED_WORK(&priv->dwork_auth, at76_dwork_auth);
+ INIT_DELAYED_WORK(&priv->dwork_assoc, at76_dwork_assoc);
+
+ spin_lock_init(&priv->mgmt_spinlock);
+ priv->next_mgmt_bulk = NULL;
+ priv->mac_state = MAC_INIT;
+
+ /* initialize empty BSS list */
+ priv->curr_bss = NULL;
+ INIT_LIST_HEAD(&priv->bss_list);
+ spin_lock_init(&priv->bss_list_spinlock);
+
+ init_timer(&priv->bss_list_timer);
+ priv->bss_list_timer.data = (unsigned long)priv;
+ priv->bss_list_timer.function = at76_bss_list_timeout;
+
+ spin_lock_init(&priv->spy_spinlock);
+
+ /* mark all rx data entries as unused */
+ for (i = 0; i < NR_RX_DATA_BUF; i++)
+ priv->rx_data[i].skb = NULL;
+
+ priv->rx_tasklet.func = at76_rx_tasklet;
+ priv->rx_tasklet.data = 0;
+
+ priv->pm_mode = AT76_PM_OFF;
+ priv->pm_period = 0;
+
+ return priv;
+}
+
+static int at76_alloc_urbs(struct at76_priv *priv,
+ struct usb_interface *interface)
+{
+ struct usb_endpoint_descriptor *endpoint, *ep_in, *ep_out;
+ int i;
+ int buffer_size;
+ struct usb_host_interface *iface_desc;
+
+ at76_dbg(DBG_PROC_ENTRY, "%s: ENTER", __func__);
+
+ at76_dbg(DBG_URB, "%s: NumEndpoints %d ", __func__,
+ interface->altsetting[0].desc.bNumEndpoints);
+
+ ep_in = NULL;
+ ep_out = NULL;
+ iface_desc = interface->cur_altsetting;
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
+ endpoint = &iface_desc->endpoint[i].desc;
+
+ at76_dbg(DBG_URB, "%s: %d. endpoint: addr 0x%x attr 0x%x",
+ __func__, i, endpoint->bEndpointAddress,
+ endpoint->bmAttributes);
+
+ if (!ep_in && usb_endpoint_is_bulk_in(endpoint))
+ ep_in = endpoint;
+
+ if (!ep_out && usb_endpoint_is_bulk_out(endpoint))
+ ep_out = endpoint;
+ }
+
+ if (!ep_in || !ep_out) {
+ dev_printk(KERN_ERR, &interface->dev,
+ "bulk endpoints missing\n");
+ return -ENXIO;
+ }
+
+ priv->rx_pipe = usb_rcvbulkpipe(priv->udev, ep_in->bEndpointAddress);
+ priv->tx_pipe = usb_sndbulkpipe(priv->udev, ep_out->bEndpointAddress);
+
+ priv->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ priv->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!priv->rx_urb || !priv->tx_urb) {
+ dev_printk(KERN_ERR, &interface->dev, "cannot allocate URB\n");
+ return -ENOMEM;
+ }
+
+ buffer_size = sizeof(struct at76_tx_buffer) + MAX_PADDING_SIZE;
+ priv->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
+ if (!priv->bulk_out_buffer) {
+ dev_printk(KERN_ERR, &interface->dev,
+ "cannot allocate output buffer\n");
+ return -ENOMEM;
+ }
+
+ at76_dbg(DBG_PROC_ENTRY, "%s: EXIT", __func__);
+
+ return 0;
+}
+
+/* Register network device and initialize the hardware */
+static int at76_init_new_device(struct at76_priv *priv,
+ struct usb_interface *interface)
+{
+ struct net_device *netdev = priv->netdev;
+ int ret;
+
+ /* set up the endpoint information */
+ /* check out the endpoints */
+
+ at76_dbg(DBG_DEVSTART, "USB interface: %d endpoints",
+ interface->cur_altsetting->desc.bNumEndpoints);
+
+ ret = at76_alloc_urbs(priv, interface);
+ if (ret < 0)
+ goto exit;
+
+ /* MAC address */
+ ret = at76_get_hw_config(priv);
+ if (ret < 0) {
+ dev_printk(KERN_ERR, &interface->dev,
+ "cannot get MAC address\n");
+ goto exit;
+ }
+
+ priv->domain = at76_get_reg_domain(priv->regulatory_domain);
+ /* init. netdev->dev_addr */
+ memcpy(netdev->dev_addr, priv->mac_addr, ETH_ALEN);
+
+ priv->channel = DEF_CHANNEL;
+ priv->iw_mode = IW_MODE_INFRA;
+ priv->rts_threshold = DEF_RTS_THRESHOLD;
+ priv->frag_threshold = DEF_FRAG_THRESHOLD;
+ priv->short_retry_limit = DEF_SHORT_RETRY_LIMIT;
+ priv->txrate = TX_RATE_AUTO;
+ priv->preamble_type = PREAMBLE_TYPE_LONG;
+ priv->beacon_period = 100;
+ priv->beacons_last_qual = jiffies;
+ priv->auth_mode = WLAN_AUTH_OPEN;
+ priv->scan_min_time = DEF_SCAN_MIN_TIME;
+ priv->scan_max_time = DEF_SCAN_MAX_TIME;
+ priv->scan_mode = SCAN_TYPE_ACTIVE;
+
+ netdev->flags &= ~IFF_MULTICAST; /* not yet or never */
+ netdev->open = at76_open;
+ netdev->stop = at76_stop;
+ netdev->get_stats = at76_get_stats;
+ netdev->ethtool_ops = &at76_ethtool_ops;
+
+ /* Add pointers to enable iwspy support. */
+ priv->wireless_data.spy_data = &priv->spy_data;
+ netdev->wireless_data = &priv->wireless_data;
+
+ netdev->hard_start_xmit = at76_tx;
+ netdev->tx_timeout = at76_tx_timeout;
+ netdev->watchdog_timeo = 2 * HZ;
+ netdev->wireless_handlers = &at76_handler_def;
+ netdev->set_multicast_list = at76_set_multicast;
+ netdev->set_mac_address = at76_set_mac_address;
+ dev_alloc_name(netdev, "wlan%d");
+
+ ret = register_netdev(priv->netdev);
+ if (ret) {
+ dev_printk(KERN_ERR, &interface->dev,
+ "cannot register netdevice (status %d)!\n", ret);
+ goto exit;
+ }
+ priv->netdev_registered = 1;
+
+ printk(KERN_INFO "%s: USB %s, MAC %s, firmware %d.%d.%d-%d\n",
+ netdev->name, interface->dev.bus_id, mac2str(priv->mac_addr),
+ priv->fw_version.major, priv->fw_version.minor,
+ priv->fw_version.patch, priv->fw_version.build);
+ printk(KERN_INFO "%s: regulatory domain 0x%02x: %s\n", netdev->name,
+ priv->regulatory_domain, priv->domain->name);
+
+ /* we let this timer run the whole time this driver instance lives */
+ mod_timer(&priv->bss_list_timer, jiffies + BSS_LIST_TIMEOUT);
+
+exit:
+ return ret;
+}
+
+static void at76_delete_device(struct at76_priv *priv)
+{
+ int i;
+
+ at76_dbg(DBG_PROC_ENTRY, "%s: ENTER", __func__);
+
+ /* The device is gone, don't bother turning it off */
+ priv->device_unplugged = 1;
+
+ if (priv->netdev_registered)
+ unregister_netdev(priv->netdev);
+
+ /* assuming we used keventd, it must quiesce too */
+ flush_scheduled_work();
+
+ kfree(priv->bulk_out_buffer);
+
+ if (priv->tx_urb) {
+ usb_kill_urb(priv->tx_urb);
+ usb_free_urb(priv->tx_urb);
+ }
+ if (priv->rx_urb) {
+ usb_kill_urb(priv->rx_urb);
+ usb_free_urb(priv->rx_urb);
+ }
+
+ at76_dbg(DBG_PROC_ENTRY, "%s: unlinked urbs", __func__);
+
+ if (priv->rx_skb)
+ kfree_skb(priv->rx_skb);
+
+ at76_free_bss_list(priv);
+ del_timer_sync(&priv->bss_list_timer);
+ cancel_delayed_work(&priv->dwork_get_scan);
+ cancel_delayed_work(&priv->dwork_beacon);
+ cancel_delayed_work(&priv->dwork_auth);
+ cancel_delayed_work(&priv->dwork_assoc);
+
+ if (priv->mac_state == MAC_CONNECTED)
+ at76_iwevent_bss_disconnect(priv->netdev);
+
+ for (i = 0; i < NR_RX_DATA_BUF; i++)
+ if (priv->rx_data[i].skb) {
+ dev_kfree_skb(priv->rx_data[i].skb);
+ priv->rx_data[i].skb = NULL;
+ }
+ usb_put_dev(priv->udev);
+
+ at76_dbg(DBG_PROC_ENTRY, "%s: before freeing priv/netdev", __func__);
+ free_netdev(priv->netdev); /* priv is in netdev */
+
+ at76_dbg(DBG_PROC_ENTRY, "%s: EXIT", __func__);
+}
+
+static int at76_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ int ret;
+ struct at76_priv *priv;
+ struct fwentry *fwe;
+ struct usb_device *udev;
+ int op_mode;
+ int need_ext_fw = 0;
+ struct mib_fw_version fwv;
+ int board_type = (int)id->driver_info;
+
+ udev = usb_get_dev(interface_to_usbdev(interface));
+
+ /* Load firmware into kernel memory */
+ fwe = at76_load_firmware(udev, board_type);
+ if (!fwe) {
+ ret = -ENOENT;
+ goto error;
+ }
+
+ op_mode = at76_get_op_mode(udev);
+
+ at76_dbg(DBG_DEVSTART, "opmode %d", op_mode);
+
+ /* we get OPMODE_NONE with 2.4.23, SMC2662W-AR ???
+ we get 204 with 2.4.23, Fiberline FL-WL240u (505A+RFMD2958) ??? */
+
+ if (op_mode == OPMODE_HW_CONFIG_MODE) {
+ dev_printk(KERN_ERR, &interface->dev,
+ "cannot handle a device in HW_CONFIG_MODE\n");
+ ret = -EBUSY;
+ goto error;
+ }
+
+ if (op_mode != OPMODE_NORMAL_NIC_WITH_FLASH
+ && op_mode != OPMODE_NORMAL_NIC_WITHOUT_FLASH) {
+ /* download internal firmware part */
+ dev_printk(KERN_DEBUG, &interface->dev,
+ "downloading internal firmware\n");
+ ret = at76_load_internal_fw(udev, fwe);
+ if (ret < 0) {
+ dev_printk(KERN_ERR, &interface->dev,
+ "error %d downloading internal firmware\n",
+ ret);
+ goto error;
+ }
+ usb_put_dev(udev);
+ return ret;
+ }
+
+ /* Internal firmware already inside the device. Get firmware
+ * version to test if external firmware is loaded.
+ * This works only for newer firmware, e.g. the Intersil 0.90.x
+ * says "control timeout on ep0in" and subsequent
+ * at76_get_op_mode() fail too :-( */
+
+ /* if version >= 0.100.x.y or device with built-in flash we can
+ * query the device for the fw version */
+ if ((fwe->fw_version.major > 0 || fwe->fw_version.minor >= 100)
+ || (op_mode == OPMODE_NORMAL_NIC_WITH_FLASH)) {
+ ret = at76_get_mib(udev, MIB_FW_VERSION, &fwv, sizeof(fwv));
+ if (ret < 0 || (fwv.major | fwv.minor) == 0)
+ need_ext_fw = 1;
+ } else
+ /* No way to check firmware version, reload to be sure */
+ need_ext_fw = 1;
+
+ if (need_ext_fw) {
+ dev_printk(KERN_DEBUG, &interface->dev,
+ "downloading external firmware\n");
+
+ ret = at76_load_external_fw(udev, fwe);
+ if (ret)
+ goto error;
+
+ /* Re-check firmware version */
+ ret = at76_get_mib(udev, MIB_FW_VERSION, &fwv, sizeof(fwv));
+ if (ret < 0) {
+ dev_printk(KERN_ERR, &interface->dev,
+ "error %d getting firmware version\n", ret);
+ goto error;
+ }
+ }
+
+ priv = at76_alloc_new_device(udev);
+ if (!priv) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ SET_NETDEV_DEV(priv->netdev, &interface->dev);
+ usb_set_intfdata(interface, priv);
+
+ memcpy(&priv->fw_version, &fwv, sizeof(struct mib_fw_version));
+ priv->board_type = board_type;
+
+ ret = at76_init_new_device(priv, interface);
+ if (ret < 0)
+ at76_delete_device(priv);
+
+ return ret;
+
+error:
+ usb_put_dev(udev);
+ return ret;
+}
+
+static void at76_disconnect(struct usb_interface *interface)
+{
+ struct at76_priv *priv;
+
+ priv = usb_get_intfdata(interface);
+ usb_set_intfdata(interface, NULL);
+
+ /* Disconnect after loading internal firmware */
+ if (!priv)
+ return;
+
+ printk(KERN_INFO "%s: disconnecting\n", priv->netdev->name);
+ at76_delete_device(priv);
+ dev_printk(KERN_INFO, &interface->dev, "disconnected\n");
+}
+
+/* Structure for registering this driver with the USB subsystem */
+static struct usb_driver at76_driver = {
+ .name = DRIVER_NAME,
+ .probe = at76_probe,
+ .disconnect = at76_disconnect,
+ .id_table = dev_table,
+};
+
+static int __init at76_mod_init(void)
+{
+ int result;
+
+ printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION " loading\n");
+
+ mutex_init(&fw_mutex);
+
+ /* register this driver with the USB subsystem */
+ result = usb_register(&at76_driver);
+ if (result < 0)
+ printk(KERN_ERR DRIVER_NAME
+ ": usb_register failed (status %d)\n", result);
+
+ led_trigger_register_simple("at76_usb-tx", &ledtrig_tx);
+ return result;
+}
+
+static void __exit at76_mod_exit(void)
+{
+ int i;
+
+ printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION " unloading\n");
+ usb_deregister(&at76_driver);
+ for (i = 0; i < ARRAY_SIZE(firmwares); i++) {
+ if (firmwares[i].fw)
+ release_firmware(firmwares[i].fw);
+ }
+ led_trigger_unregister_simple(ledtrig_tx);
+}
+
+module_param_named(debug, at76_debug, int, 0600);
+MODULE_PARM_DESC(debug, "Debugging level");
+
+module_init(at76_mod_init);
+module_exit(at76_mod_exit);
+
+MODULE_AUTHOR("Oliver Kurth <oku@masqmail.cx>");
+MODULE_AUTHOR("Joerg Albert <joerg.albert@gmx.de>");
+MODULE_AUTHOR("Alex <alex@foogod.com>");
+MODULE_AUTHOR("Nick Jones");
+MODULE_AUTHOR("Balint Seeber <n0_5p4m_p13453@hotmail.com>");
+MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/at76_usb/at76_usb.h b/drivers/staging/at76_usb/at76_usb.h
new file mode 100644
index 0000000..b20be9d
--- /dev/null
+++ b/drivers/staging/at76_usb/at76_usb.h
@@ -0,0 +1,619 @@
+/*
+ * Copyright (c) 2002,2003 Oliver Kurth
+ * (c) 2003,2004 Joerg Albert <joerg.albert@gmx.de>
+ * (c) 2007 Guido Guenther <agx@sigxcpu.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This driver was based on information from the Sourceforge driver
+ * released and maintained by Atmel:
+ *
+ * http://sourceforge.net/projects/atmelwlandriver/
+ *
+ * Although the code was completely re-written,
+ * it would have been impossible without Atmel's decision to
+ * release an Open Source driver (unfortunately the firmware was
+ * kept binary only). Thanks for that decision to Atmel!
+ */
+
+#ifndef _AT76_USB_H
+#define _AT76_USB_H
+
+/* Board types */
+enum board_type {
+ BOARD_503_ISL3861 = 1,
+ BOARD_503_ISL3863 = 2,
+ BOARD_503 = 3,
+ BOARD_503_ACC = 4,
+ BOARD_505 = 5,
+ BOARD_505_2958 = 6,
+ BOARD_505A = 7,
+ BOARD_505AMX = 8
+};
+
+/* our private ioctl's */
+/* preamble length (0 - long, 1 - short, 2 - auto) */
+#define AT76_SET_SHORT_PREAMBLE (SIOCIWFIRSTPRIV + 0)
+#define AT76_GET_SHORT_PREAMBLE (SIOCIWFIRSTPRIV + 1)
+/* which debug channels are enabled */
+#define AT76_SET_DEBUG (SIOCIWFIRSTPRIV + 2)
+#define AT76_GET_DEBUG (SIOCIWFIRSTPRIV + 3)
+/* power save mode (incl. the Atmel proprietary smart save mode) */
+#define AT76_SET_POWERSAVE_MODE (SIOCIWFIRSTPRIV + 4)
+#define AT76_GET_POWERSAVE_MODE (SIOCIWFIRSTPRIV + 5)
+/* min and max channel times for scan */
+#define AT76_SET_SCAN_TIMES (SIOCIWFIRSTPRIV + 6)
+#define AT76_GET_SCAN_TIMES (SIOCIWFIRSTPRIV + 7)
+/* scan mode (0 - active, 1 - passive) */
+#define AT76_SET_SCAN_MODE (SIOCIWFIRSTPRIV + 8)
+#define AT76_GET_SCAN_MODE (SIOCIWFIRSTPRIV + 9)
+
+#define CMD_STATUS_IDLE 0x00
+#define CMD_STATUS_COMPLETE 0x01
+#define CMD_STATUS_UNKNOWN 0x02
+#define CMD_STATUS_INVALID_PARAMETER 0x03
+#define CMD_STATUS_FUNCTION_NOT_SUPPORTED 0x04
+#define CMD_STATUS_TIME_OUT 0x07
+#define CMD_STATUS_IN_PROGRESS 0x08
+#define CMD_STATUS_HOST_FAILURE 0xff
+#define CMD_STATUS_SCAN_FAILED 0xf0
+
+/* answers to get op mode */
+#define OPMODE_NONE 0x00
+#define OPMODE_NORMAL_NIC_WITH_FLASH 0x01
+#define OPMODE_HW_CONFIG_MODE 0x02
+#define OPMODE_DFU_MODE_WITH_FLASH 0x03
+#define OPMODE_NORMAL_NIC_WITHOUT_FLASH 0x04
+
+#define CMD_SET_MIB 0x01
+#define CMD_GET_MIB 0x02
+#define CMD_SCAN 0x03
+#define CMD_JOIN 0x04
+#define CMD_START_IBSS 0x05
+#define CMD_RADIO_ON 0x06
+#define CMD_RADIO_OFF 0x07
+#define CMD_STARTUP 0x0B
+
+#define MIB_LOCAL 0x01
+#define MIB_MAC_ADDR 0x02
+#define MIB_MAC 0x03
+#define MIB_MAC_MGMT 0x05
+#define MIB_MAC_WEP 0x06
+#define MIB_PHY 0x07
+#define MIB_FW_VERSION 0x08
+#define MIB_MDOMAIN 0x09
+
+#define ADHOC_MODE 1
+#define INFRASTRUCTURE_MODE 2
+
+/* values for struct mib_local, field preamble_type */
+#define PREAMBLE_TYPE_LONG 0
+#define PREAMBLE_TYPE_SHORT 1
+#define PREAMBLE_TYPE_AUTO 2
+
+/* values for tx_rate */
+#define TX_RATE_1MBIT 0
+#define TX_RATE_2MBIT 1
+#define TX_RATE_5_5MBIT 2
+#define TX_RATE_11MBIT 3
+#define TX_RATE_AUTO 4
+
+/* power management modes */
+#define AT76_PM_OFF 1
+#define AT76_PM_ON 2
+#define AT76_PM_SMART 3
+
+struct hwcfg_r505 {
+ u8 cr39_values[14];
+ u8 reserved1[14];
+ u8 bb_cr[14];
+ u8 pidvid[4];
+ u8 mac_addr[ETH_ALEN];
+ u8 regulatory_domain;
+ u8 reserved2[14];
+ u8 cr15_values[14];
+ u8 reserved3[3];
+} __attribute__((packed));
+
+struct hwcfg_rfmd {
+ u8 cr20_values[14];
+ u8 cr21_values[14];
+ u8 bb_cr[14];
+ u8 pidvid[4];
+ u8 mac_addr[ETH_ALEN];
+ u8 regulatory_domain;
+ u8 low_power_values[14];
+ u8 normal_power_values[14];
+ u8 reserved1[3];
+} __attribute__((packed));
+
+struct hwcfg_intersil {
+ u8 mac_addr[ETH_ALEN];
+ u8 cr31_values[14];
+ u8 cr58_values[14];
+ u8 pidvid[4];
+ u8 regulatory_domain;
+ u8 reserved[1];
+} __attribute__((packed));
+
+union at76_hwcfg {
+ struct hwcfg_intersil i;
+ struct hwcfg_rfmd r3;
+ struct hwcfg_r505 r5;
+};
+
+#define WEP_SMALL_KEY_LEN (40 / 8)
+#define WEP_LARGE_KEY_LEN (104 / 8)
+
+struct at76_card_config {
+ u8 exclude_unencrypted;
+ u8 promiscuous_mode;
+ u8 short_retry_limit;
+ u8 encryption_type;
+ __le16 rts_threshold;
+ __le16 fragmentation_threshold; /* 256..2346 */
+ u8 basic_rate_set[4];
+ u8 auto_rate_fallback; /* 0,1 */
+ u8 channel;
+ u8 privacy_invoked;
+ u8 wep_default_key_id; /* 0..3 */
+ u8 current_ssid[32];
+ u8 wep_default_key_value[4][WEP_KEY_LEN];
+ u8 ssid_len;
+ u8 short_preamble;
+ __le16 beacon_period;
+} __attribute__((packed));
+
+struct at76_command {
+ u8 cmd;
+ u8 reserved;
+ __le16 size;
+ u8 data[0];
+} __attribute__((packed));
+
+/* Length of Atmel-specific Rx header before 802.11 frame */
+#define AT76_RX_HDRLEN offsetof(struct at76_rx_buffer, packet)
+
+struct at76_rx_buffer {
+ __le16 wlength;
+ u8 rx_rate;
+ u8 newbss;
+ u8 fragmentation;
+ u8 rssi;
+ u8 link_quality;
+ u8 noise_level;
+ __le32 rx_time;
+ u8 packet[IEEE80211_FRAME_LEN + IEEE80211_FCS_LEN];
+} __attribute__((packed));
+
+/* Length of Atmel-specific Tx header before 802.11 frame */
+#define AT76_TX_HDRLEN offsetof(struct at76_tx_buffer, packet)
+
+struct at76_tx_buffer {
+ __le16 wlength;
+ u8 tx_rate;
+ u8 padding;
+ u8 reserved[4];
+ u8 packet[IEEE80211_FRAME_LEN + IEEE80211_FCS_LEN];
+} __attribute__((packed));
+
+/* defines for scan_type below */
+#define SCAN_TYPE_ACTIVE 0
+#define SCAN_TYPE_PASSIVE 1
+
+struct at76_req_scan {
+ u8 bssid[ETH_ALEN];
+ u8 essid[32];
+ u8 scan_type;
+ u8 channel;
+ __le16 probe_delay;
+ __le16 min_channel_time;
+ __le16 max_channel_time;
+ u8 essid_size;
+ u8 international_scan;
+} __attribute__((packed));
+
+struct at76_req_ibss {
+ u8 bssid[ETH_ALEN];
+ u8 essid[32];
+ u8 bss_type;
+ u8 channel;
+ u8 essid_size;
+ u8 reserved[3];
+} __attribute__((packed));
+
+struct at76_req_join {
+ u8 bssid[ETH_ALEN];
+ u8 essid[32];
+ u8 bss_type;
+ u8 channel;
+ __le16 timeout;
+ u8 essid_size;
+ u8 reserved;
+} __attribute__((packed));
+
+struct set_mib_buffer {
+ u8 type;
+ u8 size;
+ u8 index;
+ u8 reserved;
+ union {
+ u8 byte;
+ __le16 word;
+ u8 addr[ETH_ALEN];
+ } data;
+} __attribute__((packed));
+
+struct mib_local {
+ u16 reserved0;
+ u8 beacon_enable;
+ u8 txautorate_fallback;
+ u8 reserved1;
+ u8 ssid_size;
+ u8 promiscuous_mode;
+ u16 reserved2;
+ u8 preamble_type;
+ u16 reserved3;
+} __attribute__((packed));
+
+struct mib_mac_addr {
+ u8 mac_addr[ETH_ALEN];
+ u8 res[2]; /* ??? */
+ u8 group_addr[4][ETH_ALEN];
+ u8 group_addr_status[4];
+} __attribute__((packed));
+
+struct mib_mac {
+ __le32 max_tx_msdu_lifetime;
+ __le32 max_rx_lifetime;
+ __le16 frag_threshold;
+ __le16 rts_threshold;
+ __le16 cwmin;
+ __le16 cwmax;
+ u8 short_retry_time;
+ u8 long_retry_time;
+ u8 scan_type; /* active or passive */
+ u8 scan_channel;
+ __le16 probe_delay; /* delay before ProbeReq in active scan, RO */
+ __le16 min_channel_time;
+ __le16 max_channel_time;
+ __le16 listen_interval;
+ u8 desired_ssid[32];
+ u8 desired_bssid[ETH_ALEN];
+ u8 desired_bsstype; /* ad-hoc or infrastructure */
+ u8 reserved2;
+} __attribute__((packed));
+
+struct mib_mac_mgmt {
+ __le16 beacon_period;
+ __le16 CFP_max_duration;
+ __le16 medium_occupancy_limit;
+ __le16 station_id; /* assoc id */
+ __le16 ATIM_window;
+ u8 CFP_mode;
+ u8 privacy_option_implemented;
+ u8 DTIM_period;
+ u8 CFP_period;
+ u8 current_bssid[ETH_ALEN];
+ u8 current_essid[32];
+ u8 current_bss_type;
+ u8 power_mgmt_mode;
+ /* rfmd and 505 */
+ u8 ibss_change;
+ u8 res;
+ u8 multi_domain_capability_implemented;
+ u8 multi_domain_capability_enabled;
+ u8 country_string[3];
+ u8 reserved[3];
+} __attribute__((packed));
+
+struct mib_mac_wep {
+ u8 privacy_invoked; /* 0 disable encr., 1 enable encr */
+ u8 wep_default_key_id;
+ u8 wep_key_mapping_len;
+ u8 exclude_unencrypted;
+ __le32 wep_icv_error_count;
+ __le32 wep_excluded_count;
+ u8 wep_default_keyvalue[WEP_KEYS][WEP_KEY_LEN];
+ u8 encryption_level; /* 1 for 40bit, 2 for 104bit encryption */
+} __attribute__((packed));
+
+struct mib_phy {
+ __le32 ed_threshold;
+
+ __le16 slot_time;
+ __le16 sifs_time;
+ __le16 preamble_length;
+ __le16 plcp_header_length;
+ __le16 mpdu_max_length;
+ __le16 cca_mode_supported;
+
+ u8 operation_rate_set[4];
+ u8 channel_id;
+ u8 current_cca_mode;
+ u8 phy_type;
+ u8 current_reg_domain;
+} __attribute__((packed));
+
+struct mib_fw_version {
+ u8 major;
+ u8 minor;
+ u8 patch;
+ u8 build;
+} __attribute__((packed));
+
+struct mib_mdomain {
+ u8 tx_powerlevel[14];
+ u8 channel_list[14]; /* 0 for invalid channels */
+} __attribute__((packed));
+
+struct at76_fw_header {
+ __le32 crc; /* CRC32 of the whole image */
+ __le32 board_type; /* firmware compatibility code */
+ u8 build; /* firmware build number */
+ u8 patch; /* firmware patch level */
+ u8 minor; /* firmware minor version */
+ u8 major; /* firmware major version */
+ __le32 str_offset; /* offset of the copyright string */
+ __le32 int_fw_offset; /* internal firmware image offset */
+ __le32 int_fw_len; /* internal firmware image length */
+ __le32 ext_fw_offset; /* external firmware image offset */
+ __le32 ext_fw_len; /* external firmware image length */
+} __attribute__((packed));
+
+enum mac_state {
+ MAC_INIT,
+ MAC_SCANNING,
+ MAC_AUTH,
+ MAC_ASSOC,
+ MAC_JOINING,
+ MAC_CONNECTED,
+ MAC_OWN_IBSS
+};
+
+/* a description of a regulatory domain and the allowed channels */
+struct reg_domain {
+ u16 code;
+ char const *name;
+ u32 channel_map; /* if bit N is set, channel (N+1) is allowed */
+};
+
+/* how long do we keep a (I)BSS in the bss_list in jiffies
+ this should be long enough for the user to retrieve the table
+ (by iwlist ?) after the device started, because all entries from
+ other channels than the one the device locks on get removed, too */
+#define BSS_LIST_TIMEOUT (120 * HZ)
+/* struct to store BSS info found during scan */
+#define BSS_LIST_MAX_RATE_LEN 32 /* 32 rates should be enough ... */
+
+struct bss_info {
+ struct list_head list;
+
+ u8 bssid[ETH_ALEN]; /* bssid */
+ u8 ssid[IW_ESSID_MAX_SIZE]; /* essid */
+ u8 ssid_len; /* length of ssid above */
+ u8 channel;
+ u16 capa; /* BSS capabilities */
+ u16 beacon_interval; /* beacon interval, Kus (1024 microseconds) */
+ u8 rates[BSS_LIST_MAX_RATE_LEN]; /* supported rates in units of
+ 500 kbps, ORed with 0x80 for
+ basic rates */
+ u8 rates_len;
+
+ /* quality of received beacon */
+ u8 rssi;
+ u8 link_qual;
+ u8 noise_level;
+
+ unsigned long last_rx; /* time (jiffies) of last beacon received */
+};
+
+/* a rx data buffer to collect rx fragments */
+struct rx_data_buf {
+ u8 sender[ETH_ALEN]; /* sender address */
+ u16 seqnr; /* sequence number */
+ u16 fragnr; /* last fragment received */
+ unsigned long last_rx; /* jiffies of last rx */
+ struct sk_buff *skb; /* == NULL if entry is free */
+};
+
+#define NR_RX_DATA_BUF 8
+
+/* Data for one loaded firmware file */
+struct fwentry {
+ const char *const fwname;
+ const struct firmware *fw;
+ int extfw_size;
+ int intfw_size;
+ /* pointer to loaded firmware, no need to free */
+ u8 *extfw; /* external firmware, extfw_size bytes long */
+ u8 *intfw; /* internal firmware, intfw_size bytes long */
+ enum board_type board_type; /* board type */
+ struct mib_fw_version fw_version;
+ int loaded; /* Loaded and parsed successfully */
+};
+
+struct at76_priv {
+ struct usb_device *udev; /* USB device pointer */
+ struct net_device *netdev; /* net device pointer */
+ struct net_device_stats stats; /* net device stats */
+ struct iw_statistics wstats; /* wireless stats */
+
+ struct sk_buff *rx_skb; /* skbuff for receiving data */
+ void *bulk_out_buffer; /* buffer for sending data */
+
+ struct urb *tx_urb; /* URB for sending data */
+ struct urb *rx_urb; /* URB for receiving data */
+
+ unsigned int tx_pipe; /* bulk out pipe */
+ unsigned int rx_pipe; /* bulk in pipe */
+
+ struct mutex mtx; /* locks this structure */
+
+ /* work queues */
+ struct work_struct work_assoc_done;
+ struct work_struct work_join;
+ struct work_struct work_new_bss;
+ struct work_struct work_start_scan;
+ struct work_struct work_set_promisc;
+ struct work_struct work_submit_rx;
+ struct delayed_work dwork_restart;
+ struct delayed_work dwork_get_scan;
+ struct delayed_work dwork_beacon;
+ struct delayed_work dwork_auth;
+ struct delayed_work dwork_assoc;
+
+ struct tasklet_struct rx_tasklet;
+
+ /* the WEP stuff */
+ int wep_enabled; /* 1 if WEP is enabled */
+ int wep_key_id; /* key id to be used */
+ u8 wep_keys[WEP_KEYS][WEP_KEY_LEN]; /* the four WEP keys,
+ 5 or 13 bytes are used */
+ u8 wep_keys_len[WEP_KEYS]; /* the length of the above keys */
+
+ int channel;
+ int iw_mode;
+ u8 bssid[ETH_ALEN];
+ u8 essid[IW_ESSID_MAX_SIZE];
+ int essid_size;
+ int radio_on;
+ int promisc;
+
+ int preamble_type; /* 0 - long, 1 - short, 2 - auto */
+ int auth_mode; /* authentication type: 0 open, 1 shared key */
+ int txrate; /* 0,1,2,3 = 1,2,5.5,11 Mbps, 4 is auto */
+ int frag_threshold; /* threshold for fragmentation of tx packets */
+ int rts_threshold; /* threshold for RTS mechanism */
+ int short_retry_limit;
+
+ int scan_min_time; /* scan min channel time */
+ int scan_max_time; /* scan max channel time */
+ int scan_mode; /* SCAN_TYPE_ACTIVE, SCAN_TYPE_PASSIVE */
+ int scan_need_any; /* if set, need to scan for any ESSID */
+
+ /* the list we got from scanning */
+ spinlock_t bss_list_spinlock; /* protects bss_list operations */
+ struct list_head bss_list; /* list of BSS we got beacons from */
+ struct timer_list bss_list_timer; /* timer to purge old entries
+ from bss_list */
+ struct bss_info *curr_bss; /* current BSS */
+ u16 assoc_id; /* current association ID, if associated */
+
+ u8 wanted_bssid[ETH_ALEN];
+ int wanted_bssid_valid; /* != 0 if wanted_bssid is to be used */
+
+ /* some data for infrastructure mode only */
+ spinlock_t mgmt_spinlock; /* this spinlock protects access to
+ next_mgmt_bulk */
+
+ struct at76_tx_buffer *next_mgmt_bulk; /* pending management msg to
+ send via bulk out */
+ enum mac_state mac_state;
+ enum {
+ SCAN_IDLE,
+ SCAN_IN_PROGRESS,
+ SCAN_COMPLETED
+ } scan_state;
+ time_t last_scan;
+
+ int retries; /* remaining retries in case of timeout when
+ * sending AuthReq or AssocReq */
+ u8 pm_mode; /* power management mode */
+ u32 pm_period; /* power management period in microseconds */
+
+ struct reg_domain const *domain; /* reg domain description */
+
+ /* iwspy support */
+ spinlock_t spy_spinlock;
+ struct iw_spy_data spy_data;
+
+ struct iw_public_data wireless_data;
+
+ /* These fields contain HW config provided by the device (not all of
+ * these fields are used by all board types) */
+ u8 mac_addr[ETH_ALEN];
+ u8 regulatory_domain;
+
+ struct at76_card_config card_config;
+
+ /* store rx fragments until complete */
+ struct rx_data_buf rx_data[NR_RX_DATA_BUF];
+
+ enum board_type board_type;
+ struct mib_fw_version fw_version;
+
+ unsigned int device_unplugged:1;
+ unsigned int netdev_registered:1;
+ struct set_mib_buffer mib_buf; /* global buffer for set_mib calls */
+
+ /* beacon counting */
+ int beacon_period; /* period of mgmt beacons, Kus */
+ int beacons_received;
+ unsigned long beacons_last_qual; /* time we restarted counting
+ beacons */
+};
+
+struct at76_rx_radiotap {
+ struct ieee80211_radiotap_header rt_hdr;
+ __le64 rt_tsft;
+ u8 rt_flags;
+ u8 rt_rate;
+ s8 rt_signal;
+ s8 rt_noise;
+};
+
+#define AT76_RX_RADIOTAP_PRESENT \
+ ((1 << IEEE80211_RADIOTAP_TSFT) | \
+ (1 << IEEE80211_RADIOTAP_FLAGS) | \
+ (1 << IEEE80211_RADIOTAP_RATE) | \
+ (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) | \
+ (1 << IEEE80211_RADIOTAP_DB_ANTNOISE))
+
+#define BEACON_MAX_DATA_LENGTH 1500
+
+/* the maximum size of an AssocReq packet */
+#define ASSOCREQ_MAX_SIZE \
+ (AT76_TX_HDRLEN + sizeof(struct ieee80211_assoc_request) + \
+ 1 + 1 + IW_ESSID_MAX_SIZE + 1 + 1 + 4)
+
+/* for shared secret auth, add the challenge text size */
+#define AUTH_FRAME_SIZE (AT76_TX_HDRLEN + sizeof(struct ieee80211_auth))
+
+/* Maximal number of AuthReq retries */
+#define AUTH_RETRIES 3
+
+/* Maximal number of AssocReq retries */
+#define ASSOC_RETRIES 3
+
+/* Beacon timeout in managed mode when we are connected */
+#define BEACON_TIMEOUT (10 * HZ)
+
+/* Timeout for authentication response */
+#define AUTH_TIMEOUT (1 * HZ)
+
+/* Timeout for association response */
+#define ASSOC_TIMEOUT (1 * HZ)
+
+/* Polling interval when scan is running */
+#define SCAN_POLL_INTERVAL (HZ / 4)
+
+/* Command completion timeout */
+#define CMD_COMPLETION_TIMEOUT (5 * HZ)
+
+#define DEF_RTS_THRESHOLD 1536
+#define DEF_FRAG_THRESHOLD 1536
+#define DEF_SHORT_RETRY_LIMIT 8
+#define DEF_CHANNEL 10
+#define DEF_SCAN_MIN_TIME 10
+#define DEF_SCAN_MAX_TIME 120
+
+#define MAX_RTS_THRESHOLD (MAX_FRAG_THRESHOLD + 1)
+
+/* the max padding size for tx in bytes (see calc_padding) */
+#define MAX_PADDING_SIZE 53
+
+#endif /* _AT76_USB_H */
--
1.6.0.2
^ permalink raw reply related [flat|nested] 37+ messages in thread* Re: [PATCH 25/25] staging: at76_usb wireless driver
2008-10-13 21:38 ` [PATCH 25/25] staging: at76_usb wireless driver Greg KH
@ 2008-10-13 21:49 ` Pavel Roskin
2008-10-13 21:51 ` Greg KH
0 siblings, 1 reply; 37+ messages in thread
From: Pavel Roskin @ 2008-10-13 21:49 UTC (permalink / raw)
To: Greg KH; +Cc: linux-kernel, John W. Linville, Greg Kroah-Hartman
On Mon, 2008-10-13 at 14:38 -0700, Greg KH wrote:
> From: Pavel Roskin <proski@gnu.org>
>
> Add the at76_usb wireless driver to the staging tree while the
> other kernel driver (out of tree) gets rewritten to use the internal
> wireless stack.
>
> This patch comes directly from the Fedora kernel tree, with only the
> directory placement of the files changed.
>
> Signed-off-by: Pavel Roskin <proski@gnu.org>
I'm not going to support this code in any way. I disclaim any
responsibility for this code.
--
Regards,
Pavel Roskin
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 25/25] staging: at76_usb wireless driver
2008-10-13 21:49 ` Pavel Roskin
@ 2008-10-13 21:51 ` Greg KH
2008-10-13 21:58 ` Pavel Roskin
0 siblings, 1 reply; 37+ messages in thread
From: Greg KH @ 2008-10-13 21:51 UTC (permalink / raw)
To: Pavel Roskin; +Cc: Greg KH, linux-kernel, John W. Linville
On Mon, Oct 13, 2008 at 05:49:33PM -0400, Pavel Roskin wrote:
> On Mon, 2008-10-13 at 14:38 -0700, Greg KH wrote:
> > From: Pavel Roskin <proski@gnu.org>
> >
> > Add the at76_usb wireless driver to the staging tree while the
> > other kernel driver (out of tree) gets rewritten to use the internal
> > wireless stack.
> >
> > This patch comes directly from the Fedora kernel tree, with only the
> > directory placement of the files changed.
> >
> > Signed-off-by: Pavel Roskin <proski@gnu.org>
>
> I'm not going to support this code in any way. I disclaim any
> responsibility for this code.
Heh, that's fine with me, but as you did write this code, I do want to
give you the proper credit. I'll maintain it while it is in the staging
tree.
You might want to poke John, as his version of this patch adds your name
to the MAINTAINERS file in the Fedora kernels, something I don't think
you want to have done :)
thanks,
greg k-h
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 25/25] staging: at76_usb wireless driver
2008-10-13 21:51 ` Greg KH
@ 2008-10-13 21:58 ` Pavel Roskin
2008-10-13 22:06 ` Greg KH
0 siblings, 1 reply; 37+ messages in thread
From: Pavel Roskin @ 2008-10-13 21:58 UTC (permalink / raw)
To: Greg KH; +Cc: linux-kernel, John W. Linville
On Mon, 2008-10-13 at 14:51 -0700, Greg KH wrote:
> On Mon, Oct 13, 2008 at 05:49:33PM -0400, Pavel Roskin wrote:
> > On Mon, 2008-10-13 at 14:38 -0700, Greg KH wrote:
> > > From: Pavel Roskin <proski@gnu.org>
> > >
> > > Add the at76_usb wireless driver to the staging tree while the
> > > other kernel driver (out of tree) gets rewritten to use the internal
> > > wireless stack.
> > >
> > > This patch comes directly from the Fedora kernel tree, with only the
> > > directory placement of the files changed.
> > >
> > > Signed-off-by: Pavel Roskin <proski@gnu.org>
> >
> > I'm not going to support this code in any way. I disclaim any
> > responsibility for this code.
>
> Heh, that's fine with me, but as you did write this code, I do want to
> give you the proper credit. I'll maintain it while it is in the staging
> tree.
>
> You might want to poke John, as his version of this patch adds your name
> to the MAINTAINERS file in the Fedora kernels, something I don't think
> you want to have done :)
OK, I don't care as long as I don't get any bug reports or support
requests.
--
Regards,
Pavel Roskin
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [PATCH 25/25] staging: at76_usb wireless driver
2008-10-13 21:58 ` Pavel Roskin
@ 2008-10-13 22:06 ` Greg KH
0 siblings, 0 replies; 37+ messages in thread
From: Greg KH @ 2008-10-13 22:06 UTC (permalink / raw)
To: Pavel Roskin; +Cc: linux-kernel, John W. Linville
On Mon, Oct 13, 2008 at 05:58:11PM -0400, Pavel Roskin wrote:
> On Mon, 2008-10-13 at 14:51 -0700, Greg KH wrote:
> > On Mon, Oct 13, 2008 at 05:49:33PM -0400, Pavel Roskin wrote:
> > > On Mon, 2008-10-13 at 14:38 -0700, Greg KH wrote:
> > > > From: Pavel Roskin <proski@gnu.org>
> > > >
> > > > Add the at76_usb wireless driver to the staging tree while the
> > > > other kernel driver (out of tree) gets rewritten to use the internal
> > > > wireless stack.
> > > >
> > > > This patch comes directly from the Fedora kernel tree, with only the
> > > > directory placement of the files changed.
> > > >
> > > > Signed-off-by: Pavel Roskin <proski@gnu.org>
> > >
> > > I'm not going to support this code in any way. I disclaim any
> > > responsibility for this code.
> >
> > Heh, that's fine with me, but as you did write this code, I do want to
> > give you the proper credit. I'll maintain it while it is in the staging
> > tree.
> >
> > You might want to poke John, as his version of this patch adds your name
> > to the MAINTAINERS file in the Fedora kernels, something I don't think
> > you want to have done :)
>
> OK, I don't care as long as I don't get any bug reports or support
> requests.
If you do, point them directly to me.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [GIT PATCH] STAGING patches for 2.6.28
2008-10-13 21:36 ` [GIT PATCH] STAGING patches for 2.6.28 Greg KH
2008-10-13 21:38 ` [PATCH 24/25] Staging: workaround build system bug Greg KH
2008-10-13 21:38 ` [PATCH 25/25] staging: at76_usb wireless driver Greg KH
@ 2008-10-17 20:34 ` Linus Torvalds
2008-10-17 21:38 ` Greg KH
2 siblings, 1 reply; 37+ messages in thread
From: Linus Torvalds @ 2008-10-17 20:34 UTC (permalink / raw)
To: Greg KH; +Cc: Andrew Morton, linux-kernel
On Mon, 13 Oct 2008, Greg KH wrote:
>
> I've now added 2 more patches to this tree, fixing a build error if you
> did not build any staging drivers into your tree (the normal mode of
> building), and added an additional wireless driver that came from the
> Fedora kernel trees.
Greg - I finally got around to merging this tree, and it got some
conflicts with the changes/cleanups to taint handling (and due to the
MAINTAINERS file cleanups/alphasort). They conflicts weren't all that
nasty, and I think they're all resolved correctly, but it might be worth
testing the TAINT_CRAP flag in particular. I tested the build in the
normal config, but didn't actually bother to test any tainted drivers.
Linus
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [GIT PATCH] STAGING patches for 2.6.28
2008-10-17 20:34 ` [GIT PATCH] STAGING patches for 2.6.28 Linus Torvalds
@ 2008-10-17 21:38 ` Greg KH
2008-10-17 22:00 ` Greg KH
0 siblings, 1 reply; 37+ messages in thread
From: Greg KH @ 2008-10-17 21:38 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Andrew Morton, linux-kernel
On Fri, Oct 17, 2008 at 01:34:42PM -0700, Linus Torvalds wrote:
>
>
> On Mon, 13 Oct 2008, Greg KH wrote:
> >
> > I've now added 2 more patches to this tree, fixing a build error if you
> > did not build any staging drivers into your tree (the normal mode of
> > building), and added an additional wireless driver that came from the
> > Fedora kernel trees.
>
> Greg - I finally got around to merging this tree, and it got some
> conflicts with the changes/cleanups to taint handling (and due to the
> MAINTAINERS file cleanups/alphasort). They conflicts weren't all that
> nasty, and I think they're all resolved correctly, but it might be worth
> testing the TAINT_CRAP flag in particular. I tested the build in the
> normal config, but didn't actually bother to test any tainted drivers.
Thanks for letting me know, I'll go build and test this right now.
greg k-h
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [GIT PATCH] STAGING patches for 2.6.28
2008-10-17 21:38 ` Greg KH
@ 2008-10-17 22:00 ` Greg KH
0 siblings, 0 replies; 37+ messages in thread
From: Greg KH @ 2008-10-17 22:00 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Andrew Morton, linux-kernel
On Fri, Oct 17, 2008 at 02:38:16PM -0700, Greg KH wrote:
> On Fri, Oct 17, 2008 at 01:34:42PM -0700, Linus Torvalds wrote:
> >
> >
> > On Mon, 13 Oct 2008, Greg KH wrote:
> > >
> > > I've now added 2 more patches to this tree, fixing a build error if you
> > > did not build any staging drivers into your tree (the normal mode of
> > > building), and added an additional wireless driver that came from the
> > > Fedora kernel trees.
> >
> > Greg - I finally got around to merging this tree, and it got some
> > conflicts with the changes/cleanups to taint handling (and due to the
> > MAINTAINERS file cleanups/alphasort). They conflicts weren't all that
> > nasty, and I think they're all resolved correctly, but it might be worth
> > testing the TAINT_CRAP flag in particular. I tested the build in the
> > normal config, but didn't actually bother to test any tainted drivers.
>
> Thanks for letting me know, I'll go build and test this right now.
Yes, this seems to be working just fine, my kernel is properly tainted
with crap now :)
thanks,
greg k-h
^ permalink raw reply [flat|nested] 37+ messages in thread